2010年12月5日 星期日

git筆記


先把用過的指令List出來
git init
Create an empty git repository or reinitialize an existing one

git add
Add file contents to the index

git commit
Record changes to the repository

git log
Show commit logs.

git config
Get and set repository or global options.

git branch
List, create, or delete branches.

git checkout
Checkout a branch or paths to the working tree.

git clone
Clone a repository into a new directory.


建立Local Repository並且加入新檔
brook@vista:~/git_test$ git init
Initialized empty Git repository in /home/brook/git_test/.git/
brook@vista:~/git_test$ echo 1 > a.txt
brook@vista:~/git_test$ git add .
brook@vista:~/git_test$ git commit -a -m "init version"
[master (root-commit) 3f4bf46] init version
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 a.txt
brook@vista:~/git_test$ git log --stat
commit 3f4bf46a188e676104bd8bb929a8ba85e85bb536
Author: Brook <rene3210@>
Date:   Sat Dec 4 22:21:16 2010 +0800

    init version

 a.txt |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)


透過ssh複製遠端的Repository
brook@vista:~/git_test2$ git clone ssh://brook@127.0.0.1/home/brook/git_test/ .
Initialized empty Git repository in /home/brook/git_test2/git_test/.git/
brook@127.0.0.1's password: 
remote: Counting objects: 3, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (3/3), done.
brook@vista:~/git_test2$ ls
a.txt


建立branch/複製遠端的branch
brook@vista:~/git_test$ git branch 顯示目前的branch
* master
brook@vista:~/git_test$ git branch new_branch建立一個名為new_branch的branch
brook@vista:~/git_test$ git branch 
* master
  new_branch
brook@vista:~/git_test$ git checkout new_branch 切換到new_branch
Switched to branch 'new_branch'
brook@vista:~/git_test$ git branch 
  master
* new_branch

複製遠端的branch
brook@vista:~/git_test2$ git checkout --track origin/new_branch 
Branch new_branch set up to track remote branch new_branch from origin.
Switched to a new branch 'new_branch'
brook@vista:~/git_test2$ git branch 
  master
* new_branch

利用pull(下載)/push(上傳)更新資料
利用pull更新資料
brook@vista:~/test$ mkdir git1
brook@vista:~/test$ mkdir git2
brook@vista:~/test$ cd git1/
brook@vista:~/test/git1$ git init
Initialized empty Git repository in /home/brook/test/git1/.git/
brook@vista:~/test/git1$ echo "01" > 01.txt
brook@vista:~/test/git1$ git add 01.txt
brook@vista:~/test/git1$ git commit -a -m "v1"
[master (root-commit) 6d3302a] v1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 01.txt
brook@vista:~/test/git1$ cd ../git2
brook@vista:~/test/git2$ git clone ../git1 .
Initialized empty Git repository in /home/brook/test/git2/.git/
brook@vista:~/test/git2$ ls
01.txt
brook@vista:~/test/git2$ cd ../git1
brook@vista:~/test/git1$ echo "012" > 01.txt 
brook@vista:~/test/git1$ git commit -a -m "v2"
[master 9824999] v2
 1 files changed, 1 insertions(+), 1 deletions(-)
brook@vista:~/test/git1$ cd ../git2/
brook@vista:~/test/git2$ git pull
remote: Counting objects: 5, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /home/brook/test/git2/../git1
   6d3302a..9824999  master     -> origin/master
Updating 6d3302a..9824999
Fast-forward
 01.txt |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
brook@vista:~/test/git2$ cat 01.txt 
012

利用push(上傳)更新資料
brook@vista:~/test/git2$ echo "0123" > 01.txt 
brook@vista:~/test/git2$ git commit -a -m "v3"
[master 3dd46af] v3
 1 files changed, 1 insertions(+), 1 deletions(-)
brook@vista:~/test/git2$ git push
Counting objects: 5, done.
Writing objects: 100% (3/3), 231 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsist
ent
remote: error: with what you pushed, and will require 'git reset --hard' to matc
h
remote: error: the work tree to HEAD.
remote: error: 
remote: error: You can set 'receive.denyCurrentBranch' configuration variable t
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing int
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in som
remote: error: other way.
remote: error: 
remote: error: To squelch this message and still keep the default behaviour, se
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
To /home/brook/test/git2/../git1
 ! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to '/home/brook/test/git2/../git1'
brook@vista:~/test/git2$ vim ../git1/.git/config 
[core]
    repositoryformatversion = 0
    filemode = true
    bare = false
    logallrefupdates = true
[receive]
    denyCurrentBranch = false
brook@vista:~/test/git2$ git push
Counting objects: 5, done.
Writing objects: 100% (3/3), 231 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /home/brook/test/git2/../git1
   9824999..3dd46af  master -> master
brook@vista:~/test/git2$ cd ../git1
brook@vista:~/test/git1$ git log -1
commit 3dd46af43524c4e81597f392f58899c78faf087b
Author: Brook <rene3210@>
Date:   Wed Dec 15 22:37:39 2010 +0800

    v3

merge預設會將每一個change重作一次
rook@vista:~/git$ git init
Initialized empty Git repository in /home/brook/git/.git/
brook@vista:~/git$ echo "01" > 01.txt
brook@vista:~/git$ git add 01.txt
brook@vista:~/git$ git commit -a -m "v1"
[master (root-commit) 0b7b5ea] v1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 01.txt
brook@vista:~/git$ git branch my_branch
brook@vista:~/git$ git checkout my_branch 
Switched to branch 'my_branch'
brook@vista:~/git$ git branch 
  master
* my_branch
brook@vista:~/git$ echo "012" > 01.txt 
brook@vista:~/git$ git commit -a -m "v2"
[my_branch de5e153] v2
 1 files changed, 1 insertions(+), 1 deletions(-)
brook@vista:~/git$ echo "0123" > 01.txt 
brook@vista:~/git$ git commit -a -m "v3"
[my_branch a8d702d] v3
 1 files changed, 1 insertions(+), 1 deletions(-)
brook@vista:~/git$ echo "01234" > 01.txt 
brook@vista:~/git$ git commit -a -m "v4"
[my_branch 8bae340] v4
 1 files changed, 1 insertions(+), 1 deletions(-)
brook@vista:~/git$ git log
commit 8bae34004943242020b4e1b54726ae1bb77bb991
Author: Brook <rene3210@>
Date:   Wed Dec 15 22:50:43 2010 +0800

    v4

commit a8d702da300bbf643c5b7a7f3be60d7133658b5f
Author: Brook <rene3210@>
Date:   Wed Dec 15 22:50:26 2010 +0800

    v3

commit de5e153e8f3414ede60891c21686811b2cf704a6
Author: Brook <rene3210@>
Date:   Wed Dec 15 22:50:16 2010 +0800

    v2

commit 0b7b5ead8e486ba7dc3f1dc75498f27ebd008805
Author: Brook <rene3210@>
Date:   Wed Dec 15 22:49:11 2010 +0800

    v1
brook@vista:~/git$ git checkout master 
Switched to branch 'master'
brook@vista:~/git$ git merge my_branch 
Updating 0b7b5ea..8bae340
Fast-forward
 01.txt |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
brook@vista:~/git$ cat 01.txt 
01234
brook@vista:~/git$ git log 
commit 8bae34004943242020b4e1b54726ae1bb77bb991
Author: Brook <rene3210@>
Date:   Wed Dec 15 22:50:43 2010 +0800

    v4

commit a8d702da300bbf643c5b7a7f3be60d7133658b5f
Author: Brook <rene3210@>
Date:   Wed Dec 15 22:50:26 2010 +0800

    v3

commit de5e153e8f3414ede60891c21686811b2cf704a6
Author: Brook <rene3210@>
Date:   Wed Dec 15 22:50:16 2010 +0800

    v2

commit 0b7b5ead8e486ba7dc3f1dc75498f27ebd008805
Author: Brook <rene3210@>
Date:   Wed Dec 15 22:49:11 2010 +0800

    v1

subversion方式的merge(squash)
brook@vista:~/git$ git init
Initialized empty Git repository in /home/brook/git/.git/
brook@vista:~/git$ echo "01" > 01.txt
brook@vista:~/git$ git add .
brook@vista:~/git$ git commit -a -m "v1"
[master (root-commit) fbf643a] v1
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 01.txt
brook@vista:~/git$ git branch my_branch
brook@vista:~/git$ git checkout my_branch 
Switched to branch 'my_branch'
brook@vista:~/git$ echo "012" > 01.txt
brook@vista:~/git$ git commit -a -m "v2"
[my_branch 51c6575] v2
 1 files changed, 1 insertions(+), 1 deletions(-)
brook@vista:~/git$ echo "0123" > 01.txt
brook@vista:~/git$ git commit -a -m "v3"
[my_branch 67873cb] v3
 1 files changed, 1 insertions(+), 1 deletions(-)
brook@vista:~/git$ git log
commit 67873cb645636a0ab70309cfa65b678ed49eb2b9
Author: Brook <rene3210@>
Date:   Wed Dec 15 22:58:42 2010 +0800

    v3

commit 51c6575ba88dcfb8a3cfd19b2b4d36ae85fd5ac1
Author: Brook <rene3210@>
Date:   Wed Dec 15 22:58:37 2010 +0800

    v2

commit fbf643a72076d43c16a089c2fe330c357bba004e
Author: Brook <rene3210@>
Date:   Wed Dec 15 22:58:12 2010 +0800

    v1
brook@vista:~/git$ git checkout master 
Switched to branch 'master'
brook@vista:~/git$ git merge --squash my_branch 
Updating fbf643a..67873cb
Fast-forward
Squash commit -- not updating HEAD
 01.txt |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
brook@vista:~/git$ git commit -a -m "merge with squash"
[master eefb013] merge with squash
 1 files changed, 1 insertions(+), 1 deletions(-)
brook@vista:~/git$ git log
commit eefb0132ae0c1eaa40b746bca7b5440c54e63cb2
Author: Brook <rene3210@>
Date:   Wed Dec 15 23:00:49 2010 +0800

    merge with squash

commit fbf643a72076d43c16a089c2fe330c357bba004e
Author: Brook <rene3210@>
Date:   Wed Dec 15 22:58:12 2010 +0800

    v1



2010年11月27日 星期六

Linux Kernel(12.1)- netfilter機制之初探


延續Linux Modules(12)- netfilter我們由nf_register_hooks()來看看netfilter這個framework是如何運作的。

struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS] __read_mostly;

int nf_register_hook(struct nf_hook_ops *reg)
{
    struct nf_hook_ops *elem;
    int err;

    err = mutex_lock_interruptible(&nf_hook_mutex);
    if (err < 0)
        return err;
    list_for_each_entry(elem, &nf_hooks[reg->pf][reg->hooknum], list) {
        if (reg->priority < elem->priority)
            break;
    }
    list_add_rcu(®->list, elem->list.prev);
    mutex_unlock(&nf_hook_mutex);
    return 0;
}

void nf_unregister_hook(struct nf_hook_ops *reg)
{
    mutex_lock(&nf_hook_mutex);
    list_del_rcu(®->list);
    mutex_unlock(&nf_hook_mutex);
    synchronize_net();
}
nf_hook_register_hook()其實就是在將要註冊的callback function依照所屬的protocol family以及hooknum插入struct list_head nf_hooks[NFPROTO_NUMPROTO][NF_MAX_HOOKS],並且會依照priority由小到大,而nf_unregister_hook()就是很簡單的reg由nf_hooks中移除。

接著我們再來看看nf_iterate(),程式碼中以//為註解方式,且為粗體字型就是我的註解。
unsigned int
nf_iterate(struct list_head *head, struct sk_buff *skb,
          unsigned int hook, const struct net_device *indev,
          const struct net_device *outdev, struct list_head **i,
          int (*okfn)(struct sk_buff *), int hook_thresh)
{
    unsigned int verdict;

    /*
     * The caller must not block between calls to this
     * function because of risk of continuing from deleted element.
     */
    list_for_each_continue_rcu(*i, head) {
        struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;

        // 註冊的priority必須小於等於hook_thresh才會被執行
        if (hook_thresh > elem->priority)
            continue;

        /* Optimization: we don't need to hold module
           reference here, since function can't sleep. --RR */
        //丟進註冊的hook function執行
        verdict = elem->hook(hook, skb, indev, outdev, okfn);
        if (verdict != NF_ACCEPT) {
#ifdef CONFIG_NETFILTER_DEBUG
            if (unlikely((verdict & NF_VERDICT_MASK) > NF_MAX_VERDICT)) {
                NFDEBUG("Evil return from %p(%u).\n", elem->hook, hook);
                continue;
            }
#endif
            //如果不是NF_ACCEPT而且也不是NF_REPEAT就回傳verdict
            // (NF_DROP/NF_STOLEN/NF_QUEUE)
            if (verdict != NF_REPEAT)
                return verdict;
            //會執行到這邊就是NF_REPEAT啦
            *i = (*i)->prev;
        }
        // 如果verdict是NF_ACCEPT就會繼續往下一個hook function執行
    }
    //如果沒有任何的hook function或者所有的hook function都是NF_ACCEPT
    return NF_ACCEPT;
}

/* Returns 1 if okfn() needs to be executed by the caller,
 * -EPERM for NF_DROP, 0 otherwise. */
int
nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
             struct net_device *indev, struct net_device *outdev,
             int (*okfn)(struct sk_buff *), int hook_thresh)
{
    struct list_head *elem;
    unsigned int verdict;
    int ret = 0;

    /* We may already have this, but read-locks nest anyway */
    rcu_read_lock();

    elem = &nf_hooks[pf][hook];
next_hook:
    // 將nf_hooks[pf][hook]這個linked list丟進nf_iterate()中執行
    verdict = nf_iterate(&nf_hooks[pf][hook], skb, hook, indev,
                         outdev, &elem, okfn, hook_thresh);
    if (verdict == NF_ACCEPT || verdict == NF_STOP) {
        // 如果是NF_ACCEPT或NF_STOP就回傳1, 到時候NF_HOOK()/NF_HOOK_COND()
        // 等macro就會執行okfn, 前面的註解也有說明
        ret = 1;
    } else if (verdict == NF_DROP) {
        // 如果是NF_DROP就會free resource並且回傳!1, 就是不會呼叫okfn()了
        kfree_skb(skb);
        ret = -EPERM;
    } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
        // 如果是QUEUE就會將他nf_queue()將資訊暫時存起來, 等候處理
        if (!nf_queue(skb, elem, pf, hook, indev, outdev, okfn,
                      verdict >> NF_VERDICT_BITS))
            goto next_hook;
    }
    rcu_read_unlock();
    // 執行到這邊有可能是NF_STOLEN, 但ret = 0, 所以不會執行okfn,
    // NF_STOLEN會改變packet原本要走的路徑
    return ret;
}


#iddef CONFIG_NETFILTER
int
nf_hook_slow(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
             struct net_device *indev, struct net_device *outdev,
             int (*okfn)(struct sk_buff *), int thresh);

/**
 * nf_hook_thresh - call a netfilter hook
 * 
 * Returns 1 if the hook has allowed the packet to pass.  The function
 * okfn must be invoked by the caller in this case.  Any other return
 * value indicates the packet has been consumed by the hook.
 */
static inline int 
nf_hook_thresh(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
               struct net_device *indev, struct net_device *outdev,
               int (*okfn)(struct sk_buff *), int thresh)
{
#ifndef CONFIG_NETFILTER_DEBUG
    if (list_empty(&nf_hooks[pf][hook]))
        return 1;
#endif
    return nf_hook_slow(pf, hook, skb, indev, outdev, okfn, thresh);
}

static inline int
nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
        struct net_device *indev, struct net_device *outdev,
        int (*okfn)(struct sk_buff *))
{
    return nf_hook_thresh(pf, hook, skb, indev, outdev, okfn, INT_MIN);
}
                   
/* Activate hook; either okfn or kfree_skb called, unless a hook
   returns NF_STOLEN (in which case, it's up to the hook to deal with
   the consequences).

   Returns -ERRNO if packet dropped.  Zero means queued, stolen or
   accepted.
*/

/* RR:
   > I don't want nf_hook to return anything because people might forget
   > about async and trust the return value to mean "packet was ok".

   AK:
   Just document it clearly, then you can expect some sense from kernel
   coders :)
*/

static inline int
NF_HOOK_THRESH(uint8_t pf, unsigned int hook, struct sk_buff *skb,
               struct net_device *in, struct net_device *out,
               int (*okfn)(struct sk_buff *), int thresh)
{
    int ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, thresh);
    if (ret == 1)
        ret = okfn(skb);
    return ret;
}

static inline int
NF_HOOK_COND(uint8_t pf, unsigned int hook, struct sk_buff *skb,
             struct net_device *in, struct net_device *out,
             int (*okfn)(struct sk_buff *), bool cond)
{
    int ret;

    if (!cond ||
            (ret = nf_hook_thresh(pf, hook, skb, in, out, okfn, INT_MIN) == 1))
        ret = okfn(skb);
    return ret;
}

static inline int
NF_HOOK(uint8_t pf, unsigned int hook, struct sk_buff *skb,
        struct net_device *in, struct net_device *out,
        int (*okfn)(struct sk_buff *))
{
    return NF_HOOK_THRESH(pf, hook, skb, in, out, okfn, INT_MIN);
}

#else /* !CONFIG_NETFILTER */

#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
#define NF_HOOK_COND(pf, hook, skb, indev, outdev, okfn, cond) (okfn)(skb)
static inline int 
nf_hook_thresh(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
               struct net_device *indev, struct net_device *outdev,
               int (*okfn)(struct sk_buff *), int thresh)
{
    return okfn(skb);
}

static inline int 
nf_hook(u_int8_t pf, unsigned int hook, struct sk_buff *skb,
        struct net_device *indev, struct net_device *outdev,
        int (*okfn)(struct sk_buff *))
{
    return 1;
}
#endif /*CONFIG_NETFILTER*/
如果沒有defined CONFIG_NETFILTER,NF_HOOK()其實就是直接呼叫okfn了。到這邊對於netfilter的運作就有基本的認識了,有機會hack其他關於netfilter的心得再和大家分享。

Kernel version:2.6.36



2010年11月6日 星期六

gnu screen


gnu screen是我非常喜歡的tool之一,在這邊寫個筆記紀錄一下免得離開Linux太久忘了。
更多資訊您可以參考http://www.gnu.org/software/screen/


"screen"提供一個window的管理機制,讓您的terminal可以在多個processes中切換。"screen"的指令預設都以"ctrl + a"為開頭。
ctrl + ? Show key bindings.

Window控制

C-a + c 建立一個新的window。
C-a 0...9 在window0~9之間切換。
C-a C-a 在目前和之前的window之間切換。
C-a A 輸入title到目前的window。
C-a n 切換到下一個window。
C-a p 切換到上一個window。
C-a " 列出所有的window供選擇切換。
C-a w 列出所有的window。

Session Management

C-a d Detach the screen session
C-a x lock screen

Copy

C-a [ copy,當您按下"C-a ["之後,您就會進入"Copy Mode",您可以移動滑鼠到您想複製的起始位置,接著按下空白鍵,然後在移動到您想複製結束位置按下空白鍵,接著切換到另外一個window按下"C-a ]"就可以貼上了。

Regions

C-a S Split the current region into two new ones.
C-a Tab Move the input focus to the next region.
C-a Q Kill all regions but the current one.
C-a X Kill the current region.

Logging

C-a H Begins/ends logging of the current window to the file ‘screenlog.n’ in the window’s default directory, where n is the number of the current window.

others

C-a : 進入command line模式。


我最愛的screenrc檔
hardstatus alwayslastline "%{= wk} %{by} %H %{wk} | %-Lw%{kw}.%{= g}%n%f* %t%{wk}.%{wk}%+Lw%< %= %{kw}.%{= G} Load: %l %{= R} [%m/%d %c] %{-}"
defscrollback 8192

熱門文章