git rebase -i <any earlier commit>. Isso exibe uma lista de confirmações no seu editor de texto configurado.
Encontre o commit que você deseja inserir depois (suponha que seja a1b2c3d). No seu editor, para essa linha, mude pickpara edit.
Comece a rebase fechando seu editor de texto (salve as alterações). Isso deixa você em um prompt de comando com o commit que você escolheu anteriormente ( a1b2c3d) como se tivesse acabado de ser confirmado .
Faça as alterações e git commit( NÃO alterando, ao contrário da maioria das edits). Isso cria um novo commit após o que você escolheu.
git rebase --continue. Isso repete as confirmações sucessivas, deixando sua nova confirmação inserida no local correto.
Cuidado para reescrever a história e quebrar qualquer outra pessoa que tentar puxar.
Isso adicionou o novo commit após o commit, que é após o que eu estava refazendo (também o último commit), em vez de logo após o que estava refazendo. O resultado foi o mesmo que se eu tivesse simplesmente feito um novo commit no final com as alterações que queria inserir. Minha história tornou-se em A -- B -- C -- Dvez de desejada A -- D -- B -- C.
XedinUnknown
2
@XedinUnknown: então você não usou o Rebase corretamente.
SLaks
3
Agora Dpode ser um commit em qualquer lugar. Suponha que tenhamos A - B - Ce tenhamos algum commit Dque nem esteja nesse ramo. No entanto, sabemos o seu SHA, podemos fazer git rebase -i HEAD~3. Agora, entre as linhas Ae Bpick, inserimos uma novapick linha que diz pick SHAdar o hash do desejado D. Não precisa ser o hash completo, apenas o reduzido. git rebase -iapenas cerejas seleciona quaisquer confirmações listadas por picklinhas no buffer; eles não precisam ser os originais listados para você.
Kaz
1
@Kaz Parece uma resposta diferente e válida.
BartoszKP
3
Ainda mais fácil, você pode usar a breakpalavra - chave no editor em sua própria linha entre duas confirmações (ou na primeira linha, para inserir uma confirmação antes da confirmação especificada).
SimonT
30
Acontece que é bastante simples, a resposta encontrada aqui . Suponha que você esteja em um galho branch. Execute estas etapas:
crie uma ramificação temporária a partir da confirmação após desejar inserir a nova confirmação (neste caso, confirmação A):
git checkout -b temp A
execute as alterações e as confirme, criando uma confirmação, vamos chamá-lo N:
git commit -a -m "Message"
(ou git addseguido por git commit)
rebase os commits que você deseja ter após o novo commit (neste caso confirma Be C) no novo commit:
Não consegui seguir a resposta aceita pelo SLaks, mas funcionou para mim. Depois de obter o histórico de consolidação que eu queria, tive git push --forceque alterar o repositório remoto.
CaractereDeEscape
1
Ao usar o rebase, a opção -Xtheirs resolve automaticamente os conflitos corretamente git rebase temp branch -Xtheirs. Resposta útil para injetar em um script!
David C
Para noobs como eu, gostaria de acrescentar que depois git rebase temp branch, mas antes git branch -d temp, tudo o que você precisa fazer é corrigir e organizar a fusão de conflitos e problemas git rebase --continue, ou seja, não há necessidade de cometer nada, etc.
Pugsley
19
Solução ainda mais fácil:
Crie seu novo commit no final, D. Agora você tem:
A -- B -- C -- D
Então corra:
$ git rebase -i hash-of-A
O Git abrirá seu editor e ficará assim:
pick 8668d21 B
pick 650f1fc C
pick 74096b9 D
Apenas mova D para o topo assim, então salve e saia
Boa idéia, no entanto, pode ser difícil introduzir D em C, quando você pretende que essas alterações sejam incorretas. para A.
BartoszKP 14/10
Eu tenho uma situação em que tenho 3 confirmações que quero refazer juntas e uma confirmação no meio que não é relacionada. É muito bom poder mover esse commit mais cedo ou mais tarde na linha de commit.
unflores
13
Supondo que o histórico de confirmação seja preA -- A -- B -- C, se você deseja inserir uma confirmação entre Ae B, as etapas são as seguintes:
git rebase -i hash-of-preA
O Git abrirá seu editor. O conteúdo pode ser assim:
pick 8668d21 A
pick 650f1fc B
pick 74096b9 C
Mude o primeiro pickpara edit:
edit 8668d21 A
pick 650f1fc B
pick 74096b9 C
Salvar e sair.
Modifique seu código e depois git add . && git commit -m "I"
git rebase --continue
Agora seu histórico de confirmação do Git é preA -- A -- I -- B -- C
Se você encontrar um conflito, o Git irá parar nesse commit. Você pode usar git diffpara localizar marcadores de conflito e resolvê-los. Depois de resolver todos os conflitos, você precisa git add <filename>dizer ao Git que o conflito foi resolvido e depois executado novamente git rebase --continue.
Se você quiser desfazer a rebase, use git rebase --abort.
Aqui está uma estratégia que evita fazer um "corte de edição" durante o rebase visto nas outras respostas que li.
Ao usar, git rebase -ivocê obtém uma lista de confirmações desde essa confirmação. Basta adicionar uma "quebra" na parte superior do arquivo, isso fará com que a rebase se quebre nesse ponto.
Uma vez lançado, git rebaseagora irá parar no ponto do "intervalo". Agora você pode editar seus arquivos e criar seu commit normalmente. Em seguida, você pode continuar a recuperação com git rebase --continue. Isso pode causar conflitos que você precisará corrigir. Se você se perder, não se esqueça de que pode sempre abortar o uso git rebase --abort.
Essa estratégia pode ser generalizada para inserir um commit em qualquer lugar, basta colocar o "break" no local em que você deseja inserir um commit.
Após reescrever o histórico, não esqueça git push -f. Os avisos usuais sobre outras pessoas que buscam sua filial se aplicam.
Desculpe, mas tenho problemas para entender como é isso "evitando rebase". Você é correndo rebaseaqui. Não há muita diferença se você criará o commit durante a rebase ou antes.
precisa saber é o seguinte
Woops, eu quis dizer evitando o "corte de edição" durante o rebase, acho que expressei mal isso.
precisa saber é o seguinte
Certo. Minha resposta também não usa o recurso "editar" do rebase. Ainda assim, essa é outra abordagem válida - obrigado! :-)
BartoszKP
6
Muitas boas respostas aqui já. Eu só queria adicionar uma solução "no rebase", em 4 etapas fáceis.
Resumo
git checkout A
git commit -am "Message for commit D"
git cherry-pick A..C
git branch -f master HEAD
Explicação
(Nota: uma vantagem desta solução é que você não toca na sua ramificação até a etapa final, quando tem 100% de certeza de que está bem com o resultado final, para ter uma etapa muito útil de "pré-confirmação" permitindo testes AB .)
Estado inicial (assumi mastero nome do seu ramo)
A -- B -- C <<< master <<< HEAD
1) Comece apontando HEAD no lugar certo
git checkout A
B -- C <<< master
/
A <<< detached HEAD
(Opcionalmente aqui, em vez de desconectar o HEAD, poderíamos criar um ramo temporário com o git checkout -b temp Aqual precisaríamos excluir no final do processo. Ambas as variantes funcionam, fazem o que você prefere, já que todo o resto permanece o mesmo.
2) Crie o novo commit D a ser inserido
# at this point, make the changes you wanted to insert between A and B, then
git commit -am "Message for commit D"
B -- C <<< master
/
A -- D <<< detached HEAD (or <<< temp <<< HEAD)
3) Em seguida, traga cópias dos últimos commits ausentes B e C (seria a mesma linha se houvesse mais commits)
git cherry-pick A..C
# (if any, resolve any potential conflicts between D and these last commits)
B -- C <<< master
/
A -- D -- B' -- C' <<< detached HEAD (or <<< temp <<< HEAD)
(Teste AB confortável aqui, se necessário)
Agora é o momento de inspecionar seu código, testar qualquer coisa que precise ser testada e você também pode comparar / comparar / inspecionar o que tinha e o que obteria após as operações.
4) Dependendo dos testes entre Ce C', está OK ou está com KO.
(OU) 4-OK) Por fim, mova o ref demaster
git branch -f master HEAD
B -- C <<< (B and C are candidates for garbage collection)
/
A -- D -- B' -- C' <<< master
(OU) 4-KO) Apenas deixe masterinalterado
Se você criou uma ramificação temporária, exclua-a com git branch -d <name> , mas se você optou pela rota HEAD desanexada, nenhuma ação será necessária neste momento, as novas confirmações serão elegíveis para a coleta de lixo logo após você reconectar HEADcom umgit checkout master
Nos dois casos (OK ou KO), neste momento, faça o checkout masternovamente para reconectar HEAD.
Respostas:
É ainda mais fácil do que na resposta do OP.
git rebase -i <any earlier commit>
. Isso exibe uma lista de confirmações no seu editor de texto configurado.a1b2c3d
). No seu editor, para essa linha, mudepick
paraedit
.a1b2c3d
) como se tivesse acabado de ser confirmado .git commit
( NÃO alterando, ao contrário da maioria dasedit
s). Isso cria um novo commit após o que você escolheu.git rebase --continue
. Isso repete as confirmações sucessivas, deixando sua nova confirmação inserida no local correto.Cuidado para reescrever a história e quebrar qualquer outra pessoa que tentar puxar.
fonte
A -- B -- C -- D
vez de desejadaA -- D -- B -- C
.D
pode ser um commit em qualquer lugar. Suponha que tenhamosA - B - C
e tenhamos algum commitD
que nem esteja nesse ramo. No entanto, sabemos o seu SHA, podemos fazergit rebase -i HEAD~3
. Agora, entre as linhasA
eB
pick
, inserimos uma novapick
linha que dizpick SHA
dar o hash do desejadoD
. Não precisa ser o hash completo, apenas o reduzido.git rebase -i
apenas cerejas seleciona quaisquer confirmações listadas porpick
linhas no buffer; eles não precisam ser os originais listados para você.break
palavra - chave no editor em sua própria linha entre duas confirmações (ou na primeira linha, para inserir uma confirmação antes da confirmação especificada).Acontece que é bastante simples, a resposta encontrada aqui . Suponha que você esteja em um galho
branch
. Execute estas etapas:crie uma ramificação temporária a partir da confirmação após desejar inserir a nova confirmação (neste caso, confirmação
A
):execute as alterações e as confirme, criando uma confirmação, vamos chamá-lo
N
:(ou
git add
seguido porgit commit
)rebase os commits que você deseja ter após o novo commit (neste caso confirma
B
eC
) no novo commit:(possivelmente você precisará usar
-p
para preservar mesclagens, se houver) - graças a um comentário não existente de ciekawy )exclua a ramificação temporária:
Depois disso, o histórico é o seguinte:
É claro que é possível que alguns conflitos apareçam durante o rebase.
Caso sua filial não seja local, somente isso introduzirá o histórico de reescritas, portanto, poderá causar problemas sérios.
fonte
git push --force
que alterar o repositório remoto.git rebase temp branch -Xtheirs
. Resposta útil para injetar em um script!git rebase temp branch
, mas antesgit branch -d temp
, tudo o que você precisa fazer é corrigir e organizar a fusão de conflitos e problemasgit rebase --continue
, ou seja, não há necessidade de cometer nada, etc.Solução ainda mais fácil:
Crie seu novo commit no final, D. Agora você tem:
Então corra:
O Git abrirá seu editor e ficará assim:
Apenas mova D para o topo assim, então salve e saia
Agora você terá:
fonte
Supondo que o histórico de confirmação seja
preA -- A -- B -- C
, se você deseja inserir uma confirmação entreA
eB
, as etapas são as seguintes:git rebase -i hash-of-preA
O Git abrirá seu editor. O conteúdo pode ser assim:
Mude o primeiro
pick
paraedit
:Salvar e sair.
Modifique seu código e depois
git add . && git commit -m "I"
git rebase --continue
Agora seu histórico de confirmação do Git é
preA -- A -- I -- B -- C
Se você encontrar um conflito, o Git irá parar nesse commit. Você pode usar
git diff
para localizar marcadores de conflito e resolvê-los. Depois de resolver todos os conflitos, você precisagit add <filename>
dizer ao Git que o conflito foi resolvido e depois executado novamentegit rebase --continue
.Se você quiser desfazer a rebase, use
git rebase --abort
.fonte
Aqui está uma estratégia que evita fazer um "corte de edição" durante o rebase visto nas outras respostas que li.
Ao usar,
git rebase -i
você obtém uma lista de confirmações desde essa confirmação. Basta adicionar uma "quebra" na parte superior do arquivo, isso fará com que a rebase se quebre nesse ponto.Uma vez lançado,
git rebase
agora irá parar no ponto do "intervalo". Agora você pode editar seus arquivos e criar seu commit normalmente. Em seguida, você pode continuar a recuperação comgit rebase --continue
. Isso pode causar conflitos que você precisará corrigir. Se você se perder, não se esqueça de que pode sempre abortar o usogit rebase --abort
.Essa estratégia pode ser generalizada para inserir um commit em qualquer lugar, basta colocar o "break" no local em que você deseja inserir um commit.
Após reescrever o histórico, não esqueça
git push -f
. Os avisos usuais sobre outras pessoas que buscam sua filial se aplicam.fonte
rebase
aqui. Não há muita diferença se você criará o commit durante a rebase ou antes.Muitas boas respostas aqui já. Eu só queria adicionar uma solução "no rebase", em 4 etapas fáceis.
Resumo
Explicação
(Nota: uma vantagem desta solução é que você não toca na sua ramificação até a etapa final, quando tem 100% de certeza de que está bem com o resultado final, para ter uma etapa muito útil de "pré-confirmação" permitindo testes AB .)
Estado inicial (assumi
master
o nome do seu ramo)1) Comece apontando HEAD no lugar certo
(Opcionalmente aqui, em vez de desconectar o HEAD, poderíamos criar um ramo temporário com o
git checkout -b temp A
qual precisaríamos excluir no final do processo. Ambas as variantes funcionam, fazem o que você prefere, já que todo o resto permanece o mesmo.2) Crie o novo commit D a ser inserido
3) Em seguida, traga cópias dos últimos commits ausentes B e C (seria a mesma linha se houvesse mais commits)
(Teste AB confortável aqui, se necessário)
Agora é o momento de inspecionar seu código, testar qualquer coisa que precise ser testada e você também pode comparar / comparar / inspecionar o que tinha e o que obteria após as operações.
4) Dependendo dos testes entre
C
eC'
, está OK ou está com KO.(OU) 4-OK) Por fim, mova o ref de
master
(OU) 4-KO) Apenas deixe
master
inalteradoSe você criou uma ramificação temporária, exclua-a com
git branch -d <name>
, mas se você optou pela rota HEAD desanexada, nenhuma ação será necessária neste momento, as novas confirmações serão elegíveis para a coleta de lixo logo após você reconectarHEAD
com umgit checkout master
Nos dois casos (OK ou KO), neste momento, faça o checkout
master
novamente para reconectarHEAD
.fonte