Rebase um único commit do Git

116

Existe uma maneira de rebase um único commit de um branch para outro branch?

Eu tenho esta estrutura de ramificação:

-- -- -- -- -- (Master)
            \
              -- -- -- -- -- XX (Feature-branch)

Tudo que eu quero fazer é realocar o último commit de Feature-branchno master e reverter Feature-branchum commit.

-- -- -- -- -- XX (Master)
            \
              -- -- -- -- -- (Feature-branch)

Como faço isso?

Kevin Meyer
fonte
3
Se você pode rebase qualquer número de commits, então por que você pergunta sobre rebase de um único? Se eu pudesse fazer perguntas no SO, eu perguntaria qual é a diferença entre rebase (um único commit) e seleção seletiva.
Val
9
Porque eu não sabia que a seleção seletiva existia, e eu faço "Faff about on branch", "Get request for fix on different branch", "conserte", "Comprometa-se com o branch errado", "D'OH!" o suficiente para que fazer a pergunta fosse útil.
Kevin Meyer de

Respostas:

116

Você pode escolher XX para dominar.

git checkout master
git cherry-pick <commit ID of XX>

E remova o último commit do branch de recursos com git reset.

git checkout Feature-branch
git reset --hard HEAD^
tewe
fonte
63
como pode uma pergunta especificamente chamada 'git rebase ...' ter a resposta aceita que contém uma escolha seletiva, que é um conceito totalmente diferente e às vezes considerado impuro?
Bondax
1
Não tenho certeza se isso é relevante, mas o commit que eu queria rebase tinha alguns arquivos que foram movidos e os cherry-pickfez parecer como se tivessem sido excluídos do local antigo e criados no novo local. Suponho que o rebase teria resolvido isso, mas agora eu já fiz push upstream, então não posso testar isso. Em qualquer caso, tome cuidado se você tiver uma situação semelhante.
waldyrious
Nota: para empurrar as alterações para Feature-brancha origem, você precisará, git push -f origin Feature-branchpois Feature-branchagora é considerado 1 commit atrás do origin/Feature-branch.
jojo
1
Qual é a diferença prática entre esta solução e a de CharlesB ?
Lii
96
git rebase --onto master branch~1 branch 

Isso diz "realocar o intervalo de commits entre o último antes do branch e o branch (ou seja, o commit XX) na ponta do branch master"

Após esta operação, a branchdica é movida para o commit XX, então você deseja defini-la de volta com

git checkout branch
git reset --hard branch@{1}^

Que diz "redefina a ponta do branch para o commit antes de seu estado anterior"

Portanto, uma escolha certa é uma solução mais simples ...

CharlesB
fonte
5
Isso não parece funcionar para mim, eu perco os commits antes de XX e o branch é rebaseizado para master com um único commit, mas eu nunca usei --ontoantes, então posso estar fazendo algo errado. BTW, o OP disse rebase, mas parece que ele quer fazer uma escolha certa.
3 de
1
meu erro, o rebase realmente move o branch no master, ele precisa ser redefinido
CharlesB
1
Qual é a diferença prática entre esta solução e a da tewe ?
Lii
1
@Lii, a única coisa que posso ver é que ele usa 3 etapas em vez de 4
CharlesB
51

Na verdade, é muito simples de fazer. A solução é fazer um rebase interativo e "descartar" todos os commits que você não deseja incluir no rebase.

git rebase -i <target_branch>onde target_branchestá o branch para o qual você deseja realocar

Então você irá editar o arquivo que é aberto e pickos commits que você quer e drop(ou dpara encurtar) todos os commits que você não quer trazer.

hrdwdmrbl
fonte
6
IMO uma solução muito melhor, e realmente aborda a questão.
GabrielOshiro
Essa deve ser a solução aceita, dado o quão geral, intuitiva e curta ela é.
Pablo Arias
1

A resposta de @Charles está correta. De qualquer forma, acabei usando isso tantas vezes, principalmente para realocar configurações específicas em um projeto

  * a8f9182 (HEAD -> produção) configuração de produção
  | * configuração de pré-produção daa18b7 (pré)
  | /  
  | * configuração local d365f5f (local)
  | /  
  * 27d2835 (dev) novo recurso incrível que salvará o mundo
* | 56d2467 (master) chato estado da arte para projeto
| /

que eu crio um novo comando para ele:

$ cat ~ / bin / git-rebaseshot 
COMMIT = $ 1
DEST = $ {2: -HEAD}
git rebase $ {COMMIT} ^ $ {COMMIT} --onto $ DEST

normalmente você deseja preencher automaticamente os nomes dos ramos para esse comando, então adicione-o fornecendo esta função (adicionando a .bashrc ou .profile):

_git_rebaseshot () 
{ 
    __gitcomp_nl "$ (__ git_refs)"
}

git autocomplete irá procurar por ele

você pode usar este comando assim:

# rebase config on prepro on actual HEAD
$ git rebaseshot prepro 
# rebase config on local onto dev
$ git rebaseshot local dev
# rebase production config on master
$ git rebaseshot pro master

Quando você divide os recursos corretamente, as possibilidades são infinitas.

* a8f9182 (HEAD -> postgres) Configuração de BBDD
* a8f9182 (local) configuração local
* a8f9182 (depuração) configuração de nível de registro
* Novo recurso a8f9182 (dev)
|

Eu acho que isso é o que quilt pessoas gostam de fazer.

este comando funcionará de qualquer maneira com qualquer sha / ref que você fornecer:

$ git rebaseshot <Feature branch> master
$ git rebaseshot <commit of XX> master
Albfan
fonte
//, você pode criar um link para algum projeto onde possamos ver isso em ação?
Nathan Basanese
Por sua natureza, branches disponíveis para rebaseshot não são comprometidos fora do repo local. Basta criar várias ramificações em cima do mestre (nível de log, conexão de banco de dados, configuração) e usar o comando entre elas. É fácil ver o efeito.
albfan
//, tive alguns problemas. Vou tentar de novo.
Nathan Basanese,
0

Aqui está outra opção:

  1. Certifique-se de ter um controle remoto com uma cópia do ramo de recursos
  2. Exclua o branch de recurso local
  3. Crie e faça checkout de um novo branch com o mesmo nome do branch de recurso antigo que você acabou de excluir do master
  4. escolha o commit da cópia remota do branch de recursos que você deseja.

Os comandos se parecem com:

git checkout Feature-branch
git push -u origin HEAD
git checkout master
git branch -D Feature-branch
git checkout -b Feature-branch
git cherry-pick HASH-OF-XX

Não é um comando de rebase, mas é um rebase em espírito.

cdmo
fonte