ref^
前のコミットを指しますが、後ref
のコミットについてはどうですか? ref
たとえばgit checkout 12345
、次のコミットをチェックアウトするにはどうすればよいですか?
ありがとう。
PSはい、gitはDAGノードポインタ構造体ツリーです。 この後にコミットを見つけるにはどうすればよいですか?
git children-of
」も参照してください。
ref^
前のコミットを指しますが、後ref
のコミットについてはどうですか? ref
たとえばgit checkout 12345
、次のコミットをチェックアウトするにはどうすればよいですか?
ありがとう。
PSはい、gitはDAGノードポインタ構造体ツリーです。 この後にコミットを見つけるにはどうすればよいですか?
git children-of
」も参照してください。
回答:
現在のコミットから始まり、その子など、すべてのコミットをリストするには、基本的には標準のgit logですが、逆の場合は次のようにします。
git log --reverse --ancestry-path 894e8b4e93d8f3^..master
ここで、894e8b4e93d8f3は、表示する最初のコミットです。
HEAD^
してください894e8b4e93d8f3^
。
...
、^..
黙って失敗する
fatal: unrecognized argument: --ancestry-path
gitのバージョン1.7.1に
Hudson(現在はJenkins)の作成者である川口
浩介(2013年11月)が公開しました:kohsuke / git-children-of:
コミットを前提として、そのコミットの直接の子を見つけます。
#!/bin/bash -e
# given a commit, find immediate children of that commit.
for arg in "$@"; do
for commit in $(git rev-parse $arg^0); do
for child in $(git log --format='%H %P' --all | grep -F " $commit" | cut -f1 -d' '); do
git describe $child
done
done
done
このスレッドで示されているように、DAG(Directed Acyclic Graph)で表される履歴に基づくVCSでは、「1つの親」または「1つの子」はありません。
C1 -> C2 -> C3
/ \
A -> B E -> F
\ /
D1 -> D2 ----/
コミットの順序は「topo-order」または「date-order」によって行われます(GitProブックを参照)
ただし、Git1.6.0以降では、コミットの子をリストできます。
git rev-list --children
git log --children
注:親コミットの場合も同じ問題^
があり、リビジョンパラメータのサフィックスはそのコミットオブジェクトの最初の親を意味します。th番目の親を^<n>
意味します<n>
(つまりrev^
と同等rev^1
)。
ブランチにいfoo
て「git merge bar
」を発行foo
すると、最初の親になります。
つまり、最初の親はマージしたときに存在していたブランチであり、2番目の親はマージしたブランチでのコミットです。
git rev-list --children
確かに私が望むもののように見えますが、それはDWIMではありません。すべての親とその子がリストされているようです。私はそれらをすべてリストして、それらを解析できると思います...でも、それは何かです。
git rev-list --children
子供だけをリストするのではなく、子供を持つ親をリストする... ...常に解析する必要があります。
$ git children0of 9dd5932
fatal: No annotated tags can describe '71d7b5dd89d241072a0a078ff2c7dfec05d52e1f'.
However, there were unannotated tags: try --tags.
どのような出力が得られますか?
git-children-of
は、SHAを人間が読める形式にフォーマットしようとするgit describeを使用することです。これは、@ TomHaleのエラーで失敗する可能性がありv1.0.4-14-g2414721
、SHAを想定している場合は混乱する結果になります。シンプルに置き換えると、echo
これは優れたツールになります。
私が見つけたのは
git rev-list --ancestry-path commit1..commit2
ここでcommit1
、現在のコミットとcommit2
現在のヘッドに設定します。これによりcommit1
、との間のパスを構築するすべてのコミットのリストが返されますcommit2
。
出力の最後の行は、commit1の子(commit2へのパス上)です。
| tail -1
子供を追加するだけです。
あなたが言っていることがわかります。以前のコミットに進むための豊富な構文があるのはイライラしますが、次のコミットに進むのはどれもありません。複雑な歴史では、「次のコミットは何か」という問題はかなり難しくなりますが、複雑なマージでは、「以前の」コミットでも同じような困難が生じます。単純なケースでは、線形の履歴を持つ単一のブランチ内で(限られた数のコミットに対してローカルでさえ)、前進および後退するのが良いでしょう。
ただし、これの実際の問題は、子のコミットが参照されず、後方リンクリストのみであることです。子コミットを見つけると、それほど悪くはありませんが、おそらくgitがrefspecロジックに入れたいとは思わない検索が行われます。
とにかく、私はこの質問に出くわしました。なぜなら、私は単に一度に1つのコミットで履歴を一歩進み、テストを行いたいだけであり、時には後退せずに前進しなければならないためです。まあ、私はこの解決策を思いついたいくつかのより多くの考えで:
現在の位置より先にコミットを選択してください。これはおそらくブランチヘッドである可能性があります。Branch〜10にいる場合は、「git checkout branch〜9」、「git checkout branch〜8」、その次は「git checkout branch〜7」のようになります。
必要に応じて、スクリプトで数を減らすのは非常に簡単です。git rev-listを解析するよりもはるかに簡単です。
BRANCH=master; git co $BRANCH~$[ $(git rev-list HEAD..$BRANCH | wc -l) - 1 ]
"ブランチに向かって行かなければなりません、それを回避する方法はありません。
@Michael の回答に基づいてchild
、自分のエイリアスをハッキングしました.gitconfig
。
デフォルトのケースでは期待どおりに機能し、用途も広いです。
# Get the child commit of the current commit.
# Use $1 instead of 'HEAD' if given. Use $2 instead of curent branch if given.
child = "!bash -c 'git log --format=%H --reverse --ancestry-path ${1:-HEAD}..${2:\"$(git rev-parse --abbrev-ref HEAD)\"} | head -1' -"
(別のcommit-ishが2番目の引数として指定されていない限り)現在のブランチの先端に向かって1ステップ先祖をたどることによって、(別のcommit-ish引数が指定されていない限り)デフォルトでHEADの子を指定します。
短いハッシュ形式が必要な場合%h
は%H
、代わりに使用してください。
デタッチされたHEAD(ブランチはありません)またはブランチに関係なくすべての子を取得するには:
# For the current (or specified) commit-ish, get the all children, print the first child
children = "!bash -c 'c=${1:-HEAD}; set -- $(git rev-list --all --not \"$c\"^@ --children | grep $(git rev-parse \"$c\") ); shift; echo $1' -"
をに変更し$1
て$*
、すべての子を印刷します。
--all
commit-ishに変更して、そのコミットの祖先である子のみを表示することもできます。つまり、指定されたコミットの「方向」の子だけを表示することもできます。これにより、出力を多くの子から1つに絞り込むことができます。
固有の「次のコミット」はありません。Gitの履歴は行ではなくDAGであるため、多くのコミットは共通の親(ブランチ)を持つことができ、コミットは複数の親(マージ)を持つことができます。
特定のブランチを念頭に置いている場合は、そのログを見て、どのコミットが現在のブランチを親としてリストしているかを確認できます。
<rev>^
「親コミット」(マージコミットの「最初の親」)。
特定の「宛先」コミットを念頭に置いていないが、代わりに任意のブランチにある可能性のある子コミットを確認したい場合は、次のコマンドを使用できます。
git rev-list --children --all | grep ^${COMMIT}
すべての子と孫を表示したい場合はrev-list --children
、次のように再帰的に使用する必要があります。
git rev-list --children --all | \
egrep ^\($(git rev-list --children --all | \
grep ^${COMMIT} | \
sed 's/ /|/g')\)
(孫だけを与えるバージョンは、より複雑なsed
、および/またはを使用しますcut
。)
最後に、それをlog --graph
コマンドに入力して、次のようにツリー構造を表示できます。
git log --graph --oneline --decorate \
\^${COMMIT}^@ \
$(git rev-list --children --all | \
egrep ^\($(git rev-list --children --all | \
grep ^${COMMIT} | \
sed 's/ /|/g')\))
注:上記のコマンドはすべて、シェル変数${COMMIT}
を、関心のある子のコミットの参照(branch、tag、sha1)に設定していることを前提としています。
${COMMIT}
は必要ありませんが、$(git rev-parse HEAD)
代わりに使用できます
${COMMIT}
。
(これは重複した質問への回答として始まりました。私はそれをきれいにするために少し編集を行いました。)
Gitのすべての内部矢印は一方向で、後ろ向きです。したがって、前進するための短い便利な構文はありません。それは単に不可能です。
「矢印に逆らって移動する」ことは可能ですが、これまでに見たことがない場合は驚くべき方法であり、その後は明らかです。私たちが持っているとしましょう:
A <-B <-C <-D <-E <-- last
^
|
\--------- middle
使い方はmiddle~2
から2回矢を次のC
に戻ってA
。では、どのようにしてからC
に移動しD
ますか?答えは次のとおりです。私たちは、から始まりE
名前を使用して、last
我々はに到達するまで、作業後方middle
、私たちは道に沿って訪問ポイントを記録します。次に、次の方向に必要なだけ移動しlast
ます:1ステップにD
、または2 ステップに移動しE
ます。
これは、ブランチがある場合に特に重要です。
D--E <-- feature1
/
...--B--C <-- master
\
F--G <-- feature2
どのコミットが1ステップ後C
ですか?あなたが質問に追加するまで、正解はありません:feature___の方向(空欄に記入)。
自身C
(とを除くC
)との間のコミットを列挙するには、たとえば、次のG
ようにします。
git rev-list --topo-order --ancestry-path master..feature2
--topo-order
複雑な分岐-とマージの存在下で、コミットは、位相幾何学、ソート順で出てくることを確認します。これは、チェーンが線形でない場合にのみ必要です。--ancestry-path
我々は後方から働くという制約手段feature2
コミットしている、私たちだけのリストコミットC
自分の祖先の1つとして。つまり、グラフまたはそれに関連するチャンクが実際に次のようになっている場合です。
A--B--C <-- master
\ \
\ F--G--J <-- feature2
\ /
H-------I <-- feature3
フォームの単純な要求は、feature2..master
コミットを列挙しJ
、G
そしてI
、そしてF
そしてH
いくつかのために。--ancestry-path
私たちはノックアウトH
とI
、彼らはの子孫ではありません:C
だけの、A
。では--topo-order
、実際の列挙順序がJ
、それからG
、それからであることを確認しF
ます。
このgit rev-list
コマンドは、これらのハッシュIDを標準出力に1行に1つずつ表示します。の方向に1つ前に移動するにfeature2
は、最後の行が必要です。
コミットを生成した後、それらを逆の順序--reverse
でgit rev-list
出力するように追加することは可能です(そして魅力的で便利です)。これは機能しますが、次のようなパイプラインで使用すると、
git rev-list --topo-order --ancestry-path --reverse <id1>...<id2> | head -1
"id2の方向の次のコミット"を取得するだけで、コミットの非常に長いリストがある場合、git rev-list
コマンドはhead
、入力の読み取りを停止して終了した書き込み先のパイプが壊れる可能性があります。パイプの破損エラーは通常シェルによって無視されるため、これはほとんど機能します。それらがあなたの使用法で無視されることを確認してください。
と一緒にコマンドに追加-n 1
するのも魅力的です。やめろ!これにより、1つ前のステップに戻った後に停止し、アクセスしたコミットの(1エントリ)リストを逆にします。したがって、これは毎回生成されるだけです。git rev-list
--reverse
git rev-list
<id2>
「ダイヤモンド」または「ベンゼン環」のグラフのフラグメントでは、次のことに注意してください。
I--J
/ \
...--H M--... <-- last
\ /
K--L
1つのコミットを "前に"からにH
向かって移動last
すると、 I
またはの いずれかが得られますK
。それについてあなたができることは何もありません:両方のコミットは一歩前進です!次に、結果のコミットから開始して別のステップに進むと、開始したパスにコミットされます。
この問題の解決策は、一度に1ステップずつ移動してパスに依存するチェーンにロックされるのを避けることです。代わりに、祖先パスチェーン全体にアクセスする予定がある場合は、他に何かを行う前に、チェーン内のすべてのコミットの完全なリストを作成します。
git rev-list --topo-order --reverse --ancestry-path A..B > /tmp/list-of-commits
次に、このリストの各コミットに1つずつアクセスして、チェーン全体を取得します。--topo-order
あなたがヒットすることを確認しますI
-と- J
そのために、とK
-と- L
(あなたがKLのペアの前または後にIJペアをやるかどうかを予測する簡単な方法はありませんが)の順に。
私はこのエイリアスを持っています ~/.gitconfig
first-child = "!f() { git log --reverse --ancestry-path --pretty=%H $1..${2:-HEAD} | head -1; }; f"
f()
?そしてhead -1
、それは最初の子である必要があります。そうでなければ、これは単にHEADを報告するだけです。
f()
。はい、head -1
勇敢な推測です。
nextref = "!f() { git log --reverse --ancestry-path --pretty=%H $1..HEAD | head -${2:-1} | tail -1; }; f"
あなたは、必要に応じて、どのくらい先に選択できるように
子コミットがすべて一部のブランチにある場合は、を使用できますgitk --all commit^..
。「コミット」はコミットを識別するものです。たとえば、コミットの省略されたSHA-1がc6661c5の場合、次のように入力します。gitk --all c6661c5^..
おそらく、SHA-1全体をgitkの「SHA1 ID:」セルに入力する必要があります。完全なSHA-1が必要になります。この例では、次の方法で入手できます。git rev-parse c6661c5
あるいは、git rev-list --all --children | grep '^c6661c5883bb53d400ce160a5897610ecedbdc9d'
おそらく関係するブランチがあるかどうかにかかわらず、このコミットのすべての子を含む行を生成します。
各コミットは、その親(マージ(標準)コミットの場合は親)へのポインターを格納します。
したがって、親からの子コミット(ある場合)を指す方法はありません。
この投稿(http://www.jayway.com/2015/03/30/using-git-commits-to-drive-a-live-coding-session/#comment-282667)は、もしそれを行うなら、きちんとした方法を示していますコミットスタックの最後に明確に定義されたタグを作成できます。基本的に
git config --global alias.next '!git checkout `git rev-list HEAD..demo-end | tail -1`'
、「demo-end」は最後のタグです。
既存の回答は、あなたが探しているコミットを含むブランチがあることを前提としています。
私の場合、git rev-list --all
ブランチが含まれていないため、探していたコミットはオンではありませんでした。
gitk --reflog
手動で調べてしまいました。
reflogでもコミットが見つからない場合は、次のいずれかを試してください。
git fsck --full
ぶら下がっている(つまり、どのブランチにもない)コミットをリストする、またはgit fsck --lost-found
他の回答でテクニックを適用するためにぶら下がっているコミットを指す参照を作成します。