Chapter 7 Common issues & tips

This section outlines some common issues you may run into, and how to fix them, as well as describing a few useful commands to make Git a little more user friendly.

7.1 Common issues and how to fix them

7.1.1 I’ve realised I made an error in my commit

If you’ve just committed some changes but realised a mistake in them you can “amend” the commit. However, this should be done before you push your changes! Things can get complicated if you try amending public commits.

To amend the commit, correct the file, add the file in Git and then use this command to combine the correction into the previous commit:

git commit --amend

(Technically this combines both commits into a new commit that overwrites the last one).

If you’ve made a typo in your commit message you can also correct it with amend. Say your last commit looks like this:

109563e Some User | 2018/01/27 10:44 Added mew featuere

Adding the -m flag to your amend allows you to add a new comment.

git commit --amend -m "Added new feature"

Your history will then look like this:

23237f1 Some User | 2018/01/27 10:44 Added new feature

7.1.2 I want to go back to an earlier commit

You’ve made some changes that didn’t work out for whatever reason, and now want to return your code to an earlier state. There are two ways to do this: reset and revert.

7.1.2.1 Reset

This option will “roll back” your directory to its earlier state, essentially going back in time and removing any changes since the commit you go back to.

Use

git reset --hard <commit-hash>

where <commit-hash> is the unique hash of the commit you want to go back to (you can find this via git log).

The --hard option in this command means that your working directory and staging area will also be reset, which is usually what you want, but be careful as you will lose any uncommitted changes when you use this command.

7.1.2.2 Revert

This option keeps all the changes you have made, but adds an extra commit with new changes that reverse the previous changes.

You will usually want to use

git revert HEAD

to revert the most recent commit (which is what the HEAD in this command refers to).

Reverting anything other than the most recent commit is not recommended.

If you want to revert multiple commits at once, you can use something of the form

git revert --no-commit HEAD~2^..HEAD

followed by

git commit -m "Reverted last three commits"

Walking through this:

  • The --no-commit part of the command means that the reversion will change the working directory and staged files, but not yet be committed. (You’ll have seen that we commit it afterwards, which is the usual way to work when reverting multiple commits at once).

  • HEAD~2^ means the commit two commits before HEAD (and e.g. HEAD~4^ would be the commit four commits before HEAD)

  • .. indicates to include all commits between the two specified

So the first command reverts the most recent commit and the two before it - three commits in all - but only makes those changes in the working directory and staging area rather than committing them. Then the second command is a standard commit command which commits them all with a message.

7.1.2.3 When should I use reset vs revert?

The two commands will result in a different git history. With reset, any changes you roll back will not appear, giving a shorter history; with revert, everything that happened will be recorded and the history will be longer. So if it’s not necessary for anyone to know about the rolled back changes, reset is probably better; if you need a record of what happened then revert is probably better.

There are a few other important considerations too:

  • You need to be a bit more careful when using reset, as it will erase any uncommitted changes and you’ll be unable to recover them.

  • If any of the changes you want to reverse have been pushed to a remote server, you should use revert so that it’s clear to others that changes have been rolled back. Using reset on a shared history will create confusion because it will not be clear what has happened.

  • You can’t (easily) revert past a merge because it’s unclear which merged branch you want to revert to. reset is easier to use when the history you want to roll back includes a merge.

7.1.3 I’ve worked on the wrong branch (but haven’t committed yet)

You’ve made some changes to your code, saved them, but realised that you’ve been working on the wrong branch before committing. Fortunately, this is pretty easy to solve. The git stash command is your friend here: it allows you to store all your file changes away since the last commit away, and bring them back where you want - usually on a new branch.

The commands are: store away any changes with

git stash

(If you check git status at this point you’ll see that your file changes since your last commit no longer appear.)

Then switch branch with

git checkout <your_branch>

and use

git stash pop

to bring your changes back. That’s it!

Using the pop command does not commit your changes - you have simply moved uncommitted changes from one branch to another - and once you have “popped” your changes they will be removed from the stash.

Occasionally popping changes from the stash will cause a merge conflict. You can resolve this in the same way as a usual merge conflict by editing the files, and then add the result to your next commit. (Note that when a pop causes a merge conflict, your changes will not be removed from the stash like normal so you will still have access to them if needed.)

Using the stash

The git stash can technically hold many different sets of changes at once, but it is not good practice to store anything in the stash long-term. It is a temporary store and should only be used to quickly move changes around when needed.

7.1.4 I’ve worked on the wrong branch (and committed it)

If you’ve only realised that you’re working on the wrong branch after committing your code, then you’ll need to do two things. The first is to get the code onto the correct branch, and the second is to remove it from the wrong branch you committed it to.

If you forgot to create a new branch, you can create one now that includes the commits you want using

git branch <new_branch_name>

then roll back the current branch as described here.

If you already created a branch but forgot to switch to it, you’ll need to move the commits to the correct branch. You can do this by checking out the correct branch and copying the commits to it using cherry-pick:

git checkout <correct_branch>
git cherry-pick <commit-hash>

where <commit-hash> is the commit you want to copy over. For multiple commits, you can copy them all over using

git cherry-pick <commit-hash-1>..<commit-hash-n>

where <commit-hash-1> is the earliest commit you want to copy and <commit-hash-n> is the most recent. Then check out the branch you accidentally committed them to and roll it back as described here.

7.2 Other tips

7.2.1 Log Customisation and Aliases

You can customise the log by adding extra arguments. For example, adding the --oneline argument the log is cut down to one line per commit.

git log --oneline

There are a lot of possible arguments to add to the log. This example will show the latest commit on each branch, give a rough branching diagram and put the date in a specified format.

git log --pretty=format:'%C(yellow)%h%Creset %an| %Cgreen%cd%Creset %s %C(cyan)%d' --graph --all --date=format:'%Y/%m/%d %H:%M'

All the possible arguments to add to git log are in the documentation here.

Eventually you’ll have too many arguments to sensibly type, so you can use an alias. An alias allows you to define a new command based on an old command. You define one like this:

git config --global alias.<your_alias_name> = <your_command>

After this you can type

git <your_alias_name>

to carry out the command.

For example, using the long, customised log from above we can define a new command, “hist”.

git config --global alias.hist = log --pretty=format:'%C(yellow)%h%Creset %an| %Cgreen%cd%Creset %s %C(cyan)%d' --graph --all --date=format:'%Y/%m/%d %H:%M'

Allowing us to type:

git hist

to view a fancy version of the log, without having to type out a huge command!

7.3 Work Items

DevOps has rich project management functionality that can be used to manage projects of all sizes. At it’s most complex you can utilise a mix of Epics, Stories, Features, Tasks, Issues and User stories to manage your project.

These terms and planning stages for a project come from software development.

Instead we recommend treating features as the main type of work item and breaking your workload down into a number of features. This is similar to what you would do on GitHub with Issues.

With features you can again add lots of metadata but the most useful will be the following:

  1. Name
  2. Description
  3. Assigned to

There are then numerous ways to visualise work allocations across Azure DevOps ranging from individual task assignments to project boards (similar to trello boards).

By utilising work items you take out the need for tracking tasks manually.