Building Git with Node.js and TypeScript - Part 0
Tags: typescript, git, node, javascript
Published: 2020-05-06 13:30:10

---
title: Building Git with Node.js and TypeScript - Part 0
published: true
description: A series of post following my process of building Git with Typescript, based on the book Building Git by James Coglan
tags: typescript, git, node, javascript
---

## Introduction

I recently found this amazing eBook, [_Building Git_](https://shop.jcoglan.com/building-git/), by James Coglan. 

> Building Git is a deep dive into the internals of the Git version control system. By rebuilding it in a high-level programming language, we explore the computer science behind this widely used tool. In the process, we gain a deeper understanding of Git itself as well as covering a wide array of broadly applicable programming topics

I'm not a Ruby developer, so I'll be implementing the Git clone, _jit_, using Node.js and Typescript. This blog series will track that process, and I'll do my best to not spoil the book either. It is full of some **incredible** details not just about Git, but also about file systems, operating systems, and more!

In this first post I'm going to share my local development environment and my code from chapter 3 section 1. There won't be a remote repository for my implementation at first, but later on, I'll be sure to upload and share that too.

Also, none of this series is sponsored and the links I provide to the book are not referrals. I'm writing this series because I like to [learn in public](https://www.swyx.io/writing/learn-in-public), and sharing links to the book because I want to support the author.

## Development Environment

For my local environment I'm using Visual Studio Code editor on macOS Catalina. I'll be using the latest versions of Node.js and TypeScript. At the time of writing this post, I'm using Node.js v14.2 and TypeScript v3.8; I'll be keeping these up to date in the future as well.

I started my project with:
```bash
mkdir jit-ts
cd jit-ts
npm init -y
npm i -D typescript @types/node
```
And then added the following sections to my `package.json`
```json
{
	"main": "./lib/jit.js",
	"types": "./lib/jit.d.ts",
	"bin": {
		"jit": "./lib/jit.js"
	},
	"scripts": {
		"build": "tsc -w -p ."
	}
}
```

Additionally, I prefer to use the built in VSCode debugger to step through and test my code so I have these two debug files in the `.vscode` directory:
### launch.json
```json
{
	"version": "0.2.0",
	"configurations": [
		{
			"type": "node",
			"request": "launch",
			"name": "jit-ts init",
			"program": "${workspaceFolder}/src/jit.ts",
			"preLaunchTask": "tsc: build - jit-ts/tsconfig.json",
			"postDebugTask": "jit cleanup",
			"outFiles": ["${workspaceFolder}/lib/**/*.js"],
			"args": ["init"]
		}
	]
}
```
### tasks.json
```json
{
	"version": "2.0.0",
	"tasks": [
		{
			"type": "typescript",
			"tsconfig": "tsconfig.json",
			"problemMatcher": [
				"$tsc"
			],
			"group": "build",
			"label": "tsc: build - jit-ts/tsconfig.json"
		},
		{
			"label": "jit cleanup",
			"type": "shell",
			"command": "rm -rf ${workspaceFolder}/.git"
		}
	]
}
```
These debug files will expand and change as the implementation grows, but these work good enough for the first section. 

Lastly, I created a typescript configuration and the source file:
```bash
mkdir src
touch src/jit.ts
npx typescript --init
```

### tsconfig.json
```json
{
	"compilerOptions": {
		"target": "es5",
		"module": "commonjs",
		"declaration": true,
		"sourceMap": true,
		"outDir": "lib",
		"rootDir": "src",
		"strict": true,
		"moduleResolution": "node",
		"esModuleInterop": true,
		"forceConsistentCasingInFileNames": true
	}
}
```

## Init Command

```js
#!/usr/bin/env node

import fs from 'fs'
import { resolve, join } from 'path'

function jit() {
	const command = process.argv[2]

	switch (command) {
		case 'init': {
			const path = process.argv[3] || process.cwd()
			const rootPath = resolve(path)
			const gitPath = join(rootPath, ".git")

			;["objects", "refs"].forEach(dir => {
				fs.mkdirSync(
					join(gitPath, dir),
					{ "recursive": true }
				)
			})

			console.log(`initialized empty jit repo in ${gitPath}`)
			break
		}
		default: {
			console.log(`jit: '${command}' is not a jit command`)
		}
	}
}

jit()
```

Chapter 3 section 1 is all about the `init` command. The code is simple to start and lacks input validation. Utilizing `process.argv` to access the command line arguments, the function starts by setting the command. Inside the `'init'` block, the code retrieves the input path from the command line arguments; this value also defaults to the user's current working directory. Next, it resolves the input path from a relative path to an absolute path and prepends `.git` to create the path for the git root directory.

> Wondering what the difference between relative and absolute paths are? The book does a fantastic job explaining the difference and why it is necessary to use an absolute path, so I encourage you to purchase a copy of [Building Git](https://shop.jcoglan.com/building-git/) for yourself and read the explanation on page 28 😉.

After path resolution, the function iterates over a shortlist of strings and generates directories using the `fs.mkdirSync` command. It uses the `recursive` property which was introduced in Node.js v10. 

Thats all the function does for now, and thus concluding the first bit of implementing Git using Node.js and TypeScript.

## Conclusion

I'm very excited about this series. Learning the intricacies of Git and building a clone in my favorite language will be a great learning experience. If you have enjoyed this first post and are interested in joining me on this learning journey, make sure to follow me on Twitter ([@ArrowoodTech](https://twitter.com/ArrowoodTech)) and here on Dev. And don't forget to check out the book, [Building Git](https://shop.jcoglan.com/building-git/).

Until next time, happy coding!