2018/04/02

git 筆記

只是筆記而已,用到才備忘。找工作很重要,從 svn 要再回到 git 還是有點燒腦。

設定 local (目前 .git 管理的範圍) 的帳號資訊
    #git config user.email "aimwang@gmail.com"
    #git config user.name "Aim Wang"

檢查改了哪些檔案
    #git status

恢復各別回未修改前的狀態,其中 filename 可以是 * 來恢復所有檔案,概念就是重新 checkout 檔案
    #git checkout -- <filename>

看看這次改了什麼
    #git diff -- <filename>

本地提交
    #git commit 

單行列出紀錄
    #git log --oneline

顯示 commit 的詳細內容
    #git show commit_id

只顯示本地工作副本的提交紀錄
    #git reflog

增加追蹤檔案
    #git add filename

停止追蹤
    #git update-index --assume-unchanged filename

繼續追蹤
    #git update-index --no-assume-unchanged filename

Merge 其他分支的某個 commit
    #git cherry-pick commit-hash

++++++++++ 分支相關 ++++++++++
列出分支
    本地
    #git branch --list
    遠端
    #git branch --remotes
    全部
    #git branch --all

切換分支
    #git checkout branch

建立分支
    #git branch branch

在 branch_name_father 建立分支 branch_name_son 並直接切過去
    #git checkout -b branch_name_son branch_name_father

將本地分支 push 成遠端分支
    #git push remote_name branch_name

將本地目前分支掛勾到遠端分支
    #git push --set-upstream-to=remote/branch_r branch_l

直接 Checkout 遠端分支到本地分支
    #git checkout -b branch_l remote/branch_r

將分支 branch 併入 master
    #git checkout master
    #git merge branch

如果有衝突 (conflict) 可以使用 mergetool 進行排除
    #git mergetool

設定 mergetool (使用 kdiff3 會有更好的介面)
    #git config merge.tool vimdiff
    #git config merge.conflictstyle diff3
    #git config mergetool.prompt false

刪除已 merge 過的 branch 分支
    #git branch -d branch

捨棄並刪除 branch 分支
    #git branch -D branch

刪除 remote_name 遠端 branch 分支
    #git push --delete remote_name branch

同步遠端分支清單
    #git fetch

++++++++++ 分支相關 ++++++++++

捨棄前一次提交 (限定未 push,發現前次提交還有問題,可以捨棄前一次提交,working tree 仍會保留修改過後的內容,其中 ^ 表示前一版)
    #git reset HEAD^

現有的專案建立新的 git 管理,然後 push 到空的 repository.
    #git init
    #git add .
    #git commit -m "First commit"
    #git remote add remote_name remote_repository_URL
    #git remote -v
    #git push remote_name master

本地建立分支,將分支推到遠端新分支,並建立連結
    #git checkout -b branch_name_son branch_name_father
    #git push remote_name branch_name
    #git push --set-upstream remote_name branch_name

在 sdk 分支進行修改,然後併入分支 develop
    先確保分支 develop 已經乾淨(完成 commit)且同步
        #git status
        #git fetch --all
        #git pull
    切換到分支 sdk
        #git checkout sdk
    修改後 commit 並 push
        #git commit -a -e
        #git push
    切回分支 develop
        #git checkout develop
    合併分支 sdk 的修改 (如果有衝突需要手動修正)
        #git merge sdk
        #git commit -a -e
        #git push

要存取 GitLab 建立的repository 會需要 ssh key 跟 password,所以請記得去設定 password,產生 ssh key 的指令如下:
    #ssh-keygen -t rsa -b 4096 -C "email address"

merge 衝突處理
    #git checkout br2
    #git merge br1
        Auto-merging file
        CONFLICT (content): Merge conflict in index.html
        Automatic merge failed; fix conflicts and then commit the result.
    #git add file
    #git commit -m "conflict fixed"

修復 .gitignore 有列出卻還出現在 modified 清單上的問題
    #git rm --cached filename


++++++++++ Repository 相關 ++++++++++

建立完整的 repository 鏡像
    一個 repository 在運行一段時間之後,可能會有很多分支。遇到需要移植到新的伺服器的狀況時,直接鏡像整個 repository 是比較單純的做法。
    #git clone --mirror src_git_url target_folder
    #cd target_folder
    #git push --mirror dst_git_url


更新 remote url
    #git remote set-url remote_name new_url

    更新後檢查 url 有沒有改成功
    #git remote -v

建立 tag 並推送到 remote
    #git tag -a tag_name -m 'tag_comment'
    #git push remote_name tag_name

++++++++++ 修改剛剛提交而且已經 push 的 message ++++++++++

先修改本地的提交
    #git commit --amend

重新 push 內容
    #git push --force-with-lease remote branch

例如使用 git bracnh --all 顯示為 remotes/origin/develop 的分支, 就執行 git push --force-with-lease origin develop

如果在重新 push 之前就已經 pull 回來, 就需要 hard reset,但是本地端的修改會消失, 執行前最好先透過 git status 找出修改過的內容並且備份
    #git fetch origin
    #git reset --hard remote/branch


2018/03/29

GNU Makefile 一些筆記

筆記而已

-   開頭,表示該行不報錯
@ 開頭,表示該行只執行,不回顯該行指令

:= 強制改變
+= 追加內容
?= 如果變數已經存在就不改變,如果變數不存在才設定

顯示變數內容(也可以用 error 方便除錯,用完就刪掉)
  $(info $$var is [${var}])

觸發錯誤
  $(error "message")

從 AOSP 看到的整合方式,動態將自己的項目加進編譯流程
  #預設目標指定為 droid
  DEFAULT_GOAL := droid
  $(DEFAULT_GOAL):

  .PHONY: mod1
  mod1:
    @echo "mod1"
  #將 mod1 加入預設目標的依賴,這裡可以透過 if 控制
  $(DEFAULT_GOAL): mod1

  .PHONY: mod2
  mod2:
    @echo "mod2"
  $(DEFAULT_GOAL): mod2

2018/01/31

如何在 PC 編譯 open source project 給 raspberry pi,以 NTP 為例

Why

很多 open source project 都很大,放在 pi 編譯有兩個缺點,第一很費時,第二很浪費空間。所以在 PC 編譯好之後再 install 到 pi 會是一個很好的選擇。如果 open source 專案只有提供 Makefile,那就直接把編譯相關的指向到 pi 的 tools。很多大型專案會提供 configure 來進行編譯設定,那就需要透過 configure 來設定 cross 了。以下就透過 ntp 這個專案來說明,其他專案也大同小異。

How

首先要下載原始碼,如果有更新的版本,請自行調整。
wget http://archive.ntp.org/ntp4/ntp-4.2/ntp-4.2.8p10.tar.gz

參考 Cross-compilingNTP host 是目標機器,build 是編譯機器,所以我們要分別在 PC 跟 pi 上面執行 config.guess
PC: x86_64-unknown-linux-gnu
pi: armv7l-unknown-linux-gnueabihf
知道 host 跟 build 該怎麼填之後,還要設定一些編譯要用的環境變數
export RPI_BASE=${HOME}/rpi
export CROSS=${RPI_BASE}/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
export CC=${CROSS}gcc
export AR=${CROSS}ar
export LD=${CROSS}ld
export AS=${CROSS}as
再來就要準備編譯了
mkdir target_pi
cd target_pi
../configure --host=armv7l-unknown-linux-gnueabihf --build=x86_64-unknown-linux-gnu --with-yielding-select=yes
make
make DESTDIR=`pwd`/Built install

跑完之後,就會在 Built 裡面建立需要安裝的檔案,tar 起來到 pi 的跟目錄下解 tar 就完成安裝了


2018/01/30

在 PC 編譯 wiringPi

參考了 raspberry pi 操控 gpio 的幾個方法
原本最想要的是直接存取,不知道哪裡沒弄好,gpio8 以上的行為怪怪的,只能 out,設定成 in 時,不管是拉 3.3v 還是 gnd 都是 low,所以改用 wiringpi 來處理。基於上篇,還是在 PC 上編譯 wiringPi 再拿去 raspberry pi 執行。

下載 wiringPi 原始碼

參考官網
git clone git://git.drogon.net/wiringPi

編譯主元件

需要編譯的內容是 wiringPi 和 devLib 這兩支,因為原先的 Makefile 內容是放在 raspberry pi 上編譯用的,所以需要做一些小小的調整,以便符合在 PC 上進行 cross compile。

wiringPi/Makefile 在 LIBS = 後面追加下列內容來蓋掉前面的設定
RPI_BASE := $(HOME)/rpi
CROSS := $(RPI_BASE)/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
CC := $(CROSS)gcc
AR := $(CROSS)ar
RANLIB := $(CROSS)ranlib

devLib/Makefile 一樣在 LIBS = 後面追加
RPI_BASE := $(HOME)/rpi
CROSS := $(RPI_BASE)/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
CC := $(CROSS)gcc
AR := $(CROSS)ar
RANLIB := $(CROSS)ranlib
INCLUDE += -I../wiringPi

原先的 Makefile 只編出 shared object,如果想要編出 static object,就在 all: 追加 $(STATIC) 就可以了。

編譯 gpio

因為是要先測試功能,所以使用 static object 的 wiringPi 元件,這樣就只需要把 gpio 程式放到 nfs 就能執行。

gpio/Makefile 還是在 LIBS = 後面追加
RPI_BASE := $(HOME)/rpi
CROSS := $(RPI_BASE)/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
CC := $(CROSS)gcc
AR := $(CROSS)ar
RANLIB := $(CROSS)ranlib
INCLUDE += -I../wiringPi -I../devLib
LDFLAGS += -L../wiringPi -L../devLib

把 gpio 放到 nfs 上面,把 raspberrypi 的 v33 接到 gpio26 進行測試,改接gnd 再測,再改回 v33 再測,終於可以正常當 input 了。

安裝 shared object

如果有多支程式需要用到 wiringPi,做成 shared object 會比較理想。先把編譯好的 libwiringPi.so.2.44 和 libwiringPiDev.so.2.44 複製到 host 的 nfs 上,然後從 raspberrypi 上複製到 /lib 同時處理 symbolic link。
sudo cp /mnt/nfs/libwiringPi.so.2.44 /lib
sudo ln -s /lib/libwiringPi.so.2.44 /lib/libwiringPi.so
sudo cp /mnt/nfs/libwiringPiDev.so.2.44 /lib
sudo ln -s /lib/libwiringPiDev.so.2.44 /lib/libwiringPiDev.so



完成

基本上到此已經能完全操控 gpio,如果為了效能跟空間,可以參考 wiringPi 的 gpio,把不需要的拿掉,放到自己的程式內部。由於 gpio 需要 sudo 執行,基於安全上的考量,可能要改寫成 gpiod,再透過 ipc 跟 shared memory 去要求或進行控制。

2018/01/27

Raspberry Pi 開發環境建置

raspberry pi 可以直接使用 debian linux 發行套件,安裝 makefile 跟 gcc 就可以拿 source code 去編譯,但是編譯速度絕對不比高速 x86 桌機,遇到需要除錯的程式,還是在 x86 linux 上面編譯好再給 raspberry pi 跑會是一個比較省時間的做法。想法很簡單,就是在 x86 linux 上安裝 raspberry pi cross tools,然後透過 nfs 讓 raspberry pi 直接 mount 去執行。

我目前使用的 x86 linux 是 debian 9 amd64,所以以下內容將以此為基準,使用 debian based 的發行套件應該都能直接套用,其他發行套件可能要做些修改。

安裝 cross tools


編譯環境不該使用 root,所以請用一般 user 登入,把 toolchain 放在 home

aimwang@debian:~$ mkdir rpi
aimwang$debian:~$ cd rpi
aimwang@debian:~/rpi$ git clone https://github.com/raspberrypi/tools.git

安裝並設定 nfs server


aimwang@debian:~$ sudo apt-get install nfs-kernel-server nfs-common
aimwang@debian:~$ sudo mkdir /srv/nfs
aimwang@debian:~$ sudo chmod 777 /srv/nfs

/etc/exports 最後增加 (IP 根據自己的環境改)
/srv/nfs 192.168.22.*(rw,sync,no_subtree_check,no_root_squash)

重新啟動 nfs server
aimwang@debian:~$ sudo /etc/init.d/nfs-kernel-server restart

準備編譯 hello world 等一下要透過 nfs 餵給 raspberry pi 執行
Makefile
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
ROOT_PATH := $(PWD)
RPI_BASE := $(HOME)/rpi
NFS_PATH := /srv/nfs
CROSS := $(RPI_BASE)/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin/arm-linux-gnueabihf-
CC := $(CROSS)gcc

all: hello nfs

nfs:
 @cp -f hello $(NFS_PATH)/.

hello:
 @$(CC) $(CFLAGS) -o hello hello.c

clean:
 @rm -f hello
hello.c
1
2
3
4
5
6
7
8
#include <stdio.h>
#include <stdlib.h>

void main (void)
{
 printf ("Hello world!\n");
 exit (0);
}

編譯啦
aimwang@debian:~/project/rpi/hello$ make

Raspberry Pi mount nfs 及執行

pi@raspberrypi:~ $ sudo mount -t nfs 192.168.22.200:/srv/nfs /mnt/nfs
pi@raspberrypi:~ $ /mnt/nfs/hello
Hello world!

完成