2009年8月29日土曜日

ステージを理解して git をもっと便利に使う(その3)

前回から引き続き、「ステージを理解して git をもっと便利に使う」というテーマでお送りする、git解説記事の第3弾です。

まずは、前回までのおさらいです。

git にはリポジトリに格納された「最新のコミット」と「ワーキングコピー」の間に「index」と呼ばれる緩衝地帯が存在しています。チェックアウト直後は

「最新のコミット」=「index」=「ワーキングコピー」

ですが、ワーキングコピーを編集した後、git addにより編集内容がstage(indexに登録)され、

「最新のコミット」≠「index(+α)」=「ワーキングコピー(+α)」

となります。

% git add

% git add -p

を積極的に使うことで、編集内容を部分的にstageする/しないをコントロールし、1コミットの内容を洗練しましょう、というのが第1回の内容でした。

第2回はgit diffとgit diff --cachedの違いについて解説しました。

% git diff

は「index」と「ワーキングコピー」の差分を表示し、

% git diff --cached

は「最新のコミット」と「index」の差分を表示する、
という内容でした。

第3回はgit resetになります。

●git reset
実行例

% git reset

git resetを使うと、一度git addでstageした変更内容をindexから削除(unstage)することができます。

例として、
「ワーキングコピーの README と src/abc.c を編集し、git add -uで両方ともstageしたが、よく考えてみると別々にコミットすべき内容だった」
という状況を考えます。git statusで確認すると、以下のように表示されます。

kt@ume% git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD ..." to unstage)
#
# modified: README
# modified: src/abc.c
#

今回はREADMEだけをコミットし、src/abc.cはその後のコミットに含めることにしたとします。
この場合、git reset src/abc.cを実行することでsrc/abc.cをunstageできます。

kt@ume% git reset src/abc.c
src/abc.c: locally modified
kt@ume% git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD ..." to unstage)
#
# modified: README
#
# Changed but not updated:
# (use "git add ..." to update what will be committed)
#
# modified: src/abc.c
#

このとおり、src/abc.cは「Changes to be committed:」から「Changed but not updated:」に移りました。
これでgit commitしても変更が反映されるのはREADMEだけです。

git add -pによりファイルの内容を部分的にstageできますが、unstageはファイル単位でしかできないようです。
git add -pを間違えた場合は、一旦git resetして再度git add -pでstageしなおしましょう。

なお、上の実行例の「Changes to be committed:」の下の行にこんなコメントが書かれているのに気づいたでしょうか?

# (use "git reset HEAD ..." to unstage)

unstageのやりかたがそのものズバリ書いてあります。
もしgit resetを忘れてしまった場合にも「git statusの出力を見れば書いてある」ということさえ覚えておけば、どうすればよいか思い出せるでしょう。



●おまけ
前回紹介したgit diff --cached ってコマンドを打つのが面倒じゃありませんか?こんなときは git configで別名を定義しましょう。

kt@ume% git config --global alias.difc "diff --cached"
kt@ume% git help difc
`git difc' is aliased to `diff --cached'

上記の例では difc を "diff --cached" の別名として定義しています。
CVSやSubversionからの乗り換えユーザには以下のようなaliasもおすすめです。

git config --global alias.ad add
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.co checkout
git config --global alias.dif diff
git config --global alias.di diff
git config --global alias.st status

3 件のコメント:

  1. 最近Gitを使い始めて、かつ一人で使ってるので、ステージングの意味合いがよくわからなかったんですが、こちらの記事で理解が深まりました。ありがとうございます。

    返信削除
  2. いえいえー、お役に立てたのなら幸いです。

    返信削除
  3. ぼちぼちgitを使い始めたところなのですが,卒直にいってどうも分かりにくい…
    ステージングのご説明,明解で目からウロコが落ちる思いでした.
    本当にありがとうございました!

    返信削除