以下の文章のオリジナルは、word文章として ここ にある(古い版)。
2017/06/23 okazaki,i はじめてのGit - 以下のファイル名、ディレクトリ名、注釈などはすべて英語とする(日本語は避ける)
概要や予備知識 o ローカルリポジトリ(自分が作業に使っているリポジトリのこと。目の前にあるものなので、ローカルなリポジトリである。 単にリポジトリとも呼んだりする) ・作業ディレクトリをもつ(開発するソースコードなどのファイルやディレクトリが置かれる)。 ・作業ディレクトリには ".git"というディレクトリがあり、コミット済やステージングしたファイル、リモートリポジトリの 情報などが保存されている(これがリポジトリの本体)。 ・作業ディレクトリにあるファイルのうち、追跡対象として登録されているものだけをgitは版管理する(コミットされた版に 対して、ありとあらゆる事ができる。版は分岐でき、各分岐はブランチと呼ぶ)。 ・作業ディレクトリ上で、(1) ファイルを新規作成や修正して新しい版を作り、(2) ステージに載せて(ステージに登録、 ステージングなどとも言われる。ステージのことをインデックスやキャッシュとも言われる)、(3) コミットをすることで、 新しい版が.gitディレクトリに保存される。 ・作業ディレクトリにある追跡対象になっているファイルはおよそ次の状態のいずれかである。 1) コミット済(版として登録されているファイルと同じ) 2) ステージ済(コミットする予定として登録されているファイルと同じ) 3) 修正中(未コミットであり、ステージにも未登録な版のファイル。ステージ登録後にコミットせずに修正することもできる) ・ふつう、ローカルリポジトリは追跡しているリモートリポジトリを持つ。リモートリポジトリは他のリポジトリのことである (同じマシン上のときもあれば、異なるマシン上のリポジトリのときもある)。リモートリポジトリから新しい版を取り寄せ たり(pull)、リモートリポジトリに新しい版を送ったり(push)できる。 ・リモートリポジトリは名前(originなど)を付けて複数登録できる。 ・新規にローカルリポジトリを作ると、ブランチはmasterになっている。ローカルリポジトリが他のリポジトリを追跡するよう に作成(clone)した場合には、追跡しているリポジトリのURLがoriginに登録されている。 o リモートリポジトリ ・ローカルリポジトリ以外のリポジトリである。 ・ふつうは、ベアリポジトリである。 o ベアリポジトリ ・作業ディレクトリを持たないリポジトリ(ローカルリポジトリの.gitディレクトリのみから成る)である。 ・作業ディレクトリを持たないため、ここで作業をしてpushやpullするような事はできない。
最初に一度だけする設定(マシン毎) $ git config --global user.name "名前" $ git config --global user.email "メールアドレス" $ git config --global core.editor emacs $ git config --global push.default simple
使い方の例(リポジトリの作成) o ローカルで、あるディレクトリを対象にして、自分だけが使う場合 $ cd ディレクトリ $ git init o 既存のベアリポジトリをクローンして利用する場合 $ git clone ベアリポジトリのURL 作業ディレクトリ名 o 新規にベアリポジトリを作り、利用する場合 あるマシンで $ mkdir ベアリポジトリのディレクトリ名.git $ cd ベアリポジトリのディレクトリ名.git #(*) $ git init --bare あるマシンで $ cd ディレクトリ(作業ディレクトリにするディレクトリ) $ git init $ git remoteadd origin 上記(*)のベアリポジトリのURL #URLは ssh://xxx@yyy:/~/ベアリポジトリのディレクトリ名.git など $ git add ファイルやディレクトリ #下記参照 $ git commit -m "注釈" #下記参照 $ git push --set-upstream origin master
使い方の例(作業) o ファイルをステージングし、ローカルリポジトリにコミットする $ git add ファイル #ファイル(ディレクトリも指定が可能)をステージングする。 #初めてaddされたファイルであれば、自動的にgitで版管理する追跡対象になる。 $ git commit -m "注釈" #ステージングされたファイルをローカルリポジトリにコミットする。 #注釈は英語で! o ローカルリポジトリの更新内容をリモートリポジトリに送る $ git push o リモートリポジトリの更新内容を作業ディレクトリに取り込む $ git pull o 新しくローカルリポジトリにブランチを作る $ git checkout -b ブランチ #ブランチを作成し、作成したブランチに移動する o 既存のブランチに移動する(ブランチを切り替える) $ git checkout ブランチ #既存のブランチに移動する(未コミットなどがあれば移動できない) o 新しくローカルリポジトリにブランチを作り、リモートリポジトリにpushする(リモートリポジトリに同名のブランチが 無いとき) $ git checkout -b ブランチ #ブランチを作成し、作成したブランチに移動する $ git push --set-upstream origin ブランチ #リモートリポジトリoriginにブランチをpush(作成)し、ローカルリポジトリのブランチが #originの作成(push)したブランチを追従するように設定する。 o リモートリポジトリにあるブランチを追跡するように、ローカルリポジトリに同名のブランチを作成し、作成したブランチ に移動する(ローカルリポジトリに同名のブランチが無いとき) $ git checkout --track origin/ブランチ o 更新内容の表示など $ git fetch #リモートリポジトリの更新内容を読み込む $ git remote -v ; git branch -vv #リモートリポジトリを表示;ブランチを表示 $ git status #作業ディレクトリの状態表示 $ git log -15 --oneline --decorate --graph --all #コミットログを表示 $ gitk --all #コミットログを表示(GUIによる) o 今、作業ディレクトリがあるブランチであり、ここにoriginのmasterブランチをマージしたいとき $ git merge origin/master
練習1 ivy.eit.hirosaki-u.ac.jpにログインして、"最初に一度だけする設定"をする。 次に、適当なディレクトリで、 $ git clone git://git.kernel.org/pub/scm/git/git.git #作業ディレクトリ名を省略した $ cd git $ git remote -v $ git branch -vv $ git status $ git log --oneline --decorate --graph --all 一画面下にスクロール SPC 一画面上にスクロール w 一行上にスクロール j 一行下にスクロール k 下に検索 / ⇒ origin/masterという文字列を検索してみる 上に検索 ? 次のもの検索 n 一番下を表示 ESC > 一番上を表示 ESC < 終了 q $ DISPLAY=hogehoge:0 gitk --all # ssh -Yでログインしている場合、DISPLAY環境変数の設定は不要。 $ DISPLAY=hogehoge:0 gitk # hogehogeはウィンドウを表示させるホストのホスト名にする。 $ DISPLAY=hogehoge:0 gitk --all & $ git log --oneline --decorate --graph --all | tail $ git checkout -b mytest e83c51633 $ git help checkout $ git status $ git log --oneline --decorate --graph --all | tail $ make #失敗するので、 Makefileの LIBS= -lssl を LIBS= -lssl -lcrypto -lz に変更して、再度makeする $ $ git status $ git add -u $ git status $ git commit -m "modify Makefile" $ git status $ git branch -vv $ git log --oneline --decorate --graph --all | head ; echo ... ; \ git log --oneline --decorate --graph --all | tail また、gitkのメニューから更新を選んで、ログを確認して、終了q。
練習2(1のつづき) $ mkdir ../hoge; cd../hoge #適当なディレクトリを作り、移動する $ cp../git/{*.[ch],Makefile,README} . $ ls Makefile cache.h commit-tree.c read-cache.c show-diff.c write-tree.c README cat-file.c init-db.c read-tree.c update-cache.c $ git init $ git add *.[ch] Makefile README $ git status $ git commit -m "the first commit" $ git log --oneline --decorate --graph --all $ git remote -v ; git branch-vv たとえば、emacsでMakefileをオリジナルのもの(LIBS= -lssl)に戻す。 $ git diff $ git add Makefile $ git commit -m "make Makefile the original" $ git log --oneline --decorate --graph --all $ git checkout -b testb $ git branch -vv emacsで MakefileのLIBSを -lssl -lcrypto -lz にする。 $ git add Makefile $ git commit -m "modify Makefile" $ git log --oneline --decorate --graph --all $ git branch -vv $ git checkout master $ git branch -vv emacsで MakefileのLIBSを -lssl -lcrypto にする。 $ git add Makefile $ git commit -m "modify Makefile, again" $ git log --oneline --decorate --graph --all
遊び(練習1のつづき。実際に行わなくてもよい。) cd ../gitなどで、練習1のディレクトリに移動する。 最初のgitを動かしてみる。そのままでは実行時にエラーになるようなので、 read-cache.cの228行目付近のif文をコメントアウトして、makeし直す。 - if (size > sizeof(structcache_header)) +// if (size > sizeof(structcache_header)) map = mmap(NULL, size,PROT_READ, MAP_PRIVATE, fd, 0); $ ./init-db # .dircacheディレクトリが作成される(.git相当) $ ./update-cache *.[ch] Makefile README #update-cacheが git add相当 $ ./write-tree #write-tree,commit-treeが git commit相当 6ca44177a19e6ca8f2f761b7415a4360d2db6b8e $ ./commit-tree 6ca44177a19e6ca8f2f761b7415a4360d2db6b8e <<eof the first commit eof Committing initial tree 6ca44177a19e6ca8f2f761b7415a4360d2db6b8e bab38708b02450867071a94a9fce18123597835d $ cat `./cat-file bab38708b02450867071a94a9fce18123597835d | sed 's/:.*$//'` #コミットの表示 tree6ca44177a19e6ca8f2f761b7415a4360d2db6b8e author okazaki,isao,,<okazaki@ivy> Fri Jun 23 14:41:39 2017 committer okazaki,isao,,<okazaki@ivy> Fri Jun 23 14:41:39 2017 the first commit $ ./read-tree 6ca44177a19e6ca8f2f761b7415a4360d2db6b8e #コミットの内容(ツリー) 100664 Makefile(dfa152bcc0e5f29d5a2db9a482d7e65660a6fe61) 100664 README (665025b11ce8fb16fadb7daebf77cb54a2ae39a1) 100664 cache.h(9e1bee21e17c134a2fb008db62679048fc819528) 100664 cat-file.c(fd690acc02ef9c06d7c4c3541f69b10ca4b4f8c9) 100664 commit-tree.c(a4a8c3d9ef0c4cc6c82b96b5d1a91ac6d3bed466) 100664 init-db.c(0eaa053919e0cc400ab9bc40d9272360117e6978) 100664 read-cache.c(4d3c01ab27d6745be53d5caf862e5ce4d939961c) 100664 read-tree.c(ec0f167a6a505659e5af6911c97f465506534c34) 100664 show-diff.c(00a29c403e751c2a2a61eb24fa2249c8956d1c80) 100664 update-cache.c(aff074c63ac827801a7d02ff92781365957f1430) 100664 write-tree.c(7abeeba116b2b251c12ae32c7b38cb048199b574) $ ./show-diff Makefile: ok README: ok cache.h: ok cat-file.c: ok commit-tree.c: ok init-db.c: ok read-cache.c: ok read-tree.c: ok show-diff.c: ok update-cache.c: ok write-tree.c: ok 次に、emacsでread-cache.cの228行目付近にfprintfを追加(追加内容は以下のdiff参照)。 $ ./show-diff Makefile: ok README: ok cache.h: ok cat-file.c: ok commit-tree.c: ok init-db.c: ok read-cache.c: 4d3c01ab27d6745be53d5caf862e5ce4d939961c --- - 2017-06-23 14:54:17.547672847 +0900 +++ read-cache.c 2017-06-23 14:53:00.644494732 +0900 @@ -228,6 +228,8 @@ map = NULL; size = st.st_size; errno = EINVAL; +fprintf( stderr, "size= %d\n", size ); +fprintf( stderr,"sizeof = %d\n", sizeof(struct cache_header) ); // if (size > sizeof(struct cache_header)) map = mmap(NULL, size,PROT_READ, MAP_PRIVATE, fd, 0); } read-tree.c: ok show-diff.c: ok update-cache.c: ok write-tree.c: ok $ ./update-cacheread-cache.c $ ./write-tree 792883deac0a678d1975ddb4acce30ed15010149 $ ./commit-tree 792883deac0a678d1975ddb4acce30ed15010149 \ -p bab38708b02450867071a94a9fce18123597835d <<eof add fprintf eof 8af70d35558e4226155fdad489654a0ece5ee196 $ cat `./cat-file 8af70d35558e4226155fdad489654a0ece5ee196 | sed 's/:.*$//'` tree 792883deac0a678d1975ddb4acce30ed15010149 parent bab38708b02450867071a94a9fce18123597835d author okazaki,isao,,<okazaki@ivy> Fri Jun 23 15:14:12 2017 committer okazaki,isao,,<okazaki@ivy> Fri Jun 23 15:14:12 2017 add fprintf 最初のコミットのツリー(6ca44177a19e6ca8f2f761b7415a4360d2db6b8e)の read-cache.c(4d3c01ab27d6745be53d5caf862e5ce4d939961c)を取り出し、diffを とってみる。 $ ./cat-file 4d3c01ab27d6745be53d5caf862e5ce4d939961c temp_git_file_nV0xt4: blob $ diff temp_git_file_nV0xt4read-cache.c 230a231,232 > fprintf( stderr,"size = %d\n", size ); > fprintf( stderr,"sizeof = %d\n", sizeof(struct cache_header) ); 使い方は次を参考にすると良い。 "git(1)の最初のコミットをビルドして使ってみた"http://qiita.com/gfx/items/826b5f846e6a960adcff "Gitの最初の姿"http://daretoku-unix.blogspot.jp/2015/03/git.html "初期のGitコマンドのソースコード"http://tanakahx.github.io/blog/2014/06/08/initial-git-source-code/
ブラウザからダウンロード https://github.com/git/git/archive/master.zip $ unzip git-master.zip $ cd git-master $ autoconf $ ./configure --prefix=$HOME/bin $ make all # doc info はめんどいらしいので除く $ make install # install-doc install-html install-info は除く # バージョンは、2.2.0.GITだった。 | git-master/INSTALLには次のように記載あり | $ make prefix=$HOME/bin all doc info | $ make prefix=$HOME/bin install install-doc install-html install-info ブラウザからダウンロード https://www.kernel.org/pub/software/scm/git/ の git-manpages-2.2.0.tar.gz $ tar xvfz git-manpages-2.2.0.tar.gz -C $HOME/bin/share/man # man{1,5,7}に追加される MANPATH=$HOME/bin/share/man:$MANPATH を .bashrcに追加する (補足) zlibが無かった場合には makeできないので、下のようにzlibをインストール後に、 再度 git-masterディレクトリで ./configure --prefix=$HOME/bin --with-zlib=$HOME/bin としてから makeする。 $ wget http://zlib.net/zlib-1.2.8.tar.gz $ md5sum zlib-1.2.8.tar.gz $ tar xvfz zlib-1.2.8.tar.gz $ cd zlib-1.2.8 $ ./configure --prefix=$HOME/bin $ make $ make install