Erreur push Git '[Rejeté à distance] Master -> Master (la branche est actuellement extraite)'


961

Hier, j'ai posté une question sur la façon de cloner un référentiel Git d'une de mes machines à une autre, comment puis-je 'git cloner' d'une autre machine? .

Je suis maintenant en mesure de cloner avec succès un référentiel Git de ma source (192.168.1.2) vers ma destination (192.168.1.1).

Mais quand j'ai fait une modification dans un fichier, a git commit -a -m "test"et a git push, j'obtiens cette erreur sur ma destination (192.168.1.1):

git push                                                
hap@192.168.1.2's password: 
Counting objects: 21, done.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (11/11), 1010 bytes, done.
Total 11 (delta 9), reused 0 (delta 0)
error: refusing to update checked out branch: refs/heads/master
error: By default, updating the current branch in a non-bare repository
error: is denied, because it will make the index and work tree inconsistent
error: with what you pushed, and will require 'git reset --hard' to match
error: the work tree to HEAD.
error: 
error: You can set 'receive.denyCurrentBranch' configuration variable to
error: 'ignore' or 'warn' in the remote repository to allow pushing into
error: its current branch; however, this is not recommended unless you
error: arranged to update its work tree to match what you pushed in some
error: other way.
error: 
error: To squelch this message and still keep the default behaviour, set
error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
To git+ssh://hap@192.168.1.2/media/LINUXDATA/working
! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to 'git+ssh://hap@192.168.1.2/media/LINUXDATA/working'

J'utilise deux versions différentes de Git (1.7 sur la télécommande et 1.5 sur la machine locale). Est-ce une raison possible?


5
Un ancien peut-il changer la réponse acceptée à stackoverflow.com/a/9283833/397872 et déplacer le fil vers l'archive ou quelque chose? Ou changer de propriétaire ou autre chose?
rishta

9
En fait, vous avez maintenant un moyen sécurisé de passer à un git config receive.denyCurrentBranch=updateInstead
référentiel

C'est le nouveau lien du livre que @stigi a mentionné: git-scm.com/book/en/v1/Git-on-the-Server
Abdelilah El Aissaoui


Mais je ne comprends pas pourquoi et comment ça marche? Ça marche, oui mais c'est tout.
Tilak Maddy

Réponses:


1149

Vous pouvez simplement convertir votre référentiel distant en référentiel nu (il n'y a pas de copie de travail dans le référentiel nu - le dossier contient uniquement les données réelles du référentiel).

Exécutez la commande suivante dans votre dossier de référentiel distant:

git config --bool core.bare true

Supprimez ensuite tous les fichiers sauf .gitdans ce dossier. Et vous pourrez ensuite effectuer des opérations git pushdans le référentiel distant sans aucune erreur.


4
Merci. J'avais aussi besoin de ça. Je suivais le tutoriel des sous-modules du Git Community Book et j'ai frappé ce barrage routier.
Shiki

6
Je ne savais pas si vous vouliez supprimer des fichiers sur le serveur ou le client ... donc je n'ai rien supprimé, et le problème disparaît après avoir fait juste git config --bool core.bare true. Y a-t-il une raison particulière pour laquelle certains fichiers doivent être supprimés? Si oui, pouvez-vous être plus précis sur ce qui doit être supprimé?
Brian Vandenberg

24
C'est la meilleure réponse possible et personne d'autre ne l'a fournie dans le trou Interwebs. Je pense que nous avons tous googlé le même message d'erreur et nous avons tous été extrêmement heureux de lire ceci.
Sebastián Grignoli

40
Bien qu'il ait obtenu beaucoup de votes, je ne pense pas que ce soit une réponse vraiment adéquate à cette question spécifique. Dire à l'utilisateur comment créer proprement un référentiel nu serait moitié moins mauvais, mais que se passe-t-il si les fichiers doivent rester extraits, par exemple lorsque c'est le référentiel avec lequel l'utilisateur travaille sur deux ordinateurs?
Nulle part homme

9
Changer le dépôt source à nu est exagéré. Tout ce que vous devez faire est de pousser vers une nouvelle branche dans le référentiel source, comme le souligne @Robert: stackoverflow.com/a/2933656/402949 .
Dan Solovay

708

J'ai juste eu la même erreur lorsque j'ai commencé à apprendre Git . Certaines des autres réponses ne sont clairement pas pour quelqu'un de nouveau à Git!

(Je vais utiliser des termes non techniques pour faire passer l'idée.) Quoi qu'il en soit, ce qui se passe, c'est que vous avez deux référentiels, l'un est l'original que vous avez créé en premier, et l'autre le travail que vous venez de créer.

En ce moment, vous êtes dans votre référentiel de travail et utilisez la branche "master". Mais vous êtes également «connecté» dans votre référentiel d'origine à la même branche «maître». Maintenant que vous êtes "connecté" dans l'original, Git craint que vous ne gâchiez parce que vous pourriez travailler sur l'original et foirer les choses. Vous devez donc revenir au référentiel d'origine et faire une "vérification de git someotherbranch", et maintenant vous pouvez pousser sans problème.

J'espère que ça aide.


76
+1 Beaucoup plus utile, merci Robert. Je n'avais aucun sens de me convertir à un dépôt nu dans mon cas. Il vous suffit de «désactiver» la branche vers laquelle vous essayez de pousser. Logique.
Eric Muyser

32
@ FMaz008: il suffit de créer une branche factice (git checkout -b dummy)
Dror Cohen

14
Man c'est bien mieux que la réponse la plus votée :) Merci. Bien que l'autre réponse soit également valable :)
Ivan Ivanić

103
Juste pour rendre cela plus clair, dans la prise en pension qui est la cible de la poussée: git checkout -b tmp. Puis , dans la source repo: git push. Puis de retour dans la cible (facultatif):git checkout master; git branch -d tmp
Hari Karam Singh

18
Le commentaire de Hari est la recette la plus simple. Je dois juste dire que même si git peut être génial à bien des égards, provenant de svn ou probablement de tout autre RV, tout cela est incroyablement non intuitif.
UnconditionallyReinstateMonica

128

Le message d'erreur décrit ce qui s'est produit. Des versions plus modernes de Git refusent de mettre à jour une branche via un push si cette branche est extraite.

La façon la plus simple de travailler entre deux référentiels non nus consiste à

  1. mettez toujours à jour les référentiels par extraction (ou extraction et fusion) ou, si vous le devez,

  2. en poussant vers une branche distincte (une branche d'importation), puis en fusionnant cette branche dans la branche principale sur la machine distante.

La raison de cette restriction est que l'opération push ne fonctionne que sur le référentiel Git distant, elle n'a pas accès à l'index et à l'arborescence de travail. Donc, si cela est autorisé, une poussée sur la branche extraite changerait le HEAD pour être incompatible avec l'index et l'arborescence de travail sur le référentiel distant.

Cela rendrait très facile la validation accidentelle d'une modification qui annule toutes les modifications poussées et rend également très difficile la distinction entre les modifications locales qui n'ont pas été validées et les différences entre la nouvelle HEAD, l'index et l'arborescence de travail qui ont été causée par le mouvement de poussée HEAD.


1
Merci. Alors, comment puis-je résoudre mon problème? Dans ma boîte 192, j'ai fait '$ cd (répertoire-projet) $ git init $ (ajouter des fichiers) $ git add.' puis dans ma boîte 191, j'ai fait un 'git clone' et édité quelques fichiers et que j'essaye de 'git push'.
hap497

16
Eh bien, j'ai décrit les possibilités dans ma réponse. Soit vous pouvez aller dans la zone 192 et récupérer dans la zone 191 (vous pouvez ajouter la zone 191 en tant que télécommande nommée - regardez git remote add box191 <191url>), ou vous pouvez pousser de la zone 191 vers une branche nommée alternativement (par exemple git push origin master:refs/heads/upload), puis dans la zone 192 et fusionner (par exemple git merge upload).
CB Bailey

3
En fait, vous avez maintenant un moyen sécurisé de passer à un référentiel non nu avec Git 2.3.0 (février 2015) et git config receive.denyCurrentBranch=updateInstead: stackoverflow.com/a/28262104/6309 : vous n'avez plus besoin de l'option 2.
VonC

122

Sommaire

Vous ne pouvez pas pousser vers la seule branche extraite d'un référentiel, car cela perturberait l'utilisateur de ce référentiel d'une manière qui se terminera très probablement par une perte de données et d'historique . Mais vous pouvez pousser vers n'importe quelle autre branche du même référentiel.

Étant donné que les référentiels nus n'ont jamais de branche extraite, vous pouvez toujours transférer vers n'importe quelle branche d'un référentiel nu.

Il existe plusieurs solutions, selon vos besoins.

Solution 1: utilisez un référentiel nu

Comme suggéré, si sur une machine, vous n'avez pas besoin du répertoire de travail, vous pouvez passer à un référentiel nu. Pour éviter de jouer avec le référentiel, vous pouvez simplement le cloner:

machine1$ cd ..
machine1$ mv repo repo.old
machine1$ git clone --bare repo.old repo

Vous pouvez maintenant envoyer tout ce que vous voulez à la même adresse qu'auparavant.

Solution 2: pousser vers une succursale non extraite

Mais si vous devez vérifier le code sur votre télécommande <remote>, vous pouvez utiliser une branche spéciale pour pousser. Disons que dans votre référentiel local, vous avez appelé votre télécommande originet vous êtes sur le maître de branche. Alors tu pourrais faire

machine2$ git push origin master:master+machine2

Ensuite, vous devez le fusionner lorsque vous êtes dans le originréférentiel distant:

machine1$ git merge master+machine2

Autopsie du problème

Lorsqu'une branche est extraite, la validation ajoute une nouvelle validation avec la tête de la branche actuelle comme parent et déplace la tête de la branche pour qu'elle soit cette nouvelle validation.

Donc

A ← B
    ↑
[HEAD,branch1]

devient

A ← B ← C
        ↑
    [HEAD,branch1]

Mais si quelqu'un pouvait pousser vers cette branche entre les deux, l'utilisateur se mettrait dans ce que git appelle le mode tête détachée :

A ← B ← X
    ↑   ↑
[HEAD] [branch1]

Maintenant, l'utilisateur n'est plus dans branch1, sans avoir explicitement demandé à vérifier une autre branche. Pire encore, l'utilisateur est désormais en dehors de toute branche , et tout nouveau commit sera juste suspendu :

      [HEAD]
        ↓
        C
      ↙
A ← B ← X
        ↑
       [branch1]

En théorie, si à ce stade, l'utilisateur vérifie une autre branche, alors ce commit suspendu devient un jeu équitable pour le garbage collector de Git .


3
Une correction technique à "autopsie": git ne se détachera pas réellement HEADdans le référentiel poussé. HEADpointera toujours vers la branche, et la branche pointera à son tour vers le (s) nouveau (s) commit (s) poussé (s); mais le répertoire de travail et l'index / zone de transfert ne seront pas modifiés. Quiconque travaille sur le référentiel poussé doit maintenant travailler dur pour se remettre des effets de la poussée: déterminez s'il y a des changements à enregistrer, et si c'est le cas, arrangez-vous soigneusement pour les enregistrer.
torek

Pour ajouter des informations supplémentaires à votre réponse, il y a très peu de raisons pour lesquelles vous souhaiteriez qu'un référentiel distant vers lequel les utilisateurs poussent ne soit pas nu, donc l'utilisation d'un référentiel nu est la meilleure solution.

2
En fait, j'ai trouvé de nombreuses situations où j'ai besoin de pousser vers un référentiel non nu, et j'utilise beaucoup la solution 2. De plus, la branche où je pousse sur le référentiel non nu n'est en aucun cas une branche temporaire, elle sert un objectif similaire à une branche de suivi à distance.
Nulle part homme

J'ai créé un dossier GIT sur mon serveur qui hébergera TOUS les référentiels créés par plusieurs utilisateurs à l'aide de SourceTree. J'ai créé un masterréférentiel sur mon PC local. J'ai ajouté leremotes dans le dossier du serveur et j'essaie de pousser mon référentiel dans le serveur afin qu'un autre utilisateur puisse le tirer / récupérer pour travailler. J'obtiens l'erreur suivante: ! [remote rejected] master -> master (branch is currently checked out)Comment puis-je l'archiver?
SearchForKnowledge

1
@SearchForKnowledge, vous rendez-vous compte que vous posez exactement la question à laquelle je réponds?!
Nulle part homme

65

Vous pouvez contourner cette "limitation" en modifiant le .git/configsur le serveur de destination. Ajoutez ce qui suit pour permettre à un référentiel git d'être poussé même s'il est "extrait":

[receive]
denyCurrentBranch = warn

ou

[receive]
denyCurrentBranch = false

Le premier permettra la poussée tout en avertissant de la possibilité de gâcher la branche, tandis que le second le permettra simplement tranquillement.

Cela peut être utilisé pour "déployer" du code sur un serveur qui n'est pas destiné à être édité. Ce n'est pas la meilleure approche, mais une approche rapide pour déployer du code.


7
L'utiliser pour "déployer" du code sur un serveur ne fonctionnera pas. Même si vous désactivez l'avertissement pour pouvoir pousser vers la branche extraite, la copie de travail n'est JAMAIS mise à jour lors d'une poussée.
Arrowmaster

10
J'utilise la méthode ci-dessus avec le cd .. && git reset --hardcrochet post-réception pour déployer. Hackish, mais fonctionne.
jholster

9
la version en ligne de commande de ce dernier seraitgit config receive.denyCurrentBranch warn
Andre Holzner

4
Ce devrait être la réponse acceptée. Certains d'entre nous savent ce que nous faisons et ne sont pas des débutants Git. Telle est la réponse pour ces gens.
Qix - MONICA A ÉTÉ MANQUÉ

2
Ha, mais la question n'a pas été posée par ces gens.
Nulle part homme

46

git config --local receive.denyCurrentBranch updateInstead

https://github.com/git/git/blob/v2.3.0/Documentation/config.txt#L2155

Utilisez-le sur le référentiel du serveur et il met également à jour l'arborescence de travail si aucun écrasement non suivi ne se produit.

Il a été ajouté dans Git 2.3 comme mentionné par VonC dans les commentaires.

J'ai compilé Git 2.3 et je l'ai essayé. Exemple d'utilisation:

git init server
cd server
touch a
git add .
git commit -m 0
git config --local receive.denyCurrentBranch updateInstead

cd ..
git clone server local
cd local
touch b
git add .
git commit -m 1
git push origin master:master

cd ../server
ls

Production:

a
b

Ouais, on bm'a poussé!


@VonC merci! C'est mon obsession du minimum d'exemples au travail :-)
Ciro Santilli 12 冠状 病 六四 事件 法轮功

Cela a-t-il des problèmes avec la validation des modifications qui ne sont pas à jour avec le serveur?
akozi

@akozi Je ne sais pas ce que vous voulez dire, si vous vous engagez localement avant de tirer, il se comportera exactement comme un --bareclone traditionnel, je pense: il --forceest nécessaire de pousser, et cela vous fera "perdre" les validations sur la télécommande.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli 新疆 改造 中心 六四 事件 法轮功 Pas de soucis maintenant. J'ai recherché la signification des options. Je pensais que updateInstead était synonyme de force.
akozi

updateInstead n'est plus une valeur valide pour
receive.denyCurrentBranch

41

J'aime l'idée d'avoir toujours un référentiel utilisable sur la boîte distante, mais au lieu d'une branche factice, j'aime utiliser:

git checkout --detach

Cela semble être une toute nouvelle fonctionnalité de Git - j'utilise la version 1.7.7.4 de git.


8
Et puis, après avoir poussé vos modifications, vous pouvez utiliser: git checkout masterpour revenir à la branche principale. Ce n'est qu'à ce moment que vos modifications sont appliquées.
MAZDAK

30

J'ai eu le même problème. Pour moi, j'utilise Git push pour déplacer du code vers mes serveurs. Je ne change jamais le code côté serveur, donc c'est sûr.

Dans le référentiel, vous appuyez sur pour taper:

git config receive.denyCurrentBranch ignore

Cela vous permettra de modifier le référentiel alors qu'il s'agit d'une copie de travail.

Après avoir exécuté un push Git, accédez à la machine distante et tapez ceci:

git checkout -f

Cela fera refléter les modifications que vous avez apportées dans la copie de travail de la machine distante.

Veuillez noter que ce n'est pas toujours sûr si vous apportez des modifications dans la copie de travail vers laquelle vous appuyez.


grâce à un journal, je fusionne votre suggestion denyCurrentBranchet mets git checkout -fdans un hooksdossier comme @ jack-senechal posté ici
Éderson T. Szlachta

Existe-t-il un moyen de faire apparaître les fichiers sur le référentiel distant sans y accéder et exécuter cette commande? À savoir par une commande du local?
Royi

24

Vous pouvez recréer votre référentiel de serveur et passer de votre maître de branche local au maître de serveur.

Sur votre serveur distant:

mkdir myrepo.git
cd myrepo.git
git init --bare

OK, depuis votre succursale locale:

git push origin master:master

3
Merci, c'était la solution pour moi car j'avais omis '--bare' sur le serveur distant. Il semble que les réponses à cette question dépendent de l'utilisation ou non du référentiel du serveur distant comme répertoire de travail et, dans le dernier cas, c'est la bonne réponse.
Cas

2
Je ne comprends pas: SI a essayé de créer et de cloner un référentiel nu, mais le clone n'a rien téléchargé et n'a rien téléchargé, donc cela ne fonctionne pas ... :-) J'ai lu des tutoriels sur les référentiels nus, mais ils disent qu'un référentiel nu ne contient aucun fichier ... Ce n'est certainement pas ce que je recherche ...
inf3rno

22

Ce que vous avez probablement fait pour provoquer cela:

Ce genre de chose se produit lorsque vous allez lancer un petit programme. Vous êtes sur le point de changer quelque chose qui fonctionnait déjà, alors vous lancez votre sort de niveau 3 d'annulation permanente:

machine1:~/proj1> git init

et vous commencez à ajouter / valider. Mais ensuite , le projet commence à s'impliquer davantage et vous voulez y travailler à partir d'un autre ordinateur (comme votre PC ou ordinateur portable), donc vous faites quelque chose comme

machine2:~> git clone ssh://machine1/~/proj1

et il clone et tout semble bon, et donc vous travaillez sur votre code à partir de machine2.

Ensuite ... vous essayez de pousser vos validations depuis machine2, et vous obtenez le message d'avertissement dans le titre.

La raison de ce message est que le dépôt git que vous avez extrait était destiné à être utilisé uniquement pour ce dossier sur machine1. Vous pouvez le cloner très bien, mais pousser peut causer des problèmes. La manière "correcte" de gérer le code dans deux emplacements différents est d'utiliser un dépôt "nu", comme cela a été suggéré. Un repo nu n'a pas été conçu pour avoir un travail accompli en elle, il est destiné à coordonner les commits provenant de sources multiples. C'est pourquoi la réponse la mieux notée suggère de supprimer tous les fichiers / dossiers autres que le dossier .git après vous git config --bool core.bare true.

Clarification de la réponse la mieux notée: la plupart des commentaires de cette réponse disent quelque chose comme "Je n'ai pas supprimé les fichiers non .git de la machine1 et j'ai quand même pu valider depuis la machine2". C'est vrai. Cependant, ces autres fichiers sont complètement "séparés" du dépôt git, maintenant. Allez- git statusy et vous devriez voir quelque chose comme "fatal: cette opération doit être exécutée dans une arborescence de travail". Donc, la suggestion de supprimer les fichiers n'est pas pour que le commit de machine2 fonctionne ; c'est pour que vous ne soyez pas confus et pensez que git suit toujours ces fichiers. Mais, la suppression des fichiers est un problème si vous voulez toujours travailler sur les fichiers sur machine1, n'est-ce pas?

Alors, que devez-vous vraiment faire?

Cela dépend de combien vous prévoyez de continuer à travailler sur machine1 et machine2 ...

Si vous avez terminé de développer à partir de machine1 et que vous avez déplacé tout votre développement vers machine2 ... faites simplement ce que la réponse la mieux suggérée: git config --bool core.bare truepuis, facultativement, supprimez tous les fichiers / dossiers autres que .git de ce dossier, car ils 'ne sont pas suivis et sont susceptibles de créer de la confusion.

Si votre travail sur machine2 n'était qu'une chose ponctuelle, et que vous n'avez pas besoin de poursuivre le développement là-bas ... alors ne vous embêtez pas à faire un repo nu; juste ftp / rsync / scp / etc. vos fichiers de la machine * 2 * au-dessus des fichiers de la machine * 1 *, validez / poussez de la machine * 1 *, puis supprimez les fichiers de la machine * 2 *. D'autres ont suggéré de créer une branche, mais je pense que c'est un peu compliqué si vous voulez simplement fusionner un développement que vous avez fait ponctuellement à partir d'une autre machine.

Si vous devez continuer le développement sur machine1 et machine2 ... alors vous devez configurer les choses correctement. Vous devez convertir votre dépôt en version nue, puis vous devez en faire un clone sur machine1 pour que vous puissiez y travailler . La façon la plus rapide de le faire est probablement de faire

machine1:~/proj1> git config --bool core.bare true
machine1:~/proj1> mv .git/ ../proj1.git
machine1:~/proj1> cd ..
machine1:~> rm -rf proj1
machine1:~> git clone proj1.git
machine1:~> cd proj1

Très important: comme vous avez déplacé l'emplacement du dépôt de proj1 vers proj1.git, vous devez le mettre à jour dans le fichier .git / config sur machine2 . Après cela, vous pouvez valider vos modifications à partir de machine2. Enfin, j'essaie de garder mes dépôts nus dans un emplacement central, loin de mes arbres de travail (c'est-à-dire ne placez pas «proj1.git» dans le même dossier parent que «proj1»). Je vous conseille de faire de même, mais je voulais garder les étapes ci-dessus aussi simples que possible.


Très détaillé et utile. Mon cas était le dernier, et vos instructions ont fonctionné comme un charme.
pojda

Je suis dans le cas 3 et j'ai fait quelque chose de légèrement différent: mk git-server; mv .git git-server / proj.git puis git clone git-server / proj.git à la fois 1 et 2 (ou origine distante git ...), en utilisant un préfixe ssh: // approprié pour la machine 2. De cette façon Je garderai une copie principale nue qui sera comme celle normalement sur GH ou un autre serveur HTTP et je continuerai à utiliser push / pull sur les deux machines.
zakmck

18

En quelques étapes de configuration, vous pouvez facilement déployer des modifications sur votre site Web à l'aide d'une ligne unique comme

git push production

Ce qui est agréable et simple, et vous n'avez pas besoin de vous connecter au serveur distant et de faire un pull ou quoi que ce soit. Notez que cela fonctionnera mieux si vous n'utilisez pas votre contrôle de production comme branche de travail! (L'OP fonctionnait dans un contexte légèrement différent, et je pense que la solution de @Robert Gould y répondait bien. Cette solution est plus appropriée pour le déploiement sur un serveur distant.)

Vous devez d'abord configurer un référentiel nu quelque part sur votre serveur, en dehors de votre racine Web.

mkdir mywebsite.git
cd mywebsite.git
git init --bare

Créez ensuite le fichier hooks/post-receive:

#!/bin/sh
GIT_WORK_TREE=/path/to/webroot/of/mywebsite git checkout -f

Et rendez le fichier exécutable:

chmod +x hooks/post-receive

Sur votre machine locale,

git remote add production git@myserver.com:mywebsite.git
git push production +master:refs/heads/master

Tout est prêt! Maintenant, à l'avenir, vous pouvez utiliser git push productionpour déployer vos modifications!

Le crédit pour cette solution va à http://sebduggan.com/blog/deploy-your-website-changes-using-git/ . Regardez là pour une explication plus détaillée de ce qui se passe.


Votre suggestion m'a beaucoup aidé, mais je n'y suis pas bare, je suis cela et fusion avec hooks(que vous suggérez) et a parfaitement fonctionné.
Éderson T. Szlachta

11

Vous devez uniquement pousser vers un référentiel nu. Un référentiel nu est un référentiel qui n'a pas de branches extraites. Si vous deviez cd dans un répertoire de référentiel nu, vous ne verriez que le contenu d'un répertoire .git.


9
Il n'y a rien de mal à pousser vers une branche non extraite dans un référentiel non nu. C'est une façon de travailler parfaitement valable.
CB Bailey

Très bien, cela fonctionnerait. Mais ce n'est pas ce que fait l'utilisateur.
RibaldEddie

13
Ce n'est pas le fait qu'il n'utilise pas un référentiel nu qui est «faux»; c'est le fait qu'il pousse vers une succursale vérifiée. Il n'y a aucune preuve qu'il a ou souhaite un référentiel nu séparé, donc votre déclaration générale selon laquelle il ne devrait pousser que vers un référentiel non nu ne donne pas au demandeur toutes les options; dont l'un pourrait résoudre plus facilement son problème immédiat.
CB Bailey

10

Vous avez 3 options

  1. Tirez et poussez à nouveau:

    git pull; git push
    
  2. Poussez dans une branche différente:

    git push origin master:foo
    

    et le fusionner à distance (soit par gitou pull-request )

    git merge foo
    
  3. Forcer (non recommandé, sauf si vous avez délibérément modifié les validations via rebase):

    git push origin master -f
    

    Si toujours refusé, désactivez denyCurrentBranch sur le référentiel distant:

    git config receive.denyCurrentBranch ignore
    

L'option 2 fonctionne pour moi. remote git init local git push origin master: branch remote git merge DONE
Jacky Chong

7

En fait, définir la télécommande sur une branche non extraite est suffisant. Après avoir vérifié votre télécommande dans une autre succursale, vous pouvez appuyer sur.


7

Vérifiez votre .git/configdans le projet de destination:

$ cat .git/config 
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
[receive]
    denyCurrentBranch = updateInstead

Si la valeur core. bareest false, vous pouvez la définir sur true:

$ git config core.bare true

puis dans votre poussée locale vers la télécommande:

git push remote_repo   // suppose the destination repo is remote_repo

cela réussira, dans remote_repo vous pouvez vérifier la version de git.

$ git log -1
commit 0623b1b900ef7331b9184722a5381bbdd2d935ba
Author: aircraft < aircraft_xxx@126.com>
Date:   Thu May 17 21:54:37 2018 +0800

et maintenant vous ne pouvez plus utiliser git dans votre "espace de travail":

$ git status
fatal: This operation must be run in a work tree

vous devez bare.barerevenir à faux.

$ git config core.bare false

5

J'ai eu le même problème en utilisant Git pour synchroniser les référentiels sur mon téléphone Android et mon ordinateur portable. La solution pour moi était de faire un pull au lieu d'un push, comme l'a suggéré @CharlesBailey.

git push origin master sur le référentiel Android échoue pour moi avec les mêmes messages d'erreur que @ hap497 a reçu en raison d'une poussée vers une extraction non nue d'un référentiel + copie de travail.

git pull droid mastersur le dépôt d'ordinateur portable et la copie de travail fonctionne pour moi. Bien sûr, vous devez avoir précédemment exécuté quelque chose comme git remote add droid /media/KINGSTON4GB/notes_repo/.


4

Les versions plus anciennes de Git permettaient de pousser vers la branche actuellement extraite d'un référentiel non nu.

Il s'avère que c'était une chose terriblement déroutante à autoriser. Ils ont donc ajouté le message d'avertissement que vous voyez, ce qui est également très déroutant.

Si le premier référentiel agit simplement comme un serveur, convertissez-le en référentiel nu comme les autres réponses le recommandent et terminez-en.

Si toutefois vous devez avoir une branche partagée entre deux référentiels qui sont tous deux en cours d'utilisation, vous pouvez y parvenir avec la configuration suivante

Repo1 - servira de serveur et sera également utilisé pour le développement

Repo2 - sera uniquement pour le développement

Configurez Repo1 comme suit

Créez une branche pour partager le travail.

git branch shared_branch

Pour être sûr, vous devez également créer un $ (REPO) .git / hooks / update qui rejette toutes les modifications apportées à autre chose que shared_branch, car vous ne voulez pas que les gens fassent le ménage avec vos branches privées.

repo1/.git/hooks  (GIT_DIR!)$ cat update
#!/bin/sh
refname="$1"
oldrev="$2"
newrev="$3"

if [ "${refname}" != "refs/heads/shared_branch" ]
then
   echo "You can only push changes to shared_branch, you cannot push to ${refname}"
   exit 1
fi

Créez maintenant une branche locale dans repo1 où vous ferez votre travail réel.

git checkout -b my_work --track shared_branch
Branch my_work set up to track local branch shared_branch.
Switched to a new branch 'my_work'

(peut être nécessaire git config --global push.default upstreampour git pushfonctionner)

Vous pouvez maintenant créer repo2 avec

git clone path/to/repo1 repo2 
git checkout shared_branch 

À ce stade, vous avez à la fois la configuration repo1 et repo2 pour travailler sur les branches locales qui poussent et tirent à partir shared_branchde repo1, sans avoir à vous soucier de ce message d'erreur ou à ne pas synchroniser le répertoire de travail dans repo1. Quel que soit le flux de travail normal que vous utilisez, il devrait fonctionner.


3

OK, si vous voulez un référentiel distant normal, créez une branche supplémentaire et vérifiez-la. Poussez-le dans une branche (qui n'est pas extraite) et fusionnez-le avec une qui est actuellement active plus tard après avoir poussé de localement.

Par exemple, sur un serveur distant:

git branch dev
git checkout dev

Sur la configuration locale:

git push 

Sur serveur distant:

git merge dev

2

Voici un test que vous pouvez faire pour voir comment fonctionnent les bareéléments du serveur:

Imaginez que vous avez un poste de travail et un serveur avec un site en direct hébergé sur celui-ci, et que vous souhaitez mettre à jour ce site de temps en temps (cela s'applique également à une situation où deux développeurs envoient leur travail dans les deux sens via un intermédiaire nu).

Initialisation

Créez un répertoire sur votre ordinateur local et cddans celui-ci, puis exécutez ces commandes:

# initialization
git init --bare server/.git
git clone server content
git clone server local
  1. Vous créez d'abord un serverrépertoire nu (notez le .git à la fin). Ce répertoire servira de conteneur pour vos fichiers de référentiel uniquement.
  2. Ensuite, clonez votre référentiel de serveur dans un contentrépertoire nouvellement créé . Il s'agit de votre répertoire live / production qui sera servi par votre logiciel serveur.
  3. Les deux premiers répertoires résident sur votre serveur, le troisième est un répertoire local sur votre poste de travail.

Workflow

Voici maintenant le workflow de base:

  1. Entrez dans le localrépertoire, créez des fichiers et validez-les. Enfin, poussez-les vers le serveur:

    # create crazy stuff
    git commit -av
    git push origin master
    
  2. Entrez maintenant dans le contentrépertoire et mettez à jour le contenu du serveur:

    git pull
    
  3. Répétez 1-2. Voici contentpeut-être un autre développeur qui peut également pousser vers le serveur, et localcomme vous pouvez le retirer.


2

L'utiliser pour le pousser vers la branche amont distante a résolu ce problème pour moi:

git push <remote> master:origin/master

La télécommande n'avait pas accès au référentiel en amont, donc c'était un bon moyen d'obtenir les dernières modifications dans cette télécommande


1
Plus généralement (car c'est l'effet net de la commande), en utilisant git push <remote> master:newbranch. L'idée est de pousser une nouvelle branche vers la télécommande, qui peut ensuite être fusionnée. De cette façon, vous évitez les problèmes d'incohérence mentionnés dans le message d'erreur.
Clay

1

J'ai dû réexécuter git --initdans un référentiel nu existant, et cela avait créé un .gitrépertoire à l'intérieur de l'arborescence du référentiel nu - je m'en suis rendu compte après git statusy avoir tapé . J'ai supprimé ça et tout allait bien à nouveau :)

(Toutes ces réponses sont excellentes, mais dans mon cas, c'était quelque chose de complètement différent (pour autant que je puisse voir), comme décrit.)


1

Je suis sûr que la plupart des gens qui consultent cette question s'arrêteront aux deux premières réponses énormes, mais j'aimerais toujours offrir ma solution.

J'ai eu une configuration de projet Web Eclipse + EGit lorsque j'ai rencontré l'erreur décrite. Ce qui m'a aidé, c'était simplement d'utiliser l'application GitHub, qui semblait résoudre magiquement le problème. Alors qu'EGit refuserait toujours la poussée, l'application de bureau GitHub hausserait simplement les épaules et pousserait mes changements. Peut-être qu'il gère la situation de connexion multiple plus gracieusement.


1

Un article que j'ai trouvé qui pourrait être utile à d'autres est Git en 5 minutes .

J'avais un projet Xcode sous contrôle de version Git que je voulais pousser vers un Ethernet distribué virtuel (VDE) que j'ai dans un DC. Le VDE exécute Centos 5.

Aucun des articles que j'ai lus sur Git ne parlait de référentiels nus. Tout cela semblait si simple jusqu'à ce que j'essaie ce que je pensais être facile venant d'un arrière-plan SVN .

Les suggestions ici pour rendre le référentiel distant fonctionnel. Encore mieux pour mes besoins était de cloner le projet Xcode projectname.git, de le copier sur le serveur distant; puis pousse comme par magie travaillé. La prochaine étape consistera à faire pousser Xcode sans erreurs sur les commits, mais pour l'instant je le fais bien depuis Terminal.

Donc:

cd /tmp (or another other directory on your system)<br/>
git clone --bare /xcode-project-directory projectname.git<br/>
scp -r projectname.git sshusername@remotehost.com:repos/<br/>

Pour pousser les modifications de votre projet Xcode après vous être engagé dans Xcode:

cd /xcode-project-directory<br/>
git push sshusername@remotehost.com:repos/projectname.git<br/>

Je suis certain qu'il existe une façon plus fluide et plus sophistiquée de faire ce qui précède, mais au minimum cela fonctionne. Pour que tout soit clair, voici quelques clarifications: /xcode-project-directoryest le répertoire dans lequel votre projet xcode est stocké. C'est probablement /Users/Your_Name/Documents/Project_Name. projectname est littéralement le nom du projet, mais vous pouvez l'appeler comme vous le souhaitez. Git s'en fiche, vous le ferez.

Pour utiliser scp, vous devez disposer d'un compte utilisateur sur le serveur distant autorisé à accéder à SSH . Toute personne exécutant son propre serveur en aura un. Si vous utilisez un hébergement mutualisé ou similaire, vous risquez de ne pas avoir de chance.

remotehost.comest le nom de votre hôte distant. Vous pouvez tout aussi facilement utiliser son adresse IP. Pour plus de clarté, j'utilise Gitosis sur l'hôte distant avec des clés SSH, donc je ne suis pas invité à entrer des mots de passe lorsque j'appuie. L'article Hosting Git Repositories, the Easy (and Secure) Way vous explique comment configurer tout cela.


1

La meilleure façon de procéder est:

mkdir ..../remote
cd ..../remote
git clone --bare .../currentrepo/

Cela clonera le référentiel, mais ne fera aucune copie de travail dans .../remote. Si vous regardez la télécommande, vous verrez un répertoire créé, appelé currentrepo.git, qui est probablement ce que vous voulez.

Ensuite, à partir de votre référentiel Git local:

git remote add remoterepo ..../remote/currentrepo.git

Après avoir apporté des modifications, vous pouvez:

git push remoterepo master

1

Je viens de rencontrer ce problème avec un dépôt git de déploiement sur Heroku .

Je ne sais pas pourquoi Heroku a un référentiel non nu de leur côté, mais comme solution de contournement, j'ai pu réinitialiser le référentiel distant et le télécharger à nouveau.

Vous ne devriez pas utiliser la copie Heroku de votre référentiel comme votre seul référentiel git pour la collaboration, mais juste au cas où, je dirai clairement: ne le faites pas sauf si vous êtes sûr d'avoir une copie complète de votre référentiel stockée en toute sécurité ailleurs que Heroku. Une réinitialisation supprimera le contenu du référentiel.

Réinitialiser:

  1. Installez la ceinture d'outils Heroku (qui contient le client de ligne de commande) si vous ne l'avez pas déjà fait.
  2. Installez le plugin heroku-repo si vous ne l'avez pas déjà fait.

    heroku plugins:install https://github.com/heroku/heroku-repo.git
    
  3. Effectuez la réinitialisation, qui supprime le référentiel et en crée un nouveau vide

    heroku repo:reset
    
  4. Poussez vers votre télécommande Heroku comme vous le feriez normalement; il va tout re-télécharger.


Vous devrez peut-être installer les outils de dépôt Heroku pour que cela fonctionne. Faireheroku plugins:install https://github.com/heroku/heroku-repo.git
Noah

1

Vous devrez modifier le fichier de configuration sur le serveur distant une fois que vous aurez créé le référentiel vide (nu), par exemple

root@development:/home/git/repository/my-project# cat config 

là tu verras

[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true

Vous rendrez cela faux à faux à vrai et j'ai supprimé logallrefupdates = true (pas sûr de son utilisation!)

à

[core]
repositoryformatversion = 0
filemode = true
bare = true

Vous pouvez tester suivant

$ git remote show origin
* remote origin
Fetch URL: my-portal@development:/home/XYZ/repository/XYZ
Push  URL: my-portal@development:/home/XYZ/repository/XYZ
HEAD branch: (unknown)

Cette branche HEAD: (inconnue) s'affichera si vous ne pouvez pas POUSSER. Donc, si la branche HEAD est inconnue, vous devez changer nu pour true et après avoir réussi, vous pouvez réutiliser le

git remote show origin

et vous allez voir

 HEAD branch: master

0

Pour moi, la solution de travail est:

À DISTANCE:

git checkout -b some_tmp_name

SUR LOCAL:

git push

À DISTANCE:

git checkout master
git branch -d some_tmp_name

Mais ce n'est pas la vraie solution, c'est juste une solution de contournement.


C'est une solution valable si vous n'avez pas de référentiel central.
Rick

0

Juste au cas où quelqu'un le trouverait utile. Pour moi, c'était un problème d'autorisations de serveur git. J'ai vérifié le projet depuis le début et j'ai poussé un fichier simple, puis j'ai reçu le "Push rejeté: le push vers l'origine / le master a été rejeté"


-1

Avec Git, deux référentiels normaux (non nus) ne peuvent pas pousser / tirer des fichiers d'avant en arrière directement. Il doit y avoir un référentiel nu intermédiaire. Apparemment, c'est un peu comme un couple marié qui a un enfant, et le couple divorce. Les parents ne se parleront pas, mais ils communiqueront par l'intermédiaire de l'enfant.

Donc, vous avez un référentiel, vous clonez ce référentiel dans un référentiel nu, puis vous le clonez dans un troisième. Le premier et le troisième peuvent échanger des informations via le deuxième référentiel, le nu. Je suppose que cela a du sens, car vous ne voudriez pas que quelqu'un puisse archiver des choses dans votre référentiel sans votre consentement, car cela pourrait provoquer des conflits de fusion, etc.

Voici donc un exemple:

Sur PC, dans ~ / workspace

git init
echo "line 1" > afile.txt
git add .
git commit -m ‘initial import’
git clone --bare . ../remote-repository.git
git remote add origin ../remote-repository.git
git push --set-upstream origin master

Sur ordinateur portable, dans ~ / workspace (ne faites pas git init, etc.)

git clone //LJZ-DELLPC/remote-repository.git/ .

// Ensuite, faites divers commits et poussez-les:

echo "line 2" > afile.txt
git add afile.txt
git commit -m 'added line 2'
git push    

Puis de retour sur PC, dans ~ / workspace

git pull

// Ensuite, faites divers commits et poussez-les:

git push

Sur ordinateur portable git pull

et ainsi de suite..

Voici un exemple concret absolu sur une seule machine, copié directement depuis la fenêtre de commande, afin que nous sachions qu'aucune étape n'a été omise, que cela a vraiment fonctionné, etc.:

lylez@LJZ-DELLPC ~
$ cd gitdir
/home/lylez/gitdir

lylez@LJZ-DELLPC ~/gitdir
$ ls

lylez@LJZ-DELLPC ~/gitdir
$ mkdir repo1

lylez@LJZ-DELLPC ~/gitdir
$ cd repo1
/home/lylez/gitdir/repo1

lylez@LJZ-DELLPC ~/gitdir/repo1
$ git init
Initialized empty Git repository in /home/lylez/gitdir/repo1/.git/

lylez@LJZ-DELLPC ~/gitdir/repo1
$ echo "line 1" > afile.txt

lylez@LJZ-DELLPC ~/gitdir/repo1
$ git add afile.txt

lylez@LJZ-DELLPC ~/gitdir/repo1
$ git commit -m 'initial import'
[master (root-commit) f407e12] initial import
 1 file changed, 1 insertion(+)
 create mode 100644 afile.txt

lylez@LJZ-DELLPC ~/gitdir/repo1
$ git clone --bar . ../repo1-bare-clone
Cloning into bare repository '../repo1-bare-clone'...
done.

lylez@LJZ-DELLPC ~/gitdir/repo1
$ git remote add origin ../repo1-bare-clone

lylez@LJZ-DELLPC ~/gitdir/repo1
$ git push --set-upstream origin master
Branch master set up to track remote branch master from origin.
Everything up-to-date

lylez@LJZ-DELLPC ~/gitdir/repo1
$ cd ..

lylez@LJZ-DELLPC ~/gitdir
$ ls
repo1  repo1-bare-clone

lylez@LJZ-DELLPC ~/gitdir
$ mkdir repo1-remote

lylez@LJZ-DELLPC ~/gitdir
$ cd repo1-remote
/home/lylez/gitdir/repo1-remote

lylez@LJZ-DELLPC ~/gitdir/repo1-remote
$ git clone ../repo1-bare-clone .
Cloning into '.'...
done.

lylez@LJZ-DELLPC ~/gitdir/repo1-remote
$ ls
afile.txt

lylez@LJZ-DELLPC ~/gitdir/repo1-remote
$ cat afile.txt
line 1

lylez@LJZ-DELLPC ~/gitdir/repo1-remote
$ echo "line 2" >> afile.txt

lylez@LJZ-DELLPC ~/gitdir/repo1-remote
$ git add afile.txt

lylez@LJZ-DELLPC ~/gitdir/repo1-remote
$ git commit -m 'added line 2'
[master 5ad31e0] added line 2
 1 file changed, 1 insertion(+)

lylez@LJZ-DELLPC ~/gitdir/repo1-remote
$ git push
Counting objects: 3, done.
Writing objects: 100% (3/3), 260 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To /home/lylez/gitdir/repo1-remote/../repo1-bare-clone
   f407e12..5ad31e0  master -> master

lylez@LJZ-DELLPC ~/gitdir/repo1-remote
$ cd ../repo1

lylez@LJZ-DELLPC ~/gitdir/repo1
$ ls
afile.txt

lylez@LJZ-DELLPC ~/gitdir/repo1
$ cat afile.txt
line 1

lylez@LJZ-DELLPC ~/gitdir/repo1
$ git pull
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From ../repo1-bare-clone
   f407e12..5ad31e0  master     -> origin/master
Updating f407e12..5ad31e0
Fast-forward
 afile.txt | 1 +
 1 file changed, 1 insertion(+)

lylez@LJZ-DELLPC ~/gitdir/repo1
$ cat afile.txt
line 1
line 2

lylez@LJZ-DELLPC ~/gitdir/repo1
$ echo "line 3" >> afile.txt

lylez@LJZ-DELLPC ~/gitdir/repo1
$ git add afile.txt

lylez@LJZ-DELLPC ~/gitdir/repo1
$ git commit -m 'added line 3'
[master 3fa569e] added line 3
 1 file changed, 1 insertion(+)

lylez@LJZ-DELLPC ~/gitdir/repo1
$ git push
Counting objects: 3, done.
Writing objects: 100% (3/3), 265 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To ../repo1-bare-clone
   5ad31e0..3fa569e  master -> master

lylez@LJZ-DELLPC ~/gitdir/repo1
$ cd ../repo1-remote/

lylez@LJZ-DELLPC ~/gitdir/repo1-remote
$ ls
afile.txt

lylez@LJZ-DELLPC ~/gitdir/repo1-remote
$ cat afile.txt
line 1
line 2

lylez@LJZ-DELLPC ~/gitdir/repo1-remote
$ git pull
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /home/lylez/gitdir/repo1-remote/../repo1-bare-clone
   5ad31e0..3fa569e  master     -> origin/master
Updating 5ad31e0..3fa569e
Fast-forward
 afile.txt | 1 +
 1 file changed, 1 insertion(+)

lylez@LJZ-DELLPC ~/gitdir/repo1-remote
$ cat afile.txt
line 1
line 2
line 3

lylez@LJZ-DELLPC ~/gitdir/repo1-remote
$ git --version
git version 2.1.1

lylez@LJZ-DELLPC ~/gitdir/repo1-remote

C'est un exemple de ce qui fonctionne et une explication de pourquoi. Il n'y a aucune désinformation ici, sauf pour votre commentaire.
Lyle Z

1
"Avec Git, deux référentiels normaux (non nus) ne peuvent pas pousser / tirer des fichiers dans les deux sens directement" - Sauf qu'ils le peuvent.
Andrew C

Très bien, postez un exemple concret au lieu d'une attaque.
Lyle Z


La première réponse dans le fil de discussion de votre site commence par, "... mais selon git ready et le wiki officiel de git, vous ne devriez pousser que vers un dépôt nu.". La réponse suivante indique: "Si vous voulez simplement pousser master -> master, alors la commande est juste: git push origin", et cela ne fonctionne tout simplement pas, et il y a des millions de publications à cet effet. La dernière réponse commence par "Je suggérerais d'avoir un référentiel nu et un référentiel de travail local (non nu) sur votre serveur.", Ce qui est exactement ce que j'ai proposé.
Lyle Z

-3

Ma solution (en cours d'utilisation)

  1. Extraire "maître" sur le serveur distant
  2. Travailler localement sur la branche "dev"
  3. Transférer les modifications au développeur distant
  4. Fusionner le dev en maître sur la télécommande

bingo

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.