
Ask HN: Best Git workflow for small teams - tmaly
I have been building up a small team of programmers that are coming from CVS.  I am looking for some ideas on ideal workflows.<p>What do you currently use for teams of 5-10 people?
======
grk
We've been using the Github flow (or some variation of it) in teams of 2-10
people for a few years now. We work on feature branches, merge after code
review using the github web UI. Here's a few things that help us:

\- Make a rule that anything that's in master can be deployed by anyone at any
time. This will enforce discipline for code review, but also for introducing
changes that f.e. require migrations. You'll use feature flags more, split db
schema changes into several deployments, make code work with both schema
version, etc. All good practices that you'll need anyway when you reach larger
scale and run into issues with different versions of code running concurrently
during deployments.

\- If you're using Github, check out the recently added options for
controlling merging. Enable branch protection for master, so that only pull
request that are green on CI and have been reviewed can be merged. Enable
different dropdown options for the merge button (eg rebase and merge), these
are useful for small changes.

\- It takes some time to get used to those constraints. Make sure that
everyone is on board, and do a regular review of the workflow just as you
would review your code. It takes some time to get used to, but I think it's
worth it in the long run.

~~~
mirasmithy
+1 for master always deployable. In teams I've led, I've made it a rule to
never commit to master, and sparingly commit to develop.

Features are developed in branches and merged into develop. Once we're happy
with things, we tag & merge into master. (Junior dev so my approach may not be
the best.)

~~~
sytse
To prevent confusion I think it is better to merge feature branches into
master and not have a development branch. Master should always be deployable
but if you're not practising continuous deployment you can merge into the
production branch to do so. This is further detailed in GitLab Flow
[http://doc.gitlab.com/ee/workflow/gitlab_flow.html](http://doc.gitlab.com/ee/workflow/gitlab_flow.html)

------
qertoip
Continuous integration AKA trunk based development is the workflow you want to
have. Ensure you meet the prerequisites first though (reliable automated
tests, solid code reviews, feature flags, etc).

To be precise, small feature branches are perfectly fine. They are meant to be
reviewed and squashed into master ("trunk") in a few hours to a few days
maximum.

Squashing instead of merging has a big advantage of being able to quickly
revert the changes if things go awry despite all best practices in place.

PS Avoid gitflow and similar workflows as they introduce leaps and thus risk.
As everything in software engineering, you want your workflow to be as
incremental as possible.

~~~
JimDabell
> Squashing instead of merging has a big advantage of being able to quickly
> revert the changes if things go awry despite all best practices in place.

Merge with --no-ff. You can revert easily, but you don't throw away the
feature branch history.

~~~
tapan_k
> but you don't throw away the feature branch history

Once a feature is merged, how is the history of a feature branch helpful?

Since I do not see/understand the benefits of retaining feature branch
history, my preference is to squash commit and merge. Perhaps, this is a
result of my habits that I carry from the ClearCase days, but would love to
hear the downsides of this approach.

~~~
JimDabell
Well given that we're talking specifically about reverting the merge when
something goes awry, firstly you want that history preserved so that you can
re-start work on it, potentially without pulling in all of the changes in one
go; and secondly so that you can determine the precise point at which the
problem happened.

Consider the difference between:

* Well we need to revert this because it's causing problems, but now we've got one massive chunk of several day's work to pick through.

…vs:

* Well we need to revert this, but we can see that the problem was specifically commit xzy, so let's yank that, do it a different way, and merge the result.

Aside from that, it can be very useful to see the individual steps in
implementing a feature for a variety of reasons. Given that a --no-ff merge
achieves everything you are aiming for with the squash, why _wouldn 't_ you
pick the more flexible approach?

------
radicalbyte
I had a lot of success with a master branch, all features built in feature
branches.

Feature branches were rebased then merged with a --no-ff. This creates a merge
commit on master which includes the ticket number and short description.

The rebase is done by the feature branch developer who is usually best
qualified to do so.

The advantage is that changes are isolated from each other, so nothing is
spread before it's reviewed. The rebase makes the history easy to follow
because it becomes linear and you can always easily see exactly what was
changed in the branch. You still retain the full history of the feature
branches.

Disadvantages: it doesn't scale to a massive team because you need to
linearize the merges back to master. So it works for upto around 20 people.

I'd recommend against Git Flow because their method of merging makes it very
unclear exactly what was changed in a branch. I actually prefer no feature
branches to using Git Flow.

~~~
jkubicek
I would strongly recommend avoiding a rebase-based strategy. When developers
at my company run into git issues, they are almost always the result of a bad
or confusing rebase.

My team's process is simple and easy for anyone to follow: all feature work is
done on feature branches. Branches should be kept small and atomic. When
they've passed code review, squash and merge into Master.

If you need to pull changes from master, always merge into your feature
branch, never rebase.

~~~
joatmon-snoo
I would disagree with the strongly recommend here, because rebasing makes it
_so_ much easier to track down bugs and isolate breaking changes.

Of course, this does require someone to be more proficient with Git beyond the
simple add, commit, fetch, push model, which has its own drawbacks.

Also, at least in Git, squash is just one use case of interactive rebase, so
I'm not quite sure what you're arguing against...

~~~
hitsurume
Can you go more in depth with this process on how rebasing things makes it
easier to track down bugs / breaking changes? Usually you can track down which
feature branch is the one that cause a regression in your code base, and you
can also look at specific commits to find out where problems happen. I can't
tell how a rebasing flow would make this any easier?

------
dasil003
I generally like GitHub Flow
([https://guides.github.com/introduction/flow/](https://guides.github.com/introduction/flow/))
because it gives you isolation for individuals, but with only one ceremonial
branch (ie. master). It might not be sufficient if you have formal release and
QA cycles where you need to batch a bunch of changes to push to a staging
environment, but all else being equal I prefer to optimize for branching,
merging and deploying to production quickly. And with current cloud and/or
containerized setups, it becomes possible to have on-demand staging
environments (or even using ngrok with dev workstations!), but YMMV.

The main cherry I like to put on top is to always rebase before merging then
merge with --no-ff (which is the default with GitHub PR merge button). This
gives linear history for purposes of git bisect but preserves the topic branch
structure so you don't have to read the tea leaves of the individual commits
to piece together the overall development timeline. That one little piece goes
a long way to addressing the concern that "rebasing destroys history" (which I
don't agree with anyway, but that's the topic of another post).

This might not be worth it for certain types of contributors who are not
programmers by trade, but for career programmers I believe mastering git and
rebase in all its flavors (-i, --onto, pull --rebase, etc) pays big dividends
that your team will appreciate more as the years go by. For git beginners
maybe you start without rebasing, then learn the ins and outs of rebasing with
local branches only before pushing, before finally going the whole hog and
rebasing topic branches with force push before merging.

One last idea I like is Zach Holman's recommendation of deploying topic
branches directly and then merging if there are no issues
([https://zachholman.com/posts/deploying-
software](https://zachholman.com/posts/deploying-software)) in order to have
easier rollbacks. Then you have 100% guarantee master is always stable.

------
neandrake
Paul Hammant has some interesting blogs about the topic and he has been
talking and promoting Trunk Based Development for a while. We use a variation
of it at work, though we have several teams of ~5 working on the same
repository.

[http://paulhammant.com/2013/04/05/what-is-trunk-based-
develo...](http://paulhammant.com/2013/04/05/what-is-trunk-based-development/)

[http://paulhammant.com/2014/09/29/shades-of-trunk-based-
deve...](http://paulhammant.com/2014/09/29/shades-of-trunk-based-development/)

[http://paulhammant.com/2013/12/04/what_is_your_branching_mod...](http://paulhammant.com/2013/12/04/what_is_your_branching_model/)

------
bas_ta
At my previous team (5-6 people worked simultaneously) we used CI & CD and we
relied on feature flags, so we could merge our branches more often and make
smaller pull requests on Github. Each part of the feature had its own branch
with a clear goal and tests written for it (we never pushed to master, every
time you start working on something, you create a branch prefixed with your
initials, make a PR, merge after review and then do it all over again). Of
course, master branch was always deployable.

Right now, I work on a smaller project, we use similar workflow - we haven't
implemented feature flags yet, but I suppose we will in the future (the
project hasn't been released yet actually). I personally don't like developing
an entire feature in a separate branch and then merging when it's all over,
because code review becomes tedious (and ineffective) and the risk of merge
conflicts increases. I would suggest you invest time in writing tests, so you
can become better at it (if you aren't already) and it becomes a natural part
of your development. Same goes for feature flags :) I was a junior when I
started working like this (I still am, kind of) and it meant the world for me
:)

------
JimDabell
Your master branch really should be your _master_ branch. A branch that
represents the most up to date working version you have, that everybody works
in relation to.

Only working, tested code should make it into master. Code reviews and
automated tests are great tools for this, but ultimately, it's up to the
individual developers to not be sloppy.

Avoid long-lived branches and big merges. If you've got big features that take
a while to complete, break them into smaller things you can deploy sooner or
use feature toggles.

Don't leave it too long between deployments. Small, frequent updates are far
easier to manage and far less risky. A dozen deployments a day are better than
a dozen a year.

Everybody should stay up to date with master. Rebase on top of master before
merging instead of having awkward merge commits that only obfuscate history.

If you have people working on features that take multiple commits to
implement, use feature branches. These should be rebased onto master and
cleaned up before merging into master.

If you combine all of the above, you're heading down a path similar to GitLab
Flow or GitHub Flow, so strongly consider using one of those instead of coming
up with your own from scratch. Don't use Git Flow. It overcomplicates things
and offers zero benefits over the alternatives. As far as I can see, it's only
popular because a lot of inexperienced Git users were feeling like they were
adrift without a workflow, and a blog post with a snappy title came along at
just the right time to catch their attention.

If your team don't have good VCS habits, you need to do something about this.
Small, frequent commits that do one thing and one thing only, good log
messages, push and pull frequently, etc. If you can't describe the change
briefly, you are doing too much in one commit. There's lots of best practices
articles for Git that have been written – read them. Also read Pro Git, which
is free on the Git website.

------
a_alakkad
We work as small team, 3-5 people max.

We just keep it simple like:

\- No one pushes to master.

\- For every feature (or update on a feature), create new branch.

\- Send pull request for reviewing (one of us is the reviewer).

\- Merge pull request into master.

\---

You could try git workflow, but it's just too complicated for small team (and
for large teams too?).

~~~
perlgeek
> You could try git workflow, but it's just too complicated for small team
> (and for large teams too?).

git flow seems overkill, unless you regularly need to patch older versions.
For software where you control which version(s) are deployed, you can usually
get away with (much) simpler workflows.

------
sanswork
[https://docs.gitlab.com/ee/workflow/gitlab_flow.html](https://docs.gitlab.com/ee/workflow/gitlab_flow.html)

~~~
no_protocol
It bothers me that all the arrows are backwards. Commits point at their
parents not their children.

~~~
adimitrov
That's an implementation detail. Most people think of git history as more of a
stream, forking and merging _while moving forward_. In this context, the
arrows pointing in the direction of chronology is perfectly sensible.

------
shocks
This is what's working for us:

    
    
      - Branch off master to make your fix/feature. Prefix branch name with "fix/" or "feature/" accordingly. We occasionally use a "script/" or "migration/" prefix too.
      - Do work. Use "git app -p" so commits are fairly small.
      - Make GH PR into master, get code reviewed. CI test are run automatically.
      - Deploy branch to staging environment and test.
      - Merge with GH, deploy to production.
    

Notes:

    
    
      - master is always in sync with production, and so is always deployable.
      - never commit to master.
      - we don't use a develop branch.

~~~
shredwheat
What is this 'git app' you speak of?

~~~
GVRV
I think the GP meant `git add -p`

------
contingencies
No branching at all + integrated CI/CD.

~~~
perlgeek
To elaborate a bit: That's usually called "Trunk based development", and it
works pretty well in small teams (at least that's where I have experience with
it), and if you have automated test, and infrastructure that runs them
automatically.

See for example [https://www.thoughtworks.com/de/insights/blog/enabling-
trunk...](https://www.thoughtworks.com/de/insights/blog/enabling-trunk-based-
development-deployment-pipelines) for a much more in-depth discussion.

~~~
je42
you usually also need feature flags.

------
atsaloli
Start out by ensuring your CVS refugees understand Git basics. We've got a
free talk on this (outline: [http://www.verticalsysadmin.com/git/git-
intro.html](http://www.verticalsysadmin.com/git/git-intro.html) video:
[https://www.youtube.com/watch?v=j6Se3jH60dA](https://www.youtube.com/watch?v=j6Se3jH60dA))
and provide professional training.

Also, the Pro Git book: [https://git-scm.com/book/en/v2](https://git-
scm.com/book/en/v2)

------
mattmahn
For my senior design team of 5 developers using Scrum and JIRA:

master ("production") branch:

\- this is deployed

\- nobody (not even GitHub Org administrators) can push; master is only
changed via approved PR

dev branch:

\- the base "working" branch during each 3-week sprint

\- pushing is allowed iff the change is trivial or already has team consensus
(e.g. changing linter rules)

\- this is where we demo to our Product Owner

"story" branches:

\- branched from dev

\- named along the the lines of "alternate-checkout-TFF-75-story"

\- base branch for any work that needs to be done for a user story

"task" branches:

\- branched from the corresponding story branch

\- (usually) named along the lines of "item-unavailable-TFF-92"

For all branches:

\- CI must pass

\- all PRs require >= 2 approvals, unless it is a trivial change then only 1

\- require PRs when merging upstream (i.e. task -> story -> dev -> master)

\- merge freely when going downstream (i.e. master -> dev -> story -> task)

\- do not merge from story-A to story-B nor task-A to task-B

\- squash commits when going task -> story and story -> dev

\- do not squash when going dev -> master

Having stroy & task branches help keep the changes for each new feature in
easily digestible chunks. The story branch is particularly helpful when two
tasks need the same code, but the story, task-A, nor task-B branches are ready
to go to dev. So we merge the shared code to the story branch, then the other
task branch can merge down the required code from the story branch.

Currently, there is some contention over our verbose branch naming scheme.
Previously, when 3/5 of the team was working on a different project, the
branch naming scheme was "name-of-story-TSS-XX-story" for stories and "name-
of-story-TSS-XX/name-of-task-TSS-XX".

------
M2Ys4U
My team comprises 4-5 Software Engineers and 1 Developer-in-Test. We develop
three (related) websites + a bunch of back-end services.

There is only one long-lived branch in each of our repositories: master. All
other branches in our GitHub repos exist only to perform a Pull Request/code
review.

PRs must not be merged in to master until all unit tests are passing (the unit
test suite is run for each new commit to a PR branch) and the change has been
reviewed by another member of the team. In almost all circumstances the person
who raised the PR is responsible for merging it. Once the PR has been merged
in to master the GitHub branch is deleted.

Our CI server creates a new build for _every_ merge commit to master,
automatically pushes this build to our integration environment, and then runs
a series out automated integration tests on the system. If the build or
automated tests fail then only PRs that fix the build are allowed to be merged
in unless they are trivial.

Once our DiT is ready to perform a test, she promotes a build to the test
environment and does her thing. Tickets that have been tested are then
reviewed by a product owner and if they are happy the build gets promoted to
the Live environment.

~~~
lamontcg
+1 on only having master as a long-lived branch.

where we started 5 years ago at work we had various different kinds of
'develop' branches and process around merging between two different eternal
branches. as we've scaled from a startup to a 200+ person company we've mostly
simplified our github workflow and gone to single-eternal-master.

------
uniacid
I've used both gitflow and the feature branch workflow which is explained
here: [https://www.atlassian.com/git/tutorials/comparing-
workflows/...](https://www.atlassian.com/git/tutorials/comparing-
workflows/feature-branch-workflow)

both work well I think for small teams just depends on how well you want to
organize things.

------
idieeasily
For my team of about 10 people per app -

    
    
      1. Never commit to master
      2. master is always deployable and gets built and deployed (CI/CD) automatically so its sacred
      3. Everyone codes in their own feature branch (username/feature)
      4. These are merged into a topic branch (origin/topic_feature) if there are more than 1 person working on a feature together
      5. That topic branch is treated as a master - no force pushes, everyone rebases and merges from their personal branches
      6. Topic branches are rebased with master periodically/sensibly and often times get built and deployed as beta for feature testing
      7. Topic branches are merged into master
    

There is a code review process at each step. Developers create merge requests
for their personal feature branches into the topic branch and then merge
requests for the topic branch into master for periodic code reviews.

We don't force push and maintain history. Proper commit message formats are
enforced to ensure that everything is standard and readable.

------
qznc
Git can adapt to any workflow. Why not start with whatever they are used to
from CVS and then tailor it to your needs over time?

------
kevinherron
We use what is basically the "GitHub" flow... forks and PRs on an instance of
GitHub enterprise.

This is nice because in addition to the isolation it provides when everyone is
working on their own fork it's easy to code review changes BEFORE they land in
the "blessed" repository.

It's also nice because junior developers aren't pushing directly to the
blessed repo either.

This model is really nice for maintenance and small feature development.

For major new development (new version, major feature that multiple people
will work on) we tend to revert back to the behavior of committing directly to
the blessed repo.

------
HHalvi
For 5-10 people it depends on what everyone is doing. I typically push some
code out in the wild (master) for stuff that wont change and do releases or
branching for incremental updates and patches. Git Branching + Git Releases
should help you out mostly also bonus if you are using github throw in some
good 'ol kanaban action using projects.

------
adipirro852
GitHub flow is the ideal way to go IMO. It is simple, easy to understand, and
widely used.

In the end, however, it is going to come down to the specifics of your app and
environment. What sort of CI do you have set up? Do you have anything that
controls when or how you are able to release code? These types of things are
what generally push teams to other models.

------
zachrose
Like others are saying here, the branch named "master" is always deployable.

Feature branches are named after a ticket. Pull requests are across branches
in the same repo, not across repos. (It's marginally easier to collaborate on
feature branches if they're all in the same repo.)

We don't (yet) do full continuous deployment, so many feature branches get
grouped together before a release. Our strategy is to test* each feature
independently and then merge all the tickets together to a branch named
"staging". The staging branch then gets run against some extra
regression/acceptance tests and whatever manual tests we may want. If they
pass we merge to master, tag, and deploy.

Seems fine so far. Specifics about our tests and deployment process drive the
Git workflow more than anything else.

*Run the test suite, test manually, whatever.

------
cdevs
Quarterly website release cycle with 3-5 developers. usually one liner bug
fixes are the only thing pushed to master without a branch as in master ->
master. Everything else is a branch / independent feature each developer is
working on and we pull them all into a staging copy of master to pretest Which
makes it easy to just delete the staging if we want to repull a feature or two
and scrap what other features we pulled, once staging is well tested we merge
with master on bitbucket as the new release.

The biggest change for us when we starte was do not push features for the 3
month release into master so at any moment or bug fix master is always ready
to go live anywhere without some dumb new feature we don't want. Keep master
clean dammit :)

------
golergka
I think that a lot of people here make assumptions about the project that are
not necessarily true. For example "everyone can deploy from master at anytime"
is a great rule for a website that can actually be deployed by one click of a
button, but a very bad practice for an iOS app, each new version of which can,
theoretically, spend up to two weeks in review.

Also, what's your QA process and what is the usual quality of your builds? How
R&D heavy are your new features, and how long do they typically take to
develop? Are your programmers own different parts of the codebase, or is every
one of them able to work on anything?

Without all this details it's impossible to know which workflow is ideal for
your particular team.

~~~
JimDabell
> For example "everyone can deploy from master at anytime" is a great rule for
> a website that can actually be deployed by one click of a button, but a very
> bad practice for an iOS app, each new version of which can, theoretically,
> spend up to two weeks in review.

What is meant by that is that what ends up in master should always be working,
complete, tested code, not half-finished stuff. It doesn't mean that you need
to deploy each and every commit to the public. It means that master is the
canonical source of truth for the current state, disregarding tasks that are
not yet complete. It means that there's a solid base for people to branch from
without worrying about things that are temporarily broken.

What I normally do with iOS teams is have the CI tool produce a new internal
build for every commit to master. That way everybody, including testers, have
the most up to date version of the application readily available. That starts
to fall apart if developers treat master as just the place to put work-in-
progress stuff. It doesn't mean that we're submitting to Apple several times a
day, it just means that we're sure what's in master is " _done_ done".

~~~
golergka
> What I normally do with iOS teams is have the CI tool produce a new internal
> build for every commit to master. That way everybody, including testers,
> have the most up to date version of the application readily available. That
> starts to fall apart if developers treat master as just the place to put
> work-in-progress stuff. It doesn't mean that we're submitting to Apple
> several times a day, it just means that we're sure what's in master is "done
> done".

I did that, but it turned out of little relevance to our QA process: new
builds were happening once an hour, while QA wanted to get a version that they
can run at least a full regression on, and it takes much more than that. So
they ended up not using this CI builds at all, instead relying on a "release"
branch version which they would get once every few days.

------
rorykoehler
We use develop branch as a pre-master. All feature branches get pushed to
origin and pull requests created to merge feature branches to develop from
there. Once a sprint is finished we merge to master and deploy to staging.
Staging gets promoted to production using pipelines. As we are in early stages
the develop branch is good but I can see us dropping it and using only master
once we start doing daily releases.

------
znpy
From my experience working in a small team (3 devs + 1 designer). Here are
some tips:

1- every dev works on a topic branch

2- always rebase before committing

3- have a jenkins running somewhere\

4- everything that gets merged into master gets automatically built and tested

5- everything that gets merged into -RELEASE gets automatically built, tested,
packaged and deployed

6- Use issues from gitlab/github

7- Did I mention to always rebase before committing?

This isn't much and isn't exaustive, but it's a start.

~~~
revscat
One note: do not rebase published branches. Do so against local branches only.

------
segmondy
You need to figure out your release cycle first, before creating/picking a
workflow.

Will you only have one version of the app released at a time, (websites) or
multiple versions (native, mobile apps). Will you have just one team or
multiple teams working on the same app at the same time?

Answer these questions first, then and only then should you seek for a
workflow.

------
aikah
I'm going to say something not popular but I miss SVN when working with teams.
Git is great for distributed open source work but it sucks at being
centralized/mono repo . SVN made it easy for instance to lock some parts of a
mono repo or to even manage who can access to what. I don't get tall that for
free with Git.

------
quintes
Master, dev, feature and release. Mostly always in fact.

An admin merges a release back into Master and back through to dev after a
milestone build, demo or production release.

Keep the same Workflow with other teams in your organisation if it exists -
unless it is fatally flawed - so that team members moving around have the same
experience. Consistency and all that

------
zoul
I am currently solving the same problem and what helped me a lot was the Git
manpage about workflows:

[https://www.kernel.org/pub/software/scm/git/docs/gitworkflow...](https://www.kernel.org/pub/software/scm/git/docs/gitworkflows.html)

------
richerlariviere
The link is down. Here is the cache version
[https://webcache.googleusercontent.com/search?q=cache:Vk2On-...](https://webcache.googleusercontent.com/search?q=cache:Vk2On-9psscJ:https://msdn.microsoft.com/en-
us/magazine/mt790182.aspx)

------
Walkman
Everyone says what Git branch workflow should you use, but honestly, it can be
complicated especially for junior developers.

Just commit everything to master and that's all! Sound stupid but worked best
for us. I have seen a big software company using this, I learned this from
them and never looked back!

~~~
bonzoq
Just make sure to rebase every time you start work to avoid merge conflicts,
but yes, this is the single most effective git workflow for small and probably
larger teams too! I'm in a small team where the lead dev comes from a top SV
company and he introduced this workflow and it works great.

~~~
blisse
Are you being serious or sarcastic?

~~~
yxhuvud
I'd assume he is serious. It is a lot simpler to avoid merge conflicts that
are hard to solve if you always rebase first.

------
gkya
If most know CVS already just use it. The burden of switching a tool and
learning a new one is not worth it if the old one is good enough. I'd just set
up a CC list for patch reviews, put a TODO file in the repo and go on with
whatever VCS my team is used to using.

~~~
amouat
CVS is terrible in comparison to modern VCS tools. It's not even atomic. I
strongly recommend against using it.

~~~
gkya
It's relatively worse in some areas but terrible is a blatant exaggeration.
Ignorant prejudice doesn't apply to technical decisions.

~~~
amouat
I honestly don't believe it is an exaggeration. Take a look at this video for
Linus's thoughts
[https://www.youtube.com/watch?v=4XpnKHJAok8](https://www.youtube.com/watch?v=4XpnKHJAok8)

------
qznc
There is the philosophical discussion, if you should rebase or not. If your
team comes from CVS there is probably no bias yet. Pick for yourself if you
prefer a clean or an accurate history.

------
NicoJuicy
I Have 3 main branches, alpha, beta and master.

Next to feature branches.

Jenkins for updating

Beta = production databases, but automatically copied, to avoid production
errors ( lots of parameters to customize stuff)

No develop in master, just merging

------
sdrothrock
Any advice for a workflow using Gitlab?

~~~
mirasmithy
Take advantage of GitLab CI.

~~~
atsaloli
[https://about.gitlab.com/gitlab-ci/](https://about.gitlab.com/gitlab-ci/)

I'm putting together a course on GitLab CI. It's powerful stuff!

~~~
sdrothrock
This looks great! Thank you. :)

Is there a contact address for basic non-technical feedback?

~~~
atsaloli
I didn't mean to claim credit for GitLab's CI page. I was just posting the URL
to be helpful.

You can get in touch with GitLab via
[https://about.gitlab.com/contact/](https://about.gitlab.com/contact/)

I _am_ developing a tutorial on GitLab CI which I'll post on Show HN once done
and I'll mention it in this thread.

