Posts Tagged ‘git’

My programming environment
Back in the old days, machines with less than 32 megabytes of RAM and 6 gigabytes of HDD were more than enough for software development. My first somewhat complex programs (small games, dynamic webpages, etc) have been written on a machine with even less resources than that. So once when I’ve taken a look at my resource usage while working on some PHP code in Eclipse and I’ve seen that the IDE used hundreds of megabytes of RAM and another half gigabyte was allocated by the browser, I began to wonder if it is possible to edit source code with a little less resource footprint but without loosing much of the handy tools an IDE can offer. And it turns out, definitely it is!
Switching to a lightweight desktop environment
Instead of Gnome or Unity, I started to use Fluxbox. I chose a nice theme in the right-click menu and was happy with my new desktop. I can start programs from that menu, or invoke them by typing their names into the small dialog box that pops up when pressing Alt+F2 (and it has tab completion).
I’m used to a couple of keyboard shortcuts for common actions like locking the screen or firing up a terminal so I added the following lines to my ~/.fluxbox/keys file:
Control Alt L :Exec xlock
Control Alt T :Exec /usr/bin/xterm -fa Monaco -fs 12 -fullscreen
As you can see, I switched to XTERM from gnome-terminal, but still wanted to use a nice monospace font.
I also said goodbye to Network Manager. Instead I use a small shell script to connect to wifi networks. I don’t like storing passwords on disk anyways.
Another thing I was missing was the desktop background image. Setting up one in Fluxbox is a little user-unfriendly though. You need to add the following line to your ~/.fluxbox/startup file:
feh --bg-center ~/Pictures/background.jpg &
I noticed that screensaver was no longer started automatically. So I set up my ~/.xscreensaver file using xscreensaver-demo and added the following line to my Fluxbox startup file:
xscreensaver -nosplash &
That’s all it took for me to get a desktop environment that fits my daily needs.
Tweaking the command line environment
Since XTERM does not support tabs, I started to use screen to overcome that. My .screenrc is really simple, it sets up a basic statusline, increases the scrollback buffer size and starts bash in four tabs:
startup_message off
vbell off
autodetach on
defscrollback 5000
hardstatus alwayslastline
hardstatus string '[%c] %w'
screen 0 bash
screen 1 bash
screen 2 bash
screen 3 bash
Speaking of bash, I decided to set up a prompt that tells me everything that might be important:
- username
- host name
- when did the last command finish
- exit status of the last command
- laptop battery state if available
- current working directory
- current git branch when working in a version controlled directory
- was the shell started from inside Vim, so I will not invoke
vim
inside it again
I have some requirements about its display as well:
- stand out from command outputs when scrolling back and forth in the
terminal window - start in a new line, even if the previous command did not output one
- various fields displayed should be easily spotted, e.g. nice formatting and
color codes - look nice on dark background
- don’t exceed 90-100 characters so in most environments, stay in one line
(this implies that stuff that can be long, e.g. current working directory,
needs to be truncated in a useful way) - the next command to be typed in should start close to the beginning of the
line (e.g. by putting it in a separate line)
An example:
--( athos@localhost[22:50:02] <0> [D42%] ~/projects/dotfiles @master )--
$ ls /tmpAnd the .bashrc snippet to do all that (I know, it’s a bit messy):
LIGHTRED='\[\033[1;31m\]'
LIGHTGREEN='\[\033[1;32m\]'
YELLOW='\[\033[1;33m\]'
LIGHTBLUE='\[\033[1;34m\]'
LIGHTPURPLE='\[\033[1;35m\]'
LIGHTCYAN='\[\033[1;36m\]'
WHITE='\[\033[1;37m\]'
NOCOLOR='\[\033[0m\]'
# Prompt
# ------
# Start with a newline as some commands don't end their output with one
PS1="\n$WHITE--("
# Integration with my .vimrc that exports a variable for shells started from vim
PS1="$PS1 \${PROMPT_EXTRA}"
# username@hostname[hh:mm:ss]
PS1="$PS1 \u@$YELLOW\h$WHITE[\t]"
# Exit code of the latest command: green "<0>" or red ">NON-ZERO<"
PS1="$PS1 \$(__x=\$?; if [[ \$__x -ne 0 ]]; then"
PS1="$PS1 echo -n \"$LIGHTRED>\$__x<\";"
PS1="$PS1 else echo -n \"$LIGHTGREEN<\$__x>\"; fi)"
# Display battery info if available
PS1="$PS1$LIGHTCYAN\$(acpi -b 2>/dev/null |"
PS1="$PS1 sed -r 's/^.*(: ([a-z])[a-z]*, ([0-9]*%)).*\$/ [\\2\\3]/i' |"
PS1="$PS1 grep --color=never -m1 '^ \\\\[.*\\\\]\$')"
# Last max 30 characters of current working directory with a less-than sign
# when truncated
PS1="$PS1 $LIGHTPURPLE"
PS1="$PS1\$(echo '\w' | sed -r 's/^.*.(.{30})/<\1/')"
# When inside a git repo, display the name of the current working branch
PS1="$PS1$LIGHTBLUE\$(git branch 2>/dev/null | grep -m1 --color=never '^[*] '"
PS1="$PS1 | sed 's/^[*] / @/')"
# New command to be entered in a new line
PS1="$PS1 $WHITE)--\n\\\$ $NOCOLOR"
# Adjust the title of the terminal window
case "$TERM" in
xterm*|rxvt*)
PS1="\[\e]0;\$PROMPT_EXTRA \u@\h: \w\a\]$PS1"
;;
*)
;;
esac
On different machines I have a .bashrc file set up on I use different colors for the hostname field, so I am less likely to mistakenly execute commands on a remote machine that I intend to run on localhost.
PROMPT_EXTRA is an environment variable that is set by my .vimrc for example, when invoking bash from a hotkey.
The editor: Vim
Switching to Vim from Eclipse took some time for me. Understanding various modes of the editor, the commands for movement and actions in those modes, the commandline, regular expression search and replace tricks, indentation, marks, tabs, windows, well, there is plenty of stuff to learn! The command vimtutor can help a lot with learning the first few steps of using Vim and a cheatsheet you make for yourself containing all the things you feel the need to learn is a must-have as well. For a couple of months I had my cheatsheet written on my desktop background image so it was always with me when I needed it, both at work, at home or even on the train. It looked something like this:
Move: hjkl b w e $ Go to matching bracket: [( [{ ]) ]}
Modes: <esc> i o a v Undo, redo: u, <ctrl>+r
Mark, go to mark: mX 'X `X Autocomplete: <ctrl>+p <ctrl>+n
Copy, cut: yMOVE yy, dMOVE dd Paste: p P
Go to line 100: 100G :100 Cut and switch to INSERT mode: cMOVE
Search, next, prev: :/regexp, n, N Search word under cursor: *
Replace between lines 40-42: :40,42s/search/replace/g
Replace in entire file: :%s/search/replace/g
Indent: <MOVE >MOVE Indent next 7 lines: 7>> 7<<
Reindent: =MOVE Reindent next 10 lines: 10==
Replace string constant: ci" ci' Rewrap next 5 lines of text: 5gqq
Open new tab: :tabedit file.txt Move between tabs: gt <number>gt
New window: :vsplit|:hsplit file Switch window: <ctrl>+w hjkl
Move window: <ctrl>+w HJKL Maximize window: <ctrl>+w _
All windows equal: <ctrl>+w = Change window size: <ctrl>+w -|+
Exec: :!<shell cmd> Exec on all lines: :%!<shell cmd>
Hex-editor: :%!xxd :%!xxd -r
Useful commands:
:edit :file :w :q :qall :q! :wq
:tabedit :Explore :syntax on :set expandtab
:set number :set tabstop=4 :set shiftwidth=4 :set autoindent
:set smartindent :set paste :set nopaste :set formatoptions+=r
:set ignorecase :set smartcase :set incsearch :set hlsearch
:nohl
Once I was familiar with the basics, I began to steal ideas from colleagues, and to customize Vim using the ~/.vimrc file. There are a lot of small features that a programmer is likely to turn on in Vim that are not enabled by default (this is an excerpt from my .vimrc, lines beginning with quote are interpreted as comments):
" Turn on line numbers
set number
" Tabs are displayed as 4 characters wide
set tabstop=4
" Indentation is 4 spaces
set shiftwidth=4
" Insert 4 spaces instead of tabs
set expandtab
" Automatic indentation
set autoindent
set smartindent
" Search while typing pattern
set incsearch
" Highlight search pattern matches
set hlsearch
" Automatically format doxygen style comments
set comments=sl:/**,mb:\ *,elx:\ */
" Insert comment leader when hitting enter in insert mode
set formatoptions+=r
" Insert comment leader when hitting o in normal mode
set formatoptions+=o
" Font name for gVim
set guifont=Monaco
" Draw a margin in the 81th column
set colorcolumn=81
" Show current line and column numbers
set ruler
" Command line is 2 lines, so it's easier to type complex commands
set cmdheight=2
" Highlight syntax
syntax on
" Some nice colorscheme
colors evening
" Make constants readable on projector as well
highlight Constant ctermbg=black ctermfg=green
" Always highlight tabs and trailing spaces.
set list
set listchars=tab:>\ ,trail:.,nbsp:.
" Always assume Unix-style line endings
set fileformats=unix
With those settings, Vim can be turned into a very programmer-friendly, basic code editor. To make it even more convenient, you can define your own hotkeys and command aliases:
" Make frequent typos work.
command Q :q
command W :w
command Wq :wq
command WQ :wq
command Wqall :wqall
command WQall :wqall
command WQAll :wqall
" Pressing F5 will invoke a bash shell and return to the window right after.
nnoremap <F5> :! clear; PROMPT_EXTRA='[VIM]' bash<CR><CR>
" Pressing F8 will turn off search highlighting
nnoremap <F8> :nohl<CR>
" Ctrl+o will open explorer in a vertical split window
nnoremap <C-o> :Texplore<CR>
" Set default view mode for explorer to tree
let g:netrw_liststyle=3
" Make explorer hide Vim's swap files
let g:netrw_list_hide='.*\.swp$'
" Pressing 't' will jump to the next search pattern match and bring it to
" the center
nnoremap t nzz
" Pressing 'T' will jump to the last search pattern match and bring it to
" the center
nnoremap T Nzz
Git hotkeys in Vim
I created a shell script and a few hotkeys to make it easy to access information from Git that I’m likely to need when looking at some code in the editor:
" Pressing F2 will show the complete git history of the file
nnoremap <F2> :!clear; vim_git.sh log "%"<CR><CR>
" Pressing F3 will search the git repository for the word under the cursor.
nnoremap <F3> :!clear; vim_git.sh grep "%" "<cword>"<CR>
" Pressing F4 will attempt to git-blame the line under the cursor.
command GitBlame :echo system('vim_git.sh blame '''.expand('%').''' '.line('.'))
nnoremap <F4> :GitBlame<CR>
Accessing manuals and API docs from Vim
By pressing K in normal mode, Vim will attempt to lookup the word under the cursor in man pages, which is nice for C developers. Since I work a lot with PHP and some other languages as well, I’ve created a small script that can extend this functionality. This script can search in an offline HTML copy of PHP’s manual in case of PHP, or can hunt through GLib’s HTML docs or the man pages in case of C/C++, or can use Google to find info about the given identifier in the context of the given programming language. (Needs
Links or similar terminal based browser to display stuff from the web or offline HTML pages.)
I did not put much effort into it, but it’s very easy to extend if you plan to use it.
To invoke that script when pressing K instead of the built-in behavior, I added the following to .vimrc:
" Pressing K will invoke vim_lookup_docs.sh in the PATH with the current
" filename and the word under the cursor. That script may attempt to open
" relevant docs according to the given arguments. Mine guesses file type
" by it's extension and either looks up the given word in various offline
" documentation or uses Google depending on file type.
nnoremap K :!vim_lookup_docs.sh "%" "<cword>"<CR><CR>
Autocomplete and code navigation: Vim + Ctags
By default, Vim offers words from all its opened buffers when pressing Ctrl+p or Ctrl+n. This is certainly more than nothing, but with additional tools, Vim can do much better. Ctags is a tool that can generate an index for entire source code directories based on the lexical elements found in the code. Many text editors, including Vim, can use such an index (tag file) to offer autocomplete suggestions or navigate throughout the code. I use Exuberant Ctags which supports a big variety of programming languages.
I like to keep my tag file near the source code I work with, but I do not want to version control it, so I use a name that most of the .gitignore files I come across will match: .tags.pyc. I know, it’s an ugly hack, but it works most of the time. ![]()
Of course, I like to keep my tag file up-to-date, but regenerating it every time I save a file in Vim would take too much resources, so I use a wrapper script around ctags that can decide when to re-generate and when and how to update the tag file based on simple heuristics.
Ctags integration in my .vimrc:
" Use .tags.pyc as a tagfile to offer suggestions when pressing Ctrl+P. This
" filename will most likely be ignored by any .gitignore files without any
" additional work. Requires vim_ctags.sh to be on PATH.
set tags=./.tags.pyc;/
command Ctags silent! !vim_ctags.sh ".tags.pyc" "%" &
autocmd BufWritePost *.c,*.cpp,*.cc,*.h,*.hpp,*.hh,*.php* Ctags
autocmd BufWritePost *.js,*.java,*.py,*.pl,*.rb,*.cs,*.sh Ctags
Ctags
When the cursor is on an identifier defined in another file in the source code, Vim can open up its definition by pressing Ctrl+]. To get back to the code using the identifier, Ctrl+t is the shortcut to use. Both these shortcuts work using the same tab or window, which I don’t really like, so I had to override these shortcuts in .vimrc to work with new tabs instead:
" Map usual tag shortcuts to use tabs
map <C-]> :tab split<CR>:exec("tag ".expand("<cword>"))<CR>
map <C-t> :tabprevious<CR>
Green bar, red bar: running unit tests from Vim
Doing TDD involves running tests in every few minutes, sometimes even seconds, so a code editor should make the basic steps of it as instant as possible. Also, the feedback from those tests should be quick and simple, yet informative. Most big IDEs can run tests and display a green or red bar depending on the result of the tests. In case of tests passing, they remain silent, but on failure, they display info about the mismatch between test expectations and actual behavior. I wanted this in Vim as well! I created a shell script again that can guess how to run tests in the directory it is invoked in. It runs tests, displays and saves their output for later use, and returns an exit code according to the result. A simple script in Vim can invoke this shell script and color the statusbar based on the result, and in case of failure, it can open the output of tests in a split window.
Let .vimrc speak:
" Pressing F9 will attempt to invoke unit tests through a shell script named
" vim_run_tests.sh and open the output in a new window in case of failure.
function RunTests()
:!clear; vim_run_tests.sh /tmp/__test_output
:if shell_error!=0
:14split + /tmp/__test_output
:hi StatusLine ctermfg=darkred ctermbg=white guibg=darkred guifg=white
:else
:hi StatusLine ctermfg=darkgreen ctermbg=black guibg=darkgreen guifg=black
:endif
endfunction
nnoremap <F9> :exec RunTests() <CR><CR>
vim_run_tests.sh looks for either a Makefile or a build.xml, and in case of the former, it uses my other script called bake to do the build out-of VCS tree.
Demo
Here’s a short screencast demonstrating some code editing in my CLI environment, recorded on an eeePC two years old (however, gtk-recordMyDesktop is slow as hell):
Summary
There are tons of plugins for Vim on the Internet I could choose from, and I’m sure they are so much better polished and offer way more features than my hacks within these scripts, but for me, these scripts and configurations have one key advantage compared to having a bunch of make-a-big-ass-IDE-out-of-Vim plugins: I know exactly what they do and when they do it, and they do their work exactly when I tell them to. Besides, scripting and configuring the hell out of your tools is certainly a fun thing to do, and I’d recommend anybody to explore and customize the tools they use to fit their needs and make the work more productive.
Source code for all of these is available at GitHub.
Oh, and don’t forget to check out Algernon’s emacs environment for ideas!

syslog-ng git repository moved
As I announced on the syslog-ng mailing list, the official syslog-ng git repositry has moved and has become accessible using the more effective “git” protocol, instead of plain HTTP.
The change has been described on the syslog-ng webpage, gitweb is also available.

Switching version control systems
We have been using GNU arch the last couple of years as a version control system, however Tom Lords’ implementation does not scale well, and some of our software packages have 10 thousands of commits. This means that a single commit operation may take _minutes_. It is awful to wait so much time for a single commit, and it really degrades productivity.
I was considering Mercurial, Bazaar-NG and git, however this was not an easy decision, as the “modern” version control systems promote the use of branches over anything else, and our current version control model relied on cherry-picking heavily:
- developer commits the solution for each bug separately to his/her branch
- QA people pick patches from developer branches and integrate them to a ‘test’ branch, once the test was successful,
- release manager picks patches from the ‘test’ branch and integrates to mainline, if he doesn’t find anything odd during review
This worked wonderfully in GNU arch, but new VC systems lack in this area. Bazaar has no cherry picking support at all, Mercurial has some incomplete support with a plugin named transplant, git has cherry picking, but that relies on heuristics (it guesses whether a patch was integrated by using a checksum of the patch).
I was considering to change the process I outlined above, but I’m not sure how that would work out. We sometimes need to work with people not really experienced with VC systems at all, asking them to manage their own branches for each bugfix/problem group seems to raise the bar a bit too high.
Nevertheless git seemed to have solutions for both worlds (e.g. picking patches AND merging branches), so I choose git over the other two, and now I converted some of the syslog-ng history to git in order to gather some real-life experience.
I like what I see so far, git 1.5.x is really way better than older versions on the usability and documentation front. I now feel comfortable enough with git as I could finally understand the working model and the structure of the git history.And git is fast like lightning ![]()



Twitter
LinkedIn