The way our team manage git branches is to create a new feature branch at the remote end, then we do a git pull and switch to the new feature branch locally. Next we do our development work, commit and push those changes. Finally we merge the reviewed code into a central remote branch. All pretty standard. When we merge, we tend to automatically delete the remote feature branch and then repeat the process. However, this can lead to having a lot of local branches that don’t track a remote branch anymore, and it’s good practice to tidy those up. So, how can you delete all the local branches that don’t track a remote? First of all have a look at all your local branches by typing:
… then take a look at all your remote branches by typing :
git branch -r
… or compare that to what Github is showing you exists at the remote end. You can do this with Github, Azure repos, whatever your remote git UI is. You’ll notice you have local branches that no longer exist in the remote repo – these are called ‘orphaned branches’, or branches that no longer track a remote, and it’s these that we want to delete. This image shows the comparison between our local branches, shown in the Git bash window, and the remote branches, shown in the Github UI.
You might think that git prune remote origin will delete all of these local branches – but alas, no. It actually removes local references to remote branches. It DOES NOT clean up local branches which no longer track a remote. SO how do we do that? Well the bad news is there is no single line command which does that, so you have two options:
Manually delete them one by one. After comparing the remote and local branches you have a list of orphaned branches as shown above. And then delete the branch by typing git branch -d thebranchname and that will remove each.
Find an automated command which does a bit of the hard work for you. I’m not going to list one here though because I haven’t found one that doesn’t carry a risk of deleting a branch incorrectly. I’d say look at this and then pick the solution which works best for you.
So, what does git remote prune origin actually do?
Git prune remote origin removes local references to remote branches. To understand what that means, read on.
Something that can be really confusing is that if you were to delete a remote branch in Github / Gitlab etc, and then run the git branch -r command, you’ll still see the deleted branch in the list of remote branches. You *know* it’s been deleted and yet there it is.
The default options for git fetch and git pull do not ‘prune’ deleted remote branches by default, so to clear these confusing remote branch references up, type:
I’ve been building a .Net Core API recently and after getting the repo set up I realised there was a problem. The bin and obj folders had been pushed to the remote branch, so once our build was kicked off, it was failing. It transpires that there’s an issue with the gitignore file and Visual Studio 2019 – I am not too sure of the exact details of the problem, but I can tell you how I fixed it.
If you don’t already have a gitignore file then you need to create one in the root of your solution, in the same place as your .sln file. The file needs to be called ‘.gitignore’. You can then copy the contents from the link above, and save it. If you DO already have one, then just edit the contents, and save it.
If you have already pushed your bin and obj folders to the remote repo
Even though you’ve fixed your .gitignore file, it won’t fix the fact that you’ve already pushed your bin and obj folders to the remote repo, so now we need to resolve that, which thankfully is easy. There are 2 steps:
Delete both the bin and obj folders from your remote repo
Delete both the bin and obj folders from your local repo
The problem is now fully resolved! However in addition to this I also found a .suo file had been pushed that shouldn’t have been, so I also had to delete that from both the remote and local repos. In my solution the file was here:
You can now build your project and git will correctly ignore the bin and obj folders and the .suo file.
How to change .gitignore file to ignore the .vs folder
The same as above, delete the folder from the remote repo, then delete it from the local repo. I then had to do a git pull and a git push to resolve everything with git.
What is git branch rename? Is that even a real git command? No it isn’t, but it is pretty easy to rename a git branch and this post will show you how. I’ll also have a detailed example of exactly how to rename your git master branch to main. Look at this screenshot of my Git bash terminal below. It shows a series of git commands that start with listing all my local branches, and then renaming one of them. The full description of each part is below.
I first typed git branch which showed me a list of local branches. In the list you can see we are currently on the main branch, and that there are 3 other branches, one of which is called branchNameNow.
Next I typed git branch -m branchNameNow newBranchName which is saying ‘please rename the branch which is called branchNameNow to newBranchName‘.
Finally I typed git branch to again list my local branches. Now you can see I am still on main, there are still 3 other branches, but we now have a branch called newBranchName instead of newBranchName.
Git rename master branch to main
Some systems still name the initial git branch master but it’s pretty common in other systems for the initial branch to be called main, which is my preference. If you want to rename your master branch to main then run this git command:
git branch -m master main
git push --set-upstream origin main
The first line renames the local master branch to main, the second line pushes new main branch to the remote repo.
The first line uses this generic command form:
git branch -m branch-name-now new-branch-name
… which renames the branch which is called branch-name-now to new-branch-name. This is exactly the same as:
git branch --move branch-name-now new-branch-name
… because -m and –move do exactly the same thing. Please note there is only 1 dash before the ‘m’ and 2 dashes before the ‘move’. It’s also worth noting that branch names are case sensitive. I normally keep all branch names lowercase to avoid causing confusing issues when trying to find a branch, and use hyphens to make the names readable.
If you’ve just realised you’re working on the wrong branch and you’ve already made changes, then this post could be for you. Picture the scene, you’ve edited a few files you’re half way through building a shiny new feature and then it dawns on you that you *forgot to create a new feature branch* before you started. OMG. If you have not staged or committed any of those changes yet then read on to find out how to keep your changes but move them to a different branch using the git stash command.
How to stash changes with git stash
The git stash command itself is really simple – in it’s most basic form with no flags. You must be on the branch where you’ve made the changes and then type:
That’s all there is to stashing those changed files away to a safe place although it’s important to understand what is stashed – all unstaged and staged files. And what isn’t stashed? Any new file, any committed file will NOT be stashed. But now you want to grab those files back and put them on the right branch before you carry on working on that new feature. If the branch you want to use already exists then you need to switch to that branch. Let’s say it’s called feature/shinybutton, then you would type:
git switch feature/shinybutton
If you need to create a new branch and switch to it immeditaley then type this instead:
git switch -c newbranch
So now you’re on the correct branch you want to take your stashed files and put them on this branch. I’ll also presume that you only want to use these files once, so that the ‘stash’ is empty once you have run the command. So type this:
git stash pop
This ‘pops’ the files out of the stash, applies them to the current branch, and clears the stash. If you want to use the stash on more than one branch then use this command instead:
git stash apply
This will ‘apply’ the files to the current branch but will keep the stash as it is, so you could then switch to another branch and apply the same changes there too.
Git stash changes – quick reference list
git stash //do this while on the branch with your uncommitted changes
git switch branchName//switch to the branch you want the changes to be put on
git stash pop //unpack the stashed files onto current branch & clear stash
git stash apply //unpack the stashed files onto current branch & keep stash
That gives you all you need to know to do a basic git stash. But there are some other details to be aware of so you can use it to it’s full potential.
Keep stashed files and use several times
Do the same as above but use git apply stash instead of git pop stash. This applies the stashed files to the current branch but leaves the files in the stash so you could switch to another branch and apply them there too.
See which files have been stashed
git stash show // lists all files that are in the stash
Undo a git stash
Just stay on the branch where you did the stash and then run git stash pop which will unload the files back on to that branch.
Include untracked files in git stash
git stash -u
Git stash one file
git stash -p
This will then start a dialogue and you’ll notice a question in the terminal window asking:
“Do you want to stash this hunk?” //WHO comes up with this?!!!
A list of options are available – click y for the one file you want to stash, and n for the rest. The patch options are as per this list:
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
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
You may be interested in some of my other posts about Git:
If you follow a typical git workflow you will probably have been developing each feature, or fixing each bug, on it’s own branch, and then merging each branch into a central development branch in the remote repo. In this kind of scenario at the end of a project you may have many local branches that are left over from this process. And now you need to delete both the local branch and the remote branches (as long as they’ve been merged!). In this post I’ll cover how to delete a branch in git – more specifically how to delete a local git branch, and how to delete a remote git branch.
How to delete a local git branch
Before you delete a local branch you need to be very sure that you have the name spelled EXACTLY right. It’s useful to see all your local git branches using the git branch command, so you can see a list of them and make a note of the name of the branch you want to delete.
Even more useful though is this command:
git branch --merged
…. which will show all the branches that have been merged into the current one.
Let’s say that we want to delete the branch that’s called feature-12 from the list shown in the image above. You can see that main is highlighted in green, and that it has an asterisk next to it – that’s telling us that we are currently on the branch called main. We can now run the command to delete the local branch feature-12 as follows:
git branch -d feature-12
It’s the -d flag that tells git to delete the local branch specified. So to delete a branch called temp-develop, for instance, you would type:
git branch - d temp-develop
And as long as that has been deleted ok you’ll see a simple message saying ‘Deleted branch feature-12 …‘ confirming it worked fine.
When can’t you delete a branch
You can’t delete a branch that you’re already on – so change branches and then delete it.
You can’t delete a branch if it contains work that hasn’t been checked in – so you should commit and push the changes, or stash them, or discard them.
Force delete a branch with work that isn’t checked in
You can use the -D flag to force deleting a branch even with work that isn’t checked in.
How to delete a remote git branch
You can delete a remote git branch from the command line by using this command:
git push origin --delete branchNameHere
So if we were deleting a remote branch called bugfix-CA619 we would type:
git push origin --delete bugfix-CA619
So now you know how to delete both local and remote git branches, and you know how to force delete, although I would very much recommend not doing this as you could lose unsaved changes!
I share screen shots quite a lot in my blog posts and got fed up of needing to blur the user name information from my Git bash terminal screenshots. So I edited the shell prompt text in order to customise Git bash. Here are the steps you need to take in order to edit the git-prompt.sh file to hide the Git bash user name.
What is the git-prompt.sh file?
The git-prompt.sh file contains all of the configuration information for the Git bash terminal and the prompt itself.
If you open that file you will notice between lines 8 and 11 it does a test to see if a file exists here – ~/.config/git/git-prompt.sh and if it does then it loads the configuration data from there instead of this default file.
How to edit the git-prompt.sh file
Find out where Git bash is installed on your system. You might need to search for gitbash.exe but on my system it was here – C:\Program Files\Git
Now you want to navigate to the subfolder \etc\profile.d and find the file called git-prompt.sh. Open it in notepad or Vs Code as we are going to edit it.
Creating a custom configuration file
The ~ part of that file path refers to the folder relating to your username so it will be something like C:\Users\johndoe\. There was already a .config folder, so I created a git folder within that. You should then copy the default git-prompt.sh file from here:
… and place the duplicate in the folder you just created at:
Now we can edit that file, leaving the original default version alone, and when you start Git bash from now on it will take the configuration from your new customised file. If you ever want to roll back to the original you can just delete your customised file and Git bash will revert to using the original, untouched file.
Editing the file to customise the text
We need to remove the if then else statement that looks for this custom file, otherwise Git bash will just crash when you try and run it. All I’ve done here is remove that block and then edit the cursor text to say brainstorm, so you could copy this text to use as the starting point for your custom file.
if test -f /etc/profile.d/git-sdk.sh
PS1='\[\033]0;$TITLEPREFIX:$PWD\007\]' # set window title
PS1="$PS1"'\n' # new line
PS1="$PS1"'\[\033[32m\]' # change to green
PS1="$PS1"'brainstorm ' # user@host<space> ----- this is where I have edited the name
PS1="$PS1"'\[\033[35m\]' # change to purple
PS1="$PS1"'$MSYSTEM ' # show MSYSTEM
PS1="$PS1"'\[\033[33m\]' # change to brownish yellow
PS1="$PS1"'\w' # current working directory
if test -z "$WINELOADERNOEXEC"
GIT_EXEC_PATH="$(git --exec-path 2>/dev/null)"
if test -f "$COMPLETION_PATH/git-prompt.sh"
PS1="$PS1"'\[\033[36m\]' # change color to cyan
PS1="$PS1"'`__git_ps1`' # bash function
PS1="$PS1"'\[\033[0m\]' # change color
PS1="$PS1"'\n' # new line
PS1="$PS1"'$ ' # prompt: always $
MSYS2_PS1="$PS1" # for detection by MSYS2 SDK's bash.basrc
# Evaluate all user-specific Bash completion scripts (if any)
if test -z "$WINELOADERNOEXEC"
for c in "$HOME"/bash_completion.d/*.bash
# Handle absence of any scripts (or the folder) gracefully
test ! -f "$c" ||
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:
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:
Fix the bad code locally by undoing that commit
Commit the changes so that the fix is recorded in our repo history
Push this new commit to the remote repo
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:
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.
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.
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 conflictto resolve.
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.
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:
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:
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.
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:
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.
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:
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. If others on your team have added work you’ll need to get these changes by using git pull, or you may wish to use git fetch first. Read about the difference between git pull and git fetch.
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 care before running any commands!
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. 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.
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.
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:
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. 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:
Now press return. If you DO have git installed it will return a single line response like this:
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?
Want to change which branch you are on?
git checkout branchname
Note, this is exactly the same as:
git switch branchname
Want to create a new branch from your current branch?
git branch newbranchname
Want to see a list of all your local branches?
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.