Skip to content
This page has been auto-translated and may contain errors.View in English

コミットループ

docs.scrimba.com

weather-appで過去20分間作業してきたとしましょう。src/index.jsの実際のバグを修正しました。気温変換がずれていたのです。その過程でstyles.cssのリスタイリングも始めましたが、その変更は途中で完成していないため、他の誰かに見せる準備ができていません。バグ修正をそれ自体のチェックポイントとして今すぐ保存したいのです。未完成のスタイリングを一緒に引きずることなく。

それがコミットループの目的です。まだリポジトリをセットアップしていない場合は、Your first repositorygit initとクローンについて説明しています。ここからは、このチャプターが1つ開いていることを前提としています。

3つのステップ:ワーキングディレクトリ、ステージングエリア、コミット

Gitで行うすべての変更は、永続的な履歴になるまでに3つのステップを通過します。ワーキングディレクトリは、プロジェクトが現在ディスク上に存在する状態です。あなたが積極的に編集しているファイルです。**ステージングエリア**は、次に保存したい変更を正確に配置する保管場所です。コミットは、それを書いたら、メッセージを説明するとともに、保存されたスナップショット自体です。

引っ越しのための荷造りを想像してください。あなたの家全体がワーキングディレクトリです。あなたが所有しているすべてのもの、どんな状態でも。玄関に梱包されてテープで封じられた箱がステージングエリアです。持っていくために意図的に選んだものだけです。それらの箱を乗せて走り去るトラックがコミットです。その瞬間に何が出発したか、そして中に何が入っているかを説明するラベルが付いた記録です。

実際のターミナルでそのメンタルモデルが表示されます。weather-appで両方のファイルを編集した後、git statusは何も変更せずに現在の状態を読み取ります:

bash
$ git status
On branch main
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   src/index.js
        modified:   styles.css

no changes added to commit (use "git add" to commit)

両方のファイルが「not staged」として表示されるのは、ファイルを編集すると、ワーキングディレクトリだけが変更されるためです。git addでGitに配置するように指示するまで、何もステージングエリアに移動しません。これが次のセクションです。

ここが、ステージングエリアが存在する理由の全体像が明確になる場所です。ステージングエリアを使用すると、ワーキングディレクトリにまだ編集されているその他のものから独立して、コミットにどの内容を含めるかを正確に選択できます。これなしに、チェックポイントを保存すると、準備ができているかどうかに関わらず、ディスク上のすべての変更を一度に取得することになります。

それを使えば、src/index.jsの完成したバグ修正をステージングし、途中のstyles.cssを除外して、実際に完成した部分だけをコミットできます。ステージングとワーキングディレクトリが同時に異なる内容を保持できるというこの1つの詳細は、最初の週にほぼすべての人を混乱させます。一度理解できれば、Gitの日々のワークフローの残りの部分がより理にかなってきます。

日々の作業では、すべてのaddcommitの前に、何か問題があるように感じるかどうかに関わらず、git statusをルーチンステップにしてください。費用はかかりませんし、プロジェクトも変更されず、意図した以上にコミットするという一般的な間違いを防ぎます。ステータスを確認してからステージングし、コミット前に再度ステータスをチェックする習慣を身に付けてください。数秒で済みます。これは、コミットのメッセージが実際に含まれるものと常に一致することを意味します。

ステージングエリアは実際のファイルで、**index**と呼ばれ、リポジトリ内の.git/indexに存在します。git addを実行するたびに、Gitはそのファイルを更新して、どのバージョンのどのファイルがステージングされているかを記録します。git commitを実行すると、Gitはワーキングディレクトリを再度チェックすることなく、インデックスがどのような内容であるかから新しいコミットを純粋に構築します。これは、先ほどgit statusで見た分割の仕組み全体です:ディスク上で編集された2つのファイルですが、インデックスはまだどちらも追跡していないため、その後のコミットは現在のところ何も含まれません。

JunoGitの3つのエリア ワーキングディレクトリはあなたのファイルが今どのように存在するかです。ステージングエリアは次に保存したい変更を正確に配置する場所で、コミットはそれを書いたら保存されたスナップショットです。ファイルを編集しただけではステージングされません。git addで何を含めるかを選択でき、それがあなたが半分完成した変更を除外しながら1つの完成した変更を保存できる理由です。
JunoGitの3つのエリア ワーキングディレクトリ、ステージングエリア、コミット:編集は最初のものに存在し、git addは正確に選択したものを2番目のものに移動し、git commitは2番目のものを永続的なスナップショットとして保存します。ステージング前とgit commit前にgit statusを実行してください。無料で、あなたのコミットが保存したいものと一致することを保ちます。
JunoGitの3つのエリア ステージングエリアは実際のファイルで、.git/indexのインデックスであり、git commitはそのスナップショットをインデックスから構築し、ワーキングディレクトリから直接構築しません。だから2つの編集されたファイルの両方を未ステージングとして表示できます。インデックスはまだどちらについても何も言われていません。このようなインデックスを理解することで、すべてのステージングコマンドは魔法ではなく、1つのファイルを読み書きするようなものに感じられます。

変更のステージング:git add

git addは、ワーキングディレクトリからステージングエリアに変更を移動します。次のコミットにどのファイルの変更を含めるかをポイントします:

bash
$ git add src/index.js
$ git status
On branch main
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   src/index.js

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   styles.css

src/index.jsが「Changes to be committed」に移動し、バグ修正がステージングされて準備ができました。styles.cssは「not staged」の下にリストされたままで、これはリスタイリングが未完成の間のあなたが望む場所です。git add styles.cssも実行すると、それもステージングされます。git add .を実行すると、現在のフォルダ内のすべての変更されたファイルを一度にステージングします。これはディスク上のすべてが実際に準備ができているのを確認したら便利です。

時々、1つのファイルに保存したい変更と保存したくない変更が両方含まれていて、それらを2つのファイルに分割することは実用的ではありません。git add -p <file>--patchの短形)は、ファイルの変更を「hunk」と呼ばれる小さなチャンクで使用でき、各チャンクについて決定するよう求めます:

bash
$ git add -p src/index.js
@@ -12,7 +12,7 @@ function celsiusToFahrenheit(celsius) {
-  return celsius * (9 / 5 + 32)
+  return (celsius * 9) / 5 + 32
Stage this hunk [y,n,q,a,d,e,?]?

そのhunkをステージングするにはyで答え、後のために置いておくにはnで、停止するにはqで答えます。これは単一ファイル内でもコミットサイズの制御を与えます。これは「このファイルの半分は完成している」があなたの状況を説明するときはいつでも手を出す価値があります。

git addは同時に2つのことを実行し、両方を知ることで、最終的にぶつかるgotchaを説明します。まず、ファイルの現在の内容を新しい**blob**に書き込みます。Gitがコミットと同じ方法でハッシュで識別される永続的に保存するオブジェクト。1つのファイルの正確な内容が1つの瞬間に。第二に、インデックスを更新して、そのファイルのそのblobを指すようにします。addについて何もその後ファイルを再度見ません。

だから、git add src/index.jsを実行してから、コミット前に同じファイルを編集し続けると、git statusはそれがステージングされて変更されたものとして同時に表示されます。インデックスはまだaddを実行したときのblobを指し、ワーキングディレクトリは先に進みました。git commitはステージングされたblobしか見ていないため、2番目のgit addは保存する前に新しい編集を引き込むものです。

Juno変更のステージングgit add <file>はそのファイルの現在の変更をステージングエリアに移動し、次のコミット準備をします。まだ追加していないファイルは除外されるため、1つのものを終了して別のものを編集中のまま残すことができます。git add .はすべての変更されたファイルを一度にステージングし、すべてが実際に準備ができたら便利です。
Juno変更のステージングgit add <file>はファイル全体をステージングし、git add -p <file>はファイルの一部だけが準備ができているときhunkごとにステージングすることができます。その2番目のものは「このファイルの半分は完成している」というのが本当の瞬間に手を出す道具です。
Juno変更のステージングgit addはファイルの現在の内容をblobに書き込んでインデックスを指しますが、その後はファイルを見ていません。コミット前にファイルを再度編集してください。statusはそれがステージングされて変更されたものとして表示されます。なぜなら、インデックスはまだ古いblobを保持しているからです。新しい編集を引き込むためにaddを再実行してください。これは初めて私がそれにぶつかったとき、混乱した10分間を費やしました。

スナップショットの保存:git commit

ステージングエリアがあなたが望むものを保持したら、git commitはそれを永続的なスナップショットとして保存し、-mフラグ(「message」の短形)は、それと一緒に移動する説明を提供します:

bash
$ git commit -m "Fix temperature conversion in Celsius-to-Fahrenheit formula"
[main 4f2a1c9] Fix temperature conversion in Celsius-to-Fahrenheit formula
 1 file changed, 1 insertion(+), 1 deletion(-)

src/index.jsだけが含まれました。それがステージングしたすべてだからです。styles.cssはまだワーキングディレクトリで編集されたままで、リスタイルが完成したときはいつでも待機しています。短いid、4f2a1c9は、このコミットの名前を付け、Historyチャプターはこのようなプロジェクトの完全なコミットリストを読むことをカバーしています。

命令として、命令法でコミットメッセージを書きます。「Fix temperature conversion」はGitが使用するのと同じ文言です(「このコミットは...」)。1行の修正より複雑なものについては、変更が必要だった理由を説明する本体を追加してください。diffは既に何が変更されたかを示しているので、本体をその背後にある理由のために保存します:

bash
$ git commit -m "Fix temperature conversion in Celsius-to-Fahrenheit formula

The formula was applying operator precedence in the wrong order,
which rounded warm temperatures down by a degree in the UI."

コミット直後に誤字や見逃した詳細に気付いた場合、git commit --amendは最も最近のコミットを、上に別のコミットを追加する代わりに新しいコミットで置き換えます:

bash
$ git commit --amend -m "Fix temperature conversion in Celsius-to-Fahrenheit formula"

まだどこにも共有していないコミットだけを修正してください。それをプッシュ(プロジェクトの共有コピーに送信)したら、修正すると他の人がすでに持っているかもしれない履歴を書き直し、Undoing thingsはその後でコミットを修正する安全な方法をカバーしています。

コミット自体は3つの部分を持つ小さなオブジェクトです:tree、著者、メッセージへのポインタ、親のコミットへのポインタです。treeはその瞬間のプロジェクト全体のディレクトリ構造のスナップショットです。すべてのファイルとフォルダについて、名前と、blobへのポインタ(ファイルの内容)またはもう1つのtree(サブフォルダ)へのポインタを記録します。git addを実行するとblobを書き込み、インデックスを1つのファイルずつ更新します。git commitはGitが現在のインデックスを1つの完成したtreeに変え、コミットオブジェクトでそれをラップする瞬間です。

同じ内容を持つ2つのファイルは、異なるフォルダに配置されている場合でも、正確に同じblobを指しているため、コミットはそのバイトを2回保存しません。その構造はまた2つのコミットを比較するのを効率的にします。Gitはそれらの2つのツリーを並べて歩き、ポインタが実際に異なるblobだけを開きます。変わらないすべてのファイルをスキップします。

Junoコミットの保存git commit -m "message"は現在ステージングされているものを永続的なスナップショットとして保存し、あなたが与えたメッセージで保存します。ステージングしなかったものはそのままで編集可能のままです。メッセージを短く保ち、コミットが行うことについて明確にしてください。あなたがそれを予想するより頻繁に将来のあなたがそれを読み直すでしょう。
Junoコミットの保存 コミットメッセージを命令として書き、「Fixed」ではなく「Fix」を、diffだけでは誰かが変更を加えた理由を推測することになるときはいつでも本体を追加してください。git commit --amendはメッセージの誤字に最適で、最後のコミットを置き換えます。ただし、そのコミットをどこかにプッシュしていない限り。
Junoコミットの保存 コミットはtreeを指し、treeは名前をblobと更なるtreeに写し、コミット時にインデックスが保持していた内容から構築されたプロジェクト全体の完全なネストされたスナップショットです。addはblobを書き込み、commitはインデックスを完成したtreeに変え、プロジェクト内のどこにでも同じ内容は1つのblobを共有し、2回保存される代わりに。その形状を想像して、2つのもの停止が魔法のように感じます:なぜ何も複製されないか、そして2つのコミットを比較することが2つのツリーを並べて歩くことを意味する理由をわかってください。その代わりにすべてのファイルを再度読むことではなく。