Besoin de réinitialiser la branche git à la version d'origine

440

Je travaillais accidentellement sur une branche que je n'aurais pas dû être pendant un certain temps, alors je me suis éloigné d'elle en lui donnant le nom approprié. Maintenant, je veux écraser la branche sur laquelle je n'aurais pas dû être sur la version d'origine (github). Y a-t-il un moyen facile de faire ceci? J'ai essayé de supprimer la branche, puis de réinitialiser la branche de suivi, mais cela me donne simplement la version sur laquelle je travaillais à nouveau.

Brad Herman
la source
Avec Git 2,23 (Août 2019): git switch -C mybranch origin/mybranch. Voir ma réponse modifiée ci
VonC

Réponses:

816

Si vous n'avez pas encore poussé vers l'origine, vous pouvez réinitialiser votre branche vers la branche amont avec:

git checkout mybranch
git reset --hard origin/mybranch

(Assurez-vous de référencer votre dernier commit dans une branche distincte, comme vous le mentionnez dans votre question)

Notez que juste après la réinitialisation, se mybranch@{1}réfère à l'ancien commit, avant la réinitialisation.

Mais si vous aviez déjà poussé, voir " Créer une branche git et rétablir l'original en état amont " pour d'autres options.


Avec Git 2,23 (Août 2019) , ce serait une commande: git switch.
À savoir:git switch -C mybranch origin/mybranch

Exemple

C:\Users\vonc\git\git>git switch -C master origin/master
Reset branch 'master'
Branch 'master' set up to track remote branch 'master' from 'origin'.
Your branch is up to date with 'origin/master'.

Cela restaure l'index et l'arbre de travail, comme un git reset --hardferait.


Comme commenté par Brad Herman , un reset --hardserait enlever tout nouveau fichier ou réinitialiser fichier modifié à HEAD .

En fait, pour être sûr de partir d'une "table rase", un git clean -f -daprès la réinitialisation garantirait un arbre de travail exactement identique à la branche que vous venez de réinitialiser.


Ce billet de blog suggère ces alias (pour la masterbranche uniquement, mais vous pouvez les adapter / étendre):

[alias]
   resetorigin = !git fetch origin && git reset --hard origin/master && git clean -f -d
   resetupstream = !git fetch upstream && git reset --hard upstream/master && git clean -f -d

Ensuite, vous pouvez taper:

git resetupstream

ou

git resetorigin
VonC
la source
26
cela SUPPRIMERA les changements NON ÉTAGÉS / ÉTAGÉS (du --hard)
Peter Ehrlich
5
J'ai utilisé la git reset --hard origin/mybranchcommande plusieurs fois lorsque je ne me suis pas soucié des modifications locales et que je voulais juste une copie propre qui correspondait à l'origine. Cependant, aujourd'hui, cela n'a pas fonctionné - j'avais encore une poignée de nouveaux fichiers non organisés, et git n'arrêtait pas de me promettre que c'était chez HEAD. La note à propos git clean -f -dde cela corrigeait en effaçant tous les nouveaux fichiers que je ne voulais pas.
Matthew Clark
@MatthewClark Cela est attendu: voir le commentaire sur stackoverflow.com/q/4327708/6309
VonC
1
Génial! Aussi, plusieurs fois, j'ai utilisé git reset --hard HEADpour revenir à un commit précédent, en ignorant tous les changements
daronwolff
Est-ce possible aussi avec sourctree?
Lonzak
20

En supposant que c'est ce qui s'est passé:

# on branch master
vi buggy.py                 # you edit file
git add buggy.py            # stage file
git commit -m "Fix the bug" # commit
vi tests.py                 # edit another file but do not commit yet

Ensuite, vous réalisez que vous apportez des modifications sur la mauvaise branche.

git checkout -b mybranch    # you create the correct branch and switch to it

Mais mastersouligne toujours votre engagement. Vous voulez qu'il pointe là où il pointait auparavant.

Solution

Le moyen le plus simple est:

git branch --force master origin/master

Une autre façon est:

git checkout master
git reset --soft origin/master
git checkout mybranch

Notez que l'utilisation reset --hardentraînera la perte de vos modifications non validées ( tests.pydans mon exemple).

user28667
la source
Cela semble plus sûr que dans ma réponse;) +1
VonC
8

J'ai un dépôt privé sur un serveur et je le rebase / le pousse régulièrement, ce qui rend nécessaire de réinitialiser souvent la branche locale sur mon autre ordinateur. J'ai donc créé l'alias suivant "catchup", ce qui permet de le faire pour la branche courante. Contrairement à l'autre réponse, il n'y a pas de nom de branche codé en dur dans cet alias.

Tiens bon.

[alias]
  catchup = "!f(){ echo -n \"reset \\033[0;33m$(git symbolic-ref -q --short HEAD)\\033[0m to \\033[0;33m$(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD))\\033[0m? (Y/n) \"; read -r ans; if [ \"$ans\" = \"y\" -o \"$ans\" = \"Y\" -o -z \"$ans\" ]; then git reset --hard $(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD)); else echo \"catchup aborted\"; fi }; f"

Correctement formaté (ne fonctionnera pas avec les sauts de ligne dans .gitconfig), il ressemble à ceci:

"
!f(){
  echo -n \"reset \\033[0;33m$(git symbolic-ref -q --short HEAD)\\033[0m to \\033[0;33m$(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD))\\033[0m? (Y/n) \";
  read -r ans;
  if [ \"$ans\" = \"y\" -o \"$ans\" = \"Y\" -o -z \"$ans\" ]; then
    git reset --hard $(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD));
  else
    echo \"catchup aborted\";
  fi
}; f
"
  • Le \\033[0;33met \\033[0msert à souligner la branche actuelle et en amont avec de la couleur.
  • $(git symbolic-ref -q --short HEAD) est le nom de la branche actuelle
  • $(git for-each-ref --format='%(upstream:short)' $(git symbolic-ref -q HEAD)) est en amont de la branche actuelle.

Étant donné que la réinitialisation est un appel potentiellement dangereux (en particulier avec l'option --hard, vous perdrez toutes les modifications non validées), il vous indique d'abord ce qu'il est sur le point de faire. Par exemple, si vous êtes sur une branche dev-container avec une télécommande appelée qcpp / dev-container et que vous entrez git catchup, vous serez invité:

réinitialiser dev-container à qcpp / dev-container? (O / n)

Si vous tapez ensuite y ou appuyez simplement sur retour, il effectuera la réinitialisation. Si vous saisissez autre chose, la réinitialisation ne sera pas effectuée.

Si vous voulez être super sûr et empêcher par programmation de perdre des modifications non stadifiées / non validées, vous pouvez pimper l'alias ci-dessus plus loin en vérifiant les différences d'index .

Le mot d'avertissement obligatoire: si vous travaillez sur un référentiel public sur lequel d'autres personnes ont basé leur travail et que vous avez besoin de cet alias, vous vous trompez ™ .

DerManu
la source
1

J'ai essayé et cela n'a pas réinitialisé ma branche actuelle sur mon github distant le plus récent. J'ai googlé et trouvé https://itsyndicate.org/blog/how-to-use-git-force-pull-properly/

qui a suggéré

git fetch origin master
git reset --hard origin/master

Je voulais réinitialiser ma branche v8, donc je l'ai fait

git fetch origin v8
git reset --hard origin/v8

et ça a marché

SimpleSi
la source
Eh bien, c'est bien que vous mentionniez aller chercher. Je l'ai fait une fois sans et j'ai tout réinitialisé il y a 2 ans :)
Adam