Posso apagar um compromisso de git mas manter as alterações

Em um dos meus ramos de desenvolvimento, fiz algumas mudanças na minha base de código. Antes de poder completar as funcionalidades em que estava a trabalhar, tive de mudar o meu ramo actual para o master para fazer uma demonstração de algumas funcionalidades. Mas usando apenas um "git checkout master" preservei as alterações que também fiz no meu ramo de desenvolvimento, quebrando assim algumas das funcionalidades do master. Então o que eu fiz foi submeter as alterações no meu ramo de desenvolvimento com uma mensagem de commit " commit&quot temporário; e depois checkout master para o demo.

Agora que eu'estou pronto com a demonstração e de volta ao trabalho no meu ramo de desenvolvimento, gostaria de remover o "commit&quot temporário; que eu fiz enquanto ainda preservava as mudanças que eu fiz. Isso é possível?

Solução

It's tão simples como isto:

git reset HEAD^

O git reset sem --hard ou --soft move seu HEAD para apontar para o commit especificado, sem alterar nenhum arquivo. O HEAD^ refere-se ao (primeiro) commit pai do seu commit atual, que no seu caso é o commit antes do commit temporário.

Note que outra opção é continuar como normalmente, e depois no próximo ponto de compromisso, em vez disso, executar:

git commit --amend [-m … etc]

que, em vez disso, editará o compromisso mais recente, tendo o mesmo efeito que acima.

Note que isto (como em quase todas as respostas idiota) pode causar problemas se você'já empurrou o mau compromisso para um lugar de onde outra pessoa pode tê-lo tirado. Tente evitar que

Comentários (19)

Há duas maneiras de lidar com isto. O que é mais fácil depende da sua situação

**Reset***

Se o compromisso do qual você quer se livrar foi o último compromisso, e você não fez nenhum trabalho adicional você pode simplesmente usar o git-reset.

git reset HEAD^

Leva a sua filial de volta ao compromisso pouco antes da sua actual CABEÇA. Entretanto, ele não'na verdade não muda os arquivos na sua árvore de trabalho. Como resultado, as alterações que estavam naquele commit aparecem como modificadas - é como um comando 'uncommit'uncommit'. Na verdade, eu tenho um alias para fazer exatamente isso.

git config --global alias.uncommit 'reset HEAD^'

Então você pode apenas utilizar o "git uncommit" no futuro para apoiar um compromisso.

**Squashing***

Esmagar um commit significa combinar dois ou mais commits em um. Eu faço isto com bastante frequência. No seu caso, você tem uma característica comprometida pela metade, e então você a terminaria e se comprometeria novamente com a mensagem de compromisso permanente apropriada.

git rebase -i 

Eu digo acima porque eu quero deixar claro que isto pode ser qualquer número de compromissos de volta. Execute git log e encontre o commit que você quer se livrar, copie seu SHA1 e use-o no lugar de . Git irá levá-lo para o modo rebase interativo. Ele mostrará todos os commits entre o seu estado atual e o que você colocar no lugar de. Então se `` for 10 commits atrás, ele mostrará todas as 10 commits.

Na frente de cada compromisso, terá a palavra "escolher". Encontre o commit que você quer se livrar e mude-o de "pegar" para "consertar" ou "esmagar". Utilizando fixup simplesmente descarta a mensagem de commit e funde as alterações no seu predecessor imediato na lista. A palavra-chave squash faz a mesma coisa, mas permite que você edite a mensagem de commit da nova submissão combinada.

Note que os commits serão novamente comprometidos na ordem em que aparecem na lista quando você sair do editor. Então se você fez um commit temporário, então fez outro trabalho no mesmo ramo, e completou o recurso em um commit posterior, então usar o rebase permitiria que você reordenasse os commits e os esmagasse.

AVISO:

Rebase modifica a história - NÃO faça isso para qualquer compromisso que você já tenha compartilhado com outros desenvolvedores.

**Abrilho***

No futuro, para evitar este problema, considere a utilização do git stash para armazenar temporariamente trabalhos não comprometidos.

git stash save 'some message'

Isto irá armazenar as suas alterações actuais no lado da sua lista de compras. Acima está a versão mais explícita do comando stash, permitindo um comentário para descrever o que você está armazenando. Você também pode simplesmente executar git stash e nada mais, mas nenhuma mensagem será armazenada.

Podes procurar na tua lista de esconderijo com...

git stash list

Isto irá mostrar-lhe todos os seus stashes, em que ramos foram feitos, e a mensagem e no início de cada linha, e identificador para aquele stash que se parece com este stash@{#} onde # é a sua posição na matriz de stashes.

Para restaurar um esconderijo (o que pode ser feito em qualquer ramo, independentemente de onde o esconderijo foi originalmente criado) você simplesmente corre...

git stash apply stash@{#}

Mais uma vez, há # a posição no conjunto de esconderijos. Se o stash que você quer restaurar está na posição 0 - ou seja, se foi o stash mais recente. Então você pode simplesmente executar o comando sem especificar a posição do stash, git irá assumir que você quer dizer a última: git stash apply.

Então, por exemplo, se eu me encontrar trabalhando no ramo errado - eu posso executar a seguinte seqüência de comandos.

git stash
git checkout 
git stash apply

No seu caso você se moveu um pouco mais pelos galhos, mas a mesma idéia ainda se aplica.

Espero que isto ajude.

Comentários (2)

Mais uma maneira de o fazer.

Adicione commit no topo do commit temporário e depois faça:

git rebase -i

Para fundir dois commits em um (o comando abrirá um arquivo de texto com instruções explícitas, edite-o).

Comentários (1)