Every developer needs to learn Git. It's how we version control our code. By using git, we can step through every change we've ever made, forward and backward in time.
This is crucial when mistakes are made. Instead of having to rewrite everything manually, you can simply revert your changes or hop to an earlier commit.
It's only going to take us 10 minutes to cover 90% of git's usage.
Installing Git
First, we need to make sure git is installed on our system.
Windows:
# Using winget in a powershell window
winget install git-all
# Chocolatey
chocolatey install git-all
MacOS:
# Using Homebrew
brew install git-all
Linux:
// Ubuntu/Debian
apt install git-all
// Arch
pacman -Sy git-all
// CentOS/Fedora
yum install git-all
You can find more info about installing git here.
Starting a git repo
We'll start by creating a new project. In my case, Ill be starting a new repo for a NES emulator I'll be writing in C. If you dont know where to store your projects, create a projects
directory wherever you know you'll find it.
Start your own project and name it whatever you'd like.
I'll be naming my project DrNES
and moving into the directory.
# Init project
mkdir -p DrNES
# Change dir into DrNES
cd DrNES
Now that we have our project directory created and we're inside of it, we can start a git repo.
# Start a git repo
git init
# Check for .git directory
ls -al .git
This makes the project directory we created into a git repo.
The Basics of Git
From here, we can create a few files for git to find.
In my case, Im going to create a source src
folder with main.c
in it and a README.md
.
This is going to lay the base file structure for my repo.
# Create README
touch README.md
# Make src folder
mkdir -p src
# Add main.c to src
touch src/main.c
For now these will be empty files.
Git Status
If we do a git status
, we will see what git is currently tracking for changes.
git status
# Output
On branch main
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
README.md
src/
nothing added to commit but untracked files present (use "git add" to track)
Git Add
In order for git to start tracking these files, we need to use git add
. This command can be used to add individual files or all files in the directory.
# Add one file to track
git add README.md
# Add everything in repo to track
# The '.' means to add everything in this directory
git add .
# Output
On branch main
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
new file: src/main.c
In my case, I use git add .
to make git track everything in my directory.
Git Commit
Once we've added our files to track, we need to commit to the changes. We use the git commit
command to do this.
# Commit our changes
git commit -m "init commit"
# Output
[main (root-commit) 1b13406] init commit
2 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 README.md
create mode 100644 src/main.c
Whenever we commit to our changes, we have to add a message to the commit for the git log
. If we just did git commit
, it would drop us into vim or whatever other editor you have set as the default.
To bypass being dropped into vim, we use git commit -m "My message here"
.
Git Push
Now we can use git push
to push our changes to a remote repo.
To that, however, we need a remote repo, otherwise we will get the following error:
# Push git changes
git push
# Output
fatal: No configured push destination.
Either specify the URL from the command-line or configure a remote repository using
git remote add <name> <url>
and then push using the remote name
git push <name>
Setting up a Github
At the moment, we dont have a remote repo to push our changes to.
Thats where something like Github or Gitlab come in.
These are remote servers that allow us to host and share our code with the world, provided by those two companies.
For my repo, Ill be using Github. I already have an account, but it should be simple to sign up for one.
Once you do, navigate to the "Repositories" tab and click "New" in top right hand corner.
That will take you to a "Create new repository" page.
On this page, we want to:
- Give the repo a name
- Add a description
- Set repo to public or private (your choice)
- Click "Create repository"
We do not want to initialize the repo with a README, because we already have a README. As of right now, I dont want to add a .gitignore
or license. I want this repo to be blank.
If we didnt already have a repo to push to Github, I would have added the README, added .gitignore
, and selected a license.
After we've created our Github repo, its going to ask whether we want to "create a new repo" or "push an existing one".
We're doing the latter, so we will follow those directions.
We do this in our terminal where our project repo is.
Lets look at each command:
-
git remote add origin github.com/User/myrepo.git
tells our local git repo where to find our remote git repo. -
git branch -M main
creates a main branch in our local repo. This main branch should be protected, more on that later. -
git push -u origin main
allows us to push our changes to the upstream repo main branch-u origin main
Our git push
may error out.
This is because we have to define an authentication method with Github.
We have two options:
Once we have that situated, we can try our git push
again.
# Push changes to Github
git push -u origin main
# Output
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 10 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 301 bytes | 301.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/0xGlitchbyte/DrNES.git
* [new branch] master -> master
branch 'master' set up to track 'origin/master'.
If we go back to Github, we should see something like this:
That's how we know our repo has been successfully pushed.
Best Practices for Git
Now that we have successfully added, committed, and pushed changes to Github, we want to start developing.
Remember I said we want to protect main
?
Best practice is to develop on a separate branch besides main
so we dont push changes that will mess up the main
branch.
So we will create a dev
branch.
# Create dev branch
git branch dev
# Switch to dev branch
git switch dev
# Push changes from local dev to remote dev
git push -u origin dev
# Output
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 10 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (4/4), 410 bytes | 410.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'dev' on GitHub by visiting:
remote: https://github.com/0xGlitchbyte/DrNES/pull/new/dev
remote:
To https://github.com/0xGlitchbyte/DrNES.git
* [new branch] dev -> dev
branch 'dev' set up to track 'origin/dev'.
Now when we git add
and git commit
on this branch, it wont affect our main branch.
Since main is our source of truth branch, where all production ready code gets push to, we need to do a pull request in Github to merge dev
into main
.
Once all changes have been approved and the pull request has been merged into main
, other people can use git pull
to get the latest changes.
You can also setup a .gitignore
file in your directory. This file will allow you to exclude files and file types to be excluded from being added for staging commits.
Different Git commands to be aware of
Git Clone
If you find a repo you come across that you'd like to contribute to, you can use git clone
to pull it from a remote server (i.e. Github) to your local machine.
# Cloning the DrNES repo with HTTPS
git clone https://github.com/0xGlitchbyte/DrNES.git
# Cloning with SSH and changing the folder name
git clone git@github.com:0xGlitchbyte/DrNES.git dr_nes
Git Fetch
git fetch
updates your remote-tracking branches under refs/remotes/<remote>/
. This operation is safe to run at any time since it never changes any of your local branches under refs/heads
. This is used instead of pull
when you just want to update the remote references.
git fetch
Git Remove
git rm
will remove files from your git repo and filesystem, if you specify it.
# Remove files from cache
git rm --cache
Git Log
git log
allows us to see a log of our commits. This is useful when we'd like to view changes passed commits may have done, or to switch to a different commit.
git log
# Output
commit 124d9e29ac5ddac77c911c83c2100ca54f9d04d0 (HEAD -> dev, origin/dev)
Author: 0xGlitchbyte <49317853+0xGlitchbyte@users.noreply.github.com>
Date: Sun Nov 5 15:40:47 2023 -0500
added hello world
commit 1b134069e7dd4469b3439b02b82b2a0d9db4e535 (origin/master, master)
Author: 0xGlitchbyte <49317853+0xGlitchbyte@users.noreply.github.com>
Date: Sun Nov 5 14:22:22 2023 -0500
init commit
Git Show
git show
shows us the details and metadata of our last commit
git show
# Output
commit 124d9e29ac5ddac77c911c83c2100ca54f9d04d0 (HEAD -> dev, origin/dev)
Author: 0xGlitchbyte <49317853+0xGlitchbyte@users.noreply.github.com>
Date: Sun Nov 5 15:40:47 2023 -0500
added hello world
diff --git a/src/main.c b/src/main.c
index e69de29..18e3a28 100644
--- a/src/main.c
+++ b/src/main.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+int main() {
+ printf("Hello World!");
+ return 0;
+}
(END)
Git Diff
git diff
allows us to view the difference between two commits.
# Will compare last commit to current changes
git diff
# Output
diff --git a/src/main.c b/src/main.c
index 18e3a28..139eeca 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,6 +1,9 @@
#include <stdio.h>
int main() {
+ // I have added some comments here
printf("Hello World!");
+
+ // And here!
return 0;
}
(END)
Git Stash
git stash
allows us to stash away any changes we have made in our current branch. This is useful when we want to keep our changes, but go back to a clean working directory to try something else.
git stash
# Output
Saved working directory and index state WIP on dev: 124d9e2 added hello world
Git Reset
git reset
will reset our changes back to a clean working directory without saving them.
git reset
Git Branch
git branch
will show a list of all current branches in the git repo.
git branch
# Output
* dev
master
(END)
Git Merge
git merge
allows you to join two development histories together. You use git merge
when you want to reconcile other branches into main
, for example. When you merge histories, its important to note you will have to reconcile any conflicting differences between the two.
# Merge dev into master with a message
git merge -m "My message here" dev
Git Rebase
git rebase
allows you to easily change a series of commits, modifying the history of your repository. You can reorder, edit, or squash commits together. You may not want to merge back into main
just yet, so you can pull a version, rebase, and continue development from the point you rebased.
git switch dev
git rebase main
Git Restore
git restore
allows you to restore or discard unstaged files in your git repo.
# Restore a file
git restore filename.txt
Git -h
git -h
is shorthand for git --help
. It will list all the options you can use with git. man git
will give you the manual page on linux for git.
git -h
usage: git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]
[--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
[-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
[--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
[--super-prefix=<path>] [--config-env=<name>=<envvar>]
<command> [<args>]
These are common Git commands used in various situations:
start a working area (see also: git help tutorial)
clone Clone a repository into a new directory
init Create an empty Git repository or reinitialize an existing one
work on the current change (see also: git help everyday)
add Add file contents to the index
mv Move or rename a file, a directory, or a symlink
restore Restore working tree files
rm Remove files from the working tree and from the index
examine the history and state (see also: git help revisions)
bisect Use binary search to find the commit that introduced a bug
diff Show changes between commits, commit and working tree, etc
grep Print lines matching a pattern
log Show commit logs
show Show various types of objects
status Show the working tree status
grow, mark and tweak your common history
branch List, create, or delete branches
commit Record changes to the repository
merge Join two or more development histories together
rebase Reapply commits on top of another base tip
reset Reset current HEAD to the specified state
switch Switch branches
tag Create, list, delete or verify a tag object signed with GPG
collaborate (see also: git help workflows)
fetch Download objects and refs from another repository
pull Fetch from and integrate with another repository or a local branch
push Update remote refs along with associated objects
'git help -a' and 'git help -g' list available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.
See 'git help git' for an overview of the system.
Final Thoughts
Git is an important tool to learn, but its not difficult to learn.
The majority of the time, youll be using these commands:
git add
git commit -m
git push
git pull
git clone
The rest are good to learn, but will be used on a case by case basis.
You can use git on any files you'd like to version control, from code to text documents.
The more you practice, the better youll get at it.
Top comments (0)