Executando verificação de segurança...
2

Git no macOS: "cannot lock ref" por causa de case sensitivity

Para quem é

Desenvolvedores usando macOS que enfrentam erros do Git ao fazer fetch/pull, como conflitos entre refs FIX/* e fix/* que não aparecem no Linux.

Sintoma

Erros semelhantes a:

error: cannot lock ref 'refs/remotes/origin/FIX/6357': is at <A> but expected <B>
! <hashA>...<hashB> FIX/6357 -> origin/FIX/6357  (unable to update local ref)

Causa (por que só acontece no macOS)

  • No macOS, o volume APFS padrão é case-insensitive: FIX/6357 e fix/6357 são tratados como o mesmo caminho.
  • No Linux (ex.: Ubuntu, ext4), o filesystem é case-sensitive: FIX/* e fix/* coexistem normalmente.
  • Quando o repositório remoto tem branches/refs que diferem apenas por maiúsculas/minúsculas, o Git no macOS tenta salvar caminhos que colidem e falha ao atualizar/lockar as refs.

Como resolver

Caminho definitivo (recomendado)

  • Trabalhar em um volume Case-Sensitive ou em ambiente Linux.
  1. Criar um disco virtual APFS Case-Sensitive e montar:
hdiutil create -size 50g -type SPARSEBUNDLE -fs 'Case-sensitive APFS' -volname DevCase ~/DevCase.sparsebundle
hdiutil attach ~/DevCase.sparsebundle
  1. Clonar e trabalhar dentro do volume:
mkdir -p /Volumes/DevCase/Projetos && cd /Volumes/DevCase/Projetos
git clone <SEU_REPO>
  1. Quando terminar:
hdiutil detach /Volumes/DevCase

Alternativa: usar Docker/VM Linux e manter o repositório dentro de um volume do container/VM (case-sensitive).

Workaround operacional (local)

Se você precisa continuar no volume case-insensitive, dá para mitigar filtrando do fetch as refs problemáticas (ex.: FIX/*) e limpando as refs locais conflitantes. No repositório local:

# 1) Não buscar mais branches em caixa alta FIX/*
git config --add remote.origin.fetch '^refs/heads/FIX/*'

# 2) Apagar as refs locais conflitantes
for ref in $(git for-each-ref --format='%(refname)' refs/remotes/origin/FIX); do
  git update-ref -d "$ref"
done

# 3) Atualizar normalmente
git fetch --all --prune --prune-tags
git pull --ff-only

Observações:

  • Isso não conserta o remoto; apenas evita o conflito local no macOS.
  • Se o time padronizar o nome das branches (ver abaixo), o problema deixa de ocorrer.

Higiene no repositório (recomendado para o time)

  • Padronize nomes de branches em minúsculas (ex.: use fix/1234 em vez de FIX/1234).
  • Evite criar branches que só diferem por maiúsculas/minúsculas.

Aliases recomendados (macOS)

Para agilizar o dia a dia, adicione ao seu ~/.zshrc:

# Fetch completo e limpo
alias gff='git fetch --all --prune --prune-tags'

# Pull seguro (fast-forward only)
alias gup='git pull --ff-only'

# Fetch + Pull na sequência
alias gfup='git fetch --all --prune --prune-tags && git pull --ff-only'

# Correção de refs conflitantes (FIX/* vs fix/*) + fetch/pull
gfix() {
  if ! git config --get-all remote.origin.fetch | grep -qx '^\^refs/heads/FIX/\*'; then
    git config --add remote.origin.fetch '^refs/heads/FIX/*'
  fi
  for ref in $(git for-each-ref --format='%(refname)' refs/remotes/origin/FIX); do
    git update-ref -d "$ref"
  done
  git fetch --all --prune --prune-tags
  git pull --ff-only
}

Uso sugerido:

# Quando notar o erro de "cannot lock ref" envolvendo FIX/*
gfix

# No dia a dia
gfup

FAQ rápido

  • Posso resolver com git config core.ignorecase? Não. Isso não “simula” case-sensitive, só influencia detecção de renomes.
  • Como desfazer o filtro do fetch? Use:
git config --unset-all remote.origin.fetch '^refs/heads/FIX/*'
  • Por que no Ubuntu não acontece? Porque o filesystem é case-sensitive; FIX/* e fix/* são caminhos diferentes.
Carregando publicação patrocinada...