gitで次のコミットを見つけるにはどうすればよいですか?(ref /の子)


236

ref^前のコミットを指しますが、refのコミットについてはどうですか? ref

たとえばgit checkout 12345、次のコミットをチェックアウトするにはどうすればよいですか?

ありがとう。

PSはい、gitはDAGノードポインタ構造体ツリーです。 この後にコミットを見つけるにはどうすればよいですか?



2
git children-of」も参照してください。
VonC 2013年

回答:


185

現在のコミットから始まり、その子など、すべてのコミットをリストするには、基本的には標準のgit logですが、逆の場合は次のようにします。

git log --reverse --ancestry-path 894e8b4e93d8f3^..master

ここで、894e8b4e93d8f3は、表示する最初のコミットです。


3
元の質問の特定のケースについては、の代わりに使用HEAD^してください894e8b4e93d8f3^
セーレンLøvborg

2
たぶん、-onelineを追加すると、より簡単な出力結果になります。
2015年

1
を使用する必要があり...^..黙って失敗する
TankorSmash

1
取得fatal: unrecognized argument: --ancestry-pathgitのバージョン1.7.1に
user151841

6
これはmaster、が現在のコミットの祖先パス上にある場合にのみ機能します。すべてのケースで機能するソリューションについては、私の回答の2番目のコードスニペットを参照しください。
トム・ヘイル

37

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番目の親はマージしたブランチでのコミットです。


6
git rev-list --children確かに私が望むもののように見えますが、それはDWIMではありません。すべての親とその子がリストされているようです。私はそれらをすべてリストして、それらを解析できると思います...でも、それは何かです。
Schwern、2010

@Schwern:true、git rev-list --children子供だけをリストするのではなく、子供を持つリストする... ...常に解析する必要があります。
VonC、2010

私は2人の子供を持つコミットでそのコードを試しました:$ git children0of 9dd5932 fatal: No annotated tags can describe '71d7b5dd89d241072a0a078ff2c7dfec05d52e1f'. However, there were unannotated tags: try --tags. どのような出力が得られますか?
トム・ヘイル

@TomHale今はテストできませんが、新しい質問を(OSとGitのバージョンで)行ってください。それで、誰でもテストできます。
VonC 2016

1
唯一の問題git-children-ofは、SHAを人間が読める形式にフォーマットしようとするgit describeを使用することです。これは、@ TomHaleのエラーで失敗する可能性がありv1.0.4-14-g2414721、SHAを想定している場合は混乱する結果になります。シンプルに置き換えると、echoこれは優れたツールになります。
Nickolay 2018年

18

私が見つけたのは

git rev-list --ancestry-path commit1..commit2

ここでcommit1、現在のコミットとcommit2現在のヘッドに設定します。これによりcommit1、との間のパスを構築するすべてのコミットのリストが返されますcommit2

出力の最後の行は、commit1の子(commit2へのパス上)です。


3
だから| tail -1子供を追加するだけです。
Jesse Glick、

8

あなたが言っていることがわかります。以前のコミットに進むための豊富な構文があるのはイライラしますが、次のコミットに進むのはどれもありません。複雑な歴史では、「次のコミットは何か」という問題はかなり難しくなりますが、複雑なマージでは、「以前の」コミットでも同じような困難が生じます。単純なケースでは、線形の履歴を持つ単一のブランチ内で(限られた数のコミットに対してローカルでさえ)、前進および後退するのが良いでしょう。

ただし、これの実際の問題は、子のコミットが参照されず、後方リンクリストのみであることです。子コミットを見つけると、それほど悪くはありませんが、おそらくgitがrefspecロジックに入れたいとは思わない検索が行われます。

とにかく、私はこの質問に出くわしました。なぜなら、私は単に一度に1つのコミットで履歴を一歩進み、テストを行いたいだけであり、時には後退せずに前進しなければならないためです。まあ、私はこの解決策を思いついたいくつかのより多くの考えで:

現在の位置より先にコミットを選択してください。これはおそらくブランチヘッドである可能性があります。Branch〜10にいる場合は、「git checkout branch〜9」、「git checkout branch〜8」、その次は「git checkout branch〜7」のようになります。

必要に応じて、スクリプトで数を減らすのは非常に簡単です。git rev-listを解析するよりもはるかに簡単です。


便利ですが、次のコミットは見つかりません。現在のコミットに向かって進みます。
シュヴェルン

1
さて、私はあなたができると思います: " BRANCH=master; git co $BRANCH~$[ $(git rev-list HEAD..$BRANCH | wc -l) - 1 ]"ブランチに向かって行かなければなりません、それを回避する方法はありません。
vontrapp 2013

8

2つの実用的な答え:

一人っ子

@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$*、すべての子を印刷します。

--allcommit-ishに変更して、そのコミットの祖先である子のみを表示することもできます。つまり、指定されたコミットの「方向」の子だけを表示することもできます。これにより、出力を多くの子から1つに絞り込むことができます。


7

固有の「次のコミット」はありません。Gitの履歴は行ではなくDAGであるため、多くのコミットは共通の親(ブランチ)を持つことができ、コミットは複数の親(マージ)を持つことができます。

特定のブランチを念頭に置いている場合は、そのログを見て、どのコミットが現在のブランチを親としてリストしているかを確認できます。


37
そのロジックによって、「以前のコミット」もありませんが、親を取得するための多くの構文があります。
Schwern、

7
@Schwern:「以前のコミット」もありません。<rev>^「親コミット」(マージコミットの「最初の親」)。
JakubNarębski、2010

6

私はさまざまな解決策を試しましたが、どれもうまくいきませんでした。自分で考えなければなりませんでした。

次のコミットを見つける

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

以前のコミットを見つける

function p() {
    git checkout HEAD^1
}

6

特定の「宛先」コミットを念頭に置いていないが、代わりに任意のブランチにある可能性のある子コミットを確認したい場合は、次のコマンドを使用できます。

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)に設定していることを前提としています。


2
これは、googleとstackoverflowを作成する方法がわからないが、尋ねようとしていた質問に答えます。必要性を積極的に認識していただきありがとうございます
Tommy Knowlton '20

私に${COMMIT}は必要ありませんが、$(git rev-parse HEAD) 代わりに使用できます
Radon8472

申し訳ありませんが、に関するメモを追加しました${COMMIT}
Matt McHenry

5

(これは重複した質問への回答として始まりました。私はそれをきれいにするために少し編集を行いました。)

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コミットを列挙しJGそしてI、そしてFそしてHいくつかのために。--ancestry-path私たちはノックアウトHI、彼らはの子孫ではありません:Cだけの、A。では--topo-order、実際の列挙順序がJ、それからG、それからであることを確認しFます。

このgit rev-listコマンドは、これらのハッシュIDを標準出力に1行に1つずつ表示します。の方向に1つ前に移動するにfeature2は、最後の行が必要です。

コミットを生成した後、それらを逆の順序--reversegit 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--reversegit 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ペアをやるかどうかを予測する簡単な方法はありませんが)の順に。


質問に追加するまでは正しい答えはありません。機能の方向に___」これは非常に良い点です。ご回答有難うございます。
Schwern

4

私はこのエイリアスを持っています ~/.gitconfig

first-child = "!f() { git log  --reverse --ancestry-path --pretty=%H $1..${2:-HEAD} | head -1; }; f"


なにf()?そしてhead -1、それは最初の子である必要があります。そうでなければ、これは単にHEADを報告するだけです。
Xerus

@Xerusは「複雑な」シェル構文を使用しているため、gitはにラップされていないと認識しませんf()。はい、head -1勇敢な推測です。
18年

いいね!:への微調整鉱山nextref = "!f() { git log --reverse --ancestry-path --pretty=%H $1..HEAD | head -${2:-1} | tail -1; }; f"あなたは、必要に応じて、どのくらい先に選択できるように
Z. Khullah

2

次の方法で次の子を見つけることができました。

git log --reverse --children -n1 HEAD (where 'n' is the number of children to show)

1
私にとって、これは最初の子ではなく、現在のコミットを示しています
Radon8472

2

子コミットがすべて一部のブランチにある場合は、を使用できます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'おそらく関係するブランチがあるかどうかにかかわらず、このコミットのすべての子を含む行を生成します。


0

各コミットは、その親(マージ(標準)コミットの場合は親)へのポインターを格納します。

したがって、親からの子コミット(ある場合)を指す方法はありません。


追加の子コミット(分岐点)を後で追加できるため、コミットは子へのポインターを格納できません。
JakubNarębski、2010

@Jakub私は本当にフォローしていません。後で追加できませんか?
Schwern、2010

1
Jakub:それはまさに私が言ったことです。「各コミットは、その親へのポインタのみを保存します。」
ラクシュマンプラサード

@Schwern:gitのコミットは不変です(これは説明責任という素晴らしい結果をもたらします)。そのため、子へのポインターは「後で追加」されません。理由の1つは、コミットの識別子(「親」リンクなどで使用される)がコミットの内容に依存することです。これは、分散システムにおける唯一のソリューションであり、中央の番号付け権限はありません。また、コミットの「子」は、ブランチによって異なります。これは、リポジトリごとに異なる場合があります(コミットは各リポジトリで同じです)。
JakubNarębski、2010

4
@becomingGuru反対票を投じました。それは本当かもしれませんが、それは私の質問に答えません。問題は「gitで次のコミットをどのように見つけるのですか?」です。「git commitはその子へのポインタを格納するのですか」ではありません。
Schwern、2010


0

既存の回答は、あなたが探しているコミットを含むブランチがあることを前提としています。

私の場合、git rev-list --allブランチが含まれていないため、探していたコミットはオンではありませんでした。

gitk --reflog手動で調べてしまいました。

reflogでもコミットが見つからない場合は、次のいずれかを試してください。

  • git fsck --full ぶら下がっている(つまり、どのブランチにもない)コミットをリストする、または
  • git fsck --lost-found 他の回答でテクニックを適用するためにぶら下がっているコミットを指す参照を作成します。
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.