Como e por que roubar árvores no git

árvores


Neste artigo, falarei sobre um truque útil, mas pouco conhecido, para trabalhar com o git - como criar facilmente um commit usando uma árvore de outro commit. Simplificando, como obter o estado desejado do projeto em qualquer ramificação, se esse estado já estiver em algum lugar do repositório. Vários exemplos serão dados de como isso possibilita resolver de maneira elegante alguns problemas práticos. E, em particular, vou falar sobre o método encontrado, que pode simplificar bastante a correção de vários conflitos durante o rebase. Além disso, este artigo é uma ótima maneira de entender na prática o que constitui um commit no git.


Conteúdo


A parte teórica. Sobre confirmações e árvores
árvore de confirmação git
Parte prática
1. Sincronização com outra ramificação
2. Comparação de dois ramos
3. Filial Reversa
4. Reverso parcial
5. Mesclagem artificial
6a Método Rebase via mesclagem - descrição
6b Método Rebase via mesclagem - script
7. Alias
Conclusão



A parte teórica. Sobre confirmações e árvores


Confirmar é provavelmente o conceito mais básico no git, vamos ver no que consiste. Cada confirmação possui seu próprio identificador exclusivo na forma de um hash, por exemplo, 5e45ecb . E com o seguinte comando, conhecendo o hash, podemos ver seu conteúdo.


git cat-file -p 5e45ecb 

 tree 8640790949c12690fc71f9abadd7b57ec0539376 parent 930741d1f5fd2a78258aa1999bb4be897ba3d015 author Mark Tareshawty <tareby...@github.com> 1542718283 -0500 committer Mark Tareshawty <tareby...@github.com> 1542718283 -0500 gpgsig -----BEGIN PGP SIGNATURE----- ... -----END PGP SIGNATURE----- Fix scoping so that we don't break the naming convention 

Estas poucas linhas são todo o conteúdo do commit:


  • tree - um link para um estado específico do projeto
  • pai - link para confirmação do pai
  • author - autor do commit original + data
  • committer - criador deste commit + date
  • gpgsig - assinatura digital (se disponível)
  • message - confirmar o texto

Deixe-me lembrá-lo de que o commit no git (diferente de outros VCS) não descreve as alterações feitas. É o contrário: cada confirmação descreve o estado específico do projeto como um todo, e o que vemos como as mudanças que ele faz é na verdade uma diferença calculada dinamicamente em comparação com o estado anterior. Também vale a pena notar que todas as confirmações são imutáveis ​​(imutáveis), ou seja, por exemplo, com rebase / seleção de cereja / alteração, absolutamente novas confirmações são criadas.


tree (tree) - na verdade, é apenas uma pasta com conteúdo imutável específico. Um objeto da árvore de tipos contém uma lista de arquivos com conteúdo específico (blobs) e subpastas (árvores). E a árvore para a qual cada confirmação aponta é a pasta raiz do projeto, ou melhor, seu estado específico.


visualizar o conteúdo da árvore

Isso pode ser feito exatamente da mesma maneira para qualquer outro objeto (commit / tree / blob) e é suficiente para receber os primeiros caracteres hash únicos: 8640790949c12690fc71f9abadd7b57ec0539376 -> 8640790.


 git cat-file -p 8640790 

 100644 blob 7ab08294a46f158c51460be3e7df6a190e15023b .env.example 100644 blob 0a1a4d1ad9ff3f35b67678ca893811e91b423af5 .gemset 040000 tree 033aa38ce0eab11fe229067c14ccce95e2b8b601 .github 100644 blob ca49bb7ffa6273b0be4ce7ba1accba456032fb11 .gitignore 100644 blob c99d2e7396e14ac072c63ec8419d9b8fede28d86 .rspec 100644 blob 65e77a2f59f635a8f24eb4714e8e43745c5c0eb9 .rubocop.yml 100644 blob 8e8299dcc068356889b365e23c948b92c6dfcd78 .ruby-version 100644 blob 19028f9885948aca2ba61f9d062e9dc21c21ad03 .stylelintrc.json 100644 blob 2f7a032fbc3f4f7195bfd91cb33889a684b572b9 .travis.yml 100644 blob 121615722a6c206a9fe24b9a1c9b647662a460d2 ARCHITECTURE.md 100644 blob 898195daeea0bbf8c5930deeaf1020ba8abab34a Gemfile 100644 blob de7ca707f9fe9172db941b65cdacaba7e024fc06 Gemfile.lock 100644 blob e6ff62fefd071b1a8ca279bae94ddbc4dd17b7a3 Gruntfile.js 100644 blob 0cac5b30fb32d36cce2aeb7d936be7b6207d68c7 MIT-LICENSE.txt 100644 blob c2c566e8cc3d440d3ee8041b79cded416db28136 Procfile 100644 blob d1fb2f575380e1e093a4d82e3f19e51f0b99a0a1 Procfile.dev 100644 blob 3a88e138f10fa65bd2cfe1a1d3292348205508b5 README.md 100644 blob 5366e6e073cc426518894cc379d3a07cf3c9cfb3 Rakefile 100644 blob e6d3d2d3e9d5122c5f75bbeee8ed0917ad38c131 app.json 040000 tree 94f83cf03bd6f1cf14672034877b14604744b7a2 app 040000 tree d4d859e82564250b4c4f2047de21e089e7555475 bin 100644 blob 1f71007621f17334fd6f2dd71c87b7a16867119c config.ru 040000 tree 9e8e4bf5ec44541aefff544672b94ca8a9d07bbf config 040000 tree 31b8d0e1fa2bb789dbd6319e04fc9f115952cf2a db 040000 tree 38e7a13e0e772c2a13e46d2007e239f679045bee doc 040000 tree a6e35ded8b35837660cf786e637912377f845515 lib 040000 tree d564d0bc3dd917926892c55e3706cc116d5b165e log 100644 blob 843523565ddee5e00f580d9c4e37fc2478fdaecc package-lock.json 100644 blob 791ee833ad316d75b1d2c83a64a3053fc952d254 package.json 040000 tree 4645317c52675d9889f89b26f4dd4d2ae1d8cbad public 040000 tree 31d3f8ae4a4ffe62787134642743ed32a35dbae2 resources 040000 tree 807ffa29868ef9c25ddb4b4126a4bb7f1b041bf0 script 040000 tree 4c3bf9a7f3679ba059b0f1c214a500d197546462 spec 040000 tree 136c8174412345531a9542cafef25ce558d2664f test 040000 tree e6524eafe066819e4181bc56c503320548d8009b vendor 

Este é realmente o recurso mais importante de como o git funciona, o identificador de confirmação é realmente um hash de seu conteúdo. Assim como os hashes de objetos embutidos nele (árvores, bolhas).


Agora vamos ver o que acontece quando fazemos


 git commit -m "Fixed bug" 

Este comando cria uma nova confirmação que captura o seguinte:


  • estado do projeto temporário (salvo como um novo objeto de árvore e seu hash obtido)
  • link para o commit atual (pai)
  • autor + committer + duas datas
  • confirmar texto

Tudo isso é salvo, com hash e um novo objeto de confirmação é obtido. E a equipe eleva automaticamente o ponteiro de ramificação atual para ele.


um pouco sobre terminologia

Como já sabemos, tree é um objeto que contém o estado do projeto em um determinado ponto no passado - quando um commit foi criado com essa árvore.


A pasta de trabalho é chamada de árvore de trabalho / cópia de trabalho / diretório de trabalho, o que é bastante lógico.


Também temos - área de preparação / índice - a área de mudanças preparadas. Mas, logicamente, essa também é uma árvore , ou melhor, o estado que é salvo ao confirmar como uma árvore. Portanto, parece-me que seria mais lógico chamar uma árvore em estágios.



árvore de confirmação git


Finalmente, podemos passar a descrever o comando git commit-tree que precisamos. Formalmente, este é um dos comandos de baixo nível, portanto raramente é mencionado e usado. Não consideraremos outros comandos de baixo nível associados a ele (como git write-tree, git-update-index, eles também são conhecidos como comandos de encanamento). Estamos interessados ​​apenas em uma consequência específica: com este comando, podemos copiar (reutilizar) facilmente a árvore de status do projeto de qualquer outra confirmação.


Olhe para o desafio dela


 git commit-tree 4c835c2 -m "Fixed bug" -p a8fc5e3 

 d9aded78bf57ca906322e26883644f5f36cfdca5 

O comando git commit-tree também confirma, mas de maneira de baixo nível. Aqui você deve especificar explicitamente a árvore (árvore) 4c835c2 já existente e um link para o commit pai a8fc5e3. E ele retorna o hash do novo commit d9aded7, e a posição do branch não muda (portanto, esse commit parece congelar no ar).



Parte prática


Exemplos de uso deste comando são demonstrados no seguinte repositório simples.



Ele contém três ramos:


master - filial principal
alpha - o ramo em que trabalhamos e somos
beta - um ramo que estava anteriormente parado no mestre


Todas as ações são fáceis de repetir localmente, para isso basta clonar o repositório, entrar no ramo alfa e depois executar os comandos dos exemplos. Esse estado inicial é comum a todos os exemplos.


 git clone https://github.com/capslocky/git-commit-tree-example.git cd ./git-commit-tree-example/ git checkout alpha 

sob janelas

Todos os comandos, incluindo o script, também funcionam no Windows. Você só precisa abrir o terminal bash na pasta do projeto, por exemplo, assim


 "C:\Program Files\Git\git-bash.exe" --cd="D:\path\project" 


1. Sincronização com outra ramificação


Desafio:
Sincronize o status do projeto na ramificação alfa com a ramificação beta . Ou seja, você precisa criar uma nova confirmação na ramificação alfa para que o estado do projeto se torne exatamente o mesmo que na ramificação beta .


Especificamente, é improvável que essa tarefa ocorra, mas esse é o caso mais adequado para demonstrar a abordagem.


A solução mais simples é pegar a árvore existente para a qual o ramo beta aponta e apenas apontá-lo a partir do novo commit para o ramo alfa. Como este é o primeiro exemplo, toda a sua lógica é considerada em detalhes suficientes.


Primeiro, encontre o hash de confirmação apontado pelo ramo beta:


 git rev-parse origin/beta 

 280c30ff81a574f8dd41721726cf60b22fb2eced 

280c30f - apenas pegue os primeiros caracteres


Agora encontre o hash de sua árvore exibindo o conteúdo do commit através do arquivo git cat:


 git cat-file -p 280c30f 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent 560b449675513bc8f8f4d6cda56a922d4e36917a author Baur <atanov...@gmail.com> 1540619512 +0600 committer Baur <atanov...@gmail.com> 1540619512 +0600 Added info about windows 

3c1afe7 - esta é a árvore que precisamos


E agora criaremos um commit apontando para esta árvore e, com o commit pai, indicaremos o commit atual:


 git commit-tree 3c1afe7 -m "Synced with branch 'beta'" -p HEAD 

 eb804d403d4ec0dbeee36aa09da706052a7cc687 

É isso aí, o commit foi criado, a equipe recebeu seu hash. Além disso, esse valor sempre será único, porque é calculado não apenas da árvore, mas também do autor e do tempo. O commit em si é congelado no ar, desde que não entre em nenhum dos galhos. É suficiente pegarmos os primeiros caracteres: eb804d4 , esse valor , exclusivo para cada caso, designarei como xxxxxxx . Vamos olhar para o seu conteúdo:


 git cat-file -p xxxxxxx 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent 64fafc79e8f6d22f5226490daa5023062299fd6c author Peter <peter...@gmail.com> 1545230299 +0600 committer Peter <peter...@gmail.com> 1545230299 +0600 Synced with branch 'beta' 

Ótimo, ele tem a mesma árvore que o commit no ramo de origem / beta. E como esse commit é um descendente direto do branch atual, para incluí-lo no branch, basta fazer a junção de avanço rápido


 git merge --ff xxxxxxx 

 Updating 64fafc7..xxxxxxx Fast-forward Azure.txt | 3 --- Bill.txt | 6 +----- Linus.txt | 15 +++++++++++++++ 3 files changed, 16 insertions(+), 8 deletions(-) 

Feito. Agora, o estado do projeto na ramificação alfa é exatamente o mesmo que na ramificação beta. [update] E se você observar o que esse commit mudou, afinal, veremos: ele reverteu todos os seus commit (alterações) do ramo alfa e adicionou todos os commit (alterações) exclusivos do ramo beta, em relação ao commit ancestral comum.




2. Comparação de dois ramos


Desafio:
Compare o ramo alfa com o ramo beta .


O primeiro exemplo mostra que a confirmação criada mostra todas as alterações que são a diferença real entre as duas ramificações. Essa propriedade facilita a comparação de uma ramificação com outra. É suficiente criar um terceiro ramo temporário e fazer um commit semelhante nele.


Então, primeiro, retorne a ramificação alfa ao seu estado original


 git reset --hard origin/alpha 

Vamos criar uma ramificação temporária na atual e permanecer nela


 git checkout -b temp 

E resta fazer o mesmo que no exemplo anterior. Mas desta vez encontraremos uma linha. Para fazer isso, usamos a sintaxe especial para acessar a origem da árvore de confirmação / beta ^ {tree} ou a mesma 280c30f ^ {tree} .


 git merge --ff $(git commit-tree origin/beta^{tree} -m "Diff with branch 'beta'" -p HEAD) 

Feito, essencialmente nós nos materializamos como um diff de confirmação entre dois ramos


 git show 

 git diff alpha origin/beta 

Obviamente, podemos criar uma confirmação "comparativa" para quaisquer duas confirmações (estados) no repositório.




3. Filial Reversa


Desafio:
Reverta as últimas confirmações.


Vamos voltar para o ramo alfa e excluir o ramo temporário


 git checkout alpha git branch -D temp 

Suponha que precisamos reverter os dois últimos commits no ramo alfa. Existem duas maneiras clássicas de fazer isso:


  1. Execute git revert duas vezes - por confirmação
  2. git reset, ou seja, redefinir a posição do ramo

Mas você pode fazer isso de uma terceira maneira:


 git merge --ff $(git commit-tree 7a714bf^{tree} -m "Reverted to commit 7a714bf" -p HEAD) 

Isso adicionará um novo commit que reverte as alterações dos dois commit anteriores. Diferentemente do primeiro método, apenas uma confirmação é criada, mesmo se você precisar reverter as últimas dez confirmações. E a diferença entre o método com git reset é que não lançamos esses commits do próprio branch.


Além disso, se você precisar retornar o estado original da ramificação, isso poderá ser feito da mesma maneira


 git merge --ff $(git commit-tree 64fafc7^{tree} -m "Reverted back to commit 64fafc7" -p HEAD) 

Ao mesmo tempo, esses dois commits permanecerão no histórico do branch, segundo o qual será visto que ele foi revertido e retornado.




4. Reverso parcial


Desafio:
Reverter as alterações em alguns arquivos nas últimas confirmações.


Novamente, retorne a ramificação alfa ao seu estado original


 git reset --hard origin/alpha 

A ramificação alfa contém 3 confirmações, em cada uma das alterações feitas no arquivo Bill.txt, na última confirmação, o arquivo Azure.txt também é adicionado. Suponha que precisamos reverter as alterações no arquivo Bill.txt nos últimos 2 commit, sem tocar em nenhum outro arquivo.


Primeiro, reverta todos os arquivos 2 confirmados


 git merge --ff $(git commit-tree 7a714bf^{tree} -m "any text" -p HEAD) 

Em seguida, retorne a ramificação para a confirmação anterior, mas sem tocar no estado do projeto no disco


 git reset HEAD~1 

E agora é suficiente fazer o zasteydit dos arquivos necessários e confirmar, e outras alterações podem ser descartadas.


 git add Bill.txt git commit -m "Reverted file Bill.txt to 7a714bf" git reset --hard HEAD 



5. Mesclagem artificial


Desafio:
Surge um ramo para outro, obtendo um resultado predeterminado.


Imagine essa situação. Um bug crítico foi detectado na produção e, como sempre, precisa ser corrigido com urgência. No entanto, não está claro quanto tempo levará para estudá-lo e fazer o hotfix correto; portanto, um hotfix temporário foi feito rapidamente, o que isolou a interação com o módulo do problema. Portanto, na ramificação mestre, uma confirmação aparece com esse patch temporário e, depois de algum tempo em vez dele no master, você precisa interromper um hotfix já desenvolvido.


Portanto, precisamos mesclar o ramo alfa para mestre, mas isso não deve ser uma mesclagem tradicional, quando todas as alterações exclusivas do ramo alfa forem adicionadas ao mestre de cima e ocorrer um conflito, e devemos substituir completamente o mestre pelo ramo alfa.


Para começar, lembre-se de que se trata a consolidação de mesclagem - na verdade, é a mesma consolidação comum, mas tem apenas duas confirmações pai, isso fica claramente visível se você olhar para o conteúdo (como a árvore é formada é uma questão separada) . E quem é determinado por quem é simples - o primeiro commit pai é considerado o principal.


 git cat-file -p 7229df8 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a parent fd54ab7dde87593b9892b6d1ffbf1afd39ba6f9e parent 280c30ff81a574f8dd41721726cf60b22fb2eced author Baur <atanov...@gmail.com> 1540619579 +0600 committer Baur <atanov...@gmail.com> 1540619592 +0600 Merge branch 'beta' into 'master' 

Redefina a ramificação alfa atual e mude para master


 git reset --hard origin/alpha git checkout master 

E agora a mesma equipe, mas com dois pais confirma


 git merge --ff $(git commit-tree alpha^{tree} -m "Merge 'alpha' into 'master', but take 'alpha' tree" -p HEAD -p alpha) 

Concluído, preparamos a ramificação alfa no mestre e não tivemos que excluir o código temporário e resolver conflitos, pois nesse caso, apenas tivemos que reescrever as alterações mais recentes.



Na verdade, não é tão estranho criar uma mesclagem com uma árvore que é copiada de outra confirmação. Tais situações podem surgir porque o git é uma ferramenta muito flexível que permite implementar uma variedade de abordagens para trabalhar com filiais e repositórios. Ainda assim, o exemplo mais comum estava em nosso repositório desde o início - tente analisar você mesmo ou abrir um spoiler para ler a explicação.


spoiler

Vamos prestar atenção em como o ramo beta foi estrangulado novamente para dominar. Durante o tempo em que duas confirmações apareceram, não havia novas confirmações no próprio ramo mestre. Isso significa que, com a mesclagem beta no mestre, quaisquer conflitos são excluídos devido a alterações simultâneas.




Se nós fizemos o git merge beta, ocorrerá a mesclagem de avanço rápido (comportamento padrão ), ou seja, o ramo mestre permaneceria no mesmo commit que o ramo beta e não haveria nenhum commit de mesclagem. Seria assim:



Mas aqui a fusão sem avanço rápido foi feita usando o comando git merge beta --no-ff. Ou seja, forçamos a criação do commit de mesclagem, embora não fosse necessário. E como o estado final desejado do projeto para a mesclagem futura era conhecido - essa é uma árvore beta, o git simplesmente copiou o link dessa árvore para um novo commit:


 git cat-file -p origin/beta 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent 560b449675513bc8f8f4d6cda56a922d4e36917a author Baur <atanov...@gmail.com> 1540619512 +0600 committer Baur <atanov...@gmail.com> 1540619512 +0600 Added info about windows 

 git cat-file -p 7229df8 

 tree 3c1afe75f54518dbd82ea7a4e3c4ff50389a573a <--- parent fd54ab7dde87593b9892b6d1ffbf1afd39ba6f9e parent 280c30ff81a574f8dd41721726cf60b22fb2eced author Baur <atanov...@gmail.com> 1540619579 +0600 committer Baur <atanov...@gmail.com> 1540619592 +0600 Merge branch 'beta' into 'master' 


6a Método Rebase via mesclagem - descrição


Desafio:
É necessário criar uma ramificação de rebase "pesada" (muitos conflitos em diferentes confirmações).


Existe um tema holivar tão clássico no git - rebase vs merge. Mas eu não vou holivarit. Pelo contrário, vou falar sobre como eles podem ser feitos amigos no contexto desta tarefa.


Em geral, o git foi projetado especificamente para que possamos efetivamente fazer a mesclagem. E quando cheguei ao projeto em que o fluxo de trabalho se baseia em rebase, a primeira vez que me senti desconfortável e incomum, até desenvolver técnicas que simplificaram meu trabalho diário com o git. Um deles é o meu método original para fazer rebase pesada.


Portanto, precisamos refazer a ramificação alfa no desenvolvimento, para que mais tarde fique manchada tão bem quanto a ramificação beta. Se começarmos a rebase como de costume, o primeiro e o último commit produzirão dois conflitos diferentes em dois lugares diferentes. Mas se, em vez de refazer, apenas fizermos uma mesclagem, haveria apenas um conflito em um lugar em uma consolidação de mesclagem.


Se você quer ter certeza disso, ofereço equipes prontas sob o spoiler.


Texto oculto

Retorne as ramificações ao seu estado original


 git checkout master git reset --hard origin/master git checkout alpha git reset --hard origin/alpha 

Crie e permaneça no ramo alfa-rebase-conflitos e rebase no mestre


 git checkout -b alpha-rebase-conflicts git rebase master 

Haverá conflitos em várias confirmações, incluindo um conflito fantasma.


Agora vamos tentar a mesclagem, volte para a ramificação alfa e exclua a ramificação para a rebase.


 git checkout alpha git branch -D alpha-rebase-conflicts 

Alterne para mestre e faça a mesclagem


 git checkout master git merge alpha 

Haverá apenas um conflito simples, nós o corrigimos e


 git add Bill.txt git commit -m "Merge branch 'alpha' into 'master'" 

Marge concluída com sucesso.


Os conflitos de Git são uma parte natural de nossas vidas, e este exemplo simples mostra que a fusão é definitivamente mais conveniente do que a recuperação a esse respeito. Em um projeto real, essa diferença é medida por uma quantidade muito maior de tempo e nervos gastos. Portanto, por exemplo, há uma recomendação ambígua para compactar todas as confirmações de uma ramificação de recurso em uma confirmação antes da mesclagem.


A idéia desse método é fazer uma mesclagem oculta temporária na qual resolveremos todos os conflitos de uma só vez. Lembre-se do resultado (árvore). Em seguida, execute a reorganização usual, mas com a opção "resolver automaticamente conflitos, escolhendo nossas alterações". E no final, adicione uma confirmação adicional à ramificação, que restaurará a árvore correta.


Vamos começar. Novamente, retorne os dois ramos ao seu estado original.


 git checkout master git reset --hard origin/master git checkout alpha git reset --hard origin/alpha 

Vamos criar uma temperatura de ramificação temporária na qual faremos a mesclagem.


 git checkout -b temp git merge origin/master 

O conflito.


Vamos resolver um conflito simples no arquivo Bill.txt como de costume (em qualquer editor).
Observe que há apenas um conflito, e não dois, como no rebase.


 git add Bill.txt git commit -m "Merge branch 'origin/master' into 'temp'" 

Retornamos à ramificação alfa, fazemos uma nova recuperação com a resolução automática de todos os conflitos a nosso favor, trazemos a ramificação temporária para o estado e excluímos a ramificação temporária em si.


 git checkout alpha git rebase origin/master -X theirs git merge --ff $(git commit-tree temp^{tree} -m "Fix after rebase" -p HEAD) git branch -D temp 


Por fim, junte lindamente o alfa no mestre.


 git checkout master git merge alpha --no-ff --no-edit 


Observe que mestre, alfa e ramificação temporária remota apontam para a mesma árvore, embora sejam três confirmações diferentes.


Contras deste método:


  • Não há correção manual de cada confirmação de conflito - os conflitos são resolvidos automaticamente. Esse commit intermediário pode não ser compilado.
  • Adicionado (mas nem sempre) um commit extra em cada rebase

Prós:


  • Corrigimos apenas conflitos reais (sem conflitos fantasmas)
  • Todos os conflitos são corrigidos apenas uma vez.
  • Os dois primeiros pontos economizam tempo
  • Um histórico completo de confirmações e todas as alterações são salvas (por exemplo, você pode fazer a escolha certa)
  • O método é implementado como um script e sempre pode ser usado, se necessário, para rebase (não requer nenhum conhecimento sobre árvores e assim por diante)


6b Método Rebase via mesclagem - script


O script está publicado aqui: https://github.com/capslocky/git-rebase-via-merge


Vamos verificar o seu trabalho no nosso exemplo. Novamente, retorne os dois ramos ao seu estado original


 git checkout master git reset --hard origin/master git checkout alpha git reset --hard origin/alpha 

Faça o download do script e torne-o executável


 curl -L https://git.io/rebase-via-merge -o ~/git-rebase-via-merge.sh chmod +x ~/git-rebase-via-merge.sh 

janelas

O arquivo aparecerá aqui: C: \ Users \ user-name \ git-rebase-via-merge.sh


Altere a ramificação padrão para a qual você precisa refazer a redefinição. No nosso caso, precisamos de origem / mestre


 nano ~/git-rebase-via-merge.sh 

 default_base_branch='origin/master' 

Vamos também criar e permanecer em um ramo temporário para não tocar no próprio ramo alfa


 git checkout -b alpha-rebase-test 

E agora você pode executar o script (em vez da origem / mestre tradicional do git rebase)


 ~/git-rebase-via-merge.sh 


resultado do script
 $ ~/git-rebase-via-merge.sh This script will perform rebase via merge. Current branch: alpha-rebase-test (64fafc7) Base branch: origin/master (9c6b60a) Continue (c) / Abort (a) c Auto-merging Bill.txt CONFLICT (content): Merge conflict in Bill.txt Automatic merge failed; fix conflicts and then commit the result. You have at least one merge conflict. Fix all conflicts in the following files, stage them up and type 'c': Bill.txt Continue (c) / Abort (a) c [detached HEAD 785d49e] Hidden temp commit to save result of merging 'origin/master' into 'alpha-rebase-test' as detached head. Merge succeeded on hidden commit: 785d49e Starting rebase automatically resolving any conflicts in favor of current branch. First, rewinding head to replay your work on top of it... Auto-merging Bill.txt [detached HEAD a680316] Added history of windows Author: Baur <atanov...@gmail.com> Date: Sat Oct 27 11:45:50 2018 +0600 1 file changed, 6 insertions(+), 3 deletions(-) Committed: 0001 Added history of windows Auto-merging Bill.txt [detached HEAD dcd34a8] Replaced history of windows Author: Baur <atanov...@gmail.com> Date: Sat Oct 27 11:55:42 2018 +0600 1 file changed, 4 insertions(+), 5 deletions(-) Committed: 0002 Replaced history of windows Auto-merging Bill.txt [detached HEAD 8d6d82c] Added file about Azure and info about Windows 10 Author: Baur <atanov...@gmail.com> Date: Sat Oct 27 12:06:27 2018 +0600 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 Azure.txt Committed: 0003 Added file about Azure and info about Windows 10 All done. Restoring project state from hidden merge with single additional commit. Updating 8d6d82c..268b320 Fast-forward Bill.txt | 4 ++++ 1 file changed, 4 insertions(+) Done. 


 ~/git-rebase-via-merge.sh origin/develop 

, ours / theirs :


ours — (HEAD)
theirs — (, origin/develop)


rebase — .



7.


git .


.


 git config alias.copy '!git merge --ff $(git commit-tree ${1}^{tree} -p HEAD -m "Tree copy from ${1}")' 

git copy xxx, xxx — .


 git copy xxx 


 git merge --ff $(git commit-tree xxx^{tree} -p HEAD -m "Tree copy from xxx") 


 git copy a8fc5e3 

 git copy origin/beta 

 git copy HEAD~3 

git amend.


 git commit --amend -m "Just for test" 

:


 git commit --amend 



, , . , . — . , , . . " " " " . ( , devops), , .

Source: https://habr.com/ru/post/pt433748/


All Articles