24-A์กฐ J238, J031
์ฐ๋ฆฌ์ ์ฒดํฌ ํฌ์ธํธ
-
init ๋ช ๋ น์ด
-
ํ์ผ๋ณ๋ก blob ์ค๋ธ์ ํธ๋ฅผ ์์ฑํ๋ค.
-
ํด์๊ฐ ์์ 8์๋ฆฌ๋ฅผ objects ํ์ ๋๋ ํ ๋ฆฌ๋ก ์์ฑํ๋ค.
-
๋๋จธ์ง ๋ถ๋ถ์ ํ์ผ๋ช ์ผ๋ก (์์์ ๋ง๋ ํด์๊ฐ ์์๋ฆฌ ๋๋ ํ ๋ฆฌ์) ์ ์ฅํ๋ค.
-
blob ์ค๋ธ์ ํธ ํ์ผ ๋ด์ฉ์ ์๋ณธ ํ์ผ์ zlib๋ก ์์ถํด์ ์ ์ฅํ๋ค.
-
-
add ๋ช ๋ น์ด
-
๋๋ ํ ๋ฆฌ์์ ์ ์ฒด ํ์ผ ๋ชฉ๋ก์ ํ์ํ๊ณ , ๊ฐ ํ์ผ ๋ด์ฉ์ ๋ํ sha256 ํด์ ๊ฐ์ ๋น๊ตํ๋ค.
-
commit์ด ์๊ฑฐ๋ ์ง์ commit ์ดํ ํด์๊ฐ์ด ๋ฌ๋ผ์ง ํ์ผ ๋ชฉ๋ก์ ์ ์ฅํ๋ค
-
-
status ๋ช ๋ น์ด
- add ๋ช ๋ น์ผ๋ก ๋ง๋ค์ด์ง ๋ณ๊ฒฝ๋ ํ์ผ ๋ชฉ๋ก์ ์ ์ฒด ๊ฒฝ๋ก์ ํจ๊ป ์ถ๋ ฅํ๋ค
-
commit ๋ช ๋ น์ด
-
blob ์ค๋ธ์ ํธ ์์ฑ
-
tree ์ค๋ธ์ ํธ ์์ฑ
-
commit ์ค๋ธ์ ํธ ์์ฑ
-
์ปค๋ฐ ๊ธฐ๋ก์ index์ ์ถ๊ฐํ๋ค.
-
-
log ๋ช ๋ น์ด
-
๋ช ๋ น ํ์์ mit log ๋๋ ํ ๋ฆฌ๋ช ์ด๋ค.
-
๋๋ ํ ๋ฆฌ๋ช /.mit/index/commits ์์ ์ปค๋ฐ์ ์ฐพ์์ ์ด๋ ฅ์ ์ถ๋ ฅํ๋ค.
-
-
commit ๋ง๋ค ํ์ฌ tree๋ฅผ ํ์ธํด์ ๋ณ๊ฒฝ๋ ํ์ผ๋ช ์ ํจ๊ป ํ์ํ๋ค
-
restore ๋ช ๋ น์ด
๋ฌธ์ ํด๊ฒฐ ๊ณผ์

init ๋ช ๋ น์ด
mit init ๋๋ ํ ๋ฆฌ๋ช
-
.mit ํ์ ๋๋ ํ ๋ฆฌ ์์ฑ
-
.mit ๋๋ ํ ๋ฆฌ ์๋์
/.mit/objects/์/.mit/index/ํ์ ๋๋ ํ ๋ฆฌ๋ฅผ ์์ฑ
add ๋ช ๋ น์ด
mit add ๋๋ ํ ๋ฆฌ๋ช
- ๋๋ ํ ๋ฆฌ์์ ์ ์ฒด ํ์ผ ๋ชฉ๋ก์ ํ์ํ๊ณ , ๊ฐ ํ์ผ ๋ด์ฉ์ ๋ํ sha256 ํด์ ๊ฐ์ ๋น๊ตํ๋ค.
- commit์ด ์๊ฑฐ๋ ์ง์ commit ์ดํ ํด์๊ฐ์ด ๋ฌ๋ผ์ง ํ์ผ ๋ชฉ๋ก์ ์ ์ฅํ๋ค
-
๋๋ ํ ๋ฆฌ์์ ์ ์ฒด ํ์ผ ๋ชฉ๋ก ์ดํด๋ณด๊ธฐ
-
ํ์ผ์ ๋๋ฉด์ ๋๋ ํ ๋ฆฌ๊ฐ ๋์ค๋ฉด ์ฌ๊ท์ ์ผ๋ก ๋๊ณ , ํ์ผ๋ช ๋ง ๋ฐ๋ณตํด์ ์ผ๋ฉด์
-
commit์ด ์๊ฑฐ๋ ์ง์ commit ์ดํ ํด์๊ฐ์ด ๋ฌ๋ผ์ง ํ์ผ ๋ชฉ๋ก์ .mit/index/ ์ ๋ณ๊ฒฝ๋ ๊ฐ์ ์ ์ฅ
(์ ์ฅ ํ์ - ํ์ผ ํด์๊ฐ / ํ์ผ ์๋ ๊ฒฝ๋ก)
์์
bc2db54bb59cfb6d25308054726bc209a126f668 somethingNew/test.txt
6b584e8ece562ebffc15d38808cd6b98fc3d97ea test.txt
๐ ๋๋ ํ ๋ฆฌ
-
์ถ๊ฐ๋ ํ์ผ(test.txt)
-
objects
-
index
์์: ๋๋ ํ ๋ฆฌ์ ์์ฑ test.txt (โcreate textโ)
ํ์ผ ์์ ํด์๊ฐ - 2e65efe2a145dda7ee51d1741299f848e5bf752e
git๋๋ก ์๊ฐํ์ ๋
1. mit add ๋๋ ํ ๋ฆฌ๋ช
2. ๋๋ ํ ๋ฆฌ๋ช
์์ ๋๋ ํ ๋ฆฌ ํน์ ํ์ผ์ ๋๋ค
- ํ์ผ์ผ ๊ฒฝ์ฐ -> ํ์ผ์ ๋ํด blob ํ์ผ์ ๋ง๋ค๊ณ , ํ๋์ ํธ๋ฆฌ์ ๊ธฐ๋ก
- ๋๋ ํ ๋ฆฌ์ผ ๊ฒฝ์ฐ -> ์ฌ๊ท์ ์ผ๋ก ๋๋ ํ ๋ฆฌ๋ช
์์ ๋๋ ํ ๋ฆฌ ํน์ ํ์ผ์ ๋๋ฉด์ ๋ชจ๋ ํ์ผ์ ๋ง๋ค๊ณ , ์ด๋ฅผ ํ๋์ ํธ๋ฆฌ์ ๋ฃ์ ๋ค์ ๊ทธ ํธ๋ฆฌ์ ํด์๊ฐ์ ์์ ํธ๋ฆฌ์ ๊ธฐ๋ก
3. ํด๋น ๋ชจ๋ ์ ๋ณด๋ค์ ๊ฐ์ง ์ต์์ ํธ๋ฆฌ(๋ฃจํธ ํธ๋ฆฌ) ๊ฐ์ฒด๋ฅผ ํ๋ ๋ง๋ค์ด object ๋ด์ ์ ์ฅ
4. .mit/index ์์ ํ์ผ์ ํ๋ ๋๊ณ ์ฌ๊ธฐ์์ commit ๊ฐ์ฒด์ tree ์์ฑ์๋ค๊ฐ ์ง์ด๋ฃ๊ธฐ
5. ๋์ค์ commit์ด ๋๊ธฐ ์ ๊น์ง add๋ฅผ ํ๋ฉด ๊ทธ๊ฒ ๊ณ์ ๊ฐฑ์ ๋จ
6. ๋์ค์ commit์ ํ๋ฉด commit message์ ํจ๊ป ์๋กญ๊ฒ commit ๊ฐ์ฒด๋ฅผ .mit/index/commits์ ์ ์ฅ
-a
-b
-c
-d
-e
-f
์ด๋ฐ ์์ผ๋ก ๋๋ ํ ๋ฆฌ๊ฐ ๋์ด ์๋ค๊ณ ๊ฐ์ ํ๋ฉด
a(๋ฃจํธ)
b(ํ์ผํด์๊ฐ) c(tree)
c -> d, e(tree)
e -> f
- .git/objects ํ์ผ ๋ด๋ถ
.git/objects
.git/objects/.DS_Store
.git/objects/d0
.git/objects/d0/5bdf0ee8f1f50e60cc2244a322d58cdd0ef873
.git/objects/bc
.git/objects/bc/2db54bb59cfb6d25308054726bc209a126f668
.git/objects/pack
.git/objects/6b
.git/objects/6b/584e8ece562ebffc15d38808cd6b98fc3d97ea
.git/objects/info
- index ํ์ผ ๋ด๋ถ (git add ๋ช
๋ น์ด ์คํ ํ ์์ฑ๋จ)
100644 d05bdf0ee8f1f50e60cc2244a322d58cdd0ef873 0 .DS_Store
100644 bc2db54bb59cfb6d25308054726bc209a126f668 0 somethingNew/test.txt
100644 6b584e8ece562ebffc15d38808cd6b98fc3d97ea 0 test.txt
test
-
ํด๋
-
ํ์ผ
-
ํ์ผ
-
mit add ๋๋ ํ ๋ช
-
๋๋ ํ ๋ฆฌ ๋ด์ ํ์ผ๋ค์ objects/2e/65โฆ ๋ฑ์ผ๋ก ๋ง๋ค์ด ์ ์ฅ
-
ํ์ผ๋ค์ ๋ชจ๋ ๊ฐ๋ฆฌํค๋ tree๋ฅผ objects ํด๋์ ์ ์ฅ
-
ํด๋น ํธ๋ฆฌ์ ํด์๊ฐ์ index์ ์ ์ฅ
-
ํธ๋ฆฌ๋ฅผ ๋ง๋ ํ, ํด๋น ํธ๋ฆฌ์ ํด์๊ฐ์ Index์ ์ ์ฅ
๋
ผ์ํ๋ ์ฌ์๋ค
- ํ์ผ๋ค์ ๋ชจ๋ objects ํด๋ ์์ ์ ์ฅํ๊ณ , ๋ณ๋์ฌํญ๋ฑ์ ๋น๊ตํ ๋ค์ Index ๋๋ ํ ๋ฆฌ ์์ ํ์ผ์ ์ด๋ฌํ ํ์ผ๋ค์ ๋ํ ํด์๊ฐ๋ค์ ๋ชจ๋ ๊ธฐ๋ก
status ๋ช ๋ น์ด
mit status ๋๋ ํ ๋ฆฌ๋ช
-
index์ ์ ์ฅ๋ ๋ณ๊ฒฝ ํ์ผ ๋ชฉ๋ก ์ค์์ ๋๋ ํ ๋ฆฌ ๋ช ์ ํฌํจํ๋ ํ์ผ๋ค ๋ชจ๋ ์ถ๋ ฅ
commit ๋ช ๋ น์ด
mit commit ๋๋ ํ ๋ฆฌ๋ช
-
์ฃผ์ด์ง ๋๋ ํ ๋ฆฌ๊ฐ ์ต์์ ๋๋ ํ ๋ฆฌ๋ก ๋์ด ์์ ๋, ํด๋น ๋๋ ํ ๋ฆฌ ์์ ํด๋๋ค์ ๋ํด์ ๋ชจ๋ blob ์ค๋ธ์ ํธ๋ฅผ ์์ฑ
-
object ํด์๊ฐ ์์ 8์๋ฆฌ๋ฅผ ํ์ ๋๋ ํ ๋ฆฌ๋ก ์์ฑํ๊ณ , ๋๋จธ์ง ๋ถ๋ถ์ ํ์ผ๋ช ์ผ๋ก ์ ์ฅ
-
ํ์ผ ๋ด์ฉ์ zlib์ผ๋ก ์์ถํด์ ์ ์ฅ
-
ํ์ผ์ ์ ์ฅํ๋ฉด์ tree ์ค๋ธ์ ํธ์ ์ ์ฅ๋ ๋ชจ๋ ํ์ผ๋ค์ ๊ธฐ๋ก
-
์ค๋ธ์ ํธ๋ blob๋ง๋ค blob ํด์๊ฐ, ์์ถ ํ ํ์ผ ํฌ๊ธฐ, ํ์ผ๋ช ์ ์ ๋ถ ๋ฐ๊ณ , ์ด๋ฅผ ๋ค์ ํ์ผ๋ก tree object ํ์ผ๋ก ์ ์ฅ(SHA256)
-
.mit/index/commits๋ฅผ ๋ณด๊ณ ์ปค๋ฐ์ด ์์ผ๋ฉด ๊ฐ์ฅ ์ต์ ์ ์ปค๋ฐ์ ๊ฐ์ ธ์ด
-
๊ฐ์ ธ์จ ์ปค๋ฐ์ ์๋ก ๋ง๋๋ commit object์ ์ด์ ํธ๋ฆฌ๋ฅผ ๊ฐ์ ธ์ ๋ฃ๊ณ , ํ์ฌ ํธ๋ฆฌ๋ ๋ฃ๊ณ .mit/objects์ blob๊ณผ ๋์ผํ ํํ๋ก ํ์ผ๋ช ์ ์ ์ฅ
-
ํด๋น ์ปค๋ฐ์ ํด์๊ฐ์ .mit/index/commits์ ๊ธฐ๋กํ๋ค
log ๋ช ๋ น์ด
mit log ๋๋ ํ ๋ฆฌ๋ช
- ๋๋ ํ ๋ฆฌ๋ช
/.mit/index/commits ์์ ์ปค๋ฐ์ ์ฐพ์์ ์ด๋ ฅ์ ์ถ๋ ฅํ๋ค.
- commit ๋ง๋ค ํ์ฌ tree๋ฅผ ํ์ธํด์ ๋ณ๊ฒฝ๋ ํ์ผ๋ช
์ ํจ๊ป ํ์ํ๋ค.
1 commit (์ปค๋ฐ ์ค๋ธ์ ํธ)
0 | 1 tree hash(ํ์ฌ)
1 tree hash์ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ค๋ค. (ํ์ผ๋ช
, ํ์ผ ํด์๊ฐ)
test.txt ๋ณ๊ฒฝํ์ต๋๋ค.
2 commit
1 tree hash | 2 tree hash
2 tree hash์ ์ ๋ณด๋ฅผ ๋ณด์ฌ์ค๋ค.
test1.txt ๋ณ๊ฒฝํ์ต๋๋ค.
-
index์ ๊ฐ ์ปค๋ฐ ๊ธฐ๋ก์ ๋จ์์๋ ํ์ฌ tree ํด์๊ฐ์ผ๋ก ๊ฐ์ ๋ณ๊ฒฝ ๋ด์ญ๋ค์ ๋ชจ๋ ์ถ๋ ฅ
restore ๋ช ๋ น์ด
mit resotore ๋๋ ํ ๋ฆฌ๋ช
{8์๋ฆฌ|64์๋ฆฌ ์ปค๋ฐํด์๊ฐ}
- ํน์ ํ ์ปค๋ฐ ํด์๊ฐ์ ์
๋ ฅํ๋ฉด, ์ต์ ์ปค๋ฐ๋ถํฐ ์ฐจ๋ก๋๋ก ์ปค๋ฐ ํ์ผ์ tree์ ํฌํจ๋ blob ๋ด์ฉ์ ๊บผ๋ด์ ํ์ผ์ ๋ณต์ํ๋ค.
- ์ปค๋ฐ ํด์๊ฐ์ ์ 8์๋ฆฌ๋ง ์
๋ ฅํ๋ ๊ฒฝ์ฐ์๋ ํด๋น object ๋๋ ํ ๋ฆฌ์ ์ปค๋ฐ ํ์ผ์ด 1๊ฐ๋ง ์๋ ๊ฒฝ์ฐ ๊ทธ ์ปค๋ฐ์ ๋ณต์ํ๋ค.
- ๋จ๊ณ๋ณ๋ก ์ปค๋ฐ์ index/commits ํ์ผ์์ ์ญ์ ํ๊ณ , ์
๋ ฅํ ์ปค๋ฐํด์๊ฐ์ ๊ฐ์ง ์ปค๋ฐ ์ ๋ณด๊น์ง๋ง ๋จ๊ฒจ๋๋๋ค.
- ๋ณต์ ๊ณผ์ ์์ ํ์์๋ commit, tree, blob ์ค๋ธ์ ํธ๋ ์ญ์ ํ์ง ์๋๋ค.
-
8์๋ฆฌ ํด๋๋ก ์ด๋ โ 64-8=56์๋ฆฌ ์ปค๋ฐ ํ์ผ ๋ณด๊ธฐ
-
ํด๋น ํ์ผ์ tree์ ํฌํจ๋ blob ๋ด์ฉ์ ๊บผ๋ด ํ์ผ ๋ณต์
์ ๋ ฅํ ์ปค๋ฐํด์๊ฐ์ ๊ฐ์ง ์ปค๋ฐ ์ ๋ณด๊น์ง ๋ฐ๋ณต
๊ฒฐ๊ณผ

init, add, commit, log๊น์ง๋ ๋ชจ๋ ์ ์ ๋์ํจ์ ํ์ธํ ์ ์์๋ค.
๊ฐ์ ํ๊ธฐ
๊ฐ์ ์ฒดํฌํฌ์ธํธ
- ํ์ผ ๊ด๋ จ ํด๋์ค ๋ง๋ค์ด ์ ์ ๋ฉ์๋๋ก ๊ด๋ฆฌํ๊ธฐ โ 2024-08-01
- ๊ณตํต์ ์ผ๋ก ์ฐ์ด๋ file ๊ฒฝ๋ก ๋ณ์ ํ ๋นํ์ฌ ์ฌ์ฌ์ฉ โ 2024-08-01
- ์์ธ์ฒ๋ฆฌ โ 2024-08-01
- restore ๊ตฌํํ๊ธฐ โ 2024-08-01
- commit log ์ ๋๋ก ํ์ผ์ ์ ์ฅํ์ง ์์๋ ๋ฌธ์ ์์ โ 2024-08-01
์ด๋ฒ ๋ฆฌํฉํ ๋ง์ ๊ตฌํํ์ง ๋ชปํ๋ ๊ธฐ๋ฅ๊ณผ ๋๋ถ์ด ๋งค์ฐ ๋ง์กฑ์ค๋ฌ์ ๋ ๊ฒฐ๊ณผ๋ฅผ ๊ฐ์ ธ์๋ค.
๊ธฐ์กด์ โ๋๋ฌด ์ง์ ๋ถํ๋ฐ?โ ๋ผ๊ณ ์๊ฐํ ๋งํผ ๋์กํ ์ฝ๋๋ผ์ ๋ฌธ์ ๊ฐ ํ๋ ํฐ์ง๋ฉด ์ด๋์ ๋ฌธ์ ๊ฐ ํฐ์ง๋์ง ์์๋ด๋ ๋ฐ๋ง ํ์ธ์์ด ๊ฑธ๋ ธ๋๋ฐ ์ด์ ๋ ๊ทธ๋๋ง ์ฝ์ ์๋ผ๋ ์๋ ์ฝ๋๊ฐ ๋์๋ค.
ํ์ผ ๊ด๋ จ ํด๋์ค ๋ง๋ค์ด ์ ์ ๋ฉ์๋๋ก ๊ด๋ฆฌํ๊ธฐ
const { existsSync, mkdirSync, writeFileSync, readFileSync } = require("fs");
const { deflateSync } = require("zlib");
const cryptoJs = require("crypto-js");
const zlib = require("zlib");
class FileManager {
static dirExceptionHandler(dir, hash) {
if (!existsSync(`./${dir}/.mit/objects/${hash.slice(0, 8)}`)) {
mkdirSync(`./${dir}/.mit/objects/${hash.slice(0, 8)}`, () => {});
}
}
static async jsonFileDeflate(file) {
const hash = cryptoJs.SHA256(file).toString();
const blob = new Blob([JSON.stringify(file, null, 2)], {
type: "application/json",
});
const converted = await blob.arrayBuffer();
const deflatedFile = deflateSync(converted);
return { hash, deflatedFile };
}
static writeFile(dir, hash, deflatedFile) {
const filePath = `./${dir}/.mit/objects/${hash.slice(0, 8)}/${hash.slice(
8
)}`;
writeFileSync(filePath, deflatedFile);
}
static jsonFileInflate(dir, hash) {
let file = readFileSync(
`./${dir}/.mit/objects/${hash.slice(0, 8)}/${hash.slice(8)}`
);
file = zlib.inflateSync(file).toString("utf-8");
return JSON.parse(file);
}
}
module.exports = { FileManager };
๊ธฐ์กด ์ฝ๋์ ๊ฒฝ์ฐ, ํ์ผ์ ์ฝ์ด์ฌ ๋๋ ๋งค ํด์๊ฐ์ ํตํด ํ์ผ์ ์ง์ โ zlib ์์ถ์ ํด์ โ JSON Parsing โ ๊ฐ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ์ ๊ฐ์ ์ผ๋ จ์ ๊ณผ์ ์ด ๊ณตํต์ ์ผ๋ก ์๋ฐ๋์๊ณ , add์ ๊ฐ์ ํจ์์ ๊ฒฝ์ฐ SHA256 ํด์ฑ โ JSON stringify โ Blob๊ฐ์ฒดํ โ zlib ์์ถ๊ณผ ๊ฐ์ ๋ณต์กํ ๊ณผ์ ์ด ๊ณ์ํด์ ์๋ฐ๋์ด์ผ๋ง ํ๋ค. ๊ทธ๋ฌ๋ค๋ณด๋ ๋ชจ๋ ํจ์๋ค์ ๋๋ถ๋ถ ์ด๋ฌํ ๋ก์ง์ด ๊ณตํต์ ์ผ๋ก ๋ค์ด๊ฐ๊ฒ ๋์๊ณ , ๊ฒฐ๊ตญ blob, commit, tree object์ commit blob ํ์ผ์ ๊ณ์ํด์ ๊ฐฑ์ ํด์ค์ผ ํ๋ commit ํจ์์ ๊ทธ์ ๋ง๋ ๊ธฐ๋ฅ์ ์ธ ํจ์๋ค์ด ๋ชจ๋ ๊ฐ๋ ์ฑ์ด ๋งค์ฐ ๋จ์ด์ง ์ ๋๋ก ์ฝ๋๊ฐ ๊ธธ๊ณ ๋์กํ๋ค. ์ด์ ์ฝ๋๋ฅผ ์ง๋ฉด์๋ ๊ณ์ ์๊ฐํ๊ณ ์์์ง๋ง, ๊ตฌํ์ ๊ธ๊ธํด์ ํ๋ค๋ณด๋ ๋ฆฌํฉํ ๋ง๊น์ง ๋ฏธ๋ค์๋ค. ์ด๋ฒ ๋ฆฌํฉํ ๋ง์์ FileManager๋ผ๋ ํด๋์ค๋ฅผ ๋๊ณ , ํด๋น ํด๋์ค์ ์ธ์คํด์ค๋ฅผ ๊ตณ์ด ๋ง๋ค์ด์ ์ฌ์ฉํ๋ ๊ฒ์ด ์๋, ๊ธฐ๋ฅ์ ์ผ๋ก ๋น์ทํ ๊ณผ์ ๋ค์ ๊ฑฐ์น๋ ํ์ผ ์์ถ๊ณผ ํด์ ์ ๊ด๋ จ๋ ํ์ผ ๊ด๋ จ ์ ์ ๋ฉ์๋๋ค์ ๋ชจ๋ ๋ฃ์ด๋์ด ํ์ํ ๋๋ง๋ค ํด๋น ์ ์ ๋ฉ์๋๋ง ๊ฐ์ ธ์์ ์ฐ๋ ๋ฐฉ์์ผ๋ก ์ค๊ณํ์ฌ ๊ธฐ์กด ์ฝ๋๋ฅผ ๊ฐ์ ํ๋ค.
async function commit(directory) {
const currentTreeHash = await treeCommit(directory);
const prevCommitHash = getLastCommit(directory);
const time = new Date();
const commitData = `${prevCommitHash} ${currentTreeHash}\n${time}`;
const hash = cryptoJs.SHA256(commitData).toString();
const blob = new Blob([JSON.stringify(commitData, null, 2)], {
type: "application/json",
});
const converted = await blob.arrayBuffer();
const compressed = zlib.deflateSync(converted);
const filePath = `./${directory}/.mit/objects/${hash.slice(0, 8)}`;
if (!fs.existsSync(filePath)) {
fs.mkdirSync(filePath, () => {
console.log("๋ง๋ค์ด์ง");
});
}
// commit object
fs.writeFileSync(`./${filePath}/${hash.slice(8)}`, compressed);
commitUpdate(directory, hash);
status(directory);
await garbageCollect(directory);
}๋น์ฅ commit ์์ ์๋ ํจ์๋ค๋ง ํ๋๋ผ๋ ๊ฐ๊ฐ์ ํจ์๊ฐ ํด๋น ์ปค๋ฐ ํจ์ ์์ ๋ก์ง์ ๋๋ถ๋ถ ๊ณตํต์ ์ผ๋ก ์ฌ์ฉํ๊ณ ์์๋ค.
async function commit(directory) {
//ํ์ฌ ๋ณ๊ฒฝ์ฌํญ์ ๋ํด์ blob ํ์ผ์ ๋ง๋ค์ด ์ ์ฅํ๊ณ , Tree Object๋ฅผ ๋ง๋ค์ด ํธ๋ฆฌ์ ํด์๊ฐ์ ๋ฐํ
const currentTreeHash = await treeCommit(directory);
//์ง์ ์ปค๋ฐ ํด์๊ฐ์ ๊ฐ์ ธ์ด(commit object์ ๊ฐ์ฅ ์ต๊ทผ ํด์๊ฐ)
const prevCommitHash = getLastCommit(directory);
const time = new Date();
//๊ฐฑ์ ํ ์ปค๋ฐ ๋ฐ์ดํฐ(commit Object์ฉ)
const commitData = `${prevCommitHash} ${currentTreeHash}\n${time}`;
const { hash, deflatedFile } = await FileManager.jsonFileDeflate(commitData);
// ํด๋น ํด๋ ์์ผ๋ฉด ๋ง๋ค์ด์ฃผ๊ธฐ
FileManager.dirExceptionHandler(directory, hash);
// commit object ์ ์ฅ
FileManager.writeFile(directory, hash, deflatedFile);
//.mit/index/commits์ ์๋ ๊ฐ์ฅ ์ต๊ทผ๊ฐ ์ต์ ํ
commitUpdate(directory, hash);
status(directory);
await garbageCollect(directory);
}ํ์ง๋ง ํ์ฌ๋ ํด๋ ์์ฑ ๋ฐ ํ์ผ ์์ฑ, ํด์ ๋ฑ์ ๊ธฐ๋ฅ์ ๊ฐ์ง FileManager์ ์ ์ ๋ฉ์๋๋ฅผ ํ์ฉํ์ฌ ํด๋น ๋ฉ์๋๊ฐ ๋ฌด์จ ์ญํ ์ ํ๋์ง์ ๋ํด์ ๋ณด๋ค ๊ฐ๋ ์ฑ์ด ์ข์์ก์ผ๋ฉฐ, ์ฝ๋์ ๊ธธ์ด๋ ๋น๊ต์ ์ค์ด๋ค์ด ๊ฐ์ ๋์๋ค๊ณ ์๊ฐํ๋ค.
๊ณตํต์ ์ผ๋ก ์ฐ์ด๋ file ๊ฒฝ๋ก ๋ณ์ ํ ๋นํ์ฌ ์ฌ์ฌ์ฉ
!fs.existsSync(`./${dir}/.mit/objects/${hash.slice(0, 8)}/${hash.slice(8)}`)
)๋ฆฌํฉํ ๋ง ์ ์๋ ๊ฒฝ๋ก๋ฅผ ํ์คํ๊ฒ ๋ณด๊ธฐ ์ํด ๋ชจ๋ ๋ก์ง์ ์ด๋ฌํ ๋ฐฉ์์ผ๋ก ํ๋์ฝ๋ฉ ํด๊ฐ๋ฉด์ ๊ฒฝ๋ก๋ฅผ ๊ฐ๊ฐ ๋ฃ์ด์คฌ๋๋ฐ, ๋ฆฌํฉํ ๋ง ๊ณผ์ ์์ ์ด๋ฌํ ๊ณตํต์ ์ผ๋ก ์ฐ์ด๋ ๊ฒฝ๋ก์ ๋ฌธ์์ด ๋ฑ์ ํ๋์ ๋ณ์์ ํ ๋นํ์ฌ ์ฌํ์ฉํ๋ ๋ฐฉ์์ผ๋ก ๊ฐ์ ํ์๋ค.
async function commitUpdate(dir, currCommitHash) {
const path = `./${dir}/.mit/index/commits`;
if (!fs.existsSync(path)) {
const { deflatedFile } = await FileManager.jsonFileDeflate(currCommitHash);
fs.writeFileSync(path, deflatedFile);
return;
}
const file = fs.readFileSync(path);
// .mit/index/commits์ ์ปค๋ฐ ํด์๊ฐ์ ํ ์ค์ฉ ๊ธฐ๋ก
let commits =
currCommitHash +
"\n" +
JSON.parse(zlib.inflateSync(file).toString("utf-8"));
const { deflatedFile } = await FileManager.jsonFileDeflate(commits);
fs.writeFileSync(path, deflatedFile);
}ํน๋ณํ index/commits์ ๋ค์ด๊ฐ๋ ๊ฒฝ์ฐ๋ ๊ฑฐ์ ์๊ธฐ ๋๋ฌธ์ ๋ฐ๋ก ๋ฉ์๋๋ฅผ ๋ง๋ค์ง ์๊ณ , objects ๋๋ ํ ๋ฆฌ ์์ ๋ค์ด๊ฐ๋ ๊ฒ๋ค๋ง ๋ฃ์ด์ฃผ์์ผ๋ฉฐ ์ด๋ฌํ ๊ฒฝ์ฐ path ๋ณ์๋ฅผ ์ฌ์ฉํ์ฌ ๋ณด๋ค ์ฝ๋์ ๊ฐ๋ ์ฑ์ ๊ฐ์ ํ์๋ค.
์์ธ์ฒ๋ฆฌ
// ์ ์ฅํ ์ปค๋ฐ ๋ก๊ทธ์์ ๋ณ๋์ฌํญ ํ์ผ๋ง ๋ฐ์ ์ ์ฅ์ํค๊ณ Tree Object์ ํ์ํ ๋ณ๋์ฌํญ ๋ฐฐ์ด ๋๊น
async function blobCommit(dir) {
const data = readChanged(dir);
let commitData = [];
for (const blob of data) {
const { hash, path, fileName, status } = blob;
if (status !== "์ญ์ ๋จ") {
const file = fs.readFileSync(path).toString();
const { hash, deflatedFile } = await FileManager.jsonFileDeflate(file);
FileManager.dirExceptionHandler(dir, hash);
FileManager.writeFile(dir, hash, deflatedFile);
const fileSize = fs.statSync(path).size;
commitData.push(`+ ${hash} ${fileSize} ${path} ${status}`);
} else {
commitData.push(`- ${hash} ${path} ${status}`);
}
}
return commitData;
}blob๋ค์ ๋ํด์ ๊ฐ๊ฐ commit์ ํ ๋ ๋ฐ์ดํฐ์ ๋ฃ์ด์ฃผ๋ ๊ณผ์ ์์ ์ญ์ ์ ๊ฒฝ์ฐ๋ง ๋ฐ๋ก ์์ธ์ฒ๋ฆฌ๋ฅผ ํ๋ฉด์ ํด๋น ํ์ผ์ ์ฝ์ด๋ค์ด๋ ๊ฒ์ด ์๋, ์ด์ ์ ํด์๊ฐ์ ๊ฐ์ ธ์ ๋ฃ์ด์ฃผ์ด ๋์ค์ ๋ณต์ํ ๋ ํด๋น ์ปค๋ฐ๋ค์ ๋ก๊ทธ์์ ํด์๊ฐ์ ์ฐพ์๋ด์ด ๋ณต์ํ๋ ๋ฐฉ์์ผ๋ก ํ๋ฉด์ ๊ธฐ์กด์ ํด์๊ฐ์ ๊ฐฑ์ ํ๋ ๊ฒฝ์ฐ์ ์์ธ์ฒ๋ฆฌ๋ฅผ ์์ผ์ฃผ์๋ค. ๋ํ ์ถ๊ฐ, ๊ฐฑ์ , ์์ ์ ๊ฒฝ์ฐ +๋ก, ์์ ์ ๊ฒฝ์ฐ๋ ๋ฐ๋ก -๋ก ๊ตฌ๋ถํ์ฌ ๋ณด์ฌ์ค์ผ๋ก์จ ์ฌ์ฉ์์ ์ ์ฅ์์ ๋ณด๋ค ๋ณด๊ธฐ ์ข์ ์ปค๋ฐ ๋ก๊ทธ๋ฅผ ๋ณผ ์ ์๋๋ก ํ์๋ค.
restore ๊ตฌํํ๊ธฐ
const { readFileSync, writeFileSync, existsSync } = require("fs");
const zlib = require("zlib");
const { FileManager } = require("./fileManager");
async function restore(dir, hash) {
const commitHashLogs = await getcommitHashLogs(dir);
// ์ ํจ์ฑ ๊ฒ์ฆ์ ํตํด ๋จผ์ ํด์๊ฐ์ ํด๋นํ๋ ๋ก๊ทธ๊ฐ ์๋์ง ๊ฒ์ฌ
const index = checkValidity(commitHashLogs, hash);
for (let i = 0; i < index; i++) {
// ๊ฐ ์ปค๋ฐ์ ์ต์ ๋ฐ์์ฌํญ ๊ฐ์ ธ์ค๊ธฐ
const treeObj = getHashObj(dir, commitHashLogs[i]);
rollBack(dir, treeObj);
}
await updateCommitHash(dir, commitHashLogs.slice(index - 1));
}
async function getcommitHashLogs(dir) {
const path = `./${dir}/.mit/index/commits`;
if (!existsSync(path)) throw new Error("์ปค๋ฐ ๋ด์ญ์ด ์์ต๋๋ค.");
const file = readFileSync(path);
const commitHashLogs = JSON.parse(
zlib.inflateSync(file).toString("utf-8")
).split("\n");
return commitHashLogs;
}
function checkValidity(hashlogs, hash) {
const index = hashlogs.findIndex((log) => log === hash);
if (index === -1)
throw new Error("ํด๋น ํด์๊ฐ์ ์ผ์นํ๋ ์ปค๋ฐ ํด์๊ฐ์ด ์์ต๋๋ค.");
return index;
}
function getHashObj(dir, hash) {
const hashObj = FileManager.jsonFileInflate(dir, hash);
const treeObj = hashObj.split("\n")[0].split(" ")[1];
return treeObj;
}
function rollBack(dir, hash) {
let blobs = FileManager.jsonFileInflate(dir, hash);
if (blobs.includes("\n")) blobs = blobs.split("\n");
if (Array.isArray(blobs)) {
blobs.forEach((blob) => {
if (blob[0] === "-") {
const blobHashToRollBack = blob.split(" ")[1];
const path = blob.split(" ")[2];
const content = FileManager.jsonFileInflate(dir, blobHashToRollBack);
writeFileSync(path, content);
}
});
} else {
if (blobs[0] === "-") {
const blobHashToRollBack = blobs.split(" ")[1];
const path = blobs.split(" ")[2];
const content = FileManager.jsonFileInflate(dir, blobHashToRollBack);
writeFileSync(path, content);
}
}
}
async function updateCommitHash(dir, hashlogs) {
const path = `./${dir}/.mit/index/commits`;
if (typeof hashlogs !== "object") {
hashlogs = hashlogs.join("\n");
}
const { deflatedFile } = await FileManager.jsonFileDeflate(hashlogs);
writeFileSync(path, deflatedFile);
console.log(
"๋ณต์์ด ์๋ฃ๋์์ต๋๋ค.\n ํด๋น ์ปค๋ฐ ์ดํ์ ์ปค๋ฐ๋ค์ ๋ชจ๋ ์ฌ๋ผ์ง๋๋ค."
);
}
/**
* 1. ์ปค๋ฐ ํด์๊ฐ์ ์
๋ ฅ ๋ฐ์์ .mit/index/commits์์ ํด์๊ฐ ์กด์ฌ ์ฌ๋ถ ํ๋จ
* 2. ์ด์ ํธ๋ฆฌ, ํ์ฌ ํธ๋ฆฌ๊ฐ ์๋๋ฐ ๊ฐ๊ฐ ๋ฃจํ
* 3. ํธ๋ฆฌ๋ก ๊ฐ์ blob ํด์๊ฐ๊ณผ ํ์ผ ์ด๋ฆ์ ๋ฝ์๋ด๊ณ , ๊ทธ๊ฑธ ๋ค์ ์์ถํด์ ํ์ฌ writeSync
*/
module.exports = { restore };
restore์ ๊ฒฝ์ฐ ๊ตฌํํ๊ณ ์ถ์์ง๋ง ์ต์ํ์ด๋ผ๋ ์กฐ๊ธ ์ ๋ค์์ ํด์ผ ํ ๊ฒ ๊ฐ์ ์์ฝ๊ฒ๋ ๊ตฌํํ์ง ๋ชปํ๋ ๊ธฐ๋ฅ์ด์๋ค. ํด๋น ๊ธฐ๋ฅ์ ๊ฒฝ์ฐ
- ํด๋น ์ปค๋ฐ ํด์๊ฐ์ ์คํ์์ ์ธ๋ฑ์ค ์ฐพ๊ธฐ
- ๋ง์ฝ ์ปค๋ฐ ํด์๊ฐ์ด ์๋ค๋ฉด ์์ธ์ฒ๋ฆฌ
- ์ธ๋ฑ์ค๋ฅผ ๋ฐ๊ณ ํด๋น ์ธ๋ฑ์ค ๊ฐ ์ด์ ๊น์ง ๋ชจ๋ ํด์๊ฐ์ ๋ํ์ฌ ํด์ ๊ฐ์ฒด์ ์ ๊ทผ
- ํด์ ๊ฐ์ฒด์์ ์ค๋ฅธ์ชฝ์ ์๋ ์ต๊ทผ commit์ ํธ๋ฆฌ ํด์๊ฐ์ ์ ๊ทผ
- ์ต๊ทผ ํธ๋ฆฌ ํด์๊ฐ์ ์ ๊ทผํ์ฌ ๊ฐ ์ปค๋ฐ ์์ ์ฌํญ ๋ฝ์์ค๊ธฐ
- ์ญ์ ์ ๊ฒฝ์ฐ๋ง ๋ฝ์๋ด์ด ๋ณต์
- ๋ณต์์ ๊ฒฝ์ฐ ์ค๋ง๋ค ๋์์๋ ํด์๊ฐ์ ํตํด objects ํด๋์ ํด์๊ฐ ์์น์ ์ ๊ทผํ์ฌ ํ์ผ์ ์ฝ๊ณ ๋ค์ ์ฐ๋ ํํ
- ๋ชจ๋ ๋ณต์ํ ํ์๋ ํด๋น ํด์๊ฐ ๊น์ง ์์ ์์ฌ์๋ ๋ชจ๋ ํด์๊ฐ ์ ๊ฑฐ
์ ๊ณผ์ ์ ๊ฑฐ์ณ restore์ ๊ตฌํํด๋ด์๋ค.
ํด๋น ํ๋ฉด์ ํ
์คํธ ํ๋ฉด์ธ๋ฐ, delete.txt๋ผ๋ ํ์ผ์ ์ง์ฐ๊ณ ์ปค๋ฐํ ๋ค์์ ๋ค์ ์ด์ ์ปค๋ฐ์ผ๋ก restore์์ผ์ค์ผ๋ก์จ ๋ค์ delete๊ฐ์ ๊ฐ์ ธ์ค๋ ๊ฒ์ ํ์ธํ์๋ค.
commit log์ ์ ๋๋ก ํด์๊ฐ์ ์ ์ฅํ์ง ๋ชปํ๋ ๋ฌธ์ ์์
static async jsonFileDeflate(file) {
const hash = cryptoJs.SHA256(file).toString();
const blob = new Blob([JSON.stringify(file, null, 2)], {
type: "application/json",
});
const converted = await blob.arrayBuffer();
const deflatedFile = deflateSync(converted);
return { hash, deflatedFile };
}
...
async function blobCommit(dir) {
const data = readChanged(dir);
let commitData = [];
for (const blob of data) {
const { hash, path, fileName, status } = blob;
if (status !== "์ญ์ ๋จ") {
const file = fs.readFileSync(path).toString();
const { hash, deflatedFile } = await FileManager.jsonFileDeflate(file);
FileManager.dirExceptionHandler(dir, hash);
FileManager.writeFile(dir, hash, deflatedFile);
const fileSize = fs.statSync(path).size;
commitData.push(`+ ${hash} ${fileSize} ${path} ${status}`);
} else {
commitData.push(`- ${hash} ${path} ${status}`);
}
}
return commitData;
}๊ธฐ์กด์๋ ๊ฐ๊ฐ์ blobํ์ผ์ ๋ํด์ ์ ์ฅํ๊ณ ํด์๊ฐ์ ์ ์ฅํ๋ ๊ณผ์ ์์ ๋๊ฐ์ ํด์๊ฐ์ด ๋ฐ๋ณตํด์ ๋์ค๋ ๋ฒ๊ทธ๊ฐ ์์๋ค. ์ฌ๊ธฐ์ ์๊พธ ๋งํ๊ธธ๋ hash ์ค์ฝํ๋ฅผ ๋ฐ๋ผ๊ฐ๋ค๋ณด๋ data์์ ๊ฐ์ ธ์ค๋ hash์ FileManager์ jsonFileDeflate์์ ๊ฐ์ ธ์ค๋ hash๊ฐ ์์๋๋ฐ, data์ ๊ฒฝ์ฐ๋ ๋ฑํ ๋ณ๋์ด ์์์ ํ์ธํ์ง๋ง jsonFileDeflate๋ฅผ ๊ฑฐ์ณ ๋์ค๋ ํด์๊ฐ์ ๊ฒฝ์ฐ ๋๊ฐ์ด ๋์ค๊ฒ ๋๋ ์ค๋ฅ๊ฐ ์์๋ค. ํ๋ํ๋ ๋ฏ์ด๊ฐ๋ฉด์ ๋ณด๋ ์ด ๋ฌธ์ ๋ ํด์๊ฐ์ฒด์ ์ฐธ์กฐ์ ๊ดํ ๋ฌธ์ ์๋ค. crypto-js๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ํตํด ํด์๊ฐ์ ์์ฑํ ๋, ์์ฑ๋๋ SHA256 ๊ฐ์ฒด๋ ๋ฌธ์์ด๋ก ๋ณํํ์ง ์๋ ์ด์ ํด์ ๊ฐ์ฒด ์์ฒด๋ฅผ ๊ฐ๋ฆฌํค๊ธฐ ๋๋ฌธ์ ๋ชจ๋๊ฐ ๊ฐ์ ๊ฐ์ฒด๋ฅผ ๊ฐ๋ฆฌํค๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ด๋ค. ์ด์ SHA256์ ํตํด ๋ง๋ค์ด์ง๋ ๊ฐ์ฒด์ toString์ ํตํด ๋ฌธ์์ด๋ก ๋ณํํด์ฃผ์๊ณ , ์ดํ์ ๋ก๊ทธ๋ฅผ ๋ค์ ํ์ธํด๋ณด๋ ์ ์์ ์ผ๋ก ์๋๋ ๊ฒ์ ํ์ธํ๋ค.
ํ์ต ๋ฉ๋ชจ
git์ ๋ด๋ถ๊ตฌ์กฐ https://bigexecution.tistory.com/171 https://tecoble.techcourse.co.kr/post/2021-07-08-dot-git/ https://80000coding.oopy.io/7267f19f-5359-4799-a740-5d0f316fb589 https://storycompiler.tistory.com/7
commander ๋ผ์ด๋ธ๋ฌ๋ฆฌ https://github.com/Jeontaeyun/TypeScript/blob/master/node.js-or/cli/README.md
Blob ๊ฐ์ฒด https://velog.io/@minh0518/Blob%EA%B0%9D%EC%B2%B4%EB%9E%80 https://developer.mozilla.org/ko/docs/Web/API/Blob
SHA256 https://velog.io/@ham3798/SHA-256-%ED%95%B4%EC%8B%9C-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98%EC%97%90-%EB%8C%80%ED%95%98%EC%97%AC https://losskatsu.github.io/blockchain/sha256/ https://devje.tistory.com/181