►
Description
A 1-hour training video for contributors new to GitLab and Gitaly.
Demonstrate how usually Git hooks are run by
git-receive-pack, but sometimes by gitaly-ruby. Deep dive into
UserCommitFiles: where do those hooks actually get run? A look at
UserMerge. How does Gitaly make merge commits. A look at the
implementation of the special feature where users are not allowed
push to a branch, but are allowed to merge into it.
Recorded 2019-03-21
A
Hello
welcome
to
the
sixth
giddily
training
video,
where
we
look
at
how
quickly
fits
into
the
rest
of
kit
lab.
Last
week
we
looked
at
the
fetch
source
branch
RPC
and
how
Italy
internally
replicates
kit
data
between
Forks
to
make
it
possible
to
have
merge
requests
across
Forks
today,
I
want
to
look
at
what
happens
in
a
merge
request
and
specifically
at
how
Italy
creates
commits
on
behalf
of
a
user
and
also
how
Italy
sort
of
fakes
doing
a
gate,
push
to
itself.
A
A
So
this
is
a
GDK
running
a
my
my
local
machine
and
get
up
Enterprise
Edition.
We
hit
the
edit
button.
The
edit
button
is
also
an
example
of
the
gait
lab,
creating
a
comment
on
behalf
of
the
user.
So
maybe
the
merges
themselves
are
not
that
different
from
how
the
Edit
button
works.
So
maybe
we
just
end
up
looking
at
this
button
if
most
of
it
works
the
same
so
I've
added
the
file
I'm
going
to
commit
the
changes
that
works.
A
A
A
A
A
Then
this
is
where
I
would
normally
be
editing,
Gately,
source
code
and
running
tests,
but
this
is
gtk
and
when
you're
running
gtk
in
development
mode,
it
runs
a
quasi,
isolated
copy
of
Catelli
that
is
in
the
Italy
stash
assembly
directory.
So
these
are
actually
the
files
that
I
care
about.
I
just
told
you
that
we're
moving
these
hooks,
so
you
can
see
that
the
actual
hook
is
still
in
a
vendor
subdirectory
of
Catelli,
and
this
thing
is
just
a
shim
that
launches
that
thing.
A
So
this
thing
does
a
directory
name
resolution
and
uses
a
relative
path
to
go
to
that
other
file.
So
I
think
this
is
the
hook.
File
I
want
to
open
to
do
fun,
stuff
and
already
have
it
open
here.
If
I
want
to
be
sure
I
just
make
it
feel,
because
if
the
pre
received
fails,
then
you
get
a
message
that
yells
at
you.
A
A
Yes,
so
I
found
the
right
file
now.
The
thing
I
wanted
to
show
is
that
is
how
this
compares
to
a
normal
push,
and
one
of
the
thing
things
that
is
that
I,
maybe
haven't
shown
yet
or
not
in
much
detail-
is
how
these
hooks
get
invoked.
So
I
made
some
edits
to
my
local
Italy,
where
I
have
to
quickly
executable
populate
this
environment
variable
with
the
process
ID
of
the
currently
running
Gately
process
and
I
wrote
some
code
in
this
hook.
A
A
But
if
I
activate
this,
if
I
come
on
this
code
and
I
run
this
now
then,
and
let's
just
truncate,
that
file.
A
A
A
That's
there's
a
complication!
Kid
received
back
process.
So
this
is
the
thing
accepting
to
get
push
and
that's
the
thing
that
then
runs
the
parry
receive
folk.
So
normally
this
is
gets.
The
job
of
kid
breed
receive
sorry
of
get
receive
back.
It
is
good,
receives
back,
receive,
backs
job
to
run
hooks
around
the
transaction
where
the
refs
actually
get
updated,
and
what
I
wanted.
The
main
thing
I
wanted
to
show
today
is:
maybe
I'll
get
there
very
quickly.
A
A
A
And
what's
interesting
about
this
is
that
this
is
completely
going
through
the
back
door
and
there
is
no
there's,
no
gate
replication
traffic
of
any
sort
going
on
here,
because
gisli
ruby
actually
creates
the
commit
directly
in
the
repository
as
a
kid
object,
and
then
it
already
exists.
We
just
don't
refer
to
it,
so
it
doesn't
know
it
exists
and
then,
by
doing
a
replicate,
we
make
it
aware
of
the
existence
of
new
commits
and
we
simulate
what
would
have
happened
during
a
real
push.
B
A
A
Almost
any
transaction
or
any
query
Inc
it's
in
false,
looking
up
the
refs,
so
the
ref
database
is
much
smaller
and
get
will
always
try
to
load
it
into
memory.
That's
a
key
value
store
that
would
result
that
contains
the
names
of
your
branches
and
your
tags,
and
then
everything
in
the
ref
database
is
supposed
to
point
to
a
valid
objects,
but
it
does
not
go
looking
in
its
object
database
until
you
give
it
an
object,
ID
to
look
for
so,
on
the
one
hand,
so
let
me
try
to
write
that
down.
A
A
Reachable
is
the
word
that
is
used,
which
will
make
yeah
that's
sort
like
a
graph
theoretic
word.
So
yeah,
that's
the
process
there,
and
this
is
yeah.
This
is
quite
different
from
normal
Bush,
even
though
a
normal
push
might
create
a
reference
for
commit
that
already
exists
on
the
server.
So
then
you're
also
only
doing
ref
updates,
but
in
the
typical
case
of
a
normal
push
like
what
I'm
doing
here
when
I
do
it's
commits,
allow
empty.
This
creates
a
new
object
that
then
doesn't
exist
yet
on
the
server.
A
A
A
Hopefully,
get
that
never
runs
to
hook,
Sandra's
bills
out
at
the
moment
it
realizes
you're
wasting
its
time,
but
I
suspect
that
the
ref
updates
I'm,
not
sure
of
it.
I
suspect
it
might
be
at
the
end
of
the
stream,
and
if
it's
at
the
end
of
the
stream,
then
the
server
doesn't
know
that
there
is
no,
that
the
list
of
represent
until
it
reached
the
end
of
the
stream.
So.
A
A
It's
legacy
code,
where
the
organization
just
doesn't
make
a
lot
of
sense
it
it's
somehow
it's
one
of
these
things
that
somehow
works
and
that
we're
a
bit
hesitant
to
touch.
That
is
also
I
mentioned
that
the
fact
that
all
these
commits
that
get
lab
creates
on
behalf
of
the
user.
The
fact
that
it
happens
in
Gately
Ruby
is
because
we
have
an
existing
bowl
of
nut
there
that
works,
and
we
didn't
want
to
duplicate
that
bowl
of
mud
on
the
other
hands,
so
we're
sort
of
stuck
with
that
parts.
A
There's
another
reason
which
is
maybe
the
more
important
reason,
which
is
that
some
of
that
application,
some
of
that
stuff
that
creates,
commits
uses,
features
of
rugged
or
Lib
get
to
which
is
the
underlying
C
library
that
we
don't
have
in
regular
gates.
So
some
of
them
would
be
hard
to
implement
without
Lipke
to
and
because
squiggly
ruby
is
currently
the
only
place
where
we
can
use
lip
get
to.
Some
of
these
are
stuck
I,
think
it'll
be
Ruby.
For
that
reason.
A
So
now
that
I
say
this
out
loud
I
think
that's
actually
the
real
reason
they're
in
there,
but
because
of
yeah
I'll
show
what
it
looks
like
in
a
minute,
because
the
it's
just
fairly
complicated
logic
to
avoid
the
risk
of
having
a
duplicate
implementation
that
behaves
slightly
differently.
All
these
things
are
not
concentrated
there.
So
what
does
that
look
like?
And
where
is
this
stuff
and
what
will
be
a
good
RPC
to
look
at
I?
Guess
we
can
just
look
at
the
web
editor.
A
A
And
yeah
this
thing
is
forwarding
to
a
ruby
and
it
has
to
do
some
special
stuff.
It's
a
bi-directional
stream.
That's
because
this
RPC
can
update
an
arbitrary
number
of
files
and
there
is
no
limits
on
the
size
of
the
files
that
get
updated.
I
think
this
is
exposed
to
the
API.
So
in
principle
you
could
try
to
make
an
API
call
where
you
take
one
gigabyte,
binary
file
and
coat
it
with
base64.
A
Put
that
in
one
post
requests:
good
luck,
but
you
could
try
that
and
then
get
up
we'll
try
to
use
this
RPC
to
make
a
commits
that
creates
that
one
gigabyte
file
as
a
good
blob
and
then
commits
it
so
to
handle
that
we
use
a
stream
RPC
on
this
stream
on
the
input,
because
we
don't,
we
can't
put
the
same
upper
bounds
on
the
size
of
the
of
the
inputs
and
I
guess
yeah
this
part
closed
and
received.
That
means
that
the
response
is
actually
sorry
response.
A
Yes,
this
means
that
the
response
is
actually
not
as
strange.
I
was
wrong:
it's
not
a
bi-directional
stream.
It's
a
stream
going
in
and
it's
a
single
response
going
back,
it's
just
success
or
in
our
success
yeah.
But
the
real
work
happens
on
the
ruby
side.
So
let's
go
there
and
there
we
should
use
so.
The
name
is
user,
commit
files,
but
I
need
to
use
lowercase
and
underscores
you.
A
A
So
if
you
would
have
sent
a
one
gigabyte,
base64
requested
to
one,
if
you
would
have
used
this
RPC
to
say,
I
want
to
create
a
file
with
this
one
gigabytes
of
binary
data,
then
slowly
in
this,
under
this
key
we're
building
up
one
Giga,
bytes,
plus
the
overhead
of
base64
in
memory
of
this
Gately
Ruby
process.
This
is
also
one
of
the
reasons
why
quickly
Ruby
is
not
so
great
with
memory
use.
A
A
More
than
once,
because
it
depends
on
the
form,
if
they're
using
the
web
ID,
then
it's
texts
and
then
we
force
it
to
be
utf-8,
so
I
guess,
then
we
have
only
one
copy,
but
I.
Don't
trust
this
code
not
to
make
a
few
copies
along
the
way.
So
you
have
at
least
one
copy
of
those
files,
and
if
it's
binary,
then
you
have
added
costs
of
having
an
intermediate
base64
representation
somewhere
I
mean
in
practice.
You
can't
commit
these
really
large
files
because
you
have
to
they.
A
At
the
same
time,
because
of
the
way
it
works,
updating,
changing
a
single
line
means
rewriting
the
whole
file,
so
you're
always
sending
the
whole
file
down
the
line
of
your
wire
yeah,
and
then
this
thing
uses
something
called
repo
multi
action.
So
that's
where
all
the
work
happens.
It
also
instance
a
it's.
A
user
objects,
github
user,
get
lab,
get
user
from
data
in
the
in
the
request.
So
this
is
a
description
of
the
user,
and
this
is
why
commits
in
the
web.
A
B
A
Well,
if
you're,
using
local
git
and
your
local
git
is
creating
the
commit
object.
So
it's
using
your
local
config,
but
if
the
abnormal
thing
about
features
like
the
merge
button
and
the
web
editor,
is
that
you're
not
creating
the
commits
you're
clicking
a
button
and
github
is
creating
a
community
and
get
lab
is
impersonating.
You
which
is
mm-hmm,
which
is
it
is
kind
of
what
you
expect,
but
if
you
think
about
it,
it's
also
kind
of
weird
and
this
weirdness
is
amplified.
A
If
you
start
thinking
about
signing
commits
because
collab
can
sign
your
commits
for
you,
because
then
Killip
would
have
to
have
your
GPG
key.
So
that's
never
going
to
happen.
But
when
you
look
at
the
commit
history
of
a
project,
that's
on
github,
a
bunch
of
those
comments
were
really
made
by
me
running
git
commands
and
some
of
them
were
made
by
gate
lab
and
if
somebody
else
had
a
gate
lab
instance.
Well
that
gate
so
permissive,
you
can
impersonate
anyone.
You
want
I,
guess
that's
the
point.
I.
B
Got
so
a
potential
future
feature
that
might
make
like
privacy
minded
people
or
offend
a
fun
authenticity
minded
people
happy
as
if
like
get
lab,
has
its
own
set
of
keys.
That
sign
on
your
behalf,
but
aren't
your
keys
to
show
that
this
user
was
logged
in
and
I
have
their
key
or
something
like
that.
That.
A
That's
an
interesting
idea,
yeah
and
I.
Guess
implicitly,
the
promise
of
an
app
like
git
lab
is
that
get
labs
application
logic?
Will
only
let
one
user
record
exist
with
your
name.
So
if
get
lab
made
the
purchase
commits,
then
your
user
names
on
it.
That
means
at
the
time
at
that
time
that
there
was
only
one
user
with
that
email
so
to
say,
because
that
is
a
unique
attributes,
but
when
you
think
about
it,
that
only
says
so
much
anyway.
A
Let's
let's
look
at
how
this
this
sausage
is
made,
so
wait.
I
was
looking
going
to
look
for
multi-action,
because
that
was
the
next
step.
That
is
a
the
function
that
actually
writes
this
so
we're
now
in
the
gait
lab
git
repository
class,
which
is
where
a
lot
of
the
Varden
a
lot
of
the
application
codes
they
used
to
live
on
the
real
side
that
did
this
stuff
used
to
be
in
a
class
with
his
name,
and
we
copied
that
code
over
and
we
have
a
class
with
the
exact
same
name
in
Gately
ruby.
A
Now
there
is
still
a
class
called
could
get
a
repository
on
the
kid
lips.
Ee
side,
so
you
can
get
nice
and
confused
by
this,
but
that's
actually
I
can
show
it
show
that
and
I
mean
no
I
won't
show
that
in
a
minute,
let's
not
make
it
more
confusing
that
it
has
to
be
so.
This
is
multi
action,
and
this
goes
into
something
called
operation
service.
A
But
so
that's
what
this
check
is
for
and
yeah,
then
we
have
another
utility
class
called
index,
get
up.get
index,
which
knows
what
these
actions
are
and
that
thing
will
apply
each
of
the
action.
So
the
actions
can
be
that
you
can
change
the
contents
of
the
file.
You
can
change
the
name,
you
can
change
the
file
modes
or
you
can
create
a
directory
or
you
can
delete
the
file.
Things
like
that.
A
A
Let's
go
back
to
multi
action,
so
in
the
end
we
just
hand
a
bunch
of
parameters
to
two
rugged,
but
a
lot
of
the
work
has
already
happened
here,
because
this
is
the
thing
that
created
the
commit
references,
all
the
objects.
If
you
are
committing
a
new
file,
then
that
file
has
to
be
written
into
the
kids
and
two
kids
object.
Database
is
a
blob,
so
that
already
happens
here.
A
So
here
all
those
things
get
committed
into
gate,
but
they're
dangling
objects
that
are
not
commits,
and
then
here
we
take
all
the
metadata
to
create
a
commit,
which
means
a
tree
message:
parents,
exactly
what
you
expect
you
know
commit.
This
is
actually,
if
you
compare
this
with
what
goes
on
in
the
commits,
it's
really
literally
the
same.
So
this
is
a
almost
literal.
Representation
of
a
kids
commit
object,
there's
a
tree.
It
is
a
parents
and
the
author,
a
committer
and
then
everything
after
that
is
the
message.
A
That's
what
a
commit
is
as
far
as
gate
is
concerned,
so
that
thing
gets
created
here
and
this
yields
the
ID
of
that
commits,
and
then
we
end
up
back.
Then
we
exit
this
do
ends
walk
you
see
if
I
can
somehow
so
that,
then
you
exit
this
block.
We
end
up
back
in
this
operation
service
thing
that
uses
that
committable
ID
to
actually
do
the
ref
transaction.
B
A
B
A
A
A
Even
this
out
a
bit,
so
this
is
the
preamble
and
this.
This
is
the
thing
that
reps
so
this
stuff
in
the
middle.
This
creates
the
dangling
commit,
and
this
thing
runs
before
and
after
because
there
is
a
do
ends,
so
this
thing
is
responsible
for
the
rev
updates
and
the
actual
Ruby
method
we're
looking
at
this
with
branch
so
that
it's
this
one
so
before
we
enter
this,
do
block
it.
It
does
some
work
of
its
own.
A
A
The
use
case
for
that
is
suppose
that
you
want
to
make
an
edits
to
the
readme
of
catalepsy
e,
but
you're,
not
a
member
of
the
collab
org
organizations.
You
don't
have
a
write
access
on
that
repo.
You
can
still
click
Edit
in
the
API
or
in
the
UI,
and
it
will
then
on-the-fly
create
a
fork
for
you
and
edits
the
file
in
your
fork
and,
if
necessary,
it
will
fetch
the
file.
I
guess
this
isn't
necessary
if
you've
already
had
a
fork
word.
A
B
A
A
This
is
some
conflict
states
that
we
are
writing
indicate
config
file,
that's
funny,
because
we
were
talking
about
that
the
other
day,
here's
the
yield,
so
this
yields
takes
us
into
actually
this
yield
takes
us
into
this
block.
So
we're
not
back
at
this
code
here
that
actually
creates
the
commented
dangling
commits.
A
A
A
It
happens
more
than
once
uh-huh
it's
not
it's
more
in
direction
of
the
hooks
uses
the
with
hooks
and
then
calls
out
dead.
Ref,
let's
see
so
what
does
with
Hook's
do
I
think
now
we're
getting
somewhere?
Oh
we're
going
to
another
class
okay.
So
this
goes
into
this
class
and
as
he
yields
on
that
great,
do
we
want
to
see
the
update
ref
or
do
you
want
to
see
how
we
run
the
hooks
around
the
update,
ref.
A
A
Because
if
you
would,
if
we
were
using
the
Arg
V,
then
you
you
can
pass
strings
for
your
arc
V
as
well,
so
I'm,
not
really
sure
I.
Don't
really
remember
why
we
did
it
like
this.
Maybe
we
didn't
want
to
leak
the
branch
names,
but
that's
not
not
very
strong
reason
not
to
do
it.
Well,
it
doesn't
matter
it's
good
update,
ref
and-
and
that
is
a
good
plumbing
command,
that
modifies
the
ref
database
and
it
is
at
as
smart
things
like.
A
A
A
A
A
It
records
the
order
of
the
hooks
and
their
significance
yeah,
so
yeah
this
thing
will
return
true
or
false.
So
if
it
fails,
if
the
exit
codes
not
0,
this
returns
false
and
then
this
message
gets
wrapped
in
this
exception
and
bubbles
up
the
stack,
and
this
actually
gets
passed
back
in
the
RPC
response
and
then
displayed
in
the
UI.
That
was
the
red
box.
A
So
we
yield
control
back
and
then
ref
update
happens
and
the
ref
update
was
up
in
this
file.
That's
this
guy,
so
this
actually
commits
the
ref
updates
to
get
ref
database.
And
after
that
has
happens,
we
end
up
back
in
this
class
and
we
run
the
post
receive
hook,
which
is
when
the
post,
what
which
is
what's
supposed
to
happen
the
post
receive,
is
there
to
have
notifications
and
events
happening
after
a
ref
changed
yeah.
So
that's
what
this
I
guess!
Yeah!
That's
the
purpose,
so
this
these
the
lines.
A
Okay,
we
hook
something
we
found
something
we've
got
sort
of
Rico
come
to
the
heart
of
this
yeah
in
this
class
here
at
the
bottom.
Get
lab
kit
hook
is
responsible
for
shelling
outs
and
running
these
things,
feeding
the
arguments
to
the
hoops
that
they
expects
and
capturing
the
outputs
that
sort
of
stuff.
A
A
Italy
Ruby
users
get
lab,
gets
repository,
multi
action,
multi
action,
grabs,
sorry
calls
operation
service.
This
is
another
one.
We
have
operation
surface
singular
and
we
have
operations
service
somewhere
else,
I,
never
know
which
one
we're
in
I
guess
this
one
is
singular:
I
call
operation
service
with
branch
and.
A
Block
is
responsible
for
creating
the
dangling
commit
that
will
end
up
on
the
branch.
If
all
goes
well
and
that's
not
a
given,
because
he
have
features
in
github
where
you
can
say
that
commitments
just
need
to
be
validated.
So
it
could
be
that
this
pre
receive
hook,
looks
at
your
commit
message,
so
you
could
be
that
if
his
file.
A
Then
this
would
go
down
the
system
all
the
way
here
until
we
create
the
dangling
comets
and
then
the
dangling
commits
its
ID
gets
presented
by
hook,
service
to
the
pre
receive
hook,
and
then
the
pre
receive
hook
makes
an
API
call
back
to
get
lap
on
the
internal
API
and
then
get
lab.
Looks
at
that
commit
and
says
well,
I
have
a
red
X
here
and
your
commit
message
doesn't
match
the
red
X.
So
no
and
then
we
receive
returns
with
exit
status.
One
and
the
whole
thing
gets
called
off.
B
A
B
A
Shall
we
look,
but
that's
how
multi-action
creates
this
data
in
the
object
database
yeah,
so
that
uses
the
index
class
at
first
and
this
thing
uses
rockets
an
object
called
rugged
index
so
repository
rockets.
This
is
an
instance
of
posit
Ori
targets
is
a
great
repository
and
when
you
instantiate
brokered
repository,
you
can
tell
it
where
its
data
directories
are
so
you
can
configure.
A
I
guess
we
can
say,
writes
with
a
string
and
:
blob
and
then
it
just
Rises
into
it
into
the
object
database.
So
this
is
pretty
much
making
direct
rugged
calls
to
create
the
gate
objects
we
want
to
own
here.
You
see
that
the
decoding,
which
is
great
when
writing
to
the
repo?
Oh,
so
if
we're
sort
of
wiggling
in
some
hotel
line
feeds
that
curly
mangling
here
lots
of
fun.
The.
A
It's
on
this
is
exposed.
The
user
commit
files.
Rpc
is
almost
directly
exposed
via
the
public
REST
API,
and
that
is
a
JSON
API.
So
the
first
iteration
of
this
thing
only
let
you
let
you
commit
files
with
text,
utf-8
text
data
and
at
some
point
somebody
came
in
and
said:
hey
I
want
to
commit
binary
stuff
too.
So
then
we
added
an
option
to
you.
Can
you
have
a
flag
on
the
API?
Where
you
can
say
this
is
binary?
A
No
so
this
base64
did
here
it
gets
unwrapped,
so
there's
a
and
as
a
field
somewhere
where
we
say
the
encoding
is
base64
if
that
field
is
set.
At
this
point,
we
decode
so
prior
to
this
line.
Contents
might
be
base64,
encoded,
binary
data,
but
then
we
we
shut
out
the
variable
and
we
override
it
with
its
decode.
A
A
A
Suppose
we
could
have
it
it
would
have
been.
Maybe
it
would
have
been
saying
there
for
us
to
do
the
base64
decoding
on
the
real
side.
But
this
is
the
sort
of
thing
where
we
had
a
lot
of
with
a
lot
of
code
to
migrate,
so
we
had
to
have
to
make
some
decisions,
so
we
expose
it
on
the
RPC
yeah,
not
sure
if
that
was
necessary
in
retrospect,
but
that's
how
it
works
now.
So
we're
probably
stuck
with
it.
A
A
This
thing
again
used
operation
percent
with
branch.
That's
the
same
wrapper
we
saw
before
and
it
does
something
so
what's
special
about
merge
is
actually
that
we
yield
to
commit
ID
all
the
way
back
to
get
lap
and
get
lap
plan
commits
it
in
sequel.
Before
the
hooks
run.
This
is
kind
of
mind-bending.
A
The
reason
this
wait
before
I'll
go
into
this
yield
later.
This
yield
is
special
about
the
merge
here.
The
community
comes
back,
this
gets
handed
back
to
with
branch,
and
then
we
go
back
into
the
wrath
of
dates
with
the
books
around
it's
the
same
transaction
stuff
that
I
showed
you
and
create
merge
commits
this.
Does
some
rugged
magic,
merge
commits
and
roguettes
creates
a
merge
commit
for
us,
so
it
doesn't
really
doesn't
do
that
much
and
I.
Could
it
doesn't
do
a
lot
of
magic
but
yeah?
B
A
That
happens
here,
so
this
thing
creates
returns,
rope
or
good
object.
It
as
a
ruby
method,
conflicts
question
mark,
and
if
that
thing
is
true,
then
there
were
conflicts
and
then
we
return
to
an
empty
return
which
means
in
Ruby
we
return
nil.
So
this
thing
can
return
nil,
and
so
that
was
here
so
this
thing
would
be
that's
interesting.
This
is
a
nil,
then
we
do
we
yield
nil
and
we
return
nil
and
I
guess
then
this
thing
will
raise
that
exception
and
then
we
bubble
mill
up
the
stack
again.
A
But
it's
it's
rugged.
Rugged
is
the
one
creating
doing
the
actual
merge
of
the
trees,
which
is
a
yeah
just
look
at
looking
at
text
files
and
history
and
trying
to
make
the
right
decisions
about
what
files
should
go,
where
all
that
logic
sits
there
in
rugged.
I
think
rugged
might
have
just
borrowed
it
from
gates,
because
it's
written
in
C
I,
don't
remember.
If
that's
the
case
and
a
rugged
is
also
the
thing
that
then
can
say
you
know
what
this
is
not
working.
There's
a
merge
conflicts
does
merge.
Conflict
is
really
just.
A
History
structure,
but
the
the
gate
allows
you
to
create
completely
pathological.
Merge,
commits
I,
could
take
two
branches
and
create
a
merge
commits
where
to
merge
everything
there's
zero
day
that
it
was
an
either
of
the
branches,
but
kids
wouldn't
see
that
or
care
it
would
still
be
a
merger
commit.
So
this
whole
the
whole
concept
of
conflicts
is
a
function
of
the
textual
merge
process.
A
A
You
see
the
the
similarity
with
user
commit
files
because
we
go
into
the
same
the
same
the
same
rapper
and
it's
the
same
thing
we're
here
we
create
a
dangling
commits.
This
merge
commit,
is
dangling
at
first
and
then
at
the
ends
of
this
block.
The
dangling
commit
idea
gets
handed
back
up
to
this
rapper
and
then
this
rubber
makes
a
rapper
makes
it
commits
on
the
target
branch.
A
Where
you
can
say
we
have
a
branch,
say
the
master
branch
and
we
have
a
bunch
of
users
who
are
allowed
to
update
the
master
branch
by
clicking
merge
on
immerse
requests,
but
they
are
not
allowed
to
push
directly
to
the
master
branch.
This
is
a
feature
that
get
lapaz
an
adds
forever,
but
at
some
points
somebody
came
along
and
won
at
this,
and
it
makes
some
sense
if
you
think
about
the
merge
request.
A
Feature
is
about
having
a
review
process
and
if
you
can
just
push
straight
to
the
master
branch,
you
can
bypass
the
review
process.
So
this
is
the
idea
is
that
you
can
say
as
an
organization.
We
don't
want
people
to
bypass
the
review
process
on
this
repo.
There
will
be
no
pushes
on
the
master
branch.
You
have
to
use
the
the
merge
function.
Oh
that
makes
sense
as
a
feature
or
like
what
that
makes
sense.
Why
I
would
want
that.
But
how
do
you
build
that?
A
Because
all
our
logic
for
blocking
pushes
goes
through
the
hooks
and
the
hooks
don't
know
if
you're
pushing
actually
nowadays
they
do
know
if
you're
pushing
from
the
with
from
the
command
line
over
HTTP
or
with
that
or
SSH
or
if
it's
through
the
web
editor.
But
even
then
you
could
be
doing
some
funny
things
and
anyway,
the
way
this
feature
could
implement.
It
is
that
during
the
merge
we
create
the
merge
commit
and
we
know
the
commit
ID.
A
Then
we
yield
to
commit
ID,
and
this
actually
then
bubbles
back
up
to
the
RPC
handler
and
RPC
handler
sends
a
probe
of
protobuf
message
back
to
the
gate
lab
clients
in
the
middle
of
the
RPC.
We
send
it
back
one
message
with
the
commit
ID
and
then
get
lab
rights
that
commit
ID
in
sequel
as
an
attribute
of
the
merge
requests,
and
then
that
is
the
blessed
commit
ID
that
is
allowed
to
finalize
to
merge
the
merge
to
commit
commit.
A
So
when
we
return
from
this
line
that
commit
is
in
sequel
on
the
gait
lab
sides.
Now
we
yielded
here
we
bubble
back
up
and
we
end
up
in
the
pre
receive
hook
in
the
hook
service
class
that
I
lost,
but
we
ended
up
free
receive
hook.
That
makes
an
API
call
back
to
get
lab
and
that
API
call
includes
the
commit,
ID
and
then
get
lab
says
well.
Here's
somebody
coming
in-
and
this
would
close
this
merge
requests.
Do
you
have
the
right
commit
ID?
A
A
B
A
A
A
A
A
A
A
A
It
was
merged,
so
this
is.
This
is
the
thing
that
you
can
do
and
that
whole
thing
about
yielding
the
committee
black
back
is
about
blocking
being
able
to
block
this
because
in
all,
in
all
other
respects
this
doing
this
push
I
just
did
looks
a
whole
lot
like
what
would
have
happened
internally
with
the
RPC.
That
creates
a
merge
comments,
but
when
I
do
this
push
the
data?
The
database
on
the
gate
website
does
not
know
this
commit
ID
and
is
not
set
to
accept
that
commit
ID.
A
B
A
A
A
B
A
A
Well,
I
hope
this
is.
Why
is
there
no
pipeline?
No,
why
is
there
a
pipeline,
because
this
is
a
local
house?
Is
that
I
don't
have
CI,
so
it
is
now
going
to
hang
until
CI
happens.
Well,
maybe
I
don't
know
well
I
thought
we
will
be
looking
at
more
than
just
this
topic,
but
I'm
always
wrong
about
that.
So,
but
now
now
we've
seen
yeah
and
I.
We've
seen
this
thing,
and
this
is
to
me
this-
is
it
like
it
feels
like.
We
now
have
covered
the
three
different
ways:
that's
data.
A
It
gets
pushed
into,
get
lab,
there's
SSH
push,
there's
HTTP
push,
and
then
there
is
this
behind-the-scenes
thing
where
we
create
dangling
commits
and
do
our
own
little
ref
transaction
in
Ruby.
That's
that
runs
the
same
hooks
that
would
have
been
running
during
a
real
good
push
and
yeah
I
don't
know.
Yet
what
will
be
the
next
topic
but
I
feel
like
this
is
like
a
nice
milestone
for
the
training
sessions
that
we've
now
reached
this
okay
time
for
me
to
see,
if
I
can
turn
off
the
recording
again
without
fumbling
bye,
everyone
good
bye.