Introduction
Today I’m going to share a git flow with the following qualities:
In development, you could make arbitrary commits.
After testing, you could turn the arbitrary commits which are more friendly in development into commits compliant with production standard.
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:
- Because every commit is small with single logic, it features unspeakable convenience no matter in experiment or debug stage.
- Record your logic in this small-commit way helps clean your mind, on the other hand, makes the logic of each function explicit.
- 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
- 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
- We need a develop branch for local development where we could make a commit whenever we feel comfortable
- We need a master branch for production. In this branch, each commit represents a designated function by the company.
- The content of above mentioned two branches should be exactly the same
- (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.
Hand-on practice
The very beginning
.gitignore is always the very beginning of everything.
- Create
.gitignore
file withvim
, 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 4I’m going to name this compressed commit as
big function 1
Then, type
:wq
and leaveNow, 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; |
- Check the content
ls
- Check commits on develop branch
git checkout develop; |
- Check the content
ls |
The second phrase
- The same as before, feature branch first, and then toBeMerged branch
git checkout develop; |
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 14 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 ontomaster
, and omit whatever ondevelop
, and then the one should be rebased istoBeMerged
. Follow this order, we get the command as follows. You could refer to official document for more detail aboutgit 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 8The 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; |
- The commit on master
ls |
- The content on master
- Let’s check the commit on master, and its content
git checkout master; |
- 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.
Comments