2017年07月19日

git 変更をリセットする

コミット内容を訂正する操作(git commit --amend)、コミットの取り消し(git revert)は、コミット自体を無かったことにはできない。
これに対して、"reset" はコミットを無かったことにできる。
"reset" は前の状態に戻す操作。

"reset" がわかりにくいので、図を書いて整理してみた。

まず、"HEAD"、"ステージングエリア"、"作業ツリー" の関係について整理しておく。
  • 作業ツリー:最新のファイルの状態
  • ステージングエリア:コミットするためのファイルの状態
  • HEAD:最新コミットの状態


git_reset01.png
"ステージングエリア"、"作業ツリー" ともに "HEAD" に一致している。


コミット直後の reset


git_reset02.png
  • ファイルを変更したら、作業ツリーが変更
  • "git add" したら、ステージングエリアが変更
  • "git commit" したら、HEAD が変更(1つ進む)



"git reset" では、戻したいコミット位置を指定する。

今 "HEAD"はコミット(Z) 。これから1つ前のコミット(Y)に戻る場合(HEAD^)
git_reset03.png


すべて1つ前に戻す


作業ツリーも、ステージングエリアもすべて1つ前に戻す。すべてクリアされるので、ある意味、簡潔でわかりやすい。
$ git log --oneline
509957a master 追加 3
1f391e3 master 追加 2
6edb23d master 追加 1

$ git reset --hard HEAD^

$ git log --oneline
1f391e3 master 追加 2
6edb23d master 追加 1

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

ステータスを確認してみても、作業ツリーに何も変更がない。




git add を取り消す


"git add" を取り消す。作業ツリーはそのまま。
最新コミットを無かったことにし、かつ、ステージングも無かったことにする。
$ git log --oneline
509957a master 追加 3
1f391e3 master 追加 2
6edb23d master 追加 1

$ git reset HEAD^

$ git log --oneline
1f391e3 master 追加 2
6edb23d master 追加 1

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)

modified: index.html

no changes added to commit (use "git add" and/or "git commit -a")

ステータスを確認すると、作業ツリーには変更があるが、ステージングはされていない。





git commit を取り消す


"git commit" を取り消す。作業ツリー、ステージングエリアはそのまま。
単に最新コミット操作を無かったことにする。
$ git log --oneline
509957a master 追加 3
1f391e3 master 追加 2
6edb23d master 追加 1

$ git reset --soft HEAD^

$ git log --oneline
1f391e3 master 追加 2
6edb23d master 追加 1

$ 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: index.html

ステータスを確認すると、ステージングがされた状態。





最新のコミット位置が "HEAD" なのに、"HEAD" に戻すとはどういうことか?

"HEAD" 位置ではなく、作業ツリー、ステージングエリアが先に進んでいる状態を想定。
コミット後に変更したものを "reset" する操作。
考え方は、コミット直後の "reset" と同じ。
git_reset04.png




git_reset05.png
"resret --soft" は、もともと "HEAD" に居るので、"HEAD" へ戻す操作をしても何も変わらない。



git_reset06.png
"resret --mixed" は、ステージングエリアを戻すので、"git add" を取り消すことになる。



git_reset07.png
"resret --hard" は、作業ツリーも戻す。すべて消え、最新コミット直後に戻る。





昔の状態に reset


コミットIDを指定して、以前のコミット状態に "reset" する。
git_reset08.png





すべて戻す


git_reset09.png
$ git log --oneline
fee81ff master 追加 5
67c1282 master 追加 4
509957a master 追加 3
1f391e3 master 追加 2
6edb23d master 追加 1

$ git reset --hard 1f391e3

$ git log --oneline
1f391e3 master 追加 2
6edb23d master 追加 1

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

ステータスを確認してみても、作業ツリーに何も変更がない。





git add を取り消す


git_reset10.png
$ git log --oneline
fee81ff master 追加 5
67c1282 master 追加 4
509957a master 追加 3
1f391e3 master 追加 2
6edb23d master 追加 1

$ git reset 1f391e3

$ git log --oneline
1f391e3 master 追加 2
6edb23d master 追加 1

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)

modified: index.html

no changes added to commit (use "git add" and/or "git commit -a")

ステータスを確認すると、作業ツリーには変更があるが、ステージングはされていない。
作業ツリーのファイルの中身は、コミット(E):fee81ff のまま。
これを再度ステージし、コミットしてみると、
$ git log --oneline
3d15bcd master "reset"後の再コミット:
1f391e3 master 追加 2
6edb23d master 追加 1

となり、ある意味 コミット(C):509957a ~ コミット(D):fee81ff までを "squash" した状態での再コミットと同じになる。





git commit を取り消す


git_reset11.png
$ git log --oneline
fee81ff master 追加 5
67c1282 master 追加 4
509957a master 追加 3
1f391e3 master 追加 2
6edb23d master 追加 1

$ git reset --soft 1f391e3

$ git log --oneline
1f391e3 master 追加 2
6edb23d master 追加 1

$ 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: index.html

ステータスを確認すると、ステージングがされた状態。
これも再度コミットすると、コミット(C):509957a ~ コミット(D):fee81ff までを "squash" した状態での再コミットと同じになる。





reset を無かったことにする


上記のように、近々のコミットを無かったことにして、昔の状態に "reset" するということはあまりないと思うが、この昔の状態に戻す "reset" の使い方としては、昔の動作を確認するために、一時的に環境をその当時の状態にし、動作確認するときに使える。

このような場合、動作確認が終われば、再度、元のコミットに戻す必要がある。
$ git reset --hard 1f391e3
$ git log --oneline
1f391e3 master 追加 2
6edb23d master 追加 1

$ git reset --hard ORIG_HEAD

$ git log --oneline
fee81ff master 追加 5
67c1282 master 追加 4
509957a master 追加 3
1f391e3 master 追加 2
6edb23d master 追加 1


"git reset --hard ORIG_HEAD" を使えば、直前の "reset" を無かったことにできる。
間違って "git reset" してしまった場合も使えるので、落ち着いて対応する。

ただし、コミットした状態に戻すだけなので、作業ツリーや、ステージングエリアで変更していたものは戻らないので注意。

また "git reset --hard ORIG_HEAD" は前回位置に戻すだけなので、さらに "git reset" を重ねてしまうと、前回位置が上書き更新され、最初の位置に戻せなくなるので注意。





まとめ


図を書いて整理したおかげで、動作が理解できた。
"reset" で、誤ってステージしてしまった・コミットしてしまった、という場合に修正できる。これを知らないとコミット履歴が汚くなる。"git reset" は便利だが、指定オプションを間違うと、目の前の作業内容を失うこともあるので、作業途中のファイルがあれば、"git stash" で退避しておくと、失敗しても救済できる。




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月18日

git コミットを取り消す

コミットしたものを取り消したい場面、
例えば、ある機能をコミットした後で、仕様変更が入り、運悪く、その機能がドロップしてしまった。
そのため、コミットしたものを削除することに。
再度、削除してコミットしても良いが、ケアレスミスで削除ミスが発生するかも。
コミットしたものを丸ごとなかったことにするのが確実。


コミットの取り消し


git_revert01.png
$ git log --oneline --graph
* e3ac1eb new_branch 追加 3
* 5cb8c6a new_branch 追加 2
* 4f42c71 new_branch 追加 1
* 1f391e3 master 追加 2
* 6edb23d master 追加 1

コミット(2):5cb8c6a と、コミット(3): e3ac1eb の差分を確認すると、
$ git diff 5cb8c6a e3ac1eb
diff --git a/index.html b/index.html
index 7743992..65aebf5 100755
--- a/index.html
+++ b/index.html

@@ -13,5 +13,6 @@
<h2>new_branch</h2>
<p>new_branch 追加 1</p>
<p>new_branch 追加 2</p>
+ <p>new_branch 追加 3</p>
</body>
</html>


コミット(3): e3ac1eb を取り消してみる。

$ git revert e3ac1eb

$ git log --oneline --graph
* 2e3f015 Revert "new_branch 追加 3"
* e3ac1eb new_branch 追加 3
* 5cb8c6a new_branch 追加 2
* 4f42c71 new_branch 追加 1
* 1f391e3 master 追加 2
* 6edb23d master 追加 1

コミット(3):e3ac1eb と、HEADコミット: 2e3f015 の差分を確認すると、
追加されていた変更が削除されている。
$ git diff e3ac1eb 2e3f015
diff --git a/index.html b/index.html
index 65aebf5..7743992 100755
--- a/index.html
+++ b/index.html

@@ -13,6 +13,5 @@
<h2>new_branch</h2>
<p>new_branch 追加 1</p>
<p>new_branch 追加 2</p>
- <p>new_branch 追加 3</p>
</body>
</html>


"revert" 操作は、指定したコミットを打ち消す内容を作成し、コミットする。

コミットした内容を無かったことにするのではなく、コミットした履歴も、コミットを訂正した履歴も両方ともにきちんと残る。またコミットした内容を取り消すときに、gitが訂正内容を準備するので、ヒューマンエラーによるミスを防ぐことにもつながり、訂正するときに便利。
git_revert02.png





複数のコミットの取り消し


取り消したいコミットが複数ある場合を考える。
git_revert01.png
$ git log --oneline --graph
* e3ac1eb new_branch 追加 3
* 5cb8c6a new_branch 追加 2
* 4f42c71 new_branch 追加 1
* 1f391e3 master 追加 2
* 6edb23d master 追加 1

コミット(1):4f42c71 と、コミット(3): e3ac1eb の差分を確認すると、
$ git diff 4f42c71 e3ac1eb
diff --git a/index.html b/index.html
index 200b61d..65aebf5 100755
--- a/index.html
+++ b/index.html

@@ -12,5 +12,7 @@
<h2>new_branch</h2>
<p>new_branch 追加 1</p>
+ <p>new_branch 追加 2</p>
+ <p>new_branch 追加 3</p>
</body>
</html>


コミット(3):e3ac1eb と、コミット(2): 5cb8c6a を取り消してみる。
コミットを複数取り消す場合、コミットした順番と逆の順序で、"revert" することで目的を達する。
$ git revert e3ac1eb
$ git revert 5cb8c6a

$ git log --oneline
3ff18a9 Revert "new_branch 追加 2"
06f718a Revert "new_branch 追加 3"
e3ac1eb new_branch 追加 3
5cb8c6a new_branch 追加 2
4f42c71 new_branch 追加 1
1f391e3 master 追加 2
6edb23d master 追加 1

git_revert03.png

単純だが、これだと訂正したいコミット数だけ、訂正コミットを行うので手間がかかるし、後から見たときに見通しが良くない。

ただ、確実に1つ1つ対応しないと不安だという場合は、このようにすべきであるが、
せめて後から履歴を眺めたときに見通しをよくするために、訂正コミットをすべて行った後、"git rebase -i" で "squash" するのがおすすめ。
訂正時に1つ1つ対応することで安心できるし、コミット履歴が整理されるので見通しが良くなる。



せめて "rebase" の手間ぐらい省きたい場合は、"revert" 操作に、"-n" or "--no-commit" オプションを指定するとよい。"-n" オプションは、逆マージまで行い、コミットを行わない操作。
コミットした順版と逆順でマージ操作のみを行い、最後にコミットする。

$ git revert -n e3ac1eb
$ git revert -n 5cb8c6a
$ git commit

$ git log --oneline
eaac52c Revert "new_branch 追加 1" & "new_branch 追加 2"
e3ac1eb new_branch 追加 3
5cb8c6a new_branch 追加 2
4f42c71 new_branch 追加 1
1f391e3 master 追加 2
6edb23d master 追加 1

git_revert04.png
後から、"squash" する必要がないので、少し手間が省ける。





マージコミットの取り消し


ブランチを切って対応した機能を本流にマージした後に仕様ドロップになってしまった場合を考える。
git_revert05.png
$ git log --oneline --graph
* ca27af6 Merge branch 'new_branch'
|\
| * 5cb8c6a new_branch 追加 2
| * 4f42c71 new_branch 追加 1
* | 509957a master 追加 3
|/
* 1f391e3 master 追加 2
* 6edb23d master 追加 1


マージコミット(D):ca27af6 に対して、"revert" 操作を行うと、
$ git revert ca27af6
error: Commit ca27af63e56738811fb79d06a44b35e5de60dd21 is a merge but no -m option was given.
fatal: revert failed

と、エラーメッセージが出る。
つまりは、マージコミットに対しては普通には "revert" できない。"-m" オプションを指定しなさいと。

"-m" or "--mainline" を使うときは続けて、"parent-number" を指定する。
"parent-number" は、"git show" を見るとわかる。
$ git show ca27af6
commit ca27af63e56738811fb79d06a44b35e5de60dd21
Merge: 509957a 5cb8c6a
・・・

マージすると、親コミットが複数存在する。"git show" で示される、①509957a と、②5cb8c6a が親コミット。

マージコミットに対して "revert" で訂正した場合、どのブランチの流れで訂正するのか?
git_revert06.png

これを指定するのが、"-m" オプション。
"git show" の結果で、"master" ブランチ側は1、"new_branch" ブランチ側が2 とわかった。
"new_branch" ブランチを、"master" ブランチへマージしたことを訂正したいので、"-m 1" を指定する。

$ git revert -m 1 ca27af6

$ git log --oneline --graph
* a30ed5c Revert "Merge branch 'new_branch'"
* ca27af6 Merge branch 'new_branch'
|\
| * 5cb8c6a new_branch 追加 2
| * 4f42c71 new_branch 追加 1
* | 509957a master 追加 3
|/
* 1f391e3 master 追加 2
* 6edb23d master 追加 1






マージコミット取り消しの注意点


マージするのが早かったと思い、一旦、"revert" でマージコミットを取り消し、取り消したブランチ側で継続して作業を行い、再度マージしたとする。
git_revert07.png
$ git log --oneline --graph
* a6ea348 new_branch 追加 4
* 20655ff new_branch 追加 3
* 5cb8c6a new_branch 追加 2
* 4f42c71 new_branch 追加 1
* 1f391e3 master 追加 2
* 6edb23d master 追加 1

コミット(1):4f42c71 と、コミット(4): a6ea348 の差分を確認する。
$ git diff 4f42c71 a6ea348
diff --git a/index.html b/index.html
index 200b61d..7743992 100755
--- a/index.html
+++ b/index.html

@@ -12,5 +12,6 @@
<h2>new_branch</h2>
<p>new_branch 追加 1</p>
+ <p>new_branch 追加 2</p>
</body>
</html>
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 0000000..02ab331
--- /dev/null
+++ b/readme.txt

@@ -0,0 +1,3 @@
+readme
+readme 変更
+



この状態でマージしてみる。

$ git checkout master
$ git merge new_branch

$ git log --oneline --graph
* 77c32e4 Merge branch 'new_branch'
|\
| * a6ea348 new_branch 追加 4
| * 20655ff new_branch 追加 3
* | a30ed5c Revert "Merge branch 'new_branch'"
* | ca27af6 Merge branch 'new_branch'
|\ \
| |/
| * 5cb8c6a new_branch 追加 2
| * 4f42c71 new_branch 追加 1
* | 509957a master 追加 3
|/
* 1f391e3 master 追加 2
* 6edb23d master 追加 1



マージ前後の差分を確認してみる。コミット:a30ed5c と、コミット: 77c32e4 の差分を確認。
$ git diff a30ed5c 77c32e4
diff --git a/readme.txt b/readme.txt
new file mode 100644
index 0000000..02ab331
--- /dev/null
+++ b/readme.txt

@@ -0,0 +1,3 @@
+readme
+readme 変更
+



すると、訂正したマージコミット分の差分(コミット(1):4f42c71 、コミット(2):5cb8c6a)が反映されていないことがわかった。
git_revert08.png

これは、マージしたことをブランチ操作として管理しているが、"revert" はブランチ管理外の操作のため、マージが訂正され、本流から削除されてしまったことはブランチの動きとして把握していない。
そのため前回マージされたコミット位置(コミット(2): 5cb8c6a)が基準となり、今回のマージが作成された。結果、コミット(1):4f42c71 、コミット(2):5cb8c6a がマージに含まれない状態でマージされている。

この動作を理解できていないと、マージしたつもりでも実際にはマージできていないので注意が必要。


では、この場合はどうするのか?

この場合、マージコミットを "revert" したものを、再度 "revert" し直すしかない。
git_revert09.png





まとめ


コミットした内容を取り消すには、再度、元の形に変更したファイルでコミットし直せば良い。
ただ、ヒューマンエラーを起こさないためにも、git に備わる機能で "revert" という便利な機能を使って、スマートな対応をしたい。
ただし、マージコミットを訂正した場合は、その後の動作を理解していないと嵌る。無駄な労力を使わないためにも、しっかりと理解して使いたい。


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

2017年07月14日

git コミット履歴を変更する

コミットした後で、間違ってコミットした!とか、コミットメッセージが適切ではなかったとか、さっきのコミットと今の変更は合わせてコミットしたほうがよかったとか。
そんな場合に、コミットした内容を訂正する方法。

直前のコミットの修正


直前のコミット限定の操作。
"git commit --amend" を使う。

コミットメッセージの修正


コミット後に、コミットメッセージが不足していたとか、レビューで「コミットメッセージが対応内容と一致していない」と指摘されたときとかに使う。
$ git log --oneline
02c1321 commit 内容
9fe9714 master 追加 2
1c0a080 master 追加1
07c5066 master branch :変更 1
830f4ca Add new file :index.html

コミットID:02c1321 のコミットメッセージを修正する。

$ git commit --amend


エディタが立ち上がるので修正する。


$ git log --oneline
ecb63b0 master 追加 3 (コミットメッセージを修正)
9fe9714 master 追加 2
1c0a080 master 追加1
07c5066 master branch :変更 1
830f4ca Add new file :index.html

コミットメッセージが修正できた(コミットIDも変更される)


コミットの修正


コミットした後に、1ファイルをステージするの忘れていたとか、"stash" から戻すのを忘れて別の修正をコミットしたとか、そんなときには必要なファイルを "git add" してステージしてから実行する。
$ git log --oneline
a383399 master 追加 3 (間違ったコミット)
9fe9714 master 追加 2
1c0a080 master 追加1
07c5066 master branch :変更 1
830f4ca Add new file :index.html

$ git add index.html
$ git commit --amend

$ git log --oneline
2e3f7ae master 追加 3 (コミット内容を修正)
9fe9714 master 追加 2
1c0a080 master 追加1
07c5066 master branch :変更 1
830f4ca Add new file :index.html




これで、コミット後に、あっ!しまった!!! と思うことがあっても落ち着いて作業できる。ただし、この操作はコミットしたという履歴を無かったことにはできない。あくまでコミットした履歴内容を訂正するだけ。






過去のコミットの修正


"git commit --amend" は直前のコミットに対してのみ。2つ前、3つ前のコミットを修正したい場合はどうするのか?
その場合は、ブランチの付け替えとして使う "rebase" 操作を使う。
"rebase" を使う場面は付け替え操作よりも、コミット内容の修正が多いと思う。


"-i" or "--interactive" オプションを使うと、「interactiveモード」で "rebase" 操作が使える。
具体的な操作は後から指定するから、とりあず指定したコミット履歴を列挙して!という操作。

git_rebase10.png
$ git log --oneline
762bccf master 追加 3
9fe9714 master 追加 2
1c0a080 master 追加1
07c5066 master branch :変更 1
830f4ca Add new file :index.html


$ git rebase -i <コミットID>


とすると、指定したコミットIDの次のコミット以降をコミット履歴の修正対象とする。

コミット(C):1c0a080 のコミット履歴を修正したい場合、1つ前の コミット(B):07c5066 を指定する。

$ git rebase -i 07c5066

pick 1c0a080 master 追加1
pick 9fe9714 master 追加 2
pick 762bccf master 追加 3

# Rebase 07c5066..762bccf onto 07c5066 (3 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out


すると、エディタが立ち上がり、そこには先頭に対象コミットが古いコミット~新しいコミットの順で並んでいる。
この "pick <コミットID> <コミットメッセージ>" と記載されている箇所に注目する。

これを以下の内容で操作することで、コミット履歴を修正できる。
Commands処理
「p」or「pick」このコミットを適用する
「r」or「reword」このコミットを適用するが、コミットメッセージは編集する
「e」or「edit」このコミットを適用するが、ファイルを修正する
「s」or「squash」このコミットを適用するが、1つ前のコミットと合体させる
「f」or「fixup」「squash」と同じだが、このコミットメッセージは破棄する
「x」or「exec」以降のコマンドをshellで実行する
「d」or「drop」このコミットを削除する



対象コミットの指定は、"HEAD" を使い、「"HEAD" から何個目までの履歴を対象とする」と指定することもできる。

$ git rebase -i HEAD~3








コミットメッセージを修正


「reword」を指定。

reword 1c0a080 master 追加1
pick 9fe9714 master 追加 2
pick 762bccf master 追加 3

として、エディタを終了すると、
続けて、コミットメッセージを修正するエディタが立ち上がるのでメッセージ内容を変更し終了する。
$ git log --oneline
0e83bbd master 追加 3
cd5173c master 追加 2
d41ea49 master 追加 1(コミットメッセージを修正)
07c5066 master branch :変更 1
830f4ca Add new file :index.html

コミットメッセージが変更された(変更したコミット以降もコミットIDが変更される)。
git_rebase11.png





コミットをまとめる1


1つ前のコミットとまとめる。
"merge" 操作時にコミットをまとめる操作があるが、"rebase" でまとめてからマージするほうが、使用頻度は多いと思う。

pick 1c0a080 master 追加1
squash 9fe9714 master 追加 2
pick 762bccf master 追加 3

# This is a combination of 2 commits.
# The first commit's message is:

master 追加1

# This is the 2nd commit message:

master 追加 2

コミットメッセージを入力するエディタが立ち上がるのでコミットメッセージを入力し終了。
$ git log --oneline
64a5d77 master 追加 3
27f2fe8 master 追加1 & master 追加 2 (コミットを圧縮)
07c5066 master branch :変更 1
830f4ca Add new file :index.html


コミットが圧縮された(変更したコミット以降もコミットIDが変更される)。
git_rebase12.png



コミットをまとめる2


"squash" と "fixup" の違いは、コミットメッセージが編集できるかどうか。

pick 1c0a080 master 追加1
fixup 9fe9714 master 追加 2
pick 762bccf master 追加 3


終了すると、メッセージを編集するエディタは起動せず完了した。
$ git log --oneline
eb3834a master 追加 3
eb91f22 master 追加1
07c5066 master branch :変更 1
830f4ca Add new file :index.html

"fixup" を指定したコミットはまとめられたが、コミットメッセージは削除された(変更したコミット以降もコミットIDが変更される)。
git_rebase13.png




コミットの順番を入れ替える


作業の区切りの良いところでコミットしていたが、後で履歴を見たときに作業の意図がわかるように整然とコミット順番を並べたいと思ったときにはコミット順番を入れ替える。

コミットを示している行を、意図したコミット順序に並び替え、エディタを終了させる。

pick 1c0a080 master 追加1
pick 762bccf master 追加 3 <<入れ替えた↓
pick 9fe9714 master 追加 2 <<入れ替えた↑


ここで注意したいことは、コミット順番が入れ替わるということは、変更差分の順番も変わるということ。
git が上手いことやってくれる訳ではないので、コンフリクトが発生することを前提として、自分の手できちんと組み替え直さないとダメ。
特に、この作業をやっている時点では、きっと自分自身では変更差分の最終形がわかっているので、この操作でのコンフリクトを理解せずに、最初のコンフリクトで思わず最終形で修正し、以降のコンフリクトでも同じ状態で保存してしまうと、本来発生していたはずの差分が発生せず、結果的にコミットが圧縮(squash)された状態になってしまう。

コミット順番の入れ替えは、過去のファイル差分の入れ替えにあたるので、確実に差分の登録順番を意識して修正すること。
$ git log --oneline
1d79372 master 追加 2'
7335bd0 master 追加 3'
1c0a080 master 追加1
07c5066 master branch :変更 1
830f4ca Add new file :index.html

コミットの順番が変更された(変更したコミット以降もコミットIDが変更される)。
git_rebase14.png




コミットを分割する


コミットしたが、内容的に2つの目的を含んだコミットだったので、別々にコミットしたほうが良かったと思った場合にコミットを分割する。

コミット(D):9fe9714 の内容を分割したいとすると、

pick 1c0a080 master 追加1
edit 9fe9714 master 追加 2
pick 762bccf master 追加 3


終了させると、"rebase" 処理が指定した箇所で止まり、shell に制御が戻される。
Stopped at 9fe9714240de35b1ed77601d14bd965e647f226c... master 追加 2
You can amend the commit now, with

git commit --amend

Once you are satisfied with your changes, run

git rebase --continue

ここで変更内容を確認してみると、コミット(D):9fe9714 までコミットされた状態で止まっている。

既にコミット(D):9fe9714 が含まれているので、このコミット分割するためには、直前のコミットを修正する
対象ファイルを変更し、ステージしたら、直前のコミットを修正する。

$ git add index.html
$ git commit --amend -m "master 追加 2-1"


分割したかったので、残りの変更も追加する。

$ git add index.html
$ git commit -m "master 追加 2-2"


コミットが修正できたら、"rebase" を継続する。

$ git rebase --continue

$ git log --oneline
48f861d master 追加 3
c9d0e42 master 追加 2-2
a85263e master 追加 2-2
1c0a080 master 追加1
07c5066 master branch :変更 1
830f4ca Add new file :index.html

コミットが分割された(変更したコミット以降もコミットIDが変更される)。
git_rebase15.png




コミットを挿入する


"edit" は分割だけではない。"rebase" 処理が指定場所で中断するので、その間にコミットを行えば、コミットを挿入することもできる。

pick 1c0a080 master 追加1
edit 9fe9714 master 追加 2
pick 762bccf master 追加 3

Stopped at 9fe9714240de35b1ed77601d14bd965e647f226c... master 追加 2
You can amend the commit now, with

git commit --amend

Once you are satisfied with your changes, run

git rebase --continue

$ git add index.html
$ git commit -m "master 挿入"
$ git rebase --continue

$ git log --oneline
ded34b1 master 追加 3
ecba81d master 挿入
9fe9714 master 追加 2
1c0a080 master 追加1
07c5066 master branch :変更 1
830f4ca Add new file :index.html

コミットが挿入された(変更したコミット以降もコミットIDが変更される)。
git_rebase16.png




コミットを削除する1


コミットを削除する。
「コミットを削除」と言っても、変更差分も無かったことにはしてくれないので、コンフリクトが起こることを前提とし、コンフリクトした場合はしっかりと内容確認して削除しないといけない。

pick 1c0a080 master 追加1
drop 9fe9714 master 追加 2
pick 762bccf master 追加 3

$ git log --oneline
f82c062 master 追加 3
1c0a080 master 追加1
07c5066 master branch :変更 1
830f4ca Add new file :index.html

コミットが削除された(変更したコミット以降もコミットIDが変更される)。
git_rebase17.png




コミットを削除する2


"drop" を指定せずとも、並んでいるコミットの行から不要なものを削除しても同様。

pick 1c0a080 master 追加1
<<< 行を削除 >>>
pick 762bccf master 追加 3

$ git log --oneline
29ff05c master 追加 3
1c0a080 master 追加1
07c5066 master branch :変更 1
830f4ca Add new file :index.html

コミットが削除された(変更したコミット以降もコミットIDが変更される)。
git_rebase18.png





shell を使う


"exec" は趣旨が異なる。コミットに対する操作ではない。
"rebase" の途中に指定した処理を挿入することができる。

全く意味が無いが、例として、"ls -a" コマンドを実行してみる。

pick 1c0a080 master 追加1
pick 9fe9714 master 追加 2
exec ls -a
pick 762bccf master 追加 3

Executing: ls -a
. .. .git index.html
Successfully rebased and updated refs/heads/master.

"ls -a" が途中で実行されたのがわかる。


コミット履歴の修正で使う場合、次のようなやり方がある。
今の作業ツリー上の変更は、コミット(D):9fe9714 と合わせてコミットしたほうが良かったと思った場合に、"stash" を使って設定してみる。
今の変更分を一旦 "stash" しておく。

$ git stash
$ git rebase -i HEAD~3



"exec" を使い、git 操作を記述する。

pick 1c0a080 master 追加1
pick 9fe9714 master 追加 2
exec git stash pop; git commit -a --amend
pick 762bccf master 追加 3

$ git log --oneline
ba09ebd master 追加 3
9706693 master 追加 2(追加修正あり)
1c0a080 master 追加1
07c5066 master branch :変更 1
830f4ca Add new file :index.html

コミット(D):9fe9714 を "rebase" したところで、shell の実行に移る。
"git stash pop" を実行し、変更したファイルを作業ツリーに戻し、続けて、
"git commit -a --amend" で直前のコミットを、現在の作業ツリーのファイルで修正コミットする(変更したコミット以降もコミットIDが変更される)。
git_rebase19.png






まとめ


"git commit --amend" はまだしも、
"rebase" は過去の歴史を変えるという非常に強力な操作のため、普段は "reword" "squash" ぐらいの内容に留めておくのが安全で良い。

コミット履歴の変更を行えば、ほとんど場合でコンフリクトが発生すると考えておき、コンフリクトの修正もコミットという履歴を理解したうえで、慎重に対応すべき。
後から修正できるからと、とりあえずコミットしておけばよいとか思わないように。
特に、他メンバーに展開したブランチに対する、コミット履歴の修正は混乱を招くだけなのでダメ。

コミット履歴の修正は、しまった!と思うような場合に、「非効率なリカバリではなく、効率よくリカバリできる手段としてのみ使用できるもの」ぐらいの意識でいたほうが良い。




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

2017年07月13日

git ブランチを付け替える

ブランチを統合する操作として "merge" がある。
もう一つ別の方法として、 "rebase" がある。





基本的な操作


git_rebase01.png



"new_branch" ブランチを "master" ブランチへ "merge" すると、以下のようになる。

$ git checkout master
$ git merge new_branch

git_rebase02.png
$ git log --oneline --graph
* e379414 Merge branch 'new_branch' Conflicts -> modified
|\
| * 0792fc6 new_branch 追加 3
| * ef693eb new_branch 追加 2
| * 24edebf new_branch 追加1
* | 762bccf master 追加 3
* | 9fe9714 master 追加 2
* | 1c0a080 master 追加1
|/
* 07c5066 master branch :変更 1
* 830f4ca Add new file :index.html


これを "rebase" を使って操作してみる。

"rebase" は、「re-base」のこと。ブランチの分岐元を付け替える操作。
分岐元を変更したい("rebase" したい)ブランチへ切り替える。今は、"new_branch" を変更する。

$ git checkout new_branch


"new_branch" ブランチの分岐元を、"master" ブランチの "HEAD" に切り替える。

$ git rebase master


コンフリクトが起きた場合は、コンフリクトを修正後、修正ファイルをステージし、継続する。

$ git add index.html
$ git rebase --continue


"rebase"が終了すると、以下のようになる。
git_rebase03.png
$ git log --oneline --graph
* 22d32e0 new_branch 追加 3
* d7e8b73 new_branch 追加 2
* 5893adb new_branch 追加1
* 762bccf master 追加 3
* 9fe9714 master 追加 2
* 1c0a080 master 追加1
* 07c5066 master branch :変更 1
* 830f4ca Add new file :index.html

"new_branch" は分岐元が付け替えられている。そして、各コミットも改めてコミットされてたのでコミットIDが変わっている。

この状態で、"master" ブランチで、"merge" を行うと、

$ git checkout master
$ git merge new_branch

コミット状態がきれいになっているので Fast-forward マージ が行われる。
Updating 762bccf..22d32e0
Fast-forward
index.html | 3 +++
1 file changed, 3 insertions(+)

git_rebase04.png
$ git log --oneline --graph
* 22d32e0 new_branch 追加 3
* d7e8b73 new_branch 追加 2
* 5893adb new_branch 追加1
* 762bccf master 追加 3
* 9fe9714 master 追加 2
* 1c0a080 master 追加1
* 07c5066 master branch :変更 1
* 830f4ca Add new file :index.html


ログを見ると、単にマージしたときと統合内容は同じだが、こちらのほうがブランチの分岐の履歴が無く、すっきりとした状態になる。

ただし、作業した結果が残らない履歴は、個人的には好みではない。

使うのであれば、本流のブランチへ統合するときに行うのではなく、バグ修正や、機能開発などの作業ブランチにおいて、個人の作業範疇でさらにブランチを切る必要があった場合に、最終的なブランチの結果としてコミットをまとめるときに使うことをすすめる。これであれば、個人単位での作業としては履歴が残ることと、後から履歴を見たときに作業の都合のために切ったブランチが全体の見通しを悪くしてしまうことを避けることができる。





onto オプション


"new_branch" ブランチを切って開発中に、開発のためにバグ修正が必要だったので "sub_branch" ブランチを切って修正した。このバグ修正が他の機能開発でも必要だとわかったので "master" ブランチへ統合したい。
git_rebase05.png

"new_branch" ブランチはまだ開発途中で取り込めない。"sub_branch" のみ取り込みたい。
必要なコミットは、コミット(X):0cb061a、コミット(Y):0a8d056 の2つのみ。
ここで "rebase" をしてみる。

$ git checkout sub_branch
$ git rebase master

"master" ブランチへマージする。

$ git checkout master
$ git merge sub_branch

Updating 762bccf..ce98d22
Fast-forward
index.html | 3 +++
1 file changed, 3 insertions(+)

$ git log --oneline --graph
* ce98d22 sub_branch 追加 2
* 216520c sub_branch 追加 1
* b4d8495 new_branch 追加1
* 762bccf master 追加 3
* 9fe9714 master 追加 2
* 1c0a080 master 追加1
* 07c5066 master branch :変更 1
* 830f4ca Add new file :index.html


git_rebase06.png

この場合、今はまだ取り込みたくなかった コミット(1):24edebf が一緒に取り込まれてしまった。

このような変則的な取り込みを行うときに、"onto" オプションを使う。

指定がややこしいが、以下のようにブランチを指定する。
現在、チェックアウトしているブランチに対して、

$ git rebase --onto <どこへ> <どこから>



今の操作であれば、"sub_branch" ブランチをチェックアウトした状態で、"new_branch" から、"master" へ、切り替える操作。

$ git checkout sub_branch
$ git rebase --onto master new_branch

"master" ブランチへマージする。

$ git checkout master
$ git merge sub_branch

Updating 762bccf..9617339
Fast-forward
index.html | 3 +++
1 file changed, 3 insertions(+)

$ git log --oneline --graph
* 9617339 sub_branch 追加 2
* 66d8fb8 sub_branch 追加 1
* 762bccf master 追加 3
* 9fe9714 master 追加 2
* 1c0a080 master 追加1
* 07c5066 master branch :変更 1
* 830f4ca Add new file :index.html

git_rebase07.png


これは、ちょっと特殊な場面だったが、次のような場合も、"oonto" オプションを使えば解決できる。

"new_branch" ブランチから、新たなブランチを切って作業を進めようとしていたが、誤って、"master" ブランチから、ブランチを切って作業していたことに気づいた。"new_branch" ブランチも履歴が進んでしまった。本当は コミット(1):24edebf からブランチを切りたかった。
git_rebase08.png

こういう場合に、"onto" オプションをつけて "rebase" をすることで修正できる。
(付け替え先はブランチ名ではなく、コミットIDを指定する。ブランチ名だと、先頭のコミットが付け替え先になる。)

$ git checkout sub_branch
$ git rebase --onto 24edebf master

$ git log --oneline --graph
* 026323a sub_branch 追加 2
* 29540b6 sub_branch 追加 1
* 24edebf new_branch 追加1
* 07c5066 master branch :変更 1
* 830f4ca Add new file :index.html

git_rebase09.png





rebase と cherry-pick


上記のような "rebase" の操作は、実は連続で cherry-pick を実行することでも同じ結果が得られる。
少ないコミットであれば、cherry-pick で操作すれば済むが、ブランチ丸ごとに対して操作することに対して、簡単に cherry-pick 操作できるようしたものが "rebase" だともいえる。





まとめ


"rebase" することのメリットとしては、
  • コミットログがきれいになる。
    無数に入り組んだ履歴ではなく、必要な情報が俯瞰できるようになり、後から履歴を見たときにわかりやすくなる。その結果、運用、保守、生産性の効率が期待できる。

という点で、作業の効率化のためにもどんどんブランチを切って作業し、それを整理していくことは良いことだと思う。
ただ、これが許されるのは閉じられた世界での話。

チーム作業で公開してしまったブランチに対してはダメ。
ブランチを作り、リモートリポジトリに push した後、他のメンバーがそのブランチから新たにブランチを切って作業していたら、もうそのブランチは "rebase" してはいけない。禁止。

"rebase" してしまうと、過去のコミットIDが変わってしまう。派生させたブランチは親ブランチを追いかけることができなくなってしまう。"merge" するときに多大なる迷惑をかけてしまう。

なので、push する前のローカルなブランチであれば "rebase" で整理して、全体の見通しを良くすることは、以降の開発効率を上げるための一手間としておススメ。





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

2017年07月11日

3.5mmステレオジャック オーディオセレクタ を自作する

パソコンとタブレットから音声出力させるときに、ヘッドホンとイヤホンを使っているが切り替えて使うことや、ケーブルが邪魔で仕方がない。
タブレット→パソコンへBluetoothで音を飛ばして音声出力の一本化をしてみたが、タブレット側でWifiの通信が阻害され、音声がクラウドにある場合にストレスが酷いのでやめた。

で、次に考えたのがオーディオセレクタ。

値段も手ごろでこれで良いかと思っていたが、ノイズが酷いとかプッシュ式のスイッチが効かないとかレビューがあって購入を悩んでいたが、もっと検索していたら結構オーディオセレクタの自作ネタがひっかかる。
費用もオーディオセレクタよりも抑えられ、既製品を買って失敗するよりは良いかなと自作することにした。

現在の音声入力はメインはデスクトップPCとタブレットの2本だが、ノートPCとTVもあるので最大4本の音声入力ができるように、3.5mmのステレオミニジャックの入力4 出力1でロータリースイッチを使って切り替えるオーディオセレクタを作成することにした。







パーツ購入


電子部品は千石電商ネット通販で購入。
ケースは、100均のセリアで手ごろサイズで、加工し易そうな箱があったので購入。
種類品名値段
ロータリースイッチアルプス電気 SRRN142100
3回路4接点
audioselector01.jpg
¥399 x 1
3.5mm ステレオジャックマル信無線電機 MJ-073Haudioselector02.jpg¥74 x 5
つまみMAV C-1S
シャフト径:φ6.1mm
audioselector03.jpg
¥168 x 1
ケーブル協和ハーモネット RKV 0.3×4列 L-1 4
芯リボンケーブル(4色カラー) 1m
audioselector04.jpg
¥250 x 1
上記4点送料¥432
ケース縦66mm x 横66mm x 高さ66mmaudioselector05.jpg¥108 x 1
合計¥1727





その他の作業に必要なもの、
半田ごて、ハンダ、六角レンチ(つまみの固定用)、電動ドリル(ケース穴あけ用)は手持ちのものを使用。
あと、あると便利なものは、マスキングテープ(ケース穴あけの位置決め)、テスター(導通チェック用)、グルーガン(半田付け箇所の補強)。




配線


ロータリースイッチの回路図から確認。
この図面は、軸側から見た番号になる。「C」の位置が共通の端子。
audioselector07.png

「C」を出力端子に割り当て、今回はこのように割り当てた。
(上図とは逆から見た絵)
audioselector06.jpg

3.5mmステレオジャックのTSRは以下。
audioselector08.jpg

audioselector13.jpg



以下の配線とした。
audioselector12.png





作業


ケースに電動ドリルで、3.5mmステレオジャック取り付け用の穴 x 5箇所 と、
ロータリースイッチの軸を通す穴 x 1個と、スイッチ回り止めの穴 x 1個をあける。

これが一番苦労した。手持ちのドリルでは十分な大きさのサイズが無かったので、最後はドリルを斜めに入れたりしながら無理矢理に削った。勢いあまってケースを少し傷つけてしまった。

あとはケーブルを切って、半田付けして、ケースに収めるのだが、
ケースに取り付ける順番を考えながら半田付けする。
グルーガンで半田付け箇所を補強したけど、見た目がいまいち。修行が足りない。

つまみの側部に六角レンチで締め付けれるねじがあるので、ロータリースイッチの軸を締め付けることで固定。

で、完成。
audioselector10.jpgaudioselector11.jpg

透明ケースなので、ケーブルが丸見えでごちゃごちゃしていたりするが、それは想定通り。
いまいちなのはグルーガンの技術。中身が丸見えなので見栄えが悪い。技術不足。
あと、ロータリースイッチの軸が長くて、つまみが浮いている感じになっているのが気になる。少し軸をカットするともう少し見栄えが良くなると思う。
改善したいところはあるが、全体的にコンパクトにできあがったので大満足。





まとめ


手順を残すために、これを書きながら、そしてロータリスイッチの導通確認をしながら作業したので、半日仕事。部品代は¥2000弱だが、手間賃を入れたら、それなりの金額。試作品作りだと思えば、こんなものか。
次に作るときがあれば、今回の反省を踏まえて必要なものをそろえておけば、実質作業は短時間になるだろう。
とは言え、この段階でも既製品と同じぐらいなので、十分じゃないだろうか。

そして、自作しているので壊れても修理がきくメリットがあるし、何より一番のメリットはノイズが気にならないというのが気持ちがいい。

posted by Zorinos at 20:00| Comment(0) | DIY | 更新情報をチェックする
ブログランキング・にほんブログ村へ
×

この広告は180日以上新しい記事の投稿がないブログに表示されております。