A brief introduction to the translator.Fascinatingly interesting article of one of the developers of
“GitHub Inc.” about the working process adopted by the company demanded to use a couple of special terms when translating.
The concept for which one word
“ workflow ” is enough in English has to be translated into Russian with the phrase
“ workflow ”. I don’t know anything better, neither with the help of the
Google translation - so both me and the readers will have to put up with it, even if unwittingly.
Another concept, “
deploy, ” is often translated into Russian by the word “
deployment, ” but in my translation I decided to recall a turn from the Soviet clerical work — “
introduction of innovations in production ” —and I will speak
about the “ introduction ” of new features. The fact is that the workflow described below does not have “releases”
(releases), which makes it somewhat inconvenient to talk
about any “deployment” of them.')
Unfortunately, some translators are prone to rudely killing the juicy metaphor of “injection” (or even “injection”, if you like) contained in the term
“ code injection ”, so it is also translated by the phrase
“ code injection ”. This confusion saddens me, but I can’t do anything. Just keep in mind that here “I’m going to introduce the code” I’ll refer to introducing it into production
(for production), and not
into someone else ’s code.
I tried to use the phrase "in Github" in the meaning of "in the company GitHub Inc.",
and "on Github" - in the sense of "on the site
GitHub.com". True, sometimes it is difficult to separate them.
Git-flow issues
I travel everywhere, teaching Git to people - and in almost every lesson and seminar I recently conducted, I was asked what I thought
about git-flow . I always answered that I think this approach is great - he took the system (Git), for which there may be a myriad of possible workflows, and I documented one proven and flexible process that many developers use for fairly simple use. This approach is also becoming
something of a standard, so that developers can move from project to project and from company to company, while remaining familiar with this standardized workflow.
However, git-flow has problems. I have often heard the opinions of people who dislike the fact that the branches of features are moving away
from develop instead of master , or to the style of handling hotfixes, but these problems are relatively minor.
For me, one of the larger
git-flow problems was its complexity — more than most developers and workgroups actually require. Its complexity has already led to the emergence
of a helper script to support the workflow. This in itself is cool, but the problem is that the assistant does not work from the Git GUI, but from the command line, and it turns out that the very people who need to really learn the complex workflow well, because they have to go through all its steps manually -
for these people, the system is not convenient enough to use it from the command line. This is what becomes a major problem.
All these problems can be easily overcome by following a much simpler workflow. We do not use
git-flow in Github. Our workflow is based on (and has always been based on) a simpler approach to Git.
Its simplicity has several advantages.
First, it is easier for people to understand it, so that they begin to use it faster, less often (or never) make mistakes that require a rollback. In addition, a
wrapper script is not required to help follow the process, so using a GUI
(and so on) does not create problems.
Github Workflow
So why don't we use
git-flow in Github
? The main problem is that we have adopted a continuous introduction of changes. The
git-flow workflow was created mainly to help “release” new code. And we do not have "releases", because the code goes
to production (the main working server) daily - sometimes several times a day. We can submit for this command to the bot in the same
chat room, which displays the results of CI
(integration testing). We strive to make the process of testing the code and its implementation as easy as possible so that every employee is comfortable in work.
This frequent introduction of new products has a number of advantages. If it happens every few hours, then it’s almost impossible for a large number of major bugs to occur. Minor bugs happen, but they can be corrected (and corrections, in turn, implemented) very quickly. Usually, we would have to do a hotfix
or something else to deviate from the normal process, but for us it becomes just a part of the normal process: in the Github workflow, there is no difference between a hotfix and a small feature.
Another advantage of continuous change is the ability to quickly respond to problems of any kind. We can respond to reports of security issues or execute small (but interesting) requests for new features - but the same process also works when making changes related to the development of a normal (or even large) feature. The process is the same and it is very simple.
How we do it
So what is the Github workflow?
- The contents of the master branch are always deployable.
- Starting work on something new, branch off from the master branch a new branch whose name corresponds to its purpose (for example, “ new-oauth2-scopes ”).
- When you commit to this branch locally, send your work regularly and to the same branch on the server.
- When you need a review, or help, or when you find a branch ready for a merge, send a merge request .
- After someone else has reviewed and approved the feature, you can merge your branch into the master branch .
- After the master branch is replenished with new code, you can immediately inject it into production and you should do it.
That's the whole workflow. It is very simple and productive, it works for fairly large working groups - 35 people are currently working in Github, maybe fifteen or twenty of them working on the same project at the same time
(github.com). I think that most development teams (groups that simultaneously work with the logic of the same code, which can generate conflicts) have the same size - or less. Especially groups that are progressive enough to engage in quick and consistent implementation.
So let's take each step in order.
The contents of the master branch are always working (deployable)
In general, this is the only hard and fast
rule in the whole system. There is only one branch, which always has some special meaning, and we called it
master . For us, this means that the code for this branch is either embedded in the production or, in the worst case, it will be introduced in a few hours. This branch is very rarely unscrewed a few commits back (to cancel work): if a problem occurs, changes from commits are canceled or completely new commits correct the problem, but the branch itself is almost never unscrewed back.
The
master branch is stable. Implementing its code for production or creating new branches based on it is always, always safe. If an untested code comes from
master to you or it breaks an assembly, then you have violated the “social contract” of the development team and you have to scratch the cats for that matter. Each branch is tested by us, and the results are sent
to the chat room - so if you have not tested it locally, you can push the branch (even with a single commit) to the server and wait until
Jenkins reports whether all the tests have been successfully passed. .
Branch from the master branch to new branches whose names match the intended purpose.
When you want to work
on something new, branch off from the stable
branch of the master a new branch whose name corresponds to the purpose. (For example, in the Githab code right now there are branches
" user-content-cache-key ", " submodules-init-task ", and " redis2-transition ".) This name has several advantages. For example, it is enough to issue the
fetch command in order to see what topics the rest are working on. In addition, leaving the branch
for some time and returning to it later, by name, it is easier to remember what it was about.
And this is nice, because when we go to a page with a list of branches on Github, it is easy to see which branches have recently been worked on
(and, approximately, what was the volume of work).
![[screenshot]](https://habrastorage.org/getpro/habr/post_images/d34/331/a8d/d34331a8d0a6f47b983a1a9d79845b03.png)
This is almost like a list of future features with a rough estimate of their current state. If you do not use this page, then you should know - it has great features: it shows you only those branches in which the work was done, which is unique in relation to the branch you have chosen at the moment, and sorts it in such a way that the branches with the most recent the work was on top. If I want to be curious, then I can click on the “Compare” button and look at the exact joint diff and the list of commits that are unique to this branch.
Now, when I am writing this, we have 44 branches in the repository with an unrelated code, but it is also clear that only nine or ten of them received the code for the last week.
Constantly send the code of the named branches to the server
Another major difference
from git-flow: we continuously
push the branches to the server. From the point of view of implementation, you have
to really worry only about the
master branch, so
push does not puzzle anyone and breaks nothing: everything that is
not master is just the code that is being worked on.
This creates a safety copy in case of loss of a laptop or hard drive failure. This supports, more importantly, the constant exchange of information between developers. With a simple
git fetch command
, you can get a list of those TODOs that everyone is working on now.
$ git fetch remote: Counting objects: 3032, done. remote: Compressing objects: 100% (947/947), done. remote: Total 2672 (delta 1993), reused 2328 (delta 1689) Receiving objects: 100% (2672/2672), 16.45 MiB | 1.04 MiB/s, done. Resolving deltas: 100% (1993/1993), completed with 213 local objects. From github.com:github/github * [new branch] charlock-linguist -> origin/charlock-linguist * [new branch] enterprise-non-config -> origin/enterprise-non-config * [new branch] fi-signup -> origin/fi-signup 2647a42..4d6d2c2 git-http-server -> origin/git-http-server * [new branch] knyle-style-commits -> origin/knyle-style-commits 157d2b0..d33e00d master -> origin/master * [new branch] menu-behavior-act-i -> origin/menu-behavior-act-i ea1c5e2..dfd315a no-inline-js-config -> origin/no-inline-js-config * [new branch] svg-tests -> origin/svg-tests 87bb870..9da23f3 view-modes -> origin/view-modes * [new branch] wild-renaming -> origin/wild-renaming
It also allows everyone to see (on the githabby page of the list of branches) what all the others are working on - you can analyze the code and decide if you want to help the developer with
something .
Create a merge request at any time
GitHub comes with an amazing code review system called
merge requests ; I'm afraid not enough developers are quite aware of it. Many use it in ordinary work on open source: forked the project, updated the code, sent a merge request to the project owner. However, this system can also be used as a means of internal corporate code verification, and so we use it.
We actually use it as a means of viewing and discussing branches, rather than as a request for a merge. GitHub supports sending a merge request from one branch to another in the same project (open or private), so in the request you can say “I need a hint or an overview of this code”, and not just “please accept this code”.
![[screenshot]](https://habrastorage.org/getpro/habr/post_images/d12/ec7/1f1/d12ec71f16a3407bee8b491f909bf4cf.png)
In this illustration, you can see how Josh asks Brian to look at the code, and he is with advice about one of the lines of code. Below you can see how Josh agrees with Brian’s considerations and replenishes the code to respond to them.
![[screenshot]](https://habrastorage.org/getpro/habr/post_images/4f6/d9e/451/4f6d9e45140bff51431559c22f9ba58c.png)
Finally, you can see that the code is still at the testing stage: this is not yet a branch prepared for deployment, we use merge requests to review the code long before we really want to merge it
into the master and send it to the deployment.
If your work on a fichey or branch is stuck and you need help or advice, or if you are a developer, you should look at your work and the designer (or vice versa), or even if you have little or no code, but there is
some A composition of screenshots and general ideas, then you open a merge request. The Gietgab system allows you to add people to the discussion by
remembering them, so if a review or response is needed from a specific person, you can mention it in the query (you saw above how Josh did it).
And this is cool, because in merge requests you can comment on individual lines of the combined diff, or individual commits, or the entire query as a whole - and the copies of the replicas will form a single discussion. You can also continue to replenish the branch with code, so if
someone points to an error or forgotten feature in the code, you can put a fix in the same branch, and GitHub will show new commits in the discussion, so you can work on the branch like this.
If the branch exists for too long and you feel that the code in it mismatches with the code of the branch of the
master , then you can pour the code
from master into your branch and continue working. In the discussion of a merge request or in the list of commits, it is easy to see when the branch was last updated with code taken
from master .![[screenshot]](https://habrastorage.org/getpro/habr/post_images/d93/f8d/6cf/d93f8d6cf682b8a07a2f7c8434ba292b.png)
When the work on the branch is fully and completely completed and you feel it is ready for implementation, then you can proceed to the next step.
Merging only after reviewing the request
We do not work directly in the
master branch
, but we do not merge the work from the named branch immediately after we consider it finished - we first try to get approval from other employees of the company. It usually has the form
“+1”, or emoji , or the comment
“: shipit:”, but we have to bring
someone else to look at the branch.
![[screenshot]](https://habrastorage.org/getpro/habr/post_images/68b/481/bac/68b481bac01639a14be98c5bb5fdcbec.png)
When approval is received and the branch has passed the CI, we can merge it
into the master and into the implementation; at this point, the merge request will be closed automatically.
Implementation directly after review
Finally, your work is finished, and its fruits are on the
master branch. This means that even if you do not implement them right now, they will still become the basis for the branches of other employees, and that the next implementation (which will most likely happen in a few hours) will launch a new product. And since it is very unpleasant to find that
someone else has run your code and suffered from this (if the code
has broken
something ), then it’s common for people to carefully check the stability of the results of the merge they have done, to implement the results themselves.
Our campfire bot, named hubot, can implement the code as directed by any employee. It is enough to submit the
hubot deploy github to production command in the chat, and the code will go to production, where restart of all the necessary processes will begin. You can judge for yourself how often this happens on the Github:
![[screenshot]](https://habrastorage.org/getpro/habr/post_images/a1c/aa6/790/a1caa6790c77bfc0a04fa43cc78fc13b.png)
As you can see, six different people (including one support and one designer) implemented the code more than two dozen times a day.
I did all of the above for branches with one commit that contains a one-line change. The process is simple, simple-minded, scalable and powerful. The same can be done with the branch of a feature containing about fifty commits, which required two weeks of work, and with one commit made in ten minutes. The process is so simple and not so much that its necessity is not annoying even in the one-combo case, so people rarely miss or bypass certain steps of it - except that it is a change so small and insignificant that it does not matter.
Our work process has both power and incredible simplicity. I think many would agree that GitHub is a very stable platform, that we respond to its problems quickly (if they arise at all), that new features are being introduced at a fast pace. There are no such compromises in terms of quality or stability, which could increase the speed and simplicity of the workflow or reduce the number of its steps.
Conclusion
Git itself is quite difficult to understand. If it is also used in the work process more complicated than necessary, then the matter will end in daily excessive effort of reason. I will always defend the use of the simplest possible system suitable for the work of your group, and until this system stops working; only then add complexity when you can’t avoid it.
For those working groups that need to prepare official releases of code at long intervals (from several weeks to several months between releases), and create hotfixes, and support branches of previous versions, and do other things that are called for by such infrequent releases of code, it makes sense
git-flow , and I would highly recommend using it.
For groups whose work is built around the delivery of code, which update production daily, continuously test and implement features, I would recommend a simpler workflow such
as GitHub Flow.