Since my early days with Git (2015?), I carried with me a private journal where I'd take note of the most unique git commands I had to use at some point.
Today I'm making this journal public (with some re-touches), hoping it helps someone else. π€
Disclaimer: If you are not familiar, here's a friendly video intro to Git.
However, most of the flows in this journal are not quite "beginner"...
Nevertheless, feel free to ask questions, suggest different approaches, or simply tell me which command helped you! :)
Entries
- 1. Git configuration
- 2.1. Change commits author/email
- 2.2. Change commits author/email - chapter 2
- 3. Cleanup local branches
- 4. Pretty Commit logs
- 5. Renaming case sensitive files
- 6. Override a file with another branch
- 7. Override a branch with another branch
- 8. Quicker amend
- 9. Checkout a PR from a forked branch
- 10. Convert a PR branch with merge commits to a clean rebased git history
- 11. Different git configs based on path location
- 12. Restart SSH Agent
- 13. Include another repo into your local repo
1. Git configuration
Problem: I need to use different git accounts for different projects. To ensure the correct account is being used, you need to setup it:
# Setting the account globally for all the projects...
git config --global user.name "your-username"
git config --global user.email "name@email.com"
# ... or just to a specific project
# (you need to be in the git project folder)
git config --local user.name "your-username"
git config --local user.email "name@email.com"
2.1. Change commits author/email
Problem: I mistakenly used the wrong e-mail on my last commit. I need to change it to a different author
git commit --amend --reset-author
2.2. Change commits author/email - chapter 2
Problem: I realized I had multiple commits with the wrong e-mail. This magical command made the trick:
git filter-branch --commit-filter 'if [ "$GIT_AUTHOR_EMAIL" = "old-author@email.com" ];
then
export GIT_COMMITTER_NAME="New Author Name";
export GIT_COMMITTER_EMAIL=new-author@email.com;
export GIT_AUTHOR_NAME="New Author Name";
export GIT_AUTHOR_EMAIL=new-author@email.com;
fi; git commit-tree "$@"'
3. Cleanup local branches
Problem: When doing git branch
, I had a lot of local old branches. I wanted to delete them all.
# delete all branches expect master
git branch | grep -v "master" | xargs git branch -D
or
# Delete all merged branches except the current one
git branch --merged | grep -v '*' | xargs git branch -D
4. Pretty Commit logs
Problem: The output of git log
is ugly and unreadable. I want something more friendly.
# Add this to your global .gitconfig
[alias]
lg = log --graph --pretty='format:%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
Now I only use git lg
. The logs are much readable, specially to understand the git history and merged branches.
5. Renaming case sensitive files
Problem: On Mac, I needed to rename a file already pushed, eg Hello.js
-> hello.js
. Doing a traditional manual rename does not work on MacOS. Solution:
git mv -f path/to/Hello.js path/to/hello.js
6. Override a file with another branch
Problem: I've changed a file by mistake (it was the devil package-lock.json
) and wanted to revert it and be the same as in the master
branch.
git checkout master package-lock.json
The file is now how it was, then you just need to commit it again.
7. Override a branch with another branch
Problem: I needed to make branch B look like branch A.
# push branch-a code into branch-b (forced)
git push origin branch-a:branch-b -f
Note in 2021: I don't remember why I did this. Today I do this in a different way:
# checkout branch-a
git checkout branch-a
# push its code to branch-b (forced)
git push origin branch-b -f
8. Quicker amend
Problem: I do amend my commits, very often. I wanted a faster way to do it.
# your global .gitconfig
[alias]
sneak = commit --amend --no-edit
# amend a commit right away without being prompt to edit the commit message.
git sneak
P.S. I remember stealing this from a Tweet, but can't remember who. :/
9. Checkout a PR from a forked branch
Problem: I needed to checkout someone's else PR that was created from a forked repo. My local repo was a fork too.
- 1. Add the original repo to your fork .git/.gitconfig file
[remote "upstream"]
url = https://github.com/author/original-repo-name.git
fetch = +refs/heads/*:refs/remotes/upstream/*
- 2. Add this 3 magic alias to your global .gitconfig.
[alias]
# Checkout a PR
pr = "!f() { git fetch -fu ${2:-upstream} refs/pull/$1/head:pr/$1 && git checkout pr/$1; }; f"
pr-clean = "!git checkout master ; git for-each-ref refs/heads/pr/* --format=\"%(refname)\" | while read ref ; do branch=${ref#refs/heads/} ; git branch -D $branch ; done && git branch -D pr"
pr-id = "!f() { git fetch upstream pull/\"$1\"/head:pr && git checkout pr; }; f"
- 3. Use this git alias to checkout new PR by id.
git pr-id 781 # 781 is the PR id.
# to pull the new commits, run the following:
git pr-clean && git pr-id 781
10. Convert a PR branch with merge commits to a clean rebased git history
Problem: I had a PR branch full of commits and merge commits. I wanted to merge it without squashing the commits, but keeping a clean git history. (without the merge commits).
Flow summary: Create a new branch that contains the diffs. Use that branch to reset my PR branch, rewriting the commit history.
# - 0. Safety guard: Create a backup of your feature branch just in case things go wrong.
git checkout -b your-branch--backup
# - 1. Get the diffs between your `feature-branch` and `master`.
## 1.1 go to master and pull the latest version
git checkout master && git fetch
## 1.2 get the diffs between master and your branch
git merge --squash origin/your-branch
# The files were modified to look like `your-branch`.
# verify it by yourself in your code editor...
# - 2. Create a new branch with these diffs
git checkout -b your-branch--clean
# - 3. Commit the changes to the new branch.
# You can do it in a single commit or multiple commits.
## This commits all the changes at once
git add . && git commit -m "The new code"
# - 4. Rewrite `your-branch` to match the `your-branch--clean`,
# cleaning all the messy git history
## 4.1 go to your original branch...
git checkout your-branch
## 4.2 ... and rewrite it to be exactly like the cleaned branch
git reset --hard origin/your-branch--clean
# - 5. That's it! Everything should work as before,
# but now with a clean commit history.
# Give it a final check. If all good, push it!
gift push -f
Go to your PR again. It should look exactly the same:
- Same nΒΊ of files changed
- Same nΒΊ of diffs added/removed. But now the commits history is clean now! β¨
P.S. If something went wrong, use the backup branch created at the beginning to start over.
11. Different git configs based on path location
Problem: I had different git configs for multiple projects - for example, different pull config and different users. I needed a better solution than creating multiple local configs per project.
Reference: Conditional git configs
- 1. Create a gift config per configuration:
.gitconfig
.gitconfig-configA
.gitconfig-configB
# .gitconfig
[includeIf "gitdir:~/Documents/git/folderA/"]
path = .gitconfig-configA
[includeIf "gitdir:~/Documents/git/folderB/"]
path = .gitconfig-configB
[core]
excludesfile = /Users/your-pc-name/.gitignore
[alias]
lg = log --....
# other alias common to everyone...
# .gitconfig-configA.
# project under folderA use userA and pull ff
[user]
name = Your Name A
email = your-name-a@email.com
[pull]
ff = only
# .gitconfig-configB
# projects under folderB use userB and pull rebase
[user]
name = Your Name B
email = your-name-b@email.com
[pull]
rebase = true
12. Restart SSH Agent
Problem: My MacOS (Catalina 10.15.7) does not load correctly all my SSH keys (from different accounts), preventing me from pulling repos with SSH.
Imagine I have a SSH key git@github.com-eagle
configured.
# The eagle SSH is list properly in pub key...
cat ~/.ssh/*.pub
# But does not show up in the SSH list...
ssh-add -L
The solution is to restart SSH agent to make it work again.
eval "$(ssh-agent -s)"
# it will output a number (eg 00123). Use it in the next command
kill -9 00123
# finally, verify the SSH connection again.
ssh git@github.com-eagle
# Output: "Hi eagle! You've successfully authenticated"
Reference: Stackoverflow - how to restart ssh-agent
13. Include another repo into your local repo
Problem: As part of the hiring process (me as the interviewer), I review multiple code exercises submitted through a repo. These repos are a copy of a template repo.
To review each exercise repo, instead of cloning them, over and over again, I add them locally to the base template repo.
# You can give any unique name to the remote repo. eg "bunny"
# add the repo and checkout its main branch
git remote add bunny https://github.com/author/reponame.git
git fetch bunny
git checkout bunny main
The advantages of remote add
over clone
:
- Cleaner: Keep my computer cleaner without all the similar folders.
- Faster: No need to
npm i
each repo because the dependencies are already there (based on the main branch) - Easy to compare: It's easier to compare the exercise to the expect result with some other git commands because it's the same codebase.
That's all for now! (2021 August 14th)
Next time I face a problem, I'll update this journal with a new entry :)
Top comments (1)
waaow. you are good