Installation
- Download and install git's homepage.
Some rules
- make useful commit messages.
- create a new branch for every new feature.
configurations for your local machine
# SET GLOBAL INFO git config --global user.name "Abhinav Yadav" git config --global user.email "abhinavay2003@gmail.com"
# FOR SPECIFIC REPO git config user.name "Abhinav" git config user.email "abhinavay2003@gmail.com"
# Verify your configuration cat .git/config
check the status
# CHECK STATUS git status git status -s # modified files
# Get remote list git remote -v
# Check all the commits git log --oneline # Check all the commits in one line git log --oneline
Check some commit:
git log -- <file> # check commits containing <file> git log --prep='abc' # look for commits containing "abc" in their name
Check current
HEADgit log -1 # show the very recent commit # something likes HEAD -> <branch-name>
Check the change of some file,
git diff file_name.abc
git ignore
Create a file
.gitignore.__pycache__/ # ignore all except /* # whitelist !.gitignore !/docker/
Repositories
# CREATE REPO git init <repo-name>
# CLONE REPO (using https or ssh) git clone <repo-link>
Staged & Commits & Push & Pull
Staged
# ADD MODIFICATION (1 FILE) git add . # add all the changes git add <file-name> # only add the <file-name> to the staged
# UNSTAGE A FILE git reset HEAD <file>
# UNSTAGED EVERYTHING git reset
Commit & Push
# MAKE COMMIT (FROM STAGED) git commit -m '<comment-for-this-commit>' git commit -a # commit any files
# PUSH TO REMOTE git push origin <branch-name> # push only <branch-name> git push --all origin # push all branches
# CHECK & TEST A COMMIT git checkout <commit-id> # after testing git checkout -- . # discard all changes git checkout <current-branch> # back to previous
Pull & Fetch
# LIST ALL REMOTE REPOS git remote -v
# UPDATE REMOTE -> LOCAL git pull origin <branch-on-remote>
# Pull (fetch) a branch from remote git checkout --track origin/<branch>
# COPY A COPY FROM REMOTE git fetch origin <branch-on-remote> # compare current branch to this copy git diff --stat FETCH_HEAD
# Just fetch the changes from remote # Appliy to the current branch git fetch
# Fetch a branch without checkout # (On branch A but wanna fetch/create branch B) git fetch origin branch-b:branch-b
# Pull from remote and replace COMPLETELY local # Checkout the branch you wanna replace first git reset --hard origin/<branch>
Difference between git pull --rebase and git pull --ff-only (Reference)
-rebase: remote changes (C) will be applied before local changes (D) resulting in the following tree
A -- B -- C -- D
-ff-only: fail if there are conflicts, otherwise, it will work!
Branches
Create
# CREATE A BRANCH git branch <branch-name>
# CREATE AND MOVE TO NEW BRANCH # This one is based on the current `HEAD` (git log -1). git checkout -b <new-branch> # new branch based on another one git checkout -b <new-branch> <existing-branch>
# Create a independent branch # (like git init, without any commit history) git checkout --orphan <new-branch>
Two branches
# CHANGE TO ANOTHER BRANCH git checkout <branch-name> # fatal: 'dev' could be both a local file and a tracking branch. git checkout <branch_name> --
# UPDATE ALL REMOTE BRANCHES TO LOCAL # (there may be deleted branches on remote) git remote update origin --prune
# LIST ALL LOCAL BRANCHES git branch
# LIST ALL LOCAL + REMOTE git branch -a
Comparing
# compare current branch with other git diff <branch>
# COMPARE 2 BRANCHES git diff <source-branch> <compared-branch>
# a specific file git diff mybranch master -- myfile
# list all diff files: current vs git diff --name-status master
# 2 files vs git diff mybranch master --name-status # can be "--name-only"
# LOCAL <-> REMOTE BRANCHES git branch -vv
# save to log file git diff --output=log.txt branch_1 branch_2 --name-status
# CORRESPONDING LOCAL BRANCH <-> REMOTE git fetch git branch --set-upstream-to=origin/<remote_branch> <local_branch>
Delete
# DEL A LOCAL BRANCH git branch -d <branch-name> git branch -D <branch> # force to delete
# DEL A REMOTE BRANCH git push origin :<branch-name>
Merge
Check if there are conflicts before merging?
# merge without commit -> check the conflicted files git merge --no-commit <other-branch> # list only the name of conflict files git diff --name-only --diff-filter=U # then reset if don't wanna merge git reset --hard
# MERGE <branch> TO CURRENT git merge <branch>
# merge + keep current changes git merge --strategy-option ours # merge + keep incoming changes git merge --strategy-option theirs
# MERGE <sub-branch> TO master + REPLACE master git checkout <sub-branch> git merge -s ours master git checkout master git merge <sub-branch> # master can be other
# Merge all files in a folder frm another commit git checkout <commit> folder/*
# MERGE `/link/to/abc.xyz` FROM `<branch-1>` TO `<branch-2>` (can be `master`) git checkout branch-2 git checkout branch-1 /link/to/abc.xyz
# MERGE ONLY SOME FOLDER git checkout <branch> git checkout <from-branch> folder1\ folder2\
# MERGE commit from ONE BRANCH to CURRENT git cherry-pick <commit hash>
# KEEP FILES/FOLDERS FROM MERGE # add line to .gitattributes echo 'file_name.txt merge=ours' >> .gitattributes
Conflict
If there are changes from both local and remote, there will be conflicts! Something likes that,
<<<<<< HEAD changes on local ====== changes from remote >>>>>> template/notetheme2
If you use Visual Studio Code, there is a small toolbar above each conflict and you can choose which one you prefer to keep!
Prefer one of them?
# keep remote changes git pull -X theirs <remote-repo>
# keep local changes git pull -X ours <remote-repo>
Keep both? Using Visual Studio Code or,
# add below line to .gitattributes (on branch being merged) echo "*.whatever merge=union" .gitattributes # on windows, remove `""`
Already in conflicted state?
git checkout --theirs path/to/file # remote git checkout --ours path/to/file # local
# Abort the conflicts # (go back to before merging) git merge --abort
Exclude from merging
Exclude some files from merge (keep
ours),# ONLY FOR FILES # add below line to .gitattributes (on branch being merged) echo "file.ext merge=ours" .gitattributes # on windows, remove `""`
Exclude some folders (we cannot use
git in this case):- If you delete these folders after merging, just commit and later merges will ignore them.
- If you meet a conflict, add the folder's name in a file called
reset_folders.sh
#!/bin/sh echo 'Reset some only-this-branch folders after merging.' git reset folder_1, folder_2 git checkout . git add . git commit -m "update from merge (keep local in some folders)"
Each time,
git merge <from-branch> && sh reset_folders.sh
Rename
# CURRENT BRANCH git branch -m <newname> git branch -M <newname> # if there are only capitalization changes
# CURRENT IS ANOTHER BRANCH git branch -m <oldname> <newname>
# RENAME REMOTE BRANCH (delete old + push new) # (rename local branch first) git push origin :<oldname> <newname> # reset the upstream branch for the new-name local branch git checkout <newname> git push origin -u <newname>
Squash
# Squash newest 5 commits git rebase -i HEAD~5
Others
Add a description (using Vim editor):
git branch --edit-description
In the case you wanna exit Vim, press <kbd>ESC</kbd> then type
:q to quit or :wq to write and quit.Tags
# Listing tags git tag # Delete local tags git tag -d <tag_name> # Delete remote tags git push --delete origin <tag_name>
Cleaning
Clean all history of a repo,
git checkout --orphan tmp_repo git add -A # Add all files and commit them git commit -am "Clean Repo" git branch -D <repo> # Deletes the <repo> branch on remote git branch -m <repo> # Rename the current branch to <repo> git push -f origin <repo> # Force push branch <repo> to github
Remove from git
Remove from git, not from system,
# a file git rm --cached <file_name>
# a folder git rm -r --cached <folder>
Discard the changes
# DISCARD CHANGES ON CURRENT DIR git checkout -- . # for all changes git checkout -- <file-name> # for a specific file (go back the last commit of this file)
# DISCARD ALL LOCAL CHANGES git reset --hard
# Get back to some prev commit and ignore all the changes (including the commits) git reset --hard <commit-id>
In the case you want to discard the changes but want to make a save before moving to another branch to test. You can use below line.
git stash
If you wanna get back to the place you saved (and remove it from the stashed list), just go back to the branch you make the save and use
git stash pop
Restore
# RESTORE FROM LAST COMMIT git checkout -- <file>
# Revert single file to a commit git checkout <commit> -- <file>
# DISCARD ALL CHANGES ON LOCAL + GET FROM REMOTE git fetch origin git reset --hard origin/master
# DISCARD ALL CHANGES + get the last update from remote git reset --hard @{u}
# EREASE ALL COMMITS + BACK TO <commit-id> git reset --hard <commit_id> # (force) to push git push -f origin master
Change remote url
# check the current remote url cat .git/config| grep "url" # change to the new one git remote set-url origin new.git.url/here
Git submodules
Git submodules allow you to keep a git repository as a subdirectory of another git repository.
# "git clone" & "git pull" to automatically update submodules. git config --global submodule.recurse true # public repo: github.com/you/blog (clone) # private repo: github.com/you/posts cd blog git submodule add <https://github.com/you/posts> # blog/posts
To stop
Fetching submodule.... when git pull: git config submodule.recurse false!To update all submodules,
# If this is the 1st time you checkout the repo git submodule update --init --recursive # Update submodules git submodule update --recursive --remote # Don't make change on the folder of submodules!!!!
# clone a repo with submodules git clone <repo> --recursive # or git clone <repo> git submodule init git submodule update
# REMOVE a submodule (suppose that it's in a/) # Make a copy (just in case) 0. mv a/submodule a/submodule_tmp 1. git submodule deinit -f -- a/submodule 2. rm -rf .git/modules/a/submodule 3. git rm -f a/submodule # Note: a/submodule (no trailing slash) 4. git rm --cached a/submodule

