Prologue
I started my open source journey few weeks back. Took a beginner friendly issue, contributed it, created a PR in couple of days. Everything was going great, all tests cases passed. Felt good!
But the ignorant me, forgot to set the git config
properly on my local, and what’s rolled after made me question my developer journey.
Two weeks passed since I raised the PR, the maintainer asked me to sign those commits. It seemed easy at first (referred stackoverflow, ChatGPT, etc.): use rebase
, amend
and then --continue
my way through all the commits. Guess what! All lead to lots of merge conflicts and many lots of reset
ting my rebase commits.
This blog is a documentation to all those commands that made this task easy for me, with a little bit showcase of my frustration throughout this journey!
Level 0: What the heck is gpg
?
Before moving forward to original commands, let’s understand what actually gpg is? The first time ChatGPT suggested to setup gpg, I ignored it.
I thought just adding user
and email
to git config
will make my life easier. But gpg seemed to be an important thing while signing commits.
GPG
stands for Gnu Privacy Guard
. It allows one to encrypt and decrypt things using public private key.
Basically:
- You generate a private and public key
- You create a password
- Private key stays with yourself and public key you add it to github
- Everytime you try to sign a commit, gpg will ask for password and use the keys to sign the commits.
It’s basically saying - the one who did this commit is Barun Debnath
and here is kinda proof of his identity!
Enough with the theoretical stuffs, let’s create a gpg key pair!
Step 1: Install GPG
- For macOS:
brew install gpg
- For Linux
sudo apt install gpg
Step 2: Generate GPG key
gpg --full-generate-key
- Follow the prompts to create your key. Note: Use strong password.
- To retrieve your GPG key ID:
gpg --list-secret-keys --keyid-format=long
- Look for the line starting with sec, and note the 16 character hexadecimal string which is your key ID.
Step 3: Configure Git
git config --global user.signingkey YOUR_KEY_ID
git config --global commit.gpgsign true
- remove
--global
to only add the gpg key at repo level - to remove gpg sign for any repo, run:
git config --global commit.gpgsign false
Step 4: Add GPG public key to Github
- Export the public key by running:
gpg --armor --export YOUR_KEY_ID
- Copy the output
- navigate to
Github GPG Keys Settings
- Click on
New GPG Key
- Add the copied public key
- navigate to
Level 1: Finally got the right git
commands to work
Enough with gpg
, let’s move to the main web of chaos - git
Git can make developers life easy as well as hard if not done correctly!
Let’s be honest, we all had tried closing/deleting a PR if it gets complicated due to merge conflict or similar issue, and raise a new fresh PR. Even if you are THE 100X CODER
who will create AGI and bring the doom of the world, 99% of chance is there you have done it.
But this approach is only good for personal projects, or somewhat in low priority projects/orgs. But in OSS contributions or in your full time work, this doesn’t leave a good impression.
Real git skills can make your (or atleast it did mine) life easier than it had been. Enough chitchat, let’s get into the commands.
Step 1: Configure git to use correct Author Information
- The very first step here will be to configure correct author name and email
git config --global user.name "Barun Debnath"
git config --global user.name "[email protected]"
- Remove
--global
if you are setting config for current repo only.
Step 2: Use interactive Rebase to Modify Past Commits
-
Interactive Rebase will help you to choose what commits you want to edit and what to skip.
-
If not done correctly, can shake your entire commit history or result into merge conflicts which your three generations won’t be able to solve!
Very first step is to determine the number of commits to modify. Let’s say you want to modify the last 3 commits:
git rebase -i HEAD~3
Step 3: Mark the commits for editing
- In the editor, change
pick
toedit
for the commits that you want to modify - e.g.
edit abc123 Commit message 1
edit def456 Commit message 2
edit ghi789 Commit message 3
Step 4: Amend each commit
- For each commit which you marked to edit, Git will pause so that you can run
amend
. git commit --amend
takes the commit and add the new staged changes to it. The changes also includes, editing commit messages and signing information.
git commit --amend --author="Your Correct Name <[email protected]>" --no-edit
git rebase --continue
- Repeat the process for each commit.
- Two important rebase subcommands to keep handy:
git rebase --skip
: completely skip the commitgit rebase --abort
: completely undo the rebase
Step 5: Force push the updated history
- Force push the changes to remote repository
git push --force
Level 2: Undo your mistakes
It might happen that you want to reset the rebased commits that you did in the previous step. Well worry not! Git already have the solution developed for noob developers like us.
-
git reflog
- Record when the tips of branches and other references were updated in local repository -
git reset
- Rewind history without changing the contents of your local files
First view the reflog for the current branch:
git reflog show origin/<branch-name>
- output will be like this
0265956 HEAD@{0}: push: updated to 0265956
5be59e3 HEAD@{1}: push: updated to 5be59e3
- Let’s say you want to restore
5be59e3
. Run:
git checkout <branch-name>
git reset --hard 5be59e3
- Force push the reset branch:
git push origin <branch-name> --force
Level 3: More Git
: Why not?
Now we are almost near the end of this blog. So let’s get to know more about less know + widely used git commands.
git push --force-with-lease
- safer alternative to--force
- This makes sure that you don’t overwrite other’s work
- Update branch with
main/master
A. Using merge
- safe and keeps the history
git checkout <branch>
git fetch origin
git merge origin/main
B. Using rebase
- clean history but rewrite commits
git checkout <branch>
git fetch origin
git rebase origin/main
May The Git Be With You!
In this blog, I only touched tip of the iceberg of Git
. It’s okay to not know Git like you know your JS or Go syntax (or C++ standard libraries), but it’s not okay to take Git lightly.
Its better to learn a little bit of Git now and then then to enter a never ending Merge Conflict Hell
.