Git Series — 2. Git Basics

Noman Nasir Minhas
Nerd For Tech
Published in
10 min readApr 12, 2021
https://images8.alphacoders.com/430/thumb-1920-430944.jpg

In previous article “Introduction & Getting Started With Git” of Git series, we went over definition of Git, Its basic features, basic flow, its advantages, difference between Git and GitHub and finally how to install Git on different Operating Systems. In this article, we will cover basics of Git starting from creating a repository to cloning an existing repository, tracking and committing changes, undoing changes, pushing and pulling changes ,managing remote branches, Tagging and Aliases. So let’s start..

Creating a new repository

Creating a new repository is simplest task in git. You just need to open a CLI tool according to your Operating System (terminal in Linux or Command Prompt/Powershell/Git Bash in Windows), cd to the directory where you need to create the repository like

for Linux:

$ cd /home/user/my_project

for macOS:

$ cd /Users/user/my_project

for Windows:

$ cd C:/Users/user/my_project

and type:

$ git init

This creates a new hidden subdirectory named .git that contains all of your necessary repository files — a Git repository skeleton.

Cloning an existing repository

If you want to clone an existing repository instead of creating a new one you can use

git clone REPO_URL

For cloning a repository from GitHub, you can find REPO_URL from the screenshot below

So, you can clone above repository by typing

git clone https://github.com/NomanNasirMinhas/Rust-Calculator.git

It will clone this repository in you current working directory opened in terminal.

As mentioned in previous article, you can use any server hosted repository as well instead of GitHub. So to use repository from your server you can type

git clone user@server:path_to_repo/repo.git

At this point, we have just created or cloned a repository and nothing in your project is tracked yet.

Tracking and Committing Changes

Ignoring Files

Before moving to tracking and committing changes we need to know about ignoring files. Often, you’ll have a class of files that you don’t want Git to automatically add or even show you as being untracked. For example node modules folder in nodeJS projects or targetfolder in rust projects. In such cases, you can create a file in project parent folder listing patterns to match them named .gitignore. Here is an example .gitignore file:

# ignore all .a files
*.a

# but do track lib.a, even though you're ignoring .a files above
!lib.a

# only ignore the TODO file in the current directory, not subdir/TODO
/TODO

# ignore all files in any directory named build
build/

# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt

# ignore all .pdf files in the doc/ directory and any of its subdirectories
doc/**/*.pdf

GitHub maintains a fairly comprehensive list of good .gitignore file examples for dozens of projects and languages at https://github.com/github/gitignore if you want a starting point for your project.

Staging files

When you have added, edited or deleted any file in your project and you want to track the changes in git you can use “git add” command with different approaches according your needs.

To track changes in a specific file just type

git add file_name.file_extension

To track changes in files of a specific extension use

git add *.file_extension

Incase there are a lot of files and you can’t add all files individually then track changes in all files contained in the folder use by

git add .

You can use multiple add commands simultaneously. For example to track changes of a specific exe file and all files of txt extension you can use

git add file_name.exe

git add *.txt

In order to check current status of all tracked files you can use “git status” for example

$ git add README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)

new file: README

Removing Files

To remove a file from Git, you have to remove it from your tracked files (more accurately, remove it from your staging area) and then commit. The git rm command does that, and also removes the file from your working directory so you don’t see it as an untracked file the next time around e.g

rm PROJECTS.md 

Another useful thing you may want to do is to keep the file in your working tree but remove it from your staging area. In other words, you may want to keep the file on your hard drive but not have Git track it anymore. This is particularly useful if you forgot to add something to your .gitignore file and accidentally staged it, like a large log file or a bunch of .a compiled files. To do this, use the --cached option:

git rm --cached README

Committing Changes

After adding all files you need to need to commit these changes by

git commit -m "Describe Your changes in a sentence or any other message"

Adding the -a option to the git commit command makes Git automatically stage every file that is already tracked before doing the commit, letting you skip the git add part

git commit -a -m 'Add new benchmarks'

After you have created several commits, or if you have cloned a repository with an existing commit history, you’ll probably want to look back to see what has happened. The most basic and powerful tool to do this is the git log command. Most clean way to do this is

$ git log --pretty=oneline
ca82a6dff817ec66f44342007202690a93763949 Change version number
085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Remove unnecessary test
a11bef06a3f659402fe7563abf99ad00de2209e6 Initial commit

Undoing Commits

One of the common undoing commits is required when you commit too early and possibly forget to add some files, or you mess up your commit message. If you want to redo that commit, make the additional changes you forgot, stage them, and commit again using the --amend option eg

git commit -m 'Initial commit'
git add forgotten_file
git commit --amend

Unstaging Files

For example, let’s say you’ve changed two files and want to commit them as two separate changes, but you accidentally type git add * and stage them both. How can you unstage one of the two? The git status command reminds you:

$ git add *
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: CONTRIBUTING.md
renamed: README.md -> README

Right below the “Changes to be committed” text, it says use git restore --staged <file>…​ to unstage. So, let’s use that advice to unstage the CONTRIBUTING.md file:

$ git restore --staged CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
renamed: README.md -> README
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md

The CONTRIBUTING.md file is modified but once again unstaged.

Unmodifying a Modified File

What if you realize that you don’t want to keep your changes to the CONTRIBUTING.md file? How can you easily unmodify it — revert it back to what it looked like when you last committed (or initially cloned, or however you got it into your working directory)? Luckily, git status tells you how to do that, too. In the last example output, the unstaged area looks like this:

Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: CONTRIBUTING.md

It tells you pretty explicitly how to discard the changes you’ve made. Let’s do what it says:

$ git checkout -- CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
renamed: README.md -> README

You can see that the changes have been reverted.

Pushing/Publishing Our Commits

Please keep in mind that up-to now our changes locally and have not yet been publish to cloud/server repository.

In order to publish your changes we just need to type

git push

or

git push <remote> <branch>

to be more specific if you have multiple remotes or multiple branches.

We will get into details of “remotes” in next section of this article and “branches” in next article of this series.

At this stage, if you had made changes in a cloned repository which you owned, this command will publish your changes but you had created a new git repository then at this point pushcommand will throw an error of upstream. This error means that we have not yet connected our local repository to a remote folder where changes are to be pushed. This brings to our next topic of “remotes”

Remotes

To be able to collaborate on any Git project, you need to know how to manage your remote repositories. Remote repositories are versions of your project that are hosted on the Internet or network somewhere.

It is entirely possible that you can be working with a “remote” repository that is, in fact, on the same host you are. The word “remote” does not necessarily imply that the repository is somewhere else on the network or Internet, only that it is elsewhere.

Checking Remotes of a git repository

To see which remote servers you have configured, you can run the git remote command. It lists the short names of each remote handle you’ve specified. If you’ve cloned your repository, you should at least see origin — that is the default name Git gives to the server you cloned from.

You can also specify -v, which shows you the URLs that Git has stored for the short name to be used when reading and writing to that remote.

$ git remote -v
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)

Results of above command show 2 remotes with same name but fetch and push. It means the url from which changes are pulled (local code is synced according to a remote code) and to which changes are pushed respectively. If we run this command in a new created git repository, then we won’t be able to see any remote. In order to add a remote your local repository we can use

git remote add <shortname> <url>

for example

git remote add origin https://github.com/paulboone/ticgit

https://github.com in above command shows that we have created our remote repository at GitHub. We can add remote repository of any other server as well by

`git remote add origin ssh://user@host:/path_to_repository

Now that we have add a remote to our local repository, we can push our changes by

git push origin master

Once we have added a remote we don’t need to add it again when pushing our commits.

Renaming and Removing Remotes

You can run git remote rename to change a remote’s short name. For instance, if you want to rename origin to repo1, you can do so with git remote rename:

$ git remote rename origin repo1

Pulling from Your Remotes

Suppose that you pushed your changes to a remote. Your other teammate working on the project cloned your repository. While he was going through the code, he saw some bugs and he made some changes in it to fix them. He then pushed changes. How will you get the changes made by your friend in your local code? You can run pull command to fetch latest code on the remote repository by

git pull

This swap your local code with the code on remote repository provided that there is no conflict between the two codes. By conflict, it means that you have made any changes to code in any file after pushing it to the remote. It might be the case that when you pull code, your code might have some uncommited local changes in code which might conflict with the code being pulled from remote. In this case we have merge issue because git can not decide which code should be kept; local or remote. Hence it is good practice to always pull code first and then make changes in it locally.

Tagging

Git has the ability to tag specific points in a repository’s history as being important. Typically, people use this functionality to mark release points (v1.0, v2.0 and so on). Git supports two types of tags: lightweight and annotated. A lightweight tag is very much like a branch that doesn’t change — it’s just a pointer to a specific commit. Annotated tags, however, are stored as full objects in the Git database.

Creating an annotated tag in Git is simple. The easiest way is to specify -a when you run the tag command:

git tag -a v1.4 -m "my version 1.4"

You can see the tag data along with the commit that was tagged by using the git show command:

$ git show v1.4
tag v1.4
Tagger: Ben Straub <ben@straub.cc>
Date: Sat May 3 20:19:12 2014 -0700
my version 1.4commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
Change version number

Another way to tag commits is with a lightweight tag. This is basically the commit checksum stored in a file — no other information is kept. To create a lightweight tag, don’t supply any of the -a, -s, or -m options, just provide a tag name:

$ git tag v1.4-lw

This time, if you run git show on the tag, you don’t see the extra tag information. The command just shows the commit:

$ git show v1.4-lw
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date: Mon Mar 17 21:52:11 2008 -0700
Change version number

By default, the git push command doesn’t transfer tags to remote servers. You will have to explicitly push tags to a shared server after you have created them. This process is just like sharing remote branches — you can run git push origin <tagname>.

$ git push origin v1.5

If you have a lot of tags that you want to push up at once, you can also use the --tags option to the git push command. This will transfer all of your tags to the remote server that are not already there.

$ git push origin --tags

Listing the existing tags in Git is straightforward. Just type git tag (with optional -l or --list):

$ git tag
v1.0
v2.0

To delete a tag on your local repository, you can use git tag -d <tagname>. For example, we could remove our lightweight tag above as follows:

$ git tag -d v1.4-lw
Deleted tag 'v1.4-lw' (was e7d5add)

Note that this does not remove the tag from any remote servers. Most intuitive way to delete a remote tag is with:

$ git push origin --delete <tagname>

Git Aliases

If you don’t want to type the entire text of each of the Git commands, you can easily set up an alias for each command using git config. Here are a couple of examples you may want to set up:

$ git config --global alias.co checkout
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status

This means that, for example, instead of typing git commit, you just need to type git ci.

In Next Article we will go through a basic and simplified flow of git from creating an empty git repository to pushing and pulling code.

--

--