Minha motivação para experimentar o git-svn é a fusão e ramificação sem esforço. Então notei que o homem git-svn (1) diz:
Executar git-merge ou git-pull NÃO é recomendado em uma ramificação da qual você planeja se comprometer. O Subversion não representa fusões de maneira razoável ou útil; então os usuários que usam o Subversion não podem ver nenhuma fusão que você fez. Além disso, se você mesclar ou extrair de uma ramificação git que é um espelho de uma ramificação SVN, o dcommit poderá confirmar a ramificação errada.
Isso significa que não posso criar um ramo local a partir do svn / trunk (ou um ramo), cortar, mesclar novamente para o svn / trunk e, em seguida, dcommit? Eu entendo que os usuários do svn verão a mesma bagunça que se mescla no svn pré 1.5.x sempre foram, mas existem outras desvantagens? Essa última frase também me preocupa. As pessoas rotineiramente fazem esse tipo de coisa?
--mergeinfo=<mergeinfo>
opção que pode passar informações de mesclagem ao SVN. Não tenho certeza de como deve ser usado.Respostas:
Na verdade, encontrei uma maneira ainda melhor com a
--no-ff
opção git merge. Toda essa técnica de squash que usei antes não é mais necessária.Meu novo fluxo de trabalho agora é o seguinte:
Eu tenho um ramo "mestre", que é o único ramo que eu dcommit partir e que clone do repositório SVN (
-s
assumir que tem um layout SVN padrão no repositóriotrunk/
,branches/
etags/
):Eu trabalho em uma filial local "work" (
-b
cria a filial "work")confirmar localmente na ramificação "trabalho" (
-s
para assinar sua mensagem de confirmação). Na sequela, suponho que você fez três confirmações locaisAgora você deseja confirmar no servidor SVN
[Eventualmente] esconde as modificações que você não deseja que sejam confirmadas no servidor SVN (geralmente você comenta algum código no arquivo principal apenas porque deseja acelerar a compilação e se concentrar em um determinado recurso)
rebase a ramificação principal com o repositório SVN (para atualizar a partir do servidor SVN)
volte para a ramificação do trabalho e faça uma nova refazer com o mestre
Verifique se está tudo bem usando, por exemplo:
Agora é hora de mesclar todos os três commits do ramo "work" no "master" usando esta
--no-ff
opção maravilhosaVocê pode observar o status dos logs:
Agora você provavelmente deseja editar (
amend
) o último commit dos seus caras do SVN (caso contrário, eles verão apenas um único commit com a mensagem "Merge branch 'work'"Finalmente confirme no servidor SVN
Volte ao trabalho e, eventualmente, recupere seus arquivos escondidos:
fonte
--no-ff
opção, você está criando explicitamente uma consolidação de mesclagem (uma consolidação com dois pais) em vez de um avanço rápido. Para garantir que todas as confirmações no ramo svn-tracking sejam confirmadas por pais solteiros, todas as fusões devem ser encaminhadas rapidamente (--ff-only
podem ajudar com isso) ou, se o tronco tiver sido alterado nas suas costas--squash
, certo?git svn dcommit
reescreve o commit do git que você fornece. Isso significa que você perde o outro pai, e agora seu repositório Git não tem registro em que você mesclou esse ramomaster
. Isso também pode deixar seu diretório de trabalho em um estado inconsistente.git merge --no-ff work -m "commit message"
em vez de ter um extragit commit --amend
passoCriar ramificações locais é definitivamente possível com o git-svn. Contanto que você esteja usando ramos locais por si mesmo e não tentando usar o git para mesclar entre os ramos svn upstream, você deve estar bem.
Eu tenho um ramo "master" que eu uso para rastrear o servidor svn. Este é o único ramo do qual eu comprometo. Se estou fazendo algum trabalho, crio um ramo de tópico e trabalho nele. Quando eu quero confirmar, eu faço o seguinte:
Também tenho outra situação em que preciso manter algumas alterações locais (para depuração) que nunca devem ser enviadas para o svn. Para isso, tenho o ramo principal acima, mas também um ramo chamado "trabalho", onde normalmente trabalho. As ramificações de tópicos são ramificadas do trabalho. Quando quero confirmar um trabalho lá, faço checkout master e uso cherry-pick para selecionar os commit no ramo de trabalho que eu quero confirmar no svn. Isso ocorre porque eu quero evitar confirmar os três commits de alteração local. Então, eu saio do ramo principal e refiz tudo.
Vale a pena correr
git svn dcommit -n
primeiro para garantir que você esteja prestes a confirmar exatamente o que pretende confirmar. Diferente do git, reescrever o histórico no svn é difícil!Eu sinto que deve haver uma maneira melhor de mesclar a mudança em uma ramificação de tópico, ignorando esses commits de mudança local do que usar cherry-pick, portanto, se alguém tiver alguma idéia, será bem-vindo.
fonte
Solução simples: remova a ramificação 'trabalho' após a mesclagem
Resposta curta: Você pode usar o git da maneira que desejar (veja abaixo um fluxo de trabalho simples), incluindo mesclagem. Apenas certifique-se de seguir cada ' trabalho de mesclagem do git ' com ' git branch -d work ' para excluir o ramo de trabalho temporário.
Explicação em segundo plano: O problema de mesclagem / dcommit é que, sempre que você 'git svn dcommit' uma ramificação, o histórico de mesclagem dessa ramificação é 'achatado': o git esquece todas as operações de mesclagem que entraram nessa ramificação: apenas o conteúdo do arquivo é preservado, mas o fato de que esse conteúdo (parcialmente) veio de um outro ramo específico está perdido. Veja: Por que o git svn dcommit perde o histórico de confirmações de mesclagem para ramificações locais?
(Nota: Não há muito o que o git-svn possa fazer a respeito: o svn simplesmente não entende as combinações muito mais poderosas do git. Portanto, dentro do repositório svn, essas informações de mesclagem não podem ser representadas de forma alguma.)
Mas este é o problema todo . Se você excluir o ramo 'work' depois que ele foi mesclado no 'master branch', seu repositório git estará 100% limpo e se parecerá exatamente com o seu repositório svn.
Meu fluxo de trabalho: Claro, primeiro clonei o repositório svn remoto em um repositório git local (isso pode levar algum tempo):
Todo o trabalho acontece dentro do "diretório local". Sempre que preciso obter atualizações do servidor (como 'svn update'), eu faço:
Eu faço todo o meu trabalho de desenvolvimento em uma ramificação separada 'work', criada assim:
Obviamente, você pode criar quantas ramificações para o seu trabalho quiser e mesclar e refazer entre elas quantas quiser (basta excluí-las quando terminar com elas - como discutido abaixo). No meu trabalho normal, comprometo-me com muita frequência:
O próximo passo (git rebase -i) é opcional --- está apenas limpando a história antes de arquivá-la no svn: Quando atingi uma milha estável que quero compartilhar com outras pessoas, reescrevi a história desse 'trabalho' ramifique e limpe as mensagens de confirmação (outros desenvolvedores não precisam ver todos os pequenos passos e erros que cometi no caminho - apenas o resultado). Para isso, eu faço
e copie o hash sha-1 do último commit que está ativo no repositório svn (como indicado por um git-svn-id). Então eu ligo
Basta colar o sha-1 hash do nosso último svn commit ao invés do meu. Você pode ler a documentação com 'git help rebase' para obter detalhes. Resumindo: este comando primeiro abre um editor apresentando suas confirmações ---- basta alterar 'pick' para 'squash' para todas as confirmações que você deseja esmagar com as confirmações anteriores. Obviamente, a primeira linha deve permanecer como uma 'escolha'. Dessa forma, você pode condensar seus muitos pequenos commits em uma ou mais unidades significativas. Salve e saia do editor. Você receberá outro editor solicitando que você reescreva as mensagens de log de confirmação.
Resumindo: depois de terminar o 'hacker de código', massageio minha ramificação 'trabalho' até que pareça como quero apresentá-lo aos outros programadores (ou como quero ver o trabalho em algumas semanas quando navego pelo histórico) .
Para enviar as alterações ao repositório svn, eu faço:
Agora estamos de volta ao antigo ramo 'mestre' atualizado com todas as alterações que ocorreram nesse período no repositório svn (suas novas alterações estão ocultas no ramo 'trabalho').
Se houver alterações que possam colidir com as novas alterações de 'trabalho', você precisará resolvê-las localmente antes de poder enviar seu novo trabalho (veja detalhes mais abaixo). Em seguida, podemos enviar nossas alterações para svn:
Nota 1: O comando 'git branch -d work' é bastante seguro: permite excluir apenas os ramos que você não precisa mais (porque eles já estão mesclados no seu ramo atual). Se você executar este comando por engano antes de mesclar seu trabalho com a ramificação 'master', você receberá uma mensagem de erro.
Nota 2: Certifique-se de excluir sua ramificação com 'git branch -d work' entre mesclagem e dcommit: Se você tentar excluir a ramificação após dcommit, você receberá uma mensagem de erro: Ao fazer 'git svn dcommit', o git esquece que sua filial foi mesclada com 'master'. Você deve removê-lo com 'git branch -D work', que não faz a verificação de segurança.
Agora, crio imediatamente um novo ramo 'trabalho' para evitar hackers acidentalmente no ramo 'mestre':
Integrando seu 'trabalho' com alterações no svn: Aqui está o que eu faço quando o 'git svn rebase' revela que outras pessoas mudaram o repositório svn enquanto eu trabalhava no meu ramo 'trabalho':
Existem soluções mais poderosas: O fluxo de trabalho apresentado é simplista: ele usa os poderes do git apenas dentro de cada rodada de 'update / hack / dcommit' --- mas deixa o histórico do projeto a longo prazo tão linear quanto o repositório svn. Tudo bem se você deseja apenas começar a usar o git mesclado em pequenos primeiros passos em um projeto svn legado.
Quando você se familiarizar com a fusão do git, sinta-se à vontade para explorar outros fluxos de trabalho: se você sabe o que está fazendo, pode misturar o git merges com o svn merges ( Usando o git-svn (ou similar) apenas para ajudar no svn merge? )
fonte
git merge --squash work
, por que não fazer isso? Eu posso ver fazendo confirmações de squash na ramificação antes da mesclagem, se você estiver criando mais de uma 'escolha' (digamos que você tenha 8 confirmações e esteja transformando cada uma das 4 confirmações em 1 e mesclando 2 confirmações para master). Além disso, quando atualizando meu ramo 'trabalho', eu façorebase
, é mais simples do que criar um outro ramo para o meu ramo e fazer fusões ...A resposta de Greg Hewgill no topo não é segura! Se algum novo commit aparecer no tronco entre os dois "git svn rebase", a mesclagem não será rápida.
Isso pode ser garantido usando o sinalizador "--ff-only" no git-merge, mas geralmente não executo o "git svn rebase" no ramo, apenas o "git rebase master" nele (supondo que seja apenas um local ramo). Depois, é garantido que um "git merge thebranch" avança rapidamente.
fonte
Uma maneira segura de mesclar ramos svn no git é usar o git merge --squash. Isso criará uma única confirmação e parará para você adicionar uma mensagem.
Digamos que você tenha um tópico svn branch, chamado svn-branch.
Neste ponto, você tem todas as alterações do svn-branch compactadas em um commit aguardando no índice
fonte
Rebase o ramo git local para o ramo mestre git e, em seguida, dcommit e, dessa forma, parece que você fez todos esses commits em sequência para que as pessoas svn possam vê-lo linearmente como estão acostumados. Supondo que você tenha um ramo local chamado topic, você poderia fazer
que executará seus commits sobre o ramo mestre, prontos para você confirmar
fonte