A flexible git flow

Introduction

Today I’m going to share a git flow with the following qualities:

  1. In development, you could make arbitrary commits.

  2. After testing, you could turn the arbitrary commits which are more friendly in development into commits compliant with production standard.

  3. The content of two branches are exactly the same, however, with totally different commit history.

In Ray’s case, when developing, I am used to write down the process, and list every possible logic that I think is feasible, and then try it. Normally a big function may consist of many small logic, and this git flow enables me to make all of them many individual commits in a feature branch. And finally after they are tested and there is no problem there, they could be turned into the commit with production standard as a big function.
In the process of implementing this git flow, I am more and more familiar with git rebase and some other advanced features of Git, and train myself to make each commit in a more strict style.
Here are some advantages that Ray personally think this git flow could provide:

  1. Because every commit is small with single logic, it features unspeakable convenience no matter in experiment or debug stage.
  2. Record your logic in this small-commit way helps clean your mind, on the other hand, makes the logic of each function explicit.
  3. Though the process looks a bit complicated, actually it only takes a little to organise branches once you are familiar with Git, and you could be more familiar with the advanced operation of Git
  4. Because of the small commit, you could train yourself to make commits in a more strict way.

An ideal commit

The git flow I am going to demonstrate today is just an example, and it doesn’t suit everyone. However, the point is the concept it takes to achieve this operation.

When we do commit locally, we hope that the commit can be as small as possible, because the smaller, the more specific and more precise function orientated the commit is, the more helpful and useful it will be when it comes to debug or experiment and validation of your logic.

For instance?

Let’s make it more specific!

Let’s say that you were debugging, and you found that the thing you printed out was different from your expectation, so you were trying different ways to get the result you wanted.

If your commit is compliant with the above mentioned principles, in this case, you will not need anoying and troublesome revising after each failed try. All that takes is a simple

git reset --hard

Even though the whoEven though the whole logic of a commit is wrong. If the function of this commit is specific enough, all you need is a simple

git reset @^ --hard

What exactly we want?

However, the git flow of production doesn’t allow us to do so. Each pushed commit in production git flow is required to run properly and towards designated function. That said, possibly, a designated function of production git flow would consist of many so called small commit we just mentioned.

What we need in a list

  • In development: We need the absolute flexibility, able to make a commit as functional specific as possible.
  • In production: We need to make each commit compliant with the requirement of company, running errorlessly on designated function

Which one could we have?

They say, you can’t have a cake and eat it, is that true?
Could we have both?

List the physical need

Let’s list and conclude more specifically what we need

  1. We need a develop branch for local development where we could make a commit whenever we feel comfortable
  2. We need a master branch for production. In this branch, each commit represents a designated function by the company.
  3. The content of above mentioned two branches should be exactly the same
  4. (Optional)We would like to keep the respective history of both branches

What it actually look like?

develop branch:

As the photo below. What’s on the left side is the content, while on the right is commit. Take a look and then you could find that each file represents a single commit named small function. It’s just an example, denoting a concept of smallest commit that I’m trying to convey

master branch:

Now let’s take a look on master branch. You could see that through the photo below, we only have 4 commits, and each of them contains 4 files(except for .gitignore commit). It’s just an example, denoting that the actual commit compliant with production standard is always bigger than the ideal commit.

Example

Hand-on practice

The very beginning

.gitignore is always the very beginning of everything.

  • Create .gitignore file with vim, and then key in those files we would like to ignore, and then type :wq and leave.

    vim .gitignore
  • Complete the first commit

    git add .ignore; git commit -m 'Added .gitignore';

develop branch

Now, we will make a develop branch based on master branch. As mentioned above, the commits are going to be the most function orientated and smallest in develop branch, while the ones in master branch are going to be compliant with production standard.

  • Firstly, let’s build develop branch based on master branch which has completed .gitignore setting.
git checkout -b develop

feature branch

And then, we could start developing

  • Make a feature branch
  • This feature branch represents the currently developing function
  • The function mentioned here is not the function we define on our own, instead, is required by company compliant with production standard.
  • So, a function with production standard is equal to a feature branch
    git checkout -b feature;

Commit freely

  • On feature branch , we could make commits arbitrarily as long as you feel comfortable.
  • Create file 1~4, and then each of them represents a smallest commit.
    touch {1..4};
    git add 1;
    git commit 1 -m 'small function 1';
    git add 2;
    git commit 2 -m 'small function 2';
    git add 3;
    git commit 3 -m 'small function 3';
    git add 4;
    git commit 4 -m 'small function 4';

The function is completed!

  • After testing, we are pretty sure that everything is okay, so we are going to turn our arbirarily made commit into production standard commit.

  • as mentioned previouly, the coverage of a feature branch is a required function of production standard.

  • So? We are going to turn an entire branch into a single commit for production standard.

  • Since we are going to keep both branches with respective histories, we can’t directly do this on feature branch. Because develop branch is going to need it later.

  • Actually in this git flow, it’s not neccesary to keep develop branch. However, in this article, I will demonstrate it in the condition that the develop branch will be kept. If you don’t want to keep it, it will be mush simpler.

A branch for being merged

  • Let’s build a disposable branch called toBeMerged production standard master branch.

    git checkout -b toBeMerged
  • Now, let’s make toBeMerged branch ready to be merged by master branch.

    git rebase -i master

Compress, rename commit

  • I mentioned I was going to compress several small commits into a commit with production standard, right? So now I’m going to squash all of the small commits. We could use fixup option. Moreover, the commit name with production standard is defintely different from the commit we make during development, so we are going to rename this compressed commit as follows:

    reword 96c6c18 small function 1
    fixup 1dd84d2 small function 2
    fixup 1a71401 small function 3
    fixup f9c90c6 small function 4
  • I’m going to name this compressed commit as

    big function 1
  • Then, type :wq and leave

  • Now, we use git log to check it, it should look like as follows:
    git log

merge

  • Let’s checkout master and merge this branch!

    git checkout master;
    git merge toBeMerged;
  • And then, let’s checkout develop branch and merge feature branch

    git checkout develop;
    git merge feature;
  • Finally, let’s delete merged feature branch and toBeMerged branch.

git branch -D feature toBeMerged
  • Let’s review it. Remember what we want?

    • On develop branch, the commits are smallest.
    • On master branch, the commits are compliant with production standard.
    • The content on both two branches should be the same.
    • (optional)Keep both branches
  • Check if the master branch looks like the one we want.

git checkout master;
git log

  • Check the content
    ls

  • Check commits on develop branch
git checkout develop;
git tag 'bigFunction1'
git log

  • Check the content
ls

The second phrase

  • The same as before, feature branch first, and then toBeMerged branch
git checkout develop;
git checkout -b feature;
touch {5..8};
git add 5;
git commit -m 'small function 5';
git add 6;
git commit -m 'small function 6';
git add 7;
git commit -m 'small function 7';
git add 8;
git commit -m 'small function 8';
git checkout -b toBeMerged;
  • Pay attention! in this case, we can’t turn toBeMerged branch into a right one for master branch with traditional rebase because they don’t have a mutual history.

  • Let’s think about it for a moment, what the toBeMerged branch should look like to match what we need for being merged by master branch?

    • They need mutual history (Identical sha1 checksum)

    • Those previously merged uncompressed commits that already exist in develop branch shouldn’t appear in toBeMerged branch. Simply speaking, small function 1~4 were already compressed as big function 1, so small function 1~4 should appear again

    • Those newly added commit should be compressed into a single commit

    • After all above listed are done, you are ready to go

The second rebasing and compressing.

  • So what are the steps?

  • We will use git rebase, git rebase --onto. We are going to rebase toBeMerged branch onto master, and omit whatever on develop, and then the one should be rebased is toBeMerged. Follow this order, we get the command as follows. You could refer to official document for more detail about git rebase --onto

    git rebase -i --onto master develop toBeMerged
  • The same as previous action, we compress the samll commits into the one compliant with production standard.

    reword 3668e72 small function 5
    fixup fd05fa1 small function 6
    fixup 3a87c08 small function 7
    fixup c38957e small function 8
  • The name of compressed commit is big function 2

  • Repeat mentioned steps, merge them first and delete them.

  • Let’s check the commit on develop branch, and the content

git checkout develop;
git tag bigFunction2;
git log --oneline
  • The commit on master

ls
  • The content on master

  • Let’s check the commit on master, and its content
git checkout master;
git log
  • commit on develop branch

ls
  • content on develop branch

Conclusion

The git flow in this article enables us to make commit as small as possible in development, even in the way we personally like, and no need to sacrifice for production standard.
The develop branch in this article is not necessary to be kept, because if there is some error in the commit with production standard, you will still need to fix it on the one with production standard. However, if you keep it, I reckon that there might be some further usage there. Well, I will leave it for your own explorations.
If you have any comments, feel free to drop me a message. I believe that communication and idea sharing is the shortcut of improving ourselves.

Deploy Supervisor on AWS and MacOS Easy Payment Gateway with PayPal REST API

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×