What can I say about Git and Github?
Once I figured out how to use the damn things, I fell in love with them.
Even if you are a single developer and don’t need to collaborate with your fellow coders, it can still help organize your workflow.
For me, I often find myself working from different machines throughout the week, and I find it super useful to spawn a console and type a command like:
… and hey presto, I know where I’m at in my project. It tells me what I have committed and which branch I am working on.
Usually if I have been working on another machine and have already committed my changes to GitHub, so I can just pull down all the latest code, and start where I left off by using:
Once all the code is up to date on my machine I can start coding, and commit my changes along with a message, and then push it all up to GitHub:
git add . git commit -m "Changed images to pure CSS with a before filter, and did some wordsmithing on the about us page" git push
The above stuff is about as tough as most people’s Git-life gets. There are people out there that do all sorts of amazing things with Git, however 80% of your Git-life will be typing in those handful of commands. I don’t care how much of a Git superhero you are, most of your day will be just pushing and pulling like the rest of us mortals.
If you have not used Git before you might think it is for large teams of people collaborating on code, or that it is just a way for everyone to synchronize their code with one another, however I think Git is also great for single person web developers.
The above commands are sufficient if you are working on your own and only have one version of your codebase (i.e. a Master Branch), but what if you have to branch off because your codebase reaches a certain level of maturity?
Well, let’s say for example that you are a web developer, and your client calls you up and tells you that he wants to change the homepage to include a slideshow. After some eye rolling you decide to start adding new code and committing your changes to GitHub, etc.
X hours later, you are happy with it and decide to show it to the client. The client looks at it and says “No, I don’t like it. Let’s go back to what we had before.” Now, after more eye rolling you somehow have to revert your code back to the way it was before the original call with the client.
Normally you would have to extract all your code manually, trying not to break things, remembering what went where etc. Mucho pain.
However, since you used Git you can easily go back in time. Just look at your commits on GitHub and find the last good one. You can also use log via the console if it is easier:
You will see an entire log of all the commits you made. Simply find the last good commit (before the client called) and reset the HEAD to it.
git reset --hard 0000000000000000000
0000000000000000000 is the commit ID in case you were wondering, and you would get that from GitHub (or git log), where each commit has a commit ID.
Ever used the video player scrub feature on YouTube, where you drag the little playhead left and right to skip to a point in the video? Same concept (kinda). The reset –hard command resets the HEAD of Git to some new point in time (ie at a specific commit) and you play from there.
Under the hood this command is not going back in time (surprise surprise), it is actually creating a brand new sequential commit that simply copies the one you are pointing at, disregards the changes you made, and then keeps moving forward.
Ok, time to talk about branches and tags.
Branches and Tags
This branching and tagging thing is not as hard as you might think.
The first time I saw branching, it scared me to death so I didn’t use it for about 3 months. I just hammered the master. I’ve since come around, and now love branching and tagging, as it makes working with other coders, deploying and reverting soooooo much easier.
The problem with using a master branch for everything and reseting when mud hits the fan (as in the slideshow example) is that you would not only undo all of your changes, but you would also undo everything else that other people had been working on.
Warning: This will cost you friends.
To illustrate how the branches workflow can be a bit neater than working entirely off of the master, let’s revisit the previous example of the client asking for a slideshow and then changing his mind.
You get the call from the client, and instead of working on the master branch you create a new branch, switch over to it and start working.
git branch slideshow git checkout slideshow
Step 1: (Yes another Step 1.)
While you are doing all this one of your colleagues is making some changes to the footer that affects the entire site (including the homepage). That guy, for sake of simplicity, is just working on master.
Guess what? Your branch is now obsolete as new changes have been made to the master!
Fear not. You have a couple of options:
1) You could merge his footer changes from master into your newly created slidehow branch so that you are up to date, with:
git merge master
Or 2) Not worry about the new footer as you are only going to show the client the slideshow at this stage.
Anyway, let’s say that you complete the slideshow code and need to push it to GitHub. You don’t want to merge your code into master, you just want to “test the water” with the client first. As this is the first time you are doing this, you will need to push with the upsteam flag.
git push origin -u slideshow
The -u flag just means that subsequent pushes and pulls can be done without having to mention the origin or branch name. It just knows which branch you are on.
At this point you can demo the site via the slideshow branch to your client, and wait for him to tell you he has changed his mind.
Then all you do is this:
git checkout master
Now refresh the page and show him the original version. Plus, he will see the new footer too. Of course, clients being clients, he will hate the new footer, and you have to tell your colleague that he has to revert all his footer changes.
You go grab a beer as your work is done, and your colleague has to stay late wishing he had bothered to use branches.
If the client did actually like the slideshow, all you would have had to do is merge your fancy new slidehow code into master:
git checkout master git merge slideshow
Now, let’s talk about Tags. Tags are just “less-fancy branches”. Very useful for declaring points in time and giving them a tag. v1.0, v1.1, etc.
You create a tag in basically the same way as you create a branch.
git tag -a v1.4 -m "version 1.4"
I personally find tags useful for declaring a stable release version. For example you could have a dev server pointing to the master branch and a production server pointing to a stable tagged version.
One small caveat. Just using git push won’t automatically push your tags. You have to actually tell Git to push the tags in a separate command:
git push --tags
This is worth talking about, because I often see this done incorrectly, which causes people to get into all sorts of trouble.
For example, let's say your colleague decides that he should start using branches. You have to type a command into your console in order to track his branch properly. Essentially tracking a branch is creating a new local branch for yourself and filling it with all the information from their remote branch on GitHub.
I am sure you are thinking of creating a new branch, switching to it and then just pulling, right? Do not do this! I am waving my hands here to indicate that you should not worry about the details here; just go with me on this.
This is the command you want to use every time you see a new branch from a colleague on GitHub:
git branch --track XXXXXXX origin/YYYYYYYYYY
XXXXXXX is the name of the new local branch you are creating, and YYYYYYYYYY is the name of your colleague’s remote branch.
I recommend using the same name for X and Y. Again there I go with the hand waving.
So If you check GitHub for the available branches you can do this:
1) look on GitHub on the dropdown menu
2) use the branch command:
git branch -r
This lists the remote branches due to the -r (remote) flag
just lists the local ones.
So you find the right branch that you want to track. For simplicity, let’s say that it is called “footer”. You would want to do something like this:
git branch --track footer origin/footer
At this point you can go into that branch locally, and hey presto you can pull and push like normal and work with your colleague.
Cool huh? Now you are collaborating and can have lots of fun merging conflicts at 2am like the rest of us
Conflicts occur when one or more persons that you are working with end up pushing code that affects your code.
For example, let’s say that you want to adjust a page title because you noticed a typo. Your colleague also sees the typo, except they decide to change the title completely. Now you have two distinct versions of a file on the same branch. Ughhhh…
Who is right?
GitHub / Git decides it doesn’t want to get in the middle of a fist fight and says “whooooo conflict, you guys figure it out, and when you’re done, push”.
It basically stalls, and gives you a terrifying looking message about some merge-conflict thing.
Don’t panic! It is not as bad as it sounds.
I am not going to get into how to fix conflicts,, but I’ll give you a 30,000 ft. overview.
When a conflict occurs you see some <<< and —- symbols marking sections of code that are in disagreement, so all this means is that you have to manually decide which code to keep and which bits to discard.
Once you clean up your file (xxxxxx), you can do this.
git add xxxxxx git commit -m "conflict resolved yehhh....obviously use better mess age here" git push
Your colleague does a new pull and everyone is in sync again.
Side note: It is worth telling them you are deciding to remove or keep their code, so they don’t try and change it back again.
Done! Merge conflict resolved. Kudos to you. Go grab a well earned beer
One last thing worth covering is cleaning up.
How to Clean Up After Yourself
If you have a branch and then realize you don’t really need it, you could leave it lying around and lose some friends, or you could just delete it both locally and from GitHub:
git branch -D branchname
That does the trick locally, but to get it off GitHub you also need to do this:
git push origin --delete branchname
While I am on the subject of neatening up the repo, I recommend maintaining a text file which lists files and folders that you don’t want Git to track, like certain images or folders.
Just maintain a text file called .gitignore and pop in all the names of all files and folders that you want Git to ignore.
80% of the time you will be using these commands:
git add . git commit -m “message” git push
I have touched on branches, tags and conflict resolution, however I’m not going to write an advanced tutorial about cherry picking and reverts and all that stuff, because you have StackOverflow for that.
I hope this persuades some of you who have not used GitHub before to try it out, and basically not fear Git and the world of merging conflicts.
A good place to start is to visit GitHub.com There are plenty of great “getting started docs” on there.