Skip to content

Git CLI Process Journey : to cmd_merge()

Git CLI์—์„œ cmd_merge()๊นŒ์ง€์˜ ์—ฌ์ •

Section titled โ€œGit CLI์—์„œ cmd_merge()๊นŒ์ง€์˜ ์—ฌ์ •โ€

์‚ฌ์šฉ์ž๊ฐ€ ํ„ฐ๋ฏธ๋„์—์„œ git merge feat๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์–ด๋–ป๊ฒŒ cmd_merge() ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋ ๊นŒ์š”? ์ด ๊ณผ์ •์€ ๋งˆ์น˜ ํŽธ์ง€๊ฐ€ ์šฐ์ฒด๊ตญ์„ ๊ฑฐ์ณ ์ตœ์ข… ๋ชฉ์ ์ง€์— ๋„๋‹ฌํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ ์—ฌ๋Ÿฌ ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์นฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์„œ์—์„œ๋Š” ๊ทธ ์—ฌ์ •์„ ๋‹จ๊ณ„๋ณ„๋กœ ์ถ”์ ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

1๋‹จ๊ณ„: ์‹œ์Šคํ…œ ์‰˜์—์„œ Git ์‹คํ–‰ ํŒŒ์ผ ์ฐพ๊ธฐ

Section titled โ€œ1๋‹จ๊ณ„: ์‹œ์Šคํ…œ ์‰˜์—์„œ Git ์‹คํ–‰ ํŒŒ์ผ ์ฐพ๊ธฐโ€
Terminal window
git merge feat

์‚ฌ์šฉ์ž๊ฐ€ ์ด ๋ช…๋ น์„ ์ž…๋ ฅํ•˜๋ฉด, ์šด์˜์ฒด์ œ์˜ ์‰˜(bash, zsh ๋“ฑ)์€ ๋จผ์ € git์ด๋ผ๋Š” ์‹คํ–‰ ํŒŒ์ผ์„ ์ฐพ์Šต๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  1. PATH ํ™˜๊ฒฝ ๋ณ€์ˆ˜ ๊ฒ€์ƒ‰: ์‰˜์€ PATH์— ๋“ฑ๋ก๋œ ๋””๋ ‰ํ† ๋ฆฌ๋“ค์„ ์ˆœ์„œ๋Œ€๋กœ ํƒ์ƒ‰ํ•ฉ๋‹ˆ๋‹ค
  2. ์‹คํ–‰ ํŒŒ์ผ ๋ฐœ๊ฒฌ: ๋ณดํ†ต /usr/bin/git ๋˜๋Š” /usr/local/bin/git์—์„œ Git ์‹คํ–‰ ํŒŒ์ผ์„ ์ฐพ์Šต๋‹ˆ๋‹ค
  3. ํ”„๋กœ์„ธ์Šค ์ƒ์„ฑ: ์‰˜์€ ์ƒˆ๋กœ์šด ํ”„๋กœ์„ธ์Šค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  git ๋ฐ”์ด๋„ˆ๋ฆฌ๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค

2๋‹จ๊ณ„: Git ๋ฉ”์ธ ํ•จ์ˆ˜ ์ง„์ž…

Section titled โ€œ2๋‹จ๊ณ„: Git ๋ฉ”์ธ ํ•จ์ˆ˜ ์ง„์ž…โ€

Git์˜ ์ง„์ž…์ ์€ git.c ํŒŒ์ผ์˜ main() ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค:

git.c
int main(int argc, const char **argv)
{
const char *cmd;
int done_help = 0;
/* ์‹คํ–‰ ํŒŒ์ผ ์ด๋ฆ„์—์„œ ๋ช…๋ น ์ถ”์ถœ
* ์˜ˆ: git-merge๋กœ ์‹คํ–‰๋˜์—ˆ๋‹ค๋ฉด "merge"๋ฅผ ์ถ”์ถœ */
cmd = argv[0];
if (!cmd)
cmd = "git-help";
else {
const char *slash = find_last_dir_sep(cmd);
if (slash)
cmd = slash + 1;
}
/* Git ํ™˜๊ฒฝ ์ดˆ๊ธฐํ™” */
startup_info = &git_startup_info;
/* ๋ช…๋ นํ–‰ ์ธ์ž ์ฒ˜๋ฆฌ */
argv++;
argc--;
/* ํ•ต์‹ฌ: handle_builtin() ํ˜ธ์ถœ! */
handle_builtin(argc, argv);
return 0;
}

3๋‹จ๊ณ„: ๋‚ด์žฅ ๋ช…๋ น์–ด ์ฒ˜๋ฆฌ - handle_builtin()

Section titled โ€œ3๋‹จ๊ณ„: ๋‚ด์žฅ ๋ช…๋ น์–ด ์ฒ˜๋ฆฌ - handle_builtin()โ€

Git์€ ๋‘ ๊ฐ€์ง€ ์ข…๋ฅ˜์˜ ๋ช…๋ น์–ด๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค:

  • ๋‚ด์žฅ ๋ช…๋ น์–ด(builtin): Git ๋ฐ”์ด๋„ˆ๋ฆฌ์— ์ง์ ‘ ํฌํ•จ๋œ ๋ช…๋ น์–ด
  • ์™ธ๋ถ€ ๋ช…๋ น์–ด: ๋ณ„๋„์˜ ์Šคํฌ๋ฆฝํŠธ๋‚˜ ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ๊ตฌํ˜„๋œ ๋ช…๋ น์–ด

merge๋Š” ๋‚ด์žฅ ๋ช…๋ น์–ด์ด๋ฏ€๋กœ handle_builtin() ํ•จ์ˆ˜์—์„œ ์ฒ˜๋ฆฌ๋ฉ๋‹ˆ๋‹ค:

git.c
static int handle_builtin(int argc, const char **argv)
{
const char *cmd;
struct cmd_struct *builtin;
cmd = argv[0];
/* ๋‚ด์žฅ ๋ช…๋ น์–ด ํ…Œ์ด๋ธ”์—์„œ "merge" ์ฐพ๊ธฐ */
builtin = get_builtin(cmd);
if (builtin)
return run_builtin(builtin, argc, argv);
return 0;
}

4๋‹จ๊ณ„: ๋ช…๋ น์–ด ํ…Œ์ด๋ธ” - Git์˜ ์ „ํ™”๋ฒˆํ˜ธ๋ถ€

Section titled โ€œ4๋‹จ๊ณ„: ๋ช…๋ น์–ด ํ…Œ์ด๋ธ” - Git์˜ ์ „ํ™”๋ฒˆํ˜ธ๋ถ€โ€

Git์€ ๋ชจ๋“  ๋‚ด์žฅ ๋ช…๋ น์–ด๋ฅผ ํ…Œ์ด๋ธ”๋กœ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ๋งˆ์น˜ ์ „ํ™”๋ฒˆํ˜ธ๋ถ€์ฒ˜๋Ÿผ ๋ช…๋ น์–ด ์ด๋ฆ„๊ณผ ์‹ค์ œ ํ•จ์ˆ˜๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค:

git.c
static struct cmd_struct commands[] = {
{ "add", cmd_add, RUN_SETUP | NEED_WORK_TREE },
{ "branch", cmd_branch, RUN_SETUP | DELAY_PAGER_CONFIG },
{ "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
{ "commit", cmd_commit, RUN_SETUP | NEED_WORK_TREE },
{ "diff", cmd_diff, NO_PARSEOPT },
{ "fetch", cmd_fetch, RUN_SETUP },
{ "log", cmd_log, RUN_SETUP },
{ "merge", cmd_merge, RUN_SETUP | NEED_WORK_TREE }, /* ์—ฌ๊ธฐ! */
{ "pull", cmd_pull, RUN_SETUP | NEED_WORK_TREE },
{ "push", cmd_push, RUN_SETUP },
{ "rebase", cmd_rebase, RUN_SETUP | NEED_WORK_TREE },
/* ... ๋” ๋งŽ์€ ๋ช…๋ น์–ด๋“ค ... */
};

๊ฐ ํ•ญ๋ชฉ์˜ ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

  • ๋ช…๋ น์–ด ์ด๋ฆ„: โ€œmergeโ€
  • ํ•จ์ˆ˜ ํฌ์ธํ„ฐ: cmd_merge (์‹ค์ œ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜)
  • ํ”Œ๋ž˜๊ทธ: RUN_SETUP | NEED_WORK_TREE (์‹คํ–‰ ์กฐ๊ฑด)

ํ”Œ๋ž˜๊ทธ์˜ ์˜๋ฏธ:

  • RUN_SETUP: Git ์ €์žฅ์†Œ ์„ค์ •์„ ๋กœ๋“œํ•ด์•ผ ํ•จ
  • NEED_WORK_TREE: ์ž‘์—… ํŠธ๋ฆฌ๊ฐ€ ํ•„์š”ํ•จ (bare ์ €์žฅ์†Œ์—์„œ๋Š” ์‹คํ–‰ ๋ถˆ๊ฐ€)

5๋‹จ๊ณ„: ๋ช…๋ น์–ด ์‹คํ–‰ ์ค€๋น„ - run_builtin()

Section titled โ€œ5๋‹จ๊ณ„: ๋ช…๋ น์–ด ์‹คํ–‰ ์ค€๋น„ - run_builtin()โ€

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

git.c
static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
{
int status;
struct stat st;
const char *prefix;
/* ํ”Œ๋ž˜๊ทธ์— ๋”ฐ๋ฅธ ์‚ฌ์ „ ์ค€๋น„ ์ž‘์—… */
if (p->option & RUN_SETUP) {
/* Git ์ €์žฅ์†Œ์ธ์ง€ ํ™•์ธํ•˜๊ณ  ์„ค์ • ๋กœ๋“œ */
prefix = setup_git_directory();
}
if (p->option & NEED_WORK_TREE) {
/* ์ž‘์—… ํŠธ๋ฆฌ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธ */
if (!have_repository || is_bare_repository())
die(_("this operation must be run in a work tree"));
}
/* ์ถ”๊ฐ€ ํ™˜๊ฒฝ ์„ค์ • */
commit_pager_choice();
/* ๋“œ๋””์–ด! ์‹ค์ œ ๋ช…๋ น์–ด ํ•จ์ˆ˜ ํ˜ธ์ถœ */
status = p->fn(argc, argv, prefix, the_repository);
/* ์ •๋ฆฌ ์ž‘์—… */
if (status)
return status;
/* ์ง€์—ฐ๋œ ์ž‘์—…๋“ค ์ˆ˜ํ–‰ */
run_post_command_hook();
return 0;
}

์ด์ œ ๋“œ๋””์–ด builtin/merge.c์˜ cmd_merge() ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋ฉ๋‹ˆ๋‹ค:

builtin/merge.c
int cmd_merge(int argc,
const char **argv,
const char *prefix,
struct repository *repo)
{
/* ๋ณ‘ํ•ฉ ์ž‘์—… ์‹œ์ž‘! */
// ...
}

ํ•จ์ˆ˜ ๋งค๊ฐœ๋ณ€์ˆ˜์˜ ์˜๋ฏธ:

  • argc: ์ธ์ž ๊ฐœ์ˆ˜ (์›๋ž˜ ๋ช…๋ น์—์„œ โ€œgitโ€ ๋ถ€๋ถ„์€ ์ œ์™ธ)
  • argv: ์ธ์ž ๋ฐฐ์—ด (argv[0]์€ โ€œmergeโ€, argv[1]์€ โ€œfeatureโ€ ๊ฐ™์€ ๋ณ‘ํ•ฉ ๋Œ€์ƒ)
  • prefix: ํ˜„์žฌ ๋””๋ ‰ํ† ๋ฆฌ์˜ Git ์ €์žฅ์†Œ ๋ฃจํŠธ๋กœ๋ถ€ํ„ฐ์˜ ์ƒ๋Œ€ ๊ฒฝ๋กœ
  • repo: ์ €์žฅ์†Œ ์ •๋ณด๋ฅผ ๋‹ด์€ ๊ตฌ์กฐ์ฒด

์ „์ฒด ํ˜ธ์ถœ ์Šคํƒ ์š”์•ฝ

Section titled โ€œ์ „์ฒด ํ˜ธ์ถœ ์Šคํƒ ์š”์•ฝโ€

์‚ฌ์šฉ์ž๊ฐ€ git merge feature๋ฅผ ์ž…๋ ฅํ–ˆ์„ ๋•Œ์˜ ์ „์ฒด ํ˜ธ์ถœ ์Šคํƒ์„ ์ •๋ฆฌํ•˜๋ฉด:

1. ์‰˜ ํ”„๋กœ์„ธ์Šค
โ””โ”€> 2. git (main ํ•จ์ˆ˜)
โ””โ”€> 3. handle_builtin()
โ””โ”€> 4. get_builtin("merge")
โ””โ”€> 5. run_builtin()
โ””โ”€> 6. cmd_merge()

ํฅ๋ฏธ๋กœ์šด ์‚ฌ์‹ค๋“ค

Section titled โ€œํฅ๋ฏธ๋กœ์šด ์‚ฌ์‹ค๋“คโ€

Git์€ ๊ฐ ๋ช…๋ น์–ด๋ฅผ ๋…๋ฆฝ์ ์ธ ํ•จ์ˆ˜๋กœ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์žฅ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค:

  • ์œ ์ง€๋ณด์ˆ˜ ์šฉ์ด์„ฑ: ๊ฐ ๋ช…๋ น์–ด๋ฅผ ๋…๋ฆฝ์ ์œผ๋กœ ์ˆ˜์ • ๊ฐ€๋Šฅ
  • ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ์„ฑ: ๊ฐœ๋ณ„ ๋ช…๋ น์–ด๋ฅผ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ ๊ฐ€๋Šฅ
  • ํ™•์žฅ์„ฑ: ์ƒˆ๋กœ์šด ๋ช…๋ น์–ด ์ถ”๊ฐ€๊ฐ€ ์‰ฌ์›€

2. ํ”Œ๋ž˜๊ทธ ์‹œ์Šคํ…œ์˜ ์ง€ํ˜œ

Section titled โ€œ2. ํ”Œ๋ž˜๊ทธ ์‹œ์Šคํ…œ์˜ ์ง€ํ˜œโ€

๋ช…๋ น์–ด๋งˆ๋‹ค ๋‹ค๋ฅธ ์š”๊ตฌ์‚ฌํ•ญ์ด ์žˆ์Šต๋‹ˆ๋‹ค:

  • git init๋Š” ์ €์žฅ์†Œ๊ฐ€ ์—†์–ด๋„ ์‹คํ–‰ ๊ฐ€๋Šฅ (RUN_SETUP ์—†์Œ)
  • git merge๋Š” ์ž‘์—… ํŠธ๋ฆฌ๊ฐ€ ํ•„์š” (NEED_WORK_TREE)
  • git config๋Š” ์–ด๋””์„œ๋“  ์‹คํ–‰ ๊ฐ€๋Šฅ (ํŠน๋ณ„ํ•œ ํ”Œ๋ž˜๊ทธ ์—†์Œ)

3. ์™œ ์ด๋ ‡๊ฒŒ ๋ณต์žกํ• ๊นŒ?

Section titled โ€œ3. ์™œ ์ด๋ ‡๊ฒŒ ๋ณต์žกํ• ๊นŒ?โ€

์ด ๋ณต์žกํ•œ ๊ตฌ์กฐ๋Š” Git์˜ ์œ ์—ฐ์„ฑ์„ ์œ„ํ•ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค:

  • ๋‹ค์–‘ํ•œ ์‹คํ–‰ ํ™˜๊ฒฝ ์ง€์›: bare ์ €์žฅ์†Œ, ์ผ๋ฐ˜ ์ €์žฅ์†Œ, ์ €์žฅ์†Œ ์™ธ๋ถ€
  • ์ผ๊ด€๋œ ์—๋Ÿฌ ์ฒ˜๋ฆฌ: ๋ชจ๋“  ๋ช…๋ น์–ด๊ฐ€ ๋™์ผํ•œ ๊ฒ€์ฆ ๊ณผ์ •์„ ๊ฑฐ์นจ
  • ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ์•„ํ‚คํ…์ฒ˜: ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ถ”๊ฐ€๊ฐ€ ๊ธฐ์กด ์ฝ”๋“œ์— ๋ฏธ์น˜๋Š” ์˜ํ–ฅ ์ตœ์†Œํ™”

์ด ๊ณผ์ •์„ ๋” ๊นŠ์ด ์ดํ•ดํ•˜๋ ค๋ฉด:

  1. GDB๋กœ ์ถ”์ ํ•˜๊ธฐ:

    Terminal window
    gdb git
    break main
    run merge feature
    step
  2. strace๋กœ ์‹œ์Šคํ…œ ์ฝœ ๊ด€์ฐฐ:

    Terminal window
    strace -e trace=execve git merge feature
  3. Git ์†Œ์Šค ์ฝ”๋“œ ์ง์ ‘ ์ˆ˜์ •:

    • cmd_merge() ์‹œ์ž‘ ๋ถ€๋ถ„์— ๋””๋ฒ„๊ทธ ๋ฉ”์‹œ์ง€ ์ถ”๊ฐ€
    • Git์„ ๋‹ค์‹œ ์ปดํŒŒ์ผํ•˜๊ณ  ์‹คํ–‰ํ•ด๋ณด๊ธฐ

์ด๋ ‡๊ฒŒ Git CLI์—์„œ cmd_merge()๊นŒ์ง€์˜ ์—ฌ์ •์€ ๋‹จ์ˆœํ•ด ๋ณด์ด๋Š” ๋ช…๋ น ํ•˜๋‚˜๊ฐ€ ์‹ค์ œ๋กœ๋Š” ์—ฌ๋Ÿฌ ๊ณ„์ธต์˜ ์ถ”์ƒํ™”์™€ ๊ฒ€์ฆ์„ ๊ฑฐ์ณ ์‹คํ–‰๋œ๋‹ค๋Š” ๊ฒƒ์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ์ด๋Š” Git์ด ๋‹จ์ˆœํ•œ ๋„๊ตฌ๊ฐ€ ์•„๋‹ˆ๋ผ ์ •๊ตํ•˜๊ฒŒ ์„ค๊ณ„๋œ ์‹œ์Šคํ…œ์ž„์„ ์•Œ๋ ค์ค๋‹ˆ๋‹ค.