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 ๋””๋ ‰ํ† ๋ฆฌ๋ช…

  1. .mit ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ

  2. .mit ๋””๋ ‰ํ† ๋ฆฌ ์•„๋ž˜์— /.mit/objects/์™€ /.mit/index/ ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์ƒ์„ฑ

add ๋ช…๋ น์–ด


mit add ๋””๋ ‰ํ† ๋ฆฌ๋ช…

- ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์ „์ฒด ํŒŒ์ผ ๋ชฉ๋ก์„ ํƒ์ƒ‰ํ•˜๊ณ , ๊ฐ ํŒŒ์ผ ๋‚ด์šฉ์— ๋Œ€ํ•œ sha256 ํ•ด์‹œ ๊ฐ’์„ ๋น„๊ตํ•œ๋‹ค.

- commit์ด ์—†๊ฑฐ๋‚˜ ์ง์ „ commit ์ดํ›„ ํ•ด์‹œ๊ฐ’์ด ๋‹ฌ๋ผ์ง„ ํŒŒ์ผ ๋ชฉ๋ก์„ ์ €์žฅํ•œ๋‹ค

  1. ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์ „์ฒด ํŒŒ์ผ ๋ชฉ๋ก ์‚ดํŽด๋ณด๊ธฐ

  2. ํŒŒ์ผ์„ ๋Œ๋ฉด์„œ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ๋‚˜์˜ค๋ฉด ์žฌ๊ท€์ ์œผ๋กœ ๋Œ๊ณ , ํŒŒ์ผ๋ช…๋งŒ ๋ฐ˜๋ณตํ•ด์„œ ์œผ๋ฉด์„œ

  3. 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

  • ํด๋”

  • ํŒŒ์ผ

  • ํŒŒ์ผ

  1. mit add ๋””๋ ‰ํ† ๋ช…

  2. ๋””๋ ‰ํ† ๋ฆฌ ๋‚ด์˜ ํŒŒ์ผ๋“ค์„ objects/2e/65โ€ฆ ๋“ฑ์œผ๋กœ ๋งŒ๋“ค์–ด ์ €์žฅ

  3. ํŒŒ์ผ๋“ค์„ ๋ชจ๋‘ ๊ฐ€๋ฆฌํ‚ค๋Š” tree๋ฅผ objects ํด๋”์— ์ €์žฅ

  4. ํ•ด๋‹น ํŠธ๋ฆฌ์˜ ํ•ด์‹œ๊ฐ’์„ index์— ์ €์žฅ

  • ํŠธ๋ฆฌ๋ฅผ ๋งŒ๋“  ํ›„, ํ•ด๋‹น ํŠธ๋ฆฌ์˜ ํ•ด์‹œ๊ฐ’์„ Index์— ์ €์žฅ


๋…ผ์˜ํ–ˆ๋˜ ์‚ฌ์•ˆ๋“ค

- ํŒŒ์ผ๋“ค์„ ๋ชจ๋‘ objects ํด๋” ์•ˆ์— ์ €์žฅํ•˜๊ณ , ๋ณ€๋™์‚ฌํ•ญ๋“ฑ์„ ๋น„๊ตํ•œ ๋’ค์— Index ๋””๋ ‰ํ† ๋ฆฌ ์•ˆ์˜ ํŒŒ์ผ์— ์ด๋Ÿฌํ•œ ํŒŒ์ผ๋“ค์— ๋Œ€ํ•œ ํ•ด์‹œ๊ฐ’๋“ค์„ ๋ชจ๋‘ ๊ธฐ๋ก

status ๋ช…๋ น์–ด


mit status ๋””๋ ‰ํ† ๋ฆฌ๋ช…

  • index์— ์ €์žฅ๋œ ๋ณ€๊ฒฝ ํŒŒ์ผ ๋ชฉ๋ก ์ค‘์—์„œ ๋””๋ ‰ํ† ๋ฆฌ ๋ช…์„ ํฌํ•จํ•˜๋Š” ํŒŒ์ผ๋“ค ๋ชจ๋‘ ์ถœ๋ ฅ

commit ๋ช…๋ น์–ด


mit commit ๋””๋ ‰ํ† ๋ฆฌ๋ช…

  1. ์ฃผ์–ด์ง„ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์ตœ์ƒ์œ„ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๋˜์–ด ์žˆ์„ ๋•Œ, ํ•ด๋‹น ๋””๋ ‰ํ† ๋ฆฌ ์•ˆ์˜ ํด๋”๋“ค์— ๋Œ€ํ•ด์„œ ๋ชจ๋‘ blob ์˜ค๋ธŒ์ ํŠธ๋ฅผ ์ƒ์„ฑ

  2. object ํ•ด์‹œ๊ฐ’ ์•ž์˜ 8์ž๋ฆฌ๋ฅผ ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ƒ์„ฑํ•˜๊ณ , ๋‚˜๋จธ์ง€ ๋ถ€๋ถ„์„ ํŒŒ์ผ๋ช…์œผ๋กœ ์ €์žฅ

  3. ํŒŒ์ผ ๋‚ด์šฉ์€ zlib์œผ๋กœ ์••์ถ•ํ•ด์„œ ์ €์žฅ

  4. ํŒŒ์ผ์„ ์ €์žฅํ•˜๋ฉด์„œ tree ์˜ค๋ธŒ์ ํŠธ์— ์ €์žฅ๋œ ๋ชจ๋“  ํŒŒ์ผ๋“ค์„ ๊ธฐ๋ก

  5. ์˜ค๋ธŒ์ ํŠธ๋Š” blob๋งˆ๋‹ค blob ํ•ด์‹œ๊ฐ’, ์••์ถ• ํ›„ ํŒŒ์ผ ํฌ๊ธฐ, ํŒŒ์ผ๋ช…์„ ์ „๋ถ€ ๋ฐ›๊ณ , ์ด๋ฅผ ๋‹ค์‹œ ํŒŒ์ผ๋กœ tree object ํŒŒ์ผ๋กœ ์ €์žฅ(SHA256)

  6. .mit/index/commits๋ฅผ ๋ณด๊ณ  ์ปค๋ฐ‹์ด ์žˆ์œผ๋ฉด ๊ฐ€์žฅ ์ตœ์‹ ์˜ ์ปค๋ฐ‹์„ ๊ฐ€์ ธ์˜ด

  7. ๊ฐ€์ ธ์˜จ ์ปค๋ฐ‹์„ ์ƒˆ๋กœ ๋งŒ๋“œ๋Š” commit object์˜ ์ด์ „ ํŠธ๋ฆฌ๋ฅผ ๊ฐ€์ ธ์™€ ๋„ฃ๊ณ , ํ˜„์žฌ ํŠธ๋ฆฌ๋„ ๋„ฃ๊ณ  .mit/objects์— blob๊ณผ ๋™์ผํ•œ ํ˜•ํƒœ๋กœ ํŒŒ์ผ๋ช…์„ ์ €์žฅ

  8. ํ•ด๋‹น ์ปค๋ฐ‹์˜ ํ•ด์‹œ๊ฐ’์„ .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 ๋ณ€๊ฒฝํ–ˆ์Šต๋‹ˆ๋‹ค.

  1. index์˜ ๊ฐ ์ปค๋ฐ‹ ๊ธฐ๋ก์— ๋‚จ์•„์žˆ๋Š” ํ˜„์žฌ tree ํ•ด์‹œ๊ฐ’์œผ๋กœ ๊ฐ€์„œ ๋ณ€๊ฒฝ ๋‚ด์—ญ๋“ค์„ ๋ชจ๋‘ ์ถœ๋ ฅ

restore ๋ช…๋ น์–ด


mit resotore ๋””๋ ‰ํ† ๋ฆฌ๋ช… {8์ž๋ฆฌ|64์ž๋ฆฌ ์ปค๋ฐ‹ํ•ด์‹œ๊ฐ’}

- ํŠน์ •ํ•œ ์ปค๋ฐ‹ ํ•ด์‹œ๊ฐ’์„ ์ž…๋ ฅํ•˜๋ฉด, ์ตœ์‹  ์ปค๋ฐ‹๋ถ€ํ„ฐ ์ฐจ๋ก€๋Œ€๋กœ ์ปค๋ฐ‹ ํŒŒ์ผ์˜ tree์— ํฌํ•จ๋œ blob ๋‚ด์šฉ์„ ๊บผ๋‚ด์„œ ํŒŒ์ผ์„ ๋ณต์›ํ•œ๋‹ค.

- ์ปค๋ฐ‹ ํ•ด์‹œ๊ฐ’์€ ์•ž 8์ž๋ฆฌ๋งŒ ์ž…๋ ฅํ•˜๋Š” ๊ฒฝ์šฐ์—๋„ ํ•ด๋‹น object ๋””๋ ‰ํ† ๋ฆฌ์— ์ปค๋ฐ‹ ํŒŒ์ผ์ด 1๊ฐœ๋งŒ ์žˆ๋Š” ๊ฒฝ์šฐ ๊ทธ ์ปค๋ฐ‹์„ ๋ณต์›ํ•œ๋‹ค.

- ๋‹จ๊ณ„๋ณ„๋กœ ์ปค๋ฐ‹์€ index/commits ํŒŒ์ผ์—์„œ ์‚ญ์ œํ•˜๊ณ , ์ž…๋ ฅํ•œ ์ปค๋ฐ‹ํ•ด์‹œ๊ฐ’์„ ๊ฐ€์ง„ ์ปค๋ฐ‹ ์ •๋ณด๊นŒ์ง€๋งŒ ๋‚จ๊ฒจ๋†“๋Š”๋‹ค.

- ๋ณต์› ๊ณผ์ •์—์„œ ํ•„์š”์—†๋Š” commit, tree, blob ์˜ค๋ธŒ์ ํŠธ๋Š” ์‚ญ์ œํ•˜์ง€ ์•Š๋Š”๋‹ค.

  1. 8์ž๋ฆฌ ํด๋”๋กœ ์ด๋™ โ†’ 64-8=56์ž๋ฆฌ ์ปค๋ฐ‹ ํŒŒ์ผ ๋ณด๊ธฐ

  2. ํ•ด๋‹น ํŒŒ์ผ์˜ 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์˜ ๊ฒฝ์šฐ ๊ตฌํ˜„ํ•˜๊ณ  ์‹ถ์—ˆ์ง€๋งŒ ์ตœ์†Œํ•œ์ด๋ผ๋„ ์กฐ๊ธˆ ์ž” ๋‹ค์Œ์— ํ•ด์•ผ ํ•  ๊ฒƒ ๊ฐ™์•„ ์•„์‰ฝ๊ฒŒ๋„ ๊ตฌํ˜„ํ•˜์ง€ ๋ชปํ–ˆ๋˜ ๊ธฐ๋Šฅ์ด์—ˆ๋‹ค. ํ•ด๋‹น ๊ธฐ๋Šฅ์˜ ๊ฒฝ์šฐ

  1. ํ•ด๋‹น ์ปค๋ฐ‹ ํ•ด์‹œ๊ฐ’์„ ์Šคํƒ์—์„œ ์ธ๋ฑ์Šค ์ฐพ๊ธฐ
    • ๋งŒ์•ฝ ์ปค๋ฐ‹ ํ•ด์‹œ๊ฐ’์ด ์—†๋‹ค๋ฉด ์˜ˆ์™ธ์ฒ˜๋ฆฌ
  2. ์ธ๋ฑ์Šค๋ฅผ ๋ฐ›๊ณ  ํ•ด๋‹น ์ธ๋ฑ์Šค ๊ฐ’ ์ด์ „๊นŒ์ง€ ๋ชจ๋“  ํ•ด์‹œ๊ฐ’์— ๋Œ€ํ•˜์—ฌ ํ•ด์‹œ ๊ฐœ์ฒด์— ์ ‘๊ทผ
  3. ํ•ด์‹œ ๊ฐœ์ฒด์—์„œ ์˜ค๋ฅธ์ชฝ์— ์žˆ๋Š” ์ตœ๊ทผ commit์˜ ํŠธ๋ฆฌ ํ•ด์‹œ๊ฐ’์— ์ ‘๊ทผ
  4. ์ตœ๊ทผ ํŠธ๋ฆฌ ํ•ด์‹œ๊ฐ’์— ์ ‘๊ทผํ•˜์—ฌ ๊ฐ ์ปค๋ฐ‹ ์ˆ˜์ •์‚ฌํ•ญ ๋ฝ‘์•„์˜ค๊ธฐ
  5. ์‚ญ์ œ์˜ ๊ฒฝ์šฐ๋งŒ ๋ฝ‘์•„๋‚ด์–ด ๋ณต์›
    • ๋ณต์›์˜ ๊ฒฝ์šฐ ์ค„๋งˆ๋‹ค ๋‚˜์™€์žˆ๋Š” ํ•ด์‹œ๊ฐ’์„ ํ†ตํ•ด objects ํด๋”์˜ ํ•ด์‹œ๊ฐ’ ์œ„์น˜์— ์ ‘๊ทผํ•˜์—ฌ ํŒŒ์ผ์„ ์ฝ๊ณ  ๋‹ค์‹œ ์“ฐ๋Š” ํ˜•ํƒœ
  6. ๋ชจ๋‘ ๋ณต์›ํ•œ ํ›„์—๋Š” ํ•ด๋‹น ํ•ด์‹œ๊ฐ’ ๊นŒ์ง€ ์œ„์— ์Œ“์—ฌ์žˆ๋Š” ๋ชจ๋“  ํ•ด์‹œ๊ฐ’ ์ œ๊ฑฐ

์˜ ๊ณผ์ •์„ ๊ฑฐ์ณ 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

Day13_ํ•™์Šต์ •๋ฆฌ