Como verificar se o branch remoto existe em um determinado repositório remoto?

105

Eu preciso fazer uma mesclagem de subárvore para um ramo específico, se ele existir em um determinado repositório remoto. O problema é que o repositório remoto não foi retirado localmente, então não posso usar git branch -r. Tudo o que tenho é um endereço remoto, algo assim https://github.com/project-name/project-name.git. Existe uma maneira de listar ramos remotos apenas por um endereço remoto? Não consegui encontrar nada útil :(

Keen
fonte

Respostas:

124
$ git ls-remote --heads [email protected]:user/repo.git branch-name

Caso branch-nameseja encontrado, você obterá a seguinte saída:

b523c9000c4df1afbd8371324083fef218669108        refs/heads/branch-name

Caso contrário, nenhuma saída será enviada.

Então, canalizar para wclhe dará 1ou 0:

$ git ls-remote --heads [email protected]:user/repo.git branch-name | wc -l

Alternativamente, você pode definir o --exit-codesinalizador no git ls-remotequal retornará o código de saída 2caso nenhuma referência correspondente seja encontrada. Esta é a solução mais idiomática. O resultado pode ser verificado diretamente em um teste de shell ou verificando a variável de status $?.

$ git ls-remote --exit-code --heads  [email protected]:user/repo.git branch-name
user487772
fonte
7
Usei git ls-remote --heads ${REPO} ${BRANCH} | grep ${BRANCH} >/dev/nullseguido porif [ "$?" == "1" ] ; then echo "Branch doesn't exist"; exit; fi
sibaz
1
Eu estava procurando por esta resposta limpa e precisa por algumas horas, brilhante.
medik
Você precisa especificar o nome do ramo como /refs/heads/branch-name. Caso contrário, o branch foo/branch-nameseria retornado mesmo quando não houvesse branch-name.
FuzzY
Parabéns pelo seu distintivo dourado de 'Grande Resposta'. :)
jmort253
4
Observação: se você não quiser especificar o URL do repo, pode especificar o nome remoto do repo, por exemplo:git ls-remote --heads origin branch-name
daveruinseverything
50
git ls-remote --heads https://github.com/rails/rails.git
5b3f7563ae1b4a7160fda7fe34240d40c5777dcd    refs/heads/1-2-stable
81d828a14c82b882e31612431a56f830bdc1076f    refs/heads/2-0-stable
b5d759fd2848146f7ee7a4c1b1a4be39e2f1a2bc    refs/heads/2-1-stable
c6cb5a5ab00ac9e857e5b2757d2bce6a5ad14b32    refs/heads/2-2-stable
e0774e47302a907319ed974ccf59b8b54d32bbde    refs/heads/2-3-stable
13ad87971cc16ebc5c286b484821e2cb0fc3e3b1    refs/heads/3-0-stable
3df6c73f9edb3a99f0d51d827ef13a439f31743a    refs/heads/3-1-stable
f4db3d72ea564c77d5a689b850751ce510500585    refs/heads/compressor
c5a809e29e9213102351def7e791c3a8a67d7371    refs/heads/deps_refactor
821e15e5f2d9ef2aa43918a16cbd00f40c221e95    refs/heads/encoding
8f57bf207ff4f28fa8da4544ebc573007b65439d    refs/heads/master
c796d695909c8632b4074b7af69a1ef46c68289a    refs/heads/sass-cleanup
afd7140b66e7cb32e1be58d9e44489e6bcbde0dc    refs/heads/serializers
Dogbert
fonte
Eu não sabia sobre o ls-remote também. Obrigado!
Keen
7
Eu precisava fazer um teste em um script bash e por isso estava realmente interessado apenas no código de saída, então fiz o seguinte em um clone local: git ls-remote --exit-code . origin/branch-name &> /dev/nullentão usado $?como operando de teste
Darren Bishop
5
@Darren, apenas usar o comando diretamente em uma condicional, como com if git ls-remote ...; then ...; fi, é menos sujeito a erros do que a verificação $?(que pode ser alterada por declarações de registro, armadilhas, etc).
Charles Duffy
Por que --heads?
Steve
@JohnLinux --headslista apenas ramos. use --tagspara listar apenas as tags.
rymo de
19

Outra maneira que você pode usar na pasta atual se for um repositório git para executar

git branch -a | egrep 'remotes/origin/${YOUR_BRANCH_NAME}$'
РАВИ
fonte
2
Use aspas duplas:git branch -a | egrep "remotes/origin/${YOUR_BRANCH_NAME}$"
Ivan
3
Isso não é ideal porque retornará verdadeiro mesmo se você corresponder apenas a parte de um nome de branch existente, mas não corresponder exatamente ao branch de destino. Portanto, isso não pode ser usado com segurança em um script para testar se o branch existe antes de fazer o check-out. Obrigado por compartilhar de qualquer maneira, pois achei útil. Pode ser corrigido assim:git branch -a | grep "\b${BRANCH}$"
EntangledLoops
2
git fetché necessário se usar git branch -apara que todas as referências remotas sejam buscadas primeiro. Caso contrário, use git ls-remoteconforme indicado por outros.
feliz
git branch -a --list '<pattern>'também é uma opção. Pipe para grep se precisar de um código de retorno para o seu script.
LOAS
17

Você também pode usar isto:

git show-branch remotes/origin/<<remote-branch-name>>

retorna o último commit e o valor de $? é 0, caso contrário, retorna "fatal: remotos de referência sha1 ruins / origin / <>" e valor de $? é 128

Ajo Paul
fonte
Isso não puxará branches do remoto antes de verificar, então você não obtém o estado remoto mais recente.
siemanko
11

Então, não há necessidade de passar manualmente o nome do repositório todas as vezes.

git ls-remote origin <branch>

Ao invés de

git ls-remote <full repo url> <branch>

Exemplo:

git ls-remote [email protected]:landmarkgroupme/in-store-application.git  uat_21dec

OU

git ls-remote origin uat_21dec

Ambos terão o mesmo resultado:

insira a descrição da imagem aqui

Mais sobre Origin : Git tem o conceito de "remotes", que são simplesmente URLs para outras cópias do seu repositório. Quando você clona outro repositório, o Git cria automaticamente um remoto chamado "origin" e aponta para ele. Você pode ver mais informações sobre o controle remoto digitando git remote show origin.

Amitesh Bharti
fonte
11

Todas as respostas aqui são específicas do shell do Linux, o que não ajuda muito se você estiver em um ambiente que não oferece suporte a esse tipo de operação - por exemplo, o prompt de comando do Windows.

Felizmente, git ls-remoteaceita um --exit-codeargumento que retorna 0 ou 2, dependendo se a ramificação existe ou não, respectivamente. Assim:

git ls-remote --exit-code --heads origin <branch-that-exists-in-origin>

retornará 0, e

git ls-remote --exit-code --heads origin <branch-that-only-exists-locally>

retornará 2.

Para PowerShell, você pode simplesmente usar a semântica de tratamento de veracidade integrada:

if (git ls-remote --heads origin <branch-that-exists-in-origin>) { $true } else { $false }

rende $true, enquanto:

if (git ls-remote --heads origin <branch-that-only-exists-locally>) { $true } else { $false }

rendimentos $false.

Ian Kemp
fonte
10

Você pode fazer algo assim no terminal Bash. Basta substituir os ecos pelos comandos que deseja executar.

if git ls-remote https://username:[email protected]/project-name/project-name.git | grep -sw "remote_branch_name" 2>&1>/dev/null; then echo "IT EXISTS..START MERGE" ; else echo "NOT FOUND" ; fi

Espero que ajude.

Sagunms
fonte
1
Eu gosto disso. outras respostas também têm ls-remote, o que eu gosto é do "se".
Stony
6
$ git ls-remote --heads origin <branch> | wc -l

funciona na maioria das vezes.

Mas não funcionará se o ramo corresponder parcialmente como abaixo,

$ git branch -a
creative/dev
qa/dev

$ git ls-remote --heads origin dev | wc -l
2

Usar

git ls-remote --heads origin <branch> | \
    cut -d$'\t' -f2 | \
    sed 's,refs/heads/,,' | \
    grep ^<branch>$ | wc -l

se você quiser uma maneira confiável.

Se você deseja usar no script e não deseja assumir origincomo remoto padrão, então

git ls-remote --heads $(git remote | head -1) "$branch" | \
    cut -d$'\t' -f2 | \
    sed 's,refs/heads/,,' | \
    grep ^"$branch"$ | wc -l

Deveria trabalhar.

Observe que git branch -a | grep ...não é confiável, pois pode demorar um pouco desde a última fetchexecução.

hIpPy
fonte
Para mim, esta é a resposta aceita, combinada com a de Amitesh (nome remoto abreviado), combinada com a de James Cache ( grep -x "$branch"é idêntico a grep ^"$branch"$). Embora em scripts eu prefiro a longo formulário muda: --line-regexp. Além disso, não há necessidade de fazer wc -l. Colocar uma saída vazia em um Bash é if [ -z ] efetivamente avaliada como verdadeira, então significa que a ramificação não existe. Isso economiza alguns milissegundos.
Amedee Van Gasse
1

Você pode adicionar o repositório que possui como remoto usando git remote add something https://github.com/project-name/project-name.gite, em seguida, fazer um git remote show somethingpara obter todas as informações sobre o remoto. Isso requer uma conexão de rede e é útil para uso humano.

Como alternativa, faça a git fetch something. Isso irá buscar todos os branches da chamada remota somethinge mantê-los em seu repositório local. Você pode então mesclá-los em sua filial local como desejar. Eu recomendo este caminho, pois se você finalmente decidir que precisa fazer a fusão, é isso que você precisa fazer.

OT: O uso de "verificado localmente" indica que você está abordando isso de um ponto de vista de sistema de controle de versão centralizado. Isso geralmente é um beco sem saída quando você está lidando com o git. Ele usa palavras como "checkout", etc. diferentemente de como os sistemas mais antigos faziam.

Noufal Ibrahim
fonte
Obrigado pelas explicações. Ainda não me acostumei com o git, e isso exige uma forma diferente de pensar.
Keen
1

Podes tentar

git diff --quiet @{u} @{0}

Aqui @{u}se refere a remote / upstream e @{0}se refere ao HEAD local atual (com a versão mais recente do git, @{0}pode ser abreviado como @). Se remoto não existir, ocorrerá um erro.

Com o git 2.16.2 (não tenho certeza de qual versão é a primeira a ter essa funcionalidade, por exemplo, git 1.7.1 não tem), você pode fazer

git checkout

Se existir uma filial remota, haverá alguma saída, como

Your branch is up to date with 'origin/master'

Caso contrário, não há saída.

nos
fonte
1

Retornará todos os branches (remotos ou locais) que contêm a consulta no nome.

git branch --all | grep <query>

alexoviedo999
fonte
0

Se os nomes de seus ramos forem muito específicos, você pode não precisar usar grep para correspondência simples de nomes de ramos:

git ls-remote --heads $(git remote | head -1) "*${BRANCH_NAME}*" | \
    cut -d$'\t' -f2 | \
    sed 's,refs/heads/,,' | \
    wc -l

que funciona para

BRANCH=master
BRANCH=mas
BRANCH=NonExistingBranch (returns 0)
BRANCH=ISSUE-123

Usamos id de problema exclusivo como nomes de branch e funciona bem.

Fabio
fonte
0

Eu só tentei isso:

git ls-remote --heads 2>/dev/null|awk -F 'refs/heads/' '{print $2}'|grep -x "your-branch"|wc -l

Isso retornará 1 se o branch "seu-branch" for encontrado e 0 caso contrário.

James Cache
fonte
0

Estou combinando algumas das respostas acima em um script:

BRANCHES=(develop master 7.0 7.0-master)
ORIGIN=bitbucket
REMOTE=github

for BRANCH in "${BRANCHES[@]}"; do
  BRANCH=$(git ls-remote --heads "${ORIGIN}" "${BRANCH}" \
      | cut --delimiter=$'\t' --fields=2 \
      | sed 's,refs/heads/,,' \
      | grep --line-regexp "${BRANCH}")
  if [ -n "${BRANCH}" ]
  then
    git branch --force "${BRANCH}" "${ORIGIN}"/"${BRANCH}"
    git checkout "${BRANCH}"
    git push "${REMOTE}" "${BRANCH}"
  fi
done

git push github --tags

Este script obterá 4 branches de um bitbucket remoto, e os enviará para um github remoto, e então enviará todas as tags para o github. Estou usando isso em um trabalho do Jenkins, é por isso que você não vê nenhum git fetchougit pull , isso já está feito na configuração do repositório de trabalhos do Jenkins.

Normalmente prefiro opções de formato longo em scripts. Eu poderia ter combinado git branche git checkoutusando git checkout -B.

Amedee Van Gasse
fonte