ref^
fait référence à la validation avant ref
, qu'en est-il pour obtenir la validation après ref
?
Par exemple, si je git checkout 12345
comment vérifier le prochain commit?
Merci.
PS Oui, git est un arbre de structure de pointeur de nœud DAG. Comment trouver le commit après celui-ci?
git
version-control
Schwern
la source
la source
git children-of
"!Réponses:
Pour répertorier tous les commits, en commençant par celui en cours, puis son enfant, et ainsi de suite - essentiellement un journal git standard, mais dans l'autre sens dans le temps, utilisez quelque chose comme
où 894e8b4e93d8f3 est le premier commit que vous souhaitez afficher.
la source
HEAD^
par894e8b4e93d8f3^
....
,^..
échoue silencieusementfatal: unrecognized argument: --ancestry-path
àmaster
trouve sur le chemin d'ascendance du commit actuel. Voir le deuxième extrait de code de ma réponse pour une solution qui fonctionnera dans tous les cas.Le créateur de Hudson (maintenant Jenkins) Kohsuke Kawaguchi vient de publier (novembre 2013):
kohsuke / git-children-of :
Comme illustré par ce fil , dans un VCS basé sur l'historique représenté par un DAG (Directed Acyclic Graph) , il n'y a pas "un parent" ou "un enfant".
La commande des commits se fait par "topo-order" ou "date-order" (voir livre GitPro )
Mais depuis Git1.6.0 , vous pouvez lister les enfants d'un commit.
Remarque: pour les validations parentes , vous rencontrez le même problème, le suffixe
^
d'un paramètre de révision signifiant le premier parent de cet objet de validation.^<n>
signifie le<n>
parent e (c.rev^
-à- d. est équivalent àrev^1
).Si vous êtes sur une branche
foo
et que vous émettez "git merge bar
", vousfoo
serez le premier parent.C'est-à-dire: le premier parent est la branche sur laquelle vous étiez lorsque vous avez fusionné, et le second est la validation sur la branche dans laquelle vous avez fusionné.
la source
git rev-list --children
ressemble vraiment à ce que je veux, mais ce n'est pas DWIM. Il semble répertorier tous les parents et leurs enfants. Je suppose que je peux tous les énumérer et les analyser ... bh, mais c'est quelque chose.git rev-list --children
n'est pas pour lister seulement les enfants, mais pour lister les parents avec leurs enfants ... vous devez toujours analyser.$ git children0of 9dd5932
fatal: No annotated tags can describe '71d7b5dd89d241072a0a078ff2c7dfec05d52e1f'.
However, there were unannotated tags: try --tags.
quelle sortie obtenez-vous?git-children-of
est qu'il utilise git decrire qui tente de formater le SHA comme lisible par l'homme, ce qui peut échouer avec l'erreur de @ TomHale, et donne des résultats commev1.0.4-14-g2414721
celui-ci sont déroutants si vous vous attendiez à un SHA. Le remplacer par un simple enecho
fait un excellent outil, merci!ce que j'ai trouvé c'est
où je mets
commit1
comme commit actuel etcommit2
à la tête actuelle. Cela me renvoie une liste de tous les commits qui créent un chemin entrecommit1
etcommit2
.La dernière ligne de la sortie est l'enfant de commit1 (sur le chemin de commit2).
la source
| tail -1
pour obtenir l'enfant.Je vois ce que tu veux dire. Il est frustrant d'avoir une syntaxe abondante pour passer aux validations précédentes, mais aucune pour passer aux suivantes. Dans une histoire complexe, le problème de «quelle est la prochaine validation» devient plutôt difficile, mais dans la fusion complexe, la même dureté émerge également avec les validations «précédentes». Dans le cas simple, à l'intérieur d'une seule branche avec un historique linéaire (même juste localement pour un nombre limité de commits), il serait intéressant et logique d'avancer et de reculer.
Le vrai problème avec cela, cependant, est que les validations des enfants ne sont pas référencées, c'est seulement une liste liée en arrière. Trouver le commit enfant prend une recherche, ce qui n'est pas trop mal, mais probablement pas quelque chose que git veut mettre dans la logique refspec.
Quoi qu'il en soit, je suis tombé sur cette question parce que je veux simplement avancer dans l'histoire, un engagement à la fois, faire des tests, et parfois vous devez avancer et non reculer. Eh bien, avec un peu plus de réflexion, j'ai trouvé cette solution:
Choisissez un commit avant votre arrivée. Cela pourrait probablement être un chef de branche. Si vous êtes à la branche ~ 10, puis "git checkout branch ~ 9" puis "git checkout branch ~ 8" pour obtenir le suivant après cela, puis "git checkout branch ~ 7" et ainsi de suite.
La décrémentation du nombre devrait être très facile dans un script si vous en avez besoin. Beaucoup plus facile que d'analyser git rev-list.
la source
BRANCH=master; git co $BRANCH~$[ $(git rev-list HEAD..$BRANCH | wc -l) - 1 ]
" Vous devez aller vers une branche, pas question.Deux réponses pratiques:
Un enfant
Sur la base de la réponse de @ Michael , j'ai piraté l'
child
alias dans mon.gitconfig
.Il fonctionne comme prévu dans le cas par défaut et est également polyvalent.
Par défaut, il donne à l'enfant de HEAD (sauf si un autre argument commit-ish est donné) en suivant l'ascendance un pas vers la pointe de la branche en cours (sauf si un autre commit-ish est donné comme deuxième argument).
Utilisez
%h
au lieu de%H
si vous voulez la forme de hachage courte.Plusieurs enfants
Avec une tête détachée (il n'y a pas de branche) ou pour obtenir tous les enfants indépendamment des branches:
Modifiez le
$1
pour$*
imprimer tous les enfants.Vous pouvez également passer
--all
à un commit-ish pour afficher uniquement les enfants qui sont les ancêtres de ce commit, en d'autres termes, pour afficher uniquement les enfants «dans le sens» du commit donné. Cela peut vous aider à réduire la sortie de nombreux enfants à un seul.la source
Il n'y a pas de "prochain commit" unique. Étant donné que l'historique dans Git est un DAG et non une ligne, de nombreuses validations peuvent avoir un parent commun (branches) et les validations peuvent avoir plusieurs parents (fusion).
Si vous avez une branche particulière en tête, vous pouvez consulter son journal et voir quel commit répertorie la branche actuelle comme son parent.
la source
<rev>^
est "parent commit" ("premier parent" pour les validations de fusion).J'ai essayé de nombreuses solutions différentes et aucune n'a fonctionné pour moi. Je devais trouver le mien.
trouver le prochain commit
trouver le commit précédent
la source
Dans le cas où vous n'avez pas de validation de "destination" particulière à l'esprit, mais que vous souhaitez plutôt voir les validations enfants qui pourraient être sur n'importe quelle branche, vous pouvez utiliser cette commande:
Si vous voulez voir tous les enfants et petits -enfants , vous devez utiliser
rev-list --children
récursivement, comme ceci:(La version qui ne donne que des petits-enfants utiliserait un système plus complexe
sed
et / oucut
.)Enfin, vous pouvez alimenter cela dans une
log --graph
commande pour voir la structure arborescente, comme ceci:Remarque : les commandes ci-dessus supposent toutes que vous avez défini la variable shell
${COMMIT}
sur une référence (branche, balise, sha1) du commit dont les enfants vous intéressent.la source
${COMMIT}
résiste pas, mais vous pouvez utiliser à la$(git rev-parse HEAD)
place${COMMIT}
.(Cela a commencé comme une réponse à une question en double. J'ai fait un peu de retouche légère pour le nettoyer.)
Toutes les flèches internes de Git sont à sens unique, pointant vers l'arrière. Il n'y a donc pas de courte syntaxe pratique pour avancer: ce n'est tout simplement pas possible.
Il est possible de "bouger contre les flèches", mais la façon de le faire est surprenante si vous ne l'avez pas vue auparavant, puis évidente après. Disons que nous avons:
L'utilisation
middle~2
suit les flèches deux fois de l'C
arrière versA
. Alors, comment pouvons-nous passer deC
àD
? La réponse est: nous commençons parE
, en utilisant le nomlast
, et nous remontons jusqu'à ce que nous arrivionsmiddle
, en enregistrant les points que nous visitons en cours de route . Ensuite, nous allons aussi loin que nous voulons dans le sens delast
: déplacer un pas versD
, ou deux versE
.Ceci est particulièrement important lorsque nous avons des succursales:
Quel engagement est une étape après
C
? Il n'y a pas de bonne réponse tant que vous n'ajoutez pas à la question: dans le sens de la fonction___ (remplissez le blanc).Pour énumérer les commits entre
C
(à l'exclusionC
) lui-même et, disonsG
, nous utilisons:Le
--topo-order
fait en sorte que même en présence de branchements et de fusions complexes, les commits sortent par ordre topologique. Ceci n'est requis que si la chaîne n'est pas linéaire. La--ancestry-path
contrainte signifie que lorsque nous travaillons en arrière à partir defeature2
, nous répertorions uniquement les validations qui ont été validéesC
comme l'un de leurs propres ancêtres. Autrement dit, si le graphique - ou la partie pertinente de celui-ci de toute façon - ressemble réellement à ceci:une simple demande du formulaire
feature2..master
énumère les commitsJ
,G
etI
, etF
etH
dans un certain ordre. Avec--ancestry-path
nous assommonsH
etI
: ils ne sont pas des descendants deC
, seulement deA
. Avec--topo-order
nous nous assurons que l'ordre d'énumération est réelleJ
, puisG
, alorsF
.La
git rev-list
commande répand ces ID de hachage sur sa sortie standard, une par ligne. Pour avancer d'un pas dans la direction defeature2
, alors, nous voulons juste la dernière ligne.Il est possible (et tentant et peut être utile) d'ajouter
--reverse
afin d'git rev-list
imprimer les validations dans l'ordre inverse après les avoir générées. Cela fonctionne, mais si vous l'utilisez dans un pipeline comme celui-ci:pour obtenir juste le "prochain commit dans le sens de id2", et il y a une très longue liste de commits, la
git rev-list
commande peut obtenir un tube cassé quand elle essaie d'écrire,head
ce qui a arrêté la lecture de son entrée et est sorti. Étant donné que les erreurs de canal cassé sont normalement ignorées par le shell, cela fonctionne principalement. Assurez-vous simplement qu'ils sont ignorés dans votre utilisation.Il est également tentant d'ajouter
-n 1
à lagit rev-list
commande, avec--reverse
. Ne fais pas ça! Cela faitgit rev-list
s'arrêter après avoir fait un pas en arrière , puis inverser la liste (une entrée) des commits visités. Donc, cela produit juste<id2>
chaque fois.Remarque importante
Notez qu'avec des fragments de graphe "diamant" ou "anneau de benzène":
déplacer un commit "en avant" de
H
verslast
vous obtiendra soitI
ouK
. Vous ne pouvez rien y faire: les deux validations sont un pas en avant! Si vous commencez ensuite à partir de la validation résultante et passez à une autre étape, vous êtes maintenant engagé sur le chemin sur lequel vous avez commencé.Le remède à cela est d'éviter de se déplacer une étape à la fois et de s'enfermer dans des chaînes dépendantes du chemin. Au lieu de cela, si vous prévoyez de visiter toute une chaîne de chemin d'ascendance, avant de faire quoi que ce soit d'autre , faites une liste complète de tous les commits de la chaîne:
Ensuite, visitez chaque commit de cette liste, un par un, et vous obtiendrez toute la chaîne. Le
--topo-order
fera en sorte que vousI
frappiez -et-J
dans cet ordre, etK
-et-L
dans cet ordre (bien qu'il n'y ait pas de moyen facile de prédire si vous ferez la paire IJ avant ou après la paire KL).la source
J'ai cet alias dans
~/.gitconfig
la source
f()
? Et ce doithead -1
être le premier enfant, sinon cela rapportera simplement la TÊTE.f()
. Oui,head -1
c'est une supposition courageuse.nextref = "!f() { git log --reverse --ancestry-path --pretty=%H $1..HEAD | head -${2:-1} | tail -1; }; f"
afin que vous puissiez choisir dans quelle mesure, en optionJ'ai réussi à trouver le prochain enfant de la manière suivante:
la source
Si les commits enfants sont tous sur une branche, vous pouvez utiliser
gitk --all commit^..
, où "commit" est quelque chose identifiant le commit. Par exemple, si l'abréviation SHA-1 du commit est c6661c5, tapezgitk --all c6661c5^..
Vous devrez probablement entrer le SHA-1 complet dans la cellule "SHA1 ID:" de gitk. Vous aurez besoin du SHA-1 complet, qui pour cet exemple peut être obtenu via
git rev-parse c6661c5
Alternativement,
git rev-list --all --children | grep '^c6661c5883bb53d400ce160a5897610ecedbdc9d'
produira une ligne contenant tous les enfants de ce commit, probablement s'il y a ou non une branche impliquée.la source
Chaque commit stocke un pointeur sur son parent (parents, en cas de commit de fusion (standard)).
Il n'y a donc aucun moyen de pointer vers un commit enfant (s'il y en a un) du parent.
la source
Ce message ( http://www.jayway.com/2015/03/30/using-git-commits-to-drive-a-live-coding-session/#comment-282667 ) montre une manière soignée si le faire si vous pouvez créer une balise bien définie à la fin de votre pile de commit. Essentiellement,
git config --global alias.next '!git checkout `git rev-list HEAD..demo-end | tail -1`'
où "demo-end" est la dernière balise.la source
Les réponses existantes supposent que vous avez une branche contenant le commit que vous recherchez.
Dans mon cas, le commit que je cherchais n'était pas activé
git rev-list --all
car aucune branche ne le contenait.J'ai fini par regarder
gitk --reflog
manuellement.Si vous ne trouvez pas votre commit même dans le reflog, essayez soit:
git fsck --full
pour répertorier les commissions pendantes (c'est-à-dire n'appartenant à aucune branche), ougit fsck --lost-found
faire des refs pointant vers les pendants s'engage à appliquer des techniques dans les autres réponses.la source