I love git. At this point I can’t imagine using any other version control system. Admittedly, I have never use Mercurial or any other distributed VCS so my experience may be skewed. Nonetheless, it has a few things about it that annoy me. Perhaps highest among these was the inability to merge my current branch into another.
Mostly, when I am using git, I am following the git flow approach to things. However, I don’t generally install the git flow tool. I am fine with doing things manually from the command line. In fact I think any developer should have to learn how to do git flow without the tool first. Its like learning to code in notepad before installing an IDE. But, I digress.
The issue with git-flow is that when you are merging, first you do a rebase of your current branch onto the target branch (git rebase target) followed by a non-fast-forward merge. What this means is that you have to checkout the target branch and then merge your working branch into it: git checkout target && merge working-branch –no-ff.
This is annoying. If I am on my working branch I just want to do git rebase target && git merge-to target, especially if the name of my current branch is long, which it often is.
So I did some googling and found a stack overflow article on the topic. There were several approaches. I liked Dmytrii Nagirniak’s the best. It uses git’s aliases. I didn’t know git had aliases before this. Indeed they are a bit more powerful that bash aliases, so I tend to think of them more as macros.
In any event, I slightly modified his solution and it works great for what I want. Just add the following to your .git/config:
(If the [alias] section header is already present, just add the definition to the end of your list of aliases.)
[alias] #merges the current branch into the specified branch (i.e. reverse of merge). Returns to the current branch if -r specified. merge-to = "!f() { export tmp_branch=`git branch | grep '* ' | tr -d '* '` && git checkout $1 && git merge $tmp_branch && [[ $2 = '-r' ]] && git checkout $tmp_branch; unset tmp_branch; }; f" |
After this I got a little carried away and wrote a few other useful alias.
#Takes to branch names (neither are the current branch) merges the first one into the second one, returning to the current branch. merge-branches = "!f() { export tmp_branch=`git branch | grep '* ' | tr -d '* '` && git checkout $2 && git merge $1 && git checkout $tmp_branch; unset tmp_branch; }; f" #Moves the branch specified to the hash, branch or tag specified. move-branch = "!f() { export tmp_branch=`git branch | grep '* ' | tr -d '* '` && git checkout $1 && git reset --hard $2 && git checkout $tmp_branch; unset tmp_branch; }; f" |