2018/05/20

[git]ブランチを消すとcommit履歴も消える

以前、gitでちまちまcommitするので、Pull Requestしてマージするときにまとめたい話をした。

http://hiro99ma.blogspot.com/2018/05/git-merge-squash.html


merge --squashするときれいになったので、こりゃいいや、と使っていた。

それはよかったのだが、てっきりこう思っていたのだ。

Pull Request用に作ったブランチにcommitがまとまっただけで、ローカルにはcommit履歴が残っている

しかし、ひさびさにcommit履歴を見てみると、squashでまとめたものしか残っていない。。。
あれ、commitの履歴って、全部残っているものではないの??


わからないときは、実験だ。


$ git init
$ touch test.txt
$ git add test.txt
$ git commit -m "first"
$ git checkout -b work/aaa
$ (test.txtを編集)
$ git commit -a -m "hello"
$ (test.txtを編集)
$ git commit -a -m "world"
$ (test.txtを編集)
$ git commit -a -m "morning"

image

$ git checkout master
$ git checkout -b aaa
$ git merge --squash work/aaa
$ git commit -m "squash merge"

image

$ git branch -D work/aaa

image


ああ、消えた!!!


$ git checkout master
$ git merge aaa
$ git branch -d aaa

image


むう、ブランチaaaがあったことすらわからないのか。
reflogには残っているけど、手元に残っているだけだろう。

image


fast-forwardだったから、ログに残っていないのだろうか?


fast-forwardを無効にしてやってみよう。

$ git config merge.ff false
(同じ手順でやっていく)
$ git merge --squash work/aaa
fatal: You cannot combine --squash with --no-ff.

ダメやん。

$ git merge --ff --squash work/aaa

これならできたけど・・・branchを消すと当然同じ結果になった。



そもそも、私は何がしたかったのかというと、以下を何とかしたかったのだ。

  • mergeしたという記録が見えない
    • ログで残すしかない?
  • --squashしたcommitの履歴が残らない
    • squashしたブランチを消さない?


--squashした記録は、ログで残すしかなさそうだ。
上でやった手順では commit -mとコメントを指定したのだが、-m なしで実行するとエディタが起動して、squash対象のcommit logを自動的に埋めん込んでくれていた。

ただ、これはこれで悩ましいな。
commitを頻繁にするのは、細かく履歴を残しているときもあるが、別の環境に移動する際にgit経由でやる場合もあるからだ。
「家に帰るのでcommit」とかも、しばしば。

まあ、ログを編集すれば良いのだけど、それだったら自分で「mergeした」と入れるだけでもよい気がする。


それよりも、問題は2番目だ。
commitはgitのどこかに必ず残っていて、ブランチはcommit idをつなげているだけだと思っていたのだ。
しかし、ブランチを削除してcommit履歴も消えると言うことは、commitはブランチに紐付いているということになる。
今までsquashせずにmergeしていて、commit履歴が全部残っていたので、そう勘違いしていたのだろう。


ブランチを消さなければ残るのだろうが、私はそこまでして履歴を残したいのだろうか?
「この行は何のためにこうしたんだっけ?」という確認をしたいときに見るかもしれないけど、そもそも記憶にないのにcommitログを見ただけでわかるとは思えない。
それよりは、mergeする単位を大きくしすぎないというか、1つの目的のためにmergeするようにしておけばよいのではなかろうか。


issueを上げて対応するためにブランチを作っていたのだけど、複数の問題が絡んでいる場合がある。
そうすると、1つのブランチでの作業が大きくなってしまう。。。

そんなときは、気付いた時点でさらにブランチを作っておけばよいのかもしれん。
あれこれ試して、自分というかチームにあう運用スタイルを作っていくしかなかろう。

2018/05/17

[android][ndk]MbedTLSをビルドしてみよう (4 挫折)

久々に挫折した・・・。
いや、「久々に挫折した」という記事を書きます。


前回からも修正を続け、よくわからないなりにMbedTLSの.aファイルを作ることができた。
それで終わらせれば良かったのだが、もともとは、複数のライブラリを使うライブラリがあるので、それをAndroid Studioからビルドしたい、ということだったのを思い出した。


MbedTLSだけのとき、build.gradleに-Dで設定をすることでビルドができていた。
それをset()で置き換えられるのであればよかったのだが、それは失敗している。

となると、他のライブラリをビルドするときにも、同じbuild.gradleの影響下で行うならば、同じ設定を使うことになる。
それは、まずい。
もしかしたら問題ないのかもしれないが、不安要素は残しておきたくない。

それを回避してできるように、ああでもないこうでもないと数日やっていたのだが、さすがに時間を掛けすぎている。
Android Studioを捨てれば、Makefileでビルドはできているので、そんなに難しいことはないだろう。



という流れで、「今回はこれで挫折して終わらせ、MakefileでAndroid用にビルドする」のが無駄が少なかろうと判断したのだ。
時間ができたらやり直そう、とは思うが・・・まあ、そういうのって、やらんよね。


ただ、まだ回避方法はあると思っている。

たとえば、今はMbedTLSに入っているCMakeLists.txtをそのまま使っているけど、それをコピーして、build.gradleに設定しないと有効にならなかった設定を編集してしまっておく、とか。


なぜやらなかったかといえば、正攻法ではない気がしたからだ。
しかし、正攻法ではない、というのは気分的なもので、実はそうするのが普通なのかもしれん。
ライブラリがアップデートされたときに、コピー&編集したCMakeLists.txtへの反映を忘れそうだから嫌だ、というだけかもしれない。


判断ができないのは、cmakeに詳しくないからだ。
付け焼き刃の知識で逃げようとしているのも、cmakeに詳しくないからだ。

では、cmakeを覚える気力があるかというと・・・無い。
なんだか、暗黙のルールが多い感じがして、気力が湧かないのだ。
まあ、そんなことをいえばmakeだって同じようなものかもしれないが、同じようなものを2つ覚えるには歳を取り過ぎたのだ。


という言い訳をして、今回は挫折した、で終わらせてもらおう。

2018/05/13

[android][ndk]MbedTLSをビルドしてみよう (3)

Android Libraryとして、既にあるCMakeLists.txtを取り込み、static libraryを作ってみる方法は分かったと思う。
まあ、単純なCファイル1つだけだったので、CMakeLists.txtもシンプルだったから問題が出なかったのだろう。

本題であるMbedTLSを取り込んだら失敗するんじゃないかと思うが、MbedTLSはAndroid OSでも動くと書いているので、案外とあっさり動くのかもしれない。

さあ、どちらだ?


はい、前者でしたー。

前回と同じようにcppディレクトリを作って、今回はその中にMbedTLSをcloneしたファイルを置き、ディレクトリの直下にあるCMakeLists.txtを「Link C++ Project with Gradle」で取り込んでみたのだが、その時点でエラーが発生した。

まあ、そうよね。。。

Android Studioに出ているログを見ると、testsあたりで失敗しているようだ。
うん、Arm用にビルドしたものは、たぶんテストできないだろうねぇ。


MbedTLSでライブラリを作るときにはlibraryディレクトリの中しか使わないので、そこにあるCMakeLists.txtを使ってみたがエラーになった。
こっちは、cmake_minimum_requiredがないとか。
では、オプションでMbedTLSをcloneした直下にあるCMakeLists.txtを制御するか、自分でCMakeLists.txtを作ってlibrary/CMakeLists.txtを呼び出すかがよいだろう。


うーん・・・・。
testsを呼び出さないようにするためのオプションは、"MSVC"らしい。
MSVCじゃないのに"MSVC"をセットするのはいやだから、後者にするか。


そう書いて、あれこれ試しながら数時間・・・。
ぜんぜんうまくいかない・・・。

L.138でエラーが出るのだが、私としてはそのルート自体を通さないつもりでいるのだ。
L.125のif文がfalseになるように、呼び出し元のCMakeLists.txtで「set(USE_STATIC_MBEDTLS_LIBRARY OFF)」としているのだが、効果があるようには見えない。


やはり、適当な解釈ではダメなのか。


少し、CMakeLists.txtのことを調べた。

「"MSVC"をセットしないと」と思っていたが、optionという項目はデフォルト値を決めているようだ。
setで設定すれば、そちらが上書きされるようである。

まあ、そう思ったからsetを使ってみたのだが、どうにもダメっぽい。
testsを通る箇所を全部コメントアウトすればライブラリができているから、そこだけのようだ。

今日はここまで。
github

[android][ndk]MbedTLSをビルドしてみよう (2)

前回の復習から。


NDKでMbedTLSをビルドしようとしたが、それ以外にもビルドしたいライブラリがあるので、まずは複数のC/C++ライブラリをビルドする用意をしておきたい。

Android Studioではcmakeを使えるようだし、MbedTLSもcmakeの設定があるので、取り込めばよさそうだ。

そのサンプルが、hello-libsであった。


hello-libsは、pre-builtされたライブラリを使うサンプルになっているが、2箇所変更するだけでpre-builtされたライブラリをビルドするところもやってくれるようになっている。


で、今回は、どうやればいいのかを調べるところからだ。


Android Studioの左下に「Build Variants」があるが、settings.gradleのコメントアウトを消すと"gen-libs"が出てきた。
設定値は"debug"である。


ツリーはこうなっている。
有効にした"gen-libs"が増えているから、settings.gradleが効いたのだろう。

image

このファイルでincludeしているのは、"app"と"gen-libs"で、両方ともフォルダがあり、中にbuild.gradleがある。
ライブラリたちを、同じように専用のフォルダを作ってまとめてしまうか、あるいはライブラリごとにフォルダを作るかだろう。

アイコンがappとは違っているので、そういうフォルダが作れるようだ。
どうも、Module、というもののようである。

image

ここで+アイコンをクリックしても良いのだろうが、ツリー画面のコンテキストメニューに「New>Module」もある。
出てくるウィザード画面はどちらも同じなので、どっちでもよいのだろう。


ウィザード画面を見たが、どれを選べばよいのだろう?
JNIになるからJava Libraryかと思ったが、違う気がする。

そもそも、最後はJNIになるし、MbedTLSも使いたいのだが、MbedTLSをJNI経由で直接扱いたいわけではなく、JNIで使いたいライブラリが中でMbedTLSを使っているだけなのだ。
gen-libsはJavaを持ってないので、同じようになっているはず。
build.gradleの「apply plugin」が"com.android.library"になっているから、Android Libraryを選べばよさそうだ。

作ってみると、アイコンも同じだったので、大丈夫だろう。
ここでは「build-libs」という名前で作った。
モジュール設定画面を見ていっても、testrunnerが入っているくらいで、gen-libsとあまり違いは無かった。


image


デフォルトで「java」というフォルダと、その中にパッケージのフォルダ階層が作られたが、それだけのようだ。

image

gen-libsの方には、cppの中にCMakeLists.txtがある。
build.gradleの中にCMakeLists.txtへのパスが書かれているので、同じようにやれば良いのだろう。
相対パスで書けるので、このフォルダごと別のプロジェクトに持っていってインポートするようなこともできるのかもしれん。


まず、javaディレクトリを削除して、cppディレクトリを作成。
その中に、const char*を返すだけのCソースとヘッダファイルを追加。
cmake関係は後回しにして、まずはjavaの痕跡を消しておきたかったのだが、syncっぽいことをしても消えないし、cppも出てこない。
testrunnerがあるせいかと思って消したが、効果無し。

だが、コンテキストメニューを出してみると「Link C++ Project with Gradle」が出てきた。
これで「Android Studio UIの使用」に書いてあることができるのだ。

image


では、cmakeの作業をせねばなるまい。
私はcmakeに詳しくないので、gen-libsの中にあるgmathのCMakeLists.txtをコピーして、"gmath"と書いてあるところを適当に置き換えた。
ライブラリやヘッダファイルがあった distributionディレクトリへのコピーもこの中でやるようなので、パスを変更する。

そして、作ったCMakeLists.txtを「Link C++ Project with Gradle」でリンクさせる。
CMakeLists.txtを指定するだけなのだが、相対パスへの変換もちゃんとやってくれる。


取りあえずビルドだ、ビルド。
とボタンを押してみるが、バイナリができないし、includeファイルのコピーもされていない。
ただ、distributionディレクトリの中にはディレクトリが追加されている。


そういえば、gen-libsをビルドできるようにしたとき、appのbuild.gradleにも変更を加えたのだった。
コメントを見ると、native libraryのビルドが行われないというissueが出ているらしく、その対応のように見える(今はv3.1.2だから直ってるかも)。
同じように追加すればビルドされるかと思ったのだが・・・ダメだ。
distributionディレクトリの中にディレクトリが追加されたのも、cmakeが行われたからというよりは、リンクする作業を行ったからやってくれただけのようにも見える。
distributionディレクトリの中を削除してビルドし直しても、gmathとgprefしか生成されないからだ。


設定ファイルを見直していくと、build.gradleに"android.defaultConfig.externalNativeBuild"が無いことに気付いた。
gen-libsだと"targets"にライブラリの名を書いているだけなのか?
appの方は"arguments"で、g++だかclangだかに与えるパラメータを書いているように見える。
よくわからんので、"targets"に今回追加したライブラリ名を書いてみた。
が、変わらず。


ツリーのビューを"Packages"に変更すると、追加したライブラリのパッケージ名が違っていることに気付いた。
AndroidManifest.xmlで変更するようだったので、書き換えた。


ここら辺までやると、distributionディレクトリの中に追加したライブラリとヘッダファイルがコピーされていた。
されていたけど、あれこれやりすぎて、どれが有効だったのかが分からん。。。


新規に、hello-libsに自分のライブラリを追加していこう。


  1. Android Studio v3.1.2を起動して、「Import an Android code sample」の"hello-libs"プロジェクトを選択。
  2. メニュー:File > Project Structure
    1. +アイコンをクリック
    2. "Android Library"を選択してNext
    3. 「Application/Library name」に"mklib"、「Package name」に"com.example.buildlibs"を設定して、Finish
    4. Android Studioがぐりぐり動き出すので、OKでダイアログを閉じて安定するまで待つ。
      1. ダイアログを閉じずに待っていたのだが、10分くらいしてもぐりぐりしたままだった
  3. 安定したら、もう一度Project Structureを開いて、左からmklibを選択し、「Dependencies」タブでjunitとtestrunner関係を削除して、OK
  4. ディレクトリ"mklib/src"にある"androidTest"、"test"、"main/java"を削除
  5. mklib/src/mainの中に"cpp"ディレクトリを作り、ソースファイルとCMakeLists.txtを置く
    1. ライブラリ名は"mklibtest"
  6. mklib/build.gradleの編集
    1. android.externalNativeBuildを追加し、cmake.pathにCMakeLists.txtのパスを追加
    2. android.defaultConfig.externalNativeBuildを追加し、cmake.targetsに"mklibtest"を追加
      1. これは、コンテキストメニューの「Link C++ Project with Gradle」から行ってもよい
    3. testInstrumentationRunnerの行を削除
  7. app/build.gradle(これはやらなくてもよいかもしれん)
    1. tasks.whenTaskAddedに、"gen-libs"のまねをして"mklib"を追加
    2. tasks.whenTaskAddedのコメントアウトを戻す
  8. メニュー:Build > Make Project


これで、distribution/mklibtestにヘッダファイルとライブラリがコピーされた。
ライブラリは今回staticにしていて、libmklibtest.a、という名前になった。

ここまでをgithubに上げておこう。


さて、ここまででライブラリはビルドできた。
アプリで使うには、app/build.gradleに追加したり、JNIを作ったりせんといかんが、今回の目的ではないのでよかろう。

次回はMbedTLSをビルドできるようにしたいが、すごく苦労しそうな気がする。

2018/05/12

[android][ndk]MbedTLSをビルドしてみよう (1)

久々にAndroidだが、アプリではなくNDKだ。


LinuxでMbedTLSを使ったアプリを作ったのだが、それをAndroidで動かしたい。
もちろん、私が作っているので、C言語だ。
理想は、画面だけAndroidのJavaなどで作って、機能的な部分はNDK/JNIで今作っているものを流用したい。

その前に、まずMbedTLSをAndroidでビルドできるのか?というところが課題となっている。
なお、私はNDKはほとんど知識がないという前提だ(実際、ないのだが)。


https://tls.mbed.org/features

一番下に移植性のことが書いてあり、Android OSも入っている。
じゃあ、ビルドは簡単かもしれん。


まず、Android Studio v3.1.2でプロジェクトを作る。
Lollipopがデフォルトで出てきたので、そのまま進める。
ただ、C++だけはチェックしておく。

image


ビルドして動かすと、画面の真ん中に「Hello from C++」とだけ表示される。
C++のnative-lib.cppで文字列を返して、それをJavaで出力させているのだ。

ビルドするソースファイルの指定は、CMakeLists.txtでやっている。
cmakeを使うようだ。
Android.mkなんかは、もう使わなくなったのかな?


NDKやcmakeは、インストールされていなければビルドエラーと一緒にリンクも出てきて、それをクリックするとインストールしてくれる。
進化したものだ。。。


MbedTLSもcppフォルダ内にcloneしておこう。
https://github.com/ARMmbed/mbedtls


cloneしたものを"android"でgrepしたが、ヒットしない。。。
ビルドしやすいようなサポートはやってないということか。


新規でC/C++ファイルをAndroid Studioに作成していくのであれば、既存のCMakeLists.txtにファイル名を記載していけばよいのだろう。
しかし、既存のライブラリを取り込むのであれば、何か簡単な方法があるのではないだろうか?

今回はMbedTLSだけだが、それ以外の既存ライブラリを使いたいことの方が多いだろう。
そのとき、全部のライブラリに関するファイル名を列挙するのも嫌だし、そもそもライブラリを1つにまとめることになってしまうのが嫌だ。

既存のライブラリは、その単位で扱いたいものである。


Android StudioのUIを使って、cmakeなりndk-buildなりでビルドできるようにしたプロジェクトをリンクできるそうだ。
https://developer.android.com/studio/projects/add-native-code?hl=JA#link-gradle

ライブラリごとにビルドするスクリプトなどを用意しておけば、それぞれプロジェクトをリンクさせるだけでよい、ということではなかろうか?


Android StudioのAndroidビューから、appなどでコンテキストメニューを表示させると「Link C++ Project with Gradle」という項目が出てきそうなことが書いてあるのだが、メニューにはない。
既にC++が使えるプロジェクトにしているから、出てこないのだろうか?

build.gradleにcmakeの項目があったので、pathをもう1つ追加してみたが、ビルドエラーになった。
なんとなく、1つしか書けないような気がする。


他のCMakeLists.txtを取り込むのは、こちらか?
https://developer.android.com/studio/projects/configure-cmake#include-other-cmake-projects

まねをしようとしたが、何をしたらまねになるのかが分からん。。。



こちらが、複数のライブラリを扱った場合のサンプルのようだ。

https://github.com/googlesamples/android-ndk/tree/master/hello-libs


pre-builtと書いてあるので、既にビルドされたライブラリを取り込むのかと思ったが、ソースファイルもあるな。
どっちを使っているのだろう?


  • hello-libs: app/src/main/cpp/CMakeLists.txt + ソースファイル
    • gen-libs: gen-libs/src/main/cpp/CMakeLists.txt
    • lib_gmath: gen-libs/src/main/cpp/gmath/CMakeLists.txt + ソースファイル(static)
    • lib_gpref: gen-libs/src/main/cpp/gpref/CMakeLists.txt + ソースファイル(shared)
    • log: NDK付属


プロジェクトを開くと、こういう風に見える。

image


組み込むライブラリのソースファイルは見えない。
distributionディレクトリを削除してリビルドしたら、やはりビルドに失敗した。


READMEにも書かれているが、ビルドしたものをdistributionにコピーしているようだ。
もし再生成したいなら、setting.gradle, app/build.gradleを変更すれば良いそうだ。


setting.gradle

include ':app'

// To generate libs used in this sample:
//   1) enable the gen-libs at end of this file
//   2) enable module build dependency in app/build.gradle
//   3) build the app's APK in Android Studio or on command line
//   4) undo step 1) and 2) above
// include ':gen-libs'

app/build.gradleは、一番最後がコメントアウトされていたから、それか?

tasks.whenTaskAdded { task ->
    if (task.name == 'externalNativeBuildRelease') {
        task.dependsOn ":gen-libs:externalNativeBuildRelease"
    } else if (task.name == 'externalNativeBuildDebug') {
        task.dependsOn ":gen-libs:externalNativeBuildDebug"
    }
}


両方を有効にしてビルドし直すと・・・おお、distributionディレクトリが復活している。
次は、これを理解するところから始めよう。

先は長いな・・・。