Como posso descomprimir o último commit em um repositório git bare?

91

Levando em consideração que existem vários comandos git que não fazem sentido em um repositório vazio (porque repositórios simples não usam índices e não têm um diretório de trabalho),

git reset --hard HEAD^ 

não é uma solução para descomprimir a última alteração em tal repositório.

Pesquisando na Internet, tudo que pude encontrar relacionado ao tema é o seguinte , no qual me são apresentadas três maneiras de fazer isso:
1. "atualizar o ref manualmente (que envolve encanamento)";
2. " git push -fde um repositório não vazio";
3. " git branch -f this $that".

Qual solução você acha mais apropriada ou de que outras maneiras existem para fazer isso? Infelizmente, a documentação que encontrei sobre repositórios básicos do git é bastante pobre.

Lavinia-Gabriela Dobrovolschi
fonte
8
@ Lavinia-Garbriela Dobrovol Não use as coisas complicadas abaixo. Você está tentando mover HEAD para um commit diferente e é para isso que o git reset se destina, mesmo em um repositório simples. De acordo com minha resposta abaixo, use: git reset --soft <commit> Com --soft, você não tenta mudar uma árvore de trabalho e índice que não existe, então git permite que você faça o reset sem problemas.
Hazok

Respostas:

130

Você pode usar o git update-refcomando. Para remover o último commit, você usaria:

$ git update-ref HEAD HEAD^

Ou se você não estiver no branch do qual não pode remover o último commit:

$ git update-ref refs/heads/branch-name branch-name^

Você também pode passar um sha1 se quiser:

$ git update-ref refs/heads/branch-name a12d48e2

Veja a documentação do comando git-update-ref .

Sylvain Defresne
fonte
@ Lavinia-Gabriela Dobrovolschi: certo, eu não estava familiarizada com a sintaxe exata.
VonC
@VonC Você pode especificar o <ref> in git update-ref <ref> <newvalue>para ser o branch certo, como "refs / heads / master" ao invés de HEAD, por exemplo. Espero não ter entendido mal sua pergunta.
Lavinia-Gabriela Dobrovolschi
@Sylvain: +1 boa edição. @ Lavinia-Gabriela Dobrovolschi obrigada pelas precisões. Isso é muito mais prático (se você tiver acesso direto ao servidor remoto, presumo).
VonC
3
Os exemplos são enganosos com relação ao branch-nameargumento. Ao usar update-refcom um “branch”, você absolutamente deve especificar o nome de referência completo do branch (ou seja, prefixar refs/heads/ao nome abreviado do branch normal). Se você usar apenas o nome abreviado, acabará criando / atualizando em $GIT_DIR/branch-namevez de $GIT_DIR/refs/heads/branch-name. A existência de ambos branch-namee refs/heads/branch-namecausará avisos “refname… é ambíguo”.
Chris Johnsen
Essa resposta é muito mais complicada do que a proposta de Zach. E sua solução funciona bem.
Krystian
32

Se você usar o seguinte em um repositório básico:

git reset --soft <commit>

então, você não encontrará os problemas que tem ao usar --harde --mixedopções em um repositório básico, pois não está tentando alterar algo que o repositório básico não tem (ou seja, árvore e índice de trabalho). No seu caso, especificamente, você gostaria de usar (do repositório básico):

git reset --soft HEAD^

Para alternar branches no repo remoto, faça:

git symbolic-ref HEAD refs/heads/<branch_name>

Para ver o uso do ramo atualmente selecionado:

git symbolic-ref HEAD

https://mirrors.edge.kernel.org/pub/software/scm/git/docs/git-symbolic-ref.html

Hazok
fonte
3
Como você seleciona o ramo que deseja mover? Seu exemplo funciona bem no master, mas git checkout other_branchnão funciona totalmente.
Gauthier
1
Hmmm ... Estou me perguntando quem votou contra mim nisso. A questão não perguntava como alternar branches em um repositório remoto, mas como reinicializar em um repositório vazio. Para alterar o branch padrão em um repo remoto, use git symbolic-ref HEAD refs / heads / <branch_name>.
Hazok de
7

A git push -fdeve funcionar bem:
se você clonar que repo nua, remova cometer o passado ( git reset --hard HEAD^como você menciona, mas em um repo não-nua local) e empurrar para trás ( -f):

  • você não muda nenhum SHA1 para os outros commits anteriores ao que você removeu.
  • você tem certeza de empurrar de volta o conteúdo exato do repositório vazio sem o commit extra (porque você acabou de cloná-lo primeiro).
VonC
fonte
@ VonC Olá Von, eu vi você responder muito no Git, então queria te perguntar ... Eu estava curioso, por que, git reset --soft <sha1>conforme mostrado na minha resposta abaixo, não seria a prática recomendada para mover o HEAD em um repositório simples?
Hazok
Acho que outro motivo de minha pergunta é que usar o soft reset para repositórios simples não é uma informação disponível e muitos fóruns parecem ter soluções alternativas desnecessariamente complexas quando parece que o soft reset é a melhor prática devido à menor quantidade de digitação e menor chance por erro.
Hazok
2
@Zach: a reset --softdeve funcionar quando feito diretamente em um repositório vazio . Suspeito que isso raramente seja feito porque um repositório simples é geralmente um repo upstream (ou seja, um repo para o qual você está enviando dados) e, na maioria das vezes, você não tem acesso local direto a ele. Mas se você fizer isso, então este é certamente outro bom exemplo de reset --softuso " " (como em stackoverflow.com/questions/5203535/… ) Então, +1 para sua resposta.
VonC
2

Você também pode usar a notação git refspec e fazer algo assim:

git push -f origin +<commit you want to revert to>:<destination_head | branch_name>

Isso força a atualização do branch de destino (como denotado pela ref) para o commit de origem conforme denotado pela +<object ref>parte.

alup
fonte
2
exceto quando há uma acl no branch - que geralmente é o caso se você "precisar fazer isso no próprio repositório" ...
David Schmitt