GitRoot

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