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.