GitRoot

Craft your forge, Build your project, Grow your community freely
 1---
 2id: "4f8d"
 3priority: 75
 4assignee: null
 5status: v0.5.0
 6---
 7
 8# Found ancestor rework
 9
10Today we need to `found acestor` when user push a new branch or force push an existing branch. All this code start in [ssh](../app/server/ssh.go).
11
12## Problem
13
14This method run through all branches and try to find previous commit. It's huge in terms of compute and not always true.
15
16## Solution
17
18After investigation go-git permit to add an observer on a packfile deserializer to store all data. This does nothing in term of computing and is every time exact.
19
20## What to do?
21
22In go git:
23
24- be able to create a `NewServer` with an optional packfile.Observer in `go-git/plumbing/server/server.go`
25- in the same file create a session with the observer `NewReceivePackSession` => `s.handler.NewReceivePackSession(sto, s.ob)`
26- in the same file add it to the session `NewReceivePackSession` => `return &rpSession{ob:ob,...}`
27- in the same file give the observer to the parser `ReceivePack` => `s.writePackfile(r, s.ob)`
28- in the same file use it when write `writePackfile` => `packfile.UpdateObjectStorage(s.storer, r, ob)`
29- finally use it in `plumbing/format/packfile/common.go` with `UpdateObjectStorage` => `p := NewParser(packfile, WithStorage(s), WithScannerObservers(ob))`
30
31In gitroot:
32
33```golang
34type Observer struct {
35	previousType plumbing.ObjectType
36	logger       logger.Logger
37}
38
39func (*Observer) OnHeader(count uint32) error {
40	return nil
41}
42
43// OnInflatedObjectHeader is called for each object header read.
44func (o *Observer) OnInflatedObjectHeader(t plumbing.ObjectType, objSize int64, pos int64) error {
45	o.previousType = t
46	if o.previousType == plumbing.CommitObject {
47		o.logger.Warn("header", logger.NewLoggerPair("type", t.String()), logger.NewLoggerPair("pos", pos))
48	}
49	return nil
50}
51
52// OnInflatedObjectContent is called for each decoded object.
53func (o *Observer) OnInflatedObjectContent(h plumbing.Hash, pos int64, crc uint32, content []byte) error {
54	if o.previousType == plumbing.CommitObject {
55		o.logger.Warn("new hash", logger.NewLoggerPair("hash", h.String()), logger.NewLoggerPair("pos", pos))
56	}
57	return nil
58}
59
60// OnFooter is called when decoding is done.
61func (o *Observer) OnFooter(h plumbing.Hash) error {
62	return nil
63}
64```
65
66then use it in [ssh](app/server/ssh.go) `handleReceivePack` with:
67
68```golang
69o := &Observer{logger: session.logger}
70svr := server.NewServer(ld, o)
71```
72
73## Remarks
74
75I have played with it and it seams to give commits sorted from top to bottom.
76
77Be carreful with multiple branch push because we don't know what commit is related to what branch.