My git alias in .bashrc

CREATED: <2012-12-26 Wed>

UPDATED: <2017-11-02 Thu>

My favorite alias are g, gau, gc, gt, gl,and gdc.

# {{ git
# Git alias
function gitshortlogcmd () {
    git log --date=short --decorate --graph "$@"
}
function gitlogcmd () {
    git log --date=short --decorate --graph --pretty=format:'%C(yellow)%h%Creset%C(green)%d%Creset %ad %s %Cred(%an)%Creset' "$@"
}
alias g="git status --short -b"
alias gb="git branch"
alias gn="git status --untracked-files=no --short -b"
alias gfl="git diff-tree --no-commit-id --name-only -r"
alias ga="git add"
alias gr="git rebase -i `git remote`/`git symbolic-ref --short HEAD`"
alias gap='git add --patch'
alias gai='git add -i'
alias gau="git add -u"
alias gc="git commit -m"
alias gca="git commit --amend"
alias gja="git --no-pager commit --amend --reuse-message=HEAD" # git just amend
alias gt="git stash"
alias gta="git stash apply"
alias gmt="git mergetool"
alias gl="gitlogcmd"
alias glp="gitlogcmd -p"
alias gls="gitlogcmd --stat"
alias gnb="git checkout -b"
alias gss="git show --stat"
alias gsl="git log --pretty=format:'%h %s (%an)' --date=short -n1 | pclip"
alias gd="git diff"
alias gds="git diff --stat"
alias gdc="git diff --cached"
alias gdcs="git diff --cached --stat"
alias gps="git push"
alias gpf="git push --force"
alias gpl="git pull"
alias gpr="git pull -r"
alias cg='cd $(git rev-parse --show-toplevel)' #goto root dir
alias ghe='git diff --name-only --diff-filter=U|grep "\.html\|\.min\.js"|xargs -I{} sh -c "git checkout --theirs {} && git add {}"'
alias gme='git diff --name-only --diff-filter=U|grep "\.html\|\.min\.js"|xargs -I{} sh -c "git checkout --our {} && git add {}"'
# delete selected local branch
alias gdd='git branch -D $(git branch | sed "s/[\* ]\+//g" | ~/bin/percol.py)'
# show diff from the branch to current HEAD
alias gdp='git diff $(git branch | sed "s/[\* ]\+//g" | ~/bin/percol.py)..HEAD'
alias grh='git reset --hard HEAD'
alias gr1='git reset --hard HEAD^'
alias gr2='git reset --hard HEAD^^'
alias gs="git show"

function gsh {
    git log --date=short --pretty=format:'%h%d %ad %s (%an)' | python ~/bin/percol.py | awk '{print $1}' | xargs -i git show {}
}

function gcn()
{
    # commit with timestamp
    local d=`date +%m%d-%H%M%S`
    git add -u . && git commit -m ${d}
}

# find full path of file who under git controll
# the optional parameter is the keyword
function gf()
{
    if [ -z "$1" ]; then
        local cli=`git ls-tree -r HEAD --name-status | python ~/bin/percol.py`
    else
        local cli=`git ls-tree -r HEAD --name-status | grep "$1" | python ~/bin/percol.py`
    fi
    local rlt=$(cd $(dirname $cli); pwd)/$(basename $cli)
    echo ${rlt}
    echo -n ${rlt} | pclip
}

function glwho () {
    local guy=`git shortlog -sn | ~/bin/percol.py | sed 's/^\s*[0-9]\+\s*//g'`
    # space is a problem, so we can't use gitshortlogcmd here
    gitshortlogcmd --pretty=format:'%C(yellow)%h%Creset%C(green)%d%Creset %ad %s %Cred(%an)%Creset' --author="$guy" "$@"
}

function gfp ()  {
    if [ -z "$1" ]; then
        echo "Usage: gfp since [file]"
        echo "  Just alias of 'git format-patch -n --stdout since -- [file]'"
        echo "  'gfp since | git am' to apply the patch"
    fi
    git format-patch -n --stdout $1 -- $2
}

function gcnb () {
    local remoteb=$(git branch --all | sed '/no branch/d' | ~/bin/percol.py)
    local localb=$(echo $remoteb | sed 's/^ *remotes\/[a-z]*\///g')
    git checkout -b $localb $remoteb
}
function grb () {
    # switch to recent git branch or just another branch

    local crtb=`git branch | grep \*`
    local ptn="no branch"
    # compatible way to detect sub-strin in bash
    # @see http://stackoverflow.com/questions/229551/string-contains-in-bash
    if [ -z "${crtb##*$ptn*}" ]; then
        # detached HEAD
        git checkout $(git branch | sed '/no branch/d' | ~/bin/percol.py)
    else
        local myrbs=`git for-each-ref --sort=-committerdate refs/heads/ | sed -e s%.*refs\/heads\/%%g`
        local crb=`git symbolic-ref --short HEAD`
        git checkout `echo "$myrbs" | sed '/$crb/d' | ~/bin/percol.py`
    fi
}

# rebase on LOCAL branches
function gri () {
    local b=`git branch | sed 's/[\* ]\+//g' | ~/bin/percol.py`
    git rebase -i ${b}
}

# rebase on ALL braches
function gra () {
    local b=`git branch --all | sed 's/[\* ]\+//g' | sed 's/remotes\///g' | ~/bin/percol.py`
    git rebase -i ${b}
}

# select a local git branch
function gsb () {
    local b=`git branch | sed "s/[\* ]\+//g" | ~/bin/percol.py`
    echo -n ${b} | pclip;
    echo ${b}
}

# print current branch name
function gcb () {
    local crb=`git symbolic-ref --short HEAD`
    echo -n ${crb} | pclip;
    echo ${crb}
}

# new local branch based on remote branch
function gnr () {
    local myrb=`git for-each-ref --sort=-committerdate refs/remotes/ | sed -e s%.*refs\/remotes\/%%g | ~/bin/percol.py`
    local mylb=`echo -n $myrb | sed 's/.*\/\([^\/]\+\)$/\1/'`
    git checkout -b $mylb $myrb
}

function gchk () {
    if [ -z "$1" ]; then
        echo "Usage: gchk commit_id"
        echo "reset hard certain version of current working directory"
    else
        rm -rf $PWD/*
        git checkout $1 -- $PWD
    fi
}

function git2fullpath {
    local fullpath=$(git rev-parse --show-toplevel)/$1
    echo -n $fullpath | pclip
    echo $fullpath
}

function glf () {
    local str=`git --no-pager log --oneline --name-only $* |  ~/bin/percol.py`
    git2fullpath $str
}


function gsf () {
    local str=`git --no-pager show --pretty=format:'%h %s (%an)' --name-only $* |  ~/bin/percol.py`
    git2fullpath $str
}

function gdf () {
    local str=`git --no-pager diff --oneline --name-only $*| ~/bin/percol.py`
    git2fullpath $str
}

function gdcf () {
    local str=`git --no-pager diff --oneline --cached --name-only $* |  ~/bin/percol.py`
    git2fullpath $str
}

function ggr () {
  if [ -z "$1" ]; then
      echo "Grep files under git controll"
      echo "Usage: ggr [filename-pattern] text-pattern"
  elif [ $# -eq "1" ]; then
      git ls-tree -r HEAD --name-only |  xargs grep -sn "$1"
  elif [ $# -eq "2" ]; then
      git ls-tree -r HEAD --name-only | grep "$1" | xargs grep -sn --color -E "$2"
  fi
}

function grpc() {
  if [ -z "$1" ]; then
      echo "Replace the content of file in latest git commit"
      echo "Usage: grpc [commit-hash] old_string new_string (string could be perl regex)"
  elif [ $# -eq "2" ]; then
      git diff-tree --no-commit-id --name-only -r HEAD | xargs perl -pi -e "s/$1/$2/g"
  elif [ $# -eq "3" ]; then
      git diff-tree --no-commit-id --name-only -r $1 | xargs perl -pi -e "s/$2/$3/g"
  fi
}

function grpf() {
  if [ -z "$1" ]; then
      echo "Replace the content of file under git"
      echo "Usage: grpf old_string new_string (string could be perl regex)"
  elif [ $# -eq "2" ]; then
      git grep -l "$1" | xargs perl -pi -e "s/$1/$2/g"
  fi
}

function gp() {
    if [ $# = 0 ]; then
        local from=`gitshortlogcmd --pretty=format:'%h %ad %s (%an)' $* | ~/bin/percol.py|sed -e"s/^[ *|]*\([a-z0-9]*\) .*$/\1/"`;
        local fn=from-$from-`date +%Y%m%d-%H%M`.patch
        git format-patch -n --stdout $from > $fn && ls $fn
    else
        local fn=from-$1-`date +%Y%m%d-%H%M`.patch
        git format-patch -n --stdout $1 > $fn && ls $fn
    fi;
}
# }}

Emacs中的完美多窗口操作

典型的工作流

  1. 在两个子窗口中对比文件内容
  2. 打开更多的窗口以参考其他信息.
  3. 对某个窗口内容比较有兴趣,跳转到该窗口,将该窗口最大化
  4. 看完最大化的窗口内容后,undo最大化操作,重新回到早先的多个小窗口模式以便继续纵览全局

将子窗口自动编号,然后按M-0…9跳转(最爱)

安装window-numbering.el,然后在.emacs中添加以下代码,

(require 'window-numbering)
(window-numbering-mode 1)

undo/redo之前的窗口操作(最爱)

安装Winner Mode,然后在.emacs中添加以下代码,

(winner-mode 1)

;; copied from http://puntoblogspot.blogspot.com/2011/05/undo-layouts-in-emacs.html
(global-set-key (kbd "C-x 4 u") 'winner-undo)
(global-set-key (kbd "C-x 4 r") 'winner-redo)

焦点移动到下一窗口(常用)

M-x other-window,快捷键是`C-x o`.

水平/垂直切分当前窗口(常用)

快捷键C-x 2/3

将当前子窗口最大化(常用)

M-x delete-other-windows,快捷键`C-x 1`.

删除当前子窗口(偶尔用)

M-x delete-window (快捷键`C-x 0`)

顺便说一下,M-x kill-buffer-and-window (快捷键`C-x 4 0`),我现在用得更多 些.

移动焦点到上下左右的窗口(基本不用)

因我较喜欢vi快捷键,所以我安装了Evil Mode.快捷键和Vi一样. C-w h/j/k/l移动至各方向的子窗口.

存储/载入窗口布局到register(基本不用)

`C-x r w`存储,`C-x r j`载入.

Convert TEX to PDF

Install TexLive in your OS.

Install latex2pdf which is dependent on TexLive.

cpan App::cpanminus # handy tool to install cpan module
cpanm Template # Template is missing on cygwin
cpanm latex2pdf # finally

Convert now!

pdf2latex cv.tex

Install perl module through source package on cygwin by using cpanm

I failed to install package "Template" by running `cpanm Template'.

It's because the binary package requires gcc4 while on my cygwin only gcc3 available.

So I install it from source package (with some hack, of course),

cpanm --look Template # Download and unpack the distribution and then open the directory with your shellI
cpanm . #install from local directory

Updated: The simpler solution is to install gcc4 at cygwin.

How to convert org to PDF

Install TexLive. The org-mode has some handy function to locate the TexLive. Press C-c C-e p to convert.

At Cygwin and Linux, installing TexLive could be installed by their package system.

At macOS, I use the TexLive source package (install-tl-unx.tar.gz). After installation, environment varaibles need be set.

Bash shell requires setup in ~/.bashrc,

if [[ `uname -s` == *Darwin* ]]; then
   #tex live on OS X
   export PATH=/usr/local/texlive/2011/bin/universal-darwin:$PATH
   export MANPATH=/usr/local/texlive/2011/texmf/doc/man:$MANPAH
   export INFOPATH=/usr/local/texlive/2011/texmf/doc/info:$INFOPATH
fi

Notes on Emacs chat between John Wiegley and Sacha Chua

See http://sachachua.com/blog/2012/07/transcript-emacs-chat-john-wiegley/ for the video and transcript.

I only record key points,

  • Use gnus heavily
  • ERC in another Emacs instance
  • Look at Magit buffer to get overview
  • Use built in vc mode, `C-x v =' to get diff of current file
  • One single org, other seven are archives
  • Helm (fork of anything.el)
  • Gnus read mail and rss (gwene), Adaptive scoring is good.
  • fetchmail to fetch from Gmail
  • Organize Structure (rename/moving files folders)
  • Twenty items in hot list in org-mode linking to other lists and areas of machine
  • Dropbox to record voice at http://dropbox.com and org-mode hook to get voice message
  • M-m to call `org-capture'
  • 'Quick Keys' on Mac plus some apple script (Viewing page in Chrome, M-n to activate emacs, put a link)
  • Emacs can view PDF
  • Reading Emacs manual from the scratch
  • Emacspeak to read the manual
  • Ledger for the accounting

How to configure yasnippet 0.7.0 and use it with Auto-Complete-Mode

I will only talk about how to set up yasnippet 0.7.0 or higher version.

If you follow `normal install` way, setup is simple

See its official documentation.

Install the yasnippet into somewhere and add following code into your .emacs:

(add-to-list 'load-path
              "~/.emacs.d/plugins/yasnippet-x.y.z")
(require 'yasnippet) ;; not yasnippet-bundle
(yas/initialize)
(yas/load-directory "~/.emacs.d/plugins/yasnippet-x.y.z/snippets")

If you use elpa package system, setup is even simpler

After installation, you only need two lines in .emacs.

(require 'yasnippet)
(yas/initialize)

Yasnippet 0.7.0 have already defined two locations for the snippets, "~/.emacs.d/yasnippet-install-path/yasnippet-x.y.z/snippets" and "~/.emacs.d/snippets". Yasnippet will load snippets in BOTH directories at startup.

So you only put your own snippets in "~/.emacs.d/snippets" and done. No need to tweak .emacs at all. To verify my claim, you can `C-h v yas/snippet-dirs' to check value of "yas/snippet-dirs". Please note "yas/root-directory" is the alias of "yas/snippet-dirs".

The real world setup is NOT simple

I will explain the reasons at first and give my complete yasnippet configuration code at the end of the this post.

Two snippets may share the same key, so I need activate `yas/dropdown-prompt'

One issue is I need a user-friendly dropdown window popped up when the key I input has several candidates. For example, when I type "inc" in C code. There are two candidates `#include "…"' and `#include <…>' available. A handy dropdown popup will help me to choose one of them as efficient as possible.

The good news is such fancy popup is a standard component of yasnippet. It's called `yas/dropdown-prompt'. Its default algorithm will activate it at highest priority.

The bad news is for some strange reason yasnippet won't load that dropdown-list by default. So you need manually load that component by one line of elisp code `(require 'dropdown-list)'.

`yas/dropdown-prompt' is not perfect

I cannot scroll down the dropdown window when there are more candidates it can display. That's especially annoying when calling `yas/insert-snippet'. In this case, we need use `yas/completing-prompt' instead. I will show the fix at the end of this article.

Yasnippet conflicts with other plugins

I use Auto Complete Mode (version 20120327 in elpa). There are two issues when using it with yasnippet.

First, it use TAB key to do the auto-complete thing while yasnippet also uses TAB key. So I need re-configure hotkeys of yasnippet.

Second, yasnippet changed its API `yas/get-snippet-tables' since version 0.7.0. This make the auto-complete cannot use yasnippet at all. This issue is reported and fixed by tkf. Actually all you need do is simple:

cd auto-complete-install-dir
rm auto-complete-config.elc
curl -L https://raw.github.com/tkf/auto-complete/337caa2ccc254a79f615bb2417f0d2fb9552b547/auto-complete-config.el > auto-complete-config.el

My final yasnippet setup

(require 'yasnippet)
(yas/initialize)
;; default TAB key is occupied by auto-complete
(global-set-key (kbd "C-c ; u") 'yas/expand)
;; default hotkey `C-c & C-s` is still valid
(global-set-key (kbd "C-c ; s") 'yas/insert-snippet)
;; give yas/dropdown-prompt in yas/prompt-functions a chance
(require 'dropdown-list)
;; use yas/completing-prompt when ONLY when `M-x yas/insert-snippet'
;; thanks to capitaomorte for providing the trick.
(defadvice yas/insert-snippet (around use-completing-prompt activate)
     "Use `yas/completing-prompt' for `yas/prompt-functions' but only here..."
       (let ((yas/prompt-functions '(yas/completing-prompt)))
             ad-do-it))

在我的Mac OS X 10.7.3上为heroku开发rails程序

rails版本为3.1,OS X版本10.7.3,postgresql版本9.1.3j

数据库必须用postgresql

heroku官方主页反对开发版本用sqlite3而生产版本用postgresql.

在OS X 10.7.3上安装postgresql

首先,检查你的OS X版本,从10.7开始OS X自带postgresql

sw_vers -productVersion

如果要安装最新版的postgresql,必须删除老版本的数据库。具体做法参考这篇文章,实际上也就是一行命令:

curl http://nextmarvel.net/blog/downloads/fixBrewLionPostgres.sh | sh

强烈推荐用homebrew安装数据库,

brew install postgresql

具体安装细节请参考postgresql官方wiki.

检测已安装的postgresql

这里是一些数据库基本操作的官方文档. 可以`psql -l`看一些已有数据库列表.

数据库用postgresql的rails项目

rails new myapp --database=postgresql

如果是从一个已经使用sqlite的项目切换数据库,就必须改config/database.yml,有一些catch,请参考stackoverflow上的讨论.

然后,`createdb myapp_development`创建postgresql数据库,`rake db:migrate`建立数据库schema并导入数据在本地数据库.简单测试可证明数据库和web程序可以无缝工作.

最后不要忘记`git commit`最新代码.

部署web程序到heroku

请参考heroku官方文档,提醒一下不要忘记运行`heroku run rake db:migrate`,否则数据库是空的.

部署结束后可以运行`heroku open`打开浏览器访问web程序首页.

如打开网站有问题,可以`heroku logs`查看日志.

针对Ruby on Rails开发的Emacs插件

我主要用两个插件rinariyari.

rinari支持在rails项目中多个文件快速跳转,另外它提供的grep工具我发觉也很有用.快捷键很容易记.

yari对ruby自带的ri工具提供一个emacs界面,优点是兼容最新的ruby,操作简单,只要使用一个函数yari-anything即可.但是其官方文档推荐的yari-anything的快捷键F1在有些远程terminal下有问题.我改成了`C-c ; r`.

阅读了rails中使用bootstrap相关文章的小结

Luca Pette的Twitter Bootstrap on Rails比较简单,直接使用了bootstrap的css,没用less,测试了simple_form,show_for,kaminari(分页数据)三个应用。要点在于kaminari有点兼容性问题,用twitter-bootstrap-kaminari-views解决这个问题,其他没难度。

@metaskill的LESS Is More - Using Twitter's Bootstrap In The Rails 3.1 Asset Pipeline讲了如何用bootstrap的less函数和变量,我很有兴趣,根据我的经验能通过less语法调用twitter的函数比较有价值。安装gem `less-rails-bootstrap`就行了,调用bootstrap的函数的技术细节省略,基本就是less语法。

Adding Twitter's Bootstrap CSS to your Rails app的作者也读了以上两篇文章,要点在于确认了@metaskill的方法,less的一些详细的例子。也提到了可以用sass,但我没有深入读下去。

Twitter Bootstrap Basics at railscasts.com非常好,一个完整的例子。Comments也不错,一些html细节。要点在于用了gem`twitter-bootstrap-rails`,看起来很强大。

结论,看来我需要转向less而不是sass,因为bootstrap用less。