Por que preciso fazer `–set-upstream` o tempo todo?

Eu crio um novo branch no Git:

git branch my_branch 

Empurre-o:

 git push origin my_branch 

Agora digamos que alguém fez algumas alterações no servidor e eu quero extrair de origin/my_branch . Eu faço:

 git pull 

Mas eu recebo:

 You asked me to pull without telling me which branch you want to merge with, and 'branch.my_branch.merge' in your configuration file does not tell me, either. Please specify which branch you want to use on the command line and try again (eg 'git pull  '). See git-pull(1) for details. If you often merge with the same branch, you may want to use something like the following in your configuration file: [branch "my_branch"] remote =  merge =  [remote ""] url =  fetch =  See git-config(1) for details. 

Eu aprendi que posso fazer funcionar com:

 git branch --set-upstream my_branch origin/my_branch 

Mas por que eu preciso fazer isso para cada ramo que eu criar? Não é óbvio que se eu forçar my_branch em origin/my_branch , então eu gostaria de puxar origin/my_branch para my_branch ? Como posso fazer disso o comportamento padrão?

Um atalho, que não depende de lembrar a syntax do git branch --set-upstream 1 é fazer:

 git push -u origin my_branch 

… a primeira vez que você empurra esse ramo. Você só precisa fazer isso uma vez, e isso configura a associação entre sua ramificação e aquela na origin da mesma maneira que git branch --set-upstream faz.

Pessoalmente, acho que é bom ter que configurar essa associação entre sua ramificação e uma no controle remoto explicitamente. É uma pena que as regras sejam diferentes para git push e git pull .


1 Pode parecer bobo, mas eu frequentemente esqueço de especificar o ramo atual, assumindo que é o padrão – não é, e os resultados são mais confusos 🙂

Atualização 2012-10-11 : Aparentemente eu não sou a única pessoa que achou fácil errar! Obrigado ao VonC por apontar que o git 1.8.0 introduz o git branch --set-upstream-to mais óbvio git branch --set-upstream-to , que pode ser usado da seguinte maneira, se você estiver no ramo my_branch :

 git branch --set-upstream-to origin/my_branch 

… ou com a opção curta:

 git branch -u origin/my_branch 

Essa alteração e seu raciocínio estão descritos nas notas de versão do git 1.8.0, release candidate 1 :

Era tentador dizer git branch --set-upstream origin/master , mas isso diz ao Git para organizar a ramificação local origin/master para integrar com a ramificação atualmente retirada, o que é altamente improvável o que o usuário quis dizer. A opção está obsoleta; use a nova opção --set-upstream-to (com um short-and-sweet -u ).

Você pode fazer isso acontecer com menos digitação. Primeiro, mude a maneira como seu push funciona:

 git config --global push.default current 

Isso irá inferir a parte origin my_branch , assim você pode fazer:

 git push -u 

Que irá criar o ramo remoto com o mesmo nome e rastreá-lo.

Você pode simplesmente

 git checkout -b my-branch origin/whatever 

em primeiro lugar. Se você definir branch.autosetupmerge ou branch.autosetuprebase (meu favorito) como always (o padrão é true ), my-branch controlará automaticamente a origin/whatever .

Veja git help config .

Você pode configurar o stream de dados mais simples de duas maneiras. Primeiro, quando você cria o ramo:

 git branch -u origin/my-branch 

ou depois de criar uma ramificação, você pode usar este comando.

 git push -u origin/my-branch 

Você também pode ramificar, fazer check-out e configurar o envio em um único comando:

 git checkout -b my-branch -t origin/my-branch 

Minha preferência pessoal é fazer isso em um comando de duas etapas:

 git checkout -b my-branch git push -u origin/my-branch 

Você pode usar:

git config –global branch.autosetupmerge sempre

que ligará o ramo upstream cada vez que você criar ou fazer o checkout de um novo branch.

Veja https://felipec.wordpress.com/2013/09/01/advanced-git-concepts-the-upstream-tracking-branch/

Isso também funciona com autosetuprebase, se você seguir um stream de trabalho mais focado em rebase, mas não o use a menos que você saiba o que está fazendo, pois ele irá padronizar seu comportamento de pull para rebase, o que pode causar resultados estranhos.

Este é o meu uso mais comum para o The Fuck .

 $ git push fatal: The current branch master has no upstream branch. To push the current branch and set the remote as upstream, use git push --set-upstream origin master $ fuck git push --set-upstream origin master [enter/↑/↓/ctrl+c] Counting objects: 9, done. ... 

Além disso, é divertido digitar palavrões no seu terminal.

By the way, o atalho para empurrar o ramo atual para um controle remoto com o mesmo nome:

 $ git push -u origin HEAD 
 git branch --set-upstream-to=origin/master 

Você também pode explicitamente dizer ao git pull qual branch remoto puxar (como mencionado na mensagem de erro):

git pull

Tenha cuidado com isso, no entanto: se você estiver em um ramo diferente e fizer um pull explícito, o refspec que você puxar será mesclado no branch em que você está!

Para o que vale a pena, se você está tentando rastrear uma ramificação que já existe no remoto (por exemplo, origem / somebranch), mas ainda não fez o check-out localmente, você pode fazer:

 $ git checkout --track origin/somebranch 

Nota: ‘-t’ é a versão abreviada da opção ‘–track’.

Isso configura a mesma associação logo de cara.

Eu uso esse alias do Git em vez de copiar / colar a sugestão do Git toda vez: https://gist.github.com/ekilah/88a880c84a50b73bd306

Fonte copiada abaixo (adicione isso ao seu arquivo ~/.gitconfig ):

 [alias] pushup = "!gitbranchname() { git symbolic-ref --short HEAD; }; gitpushupstream() { git push --set-upstream origin `gitbranchname`; }; gitpushupstream" 

Você pode configurar um alias realmente bom que possa lidar com isso sem a syntax excessivamente detalhada.

Eu tenho o seguinte alias em ~/.gitconfig :

 po = "!git push -u origin \"$(git rev-parse --abbrev-ref HEAD)\"" 

Depois de fazer um commit em um novo branch, você pode empurrar seu novo branch simplesmente digitando o comando:

 git po 

Eu pessoalmente uso estes apelidos em bash

no arquivo ~ / .gitconfig

 [alias] pushup = "!git push --set-upstream origin $(git symbolic-ref --short HEAD)" 

e no arquivo ~ / .basehrc ou ~ / .zshrc

 alias gpo="git pushup" alias gpof="gpo -f" alias gf="git fetch" alias gp="git pull" 

Para quem procura um apelido que funcione com o git pull , é isso que eu uso:

 alias up="git branch | awk '/^\\* / { print \$2 }' | xargs -I {} git branch --set-upstream-to=origin/{} {}" 

Agora, sempre que você chegar:

 $ git pull There is no tracking information for the current branch. ... 

Apenas corra:

 $ up Branch my_branch set up to track remote branch my_branch from origin. $ git pull 

E você é bom para ir

Você também pode fazer o git push -u origin $(current_branch)

Porque o git tem a habilidade legal de empurrar / puxar diferentes ramificações para diferentes repositorys “upstream”. Você poderia até usar repositorys separados para empurrar e puxar – no mesmo ramo. Isso pode criar um stream distribuído de vários níveis, e posso ver isso sendo útil em projetos como o kernel do Linux. O Git foi originalmente construído para ser usado nesse projeto.

Como conseqüência, não faz suposição sobre qual repo sua filial deve estar rastreando.

Por outro lado, a maioria das pessoas não usa o git dessa maneira, então pode ser um bom argumento para uma opção padrão.

Git é geralmente muito baixo nível e pode ser frustrante. Ainda existem GUIs e deve ser fácil escrever scripts auxiliares se você ainda quiser usá-lo a partir do shell.

Eu meio que re-descobri legit por causa deste problema (OS X apenas). Agora tudo que eu uso quando se ramificam são estes dois comandos:

legit publish [] Publica a ramificação especificada para o controle remoto. (alias: pub )

legit unpublish Remove a ramificação especificada do controle remoto. (alias: unp )

O SublimeGit vem com suporte legit por padrão, o que torna toda a rotina de ramificação tão fácil quanto pressionar Ctrl-b.

Nós usamos o phabricator e não empurramos usando o git. Eu tive que criar bash alias, que funciona no Linux / mac

 vim ~/.bash_aliases new_branch() { git checkout -b "$1" git branch --set-upstream-to=origin/master "$1" } 

Salve 

 source ~/.bash_aliases new_branch test #instead of git checkout -b test git pull