Normalmente, envio uma lista de confirmações para revisão. Se eu tiver as seguintes confirmações:
HEAD
Commit3
Commit2
Commit1
... Eu sei que posso modificar o commit da cabeça git commit --amend
. Mas como posso modificar Commit1
, já que não é o HEAD
commit?
git
git-rewrite-history
Sam Liao
fonte
fonte
Respostas:
Você pode usar o git rebase . Por exemplo, se você deseja modificar a confirmação
bbc643cd
, executeObserve o sinal de intercalação
^
no final do comando, porque você realmente precisa voltar ao commit antes do que deseja modificar .No editor padrão, modifique
pick
paraedit
na linha mencionando 'bbc643cd'.Salve o arquivo e saia: o git irá interpretar e executar automaticamente os comandos no arquivo. Você se encontrará na situação anterior em que você acabou de criar o commit
bbc643cd
.Neste ponto,
bbc643cd
é o seu último commit e você pode alterá-lo facilmente : faça as alterações e depois confirme com o comando:Depois disso, digite:
para retornar ao commit HEAD anterior.
AVISO : Observe que isso alterará o SHA-1 desse commit e de todos os filhos - em outras palavras, isso reescreve o histórico a partir desse ponto. Você pode interromper os repositórios fazendo isso se pressionar usando o comando
git push --force
fonte
reword
ação emgit rebase -i
vez deedit
(ela abre automaticamente o editor e continua com as demais etapas de rebase; isso evita o usogit commit --ammend
egit rebase --continue
quando você só precisa alterar a mensagem de confirmação e não o conteúdo )git stash
antesgit rebase
egit stash pop
depois, se houver alterações pendentes.git commit --all --amend --no-edit
aqui. Tudo o que eu tinha que fazer depoisgit rebase -i ...
eragit commit --amend
normalmente entãogit rebase --continue
.Use a fantástica rebase interativa:
Encontre a confirmação que você deseja, altere
pick
parae
(edit
) e salve e feche o arquivo. O Git retrocederá para esse commit, permitindo que você:git commit --amend
para fazer alterações ougit reset @~
para descartar a última confirmação, mas não as alterações nos arquivos (ou seja, levá-lo ao ponto em que você estava quando editou os arquivos, mas ainda não havia confirmado).O último é útil para fazer coisas mais complexas, como dividir em várias confirmações.
Em seguida, execute
git rebase --continue
e o Git repetirá as alterações subsequentes sobre o commit modificado. Você pode ser solicitado a corrigir alguns conflitos de mesclagem.Nota:
@
é uma abreviação paraHEAD
, e~
é o commit antes do commit especificado.Leia mais sobre como reescrever o histórico nos documentos do Git.
Não tenha medo de se recuperar
ProTip ™: Não tenha medo de experimentar comandos "perigosos" que reescrevem o histórico * - O Git não exclui seus commits por 90 dias por padrão; você pode encontrá-los no reflog:
* Cuidado com opções como
--hard
e no--force
entanto - elas podem descartar dados.* Além disso, não reescreva o histórico nos ramos em que você está colaborando.
Em muitos sistemas,
git rebase -i
o Vim será aberto por padrão. O Vim não funciona como a maioria dos editores de texto modernos, então veja como fazer uma nova recuperação usando o Vim . Se você preferir usar um editor diferente, altere-o comgit config --global core.editor your-favorite-text-editor
.fonte
@
como taquigrafiaHEAD
. Obrigado por postar isso.git reset @~
exatamente o que eu queria fazer depois de escolher confirmargit rebase ...
. Você é o meu herói)Interativa rebase com
--autosquash
é algo que eu freqüentemente uso quando preciso Fixup commits anteriores mais profunda na história. Essencialmente, acelera o processo ilustrado pela resposta do ZelluX e é especialmente útil quando você tem mais de um commit que precisa editar.A partir da documentação:
Suponha que você tenha um histórico parecido com este:
e você tiver as alterações que deseja alterar no Commit2, confirme suas alterações usando
Como alternativa, você pode usar o commit-sha em vez da mensagem de confirmação, portanto,
"fixup! e8adec4
ou mesmo apenas um prefixo da mensagem de confirmação.Em seguida, inicie um rebase interativo na confirmação antes
seu editor será aberto com os commits já ordenados corretamente
tudo o que você precisa fazer é salvar e sair
fonte
git commit --fixup=@~
vez degit commit -m "fixup! Commit2"
. Isso é especialmente útil quando as mensagens de confirmação são mais longas e seria difícil digitar tudo.Corre:
$ git rebase --interactive commit_hash^
cada um
^
indica quantas confirmações você deseja editar, se for apenas uma (o hash de confirmação que você especificou), basta adicionar uma^
.Usando Vim você mudar as palavras
pick
parareword
os commits que pretende alterar, salvar e sair (:wq
). Em seguida, o git solicitará cada confirmação que você marcou como reformulação, para que você possa alterar a mensagem de confirmação.Cada mensagem de confirmação que você precisa salvar e sair (
:wq
) para ir para a próxima mensagem de confirmaçãoSe você quiser sair sem aplicar as alterações, pressione
:q!
EDIT : para navegar
vim
vocêj
costuma subir,k
descer,h
ir para a esquerda el
ir para a direita (tudo isso noNORMAL
modo, pressioneESC
para ir para oNORMAL
modo). Para editar um texto, pressionei
para entrar noINSERT
modo em que você insere o texto. PressioneESC
para voltar aoNORMAL
modo :)UPDATE : Aqui está um ótimo link da lista do github Como desfazer (quase) qualquer coisa com o git
fonte
git push --force
?git push --force
faz é substituir os controles remotos confirmados pelos confirmados locais. Isso não é o caso deste tópico :)Se, por algum motivo, você não gostar de editores interativos, poderá usá-lo
git rebase --onto
.Digamos que você queira modificar
Commit1
. Primeiro, ramifique antesCommit1
:Segundo, pegue
Commit1
comcherry-pick
:Agora, corrija suas alterações, criando
Commit1'
:E finalmente, depois de ocultar outras alterações, transplante o restante de seus commits até
master
o novo commit:Leia: "rebase, na ramificação
amending
, tudo confirma entreCommit1
(não inclusivo) emaster
(inclusivo)". Ou seja, Commit2 e Commit3, cortando completamente o antigo Commit1. Você pode simplesmente selecioná-los, mas dessa maneira é mais fácil.Lembre-se de limpar seus galhos!
fonte
git checkout -b amending Commit1~1
para obter a prévia comprometergit checkout -b amending Commit1
?Baseado na documentação
Alterando a mensagem de mensagens de confirmação mais antigas ou múltiplas
O exemplo acima exibe uma lista dos últimos 3 confirmados no ramo atual, altere 3 para outro se desejar mais. A lista será semelhante à seguinte:
Substitua pick por reformular antes de cada mensagem de confirmação que você deseja alterar. Digamos que você altere o segundo commit na lista, seu arquivo terá a seguinte aparência:
Salve e feche o arquivo da lista de confirmação, isso exibirá um novo editor para você alterar sua mensagem de confirmação, alterar a mensagem de confirmação e salvar.
Por fim, pressione com força os commits alterados.
fonte
Comando completamente não interativo (1)
Eu apenas pensei em compartilhar um alias que estou usando para isso. É baseado em rebase interativa não interativa. Para adicioná-lo ao seu git, execute este comando (explicação abaixo):
A maior vantagem desse comando é o fato de não ser vim .
(1) dado que não há conflitos durante o rebase, é claro
Uso
O nome
amend-to
parece IMHO apropriado. Compare o fluxo com--amend
:Explicação
git config --global alias.<NAME> '!<COMMAND>'
- cria um alias global do git chamado<NAME>
que executará o comando não-git<COMMAND>
f() { <BODY> }; f
- uma função bash "anônima".SHA=`git rev-parse "$1"`;
- converte o argumento em revisão git e atribui o resultado à variávelSHA
git commit --fixup "$SHA"
- correção-confirmação paraSHA
. Vejagit-commit
documentosGIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
git rebase --interactive "$SHA^"
parte foi coberta por outras respostas.--autosquash
é o que é usado em conjunto comgit commit --fixup
, consulte osgit-rebase
documentos para obter mais informaçõesGIT_SEQUENCE_EDITOR=true
é o que torna a coisa toda não interativa. Este truque eu aprendi com este post do blog .fonte
amend-to
arquivos unstaged punho:git config --global alias.amend-to '!f() { SHA=
git rev-parse "$ 1"; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'
Edição de rebase interativa automatizada seguida de confirmação de confirmação pronta para uma reforma
Eu encontrei-me corrigindo um commit passado com frequência suficiente para escrever um script para ele.
Aqui está o fluxo de trabalho:
Isso o deixará no commit que você deseja editar.
Corrija e prepare o commit como deseja, em primeiro lugar.
(Você pode usar
git stash save
para manter os arquivos que não está enviando)Refaça o commit com
--amend
, por exemplo:Conclua a rebase:
Para que o procedimento acima funcione, coloque o script abaixo em um arquivo executável chamado
git-commit-edit
em algum lugar do seu$PATH
:fonte
Chegou a essa abordagem (e provavelmente é exatamente o mesmo que usar o rebase interativo), mas para mim é meio simples.
Nota: Apresento essa abordagem para ilustrar o que você pode fazer, em vez de uma alternativa cotidiana. Uma vez que tem muitos passos (e possivelmente algumas advertências).
Digamos que você queira alterar o commit
0
e que você está atualmentefeature-branch
Faça o checkout para este commit e crie um
quick-branch
. Você também pode clonar sua ramificação de recursos como um ponto de recuperação (antes de iniciar).Agora você terá algo parecido com isto:
Mudanças de palco, escondem tudo o mais.
Confirme as alterações e faça o checkout de volta para
feature-branch
Agora você terá algo parecido com isto:
Rebase
feature-branch
paraquick-branch
(resolva quaisquer conflitos ao longo do caminho). Aplique o esconderijo e removaquick-branch
.E você acaba com:
O Git não duplicará (embora eu não possa realmente dizer até que ponto) o 0 se compromete ao rebasear.
Nota: todos os hashes de confirmação são alterados a partir do commit que originalmente pretendemos alterar.
fonte
Para obter um comando não interativo, coloque um script com este conteúdo no seu PATH:
Use-o organizando suas alterações (com
git add
) e depois executegit fixup <commit-to-modify>
. Obviamente, ainda será interativo se houver conflitos.fonte
git stash
+rebase
automaçãoPois quando eu preciso modificar um commit antigo muitas vezes para as análises da Gerrit, eu venho fazendo:
GitHub upstream .
Uso:
git add
se já estiver no repositóriogit-amend-old $old_sha
Gosto disso
--autosquash
porque não esmaga outros consertos não relacionados.fonte
git amend
para aplicar alterações em um commit específico com o uso do stash atual, muito inteligente!Eu resolvi isso
1) criando um novo commit com as mudanças que eu quero ..
2) eu sei qual commit eu preciso mesclar com ele. que é confirmar 3.
então, o
git rebase -i HEAD~4
nº 4 representa o commit recente 4 (aqui o commit 3 está em quarto lugar)3) no rebase interativo, o commit recente estará localizado na parte inferior. será parecido,
4) aqui precisamos reorganizar o commit, se você deseja mesclar com um específico. deveria ser assim,
após reorganizar, você precisa substituir
p
pick
porf
(a correção será mesclada sem a mensagem de confirmação) ous
(a mesclagem de squash com a mensagem de confirmação pode mudar no tempo de execução)e salve sua árvore.
agora mesclar feito com confirmação existente.
fonte
A melhor opção é usar o "comando rebase interativo" .
Agora como usar este comando?
-i
significa "interativo" . Observe que você pode executar uma nova refazer no modo não interativo. ex:HEAD
indica sua localização atual (também pode ser o nome da filial ou confirmar o SHA). Os~n
meios "n beforeé, assimHEAD~n
será a lista de" n "confirmados antes do que você está atualmente.git rebase
tem comando diferente como:p
oupick
manter o comprometimento como está.r
oureword
: para manter o conteúdo do commit, mas altere a mensagem do commit.s
ousquash
: para combinar as alterações desse commit no commit anterior (o commit acima dele na lista).... etc.
Nota: É melhor fazer o Git trabalhar com seu editor de código para simplificar as coisas. Por exemplo, se você usar código visual, poderá adicionar assim
git config --global core.editor "code --wait"
. Ou você pode pesquisar no Google como associar você preferiu seu editor de código ao GIT.Exemplo de
git rebase
Queria alterar os 2 últimos commits que fiz, então processo assim:
Agora eu uso
git rebase
para alterar as 2 últimas mensagens confirmadas:$git rebase -i HEAD~2
Abre o editor de código e mostra o seguinte:Desde que eu quero mudar a mensagem de confirmação para este 2 confirma. Então, eu vou digitar
r
oureword
no lugar depick
. Salve o arquivo e feche a guia. Observe querebase
é executado em um processo de várias etapas, portanto, o próximo passo é atualizar as mensagens. Observe também que as confirmações são exibidas em ordem cronológica reversa, de modo que a última confirmação seja exibida nessa e na primeira confirmação na primeira linha e assim por diante.Atualize as mensagens: Atualize a primeira mensagem:
salvar e fechar Editar a segunda mensagem
salvar e fechar.
Você receberá uma mensagem como essa no final do rebase: o
Successfully rebased and updated refs/heads/documentation
que significa que você terá sucesso. Você pode exibir as alterações:Eu desejo que possa ajudar os novos usuários :).
fonte
Para mim, foi para remover algumas credenciais de um repositório. Tentei refazer o processo e encontrei uma tonelada de conflitos aparentemente não relacionados ao tentar refazer o processo - continuar. Não se preocupe em tentar se recuperar, use a ferramenta chamada BFG (brew install bfg) no mac.
fonte
Se você ainda não enviou as confirmações, pode voltar para uma confirmação anterior usando
git reset HEAD^[1,2,3,4...]
Por exemplo
Ops, esqueci de adicionar o arquivo2 ao primeiro commit ...
Isso adicionará o arquivo2 ao primeiro commit.
fonte
Bem, essa solução pode parecer muito boba, mas pode salvá-lo em determinadas condições.
Um amigo meu acabou acidentalmente cometendo muitos arquivos enormes (quatro arquivos gerados automaticamente, variando entre 3 GB a 5 GB cada) e depois fez alguns códigos adicionais, além disso, antes de perceber o problema que
git push
não estava mais funcionando!Os arquivos foram listados,
.gitignore
mas após renomear a pasta do contêiner, eles foram expostos e confirmados! E agora havia mais algumas confirmações do código, maspush
estavam em execução para sempre (tentando fazer upload de GB de dados!) E finalmente falhariam devido aos limites de tamanho de arquivo do Github .O problema com o rebase interativo ou algo semelhante era que eles lidavam com esses arquivos enormes e levavam uma eternidade para fazer qualquer coisa. No entanto, depois de passar quase uma hora na CLI, não tínhamos certeza se os arquivos (e deltas) foram realmente removidos do histórico ou simplesmente não foram incluídos nos commits atuais. O empurrão também não estava funcionando e meu amigo estava realmente preso.
Então, a solução que surgiu foi:
~/Project-old
.~/Project
).cp -r
os arquivos da~/Project-old
pasta para~/Project
.mv
editados e incluídos.gitignore
corretamente..git
pasta clonada recentemente~/Project
pela antiga. É aí que vivem os registros da história problemática!push
editado.O maior problema dessa solução é que ela lida com a cópia manual de alguns arquivos e também mescla todas as confirmações recentes em uma (obviamente com um novo hash de confirmação).
Os grandes benefícios são que, é muito claro em todas as etapas, funciona muito bem para arquivos grandes (além de sensíveis) e não deixa nenhum vestígio na história!
fonte