← Back to blog home

non-fast-forward updates were rejected Merge the remote changes before pushing again

02 Dec

When I first switched from a centralized version control to decentralized (or distributed) version control I ran in to this error:

non-fast-forward updates were rejected Merge the remote changes before pushing again

 Well,

you just have to –force or use a bare repository they told me.

First of all, don't –force. If you just started using git you almost certainly should never need to use the –force command. If you come across something that requires it there is a good chance that you simply don't quite understand git yet.

Bare Repository

A bare repository is a repository that lacks it's own working tree. What this means is that you can push to it without conflicting with anything. It's revisions are entirely based on outside changes. This is used to allow centralization in a decentralized version control system.

The idea is simple. You just create a bare repository and then different people can checkout copies of the bare repository and should be able to push/pull to/from it without any issues.

Creating a bare repository is SUPER easy. Just go to an empty directory and type.

git --bare init

Once that is done you can clone that repository and start working in it. For me this is usually the opposite of what I want. In the real world I usually start building something and then go, "oh, I should give this some version control." For that just initialize the repository in the directory your files are in and then clone from there to the bare repository as follows…

#initialize your repository. In the directory with your code type:
git init

#navigate to another directory and create a bare repository (name usually ends with '.git')
cd ~ #this could be anywhere or even a remote server
git --bare clone /path/to/repository/you/created/with/init ./my-bare-repo.git

#set up your main repository to use the remote bare repository
cd /path/to/my/repo
git remote add '/path/to/my/bare/repo'  #this could be remote on a server (probably)

That's all there is to it. Now you have a repository you (and others) can push to and not worry about receiving that fast-forward error as the bare repository has no working tree to conflict with

 

Deploying using git

Now if you were me you'd be saying, "…but if there is no working tree there are no files and I wanted to push to my development server." Then someone would say something vague about hooks or deployment systems.

Hooks are shell scripts run by git when certain actions happen. They can be used to validate commits before they are submitted or automate running unit tests and probably endless other things. In this case we will be using the post-update hook of the bare repository. Since we cannot push to a repository with a working directory we will instead make our dev site pull from our bare repository just like you did.

To do this simply clone the bare repository like before in to the web root of your dev server

cd /path/to/dev/web/root
git clone /path/to/bare/repo

Then you just have to set up your hooks. In the bare repositories hooks directory there is a file called post-update.sample. Simply rename that file (remove the word sample) and add a couple quick lines of code and you'll be in business.

cd /path/to/bare/repo
cd hooks
mv post-update.sample post-update
nano -w post-update #or whatever editor you like

 

Then simply add this code to the end of the file

cd /path/to/dev/web/root
unset GIT_DIR
git --git-dir /path/to/dev/web/root/.git pull

In the above code we change directory to the web root (where you cloned the repo in the previous step) and we unset the variable GIT_DIR. This variable holds the directory of the active repository. Since we're writing this code in a hook for the bare repository it would try to do the actions on that repo if we don't clear it first. Then we do a git pull and set the correct git-dir value in that line. Not it must end with .git after your path. '.git' is a hidden directory inside of your repository that holds all of the data.

Once that's done you just have to make the script executable

chmod +x post-update

Now maybe you're saying, "but what if I want to push the site to live" or "what if I want to push the site to multiple different servers"

For multiple different servers you can simply copy the code above and change the path. A single bare repository could automatically update the code on dozens of local document roots without any issues.

For pushing live most people will tell you to use a deployment solution. I entirely agree with this sentiment. However, for some simple sites using git to deploy is a-ok in my book. The one thing to watch for is making it too easy to accidentally push changes to the live site. The easiest choice is to set up your live site as a clone of the bare repo and just ssh in and issue a pull command when you're ready to "go live." I also wrote a script for deploying multiple branches to different locations. Using this script you can have your "master" branch automatically push to your dev server and your "live" branch automatically push to your live server.

 
 

Tags: ,

Leave a Reply

Notify me of future comments

(I don't spam or share your e-mail. Unsubscribing is as easy as clicking the "unsubscribe" link in the notifications)