2018/07/21

[git失敗]最新のpushから1つresetして編集

gitで起こしてしまった、現在進行形のお話。


別の場所で作業するので、一旦pushした。
かなり適当な内容なので、pushよりはファイルごとコピーしておきたいくらいだったのだが、面倒になったのでpushした。


で、今見直したところ、あまりにもいい加減な変更だったので、前のcommitは止めようと思った。
が、そのままではダメだけど、書き換えれば使い物にならないわけでもなさそうだったので、差分を見ながら書き換えようとした。
私はvscodeを使っているのだが、差分が見やすいので助かるのだ。


そして、何も考えずにこうやった。

$ git pull
$ git reset --soft HEAD^

そうすると、ソースファイルはpushしたものが残っているが、差分としてはまだ反映されていないような形になるので、最後に変更した箇所が見える。


無事に変更を終え、push。

$ git push

error: failed to push some refs to 'git@github.com:xxxx.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

エラーらしい。
resetしたからだろう。

$ git pull

CONFLICT (content): Merge conflict in xxxxxxx
Automatic merge failed; fix conflicts and then commit the result.

コンフリクトした。

そして困ったことに、オートマージされたので、前回削除したり追加したりしてコンフリクトしなかったところが反映されてしまったのだ。

「gitでやったらいかんこと(その1)」というところか。。。



gitだけで解決できそうだけど、調べるのが面倒だったので、手動で対応させることにした。


まず、今のコンフリクトしたファイルを適当に修正して、別の場所にコピー。
そして、ローカルでやった修正をなかったことにするため、git reset --hard HEAD^。
pushした内容に戻すため、git pull。
そして、その修正はいらないので、git revert HEAD。

あとは、移動させたファイルとオリジナルのファイルをWinMergeで比較しながら手動マージ。
アナログじゃろう?


今回はコンパイルエラーが出たので気付いたが、もっとぼーっとしていたら、オートマージに気付かなかったかもしれない。


さて、今回調べたいのは、どうするのが楽だったのか、だ。
やりたかったのは「最新pushを1つ前に戻しつつ、最新pushのソースも見ながら編集したい」だ。


うん、そうだね。

$ git pull
$ 差分を見たいソースファイルをどこかにコピー
$ git revert HEAD^
$ 差分を見ながら編集

ファイルをどこかに置けばよかっただけか。


ただ、vscode+GitLensだと、履歴と比較する機能がありそうだ。
Working Treeとも比較ができるので、次回はそれを使おう。

image

2018/07/09

[java]64bit値を扱うのにBigIntegerもある

Cからもらったunsignedな64bit値をビット演算するだけでよいかと思っていたら、数値としても扱う箇所があるのに気付いた。

うーん、uint64_tはプリミティブだから、Javaもlongで受け取って、中で数値に変換できないものか。。。


調べていると、BigIntegerというものがあった。
これを使って、引数はlongで受取り、中で16進数文字列に置き換え、それをBigIntegerにすればよさそうだ。

https://gist.github.com/hirokuma/f365c2a85dae3962ff3d5f19562b9029/a0e48bef4148691ce3fcc135c9911662ce21afc3

結果

long: -81985529216486896
long 2byte: -2
BigInteger: 18364758544493064720
BigInteger 2byte: 254

意味も無くビットシフトなんかさせてみたが、ちゃんと正の数として扱っている。

文字列は好きではないのだが、C側でやらなくてよいので、まあよかろう。

2018/07/07

[java]uint64_t相当のデータをビット演算したい

JNIを使って、CとJavaをつなごうとしている。
C側でuint64_tを使っている箇所があるので、Javaで何とかしなくてはならん。


Javaのlongは64bitなのだが、Javaにはunsignedがないので、たぶん最上位ビットが立ってたら負の数と思うだろう。
byteもそうだったし。

確認しておくべし。


longだけではなく、BigDecimalも使ってみよう。

https://gist.github.com/hirokuma/c8a67b1db8e44ce45236942088d81865/1aaa1e1893b3f83f9d1d14d494b1d4902da454ee

同じようなことをさせたいが、BigDecimalにビットシフトがないので、割り算で代用。
処理が遅くなりそうだが、まあ動作確認だからな。

結果

big decimal 2byte: fe
long 2byte: fffffffffffffffe

やはり、そうなるのか。
BigDecimalは演算してるから2byte分きっちりになったが、longはビットシフトで符号が引きずられたんだ。


そういえば、Javaには「>>>」があったな。

https://gist.github.com/hirokuma/c8a67b1db8e44ce45236942088d81865/0161393d1d388b1ad97754dbc84d3efb2eff8370

結果

big decimal 2byte: fe
long 2byte: fe

おお!
なんか、うれしくなりますな。


これはHEXで出しているから、変数として正負どちらになっているかわからん。
数字で出力させて確認。

BigDecimal : 正
longで>>:負
longで>>>:正

まあ、予想通りか。
当然だが、これをbyte型にキャストして代入すると、どれも負の数になる。

2018/06/30

[github]古いgistのURLを知りたい

ちょっとしたソースコードを載せるのに、githubのgistをしばしば使っている。
便利なのだが、編集すると、その前の内容を確認するのが難しい。
いや、差分はわかるのだけど、githubのcommit historyみたいに、その時の内容だけが見たいのだ。


どうやら、その時のハッシュが分かれば載せられるらしい。
例えば、これはzlibサンプルのrevision1のURLだ。

https://gist.github.com/hirokuma/0f038adc04c1ec38ba6c01f8b2db4fb5/4b920d2c12d7893c23a93343cd74d116de731077

URLの最後がハッシュ値なのだが、どうやって取ってくれば良いのだろう?


・・・というのを、長々と調べていた。。。
いや、なに、"Revisions"というタブがあるのは知っていたよ。
そこで差分も出てきているのは知ってる。


ただ、そこに全Revisionの差分が出ているということにまでは気がつかなかったのだ。
下の方にスクロールさせると、過去の差分があるし、Viewボタンまで付いている。
Viewをクリックすれば、そのときのURLが出てくるのだな。


はは、ははは。
私は乾いた笑いを飲み込むしかなかった。

[c/c++]zlibを使ってみよう

zlibを使わなくてはならなくなった。
名前はよく聞く・・・。
リンクするときに「-lz」と短く済むので、印象に残っている。

よく使われているので、使い方も難しくは無いだろう。


WSLのUbuntu 16.04で試す。

sudo apt install zlib1g-dev


zlibのマニュアルは、こちら。

zlib 1.2.11 Manual https://zlib.net/manual.html


ただ・・・圧縮と解凍さえ分かればよいので、使い方だけ見ておこう。
やりたいのは、ファイルではなくRAMで持っているデータなので、そこは読み替えていく。

zlib Usage Example https://zlib.net/zlib_how.html

https://zlib.net/zpipe.c


まず、テストデータを作ろう。
xxdというコマンドを使うと、ファイルをC言語の配列形式にしてくれる。
便利だ・・・。

xxd -i hirokuma.png > hirokuma.h


Exampleでは、CHUNKサイズのバッファin[]とout[]を準備している。
def()が圧縮、inf()が展開。
どちらも、二重のdo-while()になっている。

まず、def()から。
外側のdo-while()は、ファイルをCHUNKずつ読み取るためのループ。
内側のdo-while()は、deflate()を実行して、avail_outが0になっている間はループする。
「keeps calling deflate() until it is done producing output」と書いてあるので、avail_outが0ということは処理が継続しているという意味なのだろう。

圧縮中、deflate()の引数はZ_NO_FLUSHで、最後だけZ_FINISHにする。
ストリーミングで圧縮するから、ある程度データが揃うまで吐き出さないのだろうね。

簡単なサンプルを作った。
圧縮のみで、圧縮しているデータは、うちのアイコン(PNG)だ。
PNG画像もzlibで圧縮されているようだが、気にするまい。

https://gist.github.com/hirokuma/0f038adc04c1ec38ba6c01f8b2db4fb5/4b920d2c12d7893c23a93343cd74d116de731077

image

まあ、データは何でもよいのだが、内側のdo-while()がどういう周り方をするのかが気になった。

$ gcc -o tst zlib_comp.c -lz
$ ./tst
p=0x6010a0
   avail_out=1022
p=0x6014a0
p=0x6014a0
   avail_out=1024
p=0x6018a0
p=0x6018a0
   avail_out=1024
p=0x601ca0
p=0x601ca0
   avail_out=1024
p=0x6020a0
p=0x6020a0
   avail_out=1024
p=0x6024a0
p=0x6024a0
   avail_out=1024
p=0x6028a0
p=0x6028a0
   avail_out=1024
p=0x602ca0
p=0x602ca0
   avail_out=0
   avail_out=0
   avail_out=0
   avail_out=0
   avail_out=0
   avail_out=0
   avail_out=0
   avail_out=103
p=0x603030

next_inは自動的に進むようだから、全データがRAM上にあるなら、初期化だけしておけばよさそうだ。


内側のループが回ったのは、最後だけだ。
何かルールがあるのだろうか?
もし最後だけなら、通常は内側のdo-while無しでもよいのかもしれんが、これだけじゃわからんな。


というわけで、マニュアルを見てみよう。
けっこう、見づらい・・・。

https://zlib.net/manual.html#Basic

If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out).

In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that avail_out is greater than six to avoid repeated flush markers due to avail_out == 0 on return.

avail_outが0の場合は、flushオプションを同じ状態で呼び続けなくてはならん。
ということは、Z_FINISHの場合だけではないということか。


"more output space (updated avail_out)"と書いてあるが、サンプルではavail_outを再設定しているだけで、out[]のサイズは同じだな。
そもそも、fwirte()するサイズは「CHUNK - strm.avail_out」だから、8KBくらいのデータでは外側のループで回っているときはout[]がほぼ出力されず、最後にZ_FINISHしたときに書き込まれていることになる。


flushオプションもいくつか種類があるようだが、圧縮したデータそのものがほしい場合はサンプル通りにやっておけばよいんじゃ無かろうかね。


展開する方も、同じようにやった。

https://gist.github.com/hirokuma/0f038adc04c1ec38ba6c01f8b2db4fb5/2ae53cdeb15bc6e79ed4c65474040a3327b5dbad

$ ./tst
exec: comp
retval=1
exec: decomp
retval=-5
retval=-5
retval=-5
retval=-5
retval=-5
retval=-5
retval=1

追加したのは、decomp()。
-5は、Z_BUF_ERROR

サンプルではエラー処理していないし、最後に1(Z_STREAM_END)が出るところから見ると、普通なんだろう。

Z_BUF_ERROR if no progress was possible or if there was not enough room in the output buffer when Z_FINISH is used.

Note that Z_BUF_ERROR is not fatal, and inflate() can be called again with more input and more output space to continue decompressing.


APIに何があるのか読みづらかったので、こちらの解説記事の方がよさそう。
http://s-yata.jp/docs/zlib/

compress()なんてあったのか・・・。
https://zlib.net/manual.html#Utility