Get started with Git: An intro
See what I did there?
When I first started with my journey in developing software I was an art student working on games. I had never encountered a control system or anything like it, this led to some tricky mistakes and blunders that my developer project partners would painstakingly fix. Public failures like those that I made were frustrating and morale-crushing, causing an avoidance towards Git. A year later I was helping by teaching it to my peers, coding beginners, in a boot camp-like scenario. So I hope I can help you as well!
I would like to provide in this article an understanding of the Git system for those being challenged by it. There's are so many options and possible errors to encounter, I would just like to focus on the basics and help any readers with starting a project repo remotely with Git. But beyond that initialization of Git, I ask that you research the answers! Google will be your best friend in situations where Git is erroring, and StackOverflow and Git docs will be very helpful. If you are frustrated, remember it takes time, experience, and the humbling knowledge that someone has run into this problem way, waaaayy, before you have.
Originally I used the Github desktop app and Sourcetree by Atlassian, both great GUI tools, but I encourage you the reader to get more familiar with the command line, my preference being for iTerm on MacOS.
Git is a system for version control that handles changes as snapshots. Quickly assessing files as modified, staged, and committed. Git saves the state of your project when you commit your changes.
If you do not have Git installed previously and would like to work through the tutorial, here are some instructions for installation.
Lets Git Started: Getting Initialized
All of the commands that I discuss today start with -
This is the way to interact with Git and give it commands and flags like the one below:
- Do you see the init command description when you run the command above?
While in a directory (a folder) you want to have Git in, run in the command line:
This will initialize your .git, creating an empty repository with subdirectories for objects, ref/heads, and ref/tags. Docs here. Most of the time you would want this at the root of whatever working project directory you have.
Let's go looking for it as you won’t actually see it, with the command ls -a. This command should show you everything including what is hidden in your directory. Like any folder/directory the .git repo can be deleted with rm -rf, but please be careful as this command is a strong removal of files and folders.
To communicate with Github, Gitlab, etc, a connection to the remote repo will need to be added. It's called a ‘remote’ and we are going to add one!
To do this create a new repo at Github or your preferred version control hosting site, and copy the URL to it.
To add a remote run in the command line:
git remote add <name_of_remote> <url_of_repo_to_be_tracked.com>
I usually call my <name_of_remote>, origin, which is just standard, but it can be called anything as long as it is clear. The URL can be found at whatever site your remote repo was created at, though hopefully you already copied it!
Run this to list the name(s) of your remote(s):
Do you see the remote you created? What did you name it?
And yes, you can have multiple remotes, but remember them when pushing and setting commits to their stream.
An issue you may encounter is that on initializing the default branch is set to master, fine if working with older code, but most default branches are being declared as main now. This command will modify your git config so that on running git init the default starting branch where HEAD is will be called main.
git config --global init.defaultBranch main
Another issue that could happen on the initial setup of your remote, is that maybe you added a license or README in your remote repo which you didn’t pull/merge before creating a commit, you might run into an error about ‘unrelated histories’ of your local repo and remote repo. This command solves that issue. Please note, I use this when I know the remote is empty for but one thing or two unimportant files which can be replaced. Docs here.
git pull origin main --allow-unrelated-histories
Don’t be afraid of deleting your local Git repo and restarting in the beginning!
Going Beyond ‘init’: Other important concepts
In this part, I leave it up to the beginners to research and find the important commands of Git focusing on staging, branching, and merging. If these concepts and commands aren’t new to you, there's no reason to continue.
But for everyone else, Welcome to Going Beyond ‘init’! Let's get into it!
Go ahead and make a couple of files in your main directory where you initialized your .git, and it doesn’t matter what they are or what's in them.
As a resource, look at the Pro Git Book which I quote and used as a resource for this piece, which is alos free and online.
Life is a Stage
When we add the changes from your local working directory to the Git stream we are actually adding them to a “staging area”, a place where this changes can be removed or altered before committing them to the branch. Docs here.
This also means you can be super specific about the files you add to “staging”. An example is I changed my server.js file and in my user.js file. The only file I want to add is my server.js to the commit, Git allows that. It also means you can “unstage” changes.
Add some changes to your files and work through the exercise for this section:
- What command adds all the modified files to your staging area?
- What command only adds one file? What about adding two?
- What command lets you the differences in the staged file from the previous version?
- How do you unstage those files? (IDE UI answers are valid as well, but try through the command line)
Committing to it
An import concept with Git is HEAD. What you are seeing in your code, your file version, is going to be HEAD, the most current/recent commit of the branch you are on. Run this command to print which your head is:
My stdout reads ref: refs/heads/main because I am on the main branch.
You can view the commit logs by running:
It lists the commits in reverse chronological order. Docs here.
- How would you print the log in the oldest to newest order?
If you have run ‘git log’ then you have seen the structure of commits. A commit gets stored as an object with the values for the pointer of the snapshot (discussed in the overview), the author’s name and their email address, the commit message, and the pointers to the commit(s) that came before it, the parent(s).
Exercise for this section:
- Try modifying some files, adding them to staging, and then committing them.
- Try resetting the commit as if you don’t want the changes to be moved to the remote refs. Hint: here.
Sneaky tip: When working with a group or team you can check who made what commit by checking the logs.
Push it real good
A simple explanation of the push command functionality from the docs:
Updates remote refs using local refs, while sending objects necessary to complete the given refs.
This command is executing usually after a commit is created, pushing the refs to the remote repo. Thus making the recently pushed local code accessible from the remote repo.
Exercise for this section:
- Try modifying some files, adding them to staging, committing them, and pushing them. Did you specify the remote name and the current branch?
Merge, Merge, Baby, Dun Dun Dun
There won’t be a command exercise for this section, but the concept will be implemented in the next section.
Merging in Git is the joing of multiple development histories (branches) together. To merge properly you need to be on the branch to which you are merging changes to.
An example for clarity, there is a branch called ‘main’ and one named ‘hotfix42’. You would merge ‘hotfix42’ onto ‘main’, meaning you would be on ‘main’ while merging.
Question for this section:
- What's the difference between the pull and merge commands?
Lets Branch out
Branching is a powerful part of Git. It allows you to test, write, and play with code that is not your “production” level code, even allowing. Often in web development, for instance, workplaces branching looks like this:
- Main: is the Production level code, the code the user will see and use.
- Development: This is where all other branches are merged, QA testing happens here before being merged on to Main.
- All other branches: Are a task, feature, or a bug fix. These get named according to naming conventions set by the team or workflow. Will get merged onto Development.
These separate branches all have their own commit history which can be merged onto another branch viewable with the command ‘git log’.
Exercise for this section:
- Try creating a new branch from main. Is there a step you missed before a succesful new branch creation?
- Then try branching from that branch.
- Merge branch3 back on to branch2.
- Delete branch3.
- Try running ‘git log’ to see what's happening under the hood!
There you go, just some basics of merging and branching!
If you got here…
A fun treat: a Git themed Spotify playlist for your entertainment, Songs about Git.