Pour en savoir plus sur la poussée des forces, voir mon autre réponse .
Cette réponse explique que le problème fondamental de l'affiche originale est pas la façon dont il pousse la force, mais plutôt qu'il pousse à une non dénudé (au lieu d'un repo nu).
Comme indiqué dans d'autres réponses 1 il n'est généralement pas recommandé de pousser vers des dépôts non dénudés, car bien que vous puissiez mettre à jour une branche distante référence en poussant, Les pushes Git ne mettront pas réellement à jour la copie de travail ni l'index/staging-area du repo distant non-bare.
Cela signifie que la copie de travail et l'index/staging-area du dépôt distant seront toujours définis comme les versions des fichiers qui existaient. avant que vous avez poussé, tandis que la référence symbolique HEAD
sera placé à l'extrémité de la branche nouvellement poussée. Ainsi, il apparaîtra que les changements du commit précédent sont toujours mis à disposition. ce qui correspond à ce que vous avez indiqué dans votre question :
Je remarque que les fichiers contiennent des modifications périmées (celles que le repo principal distant avait auparavant).
1 Voir <a href="http://stackoverflow.com/a/5509650/456814">La réponse de VonC </a>et <a href="http://stackoverflow.com/a/5509588/456814">La réponse de ubik </a>.
Comment reproduire le problème
Tout d'abord, créez un nouveau dépôt Git non dénudé, et remplissez-le avec quelques fichiers :
mkdir main
cd main
git init
echo hello > hello.txt
git add .
git commit -m "Hello"
echo bye > bye.txt
git add .
git commit -m "Bye"
Les versions actuelles de Git ne vous permettent pas de pousser vers un dépôt non nu par défaut, vous devrez donc configurer ce dépôt pour l'autoriser :
git config receive.denyCurrentBranch warn
Ensuite, faites un autre clone, et faites un hard reset en revenant à un commit, puis poussez :
$ cd ..
$ git clone main second
$ git reset --hard head^
$ git push --force
Total 0 (delta 0), reused 0 (delta 0)
remote: warning: updating the current branch
To main
+ 3c3ee2b...2f34b62 master -> master (forced update)
Retournez maintenant au dépôt principal et vérifiez les journaux et l'état des fichiers. Vous verrez que même si la branche principale est revenue au commit original, la zone de transit contient toujours les changements du second commit qui a été annulé dans la branche par le push forcé :
$ cd ../main
$ git log --oneline --decorate
2f34b62 (HEAD, master) Add hello.txt
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: bye.txt
Solution
Si vous voulez que la copie de travail et l'index/zone d'échelonnement dans le distant non nu correspondent au commit actuel de la branche courante (représenté par la référence symbolique HEAD
), alors vous devez simplement faire une réinitialisation dure pour HEAD
:
git reset --hard HEAD
Enfin, il est recommandé de ne pousser qu'à nu au lieu de dépôts non nus, à cause de ce même problème de la copie de travail et de l'index qui ne sont plus synchronisés avec la branche de votre dépôt et les références symboliques.
Un moyen simple de convertir un repo non nu en repo nu est de le reclasser :
git clone --bare originalRepo bareRepo
cd bareRepo
git remote rm origin
Documentation
De la Page de manuel de git-config(1) (c'est moi qui souligne) :
receive.denyCurrentBranch
S'il est défini à true ou "refuse", git-receive-pack refusera une mise à jour de la référence à la branche actuellement extraite d'un dépôt non nu. Une telle poussée est potentiellement dangereuse car elle désynchronise le HEAD avec l'index et l'arbre de travail. S'il est défini à "warn", un message d'avertissement sera affiché sur stderr, mais le push sera autorisé. S'il est défini à false ou "ignore", autorise de telles poussées sans message. La valeur par défaut est "refuse".
Ce paramètre est disponible dans Git depuis la version 1.6.2 qui est sorti le 4 mars th , 2009. Comme l'indique la documentation ci-dessus, le réglage par défaut consiste à refuser les poussées, même les poussées forcées.
Démonstration que la force qui pousse n'est pas une solution au problème réel de l'affiche originale
Parce qu'il semble y avoir beaucoup de confusion à ce sujet, je vais démontrer que la poussée de force n'est pas la bonne solution pour résoudre votre problème.
Tout d'abord, créez un dépôt principal comme dans les étapes précédentes de reproduction ci-dessus, ainsi qu'un second clone de ce dépôt principal, mais cette fois, ne mettez pas receive.denyCurrentBranch
. Ce paramètre refuser des poussées, même des poussées forcées, vers des dépôts distants non dénudés, et a été le paramètre par défaut depuis la version 1.6.2 de Git .
Ensuite, à partir du second clone, essayez de forcer le push vers le repo principal :
$ git push --force
Total 0 (delta 0), 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 main
! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to 'main'
Ou avec git push origin master --force
:
$ git push origin master --force
Total 0 (delta 0), 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 main
! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to 'main'
Comme vous le verrez ci-dessus, quelle que soit la façon dont vous essayez de pousser vers le repo distant non dénudé, Git ne l'autorise pas par défaut. Même si vous définissez receive.denyCurrentBranch
pour permettre la poussée de la force, il ne touchera toujours pas l'index et l'arbre de travail du repo distant non-bare ce qui rend
git reset --hard HEAD
la solution correcte lorsque la copie de travail et la zone d'indexation/staging d'un distant non nu ne sont plus synchronisées avec la copie symbolique. HEAD
référence.
4 votes
Vous serez bientôt (git1.8.5, Q4 2013) en mesure de faire un
git push -force
plus attentivement .1 votes
En rapport : Force git à écraser les fichiers distants lors du push .
9 votes
Comme je le détaille dans ma propre réponse ,
git push --force
est en effet une autre manière valide de forcer le push, et poussera les branches tout aussi bien quegit push origin master --force
avec la méthode par défaut de Gitpush.default config settings
Les branches qui sont poussées diffèrent selon que la version de Git est antérieure ou postérieure à la version 2.0.4 votes
git push --force
fonctionne bien ces jours-ci, FWIW...4 votes
git push --force-with-lease
fonctionne encore mieux :), il refusera de mettre à jour une branche à moins qu'elle ne soit dans l'état que vous attendez. (voir developer.atlassian.com/blog/2015/04/force-with-lease )0 votes
soyez juste prudents les gars > Lorsque vous poussez du code vers la branche principale [remote repo], cela supprime le code précédent présent dans la branche principale. > et force la mise à jour de votre code avec le code précédent. c'est à dire que lorsque vous forcez le push, le code précédent sera remplacé par votre code. [consultez ce blog pour plus d'informations]( evilmartians.com/chronicles/ ) Bon codage :)