Advance Git

Beside some of the basic commands in git, there is a whole host of other commands and strategies to master to get the most out of your project and reduce the amount of time maintaining the code base.

Here are some of my favorite advanced git commands.

Proper Commit Messages

The summary or first line of the commit can be up to 50 characters.

This forces developers to think about what will be in this commit and for quick reading when looking at the summaries (such as when you use `git shortlog`).

The details or third line going forward, of the commit can be 72 characters per line

  • This is because git adds two blank spaces on either side of the details, centering it in the terminal when you use `git log`.

The commit message should explain what is going into this commit and why are you making the change. If you cannot explain it then maybe it is time to pause and reflect on this commit.

  • There are exceptions to the rules, though. If the change is obvious, then of course you can do it on one line, as long it is less than 50 characters. If you cannot do so then you will need to add in more details in the body.
  • Here is your chance to also explain if this commit will have any side effects
  • How it will fix the issues
  • Try adding links to commits if you found the answer on stack overflow
  • This help will help developers and reviews of your pull request in knowing what you have done and what reason for this commit without having to look into the code and only to guess as to the reason
  • DO NOT bunch changes into one commit if you need to use “and” then that should be a induction you should split the commit up and put them into their own commits

Use present tense person will make it easier to read the commit

Add — patch

Before we begin with rebasing lets talk a little about `add — patch`. This allows you to add part of the code into staging while leaving the rest to be commit later.

Suppose you make lots of changes to one file but forgot to commit instead of committing the whole thing and explain what is going on.

To start by typing `git add — patch LocationOfFile` this will start up the patch screen and give you options to split add some of the changes

Stage this hunk [y,n,q,a,d,/,e,?]?

By typing in `?` for help the follow will display

y — stage this hunk
n — do not stage this hunk
q — quit; do not stage this hunk or any of the remaining ones
a — stage this hunk and all later hunks in the file
d — do not stage this hunk or any of the later hunks in the file
g — select a hunk to go to
/ — search for a hunk matching the given regex
j — leave this hunk undecided, see next undecided hunk
J — leave this hunk undecided, see next hunk
k — leave this hunk undecided, see previous undecided hunk
K — leave this hunk undecided, see previous hunk
s — split the current hunk into smaller hunks
e — manually edit the current hunk
? — print help

Some of those will only appear at curtain types of hunks. Here are some of the most used sections:

  • y / Yes will stage that hunk
  • n / No will not stage that hunk
  • q / quit stops `add — patch` any remaining hunks will not be added
  • s / smaller will shrink the hunk into smaller pieces however, this will only be use in big hunks
  • e / edit remove the code that will not be stage from your text editor for that hunk

Rebase

Reapplies commits on top of the base, for example, when you are on a branch and type in `git rebase develop` it will take the first commit, on this branch, and change the SHA to the SHA of the last commit, HEAD, on the develop.

This will update the SHA for each of the commits, in that branch, if you previous push your changes up to the remote repo then you will have to to `git push -f origin branchName`. A word of warning if the branch is being shared you will need to tell everyone that is using it to pull down the branch in order to avoid duplicating code or better DO NOT rebase on a shared. Furthermore, because the SHA changes you must NEVER rebase on develop or master branch as everyone on the team will have a separated version of the project and cause unforeseen issues with commits later on.

Any example of rebasing is this:

Before Rebase

      A — -B — -C topic
     /
D — -E — -F — -G develop

After `git rebase develop`

                 A’ — B’ — C’ topic
                /
D — -E — -F — -G develop

Now why you want to do this, well because this will keep your git history clean without having multiple merge commits, those merge branches which serve no purpose other then showing when the developer merge their branch with develop or master branch. By having a clean log you to view all of the commits a glance.

So if you look at this:

ec1c2a9 Topic #6
033c6bd Merge branch ‘develop’ into topic
82a5ad2 Topic #5
82a5ad2 Topic #4
9953bb1 Topic #3
a12s7zk Merge branch ‘develop’ into topic
161e1aa Topic #2
9sdb12r Merge branch ‘develop’ into topic
a397dbe Topic #1

or this

ec1c2a9 Topic #6
82a5ad2 Topic #5
82a5ad2 Topic #4
9953bb1 Topic #3
161e1aa Topic #2
a397dbe Topic #1

Pull — rebase — preserve-merges

Now if we look at git pull, by default it does a merge instead of a rebase, this could result in the git history containing, merge commits, which undermine the result we want with rebase. By change the default to pull rebase you will not need to remember to do this when you do a pull.

git config — global pull.rebase preserve

Now remember when I said never rebase develop or master well there is an exception to the rule, if you add in — preserve-merges this or rebase = preserve in the Git config then pull — rebase will not try to remove merge commits that might be on the develop or master branch. Thus leaving existing commits alone and you will not have to force push to the remote repo since all it will do is pull down the commits and move the commits in front of which ever branch you pulling down to.

Rebase (-i) — interactive

Rebase interactive or Rebase -i, for now on, is the most powerful way of multiple git history, why would you want to do such a thing well. Lets say you have a working branch that you may make commits that are not in order or do a bunch of commits that are all part of a the same items. or you decided to hack away at a problem until you found a solution leaving behind a bunch of commits that no longer apply. If you submit a pull request like this. It will take a well to figure out what the actually changes. Also, you end up with a measly history where it becomes impossible to find what change and a reason behind it.

So along comes `rebase -i` where you can squash, fixup, reword, drop, editing and reorder, commits. Turning the commits into a groups of logical progression. Before I start with the main sections there is one other thing you can do in `rebase -i` called exec where you can executed SHELL commands during your rebasing. Most of the time, you will not need to use it but it is there if you needed it

To start you will need to type `git rebase -i` then choose either name of the branch to base off of usually develop or master but it can be any locally brunch or you can use a commit’s SHA which will be after the commit you want to use edit, for example,

git rebase -i a397dbe

82a5ad2 Topic #4
9953bb1 Topic #3
161e1aa Topic #2
a397dbe Topic #1

It goes from latest, the top, to oldest, the bottom, so If you want Topic #2 to start your rebase then you will get the SHA of Topic #1 as that is base commit to start from.

Once you do this a editor that you configure or vi by default will open up, and give you the options, by default pick is select meaning that you have choose that commit to stay.

pick 835f50c Topic #2
pick 0d5bf2f Topic #3
pick 90e56ea Topic #4
pick 25e1b8c Topic #5
pick cec1509 Topic #6
pick f7e230e Topic #7
pick 2de656d Topic #8
pick 31bc4a1 Topic #9
pick 7565ef6 Topic #10
pick c6d5e23 Topic #11
# Rebase 713274d..c6d5e23 onto 713274d (10 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like “squash”, but discard this commit’s log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

Squash

Squash is the ability to merge two commit together while preserving the commit messages. This allows you to view which commit messages and reword them into a new combine commit.

pick 90e56ea Topic #4
squash 25e1b8c Topic #5

In the example above Topic #5 will be merge into Topic #4 then open up your text editor.

# This is a combination of 2 commits.
# The first commit’s message is:
Topic #4
# This is the 2nd commit message:
Topic #5

Here you can decided what the new commit message will be or leave as is and the combine messages of Topic #4 and 5 will be use.

Fixup

Similar to squash but instead of the entering in a commit message. The message is from the commit being merge into, will be use.

pick 25e1b8c Topic #5
fixup cec1509 Topic #6
fixup f7e230e Topic #7

In this example, Topic #6 and 7 will merge into Topic #5 and use that message.

Reword

Allows you to fix misworded or misspelled commits, this gives you a second chances to fix a commit wording in order to make it more clear.

Drop

Will remove commits from git history by either stating it on the line or by removing the line completely. A huge word of warning if you remove a commit, any subsequential changes. to the same line of code. that were made by later commits will also be affected. This is because has never happen, in git history, thus any change that invades that will also change and possible be remove the code from history going forward.

Editing

It basically takes `commit — amend` to the extreme where you can amend commits in the middle of two commits instead of at the end. This allows you split commits up or remove a piece of code that was mistaken left behind.

To start editing, choose a line in `rebase -i` option, save and exit the options. Git will start to rebase until it reaches that line where it will look like this:

Stopped at 0d5bf2f05e90219eb11e2e5e91d8f6ad0c4518af… Topic #3
You can amend the commit now, with
git commit — amend
Once you are satisfied with your changes, run
git rebase — continue

Here you can amend the commit or make new commits then continue on with the rebase.

Reordering

Allows you to group together commits in order to have a logic grouping. So suppose you create a page and commit it. Then you make some other commits then later on you added more to that page, and commit them. However, those changes you want to keep then separated, form the create commit. So in `rebase -i` you can cut the line with the changes and paste it under the create commit. This will allow anyone looking at pull request to see the logical progression, of the page. But be warned, using this incorrectly could result in illogical placement of code such as a function being called but the actual function was not created.

Merge Conflicts

Of course there will be times where merge conflicts will happen. First, any tools you use for merge conflicts will still work with rebase. Keep in mine, of how time works. If you make changes to a commit that will also have changes later on. You should not make those changes unless the commit states otherwise. Or you will need to apply those changes every time the file was change in a commit.

There are also 3 options you can do:

  1. `rebase — continue` which will continue on the rebase, however, if there is a merge conflict and its not resolved you will not be able to continue until the conflict is fixed.
  2. `rebase — skip` which will skip the merge conflict however doing so may cause further issues with other commits. It is best to fix those conflicts now.
  3. `rebase — abort` which will stop the rebase and undo any changes done by this rebase. This can allow to you make smaller rebase changes or rethink what to change.

Reflog

Now you must be wondering what if you screw up and now your branch is unusable or your code is lost. No worries there is Reflog which will list most of the git commands you have done for a given time period, default 90 days. This makes it possible to use rebase without worry.

This will give you the a chance to reverse any git commands that have gone wrong for instance if a rebase has broken your application.

You can do this:

1. `git reflog` to list all of the git commands for the rebase

38b323f HEAD@{0}: rebase -i (finish): returning to refs/heads/feature/add_git_reflog
38b323f HEAD@{1}: rebase -i (pick): Clarify inc/dec operators
4fff859 HEAD@{2}: rebase -i (pick): Update java.html.markdown
34ed963 HEAD@{3}: rebase -i (pick): [yaml/en] Add more resources (#1666)
ed8ddf2 HEAD@{4}: rebase -i (pick): pythonstatcomp spanish translation (#1748)
2e6c386 HEAD@{5}: rebase -i (start): checkout 02fb96d

2. Select where to reset to, in our case its `2e6c386`, or `HEAD@{5}`

3. ‘git reset — hard HEAD@{5}’ this will reset your repo to that head

4. You can start the rebase again or leave it alone.

Refer:

From https://git-scm.com/book/ch5-2.html

Short (50 chars or less) summary of changes
More detailed explanatory text, if necessary. Wrap it to
about 72 characters or so. In some contexts, the first
line is treated as the subject of an email and the rest of
the text as the body. The blank line separating the
summary from the body is critical (unless you omit the body
entirely); tools like rebase can get confused if you run
the two together.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet,
preceded by a single space, with blank lines in
between, but conventions vary here

https://medium.com/@preslavrachev/what-s-with-the-50-72-rule-8a906f61f09c#.d3huuguud

Like what you read? Give Jason Stathopulos a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.