To install Git in Linux, run command:
sudo apt install git
To see the version of installed Git:
git --version
To see help and list of available commands:
git help
To add currently active Git branch to be written in the Terminal, add to the ~/.bashrc the following lines of code:
# Add currently active Git branch name to the Terminal
git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
}
export PS1="\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[01;33m\]\$(git_branch)\[\033[00m\]\$ "
After the code is added and changes to the file are saved, run command:
source ~/.bashrc
To generate public and private SSH key, navigate to .ssh/ folder in the Terminal:
cd ~/.ssh
and type the command:
ssh-keygen -t ed25519 -C "<comment>"
in the command above "ed25519" is the signing algorithm and it doesn't have to be that one (Ed25519 is an elliptic curve signing algorithm using EdDSA and Curve25519) but it is recommended by GitLab
To set the main branch to be named "main" instead of "master" by default, use the command:
git config --global init.defaultBranch main
To initialize empty Git repository on your computer, navigate to the folder via Terminal and type:
git init
.git will be the hidden directory in that folder. to verify that it's present (to see the list of all the files in the folder, even the hidden ones) type:
ls -a
When we initialize git and even create a file(s) after that, the branch is not automatically created. The files are just in our working directory. When we do our first commit, then the main branch is automatically created in our local repository.
The HEAD in Git is the pointer to the current branch reference, which is in turn a pointer to the last commit you made or the last commit that was checked out into your working directory. That also means it will be the parent of the next commit you do.
HEAD can be in either of two states, attached or detached, depending on if you've checked out a branch or not. Default state is attached, where any manipulation to the history is automatically recorded to the branch HEAD is currently referencing.
In detached state experimental changes can be made without impacting any existing branch. See infographic below illustrating the difference between committing in attached vs detached state.
Operations than can leave HEAD in detached state:
Checking out a particular commit, i.e.
git checkout <commit_id>
Explicitly checking out a remote branch, i.e.
git checkout origin/master
Switching to a branch using the detached flag, i.e.
git switch master --detached
Checking out a tag, i.e.
git checkout v1.0.1
Performing an interactive rebase, or a regular rebase containing conflicting changes
Moving from detached to attached state
To move from detached to attached state, you can either create a new branch from where you're at, or switch back to an existing branch.
Note: any commits created in detached state will eventually (post garbage collection) be discarded if you switch to another existing branch, without first persisting your changes in a new branch.
When we want to fetch sync information about our local and the remote repository:
git fetch
This command will not sync any files. It will just tell us what are new changes on the remote that we haven't fetched previously.
To clone the project from the remote repository to local repository:
In the Terminal navigate to the folder where you want the project to be (in that folder cloning will automatically create another folder with project's original name from remote repository)
go to GitLab/GitHub and copy SSH address (option "Clone with SSH") and then use that address in the command:
git clone <project_SSH_address)
This will do both git init and cloning.
To check out what remote repositories we have added:
git remote -v
Staging area an intermediate place where you can pick and choose which files inside your working directory you want to commit.
To see what is currently inside your staging area, use the command:
git status
This command will give us information what is in our working directory but not in our staging area (untracked files) and what is currently in our staging area.
In order to add files to the staging area, use the command:
git add <file_name>
We can add multiple file names separated by spaces.
To add all the files from the working directory to the staging area, use:
git add .
or
git add -A
To remove a specific file out of the staging area back to working directory, use command:
git reset -- <file_name>
or
git restore --staged <file_name>
To remove all the files out of the staging area and get them back to working directory:
git reset
To commit everything that is in staging area, run command:
git commit -m "<comment>"
-m stands for message. The -m flag is optional, we use it if we want to add a comment via command line (otherwise, the text editor will open and allow us to add a comment). This message/comment should explain what changes are done between previous commit and the current commit. The best practice for writing the commit messages is to write them in Present Tense. So, for example: "Complete Chapter 1", not "Completed Chapter 1".
If we want to stage all tracked, modified files and commit them we use -a (all) flag with along side with message flag. Command:
git commit -am "<comment>"
If we want to change comment in the last commit:
git commit --amend
This will open last commit log file in test editor.
If we want to change comment in multiple commits or in the commit that is not the last commit:
git rebase -i HEAD~3 (for the last 3 commits)
Or
git rebase -i <commit_id> (to move the HEAD to a specific commit)
Text editor will open with all commits ahead of the HEAD. For the commits that you wish to change the message, replace “pick” with “reword” in front of the <commit_id> and save the changes. For each selected commit, the text editor in which you can edit the commit message will open and after changes are made, save each edited file. To apply changes to the remote repository, git push –force (-f) is required.
If we want to revert commit changes:
git revert <commit_id>
This will revert changes not by deleting the commit but by doing the opposite changes (making a new commit with the previous state of the file(s)).
To see what commits are made so far on the currently active branch:
git log
To see more information about the last commit:
git show
To see more information about a specific commit:
git show <commit_id>
We don't have type/paste the whole commit ID, but it have to be even number of characters.
To discard uncommitted changes on the file in the local directory:
git checkout -- <file_name>
The special "option" -- means "treat every argument after this point as a file name, no matter what it looks like." This is not Git-specific, it's a general Unix command line convention. Normally you use it to clarify that an argument is a file name rather than an option,
To see all the code changes history in all the commits for a specific file:
git log -p <file_name>
To see all the code changes history in all the commits in the active branch:
git log -p
To see who and when committed changes to a specific file:
git blame <file_name>
We can do reset of commits from our local repository. There are three types of reset:
soft
mixed (default - if we do not specify what kind of reset we want)
hard
Soft reset moves the commit from our local git repository to the staging area. Command:
git reset --soft <commit_id>
Mixed reset moves the commit from our local git repository to the working directory. Command:
git reset --mixed <commit_id>
or, because it is default, just:
git reset <commit_id>
Hard reset removes the commit changes from our local git repository and rolls back changes in the file in our working directory.. Command:
git reset --hard <commit_id>
When we delete a file(s) in our working directory, we still need to add those files to staging area, and than do a commit to delete them them in our local repository. After that, to delete them on the remote repository, the push is needed.
To delete file from our working directory with git, use:
git rm <file_name>
To delete file from the local repository:
git rm --cashed <file_name>
We can have file named .gitignore in our working directory to tell git what files or folders not to add/commit/push. Gitignore file itself is not ignored by Git by default but we can add its name to the list inside if we do want to. We can have .gitignore file in multiple folders. Each file will dictate what to ignore in its folder and all the subfolders down the line.
To see all branches that we have locally:
git branch
To see all branches that we have locally and the branches that are on the remote repository:
git branch --all
To switch to other branch (to make it active):
git checkout <branch_name>
To see what are the differences between the branch in local and remote repository:
git diff <remote_repository_name>/<branch_name>
When creating a new branch wer we want to implement some feature, hotfix, patch… the best naming convention for that branch is as in examples:
feature/<feature_name>
hotfix/<hotfix_for>
patch/<for_for>
When we create a new branch, we can delete the parent branch if it is not needed anymore. In other words, we do not have to merge back to the parent branch.
When we want to switch to another branch (to make it active), we use:
git checkout <branch_name>
or
git switch <branch_name>
To create a branch, from the one that is currently active and switch to that new branch:
git checkout -b <new_branch_name>
or
git switch -c <new_branch_name>
To create a branch from the one that is currently active but to stay it the active one:
git branch <new_branch_name>
To create a branch, from the one that is currently not active and switch to that new branch:
git checkout -b <new_branch_name> <source_branch>
To create a branch from the one that is currently active but to stay it the active one:
git branch <new_branch_name> <source_branch>
To create branch from the specific commit that is not the last one, first detouch HEAD by going to that commit with:
git checkout <commit_id>
and than create a branch:
git checkout -b <branch_name>
To delete branch locally:
git branch -D <branch_name>
To delete branch on the remote repository:
git push --delete <remote_repository_name> <branch_name>
When a branch is deleted on the remote repository it will still be listed when we do git branch --all, even if we previously did git fetch. To get the info about deleted branches and on the remote:
git fetch --prune
To delete the refs to remote branches that no longer exist:
git remote prune origin
Git stores both local and remote refs. A repository will have local/origin and remote/origin ref collections. git remote prune origin will only prune the refs in remote/origin. This safely leaves local work in local/origin.
When we create a new branch so it doesn't exist on the remote repository, and we do the first push, we need to set its upstream branch:
git push --set-upstream <remote_repository_name> <branch_name>
This will create the upstream branch and push it.
To push an existing branch:
git push <remote_repository_name> <branch_name>
or just:
git push
To push the branch to overwrite the other branch on the remote:
git push <remote_repository> <source_branch>:<destination_branch>
If destination branch doesn't exist, it will be created.
To merge to branches, set the branch that you want to merge into as active and than:
git merge <remote_repository_name>/<branch_to_merge>
To pull the new commits from the remote repository for the active branch:
git pull <remote_repository_name> <branch_name>
or just:
git pull
Git pull is the same as git fetch + git merge
Rebase rewrites the commit history. It can be harmful to do it in shared branches. It can cause complex and hard to resolve merge conflicts.
When rebasing a branch with another one, the commits will not be sorted chronologically, but instead all the commits from the outer branch will be put on top of the commits of the base branch.
It never recommended to to rebasing that includes main or develop branches.
To do a rebase with the active branch:
git rebase <remote_repository_name>/<branch_name>
To copy only one file from another branch:
git checkout <branch_name> -- <file_name
A conflict arises when two separate branches have made edits to the same line in a file, or when a file has been deleted in one branch but edited in the other.
When we get the conflict, we should:
Edit conflicting file
git add <edited_file>
git commit
To see what are all the differences since our last commit (to see what changes are not committed yet):
git diff
To see the differences since our last commit for a specific file:
git diff <file_name>
or we can specify a branch too:
git diff <branch_name> <file_name>
To revert last commit, we use:
git revert <commit_id>
This will not delete that commit but instead create another commit that does the opposite changes to get it back to the previous state.
To revert all changes in our working directory that are done after last commit:
git reset HEAD --hard
or just:
git reset --hard
To revert all changes in our working directory that are done after a specific commit:
git reset HEAD --hard <commit_id>
If we push the branch after this, there will be a problem because the branch on the remote have newer commits. We can still push by force and overwrite everything that is not in our locally stored branch:
git push --force