Andrés Tomazos
Supongamos que tengo un historial de git lineal de 8 confirmaciones y una rama (maestra):
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> [8=master]
Quiero mover el maestro a 4 (que puedo hacer con git branch -f master 4
):
1 -> 2 -> 3 -> [4=master] -> 5 -> 6 -> 7 -> 8
Ahora el árbol de trabajo está en el estado 4.
Ahora quiero aplicar los cambios de 4 -> 8
a mi árbol de trabajo como un parche.
Es decir, sin afectar el estado de la carpeta .git quiero aplicar los cambios desde 4->8
unstaged a mi árbol de trabajo. Después de esto, el árbol de trabajo debería estar en el estado 8, pero el estado comprometido y la rama principal deberían estar en el estado 4.
Otra forma de decirlo: suponga que después de mover el maestro a 4, realicé los cambios de 4->8 manualmente a mi árbol de trabajo sin agregarlos al índice. El resultado debe ser el mismo.
¿Cuál es la forma más fácil de hacer esto?
GabeSullice
Sé que llego tarde a la fiesta, pero para referencia de otros, creo que la forma más sencilla es:
git cherry-pick --no-commit 4..8
-
Más
git reset
después de eso para obtener los cambios sin organizar.– Román Susi
12 de enero de 2017 a las 18:34
jthill
git format-patch 4..8 | xargs git apply
[edit: this next one from the comment below skips making individual patch files]
git diff 4..8 | git apply
-
O, igualmente,
git diff 4..8 | git apply
– cmbuckley
9 de enero de 2013 a las 23:27
En su caso, si en realidad no le importa el bit “sin etapas”, lo más simple es probablemente
git checkout 8 -- .
Esto actualizará su árbol e índice para que coincida con el de la confirmación 8, sin cambiar su historial de confirmación. entonces puedes git reset
para descartar los cambios de índice.
Si realmente desea dejar el archivo de índice intacto, es un poco más complicado, ya que git siempre actualiza el árbol de trabajo desde el índice. Podrías hacer algo como
GIT_INDEX_FILE=/tmp/foo git checkout 8 -- .
Esto usará la ruta /tmp/foo
como un archivo de índice temporal solo para este comando. Es posible que desee eliminar este archivo después.
En una situación más complicada en la que desea volver a aplicar parches que en realidad no lo devolverían al estado preciso de la confirmación 8, puede usar git cherry-pick --no-commit commit1 commit2 ...
para aplicar las confirmaciones en secuencia. Esto todavía modificará el índice, por supuesto.
tíofrancotirador
Haciendo que el estado de OP suceda:
cyclone% mkdir myrepo
cyclone% cd myrepo
cyclone% git init
Initialized empty Git repository in /tmp/myrepo/.git/
cyclone% echo 'Hello, world!' >hello
cyclone% git add hello
cyclone% git commit -m 'Initial import'
[master (root-commit) 6ec97b1] Initial import
1 file changed, 1 insertion(+)
create mode 100644 hello
cyclone% echo 'How are you?' >>hello
cyclone% git add hello
cyclone% git commit -m "Added 'How are you?'"
[master 8786161] Added 'How are you?'
1 file changed, 1 insertion(+)
# Now, if I reset back, the commit object
# seems to be removed (possibly due to my current
# version of Git vs. OP's older version?). To prevent
# this, I'll "name" the commit OP considers '8'.
# Thus, OP would put the commit ID corresponding
# to their '8' wherever I put 'tip'.
cyclone% git branch tip
# In all my years, I've never heard of
# 'git branch --force' -- then again, I'm not
# Linus Torvalds, so I guess I know only like
# half of Git, as do all of you (unless you ARE
# Linus Torvalds). Nonetheless, if I try the next,
# commented-out line, I get:
# fatal: Cannot force update the current branch.
#git branch -f master 'HEAD^'
# A (too?) quick Google doesn't really help on the
# matter, so... In the undying words of...
# well, somebody-or-other in the whole long history
# of ever: Lemme fix that for ya...
cyclone% git update-ref HEAD 'HEAD^'
# Now this is the crucial point: If this is going
# to be easy, you need a recent enough version of
# Git to support 'git restore', because that DOES
# make things easy (see below).
cyclone% git restore --staged .
# Now, this is actually the state OP wants, but
# since they are at a different state, I guess we'll
# wantonly destroy it...
cyclone% git checkout .
Updated 1 path from the index
Con esto, estamos en el estado de OP:
# We are on master, with no changes (staged nor unstaged)
# and master is the "old" commit:
cyclone% git status
On branch master
nothing to commit, working tree clean
# The working tree reflects the "old" commit:
cyclone% cat hello
Hello, world!
# Commit '8' (i.e. 'tip') reflects the "new"
# commit:
cyclone% git show tip:hello
Hello, world!
How are you?
Entonces, ahora viene el único comando simple que lleva el estado actual de OP al estado deseado de OP:
cyclone% git restore --source=tip .
Ahora estamos exactamente donde queremos estar:
# The changes between '4' and '8' are present, but
# not staged nor committed:
cyclone% git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: hello
no changes added to commit (use "git add" and/or "git commit -a")
# The current branch (master, as Git tells us above) is on
# what OP considers '4':
cyclone% git log
commit f4661e0c12a20acb6dd0bc4afe8c9b2301667608 (HEAD -> master)
Author: Simon "UncleSniper" Bausch <(REDACTED)>
Date: (no matter)
Initial import
# The working tree includes the changes between '4'
# and '8':
cyclone% cat hello
Hello, world!
How are you?
# The changes between '4' and '8' are "present" (see
# above), but neither staged nor committed:
cyclone% git diff
diff --git a/hello b/hello
index af5626b..b076fc1 100644
--- a/hello
+++ b/hello
@@ -1 +1,2 @@
Hello, world!
+How are you?
# In fact, nothing is staged at all:
cyclone% git diff --cached
cyclone%
Entonces sí, hay exactamente un comando (git restore --source=tip .
) entre el estado actual de OP y el estado deseado de OP, suponiendo una versión lo suficientemente reciente de Git.
git checkout master@{1} -- .
es todo lo que necesitas. Dice “revisar los archivos a los que apuntaba el maestro hace una vez”. Verificar git reflog
para ver cómo funciona esto.
Además, no debe volver a hacer la rama a la fuerza como lo hizo. Esto permitirá que git rastree todos los lugares a los que solía apuntar el maestro. Usar
git stash -u
en caso de que tenga algún trabajo en el directorio de trabajo. Después
git reset --hard master^^^^
o
git reset --hard master~4
-
“Esto permitirá que git rastree todos los lugares a los que solía apuntar el maestro”. – ¿A qué te refieres? ¿Podrías explicar un poco más este seguimiento?
– Andrés Tomazos
10 de enero de 2013 a las 0:13
-
Dijo que quería aplicar los cambios sin etapas. Checkout los organizará.
– jthill
10 de enero de 2013 a las 1:39
Khalah Jones – Dorado
git cherry-pick master~4 master~5 master~6 master~7 master~8
Sin embargo, su árbol de trabajo tiene que estar limpio.
git help cherry-pick
-
“Esto permitirá que git rastree todos los lugares a los que solía apuntar el maestro”. – ¿A qué te refieres? ¿Podrías explicar un poco más este seguimiento?
– Andrés Tomazos
10 de enero de 2013 a las 0:13
-
Dijo que quería aplicar los cambios sin etapas. Checkout los organizará.
– jthill
10 de enero de 2013 a las 1:39