2017年08月02日

git 変更をpatchファイルにする

変更差分をpatchファイルにすることができる。

事前知識として、Linuxの patch はテキストファイルに差分を適用するコマンド。
パッチファイルを作成するコマンドは以下。

$ diff -u 変更前のファイル 変更後のファイル > パッチファイル名


-u オプションは unified diff形式で出力する指定。

例として、パッチファイルを作成して、そのパッチファイルの中身を見てみる。
$ diff -u a_old.txt a_new.txt > a.patch

$ cat a.patch
--- a_old.txt 2017-08-01 09:00:00.570393470 +0900
+++ a_new.txt 2017-08-01 09:30:00.841552217 +0900
@@ -1 +1,3 @@
aaa
+
+modified 1


パッチを適用するコマンドは以下。

$ patch -u 適用するファイル名 < パッチファイル名



パッチ適用前後を比較しながら、適用内容を確認してみる。
$ cat a.txt
aaa

$ patch a.txt < a.patch
patching file a.txt

$ cat a.txt
aaa

modified 1

変更差分のパッチが適用されたことがわかる。


もし適用するファイルを間違えていたら、パッチ適用を戻す(リバースパッチ)。
-R オプションを使うことで、新旧ファイルが反転しているものとして適用することで元に戻す。

$ patch -u -R 適用するファイル名 < パッチファイル名

$ patch -R a.txt < a.patch
patching file a.txt

$ cat a.txt
aaa

リバースパッチをあてることで元に戻った。





パッチファイルの作成


git diff の出力をパッチファイルとして保存すればいい。
例えば、特定ファイルの異なるコミットの差分のパッチファイルを作る場合、

$ git diff commitID1 commitID2 -- filepath > file.patch

試しに作成してみる。
$ git log --oneline
827142f modified2 a.txt b.txt
e379d74 modified a.txt b.txt
6c5004e modified a.txt d.txt
069d76c Add file :d.txt
4bfcd75 modified c.txt
3f062b7 modified b.txt
9925985 modified a.txt
d79bc0b Add files

$ git diff 069d76c 6c5004e -- p1/p2/d.txt
diff --git a/p1/p2/d.txt b/p1/p2/d.txt
index 1d60b70..c8b35f9 100644
--- a/p1/p2/d.txt
+++ b/p1/p2/d.txt

@@ -1 +1,3 @@
ddd
+
+patch 1:d.txt


$ git diff 069d76c 6c5004e -- p1/p2/d.txt > ~/Documents/test.patch

$ cat ~/Documents/test.patch
diff --git a/p1/p2/d.txt b/p1/p2/d.txt
index 1d60b70..c8b35f9 100644
--- a/p1/p2/d.txt
+++ b/p1/p2/d.txt
@@ -1 +1,3 @@
ddd
+
+patch 1:d.txt






パッチファイルの適用


作成したパッチファイルを適用するには git apply を使う。

$ git apply file.patch


git apply は全部適用するか、または一切適用しないかのどちらか。エラーが出るまで適用するとか中途半端なことはしない。
また、適用できるかあらかじめチェックすることができる。git apply --check を使い、適用できなければエラーがでる。適用可能であれば何も出力されない。
$ git apply --check test.patch
error: patch failed: p1/p2/d.txt:1
error: p1/p2/d.txt: patch does not apply

適用したら、ステージしてコミットすれば良い。



git操作で作成したパッチファイルは、Linuxコマンドの patch コマンドと互換性を持ち、git管理されていないファイルに対しても適用できる。

$ patch -p1 < test.patch

-p オプションは差分に記載されたファイル名から指定した個数分のパス指定を取り除く指定。"-p1" なので1個除く。
差分ファイルのパスの指定には、"a" "b" がついているのでこれを除くことで、patch コマンドと互換性が取れる。
--- a/p1/p2/d.txt
+++ b/p1/p2/d.txt






まとめ


パッチを使うことで、ファイル丸ごとの置き換えはしたくない差分対応とか、離れた環境にあるリポジトリへの適用や、git管理下にないファイルに変更差分を適用したい場合に使える。
変更差分は git diff の操作なので難しいことではない。
ちょっとした変更差分でも、手動でファイルに変化点を加えていくとヒューマンエラーが介入する可能性があり神経を使うので、自動的に作業できることは自動化してしまうほうが時間もかからないし、間違いが少ない。





gitをインストール
gitサーバーのセットアップ
git ブランチについて
git 変更を一時的に退避 stash
git ブランチを合流するマージ
git ブランチを付け替える
git コミット履歴を変更する
git 変更をリセットする
git リモートでの操作
git ファイルの追跡
git リリース準備
git リモートブランチを追加
git チェックアウトをもっと便利に使う
git プロジェクトの構成
git コンフリクトに対処する
git 失敗したときの復元
posted by Zorinos at 20:00| Comment(0) | Linux | 更新情報をチェックする

2017年08月01日

git プロジェクトの構成

複数のプロジェクトの管理について整理する。
1つのリポジトリに、1つのプロジェクト(リリースモジュールが1つ)を格納するのはシンプルな形。リモートリポジトリを準備して、チームでローカルリポジトリを持つ構成だったとしても簡単に想像できる。
git_module01.png


1つのプロジェクトに複数のリリースモジュールがあり、それぞれを別チームで開発しているとする場合はどううしたら良いか。

1つのプロジェクトではあるが、リリースモジュールが相互に関連しておらず、参照する必要がなければ各チームでリポジトリを準備したほうが良い。それぞれの履歴を持つので、履歴を確認するのが簡単。

作業メンバーはそれぞれに必要なリモートリポジトリからクローンすれば良いので、チームに必要のないデータを持たなくてよい。
git_module02.png


逆に、複数モジュールがあるが最終的にまとめて結合してリリースするような場合、リポジトリが複数あると、採取的にまとめるときに、複数のリポジトリそれぞれからクローンする必要があり、このよう場合はリポジトリがまとまってくれていたほうが良かったのにと思うときがある。
git_module03.png

どのような形であれ、チーム単位で見たらそれぞれのリポジトリを単独で使って作業をする限りは管理はさほど難しくならない。
もし、他のリポジトリを自分のチームのリポジトリへ取り込む必要が出てきたらどうすれば良いか?






別のリポジトリを追跡する


例えば、ライブラリを組み込んで使うときのように、異なるモジュールを組み込んで使う場合はどうすべきか?
gitには、外部のリポジトリを取り込むことができるサブモジュールという機能がある。


例として、まずは取り込む元となるリモートリポジトリを準備する。
$ mkdir submodule.git && cd submodule.git
$ git init --bare
Initialized empty Git repository in **********/submodule.git/

このリモートリポジトリをクローンして作業する。簡単な作業として、ファイルを追加してコミットし、プッシュまでしておく。
$ git clone **********/submodule.git/
Cloning into 'submodule'...
warning: You appear to have cloned an empty repository.
done.
$ cd submodule/
$ echo "submodeule" > submodule.txt

$ git add submodule.txt

$ git commit -m "Add new file : submodule.txt"
[master (root-commit) e609385] Add new file : submodule.txt
1 file changed, 1 insertion(+)
create mode 100644 submodule.txt

$ git push origin
Counting objects: 3, done.
Writing objects: 100% (3/3), 234 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To **********/submodule.git/
* [new branch] master -> master

コミットID:e609385 でファイルを追加した。


このリモートリポジトリの取り込み先としてのプロジェクトを同様に準備する。
$ mkdir project1.git && cd project1.git
$ git init --bare
Initialized empty Git repository in **********/project1.git/

$ git clone **********/project1.git/
Cloning into 'project1'...
warning: You appear to have cloned an empty repository.
done.
$ cd project1/
$ echo "project1" > project1.txt

$ git add project1.txt

$ git commit -m "Add new file : project1.txt"
[master (root-commit) 14e6026] Add new file : project1.txt
1 file changed, 1 insertion(+)
create mode 100644 project1.txt

$ git push origin
Counting objects: 3, done.
Writing objects: 100% (3/3), 231 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To **********/project1.git/
* [new branch] master -> master

これにサブモジュール機能を適用していく。




プロジェクトにサブモジュールを追加する


"sub" ディレクトリを作成して、そこに追加してみる。
$ mkdir sub && cd sub

サブモジュールとして追加するリポジトリ(先に作ったリモートリポジトリ)を指定する。

$ git remote add **********/submodule.git/

Cloning into 'sub/submodule'...
done.

ステータスを確認してみる。
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD ..." to unstage)

new file: .gitmodules
new file: sub/submodule
取り込みたいファイルと ".gitmodules" が追加され、ステージされている。

diff も見てみる。
$ git diff --cached
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..fdda908
--- /dev/null
+++ b/.gitmodules

@@ -0,0 +1,3 @@
+[submodule "sub/submodule"]
+ path = sub/submodule
+ url = **********/submodule.git/

diff --git a/sub/submodule b/sub/submodule
new file mode 160000
index 0000000..e609385
--- /dev/null
+++ b/sub/submodule

@@ -0,0 +1 @@
+Subproject commit e60938592340493b0a9ba52682c8c0f41c1aa0c2

"+Subproject commit e60938592340493b0a9ba52682c8c0f41c1aa0c2" は、登録したサブモジュールの取り込み元となるコミットを示している。

".git/config" にも情報が書き込まれている。
[submodule "sub/submodule"]
url = **********//submodule.git/




これをコミットすれば、サブモジュールの追加が完了。プッシュもしておく。
$ git commit -m "Add submodule : sub/submodule/"
[master 1df63d2] Add submodule : sub/submodule/
2 files changed, 4 insertions(+)
create mode 100644 .gitmodules
create mode 160000 sub/submodule

$ git push origin
Counting objects: 4, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 417 bytes | 0 bytes/s, done.
Total 4 (delta 0), reused 0 (delta 0)
To **********/project1.git/
14e6026..1df63d2 master -> master

git_module04.png





サブモジュールを持つプロジェクトをクローンする


リモートリポジトリにプッシュしたので、これを他のメンバーにも展開したい。
他のメンバーはまずは普通にプロジェクトをクローンし、クローンしたファイルの中身を見てみる。
$ git clone  **********/project1.git/
Cloning into 'project1'...
done.


├ .git
└ ....
├ .gitmodules
├ project1.txt
└ sub
└ submodule

"sub/submodule" ディレクトリはあるが、肝心のサブモジュールとしてのファイルが存在していない。それに ".git/config" にもサブモジュールの情報が書き込まれていない。
git_module05.png


サブモジュールのデータを引っ張ってくるためには、以下のようにする。

$ git submodule init
$ git submodule update

または

$ git submodule update --init


init で、".gitmodules" の情報を ".git/config" に書き込む。
updateで、データを引っ張ってきた状態にする。update --init はこれらを一気に行う操作。

さらに、この2つの操作を --recursive オプションでクローンと同時に実行することもできる。

$ git clone --recursive **********/project1.git/




ここで間違えてはいけないことは update 操作。
これは取り込み元のリポジトリの最新をもってくるのではなく、取り込み先のリポジトリ(ここでは "project1.git")に登録されたサブモジュールの情報から、取り込むデータを引っ張ってくる操作。このため取り込み元のリポジトリが更新されていたとしても関係なく、取り込み先にサブモジュールとして登録されているコミットIDからデータを引っ張ってくる。
git_module06.png




サブモジュールを最新に更新する


サブモジュールの取り込み元のリポジトリが更新され、そして取り込み先でもその最新リポジトリ内容を使うことになったとする。そうなるとサブモジュール自体を最新に更新する操作が必要となる。

取り込み元のリポジトリの最新コミットで更新するのであれば以下のコマンドを使う。

$ git submodule foreach git pull <remote> <branch>


もし "master" ブランチだけであれば、省略して、

$ git submodule foreach git pull


この操作後、変化点が出てくるので、ステージして、コミットし、プッシュすれば更新完了。

$ git add.
$ git commit -m "Update submodule"
$ git push --all


サブモジュールの参照内容は切り替わっている。



では最新ではなく、取り込み元リポジトリ内の特定コミット状態に更新したい場合はどうするのか?

その前に、サブモジュールはどのような状態か調べてみる。
サブモジュールがあるディレクトリに移動し、ステータスとリモートリポジトリを見てみる。
$ cd sub/submodule/
$ git status
HEAD detached at e609385
nothing to commit, working directory clean

$ git remote -v
origin **********/submodule.git/ (fetch)
origin **********/submodule.git/ (push)

取り込み先(ここでは "project1.git")が参照するリモートリポジトリを指しておらず、取り込み元のリモートリポジトリを指している。
実は、サブモジュールがあるディレクトリ以下は、取り込み元のリポジトリの管理下にあり、さらにサブモジュールは "detached HEAD" の状態と同じだとわかる。
git_module07.png
サブモジュールは "detached HEAD" で直接コミットIDを参照しているので、取り込み元のリポジトリが変化しても影響を受けずに存在している。
そして取り込み元のgit管理下に置かれているので、取り込み元のリポジトリの内容でブランチの切替もチェックアウト操作も可能。


話を戻して、特定のコミットで更新する場合はどうすれば良いのかというと、
まずは更新するためのコミットIDを知ることから行う。サブモジュールの管理下に移動して、リモートリポジトリからプルして最新情報を取得する。後はブランチを切り替え、ログを確認するなどして必要なコミットIDを取得する。
$ git checkout new_branch
Previous HEAD position was e609385... Add new file : submodule.txt
Branch new_branch set up to track remote branch new_branch from origin.
Switched to a new branch 'new_branch'

$ git log --oneline
83386e4 modified new_branch submodule1
dba71a8 modified submodule3
62dfb39 modified submodule2
e609385 Add new file : submodule.txt

次に、そのコミットIDを使い、サブモジュールを "detached HEAD" 状態に切り替える。
例として、コミットID:dba71a8 に切り替えてみる。
$ git checkout dba71a8
Previous HEAD position was 83386e4... modified new_branch submodule1
HEAD is now at dba71a8... modified submodule3

これで更新できているので、取り込み先のgit管理下に戻して、
この状態をステージし、コミットし、プッシュすれば更新が完了する。
$ git add .
$ git commit -m "Update submodule"
[master f1b5a0b] Update submodule
1 file changed, 1 insertion(+), 1 deletion(-)

$ git push --all
Counting objects: 3, done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 286 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To **********/project1.git/
1df63d2..f1b5a0b master -> master




他のメンバーは、通常通りにリモートリポジトリから最新状態に取得しローカルリポジトリを更新したら、サブモジュールをリモートリポジトリの管理状態に更新するだけ。

$ git submodule update






サブモジュールを削除する


サブモジュールが不要になれば、サブモジュールを追加したディレクトリを指定して操作を行う。

$ git submodule deinit sub/submodule/

Cleared directory 'sub/submodule'
Submodule 'sub/submodule' (**********/submodule.git/) unregistered for path 'sub/submodule'
これでサブモジュールを削除できる。




まとめ


サブモジュールは外部のリポジトリを参照し、うまく取り込むことができるので、プロジェクトの構成内容の管理を分散できてパッと見は便利に思える。開発を前に進めて行くときは便利だと思うが、過去の内容を確認したくて過去のリビジョンをチェックアウトするときには注意が必要。サブモジュールはリポジトリの管理が異なるので、同時にはは過去の状態に戻ってくれない。サブモジュールを戻すにはそのリビジョン当時のコミットIDを指定して、別途チェックアウトしてあげないといけない。このような動作の癖を理解して、構成管理をしたうえでプロジェクトを進めないと、過去のリビジョンを急ぎ確認したいときに、間違った構成のまま作業を進めてしまって、要らない苦労をするかもしれない。
サブモジュールを取りこんでそのあとの管理の仕方をメンバー内で共有し、リポジトリが別管理であることを意識して作業することができれば便利だと思う。





gitをインストール
gitサーバーのセットアップ
git ブランチについて
git 変更を一時的に退避 stash
git ブランチを合流するマージ
git ブランチを付け替える
git コミット履歴を変更する
git 変更をリセットする
git リモートでの操作
git ファイルの追跡
git リリース準備
git リモートブランチを追加
git チェックアウトをもっと便利に使う
git 変更をpatchファイルにする
git コンフリクトに対処する
git 失敗したときの復元
posted by Zorinos at 20:00| Comment(0) | Linux | 更新情報をチェックする

2017年07月30日

git チェックアウトをもっと便利に使う

ブランチを切り替えるときに使う git checkout コマンド。
ブランチのチェックアウト操作を行うことで、作業ツリーの状態をそのブランチの最新状態に切り替えることができる。

が、チェックアウトできるのは、ブランチだけではない。
他の使い方もあるので、知っていればより便利に git checkout が使える。


まず "HEAD" の状態を確認しておく。".git/HEAD" というファイルが実体。
git_checkout01.png
$ cat .git/HEAD
ref: refs/heads/master

"refs/heads/master" を参照していることを示している。
では、"refs/heads/" にどのようなファイルがあるのか確認してみる。
└ refs
├ heads
├ master
└ new_branch
"master" ブランチと "new_branch" ブランチのファイルがある。では、肝心の "refs/heads/master" には何が書いてあるのか。
$ cat .git/refs/heads/master
b94d4058ea3ef1537213e35212debb2214507a05
"master" ブランチの最新のコミットIDが書かれている。
この実体は ".git/objects/" にあり、コミットIDをもとに探すことができる。
今、参照するコミットIDが "b94d405" なので ".git/objects/b9/4d4058ea3ef1537213e35212debb2214507a05" が "HEAD" が参照するものとなる。
"HEAD"

.git/HEAD

.git/refs/heads/master

.git/objects/b9/4d4058ea3ef1537213e35212debb2214507a05






ファイルの過去のリビジョンをチェックアウトする


「全体としては今の雰囲気が良いいけど、この部分については前の内容のほうがバランスが取れているよね」的なことを言われたり、「落ち着いて考えたらやっぱりこの内容は無し」と思うこともある。
そういう場合は、git reset で作業ツリーを元に戻すことができる。
しかし git reset は作業ツリー上のすべてのファイルを指定状態に戻す。もし、特定のファイルだけ巻き戻したいという場合には、git checkout が使える。

"HEAD" 状態に戻したい場合は以下のようにする。

git checkout HEAD <対象ファイル>

"HEAD" が参照するコミットIDから対象ファイルをロードしてきて、作業ツリー上のファイルを上書きする。
git_checkout02.png

ファイルを戻すのは、"HEAD" だけではなく、コミットIDを指定すれば過去のコミットから特定ファイルをロードすることができる。

git checkout <コミットID> <対象ファイル>

このときの "HEAD" の状態も確認してみる。
$ git checkout b60971b a.txt
$ cat .git/HEAD
ref: refs/heads/master
"HEAD" の状態に変化はなく、"master" ブランチを参照している。

ステータスを見てみる。
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD ..." to unstage)

modified: a.txt
チェックアウトしたファイルは、ロードするだけではなく、ステージされている。このような動きになることを知っておくとよい。

また、コミットIDだけではなく、タグを指定することもできる。

$ git checkout <タグ> <対象ファイル>



ファイルの変更を元に戻すためだけではなく、過去の内容をちょっと確認したい場合にも使える。コミットIDだけではなく、タグを指定することもできるので、過去のリリースバージョン当時のファイルを確認したいときになどに、その当時のファイルをチェックアウトし、確認が終われば、"HEAD"を指定して戻せば良い。




過去のリビジョンを一時的に取り出す


特定のファイルではなく、特定のコミットを指定すれば、作業ツリーがすべてその当時の状態になるのでは?
と思って、特定のコミットだけ指定してチェックアウトしてみる。

$ git checkout b60971b

Note: checking out 'b60971b'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b

HEAD is now at b60971b... Add new file : b.txt
何かメッセージが出て警告を受けた気がする。

メッセージ内容はこんな感じ。
"detached HEAD" 状態です。この時点のファイルを見て回ったり、実験的な変更を加えてコミットすることができる。別のブランチをチェックアウトすれば、その他のブランチに影響を与えることなく、ここでの変更を破棄することができる。
もし作成したコミットを残しておくために新しいブランチを作りたいなら、-b を使って再度チェックアウトをすればいい。
例:git checkout -b <new-branch-name>
"HEAD" は、今、 b60971b... Add new file : b.txt

git_checkout03.png

このときの "HEAD" の状態を確認してみる。
$ cat .git/HEAD
b60971b05d47cb17ce3f4ad01be89e3c1d9c8e29
今までと違い、コミットの実体を直接指定している。
HEAD

.git/objects/b6/0971b05d47cb17ce3f4ad01be89e3c1d9c8e29


間違って "detached HEAD" したのであれば、再度ブランチをチェックアウトして、きちんと "detached" では無い状態にする。


意図的に "detached HEAD" にしたのであれば問題無いが、もしgitがせっかく教えてくれたメッセージを無視してブランチをチェックアウトしたものだと勘違いしたまま作業してコミットまでしてしまったとする。
git_checkout04.png
この状態でブランチを切り替えてみる。
$ git checkout new_branch
Warning: you are leaving 1 commit behind, not connected to
any of your branches:

2c8dbd4 detached HEAD

If you want to keep it by creating a new branch, this may be a good time
to do so with:

git branch 2c8dbd4

Switched to branch 'new_branch'

またメッセージが出た。この内容はこんな感じ。
どのブランチにも繋がっていないコミットが1個残っている。

2c8dbd4 detached HEAD

これを新しいブランチを作ることで残したいのであれば、今がいいタイミングです。
以下のようにすればいい。

git branch <new-branch-name> 2c8dbd4

git_checkout05.png
"detached HEAD" になっていることに気づかずにコミットした状態で、他のブランチにチェックアウトすると、"detached HEAD" 状態でコミットした内容は見えなくなってしまうが、無くなったわけではない。どこからも参照されないだけで記録は残っている。

これを復活させるためには、gitが教えてくれた通りに実行すればいい。
一時的なブランチを作ればいい。

$ git checkout tmp


これで参照できるようにつながったので、後はこのブランチをマージするなりして対応すればいい。作業した内容を無事に復旧できれば、一時的なブランチなので削除すれば終了。






まとめ


git checkout でファイルの変更を無かったことにしたり、巻き戻したりできるので知っておくと、いざというときにさっと作業できるので便利。ただし、コミットIDでチェックアウトし、"detached HEAD" にしてしまうと、この状態を知っていると知らないでは、このあとの作業の内容が違ってくる。間違ったまま作業していくと、コミット内容が見える範囲から消えてしまうことになりかねない。
gitがきちんとメッセージで教えてくれているので、慣れた作業であってもメッセージを読み飛ばさないように注意したほうがいい。





gitをインストール
gitサーバーのセットアップ
git ブランチについて
git 変更を一時的に退避 stash
git ブランチを合流するマージ
git ブランチを付け替える
git コミット履歴を変更する
git 変更をリセットする
git リモートでの操作
git ファイルの追跡
git リリース準備
git リモートブランチを追加
git プロジェクトの構成
git 変更をpatchファイルにする
git コンフリクトに対処する
git 失敗したときの復元
posted by Zorinos at 20:00| Comment(0) | Linux | 更新情報をチェックする

2017年07月25日

git リモートブランチを追加

複数メンバーで作業するプロジェクトを新規で作成する場合、リモートリポジトリを準備してから作業する。これは git サーバーのセットアップ時に触れた。

この場合の手順をざっくりと言えば、こんな感じ。
  1. 空のリモートリポジトリを準備
  2. リーダーのローカルマシンへクローン
  3. ローカルマシンで初期セットアップ
  4. リモートへプッシュ
  5. メンバーが各自のマシンへクローン
  6. 各自で作業開始


でもサーバー側の準備が遅かったら、リモートリポジトリができるまで待たないといけないので、先にローカルで準備をしたほうが時間の無駄がない。
また、単独で作業をしていたプロジェクトを複数メンバーで作業することになり、公開する必要ができた場合は、後からリモートリポジトリを設定できなければいけない。



後からリモートリポジトリを設定する


  1. ローカルリポジトリで作業が進行
  2. サーバー側で準備ができ、空のリモートリポジトリを作成
  3. ローカルリポジトリにリモートリポジトリを設定
  4. リモートへプッシュ
  5. メンバーが各自のマシンへクローン
  6. 各自で作業開始



現在のブランチの状態を確認してみる。
$ git branch -a
* develop
master

まだ、リモート追跡ブランチは存在していない。

ローカルリポジトリに、新たなリモートリポジトリを設定するためには git remote を使う。

$ git remote add origin gitserver:~/git/project1.git


リポジトリを作成したら、git push する。
--all オプションを使えば、すべてのブランチを git push できる。

$ git push --all




現在のブランチの状態を確認してみる。
$ git branch -a
* develop
master
remotes/origin/develop
remotes/origin/master

リモートリポジトリが設定され、リモート追跡ブランチが設定されたことがわかる。






リモートリポジトリの設定を削除する


設定を削除するのも git remote を使う。

$ git remote rm origin



現在のブランチの状態を確認してみる。
$ git branch -a
* develop
master






リモートリポジトリの変更


gitサーバーが変更になり、サーバーアドレスが変更になった場合は、リモートリポジトリも変更しなければならない。リモートリポジトリを変更するには、一旦、削除してから再設定しても良いが、1つのコマンドで対応できる。

$ git remote set-url origin <新しいリポジトリのアドレス>


変更されたことを確認するには git remote -v を使えばよい。
$ git remote -v
origin 新しいリポジトリのアドレス/new-repo.git/ (fetch)
origin 新しいリポジトリのアドレス/new-repo.git/ (push)





まとめ


そんなに頻繁にリモートリポジトリを変更する場面は無さそうな気がするが、例えばペアを組んで作業するメンバー同士のマシンを相互にリモートリポジトリに設定すれば、作業途中の状態を他のメンバーに公開する必要がない。作業に必要な範囲だけで共有し、完成してから全メンバーへ公開すればよい。このようなやり方をするのであれば、リモートリポジトリの設定・削除は頻繁に発生する。
なんでもメインとなるリモートリポジトリを使って作業していると、メンバー数が増えれば増えるほど、サーバーの負荷があがり、逆に作業の効率が悪くなることが予想できる。gitの機能を理解して、効率よく作業を進めれる方法を身に付けたい。





gitをインストール
gitサーバーのセットアップ
git ブランチについて
git 変更を一時的に退避 stash
git ブランチを合流するマージ
git ブランチを付け替える
git コミット履歴を変更する
git 変更をリセットする
git リモートでの操作
git ファイルの追跡
git リリース準備
git チェックアウトをもっと便利に使う
git プロジェクトの構成
git 変更をpatchファイルにする
git コンフリクトに対処する
git 失敗したときの復元
posted by Zorinos at 20:00| Comment(0) | Linux | 更新情報をチェックする

2017年07月23日

git リリース準備

リリースのタイミング限定での操作ではないが、リリース時によくやることについて整理する。

コミットに印を付ける


タグの作成


リリースや、目標とするマイルストーンなどの到達点で印を付ける。
リポジトリの中でのブックマークみたいな役割として、タグを打つ。

チェックアウトしているブランチの最新のコミットに対して付ける。

$ git tag "version_1.0"




コミットID を指定して過去のコミットに対して付ける。

$ git tag "release_test" 1c0a080



  • 既に存在する同名のタグはつけれない
    $ git tag "v1.0" 9fe9714
    fatal: tag 'v1.0' already exists
  • 同一コミットに複数のタグを付けることはできる
  • 有効でない文字(space、:(コロン)、~(チルダ)、?(クエスチョンマーク)、*(アスタリスク)など)は使えない
    $ git tag "version 1.0"
    fatal: 'version 1.0' is not a valid tag name.



タグだけでは、どのようなマイルストーンなのか判りにくいが、タグに注釈コメントを付けることで詳細な情報を残すことができる。
-a オプションを使う。

$ git tag -a "version_1.0" -m "Release: deployment"


-m オプションを省略して実行するとエディタが立ち上がるので、そこで編集することも可能。

注釈コメント付きにすると、タグをつけた人の情報・日時も格納されるので、タグを付けるときは、この -a オプションを使うことをススメる。



タグの確認


リポジトリ内のタグの確認。
現在チェックアウトしているブランチ以外のタグも見える。

$ git tag

release_test
v0.1
version_1.0



特定のタグの内容を確認するときには、git show を使い、タグを指定する。

$ git show version_1.0

tag version_1.0
Tagger: hoge hogehoge <hogehoge@email.com>
Date: Sat Jul 8 21:00:00 2017 +0900

Release: deployment

commit 762bccf8cb34d4b900ddb2832dc1869c7391d218
Author: hoge hogehoge <hogehoge@email.com>
Date: Sat Jul 8 20:00:00 2017 +0900

master 追加 3

diff --git a/index.html b/index.html
index a4bf772..70450f3 100755
--- a/index.html
+++ b/index.html
@@ -8,5 +8,6 @@
<body>
<h2>master</h2>
<p>master 追加</p>
+ <p>master 追加2</p>
</body>
</html>

注釈コメントをつけたタグであれば、タグをつけた人・日時・注釈コメントも表示される。



タグの削除


タグを違う場所につけた場合に削除できる。
-d オプションを使う。

$ git tag -d release_test

Deleted tag 'release_test' (was 1c0a080)




タグのリネーム


タグをつけたが、後から名称を変更する必要が出た場合、
タグを直接的に編集してリネームすることはできない。
この場合、元のタグを使って、新しいタグを同じ位置に付けてから、元のタグを削除することで対応する。

$ git tag new_tag old_tag
$ git tag -d old_tag






タグの共有


タグを付けただけでは、ローカルリポジトリにしか反映されないので、リモートリポジトリに反映するため、git push する。

$ git push origin v1.0



個別に反映するのではなく、すべてのタグを反映するときは、--tags オプションを使う。

$ git push origin --tags




リモートリポジトリのタグを削除するには、リモートのブランチを削除する操作と同じようにし、タグ名を指定すればよい。

$ git push origin :v1.0








リリース用ファイルのアーカイブ


作業の成果物として作成コードを納品するような場合、最新の安定版のファイルだけでよく、リリースのたびに履歴は含める必要がないという場合、git archive でアーカイブが使える。

$ git archive --format=zip --prefix=mysite-1.0/ HEAD > mysite-1.0.zip


--prefix= を使うことで、作成したアーカイブファイルを展開したときにディレクトリ "mysite-1.0/" を作成し、その中に展開する。このオプションを指定しないと、その場所でフラットに展開される。

また、指定ディレクトリ "mysite-1.0/" は、"/"(スラッシュ)を付けているが、これは必須。これを忘れて "mysite-1.0" と指定すると、展開時にディレクトリ内に展開されるのではなく、各ファイルの接頭語 "mysite-1.0" が付いたファイル群ができあがってしまう。

HEAD ではなく、タグを指定しても良い。
タグ "v1.0" を使って、次は "tar.gz" で作成してみる。

$ git archive --format=tar --prefix=mysite-1.0/ v1.0 | gzip > mysite-1.0.tar.gz





もしgit管理下に ".gitignore" があると、これもアーカイブ対象となってしまう。

リリースに含める必要はないので、これを除外したい場合は、".gitattributes" というファイルを作成し、これを指定することで除外可能。
以下のような構成とする。
.
├ .gitattributes
├ .gitignore
└ index.html

".gitattributes" の中身は以下とする。

.gitignore export-ignore
.gitattributes export-ignore


".gitattributes" も含めることがポイント。


これを git archive で実行するときに、--worktree-attributes オプションを指定することで除外フィルタが有効となる。

$ git archive --format=tar --worktree-attributes --prefix=mysite-1.0/ v1.0 | gzip > mysite-1.0.tar.gz




これを展開すると、
$ tar -zxvf mysite-1.0.tar.gz
mysite-1.0/
mysite-1.0/index.html

不要なファイルが除外されていることがわかる。






まとめ


タグを付けることは、作業のマイルストーンとして重要。いついつのバージョンでのリリース状態が見たいと思ったときに、すぐに引っ張ってこれる。リリース時だけではなく、作業の目標到達点があればタグを付けるようにしておくと、履歴を遡る場合に楽になる。
アーカイブは成果物として納品するような場合でないとなかなか使わないが、知っておくと役立つ。




gitをインストール
gitサーバーのセットアップ
git ブランチについて
git 変更を一時的に退避 stash
git ブランチを合流するマージ
git ブランチを付け替える
git コミット履歴を変更する
git 変更をリセットする
git リモートでの操作
git ファイルの追跡
git リモートブランチを追加
git チェックアウトをもっと便利に使う
git プロジェクトの構成
git 変更をpatchファイルにする
git コンフリクトに対処する
git 失敗したときの復元
posted by Zorinos at 20:00| Comment(0) | Linux | 更新情報をチェックする