Estou usando o git em um novo projeto que possui dois ramos de desenvolvimento paralelos - mas atualmente experimentais:
master
: importação da base de código existente mais alguns mods dos quais geralmente tenho certezaexp1
: ramo experimental nº 1exp2
: ramo experimental nº 2
exp1
e exp2
representam duas abordagens arquitetônicas muito diferentes. Até me aprofundar, não tenho como saber qual deles (se é que existe) irá funcionar. À medida que progrido em uma ramificação, às vezes tenho edições que seriam úteis na outra ramificação e gostaria de mesclar apenas essas.
Qual é a melhor maneira de mesclar mudanças seletivas de um ramo de desenvolvimento para outro, deixando para trás todo o resto?
Abordagens que considerei:
git merge --no-commit
seguido pela desagregação manual de um grande número de edições que eu não quero tornar comum entre as ramificações.Cópia manual de arquivos comuns em um diretório temporário, seguida por
git checkout
para mover para a outra ramificação e, em seguida, mais cópia manual do diretório temporário para a árvore de trabalho.Uma variação acima. Abandone as
exp
ramificações por enquanto e use dois repositórios locais adicionais para experimentação. Isso torna a cópia manual de arquivos muito mais simples.
Todas essas três abordagens parecem tediosas e propensas a erros. Espero que exista uma abordagem melhor; algo semelhante a um parâmetro do caminho do filtro que tornaria git-merge
mais seletivo.
fonte
git merge -s ours --no-commit
seguidos por alguns nãogit read-tree
seria uma boa solução para isso? Veja stackoverflow.com/questions/1214906/…Respostas:
Você usa o comando cherry-pick para obter confirmações individuais de uma ramificação.
Se as alterações desejadas não estiverem em confirmações individuais, use o método mostrado aqui para dividir a confirmação em confirmações individuais . Grosso modo, você costuma usar
git rebase -i
o commit original para editar,git reset HEAD^
reverter seletivamente as alterações e depoisgit commit
confirmar esse bit como um novo commit no histórico.Há outro método interessante aqui na Red Hat Magazine, onde eles usam
git add --patch
ou possivelmentegit add --interactive
que permite adicionar apenas partes de um pedaço, se você deseja dividir diferentes alterações em um arquivo individual (pesquise nessa página por "divisão").Depois de dividir as alterações, agora você pode escolher apenas as que deseja.
fonte
Eu tive exatamente o mesmo problema, como mencionado por você acima. Mas eu achei isso mais claro ao explicar a resposta.
Resumo:
Faça o checkout do (s) caminho (s) da ramificação que você deseja mesclar,
Dica: Ele também funciona sem
--
gostar do visto no post vinculado.ou mesclar seletivamente pedaços
Alternativamente, o uso redefinir e, em seguida, adicionar a opção
-p
,Finalmente confirmar
fonte
foo.c
,git reset HEAD foo.c
desestabiliza esse arquivo e pode diferenciá-lo. Descobri isso depois de tentar e voltar aqui para procurar uma resposta para isso #git diff --cached
git checkout -p <revision> -- <path>
será o mesmo que emitir os três primeiros comandos que você descreveu :)Para mesclar seletivamente arquivos de um ramo em outro ramo, execute
Onde
branchX
é a ramificação da qual você deseja mesclar na ramificação atual.o
--no-commit
opção preparará os arquivos que foram mesclados pelo Git sem realmente enviá-los. Isso lhe dará a oportunidade de modificar os arquivos mesclados da maneira que desejar e depois enviá-los você mesmo.Dependendo de como você deseja mesclar arquivos, existem quatro casos:
1) Você deseja uma verdadeira mesclagem.
Nesse caso, você aceita os arquivos mesclados da maneira que o Git os mescla automaticamente e os confirma.
2) Existem alguns arquivos que você não deseja mesclar.
Por exemplo, você deseja manter a versão na ramificação atual e ignorar a versão na ramificação da qual você está mesclando.
Para selecionar a versão na ramificação atual, execute:
Isso recuperará a versão da
file1
ramificação atual e substituirá ofile1
automerged pelo Git.3) Se você deseja a versão no branchX (e não uma mesclagem verdadeira).
Corre:
Isso recuperará a versão de
file1
inbranchX
e substituiráfile1
a automática pelo Git.4) O último caso é se você deseja selecionar apenas mesclagens específicas em
file1
.Nesse caso, você pode editar o modificado
file1
diretamente, atualizá-lo para o que quiser que a versão dofile1
se torne e depois confirmar.Se o Git não puder mesclar um arquivo automaticamente, ele o reportará como "não imerso " e produzirá uma cópia na qual você precisará resolver os conflitos manualmente.
Para explicar mais com um exemplo, digamos que você deseja mesclar
branchX
no ramo atual:Você então executa o
git status
comando para visualizar o status dos arquivos modificados.Por exemplo:
Onde
file1
,file2
efile3
são os arquivos git têm sucesso fundiu-auto.O que isto significa é que as mudanças no
master
ebranchX
para todos esses três arquivos foram combinadas sem conflitos.Você pode inspecionar como a mesclagem foi realizada executando o
git diff --cached
;Se você achar que uma mesclagem é indesejável, poderá
git commit
Se você não deseja mesclar
file1
e deseja manter a versão na ramificação atualCorre
Se você não deseja mesclar
file2
e deseja apenas a versão embranchX
Corre
Se você deseja
file3
mesclar automaticamente, não faça nada.O Git já o fundiu neste momento.
file4
acima, há uma falha na mesclagem do Git. Isso significa que há alterações nos dois ramos que ocorrem na mesma linha. É aqui que você precisará resolver os conflitos manualmente. Você pode descartar a mesclagem feita editando o arquivo diretamente ou executando o comando checkout da versão na ramificação que desejafile4
se tornar.Finalmente, não esqueça
git commit
.fonte
git merge --no-commit branchX
é apenas um fast-forward, o ponteiro será atualizado, eo --no-commit é, assim, ignorado--no-ff
para impedir esse comportamento?Eu não gosto das abordagens acima. O uso de pick-cherry é ótimo para escolher uma única alteração, mas é doloroso se você deseja incluir todas as alterações, exceto algumas ruins. Aqui está a minha abordagem.
Não há
--interactive
argumento que você possa passar para o git merge.Aqui está a alternativa:
Você tem algumas alterações no 'recurso' da ramificação e deseja trazer algumas, mas não todas, para o 'mestre' de uma maneira não desleixada (ou seja, você não quer escolher e comprometer cada uma delas)
Então, apenas envolva isso em um script de shell, mude o master para $ to e o recurso para $ from e você estará pronto:
fonte
git rebase -i $to
paragit rebase -i $to || $SHELL
, para que o usuário possa ligargit --skip
etc, conforme necessário, se a rebase falhar. Também vale a pena encadear as linhas, em&&
vez de novas linhas.Há outro caminho a seguir:
É uma mistura entre
git checkout
egit add -p
pode ser exatamente o que você está procurando:fonte
Embora algumas dessas respostas sejam muito boas, sinto que nenhuma delas respondeu à restrição original do OP: selecionar arquivos específicos de ramificações específicas. Essa solução faz isso, mas pode ser tediosa se houver muitos arquivos.
Vamos dizer que você tem as
master
,exp1
eexp2
ramos. Você deseja mesclar um arquivo de cada uma das ramificações experimentais no mestre. Eu faria algo assim:Isso fornecerá diferenças de arquivo para cada um dos arquivos que você deseja. Nada mais. Nada menos. É útil que você tenha alterações radicalmente diferentes de arquivo entre versões - no meu caso, alterando um aplicativo do Rails 2 para o Rails 3.
EDIT : isso mescla arquivos, mas faz uma mesclagem inteligente. Não consegui descobrir como usar esse método para obter informações de diferenças no arquivo (talvez ainda seja para diferenças extremas. Coisas pequenas e irritantes, como espaço em branco, são mescladas novamente, a menos que você use a
-s recursive -X ignore-all-space
opção)fonte
git checkout exp1 path/to/file_a path/to/file_x
git checkout feature <path>/*
para obter grupos de arquivos.A resposta do 1800 INFORMAÇÃO está completamente correta. Como um git noob, no entanto, "usar git cherry-pick" não foi suficiente para eu descobrir isso sem um pouco mais de pesquisa na internet, então pensei em publicar um guia mais detalhado caso alguém mais esteja em um barco semelhante.
Meu caso de uso estava querendo puxar seletivamente alterações do ramo de github de outra pessoa para o meu. Se você já possui uma filial local com as alterações, precisará executar apenas as etapas 2 e 5-7.
Crie (se não for criado) um ramo local com as alterações que deseja trazer.
$ git branch mybranch <base branch>
Mude para ele.
$ git checkout mybranch
Puxe para baixo as alterações desejadas da conta da outra pessoa. Caso ainda não o tenha, adicione-os como um controle remoto.
$ git remote add repos-w-changes <git url>
Puxe tudo do ramo deles.
$ git pull repos-w-changes branch-i-want
Veja os logs de confirmação para ver quais alterações você deseja:
$ git log
Volte para a ramificação na qual deseja extrair as alterações.
$ git checkout originalbranch
Cherry escolhe seus commits, um por um, com os hashes.
$ git cherry-pick -x hash-of-commit
Dica: http://www.sourcemage.org/Git_Guide
fonte
git cherry
comando (consulte o manual primeiro) para identificar confirmações que ainda não foram mescladas.Aqui está como você pode substituir o
Myclass.java
arquivo namaster
ramificação porMyclass.java
nafeature1
ramificação. Funcionará mesmo seMyclass.java
não existirmaster
.Observe que isso substituirá - não mesclará - e ignorará as alterações locais na ramificação principal.
fonte
theirs
sobrescreverours
=> +1 Felicidades;)2. Manual copying of common files into a temp directory followed by ...copying out of the temp directory into the working tree.
A maneira simples, para realmente mesclar arquivos específicos de duas ramificações, não apenas substituir arquivos específicos por arquivos de outra ramificação.
Etapa 1: diferencie os galhos
git diff branch_b > my_patch_file.patch
Cria um arquivo de correção da diferença entre o ramo atual e o ramo_b
Etapa 2: Aplicar o patch nos arquivos que correspondem a um padrão
git apply -p1 --include=pattern/matching/the/path/to/file/or/folder my_patch_file.patch
notas úteis sobre as opções
Você pode usar
*
como curinga no padrão de inclusão.As barras não precisam ser escapadas.
Além disso, você pode usar --exclude e aplicá-lo a tudo, exceto aos arquivos correspondentes ao padrão, ou reverter o patch com -R
A opção -p1 é uma reserva do comando * unix patch e o fato de o conteúdo do arquivo de correção preceder cada nome de arquivo com
a/
oub/
(ou mais dependendo de como o arquivo de correção foi gerado) que você precisa remover para que ele possa descobrir o arquivo real para o caminho para o arquivo ao qual o patch precisa ser aplicado.Confira a página de manual do git-apply para obter mais opções.
Etapa três: não há etapa três
Obviamente, você gostaria de confirmar suas alterações, mas quem pode dizer que você não tem outros ajustes relacionados antes de fazer seu commit.
fonte
Veja como você pode fazer com que o histórico siga apenas alguns arquivos de outra ramificação com um mínimo de confusão, mesmo que uma mesclagem mais "simples" traga muito mais alterações que você não deseja.
Primeiro, você executará a etapa incomum de declarar antecipadamente que o que você está prestes a confirmar é uma mesclagem, sem o git fazer nada com os arquivos no diretório de trabalho:
. . . onde "branchname" é o que você alega estar fundindo. Se você cometer imediatamente, isso não fará alterações, mas ainda mostrará ascendência do outro ramo. Você pode adicionar mais branches / tags / etc. para a linha de comando, se necessário. Neste ponto, porém, não há alterações a serem confirmadas, portanto, obtenha os arquivos das outras revisões a seguir.
Se você estava mesclando de mais de um outro ramo, repita conforme necessário.
Agora, os arquivos da outra ramificação estão no índice, prontos para serem confirmados, com histórico.
e você terá muito o que explicar nessa mensagem de confirmação.
Observe, no entanto, caso não esteja claro, que isso é uma bagunça. Não está no espírito do que é um "ramo", e escolher a cereja é uma maneira mais honesta de fazer o que você faria aqui. Se você quisesse fazer outra "mesclagem" para outros arquivos no mesmo ramo que você não trouxe da última vez, ele o interromperá com uma mensagem "já atualizada". É um sintoma de não ramificar quando deveríamos ter, no ramo "de" deve haver mais de um ramo diferente.
fonte
git merge --no-ff --no-commit -s outs branchname1
) é exatamente o que eu estava procurando! Obrigado!Sei que estou um pouco atrasado, mas esse é o meu fluxo de trabalho para mesclar arquivos seletivos.
fonte
A maneira mais fácil é definir seu repo para o ramo com o qual você deseja mesclar e executar,
Se você correr
você verá o arquivo já preparado ...
Então corra
Simples.
fonte
Eu encontrei este post para conter a resposta mais simples. Simplesmente faça:
Exemplo:
Veja a postagem para mais informações.
fonte
É estranho que o git ainda não tenha uma ferramenta tão conveniente "pronta para uso". Eu o uso muito quando atualizo algum ramo da versão antiga (que ainda possui muitos usuários de software) apenas com algumas correções do ramo da versão atual. Nesse caso, geralmente é necessário obter rapidamente apenas algumas linhas de código do arquivo no tronco, ignorando muitas outras alterações (que não devem entrar na versão antiga) ... E, é claro, mesclagem interativa de três vias é necessário nesse caso,
git checkout --patch <branch> <file path>
não é utilizável para essa finalidade de mesclagem seletiva.Você pode fazer isso facilmente:
Basta adicionar esta linha à
[alias]
seção em seu arquivo global.gitconfig
ou local.git/config
:Isso implica que você use o Beyond Compare. Apenas mude para o software de sua escolha, se necessário. Ou você pode alterá-lo para mesclagem automática de três vias se não precisar da mesclagem seletiva interativa:
Então use assim:
Isso lhe dará a verdadeira oportunidade de mesclagem seletiva em árvore de qualquer arquivo em outra ramificação.
fonte
Não é exatamente o que você estava procurando, mas foi útil para mim:
É uma mistura de algumas respostas.
fonte
git checkout HEAD file1
para manter a versão atual e desmembrar o arquivofile1
, pode-se usar a-p
opção para selecionar parte do arquivo a ser mesclado. obrigado pelo truque!Eu faria um
Dessa forma, você pode limitar o intervalo de confirmações para um padrão de arquivo de uma ramificação.
Roubado em: http://www.gelato.unsw.edu.au/archives/git/0701/37964.html
fonte
Eu tive exatamente o mesmo problema, como mencionado por você acima. Mas achei esse blog git mais claro ao explicar a resposta.
Comando no link acima:
fonte
Gosto da resposta 'git-Interactive-Merge', acima, mas há uma mais fácil. Deixe o git fazer isso por você usando uma combinação de rebase interativa e para:
Portanto, o caso é que você queira C1 e C2 da ramificação 'feature' (ponto de ramificação 'A'), mas nada disso por enquanto.
Que, como acima, leva você ao editor interativo, onde você seleciona as linhas de 'seleção' para C1 e C2 (como acima). Salve e saia e, em seguida, ele prosseguirá com a rebase e fornecerá a ramificação 'temp' e também HEAD no master + C1 + C2:
Em seguida, você pode simplesmente atualizar o mestre para HEAD e excluir o ramo temporário e pronto:
fonte
Que tal
git reset --soft branch
? Estou surpreso que ninguém tenha mencionado ainda.Para mim, é a maneira mais fácil de selecionar seletivamente as alterações de outro ramo, pois esse comando coloca na minha árvore de trabalho todas as diferenças e eu posso escolher ou reverter facilmente qual delas preciso. Dessa forma, eu tenho controle total sobre os arquivos confirmados.
fonte
Sei que essa pergunta é antiga e há muitas outras respostas, mas escrevi meu próprio script chamado 'pmerge' para mesclar parcialmente diretórios. É um trabalho em andamento e ainda estou aprendendo os scripts git e bash.
Este comando usa
git merge --no-commit
e depois aplica as alterações que não correspondem ao caminho fornecido.Uso:
git pmerge branch path
Exemplo:
git merge develop src/
Eu não testei extensivamente. O diretório de trabalho deve estar livre de alterações não confirmadas e arquivos não rastreados.
fonte
Você pode usar
read-tree
para ler ou mesclar determinada árvore remota no índice atual, por exemplo:Para executar a mesclagem, use em
-m
vez disso.Veja também: Como mesclar um subdiretório no git?
fonte
Uma abordagem simples para mesclar / confirmar seletivamente por arquivo:
git checkout dstBranch git merge srcBranch // make changes, including resolving conflicts to single files git add singleFile1 singleFile2 git commit -m "message specific to a few files" git reset --hard # blow away uncommitted changes
fonte
Se você não tiver muitos arquivos alterados, isso deixará você sem confirmações adicionais.
1. Ramificação duplicada temporariamente
$ git checkout -b temp_branch
2. Redefina para a última confirmação desejada
$ git reset --hard HEAD~n
, onden
está o número de confirmações necessárias para voltar3. Faça o checkout de cada arquivo da ramificação original
$ git checkout origin/original_branch filename.ext
Agora você pode confirmar e forçar push (para substituir o controle remoto), se necessário.
fonte
Se você só precisar mesclar um diretório específico e deixar tudo intacto e ainda preservar o histórico, poderá tentar isso ... crie um novo
target-branch
fora do diretóriomaster
antes de experimentar.As etapas abaixo assumem que você tem duas ramificações
target-branch
esource-branch
, e o diretóriodir-to-merge
que você deseja mesclar está nosource-branch
. Suponha também que você tenha outros diretórios, comodir-to-retain
no destino, que não deseja alterar e reter o histórico. Além disso, assume que há conflitos de mesclagem nodir-to-merge
.fonte
Quando apenas alguns arquivos foram alterados entre as confirmações atuais das duas ramificações, mesclo manualmente as alterações passando pelos arquivos diferentes.
git difftoll <branch-1>..<branch-2>
fonte