howto/git/forthefirsttime

一行メモ


マニュアル・リンクなど

はじめてのGit

予備知識

リポジトリ

版管理している開発中のソースコードを蓄えているものをリポジトリという。コミットされた版が全て記録されている。 gitでは、版管理の対象はプログラムソースコードに限らず、ファイルであれば何でも良いが、 バイナリファイルでファイルサイズが大きいものは苦手。

作業ディレクトリ

通常のディレクトリのように、開発中のソースコードを置いてあるディレクトリのことを作業ディレクトリという。 gitで版管理されている場合、この作業ディレクトリには ".git"というディレクトリがあり、 版管理に関する情報や全ての版の記録が保存されている。

作業ディレクトリ内のファイルは、gitの版管理を意識せずに普通に修正等して構わない。

ローカルリポジトリ

ログインしてシェルのプロンプトが出ており、カレントディレクトリが版管理されている作業ディレクトリがあるとする。 ここにあるリポジトリのことをローカルリポジトリと呼ぶ(単にリポジトリとも呼ばれる)。

目の前のPCにログインして、sshでリモートホストにログインして、カレントディレクトリが作業ディレクトリである場合でも、 そこにあるリポジトリはローカルリポジトリである。 (リモートログインしているけどローカルリポジトリです。 つまり、プロンプトが出ているところがローカルリポジトリということ。)

リモートリポジトリ

ローカルリポジトリは、他の"上流"にあるリポジトリと結びついている場合がある(その場合が大多数)。 この上流のリポジトリのことを、リモートリポジトリと呼ぶ(これも単にリポジトリとも呼ばれたりする)。

ベアリポジトリ

作業ディレクトリを持たないリポジトリ(".git"ディレクトリのみから成るようなもの)。 リモートリポジトリはふつうはベアリポジトリである。

新しい版のコミットまでの流れ

作業ディレクトリ上で、 (1) ファイルを新規作成したり、修正して新しい版を作る。 (2) そのファイルをステージに載せる(ステージに登録、ステージングなどとも言われる。ステージのことを インデックスやキャッシュとも言われる)。 (3) コミット(commit)する。これでステージングされたファイルがリポジトリに記録され、半永久的に保存される。

もっと予備知識

基本的な操作(リポジトリの作成)

以下のファイル名、ディレクトリ名、注釈などはすべて英語とする(トラブル回避のため日本語は避ける)。

最初に一度だけする設定(マシン毎)

 $ git config --global user.name     "名前"
 $ git config --global user.email    "メールアドレス"
 $ git config --global core.editor   emacs
 $ git config --global push.default  simple

新規に、ローカルリポジトリを作る

版管理したい作業ディレクトリに移動して、初期化する。作業ディレクトリは空でも、ファイルがあっても構わない。

$ cd 作業ディレクトリ
$ git init

新規に、リモートリポジトリ(ベアリポジトリ)を作って、利用する

マシン Aにベアリポジトリを作って、マシン Bから利用する場合

マシン Aで
$ mkdir ベアリポジトリのディレクトリ名.git
$ cd ベアリポジトリのディレクトリ名.git      #(*)
$ git init --bare

マシン Bで
$ cd 作業ディレクトリ
$ git init
$ git remote add origin  ベアリポジトリのURL
                 #URLは上の(*)を示す「ssh://xxx@yyy:/~/ベアリポジトリのディレクトリ名.git」などを指定
$ git push --set-upstream origin master

さらに、マシン Cからもベアリポジトリを利用する場合

$ git clone ベアリポジトリのURL  作業ディレクトリ名

なお、ディレクトリが異なれば、マシン A, B, Cは同じPCであっても構わない。

既存のリモートリポジトリのコピー(クローン)をしてローカルリポジトリを作る

$ git clone ベアリポジトリのURL  作業ディレクトリ名

基本的な操作(日々の作業など)

ファイルをステージングし、ローカルリポジトリにコミットする

  $ git add ファイル  #ファイル(ディレクトリも指定が可能)をステージングする。
                      #初めてaddされたファイルであれば、自動的にgitで版管理する追跡対象になる。
 
  $ git commit -m "注釈"  #ステージングされたファイルをローカルリポジトリにコミットする。
                          #注釈は英語で!

ローカルリポジトリの更新内容をリモートリポジトリに送る

  $ git push

リモートリポジトリの更新内容を作業ディレクトリに取り込む

  $ git fetch  #取り込むだけ
  $ git pull   #取り込んで、作業ディレクトリのファイルにマージ(更新をファイルに適用)する

新しくローカルリポジトリにブランチを作る

  $ git checkout -b ブランチ名  #ブランチを作成し、作成したブランチに切り替える

既存の別のブランチに切り替える

  $ git checkout ブランチ名     #既存のブランチに切り替える(未コミットがあればできない)

新しくローカルリポジトリにブランチを作り、リモートリポジトリにpushする

  $ git checkout -b ブランチ名  #ブランチを作成し、作成したブランチに切り替える
  $ git push --set-upstream  origin ブランチ名
      #リモートリポジトリoriginにブランチをpushするとともに(ブランチが作成される)、ローカルリポジトリのブランチが
      #originに作成されたブランチを追跡するように設定する(--set-upstream)。

リモートリポジトリにあるブランチを追跡するように、ローカルリポジトリに同名のブランチを作成し、作成したブランチに切り替える

  $ git checkout --track origin/ブランチ名

更新内容の表示など

  $ git fetch                       #リモートリポジトリの更新内容を読み込む
  $ git remote -v ; git branch -vv  #リモートリポジトリを表示;ブランチを表示
  $ git status                      #作業ディレクトリの状態表示
  $ git log -15 --oneline --decorate --graph --all  #コミットログを表示, スクロールなどの操作はviとほぼ同じ
  $ gitk --all                                      #コミットログを表示(GUIによる)

ブランチにいて、このブランチにoriginのmasterブランチをマージする

  $ git merge origin/master

練習

作成中のプログラムがあるディレクトリ ~/pracがあるとする。

最初に一度だけする設定をせよ

git config --global user.name     'john smith' #SPCが含まれるのでクォートした
git config --global user.email    smith@ivy    #適当でよい
git config --global core.editor   emacs
git config --global push.default  simple

pracディレクトリを版管理するために、ローカルリポジトリを作成し、必要なファイルをステージングし、コミットせよ

cd ~/prac
git init
git add *.c *.h   #メタキャラが使える
git add makefile
git add 他にもあれば追加
git commit -m "the first commit"   #SPCが含まれるのでクォートした

ひとつ修正してコミットせよ(1回以上)。更新内容の表示なども試せ

emacs main.c
git add main.c
git commit -m "modify main.c"
適当なタイミングで、必要に応じて、
git remote -v ; git branch -vv
git status
git log -15 --oneline --decorate --graph --all
gitk --all

ベアリポジトリを作り、pushしてみよ

cd ~
mkdir repgit;   cd repgit
mkdir prac.git; cd prac.git
git init --bare
~/repgitディレクトリの中に prac.gitというベアリポジトリを作った。
cd ~/prac
git remote add origin  ssh://yourname@hostname:/home/yourname/repgit/prac.git
    #originに URLを登録
git push --set-upstream origin master
    #originのmasterブランチにpushするとともに、ローカルリポジトリのmasterブランチが追跡するように設定
yournameはログインID
hostnameはivy.eit.hirosaki-u.ac.jpなど

ベアリポジトリからクローンしてみよ

cd ~
mkdir tmp; cd tmp
git clone ssh://yourname@hostname:/home/yourname/repgit/prac.git prac2

クローンしたリポジトリの作業ディレクトリで、ファイルを修正してcommit, pushし、もともとの作業ディレクトリでpullしてみよ

cd ~/tmp/prac2
emacs main.c
git add main.c
git commit -m "modify main.c in prac2"
git push
cd ~/prac
git fetch
git pull
prac2とpracで更新内容などを見てみよ
git remote -v ; git branch -vv
git log -15 --oneline --decorate --graph --all
~/tmp/prac2はこのあと使わないので削除して構わない。

ブランチの追跡のポンチ絵

#ref(): File not found: "repository20211126.jpg" at page "howto/git/forthefirsttime"

ソースからgitをインストールする例

ブラウザからダウンロード 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

練習(しなくてもよい)

練習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/

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS