神奇的 Git Subtree

一直以來只知道 git 可以透過 git-submodule 管理巢狀 git 專案。也就是一個大專案中有小專案,而這兩個專案要分別用 git 做版本控制的狀況。這會發生在專案有可以抽出來跟其他專案共用的部分,或是專案需要引入一個外部現有的 git 專案的時候。舉例來說,我的 vimrc 裡面有 snippets,這個 snippets 是值得被另外拉出來成為一個專案的。又或是像 hexo,我要自訂 theme,所以我 fork 了 icarus 這個 theme 來改,但需要把它放進我的大 hexo 專案中。

用 submodule 的做法其實滿麻煩的,它的原理是:大專案紀錄某目錄是一個 submodule,所以大專案就不 track 該目錄的變更,而是 track 該目錄的 HEAD commit。該目錄的內容變更則交給他自己 track。也就是說,如果修改了小專案的內容,需要先去小專案裡面把修改 commit 進去後,再去大專案把小專案的新 commit id 給 commit 進去。光用講的都覺得混亂…

有天發現了 git-subtree 是個可以解決類似問題的工具,但差別在於 subtree 不需要事先指定哪個目錄是子專案,只要在需要的時候處理即可。什麼是需要的時候呢?

  1. 要把子專案切出去的時候(通常只會切一次)
  2. 要把子專案在本地端的變更丟出去的時候
  3. 要把一個專案放進來變成子專案的時候(通常只會放一次)
  4. 要把子專案在外面的變更拉進來的時候

除了「需要的時候」以外,子專案就像是(其實根本就是)大專案的一部分,用原有的方式去操作 git 即可,相當單純!

我覺得以我找到的資料來說,Git SubTree 共編 Library 這篇文章是講得比較清楚易懂的,有些別的文章會舉例錯誤或不知所云….XD 不過我認為需要搭配 man page 服用會比較能理解。

下面就以 hexo 為例,練習把原本用 git-submodule 管理的 theme(crboy-icarus)改成用 git-subtree 管理,並推到相同的 remote repository 去吧。

首先把 theme 的 origin 記下來,然後刪除這個 submodule

1
2
3
4
5
6
7
8
9
10
11
12
13
14
### 記下原有的 remote,方便後面操作(非必要)
$ cat .gitmodules
[submodule "themes/crboy-icarus"]
path = themes/crboy-icarus
url = https://github.com/CrBoy/hexo-theme-icarus
### 移除 submodule 並 commit
$ git submodule deinit themes/crboy-icarus
$ git rm themes/crboy-icarus
$ git commit
### 將原有的 remote 加入,並新增為 subtree
$ git remote add theme-crboy-icarus https://github.com/CrBoy/hexo-theme-icarus
$ git subtree add -P themes/crboy-icarus theme-crboy-icarus master

完成之後,原本的 submodule 現在已經成為上層專案的一部份了,任何修改都可以直接 commit 進上層專案就好。如果要把變更送到 remote theme-crboy-icarus 去,可以這樣做:

1
$ git subtree push -P themes/crboy-icarus theme-crboy-icarus master

如果這個子專案在別地方被更新了,那可以這樣把更新拉進來:

1
$ git subtree pull -P themes/crboy-icarus theme-crboy-icarus master

總結一下:用 subtree 當然是也有一些缺點的,例如子專案的東西會在母專案裡也存一份,所以會讓 git repo 變大。但這問題在現代來說不是很嚴重,整體而言我認為 subtree 比 submodule 方便得多,我會傾向使用 subtree。至於 submodule 的使用情境,目前只想到要 include 一個外部專案,而且我確定完全不會去改它的時候才比較可能使用吧。

參考資料:

分享到

CloudFlare 的 Flexible SSL

最近認真的把 blog 放上 github pages,算是差不多初始化完成了。不過 https 在這年頭是個很重要的問題啊….因為我設定了 CNAME,所以目前的網址是 hexo.crboy.net,但是如果直接連到 https://hexo.crboy.net 的話,會拿到一張 github.com 自己的 ssl 憑證,這張憑證簽給了許多 domain,其中包含 *.github.io,如下圖:

github-ssl-cert.png

雖然對於 github pages 本來給我的 crboy.githb.io 用起來是沒問題,但我自訂的 domain 可就沒辦法了。

找了一下有沒有現成解決方案,找到這篇文章:Set Up SSL on Github Pages With Custom Domains for Free,裡面教你透過 CloudFlare 的 Flexible SSL 來設定,後半段則是教你怎麼強制使用 SSL。但我只想要單純支援 SSL,不反對 user 使用 http 連線,所以後半段就不理他了。進一步找「cloudflare flexible ssl」找到這篇文章:[免費SSL]Cloudflare 免費憑證讓網站綁上SSL加密連線(https),得知原理其實很簡單:讓流量通過 cloudflare(也就是 enable 他的 cdn 功能),cloudflare 會幫你對外提供可用的 ssl 憑證。

設定方式:

  1. 把自己的 domain 的 DNS 服務放在 cloudflare 上
  2. 啟用該 domain name 的 CDN 服務
  3. 到 Page Rules 新增一個 rule:URL match 設定為 DOMANE_NAME/*(例如 hexo.crboy.net/*),setting 新增 SSL 並指定為 flexible
  4. Save and Deploy 之後就好了,剩下的就是時間問題,我自己設定的時候是馬上就可以用了….(運氣好)

不過倒是有個小小的問題…..這張憑證簽給好多 domain 啊…..而且除了我的 domain 以外也有別人的 domain,而且都是 wildcard….覺得有點擔心呢XD

cf-flexible-ssl-cert.png

另一個方式(需要花點錢)是透過 AWS 的 CloudFront(也是 CDN 服務),他也有一樣模式的東西,AWS 會幫你簽一張憑證,不過這憑證是專門簽給那個 domain 的。實際上是在 AWS Certificate Manager (ACM) 中自己決定要簽給哪些 domain,AWS 會寄信給 domain 的管理者請求 approve。雖然這樣安心多了,不過要花錢….就算了吧XD

分享到

發現一個滿方便的 ip 資訊查詢:ipinfo.io

以前都用 orange.tw 在查 ip,雖然自己也寫了一個 ip.crboy.net,不過因為實在不想花錢養一台機器,所以就把服務給停掉了。

剛剛發現 ipinfo.io 這個網站,用瀏覽器開的話相關說明也都有了。但如果直接用 curl 送 request 的話,就可以拿到自己的 ip 的相關資訊(包含地點、國家等)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ curl -D- ipinfo.io
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Date: Tue, 27 Sep 2016 10:33:36 GMT
Server: nginx/1.8.1
Set-Cookie: first_referrer=; Path=/
X-Content-Type-Options: nosniff
Content-Length: 219
Connection: keep-alive
{
"ip": "119.14.25.111",
"hostname": "host-111.25-14-119.dynamic.totalbb.net.tw",
"city": "Taipei",
"region": "",
"country": "TW",
"loc": "25.0392,121.5250",
"org": "AS9416 Hoshin Multimedia Center Inc."
}

也可以查詢特定 ip 的資訊:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ curl -D- ipinfo.io/8.8.8.8
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Date: Tue, 27 Sep 2016 10:36:40 GMT
Server: nginx/1.8.1
Set-Cookie: first_referrer=; Path=/
X-Content-Type-Options: nosniff
Content-Length: 160
Connection: keep-alive
{
"ip": "8.8.8.8",
"hostname": "No Hostname",
"city": "",
"region": "",
"country": "US",
"loc": "37.7510,-97.8220",
"org": "AS15169 Google Inc."
}

甚至 fetch 特定欄位資料:

1
2
3
4
5
6
7
8
9
10
11
$ curl -D- ipinfo.io/8.8.8.8/country
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=utf-8
Date: Tue, 27 Sep 2016 10:37:18 GMT
Server: nginx/1.8.1
Set-Cookie: first_referrer=; Path=/
Content-Length: 3
Connection: keep-alive
US
1
2
3
4
5
6
7
8
9
10
11
$ curl -D- ipinfo.io/country
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=utf-8
Date: Tue, 27 Sep 2016 10:37:22 GMT
Server: nginx/1.8.1
Set-Cookie: first_referrer=; Path=/
Content-Length: 3
Connection: keep-alive
TW

還有一些好玩的….像是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ curl -D- ipinfo.io/127.0.0.1
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Date: Tue, 27 Sep 2016 10:39:36 GMT
Server: nginx/1.8.1
Set-Cookie: first_referrer=; Path=/
X-Content-Type-Options: nosniff
Content-Length: 37
Connection: keep-alive
{
"ip": "127.0.0.1",
"bogon": 1
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ curl -D- ipinfo.io/255.255.255.255
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Date: Tue, 27 Sep 2016 10:40:46 GMT
Server: nginx/1.8.1
Set-Cookie: first_referrer=; Path=/
X-Content-Type-Options: nosniff
Content-Length: 72
Connection: keep-alive
{
"ip": "255.255.255.255",
"hostname": "No Hostname",
"bogon": 1
}

bogon: 1 根據維基百科上 Bogon filtering 的描述,看來是有擋掉不應該被查詢的 ip。不過….

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ curl -D- ipinfo.io/192.168.1.1
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
Content-Type: application/json; charset=utf-8
Date: Tue, 27 Sep 2016 10:39:56 GMT
Server: nginx/1.8.1
Set-Cookie: first_referrer=; Path=/
X-Content-Type-Options: nosniff
Content-Length: 184
Connection: keep-alive
{
"ip": "192.168.1.1",
"hostname": "ip-192-168-1-1.ap-southeast-1.compute.internal",
"city": "Momoyama-cho",
"region": "Kyoto",
"country": "JP",
"loc": "34.9500,135.7830"
}

看起來還是有些特別的 ip 可以查XD 原來這台主機放在 AWS EC2 的日本機房嗎……(思)

分享到

Hexo 學習筆記 - 套用 Icarus 佈景

挑了一下主題,暫時就用 Icarus 這個樣式吧XD

不過在 config 的時候遇到問題,怎麼改都沒效。後來找到這篇文章,裡面寫到這段話:

hexo-config 方法会去 theme 主题下的 _config.yml 中查找参数中的配置项

原來是會讀取 theme 底下的 _config.yml啊!難怪我改 Hexo 的 _config.yml(根目錄那一個)沒辦法起作用。不過奇怪的是,像是 customize.profile.author 之類的設定,在 Hexo 的 config 中修改,會起作用。不曉得 Hexo 在這邊是怎麼處理的…

分享到

搬家

今天突然覺得,應該要(再)開始好好寫 blog,想了一下,覺得實在受不了 blogger 的鳥氣。
以前評估過 Octopress 跟 Hexo,當時覺得不能用手機發文,或是用別台電腦發文,實在滿討厭的,就暫不考慮使用。
不過想到我現在的狀況….連發文都懶XD
轉念一想,其實用手機的時候,如果想寫文字,可以先筆記下來(比方說 Evernote),等到拿到電腦再好好整理文章啊!
這樣也可以提高我發文的品質,而且可以好好整理文字內容。感覺這樣滿不錯的。

於是我重新找了一下,發現這類工具好像還是以 Octopress 跟 Hexo 為大宗,而且 Hexo 據說比較易用,還是台灣人做的,當然要支持一下。(而且聽說 page render 的效能差很多….XD)
那麼,就開始學 Hexo 該怎麼用了!

分享到

好用的 mockup、wireframe 工具:Balsamiq Mockups

對於一個美術白癡來說,要設計一個網站的外觀,實在有點困難。有時候要把心中構想先畫出來給人看,都覺得力不從心,所以只好直接寫一個網頁出來,調 CSS 調老半天,只為了把心中的畫面呈現給人「看看再說」。上面所說的作法,做出來的東西比較類似於 prototype,也就是已經包含了部分 CSS/JavaScript 的完整網頁,也許缺的只是真正會 work 的功能還有各種比較細節的調整而已。但萬一這樣做出來的東西不合人家(也許是主管、客戶,甚至是自己)的胃口,那花的這些時間就算沒有全部白費,也浪費掉不少了。

或許有人會說,「我寫 prototype 超快我超強!」但你再強你有人家設計師用 photoshop 隨便畫畫強嗎?雖然人家畫出來的就是一張圖,不會動也不能點,但是省時省力,又能把想表現的重點突顯出來,用來作為前期的討論跟比較相當適合!可能講成這樣還是有人鐵齒…那試想一個狀況:客戶看了你的 prototype 之後,跟你講了一堆元件說要換位置,下面這個按鈕移到上面去(立刻修改HTML),這個選單要大一點(趕快調整 font-size, width, height,啊破版了再改一下另外那個…),這些東西的間距要小一點,整個寬度要一樣(調 margin 調老半天)…..總而言之,對於外觀的要求,在圖片上討論常常比在程式碼中討論來得容易,所以也才有所謂的 wireframe 與 mockup 的出現。

繼續閱讀

分享到

Git on Windows 安裝筆記

Git 是一套很棒的分散式版本控制系統。不過由於它一直是在 Linux 上生長的,對於在 Windows 上使用來說其實稍嫌麻煩。

Windows 上的各種 Git

在網路上搜尋通常會找到 Git for Windows 跟 msysGit 這兩個不同的名詞,我過去一直沒辦法很清楚的把他們兩者區分開來。根據 msysgit 在 github 上的首頁StackOverflow 上的討論,我目前的理解是:

  • msysGit 是 msys + Git 的完整環境,包含了 build 程式用的 toolchain,同時他的執行檔是直接在 user (或者該說是 developer) 的機器上 compile 出來的,使用者隨時可以透過 git pull 取得最新版的 msysGit 來編譯,算是給 git 開發者用的。
  • Git for Windows 可說是 msysGit 的「產出」,是預先 compile 好的 git.exe 還有其他執行檔們…其中只包含了基本的 msys 環境、有 bash、ssh、甚至 Git GUI 等工具,但是沒有 toolchain,適合單純使用(操作)git 的使用者安裝。

另外還可能會找到一個更有名的東西,稱為 TortoiseGit,這是知名專案 TortoiseSVN 的相關專案,顧名思義,就是烏龜殼包了 Git 啦!要注意的是,他只是一個 Git frontend,需要指定相關執行檔 (如 git.exe) 的位置才能工作。特別的是,他本身附帶了 PuTTY 的 ssh client (plink.exe),讓使用者可以透過比較符合 windows 使用習慣的方式來使用 ssh,如果不是很熟 linux 或是 GUI 狂熱份子可能會比較喜歡。XD

註:知名專案 cygwin 也可以安裝 git 並在 command line 下使用,但對於沒在使用 cygwin 的使用者而言麻煩得多,故此處不介紹。

這篇文章分成三個部分:首先介紹 Git for Windows (免 compile 的那個) 的安裝,接著是 msysGit (需要 compile 的那個) 的安裝,最後會介紹 TortoiseGit 的安裝,並以一個簡單的 git clone 作為結束。如果是一般單純想在 windows 上用 git 的人,可以只看第一跟第三部分即可,第二部分就當作參考資料吧!

繼續閱讀

分享到

「cannot open shared object file」的解決方案

有時候執行一些指令,會碰到下面這樣的訊息:

error while loading shared libraries: libiconv.so.2: cannot open shared object file: No such file or directory

在這個例子中,我們的程式找不到 libiconv.so.2 這個 dynamic library。那麼應該怎麼解決呢?

首先必須找到系統中的 libiconv.so.2,下面四條指令選一條作就好:

$ locate libiconv.so.2
$ whereis libiconv.so.2
$ find /usr /lib -name libiconv.so.2
$ find / -name libiconv.so.2 2>/dev/null

這時候就可以找出函式庫位置,例如:/usr/local/lib/libiconv.so

繼續閱讀

分享到

SSH 安全性設定筆記

以下收錄可增加 ssh 安全性的各種技巧,主要的修改都在 /etc/ssh/sshd_config 中,同時,修改設定後別忘了重新載入設定值或重新啟動 sshd。

  • 修改預設 port (可用多行開啟多個 port)

    Port <port>
    
  • 僅監聽特定 ip (適用於多網卡/多 IP 的情形)

    ListenAddress 192.168.1.10
    
  • 禁止 root 登入

    PermitRootlogin no
    

    管理者必須先以個人帳號登入,再 su 成 root,或利用 sudo 工作。

  • 禁止使用空密碼登入

    PermitEmptyPasswords no
    

繼續閱讀

分享到

透過 ssh 遠端存取 git repository

好,今天來寫個我架設「偽 - git server」的作法吧!

為什麼叫做「偽 - git server」呢?因為他不是真的跑起來一支 daemon 去負責 git 的 access,像是 gitolite 或是 gitosis 那樣。(事實上我也不知道該怎麼把那些東西架起來XD)
由於 git 可以透過 ssh protocol 來 access,當然要善用這點!

以下我分為單人各自使用與多人共用來講:

繼續閱讀

分享到