Réinitialiser la branche du référentiel local pour qu'elle soit comme le référentiel distant HEAD

3859

Comment réinitialiser ma branche locale pour qu'elle ressemble à la branche du référentiel distant?

J'ai fait:

git reset --hard HEAD

Mais quand je lance un git status,

On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
      modified:   java/com/mycompany/TestContacts.java
      modified:   java/com/mycompany/TestParser.java

Pouvez-vous me dire pourquoi je les ai «modifiés»? Je n'ai pas touché ces fichiers? Si je l'ai fait, je veux les supprimer.

hap497
la source
8
Selon la sortie de git statusvotre deuxième commande a git reset --hard HEADéchoué. Vous n'avez pas collé sa sortie, cependant. → Question incomplète.
Robert Siemer
2
Vous mélangez deux problèmes ici: 1) comment réinitialiser une branche locale au point où se trouve la télécommande et 2) comment effacer votre zone de transit (et éventuellement le répertoire de travail), donc cela git statusdit nothing to commit, working directory clean. - Veuillez préciser!
Robert Siemer

Réponses:

6700

La configuration de votre branche pour correspondre exactement à la branche distante peut être effectuée en deux étapes:

git fetch origin
git reset --hard origin/master

Si vous souhaitez enregistrer l'état de votre branche actuelle avant de le faire (juste au cas où), vous pouvez faire:

git commit -a -m "Saving my work, just in case"
git branch my-saved-work

Maintenant, votre travail est enregistré sur la branche "mon-travail-enregistré" au cas où vous décideriez de le récupérer (ou de le regarder plus tard ou de le comparer à votre branche mise à jour).

Notez que le premier exemple suppose que le nom du référentiel distant est "origine" et que la branche nommée "master" dans le référentiel distant correspond à la branche actuellement extraite dans votre référentiel local.

BTW, cette situation dans laquelle vous vous trouvez ressemble énormément à un cas courant où une poussée a été effectuée dans la branche actuellement extraite d'un référentiel non nu. Avez-vous récemment intégré votre référentiel local? Si ce n'est pas le cas, alors ne vous inquiétez pas - quelque chose d'autre doit avoir causé la modification inattendue de ces fichiers. Sinon, vous devez savoir qu'il n'est pas recommandé de pousser dans un référentiel non nu (et pas dans la branche actuellement extraite, en particulier).

Dan Moulding
la source
4
Merci pour votre réponse. Vous avez dit "Notez que le premier exemple suppose que le nom du référentiel distant est" origin "et que la branche nommée" master "dans le référentiel distant correspond à la branche dans votre référentiel local." Comment puis-je vérifier le nom de mon référentiel distant et le nom de ma succursale pour être sûr avant d'exécuter 'git reset --hard'? Merci encore.
hap497
21
Si vous n'avez pas nommé explicitement la télécommande, son nom est probablement juste "origine" (par défaut). Vous pouvez utiliser "git remote" pour obtenir une liste de tous les noms de télécommandes. Vous pouvez ensuite utiliser "git remote <nom>" pour voir quelles branches pousser / tirer les unes avec les autres (par exemple, si votre branche "master" a été clonée à partir de "master" dans la télécommande nommée "origin", alors vous obtiendrez une ligne qui dit "le maître fusionne avec le maître distant").
Dan Moulding,
6
"il n'est pas recommandé de pousser dans un référentiel non-nu (et pas dans la branche actuellement
extraite
27
Juste après avoir récupéré, je pense que vous pouvez également faire à la git reset FETCH_HEAD --hardplace, c'est la même signification.
Jean
6
Il n'a pas supprimé les fichiers que j'ai ajoutés.
Trismegistos
417

Je devais faire (la solution dans la réponse acceptée):

git fetch origin
git reset --hard origin/master

Suivi par:

git clean -f

supprimer des fichiers locaux

Pour voir quels fichiers seront supprimés (sans les supprimer réellement):

git clean -n -f
Akavall
la source
89
également, git clean -d -fsi des répertoires non suivis sont présents.
garg
54
aussigit clean -fdx
Swapnil Kotwal
14
Si vous voulez une copie exacte de la branche distante, vous devez suivre git clean -ffdx. Notez qu'il y en a deux f.
Trismegistos
6
Le git clean -fétait la pièce essentielle dont je avais besoin. Merci!
dgo
17
soyez prudent en utilisant la commande clean. il peut supprimer des fichiers ignorés d'autres branches.
mikoop
307

Tout d'abord, réinitialisez-le sur la HEADbranche en amont précédemment récupérée :

git reset --hard @{u}

L'avantage de la spécification @{u}ou de sa forme verbeuse @{upstream}est que le nom du référentiel distant et de la branche ne doit pas être explicitement spécifié.

Ensuite, au besoin, supprimez les fichiers non suivis, éventuellement également avec -x:

git clean -df

Enfin, au besoin, obtenez les dernières modifications:

git pull
Acumenus
la source
54
Cela semble être une meilleure réponse que celle acceptée, car elle se réinitialise dynamiquement à la branche en amont actuelle plutôt que toujours statique, commeorigin/master
Jon z
@Jonz spot on, the @{upstream}is very handy and can be used in aliases:alias resetthisbranch="git reset --hard @{upstream}"
Siddhartha
1
@GangadharJannu git reset --hardnécessite un commit, sinon il ne saurait pas à quoi vous réinitialiser. @{u}pointe vers un commit spécifique - le responsable de la branche suivie, depuis la dernière fois que vous avez effectué un git fetch.
Kristoffer Bakkejord
1
@KristofferBakkejord Merci pour l'explication, mais même sans le hachage de validation, nous pouvons le faire, git reset --hardmais il ne sera pas réinitialisé sur la branche distante
Gangadhar JANNU
3
Pour tous ceux qui ont presque ouvert une nouvelle question ici, si vous git de Powershell, utilisez des guillemets ( git reset --hard "@{u}"). Cela m'a pris un certain temps pour comprendre cela.
MPStoering
112

git reset --hard HEADne réinitialise en fait que le dernier état engagé. Dans ce cas, HEAD fait référence au HEAD de votre agence.

Si vous avez plusieurs commits, cela ne fonctionnera pas ..

Ce que vous voulez probablement faire, c'est réinitialiser le chef d'origine ou tout ce que votre référentiel distant est appelé. Je ferais probablement quelque chose comme

git reset --hard origin/HEAD

Attention cependant. Les réinitialisations matérielles ne peuvent pas être facilement annulées. Il est préférable de faire comme Dan le suggère et de dériver une copie de vos modifications avant de réinitialiser.

Mikael Ohlson
la source
2
Il y avait une suggestion incorrecte dans ma réponse que Dan a prise plus tôt. Je l'ai édité, car je ne veux induire personne en erreur. En ce qui concerne l'origine / master ou origin / HEAD, je m'attends à ce que cela dépend si vous effectuez ou non une extraction en premier. Si vous venez de cloner l'origine et qu'il n'y avait pas d'autres branches, ce que je trouve assez courant, il devrait le réinitialiser correctement. Mais bien sûr, Dan a raison.
Mikael Ohlson
73

Toutes les suggestions ci-dessus sont exactes, mais souvent pour vraiment réinitialiser votre projet, vous devez également supprimer même les fichiers qui se trouvent dans votre .gitignore.

Pour obtenir l'équivalent moral de l' effacement du répertoire de votre projet et du re-clonage à distance, procédez comme suit:

git fetch
git reset --hard
git clean -x -d -f

Avertissement : git clean -x -d -fest irréversible et vous risquez de perdre des fichiers et des données (par exemple, des choses que vous avez ignorées en utilisant .gitignore).

Christopher Smith
la source
12
Avertissement: "git clean -x -d -f" est irréversible et vous risquez de perdre des fichiers et des données dans .gitignore
Akarsh Satija
Un peu plus court: git clean -xdfc'est égal à git clean -x -d -f.
Kiryl
git clean -ffxd pour supprimer tout ce qui n'est pas dans le repo
Trismegistos
44

Utilisez les commandes ci-dessous. Ces commandes supprimeront également tous les fichiers non suivis de git local

git fetch origin
git reset --hard origin/master
git clean -d -f
Jamsheer
la source
6
Ceci est une réponse plus complète, car sans le, git clean -d -fnous aurions encore certaines choses de l'ancienne branche dans le répertoire local. Merci mec.
Flavio
3
C'est en fait ce qui fait que c'est exactement comme la télécommande. Le nettoyage est important.
David S.
1
git clean -ffxd pour vraiment supprimer tout
Trismegistos
1
C'est exactement ce dont j'avais besoin. Merci
AllJs
38

La question mélange ici deux questions:

  1. comment réinitialiser une branche locale au point où la télécommande est
  2. comment effacer votre zone de transit (et éventuellement le répertoire de travail), afin que git status ditnothing to commit, working directory clean.

La réponse unique est:

  1. git fetch --prune (facultatif) Met à jour l'instantané local du référentiel distant. Les autres commandes sont locales uniquement.
    git reset --hard @{upstream}Place le pointeur de branche locale à l'endroit où se trouve l'instantané de la télécommande, ainsi que définir l'index et le répertoire de travail dans les fichiers de cette validation.
  2. git clean -d --force Supprime les fichiers et répertoires non suivis qui empêchent git de dire «répertoire de travail propre».
Robert Siemer
la source
1
La @{upstream}syntaxe nécessite d'être définie en amont, ce qui se produit par défaut si vous git checkout <branchname>. - Sinon, remplacez-le par origin/<branchname>.
Robert Siemer
Ajouter -xà git cleanpour supprimer tout ce qui n'est pas dans le commit (c'est-à-dire même les fichiers ignorés avec le mécanisme .gitignore).
Robert Siemer
22

C'est quelque chose auquel je fais face régulièrement, et j'ai généralisé le script que Wolfgang a fourni ci-dessus pour fonctionner avec n'importe quelle branche

J'ai également ajouté une invite "Êtes-vous sûr" et une sortie de rétroaction

#!/bin/bash
# reset the current repository
# WF 2012-10-15
# AT 2012-11-09
# see http://stackoverflow.com/questions/1628088/how-to-reset-my-local-repository-to-be-just-like-the-remote-repository-head
timestamp=`date "+%Y-%m-%d-%H_%M_%S"`
branchname=`git rev-parse --symbolic-full-name --abbrev-ref HEAD`
read -p "Reset branch $branchname to origin (y/n)? "
[ "$REPLY" != "y" ] || 
echo "about to auto-commit any changes"
git commit -a -m "auto commit at $timestamp"
if [ $? -eq 0 ]
then
  echo "Creating backup auto-save branch: auto-save-$branchname-at-$timestamp"
  git branch "auto-save-$branchname-at-$timestamp" 
fi
echo "now resetting to origin/$branchname"
git fetch origin
git reset --hard origin/$branchname
Andrew Tulloch
la source
3
vous voudrez peut-être utiliser "git remote" pour obtenir le nom de la télécommande. Dans certains cas, ce ne sera pas "origine"
Yurik
17

À condition que le référentiel distant soit origin, et que cela vous intéresse branch_name:

git fetch origin
git reset --hard origin/<branch_name>

En outre, vous allez réinitialiser la branche actuelle de originà HEAD.

git fetch origin
git reset --hard origin/HEAD

Comment ça fonctionne:

git fetch origin télécharge la dernière version à distance sans essayer de fusionner ou de rebaser quoi que ce soit.

Ensuite, le git resetréinitialise la <branch_name>branche à ce que vous venez de récupérer. L' --hardoption modifie tous les fichiers de votre arborescence de travail pour qu'ils correspondent aux fichiers origin/branch_name.

eigenharsha
la source
14

J'ai fait:

git branch -D master
git checkout master

réinitialiser totalement la branche


notez que vous devez passer à une autre succursale pour pouvoir supprimer la succursale requise

user2846569
la source
5
Vous devriez lire la question une fois de plus, il n'y a rien sur l'affectation de la télécommande, mais la définition de la même chose que la télécommande, donc vous ne devriez rien faire avec la télécommande, et cela a aidé dans mon cas et non ci-dessus.
user2846569
Si vous souhaitez le définir sur le même que distant, vous devriez au moins faire une recherche à un moment donné, n'est-ce pas?
Tim
2
vous devriez au moins essayer ceci ou lire les documents: kernel.org/pub/software/scm/git/docs/git-checkout.html
user2846569
Chemin à parcourir, j'avais un fichier .pck corrompu dans la branche et le reste des options ne fonctionnait pas, merci !!
LuckyBrain
14

Voici un script qui automatise ce que la réponse la plus populaire suggère ... Voir https://stackoverflow.com/a/13308579/1497139 pour une version améliorée qui prend en charge les branches

#!/bin/bash
# reset the current repository
# WF 2012-10-15
# see /programming/1628088/how-to-reset-my-local-repository-to-be-just-like-the-remote-repository-head
timestamp=`date "+%Y-%m-%d-%H_%M_%S"`
git commit -a -m "auto commit at $timestamp"
if [ $? -eq 0 ]
then
  git branch "auto-save-at-$timestamp" 
fi
git fetch origin
git reset --hard origin/master
Wolfgang Fahl
la source
10

Si vous avez eu un problème comme moi, que vous avez déjà commis quelques modifications, mais maintenant, pour une raison quelconque, vous voulez vous en débarrasser, le moyen le plus rapide est d'utiliser git resetcomme ceci:

git reset --hard HEAD~2

J'avais 2 commits non nécessaires, d'où le nombre 2. Vous pouvez le changer en votre propre nombre de commits pour réinitialiser.

Donc, répondant à votre question - si vous avez 5 commits d'avance sur le référentiel distant HEAD, vous devez exécuter cette commande:

git reset --hard HEAD~5

Notez que vous perdrez les modifications que vous avez apportées, alors faites attention!

Karol
la source
7

Les réponses précédentes supposent que la branche à réinitialiser est la branche actuelle (extraite). Dans les commentaires, l'OP hap497 a précisé que la branche est effectivement vérifiée, mais cela n'est pas explicitement requis par la question d'origine. Puisqu'il y a au moins une question "en double", réinitialiser complètement la branche à l'état du référentiel , ce qui ne suppose pas que la branche est extraite, voici une alternative:

Si la branche "mybranch" n'est pas actuellement extraite , pour la réinitialiser à la tête de la branche distante "myremote / mybranch", vous pouvez utiliser cette commande de bas niveau :

git update-ref refs/heads/mybranch myremote/mybranch

Cette méthode laisse la branche extraite telle quelle et l'arborescence de travail intacte. Il déplace simplement la tête de mybranch vers un autre commit, quel que soit le deuxième argument donné. Cela est particulièrement utile si plusieurs branches doivent être mises à jour vers de nouvelles têtes distantes.

Soyez prudent en faisant cela, cependant, et utilisez gitkun outil similaire pour vérifier la source et la destination. Si vous le faites accidentellement sur la branche actuelle (et git ne vous en empêchera pas), vous pouvez devenir confus, car le nouveau contenu de la branche ne correspond pas à l'arborescence de travail, qui n'a pas changé (pour corriger, mettre à jour la branche à nouveau, où il était avant).

Rainer Blome
la source
7

C'est ce que j'utilise souvent:

git fetch upstream develop;
git reset --hard upstream/develop;
git clean -d --force;

Notez qu'il est bon de ne pas apporter des modifications à votre maître local / développer la branche, mais la caisse à une autre branche pour tout changement, avec le nom de la branche préfixé par le type de changement, par exemple feat/, chore/, fix/, etc. Ainsi il vous suffit de tirer les changements, pas pousser les changements du maître. Même chose pour les autres branches auxquelles d'autres contribuent. Donc, ce qui précède ne doit être utilisé que si vous avez validé des modifications dans une branche sur laquelle d'autres se sont engagées et doivent être réinitialisées. Sinon, à l'avenir, évitez de pousser vers une branche vers laquelle d'autres poussent, au lieu de payer et de pousser vers ladite branche via la branche extraite.

Si vous souhaitez réinitialiser votre branche locale à la dernière validation de la branche en amont, ce qui fonctionne pour moi jusqu'à présent est:

Vérifiez vos télécommandes, assurez-vous que votre amont et votre origine correspondent à ce que vous attendez, sinon comme prévu, puis utilisez git remote add upstream <insert URL>, par exemple, le référentiel GitHub d'origine que vous avez créé, et / ou git remote add origin <insert URL of the forked GitHub repo>.

git remote --verbose

git checkout develop;
git commit -m "Saving work.";
git branch saved-work;
git fetch upstream develop;
git reset --hard upstream/develop;
git clean -d --force

Sur GitHub, vous pouvez également extraire la branche portant le même nom que la branche locale, afin d'y enregistrer le travail, bien que cela ne soit pas nécessaire si le développement d'origine a les mêmes modifications que la branche de travail enregistré locale. J'utilise la branche de développement comme exemple, mais il peut s'agir de n'importe quel nom de branche existant.

git add .
git commit -m "Reset to upstream/develop"
git push --force origin develop

Ensuite, si vous devez fusionner ces modifications avec une autre branche alors qu'il y a des conflits, en conservant les modifications dans develop, utilisez:

git merge -s recursive -X theirs develop

Pendant l'utilisation

git merge -s recursive -X ours develop

pour conserver les modifications conflictuelles de branch_name. Sinon, utilisez un mergetool avec git mergetool.

Avec tous les changements ensemble:

git commit -m "Saving work.";
git branch saved-work;
git checkout develop;
git fetch upstream develop;
git reset --hard upstream/develop;
git clean -d --force;
git add .;
git commit -m "Reset to upstream/develop";
git push --force origin develop;
git checkout branch_name;
git merge develop;

Notez qu'au lieu de amont / développement, vous pouvez utiliser un hachage de validation, un autre nom de branche, etc. Utilisez un outil CLI tel que Oh My Zsh pour vérifier que votre branche est verte indiquant qu'il n'y a rien à valider et que le répertoire de travail est propre ( confirmée ou vérifiable par git status). Notez que cela peut réellement ajouter des validations par rapport au développement en amont s'il y a quelque chose ajouté automatiquement par une validation, par exemple des diagrammes UML, des en-têtes de licence, etc., donc dans ce cas, vous pouvez ensuite appliquer les modifications origin developà upstream develop, si nécessaire.

James Ray
la source
6

La réponse

git clean -d -f

était sous-estimé ( -d pour supprimer les répertoires). Merci!

Anael
la source
Et pour un dossier de repo complet et 100% propre sans fichiers supplémentaires, exécutez git clean -xdf. Cela supprimera tous les fichiers dont git n'a pas connaissance et fera en sorte que votre dossier corresponde exactement à la liste d'objets de git. Notez que vous pouvez ajouter -n(par exemple git clean -nxdf) pour effectuer un "what-if" et il vous dira ce qu'il supprimera sans rien faire. ( git clean )
qJake
5

Si vous souhaitez revenir à l' HEADétat du répertoire de travail et de l'index, vous devez le faire git reset --hard HEADplutôt que de le faire HEAD^. (Cela peut être une faute de frappe, tout comme le tiret simple contre le tiret double pour --hard.)

Quant à votre question spécifique sur la raison pour laquelle ces fichiers apparaissent dans le statut modifié, il semble que vous ayez peut-être effectué une réinitialisation logicielle au lieu d'une réinitialisation matérielle. Cela entraînera que les fichiers qui ont été modifiés dans le HEADcommit apparaissent comme s'ils étaient intermédiaires, ce qui est probablement ce que vous voyez ici.

Emil Sit
la source
4

Aucune quantité de réinitialisation et de nettoyage ne semblait avoir d'effet sur les fichiers non suivis et modifiés dans mon dépôt git local (j'ai essayé toutes les options ci-dessus). Ma seule solution à cela était de rm le dépôt local et de le recloner à partir de la télécommande.

Heureusement, je n'avais aucune autre branche qui m'intéressait.

xkcd: Git

Martin
la source
1

La seule solution qui fonctionne dans tous les cas que j'ai vu est de supprimer et de recloner. Peut-être qu'il y a une autre façon, mais évidemment, cette façon ne laisse aucune chance de laisser l'ancien état là, donc je le préfère. Bash one-liner, vous pouvez définir une macro si vous gâchez souvent les choses dans git:

REPO_PATH=$(pwd) && GIT_URL=$(git config --get remote.origin.url) && cd .. && rm -rf $REPO_PATH && git clone --recursive $GIT_URL $REPO_PATH && cd $REPO_PATH

* suppose que vos fichiers .git ne sont pas corrompus

sudo
la source
4
vous pouvez également simplement réinstaller votre système d'exploitation si vous voulez en être certain!
Sebastian Scholle
1

Vous avez oublié de créer une branche de fonctionnalité et vous vous êtes engagé directement sur le maître par erreur?

Vous pouvez créer la branche de fonctionnalité maintenant et redéfinir le master sans affecter le worktree (système de fichiers local) pour éviter de déclencher des builds, des tests et des problèmes avec les verrous de fichiers:

git checkout -b feature-branch
git branch -f master origin/master
Grastveit
la source
1

Seulement 3 commandes le feront fonctionner

git fetch origin
git reset --hard origin/HEAD
git clean -f
Nirmal profond
la source
-3

Si cela ne vous dérange pas d'enregistrer vos modifications locales, mais que vous souhaitez toujours mettre à jour votre référentiel pour qu'il corresponde à l'origine / HEAD, vous pouvez simplement cacher vos modifications locales, puis tirer:

git stash
git pull
Micah Walter
la source