comando git para fazer um ramo como outro

Eu estou tentando pegar um branch com mudanças e trazê-lo de volta para ser idêntico ao upstream do qual ele divergiu. As mudanças são locais e foram empurradas para o github, então nem o git reset nem o git rebase são realmente viáveis, já que eles mudam o histórico, o que é uma coisa ruim com um branch que já foi empurrado.

Eu também tentei git merge com várias estratégias, mas nenhum deles desfaz as alterações locais, ou seja, se eu tivesse adicionado um arquivo, uma mesclagem poderia trazer outros arquivos de volta na linha, mas eu ainda terei esse arquivo que o upstream não faz não tem.

Eu poderia apenas criar um novo branch fora do upstream, mas eu realmente gostaria de uma mesclagem que, em termos de histórico de revisão, aplica todas as mudanças para pegar minha ramificação e torná-la idêntica ao upstream novamente, para que eu possa empurrar com segurança essa mudança sem história de derrota. Existe tal comando ou série de comandos?

    Você pode mesclar sua ramificação upstream em sua ramificação dev com um driver de mesclagem personalizado “keepTheirs” :
    Veja ” git merge -s theirs ” necessário – mas eu sei que não existe “.
    No seu caso, apenas um .gitattributes seria necessário e um script keepTheirs como:

     mv -f $3 $2 exit 0 

    git merge --strategy=theirs Simulação # 1

    Mostra como uma mesclagem, com upstream como o primeiro pai.

    Jefromi menciona (nos comentários) que a merge -s ours , mesclando seu trabalho no upstream (ou em um branch temporário a partir do upstream) e, em seguida, avançando rapidamente sua ramificação para o resultado dessa mesclagem:

     git checkout -b tmp origin/upstream git merge -s ours downstream # ignoring all changes from downstream git checkout downstream git merge tmp # fast-forward to tmp HEAD git branch -D tmp # deleting tmp 

    Isso tem o benefício de registrar o ancestral upstream como o primeiro pai, de modo que a mesclagem signifique “absorver esse ramo de tópico desatualizado” em vez de “destruir esse ramo de tópico e substituí-lo por upstream” .

    (Editar 2011):

    Este stream de trabalho foi relatado nesta postagem do blog pelo OP :

    Por que eu quero isso de novo?

    Desde que o meu repository não tenha nada a ver com a versão pública, tudo bem, mas como agora gostaria de ter a capacidade de colaborar no WIP com outros membros da equipe e colaboradores externos, quero garantir que minhas filiais públicas sejam confiável para que outras pessoas possam se ramificar e extrair, ou seja, sem mais rebascar e redefinir as coisas que eu enviei para o backup remoto, já que agora está no GitHub e no público.

    Então isso me deixa como devo proceder.
    99% das vezes a minha cópia vai para o master upstream, então eu quero trabalhar com o meu master e empurrar para o upstream a maior parte do tempo.
    Mas de vez em quando, o que eu tenho em wip será invalidado pelo que entra no upstream e eu vou abandonar parte do meu wip .
    Nesse ponto, quero trazer meu mestre de volta em sincronia com o autor, mas não destruir nenhum ponto de commit do meu mestre publicamente enviado. Ou seja, eu quero uma mesclagem com o upstream que acaba com o changeset que torna minha cópia idêntica ao upstream .
    E é isso que o git merge --strategy=theirs deveria fazer.


    git merge --strategy=theirs Simulação # 2

    Mostra como uma mesclagem, com o nosso como o primeiro pai.

    (proposto por jcwenger )

     git checkout -b tmp upstream git merge -s ours thebranch # ignoring all changes from downstream git checkout downstream git merge --squash tmp # apply changes from tmp but not as merge. git rev-parse upstream > .git/MERGE_HEAD #record upstream 2nd merge head git commit -m "rebaselined thebranch from upstream" # make the commit. git branch -D tmp # deleting tmp 

    git merge --strategy=theirs Simulação # 3

    Esta postagem do blog menciona :

     git merge -s ours ref-to-be-merged git diff --binary ref-to-be-merged | git apply -R --index git commit -F .git/COMMIT_EDITMSG --amend 

    às vezes você quer fazer isso, e não porque você tem “porcaria” no seu histórico, mas talvez porque você queira mudar a linha de base para o desenvolvimento em um repository público onde o rebasing deve ser evitado .


    git merge --strategy=theirs Simulação # 4

    (mesmo post no blog)

    Alternativamente, se você quiser manter as ramificações upstream locais prontas para o avanço, um compromisso potencial é trabalhar com o entendimento de que, para sid / unstable, a ramificação upstream pode, de tempos em tempos, ser redefinida / rebased (com base em events que estão acabados do seu controle no lado do projeto upstream).
    Isso não é grande coisa e trabalhar com essa suposição significa que é fácil manter a ramificação upstream local em um estado em que só são necessárias atualizações rápidas.

     git branch -m upstream-unstable upstream-unstable-save git branch upstream-unstable upstream-remote/master git merge -s ours upstream-unstable git diff --binary ref-to-be-merged | git apply -R --index --exclude="debian/*" git commit -F .git/COMMIT_EDITMSG --amend 

    git merge --strategy=theirs Simulação # 5

    (proposto por Barak A. Pearlmutter ):

     git checkout MINE git merge --no-commit -s ours HERS git rm -rf . git checkout HERS -- . git checkout MINE -- debian # or whatever, as appropriate git gui # edit commit message & click commit button 

    git merge --strategy=theirs Simulação # 6

    (proposto pelo mesmo Michael Gebetsroither ):

    Michael Gebetsroou, alegando que eu estava “trapaceando”;) e deu outra solução com comandos de baixo nível de encanamento:

    (não seria correto se não fosse possível com comandos git only, tudo no git com diff / patch / apply não é uma solução real;).

     # get the contents of another branch git read-tree -u --reset  # selectivly merge subdirectories # eg superseed upstream source with that from another branch git merge -s ours --no-commit other_upstream git read-tree --reset -u other_upstream # or use --prefix=foo/ git checkout HEAD -- debian/ git checkout HEAD -- .gitignore git commit -m 'superseed upstream source' -a 

    Parece-me que você só precisa fazer:

     $ git reset --hard origin/master 

    Se não houver nenhuma mudança para empurrar o autor, e você simplesmente quiser que o ramo do upstream seja o seu ramo atual, isso fará isso. Não é prejudicial fazer isso localmente, mas você perderá quaisquer alterações locais ** que não tenham sido enviadas ao master.

    ** Na verdade, as mudanças ainda estão por aí, se você as tiver cometido localmente, já que os commits ainda estarão no seu git reflog , geralmente por pelo menos 30 dias.

    Você pode fazer isso com bastante facilidade agora:

     $ git fetch origin $ git merge origin/master -s recursive -Xtheirs 

    Isso torna o repo local sincronizado com a origem e preserva o histórico.

    Outra simulação para o git merge -s theirs ref-to-be-merged :

     git merge --no-ff -s ours ref-to-be-merged # enforce a merge commit; content is still wrong git reset --hard HEAD^2; git reset --soft HEAD@{1} # fix the content git commit --amend 

    Uma alternativa para a redefinição dupla seria aplicar o patch reverso:

     git diff --binary ref-to-be-merged | git apply -R --index 

    Há também uma maneira com pouca ajuda do comando de encanamento – IMHO o mais simples. Digamos que você queira emular “theirs” para o caso de 2 branches:

     head1=$(git show --pretty=format:"%H" -s foo) head2=$(git show --pretty=format:"%H" -s bar) tree=$(git show --pretty=format:"%T" -s bar) newhead=$(git commit-tree $tree -p $head1 -p $head2 < <<"merge commit message") git reset --hard $newhead 

    Isso mescla um número arbitrário de cabeças (2 no exemplo acima) usando a tree de um deles (barra no exemplo acima, fornecendo a tree 'theirs'), desconsiderando quaisquer problemas de diff / arquivo (commit-tree é comando de baixo nível, portanto não se preocupa com isso). Note que a cabeça pode ser apenas 1 (assim equivalente a escolha de cereja com "deles").

    Note que o header pai é especificado primeiro, pode influenciar algumas coisas (veja por exemplo - first-parent do comando git-log) - então tenha isso em mente.

    Ao invés de git-show, qualquer outra coisa capaz de gerar hashes de tree e commit pode ser usada - o que estiver acostumado a analisar (cat-file, rev-list, ...). Você pode seguir tudo com git commit --endend para embelezar interativamente a mensagem de commit.

    mude para o ramo upstream remoto e faça um git merge com a estratégia de mesclagem definida para a ours .

     git checkout origin/master git merge dev --strategy=ours git commit ... git push 

    Todo o histórico ainda estará presente, mas você terá um commit extra de mesclagem. O importante aqui é começar a partir da versão que você quer estar e mesclar a ours com o branch github.

    Pesado entregue, mas o inferno, o que pode dar errado?

    • Confira o ramo X que você quer se parecer com o Y
    • cp -r .git / tmp
    • Confira o ramo Y
    • rm -rf .git && cp -r /tmp/.git.
    • Comprometer-se e empurrar qualquer diferença
    • FEITO.