Git

How to fix common git mistakes

Paul CcariPaul Ccari
January 10, 20219 min read

Photo by Karolina Grabowska on Pexels

We all feel intimidating at first when we start working with git since we are afraid to break something but here I will show you how to fix them.

  • Change a commit message that hasn't been pushed yet
git commit --amend -m "New message"
  • Add more files and changes to commit before pushing
# add files to the staging area
git add -A

#rewrite the most recent commit
git commit --amend -m "My new message"
  • Remove files from staging before committing
# specific filename
git reset HEAD filename

# all files that has been added to the staging area
git reset
  • Remove changes from commit before pushing
# go to head and then back on the tree 1
git reset HEAD~1

# undo the commit before the hash
git reset [HASH]

git revert --no-commit HEAD~3..
  • Use and compare the different git reset options: —hard, —soft, —mixed
# moving back to the staging area from committment
git reset --soft HEAD~1

# moving back to the working directory (DEFAULT)
git reset --mixed HEAD~1

# Get rid of the commit, unstaged the changes and removed from the working directory
git reset --hard HEAD~1
  • Recover local changes from 'git reset —hard' with 'git reflog'
# it saves commits but only if they havent been gargabe collected by git
git reflog

# recover from the ref log
git reset --hard [hash]
  • Undo a commit that has already been pushed
# create a new commit where all things changed will be reverted
# revert the commit you want
git revert [HASH-TO-UNDO]
  • Push a new branch to Github that doesn't exist remotely yet
# create a new branch and switch to it
git checkout -b 'new-branch'

# current commit that we're on for each branch and see the remote
git branch -vv

# push the branch
git push -u origin new-branch
  • Copy a commit from one branch to another
# Copy a commit from a branch to another
git cherry-pick [HASH-COMMIT-TO-MOVE]
  • Move a commit that was committed on the wrong branch
# use cherry pick to copy the commit to the right branch
git cherry-pick [HASH_TO_COPY]

# remove that commit from the wrong branch (go back to working directory)
git reset HEAD~1

# will reset the file to whatever it is at the bash that we reset to
git checkout [file-name]
  • Use git stash to save local changes while pulling
# stash the local changes
git stash

# pop & apply kind of similar
# pop will throws away after apply the changes
git stash pop

# whereas git stash apply leaves it in the stash list for possible later reuse
# (or you can then git stash drop it).
git stash apply

# drop the change from the stash
git stash drop stash@{0}
  • Explore old commits with a detached HEAD, and then recover
# back to an old commit and we'll be in a detached HEAD state
# detached HEAD means that HEAD is not pointing to a branch
git checkout [HASH]

# now, we need to make a new branch from where we at and everything should be OK
git checkout -b my-new-branch
git switch -c my-new-branch
  • Fix a Pull request that has a merge conflict
# try to merge it locally first
git merge master

# resolve conflicts and commit
git commit -m 'fixed conflicts'

# push it and make the PR
git push
  • Cleanup and delete branches after a pull request
# After merging, we can delete branch from github
git branch -vv
git log --oneline --graph

# branches are just pointer to commits
# so we can safely delete branches without losing the underlying commits

# lists branches that can be deleted/pruned on your local.
git remote prune origin --dry-run

# cleanup locally remote branch
git remote prune origin
# will show: [branch-name: gone]

# delete it locally
git branch -d branch-name
  • Change the commit message of a previous commit with interactive rebase

Note: you shouldn't try to do this on commits that have already been pushed - only commits you still have locally

# start the interactive rebase
git rebase -i HEAD~3

# change pick to reword, then we can reword the commit message
# press i to insert mode in vim
# then will show the commit message to edit
# change and save, and quit vim
  • Git ignore a file that has already been committed and pushed
# we pushed an env file and didnt add a gitignore
# so we create gitignore and added .env
# thats not enough because the envfile will be still be on the branch on github

# first, we remove all of our files from our git cache with
git rm -r --cached

# add back all the files we want (env file will be exclude because of gitignore)
git add -A

# the commit that change and push it
git commit -m 'remove env from remote' && git push

IMPORTANT! If you have secrets in a file that you remove in this way, you should still consider those secrets compromised, because anyone could have pulled them already - and they are also still in the git history.

  • Add a file to a previous commit with interactive rebase
# pick a previous commit and enter an interactive rebase
git rebase -i HEAD~2

# change pick to edit on the commit where we want to add a file
# then you can create the files and add, commit (with same message commit)
git commit --amend --no-edit

# to finish the interactive rebase
git rebase --continue
  • Fix merge conflicts while changing commits during an interactive rebase
# use git rebase to back 2 commits
git rebase -i HEAD~2

# change pick to edit on the commit where we want to make changes
# then we add, and commit it without change the message
git commit --amend --no-edit

# now to finish
git rebase --continue # this wont work since the file has been changed later

# now we'll get into a merge conflict during rebase
# so we have to clean this up manually
# fix conflicts and add, commit
git commit -m "Merge rebase changes 2 into changes 3"

# now we can finish
git rebase --continue

Squash commits before they are pushed with interactive rebase

# We have created 3 commits that we want to squash together before we push them
git rebase -i HEAD~3

# change pick to squash for the last 2 commits
# (we want to squash down into the first one)

# then we'll be given the chance to make the commit message for that commit
  • Completely remove a file from pushed git history

    If we want to completely remove a file from github - including all history - there is a tool that we can use called the BFG.

    The github help article is here:

    https://help.github.com/en/github/authenticating-to-github/removing-sensitive-data-from-a-repository

    And the BGF itself is available here:

    https://rtyley.github.io/bfg-repo-cleaner/

    We'll start by downloading the BFG jar file, and then cloning a mirror of our repo with:

    git clone --mirror [repo-url]

    Then we can delete our .env file with:

    java -jar ~/Downloads/bfg-1.13.0.jar --delete-files .env my-repo.git

    which will delete the .env file. Then we can use the following command to prune the entire history and garbage collect the remains:

    git reflog expire --expire=now --all && git gc --prune=now --aggressive

    And finally, use git push to push that change to github, and remove the .env file from all of the history on github as well. -->

  • How to rebase squashing commits in the original branch

# go to the branch you want to rebase
git checkout branch0

# You need the hash that's been created when its squashed and
# last hash commit ( A -> B -> `C` )  => squash => ( `B` )
# you need the B hash (squash commit)
# and the the C hash, the last hash that's been squashed

git rebase --onto [hash commit squash commit] [last hash commit squashed]

How to rebase after squashing commits in the original branch?

  • How to rebase local branch with remote master
# First fetch the new master from the upstream repository, then rebase your work branch on that:
git fetch origin            # Updates origin/master
git rebase origin/master    # Rebases current branch onto origin/master

#other way
git pull --rebase origin master

How to rebase local branch with remote master

  • Rename local and remote branch
# Rename the local branch to the new name
git branch -m <old_name> <new_name>

# Delete the old branch on remote - where <remote> is, for example, origin
git push <remote> --delete <old_name>

# Or shorter way to delete remote branch [:]
git push <remote> :<old_name>

# Prevent git from using the old name when pushing in the next step.
# Otherwise, git will use the old upstream name instead of <new_name>.
git branch --unset-upstream <old_name>

# Push the new branch to remote
git push <remote> <new_name>

# Reset the upstream branch for the new_name local branch
git push <remote> -u <new_name>

Skip the hook husky post-checkout

I'm spreading this information around as it's super useful:

As of v2.4.0 you can now do HUSKY_SKIP_HOOKS=1 git <command> ...

Site designed & coded by Paul Ccari using React + TypeScript + TailwindCSS + MDX + Nextjs.

Lets Talk!

I am always open to collaborate, build cool stuff, or help with coding challenges. Feel free to drop an “Hi or Hola” back, or just writing me a tweet, or sending me an email.

Plus, you can follow me onFrontendUIwhere I keep creating content about front-end stuff.

@ Paul Ccari, 2021. All Rights Reserved.

Portfolio made with inPeru.