Digamos que eu tenho o seguinte repositório local com uma árvore de confirmação como esta:
master --> a
\
\
develop c --> d
\
\
feature f --> g --> h
master
é meu, este é o código de lançamento estável mais recente , develop
é meu é o 'próximo' código de lançamento e feature
é um novo recurso que está sendo preparadodevelop
.
O que eu quero poder fazer no meu repo remoto usando ganchos é que os impulsos feature
sejam recusados, a menos que o commit f
seja um descendente direto do develop
HEAD. ou seja, a aparência de árvores cometer assim porque recurso tem sido git rebase
em d
.
master --> a
\
\
develop c --> d
\
\
feature f --> g --> h
Então é possível:
- Identifique o ramo pai de
feature
? - Identifique a confirmação no ramo pai da qual
f
é descendente?
A partir daí, eu verificaria o que é HEAD da ramificação pai e veria se o f
predecessor corresponde à HEAD da ramificação pai, para determinar se o recurso precisa ser reformulado.
Respostas:
Supondo que o repositório remoto tenha uma cópia do ramo de desenvolvimento (sua descrição inicial o descreve em um repositório local, mas parece que também existe no remoto), você deve conseguir o que eu acho que deseja, mas a abordagem é um pouco diferente do que você imaginou.
A história do Git é baseada em um DAG de confirmações. Ramos (e “refs” em geral) são apenas rótulos transitórios que apontam para confirmações específicas no DAG de confirmação em crescimento contínuo. Como tal, o relacionamento entre ramificações pode variar ao longo do tempo, mas o relacionamento entre confirmações não.
Parece que
baz
é baseado em (uma versão antiga do)bar
? Mas e se excluirmosbar
?Agora parece que
baz
é baseadofoo
. Mas a ancestralidade debaz
não mudou, apenas removemos um rótulo (e o commit dangling resultante). E se adicionarmos um novo rótulo em4
?Agora parece que
baz
é baseadoquux
. Ainda assim, a ancestralidade não mudou, apenas os rótulos mudaram.Se, no entanto, perguntássemos "é comprometer
6
um descendente de confirmar3
?" (assumindo3
e6
com nomes completos de confirmação do SHA-1), a resposta seria "sim", independentemente de os rótulosbar
equux
estarem presentes.Portanto, você pode fazer perguntas como "o push enviado é descendente da ponta atual do ramo de desenvolvimento ?", Mas não é possível perguntar com segurança "qual é o ramo pai do commit enviado?".
Uma pergunta principalmente confiável que parece se aproximar do que você deseja é:
O que poderia ser implementado como:
Isso cobrirá parte do que você deseja restringir, mas talvez nem tudo.
Para referência, aqui está um histórico de exemplo estendido:
O código acima poderia ser usado para rejeitar
H
eS
ao aceitarH'
,J
,K
, ouN
, mas seria também aceitarL
eP
(eles envolvem fusões, mas eles não se fundem a ponta de desenvolver ).Para também rejeitar
L
eP
, você pode alterar a pergunta e fazerfonte
develop > release > feature
, eu voltaria a desenvolver e requer conhecer os pais. A solução para o meu problema era stackoverflow.com/a/56673640/2366390Uma reformulação
Outra maneira de formular a pergunta é "Qual é o commit mais próximo que reside em uma ramificação que não seja a ramificação atual e qual ramificação é essa?"
Uma solução
Você pode encontrá-lo com um pouco de magia da linha de comando
Com awk :
Veja como funciona:
E o resultado
Executando o código acima em
Dará a você
develop
se você executá-lo de H emaster
se você executá-lo de I.O código está disponível como uma essência
fonte
cannot handle more than 25 refs
ack
não está disponível no Mac (alguém sugeriu a substituiçãoack
comgrep
)git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'
git show-branch | sed "s/].*//" | grep "\*" | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed "s/^.*\[//"
parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"
funciona para mimVocê também pode tentar:
fonte
git log --graph --decorate --simplify-by-decoration
onde--graph
é opcional.git log --graph --decorate --simplify-by-decoration --oneline
pai git
Você pode simplesmente executar o comando
git parent
para encontrar o pai da ramificação, se você adicionar a resposta de @Joe Chrysler como um alias do git . Isso simplificará o uso.
Abra o arquivo gitconfig localizado em
"~/.gitconfig"
usando qualquer editor de texto. (Para linux). E para Windows, o caminho ".gitconfig" geralmente está localizado emc:\users\your-user\.gitconfig
Adicione o seguinte comando de alias no arquivo:
Salve e saia do editor.
Execute o comando
git parent
É isso aí!
fonte
cannot handle more than 25 refs
exceção.Eu tenho uma solução para o seu problema geral (determine se
feature
é descendente da ponta dodevelop
), mas ele não funciona usando o método descrito.Você pode usar
git branch --contains
para listar todos os ramos descendentes da ponta do edevelop
, em seguida, usargrep
para garantir quefeature
esteja entre eles.Se estiver entre eles, imprimirá
" feature"
na saída padrão e terá um código de retorno 0. Caso contrário, não imprimirá nada e terá um código de retorno 1.fonte
<branch>
, onde i realizada:git checkout -b <branch-2>
a partir de ... Esta é a resposta! Não há necessidade de grep, realmente.git branch --contains <branch>
Isso está funcionando bem para mim.
Respostas de cortesia de: @droidbot e @Jistanidiot
fonte
*
não é uma regex adequada para passar ao grep. Deve usargrep -F '*'
ou emgrep '\*'
vez disso. Boa solução caso contrário.Como nenhuma das respostas acima funcionou em nosso repositório, quero compartilhar do meu jeito, usando as últimas mesclagens em
git log
:Coloque-o em um script chamado
git-last-merges
, que também aceita um nome de filial como argumento (em vez da filial atual), além de outrosgit log
argumentosA partir da saída, podemos detectar manualmente os ramos principais com base em convenções de ramificação próprias e no número de mesclagens de cada ramo.
EDIT: Se você usa
git rebase
frequentemente em ramos secundários (e as mesclagens são encaminhadas com frequência, para que não haja muitos commit de mesclagem), essa resposta não funcionará bem, então escrevi um script para contar antecipadamente os commits (normal e mesclado) , e confirmações por trás (não deve haver nenhuma fusão por trás na ramificação pai) em todas as ramificações em comparação com a ramificação atual. Basta executar este script e deixe-me saber se funciona para você ou nãofonte
rebase
frequência (e as mesclagens sãofast-forward
feitas com frequência). Vou editar minha resposta se encontrar uma solução melhor.git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 1 | cut -d ' ' -f 8
Uma solução
A solução baseada na
git show-branch
não muito trabalho para mim (veja abaixo), para que eu tenha isso combinado com a base emgit log
e acabamos com isto:Limitações e advertências
log
comandomaster
edevelop
resultados (principalmente) em<SHA> Initial commit
Os resultados
Apesar da existência da ramificação local (por exemplo, apenas
origin/topic
está presente desde que o commitO
foi retirado diretamente pelo seu SHA), o script deve ser impresso da seguinte maneira:G
,H
,I
(filialhotfix
) →master
M
,N
,O
(filialfeature/a
) →develop
S
,T
,U
(filialfeature/c
) →develop
P
,Q
,R
(filialfeature/b
) →feature/a
J
,K
,L
(filialdevelop
) →<sha> Initial commit
*B
,D
,E
,F
(filialmaster
) →<sha> Initial commit
* - ou
master
sedevelop
os commits estiverem no topo da HEAD do mestre (~ o mestre seria rápido em desenvolver)Por que o show-branch não funcionou para mim
A solução baseada em
git show-branch
provou não ser confiável para mim nas seguintes situações:grep '\*' \
por `grep '!' \ - e isso é apenas o começo de todos os problemasmaster
edevelop
resultados emdevelop
e `` respectivamentemaster
ramificações (hotfix/
ramificações) acabam com odevelop
pai como pai, já que o pai mais próximomaster
foi marcado com e!
não*
por um motivo.fonte
"!git log --decorate --simplify-by-decoration --oneline | grep -v '(HEAD' | head -n1 | sed 's/.* (\\(.*\\)) .*/\\1/' | sed 's/\\(.*\\), .*/\\1/' | sed 's/origin\\///'"
Lembre-se de que, conforme descrito em "Git: Localizando a ramificação de uma confirmação" , você não pode identificar facilmente a ramificação em que a confirmação foi feita (as ramificações podem ser renomeadas, movidas, excluídas ...), mesmo que isso
git branch --contains <commit>
seja um começo.git branch --contains <commit>
não listar ofeature
branch e listdevelop
branch,/refs/heads/develop
Se os dois confirmarem a correspondência de ID, você estará pronto (isso significaria que a
feature
ramificação tem sua origem no HEAD dedevelop
).fonte
A mágica da linha de comando de JoeChrysler pode ser simplificada. Aqui está a lógica de Joe - por uma questão de brevidade, introduzi um parâmetro nomeado
cur_branch
no lugar da substituição de comando`git rev-parse --abbrev-ref HEAD`
nas duas versões; que podem ser inicializados da seguinte maneira:Então, aqui está o pipeline de Joe:
Podemos realizar a mesma coisa que todos os cinco filtros de comando individuais em um
awk
comando relativamente simples :Isso se divide assim:
dividir a linha em campos em
]
,^
,~
e[
caracteres.Encontre linhas que contenham um asterisco
... mas não o nome do ramo atual
Quando você encontrar essa linha, imprima seu segundo campo (ou seja, a parte entre a primeira e a segunda ocorrências de nossos caracteres separadores de campo). Para nomes simples de ramificações, será exatamente o que está entre colchetes; para refs com saltos relativos, será apenas o nome sem o modificador. Portanto, nosso conjunto de separadores de campo lida com a intenção de ambos os
sed
comandos.Então saia imediatamente. Isso significa que ele apenas processa a primeira linha correspondente, portanto não precisamos canalizar a saída
head -n 1
.fonte
Aqui está uma implementação do PowerShell da solução de Mark Reed:
fonte
Não estou dizendo que essa é uma boa maneira de resolver esse problema, no entanto, isso parece funcionar para mim.
git branch --contains $(cat .git/ORIG_HEAD)
A questão é que criar um arquivo está espreitando o funcionamento interno do git, portanto, isso não é necessariamente compatível com versões anteriores (ou com versões anteriores).fonte
Implementação de plataforma cruzada com Ant
fonte
@ Mark Reed: Você deve adicionar que a linha de confirmação não deve conter apenas um asterisco, mas começar com um asterisco! Caso contrário, as mensagens de confirmação que contêm um asterisco também serão incluídas nas linhas correspondentes. Então deve ser:
git show-branch -a | awk -F'[]^~[]' '/^\*/ && !/'"$current_branch"'/ {print $2;exit}'
ou a versão longa:
fonte
Atinge os mesmos fins que a resposta de Mark Reed, mas usa uma abordagem muito mais segura que não se comporta mal em vários cenários:
-
não mostrar*
*
fonte
Qualquer pessoa que queira fazer isso atualmente - o aplicativo SourceTree da Atlassian mostra uma ótima representação visual de como seus ramos se relacionam, por exemplo, onde eles começaram e onde estão atualmente na ordem de confirmação (por exemplo, HEAD ou 4 confirma atrás, etc.) .
fonte
Se você usar a Árvore de fontes, veja os detalhes de confirmação> Pais> e verá os números de confirmação sublinhados (links)
fonte
Uma alternativa:
git rev-list master | grep "$(git rev-list HEAD)" | head -1
Obter o último commit que é meu ramo e
master
(ou qualquer ramo que você deseja especificar)fonte
Isso não funcionou para mim quando eu tinha feito algo como
develop > release-v1.0.0 > feature-foo
: voltaria a se desenvolver, observe que houve uma recuperação, não tenho certeza se isso está agravando meu problema ...O seguinte deu o hash de confirmação correto para mim
fonte