2009-03-02 7 views
123

Supongamos que tengo 5 confirmaciones locales. Quiero enviar solo 2 de ellos a un repositorio centralizado (usando un flujo de trabajo al estilo de SVN). ¿Cómo hago esto?¿cómo presionas solo algunas de tus confirmaciones locales de git?

Esto no funcionó:

git checkout HEAD~3 #set head to three commits ago 
git push #attempt push from that head 

que termina empujando los 5 commits locales.

Supongo que podría hacer un reinicio de git para deshacer mis commits, seguido de git stash y luego git push, pero ya tengo mensajes de confirmación escritos y archivos organizados y no quiero volver a hacerlos.

Mi impresión es que algún indicador pasado a presionar o reiniciar funcionaría.

Si ayuda, aquí está mi git config

[ramanujan:~/myrepo/.git]$cat config 
[core] 
     repositoryformatversion = 0 
     filemode = true 
     bare = false 
     logallrefupdates = true 
[remote "origin"] 
     url = ssh://server/git/myrepo.git 
     fetch = +refs/heads/*:refs/remotes/origin/* 
[branch "master"] 
     remote = origin 
     merge = refs/heads/master 

Respuesta

153

Asumiendo que su cometa, está en la rama principal y que quieren empujarlos a la remota rama principal:

$ git push origin master~3:master 

Si estaba utilizando git-svn:

$ git svn dcommit master~3 

En el caso de git-svn, también puedes usar HEAD ~ 3, ya que está esperando una confirmación. En el caso de git directo, debe usar el nombre de la rama porque HEAD no se evalúa correctamente en el refspec.

También puede tomar un enfoque más larga de:

$ git checkout -b tocommit HEAD~3 
$ git push origin tocommit:master 

Si usted está haciendo un hábito de este tipo de flujo de trabajo, usted debe considerar hacer su trabajo en una rama separada. Posteriormente, se podría hacer algo como:

$ git checkout master 
$ git merge working~3 
$ git push origin master:master 

Tenga en cuenta que el "origen maestro: maestro" es probablemente parte opcional para su instalación.

+10

Nota: no tiene que usar 'master ~ 3'. Cualquier referencia al compromiso "hasta" deseado es igualmente válida, como 'HEAD ~ 3' o 'HEAD ~~~ ', o el SHA específico, o una etiqueta que etiquete que commit. – Kaz

+1

cosas buenas. Una advertencia sin embargo: estos ejemplos empujan al maestro de origen. Si está copiando y pegando esta solución, puede terminar accidentalmente actualizando la rama principal. (Por supuesto, siempre debe tener cuidado y verificar dos veces su comando antes de emitir un 'git push' ...) – nofinator

+0

Parece que esto empuja la confirmación, pero no agrega la rama de forma remota. – Nateowami

15

Lo que sí es un trabajo en una rama local llamado "trabajo". Esta rama contiene todas las confirmaciones temporales (como soluciones provisionales o de compilación privada o lo que sea) que no pretendo enviar al repositorio de subida. Trabajo lejos en esa rama, luego, cuando quiero comprometerme, cambio a la rama principal, selecciono con precisión los commits apropiados que do quiero confirmar, luego presiono master.

Después de tirar de los cambios de la corriente ascendente en mi rama principal, I git checkout work y git rebase master. Eso reescribe todos mis cambios locales para estar al final de la historia.

Estoy usando git svn con este flujo de trabajo, por lo que mi operación "push" implica git svn dcommit. También uso tig, que es un buen visualizador de repositorios gui en modo de texto, para seleccionar los commits apropiados para dominar.

+0

con git svn dcommit, puede especificar un compromiso para comprometerse hasta, por lo que el efecto deseado es bastante trivial con git-svn. –

+0

Existen desventajas en este enfoque (resumidas aquí http://stackoverflow.com/a/881014/1116674). Una buena alternativa es crear sucursales para cada función en la que esté trabajando y una rama 'work'. Luego, fusionas ramas específicas en 'master' para que no pierdas el historial en ellas. Cuando trabajas con 'work', fusionas todas tus ramas en él. Es más sobrecarga, pero podría valer la pena en algunos casos. – Hudon

11

De forma predeterminada, git-push empuja todas las ramas. Al hacer esto:

git checkout HEAD~3 #set head to three commits ago 
git push #attempt push from that head 

se mueve a una cabeza separada (que no estás en cualquier rama) y luego se presiona todas las ramas, entre ellos el maestro local (que todavía está donde estaba) para el control remoto dominar.

La solución manual es: (y peligroso)

git push origin HEAD:master 

Si encuentra que el comportamiento por defecto de empujar todas las ramas y confusas, añadir esto a su ~/.gitconfig:

[remote.origin] 
    push = HEAD 

Entonces solo la rama en la que estás está presionada. En su ejemplo (una cabeza individual), habría obtenido este mensaje de error, en lugar de presionar accidentalmente las confirmaciones erróneas:

error: unable to push to unqualified destination: HEAD 
4

1) Use "git rebase" para reordenar sus confirmaciones, si así lo desea.

git rebase -i 

Este comando mostrará algo como esto en su editor (estoy usando vim)

pick 4791291 commitA 
pick a2bdfbd commitB 
pick c3d4961 commitC 
pick aa1cefc commitD 
pick 9781434 commitE 

# Rebase .............. 
# 
# Commands: 
# p, pick = use commit 
# r, reword = use commit, but edit the commit message 
# e, edit = use commit, but stop for amending 
# s, squash = use commit, but meld into previous commit 
# f, fixup = like "squash", but discard this commit's log message 
# x, exec = run command (the rest of the line) using shell 
# 
# These lines can be re-ordered; they are executed from top to bottom. 
# 
# If you remove a line here THAT COMMIT WILL BE LOST. 
# 
# However, if you remove everything, the rebase will be aborted. 
# 
# Note that empty commits are commented out 




^G Get Help   ^O WriteOut   ^R Read File  ^Y Prev Page    ^K Cut Text   ^C Cur Pos 
^X Exit    ^J Justify   ^W Where Is   ^V Next Page   ^U UnCut Text  ^T To Spell 

2) Reordenar sus sus confirmaciones de acuerdo a su elección mediante una simple pasta de corte. Supongamos que el nuevo orden es

recoger 9.781.434 Commite

selección c3d4961 commitC

recoger 4.791.291 commitA

selección aa1cefc commitD

selección a2bdfbd commitB

hacer estos cambios en el editor y presione ctrl + O (writeOut)

O también se puede utilizar

git rebase -i HEAD~<commitNumber> 

se puede comprobar la nueva secuencia con

git log 

3) Ahora usa

git push <remoteName> <commit SHA>:<remoteBranchName> 

Si sólo hay una sucursal en remoto (origen) y uno en local (maestro), simplemente use

git push <commit SHA> 
git push aa1cefc 

Esto presionará commitB y commitD.

3

Respuesta corta:

git push <latest commit SHA1 until you want commits to be pushed>

Ejemplos:

git push fc47b2

git push HEAD~2

Respuesta larga:

Commits están unidos entre sí como una cadena con un mecanismo padre/hijo.Por lo tanto, presionando un commit en realidad también empuja todos los padres commits a este compromiso que cuando no se conoce por el control remoto. Esto se realiza implícitamente cuando git push la confirmación actual: todas las confirmaciones anteriores también se presionan porque este comando es equivalente a git push HEAD.

Así que la pregunta podría ser reescrita en cómo empujar cometer un determinado y cometen este específica podría ser CABEZA ~ 2, por ejemplo.

Si las confirmaciones que desea empujar son no consecutivas, sólo tiene que volver a pedir con un git rebase -iantes de la inserción específicas.

Cuestiones relacionadas