Git

Git is a version control system that allows developers to track changes in their code over time, collaborate on software projects, and revert to previous versions if necessary. It was created by Linus Torvalds in 2005.

Setup

git config --global user.name "github username"

git config --global user.email "github email"

#Verify Setup

git config --list

Initial Commands

#Initialization

git init

[Creates a folder .git which contains the meta-data of your git repository]

#Status

git status

[Tells us which branch we're in, no of commits, changes, etc]

#Clone

git clone repository_url folder_name

[Brings a git repository to your computer]

#Changes

git diff filename

[Shows changes made to a particular file]

git diff

[Shows all the changes wrt head]

#View changes made for a specific hash/commit id

git show hash-id

Head

In Git Head refers to the current commit on the branch that you are currently working on. It is a pointer to the last commit in the branch's history, and it moves forward as new commits are added to the branch.

#Commit Head is pointing to

git log -1

#Changes of the commit that head is pointing to

git show HEAD

#Restore file to previous version

git restore filename

[File gets restored to the version pointed by the head]

Lifecycle of a change

There are 3 main stages for any change in git.

  • Modified: It means you've made changes to a file but have not committed it yet.

  • Staged: It means that you have marked a modified file in its current version to go into your next commit.

  • Committed: It means that the data has been stored in your local database.

If you want your changes to reflect in the repository hosted on github, you've to push those changes.

#To Stage Changes

git add index.html

[Adds the file index.html to track if it's a new file.

Old files get staged]

git add .

[Adds all the files to staged state]

#To Commit Changes

git commit -m "commit message"

[Moves the change from staged to committed state]

#Add and Commit shortcut

git commit -am "commit message"

View History

git log is the command that displays the histroy of a repository. It shows the author, date, and commit message for each commit, along with other information such as the commit hash. The command can be used with various options and flags to customize the output.

#View everything

git log

#View latest n commits

git log -n 5

or

git log --max-count 5

[Shows the 5 latest commits]

#View commits made after specific date

git log --since="2 weeks ago"

[Shows commits made in the past 2 weeks]

#View commits made before specific date

[Shows commits before January 1, 2023]

git log --until="2023-01-01"

#View changes made in each commit

git log --p

[Shows the changes made in each commit, similar to diff]

#View stats for modified files in each commit

git log --stat

#View commit that added or removed a specified string

git log -S "function"

[Shows commits that added or removed lines containing the string "function"]

#View commits that changed a file matching a specific regex

git log -G "*.js"

[Shows commits that modified files with .js extension]

#View commits made by a specific person

git log --author="John Doe"

[Shows commits made by John Doe]

#View commits having a specific string in commit message

git log --grep "fix"

[Shows commits having "fix" in commit message]

#View commits from all branches

git log --all

#View history in a specific format

git log --pretty=format:"%h %s %an"

[Shows each commit with hash, subject, and author name]

#View one liner for each commit

git log --oneline

[Shows commit hash, author, date, and commit message on a single line for each commit]

#View graph of a branch and merge history

git log --graph

#View commits in reverse chronological order

git log --reverse

The commands mentioned above can be combined to filter the output even further.

git log --author="John Doe" --since="2023-01-01" -n 5 --pretty=oneline

[Shows latest 5 commits of John Doe after Jan 1, 2023 with

commit hash, author, date and commit message on a single line]

Branching, Tagging and Merging

Branching refers to the ability to create a new line of development separate from the main line of development. This allows multiple people to work on different features or bug fixes simultaneously without interfering with each other's work. Each branch has its own set of commits and its own HEAD pointer. When you start a new branch it starts off with the same commits as the branch it was created from. The default branch in git is called the master branch.

#List all branches

git branch

[Lists all branches and also tells which branch you're currently on]

#Create new branch

git branch branch-name

#Change branch

git checkout branch-name

#Create and move to new branch

git checkout -b branch-name

#Delete a brach

git branch -d branch-name

Tagging is a way to mark a specific point in the commit history with a label. This can be used to mark a specific version of the code.

#Tag a commit

git tag -a tag-name hash-id -m "commit message"

#Delete a tag

git tag -d tag-name

Merging is the process of bringing changes from one branch into another. For example, if you've been working on a new feature in a separate branch and you want to bring those changes back into the main branch, you would merge the feature branch into the main branch. There are two types of merge:

  • Fast-Forward merge: When you merge a branch into another branch, if the latter one hasn't moved forward, git will simply move the head pointer of the latter branch to the head of the merged branch.
  • Three way merge: When there are commits on both branches that nedd to be combined, git will perform a three-way merge. This creates a new merge commit that brings the changes from both branches together.

When merging, git will automatically try to merge the changes together, but sometimes conflicts can occur if the same lines of code were modified in both branches. When this happens, you'll need to resolve the conflicts manually before you can complete the merge.

#Merge a branch

git merge branch-name

Stash

It allows you to temporarily save changes that you made to your working directory but have not yet committed. This can be useful when you need to switch to a different branch to work on something else, but you don't want to commit your changes yet or lose them.

When you use the stash command, it'll save the current state of your working directory, including any modified files and any new files that have not yet been added to the repository, into a new stash and then discards the changes in your working directory, leaving it in a clean state.

Git stash is useful when you are in the middle of some changes and you've to switch to another branch for a moment, instead of committing the changes and create a new branch, you can simply use git stash to save the changes and then switch to the other branch. Once you're done with the other branch, you can apply the stash to your working directory and continue with your changes.

#Stash changes

git stash

#Display list of all stashes

git stash list

#Apply latest stash to working directory

git stash apply

#Apply nth stash to working directory

git stash apply stash@{n}

#Remove latest stash

git stash drop

#Remove nth stash

git stash drop stash@{n}

#Apply latest stash and then remove it

git stash pop

#Remove all the stashes

git stash clear

Keep in mind that when you use git stash, it'll only stash the changes that are not yet committed.

Git Remote

A remote in git is a repository that is not located on the same machine as your local repository. Remotes allow you to share your code with others and collaborate on a project.

When you clone a repository, git automatically sets up a remote named origin that points to the repository you cloned from.

#Add a custom remote

git remote add remote-name remote-url

#View list of all remotes in your local repository

git remote -v

#Change url of an existing remote

git remote set-url remote-name new-url

#Change name of a remote

git remote rename old-name new-name

#Remove a remote

git remote remove remote-name

Fetch, Push and Pull

Fetch: It is used retrieve commits and other information from a remote repository. It doesn't merge those changes with your local branch. Instead, it updates your local copy of the remote branches, so that you can see the changes that have been made to the repository since your last fetch. It is useful for keeping your local repository in sync with the remote repository, especially when working on a project with other people. It's also a good practice to fetch changes from the remote repository before trying to push your own changes, so you can ensure that you are working with the latest version of the code.

When you fetch, git retrieves all the branches that you've set up to track in your local repository and it updates the remote-tracking branches. These branches are local branches that represent the state of the corresponding branches in the remote repository. These remote-tracking branches allow you to see the changes that have been made to the remote repository since your last fetch.

#Fetch from a remote

git fetch remote-name

#Fetch from a specific branch in the remote repository

git fetch remote-name branch-name

Push: It is used to send your local commits to a remote repository. It updates the remote repository with the new commits from your local repository.

#Push changes to master branch

git push -u origin master

[origin is the remote name]

#Push changes to any branch

git push remote-name local-branch-name

#Push to remote with same name as local

git push

[It'll push commits from current local branch to the remote with same name]

#Push all local branches

git push --all origin

#Push all the tags

git push --tags origin

If the remote brance doesn't exist, git will create a new one. You can use the -u flag to set up the upstream tracking, so you don't have to specify the remote and branch name every time you push.

It's important to note that git push will fail if the remote repository has commits that you don't have in your local repository. In this case, you need to first fetch the remote changes and merge them with your local repository before you can push your own changes.

Pull: It retrieves the latest commits from a remote repository and merges them with your local repository.

#Pull from remote

git pull remote-name branch-name

Rebase

Rebasing in git is the process of taking the commits from one branch and replaying them on top of another branch. This can be used to synchronize the commits of one branch with the commits of another branch, or to change the linear history of a branch. Rebasing operates on commits, unlike merging which creates new commits. It moves the entire branch to a new starting point.

There are two types of rebase:

  • git rebase: This will replay the commits of the current branch on top of the specified branch.

  • git rebase --onto: This allows you to specify both the branch to rebase onto and the starting point of the commits to be replayed.

It is important to note that rebasing can lead to conflicts, just as mergin does. When conflicts occur, you'll have to resolve them manually before you can continue the rebase process.

#Rebase

git rebase branch-name

[You have to be on the branch which has the commits you want to apply

branch name here refers to where you want to reapply those commits]

Undo Commits

Amend: This allows you to modify the most recent commit in your local repository.

git commit --amend

Revert: This allows you to undo the changes made by a specific commit and create a new commit that undoes those changes. It preserves the commit history.

git revert commit-hash

Reset: This allows you to undo commits and move the branch pointer to a previous commit. It is used to discard commits, undoing the changes in the working directory and in the commit history. It deletes commit history.

There are 3 modes of git reset:

reset commit: This mode is used to move the branch pointer to a specific commit, discarding any commits made after that commit.

reset --soft commit: This mode is used to move the branch pointer to a specific commit, but it keeps the changes made in the commits that are being discarded in the staging area, allowing you to make new commits with those changes.

reset --hard commit: This mode is used to move the branch pointer to a specific commit, dicarding the commits and the changes made in the commits that are being discarded. It permanently deletes commits and it cannot be undone.

git reset commit-hash

git reset --soft commit-hash

git reset --hard commit-hash

.gitignore

It is a file that tells git which files or directories to ignore when committing changes to a repository. The file contains a list of patterns or specific file names that git should ignore, one per line. It is typically placed in the root directory of the repository, and it applies to all subdirectories.

Note: don't forget to add .env and node_modules files to the .gitignore file before making any commits to the remote repository.