-
Notifications
You must be signed in to change notification settings - Fork 0
git
This page covers how I use Git and GitHub to edit and collaborate on code. It might not be best practice, it's just what works best for me so far.
Git is a tool used to store open-source code (such as test suites) and allow people to collaborate on it. We often use GitHub in government because of point 12 of the service standard: Make new source code open - it makes things better because it avoids duplication and anyone can suggest improvements.
Broadly what it helps you do is to:
- create a copy (branch) of existing code
- make changes to it
- commit the changes - this saves the changes on your computer as a package of changes ready to copy them to GitHub
- push (copy) the changes back to GitHub - this makes your work public
- get the changes reviewed by raising a "pull request"
- merge the changes into the main code branch
Some terminology:
- Git is the core version control system that you access through your command prompt.
- GitHub is the website which shows everyone's code, and manages pull requests.
- GitHub Desktop is the (optional) desktop app that makes it easier to work with your project without using the command prompt.
This guide assumes that you are using a Command Line Interface (CLI) version of Git to manage code. You can also use a more visual app such as GitHub Desktop.
Before you do anything, this guide assumes that you have a Mac with enough permissions to install things on it - often referred to as a developer build.
I've written a separate guide on setting up a Mac for coding. Follow the steps in the "Initial installs" section before continuing on this page. In particular, install these first:
- Homebrew
- a code editor such as Visual Studio Code
- XCode Command Line Tools
and you'll need to make sure Terminal is working.
Open Terminal, create a "projects" folder in your home directory and navigate to it using the cd (change directory) and mkdir (make directory) commands:
cd ~
mkdir projects
cd projectsThe tilde symbol (~) represents the home directory on your computer. To find out where you are, you can use pwd (print working directory). And to list what is in the current directory, you can use ls (list).
Sign up for a GitHub account on GitHub.com. It's sensible to start with a personal email address, so that you can continue to use your GitHub account if you move to a different organisation.
As almost everything on GitHub can be public, you need to make sure that your email address is not made public when you push code to GitHub.
GitHub therefore provides you with a "no reply" email address which replaces your own address in public. This is in a format like 12345678+username@users.noreply.github.com. To set this up:
- Go to GitHub email settings (or go to your avatar in GitHub, and go to Settings then Emails from there)
- Turn on "Keep my email addresses private"
- Make a note of the email address in this section as you'll need it to continue setup.
To access your organisation you may need to:
- add your work email address as your primary GitHub email address - you can still also use your personal address
- ask your organisation's engineering team to add you to the organisation on GitHub
Once XCode Command Line Tools and Homebrew are installed, you can install Git in Terminal using:
brew install gitOnce installed, you can check that it was successful using git --version.
Then set up your GitHub username on your computer, using the hidden email address that you got in the previous step:
git config --global user.name "Brian Butterfield"
git config --global user.email "12345678+brianbutterfield@users.noreply.github.com"You will then need to set up a personal access token to enable you to keep pushing to GitHub without having to enter your password every time. It is very important to look after this and avoid sharing it.
Follow GitHub's instructions on setting up a personal access token - stop once the token is created.
Once you have a personal access token, you will be prompted for it when you first push code to GitHub. When you do this, you will be prompted for a password and you can paste your access token there instead of using the password you set up when you created your account.
Alternative Git setup guides:
If you're new to GitHub then the GitHub Hello World tutorial is worth doing to understand the basic process.
You could then set up your own personal repository to test out things like commits, pushes and pull requests.
To start contributing to a project, you will need to identify which repository you plan to work on. Each repository (repo) and organisation has different access settings. When you work for a company, you will usually need to be added to that organisation on GitHub to push to its repositories - your development team should know who can grant you access to this.
To clone (copy) the repository to your computer and enable you to work on it:
- Navigate to your projects folder using
cd ~/projects - Clone the latest code from the repository you're working with. You can get the URL from the Code menu on the front page of your repository on GitHub.com. For example,
git clone https://github.com/andrewhick/reference.git - Navigate to the repository folder:
cd reference
You should now be ready to start work on a repository.
Before you start, it's vital that you never publish user data, keys and passwords on GitHub. GitHub is very good at remembering all versions of code, so even if you correct a mistake later, login details could still exist in old versions of your code that are published online.
These are the most common steps for updating a test repository, using the command prompt. The examples assume that you're working on a branch called add-accessibility-page in the reference repository, which is in your local projects folder.
Start the command prompt, navigate to your project folder and pull the code from the repository:
cd projects/reference
git pullThis gives you the latest code without overwriting any new code you've already written on your machine. If you don't pull code before you start work then you're much more likely to have conflicts to deal with later - which is manageable and sometimes inevitable, but fiddly.
Think of a descriptive name for the branch based on what you're planning to work on, for example, "add-accessibility-page". It is good practice to stick to what you plan to do while using this branch.
The easiest way to create a branch is:
git checkout -b add-accessibility-pageWhen you next commit and push the code to GitHub, this will create a copy of that branch there.
If, instead, you've already created the branch via the GitHub website, then you'll need to ensure that the changes you make on your machine stay in sync with the changes on the same branch in Git:
git checkout -b add-accessibility-page
git pull
git branch --set-upstream-to=origin/add-accessibility-pageThe git pull in the middle is useful because it prompts you to do the "set upstream" step afterwards.
Write your code, saving regularly to your local machine - it's a good idea to have autosave turned on in your code editor.
Try to write code in logical units, so for example if you're working on fixing headings on a page, then just fix the headings in that commit and try to avoid fixing other errors that you spot at the same time - they should be in a separate commit. Your commit can be as small as a typo correction, or a whole new module of code.
Work from the principle that each time you commit code, your code will still be "complete" or "shippable", even if not all the features are there yet - try to avoid leaving "TO DO" or "work in progress" markers everywhere.
At regular intervals, it's useful to check the status of what's going to be committed. git status is always useful if you're lost.
When you've finished a "thing", however small or large, then you can commit (save) the changes.
Firstly check where you are:
git statusThis tells you which files have been changed and which can be added to the commit. You'll then need to add files to the next commit (it is easy to forget to do this!) Usually you will want to add all files to your commit, but sometimes, some configuration files (for example Gemfile.lock if you're working with Ruby) can get added without you wanting them.
Then add the files using any of the following methods:
git add . # adds all new or changed files for the commit
git add new-page.html # only adds new-page.html to the commit
git add foldername # only adds everything in the foldername folderNow you are ready to commit the code on your computer. Use git status again to check what will be in your next commit. Then do the commit and add a message with -m:
git commit -m "Add a new accessibility page"If the commit was successful then you can push it to GitHub to allow other people to view and comment on it:
git push -u origin add-accessibility-pageSome abbreviations:
-
.means "add any changed files" -
-Ameans "add all files" -
-ameans "add all modified or deleted files" -
-mis used to add a message to your commit -
-umeans "upstream" - this ensures that the new branch you've created gets copied to GitHub.
If you want to commit all modified files at once and skip the add step, you can add a flag like -a to the commit, for example git commit -am "Add a new accessibility page". However, this can make it easy for you to commit files that aren't part of your current work.
A pull request (PR) is the way to ask your colleagues if they're happy for you to pull your changes into the main branch of the repository. This must always be shippable, so it's your responsibility to ensure that the code works beforehand.
Before you raise a pull request, depending on the type of repository, you may need to carry out some checks:
- Ensure that all of your tests pass, if you're writing a test repository.
- 'Lint' your code. This is like a spelling and grammar check that your code is good enough to go live with. How you do this depends on the framework you use. For Ruby-based frameworks we do this with Rubocop (
bundle exec rubocop) which points out code issues and tells you how to fix them. You can also install inline linting tools in your text editor. - Remove any "work in progress" tags as they can cause any Continuous Integration built into GitHub to fail.
If you've made any changes as a result, then add, commit and push them again to your branch.
You can then:
- Navigate to the branch on the GitHub website
- Click "Compare and pull request"
- Resolve any conflicts that appear on the page
- Add a brief comment explaining why you're making the changes
- Review any automated checks that GitHub carries out on the repository. If they fail, then check the logs and discuss with a colleague if unsure.
- Create the pull request
- Nominate a reviewer (it's polite to talk to them too!)
If your colleagues suggest changes, then you can make these, commit and push to the branch in the same way that you did before, double-checking that your tests still pass.
Once your colleagues are happy with the code and all automated checks pass, you can then squash and merge the code on the pull request page.
You should then take the opportunity to delete the branch you worked on - the "Delete branch" option deletes it on GitHub.
To help prevent the code getting out of sync on your local machine, you should then also switch to main and pull the latest code:
git checkout main
git pullIf you want to delete the branch on your computer too, you can list the branches currently on your machine, and delete any you don't need:
git branch -l
git branch -d add-accessibility-pageYou should then switch to a new branch when you start your next piece of work.
It's very easy to make mistakes in Git, but they can usually be corrected. In general, committing little and often, and keeping your pull requests small are the safest ways to prevent things going wrong.
If there are edits in a local file and you want to quickly revert it to main, you can checkout the main version of that file:
git checkout main path/to/fileAlternatively, if you want to keep the edits you've made from a file that you've added (via git add) but you want to exclude it from your current commit, use:
git reset HEAD -- path/to/fileThis effectively reverses your add statement.
To overwrite the previous commit without making further changes:
git commit --amend --no-editTo overwrite the previous commit and change the message:
git commit --amend -m "This is the new commit message"If you have pushed too much in one go and want to revert some changes, Git will not let you push the reverted changes automatically and will return an error such as "Updates were rejected because the tip of your current branch is behind its remote counterpart."
If this happens and you still want to revert the changes, you need to force push as follows:
git push --force -u origin your-branch-name
# or
git push -f -u origin your-branch-nameIf you have started from the wrong base, your pull request commit history may end up with incorrect commits from other work you have been doing. It is possible to remove commits from a pull request with:
git checkout my-pull-request-branch
git rebase -i HEAD~n # where n is the number of last commits you want to include in interactive rebase.
# This should open your code editor. There, replace "pick" with "drop" for commits you want to discard. (There's more context on this in the link).
# Save and exit.
git push --force-with-leaseSometimes, Git and your computer can get out of sync. If you're certain that the "remote" (online) version of the code is correct (make a backup if unsure), then use the following:
git fetch origin
git reset --hard origin/mainWhen carrying out certain commands, like rebase, you may get an error as follows:
hint: Waiting for your editor to close the file... code --wait --disable-extensions: code: command not found
error: There was a problem with the editor 'code --wait --disable-extensions'.
To fix this for the Code editor, follow the "launching from the command line" steps.
Never publish passwords or any other sensitive data to GitHub. Even if you remove them later, GitHub stores all old versions of code, so they're still accessible.
As automated tests often rely on login details however, you need a way to send passwords to your tests. How you do this depends on your framework, but there are two main methods:
Your framework may allow you to pass in passwords as environment variables to your test. On a Mac, this means updating your .bash_profile file to include the variables, and calling them from your tests.
You can put passwords in a config file, then set a .gitignore file in your repository to exclude your config files from commits.
Whichever method you use, speak to a colleague who has done something similar, who can advise on the best way to do this.
If you need to switch between branches, you may be prompted to stash your work on that branch so that you don't lose your work. Use git stash to store your changes, and git stash pop to get them back again.
If you have made some changes but wish to split them across multiple commits, then you can select each change and decide whether to stage it individually for your next commit. Do this by:
git add --patch
# or
git add -pYou will then be prompted whether to stage each change or not as follows:
(1/1) Stage this hunk [y,n,q,a,d,e,?]? ?
y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk or any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk or any of the later hunks in the file
e - manually edit the current hunk
? - print helpTo add an author to a commit, add their publicly-shareable email address to the commit message separated by two empty lines like this:
git commit -am "Your commit message
Co-authored-by: co.author@example.com>"More information on co-authoring
Type git log -x where x is the number of previous commits you want to view
Go to GitHub Pages.
If you've accidentally changed a file, and committed and pushed the changes, you can remove that file from the push as follows:
git checkout HEAD^ -- /path/to/file # allows you to revert the changes from a particular file
git commit --amend --no-edit # amends the previous commit (as above)
git push -f -u origin your-branch-name # force pushes the change (as above)