Adding a new git remote to an existing project

Today I had a project that I already had in git and I had an existing remote I had already pushed to. Now I wanted to add github as well so I added the repo on github and initialized the repo with a README.mf and a LICENSE file. After adding the remote to the local repo and attempting to pull from it I got the following error:

fatal: refusing to merge unrelated histories

Apparent the way the merge command work has been changed in git v. 2.9 to make sure you do not mix histories by accident. To actually do this use the –allow-unrelated-histories switch. Solution was to add that to my pull command I all was good.

git pull origin master --allow-unrelated-histories

Now I had the README.mf and LICENSE files from github in my local repo so I could edit I push back up. Easy!

Git reflog to the rescue

Earlier today while slaving away on my code I did some wizard-like changes and solved an issue I had been having with packaging Visual Studio Tools for Office (VSTO) add-ins for Microsoft Outlook. It was soooo cool that I just had to record a video on it as it involved a number of steps and it would be easier to record a video than describing it in text. So I commited my changes and reverted to an easier commit without thinking. And boom!! All my changes was gone – including some stuff I actually needed. I shouldn’t have reset to a commit but instead I should have created a new branch from an earlier commit. Stupid is as stupid does!

After making a loud noise I remembered that all was still safe as I’m using Git…

All changes in Git are recorded in the reflog so my work wasn’t lost – I just needed to revert back to them which is easy using the reflog. Now I will not go into details on the reflog here but do look it up. All I needed was two simple commands:

  • git reflog (display the reflog and note the commit hash I wanted to go back to)
  • git reset –hard <commit hash>

Below is a more detailed example. The git reflog command shows the log of what has happened. The top entry is me screwing things up. The commit just under it (41a2195) is the working copy as it was and where I wanted to return before branching correctly. Doing the reset command specifying the hash returns me to it.

$ git reflog
afc548e HEAD@{0}: reset: moving to afc548e1029839175a7620b5c15c6a122a4db47c
41a2195 HEAD@{1}: commit (amend): Update to v. 1.0.3.0 across the board to allow update
71ab438 HEAD@{2}: commit: Update to v. 1.0.3.0 across the board to allow update
afc548e HEAD@{3}: rebase -i (finish): returning to refs/heads/master
$ git reset --hard 41a2195
$ git reflog
41a2195 HEAD@{0}: reset: moving to 41a2195
afc548e HEAD@{1}: reset: moving to afc548e1029839175a7620b5c15c6a122a4db47c
41a2195 HEAD@{2}: commit (amend): Update to v. 1.0.3.0 across the board to allow update
71ab438 HEAD@{3}: commit: Update to v. 1.0.3.0 across the board to allow update
afc548e HEAD@{4}: rebase -i (finish): returning to refs/heads/master

Again – as so many times before – thank you Linus 🙂 And now – please go read up on the git reflog if this is news to you…

First Git hook for Atlassian Bitbucket (formerly Atlassian Stash)

For my current project I’ve setup a full CI pipeline to automate the build process of the application (an EAR-file in this case) and deploy it to the test server. The build itself is a Maven build that runs all the tests and builds the EAR file. We are a number of people working on the application – some do frontend work (mainly JavaScript) and I do the backend. The Git repository we use is split into three branches as it concerns this project – one for backend (feature/eventboard_backend), one for frontend (feature/eventboard_frontend) and one that merges the two into the final result for building (feature/eventboard). So I was setting all this up – had the build script ready, the build server ready (Atlassian Bamboo), the deployment script working over SCP/SSH but I needed a nice way to automatically merge the two development branches into the main branch for the build.

The way I solved it was to write a Git post-receive hook on the Git server side (Atlassian Bitbucket). This post-receive hook detects a push to either of the two development branches and when it does merges the two into the main branch and pushes it branch back up. This push is in turn detected by Atlassian Bamboo that then kicks of the build and the deployment. So nice. Even though it took me a couple of hours to configure it has already saved so much time and all builds and deployments are consistant.

Today I extended the build script to monitor another branch so I now both deploy into our “bleeding edge” environment and our test environment.

The post-receive hook is written in bash and is as below. It took me a while to grok but a hook is simply a script that runs as the server OS user when ever something happens. The script is free to run as another user so my script runs as a special Git user so we can distinguish between which users does what. It also means that I could restrict access to feature/eventboard branch so it’s only writable by this build user.

The only caveat about this hook was that we are using Atlassian Bitbucket which apparently only accepts hooks written in Java. There is however a way to add bash-based hooks directly in the file system on the server under /<bitbucket-home>/shared/data/repositories/<repoid> where the repoid can be found in the repository settings on the Bitbucket server if logged in as admin.

#!/bin/bash

CHECKOUT_NAME=eventboard
MERGE_INTO_BRANCH=feature/eventboard
MONITOR_BRANCH1=feature/eventboard_web
MONITOR_BRANCH2=feature/eventboard_backend
WORKING_DIR=/local/stash-hooks-work

while read oldrev newrev refname
do
        branch=$(git rev-parse --symbolic --abbrev-ref $refname)
        echo "Currently on branch '$branch'"
        if [ "$MONITOR_BRANCH1" == "$branch" ] || [ "$MONITOR_BRANCH2" == "$branch" ]; then
                echo "Detected commit on $MONITOR_BRANCH1 or $MONITOR_BRANCH2 - merging..."
                if [ ! -d "$WORKING_DIR" ]; then
                        mkdir -p $WORKING_DIR
                fi
                cd $WORKING_DIR
                unset GIT_DIR
                if [ ! -d "$CHECKOUT_NAME" ]; then
                        # repo doesn't exit - abort
                        echo "*** Required repo for post-receive hook not configured - exiting..."
                        exit
                else
                        cd $CHECKOUT_NAME
                        git reset --hard
                        git checkout $MERGE_INTO_BRANCH
                        git pull origin $MERGE_INTO_BRANCH
                fi
                git fetch origin $MONITOR_BRANCH1:$MONITOR_BRANCH1
                git fetch origin $MONITOR_BRANCH2:$MONITOR_BRANCH2
                git merge $MONITOR_BRANCH1 $MONITOR_BRANCH2 -m "Merged 
                          '$MONITOR_BRANCH1' and '$MONITOR_BRANCH2' into 
                          '$MERGE_INTO_BRANCH'"
                git push origin $MERGE_INTO_BRANCH
        fi
done

git log to the rescue

Today I needed to figure out when a certain setting (DisablePrint – funnily enough disables print in the OnTime Group Calendar Notes UI’s) was added to OnTime Group Calendar and I just couldn’t remember. So how would I find out? No way was I going to do diffs all the way back through all my tags. A bit of googling and voila! – git log to the rescue. Using a combination of git log and git tag I was able to find out in a couple of minutes. Besides being very cool and an excellent display of the power of git it also highlight just why meaningful commit messages are very important as they give you this option to go back through the log and figure out when stuff was added.

Atlassian SourceTree Pro-Tip

I’m finding myself use Atlassian SourceTree more and more for my Git work as it’s both intuitive, fast and very pleasing to the eye. Yesterday at an Atlassian event (Getting Git Right) I noticed that the branches were nested in one of the demos. I wondered how they did that but it turns out to be very simple. If you (re)name a branch and use slashes (/) in the name then SourceTree will automatically nest them. Very nice and does make it easier to distinguish between feature, release, bugfix branches etc. The below video shows how you rename a branch in SourceTree using slash.