forked from chdsbd/vscode-githubinator
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgit.ts
More file actions
153 lines (142 loc) · 3.95 KB
/
git.ts
File metadata and controls
153 lines (142 loc) · 3.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import * as path from "path"
import * as fs from "mz/fs"
import * as ini from "ini"
interface IRemote {
fetch: string
url?: string
}
interface IGitDirectories {
git: string
commonGit: string
repository: string
}
export async function origin(
gitDir: string,
remote: string,
): Promise<string | null> {
const configPath = path.resolve(gitDir, "config")
if (!(await fs.exists(configPath))) {
return null
}
const configFileData = await fs.readFile(configPath, { encoding: "utf-8" })
const parsedConfig = ini.parse(configFileData)
for (const [key, value] of Object.entries(parsedConfig)) {
if (key.startsWith('remote "')) {
const origin = key.replace(/^remote "/, "").replace(/"$/, "")
if (origin === remote) {
const url = (value as IRemote).url
return url || null
}
}
}
return null
}
/** Get the SHA for a ref */
export async function getSHAForBranch(
gitDir: string,
branchName: string,
): Promise<string | null> {
const refName = `refs/heads/${branchName}`
// check for normal ref
const refPath = path.resolve(gitDir, refName)
if (await fs.exists(refPath)) {
return await fs.readFile(refPath, {
encoding: "utf-8",
})
}
// check packed-refs
const packedRefPath = path.resolve(gitDir, "packed-refs")
if (await fs.exists(packedRefPath)) {
const packRefs = await fs.readFile(packedRefPath, {
encoding: "utf-8",
})
for (const x of packRefs.split("\n")) {
const [sha, refPath] = x.split(" ") as [
string | undefined,
string | undefined,
]
if (sha && refPath && refPath.trim() === refName.trim()) {
return sha
}
}
}
return null
}
/** Get the current SHA and branch from HEAD for a git directory */
export async function head(
gitDir: string,
commonGitDir?: string,
): Promise<[string, string | null] | null> {
const headPath = path.resolve(gitDir, "HEAD")
if (!(await fs.exists(headPath))) {
return null
}
const headFileData = await fs.readFile(headPath, { encoding: "utf-8" })
if (!headFileData) {
return null
}
// If we're not on a branch, headFileData will be of the form:
// `3c0cc80bbdb682f6e9f65b4c9659ca21924aad4`
// If we're on a branch, it will be `ref: refs/heads/my_branch_name`
const [maybeSha, maybeHeadInfo] = headFileData.split(" ") as [
string,
string | undefined,
]
if (maybeHeadInfo == null) {
return [maybeSha.trim(), null]
}
const branchName = maybeHeadInfo.trim().replace("refs/heads/", "")
const sha = await getSHAForBranch(commonGitDir ?? gitDir, branchName)
if (sha == null) {
return null
}
return [sha.trim(), branchName]
}
export function dir(filePath: string) {
return walkUpDirectories(filePath, ".git")
}
function resolveCommonGitDir(gitDir: string): string {
const commondirPath = path.resolve(gitDir, "commondir")
if (fs.existsSync(commondirPath)) {
const commondir = fs.readFileSync(commondirPath, "utf8").trim()
return path.resolve(gitDir, commondir)
}
return gitDir
}
function walkUpDirectories(
file_path: string,
file_or_folder: string,
): IGitDirectories | null {
let directory = file_path
while (true) {
const newPath = path.resolve(directory, file_or_folder)
if (fs.existsSync(newPath)) {
if (fs.lstatSync(newPath).isFile()) {
const submoduleMatch = fs
.readFileSync(newPath, "utf8")
.match(/gitdir: (.+)/)
if (submoduleMatch) {
const gitDir = path.resolve(directory, submoduleMatch[1])
return {
git: gitDir,
commonGit: resolveCommonGitDir(gitDir),
repository: directory,
}
} else {
return null
}
} else {
return {
git: newPath,
commonGit: newPath,
repository: directory,
}
}
}
const newDirectory = path.dirname(directory)
if (newDirectory === directory) {
return null
}
directory = newDirectory
}
}