Thi's avatar
HomeAboutNotesBlogTopicsToolsReading
About|My sketches |Cooking |Cafe icon Support Thi
💌 [email protected]

Git

Anh-Thi Dinh
GitSkills
Left aside
Quick references for basic tasks with git. For simpler tasks, consider using Gitkraken for a visual interface. However, you have to pay to use all useful features. You might also find the note on GitKraken in commands interesting.

Installation & Tools

  • Download and install (to use command lines): git's homepage.
  • Git client tools: Github Desktop (Windows and MacOS, Linux), GitKraken (Windows, Linux, MacOS).

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 to master.
  • For temporary branches, name them starting with _.

Settings on local machine

 

Check the status

Check some commit:
Check current HEAD
Check the change of some file,
Check the list of files in the last commit,
Check all commits w.r.t. a specific file
💡 GitKraken: Ctrl + P > Type "History" > Enter the file path.

Git ignore

Create a file .gitignore.
Ignore local changes on some files from pull/push

Repositories

Clone without ssh using Personal Access Token.

Git GUI

Staged & Commits & Push & Pull

Staged

Commit & Push

Pull & Fetch

Branches

Create

Two branches

Comparing

Delete

Merge

Check if there are conflicts before merging?

Conflict

If there are changes from both local and remote, there will be conflicts! Something likes that,
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 both? Using Visual Studio Code or,
Already in conflicted state?

Exclude from merging

Exclude some files from merge (keep ours),
Exclude some folders (we cannot use git in this case):
  1. If you delete these folders after merging, just commit and later merges will ignore them.
  1. If you meet a conflict, add the folder's name in a file called reset_folders.sh
    1. Each time,

Rename

Squash

Others

Add a description (using Vim editor):
In the case you wanna exit Vim, press <kbd>ESC</kbd> then type :q to quit or :wq to write and quit.

Tags

Cleaning

Clean all history of a repo,

Remove from git

Remove from git, not from system,

Remove all commits and push the current code state

It’s useful if you accidentally added a secret key on the first commit and you want to make everything again.

Discard the changes

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.
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

Restore

Change remote url

Alias

Gitlab: Clone a private repo to local

  1. (Windows) Generate a ssh key ssh-keygen -t rsa -b 4096 -C "[email protected]" in C:\Users\dinha\.ssh under the name id_rsa (for private) and id_rsa.pub for public. It's important, the name!!!!
  1. Open and copy key in C:\Users\dinha\.ssh\id_rsa.pub
  1. Go to Gitlab > Settings > SSH Keys > paste a copied key and name it.
  1. Clone again the repo and it shoule be working!

Errors

Problem with pre-commit? (Cannot removing it?)
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.
☝
To stop Fetching submodule.... when git pull: git config submodule.recurse false!
To update all submodules,

Troubleshooting

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.
◆Installation & Tools◆Rules to be more effective◆Settings on local machine◆Check the status◆Git ignore◆Repositories◆Git GUI◆Staged & Commits & Push & Pull○Staged○Commit & Push○Pull & Fetch◆Branches○Create○Two branches○Comparing○Delete○Merge○Conflict○Exclude from merging○Rename◆Squash○Others◆Tags◆Cleaning○Remove from git○Remove all commits and push the current code state◆Discard the changes◆Restore◆Change remote url◆Alias◆Gitlab: Clone a private repo to local◆Errors◆Git submodules◆Troubleshooting◆Others
About|My sketches |Cooking |Cafe icon Support Thi
💌 [email protected]
1# SET GLOBAL INFO
2git config --global user.name "Anh-Thi DINH"
3git config --global user.email "[email protected]"
1# SPECIFIC REPO
2git config user.name "Thi"
3git config user.email "[email protected]"
1# Verify your configuration
2cat .git/config
1# IF: `Could not resolve host: github.com`
2git config --global --unset http.proxy
3git config --global --unset https.proxy
1# SAVE GITHUB AS DEFAULT
2# (don't need to log in again every time we use)
3git config credential.helper store
4git pull
1# FORMATTING DISPLAY
2git config color.ui true # add colors to the results
3git config format.pretty oneline # display only one line of each commit
1# CHECK STATUS
2git status
3git status -s # modified files
1# Get remote list
2git remote -v
1# WITH COLORS
2git log --oneline --graph --color --all --decorate
3# --graph: draw text-based branches
4# --decorate: display names and tags
1git log -- <file> # check commits containing <file>
2git log --prep='abc' # look for commits containing "abc" in their name
3git log <from>..<to> # display commints from <from> to <to> (commit's id, branch's name,...)
1git log -1
2# something likes HEAD -> <branch-name>
1git diff file_name.abc
1# get the last commit id
2git log --format="%H" -n 1
3# list of files
4git diff-tree --no-commit-id --name-only -r <commit_id>
1# with `--follow`, it works even if the file's name has changed!
2git log --follow -- filename
1# ignore
2.jekyll-cache
3.git
4__pycache__/
1__pycache__/
2
3# ignore all except
4/*
5
6# whitelist
7!.gitignore
8!/docker/
1# add a file/folder to .gitignore
2echo file.txt >> .gitignore
3echo folder >> .gitignore
1# they are assumed to be unchanged
2git update-index --assume-unchanged file_1 file_2
3
4# undo
5git update-index --no-assume-unchanged file_1 file_2
6
7# To get a list of dir's/files that are assume-unchanged
8git ls-files -v|grep '^h'
1# CREATE REPO
2git init <repo-name>
1# CLONE REPO (using https or ssh)
2git clone <repo-link>
1# Example: <https://github.com/dinhanhthi/dinhanhthi.com>
2git clone <https://<token>@github.com/dinhanhthi/dinhanhthi.com>
3# Can be applied to organization's repos.
1git gui
2gitk
1# ADD MODIFICATION (1 FILE)
2git add * # add all the changes
3git add <file-name> # only add the <file-name> to the staged
1# UNSTAGE A FILE
2git reset HEAD <file>
1# UNSTAGED EVERYTHING
2git reset
1# MAKE COMMIT (FROM STAGED)
2git commit -m '<comment-for-this-commit>'
3git commit -a # commit any files
1# UNCOMMIT (back to before commit)
2git reset --soft HEAD~1
1# PUSH TO REMOTE
2git push origin <branch-name> # push only <branch-name>
3git push --all origin # push all branches
1# CHECK & TEST A COMMIT
2git checkout <commit-id>
3# after testing
4git checkout -- . # discard all changes
5git checkout <current-branch> # back to previous
1# Commit current date
2git commit -m "`date`" # Wed Aug 28 10:22:06 CST 2019
3git commit -m "`date +'%Y-%m-%d'`" # 2019-08-28
4git commit -m "Updated: `date +'%Y-%m-%d %H:%M:%S'`" # Updated: 2019-08-28 10:22:06
1# Commit with a custom date (in the pass)
2date -v -6H # 6 hours ago -> Mon Feb 20 11:12:39 CET 2023
3# then
4GIT_AUTHOR_DATE='Mon Feb 20 11:12:39 CET 2023' GIT_COMMITTER_DATE='Mon Feb 20 11:12:39 CET 2023' git commit -m "Commit message"
5
6# In case you wanna use an alias, put below in .zshrc or .bashrc
7git_pass() {
8  GIT_AUTHOR_DATE="$(date -v -$1H)" GIT_COMMITTER_DATE="$(date -v -$1H)" git commit -m "$2"
9}
10# Then run
11git_pass 4 "commit message" # "4" means 4 hours ago!
1# LIST ALL REMOTE REPOS
2git remote -v
1# UPDATE REMOTE -> LOCAL
2git pull origin <branch-on-remote>
1# Pull (fetch) a branch from remote
2git checkout --track origin/<branch>
1# COPY A COPY FROM REMOTE
2git fetch origin <branch-on-remote>
3# compare current branch to this copy
4git diff --stat FETCH_HEAD
1# Just fetch the changes from remote
2# Appliy to the current branch
3git fetch
1# Fetch a branch without checkout
2# (On branch A but wanna fetch/create branch B)
3git fetch origin branch-b:branch-b
1# Pull from remote and replace COMPLETELY local
2# Checkout the branch you wanna replace first
3git reset --hard origin/<branch>
1# CREATE A BRANCH
2git branch <branch-name>
1# CREATE AND MOVE TO NEW BRANCH
2# This one is based on the current `HEAD` (git log -1).
3git checkout -b <new-branch>
4# new branch based on another one
5git checkout -b <new-branch> <existing-branch>
1# Create a independent branch
2# (like git init, without any commit history)
3git checkout --orphan <new-branch>
1# CHANGE TO ANOTHER BRANCH
2git checkout <branch-name>
3
4# fatal: 'dev' could be both a local file and a tracking branch.
5git checkout <branch_name> --
1# UPDATE ALL REMOTE BRANCHES TO LOCAL
2# (there may be deleted branches on remote)
3git remote update origin --prune
1# LIST ALL LOCAL BRANCHES
2git branch
1# LIST ALL LOCAL + REMOTE
2git branch -a
1# compare current branch with other
2git diff <branch>
1# COMPARE 2 BRANCHES
2git diff <source-branch> <compared-branch>
1# a specific file
2git diff mybranch master -- myfile
1# list all diff files: current vs
2git diff --name-status master
1# 2 files vs
2git diff mybranch master --name-status
3# can be "--name-only"
1# LOCAL <-> REMOTE BRANCHES
2git branch -vv
1# save to log file
2git diff --output=log.txt branch_1 branch_2 --name-status
1# CORRESPONDING LOCAL BRANCH <-> REMOTE
2git fetch
3git branch --set-upstream-to=origin/<remote_branch> <local_branch>
1# DEL A LOCAL BRANCH
2git branch -d <branch-name>
3git branch -D <branch> # force to delete
1# DEL A REMOTE BRANCH
2git push origin :<branch-name>
1# merge without commit -> check the conflicted files
2git merge --no-commit <other-branch>
3
4# list only the name of conflict files
5git diff --name-only --diff-filter=U
6
7# then reset if don't wanna merge
8git reset --hard
1# MERGE <branch> TO CURRENT
2git merge <branch>
1# merge + keep current changes
2git merge --strategy-option ours
3
4# merge + keep incoming changes
5git merge --strategy-option theirs
1# MERGE <sub-branch> TO master + REPLACE master
2git checkout <sub-branch>
3git merge -s ours master
4git checkout master
5git merge <sub-branch>
6# master can be other
1# Merge all files in a folder frm another commit
2git checkout <commit> folder/*
1# MERGE `/link/to/abc.xyz` FROM `<branch-1>` TO `<branch-2>` (can be `master`)
2git checkout branch-2
3git checkout branch-1 /link/to/abc.xyz
1# MERGE ONLY SOME FOLDER
2git checkout <branch>
3git checkout <from-branch> folder1\ folder2\
1# MERGE commit from ONE BRANCH to CURRENT
2git cherry-pick <commit hash>
1# KEEP FILES/FOLDERS FROM MERGE
2# add line to .gitattributes
3echo 'file_name.txt merge=ours' >> .gitattributes
1<<<<<< HEAD
2changes on local
3======
4changes from remote
5>>>>>> template/notetheme2
1# keep remote changes
2git pull -X theirs <remote-repo>
1# keep local changes
2git pull -X ours <remote-repo>
1# add below line to .gitattributes (on branch being merged)
2echo "*.whatever merge=union" .gitattributes
3# on windows, remove `""`
1git checkout --theirs path/to/file # remote
2git checkout --ours path/to/file # local
1# Abort the conflicts
2# (go back to before merging)
3git merge --abort
1# ONLY FOR FILES
2# add below line to .gitattributes (on branch being merged)
3echo "file.ext merge=ours" .gitattributes
4# on windows, remove `""`
1#!/bin/sh
2echo 'Reset some only-this-branch folders after merging.'
3git reset folder_1, folder_2
4git checkout .
5git add .
6git commit -m "update from merge (keep local in some folders)"
1git merge <from-branch> && sh reset_folders.sh
1# CURRENT BRANCH
2git branch -m <newname>
3git branch -M <newname> # if there are only capitalization changes
1# CURRENT IS ANOTHER BRANCH
2git branch -m <oldname> <newname>
1# RENAME REMOTE BRANCH (delete old + push new)
2# (rename local branch first)
3git push origin :<oldname> <newname>
4# reset the upstream branch for the new-name local branch
5git checkout <newname>
6git push origin -u <newname>
1# Squash newest 5 commits
2git rebase -i HEAD~5
1git branch --edit-description
1# Listing tags
2git tag
3
4# Delete local tags
5git tag -d <tag_name>
6
7# Delete remote tags
8git push --delete origin <tag_name>
1git checkout --orphan tmp_repo
2git add -A                      # Add all files and commit them
3git commit -am "Clean Repo"
4git branch -D <repo>            # Deletes the <repo> branch on remote
5git branch -m <repo>            # Rename the current branch to <repo>
6git push -f origin <repo>       # Force push branch <repo> to github
1# a file
2git rm --cached <file_name>
1# a folder
2git rm -r --cached <folder>
1# Remove all git history
2rm -rf .git
3
4# Initialize fresh repository
5git init
6
7# Add all files
8git add .
9
10# Make initial commit
11git commit -m "Initial commit"
12
13# Add remote (replace with your repo URL)
14git remote add origin https://github.com/username/repo.git
15
16# Force push to overwrite remote history
17git push -u origin main --force
1# DISCARD CHANGES ON CURRENT DIR
2git checkout -- . # for all changes
3git checkout -- <file-name> # for a specific file (go back the last commit of this file)
1# DISCARD ALL LOCAL CHANGES
2git reset --hard
1# Get back to some prev commit and ignore all the changes (including the commits)
2git reset --hard <commit-id>
1git stash
1git stash pop
1# RESTORE FROM LAST COMMIT
2git checkout -- <file>
1# Revert single file to a commit
2git checkout <commit> -- <file>
1# DISCARD ALL CHANGES ON LOCAL + GET FROM REMOTE
2git fetch origin
3git reset --hard origin/master
1# DISCARD ALL CHANGES + get the last update from remote
2git reset --hard @{u}
1# EREASE ALL COMMITS + BACK TO <commit-id>
2git reset --hard <commit_id>
3# (force) to push
4git push -f origin master
1# check the current remote url
2cat .git/config| grep "url"
3
4# change to the new one
5git remote set-url origin new.git.url/here
1# use `git br` instead of `git branch`
2git config alias.br branch
1rm .git/hooks/pre-commit
2# use sudo if needed
1# error: invalid object Error building trees
2git hash-object -w <error-file>
1# "git clone" & "git pull" to automatically update submodules.
2git config --global submodule.recurse true
3
4# public repo: github.com/you/blog (clone)
5# private repo: github.com/you/posts
6
7cd blog
8git submodule add <https://github.com/you/posts> # blog/posts
1# If this is the 1st time you checkout the repo
2git submodule update --init --recursive
3
4# Update submodules
5git submodule update --recursive --remote
6# Don't make change on the folder of submodules!!!!
1# clone a repo with submodules
2git clone <repo> --recursive
3# or
4git clone <repo>
5git submodule init
6git submodule update
1# REMOVE a submodule (suppose that it's in a/)
2# Make a copy (just in case)
30. mv a/submodule a/submodule_tmp
41. git submodule deinit -f -- a/submodule
52. rm -rf .git/modules/a/submodule
63. git rm -f a/submodule
7# Note: a/submodule (no trailing slash)
84. git rm --cached a/submodule