Erreur Git Push: refus de mettre à jour la branche extraite

196

J'ai résolu certains conflits de fusion, commis puis j'ai essayé de pousser mes modifications et j'ai reçu l'erreur suivante:

c:\Program Files (x86)\Git\bin\git.exe push --recurse-submodules=check "origin" master:master
Done
remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error: 
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error: 
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
To C:/Development/GIT_Repo/Project
 ! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to 'C:/Development/GIT_Repo/Project'

Quelqu'un sait-il ce qui pourrait être à l'origine de cette erreur?

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

Réponses:

229

Raison: vous passez à un référentiel non dénudé

Il existe deux types de référentiels: nus et non nus

Les référentiels nus n'ont pas de copie de travail et vous pouvez y accéder. Ce sont les types de référentiels que vous obtenez dans Github! Si vous souhaitez créer un référentiel nu, vous pouvez utiliser

git init --bare

Donc, en bref, vous ne pouvez pas pousser vers un référentiel non nu(Edit: Eh bien, vous ne pouvez pas pousser vers la branche actuellement retirée d'un référentiel. Avec un référentiel nu, vous pouvez pousser vers n'importe quelle branche car aucune n'est extraite. Bien que possible, pousser vers des référentiels non dénudés n'est pas courant) . Ce que vous pouvez faire, c'est récupérer et fusionner à partir de l'autre référentiel. C'est ainsi pull requestque fonctionne le Github. Vous leur demandez de se retirer de vous et vous ne les forcez pas.


Mise à jour : Merci à VonC de l'avoir signalé, dans les dernières versions de git (actuellement 2.3.0), il est possible de pousser vers la branche extraite d'un référentiel non nu . Néanmoins, vous ne pouvez toujours pas pousser vers un arbre de travail sale , ce qui n'est pas une opération sûre de toute façon.

Shahbaz
la source
1
Oui! C'est correct merci! Comme j'ai environ un million de choses à faire, j'ai accidentellement cloné le répertoire de travail .... doh!
Funky
25
En fait, vous pouvez très bien pousser vers un référentiel non nu, vous ne pouvez pas pousser vers la seule branche qui est actuellement extraite .
Nulle part homme le
1
Il existe en fait des dizaines d'autres scénarios. Par exemple, certains de mes référentiels se trouvent uniquement sur mon poste de travail et mon ordinateur portable (pas de code, mais des notes que je prends). Sur chacun, j'ai deux branches, "poste de travail" et "ordinateur portable". Sur le poste de travail, je ne vérifie que "poste de travail", et je pousse uniquement vers la branche "poste de travail" sur l'ordinateur portable (et vice-versa).
Nowhere man
8
En fait, vous avez maintenant un moyen sécurisé de passer à un git config receive.denyCurrentBranch=updateInstead
référentiel
1
@skelly Votre clone n'est pas nu, tandis que la copie sur github. Ainsi, alors que les deux clones ont tout l'historique, la copie sur github n'a pas de commit extrait, mais votre copie en a, pour vous permettre de travailler!
Shahbaz
115

J'ai résolu ce problème en vérifiant d'abord que la télécommande n'avait rien vérifié (ce n'était vraiment pas censé le faire), puis je l'ai mis à nu avec:

$ git config --bool core.bare true

Après ce git push a bien fonctionné.

Sasha Pachev
la source
3
C'est le correctif à une ligne que je cherchais .. mais peut-être expliquer les repos non nus comme la réponse
@shahbaz
Cela permettra de pousser l'historique des modifications, mais ces modifications ne seront pas reflétées dans le référentiel non nu.
jhill515
voulez-vous git config core.bare falseet git reset --hard ?
avion
1
Comme mentionné ci-dessus, la télécommande ne sera pas modifiée lorsque vous appuyez dessus.
user1097111
46

Résumé

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 effectuer une poussée vers n'importe quelle branche d'un référentiel nu.

Autopsie du problème

Lorsqu'une branche est extraite, la validation ajoute un nouveau commit avec la tête de la branche actuelle comme parent et déplace la tête de la branche pour être ce nouveau commit.

Alors

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 la branche1, 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 simplement suspendu :

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

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

Nulle part l'homme
la source
Je me suis un peu développé dans stackoverflow.com/questions/2816369/…
Nowhere man
21

cd dans le repo / répertoire dans lequel vous poussez sur la machine distante et entrez

$ git config core.bare true
Ricky
la source
Cela ne fonctionne pas. Le référentiel reste vide après l'avoir poussé.
Sören
comme dit par jhil515 ci-dessus, les fichiers non nus ne sont pas mis à jour, seulement les bases de données.
Denis Cousineau
19

Pour moi, ce qui suit a fait l'affaire:

git config --global receive.denyCurrentBranch updateInstead

J'ai configuré le lecteur F :, presque dans son intégralité, pour synchroniser entre mon bureau Windows 10 et mon ordinateur portable Windows 10, à l'aide de Git. J'ai fini par exécuter la commande ci-dessus sur les deux machines.

J'ai d'abord partagé le lecteur F du bureau sur le réseau. Ensuite, j'ai pu le cloner sur mon ordinateur portable en exécutant:

F: git clone 'file://///DESKTOP-PC/f'

Malheureusement, tous les fichiers se sont retrouvés sous "F: \ f \" sur mon ordinateur portable, pas directement sous F: \. Mais j'ai pu les couper et les coller manuellement. Git a toujours travaillé depuis le nouvel emplacement par la suite.

Ensuite, j'ai essayé d'apporter des modifications aux fichiers sur l'ordinateur portable, de les valider et de les repousser sur le bureau. Cela n'a pas fonctionné jusqu'à ce que j'exécute la commande git config mentionnée ci-dessus.

Notez que j'ai exécuté toutes ces commandes à partir de Windows PowerShell, sur les deux machines.

MISE À JOUR: J'ai toujours eu des problèmes pour pousser les changements, dans certains cas. J'ai finalement commencé à extraire les modifications à la place, en exécutant ce qui suit sur l'ordinateur sur lequel je veux extraire les derniers commit (s):

git pull --all --prune

Stephen G Tuggy
la source
1
Je préfère ce local au git repo:git config receive.denyCurrentBranch updateInstead
klor
14

Comme il existe déjà un référentiel, l'exécution

git config --bool core.bare true

sur le référentiel distant devrait suffire

De la documentation core.bare

Si true (nu = vrai), le référentiel est supposé être nu sans aucun répertoire de travail associé. Si tel est le cas, un certain nombre de commandes qui nécessitent un répertoire de travail seront désactivées, telles que git-add ou git-merge (mais vous pourrez y pousser).

Ce paramètre est automatiquement deviné par git-clone ou git-init lorsque le référentiel est créé. Par défaut, un référentiel se terminant par "/.git" est supposé non nu (nu = faux), tandis que tous les autres référentiels sont supposés être nu (nu = vrai).

Johnny
la source
12

TLDR

  1. Pull & pousser à nouveau: git pull &&& git push.
  2. Encore un problème? Poussez dans une branche différente: git push origin master:fooet fusionnez-la sur le repo distant.
  3. Vous pouvez également forcer la poussée en ajoutant -f( denyCurrentBranchdoit être ignoré).

Fondamentalement, l'erreur signifie que votre référentiel n'est pas à jour avec le code distant (son index et son arborescence de travail ne correspondent pas à ce que vous avez poussé).

Normalement, vous devriez d' pullabord obtenir les modifications récentes et pushrecommencer.

Si cela ne vous aide pas, essayez de pousser dans une branche différente, par exemple:

git push origin master:foo

fusionnez ensuite cette branche sur le référentiel distant avec master.

Si vous avez intentionnellement modifié certaines validations passées via git rebaseet que vous souhaitez remplacer le repo par vos modifications, vous souhaiterez probablement forcer le push en ajoutant -f/ --forceparameter (déconseillé si vous ne l'avez pas fait rebase). Si ne fonctionne toujours pas, vous devez définir receive.denyCurrentBranchà ignorela télécommande comme suggéré par un message git via:

git config receive.denyCurrentBranch ignore
Kenorb
la source
3

Peut-être que votre dépôt à distance se trouve dans la branche que vous souhaitez pousser. Vous pouvez essayer de retirer une autre branche de votre machine distante. J'ai fait cela, alors que ces erreurs ont disparu, et j'ai poussé le succès vers mon dépôt à distance. Notez que j'utilise ssh pour connecter mon propre serveur au lieu de github.com.

JZAU
la source
1

J'ai cette erreur parce que le dépôt git a été (accidentellement) initialisé deux fois au même emplacement: d'abord comme un dépôt non nu et peu de temps après comme un dépôt nu. Étant donné que le dossier .git reste, git suppose que le référentiel n'est pas nu. La suppression du dossier .git et des données du répertoire de travail a résolu le problème.

xastor
la source
1
Dans ma situation, c'était le cas. La suppression du .gitdossier sur la télécommande m'a permis de pousser le commit initial.
tim.rohrer
0

J'ai eu cette erreur lorsque je jouais pendant la lecture de progit. J'ai créé un référentiel local, puis je l'ai récupéré dans un autre référentiel sur le même système de fichiers, j'ai fait une modification et j'ai essayé de pousser. Après avoir lu la réponse de NowhereMan, une solution rapide consistait à aller dans le répertoire "distant" et à extraire temporairement un autre commit, à pousser à partir du répertoire dans lequel j'avais apporté des modifications, puis à revenir en arrière et à remettre la tête sur master.

Nathan Chappell
la source