DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’» is a community of 968,547 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Create account Log in
Jennie
Jennie

Posted on • Updated on

Git productive - helpful commands and VSCode tips to get things done fast

One day I saw this tweet:

It brought me back to several years ago when I just start using git every day, and I haven't understood what's the difference between rebasing and merging yet, my dear team-mate typed CLI commands like being possessed by the flash, got things done in just a few seconds. Before I could even see what happened, he cleared the screen (he got OCD on that LOL). That's the moment I started to realize GUI may not always be faster and easier than CLI.

So here, I would like to share some tips that work really well for me. The tips contain:

  • git commands - you may always get more details via git --help
  • Oh-my-zsh alias - Oh-my-zsh does not only provide fancy terminal UI, it also presets commonly used command shortcuts. I only used a small part that I feel very intuitive and easy to remember.
  • VSCode extensions

Preparing to work

Cloning a remote repository to the local environment

Most of time I just copy and paste the hint given by websites to the terminal:

Or simply typing

git clone <git_url> [destination]
Enter fullscreen mode Exit fullscreen mode

With Oh-my-zsh, could even make it shorter to gcl Which also includes an option to recursively clone the submodules of the repository.

But my favorite now is using the VSCode git command, so after clone, it could help me to open the project right away and start my work:

  1. command + shift + p in Mac or ctrl + shift + p in windows to open command palette, and type git to find Git: Clone

VSCode command platte - git clone

  1. Enter the repository URL

VSCode command platte - git clone

Or just use the awesome "Clone from Github" to select GitHub repository:

VSCode command palette - git clone from Github

  1. Choose destination:

VSCode command platte - git clone

  1. And clone

VSCode command platte - git clone

  1. Once finished, it will ask for opening the repo:

VSCode command palette - git clone

Checking out a specific branch

I usually check out my own branch or the main branches with Oh-my-zsh alias

gco <branch>
Enter fullscreen mode Exit fullscreen mode

With the help of the tab key to auto-complete. The original command is:

git checkout <branch>
Enter fullscreen mode Exit fullscreen mode

But when it comes to other people's branches, it is not that effective. And again, the VSCode git extension saved me with a nice branch selection on the status bar:
VSCode status bar - switch git branch

VSCode status bar - switch git branch

Checking out a new branch

Checking out a new branch just need to add a -b option:

git checkout -b <branch>
// In Oh-my-zsh:
gco -b <branch>
Enter fullscreen mode Exit fullscreen mode

Renaming a branch

Sometimes I found my branch name has a typo or got a better idea of the name before I pushing it to the remote. Then I will do

git branch -m <new_branch_name>
// In Oh-my-zsh:
gb -m <new_branch_name>
Enter fullscreen mode Exit fullscreen mode

Checking branch status

For existing branches that have been pushed to remote before, it's a good habit to check the status of it after a while, in case someone else has pushed a new thing to the branch, or myself pushed something on my home laptop but forgot to update the work laptop to the latest version.
Here is the command:

git fetch
git status
Enter fullscreen mode Exit fullscreen mode

In Oh-my-zsh:

gf
gst
Enter fullscreen mode Exit fullscreen mode

And it will log something like:

Branch is not up to date

Sometimes this is not clear enough, then I will check the git history. And the basic log could satisfy this for most of the time:

git log
Enter fullscreen mode Exit fullscreen mode

This command provides a lot of interesting options (quite complicated to remember honestly), like --stat to show simple file diffs, --graph to draw a commit graph, --oneline to show only one line for each commits... Well, adding these will become too long to type, so I prefer to use Oh-my-zsh alias:

glg // git log --stat
glgg // git log --graph
glo // git log --oneline --decorate
Enter fullscreen mode Exit fullscreen mode

Keeping branch up to date

If my local branch hasn't had any changes yet, and the git status notifies me there are some new commits in the remote branch like this:
Branch is not up to date

Then just do:

git pull
// In oh-my-zsh
gl
Enter fullscreen mode Exit fullscreen mode

To update the local branch.

If there are some new changes in the local branch, then things will be a little complicated. Well, let's discuss later in the "Resolving conflicts" section.

Finishing and committing the changes

Verifying the changes

Before I commit the changes, I love to double-check my changes in case I commit some testing code (e.g. console logs) that I forgot to remove. And the VSCode built-in git diff is really helpful here:
VSCode built-in source control

Committing the changes

After verification, I may stage the files that I would like to commit at the same time:
VSCode source control - stage file

And enter a proper message in the textbox, click the "tick" button to commit.

However, this may easily fail thanks to the commit hooks(linting configured with husky) without an intuitive error message display(Actually the output is available in the "OUTPUT" console, but the format is simplified and not that readable). So I often like to commit in the terminal instead:

git commit -m 'My commit message'
// In Oh-my-zsh
gc -m 'My commit message'
Enter fullscreen mode Exit fullscreen mode

Or simply add all changes and commit together:

git commit -am 'My commit message'
// In Oh-my-zsh
gc -am 'My commit message'
// Or
gcam 'My commit message'
Enter fullscreen mode Exit fullscreen mode

Note that the -a option will not include the newly created untracked files. So I will need to do this instead sometimes:

// Add all files under the current folder:
git add .
// In Oh-my-zsh:
ga .

// Or just want to add all not ignored files in the repo:
git add --all
// In Oh-my-zsh:
gaa
Enter fullscreen mode Exit fullscreen mode

Fixing the commit msg

Like my branch naming, I may found some typo in my commit message, or missed some files in my commit. Then I will add the file changes in and do:

git commit --am
// In Oh-my-zsh
gc --am
Enter fullscreen mode Exit fullscreen mode

Push the changes to remote

If the branch is new and never set the remote upstream, it's better to:

git push -u origin <branch_name>
// In Oh-my-zsh:
gpsup
Enter fullscreen mode Exit fullscreen mode

So I could track branch status like I mentioned in "Keeping branch up to date" section. And next time I will not need to assign the upstream name anymore, just do:

git push
// In Oh-my-zsh:
gp
// or 
ggp
Enter fullscreen mode Exit fullscreen mode

Resolving the conflicts

Rebase is my first choice

rebase is always my first choice of few commits differences. So it will help to make sure my changes are newer than the latest source branch.

git rebase

To rebase my upstream branch, can use git pull:

git pull --rebase
// In Oh-my-zsh:
ggu
Enter fullscreen mode Exit fullscreen mode

Or more often, rebase on the main branch like this:

git rebase origin/master
// In Oh-my-zsh:
grb origin/master
// Or
grbm
Enter fullscreen mode Exit fullscreen mode

Adding upstream name there will ensure git to fetch remote updates first and then do the rebase, making sure rebasing on the latest commit.

Squashing commits before rebasing or merging

Sometimes I made many commits during the development but they are too small to be kept in the main branch, or I changed one part of code back and forth to improve it. And these small commits cause me quite some trouble to rebase the main branch. In this scenario, I may consider squash the commits before resolving conflicts.

If all the commits are mine and I just want to simply squash all commits into 1, I will:

  1. Check how many commits in my merge request (e.g. this) or from my git log (refer to Checking branch status section)
  2. git reset --soft HEAD~<commit_count> or git reset --soft <commit_SHA>(The commit SHA here shall be the last commit to keep) to remove those commits and put the changes back to uncommitted status - NOTE that resetting a merge commit will reset all the commits in that merge together
  3. gc -m <new_commit_message> to create a new commit
  4. gp -f - If the commits has been pushed before, it is required to force push here as it changes the git history. NOTE that force push is a dangerous action, make sure it is safe to do that.

If it requires to keep the commit messages and authors. Then use the interactive mode:

  1. git rebase -i HEAD~<commit_counts> or git rebase -i <commit_SHA> - similar to the git reset above
  2. Then it will open a command line editor like vi : git rebase -i Follow the instructions and update the command word like pick at the start of each line. Let's say I just want to squash all into 1, then I will require to keep the top commit as pick, and change the rest to squash or s.
  3. And save. If successful, I will see such kind of message to confirm the squash: git rebase -i

Merging for a complicated situation

If I am trying to make a shared base branch up to date, rebasing will cause all the child branches to get significant conflicts. If I am working on a big change, and there are many small commits for better version controlling, rebasing may cause many times of conflict resolving which could be super confusing until I got lost in the conflicts. And now it's better to use merge instead.

git merge

To merge my upstream branch, can use git pull:

git pull
// In Oh-my-zsh:
ggl
Enter fullscreen mode Exit fullscreen mode

Or more often, merge the main branch like this:

git merge origin/master
// In Oh-my-zsh:
gm origin/master
Enter fullscreen mode Exit fullscreen mode

Resolving the conflicts

I used to love the conflict resolver in Webstorm a lot, but sadly Webstorm always eats up my CPU and memory. So I gave it up one day and never come back. Well, I have to say, it was really really good that I took quite some time to get used to the new flow with VSCode.

When there's a conflict, refreshing the "SOURCE CONTROL" panel, and will see the conflict files under "Merge changes":

VSCode git conflicts

Select and open the conflict file, and I have to make a choice Current Change or Incoming Change. Well, at least it looks not that confusing as ours and theirs.

The comparison is unlike the Webstorm's side-by-side but an up-and-down style, which only works well when the conflict block of code is not that large.

Well, here I just stick on this tool as I don't want to introduce any new tools for not that much happen case.

Tracing what happened

When something is broken or looks weird, the meaningful git message and the long git history finally appears to be a big help. And GitLens is super helpful here.

GitLens

Despite it provides so many functions, I almost only use LINE HISTORY and FILE HISTORY to help me understand how things get here step by step, like this:

gitlens

Clearing staled branches

In Remote

If I have ever checkout any remote branches that have been merged later, those references will not go away in my local. Usually, it is fine but in the large codebase it could mess up the git commands to prevent me from committing. So I do regular clean up now by:

git remote prune origin
// or maybe even better
git fetch --all --prune
// In Oh-my-zsh:
gfa
Enter fullscreen mode Exit fullscreen mode

In Local

By contrast, clearing in local is not that simple. I did clear manually for quite some time in this way:

git branch | cat  // to list all the local branches
git branch -D <branch_name>
Enter fullscreen mode Exit fullscreen mode

Then I found the shortcut in Oh-my-zsh to remove all the branches that have been merged to master/develop/dev:

gbda
Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
lookrain profile image
Lu Yu

πŸ‘

🌚 Life is too short to browse without dark mode