Git

How to revert a commit in git

Git

Git revert is the command you need to undo a commit in Git, and is the safest way to change history in a git repo. Rather than just discarding changes, like git reset, which I covered in this post, git revert looks at the changes made in a commit and then reverses, or applies the inverse, of each of those changes in a new commit. So rather than hiding what happened by discarding the work in the files you’re undoing, and risking losing work, it records the ‘undo’ in the history. This is much safer way of working and is always the recommended way to undo a commit, especially if you have already pushed your changes to a remote repo.

How to use git revert to undo a commit after you have pushed

Let’s say you’ve pushed some code into the repo and now you’ve realised that something is really wrong. You’ve been working all morning, you’ve made 3 commits, and you now know that the 3rd commit is bad and contains a mistake.

We can use git log to see all our commits, even better we can use :

git log --oneline

… to see a condensed, simple list of our commits, and the hash id for each. It will look like this:

using git log to see commit hash id

The commit with hash id 2667ffe is the first commit, and is good. But the 3rd commit which has a hash id of c7c318a is bad and we want to ‘undo’ it. We’ve pushed this code to the remote branch so the important (really, really important) thing to be aware of here is that while you’ve slowly been dawning on the fact you’ve pushed some bad code into the repo, your team mates may have pulled that code down to their local repos and are currently wondering why something is wrong.

This is where git reset would NOT work because simply discarding the bad files in your local repo won’t help make everyone else’s bad code get better. So what we want to do, in plain English is:

  1. Fix the bad code locally by undoing that commit
  2. Commit the changes so that the fix is recorded in our repo history
  3. Push this new commit to the remote repo
  4. Let our team mates know so they can pull down the new, fixed, code

And to do that we will firstly do a git revert of that third commit, so we get the hash id from the git log as shown above, and then type:

git revert c7c318a

This will bring up a series of messages in the terminal window, showing you that you are in the process of reverting the commit. It will suggest a message for this new commit, which you can edit if you want to by placing your cursor where you want to type and then typing (sounds obvious but it is not intuitive). Once you’ve finished editing that message press Esc followed by :wq (you have to hold all 3 of these keys down together). That will save the message, do the commit, and exit from the Vim terminal.

So that is the problem resolved in your local repo, now you need to push this new commit to the remote repo, so type:

git push

And finally you need to let your team mates know you broke it – but you’ve fixed it too!

Getting a merge conflict when using git revert

Depending on the specific details of the changes you’ve made in each of those commits you may get a merge conflict. If so you’ll see something like this, and the file(s) with conflicts will open in your editor asking you to handle the conflict and choose which bits of code you want to keep or discard. You follow the onscreen prompts and then set the commit message, save and then push the new commit, just as described above.

undo a commit with git revert

Summary

Git revert is a ‘forward moving’ undo operation. Git reset is a backwards moving undo operation. Git revert preserves the change history in your repo, git reset discards the changes. So now you know how to undo a commit in git after you have pushed.

git fetch vs pull

Git

Should I use git fetch or git pull? What does git fetch do exactly?! In this post I’ll clarify the difference between the two git commands – and to answer the git fetch vs pull question.

In summary it’s a simple difference – git fetch ‘fetches’ all of the information about your git repo, so you can see what branches have changes – but you don’t actually pull down any of the file changes. Git pull on the other hand, gets the information AND all of the changed files. Read on for a little more detail about each command.

What is git fetch?

Let’s say you’re working as part of development team and you are all working in the same repo. If 5 of your colleagues had pushed new code into the repo, on Monday morning you might want to know exactly what changes are waiting for you to pull down. That’s what you can use git fetch for – it’s all of the changed file information from the remote branch. So why would you use it? It’s useful if you are expecting to have some conflicts from changes that have been made in the remote branch. Maybe you know a colleague has been working in the same part of the code as you. Once you are in a merge conflict situation you have to resolve it before you can continue coding, so getting some information on which files are involved in the conflict can be really useful to avoid that scenario – and that’s where git fetch is really useful. It can also be useful if you are working on a restricted internet connection, and if some of the files that may need to be pulled are very big.

What is git pull?

git pull = git fetch + git merge

So git pull ‘fetches’ all of the changed file information and then merges the changed files into your local branch. It updates your current local branch with any new files that have been added to the remote branch since you last pulled. So you need to make sure you are on the correct branch before you run git pull. If there are any conflicts caused by the new files being merged into your local branch will have a merge conflict to resolve.

In conclusion

When considering the git fetch vs git pull question, most of the time I just use git pull, especially if I’m working on a solo project or on a very small team where the files are small. But it’s certainly useful to know what git fetch does and when to use it.

What is git? Git explained in plain English – Part 2

Git

This is a follow up to my previous post ‘What is git? Explained in plain English‘. In that post I explain what git is, what a git repository is, what a branch is, and how to create a remote repo. In this post I’ll cover the following topics:

  • how to use git commit to save your changes
  • how to use git to push to a remote branch
  • describe some typical git workflows
  • talk about how to use and manage branches
  • using git log and git status to find information about your repo and branches
  • how to clone a remote repository

How to use git commit to save your changes

So you’ve been coding, and building your website or app. Once you’ve made changes in a few files you might want to ‘commit‘ those changes. Think of a commit as a way of grouping changes and of providing a snapshot, a marker if you like, of all your project files at that moment. The ‘commit‘ will be given a unique reference so if you wanted to rollback to this point at a later time, you can. When you commit any changes you add a comment to that commit which you can use to describe the changes you’ve made. Such as:

– “Added new product pages
“Fixed the sign up bug”
“Please, please work!”

If you’re working as part of a team, you may need to add a bug ticket reference here too.

“PROJ001-747A added new signup form”

You will need to type:

git commit -a -m "Your commit message goes here"

The -m tells git to use the message in the quotes against this commit.
The -a tells git to automatically stage all un-committed files to this commit. Huh? What’s staging?!

What is git stage?

Actually git stage isn’t a real command but it’s often what people look for because we talk about ‘staging‘ files sometimes before we commit our changes. Let’s say the team you’re working on doesn’t want everyone to push their changes to the remote repo all the time. In that case you may want to do lots of commits through your work day and then one push at the end of the day. But if you’ve worked on 3 different features you don’t really want to put all of these in one commit with only one commit message. You will want to ‘stage‘ your changes, i.e. break it all down into ‘stages‘. There is some logic to the terminology I guess?! On the command line you stage your changes by typing:

git add .   

It would so much clearer if this was git stage rather than git add, but there you go! Now that you know how to use git add and git commit to finalise your changes you may also at some point need to know how to undo git commit!

How to git push to a remote branch

Once you’ve finished your work you’ll want to ‘push your changes‘. This means you’re going to send your changes from your local repo to your remote repo, or to put it another way you will transfer your commits from your local repo to the remote repo.

Why do we do this? Once your code is in the remote repo it will be accessible by anyone else with permission to access it, so if you’re working on a team you’ll need to do this before they can see, or use, what you’ve coded. Even if you’re working on your own, pushing to a remote branch means you have a remote backup of your code. Remember you can’t push your changes until you’ve committed them.

So how do we know which branch we will be pushing to? Your local branch will have an upstream branch set (I think of this as a branch which is paired with my local branch). If it doesn’t have an upstream branch then when you push you’ll get a message saying “fatal: The current branch yourbranchname has no upstream branch.” so you’ll have to set the upstream branch when you push, like this:

git push --set-upstream origin yourbranchname

If you already have an upstream branch set, which is the case most of the time, you can just type:

git push

If all goes well you’ll see some percentages and some messages from git about the files that have been pushed successfully. Your remote upstream branch will now contain all of your commits.

How to use and manage git branches

Each time you set a repo up it makes sense to name your branches consistently so that your workflow becomes second nature from project to project. I always have my main branch as main, my central development branch as, you’ve guessed it, develop.

Let’s say you are working as part of a team of 3 developers and you’re all working on the codebase at the same time. You’ll have your current production code in main (actually you probably won’t, it tends to be in a versioned branch but for simplicity’s sake for now lets just say here that it’s called main!).

You’ll start by creating your develop branch from main. That is, you’ll tell git you want it to create a new branch called develop from your existing main branch, main. To start with check that you are currently on the main branch by typing:

git status

If you are on the main branch already then you’ll see a message saying :

on branch main

If you aren’t then switch to branch main by typing:

git checkout main

And now you can create your new branch, and switch to the new branch, by typing:

git branch develop
git checkout develop

You could do that in one line by typing:

git checkout -b develop

Either way, you have now created a central development branch.

Using feature branches

Now developer 1 needs to create a branch that they can work on without effecting anyone else for a while, so they create a new branch from develop and call it devname-feature. They then checkout that branch and do all of their work locally in that branch, pushing their changes regularly to the remote branch without having to worry about what anyone else is doing.

So how would you do this using git commands?

git checkout main
git branch devname-feature
git checkout devname-feature

Line by line that means:

|—> switch to the branch that’s called ‘main
|—> create a new branch called ‘devname-feature
|—> switch to branch ‘ devname-feature

git commit -m "built new feature abc"
git push

Line by line that means:

|—> commit your code changes to the local repo with the message ‘built feature 123’
|—> push local changes to the remote repo

At the same time developer 2 needs to create a branch for the same reasons so they create a new branch from develop and call it devname-myfeature or feature-ref456.

They then checkout that branch and do all of their work locally in that branch, pushing their changes regularly to the remote branch without having to worry about what anyone else is doing. Sound familiar?!

At the same time developer 3 needs to create a branch…. ok you get the picture now.

Using git log to see all your commits

Git log shows you a list of commits made to your repository, including the comment against the commit, the commit author, and the commit SHA hash id – it’s a really easy way of finding the SHA id of a commit, which you may need to if you want to undo back to a certain commit. In it;s simplest form, to see a list of your commits type:

git log

If you want a really simple list of your commits type:

git log --oneline

Using git status to understand your branch

Git status is super useful – it will never change anything, so you can’t cause any problems by using this command! It will tell you the current state of your working directory.

It will tell you if you have any changed files that are uncommitted and which branch you are on. If your local branch has an upstream branch then it will also tell you if you are ahead or behind the upstream branch. If you are ahead then you will need to push your changes to the remote branch. If you are behind, then it means someone else has pushed their changes to the remote branch and you need to pull them down to your local branch. It can also be really useful to understand what’s happening of you have a merge conflict – but I will talk about that in another post.

How to clone a remote git repository

Click the green code button from the repo page in GitHub. There are different ways to clone, using SSH, https, or Github CLI.

how to clone a remote git repo

I’ll use https here, so make sure you have that selected from the popup and copy the path that should start with https://. Then use the git clone command, so type this:

git clone https://github.com/yourNameHere/repoNameHere

Once it’s been cloned that repo is now set up on your local machine and you can get working. Once you’ve made some changes you will commit them, and push them to the remote branch, just as I described before.

A typical git workflow

The way you use Git can vary depending on the team you’re working in, both in terms of the number of people using the repo, and in terms of preference. I’ve typically found that each software team has a slightly different process, so just take this as a typical example.

You are most likely when working as part of a team to need to clone a remote repo to get started, rather than creating a repo locally and then setting everything up. So presuming the remote repo is ready to go, and that your github account has access to it, you will need to clone a git repo to get started.

Then you will do some work and commit your changes by using git add to stage these changes, and git commit to confirm the change.

Then you will push your changes to the remote branch by using git push.

In conclusion

So after reading both of my ‘Git in Plain English’ posts you know how to create a repo, connect a local repo to a remote repo, and clone a git repo. You also can now commit your changes, and push to a remote branch. And finally you have some idea of how to use branches to use git a typical way.

There is an awful lot of capability in git and I’d recommend now learning about using git rebase, and git stash. As always when using git, proceed with carefully before running any commands!

How to undo a commit in git (or ‘git undo commit’!)

Git

Have you ever accidentally committed something to your git repo, or realised after you’ve committed your changes that you’ve made a mistake? If so, this blog post is for you and it will teach you how to ‘git undo’ a commit. Git reset is what you need and I will walk through the steps of how to undo a git commit in this post. Git is one of the most popular version control systems being used today and if you are not familiar with it yet, you should read this post which explains Git in plain English. It is important to be able to undo a commit if you make a mistake and luckily git lets us do this by using git reset. Lots of people search for git undo commit, but there is no such command – you are looking for git reset. But before you use it you need to understand the different options when using git reset, and also whether you should be using git rest or git revert.

Git reset or git revert?

This post focuses on discarding your changes using git reset and will enable you to discard your changes with no record of the undo. If you want new commits to reflect the ‘undoing’ then you need to use git revert.

Git reset (not ‘git undo commit’!)

In order to undo a git commit, you need to use the git reset command. This will remove the most recent commits from your current branch. Beware though, depending on the flags you set when you use this command you may lose some of your work, so read on to ensure you use the correct options for your situation. Also how many commits it removes, and what it does with the now uncommitted changes also depend on the flags you set when you run the command.

Git undo last commit and keep the changes

To undo only the last commit in git and keep the changes (presuming you have not already pushed the code):

git reset --soft HEAD~1

This will undo the last commit but all your changes will still exist, it’s just that the files that the changes were made in have gone back to their uncommitted state.

Git undo last commit and discard the changes

To undo only the last commit in git and discard the changes (be careful, you may lose work here as your changes will be discarded completely):

git reset --hard HEAD~1

This will undo the last commit discard all changes that were made in the files from that commit. You will lose work if you do this, so proceed with caution!

Undo more than one commit

In order to undo more than one commit you can use a variation of a command shown above but just change the number of commits. So this command would remove the last 4 commits and keep the changed files:

>git reset --soft HEAD~4

Undo back to a specific commit

If you want to roll back to a specific commit then you will need to know it’s hash id. To see all your commits you can use git log which will list all commits and their hash id numbers.

Once you have found the relevant commit, copy its hash id and then type:

>git reset --soft 123456

…where 123456 is the hash id of the commit. This will undo your changes back to that commit and will keep your files. If you want to discard your files then use:

 >git reset --hard 123456 

What is git? Explained in plain English.

Git

Life as a developer involves using Git all the time. When I started my first software job in 1999 (OMG that sounds like a long time ago) Git did not exist. You just had copies of folders on your machine called mywebsite, mywebsite-copy, mywebsite-copy1…. you get the picture. And that worked to a point when all you were dealing with was a bit of HTML, and some images. In 2005 Git was introduced and gradually became irreversibly entwined in the life of a software developer. You can’t be a dev now without knowing Git, and I can’t imagine life building software without it. However, if you’re new to life as a dev and you don’t know the answer to the question “What is Git“, or “What is a git repository” it can be a bit uncomfortable to ask your new team mates that question!

Who is this post for?

This post is intended as a plain English introduction to Git for anyone starting out, for anyone who doesn’t know what Git is, and for anyone else who needs a refresher, or who wants clarification for what they think they know. It’s the post I wish I had found when I joined the first dev team I ever worked with who used Git.

What is git?

Git is a piece of software that’s used to track changes in files. In it’s simplest form that’s all it is. It has no front end, you interact with it via the command line using tools such as Git Bash, Command (Windows), or Terminal (Mac). There are other ways of interacting with it – using Visual Studio Code for example – but I think it’s worth understanding Git on the command line before you use any other tool, so this post will concentrate only on the command line.

Before you run any command written in this post I’ll presume you’ve opened your command line tool and that you’re in the root of your project. The ‘>’ symbol represents the cursor. Don’t type this, just type the words after it! I’ll also presume after every command that you’ll press return, so I won’t write it each time.

Do I already have git installed?

You can check this in your command window – open your command tool of choice and type:

>git --version

Now press return. If you DO have git installed it will return a single line response like this:

>git version 2.29.2.windows.2

If you don’t have git installed you’ll see an error message, and you’ll need to install if from here – https://git-scm.com/book/en/v2/Getting-Started-Installing-Git

What is a git repository (or git repo)?

Repo is short for repository. The literal meaning of the word repository is “a place in which things may be stored“. In this context a repository contains all of your code including a list of all the historical changes, i.e. who changed what file, when, and why. It also contains at least one branch (see below) and will probably, eventually, contain multiple branches.

When you clone a repository you are creating a copy of the remote repository and putting it on your local machine.

What are branches in git?

When you create a repo a single branch is automatically created to hold your files. It’s often called main, sometimes it’s called master. You can call it whatever you want but in this post I’ll always presume your default branch is called main. You can decide how you want to use your branches (more on that in ‘A typical workflow‘ in the next post in the series) but again I’ll presume that your most current version of your code is kept in your default branch – main.

A branch contains your whole codebase. Lets say I’m building a website and I’m running it locally (on localhost). I could have 3 branches – main, feature-one and feature-two, where feature-one contains all the code that has got feature one in it, and where feature-two contains all of the code for feature two in it. And main may contain the current version of the production code. While I’ve got feature-one selected as my current branch, when I run localhost I’ll see the website including feature one. If I then switch to the feature-two branch and run the website on localhost, I’ll see a version of the website including only feature two. That way I can test each separately and when I’m ready I can merge both of those branches into my main branch and release them to the live website.

How does git work?

It turns your project folder into a repository, and in here it will keep ‘snapshots’ of your project each time you commit any changes to any files. All of this is done locally on your computer, so you can use it for version control without even having an internet connection. However, by connecting your local code repository with a remote one, you always have a centralised code store that anyone who has permission can access, and it also serves as a remote back up of your work.

If you want to work on a new feature you’ll create a new branch to do this work on, and when your work is done, you’ll then ‘merge’ any new changes into the main branch. To start with this branch is a direct copy of main. At any given time you will have a branch ‘selected’ on your local machine, and any code changes you make will only effect the files in this branch.

That’s a simplified overview but it gives you the general picture.

Not sure what branch you are currently using?

>git status

Want to change which branch you are on?

>git checkout branchname

Want to create a new branch from your current branch?

>git branch newbranchname

Want to see a list of all your local branches?

 >git branch

What is github?

Github is a hosting service for git repositories and you can find it here – https://github.com/. It also provides a user interface to interact with your git repos. It does other stuff, but that’s the basic description.

There are other websites that do the same kind of thing, for instance Gitlab.

What is git bash?

Git bash is a command line tool – https://www.atlassian.com/git/tutorials/git-bash. It’s the one I prefer to use although I originally used Command (CMD) on my PC. Git bash gives you a little more information, it shows you what folder you are in, it shows you what branch you’re on. It includes colour coding whereas CMD is white text on black only. When I create a new project I open my C:\ folder in Windows explorer, right click my Repos folder and click “open with Git Bash”. That opens Git bash already in that folder. Then I can create my new git repo from there – although I may not have to, for instance if you create a new React app it will already be initialised as a local git repo. A tip for Git bash is that to paste text you should right click where you want to paste the copied text, and then select paste from the context menu that appears.

How to create a remote repo

Presuming your starting point is as described above, i.e. that you have a local code repo created but no remote repo to push it to, then you’ll need to create a remote repo and then ‘connect’ the local to the remote.

I’d recommend going to github and creating a new Repo there. Once the repo is created you see a page with all of the commands listed as follows.

>git branch -M main
>git remote add origin https://github.com/EmilyChristy/learn-git-app.git
>git push -u origin main

The first line renames the master branch to main.
The second line connects the local repo to the remote repo. [At this point your local repo has code in it, but the remote repo is empty.]
The last line pushes the local code to the remote repo.

What does the -M mean in git branch -M main?

The -M is a shortcut for --move --force. Move means to rename a branch, and force means force this change even if the branch already exists. Further info can be found here – https://git-scm.com/docs/git-branch#Documentation/git-branch.txt.

In conclusion

You now know what git is, you understand what a git repository is, what branches are in git, and how to create a local and remote repo. My next post will cover common tasks such as staging and committing changes, pushing to a remote repo, cloning a remote repo, and an example git workflow – https://www.brainstormcreative.co.uk/git/what-is-git-git-explained-in-plain-english-part-2/.