vimのキーバインド<C-j>がinsertモード移行からmapできない時の解決方法
背景
vimとTmuxをシームレスに移動するためのプラグインを真似したかった.
vimの<C-j>をremapできなかったので, その対策を記す.
やりたかったこと
vim の normalモードで<C-j>に他のキーバインドを当てたい.
できなかったこと
normalモードで<C-j>を入力するとinsertモードに移行する.
:map <C-j>
で<Plug>IMAP_JumpForward
が出力される.
解決方法
$HOME/.vim/plugin/imaps.vim
の480行目あたりを編集する.
imap, nmap, vmap
をコメントアウトする.
" Default maps for IMAP_Jumpfunc {{{ " map only if there is no mapping already. allows for user customization. " NOTE: Default mappings for jumping to the previous placeholder are not " provided. It is assumed that if the user will create such mappings " hself if e so desires. if !hasmapto('<Plug>IMAP_JumpForward', 'i') " imap <C-J> <Plug>IMAP_JumpForward コメントアウト endif if !hasmapto('<Plug>IMAP_JumpForward', 'n') " nmap <C-J> <Plug>IMAP_JumpForward コメントアウト endif if exists('g:Imap_StickyPlaceHolders') && g:Imap_StickyPlaceHolders if !hasmapto('<Plug>IMAP_JumpForward', 'v') " vmap <C-J> <Plug>IMAP_JumpForward コメントアウト endif else if !hasmapto('<Plug>IMAP_DeleteAndJumpForward', 'v') " vmap <C-J> <Plug>IMAP_DeleteAndJumpForward コメントアウト endif endif " }}}
上記でできた.
git revertについて
git revertを理解する上で必要な知識
前回, 前々回でgit reset
, git rebase
について触れた.
ここからはgit reset
を理解してることを前提に話を進めていく.
参考ページ Git チュートリアル: 変更を元に戻す | アトラシアン
git revertの概要
git revert
は, コミットを打ち消すような動作をする.
コミットの編集履歴を辿り, 前回コミットで変更された部分(差分)のみを"打ち消す"ようなコミットを行う.
git reset と git revertの違い
例として, 前回コミットした内容に間違いが含まれていたため,
前回のコミットを取り消して, 改めてコミットしたい場合を考える.
# コミット A,B,Cがあり, Cに間違いが含まれている. # そこで, Cを取り消して, 改めてコミットを行いたい. A -> B -> C (間違いを含むコミット) ↑ HEAD
これを実現する方法は, 2つある.
それがgit reset
とgit revert
である.
git resetを使った方法
git reset
は怖くないgit reset - namu_r21の日記でも触れたように, working tree, index, headを過去コミットの状態に完全に戻すコマンドである.
つまり, そもそも"コミットなんてなかった"という状態にすることができる.
# git resetでCをなかったことにする A -> B -> C (間違いを含むコミット) ↑ HEAD $ git reset --hard HEAD~1 A -> B # Cなんてなかった ↑ HEAD
この状態で改めて変更をコミットすると以下のような状態になる.
ここで, 注意すべきは改めてコミットしたものは新しいコミットとして見なされることである.
# git resetでCをなかったことにした後 A -> B ↑ HEAD # 改めてcommit $ git commit A -> B -> D (Cとは異なるコミットとして扱われる.) ↑ HEAD
git revertを使った方法
対して, git revert
は, コミットを打ち消すような動作をする.
前回コミットで変更された部分(差分)のみを"打ち消す".
コミットCはそのまま残し, コミットCによって行われた変更部分を打ち消すコミットを発行する.
# git revertでCで行われた変更を打ち消す A -> B -> C (間違いを含むコミット) ↑ HEAD $ git revert A -> B -> C -> C' ( Cによって行われた変更を打ち消すコミット) ↑ HEAD
この時, working treeはコミットBと同じ状態になっている. 改めて, コミットを行う場合は以下のような状態になる.
# git revertでCで行われた変更を打ち消した後, A -> B -> C -> C' ↑ HEAD # 改めてcommit $ git commit A -> B -> C -> C' -> D ↑ HEAD
このようにすることで,
git revert
によってログを残しながらコミットCを"なかったこと"にすることができる.
ここがgit reset
とgit revert
の違いである.
なぜgit revertが必要なのか
個人でgitを利用し, ローカルリポジトリだけで開発を行っている場合はこの2つを混同しても特に問題はない. しかし, リモートリポジトリが関係すると話は別になる.
例えば, ローカルでコミットCまで開発しリモート(origin)にpushしてしまった場合を考える.
# 間違いが含むコミットCをoriginにpushしてしまった. A -> B -> C (間違いを含むコミット) ↑ HEAD origin/HEAD
git reset
を使って, コミットCをなかったことにして
改めてコミットを行うと以下のような状態になる.
# 間違いが含むコミットCを``git reset``によってなかったことにして # 改めてコミットを行う. A -> B -> -> D ↑ ↑ origin/HEAD HEAD $ git push origin CONFLICT!
この状態でgit push origin
を行うと, コンフリクトが起きる.
origin
側からすると,
- Bと繋がっているはずのCコミットがなくなっている
- Bと繋がっていないはずのコミットDが送られてくる
という状態になり, エラーを吐く.
これをgit revert
を使うことで繋がりを守ったまま
コミットCを処理できるため, エラーを吐かない.
# 間違いが含むコミットCを``git revert``によって"打ち消し"て # 改めてコミットを行う. A -> B -> C -> C' -> D ↑ ↑ origin/HEAD HEAD $ git push origin A -> B -> C -> C' -> D ↑ HEAD origin/HEAD
チーム開発における git revertの有効性と git resetのヤバさ
チームで開発しているリポジトリのログをgit reset
で汚してし,それを共有すると全員のリポジトリでコンフリクトが起きる.
なおかつ, logが残らないので原因追及ができなくて死ぬ.
チーム開発するときは,
- リモートにpush後のコミットを訂正する際は, git revertを使う( 不用意にgit resetしない)
- 間違っても, git resetでログをめちゃくちゃにした後にリモートリポジトリに反映しない
- pushする前に本当にpushしても問題ないかを確認する.
まとめ
git revert
は,コミットを残しつつコミットの変更を打ち消す.git reset
は, コミットそのものを無かったことにする.
git rebaseってなによ?
git rebaseってなに?
前回, 前々回に続いて
今回は, git rebase
について書く.
git rebase
は コミットログを綺麗にする 機能である.
git rebase
を使えば,
- 複数のコミットを1つにまとめる
- コミットのノードを変える
ことができる.
なにも考えずにgit commit
しまくって,
後からgit rebase
でログを綺麗にまとめる使い方が主流みたい.
どうやって使うの?
このサイトがとってもわかりやすい.
わかりやすすぎて正直書くことがない...
今後, 使いそうなものをpickupして書こう.
複数コミットをまとめる方法
基本的には, HEADからの距離
か 対象コミットのhash値
を使う.
# -i はinteractiveモード $ git rebase -i <hash値> or <HEAD~n>
例えば, 2つのコミットを1つにまとめる場合.
$ git log --oneline ... fl32k49 commit C r43ng9c commit B 2Ofncfb commit A $ git rebase -i HEAD~1 or $ git rebase -i r43ng9c
rebase
すると, editorが開く.
ここで, 各コミットの扱いを設定する.
# rebase すると開くファイル pick r43ng9c commit B pick fl32k49 commit C
ちなみに, rebaseファイルで使うコマンドは以下の通り.
- pick(コミットを採用)
- reword(コミットを採用するが、コミットメッセージを変更)
- edit(コミットを採用するが、ファイルを修正する)
- squash(一個前のコミットと合体させる)
- fixup(コミットメッセージを変更しない点以外、squashと同じ)
- exec(shellでコマンドを実行する)
ここで, コミットBにコミットCを結合する場合を考える.
pick r43ng9c commit B squash fl32k49 commit C # squashは s だけでもいい
このファイルを上書き保存すると, コメント編集用のファイルが開く. コメントを書き換えて保存するとrebase完了.
コンフリクト発生!!!
コミット同士を無理やり結合しているので, 衝突する場合がある.
その時, rebase
は一時中断されるのだが, その時に使うコマンドを記す.
- git rebase --continue(衝突などを解決した後に実行して、rebaseを続行する)
- git rebase --skip(エラーを無視する)
- git rebase --abort(rebaseをやめる)
注意すべきこと
rebase
はコミットを書き換えるわけではなく, 新しくコミット を行う
このため, リモートリポジトリのコミットを
git rebase
で書き換えてしまうと大量のconflictを引き起こす.
だから, リモートリポジトリに対しgit rebase
による編集は控えた方が良い.
リモートリポジトリが関係する場合は, git revert
でノードの編集を行うことが慣習になってる.
簡単ながら, git rebase
についてまとめた.
怖くないgit reset
git reset について
git reset... 怖い!!!
どのサイトに行っても, git resetは操作がログに残らないので, 慎重に!!
といった書き込みが多く, 少しgit reset
恐怖症になっていた.
そこで改めてgit reset
について再勉強した.
参考サイトから大事だと思う部分をpickupさせていただきました. 先人様様です.
git reset についてもまとめてみる - murankの日記
resetは何を操作しているのか.
それは, working tree
とindex
とhead
である.
対象 | 説明 |
---|---|
head | 最新コミットを表す代名詞 |
index | Addされたファイルを記憶する領域 |
working tree | 作業中のファイルを記憶する領域 |
操作対象を決める --soft と --hard オプション
resetには--soft
と--hard
というオプションがある.
これは, どの操作対象をresetするかを決めるオプションである.
オプション | HEAD | index | working tree |
---|---|---|---|
--soft | ○ | ||
no option | ○ | ○ | |
--hard | ○ | ○ | ○ |
つまり,
git reset <何を戻す?> <どこまで戻す?>
というコマンドである.
git resetの動作
何となく, resetの機能は掴めてきた.
とは言っても, 実際にどのように動作しているのかイメージしづらい.
ここを見ると, head, index, working treeの動きが視覚的に見てわかりやすい.
git resetを使う場面をケース別に考える.
1 : 間違えて必要のないファイルをindexに追加してしまったのでindexを消去したい. しかし, working treeを消したくない場合.
# indexをHEADの状態に戻す(headは同じ場所を指す). $ git reset HEAD
2 : 今のコミット上で編集済みのworking tree, indexがある.この2つを保持したまま, 直前のコミットに戻りたい.
# headだけを直前のコミットに戻す. $ git reset --soft HEAD^
3 : 一度全てを今のコミットの初期状態に戻したい!
# head, index, working treeをHEADの状態に戻す $ git reset --hard HEAD
4 : 直近のコミットは致命的なバグを含んでいる! n個前のコミットに全てを戻そう!!
# head, index, working treeをn個前のコミットに戻す $ git reset --hard n個前のコミットのhash値
例えば, コミットした後に直前のコミットにミスが含まれていることに気づいた場合,ケース2
で対処できる.
# index, working treeを保持したまま, 直前のコミットに移動 $ git reset --soft HEAD^ # 新しくコミットする $ git add . $ git commit -m "replace commit"
しかし, これをやると ログに編集作業が残らない .
git では編集ログはわかりやすく残す
ことが流儀とされているので, ログが残らない ことはタブーらしい.
だから, git reset
は云々... って言われているみたい.
まとめ
理解すれば, git reset
もそれほど怖くないとわかった.
あと, git reset
でやらかした場合は, git reflog
で全ての編集作業を辿れるので,このコマンドは覚えておいたほうがいいと思う.
以上, git resetについて簡単にまとめた.
gitのreset / rebase / revertがいまいち理解できてなかった件について
git reset / rebase / revert... 何が違うの?
gitは過去のコミットを自由に編集できることは知っていたけども,
いまいち理解できていなかった.
ちょっと触ってなんとなく感覚をつかんだのでメモ.
今後詰まったときのために, コマンド早見表でも書いておこう.
やりたいこと | 適正コマンド |
---|---|
ある地点のコミットまで完全に歴史を消して戻りたい! | reset |
あるコミットだけをなかったことにしたい!(ログは残す) | revert |
複数のコミットを1つのコミットとしてまとめたい!(ログ残らない) | rebase |
なぜかgemが環境変数http_proxyを読んでくれない理由
問題発生!!!
$echo $http_proxy http://my.proxy:port/ $sudo gem install *** ...(don't work)
がプロキシを通らない!!!
この理由がどっかのサイトに書いてあった.
sudoすると, bashrc(zshrc)を読まない.
つまり, bashrc(zshrc)
で設定している環境変数は読み込まれない。
と, いうことはhttp_proxy
が設定されない!
つまりプロキシ設定がなされない!
ということらしい。
sudo
するときはこれに気を付けたい。
mint17にbrewを入れる
パッケージ管理ソフトの話
世の中にはいろいろパッケージ管理ソフトがあるよねー。
パッケージ管理ソフトっていうとちょっとわかりづらい。 語弊や誤植を恐れずに言えば、google playやappleのapp store的に色んなソフトウェアを配信するためのソフトウェアととらえて問題ないと思う(少なくとも僕はそれくらいの理解で留まっている)。
細かく見ると, ソフトウェア開発にはバージョンが大きくかかわるのでかなり細かく管理されている。だから一緒というにはかなり無理があると思うが...
バージョン管理ソフトは 例えば, linuxならば yum, apt-getあたりが有名だし
macならば macportとかhomebrewが有名。
ぼくはmacユーザでなおかつミーハーなのでhomebrewが大好き。 依存関係あたりの解決が楽だし最近はbrew関連のエントリが多いので管理も楽。
この前先輩に聞いた話によるとlinuxにもbrewがあるらしい。。。
その名もlinux brew
。
まんまだよね。
linux brew
これはapt-getでインストールする。 linuxbrewを入れるエントリはここがわかりやすかった.
ここで少し躓く。
mintを入れたばっかりの僕はapt-get update
, apt-get upgrade
を繰り返してから上記エントリのapt-get installを実行したら通った。
...あと, このエントリのコマンド, ちょっと綴りがちがうっぽい... だから, コマンドは公式を参照しよう。
って感じで簡単にlinuxbrewが入りました。 linuxでもmacでもbrewが使えると移行が簡単になりそうだし、 胸が高鳴るね。