Last modified on 01 Oct 2021.
Quick references for basic tasks with git.
👉 Note about Github.
Installation & Tools
- Download and install (to use command lines): git’s homepage.
- Git client tools: Github Desktop (Windows and MacOS), GitKraken (Windows, Linux, MacOS).
- Read
html
files in repository on Github: use this tool.
Rules to be more effective
- Do commit early and often.[ref]
- Do make useful commit messages.
- Create a new branch for every new feature.
- Use
pull
requests to merge code tomaster
.[ref] - For temporary branches, name them starting with
_
.
Settings on local machine
# SET GLOBAL INFO
git config --global user.name "Anh-Thi DINH"
git config --global user.email "[email protected]"
# SPECIFIC REPO
git config user.name "Thi"
git config user.email "[email protected]"
# Verify your configuration
cat .git/config
# IF: `Could not resolve host: github.com`
git config --global --unset http.proxy
git config --global --unset https.proxy
# SAVE GITHUB AS DEFAULT
# (don't need to log in again every time we use)
git config credential.helper store
git pull
# FORMATTING DISPLAY
git config color.ui true # add colors to the results
git config format.pretty oneline # disply only one line of each commit
Check the status
# CHECK STATUS
git status
git status -s # modified files
# Get remote list
git remote -v
# WITH COLORS
git log --oneline --graph --color --all --decorate
# --graph: draw text-based branches
# --decorate: display names and tags
Check some commit:
git log -- <file> # check commits containing <file>
git log --prep='abc' # look for commits containing "abc" in their name
git log <from>..<to> # display commints from <from> to <to> (commit's id, branch's name,...)
Check current HEAD
git log -1
# something likes HEAD -> <branch-name>
Check the change of some file,
git diff file_name.abc
Check the list of files in the last commit,
# get the last commit id
git log --format="%H" -n 1
# list of files
git diff-tree --no-commit-id --name-only -r <commit_id>
Git ignore
Create a file .gitignore
.
# ignore
.jekyll-cache
.git
__pycache__/
__pycache__/
# ignore all except
/*
# whitelist
!.gitignore
!/docker/
Ignore local changes on some files from pull
/push
,
# they are assumed to be unchanged
git update-index --assume-unchanged file_1 file_2
# undo
git update-index --no-assume-unchanged file_1 file_2
# To get a list of dir's/files that are assume-unchanged
git ls-files -v|grep '^h'
Repositories
# CREATE REPO
git init <repo-name>
# CLONE REPO (using https or ssh)
git clone <repo-link>
Git GUI
git gui
gitk
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
# UNCOMMIT (back to before commit)
git reset --soft HEAD~1
# 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 <current-branch>
Pull
# LIST ALL REMOTE REPOS
git remote -v
# UPDATE REMOTE -> LOCAL
git pull origin <branch-on-remote>
# COPY A COPY FROM REMOTE
git fetch origin <branch-on-remote>
# compare current branch to this copy
git diff --stat FETCH_HEAD
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>
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"
# save to log file
git diff --output=log.txt branch_1 branch_2 --name-status
# LOCAL <-> REMOTE BRANCHES
git branch -vv
# 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
# MERGE <branch> TO CURRENT
git merge <branch>
# 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 `/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>
Others
Add a description (using Vim editor):
git branch --edit-description
In the case you wanna exit Vim, press ESC then type :q
to quit or :wq
to write and quit.
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
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>
# 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
Alias
# use `git br` instead of `git branch`
git config alias.br branch
Gitlab: Clone a private repo to local
- (Windows) Generate a ssh key
ssh-keygen -t rsa -b 4096 -C "[email protected]"
inC:\Users\dinha\.ssh
under the nameid_rsa
(for private) andid_rsa.pub
for public. It’s important, the name!!!! - Open and copy key in
C:\Users\dinha\.ssh\id_rsa.pub
- Go to Gitlab > Settings > SSH Keys > paste a copied key and name it.
- Clone again the repo and it shoule be working!
Errors
error: invalid object Error building trees
git hash-object -w <error-file>
You can also go back to the previous commit (git reset --hard
) and you LOSE all uncommit files.
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
Go to ~/.ssh/
(Linux) or C:\Users\dinha\.ssh
(Windows), remove the host from known_hosts
and re-connect again.
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
# update submodules
git submodule update --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
Others
- fast-forward means that the commits can be applied directly on top of the working tree without requiring a merge. When
git pull
and get this message, we can be sure that the new update are not confict with our current modifications. - Find big files / commits: Using this scripts and this answer.