履歴からブランチをチェックアウトする Gitエイリアス
業務中に1日に3,4個のブランチを行ったり来たりする時が往々にしてあり、タスクごとにブランチ名を記憶して切り替えるのは、記憶力の悪い自分にとっては非常にストレスフルな作業でした。
そこで、ブランチ移動履歴からブランチを選択してブランチ切り替えできる Gitエイリアスを設定してみたら、かなり快適に作業ができるようになりました!
[alias] history = "!f() { git --no-pager reflog | awk '$3 == \"checkout:\" && /moving from/ {print $8}' | awk 'a[$0]++ == 0' | head | peco | xargs git checkout; }; f"
エイリアスの詳細
操作履歴の一覧を取得
$ git --no-pager reflog 1de01c5 (HEAD -> master) HEAD@{0}: checkout: moving from test-3 to master 71d27e1 (test-3) HEAD@{1}: commit: commit in test-3 1de01c5 (HEAD -> master) HEAD@{2}: checkout: moving from master to test-3 1de01c5 (HEAD -> master) HEAD@{3}: checkout: moving from test-2 to master 45b93f3 (test-2) HEAD@{4}: commit: commit in test-2 1de01c5 (HEAD -> master) HEAD@{5}: checkout: moving from master to test-2 1de01c5 (HEAD -> master) HEAD@{6}: checkout: moving from test-2 to master 4ddaa52 (test-1) HEAD@{7}: checkout: moving from test-1 to test-2 4ddaa52 (test-1) HEAD@{8}: commit: test-1 commit 1de01c5 (HEAD -> master) HEAD@{9}: checkout: moving from master to test-1 1de01c5 (HEAD -> master) HEAD@{10}: checkout: moving from test-1 to master 1de01c5 (HEAD -> master) HEAD@{11}: checkout: moving from master to test-1 1de01c5 (HEAD -> master) HEAD@{12}: commit (initial): first commit
reflog
はデフォルトでページャされるので、 --no-pager
を指定して ページャせずに出力をパイプで渡すようにしています。
移動履歴のブランチを抽出
$ git --no-pager reflog | awk '$3 == "checkout:" && /moving from/ {print $8}' master test-3 master test-2 master test-2 test-1 master test-1
$3 == "checkout:"
でチェックアウト操作のみに絞り込み、 /moving from/
にてブランチ移動だけを対象として、{print $8}
で移動先のブランチを出力しています。
ブランチ名の重複を削除
$ git --no-pager reflog | awk '$3 == "checkout:" && /moving from/ {print $8}' | awk 'a[$0]++==0' master test-3 test-2 test-1
uniq
を利用した場合は sort & uniq
を実行する必要があり、処理が多くなってしまうので、awk
で重複を排除しています。
ブランチを選択して切り替え
最後に peco に出力を渡して、選択されたブランチにチェックアウトすれば完了です。
$ git --no-pager reflog | awk '$3 == "checkout:" && /moving from/ {print $8}' | awk 'a[$0]++==0' | head | peco | xargs git checkout master test-3 test-2 test-1
対象ブランチを移動履歴の最新10件のみに絞り込むために、head
を途中で挟んでいます。
対象のブランチを上限したい時は head -n {行数}
で調整が可能です。
さいごに
想像していた以上に便利に使えていて満足です。
余談ですが、シェルスクリプトのワンライナーはパーツが組み合わさりデータが少しずつ整理されていく過程に美しさを感じて非常に気持ち良いです!
DockerでMongoDBをインストールして試してみる
DockerでMongoDBをインストールして試してみる
MongoDBとはドキュメント指向でJSONライクな形式でデータを格納するデータベースである
簡単に触ってみようと思いDockerでインストールしたので、メモを残しておく
イメージの取得
Docker Hubにイメージが置いてあるので、そこからイメージを取得する
$ docker pull mongo
コンテナの生成
取得したイメージからコンテナを生成する。
--name some-mongo
はコンテナのエイリアスを指定している。
-d
オプションでは、コンテナのバックグランド実行を指定している。
最後のmongo
で生成元のイメージを指定している。
$ docker run --name some-mongo -d mongo
コンテナを確認してみると、無事に生成されているのが確認できる。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 61c8b5f2f4af mongo "/entrypoint.sh mongo" 24 minutes ago Up 24 minutes 27017/tcp some-mongo
コンテナに接続してMongoDBを試してみる
コンテナの生成が完了したので、後はコンテナの中に入り、mongo
コマンドを実行することで、MongoDBを色々試すことが出来る状態になります
$ docker exec -it some-mongo bash
root@61c8b5f2f4af:/# mongo MongoDB shell version v3.4.2 ... >
MongoDBの簡単な使い方はMongoDB超入門などを参照すると分かりやすいです
Elixir + Phoenix でお手軽にJSONを返すWebAPIを構築
この記事はHamee Advent Calendar 2016の15日目の記事です。
今回は、ElixirのWebフレームワークPhoenixを使って、QiitaのAdvent Calendar 2016ランキングをJSONで返すWebAPIを構築してみます。
調べているとDBを利用する場合の記事が多く、DBを利用しない場合に上手く動作しなかったので、DBを使わない場合のの実装方法をまとめておきます。
やること
前提条件
- Elixirの環境構築済み
インストール
詳細は公式のインストールガイドをご参照ください。
Phoenixのインストール
以下のコマンドでPhoenixをインストールします。
$ mix archive.install https://github.com/phoenixframework/archives/raw/master/phoenix_new.ez
node.jsのインストール
Phoenixではjavascript, cssのcompileにbrunch.ioを利用しているため、node.js(>= 5.0.0)が必要になります。
macの場合はhomebrew経由でインストールできます。
$ brew install node
プロジェクトの作成
プロジェクトを作成していきましょう。
今回はスクレイピング結果をそのままJSON形式で返すAPIサーバーで、DBとViewは不要なので、オプションでその旨を指定しておきます。
$ mix phoenix.new --no-ecto --no-brunch --no-html web_api
ルーティングの設定
web/router.ex
に、ルーティングの設定を追記していきます。
get "/ranking", CalendarController, :index
が新しく追記した部分です。
/api/ranking
にGETリクエストがあった際に、CalendarController
のindex
アクションを実行します。
web/router.ex
defmodule WebApi.Router do use WebApi.Web, :router pipeline :api do plug :accepts, ["json"] end scope "/api", WebApi do pipe_through :api get "/ranking", CalendarController, :index end end
ライブラリのインストール
コントローラーの実装に入る前に、スクレイピングで使用するライブラリの依存関係をmix.exs
に追記していきます。
mix.exs
defmodule WebApi.Mixfile do use Mix.Project def project do [app: :web_api, version: "0.0.1", elixir: "~> 1.2", elixirc_paths: elixirc_paths(Mix.env), compilers: [:phoenix, :gettext] ++ Mix.compilers, build_embedded: Mix.env == :prod, start_permanent: Mix.env == :prod, deps: deps()] end # Configuration for the OTP application. # # Type `mix help compile.app` for more information. def application do [mod: {WebApi, []}, applications: [:phoenix, :phoenix_pubsub, :cowboy, :logger, :gettext, :httpoison, :floki]] end # Specifies which paths to compile per environment. defp elixirc_paths(:test), do: ["lib", "web", "test/support"] defp elixirc_paths(_), do: ["lib", "web"] # Specifies your project dependencies. # # Type `mix help deps` for examples and options. defp deps do [ {:phoenix, "~> 1.2.1"}, {:phoenix_pubsub, "~> 1.0"}, {:gettext, "~> 0.11"}, {:cowboy, "~> 1.0"}, {:httpoison, "~> 0.10.0"}, {:floki, "~> 0.11.0"} ] end end
コントローラーの実装
最後にQiitaのAdvent Calendar 2016ランキングからデータを抽出して、JSON形式で返す処理を実装していきます。
JSON形式で返す処理はjson conn, calendars
の部分です。
このように記述することで、PhoenixがJSON形式に変換してレスポンスを投げてくれます。
web/controllers/calendar_controller.ex
defmodule WebApi.CalendarController do use WebApi.Web, :controller def index(conn, _params) do calendars = ranking() json conn, calendars end # Advent Calendar 2016ランキングからランキング情報を抽出 defp ranking() do url = "http://qiita.com/advent-calendar/2016/ranking/subscriptions" HTTPoison.start res = HTTPoison.get! url %HTTPoison.Response{status_code: 200, body: body} = res body |> Floki.find(".adventCalendarRankingListItem-top, .adventCalendarRankingListItem") |> Enum.map(&parse_item/1) end # DOM要素からランキング、タイトル、ページリンクを抽出 defp parse_item(item) do rank = Floki.find(item, ".adventCalendarRankingListItem_rank") |> Floki.text title_link = Floki.find(item, ".adventCalendarRankingListItem_name > a") title = Floki.text(title_link) url = "http://qiita.com#{Floki.attribute(title_link, "href")}" %{rank: rank, title: title, url: url} end end
レスポンスを取得してみる
サーバーを起動して、レスポンスを取得してみます。
$ mix compile $ mix phoenix.server
$ curl "http://localhost:4000/api/ranking" | jq [ { "url": "http://qiita.com/advent-calendar/2016/docker", "title": "Docker", "rank": "1" }, { "url": "http://qiita.com/advent-calendar/2016/git", "title": "Git", "rank": "2" }, { "url": "http://qiita.com/advent-calendar/2016/go", "title": "Go", "rank": "3" }, { "url": "http://qiita.com/advent-calendar/2016/job", "title": "転職", "rank": "4" }, { "url": "http://qiita.com/advent-calendar/2016/deeplearning", "title": "DeepLearning", "rank": "5" }, { "url": "http://qiita.com/advent-calendar/2016/vim", "title": "Vim", "rank": "6" }, { "url": "http://qiita.com/advent-calendar/2016/ruby", "title": "Ruby", "rank": "7" }, { "url": "http://qiita.com/advent-calendar/2016/python", "title": "Python", "rank": "8" }, { "url": "http://qiita.com/advent-calendar/2016/muscle", "title": "筋肉", "rank": "9" }, { "url": "http://qiita.com/advent-calendar/2016/nodejs", "title": "Node.js", "rank": "10" }, { "url": "http://qiita.com/advent-calendar/2016/go2", "title": "Go (その2)", "rank": "11" }, { "url": "http://qiita.com/advent-calendar/2016/ouch-hack", "title": "おうちハック", "rank": "12" }, { "url": "http://qiita.com/advent-calendar/2016/go3", "title": "Go (その3)", "rank": "13" }, { "url": "http://qiita.com/advent-calendar/2016/vim2", "title": "Vim (その2)", "rank": "14" }, { "url": "http://qiita.com/advent-calendar/2016/se", "title": "システムエンジニア", "rank": "15" }, { "url": "http://qiita.com/advent-calendar/2016/python_python", "title": "Python", "rank": "16" }, { "url": "http://qiita.com/advent-calendar/2016/docker2", "title": "Docker2", "rank": "17" }, { "url": "http://qiita.com/advent-calendar/2016/tensorflow", "title": "TensorFlow", "rank": "18" }, { "url": "http://qiita.com/advent-calendar/2016/swift", "title": "Swift", "rank": "19" }, { "url": "http://qiita.com/advent-calendar/2016/job2", "title": "転職(その2)", "rank": "20" } ]
ターミナルで実行した直前のコマンドをコマンドだけでクリップボードにコピーする方法
結論から言うと、以下のシェルコマンドで目的が達成できました。
fc -ln | tail -n1 | pbcopy
上記の流れとしては、最初に【fc】コマンドにて実行コマンドの履歴を表示します。
その次に、【tail】コマンドで最後の1行のみを表示することで、直前の実行コマンドを標準出力に表示します。
最後に出力された内容を【pbcopy】コマンドでクリップボードにコピーしています。
ここで登場している【fc】コマンドはコマンドの再実行やリスト表示を行うことが可能なコマンドです。
詳細はfc - コマンドを再実行・コマンド履歴をリスト表示 - Linuxコマンドを確認してください。
Scalaの軽量フレームワークScalatra
ScalatraはSinatraに影響を受けたScalaの軽量Webフレームワークです。
簡単に触ってみたので、導入手順をメモしておきます。
giter8のインストール
ScalatraはScalaのスキャフォールディングツールgiter8
を使って、テンプレートからプロジェクトを生成します。
インストールはhomebrewを使って行います。
$ brew update && brew install giter8
プロジェクトの雛形生成
先ほどインストールしたgiter8
を使って、Scalatraのプロジェクトを作成します。
$ g8 scalatra/scalatra-sbt
生成されたプロジェクトのソースコードを確認してみます。
アプリケーションのメインとなるソースコードはsrc/main/scala/com/example/app/MyScalatraServlet.scala
になります。
MyScalatraServlet.scala
の部分は、g8で雛形を作成する際に入力したファイル名になっています。
package com.example.app import org.scalatra._ class MyScalatraServlet extends SimplescalatraStack { get("/") { <html> <body> <h1>Hello, world!</h1> Say <a href="hello-scalate">hello to Scalate</a>. </body> </html> } }
このソースコードは、サーバーのルート(/)にアクセスした際に記述されたHTMLをレスポンスとして返す処理が書いてあります。
HTMLページを表示してみる
以下のコマンドでサーバーを起動します。
$ sbt > ~jetty:start
上記コマンドの~
を付けることでソースコードの変更時にサーバーを自動で再起動されるようになります。
毎回起動し直すのは、面倒なので~
を付けることをお勧めします。
http://localhost:8080にアクセスして、HTMLページが表示されれば導入完了です。
さいごに
Scalatraは非常にシンプルに使うことができるので、簡単なREST API などを実装するのに向いているのかなと思います。
Scala.jsを触ってみた
Scala.jsというScalaで記述な可能なAltJSがあったので、興味本意で導入部分だけですが、触ってみました。
導入
早速、Scala.jsの導入を行っていきます。
プロジェクトの作成
activotr new
コマンドでテンプレートからScalaのプロジェクトを作成します。
$ activator new Fetching the latest list of templates... Browse the list of templates: http://typesafe.com/activator/templates Choose from these featured templates or enter a template name: 1) minimal-akka-java-seed 2) minimal-akka-scala-seed 3) minimal-java 4) minimal-scala 5) play-java 6) play-scala (hit tab to see a list of all templates) > 4
sbtの設定
project/plugins.sbt
に以下を追記
addSbtPlugin("org.scala-js" % "sbt-scalajs" % "0.6.12")
build.sbt
に以下を追記
enablePlugins(ScalaJSPlugin) name := "Scala.js Tutorial" scalaVersion := "2.11.7" // or any other Scala version >= 2.10.2
Hello Worldを表示するアプリケーションの作成
src/main/scala/com/example/Hello.scala
を作成
package com.example import scala.scalajs.js.JSApp object Hello extends JSApp { def main(): Unit = { println("Hello world") } }
sbt
を起動して上記のファイルを実行してみます。
$ sbt > run [info] Running com.example.Hello Hello world [success] Total time: 6 s, completed 2016/10/03 23:45:15
JavaScriptファイルに変換
fastOptJS
コマンドでScalaのファイルをJavaScriptのファイルに変換します。
> fastOptJS [success] Total time: 2 s, completed 2016/10/03 23:46:46
JavaScriptファイルを読み込む
実際にHTMLを作成して、先ほど生成したJavaScriptファイルを読み込んでみます。
index.html
を以下の内容で作成します。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <script src="./target/scala-2.11/scalajs-fastopt.js"></script> </head> <body> <script type="text/javascript"> com.example.TutorialApp().main() </script> </body> </html>
index.html
でブラウザで読み込んでみます。
無事に読み込まれ、コンソール上に"Hello World"と表示されています。
さいごに
正直、型安全をメリットとするならTypeScriptの方で良いなとは思いました。