Git life

Nuh

I have been using Git for more than 2 years now and I thought it was time I reflected on my story with it and jot down the things that have become second nature.

What is git?

I am going to keep it simple and give a practical summary of what it is.

It is a command-line software that will help remember and track for you different versions of your workspace (a folder, a file etc). It is very good at doing its job, allowing you to name things and assign messages to changes.

For an official definition, head over to GIT SCM

Why git?

As developers, we write a lot and we remember too little of that. Git was built long ago as there arose the need to make machines remember for you what changes you made at different stages, compare them, get back to when things go wrong and allow multiple people to contribute to the same workspace.

Today, that’s why we still use and need Git or its alternatives. Here’s a quick checklist of things it helps with day to day:

  • Gives developers confidence and independence when working on a shared project
  • Keeps trail that can be reverted to when things go wrong, and to study when and why a certain decision was committed in history
  • Gives developers the ability to shorten and divide their tasks as well as reviewing for code quality async
  • Makes development and deployment lifecycle faster

… and many, many more

My initial impression

One thing with me when encountering new things is trying to be open-minded and finding what is intriguing or genius about something. When I came across TFS and Git, my initial reactions was “wow, what a heritage”. Why was I surprised? Because developers solved a painful problem of theirs via software. The art of automating as many things as a possible so you can build the next automation for the automatable processes in the real world.

As for using git, I knew I needed to get comfortable what the words used in commands actually mean in plain English and how that relates to their role. I found easy the basics e.g. create a commit, create a branch, push etc.

The commonly used commands

Here are the commands I use on a daily basis. Note: this list contains commands that are mutually exclusive

  • git remote update

    I use this to check if there has been any updates in the remote repository my local one is connected to

  • git checkout BRANCH_NAME

    For navigating to a branch I want to work with

  • git branch -m NEW_BRANCH_NAME

    When I need to create a new branch. I will then move to this branch using the git command above it

  • git pull

    To sync current local branch with any new changes found on the remote branch. This is branch specific, it will pull from the remote branch that your current branch is connected to

  • git merge SOURCE_BRANCH_NAME

    When I need to merge changes from a different branch to the current one I am on

  • git rebase SOURCE_BRANCH_NAME

    For merging changes from a different branch to mine, except it preserves the order that things came in from the source branch.

    It collects the stack of history that is different from what is in the source branch and moves it aside. Then, brings the stack of new history that my branch doesn’t have from the source branch and stacks it on top. Then brings what we put aside and puts it at the top of the stack.

    If the history between the two histories got out of sync in a disorderly way, then conflicts will arise. You will learn how to deal with some of the cases in the next section

  • git commit -m "YOUR_MESSAGE_ABOUT_WHAT_YOU_DID"

    This is how you’d create a point in the timeline that git keeps. And you have to assign a message, even as short as just 1 character (but how useful would that be?).

    For me, I usually write something like this:

    [+] Adds component for ...
    [+] Adds functionality for ...
    [*] Amends component/functionality
    [*] Fixes issue with ....
    [-] Removes unnecessary ...
    [-] Removes functionality or fault etc ...

    It summarises my todo list before I started working, and what kind of impact that has on the codebase.

  • git push --set-upstream origin BRANCH_NAME

    For creating a mirror “remote” branch in the remote repository I am connected with, here referred to as “origin”. This will copy over everything in the local branch and create a link between for future exchanges e.g. pull, push etc

    After this, you can then normally just do git push for the rest of the branch’s life except in certain scenarios (will cover one or two such scenarios in the next section).

The get-out-of-jail git commands

  • git rebase

    We use this as the default way to merge things.

    Conflicts do happen, don’t worry … git will tell you when there are

    How do you resolve them? It depends. I will give my two cents based on the two systems I use.

    I primarily use VS code so here we go.

    • Open the files identified as having conflicts in VS code. Find areas flagged and accept which of the changes you want to keep for each file. You can also see files with conflicts in the changes tab inside VS code under “Merge” I believe (See VS Code src control)
    • Then stage these changes via git add * or replace * with any specific folder or file path, Then continue to the next or final stage of the rebase process via git rebase --continue

    If you use Visual Studio, there’s an option to open in its default 3 way merge tool and choose left of right on what to keep, and should see what is going to be saved after the choice in a window below it.

    Merging commits

    I like to do this before I contribute a timeline point (commit) to the remote repository wherein it will always be visible to the rest of the team. I squash commits using git rebase -i Head~NUMBER, where NUMBER can be replaced with how many commits in the timeline, starting from the top/latest, you want to review. -i is just so that it opens something like notepad to edit rather than vim or default terminal editor which might not be friendly to many of us.

    Once there, you can choose which commit should be merged into which by labelling the ones to be merged as s or squash and the ones to be preserved as p or pick. The ones to be squashed will then be squashed onto the picked ones.

    This is also known as the history rewriting command of git

  • git cherry-pick

    This behaves like the rebase above and is usually used for when something exists in a different branch (or point in history), and you want to copy it over to where you are now. It is a get out of jail card if you accidentally committed to the wrong branch

    All it needs is the commit hash, its ID in the history. All branches more or less share the same history, just well organised by git.

    git cherry-pick COMMIT_HASH and you are done, you have what you wanted added to your current branch as a new commit or just delayed by conflicts that you get alerted to. The conflicts can be resolved just like the rebase ones, and continued with git cherry-pick --continue.

  • git stash

    Imagine you have changes you have to commit but you want to move to another branch so you can do a very quick test or bug fix. If you ever tried, you will know that untracked and unstaged changes will follow you silently and staged changes will prevent you from going to another branch until you abandon them or commit them.

    Then git stash comes to your rescue. Just like that, it adds your current uncommitted changes to a queue it keeps outside of the timeline it tracks. The queue is independent of any branch and you can get back to them anytime from any branch, and even keep copies there if so desired.

    How do you get things back from git stash? just run git stash pop if what you want is the last thing to have been stashed, and repeat to continue and get the next last etc. If you want to get a specific one, first use git stash list to see what is stashed and their order, then get stash pop@{INDEX} to just get the stash at INDEX in the stash list. You can use drop instead of pop to delete forever from the stashed list.

    I leave you to delve into anything else about git stash in your own time.

  • git log

    To see the history of commits of the current branch and sibling branches as well. A good terminal will present them all nicely. This is when you will realise that git messages are important.

    Why is this a get-out-of-jail card? Because you need it if you ever need to revert to a different point in the timeline or back from it, cherry-pick, and just to see whether your changes actually made to the timeline or they were lost somewhere in an unknown void.

  • git reflog

    This is a log that keeps track of your interactions with git and where in the timeline you have been during the interactions. Very useful for travelling back in time.

    Imagine, you were rebasing and something went terribly wrong such as picking all the wrong changes in each conflict and deleting more, but saving all that to the timeline. Not to worry, you can travel to the point before you started the rebase by using git reflog to find where that was and what the ID/Hash of that point in time was.

  • git commit --amend

    I use this to merge new changes on to the last commit, rather than creating a new point in time (AKA commit), and also to change the message I gave to the last commit.

    If during this process, you want to abandon the merge, you can just remove the commit message that is already there (all of it) and save. Then it will abandon the merge, and you should still have your changes as uncommitted.

  • git reset --hard

    DESTRUCTIVE COMMAND - it will wipe away anything you haven’t committed yet.

    For resetting, or going back to an earlier commit. Usually when you have committed something by mistake.

    You can specify how far back in the timeline you want to go by counting backwards from head e.g. git reset --hard Head@3 to go back to the third last commit.

    Be sure to do more reading on this.

  • git aliases

    Helps save my fingers and brain from exhaustion and stiffness. I shorten all the commands you have seen by setting aliases for them. Examples:

, git remote update becomes git ru, git commit --amend becomes git cia, git commit -m becomes git ci, git checkout becomes git ch, git branch -m becomes git nb, git branch -a becomes git ab, git status becomes git st

Superpower commands

  • git config

    Perfect for swapping out git defaults with your own such as the diff tool, aliases for commands, editor tool - you don’t have to be scared of vim or vi any more, just swap in Notepad.

    Anyway, I recommend the git config piece put together by Atlassian.

    If you want to just have a peak at what is available, try git config --global --edit for the global config and git config --local --edit.

And the journey continues with git.

Nuh © 2024