2018年以降の記事はGitHub Pagesに移行しました

Pro Gitと入門gitでGitの復習 基本操作編

あらすじ

めっきりadd, commitくらいしか使っていないGitをもう一回さわってみて学びなおす。Pro Gitのページもブクマしただけで真剣に読んでいなかったので読み進める。
続き。

参考

リポジトリの作成

リポジトリにしたいディレクトリの中でinitコマンドで作成 or init ディレクトリ で生成。

$ git init
Initialized empty Git repository in c:/project/testRemote/test/.git/

以後は基本的にリポジトリの中で作業。

コンフィグ

コンフィグファイルの適用範囲と優先度

下に行くほど適用範囲は狭くなり、優先度が上がる。(同じオプションがあったら下のものが適用される)

ファイル Windows(msysGit)では 範囲 優先度 configコマンドでの設定方法
/etc/gitconfig (msysのルート)/etc/gitconfig システム全体 --system
~/.gitconfig %USERPROFILE%\.gitconfig あるユーザ --global
(リポジトリ内).git/config (リポジトリ内).git/config そのリポジトリ (指定なし)
コンフィグの一覧を見る

そのリポジトリのコンフィグを見る。

$ git config --list
user.name=kk_Ataka
...

あるユーザのコンフィグを見る。

$ git config --list --global

システム全体のコンフィグを見る。

$ git config --list --system
コンフィグの確認(特定の)
$ git config user.name
kk_Ataka
コンフィグの編集
$ git config --global user.name "kk_Ataka"
$ git config --global user.email "test@example.com"

リポジトリ作成

.git ファイルを作成し、その中にGitリポジトリのスケルトンが格納される。→スケルトン?

リポジトリを作成する
$ git init testdir
Initialized empty Git repository in c:/project/testdir/.git/

リポジトリのクローン

既存のリポジトリを歴史毎ごっそり持ってくる。プロトコルにはhttp,https,git等がある。

既存リポジトリのクローン
$ git clone http://github.com/gosyujin/excel_for_ruby.git
Cloning into excel_for_ruby...
remote: Counting objects: 22, done.
remote: Compressing objects: 100% (13/13), done.
remote: Total 22 (delta 2), reused 21 (delta 1)
Unpacking objects: 100% (22/22), done.
$ cd excel_for_ruby\
$ git log
commit b6cd9964b1e586d8be280acd40c9719f6cc045c0
Author: kk_Ataka <kk_ataka@---.---.jp>
Date:   Sun Dec 25 17:36:53 2011 +0900

    .gitignore追加

状態確認

作業ツリーの状態確認
  • 変更なし
$ git status
# On branch master
nothing to commit (working directory clean)
  • 変更あり
  • Untracked files

まだGitに追跡されていないファイル。(=前回コミット時になかったファイル)これからaddする必要がある。赤く表示される。

$ git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       README
nothing added to commit but untracked files present (use "git add" to track)
  • new file

addで新しく追跡開始されたファイルmenu.htmlがステージされている。緑で表示される。

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   menu.html
  • modified

既に追跡されているファイルが変更された。赤で表示される。これからaddでステージする。

$ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   index.html
#
no changes added to commit (use "git add" and/or "git commit -a")

ファイル追加(追跡)

リポジトリに追加(追跡の開始)
ステージング

追跡の開始ともいうらしい。ディレクトリを指定すると、その下を再帰的に追跡する。

$ git add index.html

ファイル比較

ファイルの比較
  • 作業ツリーの内容とステージングエリアの比較
$ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   index.html
#
no changes added to commit (use "git add" and/or "git commit -a")
$ git diff
diff --git a/index.html b/index.html
index a633da3..bc2a94f 100644
--- a/index.html
+++ b/index.html
@@ -1,8 +1,9 @@
 <html>
   <head>
-    <title>Welcome !!</title>
+    <title>Welcome</title>
   </head>
   <body>
     <h1>Hello</h1>
+    <p>Hello world</p>
   </body>
 </html>
  • ステージされた内容と直近のコミットの比較
$ git add index.html
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   index.html
#
$ git diff

add してdiff すると出力はなし。--cached, --stagedオプションをつけるとステージされた内容との比較を取る。

$ git diff --cached
diff --git a/index.html b/index.html
index a633da3..bc2a94f 100644
--- a/index.html
+++ b/index.html
@@ -1,8 +1,9 @@
 <html>
   <head>
-    <title>Welcome !!</title>
+    <title>Welcome</title>
   </head>
   <body>
     <h1>Hello</h1>
+    <p>Hello world</p>
   </body>
 </html>
$ git diff --staged
diff --git a/index.html b/index.html
index a633da3..bc2a94f 100644
--- a/index.html
+++ b/index.html
@@ -1,8 +1,9 @@
 <html>
   <head>
-    <title>Welcome !!</title>
+    <title>Welcome</title>
   </head>
   <body>
     <h1>Hello</h1>
+    <p>Hello world</p>
   </body>
 </html>

ステージした後に編集。

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   index.html
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   index.html

これをdiff, diff --stagedで比較すると……。

$ git diff
diff --git a/index.html b/index.html
index bc2a94f..341bb47 100644
--- a/index.html
+++ b/index.html
@@ -4,6 +4,7 @@
   </head>
   <body>
     <h1>Hello</h1>
-    <p>Hello world</p>
+    <p>Hello world !!</p>
+    <span>I am typo</span>
   </body>
 </html>
$ git diff --staged
diff --git a/index.html b/index.html
index a633da3..bc2a94f 100644
--- a/index.html
+++ b/index.html
@@ -1,8 +1,9 @@
 <html>
   <head>
-    <title>Welcome !!</title>
+    <title>Welcome</title>
   </head>
   <body>
     <h1>Hello</h1>
+    <p>Hello world</p>
   </body>
 </html>

diffが作業ツリーの内容とステージングエリアの比較でdiff --stagedがステージされた内容と直近のコミットの比較だから歴史としてはa633da3 -> bc2a94f -> 341bb47こうか。

ファイル削除(追跡除外)

ファイルの削除(追跡の除外)

通常のrmだと作業ツリーからファイルを消しただけ。

$ rm VERSION

$ git status
# On branch master
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       deleted:    VERSION
#
no changes added to commit (use "git add" and/or "git commit -a")

git rm 後にcommitする事で追跡対象から除外する。

$ git rm VERSION
rm 'VERSION'

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       deleted:    VERSION
#
$ git commit -m "Deleted VERSION file"
[master 5981baf] Deleted VERSION file
 0 files changed, 0 insertions(+), 0 deletions(-)
 delete mode 100644 VERSION

$ git status
# On branch master
nothing to commit (working directory clean)

コミット

コミットを行う

ログ記述のためにgit config core.editorや環境変数EDITORに適切なエディタが設定されている必要がある。VIなど

$ git commit index.html
 1
 2 # Please enter the commit message for your changes. Lines starting
 3 # with '#' will be ignored, and an empty message aborts the commit.
 4 # On branch master
 5 # Changes to be committed:
 6 #   (use "git reset HEAD <file>..." to unstage)
 7 #
 8 #       modified:   index.html
 9 #

commit -v でdiffを確認する事も出来る。

 1
 2 # Please enter the commit message for your changes. Lines starting
 3 # with '#' will be ignored, and an empty message aborts the commit.
 4 # Explicit paths specified without -i nor -o; assuming --only paths...
 5 # On branch master
 6 # Changes to be committed:
 7 #   (use "git reset HEAD <file>..." to unstage)
 8 #
 9 #       modified:   index.html
10 #
11 diff --git a/index.html b/index.html
12 index a633da3..341bb47 100644
13 --- a/index.html
14 +++ b/index.html
15 @@ -1,8 +1,10 @@
16  <html>
17    <head>
18 -    <title>Welcome !!</title>
19 +    <title>Welcome</title>
20    </head>
21    <body>
22      <h1>Hello</h1>
23 +    <p>Hello world !!</p>
[master (root-commit) 4b5c302] First commit.
 1 files changed, 8 insertions(+), 0 deletions(-)
 create mode 100644 index.html
コミットを行う(コミットログまでワンライナー)

commit -mでコミットログを指定できる。-mを打つ毎に改行される

$ git commit -m "Modified index.html title" -m "Added menu.html"
[master eaa9ebc] Modified index.html title
 2 files changed, 6 insertions(+), 1 deletions(-)
 create mode 100644 menu.html
追跡ファイルのステージを省略

addを省く。

$ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   menu.html
#
no changes added to commit (use "git add" and/or "git commit -a")
$ git commit -a -m "Added head tag"
[master 1d4d741] Added head tag
 1 files changed, 2 insertions(+), 0 deletions(-)
$ git status
# On branch master
nothing to commit (working directory clean)

追跡可能じゃないとできない?

$ touch VERSION

$ git commit -a -m "Added VERSION file"
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       VERSION
nothing added to commit but untracked files present (use "git add" to track)

コミットのやり直し

誤ってtypoしたままコミットしてしまった。

$ cat README
Haloo Wold

$ git commit -a -m "Typo commit"
[master 663daa6] Typo commit
 1 files changed, 1 insertions(+), 0 deletions(-)

$ git log
commit 663daa64c7fab6a23e17a7e544dd81df85d88dc6
Author: kk_Ataka <test@example.com>
Date:   Tue Feb 21 18:50:59 2012 +0900

    Typo commit

commit 5981baf9b3a9bd4a1d5a9cf5f26738391fbb9fff
Author: kk_Ataka <test@example.com>
Date:   Tue Feb 21 13:10:02 2012 +0900

    Deleted VERSION file

コミットした後commit --amendで前回のコミット直前からやり直せる?

$ vi README
$ git add README
$ git commit --amend

$ git log
commit a59ff99de68cbf359c814f25cda9c926ef9cdad9
Author: kk_Ataka <test@example.com>
Date:   Tue Feb 21 18:50:59 2012 +0900

    Modified typo
commit 5981baf9b3a9bd4a1d5a9cf5f26738391fbb9fff
Author: kk_Ataka <test@example.com>
Date:   Tue Feb 21 13:10:02 2012 +0900

    Deleted VERSION file

ステージのやり直し

ステージングエリアに入れたファイルを取り消したいときはresetコマンドを使う。

$ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   README
#
no changes added to commit (use "git add" and/or "git commit -a")

$ git add README

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   README
#

ここでステージングエリアに入れたREADMEファイルをreset。

$ git reset HEAD README
Unstaged changes after reset:
M       README
$ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   README
#
no changes added to commit (use "git add" and/or "git commit -a")

HEADってなんじゃらほい? 今自分が作業じているローカルブランチへのポインタ。上から見ていくと今はmasterから動いていないので作業しているブランチはmasterのまま=HEADもmaster。

変更の取り消し

SubversionでいうところのRevertであっている? 編集したファイルを直前のコミットの状態まで戻す。実はずっとgit statusコマンド打っていたときに出ていた。

$ git diff README
diff --git a/README b/README
index 27f338f..557db03 100644
--- a/README
+++ b/README
@@ -1 +1 @@
-Hello Wrld
+Hello World

$ git status
# On branch master
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   README
#
no changes added to commit (use "git add" and/or "git commit -a")

checkout -- で戻せるようだ。

$ git checkout -- README

$ git diff README

$ cat README
Hello Wrld

リモート関連

(リモート)リポジトリの作成

作業ディレクトリがいらない場合はinit --bareオプションをつける。ディレクトリ名に.gitをつけるのは慣例……だったかな? 何かに書いてあった気がする。

$ git init --bare remote1.git
Initialized empty Git repository in c:/project/testRemote/remote1.git/
リモートリポジトリの追加

追加はremote add [shortname] [url]で行う。以後、gitコマンドからはshortnameで指定できるようになる。

$ git remote add rem1 c:/project/testRemote/remote1

ここでURLを間違えていた事に気づく。(.git忘れた)が、同じshortnameにaddしても既にあるよって言われてしまうので削除しないといけない。

$ git remote add rem1 c:/project/testRemote/remote1.git
fatal: remote rem1 already exists.

また、Windows?msysGit?を使っている場合は、Windows感覚でパスを打ちこむとエスケープされる。

$ git remote add rem1 c:\project\testRemote\remote1.git

$ git remote -v
rem1    c:projecttestRemoteremote1.git (fetch)
rem1    c:projecttestRemoteremote1.git (push)

円マークを重ねるのとスラッシュとでは表記は変わるけど違いはないようだ。

$ git remote add rem1 c:/project/testRemote/remote1.git

$ git remote add rem2 c:\\project\\testRemote\\remote2.git

$ git remote -v
rem1    c:/project/testRemote/remote1.git (fetch)
rem1    c:/project/testRemote/remote1.git (push)
rem2    c:\project\testRemote\remote2.git (fetch)
rem2    c:\project\testRemote\remote2.git (push)
リモートリポジトリのリネーム

remote rename [shortname_now] [shortname_after]でいける。

$ git remote rename rem1 remo

$ git remote
rem2
remo
リモートリポジトリの削除

remote rm [shortname]

$ git remote rm rem1
リモートリポジトリの確認

リポジトリからcloneしてきた場合はoriginという名前が付けられる。Gitがデフォルトでつけるshortname。よくgit push origin masterとかで出てくるorigin。

$ git remote -v
origin  http://github.com/gosyujin/evernote_for_ruby.git (fetch)
origin  http://github.com/gosyujin/evernote_for_ruby.git (push)

git initでローカルに作成したリポジトリだとoriginもないので何も表示されない。

$ git remote

addした後はそのリポジトリのshortnameが列挙される。

$ git remote
rem1
rem2

remote -vでURLも。

$ git remote -v
rem1    c:/project/testRemote/remote1.git (fetch)
rem1    c:/project/testRemote/remote1.git (push)
rem2    c:\project\testRemote\remote2.git (fetch)
rem2    c:\project\testRemote\remote2.git (push)

remote show [shortname]でより詳しく。

$ git remote show rem1
* remote rem1
  Fetch URL: c:/project/testRemote/remote1.git
  Push  URL: c:/project/testRemote/remote1.git
  HEAD branch: master
  Remote branch:
    master tracked
  Local ref configured for 'git push':
    master pushes to master (up to date)
リモートリポジトリからデータ取得(フェッチ、プル)

リモートにあるデータの内、まだ持っていないものを取得できる。fetchコマンドを使う。

$ git fetch rem1

$ git fetch rem2

空のリポジトリからfetchしているので特に何も起こらなかった……。cloneした後(最近fetchした後)からの変更を取得できる。ただし、これだと取得しただけなのでfetch後マージをしてやる必要がある。フェッチ、マージを一気にやってくれるgit pullというコマンドもある。

リモートリポジトリへのデータ登録(プッシュ)

ローカルにコミットしたデータをプッシュ。という事でpushコマンドを使用。push [shortname] [branch]でプッシュ先とプッシュするブランチを指定。

$ git push rem1 master
Counting objects: 26, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (22/22), done.
Writing objects: 100% (26/26), 2.33 KiB, done.
Total 26 (delta 5), reused 0 (delta 0)
Unpacking objects: 100% (26/26), done.
To c:/project/testRemote/remote1.git
 * [new branch]      master -> master

次はブランチから。