223 votes

Pourquoi dois-je faire "git push --set-upstream origin <branch>" ?

J'ai créé une branche locale pour tester Solaris et Sun Studio. J'ai ensuite poussé la branche en amont. Après avoir validé un changement et essayé de pousser les changements :

$ git commit blake2.cpp -m "Add workaround for missing _mm_set_epi64x"
[solaris 7ad22ff] Add workaround for missing _mm_set_epi64x
 1 file changed, 5 insertions(+)
$ git push
fatal: The current branch solaris has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin solaris

Pourquoi dois-je faire quelque chose de spécial pour ça ?

Y a-t-il un cas d'utilisation raisonnable où quelqu'un créerait <branch> pousse le <branch> à distance, et ensuite demander un commit sur <branch> n'est pas censé être pour <branch> ?


J'ai suivi cette question et cette réponse sur Stack Overflow : Pousser une nouvelle branche locale vers un dépôt Git distant et le suivre également . Je suppose que c'est un autre exemple de réponse incomplète ou fausse. Ou, c'est un autre exemple de Git prenant une tâche simple et la rendant difficile.


Voici la vue sur une autre machine. La branche existe clairement, elle a donc été créée et poussée :

$ git branch -a
  alignas
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/alignas
  remotes/origin/arm-neon
  remotes/origin/det-sig
  remotes/origin/master
  remotes/origin/solaris

2 votes

3 votes

Merci @Alexi. Malheureusement, le dup cité n'explique pas le cas d'utilisation ridicule qui est représenté par défaut. (Ce ne sont pas des questions rhétoriques. Je suis sincèrement intéressé par la raison de ce design UX).

2 votes

Notez que ceci est configurable. Si vous faites git config --add push.default current alors git push créera automatiquement la branche dans le repo distant si nécessaire.

391voto

torek Points 25463

TL;DR : git branch --set-upstream-to origin/solaris


La réponse à la question que vous avez posée - que je reformulerai un peu en disant "dois-je définir un amont" - est la suivante : non, vous n'avez pas à le faire ont pour fixer un amont du tout.

Si vous n'avez pas d'amont pour la branche courante, cependant, Git change son comportement sur git push et sur d'autres commandes également.

L'histoire complète de la poussée ici est longue et ennuyeuse et remonte à avant la version 1.5 de Git. Pour la raccourcir un peu, git push a été mal mis en œuvre. 1 À partir de la version 2.0 de Git, Git dispose désormais d'un bouton de configuration orthographié push.default qui a désormais pour valeur par défaut simple . Pour plusieurs versions de Git avant et après 2.0, chaque fois que vous exécutez git push Git cracherait beaucoup de bruit pour essayer de vous convaincre de mettre en place push.default juste pour obtenir git push de se taire.

Vous ne mentionnez pas la version de Git que vous exécutez, ni si vous avez configuré push.default donc nous devons deviner. Je pense que vous utilisez Git version 2-point-quelque chose, et que vous avez configuré push.default a simple pour qu'il se taise. Précisez quelle version de Git vous avez, et ce que vous avez éventuellement push.default réglé sur, fait Mais en fin de compte, le fait que vous receviez une nouvelle plainte de la part de Git indique que votre système Git est configuré pour éviter une des erreurs du passé.

Qu'est-ce qu'un amont ?

Un site en amont est simplement un autre nom de branche, généralement une branche de suivi à distance, associée à une branche (régulière, locale).

Chaque branche a la possibilité de disposer d'un (1) jeu en amont. C'est-à-dire que chaque branche a un amont ou n'a pas d'amont. Aucune branche ne peut avoir plus d'un amont.

L'amont devrait mais il n'est pas nécessaire qu'il s'agisse d'une branche valide (qu'il s'agisse d'un suivi à distance comme le origin/_B_ ou local comme master ). C'est-à-dire que si la branche actuelle B a en amont U , git rev-parse _U_ devrait travail. Si elle ne fonctionne pas - si elle se plaint que U n'existe pas - alors la plupart de Git agit comme si l'amont n'était pas du tout défini. Quelques commandes, comme git branch -vv L'affichage de l'écran, qui montre le réglage en amont mais le marque comme "disparu".

A quoi bon un amont ?

Si votre push.default est réglé sur simple o upstream le réglage en amont rendra git push utilisé sans arguments supplémentaires, juste le travail.

C'est tout. C'est tout ce qu'il fait pour git push . Mais c'est assez significatif, puisque git push est l'un des endroits où une simple faute de frappe provoque de gros maux de tête.

Si votre push.default est réglé sur nothing , matching ou current la définition d'un amont ne fait rien du tout pour git push .

(Tout ceci suppose que votre version de Git est au moins 2.0).

L'amont affecte git fetch

Si vous exécutez git fetch sans arguments supplémentaires, Git calcule dont à distance pour aller chercher en consultant l'amont de la branche courante. Si l'amont est une branche de suivi à distance, Git récupère à partir de cet amont. (Si le flux amont n'est pas défini ou s'il s'agit d'une branche locale, Git essaie de récupérer les données à partir de origin .)

L'amont affecte git merge y git rebase trop

Si vous exécutez git merge o git rebase sans arguments supplémentaires, Git utilise l'amont de la branche courante. Il raccourcit donc l'utilisation de ces deux commandes.

L'amont affecte git pull

Vous ne devez jamais 2 utiliser git pull de toute façon, mais si vous le faites, git pull utilise le paramètre amont pour déterminer à partir de quelle télécommande récupérer les données, et ensuite avec quelle branche fusionner ou rebaser. C'est-à-dire, git pull fait la même chose que git fetch -parce qu'en fait exécute git fetch -et fait ensuite la même chose que git merge o git rebase parce qu'en fait exécute git merge o git rebase .

(Vous devriez généralement effectuer ces deux étapes manuellement, au moins jusqu'à ce que vous connaissiez suffisamment bien Git pour que lorsque l'une ou l'autre des étapes échoue, ce qui finira par arriver, vous reconnaissiez ce qui s'est mal passé et sachiez quoi faire).

L'amont affecte git status

C'est peut-être même le plus important. Une fois que vous avez un jeu en amont, git status peut signaler la différence entre votre branche actuelle et son amont, en termes de commits.

Si, comme c'est le cas normalement, vous êtes sur la branche B avec son amont fixé à origin/_B_ et tu exécutes git status vous verrez immédiatement si vous avez des commits que vous pouvez pousser, et/ou des commits sur lesquels vous pouvez fusionner ou rebaser.

Cela s'explique par le fait que git status court :

  • git rev-list --count @{u}..HEAD : combien de commits avez-vous sur B qui ne sont pas sur origin/_B_ ?
  • git rev-list --count HEAD..@{u} : combien de commits avez-vous sur origin/_B_ qui ne sont pas sur B ?

La mise en place d'un système en amont vous permet d'obtenir toutes ces choses.

Comment se fait-il que master a déjà un jeu en amont ?

Lorsque vous clonez pour la première fois à partir d'une certaine distance, en utilisant :

$ git clone git://some.host/path/to/repo.git

ou similaire, la dernière étape que fait Git est, essentiellement, git checkout master . Cela vérifie votre branche locale master -sauf que vous ne le faites pas ont une succursale locale master .

D'autre part, vous faire ont une branche de suivi à distance nommée origin/master parce que tu viens de le cloner.

Git devine que vous vouliez dire : " faites-moi un nouveau local ". master qui pointe vers le même commit que le suivi à distance origin/master et, tant que vous y êtes, définissez l'amont pour master a origin/master ."

Cela se produit pour cada branche que vous git checkout que vous n'avez pas déjà. Git crée la branche et lui permet de "suivre" (avoir comme amont) la branche de suivi à distance correspondante.

Mais cela ne fonctionne pas pour nouveau branches, c'est-à-dire les branches sans suivi à distance. mais .

Si vous créez un nouveau branche :

$ git checkout -b solaris

il n'y a, à ce jour, aucune origin/solaris . Votre bureau local solaris ne peut pas branche de suivi à distance origin/solaris parce qu'il n'existe pas.

Quand tu pousses la nouvelle branche pour la première fois :

$ git push origin solaris

que crée solaris en origin et, par conséquent, crée également origin/solaris dans votre propre dépôt Git. Mais c'est trop tard : vous avez déjà un dépôt local solaris que n'a pas d'amont . 3

Git ne devrait-il pas simplement définir cela, maintenant, comme l'amont automatiquement ?

Probablement. Voir "mal mis en œuvre" et la note de bas de page 1. Il est difficile de changer maintenant : Il y a des millions 4 de scripts qui utilisent Git et certains peuvent très bien dépendre de son comportement actuel. Changer le comportement nécessite une nouvelle version majeure, un nag-ware pour vous forcer à définir un certain champ de configuration, et ainsi de suite. En bref, Git est victime de son propre succès : toutes les erreurs qu'il contient aujourd'hui ne peuvent être corrigées que si le changement est soit invisible, soit nettement meilleur, soit effectué lentement au fil du temps.

Le fait est que ce n'est pas le cas aujourd'hui, sauf si vous utilisez --set-upstream o -u pendant le git push . C'est ce que le message vous dit.

Tu n'es pas obligé de faire ça comme ça. Eh bien, comme nous l'avons noté ci-dessus, vous n'êtes pas obligé de le faire du tout, mais supposons que vous veulent un amont. Vous avez déjà créé la branche solaris en origin par une poussée antérieure, et comme votre git branch montre, vous avez déjà ont origin/solaris dans votre dépôt local.

Vous ne l'avez simplement pas défini comme l'amont pour solaris .

Pour le définir maintenant, plutôt que lors de la première poussée, utilisez git branch --set-upstream-to . Le site --set-upstream-to La sous-commande prend le nom de toute branche existante, telle que origin/solaris et définit l'amont de la branche courante à cette autre branche.

C'est tout - c'est tout ce qu'il fait - mais il a toutes les implications mentionnées ci-dessus. Cela signifie que vous pouvez simplement exécuter git fetch puis regarder autour, puis courir. git merge o git rebase comme il se doit, puis faites de nouveaux commits et exécutez git push sans avoir à faire des efforts supplémentaires.


1 Pour être honnête, il n'était pas évident à l'époque que la mise en œuvre initiale était sujette à des erreurs. Cela n'est devenu clair que lorsque chaque nouvel utilisateur faisait les mêmes erreurs à chaque fois. Elle est maintenant "moins mauvaise", ce qui ne veut pas dire "excellente".

2 "Jamais" est un peu fort, mais je trouve que les nouveaux Git comprennent beaucoup mieux les choses quand je sépare les étapes, surtout quand je peux leur montrer ce que git fetch réellement fait, et ils peuvent alors voir ce que git merge o git rebase fera ensuite.

3 Si vous exécutez votre premièrement git push como git push -u origin solaris c'est-à-dire que si vous ajoutez l'élément -u flag-Git mettra origin/solaris comme l'amont de votre branche actuelle si (et seulement si) le push réussit. Vous devez donc fournir -u sur le premièrement pousser. En fait, vous pouvez le fournir lors de n'importe quelle poussée ultérieure, et il fixera ou de changer l'amont à ce moment-là. Mais je pense git branch --set-upstream-to est plus facile, si vous avez oublié.

4 Mesuré par la méthode Austin Powers / Dr Evil qui consiste à dire simplement "un MILLLL-YUN", en tout cas.

0 votes

Aussi : stackoverflow.com/a/17096880/6309 aurait fixé l'amont dès la première poussée. +1

3 votes

Si le cas commun est de {créer une branche/pousser une branche/utiliser une branche}, alors le résultat de Pousser une nouvelle branche locale vers un dépôt Git distant et le suivre également être quelque chose qui fonctionne réellement ? Et si quelqu'un veut {créer une branche/pousser la branche/ne pas utiliser la branche}, alors ne devrait-il pas faire quelque chose de spécial, comme --set-upstream /dev/null ? Pourquoi la charge est-elle repoussée sur le cas commun ? Je ne comprends vraiment pas certaines de ces décisions en matière d'ingénierie et de convivialité.

2 votes

@VonC : c'est vrai, c'est le but de git push -u mais il semble vraiment que git push -u devrait être la valeur par défaut, ou du moins la valeur par défaut s'il n'y a pas d'amont mais et il devrait y avoir un git push --no-set-upstream lorsqu'il n'y a pas actuellement d'amont et que vous voulez que cela reste ainsi (pour une raison incompréhensible :-) ).

77voto

Adam Points 995

La différence entre

git push origin <branch>

et

git push --set-upstream origin <branch>

c'est qu'ils poussent tous les deux très bien vers le dépôt distant, mais c'est quand vous tirez que vous remarquez la différence.

Si vous le faites :

git push origin <branch>

quand vous tirez, vous devez le faire :

git pull origin <branch>

Mais si vous le faites :

git push --set-upstream origin <branch>

alors, en tirant, vous n'avez qu'à faire :

git pull

Donc, en ajoutant le --set-upstream permet de ne pas avoir à spécifier de quelle branche vous voulez tirer à chaque fois que vous faites git pull .

2 votes

La différence entre deux versions de "git push" dont je ne vois pas pourquoi je voudrais/devrais les utiliser. Inutile !

1 votes

@FrankPuck c'est Git, il professe être utilisable pour une utilisation hors ligne, mais sans Google ou SO il est impossible de l'utiliser dès que l'on quitte le "sentier battu". Expliqué brièvement : --set-upstream en git push (par opposition à git branch con --set-upstream-to ) est ce que -b est de git checkout (par opposition à git branch ou de nos jours git switch -c ). C'est de la folie dans tous les sens du terme et vous ne devriez pas en attendre moins. Bien sûr, avec git push set-upstream vous voudrez spécifier remote branch alors qu'avec git branch --set-upstream-to vous utilisez remote/branch (également connu sous le nom de commreftreeish ).

1 votes

Merci. Court et précis.

20voto

ElpieKay Points 7502

Une commande complète est la suivante git push <remote> <local_ref>:<remote_ref> . Si vous exécutez seulement git push En effet, git ne sait pas quoi faire exactement, à moins que vous n'ayez fait une configuration qui aide git à prendre une décision. Dans un repo git, nous pouvons configurer plusieurs remotes. Nous pouvons également pousser une référence locale vers n'importe quelle référence distante. La commande complète est la manière la plus directe de faire un push. Si vous voulez taper moins de mots, vous devez d'abord configurer, comme --set-upstream.

6voto

DannyMoshe Points 2815

Le drapeau -u spécifie que vous voulez lier votre branche locale à la branche en amont branche. Cela créera également une branche amont si elle n'existe pas. Aucune de ces réponses ne couvre la façon dont je le fais (dans sa forme complète), alors la voici :

git push -u origin <your-local-branch-name>

Donc si votre local le nom de la branche est café

git push -u origin coffee

2voto

Jerry Chen Points 51

Si je comprends bien, "-u" ou "--set-upstream" vous permet de spécifier le dépôt amont (distant) pour la branche sur laquelle vous vous trouvez, de sorte que la prochaine fois que vous exécutez "git push", vous n'aurez même pas à spécifier le dépôt distant.

Pousser et définir le dépôt amont (distant) comme origine :

$ git push -u origin

La prochaine fois que vous pousserez, vous n'aurez pas à spécifier le référentiel distant :

$ git push

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X