Suponha que eu tenha o seguinte histórico de consolidação na minha ramificação somente local:
A -- B -- C
Como insiro um novo commit entre Ae B?
Suponha que eu tenha o seguinte histórico de consolidação na minha ramificação somente local:
A -- B -- C
Como insiro um novo commit entre Ae B?
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, mude pickpara edit.a1b2c3d) como se tivesse acabado de ser confirmado .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.
A -- B -- C -- Dvez de desejada A -- D -- B -- C.
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 B pick, inserimos uma nova pick 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ê.
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).
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:
git rebase temp branch
(possivelmente você precisará usar -ppara preservar mesclagens, se houver) - graças a um comentário não existente de ciekawy )
exclua a ramificação temporária:
git branch -d temp
Depois disso, o histórico é o seguinte:
A -- N -- B -- C
É 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.
git push --forceque alterar o repositório remoto.
git rebase temp branch -Xtheirs. Resposta útil para injetar em um script!
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.
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
pick 74096b9 D
pick 8668d21 B
pick 650f1fc C
Agora você terá:
A -- D -- B -- C
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.
break
pick <B's hash> <B's commit message>
pick <C's hash> <C's commit message>
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.
rebaseaqui. 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
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.