If you don't already have a GitHub account, you'll need to create one here. It's up to you which email address you use to sign up with, but if there's an academic email (eg .ac.uk) listed on your account (as either a primary or secondary address), you'll be able to get GitHub Pro for free as a student, which is really nice. To do so, just go to their education centre and send them a photo of your student card, the verification process should be pretty much instant.
As an aside, once you've made an account, I'd very strongly recommend you go to your account settings and add your name in the first box. It makes it a lot easier to figure out who's who without having to remember everyone's usernames. Not required, but useful
Once you've got an account, download GitHub Desktop on your computer. While you can use git entirely through the command line, the desktop app is a nice easy way to see exactly what's going on so you don't get mixed up.
If you think you'll be doing a lot of coding, I'd highly recommend using Visual Studio Code as your editor. It's got great support for most languages, an extension for pretty much everything, and you can link your GitHub account and interact with repositories directly from VS Code. We won't be covering it in this tutorial, but after you've finished it's worth having a play around with VS Code to get used to it.
Useful Terminology
Repository: The project or folder with all your code, branches, commits, issues, pull requests, and more. Often shortened to "repo"
Commit: A snapshot of changes made to some code
Branch: A branch on the code tree, where commits live in a chain
Clone: A local version of a repository, including all commits and branches
Remote: A common repository on GitHub that all team members use to exchange their changes
Fork: A copy of a repository on GitHub owned by a different user
Pull request: A place to compare and discuss the differences introduced on a branch with reviews, comments, integrated tests, and more
Pull: The action to "pull" the changes from remote to your local copy
Fetch: Similar to pull, but only gets information about the changes without actually pulling them all
Push: The action to "push" the changes from your local copy to remote
Your First Repository
Creating the Repo
To start off with, you'll need to create your first repository. Normally this is a blank one you use to store a project in, but for this tutorial we're going to clone one I've created. Head over to my tutorial repository and click the big green button that says "Use this template", then click "create new repository". Give it a useful name, and a description that will help you understand what this is in a few month's time. I'd recommend creating this as a private repository so only you can see it, but it's possible to make it public if you want to show it off to the world.
Recommended settings for creating your new repository
After it's generated, you'll notice you've now got a brand new repository of your own, with the code we'll use in the rest of this tutorial. The default settings of any new repository automatically enable pretty much everything you need, but there's plenty of useful things available if you go through the settings in your own time.
Opening in Desktop
Now you've got the repo created, you'll want to set it up on your own laptop. Open the GitHub Desktop app you downloaded earlier, log in with your account, and click "Clone a repository from the internet". Under "Your repositories" you should see the one you just created. Click it, and press "clone" at the bottom.
Cloning your new repository to your local machine
What this has done is downloaded the entire repository to your machine, so you can work with it locally. One of the most important features of Git is it is decentralised, meaning the copy you've got on your own machine will contain the entire history of the repository for you to work with offline. But more on that later.
If you click the "Show in Explorer/Finder" button, you'll see those files in whichever folder you cloned the repo into. Anything in here will be tracked by Git and can be included in your repository.
Your First Commit
Any changes to your code are made in something called a "commit", which contains information about what code has changed, and a description for you to write what you've done. This makes it easy to track the changes your code goes through, and what decisions were made.
In this folder, create a new file called hello.py, and open it in your favourite text editor. This could be NotePad, NodePad++, VS Code, TextEdit, or anything else you fancy. Type in here the code below, or write your own if you're feeling ambitious.
print("Hello GitHub!")
Save and close this file, and switch back to GitHub Desktop. You'll see it's found your new file, and will be showing you a preview of what it contains. Along the left hand side is a list of all the files that have changed, which is useful if you've done a lot since your last commit. Make sure your new file is ticked.
Committing your first file to your repository
Below that is where you write some information about your commit. The first line is the title of the commit. This should be short and sweet, but still descriptive, as it will show up in a few places. In general it's best to keep this to no more than 80 characters or so, but there's no hard limit. In the bigger box below is where you write your detailed description. This should be where you explain everything you've done, so anyone looking at that commit can see what you did and why. Once you've filled in all the information, click the blue button at the bottom to make the commit.
Your commit has been created, but not pushed yet
Congratulations, you've made your first commit! But if you go online and try find it, you'll notice it's not there yet. Well, remember earlier I said it created an offline copy of the repo? You have to manually sync that back up to GitHub. This is easy to do, just click the blue "Push origin" button to push your changes, and they'll show up online.
Issues
If you're collaborating with others on a repository, Issues are a very handy way of keeping track of problems in the code. They can refer to specific lines in your code, have comments to discuss solutions, and keep a permanent history after they are closed.
If you looked through the example code I included in the repo you cloned, you may have noticed there was a problem that would cause it not to work. In the web version of GitHub, if you click on client.py, you might see the port number is set to 4000, while the server is using 3000, which is a problem we need to share with the other people in our repository!
Click on the little "6" to the left of the code to select that line - you should notice it changes colour. Click on the three dots that appear, and select "reference in new issue".
Creating a new issue from a specific line of code
This will bring up the issues editor, where you can describe the problem you're reporting. It's very important here to be as descriptive as you can in your issue, so other people can understand what the problem is, and have the best chance of figuring out how to fix it. Add a useful title and a detailed description, then click the green "submit new issue" button.
Creating a new issue about the incorrect port number
You'll notice the "issues" tab at the top of your repository now has a number next to it. This is a count of the number of currently open issues, which is a handy way of seeing what problems there are if you're ever feeling in a bug squashing mood.
Branches
Now we've identified a bug, let's try fix it. But rather than fixing it in the main branch, we're going to fix it in another branch. Often, the main branch (which used to be called "master" until recently) will be protected so only approved code can be pushed to it, but we'll touch more on that later.
Back in GitHub Desktop, along the top, click the middle option where it tells your your current branch. If you made your GitHub account today this might be called "main" instead of "master", but it doesn't matter. Press the button to create a new branch, and name it something useful like "port-fix". Click the blue button to make it. At this point if you had any code not yet committed, you'd be given the option to bring those changes with you to the new branch.
Switching the current branch to a new one
Now, open up client.py and change the port number from 4000 to 3000, then save and close the file. You'll see GitHub has recognised the file has changed, and should now be showing you the changes you've made. Like before, add a useful title and description to this change, and create a commit.
Creating a new commit to change the client port
Much like before, you'll have to push these changes to GitHub in order for them to sync with the version stored in the cloud. As this is a brand new branch, the option shows up as "publish branch" this time, but it's the same thing. Click the blue button again, and it'll be synced up. Open up your repo in your web browser to see if it's changed.
Pull Requests
Pull Requests are a powerful feature used to merge code between different branches, and are used frequently to suggest changes or features get added to a protected branch. When you opened your repo in the last step, you may have noticed a banner along the top inviting you to create a pull request, like in the picture below. Click the green button to open the pull request wizard.
Banner to create a new pull request
By default, the window you'll be greeted with will have all the information pre-filled for you based on the commits you made in the PR, but sometimes it's useful to change that. In the description box, if you type a "#", GitHub will automatically suggest open issues for you which you can link to this pull request. Click on the issue you made earlier to add it to this PR, and you'll see a number has been placed after the # - in my case it's #1. It's useful to add a few words to say that it fixes the issue too.
Linking an issue to a pull request
Once you're happy, click the green button to create the pull request. Once it's created you'll see the issue you linked in the text has turned blue, allowing you to click it and view the issue directly. The pull request also shows up on the issue page, so you can see where things get mentioned in other places of your repo.
Much like with issues, you'll notice now there's a "1" next to the "pull requests" tab along the top, showing you there's open requests which people want merging in. If you've clicked away, go back to your pull request, so we can see how to close it.
If you're working in a repository with other people, it's often configured that you'll need people to approve or review a pull request before it can be merged. You can add people by clicking the cogs next to "reviewer" in the options on the right hand side, sometimes you'll need a certain number of people in this list to approve. That's out of the scope of this tutorial though, so don't worry about it too much now.
Your pull request is ready to merge!
Once everything's sorted with the pull request (any required reviewers have approved it, conflicts have been resolved, etc), there should be a nice big green tick next to it showing it can be merged in. Click the green button to merge this pull request and have your changes applied. You'll have an option here to change any messages, but the defaults are fine, just press the green "confirm merge" button again and let it work.
Once you've made a pull request, you'll have an option to delete the source branch. If you created the branch just for this issue and won't be using it any more, feel free to delete it to prevent clutter. Some people prefer to use one branch for all their changes and periodically merge it in when it's ready, while others will do one branch per PR. It's up to you which you prefer.
If you open the issues tab on the top now, you'll see the issue you created has disappeared, and been automatically moved to the "closed" list. This is because GitHub recognised it was mentioned in the pull request you just merged, and marked it as closed automatically. If you click on the issue, you can see the reference to the pull request, and it shows as being the reason the issue was closed. This is useful for showing the trail of events that happened to fix the problem, and who's responsible for them.
The issue from before, now showing as being closed as a result of your pull request
Remember how when you made a commit you had to push that to the cloud? Well, that also applies in reverse. Back in GitHub Desktop, click the button that says "fetch origin" to update your local copy, and now if you switch your branch back to master (or main), you'll see the changes you made in the pull request have been synced over. You can see these changes in the "history" tab on the left hand side, which shows an overview of everything that's changed.
History of this branch, showing the merged pull request
Browsing History
Changes in a file
Because Git keeps track of all changes made to a file, you can easily go back and look at it at any point in history. In the web version, open up client.py and click on the "history" icon with the clock in the top right. This will show you a list of all the changes this file has had, and all the commits that made them.
History of all changes made to client.py
Viewing Old Code
Let's say you wanted to see how your code looked at a specific commit, but you've got your code split over a number of different files. That's easy to do. From the example above, let's click the oldest commit we have, which was called "Initial commit". This was the automatically generated commit when you cloned the repository from the template, and shows all the files being created. In the top right, you'll see a button to "Browse files" - if you click on this, GitHub will show you the entire repository as it was when this commit was made, which you can browse through to see the old code.
Viewing the changes made in a specific commit
Git Blame
Sometimes, you'll be looking through some old code, and may want to know when a change was made, why, or by who. Luckily, Git offers a way to do this without having to manually search through all the commits, which is really handy if you've got a busy repo.
Click on your repository name in the top left to go back to the current view, and open client.py again. Like before, click the line number (6) to select the line, and click the three dots, this time clicking on "View git blame". This will bring you to a window which shows you the last time each line of code was changed, and you can see line 6 there was changed more recently than the rest.
From here, you can click the commit message to view it and see more details, or if you've like to see the next most recent change, click the little icon just next to the line number that looks a little bit like a weird deck of cards. This will let you move backwards through the changes, until you find the one you are looking for.
Blame log of all changes made to client.py
Further Reading
And that's it for this tutorial! We've covered the basics of Git and GitHub, and hopefully have helped you learn a bit about the process. The repository you created will be there until you delete it, and depending on the settings you picked at the start, should be private to you, so feel free to use it as a playground to try different things and get used to GitHub more.
I've linked some more resources below if you want to learn more. Some of them I've tried and think are good, some I've not tried but look fun. Git is a very powerful but complex piece of software, so there's never going to be one perfect way to learn it beyond trying it yourself.
A similar tutorial to this one, but centred around using the command line rather than GitHub Desktop, which you may find useful if you're into that sort of thing
The official GitHub Cheat Sheet, summarising the basic commands you need, and with some useful terminology that I copied into the top of this guide
Similarly, the official GitHub Training Guide, which goes into much more detail into each process summarised in this tutorial, and then delves deeper into more complex topics
A fun git-based game, to teach you the different concepts of git in a hands-on game, where each level focuses on something new
An introduction to GitHub Actions, which is a very powerful tool built in to GitHub which you can configure to automatically run and test your code each time you commit it, and run checks before allowing a pull request to be made
A specific example of tests in Python using GitHub Actions, which is handy if you've got a lot of Python code in your repo and want it automatically checked to make sure your changes don't brake something accidentally without you realising
Very good guide on how to set up protection, which is very important if there's more than one or two people working on a repo. It covers things like protected branches, PR reviewers, etc.
Guide from GitHub building off of the tags system to create "Releases" for your code
A guide to submodules, which can be handy for splitting a project into multiple repositories, either for tracking separately (e.g. by different teams), or for libraries that you might re-use in various projects
Basic formatting for Markdown (.md) files, which GitHub uses a lot for things like readme files. Covers basics like headings, lists, images, etc
Advanced formatting for Markdown, which covers things like tables, code with syntax highlighting, diagrams, and more snazzier features