One of the things that many tutorials and guides never teach you about git
is how to use it for your day-to-day work. Over time you learn what works and what doesn't, but it isn't always obvious and certainly isn't obvious how you should use it from the start.
So let's explore a possible typical workflow.
Starting off
Using an existing repo
git clone some-repo.git
- This is the usual starting point if you are aiming to work with an existing repo. You can append a directory name to the end which is where the repository will be cloned to. Some people also prefer to create a new directory, cd in to it, and run git clone some-repo.git .
Creating a new repo
Otherwise, run git init
within the directory you wish to use for your repo will initialise it. You can have existing files within this directory. If you use this method, you will need to also add the files you want git
to keep track of, you can use the following methods:
- Add a
.gitignore
file to the root of the directory containing a list of files/types you do not want included. You can list explicit files and/or wildcard matches like*.so
which will exclude all files ending in.so
, orrandom*
which will exclude anything with 'random' as the the first part of the file name. A.gitignore
with a single*
wildcard in it will exclude everything. git add .
- This will add everything in the working directory, ideally you want to have the.gitignore
done before doing this.git add path/filename
- Add a file explicitly. If you set up a.gitignore
exclude everything then you will need to usegit add -f path/filename
to force tracking of that file.git add -u
- If you already have your files tracked with git, then using this command will add only updated/changed files.- Note: You need to
git add
any time you have modified files and are going to do a commit, generallygit
will warn you when changes have been made which haven't been tracked.
If you intend to keep your newly created repo in a remote such as BitBucket or GitHub, go to those sites and create a repository using their interfaces, they will then give you a detailed set of commands to run to add the remote to your repo. Generally speaking it will follow this format;
git remote add origin git@git-repo-url/reponame.git
- to add the remote as origingit push -u origin master
- to push everything upstream, assuming you've initialised and added files to your repo of course.
Tracking changes
Before performing any work, and assuming you're working with a project which is being stored remotely, you should ideally git pull
to check upstream for changes before starting and ensure your local repo is up to date.
If you're working with someone else's project (or in a team) then it is always recommended that you work in a new branch to avoid contaminating the master
branch.
git checkout -b newbranchname
will create and checkout a new branch with the name specified by newbranchname, this is how you will perform the bulk of your work.
You can have multiple branches, for example you may have a branch of master
called dev_vector
where you are writing new code for some vector calculations, and then you can have another branch from master
named documentation
where you're adding docs to the source. You can also branch a branch and get messy via git checkout -b new_vector dev_vector
- this is a new branch off of dev_vector
Now, do some work in that branch, and add your changes:
git add -u
to add only updated files, and/orgit add files-explicitly
, or wildcardgit add .
which will add everything not blocked by.gitignore
At this stage git
is tracking the changes you've made, but they haven't actually been added to the repo proper, essentially you've just prepared git
for a commit; so either
git commit
to commit the files, this will then pop-up a commit message in your preferred text editor where you should ideally describe what changes have been made (as a whole)git commit -m
"Your message here" if you want to do a quick commit without adding a fancy message.
A small note on commit messages
Commit messages are an important guide to you when looking at the history of a project, and a well written commit message is invaluable. We've all been guilty of writing such gems as "asdasdasd" (much like how we probably mashed the keyboard for a game save name at least once), and when trying to find a breaking change, this is just plain unhelpful. Rather than extoll the virtues of commit messages here, please read this excellent post by Chris Beams.
Now! If you're working with a repo that is tracked upstream (I really hope you are, or at least keep regular backups), run git push
. This is optional, you can just keep it all local if you want, and sometimes this is the case when you're just experimenting with code in a random branch. You can of course just keep the master
branch upstream, and keep all your branches local.
In the case that you are working on someone elses, or an organizations project, please do follow their guidelines for commits if they have a guide.
Merge to the Master branch
Assuming you've made all your changes and committed them to the hallows of git
, you're now in a position to get them in to the master
branch which is where the main code is developed.
The first thing you should do is make sure master
is up to date, so quickly do;
git checkout master
git pull
Now checkout back to your working branch, git checkout branchname
. You should then git rebase master
your changes on the current master
, this is the fun part. What this does is rewinds your changes back to the point where you branched, then replays your changes on to the master
from the point where you branched off. If things go smoothly, then there won't be anything for you to do apart from git add -u
and git commit
, before the next step.
If for some reason you had issues then git
will tell you all about it. Likely you will need to edit the problem files where git
will have inserted lines which include the lines to be changed, and the changes.
So now that your branch is updated to the current master
, it's time to actually merge your changes.
git checkout master
git merge branchname
Since we prepared by first getting the branch updated to master
, this should have been completely pain free (this is why we update the branch first). So go ahead and perform the holy trinity;
git add -u
git commit
git push
Notes: Some extra little helpful tidbits
Instead of doing lots of small commits and pushes, you can amend the last commit and add to it with git commit --amend
. For example, you forgot to rename something, or added a new file, rather than adding yet another commit, just amend the last one. But be aware, don't make this your primary mode of committing code and be sure to create a regular commit - the last --amend
you do will be the last full commit before the next.
To simplify the above, git commit --amend
will append changes to the last commit, a git commit
is a new commit.
If you really screwed up with your changes, you can run git reset --hard
or git reset --hard *some commit*
, this will take your current branch back to the last commit or commit specified and change all staged (git add) files back to that point. Use with caution!
You can checkout a commit, run git log
to see a list of commits, and then git checkout *change-hash*
where change-hash looks similar to commit 917854a9760fc662b341efe1c0b51671535ab423
under git log
.
Want to know what changed between commits? Run git log
to view the history, then run git diff 14b8..b410
where 14b8..b410 is the first few characters of the commits you want to compare. Order matters! so if you compare most-recent..least-recent
then you will get changes listed in reverse order to the actual commit timeline. To view changes in timeline order you will need to compare least-recent to most-recent.
You can also run git diff path/to/filename
to see only what has changed with that file, likewise you can also use git log path/to/file
to see its history.
There is also git log -p path/to/filename
, this will give you a change log which also contains a diff between each change. This and the above commands can be used to compare branches as well.