2012/05/24

google android market play to PC

http://www.hacktabs.com/download-android-apps-apk-to-your-pc-from-android-market-or-google-play/

2012/05/22

RS232

有些字眼其實很容易混淆人,不久前,有同事就在問『什麼是 RS232』?『跟 Serial Port的差異』?『那什麼又是 COM Port』?

不管這個,先回想一下,在 linux 上要對 COM Port 做 I/O 其實很簡單,一般是用 minicom 這支工具,但是基本觀念若懂的話,也可以在 console mode 下命令,可以參考這篇

1. 確認你的 COM port, 像我的是 /dev/ttyUSB0
2. 確認設定,例如我的是 115200, 8N1, off
--> stty -F /dev/ttyUSB0 raw ispeed 115200 ospeed 115200 cs8 -ignpar -cstopb -ixon 


3. 讀取: cat /dev/ttyUSB0, 或是上面那篇參考文件裡面也有些技巧可用
4. 寫入 echo "CONTENT" > /dev/ttyUSB0

PS1: 步驟2的設定,只要在同一個 console 執行過一次,當然不同的 console(例如重開機,重登入等)都得設定過一次,也可以寫在 .bashrc 中
PS2: 步驟 3, 4 可以同時做,也就是用一個 console 做 cat, 這樣不會離開,再用另一個 console 寫入

2012/04/10

apt-rdepends

http://blog.hartwork.org/?p=108

2012/04/07

source navigator on ubuntu 12.04


執行底下的 script


#!/bin/bash
wget http://svn.exactcode.de/t2/trunk/package/develop/sourcenav-ng/tk-lastevent.patch
wget http://nchc.dl.sourceforge.net/sourceforge/sourcenav/sourcenav-6.0.tar.gz

tar zxvf sourcenav-6.0.tar.gz
cp tk-lastevent.patch sourcenav-6.0
cd sourcenav-6.0
patch -p1 < tk-lastevent.patch
./configure
make
sudo make install

2012/04/02

ubuntu 12.04 build android

http://endroid.blogspot.com/2011/07/android-development-notes.html

2012/02/06

在揮別的時候.不要說再見 baby, don't say good-bye

我總是最耀眼的那一個。朋友,珍重....

2012/02/03

android api diff ?

不知道從何時開始,不知道怎麼找到的,因此跟大家分享一下 要研究 android 各級 api 之間的差異的話,用底下的界面非常方便: 例如要研究 android 4.0 http://developer.android.com/sdk/api_diff/14/changes.html http://developer.android.com/sdk/api_diff/15/changes.html 其中 14, 15 是 api level, 可以從底下找資訊, 值得注意的是,android 各 api level 跟版本的關係有點亂....舉個例來說,我的手機早期自動更新到 2.3.6, 但在 AOSP 上面根本找不到

2012/01/31

超感動 ICS4.0.3

我的 Nexus S 手動升級到 4.0.3!!!!

讀者請注意,若您因為看本文,照著操作卻導致手機故障,作者概不負任何責任。

☆☆經本人實際測試過可行,不代表您的手機也可行☆☆


  1. 首先,下載 Android ICS4.0.3更新影像檔 ,這一步您可以直接用手機下載,或是用 NB 下載再傳上去
  2. 將之更改名稱為 update.zip, 事實上這只是怕您升級之後忘了殺掉,久了又忘了這個檔案的功用,如果您習慣夠好,也可以不必更名
  3. 如果您是用手機下載,請跳到下一步,否則請用 usb cable 連接電腦,若您不會這一步,請教會的人吧,或是上網查怎麼用 usb cable 讓 NB/Phone 互傳檔案。記得放在 /sdcard 最上層(應該等於 /mnt/sdcard)。
  4. 用手機下載的檔案是放在 /download 請用「文件管理器」這類的工具將之更名+移至 sdcard  最上層(/mnt/sdcard)。
  5. 做完 step 3, 4 之後,請關機.....也就是長按 Power 鍵,按確認關機
  6. 接下來要進一般人不會看到的畫面.....是還不會出問題,可以玩玩看
    先按著 V+ 不放, 也就是平常調聲音變大的那個鈕,通常是指「左側上方」那個按鍵, 然後....
    再按著 Power 鍵 ==> 很快就開機進 bootloader 畫面,是純文字的,所以別奇怪
  7. 在 bootloader 畫面的操作只有兩個:
    V+ 向上, V- 向下, 然後 Power 是確認: 噫?是三個?好吧,我們的算法不一樣
  8. 此時應該很快會看到一個類似警告標誌,很像而已,三角形附近還有個小綠人....
     
  9. 請注意
    再接下去就要破壞你的手機啦!!!!請先按著 Power 鍵不放,再按 V+,跟 step 6 順序不太一樣。然後就會再進一個選單....操作方式一樣.....
  10. 此時請選『Apply update from /sdcard』,操作並選擇 update.zip 或是您下載的檔案VQ8PQk_V.zip
  11. 確認更新......手機在這一步之後原系統會被破壞.....不過當然一些常見的設定會保留,別怕,就給他更新下去啦。
  12. 更新大概也只需要等個5分鐘吧,我沒仔細量,但是很快.....之後就從選單選「reboot」
  13. 如果開機時,能看到亂七八糟的方塊閃來閃去的話......恭喜!!!!
    否則.....我沒發生這個否則,請送修.....

2012/01/20

多媒體檔案處理 ffmpeg, netpbm...

用 ffmpeg 來處理影片及照片是非常理想的。會寫這個議題,主要是因為我想節省上傳到 blog 的時間。若仔細一點會發現,當我們把檔案上傳到 Picasa 或 blogger 時,所占用的空間比原始檔案小很多很多!其實是因為 google 有在伺服器端處理過。

上述現象我多年前一開始用 Picasa 就知道了,後來發現上傳到 blogger 的照片也會自動放到 Picasa。不過一向都很懶,最近閒閒的,就寫了幾個 script 用來處理影片及照片,這樣也可以節省上傳的時間。這一點不比較不知道,我們自己先處理過後,上傳節省的時間可真的是非常驚人啊!如果.........嘿嘿..........如果什麼我就不多說了,總之勤勞一點會讓自己省很多時間,而時間就是金錢啊!

上面連結是我整理的文件,裡面就有 script....系統當然要安裝 ffmpeg 及 netpbm 而且我在用的環境可不是 windows, 而是 ubuntu, 這一點對 windows 的朋友們只能說聲抱歉了!但是好消息是,這兩套軟體其實都有 windows 版的 ffmpegnetpbm , 請自行上網直取最新版,用法當然都一樣,只是請自行寫 windows 下的 .bat 檔來用吧。

上面的網址有人反應不通,可以再試一次,或是直接 copy 底下的內容,不過我懶得貼 USAGE, 每個指令的 USAGE 都不一樣,請自行編輯自己的 USAGE:

  • video2avi
    把影片轉成 avi 格式,而且大小是 320x240, 這是因為我要上傳到 blog 解析度剛好
    [ "$#" = "2" ] || usage
    ffmpeg -i $1 -vcodec mpeg4 -s 320x240 -b 300k -r 30 -acodec copy -ar 22050 -ab 64k -f avi $2
    
  • video2img
    把影片存成每秒 n 張的圖片
    [ "$#" = "3" ] || usage
    ffmpeg -i $1 -r $2 -f image2 $3
    
    範例: video2img MOV00001.mpg 10 micro-video-%03d
  • video-from-img
    [ "$#" = "3" ] || usage
    ffmpeg -i $1 -r $2 -f image2 -c:v libx264 -r 30 $3
    範例: video-from-img img%03d.png 1/5 out.mp4
      如果照片沒照順序,需要用以下的命令,請自行參考
    ffmpeg -i '*.png' -r 1 -f image2 -pattern_type glob -c:v libx264 out.mp4
  • video2mp3
    將影片中的音軌取出存成 mp3
    [ "$#" = "2" ] || usage
    ffmpeg -i $1 -vn -acodec libmp3lame -ab 192k $2
    
  • video2vcddvd
    將影片轉成 vcd 或是 dvd,可以分開成兩個指令較方便
    [ "$#" = "3" ] || usage
    [ "$2" = "vcd" ] && ffmpeg -i $1 -target ntsc-vcd $3
    [ "$2" = "dvd" ] && ffmpeg -i $1 -target ntsc-dvd $3
    
  • video_cut
    [ "$#" = "4" ] || usage
    ffmpeg -i $1 -ss $2 -t $3 -f image2 $4
    
    還有一種語法如下,只截一張:
    ffmpeg -i $1 -y -f  image2  -ss $2 -vframes 1  $3
    -ss 的時間單位也可以是秒,如下:
    ffmpeg -i $1 -y -f  image2  -ss $2 -vframes 1  $3
    
  • video_histogram
    如果影片偏暗或是偏亮,可以用這個方法將亮度調「平均」,因為是計算的,絕對無法真的平均,所以除非你不喜歡影片亮度再試。
    [ "$#" = "2" ] || usage
    rm -rf /tmp/my-video; mkdir -p /tmp/my-video/{orig,hhh}
    ffmpeg -i $1 -r 30 -f image2 /tmp/my-video/orig/%05d.pnm
    pushd /tmp/my-video/orig
    for i in `\ls`; do
      FILE=`echo $i| cut -d. -f1`;
      pnmhisteq $i > ../hhh/${FILE}.pnm;
    done
    popd
    ffmpeg -i /tmp/my-video/hhh/%05d.pnm -r 30 $2
    
  • img_resize - 用 ffmpeg
    將相片縮小成 1600x1200, 這是 blog 預設的圖片大小,而通常相機也都遠大於這解析度。另外大家可能不知道,相機為了盡可能保持影片資訊,雖然是有壓縮的,但是其實是調成盡可能保存影片資訊,只要調整一下壓縮比例至 99% 或是 90% 就大大降低檔案大小。總之一句話,經過這樣轉換後,照片大小縮小很多很多。
    底下指令因為太簡單,我並沒有寫成 script, 只是寫個範例
    ffmpeg -i $1  -s 1600x1200 a.jpg
  • img_resize 2 - 用 netpbm
    用 ffmpeg 處理照片有時會遇到無法讀取的問題,也就是有些相機的格式不被讀取, 譬如我就遇到如下的錯誤訊息:
    [mjpeg @ 0x139bcc0]error count: 71
    [mjpeg @ 0x139bcc0]error y=23 x=156
    Input #0, image2, from '20120206_133247.jpg':
      Duration: 00:00:00.04, start: 0.000000, bitrate: N/A
        Stream #0.0: Video: mjpeg, yuvj422p, 3264x2448, 25 tbr, 25 tbn, 25 tbc
    

    因此只好改用 netpbm 來轉換,轉換命令如下列範例:
    jpegtopnm 20120206_133247.jpg | pnmscale -xsize=1600 -ysize=1200 | pnmtojpeg - > aaa.jpeg
    
  • 將影片變成快動作/慢動作
    這功能要由 mencoder 來實作,底下也只是範例,可以自行改成 script。mencoder 功能一樣很強大,算是編輯影片必備,例如將照片合成時加上配樂。
    mencoder -ovc copy -nosound -speed 5 in.mpg -o fast.mpg
  • 切割音軌
    用另一個軟體做的範例,ffmpeg 也可以做到
    cdparanoia -B  : 整張 CD
    cdparanoida -B 3-7 : 只抓 3,4,5,6,7 音軌
    cdparanoia "2[:35.00]-2[2:30.00]" : 抓第二軌
    

文章共享


Linux 基本觀念+常用命令
regular expression and  ...
Android 系統初探 /proc, /sys and others

再探 /proc


2012/01/19

mm busybox on android tree

寫過一篇 cross compile busybox for android,因為剛剛看到一篇mm busybox on android tree,覺得不錯就貼上來。(註:編譯出來的檔案會小很多)

基本上相當簡單,照底下的做就行了....


  • cd $ANDROID/external/
  • git clone https://github.com/CyanogenMod/android_external_busybox.git --branch ics
  • cd android_external_busybox
  • mm
希望您能一切順利。這邊要提醒的是,這個 android_external_busybox 因為跟 android bionic 有很大的相關性,因此您得切換到與您的 android 版本相關的分支才行

若比對 gingerbread 與 ics 的差異...

  • Android.mk: BIONIC_ICS := false --> BIONIC_ICS := true
  • networking/nslookup.c: # define _res _nres  --> # define _res (*__res_get_state())
    這個變動若您在 android 需要寫程式對 dns 有需求的話,可能會遇到問題,請見這篇
  • util-linux/dmesg.c: 加了底下這些,不影響大局:
    diff -ruN busybox-gingerbread//util-linux/dmesg.c busybox-ics/util-linux/dmesg.c
    --- busybox-gingerbread//util-linux/dmesg.c     2012-01-19 17:23:20.415785436 +0800
    +++ busybox-ics/util-linux/dmesg.c      2012-01-19 17:10:43.165785088 +0800
    @@ -10,16 +10,24 @@
      */
    
     //usage:#define dmesg_trivial_usage
    -//usage:       "[-c] [-n LEVEL] [-s SIZE]"
    +//usage:       "[-c] [-n LEVEL] [-r] [-s SIZE] [-C]"
     //usage:#define dmesg_full_usage "\n\n"
     //usage:       "Print or control the kernel ring buffer\n"
     //usage:     "\n       -c              Clear ring buffer after printing"
     //usage:     "\n       -n LEVEL        Set console logging level"
    +//usage:     "\n       -r              Show level prefix"
     //usage:     "\n       -s SIZE         Buffer size"
    +//usage:     "\n       -C              Colored output"
    
     #include 
     #include "libbb.h"
    
    +#define COLOR_DEFAULT 0
    +#define COLOR_WHITE   231
    +#define COLOR_YELLOW  226
    +#define COLOR_ORANGE  166
    +#define COLOR_RED     196
    +
     int dmesg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
     int dmesg_main(int argc UNUSED_PARAM, char **argv)
     {
    @@ -29,11 +37,13 @@
            enum { 
                    OPT_c = 1 << 0,
                    OPT_s = 1 << 1,
    -               OPT_n = 1 << 2
    +               OPT_n = 1 << 2,
    +               OPT_r = 1 << 3,
    +               OPT_C = 1 << 4
            };
    
            opt_complementary = "s+:n+"; /* numeric */
    -       opts = getopt32(argv, "cs:n:", &len, &level);
    +       opts = getopt32(argv, "cs:n:rC", &len, &level);
            if (opts & OPT_n) {
                    if (klogctl(8, NULL, (long) level))
                            bb_perror_msg_and_die("klogctl");
    @@ -55,13 +65,37 @@
                    return EXIT_SUCCESS;
    
    
    -       if (ENABLE_FEATURE_DMESG_PRETTY) {
    +       if ((ENABLE_FEATURE_DMESG_PRETTY || (opts & OPT_C)) && !(opts & OPT_r)) {
                    int last = '\n';
    -               int in = 0;
    +               int in = 0, l, color;
    +               char pfx[16], *lvl;
    
                    /* Skip <#> at the start of lines */
                    while (1) {
                            if (last == '\n' && buf[in] == '<') {
    +                               if (opts & OPT_C) {
    +                                       lvl = buf + in + 1;
    +                                       sscanf(lvl, "%d", &level);
    +
    +                                       switch (level) {
    +                                       case 1:
    +                                       case 2:
    +                                       case 3: color = COLOR_RED;    break;
    +                                       case 4: color = COLOR_ORANGE; break;
    +                                       case 5: color = COLOR_YELLOW; break;
    +                                       case 7: color = COLOR_WHITE;  break;
    +                                       case 6: // common dmesg info
    +                                       default: color = COLOR_DEFAULT;
    +                                       }
    +
    +                                       if (color != COLOR_DEFAULT)
    +                                               l = sprintf(pfx, "%c[%d;%d;%dm",
    +                                                       0x1B, 38, 5, color);
    +                                       else
    +                                               l = sprintf(pfx, "%c[%dm", 0x1B, 0);
    +
    +                                       full_write(STDOUT_FILENO, pfx, l);
    +                               }
                                    in += 3;
                                    if (in >= len)
                                            break;
    @@ -72,9 +106,17 @@
                            if (in >= len)
                                    break;
                    }
    +
    +               if (opts & OPT_C) {
    +                       /* Reset default terminal color */
    +                       l = sprintf(pfx, "%c[%dm", 0x1B, 0);
    +                       full_write(STDOUT_FILENO, pfx, l);
    +               }
    +
                    /* Make sure we end with a newline */
                    if (last != '\n')
                            bb_putchar('\n');
    +
            } else {
                    full_write(STDOUT_FILENO, buf, len);
                    if (buf[len-1] != '\n')
    

2012/01/09

svn on windows 的帳號管理

先前寫過二篇 svn  相關的文,一篇是 svn 另一篇是 svn server on windows xp, 其實安裝都不會是太大問題,問題在於使用時....

首先,repository 的觀念並不是每個人都有,要從個人寫程式,進化到一群人寫程式,是不一定要版本控制的。反過來說,個人寫程式也應該要有版本控制的觀念才好。我先來解釋這個概念。

版本控制可以讓『寫程式』的人,可以追蹤舊版本、分支等等,而不必像大多數人用 'zip' 把目錄壓縮起來,或是整個目錄變成 copy project project.bak 這種方式。這是一個很重要的需求。版本控制通常都可以很容易就做 diff, patch, branch, merge 等等,這對多人合作開發是非常重要的需求。

接下來,該說的話,我在前文大概都寫過了,講一下我忘了講的部份,其實,每個 repository 跟 project 是「可以一樣」「也可以不一樣」,這個我不再多說,只是要再講一遍的是,以 svn 來說,它能對每個 repository 做存取權限的控管,找一下  conf 目錄就有了。

若是用 apache ,也就是用 http:// 或是 https:// 來存取的話,存取權限當然就是要在 apache 中設定。

若是用 svn:// 來存取的話,設定檔就是在 conf/ 目錄下的三個檔:passwd, authz, svnserve.conf。

正常來說 apache, svn 都要有自己的帳號管理,尤其 svn 的三個設定檔中的密碼竟然是明文的,所以非常不建議使用 svn 的內建控管機制。

好加在的是,apache 可以結合 windows 控管機制,這個我在前文中就有講了怎麼安裝。現在說說每個 repository 如何做管理?

最簡單的方法,就是在 repository 的目錄採用 windows 的網路芳鄰的分享機制來做. 如果不滿意,可以參考這篇來實作

2012/01/04

反組譯 c/c++ disassembly

這篇不是教人家怎麼反組譯,因為大部份都需要好的工具,就像要反組譯 android apk 可以用 smali 一樣。

在 android 上要反組譯 c/c++ 的執行檔是相當麻煩的,不過常用的 Linux  工具可以提供我們一個思考方向:nm, objdump, 甚至是 gdb。

寫在前面:其實是有你看這篇時心中想要的工具,不過好用的是要錢的,不要錢的我自己都編譯不了,但是還是提供一下資訊供大家參考: boomerang

objdump 是很常見的,網路上也有相當多的文件,有興趣的人可以自行找找看,或是參考這篇

我舉個簡單的例子來說明 nm, objdump

#include 

int sum(int a, int b){
  return a+b;
}

int main(int argc, char* argv[])
{
  int i, j;
  i = 10;
  j = i*2;
  printf ("Hello, %d + %d == %d\n", i, j, sum(i, j));
  return 0;
}

編譯: 通常拿到執行檔的時候,它的編譯選項是不可能加 -g 的(gcc -g hello.c -o hello),如果有的話,算是你幸運,可以直接下 objdump -S hello 就可以得到下面的結果(大部份都略過):

00000000004004f4 :
#include 

int sum(int a, int b){
  4004f4:       55                      push   %rbp
  4004f5:       48 89 e5                mov    %rsp,%rbp
  4004f8:       89 7d fc                mov    %edi,-0x4(%rbp)
  4004fb:       89 75 f8                mov    %esi,-0x8(%rbp)
  return a+b;
  4004fe:       8b 45 f8                mov    -0x8(%rbp),%eax
  400501:       8b 55 fc                mov    -0x4(%rbp),%edx
  400504:       8d 04 02                lea    (%rdx,%rax,1),%eax
}
  400507:       c9                      leaveq 
  400508:       c3                      retq   

上面可以見到 sum() 的程式碼......其實 main() 的也有,往下找....

0000000000400509 
: int main(int argc, char* argv[]) { 400509: 55 push %rbp 40050a: 48 89 e5 mov %rsp,%rbp 40050d: 48 83 ec 20 sub $0x20,%rsp 400511: 89 7d ec mov %edi,-0x14(%rbp) 400514: 48 89 75 e0 mov %rsi,-0x20(%rbp) int i, j; i = 10; 400518: c7 45 fc 0a 00 00 00 movl $0xa,-0x4(%rbp) j = i*2; 40051f: 8b 45 fc mov -0x4(%rbp),%eax 400522: 01 c0 add %eax,%eax 400524: 89 45 f8 mov %eax,-0x8(%rbp) printf ("Hello, %d + %d == %d\n", i, j, sum(i, j)); 400527: 8b 55 f8 mov -0x8(%rbp),%edx 40052a: 8b 45 fc mov -0x4(%rbp),%eax 40052d: 89 d6 mov %edx,%esi 40052f: 89 c7 mov %eax,%edi 400531: e8 be ff ff ff callq 4004f4 400536: 89 c1 mov %eax,%ecx 400538: b8 4c 06 40 00 mov $0x40064c,%eax 40053d: 8b 55 f8 mov -0x8(%rbp),%edx 400540: 8b 75 fc mov -0x4(%rbp),%esi 400543: 48 89 c7 mov %rax,%rdi 400546: b8 00 00 00 00 mov $0x0,%eax 40054b: e8 a0 fe ff ff callq 4003f0 return 0; 400550: b8 00 00 00 00 mov $0x0,%eax }
不過,問題是,我們拿到的執行檔應該是沒有加 -g 這個 debug 選項的,事實上,在沒有更好的工具時,有一個方法可以「觀察」,就是 nm -s hello (PS: 假設 gcc hello.c -o hello)
...
0000000000600e24 d __init_array_end
0000000000600e24 d __init_array_start
00000000004005f0 T __libc_csu_fini
0000000000400560 T __libc_csu_init
                 U __libc_start_main@@GLIBC_2.2.5
0000000000601020 A _edata
0000000000601030 A _end
0000000000400638 T _fini
00000000004003c8 T _init
0000000000400410 T _start
000000000040043c t call_gmon_start
0000000000601020 b completed.6557
0000000000000000 a crtstuff.c
0000000000000000 a crtstuff.c
0000000000601010 W data_start
0000000000601028 b dtor_idx.6559
00000000004004d0 t frame_dummy
0000000000000000 a hello.c
0000000000400509 T main
                 U printf@@GLIBC_2.2.5
00000000004004f4 T sum

此時可以見到程式中定義了 main, 使用(呼叫)了 printf(), 及 sum()
PS: 上面有很多底線開頭的符號,都可以直接略過,因為那都是「內建」符號

講到這邊,有人可能要大聲抗議,這怎麼叫反組譯啊!!!!我可沒說反組譯回 C/C++ source code.....若你能讀懂組合語言的話.....當然,正常程式寫作上,光函式名稱, 也就是符號表就常常暗示了很大的一部份程式運作了。

還有一個命令叫 strings, 上面無 -g 的 hello 也可以用 strings hello 得到下面結果:
/lib64/ld-linux-x86-64.so.2
__gmon_start__
libc.so.6
printf
__libc_start_main
GLIBC_2.2.5
fff.
=p       
l$ L
t$(L
|$0H
Hello, %d + %d == %d
看到最後一行的 hello, %d + %d == %d 了嗎?那就是出現在程式中的字串

最後最後,提供一個 debug 的工具叫 strace,我會提它是因為它也是 busybox  有提供的工具。
strace 的功能是「追蹤命令執行時所呼叫到的系統函式」,這一段說明恐怕你不容易了解,但是能追蹤系統呼叫通常也是解密的最重要線索,用法如下:
strace ./hello
PS: strace 後面要接的是執行的命令,因此是 ./hello, 而不是 hello
PS2: strace 還有一些參數,例如把輸入導到檔案之類的,可以自行上網查。


2011/10/21

Git == SVN 愛用者的快速入門

我想,很多人是 SVN  的愛用者,若有像我一樣要換到 git 的人,可以參考本文的原始文章: Git - SVN 快速入門。底下是翻譯

如果你只是想追蹤某人的專案的話,下面這樣就夠了:
git clone url
git pull
svn checkout url
svn update

在進一步閱讀前,你應該知道的事

  • Repositories.
    在 subversion 中,每個專案有一個單一的放置源碼的地方,英文叫 Repository,在 SVN 中它用來管理源碼、管理變動記錄、或是讓你上傳源碼
    但是在 Git 卻不一樣,它是分散式的,每個專案的複製品有它自己的專案倉庫,在做與 SVN 一樣的管理時,並不需要連線,你可以在本地端做完。也就是說,在本地端的分支進展,是可以與所謂的遠端分開的不同分支。雖然名詞上一樣,但是觀念上卻完全不同。
  • URL.在 SVN 中,URL 指的就是前面的 Repository的位址或其目錄樹位址,所以你必須對 Repository 做好目錄管理,譬如,最常見的 trunk/, branches/ 及tags/ 等。
    但是在 Git 中,URL 就只是 Repository 的位址而已,也就是說,你無法透過 URL 來指定分支什麼的。換句話說,Git 的倉庫要就整個被提取而 SVN 則可以從倉庫中提取個別的物品。看似 SVN 比較合理點,但是反過來思考二個問題,當對方的倉庫沒開門時,你就提取不到東西,而且若你想開分行時,將會占用另一個倉庫。我這樣說或許有人會說,Git 只是一開始就弄一個新倉庫,還不是一樣要占用一個倉庫?其實觀念上完全不同,你在本地端不管是 Git 或 SVN 本來也都一樣要占用完全的備份,而 SVN 則在新分支時又要重新占用一個新的備份。
  • Revisions.
    SVN 在版本的控管上是用 Revision, 而且會自動遞增。這在理論上或許很方便,實務上對 Repository 有人懶得管,或是分支的管理上,Revision 都反而增加了困擾。當然可以用 Tag 來稍微解決問題,但是常用 SVN 的人就知道,這確實是個很大的困擾。尤其到後期,你根本無法知道哪個 Revision 是你要的。若混用了 Repository 及 branch, 光是要記 Revision 就是一場災難。
    而 Git 則用 HEAD 來代表當前的版本,你可以搭配 HEAD^, HEAD^^ = HEAD~2 來表示更早的版本。而且 Git 在分支的管理上更是輕便,隨時可以切換分支,這一點是 SVN 比不上的。
  • Commits.
    首先一點是,SVN 的 commit 是丟到伺服器上,就是真的『提交』。而 Git 的 commit 則是丟到本地端的 Repository,跟 SVN 的 commit 相對應的反而是 push。
    第二點,Git 把每次的提交動作,分出 author, 及 committer, 也就是作者與提交者,兩個是不同的。底下的命令可以設定成全域值:
    git config --global user.name "Your Name Comes Here"
    git config --global user.email you@yourdomain.example.com
    
  • Commands.
    Git 有一個很特殊的用法,就是一般的用法是 "git command“ 你也可以用 “git-command” 的型式,這樣在 bash 下很容易用 tab 來找出你可以用的命令.
  • Colors.
    Git 很貼心的可以將命令的輸出著色,因為有些人討厭顏色,其實我也是,所以預設是關掉的。可以試著用下面的命令來打開:
    git config --global color.diff auto
    git config --global color.status auto
    git config --global color.branch auto
    
  • Visualize.
    Git 也有圖形界面可以用,最簡單的就是 gitk

Commiting

除了前面算是緒言的部份外,首先要介紹的是,如何讓你的專案交由 Git 來追蹤,並且看看在那之後每日必做的功課。先切換工作目錄到你的專案去吧,然後.....

git init
git add .
git commit
svnadmin create repo
svn import file://repo
git init 初始化 repository, 而 git add . 則會將目錄下所有東西加到 repository 中。事實上,與其相對應的 svn 是不存在的,因為 svn 沒有本地端的 repository 的觀念,所以上面的例子是用 svnadmin  來實作的,而這通常是在伺服器端。要注意的是,git commit 之後,才算真正的進入到 repository 中,不過貌似有個比較正式的名詞叫 staged.

git diffsvn diff | less
比對不同版本的差異。這邊講的版本,其實是每次的 commit 視為一個版本,跟實務上的版本是不一樣的。
git diff rev pathsvn diff -rrev path
Git embeds special information in the diffs about adds, removals and mode changes:
git applypatch -p0
That will apply the patch while telling Git about and performing those "meta-changes".
There is a more concise representation of changes available:
git statussvn status
This will show the concise changes summary as well as list any files that you haven't either ignored or told Git about. In addition, it will also show at the top which branch you are in.
While we are at the status command, over time plenty of the "Untracked files" will get in there, denoting files not tracked by Git. Wait a moment if you want to add them, run git clean if you want to get rid of all of them, or add them to the .gitignore file if you want to keep them around untracked (works the same as the svn:ignore property in SVN).
To restore a file from the last revision:
git checkout pathsvn revert path
You can restore everything or just specified files.
So, just like in SVN, you need to tell Git when you add, move or remove any files:
git add file
git rm file
git mv file
svn add file
svn rm file
svn mv file
You can also recursively add/remove whole directories and so on; Git's cool!
So, it's about time we commit our changes. Big surprise about the command:
git commit -asvn commit
to commit all the changes or, as with Subversion, you can limit the commit only to specified files and so on. A few words on the commit message: it is customary to have a short commit summary as the first line of the message, because various tools listing commits frequently show only the first line of the message. You can specify the commit message using the -m parameter as you are used, but you can pass several -m arguments and they will create separate paragraphs in the commit message:
If you don't pass any -m parameter or pass the -e parameter, your favorite $EDITOR will get run and you can compose your commit message there, just as with Subversion. In addition, the list of files to be committed is shown.
And as a bonus, if you pass it the -v parameter it will show the whole patch being committed in the editor so that you can do a quick last-time review.
By the way, if you screwed up committing, there's not much you can do with Subversion, except using some enigmatic svnadmin subcommands. Git does it better - you can amend your latest commit (re-edit the metadata as well as update the tree) using git commit --amend, or toss your latest commit away completely using git reset HEAD^, this will not change the working tree.

Browsing

Now that we have committed some stuff, you might want to review your history:
git log
git blame file
svn log | less
svn blame file
The log command works quite similar in SVN and Git; again, git log is quite powerful, please look through its options to see some of the stuff it can do.
The blame command is more powerful as it can detect the movement of lines, even with file copies and renames. But there is a big chance that you probably want to do something different! Usually, when using annotate you are looking for the origin of some piece of code, and the so-calledpickaxe of Git is much more comfortable tool for that job (git log -Sstring shows the commits which add or remove any file data matchingstring).
You can see the contents of a file, the listing of a directory or a commit with:
git show rev:path/to/file
git show rev:path/to/directory
git show rev
svn cat url
svn list url
svn log -rrev url
svn diff -crev url

Tagging and branching

Subversion marks certain checkpoints in history through copies, the copy is usually placed in a directory named tags. Git tags are much more powerful. The Git tag can have an arbitrary description attached (the first line is special as in the commit case), some people actually store the whole release announcements in the tag descriptions. The identity of the person who tagged is stored (again following the same rules as identity of the committer). You can tag other objects than commits (but that is conceptually rather low-level operation). And the tag can be cryptographically PGP signed to verify the identity (by Git's nature of working, that signature also confirms the validity of the associated revision, its history and tree). So, let's do it:
git tag -a namesvn copy http://example.com/svn/trunk http://example.com/svn/tags/name
To list tags and to show the tag message:
git tag -l
git show tag
svn list http://example.com/svn/tags/
svn log --limit 1 http://example.com/svn/tags/tag
Like Subversion, Git can do branches (surprise surprise!). In Subversion, you basically copy your project to a subdirectory. In Git, you tell it, well, to create a branch.
git branch branch
git checkout branch
svn copy http://example.com/svn/trunk http://example.com/svn/branches/branch
svn switch http://example.com/svn/branches/branch
The first command creates a branch, the second command switches your tree to a certain branch. You can pass an extra argument togit branch to base your new branch on a different revision than the latest one.
You can list your branches conveniently using the aforementioned git-branch command without arguments the listing of branches. The current one is denoted by an "*".
git branchsvn list http://example.com/svn/branches/
To move your tree to some older revision, use:
git checkout rev
git checkout prevbranch
svn update -r rev
svn update
or you could create a temporary branch. In Git you can make commits on top of the older revision and use it as another branch.

Merging

Git supports merging between branches much better than Subversion - history of both branches is preserved over the merges and repeated merges of the same branches are supported out-of-the-box. Make sure you are on one of the to-be-merged branches and merge the other one now:
git merge branchsvn merge -r 20:HEAD http://example.com/svn/branches/branch
(assuming the branch was created in revision 20 and you are inside a working copy of trunk)
If changes were made on only one of the branches since the last merge, they are simply replayed on your other branch (so-called fast-forward merge). If changes were made on both branches, they are merged intelligently (so-called three-way merge): if any changes conflicted, git mergewill report them and let you resolve them, updating the rest of the tree already to the result state; you can git commit when you resolve the conflicts. If no changes conflicted, a commit is made automatically with a convenient log message (or you can dogit merge --no-commit branch to review the merge result and then do the commit yourself).
Aside from merging, sometimes you want to just pick one commit from a different branch. To apply the changes in revision rev and commit them to the current branch use:
git cherry-pick revsvn merge -c rev url

Going Remote

So far, we have neglected that Git is a distributed version control system. It is time for us to set the record straight - let's grab some stuff from remote sites.
If you are working on someone else's project, you usually want to clone its repository instead of starting your own. We've already mentioned that at the top of this document:
git clone urlsvn checkout url
Now you have the default branch (normally master), but in addition you got all the remote branches and tags. In clone's default setup, the default local branch tracks the origin remote, which represents the default branch in the remote repository.
Remote branch, you ask? Well, so far we have worked only with local branches. Remote branches are a mirror image of branches in remote repositories and you don't ever switch to them directly or write to them. Let me repeat - you never mess with remote branches. If you want to switch to a remote branch, you need to create a corresponding local branch which will "track" the remote branch:
git checkout -b branchorigin/branchsvn switch url
You can add more remote branches to a cloned repository, as well as just an initialized one, using git remote add remote url. The command git remote lists all the remotes repositories and git remote show remote shows the branches in a remote repository.
Now, how do you get any new changes from a remote repository? You fetch them: git fetch. At this point they are in your repository and you can examine them using git log origin (git log HEAD..origin to see just the changes you don't have in your branch), diff them, and obviously, merge them - just do git merge origin. Note that if you don't specify a branch to fetch, it will conveniently default to the tracking remote.
Since you frequently just fetch + merge the tracking remote branch, there is a command to automate that:
git pullsvn update

Sharing the Work

Your local repository can be used by others to pull changes, but normally you would have a private repository and a public repository. The public repository is where everybody pulls and you... do the opposite? Push your changes? Yes! We do git push remote which will push all the local branches with a corresponding remote branch - note that this works generally only over SSH (or HTTP but with special webserver setup). It is highly recommended to setup a SSH key and an SSH agent mechanism so that you don't have to type in a password all the time.
One important thing is that you should push only to remote branches that are not currently checked out on the other side (for the same reasons you never switch to a remote branch locally)! Otherwise the working copy at the remote branch will get out of date and confusion will ensue. The best way to avoid that is to push only to remote repositories with no working copy at all - so called bare repositories which are commonly used for public access or developers' meeting point - just for exchange of history where a checked out copy would be a waste of space anyway. You can create such a repository. See Setting up a public repository for details.
Git can work with the same workflow as Subversion, with a group of developers using a single repository for exchange of their work. The only change is that their changes aren't submitted automatically but they have to push (however, you can setup a post-commit hook that will push for you every time you commit; that loses the flexibility to fix up a screwed commit, though). The developers must have either an entry in htaccess (for HTTP DAV) or a UNIX account (for SSH). You can restrict their shell account only to Git pushing/fetching by using the git-shell login shell.
You can also exchange patches by mail. Git has very good support for patches incoming by mail. You can apply them by feeding mailboxes with patch mails to git am. If you want to send patches use git format-patch and possibly git send-email. To maintain a set of patches it is best to use the StGIT tool (see the StGIT Crash Course).
If you have any questions or problems which are not obvious from the documentation, please contact us at the Git mailing list atgit@vger.kernel.org. We hope you enjoy using Git!