Skip to content

Latest commit

 

History

History
239 lines (173 loc) · 6.28 KB

git-repo.md

File metadata and controls

239 lines (173 loc) · 6.28 KB

GitRepo (class)

An object that points to a git repository on disk and provides utility methods for getting information from that repo.

To use it, construct a GitRepo object, passing in the path to the repo:

// The path here is just an example
const repo = new GitRepo("/home/suchipi/Code/yavascript");

Then, you can use methods/properties on the repo object:

console.log(repo.branchName() || repo.commitSHA());
declare class GitRepo {
  static findRoot(fromPath: string | Path): Path;
  constructor(repoDir: string | Path);
  repoDir: Path;
  commitSHA(): string;
  branchName(): string | null;
  isWorkingTreeDirty(): boolean;
  isIgnored(path: string | Path): boolean;
}

GitRepo.findRoot (static method)

Given a path to a file or folder on disk, searches upwards through the directory ancestry to find a .git folder, then returns the Path that contains that .git folder. If no .git folder is found, an error will be thrown.

For example, if you have a git repo at /home/suchipi/Code/my-project, such that /home/suchipi/Code/my-project/.git exists, calling GitRepo.findRoot("/home/suchipi/Code/my-project/src/index.js") will return a Path object pointing to /home/suchipi/Code/my-project.

This function can be useful in order to set the current working directory of a script relative to the root of the git repo the script appears in. By doing so, the script can be invoked from any directory.

For instance, consider this theoretical filesystem layout:

my-project
- src
  - my-script.js
- README.md

If my-script.js contained the following content:

#!/usr/bin/env yavascript

cat("README.md");

Then running src/my-script.js would print the contents of the README as expected.

However, suppose someone ran the script from a different folder:

$ cd src
$ ./my-script.js

Now an error occurs!

To make the script resilient against this, you can use cd at the top of the script:

#!/usr/bin/env yavascript

// __dirname is a special variable that refers to the folder the current script is in.
cd(__dirname);
cd("..");

cat("README.md");

However, if the location of my-script.js later changes, you will have to remember to update the script. For instance, if src/my-script.js got moved to src/tools/my-script.js, you would need to update the script like so:

#!/usr/bin/env yavascript

cd(__dirname);
cd("../.."); // Changed this line

cat("README.md");

Since README.md will always be in the repository root, using GitRepo.findRoot would make the cd resilient against file moves:

#!/usr/bin/env yavascript

cd(GitRepo.findRoot(__dirname));

cat("README.md");

Depending on how you anticipate your codebase changing over time, and how you expect others to use your scripts, it might make sense to use cd(__dirname), cd(GitRepo.findRoot(__dirname)), or no cd at all. Pick what makes the most sense for your situation.

static findRoot(fromPath: string | Path): Path;

GitRepo (constructor)

Creates a new GitRepo object for the given repo on disk.

constructor(repoDir: string | Path);

GitRepo.prototype.repoDir (Path property)

The root folder of the git repo that this GitRepo object represents (the folder that contains the '.git' folder).

repoDir: Path;

GitRepo.prototype.commitSHA (method)

Returns the full SHA-1 hash string associated with the repo's current commit.

For example:

const repo = new GitRepo(".");
const sha = repo.commitSHA();
console.log(sha);
// "2a0a15f9872406faebcac694562efeae3447a4ba"

To obtain this information, the command git rev-parse HEAD gets run within the repo's directory.

If the repo has unstaged or uncommitted changes, that state will NOT be reflected in the SHA-1 hash. As such, it may be desirable to use this method in conjunction with GitRepo.prototype.isWorkingTreeDirty.

commitSHA(): string;

GitRepo.prototype.branchName (method)

If the commit SHA the git repo is currently pointed at is the tip of a named branch, returns the branch name. Otherwise, returns null.

This is done by running git rev-parse --abbrev-ref HEAD within the repo directory.

Example:

const repo = new GitRepo(".");
const branch = repo.branchName();
console.log(branch);
// "main"

The most common situation where there is no current branch is when the repository is in "detached HEAD" state.

branchName(): string | null;

GitRepo.prototype.isWorkingTreeDirty (method)

Returns a boolean indicating whether there are uncommited changes in the git repo. true means there are changes, false means there are no changes (ie. the repo is clean).

This is done by running git status --quiet within the repo directory.

isWorkingTreeDirty(): boolean;

GitRepo.prototype.isIgnored (method)

Returns a boolean indicating whether the provided path is ignored by one or more .gitignore files in the repository.

Example:

const repo = new GitRepo(".");
const ignoreStatus = repo.isIgnored("README.md");
console.log(ignoreStatus);
// false

To obtain this information, the command git check-ignore <the-path> gets run within the repo's directory.

An error will be thrown if the provided path is not within the repository's directory tree. For instance, calling gitRepo.isIgnored("/tmp") on a gitRepo pointed at /home/suchipi/my-project would throw an error, because /tmp is not a child of /home/suchipi/my-project.

NOTE: When passing relative paths to isIgnored, they will be resolved relative to the repo root, NOT relative to pwd(). It's best practice to always pass around absolute paths in your program instead of relative ones so that this type of ambiguity is avoided.

isIgnored(path: string | Path): boolean;