Comment avancer et reculer entre les commits dans git?

105

Je fais un git bisectet après être arrivé au commit problématique, j'essaie maintenant de faire un pas en avant / en arrière pour m'assurer que je suis dans le bon.

Je sais HEAD^revenir en arrière dans l'histoire mais y a-t-il un autre raccourci pour me faire avancer (vers un commit spécifique dans le futur) comme ceci:

A - B - C(HEAD) - D - E - F

Je sais que mon objectif est F et je veux passer de C à D .


REMARQUE: ce n'est pas un doublon de Git: comment se déplacer entre les commits , ma question est légèrement différente et n'y répond pas

Kostas
la source
1
stackoverflow.com/questions/2263674/ ... peut également vous aider.
VonC
git checkout -b new_branch HEAD~4pour revenir 4 commits de HEAD comme dans stackoverflow.com/a/4940090/911945
Anton Tarasenko

Réponses:

57

J'ai un peu expérimenté et cela semble faire l'affaire pour naviguer vers l'avant ( modifier : cela ne fonctionne bien que lorsque vous avez un historique linéaire sans commits de fusion):

git checkout $(git rev-list --topo-order HEAD..towards | tail -1)

towardsest un SHA1 du commit ou une balise.

Explication:

  • la commande à l'intérieur $()signifie: récupérez tous les commits entre courant HEADet towardscommit (à l'exclusion HEAD), et triez-les dans l'ordre de priorité (comme git logpar défaut - au lieu de l'ordre chronologique qui est étrangement celui par défaut rev-list), puis prenez le dernier ( tail), c'est-à-dire celui vers lequel nous voulons aller.
  • ceci est évalué dans le sous-shell et transmis à git checkoutpour effectuer une extraction.

Vous pouvez définir une fonction accessible en tant qu'alias en attente de paramètres dans votre .profilefichier pour avancer vers le commit particulier:

# Go forward in Git commit hierarchy, towards particular commit 
# Usage:
#  gofwd v1.2.7
# Does nothing when the parameter is not specified.
gofwd() {
  git checkout $(git rev-list --topo-order HEAD.."$*" | tail -1)
}

# Go back in Git commit hierarchy
# Usage: 
#  goback
alias goback='git checkout HEAD~'
jakub.g
la source
2
Aller de l'avant fonctionne bien sur des parties droites de l'histoire, mais se déroule en boucle lors de la rencontre d'une fusion.
Kostas
Ouais, je ne l'ai pas testé sur les fusions. Je vais essayer de jeter un coup d'œil pendant mon temps libre, mais j'ai peu d'incitation temporairement, puisque nous avons accepté d'avoir une histoire strictement linéaire dans notre projet;)
jakub.g
2
Très bonne réponse! Modifié pour spécifier automatiquement la branche actuelle: stackoverflow.com/a/23172256/480608
Raine Revere
Ceci est une erreur. git logaffiche les commits dans l'ordre chronologique, par défaut, le même que rev-list, sauf lors de l'utilisation de l' --graphindicateur.
papiro
Preuve assez convaincante que git est trop complexe. Pour quelque chose qui est généralement aussi simple que Annuler ou Refaire, nous avons ici une liste folle de réponses contradictoires. Et je ne suis même pas entré dans aucune des réponses liées. FWIW, j'ai essayé une version de ceci avec un simple ensemble linéaire de commits et j'ai finalement abandonné.
Snowcrash
49

Tout ce dont vous avez besoin pour obtenir un état de tête clair et non détaché est de réinitialiser, pas de vérifier.

git reset HEAD@{1}
d3day
la source
5
ou git reset "HEAD@{1}"dans certains shells comme fish et powershell .. git reflogpeut également être utile pour trouver le bon commit.
steve cook
1
Utilisez toujours des guillemets simples dans les commandes shell sauf si vous souhaitez explicitement que le shell tente d'interpréter / développer le contenu. Ceci est particulièrement important dans des cas comme celui-ci, où le but est d'empêcher le shell d'interpréter les caractères spéciaux. De cette façon, vous n'avez pas besoin de savoir si la chaîne contient quelque chose de problématique.
Chris Page
Je l'ai fait pour revenir en arrière, puis je l'ai fait git reset HEADpour revenir là où j'étais ... maintenant je n'ai aucune idée de l'état dans lequel se trouve mon référentiel et tout est effrayant. Qu'est-ce que je devrais faire maintenant?
theonlygusti
47

Je crois que vous pouvez faire:

git reset HEAD@{1}

Faire avancer un engagement dans le temps. Pour faire avancer plusieurs validations, utilisez HEAD @ {2}, HEAD @ {3}, etc.

w0utert
la source
20

C'est ce que j'utilise pour naviguer dans les deux sens.

passer au prochain commit

function n() {
    git log --reverse --pretty=%H master | grep -A 1 $(git rev-parse HEAD) | tail -n1 | xargs git checkout
}

passage au commit précédent

function p() {
    git checkout HEAD^1
}
MK
la source
Merci! J'utilise ça maintenant! Notes pour les autres débutants comme moi : pour rattacher HEAD, git checkout <current branch>s'attache au dernier commit. git checkout -b <new-branch-name>à partir de la validation actuelle permet des changements dans la nouvelle branche. git rebase -ifonctionne également. De plus , j'ai nommé ma n()fonction nx()pour éviter tout conflit avec le gestionnaire de version de nœud "n". Assurez-vous de vérifier les alias!
Steven Choi
function () {...} est pour la création d'un fichier de script bash Unix / Linux, je viens de Windows, un peu difficile pour moi de comprendre d'abord
IcyBrk
9

Dites que F est le dernier commit sur trunk (insérez votre propre nom de branche ici) ... vous pouvez vous y référer comme trunk~0(ou simplement trunk), E comme trunk~1, D comme trunk~2etc.

Jetez un œil dans votre reflog pour encore plus de façons de nommer les commits.

Inutile
la source
1
~ retourne, pas vers l'avant, coffre ~ 2 est A
EmmanuelMess
Oui. Cette réponse suppose que vous avez une branche appelée tronc pointant vers Fet que vous savez où dans l'historique de cette branche vous voulez vous déplacer. Il n'essaie pas d'avancer par rapport à HEAD, mais moins loin par rapport au tronc.
Inutile
@EmmanuelMess comment va trunk~2A?
theonlygusti
@theonlygusti Vous reculez de HEAD deux fois.
EmmanuelMess
Vous supposez toujours que la branche trunket votre courant HEADsont identiques, ce qui n'est pas montré dans la question, ce que j'ai déclaré n'est pas ce que je suppose, et ce qui est très improbable à mi-chemin d'unbisect
inutile
3

Traverser en arrière est trivial puisque vous vous déplacez dans l'arbre, et il y a toujours un chemin à parcourir

  function git_down
        git checkout HEAD^
  end

Lorsque vous avancez, vous vous déplacez vers le haut de l'arbre, vous devez donc être explicite sur la branche que vous ciblez:

  function git_up 
        git log --reverse --pretty=%H $argv | grep -A 1 (git rev-parse HEAD) | tail -n1 | xargs git checkout
  end

Utilisation: git down,git up <branch-name>

Dziamid
la source
Reculer n'est pas non plus tout à fait unique, lorsque des fusions sont impliquées. Bien que ce HEAD^soit généralement un défaut raisonnable.
kdb
2

Si vous voulez voir plus loin, vous pouvez faire cette astuce, car Git n'a pas de commande stricte pour cela.

git log --reverse COMMIT_HASH..

Exemple

Liste des hachages de l'historique des journaux:

A
B
C -> put this
D

en utilisant la commande git log --reverse C.., en sortie , vous verrez B et A .

dimpiax
la source
1

Probablement pas la meilleure façon, mais vous pouvez utiliser git logpour afficher la liste des commits, puis utiliser git checkout [sha1 of D]pour passer à D.

génération bb
la source
6
Je ne comprends pas, s'il est en C, alors git log ne lui montrera que C, B et A.
Bilthon
Ok, compris, mais vous devrez faire un git-log délicat comme indiqué dans le lien donné par VonC
Bilthon
1

Je viens de faire un test à ce sujet. dites par exemple que vous êtes dans la branche principale Puis faites:

git checkout HEAD@{3}

Alors la tête se détache, et vous pouvez alors réessayer pour aller à n'importe quel autre commit:

git checkout HEAD@{4}

Une fois que vous avez terminé de regarder autour de vous, vous pouvez revenir à votre état d'origine simplement en vous connectant à cette branche. Dans mon exemple: master branch

git checkout master

Si vous ne voulez pas revenir à l'état d'origine et que vous voulez garder l'un des commits en tête et continuer à partir de là, vous devez alors vous dériver à partir de là. par exemple après "git checkout HEAD @ {4}", vous pouvez émettre

git checkout -b MyNewBranch
user1322977
la source
0

Pour contourner ce problème, vous pouvez simplement revenir à HEAD avec

git checkout <branch>

Et puis passez au commit que vous souhaitez, avec

git checkout HEAD~<offset>
Patrizio Bertoni
la source
0

Si vous utilisez vs code, l'historique Git est un plugin génial où vous pouvez voir efficacement les commits et vérifier leur contenu dans l'éditeur lui-même. consultez le lien

Rahil Ahmad
la source
0
branchName=master; commitInOrder=1; git checkout $(git log --pretty=%H "${branchName}" | tac | head -n "${commitInOrder}" | tail -n 1)

où:

branchName est égal au nom de la succursale

commitInOrder équivaut à un commit dans l'ordre à partir du tout premier commit dans la branche sélectionnée (donc 1 est le tout premier commit, 2 est le deuxième commit dans la branche, etc.)

client
la source