Git tool

์ง€๊ธˆ๊นŒ์ง€ ์ผ์ƒ์ ์œผ๋กœ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ๋ช…๋ น์–ด๋“ค๊ณผ ๋ช‡ ๊ฐ€์ง€ Workflow๋ฅผ ๋ฐฐ์› ๋‹ค. ํŒŒ์ผ์„ ์ถ”์ ํ•˜๊ณ  ์ปค๋ฐ‹ํ•˜๋Š” ๋“ฑ์˜ ๊ธฐ๋ณธ์ ์ธ ๋ช…๋ น์–ด๋ฟ๋งŒ ์•„๋‹ˆ๋ผ Staging Area๊ฐ€ ์™œ ์ข‹์€์ง€๋„ ๋ฐฐ์› ๊ณ  ๊ฐ€๋ณ๊ฒŒ ํ† ํ”ฝ ๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“ค๊ณ  Mergeํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ๋‹ค๋ค˜๋‹ค. ์ด์ œ๋Š” ์†Œ์Šค์ฝ”๋“œ ๊ด€๋ฆฌ๋ฅผ Git ์ €์žฅ์†Œ๋กœ ์ถฉ๋ถ„ํžˆ ํ•ด๋‚ผ ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

์ด ์žฅ์—์„œ๋Š” ์ผ์ƒ์ ์œผ๋กœ ์‚ฌ์šฉํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ์œ„๊ธ‰ํ•œ ์ƒํ™ฉ์—์„œ ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•œ Git ๋„๊ตฌ๋ฅผ ์‚ดํŽด๋ณธ๋‹ค.

๋ฆฌ๋น„์ „ ์กฐํšŒํ•˜๊ธฐ

๋ฆฌ๋น„์ „ ํ•˜๋‚˜๋ฅผ ์กฐํšŒํ•  ์ˆ˜๋„ ์žˆ๊ณ  ๋ฒ”์œ„๋ฅผ ์ฃผ๊ณ  ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ์กฐํšŒํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ž˜ ์“ฐ์ง„ ์•Š์ง€๋งŒ ์•Œ์•„๋‘๋Š”๊ฒŒ ์ข‹๋‹ค.

๋ฆฌ๋น„์ „ ํ•˜๋‚˜ ๊ฐ€๋ฆฌํ‚ค๊ธฐ

์‚ฌ๋žŒ์€ ์ปค๋ฐ‹์„ ๋‚˜ํƒ€๋‚ด๋Š” SHA-1 ํ•ด์‹œ ๊ฐ’์„ ์‰ฝ๊ฒŒ ๊ธฐ์–ตํ•  ์ˆ˜ ์—†๋‹ค. ์ด ์ ˆ์—์„œ๋Š” ์ปค๋ฐ‹์„ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ช‡ ๊ฐ€์ง€ ์„ค๋ช…ํ•œ๋‹ค. ์ข€ ๋” ์‚ฌ๋žŒ์ด ๊ธฐ์–ตํ•˜๊ธฐ ์‰ฌ์šด ๋ฐฉ๋ฒ•๋“ค์ด๋‹ค.

์งง์€ SHA-1

ํ•ด์‹œ ๊ฐ’์˜ ์•ž ๋ช‡ ๊ธ€์ž๋งŒ์œผ๋กœ๋„ ์–ด๋–ค ์ปค๋ฐ‹์ธ์ง€ ์ถฉ๋ถ„ํžˆ ์‹๋ณ„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ค‘๋ณต๋˜์ง€ ์•Š์œผ๋ฉด ํ•ด์‹œ ๊ฐ’์˜ ์•ž 4์ž๋งŒ ์‚ฌ์šฉํ•ด๋„ ๋œ๋‹ค. ์œ ์ผํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ์งง์€ SHA-1 ๊ฐ’์ด๋ผ๋„ ๊ดœ์ฐฎ๋‹ค.

๋จผ์ € git log ๋ช…๋ น์œผ๋กœ ์–ด๋–ค ์ปค๋ฐ‹์ด ์žˆ๋Š”์ง€ ์กฐํšŒํ•œ๋‹ค:

$ git log
commit 734713bc047d87bf7eac9674765ae793478c50d3
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Jan 2 18:32:33 2009 -0800

    fixed refs handling, added gc auto, updated tests

commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 15:08:43 2008 -0800

    Merge commit 'phedders/rdocs'

commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 14:58:32 2008 -0800

    added some blame and merge stuff

git show ๋ช…๋ น์œผ๋กœ 1c002dd....๋กœ ์‹œ์ž‘ํ•˜๋Š” ์ปค๋ฐ‹์„ ์กฐํšŒํ•œ๋‹ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์กฐํšŒ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋‹ค์Œ ๋ช…๋ น์–ด๋Š” ๋ชจ๋‘ ๊ฐ™๋‹ค(๋‹จ ์งง์€ ํ•ด์‹œ ๊ฐ’์ด ๋‹ค๋ฅธ ์ปค๋ฐ‹๊ณผ ์ค‘๋ณต๋˜์ง€ ์•Š๋‹ค๊ณ  ๊ฐ€์ •):

$ git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b
$ git show 1c002dd4b536e7479f
$ git show 1c002d

git log ๋ช…๋ น์–ด์— --abbrev-commit ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์งง์€ ํ•ด์‹œ ๊ฐ’์„ ๋ณด์—ฌ์ค€๋‹ค. ๊ธฐ๋ณธ์œผ๋กœ 7์ž๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ  ํ•ด์‹œ ๊ฐ’์ด ์ค‘๋ณต๋˜๋ฉด ๋” ๊ธด ํ•ด์‹œ ๊ฐ’์„ ๋ณด์—ฌ์ค€๋‹ค:

$ git log --abbrev-commit --pretty=oneline
ca82a6d changed the version number
085bb3b removed unnecessary test code
a11bef0 first commit

๋ณดํ†ต์€ 8์ž์—์„œ 10์ž ๋‚ด์™ธ๋กœ๋„ ์ถฉ๋ถ„ํ•˜๋‹ค. ์ด ์ •๋„๋กœ๋„ ์ค‘๋ณต๋˜์ง€ ์•Š๋Š”๋‹ค. ๋Œ€๊ทœ๋ชจ ํ”„๋กœ์ ํŠธ์ธ ๋ฆฌ๋ˆ…์Šค ์ปค๋„๋„ ์ปค๋ฐ‹์„ ๊ฐ€๋ฆฌํ‚ค๋Š”๋ฐ ํ•ด์‹œ ๊ฐ’ 40์ž ์ค‘์—์„œ 12์ž๋งŒ ์‚ฌ์šฉํ•œ๋‹ค.

SHA-1 ํ•ด์‹œ ๊ฐ’์— ๋Œ€ํ•œ ๋‹จ์ƒ

Git์„ ์“ฐ๋Š” ์‚ฌ๋žŒ ์ค‘์—์„œ ๊ฐ€๋Šฅ์„ฑ์ด ๋‚ฎ๊ธด ํ•˜์ง€๋งŒ ์–ธ์  ๊ฐ€ SHA-1 ๊ฐ’์ด ์ค‘๋ณต๋ ๊นŒ ๋ด ๊ฑฑ์ •ํ•˜๋Š” ์‚ฌ๋žŒ๋„ ์žˆ๋‹ค. ์ •๋ง ๊ทธ๋ ‡๊ฒŒ ๋˜๋ฉด ์–ด๋–ค ์ผ์ด ๋ฒŒ์–ด์งˆ๊นŒ?

์ด๋ฏธ ์žˆ๋Š” SHA-1 ๊ฐ’์„ Git ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ปค๋ฐ‹ํ•˜๋ฉด ์ƒˆ๋กœ์šด ๊ฐœ์ฒด๋ผ๊ณ  ํ•ด๋„ ์ด๋ฏธ ์ปค๋ฐ‹ํ•œ ๊ฒƒ์œผ๋กœ ๊ฐ„์ฃผ๋œ๋‹ค. ๊ทธ๋ž˜์„œ ํ•ด๋‹น SHA-1 ๊ฐ’์˜ ์ปค๋ฐ‹์„ Checkoutํ•˜๋ฉด ํ•ญ์ƒ ์ฒ˜์Œ์— ์ €์žฅํ•œ ์ปค๋ฐ‹๋งŒ Checkout๋œ๋‹ค.

๊ทธ๋Ÿฌ๋‚˜ ํ•ด์‹œ ๊ฐ’์ด ์ค‘๋ณต๋˜๋Š” ์ผ์€ ์ผ์–ด๋‚˜๊ธฐ ์–ด๋ ต๋‹ค. SHA-1 ๊ฐ’์˜ ํฌ๊ธฐ๋Š” 20 ๋ฐ”์ดํŠธ(160๋น„ํŠธ)์ด๋‹ค. ํ•ด์‹œ ๊ฐ’์ด ์ค‘๋ณต๋  ํ™•๋ฅ ์ด 50%๊ฐ€ ๋˜๋Š” ๋ฐ ํ•„์š”ํ•œ ๊ฐœ์ฒด์˜ ์ˆ˜๋Š” 2^80์ด๋‹ค. ์ด ์ˆ˜๋Š” 1.2 ์ž('์ž'๋Š” '๊ฒฝ'์˜ '์–ต'๋ฐฐ - 10^24)์ด๋‹ค(์ถฉ๋Œ ํ™•๋ฅ ์„ ๊ตฌํ•˜๋Š” ๊ณต์‹์€ p=(n(n-1)/2) * (1/2^160)์ด๋‹ค). ์ฆ‰, ์ง€๊ตฌ์— ์กด์žฌํ•˜๋Š” ๋ชจ๋ž˜์•Œ์˜ ์ˆ˜์— 1200์„ ๊ณฑํ•œ ์ˆ˜์™€ ๋งž๋จน๋Š”๋‹ค.

์•„์ง๋„ SHA-1 ํ•ด์‹œ ๊ฐ’์ด ์ค‘๋ณต๋ ๊นŒ ๋ด ๊ฑฑ์ •ํ•˜๋Š” ์‚ฌ๋žŒ๋“ค์„ ์œ„ํ•ด ์ข€ ๋” ๋ง๋ถ™์ด๊ฒ ๋‹ค. ์ง€๊ตฌ์—์„œ ์•ฝ 6.5์–ต ๋ช…์˜ ์ธ๊ตฌ๊ฐ€ ๊ฐœ๋ฐœํ•˜๊ณ  ๊ฐ์ž ๋งค์ดˆ ๋ฆฌ๋ˆ…์Šค ์ปค๋„ ํžˆ์Šคํ† ๋ฆฌ ์ „์ฒด์™€(100๋งŒ ๊ฐœ) ๋งž๋จน๋Š” ๊ฐœ์ฒด๋ฅผ ์Ÿ์•„ ๋‚ด๊ณ  ๋ฐ”๋กœ Pushํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž. ์ด๋Ÿฐ ์ƒํ™ฉ์—์„œ ํ•ด์‹œ ๊ฐ’์˜ ์ถฉ๋Œ ๋‚  ํ™•๋ฅ ์ด 50%๊ฐ€ ๋˜๊ธฐ๊นŒ์ง€๋Š” 5๋…„์ด ๊ฑธ๋ฆฐ๋‹ค. ๊ทธ๋ƒฅ ์–ด๋Š ๋‚  ๋™๋ฃŒ๊ฐ€ ์ „๋ถ€ ํ•œ์ˆœ๊ฐ„์— ๋Š‘๋Œ€์—๊ฒŒ ๋ฌผ๋ ค ์ฃฝ์„ ํ™•๋ฅ ์ด ํ›จ์”ฌ ๋” ๋†’๋‹ค.

๋ธŒ๋žœ์น˜๋กœ ๊ฐ€๋ฆฌํ‚ค๊ธฐ

๋ธŒ๋žœ์น˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ปค๋ฐ‹์„ ๋‚˜ํƒ€๋‚ด๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์ด๋‹ค. ์ปค๋ฐ‹ ๊ฐœ์ฒด๋‚˜ SHA-1 ๊ฐ’์ด ํ•„์š”ํ•œ ๊ณณ์ด๋ฉด ๋ธŒ๋žœ์น˜ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ topic1 ๋ธŒ๋žœ์น˜์˜ ์ตœ๊ทผ ์ปค๋ฐ‹์„ ๋ณด๊ณ  ์‹ถ์œผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์‹คํ–‰ํ•œ๋‹ค. topic1 ๋ธŒ๋žœ์น˜๊ฐ€ ca82a6d๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‘ ๋ช…๋ น์˜ ๊ฒฐ๊ณผ๋Š” ๊ฐ™๋‹ค:

$ git show ca82a6dff817ec66f44342007202690a93763949
$ git show topic1

๋ธŒ๋žœ์น˜๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฐœ์ฒด์˜ SHA-1 ๊ฐ’์— ๋Œ€ํ•œ ๊ถ๊ธˆ์ฆ์€ rev-parse์ด๋ผ๋Š” Plumbing ๋„๊ตฌ๊ฐ€ ํ•ด๊ฒฐํ•ด ์ค€๋‹ค. _9์žฅ_์—์„œ ์ด ๋„๊ตฌ์— ๋Œ€ํ•ด ์ข€ ๋” ์ž์„ธํžˆ ์„ค๋ช…ํ•œ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ rev-parse์€ ์ €์ˆ˜์ค€ ๋ช…๋ น์–ด์ด๊ธฐ ๋•Œ๋ฌธ์— ํ‰์†Œ์—๋Š” ์ „ํ˜€ ํ•„์š”ํ•˜์ง€ ์•Š์ง€๋งŒ ๊ทธ๋ž˜๋„ ํ•œ๋ฒˆ ์‚ฌ์šฉํ•ด๋ณด๊ณ  ์–ด๋–ค ๊ฒฐ๊ณผ๊ฐ€ ๋‚˜์˜ค๋Š”์ง€ ์•Œ์•„ ๋‘์ž:

$ git rev-parse topic1
ca82a6dff817ec66f44342007202690a93763949

RefLog๋กœ ๊ฐ€๋ฆฌํ‚ค๊ธฐ

Git์€ ์ž๋™์œผ๋กœ ๋ธŒ๋žœ์น˜์™€ HEAD๊ฐ€ ์ง€๋‚œ ๋ช‡ ๋‹ฌ ๋™์•ˆ์— ๊ฐ€๋ฆฌ์ผฐ์—ˆ๋˜ ์ปค๋ฐ‹์„ ๋ชจ๋‘ ๊ธฐ๋กํ•˜๋Š”๋ฐ ์ด ๋กœ๊ทธ๋ฅผ Reflog๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.

git reflog๋ฅผ ์‹คํ–‰ํ•˜๋ฉด Reflog๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค:

$ git reflog
734713b HEAD@{0}: commit: fixed refs handling, added gc auto, updated
d921970 HEAD@{1}: merge phedders/rdocs: Merge made by recursive.
1c002dd HEAD@{2}: commit: added some blame and merge stuff
1c36188 HEAD@{3}: rebase -i (squash): updating HEAD
95df984 HEAD@{4}: commit: # This is a combination of two commits.
1c36188 HEAD@{5}: rebase -i (squash): updating HEAD
7e05da5 HEAD@{6}: rebase -i (pick): updating HEAD

Git์€ ๋ธŒ๋žœ์น˜๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ๊ทธ ์ •๋ณด๋ฅผ ์ž„์‹œ ์˜์—ญ์— ์ €์žฅํ•œ๋‹ค. ๊ทธ๋ž˜์„œ ์˜ˆ์ „์— ๋ญ˜ ๊ฐ€๋ฆฌ์ผฐ์—ˆ๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. @{n} ๊ทœ์น™์„ ์‚ฌ์šฉํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด HEAD๊ฐ€ 5๋ฒˆ ์ „์— ๊ฐ€๋ฆฌ์ผฐ๋˜ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค:

$ git show HEAD@{5}

์ˆœ์„œ๋ฟ ์•„๋‹ˆ๋ผ ์‹œ๊ฐ„๋„ ๊ฐ€๋Šฅํ•˜๋‹ค. ์–ด์ œ ๋‚ ์งœ์˜ master ๋ธŒ๋žœ์น˜๋ฅผ ๋ณด๊ณ  ์‹ถ์œผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ํ•œ๋‹ค:

$ git show master@{yesterday}

์ด ๋ช…๋ น์€ ์–ด์ œ master ๋ธŒ๋žœ์น˜๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ๋˜ ๊ฒƒ์ด ๋ฌด์—‡์ธ์ง€ ๋ณด์—ฌ์ค€๋‹ค. Reflog์— ๋‚จ์•„์žˆ๋Š” ๊ฒƒ๋งŒ ์กฐํšŒํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋„ˆ๋ฌด ์˜ค๋ž˜๋œ ์ปค๋ฐ‹์€ ์กฐํšŒํ•  ์ˆ˜ ์—†๋‹ค.

git log -g ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜๋ฉด git reflog ๊ฒฐ๊ณผ๋ฅผ git log ๋ช…๋ น๊ณผ ๊ฐ™์€ ํ˜•ํƒœ๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค:

$ git log -g master
commit 734713bc047d87bf7eac9674765ae793478c50d3
Reflog: master@{0} (Scott Chacon <schacon@gmail.com>)
Reflog message: commit: fixed refs handling, added gc auto, updated
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Jan 2 18:32:33 2009 -0800

    fixed refs handling, added gc auto, updated tests

commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Reflog: master@{1} (Scott Chacon <schacon@gmail.com>)
Reflog message: merge phedders/rdocs: Merge made by recursive.
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 15:08:43 2008 -0800

    Merge commit 'phedders/rdocs'

reflog์˜ ์ผ์€ ๋ชจ๋‘ ๋กœ์ปฌ์˜ ์ผ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‚ด reflog๊ฐ€ ๋™๋ฃŒ์˜ ์ €์žฅ์†Œ์—๋Š” ์žˆ์„ ์ˆ˜ ์—†๋‹ค. ์ด์ œ ๋ง‰ Cloneํ•œ ์ €์žฅ์†Œ์—๋„ ์•„๋ฌด๊ฒƒ๋„ ํ•œ๊ฒŒ ์—†์–ด์„œ reflog๊ฐ€ ํ•˜๋‚˜๋„ ์—†๋‹ค. git show HEAD@{2.months.ago} ๊ฐ™์€ ๋ช…๋ น์€ ์ ์–ด๋„ ๋‘ ๋‹ฌ ์ „์— Cloneํ•œ ์ €์žฅ์†Œ์—์„œ๋‚˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ์ด ๋ช…๋ น์„ 5๋ถ„ ์ „์— Cloneํ•œ ์ €์žฅ์†Œ์— ์‚ฌ์šฉํ•˜๋ฉด ์•„๋ฌด๊ฒƒ๋„ ๋‚˜์˜ค์ง€ ์•Š๋Š”๋‹ค.

๊ณ„ํ†ต ๊ด€๊ณ„๋กœ ๊ฐ€๋ฆฌํ‚ค๊ธฐ

๊ณ„ํ†ต ๊ด€๊ณ„๋กœ๋„ ์ปค๋ฐ‹์„ ํ‘œํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฆ„ ๋์— ^๋ฅผ ๋ถ™์ด๋ฉด Git์€ ํ•ด๋‹น ์ปค๋ฐ‹์˜ ๋ถ€๋ชจ๋ฅผ ์ฐพ๋Š”๋‹ค. ํ”„๋กœ์ ํŠธ ํžˆ์Šคํ† ๋ฆฌ๊ฐ€ ์•„๋ž˜์™€ ๊ฐ™์„ ๋•Œ:

$ git log --pretty=format:'%h %s' --graph
* 734713b fixed refs handling, added gc auto, updated tests
*   d921970 Merge commit 'phedders/rdocs'
|\
| * 35cfb2b Some rdoc changes
* | 1c002dd added some blame and merge stuff
|/
* 1c36188 ignore *.gem
* 9b29157 add open3_detach to gemspec file list

HEAD^๋Š” ๋ฐ”๋กœ "HEAD์˜ ๋ถ€๋ชจ"๋ฅผ ์˜๋ฏธํ•˜๋ฏ€๋กœ ๋ฐ”๋กœ ์ด์ „ ์ปค๋ฐ‹์„ ๋ณด์—ฌ์ค€๋‹ค:

$ git show HEAD^
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 15:08:43 2008 -0800

    Merge commit 'phedders/rdocs'

^ ๋’ค์— ์ˆซ์ž๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด d921970^2๋Š” "d921970์˜ ๋‘ ๋ฒˆ์งธ ๋ถ€๋ชจ"๋ฅผ ์˜๋ฏธํ•˜๊ธฐ์— ๋‘ ๋ฒˆ์งธ ๋ถ€๋ชจ๊ฐ€ ์žˆ๋Š” Merge ์ปค๋ฐ‹์—๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฒซ ๋ฒˆ์งธ ๋ถ€๋ชจ๋Š” Mergeํ•  ๋•Œ Checkoutํ–ˆ๋˜ ๋ธŒ๋žœ์น˜๋ฅผ ๋งํ•˜๊ณ  ๋‘ ๋ฒˆ์งธ ๋ถ€๋ชจ๋Š” Mergeํ•œ ๋Œ€์ƒ ๋ธŒ๋žœ์น˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค.

$ git show d921970^
commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 14:58:32 2008 -0800

    added some blame and merge stuff

$ git show d921970^2
commit 35cfb2b795a55793d7cc56a6cc2060b4bb732548
Author: Paul Hedderly <paul+git@mjr.org>
Date:   Wed Dec 10 22:22:03 2008 +0000

    Some rdoc changes

๊ณ„ํ†ต์„ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ~๋ผ๋Š” ๊ฒƒ๋„ ์žˆ๋‹ค. HEAD~์™€ HEAD^๋Š” ๋˜‘๊ฐ™์ด ์ฒซ ๋ฒˆ์งธ ๋ถ€๋ชจ๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ํ•˜์ง€๋งŒ ๊ทธ ๋’ค์— ์ˆซ์ž๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ฌ๋ผ์ง„๋‹ค. HEAD~2๋Š” ๋ช…๋ น์„ ์‹คํ–‰ํ•  ์‹œ์ ์˜ "์ฒซ ๋ฒˆ์งธ ๋ถ€๋ชจ์˜ ์ฒซ ๋ฒˆ์งธ ๋ถ€๋ชจ", ์ฆ‰ "์กฐ๋ถ€๋ชจ"๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค. ์œ„์˜ ์˜ˆ์ œ์—์„œ HEAD~3์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค:

$ git show HEAD~3
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date:   Fri Nov 7 13:47:59 2008 -0500

    ignore *.gem

์ด ๊ฒƒ์€ HEAD^^^์™€ ๊ฐ™์€ ํ‘œํ˜„์ด๋‹ค. ๋‹ค์‹œ ๋งํ•ด์„œ ์ฒซ ๋ฒˆ์งธ ๋ถ€๋ชจ์˜ ์ฒซ ๋ฒˆ์งธ ๋ถ€๋ชจ์˜ ์ฒซ ๋ฒˆ์งธ ๋ถ€๋ชจ๋ฅผ ๋งํ•œ๋‹ค:

$ git show HEAD^^^
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date:   Fri Nov 7 13:47:59 2008 -0500

    ignore *.gem

์ด ๋‘ ํ‘œํ˜„์„ ๊ฐ™์ด ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์œ„์˜ ์˜ˆ์ œ์—์„œ HEAD~3^2๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ฆ์กฐ๋ถ€๋ชจ์˜ Merge ์ปค๋ฐ‹์˜ ๋‘ ๋ฒˆ์งธ ๋ถ€๋ชจ๋ฅผ ์กฐํšŒํ•œ๋‹ค.

๋ฒ”์œ„๋กœ ์ปค๋ฐ‹ ๊ฐ€๋ฆฌํ‚ค๊ธฐ

์ปค๋ฐ‹์„ ํ•˜๋‚˜์”ฉ ์กฐํšŒํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ๋ฒ”์œ„๋ฅผ ์ฃผ๊ณ  ์—ฌ๋Ÿฌ ์ปค๋ฐ‹์„ ํ•œ๊บผ๋ฒˆ์— ์กฐํšŒํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ๋ฒ”์œ„์„ ์ฃผ๊ณ  ์กฐํšŒํ•˜๋ฉด ๋ธŒ๋žœ์น˜๋ฅผ ๊ด€๋ฆฌํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค. ๋ธŒ๋žœ์น˜๊ฐ€ ์ƒ๋‹นํžˆ ๋งŽ๊ณ  "์™œ ์•„์ง๋„ ์ฃผ ๋ธŒ๋žœ์น˜์— Merge๊ฐ€ ์•ˆ๋œ ๋ธŒ๋žœ์น˜๋“ค์€ ๋ฌด์—‡์— ๋Œ€ํ•œ ๋ธŒ๋žœ์น˜์ผ๊นŒ?"๋ผ๋Š” ์˜๋ฌธ์ด ๋“ค๋ฉด ๋ฒ”์œ„๋ฅผ ์ฃผ๊ณ  ์–ด๋–ค ๋ธŒ๋žœ์น˜์ธ์ง€ ์‰ฝ๊ฒŒ ์•Œ์•„๋ณผ ์ˆ˜ ์žˆ๋‹ค.

Double Dot

๋ฒ”์œ„๋ฅผ ํ‘œํ˜„ํ•˜๋Š” ๋ฌธ๋ฒ•์œผ๋กœ Double Dot(..)์„ ๋งŽ์ด ์“ด๋‹ค. Double Dot์€ ํ•œ์ชฝ์—๋Š” ์žˆ๊ณ  ๋‹ค๋ฅธ ์ชฝ์—๋Š” ์—†๋Š” ์ปค๋ฐ‹์ด ๋ฌด์—‡์ธ์ง€ Git์—๊ฒŒ ๋ฌผ์–ด๋ณด๋Š” ๊ฒƒ์ด๋‹ค. ์˜ˆ๋“ค ๋“ค์–ด ๊ทธ๋ฆผ 6-1๊ณผ ๊ฐ™์€ ์ปค๋ฐ‹ ํžˆ์Šคํ† ๋ฆฌ๊ฐ€ ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž.

experiment ๋ธŒ๋žœ์น˜์˜ ์ปค๋ฐ‹๋“ค ์ค‘์—์„œ ์•„์ง master ๋ธŒ๋žœ์น˜์— Mergeํ•˜์ง€ ์•Š์€ ๊ฒƒ๋งŒ ๋ณด๊ณ  ์‹ถ์œผ๋ฉด master..experiment๋ผ๊ณ  ์‚ฌ์šฉํ•œ๋‹ค. ์ด ํ‘œํ˜„์€ "master์—๋Š” ์—†์ง€๋งŒ, experiment์—๋Š” ์žˆ๋Š” ์ปค๋ฐ‹"์„ ์˜๋ฏธํ•œ๋‹ค. ์—ฌ๊ธฐ์—์„œ๋Š” ์„ค๋ช…์„ ์‰ฝ๊ฒŒ ํ•˜๊ณ ์ž ์‹ค์ œ ์กฐํšŒ ๊ฒฐ๊ณผ๊ฐ€ ์•„๋‹ˆ๋ผ ๊ทธ๋ฆผ 6-1์˜ ๋ฌธ์ž๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค:

$ git log master..experiment
D
C

๋ฐ˜๋Œ€๋กœ experiment์—๋Š” ์—†๊ณ  master์—๋งŒ ์žˆ๋Š” ์ปค๋ฐ‹์ด ๊ถ๊ธˆํ•˜๋ฉด ๋ธŒ๋žœ์น˜ ์ˆœ์„œ๋ฅผ ๊ฑฐ๊พธ๋กœ ์‚ฌ์šฉํ•œ๋‹ค. experiment..master๋Š” experiment์—๋Š” ์—†๊ณ  master์—๋งŒ ์žˆ๋Š” ๊ฒƒ์„ ์•Œ๋ ค์ค€๋‹ค:

$ git log experiment..master
F
E

experiment ๋ธŒ๋žœ์น˜๋ฅผ Mergeํ•˜๊ธฐ ์ „์— ๋ฌด์—‡์ด ๋ณ€๊ฒฝ๋๋Š”์ง€ ๊ถ๊ธˆํ•˜๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ฆฌ๋ชจํŠธ ์ €์žฅ์†Œ์— Pushํ•  ๋•Œ์—๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์ฐจ์ด๊ฐ€ ๊ถ๊ธˆํ•˜๋‹ค. ์ด๋ ‡๊ฒŒ ๊ถ๊ธˆํ•œ ์ƒํ™ฉ์—์„œ ๊ต‰์žฅํžˆ ์œ ์šฉํ•˜๋‹ค:

$ git log origin/master..HEAD

์ด ๋ช…๋ น์€ origin ์ €์žฅ์†Œ์˜ master ๋ธŒ๋žœ์น˜์—๋Š” ์—†๊ณ  ํ˜„์žฌ Checkout์ค‘์ธ ๋ธŒ๋žœ์น˜์—๋งŒ ์žˆ๋Š” ์ปค๋ฐ‹์„ ๋ณด์—ฌ์ค€๋‹ค. Checkoutํ•œ ๋ธŒ๋žœ์น˜๊ฐ€ origin/master๋ผ๋ฉด git log origin/master..HEAD๊ฐ€ ๋ณด์—ฌ์ฃผ๋Š” ์ปค๋ฐ‹์ด Pushํ•˜๋ฉด ์„œ๋ฒ„์— ์ „์†ก๋  ์ปค๋ฐ‹์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ•œ์ชฝ์˜ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ์ƒ๋žตํ•˜๋ฉด Git์€ HEAD๋ผ๊ณ  ๊ฐ€์ •ํ•œ๋‹ค. git log origin/master..๋Š” git log origin/master..HEAD์™€ ๊ฐ™๋‹ค.

์„ธ ๊ฐœ ์ด์ƒ์˜ ๋ ˆํผ๋Ÿฐ์Šค

Double Dot์€ ๊ฐ„๋‹จํ•˜๊ณ  ์œ ์šฉํ•˜๋‹ค. ํ•˜์ง€๋งŒ, ๋‘ ๊ฐœ ์ด์ƒ์˜ ๋ธŒ๋žœ์น˜์—๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ํ˜„์žฌ ์ž‘์—… ์ค‘์ธ ๋ธŒ๋žœ์น˜์—๋Š” ์žˆ์ง€๋งŒ ๋‹ค๋ฅธ ์—ฌ๋Ÿฌ ๋ธŒ๋žœ์น˜์—๋Š” ์—†๋Š” ์ปค๋ฐ‹์ด ๋ณด๊ณ  ์‹ถ์œผ๋ฉด ..์œผ๋กœ๋Š” ํ™•์ธํ•  ์ˆ˜ ์—†๋‹ค. ^๊ณผ --not ์˜ต์…˜ ๋’ค์— ๋ธŒ๋žœ์น˜ ์ด๋ฆ„์„ ๋„ฃ์œผ๋ฉด ๊ทธ ๋ธŒ๋žœ์น˜์— ์—†๋Š” ์ปค๋ฐ‹์„ ์ฐพ์•„์ค€๋‹ค. ๋‹ค์Œ ๋ช…๋ น์–ด๋Š” ๋ชจ๋‘ ๊ฐ™์€ ๋ช…๋ น์ด๋‹ค:

$ git log refA..refB
$ git log ^refA refB
$ git log refB --not refA

Double Dot์œผ๋กœ๋Š” ์„ธ ๊ฐœ ์ด์ƒ์˜ ๋ ˆํผ๋Ÿฐ์Šค์— ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์ง€๋งŒ ์ด ์˜ต์…˜์€ ๊ฐ€๋Šฅํ•˜๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด refA๋‚˜ refB์—๋Š” ์žˆ์ง€๋งŒ refC์—๋Š” ์—†๋Š” ์ปค๋ฐ‹์„ ๋ณด๋ ค๋ฉด ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค:

$ git log refA refB ^refC
$ git log refA refB --not refC

์ด ์กฐ๊ฑด์„ ์ž˜ ์‘์šฉํ•˜๋ฉด ์ž‘์—… ์ค‘์ธ ๋ธŒ๋žœ์น˜์™€ ๋‹ค๋ฅธ ๋ธŒ๋žœ์น˜๋ฅผ ๋งค์šฐ ์ƒ์„ธํ•˜๊ฒŒ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋‹ค.

Triple Dot

Triple Dot์€ ์–‘์ชฝ์— ์žˆ๋Š” ๋‘ ๋ ˆํผ๋Ÿฐ์Šค ์‚ฌ์ด์—์„œ ๊ณตํ†ต์œผ๋กœ ๊ฐ€์ง€๋Š” ๊ฒƒ์„ ์ œ์™ธํ•˜๊ณ  ์„œ๋กœ ๋‹ค๋ฅธ ์ปค๋ฐ‹๋งŒ ๋ณด์—ฌ์ค€๋‹ค. ๊ทธ๋ฆผ 6-1์˜ ์ปค๋ฐ‹ ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ๋‹ค์‹œ ๋ณด์ž. ๋งŒ์•ฝ master์™€ experiment์˜ ๊ณตํ†ต๋ถ€๋ถ„์€ ๋นผ๊ณ  ๋‹ค๋ฅธ ์ปค๋ฐ‹๋งŒ ๋ณด๊ณ  ์‹ถ์œผ๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ํ•˜๋ฉด ๋œ๋‹ค:

$ git log master...experiment
F
E
D
C

์šฐ๋ฆฌ๊ฐ€ ์•„๋Š” log ๋ช…๋ น์˜ ๊ฒฐ๊ณผ๋ฅผ ์ตœ๊ทผ ๋‚ ์งœ์ˆœ์œผ๋กœ ๋ณด์—ฌ์ค€๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” ์ปค๋ฐ‹์„ ๋„ค ๊ฐœ ๋ณด์—ฌ์ค€๋‹ค.

๊ทธ๋ฆฌ๊ณ  log ๋ช…๋ น์— --left-right ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๊ฐ ์ปค๋ฐ‹์ด ์–ด๋Š ๋ธŒ๋žœ์น˜์— ์†ํ•˜๋Š”์ง€๋„ ๋ณด์—ฌ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ์ข€ ๋” ์ดํ•ดํ•˜๊ธฐ ์‰ฝ๋‹ค:

$ git log --left-right master...experiment
< F
< E
> D
> C

์œ„์™€ ๊ฐ™์€ ๋ช…๋ น๋“ค์„ ์‚ฌ์šฉํ•˜๋ฉด ์›ํ•˜๋Š” ์ปค๋ฐ‹์„ ์ข€ ๋” ๊ผผ๊ผผํ•˜๊ฒŒ ์‚ดํŽด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

๋Œ€ํ™”ํ˜• ๋ช…๋ น์–ด

Git์€ ๋Œ€ํ™”ํ˜• ๋ช…๋ น์–ด๋„ ์ œ๊ณตํ•ด์„œ ์ข€ ๋” ์‰ฝ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ ์†Œ๊ฐœํ•˜๋Š” ๋ช‡ ๊ฐ€์ง€ ๋Œ€ํ™”ํ˜• ๋ช…๋ น์–ด๋ฅผ ์ด์šฉํ•˜๋ฉด ๋ฐ”๋กœ ์ „๋ฌธ๊ฐ€์ฒ˜๋Ÿผ ๋Šฅ์ˆ™ํ•˜๊ฒŒ ์ปค๋ฐ‹ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋Œ€ํ™”ํ˜•์œผ๋กœ ์ปค๋ฐ‹ํ•  ํŒŒ์ผ์„ ๊ณ ๋ฅผ ์ˆ˜๋„ ์žˆ๊ณ  ์ˆ˜์ •๋œ ํŒŒ์ผ์˜ ์ผ๋ถ€๋ถ„๋งŒ ์ปค๋ฐ‹ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์ˆ˜์ •ํ•œ ํŒŒ์ผ์ด ๋งค์šฐ ๋งŽ๊ณ  ํ†ต์งธ๋กœ ์ปค๋ฐ‹ํ•˜์ง€ ์•Š๊ณ  ์ด์Šˆ ๋ณ„๋กœ ๋‚˜๋ˆ ์„œ ์ปค๋ฐ‹ํ•  ๋•Œ ์œ ์šฉํ•˜๋‹ค. ์ด์Šˆ ๋ณ„๋กœ ๋‚˜๋ˆ ์„œ ์ปค๋ฐ‹ํ•˜๋ฉด ๋™๋ฃŒ๊ฐ€ ์‰ฝ๊ฒŒ ๊ฒ€ํ† ํ•  ์ˆ˜ ์žˆ๋‹ค. git add ๋ช…๋ น์— -i๋‚˜ --interactive ์˜ต์…˜์„ ์ฃผ๊ณ  ์‹คํ–‰ํ•˜๋ฉด Git์€ ์•„๋ž˜์™€ ๊ฐ™์€ ๋Œ€ํ™”ํ˜• ๋ชจ๋“œ๋กœ ๋“ค์–ด๊ฐ„๋‹ค:

$ git add -i
           staged     unstaged path
  1:    unchanged        +0/-1 TODO
  2:    unchanged        +1/-1 index.html
  3:    unchanged        +5/-1 lib/simplegit.rb

*** Commands ***
  1: status     2: update      3: revert     4: add untracked
  5: patch      6: diff        7: quit       8: help
What now>

์ด ๋ช…๋ น์–ด๋Š” Staging Area์˜ ํ˜„์žฌ ์ƒํƒœ๊ฐ€ ์–ด๋–ป๊ณ  ํ•  ์ˆ˜ ์žˆ๋Š” ์ผ์ด ๋ฌด์—‡์ธ์ง€ ๋ณด์—ฌ์ค€๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ git status ๋ช…๋ น์ด ๋ณด์—ฌ์ฃผ๋Š” ๊ฒƒ๊ณผ ๊ฐ™์ง€๋งŒ ์ข€ ๋” ๊ฐ„๊ฒฐํ•˜๊ณ  ์ •๋ˆ๋ผ ์žˆ๋‹ค. ์™ผ์ชฝ์—๋Š” Staged ์ƒํƒœ์ธ ํŒŒ์ผ๋“ค์„ ๋ณด์—ฌ์ฃผ๊ณ  ์˜ค๋ฅธ์ชฝ์—๋Š” Unstaged์ธ ํŒŒ์ผ๋“ค์„ ๋ณด์—ฌ์ค€๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๋งˆ์ง€๋ง‰ Commands ๋ถ€๋ถ„์—์„œ๋Š” ํ•  ์ˆ˜ ์ผ์ด ๋ฌด์—‡์ธ์ง€ ๋ณด์—ฌ์ค€๋‹ค. ํŒŒ์ผ์„ Stageํ•˜๊ณ  Unstageํ•˜๋Š” ๊ฒƒ, Untracked ์ƒํƒœ์˜ ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ, Stageํ•œ ํŒŒ์ผ์„ diffํ•ด๋ณด๋Š” ๊ฒƒ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ์ˆ˜์ •ํ•œ ํŒŒ์ผ์˜ ์ผ๋ถ€๋ถ„๋งŒ Staging Area์— ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

Staging Area์— ํŒŒ์ผ ์ถ”๊ฐ€ํ•˜๊ณ  ์ถ”๊ฐ€ ์ทจ์†Œํ•˜๊ธฐ

What now> ํ”„๋กฌํ”„ํŠธ์—์„œ 2๋‚˜ u๋ฅผ(update) ์ž…๋ ฅํ•˜๋ฉด Staging Area์— ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋Š” ํŒŒ์ผ์„ ์ „๋ถ€ ๋ณด์—ฌ์ค€๋‹ค:

What now> 2
           staged     unstaged path
  1:    unchanged        +0/-1 TODO
  2:    unchanged        +1/-1 index.html
  3:    unchanged        +5/-1 lib/simplegit.rb
Update>>

TODO์™€ index.html ํŒŒ์ผ์„ Stageํ•˜๋ ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ์ž…๋ ฅํ•œ๋‹ค:

Update>> 1,2
           staged     unstaged path
* 1:    unchanged        +0/-1 TODO
* 2:    unchanged        +1/-1 index.html
  3:    unchanged        +5/-1 lib/simplegit.rb
Update>>

* ํ‘œ์‹œ๊ฐ€ ๋ถ™์€ ํŒŒ์ผ์€ stageํ•˜๋„๋ก ์„ ํƒํ•œ ๊ฒƒ์ด๋‹ค. ์„ ํƒํ•˜๊ณ  Update>> ํ”„๋กฌํ”„ํŠธ์— ์•„๋ฌด๊ฒƒ๋„ ์ž…๋ ฅํ•˜์ง€ ์•Š๊ณ  ์—”ํ„ฐ๋ฅผ ์น˜๋ฉด Git์€ ์„ ํƒํ•œ ํŒŒ์ผ์„ Staging Area๋กœ ์ถ”๊ฐ€ํ•œ๋‹ค:

Update>>
updated 2 paths

*** Commands ***
  1: status     2: update      3: revert     4: add untracked
  5: patch      6: diff        7: quit       8: help
What now> 1
           staged     unstaged path
  1:        +0/-1      nothing TODO
  2:        +1/-1      nothing index.html
  3:    unchanged        +5/-1 lib/simplegit.rb

์ด์ œ TODO์™€ index.html ํŒŒ์ผ์€ Stageํ–ˆ๊ณ  simplegit.rb ํŒŒ์ผ๋งŒ ์•„์ง Unstaged ์ƒํƒœ๋กœ ๋‚จ์•„ ์žˆ๋‹ค. ์ด์ œ TODO ํŒŒ์ผ์„ ๋‹ค์‹œ Unstageํ•˜๊ณ  ์‹ถ์œผ๋ฉด 3์ด๋‚˜ r์„(Revert) ์ž…๋ ฅํ•œ๋‹ค:

*** Commands ***
  1: status     2: update      3: revert     4: add untracked
  5: patch      6: diff        7: quit       8: help
What now> 3
           staged     unstaged path
  1:        +0/-1      nothing TODO
  2:        +1/-1      nothing index.html
  3:    unchanged        +5/-1 lib/simplegit.rb
Revert>> 1
           staged     unstaged path
* 1:        +0/-1      nothing TODO
  2:        +1/-1      nothing index.html
  3:    unchanged        +5/-1 lib/simplegit.rb
Revert>> [enter]
reverted one path

๋‹ค์‹œ Status๋ฅผ ์„ ํƒํ•˜๋ฉด TODO ํŒŒ์ผ์ด Unstaged ์ƒํƒœ์ธ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค:

*** Commands ***
  1: status     2: update      3: revert     4: add untracked
  5: patch      6: diff        7: quit       8: help
What now> 1
           staged     unstaged path
  1:    unchanged        +0/-1 TODO
  2:        +1/-1      nothing index.html
  3:    unchanged        +5/-1 lib/simplegit.rb

Staged ํŒŒ์ผ์˜ ๋ณ€๊ฒฝ๋‚ด์šฉ์„ ๋ณด๋ ค๋ฉด 6์ด๋‚˜ d๋ฅผ(diff) ์ž…๋ ฅํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๋จผ์ € Staged ์ƒํƒœ์ธ ํŒŒ์ผ์„ ๋ณด์—ฌ์ค€๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ์ค‘์—์„œ ํŒŒ์ผ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•œ๋‹ค. ๊ทธ ๊ฒฐ๊ณผ๋Š” ๋ช…๋ น ์ค„์—์„œ git diff --cached๋ผ๊ณ  ์‹คํ–‰ํ•œ ๊ฒฐ๊ณผ์™€ ๊ฐ™๋‹ค:

*** Commands ***
  1: status     2: update      3: revert     4: add untracked
  5: patch      6: diff        7: quit       8: help
What now> 6
           staged     unstaged path
  1:        +1/-1      nothing index.html
Review diff>> 1
diff --git a/index.html b/index.html
index 4d07108..4335f49 100644
--- a/index.html
+++ b/index.html
@@ -16,7 +16,7 @@ Date Finder

 <p id="out">...</p>

-<div id="footer">contact : support@github.com</div>
+<div id="footer">contact : email.support@github.com</div>

 <script type="text/javascript">

๋Œ€ํ™”ํ˜• ๋ชจ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Staging Area์— ํŒŒ์ผ์„ ์ข€ ๋” ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

ํŒŒ์ผ์˜ ์ผ๋ถ€๋ถ„๋งŒ Staging Area์— ์ถ”๊ฐ€ํ•˜๊ธฐ

ํŒŒ์ผ์˜ ์ผ๋ถ€๋ถ„๋งŒ Staging Area์— ์ถ”๊ฐ€ํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด simplegit.rb ํŒŒ์ผ์€ ๊ณ ์นœ ๋ถ€๋ถ„์ด ๋‘ ๊ตฐ๋ฐ์ด๋‹ค. ๊ทธ ์ค‘ ํ•˜๋‚˜๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ  ๋‚˜๋จธ์ง€๋Š” ๊ทธ๋Œ€๋กœ ๋‘๊ณ  ์‹ถ๋‹ค. Git์—์„œ๋Š” ์ด๋Ÿฐ ์ž‘์—…๋„ ๋งค์šฐ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋Œ€ํ™”ํ˜• ํ”„๋กฌํ”„ํŠธ์—์„œ 5, p๋ฅผ(patch) ์ž…๋ ฅํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด Git์€ ๋ถ€๋ถ„์ ์œผ๋กœ Staging Area์— ์ถ”๊ฐ€ํ•  ํŒŒ์ผ์ด ์žˆ๋Š”์ง€ ๋ฌป๋Š”๋‹ค. ํŒŒ์ผ์„ ์„ ํƒํ•˜๋ฉด ํŒŒ์ผ์˜ ํŠน์ • ๋ถ€๋ถ„์„ Staging Area์— ์ถ”๊ฐ€ํ•  ๊ฒƒ์ธ์ง€ ๋ถ€๋ถ„๋ณ„๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ๋ฌป๋Š”๋‹ค:

diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index dd5ecc4..57399e0 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -22,7 +22,7 @@ class SimpleGit
   end

   def log(treeish = 'master')
-    command("git log -n 25 #{treeish}")
+    command("git log -n 30 #{treeish}")
   end

   def blame(path)
Stage this hunk [y,n,a,d,/,j,J,g,e,?]?

์—ฌ๊ธฐ์—์„œ ?๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์„ ํƒ ๊ฐ€๋Šฅํ•œ ๋ช…๋ น์–ด๋ฅผ ์„ค๋ช…ํ•ด์ค€๋‹ค:

Stage this hunk [y,n,a,d,/,j,J,g,e,?]? ?
y - stage this hunk
n - do not stage this hunk
a - stage this and all the remaining hunks in the file
d - do not stage this hunk nor any of the remaining hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help

y๋‚˜ n์„ ์ž…๋ ฅํ•˜๋ฉด ๊ฐ ๋ถ€๋ถ„์„ Stageํ• ์ง€ ๋ง์ง€ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ, ํŒŒ์ผ์„ ํ†ต์งธ๋กœ stageํ•˜๊ฑฐ๋‚˜ ํ•„์š”ํ•  ๋•Œ๊นŒ์ง€ ์•„์˜ˆ ๊ทธ๋Œ€๋กœ ๋‚จ๊ฒจ ๋‘๋Š” ๊ฒƒ์ด ๋‹ค์Œ์— ๋” ์œ ์šฉํ• ์ง€๋„ ๋ชจ๋ฅธ๋‹ค. ์–ด์จŒ๋“  ํŒŒ์ผ์˜ ํ•œ ๋ถ€๋ถ„์€ Stageํ•˜๊ณ  ๋‹ค๋ฅธ ๋ถ€๋ถ„์€ unstaged ์ƒํƒœ๋กœ ๋‚จ๊ฒจ๋†“๊ณ  status ๋ช…๋ น์œผ๋กœ ํ™•์ธํ•ด๋ณด๋ฉด ๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค:

What now> 1
           staged     unstaged path
  1:    unchanged        +0/-1 TODO
  2:        +1/-1      nothing index.html
  3:        +1/-1        +4/-0 lib/simplegit.rb

simplegit.rb ํŒŒ์ผ์˜ ์ƒํƒœ๋ฅผ ๋ณด์ž. ์–ด๋–ค ์ค„์€ Staged ์ƒํƒœ์ด๊ณ  ์–ด๋–ค ์ค„์€ Unstaged๋ผ๊ณ  ์•Œ๋ ค์ค„ ๊ฒƒ์ด๋‹ค. ์ด ํŒŒ์ผ์€ ๋ถ€๋ถ„์ ์œผ๋กœ Stageํ•˜์˜€๋‹ค. ์ด์ œ ๋Œ€ํ™”ํ˜• ๋ชจ๋“œ๋ฅผ ์ข…๋ฃŒํ•˜๊ณ  ์ผ๋ถ€๋ถ„๋งŒ Stageํ•œ ํŒŒ์ผ์„ ์ปค๋ฐ‹ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋์œผ๋กœ ๋Œ€ํ™”ํ˜• ์Šคํฌ๋ฆฝํŠธ๋กœ๋งŒ ํŒŒ์ผ ์ผ๋ถ€๋ถ„์„ Stageํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. git add -p๋‚˜ git add --patch๋กœ๋„ ๊ฐ™์€ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค.

Stashing

๋‹น์‹ ์ด ์–ด๋–ค ํ”„๋กœ์ ํŠธ์—์„œ ํ•œ ๋ถ€๋ถ„์„ ๋‹ด๋‹นํ•˜๊ณ  ์žˆ๋‹ค๊ณ  ํ•˜์ž. ๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์—์„œ ๋ญ”๊ฐ€ ์ž‘์—…ํ•˜๋˜ ์ผ์ด ์žˆ๊ณ  ๋‹ค๋ฅธ ์š”์ฒญ์ด ๋“ค์–ด์™€์„œ ์ž ์‹œ ๋ธŒ๋žœ์น˜๋ฅผ ๋ณ€๊ฒฝํ•ด์•ผ ํ•  ์ผ์ด ์ƒ๊ฒผ๋‹ค๊ณ  ์น˜์ž. ์•„์ง ์™„๋ฃŒํ•˜์ง€ ์•Š์€ ์ผ์„ ์ปค๋ฐ‹ํ•˜๋Š” ๊ฒƒ์€ ์ข€ ๊ป„๋„๋Ÿฝ๋‹ค. ์ด๋Ÿฐ ์ƒํ™ฉ์—์„œ๋Š” ์ปค๋ฐ‹ํ•˜์ง€ ์•Š๊ณ  ๋‚˜์ค‘์— ๋‹ค์‹œ ๋Œ์•„์™€์„œ ์ž‘์—…์„ ๋‹ค์‹œ ํ•˜๊ณ  ์‹ถ์„ ๊ฒƒ์ด๋‹ค. ์ด ๋ฌธ์ œ๋Š” git stash๋ผ๋Š” ๋ช…๋ น์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

Stash ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜๋ฉด ์›Œํ‚น ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์ˆ˜์ •ํ•œ ํŒŒ์ผ๋งŒ ์ €์žฅํ•œ๋‹ค. Stash๋Š” Modified์ด๋ฉด์„œ Tracked ์ƒํƒœ์ธ ํŒŒ์ผ๊ณผ Staging Area์— ์žˆ๋Š” ํŒŒ์ผ๋“ค์„ ๋ณด๊ด€ํ•ด๋‘๋Š” ์žฅ์†Œ๋‹ค. ์•„์ง ๋๋‚˜์ง€ ์•Š์€ ์ˆ˜์ •์‚ฌํ•ญ์„ ์Šคํƒ์— ์ž ์‹œ ์ €์žฅํ–ˆ๋‹ค๊ฐ€ ๋‚˜์ค‘์— ๋‹ค์‹œ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•˜๋˜ ์ผ์„ Stashํ•˜๊ธฐ

์˜ˆ์ œ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•˜๋‚˜ ์‚ดํŽด๋ณด์ž. ํŒŒ์ผ์„ ๋‘ ๊ฐœ ์ˆ˜์ •ํ•˜๊ณ  ๊ทธ ์ค‘ ํ•˜๋‚˜๋Š” Staging Area์— ์ถ”๊ฐ€ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  git status ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค:

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#      modified:   index.html
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#
#      modified:   lib/simplegit.rb
#

์ด์ œ ๋ธŒ๋žœ์น˜๋ฅผ ๋ณ€๊ฒฝํ•œ๋‹ค. ์•„์ง ์ž‘์—… ์ค‘์ธ ํŒŒ์ผ์€ ์ปค๋ฐ‹ํ•  ๊ฒŒ ์•„๋‹ˆ๋ผ์„œ ๋ชจ๋‘ Stashํ•œ๋‹ค. git stash๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์Šคํƒ์— ์ƒˆ๋กœ์šด Stash๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค:

$ git stash
Saved working directory and index state \
  "WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")

๋Œ€์‹  ์›Œํ‚น ๋””๋ ‰ํ† ๋ฆฌ๋Š” ๊นจ๋—ํ•ด์กŒ๋‹ค:

$ git status
# On branch master
nothing to commit, working directory clean

์ด์ œ ์•„๋ฌด ๋ธŒ๋žœ์น˜๋‚˜ ๊ณจ๋ผ์„œ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค. ์ˆ˜์ •ํ•˜๋˜ ๊ฒƒ์€ ์Šคํƒ์— ์ €์žฅํ–ˆ๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์ด git stash list๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ €์žฅํ•œ Stash๋ฅผ ํ™•์ธํ•œ๋‹ค:

$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log

Stash ๋‘ ๊ฐœ๋Š” ์›๋ž˜ ์žˆ์—ˆ๋˜ ๊ฒƒ์ด๋‹ค. ๊ทธ๋ž˜์„œ ํ˜„์žฌ ์ด ์„ธ ๊ฐœ์˜ Stash๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด์ œ git stash apply๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Stash๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. git stash ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ฉด ์ด ๋ช…๋ น์— ๋Œ€ํ•œ ๋„์›€๋ง์„ ๋ณด์—ฌ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ํŽธ๋ฆฌํ•˜๋‹ค. ๋‹ค๋ฅธ Stash๋ฅผ ๊ณ ๋ฅด๊ณ  ์‹ถ์œผ๋ฉด Stash ์ด๋ฆ„์„ ์ž…๋ ฅํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฆ„์ด ์—†์œผ๋ฉด Git์€ ๊ฐ€์žฅ ์ตœ๊ทผ์˜ Stash๋ฅผ ์ ์šฉํ•œ๋‹ค:

$ git stash apply
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#
#      modified:   index.html
#      modified:   lib/simplegit.rb
#

Git์€ Stash์— ์ €์žฅํ•  ๋•Œ ์ˆ˜์ •ํ•˜๋˜ ํŒŒ์ผ์„ ๋ณต์›ํ•ด์ค€๋‹ค. ๋ณต์›ํ•  ๋•Œ์˜ ์›Œํ‚น ๋””๋ ‰ํ† ๋ฆฌ๋Š” Stashํ•  ๋•Œ์˜ ๊ทธ ๋ธŒ๋žœ์น˜์ด๊ณ  ์›Œํ‚น ๋””๋ ‰ํ† ๋ฆฌ๋„ ๊นจ๋—ํ•œ ์ƒํƒœ์˜€๋‹ค. ํ•˜์ง€๋งŒ, ๊ผญ ๊นจ๋—ํ•œ ์›Œํ‚น ๋””๋ ‰ํ† ๋ฆฌ๋‚˜ Stashํ•  ๋•Œ์™€ ๊ฐ™์€ ๋ธŒ๋žœ์น˜์— ์ ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์–ด๋–ค ๋ธŒ๋žœ์น˜์—์„œ Stashํ•˜๊ณ  ๋‹ค๋ฅธ ๋ธŒ๋žœ์น˜๋กœ ์˜ฎ๊ธฐ๊ณ ์„œ ๊ฑฐ๊ธฐ์— Stash๋ฅผ ๋ณต์›ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ผญ ์›Œํ‚น ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ๊นจ๋—ํ•œ ์ƒํƒœ์ผ ํ•„์š”๋„ ์—†๋‹ค. ์›Œํ‚น ๋””๋ ‰ํ† ๋ฆฌ์— ์ˆ˜์ •ํ•˜๊ณ  ์ปค๋ฐ‹ํ•˜์ง€ ์•Š์€ ํŒŒ์ผ๋“ค์ด ์žˆ์„ ๋•Œ์—๋„ Stash๋ฅผ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋งŒ์•ฝ ์ถฉ๋Œ์ด ๋‚˜๋ฉด ์•Œ๋ ค์ค€๋‹ค.

Git์€ Stash๋ฅผ ์ ์šฉํ•  ๋•Œ Staged ์ƒํƒœ์˜€๋˜ ํŒŒ์ผ์„ ์ž๋™์œผ๋กœ ๋‹ค์‹œ Staged ์ƒํƒœ๋กœ ๋งŒ๋“ค์–ด ์ฃผ์ง€ ์•Š๋Š”๋‹ค. ๊ทธ๋ž˜์„œ git stash apply ๋ช…๋ น์„ ์‹คํ–‰ํ•  ๋•Œ --index ์˜ต์…˜์„ ์ฃผ์–ด์•ผ Staged ์ƒํƒœ๊นŒ์ง€ ๋ณต์›ํ•œ๋‹ค. ๊ทธ๋Ÿผ ์›๋ž˜ ์ž‘์—…ํ•˜๋˜ ์ƒํƒœ๋กœ ๋Œ์•„์˜ฌ ์ˆ˜ ์žˆ๋‹ค:

$ git stash apply --index
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#      modified:   index.html
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#
#      modified:   lib/simplegit.rb
#

apply ์˜ต์…˜์€ ๋‹จ์ˆœํžˆ Stash๋ฅผ ์ ์šฉํ•˜๋Š” ๊ฒƒ๋ฟ์ด๋‹ค. Stash๋Š” ์—ฌ์ „ํžˆ ์Šคํƒ์— ๋‚จ์•„ ์žˆ๋‹ค. git stash drop ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•ด๋‹น Stash๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค:

$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
$ git stash drop stash@{0}
Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)

๊ทธ๋ฆฌ๊ณ  git stash pop์ด๋ผ๋Š” ๋ช…๋ น๋„ ์žˆ๋Š”๋ฐ ์ด ๋ช…๋ น์€ Stash๋ฅผ ์ ์šฉํ•˜๊ณ  ๋‚˜์„œ ๋ฐ”๋กœ ์Šคํƒ์—์„œ ์ œ๊ฑฐํ•ด์ค€๋‹ค.

Stash ๋˜๋Œ๋ฆฌ๊ธฐ

Stash๋ฅผ ์ ์šฉํ•˜๊ณ  ๋‚˜์„œ ์•„์ฐจ ์‹ถ์„ ๋•Œ์—๋Š” ๋‹ค์‹œ ๋˜๋Œ๋ ค ๋†“์•„์•ผ ํ•œ๋‹ค. Git์€ stash unapply ๊ฐ™์€ ๋ช…๋ น์„ ์ œ๊ณตํ•˜์ง€๋Š” ์•Š๋Š”๋‹ค. ํ•˜์ง€๋งŒ, Stash๋ฅผ ์ด์šฉํ•ด์„œ ํŒจ์น˜๋ฅผ ๋งŒ๋“ค๊ณ  ๊ทธ๊ฒƒ์„ ๊ฑฐ๊พธ๋กœ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค:

$ git stash show -p stash@{0} | git apply -R

Stash๋ฅผ ๋ช…์‹œํ•˜์ง€ ์•Š์œผ๋ฉด Git์€ ๊ฐ€์žฅ ์ตœ๊ทผ์˜ Stash๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค:

$ git stash show -p | git apply -R

stash-unapply๋ผ๋Š” alias๋ฅผ ๋งŒ๋“ค๊ณ  ํŽธ๋ฆฌํ•˜๊ฒŒ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค:

$ git config --global alias.stash-unapply '!git stash show -p | git apply -R'
$ git stash apply
$ #... work work work
$ git stash-unapply

Stash๋ฅผ ์ ์šฉํ•œ ๋ธŒ๋žœ์น˜ ๋งŒ๋“ค๊ธฐ

๋ณดํ†ต Stash์— ์ €์žฅํ•˜๋ฉด ํ•œ๋™์•ˆ ๊ทธ๋Œ€๋กœ ์œ ์ง€ํ•˜๊ณ  ๊ทธ ๋ธŒ๋žœ์น˜์—์„œ๋Š” ๊ณ„์† ์ƒˆ๋กœ์šด ์ผ์„ ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ €์žฅํ•œ Stash๋ฅผ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋ฌธ์ œ๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค. ์ˆ˜์ •ํ•œ ํŒŒ์ผ์— Stash๋ฅผ ์ ์šฉํ•˜๋ฉด ์ถฉ๋Œ์ด ๋‚  ์ˆ˜ ์žˆ๋‹ค. ์ถฉ๋Œ์ด ๋‚˜๋ฉด ์ถฉ๋Œ์„ ํ•ด๊ฒฐํ•ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Stashํ•œ ๊ฒƒ์€ ๋‹ค์‹œ ํ…Œ์ŠคํŠธํ•ด์•ผ ํ•œ๋‹ค. git stash branch ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ฉด Stashํ•  ๋‹น์‹œ์˜ ์ปค๋ฐ‹์„ Checkoutํ•œ ํ›„ ์ƒˆ๋กœ์šด ๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“ค๊ณ  ์—ฌ๊ธฐ์— ์ ์šฉํ•œ๋‹ค. ์ด ๋ชจ๋“  ๊ฒƒ์ด ์„ฑ๊ณตํ•˜๋ฉด Stash๋ฅผ ์‚ญ์ œํ•œ๋‹ค:

$ git stash branch testchanges
Switched to a new branch "testchanges"
# On branch testchanges
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#      modified:   index.html
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#
#      modified:   lib/simplegit.rb
#
Dropped refs/stash@{0} (f0dfc4d5dc332d1cee34a634182e168c4efc3359)

์ด ๋ช…๋ น์€ ๋ธŒ๋žœ์น˜๋ฅผ ์ƒˆ๋กœ ๋งŒ๋“ค๊ณ  Stash๋ฅผ ๋ณต์›ํ•ด์ฃผ๋Š” ๋งค์šฐ ํŽธ๋ฆฌํ•œ ๋„๊ตฌ๋‹ค.

ํžˆ์Šคํ† ๋ฆฌ ๋‹จ์žฅํ•˜๊ธฐ

Git์œผ๋กœ ์ผํ•˜๋‹ค ๋ณด๋ฉด ์–ด๋–ค ์ด์œ ๋กœ๋“  ์ปค๋ฐ‹ ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•  ๋•Œ๊ฐ€ ์žˆ๋‹ค. ๊ฒฐ์ •์„ ๋‚˜์ค‘์œผ๋กœ ๋ฏธ๋ฃฐ ์ˆ˜ ์žˆ๋˜ ๊ฒƒ์€ Git์˜ ์žฅ์ ์ด๋‹ค. Staging Area๊ฐ€ ์žˆ์–ด์„œ ์ปค๋ฐ‹ํ•  ํŒŒ์ผ์„ ๊ณ ๋ฅด๋Š” ์ผ์„ ์ปค๋ฐ‹ํ•˜๋Š” ์ˆœ๊ฐ„์œผ๋กœ ๋ฏธ๋ฃฐ ์ˆ˜ ์žˆ๊ณ  Stash ๋ช…๋ น์œผ๋กœ ํ•˜๋˜ ์ผ์„ ๋ฏธ๋ฃฐ ์ˆ˜ ์žˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ์ด๋ฏธ ์ปค๋ฐ‹ํ•œ ๋‚ด์šฉ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฑฐ์˜ ๋ชจ๋“  ๊ฒƒ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ปค๋ฐ‹ ์ˆœ์„œ๋„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๊ณ  ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€์™€ ์ปค๋ฐ‹ํ•œ ํŒŒ์ผ๋„ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ปค๋ฐ‹์„ ํ•˜๋‚˜๋กœ ํ•ฉ์น˜๊ฑฐ๋‚˜ ๋ฐ˜๋Œ€๋กœ ํ•˜๋‚˜์˜ ์ปค๋ฐ‹์„ ์—ฌ๋Ÿฌ ๊ฐœ๋กœ ๋ถ„๋ฆฌํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์•„๋‹ˆ๋ฉด ์ปค๋ฐ‹ ์ „์ฒด๋ฅผ ์‚ญ์ œํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ, ์ด ๋ชจ๋“  ๊ฒƒ์€ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๊ณผ ์ฝ”๋“œ๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ์ „์— ํ•ด์•ผ ํ•œ๋‹ค.

์ด ์ ˆ์—์„œ๋Š” ์‚ฌ๋žŒ๋“ค๊ณผ ์ฝ”๋“œ๋ฅผ ๊ณต์œ ํ•˜๊ธฐ ์ „์— ์ปค๋ฐ‹ ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ์˜ˆ์˜๊ฒŒ ๋‹จ์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด์„œ ์„ค๋ช…ํ•œ๋‹ค.

๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹์„ ์ˆ˜์ •ํ•˜๊ธฐ

ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ๋‹จ์žฅํ•˜๋Š” ์ผ ์ค‘์—์„œ๋Š” ๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹์„ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ž์ฃผ ํ•˜๋Š” ์ผ์ด๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‘ ๊ฐ€์ง€๋กœ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋Š”๋ฐ ํ•˜๋‚˜๋Š” ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ด๊ณ  ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” ํŒŒ์ผ ๋ชฉ๋ก์„ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๋‹ค:

$ git commit --amend

์ด ๋ช…๋ น์€ ์ž๋™์œผ๋กœ ํ…์ŠคํŠธ ํŽธ์ง‘๊ธฐ๋ฅผ ์‹คํ–‰์‹œ์ผœ์„œ ๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋ฅผ ์—ด์–ด์ค€๋‹ค. ์—ฌ๊ธฐ์— ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  ํŽธ์ง‘๊ธฐ๋ฅผ ๋‹ซ์œผ๋ฉด ํŽธ์ง‘๊ธฐ๋Š” ์ˆ˜์ •ํ•œ ๋ฉ”์‹œ์ง€๋กœ ๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹์„ ์ˆ˜์ •ํ•œ๋‹ค.

์ปค๋ฐ‹ํ•˜๊ณ  ๋‚˜์„œ ์ƒˆ๋กœ ๋งŒ๋“ค์—ˆ๊ฑฐ๋‚˜ ๋‹ค์‹œ ์ˆ˜์ •ํ•œ ํŒŒ์ผ์„ ๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹์— ํฌํ•จํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ฐฉ๋ฒ•์€ ๊ฐ™๋‹ค. ํŒŒ์ผ์„ ์ˆ˜์ •ํ•˜๊ณ  git add ๋ช…๋ น์œผ๋กœ Staging Area์— ๋„ฃ๊ฑฐ๋‚˜ git rm ๋ช…๋ น์œผ๋กœ ํŒŒ์ผ ์‚ญ์ œํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  git commit --amend ๋ช…๋ น์œผ๋กœ ์ปค๋ฐ‹ํ•˜๋ฉด ๋œ๋‹ค. ์ด ๋ช…๋ น์€ ํ˜„ Staging Area์˜ ๋‚ด์šฉ์„ ์ด์šฉํ•ด์„œ ์ˆ˜์ •ํ•œ๋‹ค.

์ด๋•Œ SHA-1 ๊ฐ’์ด ๋ฐ”๋€Œ๊ธฐ ๋•Œ๋ฌธ์— ๊ณผ๊ฑฐ์˜ ์ปค๋ฐ‹์„ ๋ณ€๊ฒฝํ•  ๋•Œ ์ฃผ์˜ํ•ด์•ผ ํ•œ๋‹ค. rebase์ฒ˜๋Ÿผ ์ด๋ฏธ Pushํ•œ ์ปค๋ฐ‹์€ ์ˆ˜์ •ํ•˜๋ฉด ์•ˆ ๋œ๋‹ค.

์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ ์ˆ˜์ •ํ•˜๊ธฐ

์ตœ๊ทผ ์ปค๋ฐ‹์ด ์•„๋‹ˆ๋ผ ์˜ˆ์ „ ์ปค๋ฐ‹์„ ์ˆ˜์ •ํ•˜๋ ค๋ฉด ๋‹ค๋ฅธ ๋„๊ตฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค. ํžˆ์Šคํ† ๋ฆฌ ์ˆ˜์ •์šฉ ๋„๊ตฌ๋Š” ์—†์ง€๋งŒ rebase ๋ช…๋ น์„ ์ด์šฉํ•˜์—ฌ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ˜„์žฌ ์ž‘์—…ํ•˜๋Š” ๋ธŒ๋žœ์น˜์—์„œ ๊ฐ ์ปค๋ฐ‹์„ ํ•˜๋‚˜ํ•˜๋‚˜ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์–ด๋Š ์‹œ์ ๋ถ€ํ„ฐ HEAD๊นŒ์ง€์˜ ์ปค๋ฐ‹์„ ํ•œ ๋ฒˆ์— Rebaseํ•œ๋‹ค. ๋Œ€ํ™”ํ˜• Rebase ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ปค๋ฐ‹์„ ์ฒ˜๋ฆฌํ•  ๋•Œ๋งˆ๋‹ค ๋ฉˆ์ถ˜๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ๊ฐ ์ปค๋ฐ‹์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ๋ณ€๊ฒฝํ•˜๋Š” ๋“ฑ์˜ ์ผ์„ ์ง„ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. git rebase ๋ช…๋ น์— -i ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋Œ€ํ™”ํ˜• ๋ชจ๋“œ๋กœ Rebaseํ•  ์ˆ˜ ์žˆ๋‹ค. ์–ด๋–ค ์‹œ์ ๋ถ€ํ„ฐ HEAD๊นŒ์ง€ Rebaseํ•  ๊ฒƒ์ธ์ง€ ์•„๊ทœ๋จผํŠธ๋กœ ๋„˜๊ธฐ๋ฉด ๋œ๋‹ค.

๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€ ์„ธ ๊ฐœ๋ฅผ ๋ชจ๋‘ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ๊ทธ ์ค‘ ๋ช‡ ๊ฐœ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์‚ดํŽด๋ณด์ž. git rebase -i์˜ ์•„๊ทœ๋จผํŠธ๋กœ ํŽธ์ง‘ํ•˜๋ ค๋Š” ๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹์˜ ๋ถ€๋ชจ๋ฅผ HEAD~2^๋‚˜ HEAD~3๋กœ ํ•ด์„œ ๋„˜๊ธด๋‹ค. ๋งˆ์ง€๋ง‰ ์„ธ ๊ฐœ์˜ ์ปค๋ฐ‹์„ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ~3์ด ์ข€ ๋” ๊ธฐ์–ตํ•˜๊ธฐ ์‰ฝ๋‹ค. ๊ทธ๋ ‡์ง€๋งŒ, ์‹ค์งˆ์ ์œผ๋กœ ๊ฐ€๋ฆฌํ‚ค๊ฒŒ ๋˜๋Š” ๊ฒƒ์€ ์ˆ˜์ •ํ•˜๋ ค๋Š” ์ปค๋ฐ‹์˜ ๋ถ€๋ชจ์ธ ๋„ค ๋ฒˆ์งธ ์ด์ „ ์ปค๋ฐ‹์ด๋‹ค.

$ git rebase -i HEAD~3

์ด ๋ช…๋ น์€ rebaseํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”์‹œ์ง€์˜ ์ˆ˜์ • ์—ฌ๋ถ€์— ๊ด€๊ณ„์—†์ด HEAD~3..HEAD ๋ฒ”์œ„์— ์žˆ๋Š” ๋ชจ๋“  ์ปค๋ฐ‹์„ ์ˆ˜์ •ํ•œ๋‹ค. ๋‹ค์‹œ ๊ฐ•์กฐํ•˜์ง€๋งŒ ์ด๋ฏธ ์ค‘์•™์„œ๋ฒ„์— Pushํ•œ ์ปค๋ฐ‹์€ ์ ˆ๋Œ€ ๊ณ ์น˜์ง€ ๋ง์•„์•ผ ํ•œ๋‹ค. Pushํ•œ ์ปค๋ฐ‹์„ Rebaseํ•˜๋ฉด ๊ฒฐ๊ตญ ๊ฐ™์€ ๋‚ด์šฉ์„ ๋‘ ๋ฒˆ Pushํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค์ด ํ˜ผ๋ž€์Šค๋Ÿฌ์›Œ ํ•œ๋‹ค.

์‹คํ–‰ํ•˜๋ฉด ํ…์ŠคํŠธ ํŽธ์ง‘๊ธฐ๊ฐ€ ์—ด๋ฆฌ๊ณ  ๊ทธ ์•ˆ์—๋Š” ์ˆ˜์ •ํ•˜๋ ค๋Š” ์ปค๋ฐ‹ ๋ชฉ๋ก์ด ์ฒจ๋ถ€๋œ๋‹ค:

pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file

# Rebase 710f0f8..a5f4a0d onto 710f0f8
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

์ด ์ปค๋ฐ‹์€ ๋ชจ๋‘ log ๋ช…๋ น๊ณผ๋Š” ์ •๋ฐ˜๋Œ€์˜ ์ˆœ์„œ๋กœ ๋‚˜์—ด๋œ๋‹ค. log ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๋‹ค:

$ git log --pretty=format:"%h %s" HEAD~3..HEAD
a5f4a0d added cat-file
310154e updated README formatting and added blame
f7f3f6d changed my name a bit

์œ„ ๊ฒฐ๊ณผ์˜ ์—ญ์ˆœ์ž„์„ ๊ธฐ์–ตํ•˜์ž. ๋Œ€ํ™”ํ˜• rebase๋Š” ์Šคํฌ๋ฆฝํŠธ์— ์ ํ˜€ ์žˆ๋Š” ์ˆœ์„œ๋Œ€๋กœ HEAD~3๋ถ€ํ„ฐ ์ ์šฉํ•˜๊ธฐ ์‹œ์ž‘ํ•˜๊ณ  ์œ„์—์„œ ์•„๋ž˜๋กœ ๊ฐ๊ฐ์˜ ์ปค๋ฐ‹์„ ์ˆœ์„œ๋Œ€๋กœ ์ˆ˜์ •ํ•œ๋‹ค. ์ˆœ์„œ๋Œ€๋กœ ์ ์šฉํ•˜๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ œ์ผ ์œ„์— ์žˆ๋Š” ๊ฒƒ์ด ์ตœ์‹ ์ด ์•„๋‹ˆ๋ผ ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ๊ฒƒ์ด๋‹ค.

ํŠน์ • ์ปค๋ฐ‹์—์„œ ์‹คํ–‰์„ ๋ฉˆ์ถ”๊ฒŒ ํ•˜๋ ค๋ฉด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•œ๋‹ค. pick์ด๋ผ๋Š” ๋‹จ์–ด๋ฅผ edit๋กœ ์ˆ˜์ •ํ•˜๋ฉด ๊ทธ ์ปค๋ฐ‹์—์„œ ๋ฉˆ์ถ˜๋‹ค. ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์ •ํ•˜๋ ค๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ํŽธ์ง‘ํ•œ๋‹ค:

edit f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file

์ €์žฅํ•˜๊ณ  ํŽธ์ง‘๊ธฐ๋ฅผ ์ข…๋ฃŒํ•˜๋ฉด Git์€ ๋ชฉ๋ก์— ์žˆ๋Š” ์ปค๋ฐ‹ ์ค‘์—์„œ ๊ฐ€์žฅ ์˜ค๋ž˜๋œ ์ปค๋ฐ‹์œผ๋กœ ์ด๋™ํ•˜๊ณ , ์•„๋ž˜์™€ ๊ฐ™์€ ๋ฉ”์‹œ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๊ณ , ๋ช…๋ น ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค:

$ git rebase -i HEAD~3
Stopped at 7482e0d... updated the gemspec to hopefully work better
You can amend the commit now, with

       git commit --amend

Once youโ€™re satisfied with your changes, run

       git rebase --continue

์ •ํ™•ํžˆ ๋ญ˜ ํ•ด์•ผ ํ•˜๋Š”์ง€ ์•Œ๋ ค์ค€๋‹ค. ์•„๋ž˜์™€ ๊ฐ™์€ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ณ :

$ git commit --amend

์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  ํ…์ŠคํŠธ ํŽธ์ง‘๊ธฐ๋ฅผ ์ข…๋ฃŒํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค:

$ git rebase --continue

์ด๋ ‡๊ฒŒ ๋‚˜๋จธ์ง€ ๋‘ ๊ฐœ์˜ ์ปค๋ฐ‹์— ์ ์šฉํ•˜๋ฉด ๋์ด๋‹ค. ๋‹ค๋ฅธ ๊ฒƒ๋„ pick์„ edit๋กœ ์ˆ˜์ •ํ•ด์„œ ์ด ์ž‘์—…์„ ๋ช‡ ๋ฒˆ์ด๋“  ๋ฐ˜๋ณตํ•  ์ˆ˜ ์žˆ๋‹ค. Git์ด ๋ฉˆ์ถœ ๋•Œ๋งˆ๋‹ค ์ปค๋ฐ‹์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๊ณ  ์™„๋ฃŒํ•  ๋•Œ๊นŒ์ง€ ๊ณ„์† ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ปค๋ฐ‹ ์ˆœ์„œ ๋ฐ”๊พธ๊ธฐ

๋Œ€ํ™”ํ˜• Rebase ๋„๊ตฌ๋กœ ์ปค๋ฐ‹ ์ „์ฒด๋ฅผ ์‚ญ์ œํ•˜๊ณ  ์ˆœ์„œ๋„ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๋‹ค. "added cat-file" ์ปค๋ฐ‹์„ ์‚ญ์ œํ•˜๊ณ  ๋‹ค๋ฅธ ๋‘ ์ปค๋ฐ‹์˜ ์ˆœ์„œ๋ฅผ ๋ณ€๊ฒฝํ•˜๋ ค๋ฉด ์ด rebase ์Šคํฌ๋ฆฝํŠธ๋ฅผ:

pick f7f3f6d changed my name a bit
pick 310154e updated README formatting and added blame
pick a5f4a0d added cat-file

์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•œ๋‹ค:

pick 310154e updated README formatting and added blame
pick f7f3f6d changed my name a bit

์ˆ˜์ •ํ•œ ๋‚ด์šฉ์„ ์ €์žฅํ•˜๊ณ  ํŽธ์ง‘๊ธฐ๋ฅผ ์ข…๋ฃŒํ•˜๋ฉด Git์€ ๋ธŒ๋žœ์น˜๋ฅผ ์ด ์ปค๋ฐ‹๋“ค์˜ ๋ถ€๋ชจ๋กœ ์ด๋™์‹œํ‚ค๊ณ ์„œ 310154e์™€ f7f3f6d๋ฅผ ์ˆœ์„œ๋Œ€๋กœ ์ ์šฉํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ปค๋ฐ‹ ์ˆœ์„œ๊ฐ€ ๋ณ€๊ฒฝ๋๊ณ  "added cat-file" ์ปค๋ฐ‹์ด ์ œ๊ฑฐ๋œ ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ปค๋ฐ‹ ํ•ฉ์น˜๊ธฐ

๋Œ€ํ™”ํ˜• Rebase ๋ช…๋ น์„ ์ด์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ์ปค๋ฐ‹์„ ๊พน๊พน ๋ˆŒ๋Ÿฌ์„œ ํ•˜๋‚˜์˜ ์ปค๋ฐ‹์œผ๋กœ ๋งŒ๋“ค์–ด ๋ฒ„๋ฆด ์ˆ˜ ์žˆ๋‹ค. Rebase ์Šคํฌ๋ฆฝํŠธ์— ์ž๋™์œผ๋กœ ํฌํ•จ๋œ ๋„์›€๋ง์— ์„ค๋ช…๋ผ ์žˆ๋‹ค:

#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

"pick"์ด๋‚˜ "edit"๋ง๊ณ  "squash"๋ฅผ ์ž…๋ ฅํ•˜๋ฉด Git์€ ํ•ด๋‹น ์ปค๋ฐ‹๊ณผ ๋ฐ”๋กœ ์ด์ „ ์ปค๋ฐ‹์„ ํ•ฉ์น  ๊ฒƒ์ด๊ณ  ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋„ Mergeํ•œ๋‹ค. ๊ทธ๋ž˜์„œ 3๊ฐœ์˜ ์ปค๋ฐ‹์„ ๋ชจ๋‘ ํ•ฉ์น˜๋ ค๋ฉด ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•œ๋‹ค:

pick f7f3f6d changed my name a bit
squash 310154e updated README formatting and added blame
squash a5f4a0d added cat-file

์ €์žฅํ•˜๊ณ  ๋‚˜์„œ ํŽธ์ง‘๊ธฐ๋ฅผ ์ข…๋ฃŒํ•˜๋ฉด Git์€ 3๊ฐœ์˜ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋ฅผ Mergeํ•  ์ˆ˜ ์žˆ๋„๋ก ์—๋””ํ„ฐ๋ฅผ ๋ฐ”๋กœ ์‹คํ–‰ํ•ด์ค€๋‹ค:

# This is a combination of 3 commits.
# The first commit's message is:
changed my name a bit

# This is the 2nd commit message:

updated README formatting and added blame

# This is the 3rd commit message:

added cat-file

์ด ๋ฉ”์‹œ์ง€๋ฅผ ์ €์žฅํ•˜๋ฉด 3๊ฐœ์˜ ์ปค๋ฐ‹์ด ๋ชจ๋‘ ํ•ฉ์ณ์ง„ ํ•˜๋‚˜์˜ ์ปค๋ฐ‹๋งŒ ๋‚จ๋Š”๋‹ค.

์ปค๋ฐ‹ ๋ถ„๋ฆฌํ•˜๊ธฐ

์ปค๋ฐ‹์„ ๋ถ„๋ฆฌํ•œ๋‹ค๋Š” ๊ฒƒ์€ ๊ธฐ์กด ์ปค๋ฐ‹์„ Resetํ•˜๊ณ (ํ˜น์€ ๋˜๋Œ๋ ค ๋†“๊ณ ) Stage๋ฅผ ์—ฌ๋Ÿฌ ๊ฐœ๋กœ ๋ถ„๋ฆฌํ•˜๊ณ  ๋‚˜์„œ ๊ทธ๊ฒƒ์„ ์›ํ•˜๋Š” ํšŸ์ˆ˜๋งŒํผ ๋‹ค์‹œ ์ปค๋ฐ‹ํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ์˜ˆ๋กœ ๋“ค์—ˆ๋˜ ์ปค๋ฐ‹ ์„ธ ๊ฐœ ์ค‘์—์„œ ๊ฐ€์šด๋ฐ ๊ฒƒ์„ ๋ถ„๋ฆฌํ•ด๋ณด์ž. ์ด ์ปค๋ฐ‹์€ "updated README formatting and added blame"๋ผ๋Š” ์ปค๋ฐ‹์ธ๋ฐ "updated README formatting"๊ณผ "added blame"์œผ๋กœ ๋ถ„๋ฆฌํ•ด๋ณด์ž. rebase -i ์Šคํฌ๋ฆฝํŠธ์—์„œ ํ•ด๋‹น ์ปค๋ฐ‹์„ "edit"๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค:

pick f7f3f6d changed my name a bit
edit 310154e updated README formatting and added blame
pick a5f4a0d added cat-file

์œ„์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•˜๊ณ  ๋‚˜์„œ ์ €์žฅํ•˜๊ณ  ํŽธ์ง‘๊ธฐ๋ฅผ ์ข…๋ฃŒํ•˜๋ฉด Git์€ ์ œ์ผ ์˜ค๋ž˜๋œ ์ปค๋ฐ‹์˜ ๋ถ€๋ชจ๋กœ ์ด๋™ํ•˜๊ณ ์„œ f7f3f6d๊ณผ 310154e์„ ์ฒ˜๋ฆฌํ•˜๊ณ  ์ฝ˜์†” ํ”„๋กฌํ”„ํŠธ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค. ์—ฌ๊ธฐ์„œ ์ปค๋ฐ‹์„ ํ•ด์ œํ•˜๋Š” git reset HEAD^๋ผ๋Š” ๋ช…๋ น์œผ๋กœ ์ปค๋ฐ‹์„ ํ•ด์ œํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด ์ˆ˜์ •ํ–ˆ๋˜ ํŒŒ์ผ์€ Unstaged ์ƒํƒœ๊ฐ€ ๋œ๋‹ค. ๊ทธ๋‹ค์Œ์— ํŒŒ์ผ๋“ค์„ Stageํ•œ ํ›„ ์ปค๋ฐ‹ํ•˜๋Š” ์ผ์„ ์›ํ•˜๋Š” ๋งŒํผ ๋ฐ˜๋ณตํ•˜๊ณ  ๋‚˜์„œ git rebase --continue๋ผ๋Š” ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ฉด ๋‚จ์€ Rebase์ž‘์—…์ด ๋๋‚œ๋‹ค:

$ git reset HEAD^
$ git add README
$ git commit -m 'updated README formatting'
$ git add lib/simplegit.rb
$ git commit -m 'added blame'
$ git rebase --continue

๋‚˜๋จธ์ง€ a5f4a0d ์ปค๋ฐ‹๋„ ์ฒ˜๋ฆฌ๋˜๋ฉด ํžˆ์Šคํ† ๋ฆฌ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค:

$ git log -4 --pretty=format:"%h %s"
1c002dd added cat-file
9b29157 added blame
35cfb2b updated README formatting
f3cc40e changed my name a bit

๋‹ค์‹œ ๊ฐ•์กฐํ•˜์ง€๋งŒ, ๋ชฉ๋ก์— ์žˆ๋Š” ๋ชจ๋“  ์ปค๋ฐ‹์˜ SHA-1 ๊ฐ’์€ ๋ณ€๊ฒฝ๋œ๋‹ค. ๊ทธ๋ž˜์„œ ์ด๋ฏธ ์„œ๋ฒ„์— Pushํ•œ ์ปค๋ฐ‹์„ ์ˆ˜์ •ํ•˜๋ฉด ์•ˆ๋œ๋‹ค.

filter-branch๋Š” ํฌํฌ๋ ˆ์ธ

์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š” ์ปค๋ฐ‹์ด ๋„ˆ๋ฌด ๋งŽ์•„์„œ rebase ์Šคํฌ๋ฆฝํŠธ๋กœ ์ˆ˜์ •ํ•˜๊ธฐ ์–ด๋ ค์šธ ๊ฒƒ ๊ฐ™์œผ๋ฉด ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ๋ชจ๋“  ์ปค๋ฐ‹์˜ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ๋ณ€๊ฒฝํ•˜๊ฑฐ๋‚˜ ์–ด๋–ค ํŒŒ์ผ์„ ์‚ญ์ œํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์‚ดํŽด๋ณด์ž. filter-branch๋ผ๋Š” ๋ช…๋ น์œผ๋กœ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ rebase๊ฐ€ ์‚ฝ์ด๋ผ๋ฉด ์ด ๋ช…๋ น์€ ํฌํฌ๋ ˆ์ธ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. filter-branch๋„ ์—ญ์‹œ ์ˆ˜์ •ํ•˜๋ ค๋Š” ์ปค๋ฐ‹์ด ์ด๋ฏธ ๊ณต๊ฐœ๋ผ์„œ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๊ณผ ํ•จ๊ป˜ ๊ณต์œ ํ•˜๋Š” ์ค‘์ด๋ผ๋ฉด ์‚ฌ์šฉํ•˜์ง€ ๋ง์•„์•ผ ํ•œ๋‹ค. ํ•˜์ง€๋งŒ, ์ž˜ ์“ฐ๋ฉด ๊ฝค ์œ ์šฉํ•˜๋‹ค. filter-branch๊ฐ€ ์–ด๋–ค ๊ฒฝ์šฐ์— ์œ ์šฉํ• ์ง€ ์˜ˆ๋ฅผ ๋“ค์–ด์„œ ์„ค๋ช…ํ•œ๋‹ค.

๋ชจ๋“  ์ปค๋ฐ‹์—์„œ ํŒŒ์ผ์„ ์ œ๊ฑฐํ•˜๊ธฐ

๊ฐ‘์ž๊ธฐ ๋ˆ„๊ตฐ๊ฐ€ ์ƒ๊ฐ ์—†์ด git add . ๊ฐ™์€ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•ด ๋ฒ„๋ ค์„œ ๊ณต๋ฃก ๋˜ฅ ๋ฉ์–ด๋ฆฌ๊ฐ€ ์ปค๋ฐ‹๋๊ฑฐ๋‚˜ ์‹ค์ˆ˜๋กœ ์•”ํ˜ธ๊ฐ€ ํฌํ•จ๋œ ํŒŒ์ผ์„ ์ปค๋ฐ‹ํ•ด์„œ ์ด๋Ÿฐ ํŒŒ์ผ๋“ค์„ ๋‹ค์‹œ ์‚ญ์ œํ•ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์„ ์‚ดํŽด๋ณด์ž. ์ด๋Ÿฐ ์ƒํ™ฉ์€ ์ƒ๊ฐ๋ณด๋‹ค ์ž์ฃผ ๋ฐœ์ƒํ•œ๋‹ค. filter-branch๋Š” ํžˆ์Šคํ† ๋ฆฌ ์ „์ฒด์—์„œ ํ•„์š”ํ•œ ๊ฒƒ๋งŒ ๊ณจ๋ผ๋‚ด๋Š” ๋ฐ ์‚ฌ์šฉํ•˜๋Š” ๋„๊ตฌ๋‹ค. filter-branch์˜ --tree-filter๋ผ๋Š” ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ํžˆ์Šคํ† ๋ฆฌ์—์„œ passwords.txt๋ผ๋Š” ํŒŒ์ผ์„ ์•„์˜ˆ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ๋‹ค:

$ git filter-branch --tree-filter 'rm -f passwords.txt' HEAD
Rewrite 6b9b3cf04e7c5686a9cb838c3f36a8cb6a0fc2bd (21/21)
Ref 'refs/heads/master' was rewritten

--tree-filter ์˜ต์…˜์€ ํ”„๋กœ์ ํŠธ๋ฅผ Checkoutํ•œ ํ›„์— ๊ฐ ์ปค๋ฐ‹์— ๋ช…์‹œํ•œ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰์‹œํ‚ค๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ์ปค๋ฐ‹ํ•œ๋‹ค. ์ด ์˜ˆ์ œ์—์„œ๋Š” ๊ฐ ์Šค๋ƒ…์ƒท์— passwords.txt๋ผ๋Š” ํŒŒ์ผ์ด ์žˆ์œผ๋ฉด ๊ทธ ํŒŒ์ผ์„ ์‚ญ์ œํ•œ๋‹ค. ์‹ค์ˆ˜๋กœ ํŽธ์ง‘๊ธฐ์˜ ๋ฐฑ์—…ํŒŒ์ผ์„ ์ปค๋ฐ‹ํ–ˆ์œผ๋ฉด git filter-branch --tree-filter "find * -type f -name '*~' -delete" HEAD๋ผ๊ณ  ์‹คํ–‰ํ•ด์„œ ์‚ญ์ œํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด ๋ช…๋ น์€ ๋ชจ๋“  ํŒŒ์ผ๊ณผ ์ปค๋ฐ‹์„ ์ •๋ฆฌํ•˜๊ณ  ๋ธŒ๋žœ์น˜ ํฌ์ธํ„ฐ๋ฅผ ๋‹ค์‹œ ๋ณต์›ํ•ด์ค€๋‹ค. ํ…Œ์ŠคํŒ… ๋ธŒ๋žœ์น˜์—์„œ ์‚ฌ์šฉํ•  ๋ช…๋ น์„ ์ ๊ฒ€ํ•˜๊ณ  ๋‚˜์„œ master ๋ธŒ๋žœ์น˜๋ฅผ ์ •๋ฆฌํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  filter-branch ๋ช…๋ น์— --all ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ชจ๋“  ๋ธŒ๋žœ์น˜์— ์ ์šฉ๋œ๋‹ค.

ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๋งŒ๋“ค๊ธฐ

๋‹ค๋ฅธ VCS์—์„œ ์ฝ”๋“œ๋ฅผ ์ž„ํฌํŠธํ•˜๋ฉด ๊ทธ VCS๋งŒ์„ ์œ„ํ•œ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค. SVN์—์„œ ์ฝ”๋“œ๋ฅผ ์ž„ํฌํŠธํ•˜๋ฉด trunk, tags, branch ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ํฌํ•จ๋œ๋‹ค. ๋ชจ๋“  ์ปค๋ฐ‹์— ๋Œ€ํ•ด trunk ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๋งŒ๋“ค ๋•Œ์—๋„ filter-branch ๋ช…๋ น์ด ์œ ์šฉํ•˜๋‹ค:

$ git filter-branch --subdirectory-filter trunk HEAD
Rewrite 856f0bf61e41a27326cdae8f09fe708d679f596f (12/12)
Ref 'refs/heads/master' was rewritten

์ด์ œ trunk ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๋งŒ๋“ค์—ˆ๋‹ค. Git์€ ์ž…๋ ฅํ•œ ๋””๋ ‰ํ† ๋ฆฌ์™€ ๊ด€๋ จ์ด ์—†๋Š” ์ปค๋ฐ‹์„ ์ž๋™์œผ๋กœ ์‚ญ์ œํ•œ๋‹ค.

๋ชจ๋“  ์ปค๋ฐ‹์˜ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์ˆ˜์ •ํ•˜๊ธฐ

ํ”„๋กœ์ ํŠธ๋ฅผ ์˜คํ”ˆ์†Œ์Šค๋กœ ๊ณต๊ฐœํ•  ๋•Œ์—๋„ ํšŒ์‚ฌ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋กœ ์ปค๋ฐ‹๋œ ๊ฒƒ์„ ๊ฐœ์ธ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋กœ ๋ณ€๊ฒฝํ•ด์•ผ ํ•œ๋‹ค. ์•„๋‹ˆ๋ฉด ์•„์˜ˆ git config๋กœ ์ด๋ฆ„๊ณผ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์„ ์žŠ์—ˆ์„ ์ˆ˜๋„ ์žˆ๋‹ค. ์–ด์จŒ๋“  filter-branch ๋ช…๋ น์˜ --commit-filter ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ ์ปค๋ฐ‹์— ๋“ฑ๋ก๋œ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ๋ณ€๊ฒฝํ•  ๋•Œ๋Š” ์กฐ์‹ฌํ•ด์•ผ ํ•œ๋‹ค.

$ git filter-branch --commit-filter '
        if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ];
        then
                GIT_AUTHOR_NAME="Scott Chacon";
                GIT_AUTHOR_EMAIL="schacon@example.com";
                git commit-tree "$@";
        else
                git commit-tree "$@";
        fi' HEAD

์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์ƒˆ ์ฃผ์†Œ๋กœ ๋ณ€๊ฒฝํ–ˆ๋‹ค. ๋ชจ๋“  ์ปค๋ฐ‹์€ ๋ถ€๋ชจ์˜ SHA-1 ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์กฐ๊ฑด์— ๋งŒ์กฑํ•˜๋Š” ์ปค๋ฐ‹์˜ SHA-1๊ฐ’๋งŒ ๋ฐ”๋€Œ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ๋ชจ๋“  ์ปค๋ฐ‹์˜ SHA-1 ๊ฐ’์ด ๋ฐ”๋€๋‹ค.

Git์œผ๋กœ ๋ฒ„๊ทธ ์ฐพ๊ธฐ

Git์€ ๊ต‰์žฅํžˆ ์œ ์—ฐํ•ด์„œ ์–ด๋–ค ํ”„๋กœ์ ํŠธ์—๋‚˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฒŒ๋‹ค๊ฐ€ ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚จ ๋ฒ”์ธ์ด๋‚˜ ๋ฒ„๊ทธ๋„ ์‰ฝ๊ฒŒ ์ฐพ์„ ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค.

ํŒŒ์ผ ์–ด๋…ธํ…Œ์ด์…˜

๋ฒ„๊ทธ๋ฅผ ์ฐพ์„ ๋•Œ ๋จผ์ € ๊ทธ ์ฝ”๋“œ๊ฐ€ ์™œ, ์–ธ์ œ ์ถ”๊ฐ€ํ–ˆ๋Š”์ง€ ์•Œ๊ณ  ์‹ถ์„ ๊ฒƒ์ด๋‹ค. ์ด๋•Œ๋Š” ํŒŒ์ผ ์–ด๋…ธํ…Œ์ด์…˜์„ ํ™œ์šฉํ•œ๋‹ค. ํ•œ์ค„ํ•œ์ค„ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ปค๋ฐ‹ํ•œ ์‚ฌ๋žŒ์ด ๋ˆ„๊ตฌ์ธ์ง€, ์–ธ์ œ ๋งˆ์ง€๋ง‰์œผ๋กœ ์ปค๋ฐ‹ํ–ˆ๋Š”์ง€ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. ์–ด๋–ค ๋ฉ”์†Œ๋“œ์— ๋ฒ„๊ทธ๊ฐ€ ์žˆ์œผ๋ฉด git blame ๋ช…๋ น์œผ๋กœ ๊ทธ ๋ฉ”์†Œ๋“œ์˜ ๊ฐ ์ค„์„ ๋ˆ„๊ฐ€ ์–ธ์ œ ๋งˆ์ง€๋ง‰์œผ๋กœ ๊ณ ์ณค๋Š”์ง€ ์ฐพ์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค:

$ git blame -L 12,22 simplegit.rb
^4832fe2 (Scott Chacon  2008-03-15 10:31:28 -0700 12)  def show(tree = 'master')
^4832fe2 (Scott Chacon  2008-03-15 10:31:28 -0700 13)   command("git show #{tree}")
^4832fe2 (Scott Chacon  2008-03-15 10:31:28 -0700 14)  end
^4832fe2 (Scott Chacon  2008-03-15 10:31:28 -0700 15)
9f6560e4 (Scott Chacon  2008-03-17 21:52:20 -0700 16)  def log(tree = 'master')
79eaf55d (Scott Chacon  2008-04-06 10:15:08 -0700 17)   command("git log #{tree}")
9f6560e4 (Scott Chacon  2008-03-17 21:52:20 -0700 18)  end
9f6560e4 (Scott Chacon  2008-03-17 21:52:20 -0700 19)
42cf2861 (Magnus Chacon 2008-04-13 10:45:01 -0700 20)  def blame(path)
42cf2861 (Magnus Chacon 2008-04-13 10:45:01 -0700 21)   command("git blame #{path}")
42cf2861 (Magnus Chacon 2008-04-13 10:45:01 -0700 22)  end

์ฒซ ํ•ญ๋ชฉ์€ ๊ทธ ์ค„์„ ๋งˆ์ง€๋ง‰์— ์ˆ˜์ •ํ•œ ์ปค๋ฐ‹์˜ SHA-1 ๊ฐ’์ด๋‹ค. ๊ทธ๋‹ค์Œ ๋‘ ํ•ญ๋ชฉ์€ ๋ˆ„๊ฐ€, ์–ธ์ œ ๊ทธ ์ค„์„ ์ปค๋ฐ‹ํ–ˆ๋Š”์ง€ ๋ณด์—ฌ์ค€๋‹ค. ๊ทธ๋ž˜์„œ ๋ˆ„๊ฐ€, ์–ธ์ œ ์ปค๋ฐ‹ํ–ˆ๋Š”์ง€ ์‰ฝ๊ฒŒ ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ ๋’ค์— ํŒŒ์ผ์˜ ์ค„ ๋ฒˆํ˜ธ์™€ ๋‚ด์šฉ์„ ๋ณด์—ฌ์ค€๋‹ค. ๊ทธ๋ฆฌ๊ณ  ^4832fe2 ์ปค๋ฐ‹์ด ๊ถ๊ธˆํ•  ํ…๋ฐ ์ด ํ‘œ์‹œ๊ฐ€ ๋ถ™์–ด ์žˆ์œผ๋ฉด ํ•ด๋‹น ์ค„์ด ์ฒ˜์Œ ์ปค๋ฐ‹ํ•œ ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ํ•ด๋‹น ์ค„์€ 4832fe2์—์„œ ์ปค๋ฐ‹๋œ ํ›„ ๋ณ€๊ฒฝ๋œ ์ ์ด ์—†๋‹ค. ์ง€๊ธˆ๊นŒ์ง€ ์ปค๋ฐ‹์„ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฐ์šฐ๋ฉด์„œ ^์„ ์ ์–ด๋„ ์„ธ ๊ณณ์—์„œ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ๋ฐฐ์› ๊ธฐ ๋•Œ๋ฌธ์— ์•ฝ๊ฐ„ ํ—ท๊ฐˆ๋ฆด ์ˆ˜ ์žˆ์œผ๋‹ˆ ํ˜ผ๋™ํ•˜์ง€ ๋ง์ž.

Git์€ ํŒŒ์ผ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•œ ์ด๋ ฅ์„ ๋ณ„๋„๋กœ ๊ธฐ๋กํ•ด๋‘์ง€ ์•Š๋Š”๋‹ค. ํ•˜์ง€๋งŒ, ์›๋ž˜ ์ด ์ •๋ณด๋“ค์€ ๊ฐ ์Šค๋ƒ…์ƒท์— ์ €์žฅ๋˜๊ณ  ์ด ์ •๋ณด๋ฅผ ์ด์šฉํ•˜์—ฌ ๋ณ€๊ฒฝ ์ด๋ ฅ์„ ๋งŒ๋“ค์–ด ๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋Ÿฌ๋‹ˆ๊นŒ ํŒŒ์ผ์— ์ƒ๊ธด ๋ณ€ํ™”๋Š” ๋ฌด์—‡์ด๋“ ์ง€ ์•Œ์•„๋‚ผ ์ˆ˜ ์žˆ๋‹ค. Git์€ ํŒŒ์ผ ์–ด๋…ธํ…Œ์ด์…˜์„ ๋ถ„์„ํ•˜์—ฌ ์ฝ”๋“œ๋“ค์ด ์›๋ž˜ ์–ด๋–ค ํŒŒ์ผ์—์„œ ์ปค๋ฐ‹๋œ ๊ฒƒ์ธ์ง€ ์ฐพ์•„์ค€๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด๋ณด์ž. GITServerHandler.m์„ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํŒŒ์ผ๋กœ ๋ฆฌํŒฉํ† ๋งํ–ˆ๋Š”๋ฐ ๊ทธ ์ค‘ ํ•œ ํŒŒ์ผ์ด GITPackUpload.m์ด๋ผ๋Š” ํŒŒ์ผ์ด๋ผ๊ณ  ํ•˜์ž. -C ์˜ต์…˜์œผ๋กœ GITPackUpload.m ํŒŒ์ผ์„ ์ถ”์ ํ•ด๋ณด๋ฉด ๊ฐ ์ฝ”๋“œ๊ฐ€ ์›๋ž˜ ์–ด๋–ค ํŒŒ์ผ๋กœ ์ปค๋ฐ‹๋œ ๊ฒƒ์ธ์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค:

$ git blame -C -L 141,153 GITPackUpload.m
f344f58d GITServerHandler.m (Scott 2009-01-04 141)
f344f58d GITServerHandler.m (Scott 2009-01-04 142) - (void) gatherObjectShasFromC
f344f58d GITServerHandler.m (Scott 2009-01-04 143) {
70befddd GITServerHandler.m (Scott 2009-03-22 144)         //NSLog(@"GATHER COMMI
ad11ac80 GITPackUpload.m    (Scott 2009-03-24 145)
ad11ac80 GITPackUpload.m    (Scott 2009-03-24 146)         NSString *parentSha;
ad11ac80 GITPackUpload.m    (Scott 2009-03-24 147)         GITCommit *commit = [g
ad11ac80 GITPackUpload.m    (Scott 2009-03-24 148)
ad11ac80 GITPackUpload.m    (Scott 2009-03-24 149)         //NSLog(@"GATHER COMMI
ad11ac80 GITPackUpload.m    (Scott 2009-03-24 150)
56ef2caf GITServerHandler.m (Scott 2009-01-05 151)         if(commit) {
56ef2caf GITServerHandler.m (Scott 2009-01-05 152)                 [refDict setOb
56ef2caf GITServerHandler.m (Scott 2009-01-05 153)

์–ธ์ œ๋‚˜ ์ฝ”๋“œ๊ฐ€ ์ปค๋ฐ‹๋  ๋‹น์‹œ์˜ ํŒŒ์ผ์ด๋ฆ„์„ ์•Œ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฝ”๋“œ๋ฅผ ์–ด๋–ป๊ฒŒ ๋ฆฌํŒฉํ† ๋งํ•ด๋„ ์ถ”์ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์–ด๋–ค ํŒŒ์ผ์— ์ ์šฉํ•ด๋ด๋„ ๊ฐ ์ค„์„ ์ปค๋ฐ‹ํ•  ๋‹น์‹œ์˜ ํŒŒ์ผ์ด๋ฆ„์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ๋ฒ„๊ทธ๋ฅผ ์ฐพ์„ ๋•Œ ์ •๋ง ์œ ์šฉํ•˜๋‹ค.

์ด์ง„ ํƒ์ƒ‰

ํŒŒ์ผ ์–ด๋…ธํ…Œ์ด์…˜์€ ํŠน์ • ์ด์Šˆ์™€ ๊ด€๋ จ๋œ ์ปค๋ฐ‹์„ ์ฐพ๋Š” ๋ฐ์—๋„ ์ข‹๋‹ค. ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ์„ ๋•Œ ์˜์‹ฌ์Šค๋Ÿฌ์šด ์ปค๋ฐ‹์ด ์ˆ˜์‹ญ, ์ˆ˜๋ฐฑ ๊ฐœ์— ์ด๋ฅด๋ฉด ๋„๋Œ€์ฒด ์–ด๋””์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด์•ผ ํ• ์ง€ ๋ชจ๋ฅผ ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ๋Š” git bisect ๋ช…๋ น์ด ์œ ์šฉํ•˜๋‹ค. bisect ๋ช…๋ น์€ ์ปค๋ฐ‹ ํžˆ์Šคํ† ๋ฆฌ๋ฅผ ์ด์ง„ ํƒ์ƒ‰ ๋ฐฉ๋ฒ•์œผ๋กœ ์ขํ˜€ ์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ์ด์Šˆ์™€ ๊ด€๋ จ๋œ ์ปค๋ฐ‹์„ ์ตœ๋Œ€ํ•œ ๋น ๋ฅด๊ฒŒ ์ฐพ์•„๋‚ผ ์ˆ˜ ์žˆ๋„๋ก ๋„์™€์ค€๋‹ค.

์ฝ”๋“œ๋ฅผ ์šด์šฉ ํ™˜๊ฒฝ์— ๋ฐฐํฌํ•˜๊ณ  ๋‚œ ํ›„์— ๊ฐœ๋ฐœํ•  ๋•Œ ๋ฐœ๊ฒฌํ•˜์ง€ ๋ชปํ•œ ๋ฒ„๊ทธ๊ฐ€ ์žˆ๋‹ค๊ณ  ๋ณด๊ณ ๋ฐ›์•˜๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ์™œ ๊ทธ๋Ÿฐ ํ˜„์ƒ์ด ๋ฐœ์ƒํ•˜๋Š”์ง€ ์•„์ง ์ดํ•ดํ•˜์ง€ ๋ชปํ•˜๋Š” ์ƒํ™ฉ์„ ๊ฐ€์ •ํ•ด๋ณด์ž. ํ•ด๋‹น ์ด์Šˆ๋ฅผ ๋‹ค์‹œ ๋งŒ๋“ค๊ณ  ์ž‘์—…ํ•˜๊ธฐ ์‹œ์ž‘ํ–ˆ๋Š”๋ฐ ๋ญ๊ฐ€ ์ž˜๋ชป๋๋Š”์ง€ ์•Œ์•„๋‚ผ ์ˆ˜ ์—†๋‹ค. ์ด๋Ÿด ๋•Œ bisect๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ”๋“œ๋ฅผ ๋’ค์ ธ ๋ณด๋Š” ๊ฒŒ ์ข‹๋‹ค. ๋จผ์ € git bisect start ๋ช…๋ น์œผ๋กœ ์ด์ง„ ํƒ์ƒ‰์„ ์‹œ์ž‘ํ•˜๊ณ  git bisect bad๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ํ˜„์žฌ ์ปค๋ฐ‹์— ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๊ณ  ํ‘œ์‹œ๋ฅผ ๋‚จ๊ธฐ๊ณ  ๋‚˜์„œ ๋ฌธ์ œ๊ฐ€ ์—†๋Š” ๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹์„ git bisect good [good_commit] ๋ช…๋ น์œผ๋กœ ํ‘œ์‹œํ•œ๋‹ค.

$ git bisect start
$ git bisect bad
$ git bisect good v1.0
Bisecting: 6 revisions left to test after this
[ecb6e1bc347ccecc5f9350d878ce677feb13d3b2] error handling on repo

์ด ์˜ˆ์ œ์—์„œ ๋งˆ์ง€๋ง‰์œผ๋กœ ๊ดœ์ฐฎ์•˜๋˜ ์ปค๋ฐ‹(v1.0)๊ณผ ํ˜„์žฌ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ์ปค๋ฐ‹ ์‚ฌ์ด์— ์žˆ๋Š” ์ปค๋ฐ‹์€ ์ „๋ถ€ 12๊ฐœ์ด๊ณ  Git์€ ๊ทธ ์ค‘๊ฐ„์— ์žˆ๋Š” ์ปค๋ฐ‹์„ Checkoutํ•ด์ค€๋‹ค. ์—ฌ๊ธฐ์—์„œ ํ•ด๋‹น ์ด์Šˆ๊ฐ€ ๊ตฌํ˜„๋๋Š”์ง€ ํ…Œ์ŠคํŠธํ•ด๋ณด๊ณ  ๋งŒ์•ฝ ์ด์Šˆ๊ฐ€ ์žˆ์œผ๋ฉด ๊ทธ ์ค‘๊ฐ„ ์ปค๋ฐ‹ ์ด์ „์œผ๋กœ ๋ฒ”์œ„๋ฅผ ์ขํžˆ๊ณ  ์ด์Šˆ๊ฐ€ ์—†์œผ๋ฉด ๊ทธ ์ค‘๊ฐ„ ์ปค๋ฐ‹ ์ดํ›„๋กœ ๋ฒ”์œ„๋ฅผ ์ขํžŒ๋‹ค. ์ด์Šˆ๋ฅผ ๋ฐœ๊ฒฌํ•˜์ง€ ๋ชปํ–ˆ์œผ๋ฉด git bisect good์œผ๋กœ ์ด์Šˆ๊ฐ€ ์•„์ง ์—†์Œ์„ ์•Œ๋ฆฌ๊ณ  ๊ณ„์† ์ง„ํ–‰ํ•œ๋‹ค:

$ git bisect good
Bisecting: 3 revisions left to test after this
[b047b02ea83310a70fd603dc8cd7a6cd13d15c04] secure this thing

ํ˜„์žฌ ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ์ปค๋ฐ‹๊ณผ ์ง€๊ธˆ ํ…Œ์ŠคํŠธํ•œ ์ปค๋ฐ‹ ์‚ฌ์ด์—์„œ ์ค‘๊ฐ„์— ์žˆ๋Š” ์ปค๋ฐ‹์ด Checkout๋๋‹ค. ๋‹ค์‹œ ํ…Œ์ŠคํŠธํ•ด๋ณด๊ณ  ์ด์Šˆ๊ฐ€ ์žˆ์œผ๋ฉด git bisect bad๋กœ ์ด์Šˆ๊ฐ€ ์žˆ๋‹ค๊ณ  ์•Œ๋ฆฐ๋‹ค:

$ git bisect bad
Bisecting: 1 revisions left to test after this
[f71ce38690acf49c1f3c9bea38e09d82a5ce6014] drop exceptions table

์ด์ œ ์ด์Šˆ๋ฅผ ์ฒ˜์Œ ๊ตฌํ˜„ํ•œ ์ปค๋ฐ‹์„ ์ฐพ์•˜๋‹ค. ์ด SHA-1 ๊ฐ’์„ ํฌํ•จํ•œ ์ด ์ปค๋ฐ‹์˜ ์ •๋ณด๋ฅผ ํ™•์ธํ•˜๊ณ  ์ˆ˜์ •๋œ ํŒŒ์ผ์ด ๋ฌด์—‡์ธ์ง€ ํ™•์ธํ•œ๋‹ค. ์ด ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•œ ์‹œ์ ์— ๋„๋Œ€์ฒด ๋ฌด์Šจ ์ผ์ด ์žˆ์—ˆ๋Š”์ง€ ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ดํŽด๋ณธ๋‹ค:

$ git bisect good
b047b02ea83310a70fd603dc8cd7a6cd13d15c04 is first bad commit
commit b047b02ea83310a70fd603dc8cd7a6cd13d15c04
Author: PJ Hyett <pjhyett@example.com>
Date:   Tue Jan 27 14:48:32 2009 -0800

    secure this thing

:040000 040000 40ee3e7821b895e52c1695092db9bdc4c61d1730
f24d3c6ebcfc639b1a3814550e62d60b8e68a8e4 M  config

์ด์ œ ์ฐพ์•˜์œผ๋‹ˆ๊นŒ git bisect reset ๋ช…๋ น์„ ์‹คํ–‰์‹œ์ผœ์„œ ์ด์ง„ ํƒ์ƒ‰์„ ์‹œ์ž‘ํ•˜๊ธฐ ์ „์œผ๋กœ HEAD๋ฅผ ๋Œ๋ ค๋†“๋Š”๋‹ค:

$ git bisect reset

์ˆ˜๋ฐฑ ๊ฐœ์˜ ์ปค๋ฐ‹๋“ค ์ค‘์—์„œ ๋ฒ„๊ทธ๊ฐ€ ๋งŒ๋“ค์–ด์ง„ ์ปค๋ฐ‹์„ ์ฐพ๋Š” ๋ฐ ๋ช‡ ๋ถ„๋ฐ–์— ๊ฑธ๋ฆฌ์ง€ ์•Š๋Š”๋‹ค. ํ”„๋กœ์ ํŠธ๊ฐ€ ์ •์ƒ์ ์œผ๋กœ ์ˆ˜ํ–‰๋˜๋ฉด 0์„ ๋ฐ˜ํ™˜ํ•˜๊ณ  ๋ฌธ์ œ๊ฐ€ ์žˆ์„ ๊ฒฝ์šฐ 1์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ๋งŒ๋“ค๋ฉด ์ด git bisect ๊ณผ์ •์„ ์™„์ „ํžˆ ์ž๋™ํ™” ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋จผ์ € bisect start ๋ช…๋ น์œผ๋กœ bisect๋ฅผ ์‚ฌ์šฉํ•  ๋ฒ”์œ„๋ฅผ ์•Œ๋ ค์ค€๋‹ค. ์œ„์—์„œ ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ฌธ์ œ๊ฐ€ ์žˆ๋‹ค๊ณ  ์•„๋Š” ์ปค๋ฐ‹๊ณผ ๋ฌธ์ œ๊ฐ€ ์—†๋‹ค๊ณ  ์•„๋Š” ์ปค๋ฐ‹์„ ๋„˜๊ธฐ๋ฉด ๋œ๋‹ค:

$ git bisect start HEAD v1.0
$ git bisect run test-error.sh

๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด ์ฒซ ์ปค๋ฐ‹์„ ์ฐพ์„ ๋•Œ๊นŒ์ง€ Checkoutํ•  ๋•Œ๋งˆ๋‹ค test-error.sh๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. make๋“ ์ง€ make tests๋“ ์ง€ ์–ด์จŒ๋“  ์ด์Šˆ๋ฅผ ์ฐพ๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜์—ฌ ์ฐพ๋Š”๋‹ค.

์„œ๋ธŒ๋ชจ๋“ˆ

ํ”„๋กœ์ ํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋‹ค ๋ณด๋ฉด ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์ข…์ข… ์žˆ๋‹ค. ๋ณดํ†ต ์‚ฌ์šฉํ•  ํ”„๋กœ์ ํŠธ๋“ค์€ ๋…๋ฆฝ์ ์œผ๋กœ ๊ฐœ๋ฐœ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด๋‹ค. ์ด๋Ÿฐ ์ƒํ™ฉ์—์„œ ์ž์ฃผ ์ƒ๊ธฐ๋Š” ์ด์Šˆ๋Š”, ๋‘ ํ”„๋กœ์ ํŠธ๋ฅผ ์„œ๋กœ ๋ณ„๊ฐœ๋กœ ๋‹ค๋ฃจ๋ฉด์„œ๋„ ๊ทธ ์ค‘ ํ•˜๋‚˜๋ฅผ ๋‹ค๋ฅธ ํ•˜๋‚˜ ์•ˆ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

Atom ํ”ผ๋“œ๋ฅผ ์ œ๊ณตํ•˜๋Š” ์›น์‚ฌ์ดํŠธ๋ฅผ ๋งŒ๋“ ๋‹ค๊ณ  ๊ฐ€์žฅํ•˜์ž. Atom ํ”ผ๋“œ๋ฅผ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ๋Š” ์ง์ ‘ ์ž‘์„ฑํ•˜์ง€ ์•Š๊ณ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๊ฐ€์ ธ๋‹ค ์“ฐ๊ธฐ๋กœ ํ–ˆ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด CPAN์ด๋‚˜ Ruby gem ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๊ด€๋ฆฌ ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ ํ•ด๋‹น ์†Œ์Šค์ฝ”๋“œ๋ฅผ ํ”„๋กœ์ ํŠธ๋กœ ๋ณต์‚ฌํ•ด์•ผ ํ•œ๋‹ค. ์‚ฌ์‹ค ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ ต๋‹ค. ํ•˜์ง€๋งŒ ์ˆ˜์ •ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋ชจ๋“  ์‚ฌ์šฉ์ž๊ฐ€ ์ด์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ฐฐํฌํ•˜๋Š” ๊ฒƒ์€ ๋” ์–ด๋ ต๋‹ค. ๊ทธ๋ž˜์„œ ํ”„๋กœ์ ํŠธ์— ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ฝ”๋“œ๋ฅผ ํฌํ•จ์‹œ์ผœ์„œ ์ˆ˜์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์‚ฌ์šฉํ•œ๋‹ค. ์ด๋ ‡๊ฒŒ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์ฝ”๋“œ๋ฅผ ํฌํ•จ์‹œํ‚ค๋ฉด ์›๋ž˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ”„๋กœ์ ํŠธ์˜ ์ฝ”๋“œ์™€ Mergeํ•˜๊ธฐ ์–ด๋ ต๊ฒŒ ๋œ๋‹ค.

Git์˜ ์„œ๋ธŒ๋ชจ๋“ˆ์€ ์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์ค€๋‹ค. ์„œ๋ธŒ๋ชจ๋“ˆ์€ Git ์ €์žฅ์†Œ ์•ˆ์— ๋‹ค๋ฅธ Git ์ €์žฅ์†Œ๋ฅผ ๋‘˜ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค€๋‹ค. ์ด๋ ‡๊ฒŒ ํ•ด๋„ ๋‘ Git ์ €์žฅ์†Œ ๋ชจ๋‘ ์—ฌ์ „ํžˆ ๋…๋ฆฝ์ ์œผ๋กœ ๊ด€๋ฆฌ๋œ๋‹ค.

์„œ๋ธŒ๋ชจ๋“ˆ ์‹œ์ž‘ํ•˜๊ธฐ

ํ•œ ๋ฒˆ Ruby ์›น์„œ๋ฒ„ ๊ฒŒ์ดํŠธ์›จ์ด ์ธํ„ฐํŽ˜์ด์Šค์ธ Rack ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํ”„๋กœ์ ํŠธ์— ์ถ”๊ฐ€ํ•ด๋ณด์ž. ์ถ”๊ฐ€ํ•˜๊ณ  ๋‚˜์„œ๋„ ์•ž์œผ๋กœ ์—ฌ์ „ํžˆ ํ•ด๋‹น ์ €์žฅ์†Œ์—์„œ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋งˆ์Œ ๋†“๊ณ  ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋จผ์ € git submodule add ๋ช…๋ น์œผ๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์„œ๋ธŒ๋ชจ๋“ˆ๋กœ ์ถ”๊ฐ€ํ•œ๋‹ค:

$ git submodule add git://github.com/chneukirchen/rack.git rack
Initialized empty Git repository in /opt/subtest/rack/.git/
remote: Counting objects: 3181, done.
remote: Compressing objects: 100% (1534/1534), done.
remote: Total 3181 (delta 1951), reused 2623 (delta 1603)
Receiving objects: 100% (3181/3181), 675.42 KiB | 422 KiB/s, done.
Resolving deltas: 100% (1951/1951), done.

์ด์ œ ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋ณด๋ฉด rack์ด๋ผ๋Š” ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์ƒ๊ฒผ์„ ๊ฒƒ์ด๋‹ค. ๊ทธ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ Rack ํ”„๋กœ์ ํŠธ์ด๋‹ค. rack ๋””๋ ‰ํ† ๋ฆฌ ์•ˆ์—์„œ ์ˆ˜์ •ํ•˜๊ณ  Pushํ•  ๊ถŒํ•œ์ด ์žˆ๋Š” ์ €์žฅ์†Œ๋ฅผ ํ•˜๋‚˜ ์ถ”๊ฐ€ํ•˜๊ณ  ๋‚˜์„œ ๊ทธ ์ €์žฅ์†Œ์— Pushํ•œ๋‹ค. ๋ฌผ๋ก  ์›๋ž˜ ํ”„๋กœ์ ํŠธ ์ €์žฅ์†Œ์—์„œ๋„ Fetchํ•˜๊ณ  Mergeํ•  ์ˆ˜ ์žˆ๋‹ค. ์„œ๋ธŒ๋ชจ๋“ˆ์„ ์ถ”๊ฐ€ํ•œ ์งํ›„ ๋ฐ”๋กœ git status๋ผ๋Š” ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๋‘ ํŒŒ์ผ์ด ์ƒ๊ธด ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค:

$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#      new file:   .gitmodules
#      new file:   rack
#

.gitmodules ํŒŒ์ผ์„ ์‚ดํŽด๋ณด์ž. ์ด ๊ฒƒ์€ ๋กœ์ปฌ ๋””๋ ‰ํ† ๋ฆฌ์™€ ํ”„๋กœ์ ํŠธ URL์˜ ๋งคํ•‘ ์ •๋ณด๊ฐ€ ์ €์žฅ๋œ ์„ค์ •ํŒŒ์ผ์ด๋‹ค:

$ cat .gitmodules
[submodule "rack"]
      path = rack
      url = git://github.com/chneukirchen/rack.git

์„œ๋ธŒ๋ชจ๋“ˆ ๊ฐœ์ˆ˜๋งŒํผ ์ด ํ•ญ๋ชฉ์ด ์ƒ๊ธด๋‹ค. ์ด ํŒŒ์ผ๋„ .gitignore ํŒŒ์ผ์ฒ˜๋Ÿผ ๋ฒ„์ „ ๊ด€๋ฆฌ๋œ๋‹ค. ๋‹ค๋ฅธ ํŒŒ์ผ์ฒ˜๋Ÿผ Pushํ•˜๊ณ  ํ’€ํ•œ๋‹ค. ์ด ํ”„๋กœ์ ํŠธ๋ฅผ Cloneํ•˜๋Š” ์‚ฌ๋žŒ์€ .gitmodules ํŒŒ์ผ์„ ๋ณด๊ณ  ์–ด๋–ค ์„œ๋ธŒ๋ชจ๋“ˆ ํ”„๋กœ์ ํŠธ๊ฐ€ ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

.gitmodules์€ ์‚ดํŽด๋ดค๊ณ  ์ด์ œ rack ํ•ญ๋ชฉ์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด์ž. git diff ๋ช…๋ น์„ ์‹คํ–‰์‹œํ‚ค๋ฉด ํฅ๋ฏธ๋กœ์šด ์ ์„ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ๋‹ค:

$ git diff --cached rack
diff --git a/rack b/rack
new file mode 160000
index 0000000..08d709f
--- /dev/null
+++ b/rack
@@ -0,0 +1 @@
+Subproject commit 08d709f78b8c5b0fbeb7821e37fa53e69afcf433

Git์€ rack ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์„œ๋ธŒ๋ชจ๋“ˆ๋กœ ์ทจ๊ธ‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํŒŒ์ผ๋“ค์„ ์ง์ ‘ ์ถ”์ ํ•˜์ง€ ์•Š๊ณ  ์ปค๋ฐ‹ ํ•˜๋‚˜๋งŒ ์ €์žฅํ•œ๋‹ค. rack ๋””๋ ‰ํ† ๋ฆฌ์—์„œ ์ˆ˜์ •์„ ํ•˜๊ณ  ์ปค๋ฐ‹ํ•˜๋ฉด ๋‹ค๋ฅธ ์‚ฌ๋žŒ์ด ๊ฐ™์€ ํ™˜๊ฒฝ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋„๋ก HEAD๊ฐ€ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ปค๋ฐ‹์ด ์Šˆํผํ”„๋กœ์ ํŠธ์— ์ €์žฅ๋œ๋‹ค.

master์ฒ˜๋Ÿผ ๋ธŒ๋žœ์น˜ ์ด๋ฆ„ ๊ฐ™์€ ๋ ˆํผ๋Ÿฐ์Šค๊ฐ€ ์ €์žฅ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ปค๋ฐ‹์˜ SHA-1 ๊ฐ’์ด ์ €์žฅ๋œ๋‹ค.

์Šˆํผํ”„๋กœ์ ํŠธ๋„ ์ปค๋ฐ‹ํ•ด์•ผ ๋œ๋‹ค:

$ git commit -m 'first commit with submodule rack'
[master 0550271] first commit with submodule rack
 2 files changed, 4 insertions(+), 0 deletions(-)
 create mode 100644 .gitmodules
 create mode 160000 rack

rack ๋””๋ ‰ํ† ๋ฆฌ์˜ ๋ชจ๋“œ๋Š” 160000์ด๋‹ค. 160000 ๋ชจ๋“œ๋Š” ์ผ๋ฐ˜์ ์ธ ํŒŒ์ผ์ด๋‚˜ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์•„๋‹ˆ๋ผ๋Š” ์˜๋ฏธ๋‹ค.

ํ•˜์œ„ ํ”„๋กœ์ ํŠธ์˜ ๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹์ด ๋ฐ”๋€” ๋•Œ๋งˆ๋‹ค ์Šˆํผํ”„๋กœ์ ํŠธ์— ์ €์žฅ๋œ ์ปค๋ฐ‹๋„ ๋ฐ”๊ฟ”์ค€๋‹ค. rack ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋ณ„๋„์˜ ํ”„๋กœ์ ํŠธ๋กœ ์ทจ๊ธ‰ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋“  Git ๋ช…๋ น์€ ๋…๋ฆฝ์ ์œผ๋กœ ๋™์ž‘ํ•œ๋‹ค:

$ git log -1
commit 0550271328a0038865aad6331e620cd7238601bb
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Apr 9 09:03:56 2009 -0700

    first commit with submodule rack
$ cd rack/
$ git log -1
commit 08d709f78b8c5b0fbeb7821e37fa53e69afcf433
Author: Christian Neukirchen <chneukirchen@gmail.com>
Date:   Wed Mar 25 14:49:04 2009 +0100

    Document version change

์„œ๋ธŒ๋ชจ๋“ˆ์ด ์žˆ๋Š” ํ”„๋กœ์ ํŠธ Cloneํ•˜๊ธฐ

์„œ๋ธŒ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ Cloneํ•˜๋ฉด ํ•ด๋‹น ์„œ๋ธŒ๋ชจ๋“ˆ ๋””๋ ‰ํ† ๋ฆฌ๋Š” ๋นˆ ๋””๋ ‰ํ„ฐ๋ฆฌ๋‹ค:

$ git clone git://github.com/schacon/myproject.git
Initialized empty Git repository in /opt/myproject/.git/
remote: Counting objects: 6, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (6/6), done.
$ cd myproject
$ ls -l
total 8
-rw-r--r--  1 schacon  admin   3 Apr  9 09:11 README
drwxr-xr-x  2 schacon  admin  68 Apr  9 09:11 rack
$ ls rack/
$

๋ถ„๋ช…ํžˆ rack ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์žˆ์ง€๋งŒ ๋น„์›Œ์ ธ ์žˆ๋‹ค. ๋จผ์ € git submodule init ๋ช…๋ น์œผ๋กœ ์„œ๋ธŒ๋ชจ๋“ˆ์„ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  git submodule update ๋ช…๋ น์œผ๋กœ ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ์ „๋ถ€ ๊ฐ€์ ธ์˜ค๋ฉด ์Šˆํผํ”„๋กœ์ ํŠธ์— ์ €์žฅ๋œ ์ปค๋ฐ‹์œผ๋กœ Checkout๋œ๋‹ค:

$ git submodule init
Submodule 'rack' (git://github.com/chneukirchen/rack.git) registered for path 'rack'
$ git submodule update
Initialized empty Git repository in /opt/myproject/rack/.git/
remote: Counting objects: 3181, done.
remote: Compressing objects: 100% (1534/1534), done.
remote: Total 3181 (delta 1951), reused 2623 (delta 1603)
Receiving objects: 100% (3181/3181), 675.42 KiB | 173 KiB/s, done.
Resolving deltas: 100% (1951/1951), done.
Submodule path 'rack': checked out '08d709f78b8c5b0fbeb7821e37fa53e69afcf433'

rack ๋””๋ ‰ํ† ๋ฆฌ๋Š” ์ด์ œ ๋ณต์›ํ–ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ˆ„๊ตฐ๊ฐ€ rack์„ ์ˆ˜์ •ํ•˜๋ฉด ๊ทธ ์ฝ”๋“œ๋ฅผ ๊ฐ€์ ธ๋‹ค Mergeํ•œ๋‹ค:

$ git merge origin/master
Updating 0550271..85a3eee
Fast forward
 rack |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
[master*]$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#      modified:   rack
#

Mergeํ•ด์„œ ์„œ๋ธŒ๋ชจ๋“ˆ์˜ HEAD ๊ฐ’์ด ๋ณ€๊ฒฝ๋๋‹ค. ์Šˆํผํ”„๋กœ์ ํŠธ๊ฐ€ ์•„๋Š” ์ปค๋ฐ‹๊ณผ ์„œ๋ธŒ๋ชจ๋“ˆ์˜ HEAD๊ฐ€ ๋‹ฌ๋ผ์„œ ์•„์ง ์›Œํ‚น ๋””๋ ‰ํ† ๋ฆฌ์˜ ์ƒํƒœ๋Š” ๊นจ๋—ํ•œ ์ƒํƒœ๊ฐ€ ์•„๋‹ˆ๋‹ค:

$ git diff
diff --git a/rack b/rack
index 6c5e70b..08d709f 160000
--- a/rack
+++ b/rack
@@ -1 +1 @@
-Subproject commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
+Subproject commit 08d709f78b8c5b0fbeb7821e37fa53e69afcf433

์ด๋Ÿด ๋•Œ git submodule update ๋ช…๋ น์„ ์‹คํ–‰ํ•ด์„œ ํ•ด๊ฒฐํ•œ๋‹ค:

$ git submodule update
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 1), reused 2 (delta 0)
Unpacking objects: 100% (3/3), done.
From git@github.com:schacon/rack
   08d709f..6c5e70b  master     -> origin/master
Submodule path 'rack': checked out '6c5e70b984a60b3cecd395edd5b48a7575bf58e0'

์„œ๋ธŒ๋ชจ๋“ˆ ํ”„๋กœ์ ํŠธ๋ฅผ ํ’€ํ•  ๋•Œ๋งˆ๋‹ค git submodule update ๋ช…๋ น์„ ์‹คํ–‰ํ•ด์•ผ ํ•œ๋‹ค. ๋ญ”๊ฐ€ ์†๋Š” ๊ฒƒ ๊ฐ™์ง€๋งŒ ์ž˜ ๋œ๋‹ค.

๊ฐœ๋ฐœ์ž๋“ค์ด ํ”ํžˆ ์ €์ง€๋ฅด๋Š” ์‹ค์ˆ˜๋กœ ์„œ๋ธŒ๋ชจ๋“ˆ์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  ๋‚˜์„œ ์„œ๋ฒ„์— Pushํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ์Šˆํผํ”„๋กœ์ ํŠธ๋Š” Pushํ–ˆ์ง€๋งŒ ํ”„๋กœ์ ํŠธ๊ฐ€ ์•„๋Š” ์ปค๋ฐ‹์€ ์•„์ง Pushํ•˜์ง€ ์•Š๊ณ  ๊ฐœ๋ฐœ์ž PC์—๋งŒ ์žˆ๋‹ค. ๋งŒ์•ฝ ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๊ฐ€ git submodule update๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์Šˆํผํ”„๋กœ์ ํŠธ์— ์ €์žฅ๋œ ์ปค๋ฐ‹์„ ์„œ๋ธŒ๋ชจ๋“ˆ ํ”„๋กœ์ ํŠธ์—์„œ ์ฐพ์„ ์ˆ˜ ์—†์–ด์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค:

$ git submodule update
fatal: reference isnโ€™t a tree: 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Unable to checkout '6c5e70b984a60b3cecd395edd5ba7575bf58e0' in submodule path 'rack'

๋ˆ„๊ฐ€ ๋งˆ์ง€๋ง‰์œผ๋กœ ์„œ๋ธŒ๋ชจ๋“ˆ์„ ์ˆ˜์ •ํ–ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ :

$ git log -1 rack
commit 85a3eee996800fcfa91e2119372dd4172bf76678
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Apr 9 09:19:14 2009 -0700

    added a submodule reference I will never make public. hahahahaha!

๊ทธ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ์ด๋ฉ”์ผ์„ ๋ณด๋‚ด๊ฑฐ๋‚˜ ์ „ํ™”๋ฅผ ๊ฑด๋‹ค.

์Šˆํผํ”„๋กœ์ ํŠธ

ํ”„๋กœ์ ํŠธ ๊ทœ๋ชจ๊ฐ€ ํฌ๋ฉด CVS๋‚˜ Subversion์—์„œ๋Š” ๋ชจ๋“ˆ ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐ„๋‹จํžˆ ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ๋กœ ๋งŒ๋“ค์—ˆ๋‹ค. ๊ฐ€๋” Git์—์„œ๋„ ์ด๋Ÿฐ Workflow์„ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๊ฐœ๋ฐœ์ž๋“ค์ด ์žˆ๋‹ค.

Git์—์„œ๋Š” ๊ฐ ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋ณ„๋„์˜ Git ์ €์žฅ์†Œ๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๊ทธ ์ €์žฅ์†Œ๋ฅผ ํฌํ•จํ•˜๋Š” ์ƒ์œ„ ์ €์žฅ์†Œ๋ฅผ ๋งŒ๋“ ๋‹ค. ์Šˆํผํ”„๋กœ์ ํŠธ์˜ ํƒœ๊ทธ์™€ ๋ธŒ๋žœ์น˜๋ฅผ ์ด์šฉํ•ด์„œ ๊ฐ ํ”„๋กœ์ ํŠธ์˜ ๊ด€๊ณ„๋ฅผ ๊ตฌ์ฒด์ ์œผ๋กœ ์ •์˜ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ Git๋งŒ์˜ ์žฅ์ ์ด๋‹ค.

์„œ๋ธŒ๋ชจ๋“ˆ ์‚ฌ์šฉํ•  ๋•Œ ์ฃผ์˜ํ•  ์ ๋“ค

์ „์ฒด์ ์œผ๋กœ ์„œ๋ธŒ๋ชจ๋“ˆ์€ ์–ด๋ ต์ง€ ์•Š๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ์„œ๋ธŒ๋ชจ๋“ˆ์˜ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค. git submodule update ๋ช…๋ น์„ ์‹คํ–‰์‹œํ‚ค๋ฉด ํŠน์ • ๋ธŒ๋žœ์น˜๊ฐ€ ์•„๋‹ˆ๋ผ ์Šˆํผํ”„๋กœ์ ํŠธ์— ์ €์žฅ๋œ ์ปค๋ฐ‹์„ Checkoutํ•ด ๋ฒ„๋ฆฐ๋‹ค. ๊ทธ๋Ÿฌ๋ฉด detached HEAD๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ์ƒํƒœ๊ฐ€ ๋œ๋‹ค. detached HEAD๋Š” HEAD๊ฐ€ ๋ธŒ๋žœ์น˜๋‚˜ ํƒœ๊ทธ ๊ฐ™์€ ๊ฐ„์ ‘ ๋ ˆํผ๋Ÿฐ์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚ค์ง€ ์•Š๊ณ  ์ปค๋ฐ‹์„ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค. ๋ฐ์ดํ„ฐ๋ฅผ ์žƒ์–ด ๋ฒ„๋ฆด ์ˆ˜๋„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ผ๋ฐ˜์ ์œผ๋กœ detached HEAD ์ƒํƒœ๋Š” ํ”ผํ•ด์•ผ ํ•œ๋‹ค.

submodule update๋ฅผ ์‹คํ–‰ํ•˜๊ณ  ๋‚˜์„œ ๋ณ„๋„์˜ ์ž‘์—…์šฉ ๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ์„œ๋ธŒ๋ชจ๋“ˆ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  ์ปค๋ฐ‹ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚˜์ค‘์— ์ปค๋ฐ‹ํ•œ ๊ฒƒ์„ ์žŠ์€ ์ฑ„๋กœ ์Šˆํผํ”„๋กœ์ ํŠธ์—์„œ ๋‹ค์‹œ git submodule update๋ฅผ ์‹คํ–‰์‹œํ‚ค๋ฉด Git์€ ์•„๋ฌด ๋ง ์—†์ด Checkoutํ•ด ๋ฒ„๋ฆฐ๋‹ค. ์—„๋ฐ€ํžˆ ๋งํ•ด์„œ ์ปค๋ฐ‹์„ ์—†์–ด์ง„ ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ ๋ธŒ๋žœ์น˜์— ์†ํ•˜์ง€ ์•Š๋Š” ์ปค๋ฐ‹์„ ์ฐพ์•„๋‚ด๊ธฐ๋ž€ ์ •๋ง ์–ด๋ ต๋‹ค.

git checkout -b work ๊ฐ™์€ ๋ช…๋ น์œผ๋กœ ์ž‘์—…ํ•  ๋•Œ๋งˆ๋‹ค work ๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“ค๋ฉด ์ด ๋ฌธ์ œ๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ๋‹ค. ์‹ค์ˆ˜๋กœ submodule update ๋ช…๋ น์„ ์‹คํ–‰ํ•ด ๋ฒ„๋ ค์„œ ํ•˜๋˜ ์ผ์„ ๋†“์ณ๋ฒ„๋ ค๋„ ํฌ์ธํ„ฐ๊ฐ€ ์žˆ์–ด์„œ ์–ธ์ œ๋“ ์ง€ ๋˜์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์„œ๋ธŒ๋ชจ๋“ˆ์ด ์žˆ๋Š” ์Šˆํผํ”„๋กœ์ ํŠธ์˜ ๋ธŒ๋žœ์น˜๋ฅผ ์˜ค๊ฐˆ ๋•Œ๋Š” ์•ฝ๊ฐ„์˜ ์ถ”๊ฐ€์ž‘์—…์ด ํ•„์š”ํ•˜๋‹ค. ๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“ค๊ณ  ์„œ๋ธŒ๋ชจ๋“ˆ์„ ์ถ”๊ฐ€ํ•œ๋‹ค. ๊ทธ ๋‹ค์Œ์— ์„œ๋ธŒ๋ชจ๋“ˆ์ด ์—†๋Š” ๋ธŒ๋žœ์น˜๋กœ ๋Œ์•„๊ฐ„๋‹ค. ๊ทธ๋ ‡์ง€๋งŒ, ์ด๋ฏธ ์ถ”๊ฐ€ํ•œ ์„œ๋ธŒ๋ชจ๋“ˆ ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ untracked ์ƒํƒœ๋กœ ๋ณด์ธ๋‹ค:

$ git checkout -b rack
Switched to a new branch "rack"
$ git submodule add git@github.com:schacon/rack.git rack
Initialized empty Git repository in /opt/myproj/rack/.git/
...
Receiving objects: 100% (3184/3184), 677.42 KiB | 34 KiB/s, done.
Resolving deltas: 100% (1952/1952), done.
$ git commit -am 'added rack submodule'
[rack cc49a69] added rack submodule
 2 files changed, 4 insertions(+), 0 deletions(-)
 create mode 100644 .gitmodules
 create mode 160000 rack
$ git checkout master
Switched to branch "master"
$ git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#      rack/

์„œ๋ธŒ๋ชจ๋“ˆ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋‹ค๋ฅธ ๊ณณ์— ์˜ฎ๊ฒจ ๋‘๊ฑฐ๋‚˜ ์‚ญ์ œํ•ด์•ผ ํ•œ๋‹ค. ์‚ญ์ œํ•  ๊ฒฝ์šฐ๋Š” ์›๋ž˜ ๋ธŒ๋žœ์น˜๋กœ ๋Œ์•„์™”์„ ๋•Œ ์„œ๋ธŒ๋ชจ๋“ˆ์„ ๋‹ค์‹œ Cloneํ•ด์•ผ ํ•˜๊ณ , ์ด ๊ฒฝ์šฐ ์•„์ง Pushํ•˜์ง€ ์•Š์•˜๋˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด๋‚˜ ๋ธŒ๋žœ์น˜๋ฅผ ์žƒ์„ ์ˆ˜ ์žˆ๋‹ค.

rack์ด๋ผ๋Š” ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์žˆ๊ณ  ์ด๊ฒƒ์„ ์„œ๋ธŒ๋ชจ๋“ˆ๋กœ ๋ฐ”๊พธ๋ ค๊ณ  ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•˜์ž. ๋จผ์ € rack ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์‚ญ์ œํ•˜๊ณ  submodule add๋ฅผ ์‹คํ–‰ํ•˜๋ฉด Git์€ ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๋ฅผ ๋ฑ‰๋Š”๋‹ค:

$ rm -Rf rack/
$ git submodule add git@github.com:schacon/rack.git rack
'rack' already exists in the index

rack ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ Staging Area์—์„œ ์ œ๊ฑฐํ•˜๋ฉด ์„œ๋ธŒ๋ชจ๋“ˆ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.

$ git rm -r rack
$ git submodule add git@github.com:schacon/rack.git rack
Initialized empty Git repository in /opt/testsub/rack/.git/
remote: Counting objects: 3184, done.
remote: Compressing objects: 100% (1465/1465), done.
remote: Total 3184 (delta 1952), reused 2770 (delta 1675)
Receiving objects: 100% (3184/3184), 677.42 KiB | 88 KiB/s, done.
Resolving deltas: 100% (1952/1952), done.

ํ•œ ๋ธŒ๋žœ์น˜์—์„œ๋Š” ํ•ด๊ฒฐํ–ˆ๋‹ค. ์•„์ง ํ•ด๋‹น ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ์„œ๋ธŒ๋ชจ๋“ˆ๋กœ ๋งŒ๋“ค์ง€ ์•Š์€ ๋ธŒ๋žœ์น˜๋ฅผ Checkoutํ•˜๋ ค๊ณ  ํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋‚œ๋‹ค:

$ git checkout master
error: Untracked working tree file 'rack/AUTHORS' would be overwritten by merge.

๋‹ค๋ฅธ ๋ธŒ๋žœ์น˜๋กœ ๋ฐ”๊พธ๊ธฐ ์ „์— rack ์„œ๋ธŒ๋ชจ๋“ˆ ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ ๋‹ค๋ฅธ ๊ณณ์œผ๋กœ ์˜ฎ๊ฒจ ๋‘”๋‹ค:

$ mv rack /tmp/
$ git checkout master
Switched to branch "master"
$ ls
README  rack

๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ ๋‹ค์‹œ ์„œ๋ธŒ๋ชจ๋“ˆ์ด ์žˆ๋Š” ๋ธŒ๋žœ์น˜๋กœ ๋Œ์•„๊ฐ€๋ฉด rack ๋””๋ ‰ํ† ๋ฆฌ๋Š” ํ…… ๋น„์–ด ์žˆ๋‹ค. git submodule update ๋ช…๋ น์œผ๋กœ ๋‹ค์‹œ Cloneํ•˜๊ฑฐ๋‚˜ /tmp/rack/์— ๋ณต์‚ฌํ•ด๋‘” ํŒŒ์ผ์„ ๋‹ค์‹œ ๋ณต์‚ฌํ•œ๋‹ค.

Subtree Merge

์„œ๋ธŒ๋ชจ๋“ˆ ์‹œ์Šคํ…œ์ด ๋ฌด์—‡์ด๊ณ  ์–ด๋””์— ์“ฐ๋Š”์ง€ ๋ฐฐ์› ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ฐ™์€ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ๋˜ ํ•˜๋‚˜ ์žˆ๋‹ค. Git์€ Mergeํ•˜๋Š” ์‹œ์ ์— ๋ฌด์—‡์„ Mergeํ• ์ง€, ์–ด๋–ค ์ „๋žต์„ ์‚ฌ์šฉํ• ์ง€ ๊ฒฐ์ •ํ•ด์•ผ ํ•œ๋‹ค. Git์€ ๋ธŒ๋žœ์น˜ ๋‘ ๊ฐœ๋ฅผ Mergeํ•  ๋•Œ์—๋Š” Recursive ์ „๋žต์„ ์‚ฌ์šฉํ•˜๊ณ  ์„ธ ๊ฐœ ์ด์ƒ์˜ ๋ธŒ๋žœ์น˜๋ฅผ Mergeํ•  ๋•Œ์—๋Š” Octopus ์ „๋žต์„ ์‚ฌ์šฉํ•œ๋‹ค. ์ด ์ „๋žต์€ ์ž๋™์œผ๋กœ ์„ ํƒ๋œ๋‹ค. Mergeํ•  ๋ธŒ๋žœ์น˜๊ฐ€ ๋‘๊ฐœ๋ฉด Recursive ์ „๋žต์ด ์„ ํƒ๋œ๋‹ค. Recursive ์ „๋žต์€ Mergeํ•˜๋ ค๋Š” ๋‘ ์ปค๋ฐ‹๊ณผ ๊ณตํ†ต ์กฐ์ƒ ์ปค๋ฐ‹์„ ์ด์šฉํ•˜๋Š” three-way merge๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹จ ๋‘ ๊ฐœ์˜ ๋ธŒ๋žœ์น˜์—๋งŒ ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. Octopus ์ „๋žต์€ ๋ธŒ๋žœ์น˜๊ฐ€ ์—ฌ๋Ÿฌ ๊ฐœ๋ผ๋„ Mergeํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ๋น„๊ต์  ์ถฉ๋Œ์ด ์‰ฝ๊ฒŒ ์ผ์–ด๋‚œ๋‹ค.

๋‹ค๋ฅธ ์ „๋žต๋„ ์žˆ๋Š”๋ฐ ๊ทธ์ค‘ ํ•˜๋‚˜๊ฐ€ Subtree Merge๋‹ค. ์ด Merge๋Š” ํ•˜์œ„ ํ”„๋กœ์ ํŠธ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐ์—๋„ ์‚ฌ์šฉํ•œ๋‹ค. ์œ„์—์„œ ์‚ฌ์šฉํ–ˆ๋˜ Rack ์˜ˆ์ œ๋ฅผ ์ ์šฉํ•ด ๋ณด์ž.

Subtree Merge๋Š” ๋งˆ์น˜ ํ•˜์œ„ ํ”„๋กœ์ ํŠธ๊ฐ€ ์•„์˜ˆ ํ•ฉ์ณ์ง„ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ผ ์ •๋„๋กœ ํ•œ ํ”„๋กœ์ ํŠธ๋ฅผ ๋‹ค๋ฅธ ํ”„๋กœ์ ํŠธ์˜ ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ์— ์—ฐ๊ฒฐํ•ด์ค€๋‹ค. ์ •๋ง ๋†€๋ผ์šด ๊ธฐ๋Šฅ์ด๋‹ค.

Rack ํ”„๋กœ์ ํŠธ๋ฅผ ๋ฆฌ๋ชจํŠธ ์ €์žฅ์†Œ๋กœ ์ถ”๊ฐ€์‹œํ‚ค๊ณ  ๋ธŒ๋žœ์น˜๋ฅผ Checkoutํ•œ๋‹ค:

$ git remote add rack_remote git@github.com:schacon/rack.git
$ git fetch rack_remote
warning: no common commits
remote: Counting objects: 3184, done.
remote: Compressing objects: 100% (1465/1465), done.
remote: Total 3184 (delta 1952), reused 2770 (delta 1675)
Receiving objects: 100% (3184/3184), 677.42 KiB | 4 KiB/s, done.
Resolving deltas: 100% (1952/1952), done.
From git@github.com:schacon/rack
 * [new branch]      build      -> rack_remote/build
 * [new branch]      master     -> rack_remote/master
 * [new branch]      rack-0.4   -> rack_remote/rack-0.4
 * [new branch]      rack-0.9   -> rack_remote/rack-0.9
$ git checkout -b rack_branch rack_remote/master
Branch rack_branch set up to track remote branch refs/remotes/rack_remote/master.
Switched to a new branch "rack_branch"

Checkoutํ•œ rack_branch์˜ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ์™€ origin ํ”„๋กœ์ ํŠธ์˜ master ๋ธŒ๋žœ์น˜์˜ ๋ฃจํŠธ ๋””๋ ‰ํ† ๋ฆฌ๋Š” ๋‹ค๋ฅด๋‹ค. ๋ธŒ๋žœ์น˜๋ฅผ ๋ฐ”๊ฟ”๊ฐ€๋ฉฐ ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ์ง€ ํ™•์ธํ•œ๋‹ค:

$ ls
AUTHORS        KNOWN-ISSUES   Rakefile      contrib        lib
COPYING        README         bin           example        test
$ git checkout master
Switched to branch "master"
$ ls
README

์—ฌ๊ธฐ์—์„œ Rack ํ”„๋กœ์ ํŠธ๋ฅผ master ๋ธŒ๋žœ์น˜์˜ ํ•˜์œ„ ๋””๋ ‰ํ† ๋ฆฌ์— ๋„ฃ์œผ๋ ค๋ฉด git read-tree ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. _9์žฅ_์—์„œ read-read ๋ฅ˜์˜ ๋ช…๋ น์–ด๋ฅผ ์ข€ ๋” ์ž์„ธํžˆ ๋‹ค๋ฃฌ๋‹ค. ์—ฌ๊ธฐ์—์„œ๋Š” ์›Œํ‚น ๋””๋ ‰ํ† ๋ฆฌ์™€ Staging Area๋กœ ์–ด๋–ค ๋ธŒ๋žœ์น˜๋ฅผ ํ†ต์งธ๋กœ ๋„ฃ์„ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ๋งŒ ์•Œ๋ฉด ๋œ๋‹ค. master ๋ธŒ๋žœ์น˜๋กœ ๋˜๋Œ์•„๊ฐ€์„œ rack_branch๋ฅผ rack ๋””๋ ‰ํ† ๋ฆฌ์— ๋„ฃ๋Š”๋‹ค:

$ git read-tree --prefix=rack/ -u rack_branch

๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ ์ปค๋ฐ‹์„ ํ•˜๋ฉด rack ๋””๋ ‰ํ† ๋ฆฌ๋Š” rack ํ”„๋กœ์ ํŠธ์˜ ํŒŒ์ผ๋“ค์„ ์ง์ ‘ ๋ณต์‚ฌํ•ด ๋„ฃ์€ ๊ฒƒ๊ณผ ๋˜‘๊ฐ™๋‹ค. ๋ณต์‚ฌํ•œ ๊ฒƒ๊ณผ ๋‹ค๋ฅธ ์ ์€ ๋ธŒ๋žœ์น˜๋ฅผ ์ž์œ ๋กญ๊ฒŒ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๊ณ  ์ตœ์‹  ๋ฒ„์ „์˜ Rack ํ”„๋กœ์ ํŠธ์˜ ์ฝ”๋“œ๋ฅผ ์‰ฝ๊ฒŒ ๋Œ์–ด ์˜ฌ ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค:

$ git checkout rack_branch
$ git pull

๊ทธ๋ฆฌ๊ณ  git merge -s subtree๋ผ๋Š” ๋ช…๋ น์–ด๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ master ๋ธŒ๋žœ์น˜์™€ Mergeํ•  ์ˆ˜ ์žˆ๊ณ  ์›ํ•˜๋“  ์›ํ•˜์ง€ ์•Š๋“  ๊ฐ„์— ํžˆ์Šคํ† ๋ฆฌ๋„ ํ•จ๊ป˜ Merge๋œ๋‹ค. ์ˆ˜์ • ๋‚ด์šฉ๋งŒ Mergeํ•˜๊ฑฐ๋‚˜ ์ปค๋ฐ‹ ๋ฉ”์‹œ์ง€๋ฅผ ๋‹ค์‹œ ์ž‘์„ฑํ•˜๋ ค๋ฉด -s subtree ์˜ต์…˜์—๋‹ค๊ฐ€ --squash, --no-commit๋ฅผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค:

$ git checkout master
$ git merge --squash -s subtree --no-commit rack_branch
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested

Rack ํ”„๋กœ์ ํŠธ์˜ ์ตœ์‹  ์ฝ”๋“œ๋ฅผ ๊ฐ€์ ธ๋‹ค๊ฐ€ Mergeํ–ˆ๊ณ  ์ด์ œ ์ปค๋ฐ‹ํ•˜๋ฉด ๋œ๋‹ค. ๋ฌผ๋ก  ๋ฐ˜๋Œ€๋กœ ํ•˜๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค. rack ๋””๋ ‰ํ† ๋ฆฌ๋กœ ์ด๋™ํ•ด์„œ ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๊ณ  rack_branch ๋ธŒ๋žœ์น˜๋กœ Mergeํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  Rack ํ”„๋กœ์ ํŠธ ์ €์žฅ์†Œ์— Pushํ•  ์ˆ˜ ์žˆ๋‹ค.

rack ๋””๋ ‰ํ† ๋ฆฌ์™€ rack_branch ๋ธŒ๋žœ์น˜์™€์˜ ์ฐจ์ด์ ๋„ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋‹ค. ์ผ๋ฐ˜์ ์ธ diff ๋ช…๋ น์€ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ณ  git diff-tree ๋ช…๋ น์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค:

$ git diff-tree -p rack_branch

๋˜ rack ๋””๋ ‰ํ† ๋ฆฌ์™€ ์ €์žฅ์†Œ์˜ master ๋ธŒ๋žœ์น˜์™€ ๋น„๊ตํ•  ์ˆ˜ ์žˆ๋‹ค:

$ git diff-tree -p rack_remote/master

์š”์•ฝ

์ปค๋ฐ‹๊ณผ ์ €์žฅ์†Œ๋ฅผ ๊ผผ๊ผผํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜๋Š” ๋„๊ตฌ๋ฅผ ์‚ดํŽด๋ณด์•˜๋‹ค. ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธฐ๋ฉด ๋ฐ”๋กœ ๋ˆ„๊ฐ€, ์–ธ์ œ, ๋ฌด์—‡์„ ํ–ˆ๋Š”์ง€ ์ฐพ์•„๋‚ด์•ผ ํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ํ”„๋กœ์ ํŠธ๋ฅผ ์ชผ๊ฐœ๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๋“ค๋„ ๋ฐฐ์› ๋‹ค. ์ด์ œ Git ๋ช…๋ น์–ด๋Š” ๊ฑฐ์˜ ๋ชจ๋‘ ๋ฐฐ์šด ๊ฒƒ์ด๋‹ค. ๋…์ž๋“ค์ด ํ•˜๋ฃจ๋นจ๋ฆฌ ์ต์ˆ™ํ•ด์ ธ์„œ ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉํ–ˆ์œผ๋ฉด ์ข‹๊ฒ ๋‹ค.

Last updated

Was this helpful?