6 pontos por GN⁺ 2023-11-03 | 1 comentários | Compartilhar no WhatsApp
  • Mesmo usando Git há muito tempo, há muita sobreposição e reutilização de termos, então memorizar comandos não basta para prever o comportamento real
  • Termos e símbolos como HEAD, heads, detached HEAD, ours/theirs, ../... mudam de significado conforme o contexto
  • index, staged e cached estão todos ligados a .git/index, mas reset, revert e restore, apesar dos nomes parecidos, afetam de formas diferentes o histórico de commits, a árvore de trabalho e os ponteiros de branch
  • O fato de main rastrear o remoto e um remote-tracking branch como origin/main são coisas diferentes, e checkout reúne em um só comando a troca de branch e a restauração de arquivos
  • Para entender Git, é preciso olhar não só para comandos isolados, mas também para o modelo interno em que branches, referências, commits, índice e estado de rastreamento remoto se encaixam

HEAD, branch e detached HEAD

  • No Git, heads se refere a branches, e internamente os branches ficam armazenados no diretório .git/refs/heads
    • O glossário oficial do Git distingue branch como todos os commits sobre ele e head como o commit mais recente, mas dá para ver isso como duas formas de olhar para o mesmo objeto
  • HEAD aponta para o branch atual e fica armazenado em .git/HEAD
    • A própria expressão “head é um branch, e HEAD é o branch atual” mostra bem como a terminologia do Git pode ser confusa
  • O estado de detached HEAD é quando HEAD aponta diretamente para um ID de commit, e não para um branch
    • Ao fazer checkout de uma tag, como a tag não é um branch, você pode entrar em detached HEAD
    • Nesse estado, git pull não funciona, e git push também não funciona a menos que seja feito de uma forma especial
    • git commit, git merge, git rebase e git cherry-pick funcionam, mas os novos commits podem ficar difíceis de encontrar porque não ficam ligados a nenhum branch
    • Você pode sair do detached HEAD criando um novo branch ou trocando para um branch existente

ours e theirs mudam entre merge e rebase

  • Na resolução de conflitos, git checkout --ours file.txt escolhe o arquivo do lado “ours”, mas a referência muda entre merge e rebase
  • No merge, o branch atual é ours, e o branch que está sendo incorporado é theirs
    • Exemplo: se você fizer git checkout merge-into-ours e depois git merge from-theirs, o branch atual será ours
  • No rebase, o branch atual é theirs, e o branch de destino do rebase é ours
    • Exemplo: se você fizer git checkout theirs e depois git rebase ours, o branch de destino será ours
  • Essa diferença tem relação com o fato de que git rebase main internamente faz merge repetido dos commits do branch atual sobre uma cópia do branch main
  • ourstheirs explica rapidamente os termos ours e theirs
    • No VSCode, “current change” e “incoming change” também podem confundir pelo mesmo motivo

Mensagens de estado remoto e fast-forward

  • Your branch is up to date with 'origin/main' não quer dizer que o main atual esteja no estado mais recente do remoto
    • Quer dizer apenas que o branch local é igual ao origin/main do momento do último git fetch ou git pull
    • Se o último fetch foi há 5 dias, então ele está “atualizado” segundo o estado de 5 dias atrás
  • O Git guarda no reflog informações sobre os fetches recentes, mas a mensagem de estado não mostra o horário “com base no último fetch”
  • can be fast-forwarded significa que o branch remoto está à frente do branch local e que não há commits locais extras, então dá para mover só o ponteiro para frente
    • Exemplo: se main é A-B-C e origin/main é A-B-C-D-E, então depois de git pull ambos viram A-B-C-D-E
    • Nesse caso não há possibilidade de conflito de merge
  • Quando fast-forward não é possível, é porque os dois branches divergiram
    • Exemplo: se main tem um commit X que origin/main não tem, e origin/main tem D e E que main não tem, então não dá para fazer fast-forward
    • Nessa situação o Git informa que os dois branches estão em estado de divergence e que cada lado tem uma quantidade diferente de commits

Sintaxe para selecionar commits: ^, ~, .., ...

  • HEAD^ e HEAD~ apontam ambos para o commit anterior imediato
    • HEAD^^^, HEAD~~~ e HEAD~3 apontam todos para o commit de 3 passos atrás
  • Em commits de merge, que têm múltiplos pais, o significado de HEAD^2 e HEAD^3 muda
    • HEAD^ é o primeiro pai
    • HEAD^2 é o segundo pai
    • HEAD^3 é o terceiro pai
    • HEAD~3 significa pai do pai do pai, então é diferente de HEAD^3
  • git log main..test e git log main...test também funcionam de forma diferente
    • main..test mostra os commits que existem só em test
    • test..main mostra os commits que existem só em main
    • main...test mostra juntos os commits exclusivos de cada lado
  • Em git diff, .. e ... são interpretados de forma diferente de git log
    • git diff test..main compara incluindo tanto as mudanças do lado test quanto do lado main
    • git diff test...main compara o ancestral comum com a ponta de main, mostrando diff de um lado só
  • A confusão com a notação de pontos também é tratada em pain in dots

reference, refspec, tree-ish

  • No Git, reference é usada com vários sentidos
    • Branches e tags como main e v0.2
    • HEAD, que aponta para o branch atual
    • Expressões como HEAD^^^, que são interpretadas como IDs de commit
  • A documentação do Git chama com mais rigor expressões como HEAD^^^ de “revision parameters”, mas no uso cotidiano elas podem ser tratadas como referências
  • Uma symbolic reference é uma referência que aponta para outra referência, como HEAD
    • HEAD é um conceito central que afeta bastante o comportamento dos comandos principais do Git
  • As configurações de remoto em .git/config incluem um refspec
    • Exemplo: +refs/heads/main:refs/remotes/origin/main
    • Em muitos casos, usa-se o valor padrão criado por git clone ou git remote add
  • tree-ish se refere ao tipo de objeto que pode ocupar o lugar de THING em git checkout THING .
    • ID de commit
    • Referência de commit como main, HEAD^^ ou v0.3.2
    • Um subdiretório dentro de um commit, como main:./docs
    • Na prática, muitas vezes basta entender como “um commit ou uma referência de commit”

index, staged, cached

  • index, staged e cached estão todos relacionados a .git/index
    • .git/index é o arquivo usado quando você faz stage das mudanças com git add
  • Existem vários termos espalhados por comandos diferentes para se referir à mesma coisa
    • git diff --cached
    • git rm --cached
    • git diff --staged
    • .git/index
  • Mas as flags --index e --cached nem sempre significam a mesma coisa
    • Um texto de Junio Hamano, maintainer principal do Git, explica as diferenças em detalhe
  • Por motivos de desempenho, o index também lista arquivos untracked, mas em geral staging area não é entendida como incluindo arquivos untracked

reset, revert, restore

  • reset, revert e restore parecem palavras parecidas, mas no Git afetam coisas diferentes
  • git revert COMMIT cria um novo commit no branch atual que faz o oposto de COMMIT
    • Se COMMIT adicionou 3 linhas, o novo commit remove essas 3 linhas
  • git reset --hard COMMIT força o branch atual a voltar para o estado de COMMIT
    • É uma operação muito perigosa, porque apaga as mudanças novas feitas depois de COMMIT
  • git restore --source=COMMIT PATH restaura os arquivos de PATH para o estado que tinham em COMMIT
    • Não muda outros arquivos nem o histórico de commits
  • git reset --hard e git restore . sozinhos costumam se comportar de forma parecida, mas git reset --hard COMMIT e git restore --source COMMIT . funcionam de forma completamente diferente

track, remote-tracking branch, untracked files

  • O Git usa a palavra track de três formas diferentes
    • Untracked files: em git status significa arquivos que o Git não gerencia e que não estão incluídos em commit nenhum
    • Um remote-tracking branch como origin/main é uma referência local com o ID do commit para o qual o main do remoto origin apontava no momento do último git pull ou git fetch
    • Um branch local pode ser configurado para rastrear um branch remoto, como em “branch foo set up to track remote branch bar from origin”
  • Dizer que main é um branch que rastreia um remoto e dizer que origin/main é um remote-tracking branch são coisas diferentes
  • main é um branch de verdade, então você pode fazer commits e merges nele
    • Se em .git/config ele estiver configurado para rastrear o main remoto, git pull e git push ficam mais práticos de usar
  • origin/main, apesar do nome “remote-tracking branch”, não é um branch comum
    • Você não pode fazer commit diretamente nele
    • Ele só é atualizado quando git pull ou git fetch trazem o estado mais recente do main remoto

checkout, reflog, merge/rebase/cherry-pick

  • git checkout coloca duas operações diferentes no mesmo comando
    • git checkout BRANCH troca de branch
    • git checkout file.txt descarta mudanças não staged em file.txt
  • Para reduzir essa confusão, o Git separou essas funções em git switch e git restore, mas o checkout antigo ainda pode ser usado
  • reflog significa reference log e é o registro do que uma referência apontou no passado
    • Referência é um termo amplo que inclui branches, tags e HEAD
    • O reflog pode ajudar a sair de situações muito ruins no Git, como apagar por engano um branch importante
  • merge, rebase e cherry-pick combinam commits de formas diferentes
    • merge cria um novo commit que junta dois branches
    • rebase copia, um por um, os commits do branch atual sobre o branch de destino
    • cherry-pick é parecido com rebase, mas com sintaxe diferente, e copia commits para o branch atual
  • git rebase --onto main otherbranch mybranch pode ser usado para mover só parte dos commits de mybranch para cima de main
    • Na estrutura de exemplo, isso serviria quando você quiser fazer rebase apenas de F e G sobre main
    • A sintaxe é difícil de memorizar porque envolve nomes de três branches

commit e outros termos confusos

  • commit é usado no Git tanto como verbo quanto como substantivo
    • Verbo: “faça commit com frequência”
    • Substantivo: o commit mais recente de main
  • Um commit do Git pode ser visto de três formas
    • Como um snapshot do estado atual de todos os arquivos
    • Como um diff em relação ao commit pai
    • Como o histórico de todos os commits anteriores
  • Cada comando lida com commit de um jeito diferente
    • git show trata commit como diff
    • git log trata commit como histórico
    • git restore trata commit como snapshot
  • blob, tree, origin, upstream, downstream, a relação entre fetch e pull, stash, worktree, subtree e submodule também entram na lista de termos confusos do Git
  • Entre os termos do GitHub, “pull request”, “squash and merge” e “rebase and merge” são citados como exemplos de nomenclatura confusa

Os três eixos da confusão recorrente

  • Os termos mais confusos do Git podem ser resumidos em três pontos
    • head é branch, e HEAD é o branch atual
    • “remote tracking branch” e “branch that tracks a remote” são coisas diferentes
    • index, staged e cached apontam todos para a mesma coisa
  • O texto de 2012 the most confusing git terminology também trata de como a terminologia do Git se conecta com a do CVS e do Subversion
  • A confusão de termos no Git não aparece só em funcionalidades específicas, mas se repete em boa parte das funções centrais
  • Especialmente ao falar de branches, “tracking” é usado de várias formas, o que dificulta perceber a diferença à primeira vista
  • Algumas explicações incluem cantos raros do Git, então fica registrado o aviso de que pode haver algum engano

1 comentários

 
GN⁺ 2023-11-03
Comentários do Hacker News
  • Eu tinha dificuldade para decorar a maioria desses termos, mas a chave que fez tudo se encaixar foi perceber que muitas coisas no Git, no fim das contas, são ponteiros para commits
    Nomes de branch, HEAD e tags são todos ponteiros. HEAD aponta para o commit que você está vendo agora, e um nome de branch como my-feature aponta para o commit mais recente daquela branch. Se você fizer git checkout -b my-feature a partir de main, então main, my-feature e HEAD passarão a apontar para o commit mais recente de main
    Sempre que você faz commit em my-branch, HEAD e my-branch se movem para apontar para o novo commit. detached HEAD significa que o commit para o qual HEAD aponta não é apontado por nenhuma branch. A diferença entre tags e branches é que tags apontam para um commit específico e não se movem
    Outra coisa que me confundia era por que muitos comandos pareciam inconsistentes, e o motivo é que o Git assume argumentos padrão. git checkout file.txt é o mesmo que git checkout HEAD -- file.txt, e git rebase main quando você está em my-branch é o mesmo que git rebase main my-branch. Só que a forma mais longa também pode ser executada a partir de outra branch
    Por fim, quando tudo vira um caos, o comando que te tira de praticamente qualquer estado estranho é git reflog. Ele mostra todos os commits para os quais HEAD já apontou. Mesmo assim, é bom ver que o Git reconhece essa confusão e está criando comandos com interfaces menos surpreendentes e mais simples
    • Se usar o nome que o Git dá a esse conceito, “ponteiros para commit” são refs. É daí que vem o nome reflog
      Outra coisa que muita gente que usa Git não percebe é que as refs de branches e tags remotas que você buscou também são refs, então podem ser referenciadas em qualquer lugar onde um nome de ref seja aceito
      Por exemplo, se você quiser dizer “não me importo com o que tem nesta branch, não faça fast-forward, merge nem rebase; só sobrescreva minha branch local com o conteúdo remoto”, pode fazer assim: git checkout foo, git reset --hard origin/foo
    • Tecnicamente, o ponteiro HEAD não aponta diretamente para um commit; normalmente ele aponta para um ponteiro de branch, como my-branch, e esse ponteiro de branch é que aponta para o commit. O estado detached HEAD é a exceção
      Quando você faz commit em my-branch, não é que HEAD e my-branch se movam ambos para o novo commit; HEAD continua apontando para o ponteiro my-branch, e só my-branch é movido para apontar para o novo commit. Claro, se você seguir HEAD, depois my-branch, e então o commit, vai chegar ao novo commit
      detached HEAD é quando HEAD aponta diretamente para um commit em vez de para um ponteiro de branch. Mesmo no estado detached HEAD, HEAD e um ponteiro de branch podem ambos apontar para o commit mais recente. Se você olhar git log --decorate, em vez do usual (HEAD -> my-branch), verá algo como (HEAD, my-branch) no commit mais recente
    • Essa explicação é boa. Mas uma parte ainda mais confusa em que às vezes esbarro é que existem dois tipos de tag. A maioria das tags é, como foi dito, uma tag leve, que aponta para um objeto commit e nada mais
      Já uma tag anotada pode conter mensagem, timestamp, SHA etc. Elas são objetos Git de verdade e se comportam de forma bem parecida com objetos commit, mas normalmente ainda assim referenciam outro objeto Git, geralmente um commit
    • Se você é excessivamente cauteloso como eu, também vale executar git rev-parse HEAD antes de começar um procedimento complicado com muitos conflitos ou várias movimentações, e copiar essa string para algum lugar seguro
      No mínimo, isso dá a tranquilidade de ter marcado exatamente um estado que você sabe que está correto. Em vez de voltar para algum ponto já várias etapas dentro do caos, normalmente dá para voltar para o último estado bom. Claro, assumindo que você não tenha usado coisas como git gc ou git filter-branch de forma descuidada
    • Essa explicação também mostra bem como a estrutura em árvore interna do Git governa tudo
      Parece piada, mas não é bem piada dizer que, para usar Git, você realmente precisa de um diploma em ciência da computação. Concordo que os argumentos padrão do Git criam uma experiência de uso muito inconsistente
      git checkout ., git reset --hard/soft e git cleanup também parecem todos absurdamente parecidos, mas na prática são muito diferentes. Ainda assim, continuo preferindo Git a Perforce ou SVN. Antigamente eu talvez gostasse um pouco mais do Mercurial, mas não sei se ainda seria assim hoje
      git reflog é rei e mostra a verdade
  • Já faz uns 10 anos que o Git “venceu” a guerra dos sistemas de controle de versão graças a mais uma moda tecnológica sem fundamento, e ainda assim continua sendo difícil em tarefas que deveriam ser triviais
    Lembro de ter visto um texto em que Linus Torvalds dizia estar surpreso que as pessoas começaram a usar Git diretamente, em vez de colocarem uma camada mais amigável por cima. Se a indústria fosse capaz de fazer autocrítica, admitiria que escolher Git foi um erro e migraria para outro sistema de controle de versão. Em vez de desperdiçar uma quantidade absurda de tempo com uma ferramenta cujo único trabalho é armazenar texto
    • Eu não vejo o Git como uma ferramenta para armazenar texto. Vejo como uma ferramenta para coordenar com bastante precisão e confiabilidade mudanças que várias pessoas fazem no mesmo “texto”, sem bloquear o progresso de ninguém. Tente fazer isso no Word para ver a diferença
      Claro que pode melhorar. Mesmo assim, o ódio que o Git recebe sempre me surpreende. Git é uma ferramenta fantástica e está muito à frente de ferramentas feitas para não desenvolvedores, como Word ou Google Docs
      Talvez eu diga isso porque já tenho idade suficiente para lembrar da época em que o Subversion era rei
    • Concordo fortemente
      Toda semana vejo colegas se confundindo por causa do Git, vejo pedidos de ajuda online e vejo mais um texto como este tentando explicar de novo algo que deveria ser simples
      Não me lembro de ver gente desperdiçando horas para desfazer a bagunça que fizeram em SVN, TFVC, Perforce etc. enquanto estavam programando
      Ferramentas existem para facilitar a vida. Se não fazem isso, não vale a pena gastar tempo com elas
    • Em 2013, ainda não era nada claro que o Git venceria. Havia bastante gente usando darcs, Mercurial, svn e até cvs, e as ferramentas daquela época geralmente tinham plugins que davam suporte a todos eles

Ainda queria que existisse essa diversidade. A monocultura do Git também significa que qualquer tentativa de substituir o Git precisa primeiro reimplementá-lo. Então acabamos ficando presos ao Git quase para sempre, como ASCII ou a tecla Scroll Lock.

  • O Git venceu por bons motivos e era claramente melhor do que o que veio antes. Hoje pode até ser moda falar mal do Git, como aconteceu com jQuery, mas quando surgiu foi uma melhoria evidente.
  • Escrevi recentemente sobre um problema parecido, sobre por que podemos acabar presos ao Git.
    A preocupação central é que o GitHub é bom demais, então vamos ficar presos ao Git a menos que o GitHub separe o Git do motor de gerenciamento de texto e passe a permitir outros motores.
    https://trolololo.xyz/github
    https://news.ycombinator.com/item?id=38098109
  • A terminologia do Git faz sentido em muitos casos só depois que você já entendeu como ele funciona, mas sem conhecer os detalhes de implementação, ou quando colocada ao lado de outros termos, parece quase um caso clínico de algo que não faz sentido.
    É uma terminologia de abstração com vazamento.
    • Em parte sim, mas também porque partes diferentes do Git foram feitas por pessoas diferentes, que deram nomes separadamente. O Linus originalmente chamava isso de cache, e era o termo mais próximo da ciência da computação.
      Depois, ao que parece, o Junio trocou para index, mais específico para um sistema de controle de versão distribuído, e a maioria dos usuários passou a chamar isso de staging area. Agora essa evolução da terminologia ficou fossilizada na UI e nos internals do Git.
    • Não é que faça sentido; é só nomenclatura desleixada. Dar bons nomes exige esforço, e os primeiros desenvolvedores do Git não fizeram isso.
    • Se você imaginar que, para uso básico, seria preciso conhecer os internals do sistema operacional, da IDE e do compilador, isso na prática é design ruim de API.
  • “Your branch is up to date with origin/master” é a maior mentira que escuto todos os dias. Então sempre dou pull.
    • Tecnicamente é verdade. origin/master não significa o master que está na origin, e sim o commit para o qual o último origin/master conhecido apontava. Esse valor é atualizado quando você faz fetch, e pull faz fetch automaticamente.
      Se você olhar ls -l .git/refs/remotes/origin/master, vai ver que origin/master é só um arquivo no seu sistema. Também dá para ver quando ele mudou. Ele não é atualizado magicamente.
      Quando você faz git fetch origin, se houve mudança, o timestamp e o conteúdo mudam. Você pode confirmar com cat .git/refs/remotes/origin/master.
      A base do Git é bem simples; dá para implementar as estruturas de dados centrais e algumas operações em um dia. Vale muito a pena entender isso. De algum jeito, o Git conseguiu construir uma interface de usuário muito complexa em cima de um núcleo bastante simples.
    • Essa mensagem só quer dizer que o Git não vai acessar a internet nem o repositório remoto para verificar atualizações, a menos que você mande explicitamente. Considero essa característica desejável. Só que a mensagem poderia ser mais clara.
    • Deveria ser algo como “Your branch is up to date with the local copy of origin/master, last updated on XXXX-XX-XX:XX:XX:XX”.
    • Eu apago a branch local master. Normalmente não posso fazer push para master, ou simplesmente não quero trabalhar direto em master. Nesse caso, não há motivo para manter uma branch local mutável chamada master.
      Então só preciso manter origin/master atualizado, e para isso fetch basta.
    • git fetch && git pull
      Estou esperando o dia em que vou me aposentar daqui a 3 anos e finalmente lavar as mãos desse lixo quebrado.
  • Uso Git desde praticamente o começo, e só esta semana descobri porcelain. Tenho um projeto que faz parsing da saída de git status, e adicionar a flag --porcelain ajudou muito. Ela gera uma saída mais concisa e mais fácil de processar por programa.
    Fiquei curioso sobre quantos comandos têm saídas mais amigáveis para máquina e acabei indo até a página “Git Internals - Plumbing and Porcelain” do git-scm. Em resumo, o Git foi escrito desde o início mais como um conjunto de ferramentas para lidar com controle de versão do que como um sistema de versionamento refinado.
    Muita gente que usou Git desde o começo aprendeu tarefas de controle de versão com esses comandos de baixo nível e acabou propagando esse fluxo de trabalho para outras pessoas. Essa é a camada de plumbing. Depois o Git criou uma camada mais polida, chamada porcelain.
    Ainda não entendo totalmente quais comandos pertencem a qual camada, mas isso ajudou a entender os fluxos de trabalho mais novos recomendados nos últimos anos. Também me ajuda a julgar melhor quando vou mudar meu próprio fluxo de trabalho.
    https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Po...
    • É um sinal bem claro de que o Linus estava satisfeito com a estrutura interna, o plumbing, mas achava que a porcelain, isto é, a UI, precisava de ajustes. Originalmente, a porcelain era toda composta por scripts chamando o plumbing.
      Infelizmente, eles acabaram hardcodando essa UI para ficar mais rápida, mas sem melhorá-la.
  • A voz de escrita da Julia é realmente muito boa. Ela escreve coisas de grande valor até para desenvolvedores veteranos, mantendo ao mesmo tempo um tom acolhedor e nada excludente para quem está chegando agora na área.
  • Acho que tenho “síndrome de Estocolmo com Git”. Esses termos não me confundem tanto assim, mas acho que isso tem muito a ver com o fato de eu estar profundamente preso ao Git desde por volta de 2011, sem praticamente aprender outros sistemas.
    Olhando para trás, devo ter ficado extremamente confuso quando comecei, mas provavelmente fingi que não estava para parecer descolado.
    • Foi depois de ver a CLI do sistema de controle de versão Fossil que percebi que eu tinha síndrome de Estocolmo. Era intuitiva demais.
    • Antes de usar Git, eu usava cvs e svn, e comparado ao svn, o Git era muito mais fácil de entender.
    • O único outro sistema de versionamento que usei foi o Plastic SCM, e, com ou sem síndrome de Estocolmo, o Git é muito melhor.
  • Vale ver também: a Git staging area é literalmente um termo com o qual todo mundo concorda.

https://news.ycombinator.com/item?id=28143078
“Your branch is up to date with ‘origin/main’” na verdade é um pouco enganoso. Dá para entender como se o branch main estivesse atualizado, mas na prática não é isso
Também não precisa exagerar no “falando estritamente”. Não se aplica aqui o problema dos dois generais? Se for realmente minucioso, não dá para saber se está “atualizado” exatamente neste instante. Mesmo fazendo fetch antes do status, continua sendo assim
Então, qual seria uma expectativa razoável? Algo como: a ref no banco de objetos do meu computador é igual, da última vez que verifiquei, à ref de um outro banco de objetos lá do outro lado
Uma simples chamada de status não pode fazer um fetch pela rede, nem ficar relembrando toda vez os princípios básicos da ferramenta que você está usando. Pelo menos eu acho isso. Mas, surpreendentemente, muitos comentários na resposta do StackOverflow acham que essas duas coisas seriam necessárias
Algo como “is up to date with the origin’s main as of your last fetch 5 days ago” parece mais razoável. Porque só informa há quanto tempo foi o último fetch
[1] https://stackoverflow.com/questions/27828404/why-does-git-st...
Outra coisa: eu achava que ORIG_HEAD tinha relação com a “head da origin”, como FETCH_HEAD. Mas não era isso. Essa “pseudoref” parece ser usada como ponto de salvamento antes de reescritas mais complexas, como rebase, e foi implementada antes de existir reflog. Provavelmente significa “original head”

  • Sou bastante simpático ao Git, mas concordo com o autor sobre a redação dessa mensagem. Só não concordo com a alternativa proposta
    “Your branch is up to date with ‘origin/main’” está tecnicamente correto, mas a expressão up to date, lida por alto, sugere duas coisas. Que main é igual a origin/main e que origin/main também está atualizado, isto é, que foi atualizado durante o comando ou mantido automaticamente em dia e sincronizado com sucesso recentemente
    Isso não é um sinal legível por máquina que precisa ser verdadeiro por um ciclo de CPU; é uma mensagem de estado mostrada ao usuário. Mesmo sem entrar em teoria de redes, essa interpretação é razoável
    “Up to date” parece mais algo de ter alcançado no tempo do que no espaço. A posição do branch local está mais perto de um “para onde este branch aponta” no espaço, enquanto o estado da ref remota está mais perto de um “quando foi a última vez que atualizei essa ref remota” no tempo. Claro, isso é bem subjetivo, e ambas podem ter os dois sentidos
    Formulações melhores poderiam ser “Your branch matches origin/main”, “Your branch’s head is the same as origin/main”, “Your branch is pointing to the same commit as origin/main”. É um meio-termo entre clareza e verbosidade. Também daria para acrescentar entre parênteses algo como “remote ref last updated 5 days ago”, como sugerido pelo autor
  • Não concordo que seria irritante uma chamada de status fazer um fetch pela rede. Eu acho que operações de rede devem ser explícitas, não implícitas. Quando faço git status, quero saber o estado do meu repositório no sistema de arquivos
    Se eu quiser saber o que está acontecendo em outros remotos, posso eu mesmo fazer fetch e depois comparar
  • O que eu espero é obter a informação mais recente possível no momento em que o comando status começa. Pode existir uma condição de corrida enquanto a informação está sendo impressa no terminal, mas é uma janela de tempo muito pequena
    Em geral isso significa querer um fetch. O problema dos dois generais só se aplica ao lado remoto. O remoto pode continuar retransmitindo por um tempo se não receber confirmação de que o cliente recebeu os dados. Isso não é problema do cliente
    Se o cliente não conseguir receber os dados do servidor, o comportamento correto seria ficar esperando e, depois de um timeout, mostrar um erro; e o fetch atual provavelmente já faz isso
  • A etapa mais valiosa para aprender Git é ter o modelo mental correto. É tudo um grafo
    Esta ferramenta é compartilhada com frequência e se encaixa bem aqui também. Ela visualiza o modelo interno do Git e o efeito de vários comandos
    https://learngitbranching.js.org/
    Aprendi mais usando essa ferramenta por 10 minutos do que em cerca de 10 anos de experiência anterior com Git. Recomendo muito
  • Não quero aumentar a pilha, mas também é um problema o pessoal do Bitbucket ter criado o termo pull request
    “pull” é a ação de mesclar mudanças remotas no repositório local. O que o usuário está realmente pedindo é que o servidor mescle suas mudanças remotas em algum branch. O “merge request” do GitLab é o termo correto
    Já vi gente fazer fetch e achar que commits tinham sumido. Eles só ficaram escondidos porque o repositório andou para trás no tempo. O Git deixa esse tipo de detalhe escondido no status; se você não usa git-prompt ou powerline-shell, é como trabalhar no escuro
    • A ideia original que ainda resta em git-request-pull(1) era que cada um de nós teria seu próprio repositório Git em algo como kernel.org/git ou redhat.com/git, e pediria por email que outras pessoas fizessem pull de repositórios hospedados em servidores, organizações e domínios diferentes
      O GitHub se inspirou no comando request-pull do Git, mas reinterpretou isso como uma mesclagem de um repositório GitHub para outro repositório GitHub
    • Do ponto de vista do servidor, o usuário é o remoto e o servidor é o local. Então o usuário está pedindo ao servidor que faça pull do lado dele
      Pelo menos, eu sempre li dessa forma
    • O livro do Git explica a origem desse termo e por que ele faz sentido
      Resumindo, não é um pedido ao servidor, e sim a outra pessoa. Você está pedindo que a outra pessoa faça pull do seu branch para revisar as mudanças com as quais você quer contribuir para o projeto

[0] https://git-scm.com/book/en/v2/Distributed-Git-Contributing-...

  • “pull request” foi popularizado pelo GitHub, e me parece um termo bom. A distinção entre fazer pull de outro repositório ou fazer um “merge request” dentro do mesmo repositório não é tão interessante assim. “merge request” parece um termo mais característico do GitLab
  • Isso sempre foi o mais difícil de entender. Dá a impressão de que, naturalmente, não deveria ser um pull request, mas sim um push request ou merge request