学習・研究ファイルのリポジトリ化について

→まとめ

概要

個人PCで作業を行なう場合でも,大切なファイル(ディレクトリ)は リモートリポジトリにマスターファイルを置き,つねに同期を取りながら バックアップのある状態で作業する。

また,修正履歴を全て保存できるので,「ファイル名を変えてバックアップ」 のようなことを一切せずに済むようになる。

この操作にはSCMソフトウェア Git を使用するので,あらかじめインストールしておく。

リポジトリを利用したファイル操作の流れ

Image of Using Repository

  1. 事前準備
  2. 日常作業の流れ

Gitの準備

サーバ接続鍵の作成

講義用GitBucketサーバにスムーズに繋ぐための準備手順を示す。 そのためには公開鍵認証用の鍵ファイルを作成する。 計算機故障等でなくすと困るのでroyで作成して それを手元計算機にコピーするようにする。

  1. 接続用公開鍵の作成

    royにログインし,以下のようにコマンド起動する。 なお,他の科目でこの作業をした場合は不要。

    ssh-keygen
    Generating public/private rsa key pair.
    Enter passphrase (empty for no passphrase): パスフレーズ入力
    Enter same passphrase again: : パスフレーズ入力
    

    パスフレーズは15〜20文字程度のすばやく打てるものを付ける。

  2. 鍵ファイルのコピー

    (自分のPCでも同じ鍵を使う場合は) 手元のPCにroy上の鍵ファイルをコピーする。

    scp c1yyxxx@roy.e.koeki-u.ac.jp:.ssh/id_rsa'*' ~/.ssh
    

    c1yyxxx にはroyでの自分のユーザ名を入れる。

  3. サーバ接続情報の登録

    ~/.ssh/config に以下の記述を追加する。

    Host gitbk
      HostName	www.yatex.org
      User		GitBucketサーバのユーザ名
      Port		29418
      AddressFamily	inet
    
  4. サーバへの鍵登録

    講義用 GitBucket サーバにログインし、右上のユーザアイコンをクリックで開いて、 「Account Settings」に進み左に出てくる 「SSH Keys」を開く。

    Add a public SSH Key
    Title
    この欄に鍵につける名前を入れる
    Key
    この欄に cat ~/.ssh/id_rsa.pub して
    得られる行を貼り付ける
  5. 接続実験

    上記手順全て完了したら,手元の計算機の端末から接続できるか確認する。

    ssh gitbk
    Enter passphrase for key '/home/taro/.ssh/id_rsa': (パスフレーズ入力)
     Welcome to
       _____   _   _     ____                   _             _
      / ____| (_) | |   |  _ \                 | |           | |
     | |  __   _  | |_  | |_) |  _   _    ___  | | __   ___  | |_
     | | |_ | | | | __| |  _ <  | | | |  / __| | |/ /  / _ \ | __|
     | |__| | | | | |_  | |_) | | |_| | | (__  |   <  |  __/ | |_
      \_____| |_|  \__| |____/   \__,_|  \___| |_|\_\  \___|  \__|
    
     Successfully SSH Access.
    

  6. ssh-agentの利用

    ssh-agentはSSHの秘密鍵パスフレーズをメモリに記憶してくれる。 パスフレーズは ssh-add コマンドで記憶させる 自動的にssh-agentが起動される環境では、いきなり ssh-add と起動してみる。

    ssh-add
    Enter passphrase for /home/irhome/c121/c121456/.ssh/id_rsa: 
    

    このようにパスフレーズが聞かれたら入力するとログアウトまで 登録したサーバログイン時にパスフレーズ入力が省略できる。 聞かれない場合は ssh-agent を手で起動する。

    exec ssh-agent zsh
    emacs &
    ssh-add
    Enter passphrase for /home/irhome/c121/c121456/.ssh/id_rsa: 
    

    以後の編集作業は上で起動し直した方のemacsで行なうとよい。

    以上いずれかで ssh-add にパスフレーズを打ち込めたら再度確認する。

    ssh gitbk
    

    今度はパスフレーズなしでWelcomeメッセージが表示されるはずである。

リポジトリの準備

ここでは ~/hoge にある内容を履歴管理する。 通常はあるディレクトリを決めてその配下を管理する。

GitBucketサーバへのリポジトリ作成

作業ディレクトリのローカルリポジトリ化

保存したい作業ディレクトリを決めて, そこでGitリポジトリを構築する。

mkdir hoge
cd hoge
cat > .gitignore<<EOF
*.aux
*.log
*.toc
*.o
*~
\#*
.DS*
tmp/
EOF
git init; git add .; git commit -m init

GitBucketサーバにログインし、右上の +▼ から新規リポジトリを作成する。Repository name(リポジトリ名) と Description(説明)を埋めて末尾の緑ボタンで作成する。

以下のメッセージが出るのでそのとおりにコマンド入力する。

touch README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin https://www.yatex.org/gitbucket/git/ユーザ名/リポジトリ名.git
git push -u origin master

日常の編集操作

リポジトリ内でのコマンドライン操作

Emacsでの操作

Emacsでファイルを編集した場合は,ある程度の修正ができたところで コミット(C-x v v)や,push (C-x v P) をする。

コミットすると,ログ記述バッファが開くので,やった作業の簡潔な説明を書き, C-c C-c で確定する。

複数ホストでの編集

一度サーバリポジトリに登録しておけば,作業の続きをネットに繋がった 別ホストで行なえる。たとえば,royや個人のPC複数台で行なう例を示す。

Repository Tree

大まかな流れとしては,royなどにログイン後, サーバからリポジトリを複製する。その後は以下の流れで作業を行なう。

  1. サーバ上の更新をpullする(git pull)
  2. 複製したリポジトリ内で作業しコミットをこまめに行なう
  3. 切りのよいところでpushする(git push)

必ず「pullしてから作業開始」と, 「作業の最後にpush」を忘れないようにする。

なお,pullのときに他のリポジトリを指定すると,そこから更新を 直接取得できる。たとえば,royのtaro/ディレクトリで作業した 結果をサーバにpushしていなくても,たとえばmypcから,

cd ~/foo
git pull ssh://roy/foo

とすると更新をmypcに取得でき,さらにこれを

git push

するとサーバに更新を送り込むことができる。

マージと衝突

マージ

[サーバリポジトリ]
  |   |    |
  |   |   複製C
  |  複製B
複製A

上図のような関係で運用していて,複製Aで行なった更新をサーバにpushし, 次の日,複製Bで作業を始めるときにpullし忘れてから作業し始めたとする。 すると,Bでコミットしたものをpushするときに以下のようになる。

git push
To ssh://gitbk/user/repo
 ! [rejected]        master -> master (fetch first)
error: failed to push some refs to 'ssh://gitbk/user/repo'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

先にAでの更新を取り込んでおくべきだった。この場合はあとで Aの更新を取り込み,マージする。

git pull

マージ(修正の併合)メッセージの入力を促されるので、 たいていそのまま保存終了(ZZ)する。。

Merge branch 'master' of ssh://gitbk/user/repo

(viが上がっている場合はZZ、その他のエディタは保存終了する)

衝突と解決

マージすべきときに,同じ箇所に違う修正を施していると衝突が起こる。

git pull
8e0e4e8..bccdf15  master     -> origin/master
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
git ls-files -u|cut -f 2|sort -u          # 衝突ファイル一覧を得る
hello.c

ファイルを開くと衝突箇所に `<<<<<<<' というマークが付く。2つの修正候補のどちらかを残して他を消す。

int main(int argc, char **argv)
{
<<<<<<< HEAD
        printf("HELLO, WORLD!\n");
======= 
        printf("Hello, world!\n");
>>>>>>> 1463819fb69e5fefca8e6681058d751596df0da2
        return 0;
}

ここでは下(赤)の方を選んだとして,

int main(int argc, char **argv)
{
	printf("Hello, world!\n");
        return 0;
}

のように修正し,git add で修正済みとする。

git add hello.c
git commit -m resolved hello.c

リポジトリ管理下のファイル操作

リポジトリ管理しているファイルの,コピー/移動/削除は cp/mv/rm で行なってはいけない。リポジトリの登録情報とずれるからである。 これらは全てgitのサブコマンド cp/mv/rm aで行なう。

git cp 履歴を含めてファイルをコピーする。ディレクトリをまるごとコピーする こともできる。
git mv 履歴ごとファイルを移動する,またはリネームする。 ディレクトリをまるごと移動することもできる。
git rm リポジトリ内ファイルと作業ディレクトリのファイルを両方削除する。 git rm -r でディレクトリごと削除することもできる。

任意時点のファイルの取り出し

git log してみると,全ての履歴に 日付けとチェンジセットIDが付いているのが分かる。 このIDでリビジョン指定ができ,その時点の状態を特定できる。

たとえば,2013年2月2日の時点のファイルを取り出したいとする。 眺めたいだけ,1つだけファイルを取り出したい,全てのファイル集合を見たい, 場合によって切り替える。以下,REV というリビジョンの ファイルの取り出し方について示す。

あとから取り出すであろうリビジョンにはタグ をつけられる。

# 現在のワーキングリビジョンに hogehoge-1 というタグをつける
git tag hogehoge-1

# リビジョン321eに hogehoge-0.5 というタグをつける
git tag -r 321e hogehoge-0.5

タグをつけたリビジョンは,タグ名でアクセスできる。たとえば,

git show hogehoge-0.5
git archive hogehoge-0.5 /tmp/hogehoge-0.5.tar.gz

まとめ

コマンドライン操作

コマンドはたらき
git statusリポジトリの状態表示
git clone gi clone URL1 URL2
で URL1 のリポジトリを URL2 に複製する。 URLにはリポジトリを示すディレクトリや,
ssh://サーバ/ディレクトリ
形式が指定可能。
git pull 複製元リポジトリの更新を取得する。後ろにリポジトリURLを 指定して別のリポジトリからの取得も可能。
git push 複製元リポジトリへ更新を送り込む。後ろにURLを指定可。
git add 指定したファイルを更新登録
git log 更新履歴とログを出力
git diff リポジトリ登録版との差分出力
git diff REV [ファイル]
とすると,リビジョン REV との差分を出力する。 REV1 REV2 とすると,REV1 から REV2 への差分を出力する。
git checkout [file] 最後のコミット以後の修正を破棄して元に戻す。

Emacsでのキー操作

ファイル編集モードでのキー

キーはたらき
C-x v vコミット
C-x v lログを見る
C-x v = 差分を見る
C-u C-x v = として,2つのリビジョンを指定すると それらの差分を見られる。
C-x v g git blame を行なう
どの行をどのリビジョンで採り入れたかを視覚的に調べられる
C-x v +pull を行なう
C-x v Ppush を行なう
C-x v dディレクトリ単位でstatus

log-view(C-x v l)モードのキー

キーはたらき
n次(下)のログへ
p前(上)のログへ
dそのチェンジセットの差分表示
aそのリビジョンで annotate 表示

vc-annotate(C-x v g)モードのキー

vc-annotate は,タイムマシンのように目の前に以前のリビジョンの 内容がどんどん現われるので,昔のリビジョンをじっくり参照したいときに便利。

キーはたらき
p古いリビジョンへ
n新しいリビジョンへ
jカーソル行のリビジョンへ
aカーソル行のリビジョンの直前リビジョンへ
wワーキング(作業中)リビジョンへ
v冗長表示切り替え
d該当リビジョンの差分表示
l該当リビジョンのログ表示
yuuji(atmark)e.koeki-u.ac.jp