Git tricks
I forget adding recursive when cloning
git submodule update --init --recursive
add more things to the last commit (amend)
# add the modifications
git add *
# amend
git commit --amend --no-edit
# this will also allow you to change the commit message
git commit --amend
you can also fully revert the commit and commit again
git reset --hard HEAD~1
undo/reset anything using reflog
git reflog
keeps track of all your git commands, which is very useful to undo/redo.
git reflog
# output is like:
# c4ddb13 (HEAD -> master, origin/master, origin/HEAD) HEAD@{0}: pull: Fast-forward
# b9a8d4f HEAD@{1}: pull: Fast-forward
# 040fa10 HEAD@{2}: pull: Fast-forward
Notation:
HEAD
is the current state.HEAD~<n>
means the n-th ancestor of HEAD (back trace through commit history/graph)HEAD@{n}
means the n-th history command throughreflog
(it's different from ancestor!)
After finding the aimed commit, we can reset by:
# soft: revert commits (but changes are still staged, i.e., after `git add`)
git reset --soft <commit>
# mixed: revert commits and unstage changes.
git reset --mixed <commit>
# hard: revert commits, undo changes. Your branch will be the same as <commit> again.
git reset --hard <commit>
command line diff
If you cannot use VS Code or Github.
# see changes (before git add)
git diff
# after git add
git diff --staged
checkout a history commit, and also update all submodules to the corresponding commits
git log # find your commit
git log --reverse # old-to-new history
git checkout <hash> # only checkout main repo
git submodule update --recursive # checkout all submodules too.
force git pull
# reset all changes
git reset --hard HEAD
# WARN: this delete all untracked files & dirs.
# git clean -f -d -n # dry-run
git clean -f -d
# pull
git pull
remove a large file wrongly committed and left in git history
large file, even if removed in current branch, will be left in history and every clone suffers from it.
The best choice is never to upload any, but if you have committed, this will save you:
# FOLDERNAME is what you want to remove from ALL history
git filter-branch -f --index-filter "git rm -rf --cached --ignore-unmatch FOLDERNAME" -- --all
# further clean
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now
# push to remote
git push --all --force
embed mp4 in readme.md (github only)
You just edit the markdown file in github webpage, drag and drop your mp4 video to it, and it will work.
It only writes a URL into your markdown, but github will render it as a video:
**A GUI for training/visualizing NeRF is also available!**
https://user-images.githubusercontent.com/25863658/155265815-c608254f-2f00-4664-a39d-e00eae51ca59.mp4
manage remote repo url
# change remote origin
git remote set-url origin [new_repo_url]
# or you can add it as another remote
git remote set-url origin2 [new_repo_url]
git push -u origin2 main
un-ignore specific files
say you want to exclude everything in datasets/
except datasets/splits/*
.`
#datasets # this will not work!
datasets/* # the /* matters!
!datasets/splits/
use ssh for git command (avoid permission denied error)
You need to generate a SSH key for your machine and add it to github.
cd ~/.ssh
ssh-keygen -t ecdsa -b 521 -C "your_email@example.com"
cat id_ecdsa.pub
Then copy the public key and add it in https://github.com/settings/keys
Now you should be able to clone through ssh!
fetch branch from a forked repo without clone
git remote add theirusername https://github.com/theirusername/reponame
git fetch theirusername
git checkout -b mynamefortheirbranch theirusername/theirbranch
multiple accounts in the same shell
This happens when you want to switch to another github/gitlab account for a specific repo:
- Set local user name and email:
git config --local user.email "subaccount@gmail.com"
git config --local user.name subaccount
- Normally init repo and commit.
- Set remote URL in this format (add
USERNAME@
before github.com!)
git remote set-url origin https://USERNAME@github.com/USERNAME/PROJECTNAME.git
- Create a PAT through web client. (Settings > developer settings > personal access tokens)
- Push, enter your PAT through the GUI.
art of merge request
In a collaborated project where you need to work on your branch, but keep updated with the main branch:
# create your branch from main
git checkout -b mybranch
# work on your branch and commits... maybe also push to your remote branch.
# now you want to merge to main, but other people also merged many things already.
# fetch remote changes
git fetch origin
# rebase (replay) your changes to origin/main (ours are incoming)
git rebase origin/main
# or origin/main's changes into your code (they are incoming), sometimes this is easier
git merge origin/main
# now your commits and other people's commits are both applied, but this has diverged from your remote branch since rebase will add other people's commits (if you have pushed before), so you need to force update your remote branch
git push origin --force
You may want to squash your commits before rebasing:
# reset to that earliest+1 commit you want to squash
git reset --soft HEAD~3 # go back 3 commit from head (will squash HEAD, HEAD~, HEAD~2)
git reset --soft <commit id> # will squash commits AFTER this commit
# now simply commit all changes
git commit -m 'squash!'
Another case is that you are working on a branch and submitted MR to origin/main, which is squash-merged later, but you are still working on the same branch with some new commits. (The best practice is not to work on the same branch until its MR is merged, but sometimes this does happen...)
Now the origin/main's commit history has diverged from your branch (as it contains only some of your commits but squashed). To fix this:
# sync local main first
git checkout main
git fetch origin
git pull
# create a new branch for MR
git checkout -b mr_branch
# merge your old branch to it
git merge old_branch
# now mr_branch contains exactly one commit from origin/main with your new commits squashed. we can submit MR with this branch now!
pushed a branch with wrong name
We need to create a new branch with correct name, delete the old branch and push new branch again.
# rename (move) local branch
git branch -m <correct_name>
# push it to remote
git push origin -u <correct_name>
# delete a remote branch.
git push origin --delete <wrong_name>
# delete a local branch.
git branch -d <wrong_name>
merge part of your changes to main
This is not easy, especially if these changes are in many different commits, and between them you have commits that you do not want to merge to main.
We need to wipe the commit history and re-commit those needed changes:
# create new branch from current branch
git checkout -b mybranch_to_merge
# make sure you have synced all changes from origin/main !!!
# if this is impossible, at least fetch them
# mixed reset to origin/main
git reset --mixed origin/main
# now you see all the changes you have done, all unstaged.
# add back those changes you want to merge, and commit
# push to remote and create MR
# if you have unmerged changes from origin/main, you may want to undo those changes
git checkout <file/folder>