Using Git In Your Workflow

to check file changes:

$ git status

Commonly used commands. 3 main categories:

  1. Changes not staged for commit
  2. Changes to be committed
  3. Untracked files

to add a file to be tracked by git to the “staging area” (the example below adds 2 new files directly and all files in the css directory):

$ git add new-page.html index.html css/*

To record the removal of a file:

$ git rm file.html

Check status again to make sure we've prepared the correct modifications:

$ git status

To commit the changes:

$ git commit -m "write a good comment"

If you have a longer commit message, possibly with multiple paragraphs, you can leave out the “-m” parameter and Git will open an editor application for you (which you can also configure via the “core.editor” property).

Git saves every commit that is ever made in the course of your project. Especially when collaborating with others, it's important to see recent commits to understand what happened.

$ git log

It lists the commits in chronological order, beginning with the newest item. If there are more items than it can display on one page, the command line indicates this by showing a colon (“:”) at the end of the page. You can then go to the next page with the SPACE key and quit with the “q” key.

Every commit item consists (amongst other things) of the following metadata:

  1. Commit Hash
  2. Author Name & Email
  3. Date
  4. Commit Message

Branching & Merging

To create a new branch (using a name that fits the context of the branch's use). This command only creates the branch but does not make it active:

$ git branch contact-form

To list all of the branches (the -v command gives more detail):

$ git branch -v

To make a branch active (to see which branch is currently active, use the ‘git checkout' command):

$ git checkout contact-form

To save temporary changes (before checking out a different branch), stash away these local changes so we have a clean working copy before starting to work on our new feature::

$ git stash

Then check status:

$ git status

You will see something like:

# On branch master
nothing to commit (working directory clean)

The local changes are now safely stored on a clipboard, ready to be restored any time we want to continue working on them.

To view current stashes (The newest stash will always be at the top of the list, named “stash@{0}”. Older stashes have higher numbers):

$ git stash list

When you're ready to restore a saved stash, you have two options:

1. Calling “git stash pop” will apply the newest stash and clear it from your stash clipboard.

$ git stash pop

2. Calling “git stash apply ‘stashname' will also apply the specified stash:

$ git stash apply <stashname>

but it will remain saved. You can delete it later via:

$ git stash drop <stashname>

You can choose to not specify the stash when using any of these commands. Then, Git will simply take the newest stash (always “stash@{0}”).

When to Stash

Stashing helps you get a clean working copy. While this can be helpful in many situations, it's strongly recommended…

  1. before checking out a different branch.
  2. before pulling remote changes.
  3. before merging or rebasing a branch.

Merging Changes

performing a merge requires just two steps:

  1. Check out the branch that should receive the changes.
  2. Call the “git merge” command with the name of the branch that contains the desired changes.
$ git checkout master
$ git merge contact-form

To check that the merge was successful:

$ git log

When you have created a new local branch and want to push it to your git repository as a new branch:

$ git push -u origin <branchname>

This will automatically add the new branch to GitLab

Connecting a Remote Repository

When you clone a repository from a remote server, Git automatically remembers this connection for you. It saves it as a remote called “origin” by default. In other cases where you started with a fresh local repository, no remote connections are saved. In that situation, we need to connect our local repository to a new remote before we can try some remote interactions:

$ git remote add <shortname><ur>


$ git remote add crash-course-remote

To check if it worked:

$ git remote -v

To view branches (or use ‘git branch -av' as displayed on the cheatsheet):

$ git branch -va

The “git remote add” command establishes a relationship – but no data is exchanged yet.

To update the information about a remote, you have to explicitly request this data. Most notably, a “Fetch” operation does this for you. Fetch will not touch any of your local branches or the files in your working copy. It just downloads data from the specified remote and makes it visible for you. You can decide later if you want to integrate new changes into your local project.:

$ git fetch crash-course-remote

To be able to work with a branch – to have our working copy populated with its files – we need to create a new local branch that's based on this remote branch. We're telling the “git checkout” command which remote branch we want to have. Example:

$ git checkout --track crash-course-remote/faq-content

This command does a couple of things:

  1. It creates a new local branch with the same name as the remote one (“faq-content”).
  2. It checks this new branch out, i.e. it makes it our local HEAD branch and populates our working copy with the associated files from that branch's latest revision.
  3. Since we're using the “–track” flag, it establishes a so-called “tracking relationship” between the new local branch and the remote branch it's based on.

To push changes made locally to the remote branch:

$ git push <remote><branch>


$ git push crash-course-remote faq-content 

To integrate remote changes you may first want to inspect them. Example:

$ git fetch origin
$ git log origin/master

The “git log” command now shows you the commits that happened recently on the “master” branch of the remote called “origin”. If you decide you want to integrate these changes into your working copy, the “git pull” command is what you need:

$ git pull <remote><branch>


$ git pull origin master

This command downloads new commits from the remote and directly integrates them into your working copy. It's actually a “fetch” command (which only downloads data) and a “merge” command (which integrates this data into your working copy) combined.

As with the “git push” command: in case no tracking connection was established for your local HEAD branch, you will also have to tell Git from which remote repository and which remote branch you want to pull (“git pull origin master”, e.g.). In case a tracking connection already exists, a vanilla “git pull” is sufficient.

The target of the integration, however, is independent of a tracking connection and is always the same: your local HEAD branch and, thereby, your working copy.

Publishing a Local Branch

This command tells Git to publish our current local HEAD branch on the “origin” remote under the name “contact-form” (it makes sense to keep names between local branches and their remote counterparts the same). The “-u” flag establishes a tracking connection between that newly created branch on the remote and our local “contact-form” branch. Example:

$ git checkout contact-form
$ git push -u origin contact-form

After having created that new remote branch like this, updating it with new local commits that you create in the future is easy: simply call the “git push” command with no options as we did in our earlier example.

Anyone with access to your remote repository can now also start working on “contact-form”: he can create a local branch on his machine that tracks this remote branch and also push changes to it.

To delete a local branch (example):

$ git branch -d contact-form

To delete a remote branch (example):

$ git branch -dr origin/contact-form

Undoing Things

The “–amend” flag of the “git commit” allows you to change the very last commit really easily. If you just want to correct the commit message, you simply “commit again” – without any staged changes but with the correct message:

$ git commit --amend -m "This is the correct message"

If you want to add some more changes to that last commit, you can simply stage them as normal and then commit again:

$ git add some/changed/file.ext
$ git commit --amend -m "commit message"

Undoing Local Changes

Changes are called “local” when they haven't been committed, yet: all the modifications that are currently present in your working directory are “local”, uncommitted changes. Sometimes, you'll produce code that is worse than what you had before. These are the times when you want to discard these changes and start fresh with the last committed version.

To restore a file to its last committed version, you use the “git checkout” command:

$ git checkout HEAD file/to/restore.ext

You already know that the “checkout” command is mainly used to switch branches. However, if you use it with the HEAD reference and the path to a file, it will discard any uncommitted changes in that file.

To discard all current changes in your working copy and restore the last committed version of your complete project, use the “git reset” command:

$ git reset --hard HEAD

Discarding uncommitted changes cannot be undone. This is because they have never been saved in your repository. Therefore, Git has no chance to restore this kind of changes.

Undoing Committed Changes

Sometimes you'll want to undo a certain commit. E.g. when you notice that your changes were wrong, when you introduced a bug, or simply when the customer has decided he doesn't want this anymore.

Using the “git revert” command is one possibility to undo a previous commit. However, the command doesn't delete any commits. Instead, it reverts the effects of a certain commit, effectively undoing it. It does this by producing a new commit with changes that revert each of the changes in that unwanted commit. For example, if your original commit added a word in a certain place, the reverting commit will remove exactly this word, again.

Simply provide the hash of the commit you want to revert (example):

$ git revert 2b504be

Then check the log:

$ git log

Another tool to “undo” commits is the “git reset” command. It neither produces any new commits nor does it delete any old ones. It works by resetting your current HEAD branch to an older revision (also called “rolling back” to that older revision). Example:

$ git reset --hard 2be18d9

After this command, your currently checked out branch will be at revision 2be18d9. The commits that came after this one are effectively undone and are no longer visible in the history of this branch.

Be careful, however: calling the command with the “–hard” option will discard all local changes that you might currently have. The project is completely restored as it was in that past revision. If you call it with “–keep” instead of “–hard”, all changes from rolled back revisions will be preserved as local changes in your working directory. Note

Just like “revert”, the “reset” command also doesn't delete any commits. It just makes it look as if they hadn't existed and removes them from the history. However, they are still stored in Git's database for at least 30 days. So if you should ever notice you accidentally removed commits you still need, they can still be restored.

Both commands, revert and reset, only affect your current HEAD branch. Therefore, you should make sure you have checked out the correct branch before starting to play with them.

The Golden Rules of Version Control

1: Commit Only Related Changes

When crafting a commit, it's very important to only include changes that belong together. You should never mix up changes from multiple, different topics in a single commit. For example, imagine wrapping both some work for your new login functionality and a fix for bug #122 in the same commit:

Understanding what all those changes really mean and do gets hard for your teammates (and, after some time, also for yourself). Someone who's trying to understand the progress of that new login functionality will have to untangle it from the bugfix code first. Undoing one of the topics gets impossible. Maybe your login functionality introduced a new bug. You can't undo just this one without undoing your work for fix #122, also!

Instead, a commit should only wrap related changes: fixing two different bugs should produce (at the very least) two separate commits; or, when developing a larger feature, every small aspect of it might be worth its own commit. Small commits that only contain one topic make it easier for other members of your team to understand the changes – and to possibly undo them if something went wrong.

2: Write Good Commit Messages

Time spent on crafting a good commit message is time spent well: it will make it easier to understand what happened for your teammates (and after some time also for yourself). Begin your message with a short summary of your changes (up to 50 characters as a guideline). Separate it from the following body by including a blank line. The body of your message should provide detailed answers to the following questions: What was the motivation for the change? How does it differ from the previous version?

3. What Makes a Good Commit?

The better and more carefully you craft your commits, the more useful will version control be for you. Here are some guidelines about what makes a good commit:

Related Changes

As stated before, a commit should only contain changes from a single topic. Don't mix up contents from different topics in the same commit. This will make it harder to understand what happened.

Completed Work

Never commit something that is half-done. If you need to save your current work temporarily in something like a clipboard, you can use Git's “Stash” feature (which will be discussed later in the book). But don't eternalize it in a commit.

Tested Work

Related to the point above, you shouldn't commit code that you think is working. Test it well – and before you commit it to the repository.

Short & Descriptive Messages

A good commit also needs a good message. See the paragraph above on how to “Write Good Commit Messages” for more about this.

Finally, you should make it a habit to commit often. This will automatically help you to keep your commits small and only include related changes.

4: Never Commit Half-Done Work

You should only commit code when it’s completed. This doesn’t mean you have to complete a whole, large feature before committing. Quite the contrary: split the feature’s implementation into logical chunks and remember to commit early and often. But don’t commit just to get half-done work out of your way when you need a “clean working copy”. For these cases, consider using Git’s “Stash” feature instead.

5: Never Amend Published Commits

Using the “amend” option is a great little helper that you'll come to appreciate yourself very quickly. However, you'll need to keep the following things in mind when using it:

(a) It can only be used to fix the very last commit. Older commits can't be modified with “amend”. (b) You should never “amend” a commit that has already been published / pushed to a remote repository! This is because “amend” effectively produces a completely new commit object in the background that replaces the old one. If you're the only person who had this commit, doing this is safe. However, after publishing the original commit on a remote, other people might already have based new work on this commit. Replacing it with an amended version will cause problems.

To continue with even more usage examples:

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.