Skip to content

Commit a007ecb

Browse files
authored
Merge pull request #4 from zikani03/zikani03/issue#3
feat: Make in-memory option, closes #3
2 parents 85da027 + f832342 commit a007ecb

File tree

4 files changed

+73
-13
lines changed

4 files changed

+73
-13
lines changed

README.md

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,29 @@
11
git-monorepo
22
============
33

4-
Make Git monorepos like a boss.
4+
> Make Git monorepos like a boss.
5+
6+
`git-monorepo` is a tool that allows you to combine two or more Git repositories into one repository and preserves the commit history for each repo as well as the directory structure.
57

68
## Features
79

8-
- Preserve commit history for each repo
9-
- Preserve Directory structure of each repo
10-
- Ordering Commits chronologically
10+
- Preserves commit history for each repo
11+
- Preserves Directory structure of each repo
12+
- Orders Commits chronologically
13+
14+
## Building
15+
16+
git-monorepo requires atleast Go 1.18 to build.
17+
18+
```sh
19+
$ git clone https://github.com/zikani03/git-monorepo
20+
$ go build -o git-monorepo ./cmd/main.go
21+
```
1122

1223
## Usage
1324

25+
> NOTE: It's currently very CPU intensive at the moment, I'm gonna look for ways to reduce CPU usage. May also be memory intensive if you use the `--in-memory` flag. I also haven't tried it on very large repos (i.e. repos with very many many commits)
26+
1427
### Create monorepo locally
1528

1629
```shell
@@ -25,9 +38,13 @@ $ git-monorepo init --sources https://github.com/nndi-oss/ussdproxy,gh:nndi-oss/
2538

2639
## IDEAS / TODO
2740

28-
- Make Submodules instead of mangling history
29-
- Parallel clones
30-
- Create monorepo locally and push to github
41+
- Support "squashing-merging" - that is merge the repos without preserving fine-grained commit history
42+
43+
- Make Git Submodules instead of mangling history
44+
45+
- Clone repositories in parallel
46+
47+
- Create monorepo locally and push to github (and other git hosting services)
3148

3249
```shell
3350
$ git monorepo init --preserve-history \

cmd/main.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ type InitCmd struct {
3030
Daemonize bool `help:"Daemonize or run in foreground"`
3131
Mangle bool `help:"Combine files from repos in one directory (not recommended!)"`
3232
PreserveHistory bool `help:"Preserve history from the repos"`
33+
InMemory bool `help:"Clone repos in-memory instead of a temporary directory on file system"`
3334
MakeSubmodules bool `help:"Add child repositories as submodules (not ideal!)"`
3435
TargetDir string `name:"target" help:"The target directory to create repo in. Must not exist" type:"path"`
3536
Sources []string `help:"Source repositories with support for 'git-down' shortcuts"`
@@ -47,6 +48,9 @@ func CheckIfError(err error) {
4748

4849
func (r *InitCmd) Run(globals *Globals) error {
4950
repo := gitMonorepo.NewMonorepoFromSources(r.Sources)
51+
if r.InMemory {
52+
repo = gitMonorepo.NewMonorepoFromSourcesInMemory(r.Sources)
53+
}
5054
err := repo.Init(r.TargetDir)
5155
CheckIfError(err)
5256

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module github.com/zikani03/git-monorepo
22

3-
go 1.17
3+
go 1.18
44

55
require (
66
github.com/alecthomas/kong v0.5.0

monorepo.go

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"io"
66
"io/fs"
7+
"os"
78
"path"
89
"sort"
910
"strings"
@@ -21,6 +22,7 @@ type Monorepo struct {
2122
// done chan bool
2223
Dir string
2324
SourceRepositoryURLs []string
25+
UseInMemoryStorage bool
2426
}
2527

2628
type RepositoryCommit struct {
@@ -31,6 +33,14 @@ type RepositoryCommit struct {
3133
func NewMonorepoFromSources(repos []string) *Monorepo {
3234
return &Monorepo{
3335
SourceRepositoryURLs: repos,
36+
UseInMemoryStorage: false,
37+
}
38+
}
39+
40+
func NewMonorepoFromSourcesInMemory(repos []string) *Monorepo {
41+
return &Monorepo{
42+
SourceRepositoryURLs: repos,
43+
UseInMemoryStorage: true,
3444
}
3545
}
3646

@@ -63,14 +73,34 @@ func (m *Monorepo) initWithCommitsBetween(targetDir string, fromTime, toTime tim
6373

6474
worktreeDir := billyfs.New(targetDir)
6575

76+
dirsToClean := make([]string, 0)
6677
for _, urlSpec := range m.SourceRepositoryURLs {
6778
sourceRepositoryUrl := makeFullUrl(urlSpec)
68-
repo, err := git.Clone(memory.NewStorage(), nil, &git.CloneOptions{
69-
URL: sourceRepositoryUrl,
70-
})
71-
if err != nil {
72-
return fmt.Errorf("failed to git clone %s : %v", sourceRepositoryUrl, err)
79+
var repo *git.Repository
80+
var err error
81+
if m.UseInMemoryStorage {
82+
storage := memory.NewStorage()
83+
repo, err = git.Clone(storage, nil, &git.CloneOptions{
84+
URL: sourceRepositoryUrl,
85+
})
86+
if err != nil {
87+
fmt.Println(fmt.Errorf("failed to git clone %s : %v", sourceRepositoryUrl, err))
88+
return err
89+
}
90+
} else {
91+
tmpDirName, err := os.MkdirTemp(os.TempDir(), "monorepo_")
92+
if err != nil {
93+
return err
94+
}
95+
storage := filesystem.NewStorage(billyfs.New(tmpDirName), cache.NewObjectLRUDefault())
96+
repo, err = git.Clone(storage, nil, &git.CloneOptions{URL: sourceRepositoryUrl})
97+
if err != nil {
98+
fmt.Println(fmt.Errorf("failed to git clone %s to %s: %v", sourceRepositoryUrl, tmpDirName, err))
99+
return err
100+
}
101+
dirsToClean = append(dirsToClean, tmpDirName)
73102
}
103+
74104
// retrieves the branch pointed by HEAD
75105
repoRef, err := repo.Head()
76106
if err != nil {
@@ -166,5 +196,14 @@ func (m *Monorepo) initWithCommitsBetween(targetDir string, fromTime, toTime tim
166196
}
167197
}
168198

199+
// Clean up the tmp directories
200+
if len(dirsToClean) > 0 {
201+
for _, dirToPurge := range dirsToClean {
202+
if err := os.RemoveAll(dirToPurge); err != nil {
203+
fmt.Printf("failed to remove tmp directory at %s got %v\n", dirToPurge, err)
204+
}
205+
}
206+
}
207+
169208
return nil
170209
}

0 commit comments

Comments
 (0)