-
Use vimdiff as git mergetool
Using vimdiff as a git mergetool can be pretty confusing - multiple windows and little explanation. This is a short tutorial which explains basic usage, and what the LOCAL, BASE, and REMOTE keywords mean. This implies that you have at least a little bit of basic vim knowledge (how to move, save, and switch between split windows). If you don’t, there’s a short article for you: Using vim for writing code. Some basic understanding of git and branching is required as well, obviously.
Git config
Prior to doing anything, you need to know how to set vimdiff as a git mergetool. That being said:
git config merge.tool vimdiff git config merge.conflictstyle diff3 git config mergetool.prompt false
This will set git as the default merge tool, will display a common ancestor while merging, and will disable the prompt to open the vimdiff.
Creating merge conflict
Let’s create a test situation. You are free to skip this part or you can work along with the tutorial.
mkdir zoo cd zoo git init vi animals.txt
Let’s add some animals:
cat dog octopus octocat
Save the file.
git add animals.txt git commit -m "Initial commit" git branch octodog git checkout octodog vi animals.txt # let's change octopus to octodog git add animals.txt git commit -m "Replace octopus with an octodog" git checkout master vi animals.txt # let's change octopus to octoman git add animals.txt git commit -m "Replace octopus with an octoman" git merge octodog # merge octodog into master
That’s where we get a merge error:
Auto-merging animals.txt CONFLICT (content): Merge conflict in animals.txt Automatic merge failed; fix conflicts and then commit the result.
Resolving merge conflict with vimdiff
Let’s resolve the conflict:
git mergetool
This looks terrifying at first, but let me explain what is going on.
From left to right, top to the bottom:
LOCAL
– this is file from the current branchBASE
– common ancestor, how file looked before both changesREMOTE
– file you are merging into your branchMERGED
– merge result, this is what gets saved in the repoLet’s assume that we want to keep the “octodog” change (from REMOTE). For that, move to the MERGED file (
Ctrl + w, j
), move your cursor to a merge conflict area and then::diffget RE
This gets the corresponding change from REMOTE and puts it in MERGED file. You can also:
:diffg RE " get from REMOTE :diffg BA " get from BASE :diffg LO " get from LOCAL
Save the file and quit (a fast way to write and quit multiple files is
:wqa
).Run
git commit
and you are all set!If you’d like to get even better about using Vim, I wrote a book about it: Mastering Vim. I’m pretty proud of how it turned out, and I hope you like it too.
-
Git pretty log output
This alias has been around the web for quite some time, but it does look fantastic indeed.
To add the alias
git pretty-log
, execute the following command (join string prior to executing):git config alias.pretty-log 'log --graph --pretty=format:"%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset"'
-
Download gists from prompt
I wrote a little script to download gists from the command prompt.
Generate your Github API Token under Settings -> Applications, change it within a script, and then:
chmod +x shgist.py mv shgist.py ~/bin/shgist
Where ~/bin is a directory in your path. Now you can use it as shgist file to quickly download your gists (Gist on Github).
#!/usr/bin/env python # Ruslan Osipov # Usage: shgist keywords # Description: Gists downloader import urllib import urllib2 import sys import json token = 'Personal API Access Token' # Github Settings -> Applications class Gist: def __init__(self, token): """ token -- str, github token """ self.token = token self.url = 'https://api.github.com' def find_by_name(self, keywords): """ keywords -- list of strings """ gists, urls = self._get_gists() for i, gist in enumerate(gists): for keyword in keywords: if keyword not in gist: del gists[i] del urls[i] break if len(gists) == 0: print "Sorry, no gists matching your description" return if len(gists) == 1: self._download_gist(gists[0], urls[0]) return for i, gist in enumerate(gists): print i, gist while True: num = raw_input("Gist number, 'q' to quit: ") if num == 'q': print "Quiting..." return try: num = int(num) if 0 <= num < len(gists): break print "Number should be within specified range" except: print "Only integers or 'q' are allowed" self._download_gist(gists[num], urls[num]) def _download_gist(self, name, url): """ name -- str, filename url -- str, raw gist url """ print "Downloading %s..." % name gist = self._send_get_request(url) open(name, 'wb').write(gist) def _get_gists(self): """ Returns 2 lists which should be treated as ordered dict """ url = '/gists' response = self._send_get_request(self.url + url) response = json.loads(response) gists, urls = [], [] for gist in response: for name, meta in gist['files'].items(): gists.append(name) urls.append(meta['raw_url']) return gists, urls def _send_get_request(self, url): """ url -- str """ headers = { 'Authorization': 'token ' + self.token } request = urllib2.Request(url, headers=headers) response = urllib2.urlopen(request) return response.read() argv = sys.argv[1:] if not len(argv): print "Usage: shgist keywords" sys.exit(0) gist = Gist(token) gist.find_by_name(argv)
-
My most used bash commands
Shell history can tell a lot about its owner. What’s in your shell?
history | awk '{CMD[$2]++;count++;} END { for (a in CMD)print CMD[a] " " CMD[a]/count*100 "% " a;}' | grep -v "./" | column -c3 -s " " -t | sort -nr | nl | head -n10 1 580 38.0328% git # I keep everything under VCS 2 202 13.2459% cd # Moving around a lot 3 171 11.2131% vi # Favorite text editor 4 127 8.32787% ls # I'm a curious person 5 43 2.81967% rm # I also like when it's clean 6 26 1.70492% usrswitch # https://gist.github.com/ruslanosipov/5453510 7 25 1.63934% exit # I don't like hitting the red cross button 8 18 1.18033% source # Reloading bash configuration files 9 17 1.11475% clear # Like when it's *really* clean 10 15 0.983607% gitk # Sometimes it is too messy for git log
-
Colorless week results
A round-up of The Week Without Colorful Prompt.
I worked with the colors disabled in bash, git, and vim for a week. So how did it go? It is definitely an interesting experience, but such a harsh change that it doesn’t really work out with everything.
Bash
Disabling colorful PS1 and removing color output for ls commands forced me to concentrate more on the actual text, changing the perception of the general bash workflow. I was more concentrated on the task, missed less details, and generally paid more attention to the output.
Git
Never repeat my mistake by disabling colors for git diff. Log and status are fairly easy to read, but the disabling of colors noticeably slows down the workflow.
Vim
Vim without code highlight forces you to remember your code structure more effectively, which is a great thing. Not having a need to rely on color can hint that a programmer has better understanding of the code he/she is writing.
Now that the experiment is over I have mostly returned to using colorful prompt. But I do turn syntax highlight off once in a while - it allows you to see problems from new angle and work more efficiently at finding a solution. Try it and see for yourself!