Stop git committing chmod changes

Pretty self explanatory. Just do this:

git config core.fileMode false

The documentation says this about it:

core.fileMode 
If false, the executable bit differences between the index and the 
working copy are ignored; useful on broken filesystems like FAT. 
See git-update-index(1). True by default.

Here’s a warning from a guy on StackOverflow:

core.fileMode is not the best practice and should be used carefully. This setting only covers the executable bit of mode and never the read/write bits. In many cases you think you need this setting because you did something like chmod -R 777, making all your files executable. But in most projects most files don’t need and should not be executable for security reasons.

The proper way to solve this kind of situation is to handle folder and file permission separately, with something like:

find . -type d -exec chmod a+rwx {} \; # Make folders traversable and read/write
find . -type f -exec chmod a+rw {} \; # Make files read/write

If you do that, you’ll never need to use core.fileMode, except in very rare environment.

Line Endings in Git with Windows

Devving on Windows is a PITA.

Anyway, ever seen a message like this?

warning: LF will be replaced by CRLF in tests/unit/Del/Console/CommandTest.php.
The file will have its original line endings in your working directory.
warning: LF will be replaced by CRLF in tests/unit/Del/Console/CommandTest.php.
The file will have its original line endings in your working directory.

We only want LF. To squelch this crap, run the following:

git config core.autocrlf false

Yay.

Use Git bisect to find dodgy commits

Today I had the mammoth task of checking through 512 git commits to find a piece of code that broke something.

Usually i would git log, look back however many commits, and then do a git reset –hard COMMIT_NUMBER, then check if it worked. If it did, I would git pull back to the HEAD again, and try a resetting back to a more recent commit, until I found the bad code.

Never again! Git bisect to the rescue!

Find any good commit in the past, and note the commit number. Find any bad commit where the code is broken, and note the commit number.

Now, do the following:

git bisect start
git bisect good 514d83c
git bisect bad b27f38e

capture

Git checks out the middle commit between the good and bad ones. At this point I reloaded my page to see if the code was working or not. The code was working, so I then told git that it was good:

git bisect good

capture

Again the code was working, so as you can see I ran it again. Each time, git bisect jumps half way, iterating and narrowing down the options. Keep doing this and checking your code until it breaks, then say:

git bisect bad

Here’s the rest of the output:

capture

Now we have the exact commit number, and can do a git diff to find out what you did wrong! 🙂

Once you have the commit in question, tell git bisect that you are finished:

git bisect reset

I am amazed that I’m only just finding out about this awesome feature of Git! I’m sure you’ll love it too, try it!

Have fun!

Updating a forked GitHub Repo

At the PHPNW 2014 conference, they had a ‘Hackathon’, where everyone got together and started hacking away at projects. I had a shot at the JoindIn website.

Anyway, I forked the repositories so I could work on my own branch. Now though, my fork is outdated, and needs updating. So in order to remedy this, we add another remote.

From your local machine’s cloned repo, you simply say:

git remote add upstream https://github.com/joindin/joindin-web2.git
git checkout master
git pull upstream master
git push origin master

Thanks to Derick Rethans of XDebug fame for this info 😀

Fixing Git Submodule Issues

If you’ve set up a Git ‘Push to Deploy’ setup for your site based on my earlier post, you may or may not have run into some anomalous behaviour! Namely, when you run git submodule init, you get a message similar to this:

No submodule mapping found in .gitmodules for path 'js/jquery-browser-fingerprint'

Or even :

fatal: reference is not a tree: 48d1407779fb1e8dc6d3c6c6fb87df4c1cbc65ed
Unable to checkout '48d1407779fb1e8dc6d3c6c6fb87df4c1cbc65ed' in submodule path 'cms/js/flipswitch'

Thankfully, these issues are easily fixed. modules should be listed in a file in your root .gitmodules, and look like this:

[submodule "jquery-browser-fingerprint"]
 path = /js/jquery-browser-fingerprint
 url = git://github.com/carlo/jquery-browser-fingerprint.git

Listing your submodules in here will fix your first problem. The second issue is caused by referencing a commit that hasn’t been pushed! Did you copy project files from somewhere else? Try pushing the commit from your other project.

A clearer way to sort these issues however, is to clear whatever cache git has for those submodules. Typing this clears it.

git rm --cached js/jquery-browser-fingerprint

This should allow you to run git submodule init, and git submodule update. One last point. You don’t remember ever having to create this .gitmodules file before, so why now? Basically it allows you to set custom folders etc for the submodule. If you’re happy with the defaults, you should theoretically be able to skip the submodules file, and  can combine both git commands into this:

git submodule update --init

This updates everything and initialises in one! So to sum up, try removing the cached stuff in git, then run the combined update init file! Happy pushing, pulling, and deploying!

Using Git Push to Deploy your websites

If you’re STILL using some sort of FTP to deploy your website, you are falling behind! FTP sucks for a variety of reasons. My Favourite FTP client? I dobn’t have one! Dreamweavers file manager/ftp client was quite good, but thats the only thing I used dreamweaver for, the Sync site button. And even that left horrible _notes folders lying around everywhere. The one thing I liked was the cloak file ability, so only certain files/folders were uploaded. But Dreamweaver is sh*t. And will forget what it had previously done. So using Filezilla and manually uploading the things you wanted was your only option. And the setting ftp rules thing was more hassle than its worth. So it’s time to move on.

If your project isn’t big enough to be requiring Continuous Integration software from the likes of Jenkins, then a Git ‘push to deploy’ setup might be exactly what you are looking for. Make changes, commit, and push, which sets off the deployment process using a git hook, which is nothing more fancy than a bash script. So lets get started! I assume you have a live server with SSH access, and a development server which you will be working on.

SSH into your live server as root (or sudo su once logged in). We will be creating a user group for every user that will be pushing should be added to, and creating a folder for keeping your repositories in.

groupadd geeks
usermod -a -G geeks myusername
usermod -a -G geeks otherusernameetc
mkdir /var/git
chmod 775 /var/git
chgrp geeks /var/git

Now exit from being root and be logged in as whatever your normal ssh username is. We will be initialising a Git repository in the sites document root.

cd /home/myusername/www
git init
git add .
git commit -a

Now we will create a bare repository which will be the origin. This is what our dev copies will push to, which will set off a hook deploying to the web doc root. Once we create it, we’ll push whatever is in the sites doc folder already to it.

cd /var/git
mkdir yourprojectname.git
cd yourprojectname.git
git init --bare
cd /home/myusername/www/
git push /var/git/yourproject.git master

Now we add the live’s ‘origin’ repository as a remote for the live. Edit /home/myusername/www/.git/config, add add the following:

[remote "origin"]
    url = /var/git/yourprojectname.git 
    fetch = +refs/heads/*:refs/remotes/origin/*

Great. Now all that’s required is to set up what we call a ‘Git Hook’, a bash script which will trigger when we push to the master repository.
Edit /var/git/myproject.git/hooks/post-update :

echo
echo "*********************************"
echo "*** Deploying Website LIVE ***"
echo "*********************************"
echo
cd /home/myusername/www || exit
unset GIT_DIR
git pull origin master
git submodule init
git submodule update
exec git update-server-info

Save the file, and edit its permissions to make it an executable:

chmod +x /var/git/yourprojectname.git/hooks/post-update

You’re all set! The last stage is to clone your repository to your testing server, so, on your testing server:

cd ~/Sites
git clone myusername@myliveserverIP:/var/git/yourprojectname.git yourprojectname

And Bob is indeed your uncle! Test it out! If you have an index page (be it PHP or HTML, whatever) :

nano index.php
    <h1>My Groovy new Website</h1>
git add .
git commit -a
git push origin master

Now go check your live site! You should see your changes reflected on your production server 🙂 Have fun people!