How to use git successfully even with a little background knowledge.
Git is a version control system. Probably the best way to learn it is just to read the documentation. In case you do not have much time and just need to jump on the train, this document helps you to understand the basics fast.
Git keeps the versions as a snapshots on your local machine. It enables you to work completely offline and synchronize the code with the remote repository when it suits you.
There are four levels in the git hierarchy
Git Levels | Description |
---|---|
Working Tree | The actual files in the local directory managed by git. |
Index | Git structure of the files. Not in index - does not exist for git. |
Committed | There is a snapshot version of the files. It can be shared. |
Remote Repository | The commit (snapshot) was shared through push or pull with others. |
In terms of files, they can be in one of three states
First step is to create account on some git site such as GitHub, GitLab etc.
Once you have it, add your public SSH key to it.
After the git installation, there is a need of some configurations.
git config --global user.name "Name Surname"
git config --global user.email "username@email.com"
Git Command | Description |
---|---|
git init | Create an empty Git repository or reinitialize an existing one. |
git clone | Clones remote git repository to your machine as local git repository. |
git add | Add file contents to the index. |
git commit | Record changes to the repository. |
git push | Pushes local repository to the remote one. |
git fetch | Downloads content from remote git repository. |
git merge | Incorporates changes from given named branch to current branch. |
git pull | Does git fetch and git merge. |
git branch | Branch is simply a pointer to specific snapshot (version). |
HEAD | Special pointer which point at the branch you are currently on. |
git checkout | Changes branch at which the HEAD is pointing and updates the local files to match with that branch (switch branches). |
Git has a beautifully done manual, so adding --help
after any command is usually sufficient help once you start using the
git.
# Example of help for rm command
git rm --help
It is either possible to create a new repository (project) or to find some already existing.
Create repository from scratch
On your GITSITE create a new repository and get its URL under button “clone” (e.g. https://github.com/USERNAME/PROJECT.git)
# Clone the repository (project) to your machine
git clone git@YOUR_PROJECT_PATH.git
# Create README.md about your project
echo "# REPOSITORY_NAME" >> README.md #touch README.md
Create repository from existing directory
cd EXISTING_DIRECTORY
echo "# REPOSITORY_NAME" >> README.md #touch README.md
# Create an empty Git repository or reinitialize an existing one
git init
# Add remote site git@GITSITE:USER/REPOSITORY.git as origin
git remote add origin git@GITSITE.com:USER_NAME/REPOSITORY_NAME.git
Create a repository from an existing repository
There is an option to use an existing project as your starting point by making a copy. It is called a fork, by doing so you will have your own copy of the whole project. Then you can just git clone and start doing stuff.
Files can be either untracked, added, modified or deleted.
# Show status of git files, which where not added, which were deleted but added etc.
git status
# Show changes between staged file and file in the working tree.
git diff path/to/file
Stage files to the index for the next commit.
# Add the one file (README.md) to the index (will be commited).
git add README.md
# Add all the files from current directory.
git add .
# Add all files to the index.
git add -A # git add --all
Remove Files from the Index
# Remove files from the working tree and from the index (File is deleted and will not be commited).
git rm FILE
# Delete directory (option recursive).
git rm -r DIR
# Remove FILE only from index (file will not be commited) it doesn't delete it locally.
git rm --cached FILE
# Forced remove - the file is deleted from index and working tree even when it has local modifications.
git rm -f FILE
Rename or move files
# Move or rename files.
git mv file/path new/file/path
Discard Local Changes
# Discard changes in working directory.
git checkout -- FILENAME
# Commit (record) the changes with a meaningful message.
git commit -m "Initial commit, README.md created."
# Write commit message in advance to a file and then use it for commit.
git commit -eF commit_message.txt
# Redo last commit with new changes
git commit --amend
# Pushes the current branch to the remote repository called "origin".
git push -u origin
# Pushes local "main" branch to the remote repository called "origin".
git push -u origin main
# Pushes local "main" branch to the "dev" branch of remote repository "origin".
git push origin main:dev
# Forcing push if necessary (rewriting commits history perhaps).
git push -f
.gitignore
file specifies intentionally untracked files
to be ignored.
# Ignore all .ipynb checkpoints
.ipynb_checkpoints
# Ignore knapsack instances directory
./knapsack/instances
# Show all commits of the current branch.
git log
# Show all commits that are fetched, graphically.
git log --all --graph
# Show commits affecting the a specific file (--oneline makes message and commit's hash shorter).
git log --oneline path/to/file.sth
# Diff file with it's version from given commit (commit's hash taken from git log).
git diff 0a42637 path/to/file.sh
# Show information about given commit, tag, etc.
git show 0a42637
The main branch is by default called “main”. In the past, it was often called “master”. Good practise is to create a separate branch for development.
# Show branches - the current is marked with asterix
git branch
# List all branches, also the remote ones
git branch -a
# Create branch
git branch BRANCH_NAME
# Change to a branch
git checkout BRANCH_NAME
# Change the current branch to main
git checkout main
# Crate branch and check out to it in one step
git checkout -b BRANCH_NAME
# Delete branch
git branch -d BRANCH_NAME
# Remove branches deleted on the remote
git fetch --prune origin
# or
git remote prune origin
# Rename branch
git branch -m NEW_BRANCH_NAME
Merge the ANOTHER_BRANCH to main.
git checkout main
git merge ANOTHER_BRANCH
# Merge the local content with BRANCH_NAME of REMOTE_NAME
git merge --allow-unrelated-histories REMOTE_NAME/BRANCH_NAME
# No fast-foreward (--no-ff)
git merge --no-ff ANOTHER_BRANCH
# Apply all changes from another branch (then it can be commited in one commit).
git merge --squash ANOTHER_BRANCH
Once you clone a repository, it sets a remote for the repository under the origin. Thanks to that you can push your code to origin (the remote repository) or to pull code from the repository.
# Show the remotes
git remote -v
# Add remote
git remote add NAME URL
# Add remote and fetch
git remote add -f NAME URL
# Delete remote
git remote remove NAME URL
# Set remote url
git remote set-url origin git@github.com:USERNAME/REPOSITORY.git
# Fetch files from origin( remote site).
git fetch origin
# Create the desired BRANCH_NAME from origin and change to it.
git checkout -b BRANCH_NAME origin/BRANCH_NAME
# Git pull - equivalent to git fetch and git merge.
git pull
# Fetch origin branch from remote origin( and merge it with local branch origin).
git pull origin main
Git pull using git fetch and git merge.
# Downloads content from a remote repository and write to .git/FETCH_HEAD
git fetch
# Merges the FETCH_HEAD to the current branch.
git merge FETCH_HEAD
Create the pull request
In case you do not have the push rights in order to merge your changes to the remote repository you need to create Pull Request at the git site, so the owner can pull your changes.
# Show information about files in the index and the working tree
git ls-files
For example, I got this error:
git fatal: no submodule mapping found in .gitmodules for path
I used this command to get staged files that git considers to be submodules (160000).
git ls-files --stage | grep 160000
Save the changes from the last commit on and clean them
So the working directory is at the stage of last commit.
# Saves all differences from last commit away and clean them off (equivalent to git stash push).
git stash
# Shows list of stashes.
git stash list
# Restored changes from the last stash.
git stash apply
# See the most recent stash (equivalent to git stash show -p stash@{0}).
git stash show -p
# See older stash
git stash show -p stash@{1}
# Drop the last stash.
git stash drop
Undo stuff before commit, i.e. reset the Index and Working Tree or the Index only.
# Removes unwanted staging of many files - resets the index only.
git reset
# Deletes all changes from the last commit - resets index and the working tree.
git reset --hard
Remove changes after commit i.e. reset to the specific commit.
# Resets branch (HEAD) to given commit, but the working tree and index stay the same.
git reset --soft HASH_OF_COMMIT
# Resets branch (HEAD) and index to the given commit, files (working tree) stays untouched.
git reset --mixed HASH_OF_COMMIT
# Resets the index and the working tree, everything is reseted to the given commit.
git reset --hard HASH_OF_COMMIT
Remove changes and keep history
# Revert some existing commits (Requires no local modifications from the HEAD commit)
git revert
Remove changes without history
# Move HEAD to the second latest commit
git reset HEAD^
# Do the modifications
# Commit the changes
# Forcefully push the changes (to rewrite the history)
git push -f
git clone --bare https://githost.org/OLD_REPOSITORY.git
cd OLD_REPOSITORY
git push --mirror https://github.com/NEW_REPOSITORY.git
# Clone the repository from the old site.
git clone git@GITSITE_OLD.com:USER/PROJECT.git
# Go to the repo directory.
cd PROJECT
# Rename remote origin to old-origin
git remote rename origin old-origin
# Add new remote and call it origin
git remote add origin git@GITSITE_NEW.com:USER/PROJECT.git
# Push everything to the new origin
git push -u origin --all
git push -u origin --tags
# Delete file from every commit
git filter-branch --index-filter 'git rm --cached --ignore-unmatch path/to/file' HEAD
# Move (rename) file through all history
git filter-branch -f --tree-filter 'if [ -d path/to/dir ]; then mkdir -p path/to/new/dir && git mv path/to/dir path/to/new/dir; fi' HEAD
# Clone the repository
git clone git@GITSITE.com:PROJECT_PATH.git
Update the Content from Remote
If there is a time lag between cloning and the time you want to work on the repository, the remote repository may have changed. Then it is reasonable to update the local content from the remote i.e. pull the changes.
git checkout main
# Git pull fetches the last version from the origin (GITSITE:repo) and merges it with the local content
git pull # git pull origin
Develop the Code as a New Branch
Instead of modifying the main, and pushing to the origin/main. Create a development branch and make the changes there. Don’t merge the branch with main. Push the development branch to remote and create a pull request.
# Create your development branch
git branch BRANCH_NAME
# Check out the branch
git checkout BRANCH_NAME
# Record the changes to be commited
git add PATH_TO_FILE, PATH_TO_FILE_1
# Check if everything is git added or git deleted
git status
# Commit the changes
git commit -m "Meaningful description of the changes"
# Push the local changes to the branch BRANCH_NAME of remote site
git push -u origin BRANCH_NAME
Fork the repository. Clone it and treat it as your own.
Once you are happy with your changes, create a pull request on the GITSITE.
How To: Merge a Git submodule into its main repository
# Add submodule
git submodule add https://github.com/NEW_REPOSITORY.git REPO_NAME
# List all git configurations with specified origin
git config --list --show-origin
# Set vim as your default git editor.
git config --global core.editor "vim"
# Set vimdiff as your difftool
git config --global diff.tool vimdiff
# Diff changes with a diff tool of your choice
git difftool