์—ฌ๋Ÿฌ interface ํƒ€์ž…์„ ์กฐ๊ฑด๋ณ„๋กœ ํ•˜๋‚˜์˜ ํƒ€์ž… ์•ˆ์—์„œ ์ •์˜ํ•˜๊ณ  ์‹ถ์„ ๋•Œ
export enum SearchType {
  FRUIT = โ€˜FRUITโ€™,
  FOOD = โ€˜FOODโ€™,
  CLOTHES = โ€˜CLOTHESโ€™,
  SHOES = โ€˜SHOESโ€™,
  BAGS = โ€˜BAGSโ€™,
}

type TypeName<T> = T extends SearchType.FRUIT
  ? FruitItem
  : T extends SearchType.FOOD
  ? FoodItem
  : T extends SearchType.CLOTHES
  ? ClothesItem
  : T extends SearchType.SHOES
  ? ShoesItem
  : BagsItem;


์‚ฌ์šฉ ์Šคํƒ ๋ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ: React, lodash

 

์–˜ ์ข€ ๊ท€์—ฝ๋„ค ์ฒธ์‹œ? ์ฒธ์„ธ์ด?

 
 

Debounce ์‚ฌ์šฉ ๋ชฉ์ : ๊ฒ€์ƒ‰์‹œ input์˜ onChange๋งˆ๋‹ค ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ debounce๋ฅผ ํ†ตํ•ด ๋ฐฉ์ง€

 

 

1. Input์˜ onChange๋ฅผ ํ†ตํ•œ api ํ˜ธ์ถœ

 
์•„๋ž˜ ํ•จ์ˆ˜๋ฅผ ์‚ดํŽด๋ณด์ž.
 

 
 
 
 
์ด ํ•จ์ˆ˜๋Š” input์— ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•  ๊ฒฝ์šฐ input์˜ onChange๋ฅผ ํ†ตํ•ด ํฌ์ผ“๋ชฌ์„ ์กฐํšŒํ•˜๋Š” api๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค.

input์˜ onChange๋Š” input์— ๊ฐ’์ด ์ž…๋ ฅ๋  ๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๊ธ€์ž ์ˆ˜ ๋งŒํผ handleSearch ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ์„ ์•„๋ž˜์—์„œ ๋ณผ ์ˆ˜ ์žˆ๋‹ค. (๊ฒ€์ƒ‰ ์„ฑ๋Šฅ ์ €ํ•˜)


 

 
 
์ด๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด lodash์˜ debounce ํ•จ์ˆ˜๋ฅผ ์ ์šฉํ•ด ๋ณผ ๊ฒƒ์ด๋‹ค.

๐Ÿ’กLodash๋ž€? A modern JavaScript utility library delivering modularity, performance & extras. (๊ณต์‹ ๋ฌธ์„œ์—์„œ ์ •์˜ํ•˜๊ณ  ์žˆ๋Š” lodash์˜ ์˜๋ฏธ์ด๋‹ค; ๋ชจ๋“ˆ์„ฑ, ์„ฑ๋Šฅ๊ณผ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ ๋“ฑ์„ ์ œ๊ณตํ•˜๋Š” ๋ชจ๋˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์œ ํ‹ธ๋ฆฌํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.)



2. Lodash์˜ debounce ์ ์šฉ

$ npm i -g npm //npm ์„ค์น˜ ์™„๋ฃŒ์‹œ ์ƒ๋žต
$ npm i --save lodash


์œ„ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด lodash๋ฅผ ์„ค์น˜ํ•œ๋‹ค.


 

Creates a debounced function that delays invoking func until after wait milliseconds have elapsed since the last time the debounced function was invoked.
 
 
 

import { debounce } from 'lodash';



ํ•„์š”ํ•œ ํ•จ์ˆ˜ debounce๋งŒ ๊ตฌ์กฐ๋ถ„ํ•ด๋กœ importํ•œ๋‹ค. (์ „์ฒด lodash๋ฅผ importํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ›จ์”ฌ ์ ๋‹ค)
 
 

   const getPokemon = debounce(async (value: string) => {
    await axios
      .get(`https://pokeapi.co/api/v2/pokemon/${value}`)
      .then((res) => {
        setPokemon(res);
      })
      .catch((err) => {
        return;
      });
  }, 300);

 
 
 
๊ทธ๋Ÿฐ ๋‹ค์Œ ๊ธฐ์กด getPokemon ํ•จ์ˆ˜๋ฅผ debounce ํ•จ์ˆ˜๋กœ ๊ฐ์‹ธ์ค€๋’ค ์ง€์—ฐ์‹œ๊ฐ„์„ ์ˆซ์ž๋กœ ์ ์–ด์ค€๋‹ค. (์œ„ ์˜ˆ์‹œ์—์„œ๋Š” 0.3์ดˆ๋กœ ์„ค์ •) 
 
 
์ด๋ ‡๊ฒŒ ํ•˜๋ฉด input์— ํƒ€์ดํ•‘์ด ๋˜๋”๋ผ๋„ ํ•จ์ˆ˜ ํ˜ธ์ถœ์„ 0.3์ดˆ๋งˆ๋‹ค ํ•˜๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.
 
 

 3. State ๋ณ€๊ฒฝ๊ณผ debounce ๋™์‹œ ์ ์šฉ

๊ทธ๋ ‡๋‹ค๋ฉด ๋งŒ์•ฝ state ๋ณ€๊ฒฝ๊ณผ debouce๋ฅผ ํ•จ๊ป˜ ํ˜ธ์ถœํ•  ๊ฒฝ์šฐ debounce๋Š” ํšจ๊ณผ์ ์œผ๋กœ ์ž‘๋™ํ• ๊นŒ?


์•„๋ž˜ handleSearch ํ•จ์ˆ˜๋Š” input์˜ onChange๊ฐ€ ํ˜ธ์ถœ๋  ๋•Œ๋งˆ๋‹ค(๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค) ์‹คํ–‰๋œ๋‹ค.

handleSearch๋‚ด์—์„œ setText๋ฅผ ํ†ตํ•ด ๋ณ€ํ•˜๋Š” input๊ฐ’์„ ๋™์‹œ์— ์ €์žฅํ•˜๊ณ , debounce๋ฅผ ํ†ตํ•ด api๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ํ•จ์ˆ˜๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค.
 

const getPokemon = debounce(async (value: string) => {
    await axios
      .get(`https://pokeapi.co/api/v2/pokemon/${value}`)
      .then((res) => {
        setPokemon(res);
      })
      .catch((err) => {
        return;
      });
  }, 300);

const handleSearch = (e) => {
  setText(e.target.value);
  getPokemon(e.target.value);
}



์œ„ ํ•จ์ˆ˜์—์„œ ๋ฌธ์ œ์ ์€ ์šฐ๋ฆฌ์˜ ์˜ˆ์ƒ๊ณผ ๋‹ค๋ฅด๊ฒŒ getPokemonํ•จ์ˆ˜๊ฐ€ 0.3์ดˆ๋งˆ๋‹ค๊ฐ€ ์•„๋‹Œ input์˜ value๊ฐ€ ๋ฐ”๋€”๋•Œ๋งˆ๋‹ค ํ˜ธ์ถœ๋œ๋‹ค๋Š” ์ ์ด๋‹ค.

์ด ์ฝ”๋“œ์˜ ๋ฌธ์ œ์ ์€ setText ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰ํ•  ๋•Œ๋งˆ๋‹ค ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์žฌ๋ Œ๋”๋ง๋˜์–ด debounceํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋Š” getPokemonํ•จ์ˆ˜๋ฅผ ์žฌ์ƒ์„ฑํ•œ๋‹ค๋Š” ์ ์ด๋‹ค.
 

 4. ์ปดํฌ๋„ŒํŠธ ์žฌ๋ Œ๋”๋ง์— ๊ด€๊ณ„์—†์ด debounce ํ•จ์ˆ˜ ์‹คํ–‰ํ•˜๊ธฐ

const getPokemon = useCallback(debounce(async (value: string) => {
    await axios
      .get(`https://pokeapi.co/api/v2/pokemon/${value}`)
      .then((res) => {
        setPokemon(res);
      })
      .catch((err) => {
        return;
      });
  }, 300),
  []
;

const handleSearch = (e) => {
  setText(e.target.value);
  getPokemon(e.target.value);
}


์ •๋‹ต์€ useCallback ํ•จ์ˆ˜๋กœ debounceํ•จ์ˆ˜๋ฅผ ๊ฐ์‹ธ์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

์œ„์˜ getPokemon ํ•จ์ˆ˜๋Š” handleSearch์—์„œ text๊ฐ€ ๋ณ€๊ฒฝ์ด ๋˜์–ด๋„ ์ด ๋ณ€์ˆ˜๋ฅผ ๊ตฌ๋…ํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— debounceํ•จ์ˆ˜๋ฅผ ์žฌ์ƒ์„ฑํ•˜์ง€ ์•Š๋Š”๋‹ค.



 

์›๋ฌธ: https://marmelab.com/blog/2024/01/23/react-19-new-hooks.html

 

 

์ผ๋ฐ˜์ ์ธ ์ƒ๊ฐ๊ณผ ๋‹ฌ๋ฆฌ React coreํŒ€์€ ๋ฆฌ์•กํŠธ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์™€ Next.js์—๋งŒ ์˜ค์ง ์ดˆ์ ์„ ๋‘์ง„ ์•Š๋Š”๋‹ค. ์ƒˆ๋กœ์šด client-side ํ›…๋“ค์ด ๋‹ค์Œ React ๋ฉ”์ธ ๋ฒ„์ „์ธ 19๋ฒ„์ „์— ๋„์ž…๋œ๋‹ค. ๊ทธ๋“ค์€ ๋ฆฌ์•กํŠธ์˜ ๋‘ ๊ฐ€์ง€ ์ฃผ์š” ๋ฌธ์ œ์ , ์ฆ‰ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ(data fetching)๊ณผ ํผ(form)์— ์ดˆ์ ์„ ๋งž์ถ”๊ณ  ์žˆ๋‹ค. ์ด ํ›…๋“ค์€ ์‹ฑ๊ธ€ ํŽ˜์ด์ง€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ž‘์—…์„ ํ•˜๋Š” ๊ฐœ๋ฐœ์ž๋ฅผ ํฌํ•จํ•ด React ๊ฐœ๋ฐœ์ž๋“ค์˜ ์ƒ์‚ฐ์„ฑ์„ ํ–ฅ์ƒ์‹œ์ผœ์ค„ ๊ฒƒ์ด๋‹ค.

 

๋” ์ด์ƒ ๊ณ ๋ฏผํ•˜์ง€ ๋ง๊ณ , ์ƒˆ๋กœ์šด ํ›…๋“ค์„ ์‚ดํŽด๋ณด์ž!

 

 

์ฃผ๋ชฉ: ์ด ํ›…๋“ค์€ React์˜ Canary์™€ ์‹คํ—˜์  ์ฑ„๋„์—์„œ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด ํ›…๋“ค์€ ๊ณง ์ถœ์‹œ๋  ๋ฆฌ์•กํŠธ 19์— ํฌํ•จ๋˜์ง€๋งŒ, API๋Š” ์ตœ์ข… ์ถœ์‹œ ์ „์— ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๋‹ค.

 

 

use(Promise)

 

์ด ์ƒˆ๋กœ์šด ํ›…์€ ํด๋ผ์ด์–ธํŠธ์˜ 'suspending'์„ ์œ„ํ•œ ๊ณต์‹ API์ด๋‹ค. ๋‹น์‹ ์€ ๊ทธ๊ฒƒ์„ promise๋กœ ๋„˜๊ธธ ์ˆ˜ ์žˆ๊ณ  ๋ฆฌ์•กํŠธ๋Š” ๊ทธ๊ฒƒ์ด ํ•ด๊ฒฐ๋  ๋•Œ๊นŒ์ง€ ๊ทธ๊ฒƒ์„ ์ค‘๋‹จ์‹œํ‚ฌ ๊ฒƒ์ด๋‹ค. React use ๋ฌธ์„œ์—์„œ ๊ฐ€์ ธ์˜จ ๊ธฐ๋ณธ ๊ตฌ๋ฌธ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

import { use } from 'react';

function MessageComponent({ messagePromise }) {
    const message = use(messagePromise);
    // ...
}

 

์ข‹์€ ์†Œ์‹์€ ์ด ํ›…์ด ๋ฐ์ดํ„ฐ ํŒจ์นญ์— ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์—ฌ๊ธฐ ๋งˆ์šดํŠธ์‹œ์™€ ๋ฒ„ํŠผ ํด๋ฆญ์‹œ ๋ฐ์ดํ„ฐ ํŒจ์นญ์„ ํ•˜๋Š” ๊ตฌ์ฒด์ ์ธ ์˜ˆ์‹œ๊ฐ€ ์žˆ๋‹ค. ์ด ์ฝ”๋“œ๋Š” ๋‹จ์ผ useEffect๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค:

 

 

 

<Suspense> ๋ฌธ์„œ์˜ ์ด ๊ฒฝ๊ณ ๋ฅผ ๊ธฐ์–ตํ•˜๋Š”๊ฐ€?

 

ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์˜๊ฒฌ ์—†๋Š” Suspense ์ง€์› ๋ฐ์ดํ„ฐ ํŒจ์นญ์€ ์•„์ง ์ง€์›๋˜์ง€ ์•Š๋Š”๋‹ค.

 

์ด๋Š” React19์—์„œ๋Š” ๋” ์ด์ƒ ์‚ฌ์‹ค์ด ์•„๋‹ˆ๋‹ค.

 

์ƒˆ๋กœ์šด use ํ›…์€ ์ˆจ๊ฒจ์ง„ ํž˜์ด ์žˆ๋‹ค: ๋‹ค๋ฅธ ๋ชจ๋“  React Hook๋“ค๊ณผ ๋‹ฌ๋ฆฌ, use๋Š” loop์™€ if์™€ ๊ฐ™์€ ์กฐ๊ฑด ์ ˆ์—์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ด ๋ง์ด ์ฆ‰, ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•ด TanStack Query์™€ ๊ฐ™์€ ์„œ๋“œํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋” ์ด์ƒ ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†์Œ์„ ์˜๋ฏธํ• ๊นŒ? TanStack Query๊ฐ€ ๋‹จ์ˆœํžˆ Promise๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ ์ด์ƒ์˜ ์—ญํ• ์„ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋” ๋‘๊ณ  ๋ด์•ผ ํ•œ๋‹ค.

 

ํ•˜์ง€๋งŒ ๊ทธ๊ฒƒ์€ ์˜ฌ๋ฐ”๋ฅธ ๋ฐฉํ–ฅ์œผ๋กœ ๋‚˜์•„๊ฐ€๋Š” ํ›Œ๋ฅญํ•œ ๋‹จ๊ณ„์ด๋ฉฐ REST ๋˜๋Š” GraphQL API๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ์‹ฑ๊ธ€ ํŽ˜์ด์ง€ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‰ฝ๊ฒŒ ๋งŒ๋“ค ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค. ๋‚˜๋Š” ์ด ์ƒˆ๋กœ์šด ํ›…์— ๋งค์šฐ ์—ด๊ด‘ํ•œ๋‹ค!

 

React ๋ฌธ์„œ์—์„œ use(Promise) ํ›…์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์ฝ์–ด๋ณด์•„๋ผ.

 

use(Context)

React Context๋ฅผ ์ฝ๋Š”๋ฐ ๊ฐ™์€ use ํ›…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ฃจํ”„ ์•ˆ์—์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ if์™€ ๊ฐ™์€ ์กฐ๊ฑด๋ฌธ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์„ ์ œ์™ธํ•˜๋ฉด ์ด๋Š” ์ •ํ™•ํžˆ useContext์™€ ๊ฐ™๋‹ค.

 

 

import { use } from 'react';

function HorizontalRule({ show }) {
    if (show) {
        const theme = use(ThemeContext);
        return <hr className={theme} />;
    }
    return false;
}

 

๋ฃจํ”„ ํ˜น์€ ์กฐ๊ฑด์ ˆ์—์„œ ์ปจํ…์ŠคํŠธ๋ฅผ ์ฝ๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‘˜๋กœ ๋‚˜๋ˆ„๋Š” ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด๊ฒƒ์€ ์ผ๋ถ€ ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋Œ€ํ•œ ์ปดํฌ๋„ŒํŠธ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๋‹จ์ˆœํ™”ํ•  ๊ฒƒ์ด๋‹ค.

 

์ปจํ…์ŠคํŠธ๊ฐ€ ๋ฐ”๋€Œ์—ˆ๋”๋ผ๋„ ์ปดํฌ๋„ŒํŠธ์˜ ๋ฆฌ๋ Œ๋”๋ง์„ ์กฐ๊ฑด์ ์œผ๋กœ ๊ฑด๋„ˆ๋›ธ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์„ฑ๋Šฅ ์ธก๋ฉด์—์„œ๋„ ํฐ ํ˜๋ช…์ด ๋  ์ˆ˜ ์žˆ๋‹ค.

 

React ๋ฌธ์„œ์—์„œ use(Context) ํ›…์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์ฝ์–ด๋ณด์•„๋ผ.

 

Form Actions

 

์ด ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ํ•จ์ˆ˜๋ฅผ <form>์˜ ์•ก์…˜ ํ”„๋กญ์— ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ๋‹ค. ํผ์ด ์ œ์ถœ๋˜๋ฉด React๋Š” ์ด ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•œ๋‹ค:

 

 

 

 

๋งŒ์•ฝ ๋‹น์‹ ์ด <form action> ํ”„๋กญ์„ React18์—์„œ ์ถ”๊ฐ€ํ•œ๋‹ค๋ฉด ๋‹น์‹ ์€ ๊ฒฝ๊ณ (warning)๋ฅผ ๋ฐ›๊ฒŒ ๋  ๊ฒƒ์„ ๊ธฐ์–ตํ•˜๋ผ:

 

Warning: Invalid value for prop action on <form> tag. Either remove it from the element or pass a string or number value to keep it in the DOM.

 

๋‹ค์Œ๊ณผ ๊ฐ™์€ form์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ๋Š” React 19์—์„œ ์ด ๊ฒฝ๊ณ ๋Š” ๋” ์ด์ƒ ์‚ฌ์‹ค์ด ์•„๋‹ˆ๋‹ค.

 

import { useState } from 'react';

const AddToCartForm = ({ id, title, addToCart }) => {
  const formAction = async (formData) => {
    try {
      await addToCart(formData, title);
    } catch (e) {
      // show error notification
    }
  };

  return (
    <form action={formAction}>
      <h2>{title}</h2>
      <input type="hidden" name="itemID" value={id} />
      <button type="submit">Add to Cart</button>
    </form>
  );
};

type Item = {
  id: string;
  title: string;
};

const Cart = ({ cart }: { cart: Item[] }) => {
  if (cart.length == 0) {
    return null;
  }
  return (
    <>
      Cart content:
      <ul>
        {cart.map((item, index) => (
          <li key={index}>{item.title}</li>
        ))}
      </ul>
      <hr />
    </>
  );
};

export const App = () => {
  const [cart, setCart] = useState<Item[]>([]);

  const addToCart = async (formData: FormData, title) => {
    const id = String(formData.get('itemID'));
    // simulate an AJAX call
    await new Promise((resolve) => setTimeout(resolve, 1000));
    setCart((cart: Item[]) => [...cart, { id, title }]);

    return { id };
  };

  return (
    <>
      <Cart cart={cart} />
      <AddToCartForm
        id="1"
        title="JavaScript: The Definitive Guide"
        addToCart={addToCart}
      />
      <AddToCartForm
        id="2"
        title="JavaScript: The Good Parts"
        addToCart={addToCart}
      />
    </>
  );
};

 

accToCart ํ•จ์ˆ˜๋Š” ์„œ๋ฒ„ Action์ด ์•„๋‹ˆ๋‹ค. ์ด๊ฒƒ์€ ํด๋ผ์ด์–ธํŠธ ์ธก์—์„œ ํ˜ธ์ถœ๋˜๋ฉฐ ๋น„๋™๊ธฐ ๊ธฐ๋Šฅ์ผ ์ˆ˜ ์žˆ๋‹ค.

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ๋ฆฌ์•กํŠธ์—์„œ ๊ฒ€์ƒ‰ ํผ๊ณผ ๊ฐ™์€ AJAX ํผ์˜ ์ฒ˜๋ฆฌ๊ฐ€ ํฌ๊ฒŒ ๊ฐ„๋‹จํ•ด์งˆ ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์€ ์–‘์‹ ์ œ์ถœ(์œ ํšจ์„ฑ ํ™•์ธ, ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ ๋“ฑ)์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๊ฒƒ ์ด์ƒ์˜ ์ผ์„ ํ•˜๋Š” React Hook Form๊ณผ ๊ฐ™์€ ์„œ๋“œํŒŒํ‹ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์—†์•จ๋งŒํผ ์ถฉ๋ถ„ํ•˜์ง€ ์•Š์„ ์ˆ˜ ์žˆ๋‹ค. 

 

Tip: ๋‹น์‹ ์€ ์œ„ ์˜ˆ์ œ์—์„œ ๋ช‡๋ช‡ ์‚ฌ์šฉ์„ฑ ๋ฌธ์ œ๋ฅผ ๋ฐœ๊ฒฌํ•  ์ˆ˜ ์žˆ๋‹ค. (submit์„ ์ง„ํ–‰ํ•  ๋•Œ submit ๋ฒ„ํŠผ์ด ํ™œ์„ฑํ™”๋˜์ง€ ์•Š์Œ, ํ™•์ธ ๋ฉ”์„ธ์ง€ ๋ˆ„๋ฝ, ๋Šฆ์€ ์นดํŠธ ์—…๋ฐ์ดํŠธ). ๋‹คํ–‰ํžˆ๋„ ๋” ๋งŽ์€ ํ›…๋“ค์ด ์ด๋Ÿฌํ•œ ์‚ฌ์šฉ ์‚ฌ๋ก€๋ฅผ ๋•๊ธฐ ์œ„ํ•ด ์ œ๊ณต๋˜๊ณ  ์žˆ๋‹ค. ๊ณ„์† ์ฝ์–ด๋ณด๊ธธ!

 

 

React ๋ฌธ์„œ์—์„œ the <form action> prop์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์ฝ์–ด๋ณด์•„๋ผ.

 

 

useFormState

 

์ด ์ƒˆ๋กœ์šด ํ›…์€ ์•„๋ž˜ ๋ฌ˜์‚ฌํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ๋น„๋™๊ธฐ ํผ ์•ก์…˜์„ ๋•๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. useFormState๋ฅผ ํ˜ธ์ถœํ•ด ํผ์ด ์ œ์ถœ๋œ ๋งˆ์ง€๋ง‰ ์‹œ์ ๋ถ€ํ„ฐ ์•ก์…˜์˜ ๋ฐ˜ํ™˜ ๊ฐ’์— ์ ‘๊ทผํ•œ๋‹ค.

 

import { useFormState } from 'react-dom';
import { action } from './action';

function MyComponent() {
    const [state, formAction] = useFormState(action, null);
    // ...
    return <form action={formAction}>{/* ... */}</form>;
}

 

 

์˜ˆ๋ฅผ ๋“ค์–ด, ์ด๊ฒƒ์€ ๋‹น์‹ ์ด ํผ ์•ก์…˜์—์„œ ๋ฐ˜ํ™˜๋œ ํ™•์ธ ํ˜น์€ ์—๋Ÿฌ ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด์—ฌ์ฃผ๊ฒŒ ํ•œ๋‹ค.

 

import { useState } from 'react';
import { useFormState } from 'react-dom';

const AddToCartForm = ({ id, title, addToCart }) => {
  const addToCartAction = async (prevState, formData) => {
    try {
      await addToCart(formData, title);
      return 'Added to cart';
    } catch (e) {
      return "Couldn't add to cart: the item is sold out.";
    }
  };

  const [message, formAction] = useFormState(addToCartAction, null);

  return (
    <form action={formAction}>
      <h2>{title}</h2>
      <input type="hidden" name="itemID" value={id} />
      <button type="submit">Add to Cart</button>&nbsp;
      {message}
    </form>
  );
};

type Item = {
  id: string;
  title: string;
};

export const App = () => {
  const [cart, setCart] = useState<Item[]>([]);

  const addToCart = async (formData: FormData, title) => {
    const id = String(formData.get('itemID'));
    // simulate an AJAX call
    await new Promise((resolve) => setTimeout(resolve, 1000));
    if (id === '1') {
      setCart((cart: Item[]) => [...cart, { id, title }]);
    } else {
      throw new Error('Unavailable');
    }

    return { id };
  };

  return (
    <>
      <AddToCartForm
        id="1"
        title="JavaScript: The Definitive Guide"
        addToCart={addToCart}
      />
      <AddToCartForm
        id="2"
        title="JavaScript: The Good Parts"
        addToCart={addToCart}
      />
    </>
  );
};

 

 

์ฃผ๋ชฉ: useFormState๋Š” react๊ฐ€ ์•„๋‹ˆ๋ผ react-dom์—์„œ ๋ถ€ํ„ฐ import๋˜์–ด์•ผ ํ•œ๋‹ค.

 

 

React ๋ฌธ์„œ์—์„œ useFormState์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์ฝ์–ด๋ณด์•„๋ผ.

 

 

 

useFormStatus

 

useFormStatus๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ถ€๋ชจ <form>์ด ํ˜„์žฌ ์ œ์ถœ ์ค‘์ด๊ฑฐ๋‚˜ ์„ฑ๊ณต์ ์œผ๋กœ ์ œ์ถœํ–ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์žˆ๋‹ค. ํผ์˜ ์ž์‹์—์„œ ํ˜ธ์ถœํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ๋‹ค์Œ ์†์„ฑ์„ ๊ฐ€์ง„ ๊ฐœ์ฒด๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค:

 

const { pending, data, method, action } = useFormStatus();

 

 

๋‹น์‹ ์€ ๋ฐ์ดํ„ฐ ์†์„ฑ์„ ํ†ตํ•ด ์œ ์ €๊ฐ€ ์ œ์ถœ ์ค‘์ธ ๋ฐ์ดํ„ฐ๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค. ํผ์ด ์ œ์ถœ๋˜๋Š” ๋™์•ˆ ๋ฒ„ํŠผ์ด ๋น„ํ™œ์„ฑํ™”๋œ pending ์ƒํƒœ ๋˜ํ•œ ์•„๋ž˜ ์˜ˆ์‹œ์™€ ๊ฐ™์ด ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค:

 

import { useState } from 'react';
import { useFormStatus } from 'react-dom';

const AddToCartForm = ({ id, title, addToCart }) => {
  const formAction = async (formData) => {
    try {
      await addToCart(formData, title);
    } catch (e) {
      // show error notification
    }
  };

  return (
    <form action={formAction}>
      <h2>{title}</h2>
      <input type="hidden" name="itemID" value={id} />
      <SubmitButton />
    </form>
  );
};

const SubmitButton = () => {
  const { pending } = useFormStatus();
  return (
    <button disabled={pending} type="submit">
      Add to Cart
    </button>
  );
};

type Item = {
  id: string;
  title: string;
};

const Cart = ({ cart }: { cart: Item[] }) => {
  if (cart.length == 0) {
    return null;
  }
  return (
    <>
      Cart content:
      <ul>
        {cart.map((item, index) => (
          <li key={index}>{item.title}</li>
        ))}
      </ul>
      <hr />
    </>
  );
};

export const App = () => {
  const [cart, setCart] = useState<Item[]>([]);

  const addToCart = async (formData: FormData, title) => {
    const id = String(formData.get('itemID'));
    // simulate an AJAX call
    await new Promise((resolve) => setTimeout(resolve, 1000));
    setCart((cart: Item[]) => [...cart, { id, title }]);

    return { id };
  };

  return (
    <>
      <Cart cart={cart} />
      <AddToCartForm
        id="1"
        title="JavaScript: The Definitive Guide"
        addToCart={addToCart}
      />
      <AddToCartForm
        id="2"
        title="JavaScript: The Good Parts"
        addToCart={addToCart}
      />
    </>
  );
};

 

 

์ฃผ๋ชฉ: useFormStatus๋Š” react๊ฐ€ ์•„๋‹Œ react-dom์—์„œ importํ•ด์•ผ ํ•œ๋‹ค. ๋˜ํ•œ ๋ถ€๋ชจ ํผ์ด ์œ„์—์„œ ์„ค๋ช…ํ•œ action prop์„ ์‚ฌ์šฉํ•  ๋•Œ๋งŒ ์ž‘๋™ํ•œ๋‹ค.

 

์ด ํ›…์€ useFormState์™€ ํ•จ๊ป˜ ๋ถˆํ•„์š”ํ•œ ์ปจํ…์ŠคํŠธ ํšจ๊ณผ๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์–ด์ˆ˜์„ ํ•˜๊ฒŒ ๋งŒ๋“ค์ง€ ์•Š๊ณ  ํด๋ผ์ด์–ธํŠธ ์ธก ํผ์˜ ์œ ์ € ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚ฌ ๊ฒƒ์ด๋‹ค. useFormStatus ํ›„ํฌ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ React ๋ฌธ์„œ์—์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

useOptimistic

 

์ด ์ƒˆ๋กœ์šด ํ›…์€ actioin์ด ์ œ์ถœ๋˜๋Š” ๋™์•ˆ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ตœ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. 

 

 

import { useOptimistic } from 'react';

function AppContainer() {
    const [optimisticState, addOptimistic] = useOptimistic(
        state,
        // updateFn
        (currentState, optimisticValue) => {
            // merge and return new state
            // with optimistic value
        },
    );
}

 

 

์œ„ ์นดํŠธ ์˜ˆ์ œ์—์„œ ์šฐ๋ฆฌ๋Š” AJAX ํ˜ธ์ถœ์ด ์™„๋ฃŒ๋˜๊ธฐ ์ „์— ์ƒˆ ํ•ญ๋ชฉ์ด ์ถ”๊ฐ€๋œ ์นดํŠธ๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ๋‹ค: 

 

import { useState, useOptimistic } from 'react';

const AddToCartForm = ({ id, title, addToCart, optimisticAddToCart }) => {
  const formAction = async (formData) => {
    optimisticAddToCart({ id, title });
    try {
      await addToCart(formData, title);
    } catch (e) {
      // show error notification
    }
  };

  return (
    <form action={formAction}>
      <h2>{title}</h2>
      <input type="hidden" name="itemID" value={id} />
      <button type="submit">Add to Cart</button>
    </form>
  );
};

type Item = {
  id: string;
  title: string;
};

const Cart = ({ cart }: { cart: Item[] }) => {
  if (cart.length == 0) {
    return null;
  }
  return (
    <>
      Cart content:
      <ul>
        {cart.map((item, index) => (
          <li key={index}>{item.title}</li>
        ))}
      </ul>
      <hr />
    </>
  );
};

export const App = () => {
  const [cart, setCart] = useState<Item[]>([]);

  const [optimisticCart, optimisticAddToCart] = useOptimistic<Item[], Item>(
    cart,
    (state, item) => [...state, item]
  );

  const addToCart = async (formData: FormData, title) => {
    const id = String(formData.get('itemID'));
    // simulate an AJAX call
    await new Promise((resolve) => setTimeout(resolve, 1000));
    setCart((cart: Item[]) => [...cart, { id, title }]);

    return { id };
  };

  return (
    <>
      <Cart cart={optimisticCart} />
      <AddToCartForm
        id="1"
        title="JavaScript: The Definitive Guide"
        addToCart={addToCart}
        optimisticAddToCart={optimisticAddToCart}
      />
      <AddToCartForm
        id="2"
        title="JavaScript: The Good Parts"
        addToCart={addToCart}
        optimisticAddToCart={optimisticAddToCart}
      />
    </>
  );
};

 

 

UI๋ฅผ ์ตœ์ ์œผ๋กœ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฒƒ์€ ์›น ์•ฑ์˜ ์œ ์ € ๊ฒฝํ—˜์„ ํ–ฅ์ƒ์‹œํ‚ค๋Š” ์ข‹์€ ๋ฐฉ๋ฒ•์ด๋‹ค. ์ด ํ›…์€ ์ด ์‚ฌ์šฉ ์‚ฌ๋ก€์— ๋งŽ์€ ๋„์›€์ด ๋œ๋‹ค. useOptimistic์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์€ React ๋ฌธ์„œ์—์„œ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.

 

 

๋ณด๋„ˆ์Šค: ๋น„๋™๊ธฐ ์ „ํ™˜

React์˜ Transition API๋Š” UI ์ฐจ๋‹จ์—†์ด ์ƒํƒœ๋ฅผ ์—…๋ฐ์ดํŠธํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž๊ฐ€ ๋งˆ์Œ์„ ๋ฐ”๊ฟ€ ๊ฒฝ์šฐ ์ด์ „ ์ƒํƒœ ๋ณ€๊ฒฝ์„ ์ทจ์†Œํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ด ์•„์ด๋””์–ด๋Š” startTransition๋ฅผ ํ˜ธ์ถœํ•ด ์ƒํƒœ ๋ณ€ํ™”๋ฅผ ๊ฐ์‹ผ๋‹ค.

 

function TabContainer() {
    const [isPending, startTransition] = useTransition();
    const [tab, setTab] = useState('about');

    function selectTab(nextTab) {
        // instead of setTab(nextTab), put the state change in a transition
        startTransition(() => {
            setTab(nextTab);
        });
    }
    // ...
}

 

๋‹ค์Œ ์˜ˆ๋Š” ์ด Transition API๋ฅผ ์‚ฌ์šฉํ•œ ํƒญ ๋„ค๋น„๊ฒŒ์ด์…˜์„ ๋ณด์—ฌ์ค€๋‹ค. "Posts"์„ ํด๋ฆญํ•œ ๋‹ค์Œ ์ฆ‰์‹œ "Contact"๋ฅผ ํด๋ฆญํ•œ๋‹ค. ์ด๋กœ ์ธํ•ด "Posts"์˜ ๋Š๋ฆฐ ๋ Œ๋”๋ง์ด ์ค‘๋‹จ๋œ๋‹ค. "Contact" ํƒญ์ด ์ฆ‰์‹œ ํ‘œ์‹œ๋œ๋‹ค. ์ด ์ƒํƒœ ์—…๋ฐ์ดํŠธ๋Š” ํŠธ๋žœ์ง€์…˜์œผ๋กœ ํ‘œ์‹œ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋Š๋ฆฐ ๋ฆฌ๋ Œ๋”(re-render)๋Š” ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ต์ œํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

import { useState, useTransition } from 'react';
import TabButton from './TabButton';
import AboutTab from './AboutTab';
import PostsTab from './PostsTab';
import ContactTab from './ContactTab';

export function App() {
  const [isPending, startTransition] = useTransition();
  const [tab, setTab] = useState('about');

  function selectTab(nextTab) {
    startTransition(() => {
      setTab(nextTab);
    });
  }

  return (
    <>
      <TabButton isActive={tab === 'about'} onClick={() => selectTab('about')}>
        About
      </TabButton>
      <TabButton isActive={tab === 'posts'} onClick={() => selectTab('posts')}>
        Posts (slow)
      </TabButton>
      <TabButton
        isActive={tab === 'contact'}
        onClick={() => selectTab('contact')}
      >
        Contact
      </TabButton>
      <hr />
      {tab === 'about' && <AboutTab />}
      {tab === 'posts' && <PostsTab />}
      {tab === 'contact' && <ContactTab />}
    </>
  );
}

 

 

React 18.2์—์„œ๋Š” Transition ํ›…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. React 19์˜ ์ƒˆ๋กœ์šด ์ ์€ ์ด์ œ ๋น„๋™๊ธฐ ๊ธฐ๋Šฅ์„ ์ง€๋‚˜ Transition์„ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, React๋Š” Transition์„ ์‹œ์ž‘ํ•˜๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๊ณ  ์žˆ๋‹ค.

 

์ด๋Š” AJAX ํ˜ธ์ถœ์„ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์ œ์ถœํ•˜๊ณ  ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ํŠธ๋žœ์ง€์…˜์œผ๋กœ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐ ์œ ์šฉํ•˜๋‹ค. ํŠธ๋žœ์ง€์…˜์˜ pending ์ƒํƒœ๋Š” ๋น„๋™๊ธฐ ๋ฐ์ดํ„ฐ ์ œ์ถœ๊ณผ ํ•จ๊ป˜ ์‹œ์ž‘๋œ๋‹ค. ์ด๋Š” ์œ„์—์„œ ์„ค๋ช…ํ•œ ํผ actions ๊ธฐ๋Šฅ์—์„œ ์ด๋ฏธ ์‚ฌ์šฉ๋˜๊ณ  ์žˆ๋‹ค. React๊ฐ€ startTransition์œผ๋กœ ๊ฐ์‹ธ์ง„ <form action> ํ•ธ๋“ค๋Ÿฌ๋ฅผ ํ˜ธ์ถœํ•˜์—ฌ ํ˜„์žฌ ํŽ˜์ด์ง€๋ฅผ ์ฐจ๋‹จํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

 

์ด ๊ธฐ๋Šฅ์€ ์•„์ง React ์„ค๋ช…์„œ์— ๋ฌธ์„œํ™”๋˜์–ด ์žˆ์ง€ ์•Š์ง€๋งŒ pull request์—์„œ ์ด ๊ธฐ๋Šฅ์— ๋Œ€ํ•œ ์ž์„ธํ•œ ๋‚ด์šฉ์„ ์ฝ์„ ์ˆ˜ ์žˆ๋‹ค.

 

๊ฒฐ๋ก 

์ด๋Ÿฌํ•œ ๋ชจ๋“  ๊ธฐ๋Šฅ๋“ค์€ ํด๋ผ์ด์–ธํŠธ ์ „์šฉ์ธ ๋ฆฌ์•กํŠธ ์•ฑ์—์„œ ์ž‘๋™ํ•˜๋ฉฐ, Vite์™€ ํ•จ๊ป˜ ๋ฒˆ๋“ค๋œ ์•ฑ์—์„œ ์ž‘๋™ํ•œ๋‹ค. ๋น„๋ก ์„œ๋ฒ„ ํ†ตํ•ฉํ˜• ๋ฆฌ์•กํŠธ ์•ฑ์—์„œ๋„ ์ด๊ฒƒ์ด ์ž‘๋™ํ•˜์ง€๋งŒ ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด Next ํ˜น์€ Remix์™€ ๊ฐ™์€ SSR ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†๋‹ค. 

 

์ด๋Ÿฌํ•œ ๊ธฐ๋Šฅ์„ ํ†ตํ•ด ๋ฆฌ์•กํŠธ์—์„œ ๋ฐ์ดํ„ฐ ํŒจ์นญ๊ณผ ํผ์„ ๊ตฌํ˜„ํ•˜๊ธฐ๊ฐ€ ํ›จ์”ฌ ์‰ฌ์›Œ์ง„๋‹ค. ํ•˜์ง€๋งŒ ํ›Œ๋ฅญํ•œ ์œ ์ € ๊ฒฝํ—˜์„ ๋งŒ๋“ค๋ ค๋ฉด ์ด ๋ชจ๋“  ํ›…๋ฅผ ํ†ตํ•ฉํ•ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๋Š” ๋ณต์žกํ•  ์ˆ˜ ์žˆ๋‹ค. ๋˜๋Š” ์ตœ์ ์˜ ๋นŒํŠธ์ธ ์—…๋ฐ์ดํŠธ๋ฅผ ์ง€์›ํ•˜๋Š” ์‚ฌ์šฉ์ž ์นœํ™”์ ์ธ ํผ์„ ๊ฐ€์ง„ react-admin๊ณผ ๊ฐ™์€ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

์ด ๊ธฐ๋Šฅ๋“ค์€ ์™œ React 18.3์ด ์•„๋‹Œ React 19์— ๋„์ž…๋˜๋Š” ๊ฒƒ์ผ๊นŒ? ์ด ๊ธฐ๋Šฅ๋“ค์—๋Š” ์•ฝ๊ฐ„์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ํฌํ•จ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์— 18.3 release์—๋Š” ์—†์„ ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค.

 

React 19๋Š” ์–ธ์ œ ์˜ฌ ๊ฒƒ์ธ๊ฐ€ ? ์•„์ง ETA๋Š” ์—†์ง€๋งŒ ์ด ๊ฒŒ์‹œ๋ฌผ์— ์–ธ๊ธ‰๋œ ๋ชจ๋“  ๊ธฐ๋Šฅ์€ ์ด๋ฏธ ์ž‘๋™ํ•˜๊ณ  ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์•„์ง ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•˜๊ณ  ์‹ถ์ง€๋Š” ์•Š๋‹ค. (Next.js๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ํ•œ๋‹ค๊ณ  ํ•ด๋„) canary release๋ฅผ ํ”„๋กœ๋•ํŠธ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์€ ์ข‹์€ ์ƒ๊ฐ์ด ์•„๋‹ˆ๋‹ค.

 

๋ฆฌ์•กํŠธ ์ฝ”์–ด ํŒ€์ด SSR ์•ฑ์—์„œ ์ผํ•˜๋Š” ์‚ฌ๋žŒ๋“ค๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ชจ๋“  ๋ฆฌ์•กํŠธ ๊ฐœ๋ฐœ์ž๋“ค์˜ ๊ฐœ๋ฐœ์ž ๊ฒฝํ—˜์„ ๊ฐœ์„ ํ•˜๊ธฐ ์œ„ํ•ด ๋…ธ๋ ฅํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ์ •๋ง ๊ธฐ์œ ์ผ์ด๋‹ค. ๋˜ํ•œ ๊ทธ๋“ค์€ ์ปค๋ฎค๋‹ˆํ‹ฐ ํ”ผ๋“œ๋ฐฑ์— ๊ท€๋ฅผ ๊ธฐ์šธ์ด๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™๋‹ค - ๋ฐ์ดํ„ฐ ํŒจ์นญ ๋ฐ ํผ ํ•ธ๋“ค๋ง์€ ๋งค์šฐ ํ”ํ•œ ๋ฌธ์ œ์ด๋‹ค.

 

๋‚˜๋Š” React์˜ Stable ๋ฆด๋ฆฌ์ฆˆ์— ์ด ๊ธฐ๋Šฅ๋“ค์ด ๋ณด์ด๊ธธ ๊ธฐ๋Œ€ํ•œ๋‹ค!

 

์›๋ฌธ:  https://dev.to/reenatoteixeira/everything-that-you-need-to-know-about-git-2440

 

 
 
๋‚˜๋Š” ๋‹น์‹ ์ด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋˜๋Œ๋ฆฌ๊ณ  ์†์‹ค๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต๊ตฌํ•  ์ˆ˜ ์žˆ๋„๋ก ์ฝ”๋“œ ๋ฒ„์ „์˜ ์ค‘์š”์„ฑ์„ ์ƒ๊ฐํ•  ๊ฒƒ์ด๋ผ๊ณ  ํ™•์‹ ํ•œ๋‹ค. ์ฐฝ์˜์ ์ธ ์ด๋ฆ„์œผ๋กœ ํŒŒ์ผ ๋ณต์‚ฌ๋ณธ์„ ๋งŒ๋“ค์–ด ๊ฐ€๋ฉฐ ๋ฒ„์ „ ๊ด€๋ฆฌ๋ฅผ ํ•˜๋Š” ๋ˆ„๊ตฐ๊ฐ€(์ €๋Š” ์•„๋‹˜)๋ฅผ ์•Œ ๊ฑฐ๋ผ๊ณ  ์ƒ๊ฐํ•œ๋‹ค..
 

 
์ด๊ฒƒ์€ ์•„๋งˆ๋„ 1972๋…„ ์ด์ „์— ์ฒ˜์Œ์œผ๋กœ ์ค‘์•™ ์ง‘์ค‘์‹ ๋ฒ„์ „ ์ œ์–ด ์†Œํ”„ํŠธ์›จ์–ด ์ค‘ ํ•˜๋‚˜์ธ SCCS(Source Code Control System)๊ฐ€ ์ถœ์‹œ๋˜๋ฉด์„œ ๋ˆ„๊ตฌ๋‚˜ ์ž์‹ ์˜ ์ฝ”๋“œ๋กœ ๋ฒ„์ „ ์ œ์–ด๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด์—ˆ์„ ๊ฒƒ์ด๋‹ค. 
 
๊ทธ๋Ÿฌ๋‚˜ ์šฐ๋ฆฌ๋Š” ์—ฌ๊ธฐ์„œ SCSS๋ฅผ ์–˜๊ธฐํ•˜๋ ค๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ, ์šฐ๋ฆฌ๊ฐ€ ๊ฐ€์žฅ ๊ด€์‹ฌ์žˆ์–ด ํ•˜๋Š” ๊ฒƒ์€ ๋‚ด๋…„(07/04/2005)์— 20์ฃผ๋…„์„ ๋งž๋Š” ๋ถ„์‚ฐํ˜• ์˜คํ”ˆ์†Œ์Šค ๋ฒ„์ „ ์ œ์–ด ์†Œํ”„ํŠธ์›จ์–ด์ธ GIT์ด๋‹ค. 
 

๋ชฉ์ฐจ

 

1. GIT์ด๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

 

GIT์€ ๋ฆฌ๋ˆ…์Šค ์ปค๋„ ์ œ์ž‘์ž์ธ Linus Torvald์ด ๊ฐœ๋ฐœํ•œ 2005๋…„์— ์ถœ์‹œ๋œ ๋ถ„์‚ฐํ˜• ์˜คํ”ˆ์†Œ์Šค ๋ฒ„์ „ ๊ด€๋ฆฌ ์‹œ์Šคํ…œ์ด๋‹ค. 
 
GIT์„ ํ†ตํ•ด ์šฐ๋ฆฌ๋Š” ํ”„๋กœ์ ํŠธ์˜ ๋ฒ„์ „์„ ์ „์—ญ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ณ (์ž‘์—…ํ•˜๋Š” ํด๋”์—์„œ) ๋ชจ๋“  ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋ฆฌ๋ชจํŠธ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์™€ ์‹ฑํฌ๋ฅผ ๋งž์ถœ ์ˆ˜ ์žˆ๋‹ค(์˜ˆ๋ฅผ ๋“ค์–ด GitHub์—์„œ). 

 



 

2. GIT์€ ์–ด๋–ป๊ฒŒ  ์ž‘๋™ํ• ๊นŒ?

 

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

๊ทธ๋Ÿฌ๋‚˜ ์ด๊ฒƒ์ด GIT์ด ์ž‘๋™ํ•˜๋Š” ๋ฐฉ์‹์€ ์•„๋‹ˆ๋‹ค! (thanks God)

 

์ด๊ฒƒ์€ ์ค‘์•™ ์ง‘์ค‘๋œ ๋ฒ„์ „ ์ปจํŠธ๋กค ์‹œ์Šคํ…œ์ด ์ž‘๋™๋˜๋Š” ๋ฐฉ์‹์œผ๋กœ, ์‚ฌ์šฉ์ž๋Š” ํŒŒ์ผ์„ 'check-out(์ฒดํฌ์•„์›ƒ)'ํ•˜๊ณ  'check-in(์ฒดํฌ์ธ)'ํ•ด์•ผ ํ•œ๋‹ค. ํŠน์ • ํŒŒ์ผ์— ๋Œ€ํ•œ ์ž‘์—…์ด ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค ํ•ด๋‹น ํŒŒ์ผ์„ ์ฒดํฌ์•„์›ƒํ•˜์—ฌ ์ €์žฅ์†Œ์—์„œ ์ œ๊ฑฐํ•œ ๋‹ค์Œ ์ž‘์—…์ด ์™„๋ฃŒ๋˜๋ฉด ํŒŒ์ผ์„ ์ฒดํฌ์ธํ•˜์—ฌ ์ €์žฅ์†Œ๋กœ ๋ฐ˜ํ™˜ํ•ด์•ผ ํ•œ๋‹ค.


 
GIT๊ฐ™์€ ๋ถ„์‚ฐํ˜• ์‹œ์Šคํ…œ์—์„œ๋Š” ๊ฐ™์€ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์˜ ํŒŒ์ผ์— ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ๋“ค์ด ๋™์‹œ์— ํŒŒ์ผ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ํŒŒ์ผ์„ ์กฐ์ž‘ํ•  ๋•Œ๋งˆ๋‹ค ํŒŒ์ผ์„ ๋กœ์ปฌ๋กœ ๋ณต์ œ(๋˜๋Š” ์ „์ฒด ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ๋ณต์ œ)ํ•œ ๋‹ค์Œ ์ˆ˜์ •์‚ฌํ•ญ์„ ์›๊ฒฉ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋กœ ๋‹ค์‹œ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์—ฌ๋Ÿฌ ์‚ฌ๋žŒ์ด ๋™์ผํ•œ ํŒŒ์ผ์„ ์กฐ์ž‘ํ•˜๋ฉด์„œ ๋™์ผํ•œ ํ”„๋กœ์ ํŠธ์—์„œ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋‹ค.


์ด๊ฒƒ์€ ์„ธ๊ณ„ ์—ฌ๋Ÿฌ ์ง€์—ญ์˜ ์‚ฌ๋žŒ๋“ค์ด ๊ฐ™์€ ํ”„๋กœ์ ํŠธ์—์„œ ์ž‘์—…ํ•˜๊ณ  ์ˆ˜์ • ๋ฐ ๋ฐœ์ƒ ๊ฐ€๋Šฅํ•œ ์ถฉ๋Œ์„ ๊ด€๋ฆฌํ•˜๋Š” ๋Œ€๊ทœ๋ชจ ์˜คํ”ˆ ์†Œ์Šค ํ”„๋กœ์ ํŠธ์˜ ๋ฐฐํฌ๋ฅผ ํ—ˆ์šฉํ•œ๋‹ค(์—ฌ๊ธฐ์„œ ๋ณ‘ํ•ฉ ์ถฉ๋Œ(merge conflicts)์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค).


3. GIT ์„ค์น˜ํ•˜๊ธฐ


GIT์€ ๋งค์šฐ ๊ฐ„๋‹จํ•œ ์„ค์น˜ ํ”„๋กœ์„ธ์Šค๋ฅผ ํ†ตํ•ด ์ฃผ์š” ์šด์˜ ์ฒด์ œ(Windows, Linux, MacOs...)์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ด๋Š” ๋ช…๋ น์ค„์ด๋‚˜ git-scm.com ์˜ ๊ณต์‹ ์„ค์น˜ ํ”„๋กœ๊ทธ๋žจ์„ ํ†ตํ•ด ์„ค์น˜๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

3.1 ์œˆ๋„์šฐ์—์„œ ์„ค์น˜ํ•˜๊ธฐ


์œˆ๋„์šฐ์— GIT๋ฅผ ์„ค์น˜ํ•˜๋ ค๋ฉด ๊ณต์‹ ์›น์‚ฌ์ดํŠธ์— ๋“ค์–ด๊ฐ€์„œ ์„ค์น˜ ํ”„๋กœ๊ทธ๋žจ์„ ๋‹ค์šด๋กœ๋“œํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋‚˜์„œ ์ง€์‹œ์‚ฌํ•ญ์„ ๋”ฐ๋ผ๊ฐ€๋ฉด ๋ชจ๋“  ๊ฒƒ์ด ์ž˜ ๋  ๊ฒƒ์ด๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ๋Š” ํ„ฐ๋ฏธ๋„์—์„œ GIT ๋ช…๋ น์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

3.2 ๋ฆฌ๋ˆ…์Šค์—์„œ ์„ค์น˜ํ•˜๊ธฐ


๋ฆฌ๋ˆ…์Šค์˜ ๊ฒฝ์šฐ๋Š” ์•„๋ž˜ ๋ช…๋ น์„ ์‚ฌ์šฉํ•ด GIT๋ฅผ ์„ค์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค:

sudo apt install git-all


์ด ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด GIT์ด ์šฐ๋ฆฌ์˜ ํ„ฐ๋ฏธ๋„์—์„œ ์‹คํ–‰๋  ์ค€๋น„๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค.

3.3 Mac์—์„œ ์„ค์น˜ํ•˜๊ธฐ


Mac์˜ ๊ฒฝ์šฐ GIT๋ฅผ ์„ค์น˜ํ•˜๋Š” ๊ฐ€์žฅ ์‰ฌ์šด ๋ฐฉ๋ฒ•์€ Homebrew๋ฅผ ์„ค์น˜ํ•œ ๋‹ค์Œ ํ„ฐ๋ฏธ๋„์—์„œ ์•„๋ž˜ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์ด๋‹ค:
 

brew install git

 
์ด ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด GIT์ด ์šฐ๋ฆฌ์˜ ํ„ฐ๋ฏธ๋„์—์„œ ์‹คํ–‰๋  ์ค€๋น„๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค.


4. GIT ๊ตฌ์„ฑํ•˜๊ธฐ

 
์„ค์น˜ํ•œ ํ›„์—๋Š” ์•„๋ž˜ ์‹คํ–‰์„ ํ†ตํ•ด GIT์„ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค:

git config --global user.name "[username]"
# e.g. John Doe
git config --global user. email "[email@email.com]"
# e.g. johndoe@email.com


 

๋˜ํ•œ --global ํƒœ๊ทธ๋ฅผ ์ œ๊ฑฐํ•˜์—ฌ ํŠน์ • ๋กœ์ปฌ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์— ๋Œ€ํ•œ ํŠน์ • ์‚ฌ์šฉ์ž๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 


 5. ๋กœ์ปฌ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ์‹œ์ž‘ํ•˜๊ธฐ

 
GIT์ด ๊ตฌ์„ฑ๋˜๋ฉด ๋กœ์ปฌ ์ €์žฅ์†Œ๋ฅผ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ์ƒˆ ์ €์žฅ์†Œ๋ฅผ ์ฒ˜์Œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๊ฑฐ๋‚˜ ๊ธฐ์กด ์›๊ฒฉ ์ €์žฅ์†Œ๋ฅผ ๋ณต์ œํ•  ์ˆ˜ ์žˆ๋‹ค.

5.1 ์ฒ˜์Œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•˜๊ธฐ(git init)


์ƒˆ ๋ ˆํฌ์ง€ํ† ๋ฆฌ๋ฅผ ์‹œ์ž‘ํ•˜๋ ค๋ฉด ์›ํ•˜๋Š” ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋ฃจํŠธ ํด๋”๋กœ ์ด๋™ํ•˜๊ณ  ์•„๋ž˜ ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

git init

 

 

์ด๋ฅผ ํ†ตํ•ด ํ”„๋กœ์ ํŠธ ํด๋”์—  .git ๋””๋ ‰ํ† ๋ฆฌ๊ฐ€ ์ƒ์„ฑ๋˜๋ฉฐ, ์ด ๋””๋ ‰ํ† ๋ฆฌ๋Š” ๋กœ์ปฌ ์ €์žฅ์†Œ์˜ ์ž‘์—… ํด๋”์˜ ๋ฒ„์ „ ์ปจํŠธ๋กค์„ ๋‹ด๋‹นํ•œ๋‹ค. 

 

5.2 ๊ธฐ์กด ๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋ณต์ œํ•˜๊ธฐ(git clone)

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

 

git clone [repository-url]

 

 

๊ทธ๋ฆฌ๊ณ  ๋‚˜๋ฉด ์ „์ฒด ๋ ˆํฌ์ง€ํ† ๋ฆฌ๊ฐ€ ์šฐ๋ฆฌ์˜ ๋กœ์ปฌ ์ €์žฅ์†Œ์— ๋ณต์ œ๋  ๊ฒƒ์ด๊ณ  ์ž๋™์œผ๋กœ ์—ฐ๊ด€๋œ ์›๊ฒฝ ์ €์žฅ์†Œ์™€ ์—ฐ๊ฒฐ๋  ๊ฒƒ์ด๋‹ค.

 

๋ ˆํฌ์ง€ํ† ๋ฆฌ ๋ณต์ œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋”์ด์ƒ git remote ๋ช…๋ น์–ด๋ฅผ ๋ฏธ๋ž˜์— ์‚ฌ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ๋œปํ•œ๋‹ค.

 


 

6. GIT์œผ๋กœ ์ž‘์—…ํ•˜๊ธฐ

์šฐ๋ฆฌ์˜ ๋กœ์ปฌ ์ €์žฅ์†Œ์—์„œ ์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์— ํ•„์š”ํ•œ ํŒŒ์ผ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ์ง€๋งŒ ๊ทธ ํŒŒ์ผ๋“ค์ด ์ž๋™์œผ๋กœ GIT์— ์˜ํ•ด ๋™๊ธฐํ™”๋˜์ง€๋Š” ์•Š์„ ๊ฒƒ์ด๋‹ค. ์šฐ๋ฆฌ๋Š” ๋ฒ„์ „ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ์ƒ๊ธธ ๊ฒฝ์šฐ GIT์— ๋ณด๊ณ ํ•ด์•ผ ํ•œ๋‹ค.

 

๊ทธ๋Ÿฌ๋ฏ€๋กœ ์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ๊ฐ€ ์›ํ•˜๋Š” ๋Œ€๋กœ ํŒŒ์ผ์„ ์กฐ์ž‘ํ•˜๊ณ  ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ˆ˜์ •ํ•œ ํ›„์—๋Š” ๊นƒ์— ์ˆ˜์ •๋œ ํŒŒ์ผ์„ ๋ณด๋‚ธ๋‹ค.

 

์ด๋ฅผ ์œ„ํ•ด ๋ฒ„์ „ ์ปจํŠธ๋กค์— 3๋‹จ๊ณ„์˜ ๋ฌดํ•œ ํ”Œ๋กœ์šฐ๊ฐ€ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

 

 MODIFY -> STAGE -> COMMIT

 

 

  • MODIFY(์ˆ˜์ • ๋‹จ๊ณ„): ๋ฒ„์ „ ์ปจํŠธ๋กค์˜ ์ฒซ ๋ฒˆ์งธ ์ž‘์—…์€ MODIFY์ด๋‹ค. ์—ฌ๊ธฐ์„œ๋Š” ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋งˆ์ง€๋ง‰ ๋ฒ„์ „๊ณผ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝ๋œ ํŒŒ์ผ์„ ์ฐพ๋Š”๋‹ค.
  • STAGE(์Šคํ…Œ์ด์ง€ ๋‹จ๊ณ„): ๋‘ ๋ฒˆ์งธ stage ๋‹จ๊ณ„์—์„œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋‹ค์Œ ์ปค๋ฐ‹์— ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์€ ํŒŒ์ผ์„ ์ˆ˜์ •๋œ ํŒŒ์ผ์— ์œ„์น˜ ์‹œํ‚จ๋‹ค.
  • COMMIT(์ปค๋ฐ‹ ๋‹จ๊ณ„): ๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„์ธ commit ๋‹จ๊ณ„์—์„œ๋Š” ์šฐ๋ฆฌ๊ฐ€ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํ™•์ธํ•  ๋•Œ ์Šคํ…Œ์ด์ง€์˜ ์ˆ˜์ •๋œ ํŒŒ์ผ์„ ๋กœ์ปฌ ์ €์žฅ์†Œ์— ๋ณด๋‚ธ๋‹ค.

 

์ˆ˜์ •๋œ ํŒŒ์ผ๋“ค์„ ์ปค๋ฐ‹ํ•œ ํ›„์—๋Š” ๋กœ์ปฌ ์ €์žฅ์†Œ์—์„œ ์ƒˆ๋กœ์šด ๋ฒ„์ „์„ ๊ฐ€์ง€๊ฒŒ ๋˜๋ฉฐ, ๋‹ค์‹œ ์—…๋ฐ์ดํŠธ ์‚ฌํ•ญ๋“ค์„ ๋ฐ›๊ณ  ํ•œ ๋ฒˆ ๋” '์ˆ˜์ •'ํ•˜๊ณ  '์Šคํ…Œ์ด์ง€'์— ์œ„์น˜์‹œํ‚ค๊ณ  ๋‹ค์‹œ '์ปค๋ฐ‹'ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ ์ƒˆ๋กœ์šด ๋ฒ„์ „์„ ํ™•์ธํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. (๊ทธ๋ž˜์„œ '๋ฌดํ•œ' ํ”Œ๋กœ์šฐ๋ผ๊ณ  ํ•œ ๊ฒƒ ใ…Žใ…Ž)

 

์ปค๋ฐ‹์€ ์ˆ˜์ •๋œ ํŒŒ์ผ์˜ ์ด์ „ ๋ฒ„์ „์„ ๋ฎ์–ด์“ฐ์ง€ ์•Š์œผ๋ฉฐ, ๋งˆ์ง€๋ง‰ ๋ฒ„์ „์— ๋Œ€ํ•œ ํฌ์ธํ„ฐ๊ฐ€ ์žˆ๋Š” ์ƒˆ ๋ฒ„์ „์„ ํฌํ•จํ•˜๋ฏ€๋กœ GIT์— ์˜ํ•ด ํŠธ๋ž˜ํ‚น๋˜๋Š” ๊ฐ ํŒŒ์ผ์˜ ๋ฒ„์ „์„ ์ถ”์ ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

 

6.1 ์ถ”๊ฐ€ํ•˜๊ณ  ์ปค๋ฐ‹ํ•˜๊ธฐ(git add์™€ git commit)

๋ณต์žกํ•˜๊ฒŒ ๋“ค๋ฆด์ง€ ๋ชจ๋ฅด์ง€๋งŒ, ๋ฒ„์ „ ์ œ์–ด ํ๋ฆ„์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๋‹ค๋‹ค. ์›ํ•˜๋Š” ์ˆ˜์ •์ด ์™„๋ฃŒ๋˜์—ˆ์œผ๋ฏ€๋กœ, ์šฐ๋ฆฌ๋Š” ์•„๋ž˜ ๋ช…๋ น์œผ๋กœ ์ปค๋ฐ‹ํ•˜๊ณ ์ž ํ•˜๋Š” ๋‹จ๊ณ„์— ์ˆ˜์ •๋œ ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•œ๋‹ค:

git add [filename]

 

git add -A : ๋ชจ๋“  ์ˆ˜์ •๋œ ํŒŒ์ผ์„ ์Šคํ…Œ์ด์ง€์— ํ•œ ๋ฒˆ์— ์ถ”๊ฐ€
git add *. [extensão-do-arquivo] : ํŠน์ • ์ต์Šคํ…์…˜ ํŒŒ์ผ์˜ ์ˆ˜์ •๋œ ํŒŒ์ผ์„ ์Šคํ…Œ์ด์ง€์— ํ•œ ๋ฒˆ์— ์ถ”๊ฐ€ (git add *.html ๊ณผ ๊ฐ™์ด)

 

 

์šฐ๋ฆฌ๋Š” git status ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ์–ธ์ œ๋“ ์ง€ ํ˜„์žฌ ๋กœ์ปฌ ์ €์žฅ์†Œ ์ƒํƒœ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค:

 

 

์ƒˆ ํŒŒ์ผ์„ ๋งŒ๋“  ํ›„ ์ €์žฅ์†Œ ๋‚ด์—์„œ git status๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ƒˆ ํŒŒ์ผ์ด "Untracked(์ถ”์ ๋˜์ง€ ์•Š์Œ)"์œผ๋กœ ํ‘œ์‹œ๋œ๋‹ค. ์ฆ‰, ์ด ํŒŒ์ผ์€ ์ƒˆ๋กœ์šด ๊ฒƒ์ด๋ฉฐ GIT์— ์˜ํ•ด ์ถ”์ ๋˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์–ด๋–ค ์ปค๋ฐ‹์—๋ผ๋„ ์ถ”๊ฐ€๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

 

GIT๊ฐ€ ์ €์žฅ์†Œ ๋‚ด์˜ ํŠน์ • ํŒŒ์ผ์ด๋‚˜ ํด๋”๋ฅผ ๋ฌด์‹œํ•˜๋„๋ก ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„œ๋Š” ๋ฃจํŠธ ํด๋”์— .gitignore๋ผ๋Š” ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๊ณ , ๊ทธ ์•ˆ์—์„œ ๋ฌด์‹œํ•ด์•ผ ํ•  ํŒŒ์ผ์ด๋‚˜ ํด๋”์˜ ์ด๋ฆ„์„ ์ ์œผ๋ฉด ๋œ๋‹ค.

์ฃผ์˜: ๋ฌด์‹œ๋œ ํŒŒ์ผ๊ณผ ํด๋”๋Š” ๋” ์ด์ƒ GIT ํŠธ๋ž™์— ๋‚˜ํƒ€๋‚˜์ง€ ์•Š์œผ๋ฉฐ, ์‹ฌ์ง€์–ด "Untracked"๋กœ๋„ ํ‘œ์‹œ๋˜์ง€ ์•Š๋Š”๋‹ค. ์ถ”์ ์„ ์žฌ์„ค์ •ํ•˜๋ ค๋ฉด .gitignore ํŒŒ์ผ์—์„œ ์›ํ•˜๋Š” ์ด๋ฆ„์„ ์‚ญ์ œํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค.

 

 

ํŒŒ์ผ์„ ํฌํ•จํ•˜๊ธฐ ์œ„ํ•ด git add ๋ช…๋ น์„ ์ถ”๊ฐ€ํ•  ํŒŒ์ผ์˜ ์ด๋ฆ„("index.html")์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค:

 

 

 

์ด๋Ÿฌํ•œ ๋ฐฉ์‹์œผ๋กœ git status ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋ฉด ์ƒˆ ํŒŒ์ผ์ด "stage"์— ์ถ”๊ฐ€๋˜์—ˆ์œผ๋ฉฐ ์ตœ์ข…์ ์œผ๋กœ ๋‹ค์Œ ์ปค๋ฐ‹์—์„œ ๋ณด๋‚ผ ์ค€๋น„๊ฐ€ ๋˜์—ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ๊ณ , ์ด๋Š” ์•„๋ž˜ ๋ช…๋ น์„ ํ†ตํ•ด ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค:

 

git commit -m "[descriptive-message]"

 

์ปค๋ฐ‹์€ ๊ณ ์œ  ID(ํ•ด์‹œ ์ฝ”๋“œ)๋ฅผ ๊ฐ€์ง€๋ฉฐ, ๋ณ€๊ฒฝํ•  ์ˆ˜ ์—†๋‹ค. ์ฆ‰, ์ปค๋ฐ‹์€ ํ™•์ธ๋˜๋ฉด ์ˆ˜์ •ํ•  ์ˆ˜ ์—†๋‹ค.

git commit -a: ์ง์ ‘ ์ปค๋ฐ‹์„ ์ˆ˜ํ–‰ํ•˜๋ฉฐ ๋ชจ๋“  ์ˆ˜์ •๋œ ํŒŒ์ผ์„ ์Šคํ…Œ์ด์ง€์— ์ถ”๊ฐ€ํ•˜๊ณ  ์ปค๋ฐ‹ํ•œ๋‹ค.

 

ํŒŒ์ผ์„ ์„ฑ๊ณต์ ์œผ๋กœ ์ปค๋ฐ‹ํ•œ ํ›„ git status๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹์„ ํ†ตํ•ด ๋ชจ๋“  ์ˆ˜์ • ์‚ฌํ•ญ์ด ๋กœ์ปฌ ์ €์žฅ์†Œ์— ํšจ๊ณผ์ ์œผ๋กœ ์ €์žฅ๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋” ์ด์ƒ ์—…๋กœ๋“œํ•  ์ˆ˜์ •๋œ ํŒŒ์ผ์ด ์—†์Œ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

 

๋˜ํ•œ ํ•ด์‹œ ์ฝ”๋“œ, ๋ธŒ๋žœ์น˜, ์ž‘์„ฑ์ž, ๋‚ ์งœ ๋“ฑ ๋ชจ๋“  ์ปค๋ฐ‹์˜ ์ผ๋ถ€ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ฃผ๋Š” git log ๋ช…๋ น์„ ์‚ฌ์šฉํ•ด ์ €์žฅ์†Œ์˜ ์ปค๋ฐ‹ ๋กœ๊ทธ๋ฅผ ๊ฒ€ํ† ํ•ด ๋ณ€๊ฒฝํ•œ ๋‚ด์šฉ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

์ด ๋ชจ๋“  ๊ณผ์ •์„ ๋ฐ˜๋ณตํ•˜์—ฌ ํ”„๋กœ์ ํŠธ์— ํ•„์š”ํ•œ ์ƒˆ ํŒŒ์ผ์„ ์ถ”๊ฐ€ํ•˜๊ณ  ์ˆ˜์ •ํ•œ ํ›„ ์ƒˆ๋กœ์šด ์ปค๋ฐ‹์„ ๋งŒ๋“ค์–ด ๋กœ์ปฌ ์ €์žฅ์†Œ๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๋‹ค.

 

 

git log -N : ๋งˆ์ง€๋ง‰ N๊ฐœ์˜ ์ปค๋ฐ‹์ด ํฌํ•จ๋œ log๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.
git log [branch-A] [branch-B]: "branch-B"์—๋Š” ์žˆ์ง€๋งŒ "A"์—๋Š” ์—†๋Š” ์ปค๋ฐ‹ ๋กœ๊ทธ๋ฅผ ํ‘œ์‹œํ•œ๋‹ค.
git log --follow [filename]: ํŒŒ์ผ์˜ ์ด๋ฆ„์„ ๋ณ€๊ฒฝํ•œ ๊ฒฝ์šฐ์—๋„ ์ง€์ •ํ•œ ํŒŒ์ผ์„ ๋ณ€๊ฒฝํ•œ ์ปค๋ฐ‹ ๋กœ๊ทธ๋ฅผ ํ‘œ์‹œํ•œ๋‹ค.
git diff: ์ €์žฅ์†Œ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์ตœ์‹  ๋ฒ„์ „๊ณผ ๋น„๊ตํ•˜์—ฌ ๋ณ€๊ฒฝํ•œ ๋‚ด์šฉ์„ ๋‚˜์—ดํ•œ๋‹ค.
git diff [nome-do-arquivo]: ์ €์žฅ์†Œ์—์„œ ๋งˆ์ง€๋ง‰์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฒ„์ „๊ณผ ๊ด€๋ จํ•˜์—ฌ ์ง€์ •๋œ ํŒŒ์ผ์— ๋Œ€ํ•ด ์ˆ˜ํ–‰ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋‚˜์—ดํ•œ๋‹ค.

 

6.2 ์ปค๋ฐ‹ ์ „๊ณผ ํ›„์—์„œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ ์ทจ์†Œํ•˜๊ธฐ

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

 

๊ทธ๋Ÿฌ๋‚˜ ๋ณ€๊ฒฝ์„ ์ทจ์†Œํ•˜๋Š” ์ƒˆ๋กœ์šด ์ปค๋ฐ‹์„ ๋งŒ๋“ค๊ฑฐ๋‚˜ ์ด์ „ ์ปค๋ฐ‹์—์„œ ์ž˜๋ชป๋œ ์ •๋ณด๋ฅผ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์–ด๋Š ์ชฝ์ด๋“  ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ ๋ช…๋ น ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค:

 

git checkout -- [filename]
# ์ปค๋ฐ‹ ์ „์— ๋กœ์ปฌ ํŒŒ์ผ์— ๋Œ€ํ•œ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ํ๊ธฐ(๋Œ์ดํ‚ฌ ์ˆ˜ ์—†๋Š” ์ž‘์—…)

 

git reset --hard HEAD
# ์Šคํ…Œ์ด์ง€ ๋‹จ๊ณ„(์ปค๋ฐ‹ ์ „)์— ์žˆ๋Š” ํŒŒ์ผ์˜ ๋ณ€๊ฒฝ ๋‚ด์šฉ์„ ํ๊ธฐ

 

git reset --hard HEAD~1
# ๋กœ์ปฌ ๋ฆฌํฌ์ง€ํ† ๋ฆฌ์—์„œ ์ˆ˜ํ–‰ํ•œ ๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹์„ ํ๊ธฐ(๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹๋งŒ ํ•ด๋‹น)

 

git commit --amend
# ๋กœ์ปฌ ์ €์žฅ์†Œ์—์„œ ์ˆ˜ํ–‰ํ•œ ๋งˆ์ง€๋ง‰ ์ปค๋ฐ‹์„ ๋Œ€์ฒดํ•˜์—ฌ ์ƒˆ ์ปค๋ฐ‹์„ ์ž‘์„ฑ

 

git revert [commit-hash]
# ์ง€์ •ํ•œ ์ปค๋ฐ‹์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋˜๋Œ๋ฆฌ๋Š” ์ƒˆ ์ปค๋ฐ‹์„ ์ž‘์„ฑ

 


 

7. ๋ธŒ๋žœ์น˜์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ธฐ

๋ธŒ๋žœ์น˜๋Š” ์ €์žฅ์†Œ์˜ ๊ฐ€์ง€์น˜๊ธฐ(ramification)์— ์ง€๋‚˜์ง€ ์•Š์œผ๋ฉฐ, ์ง€๊ธˆ๊นŒ์ง€ ๋ชจ๋“  ์ž‘์—…์€ ๋ธŒ๋žœ์น˜ 'master/main'์—์„œ ์ˆ˜ํ–‰๋˜์—ˆ๋‹ค. 

 

๊ธฐ๋ณธ์ ์œผ๋กœ ๋ ˆํฌ์ง€ํ† ๋ฆฌ์— ์ƒ์„ฑ๋œ ์ฒซ ๋ฒˆ์งธ ๋ธŒ๋žœ์น˜๋Š” ๋ ˆํฌ์ง€ํ† ๋ฆฌ์˜ ๋ฉ”์ธ ๋ธŒ๋žœ์น˜์ธ master/main ์ด๋‹ค.

 

7.1 ์™œ ๋ธŒ๋žœ์น˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฐ€?

์ฒ˜์Œ์—๋Š” ๋ณ„๊ฒƒ ์•„๋‹Œ ๊ฒƒ์ฒ˜๋Ÿผ ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ ๋ธŒ๋žœ์น˜๋Š” ํ”„๋กœ์ ํŠธ ๊ฐœ๋ฐœ์— ๋ง‰๋Œ€ํ•œ ํŒŒ์›Œ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค.

 

์šฐ๋ฆฌ๊ฐ€ ์›น ํ”Œ๋žซํผ์„ ๊ฐœ๋ฐœํ•˜๊ณ  ์žˆ๊ณ , ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜๊ณ  ์‹ถ์ง€๋งŒ, ์šฐ๋ฆฌ์˜ ์ €์žฅ์†Œ๋Š” ์ด๋ฏธ ํ˜ธ์ŠคํŠธ๋˜์—ˆ๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค๊ณผ ๊ณต์œ ํ•˜๊ณ  ์žˆ๊ณ , ์–ด๋–ค ๋ฌธ์ œ๊ฐ€ ์žˆ๋Š” ๋ณ€๊ฒฝ๋“ค์ด ๊ทธ๊ฒƒ๋“ค์—๊ฒŒ ๋‚˜์œ ๊ฒฝํ—˜์„ ์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด๋ผ. ์ด ์ƒํ™ฉ์—์„œ ์šฐ๋ฆฌ๋Š” ๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ์„๊นŒ?

 

ํ”„๋กœ์ ํŠธ ํด๋”๋ฅผ ๋ณต์‚ฌํ•˜์—ฌ ๋ถ™์—ฌ๋„ฃ๊ณ  ์ƒˆ๋กœ์šด "ํ…Œ์ŠคํŠธ ๋ฒ„์ „"์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์— ๋Œ€ํ•ด ์ƒ๊ฐํ•ด๋ณธ ์ ์ด ์žˆ๋‹ค๋ฉด, ๋งž๋Š” ๋ง์ด๋‹ค! ์Œ, ๊ฑฐ์˜...

 

GIT๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด, ์šฐ๋ฆฌ๋Š” ๋ธŒ๋žœ์น˜๋“ค๋กœ ๋น„์Šทํ•œ ์ผ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ๋ธŒ๋žœ์น˜์ด๊ธฐ ๋•Œ๋ฌธ์—, ์šฐ๋ฆฌ๋Š” ๋‹จ์ˆœํžˆ "ํ…Œ์ŠคํŠธ"๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ์ƒˆ๋กœ์šด ๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ ํ”„๋กœ์ ํŠธ์˜ ๋ฒ„์ „์„ ์™„์ „ํžˆ ๊ณ ๋ฆฝ๋œ ๋ธŒ๋žœ์น˜์—์„œ, main ๋ธŒ๋žœ์น˜์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ๋ฐ”๊ฟ€ ์ค€๋น„๋ฅผ ํ•œ๋‹ค.

 

 

 

7.2 ๋ธŒ๋žœ์น˜ ๋งŒ๋“ค๊ธฐ (git branch)

๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์€ master/main ๋ธŒ๋žœ์น˜์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ๋…๋ฆฝ์ ์œผ๋กœ ์ž‘์—…ํ•  ์ˆ˜ ์žˆ๋Š” ์ €์žฅ์†Œ์˜ ๋ณ‘๋ ฌ ๋ณต์‚ฌ๋ณธ์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด์„œ ์šฐ๋ฆฌ๋Š” ๋‹จ์ˆœํžˆ ์•„๋ž˜์˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ๋œ๋‹ค:

 

git branch [branch-name]

 

 

ํŠน์ • ๋ธŒ๋žœ์น˜์˜ ์ด๋ฆ„ ์—†์ด git branch ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ ค๋ฉด ์ €์žฅ์†Œ์— ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ธŒ๋žœ์น˜ ๋ชฉ๋ก์„ ํ‘œ์‹œํ•˜๋ฉฐ, "*"์˜ ํ‘œ์‹œ๋Š” ํ˜„์žฌ ์‚ฌ์šฉ ์ค‘์ธ ๋ธŒ๋žœ์น˜๋ฅผ ๋‚˜ํƒ€๋‚ธ๋‹ค.

 

git branch test ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๊ธฐ ์ „์— git branch ๋ช…๋ น์€ master ๋ธŒ๋žœ์น˜๋งŒ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

git checkout [branch-name]

 

git checkout test ๋ช…๋ น์„ ์‹คํ–‰ํ•œ ํ›„ ํ™œ์„ฑ ๋ธŒ๋žœ์น˜๊ฐ€ ์ „ํ™˜๋˜๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ทธ ์ˆœ๊ฐ„๋ถ€ํ„ฐ ๋ชจ๋“  ์ปค๋ฐ‹๋œ ์ •๋ณด๋Š” ๋ธŒ๋žœ์น˜ master/main ์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๊ณ  ์ €์žฅ์†Œ์˜ test ๋ธŒ๋žœ์น˜๋กœ ์ „์†ก๋œ๋‹ค.

 

 

ํ•„์š”ํ•œ ๋งŒํผ์˜ ๋ธŒ๋žœ์น˜๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์•„๋ž˜ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ์กด ๋ธŒ๋žœ์น˜์™€ ์ƒํ˜ธ ์ž‘์šฉํ•  ์ˆ˜ ์žˆ๋‹ค:

git checkout -b [branch-name]
 -> ์ง€์ •๋œ ์ด๋ฆ„์œผ๋กœ ์ƒˆ ๋ธŒ๋žœ์น˜๋ฅผ ๋งŒ๋“ค๊ณ  ์ง์ ‘ ๊ทธ ๋ธŒ๋žœ์น˜๋กœ ์ „ํ™˜ํ•œ๋‹ค.
git branch -d [branch-name] -> ์ง€์ •ํ•œ branch๋ฅผ ์‚ญ์ œํ•œ๋‹ค.
git branch -m [new-name] -> ํ˜„์žฌ branch์˜ ์ด๋ฆ„์„ ์ง€์ •๋œ ์ด๋ฆ„์œผ๋กœ ๋ณ€๊ฒฝํ•œ๋‹ค.

 

 

7.3 ๋ธŒ๋žœ์น˜ ๋ณ‘ํ•ฉํ•˜๊ธฐ(git merge)

๋‹ค๋ฅธ ๋ธŒ๋žœ์น˜ ์ž‘์—…์„ ์™„๋ฃŒํ•˜๊ณ  ๋ณ€๊ฒฝํ•œ ๋‚ด์šฉ์ด ํ”„๋กœ์ ํŠธ์— ๋ฌธ์ œ๋ฅผ ์ผ์œผํ‚ค์ง€ ์•Š์•˜๋‹ค๊ณ  ํ™•์‹ ํ•œ๋‹ค๋ฉด, ํ˜„์žฌ ๋ธŒ๋žœ์น˜์˜ ๋ชจ๋“  ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ ์šฉํ•˜์—ฌ master/main ๋ธŒ๋žœ์น˜๋กœ ๋ณ‘ํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค

 

๋ธŒ๋žœ์น˜๋ฅผ ๋ณ‘ํ•ฉํ•˜๋ ค๋ฉด ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋ฐ›์„ ๋ธŒ๋žœ์น˜๋กœ ์ „ํ™˜ํ•˜๊ณ  ๋‹ค์Œ ๋ช…๋ น์„ ์‹คํ–‰ํ•ด์•ผ ํ•œ๋‹ค.

 

git merge [branch-name]
# ์ง€์ •๋œ ๋ธŒ๋žœ์น˜๋ฅผ ํ˜„์žฌ ํ™œ์„ฑ๋œ ๋ธŒ๋žœ์น˜๋กœ ๋ณ‘ํ•ฉ

 

์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๋Š” branch 'test'์— ์žˆ๊ธฐ ๋•Œ๋ฌธ์— git checkout ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด master ๋ธŒ๋žœ์น˜๋กœ ์ „ํ™˜ํ•ด์•ผ ํ•˜๋ฉฐ git merge ๋ช…๋ น์–ด๋ฅผ ๋ณ‘ํ•ฉํ•˜๊ณ  ์‹ถ์€ ๋ธŒ๋žœ์น˜ ์ด๋ฆ„๊ณผ ํ•จ๊ป˜ ์‹คํ–‰ํ•ด์•ผ ํ•œ๋‹ค. (์—ฌ๊ธฐ์„œ๋Š” 'test')

 

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด test ๋ธŒ๋žœ์น˜์—์„œ ์ˆ˜ํ–‰๋œ ๋ชจ๋“  ์ž‘์—…(์ด ๊ฒฝ์šฐ style.css ํŒŒ์ผ ์ž‘์„ฑ)์ด master ๋ธŒ๋žœ์น˜์— ๋ณ‘ํ•ฉ๋œ๋‹ค.

 

 

 

7.4 ๋ณ‘ํ•ฉ ์ถฉ๋Œ

์„œ๋กœ ๋‹ค๋ฅธ ๋ธŒ๋žœ์น˜๋ฅผ ๊นƒ ๋จธ์ง€(git merge)๋กœ ๋ณ‘ํ•ฉํ•  ๋•Œ ๋™์ผํ•œ ํ–‰์—์„œ ํ•˜๋‚˜ ์ด์ƒ์˜ ํŒŒ์ผ์ด ๋ณ€๊ฒฝ๋˜์–ด ๋ณ‘ํ•ฉ์„ ์ž๋™์œผ๋กœ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ์—์„œ ์ผ๋ถ€ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

์ด๋ ‡๊ฒŒ ๋˜๋ฉด git status ๋ช…๋ น์„ ์‹คํ–‰ํ•˜์—ฌ ์–ด๋–ค ํŒŒ์ผ์ด ์ถฉ๋Œํ•˜๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

์šฐ๋ฆฌ๋Š” ๋ณ‘ํ•ฉ์„ ์ง„ํ–‰ํ•˜๊ธฐ ์ „์— ์–ด๋–ค ๋ณ€๊ฒฝ ์‚ฌํ•ญ์ด ๋ฐœ์ƒํ•ด์•ผ ํ•˜๋Š”์ง€ ์ •์˜ํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๊ฒ€ํ† ํ•˜์—ฌ ์ƒํ˜ธ ํ˜ธํ™˜๋˜๋„๋ก ์ถฉ๋Œ์„ ํ•ด๊ฒฐํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์œ„ํ•ด GIT๋Š” ์ถฉ๋Œํ•˜๋Š” ํŒŒ์ผ์— ๋งˆ์ปค๋ฅผ ์‚ฝ์ž…ํ•˜์—ฌ ํ•ด๊ฒฐ์„ ๋•๋Š”๋‹ค.

 

 

 

์ถฉ๋Œ์„ ํ•ด๊ฒฐํ•œ ํ›„ ์ˆ˜์ •๋œ ํŒŒ์ผ์„ ๋‹ค์‹œ ์Šคํ…Œ์ด์ง€์— ์˜ฌ๋ ค๋†“๊ณ  ์ƒˆ๋กœ์šด ์ถฉ๋Œ ์—†๋Š” ๋ฒ„์ „์„ ์ปค๋ฐ‹ํ•˜๊ณ  git merge ๋ช…๋ น์„ ๋‹ค์‹œ ์‹คํ–‰ํ•˜๋ฉด ๋ฌธ์ œ ์—†์ด ์„ฑ๊ณต์ ์œผ๋กœ ๋ณ‘ํ•ฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 


 

8. ์›๊ฒฉ ์ €์žฅ์†Œ์™€ ๋™๊ธฐํ™”

์šฐ๋ฆฌ๋Š” ์ด๋ฏธ ๋กœ์ปฌ ์ €์žฅ์†Œ๋ฅผ ์›๊ฒฉ ์ €์žฅ์†Œ์— ์—ฐ๊ฒฐํ•˜๊ณ  ๋ชจ๋“  ์ž‘์—…์„ ์›๊ฒฉ์œผ๋กœ ๋™๊ธฐํ™”ํ•˜์—ฌ ์ตœ์‹  ์ƒํƒœ๋กœ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ณ  ์žˆ๋‹ค.

 

์ด๋ฅผ ์œ„ํ•ด git push ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•ด ๋กœ์ปฌ ์ €์žฅ์†Œ๋กœ๋ถ€ํ„ฐ ๋ชจ๋“  ์ปค๋ฐ‹์„ ์›๊ฒฝ ์ €์žฅ์†Œ๋กœ ๋ณด๋‚ด์•ผ ํ•œ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ๋จผ์ € ์›๊ฒฉ ์ €์žฅ์†Œ๋ฅผ ๊ตฌ์„ฑํ•ด์•ผ ํ•œ๋‹ค.

 

8.1 ์›๊ฒฉ ์ €์žฅ์†Œ ๊ตฌ์„ฑํ•˜๊ธฐ

 

์›๊ฒฉ ์ €์žฅ์†Œ๋ฅผ ๊ตฌ์„ฑํ•˜๋Š” ๊ฒƒ์€ ๋งค์šฐ ๊ฐ„๋‹จํ•˜๋‹ค. ์šฐ๋ฆฌ๋Š” ์ด๋ฅผ ์œ„ํ•ด Github๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค.

 

๋จผ์ € GitHub ๊ณ„์ •์—์„œ ๋นˆ ์ €์žฅ์†Œ๋ฅผ ์ƒˆ๋กœ ์‹œ์ž‘ํ•ด์•ผ ํ•œ๋‹ค(์ด๋ฆ„์„ ์„ ํƒํ•˜๊ณ  "Creating repository"๋ฅผ ํด๋ฆญํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด ๋œ๋‹ค) :

 

 

 

๋‹ค์Œ์œผ๋กœ ์›๊ฒฉ ์ €์žฅ์†Œ์™€ ๋กœ์ปฌ ์ €์žฅ์†Œ์™€์˜ ๊ด€๊ณ„๋ฅผ ๋‹ค์Œ ๋ช…๋ น์–ด๋ฅผ ์šฐ๋ฆฌ์˜ ๋กœ์ปฌ ์ €์žฅ์†Œ์—์„œ ์‹คํ–‰ํ•ด ๊ตฌ์„ฑํ•ด์•ผ ํ•œ๋‹ค.

 

git remote add origin [remote-repository-url]

 

 

 

 

git remote -v : ๋กœ์ปฌ ์ €์žฅ์†Œ์— ์—ฐ๊ฒฐ๋˜์–ด ์žˆ๋Š” ์›๊ฒฉ ์ €์žฅ์†Œ์˜ URL์„ ๋ณด์—ฌ์ค€๋‹ค.

 

 

์›๊ฒฉ ์ €์žฅ์†Œ๊ฐ€ ์ ์ ˆํ•˜๊ฒŒ ์—ฐ๊ฒฐ๋˜์—ˆ๋‹ค๋ฉด, ์šฐ๋ฆฌ๋Š” ์šฐ๋ฆฌ์˜ ๋กœ์ปฌ ๋ธŒ๋žœ์น˜ master/main์˜ ์ด๋ฆ„์„ git branch -m main ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด  main์œผ๋กœ ๋ฐ”๊ฟ”์•ผ ํ•œ๋‹ค(๋‹น์‹ ์˜ ๋กœ์ปฌ ๋ธŒ๋žœ์น˜๊ฐ€ ์ด๋ฏธ main์œผ๋กœ ๋ถˆ๋ฆฌ๊ณ  ์žˆ๋‹ค๋ฉด ์ด ๋‹จ๊ณ„๋ฅผ ๋ฌด์‹œํ•˜๋ผ).

 

 

 

์šฐ๋ฆฌ๊ฐ€ push ํ•˜๋Š” ๋กœ์ปฌ ์ €์žฅ์†Œ์˜ ๋ฉ”์ธ ๋ธŒ๋žœ์น˜๋ฅผ ์›๊ฒฉ ์ €์žฅ์†Œ์˜ ๋ฉ”์ธ ๋ธŒ๋žœ์น˜์™€ ๋™์ผํ•œ ์ด๋ฆ„์œผ๋กœ ์œ ์ง€ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•˜๋‹ค.

 

 

๋งˆ์ง€๋ง‰์œผ๋กœ ์œ„์˜ ๋‹จ๊ณ„๋ฅผ ์™„๋ฃŒํ•œ ํ›„ ๋‹ค์Œ ๋ช…๋ น์„ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ์ปฌ ์ €์žฅ์†Œ๋ฅผ ์ฒ˜์Œ์œผ๋กœ ์›๊ฒฉ ์ €์žฅ์†Œ์™€ ๋™๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค:

 

git push -u origin main

 

 

 

 

git push-u origin main ๋ช…๋ น์„ ์‹คํ–‰ํ•  ๋•Œ GitHub credentials(์‚ฌ์šฉ์ž ๋ฐ ์•ก์„ธ์Šค ํ† ํฐ)์„ ์ž…๋ ฅํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

 

๋งŒ์•ฝ Github ์•ก์„ธ์Šค ํ† ํฐ์ด ๋ฌด์—‡์ธ์ง€ ๋ชจ๋ฅธ๋‹ค๊ฑฐ๋‚˜ ํ•˜๋‚˜์˜ ์•ก์„ธ์Šค ํ† ํฐ์„ ์„ค์ •ํ•˜์ง€ ์•Š์•˜๋‹ค๋ฉด ์—ฌ๊ธฐ๋ฅผ ํด๋ฆญํ•˜๋ผ.

GitHub CLI๋ฅผ ์‚ฌ์šฉํ•ด ์ธ์ฆ์„ ๊ตฌ์„ฑํ•จ์œผ๋กœ์จ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ์—ฌ๊ธฐ๋ฅผ ํด๋ฆญํ•˜์—ฌ ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์„ธ์š”.

 

 

์ธ์ฆ(Authenticating)์„ ํ•œ ํ›„์—๋Š” git push ์‹คํ–‰์ด ์„ฑ๊ณต์ ์œผ๋กœ ๋˜์–ด์•ผ ํ•˜๊ณ  ๋กœ์ปฌ ์ €์žฅ์†Œ์˜ ๋ชจ๋“  ์ปค๋ฐ‹์ด ์›๊ฒฉ ์ €์žฅ์†Œ์™€ ๋™๊ธฐํ™”๋œ๋‹ค.

 

 

 

 

 

 

8.2  ์ฒ˜์Œ ์ดํ›„ Git push (git push)

 

์œ„์˜ ๋ชจ๋“  ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์นœ ํ›„์—๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ๋ณ„๋„์˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์—†์ด git push ๋ช…๋ น๋งŒ์œผ๋กœ ์ƒˆ๋กœ์šด ๋™๊ธฐํ™”๋ฅผ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

 

 

์ด ๊ฒฝ์šฐ github CLI๋ฅผ ์ด์šฉํ•˜์—ฌ git push ๋ช…๋ น ์‹คํ–‰์— ํ•„์š”ํ•œ ์ธ์ฆ์„ ๊ฑด๋„ˆ๋›ฐ์—ˆ๋‹ค. ์—ฌ๊ธฐ๋ฅผ ํด๋ฆญํ•˜๋ฉด ๋ฐฉ๋ฒ•์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

 

 

8.3  ๋กœ์ปฌ ์ €์žฅ์†Œ ์—…๋ฐ์ดํŠธํ•˜๊ธฐ (git pull)

 

๋ถ„์‚ฐ๋œ ์›๊ฒฉ ์ €์žฅ์†Œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์›๊ฒฉ์œผ๋กœ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ (์›๊ฒฉ ์ €์žฅ์†Œ์—์„œ ์ง์ ‘) ๋กœ์ปฌ ์ €์žฅ์†Œ๊ฐ€ ์˜ค๋ž˜๋œ ์ƒํƒœ์ผ ์ˆ˜ ์žˆ๋‹ค.

 

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

 

 

git pull

 

 

์ƒˆ๋กœ์šด README.md ํŒŒ์ผ์ด ์šฐ๋ฆฌ์˜ ์›๊ฒฉ ์ €์žฅ์†Œ์— ์ง์ ‘ ์ƒ์„ฑ๋˜์–ด ์šฐ๋ฆฌ์˜ ๋กœ์ปฌ ์ €์žฅ์†Œ๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜์ง€ ์•Š์•˜๋‹ค๊ณ  ์ƒ๊ฐํ•ด๋ณด๋ผ.

 

 

 

์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ git pull์„ ์‚ฌ์šฉํ•˜์—ฌ ์›๊ฒฉ ์ €์žฅ์†Œ๋กœ๋ถ€ํ„ฐ์˜ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ๋กœ์ปฌ ์ €์žฅ์†Œ ๋‚ด์—์„œ ๋™๊ธฐํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค. 

 

 

 

 

์ฒ˜์Œ 7๊ฐœ์˜ ํ–‰์ด git pull ๋ช…๋ น์„ ์‹คํ–‰ํ•  ๋•Œ git fetch ๋ช…๋ น์˜ return ๊ฐ’์ด๋‹ค. ์ฆ‰, git fetch ๋ช…๋ น์„ ๋จผ์ € ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  git pull ๋ช…๋ น์„ ์‹คํ–‰ํ•˜๋ฉด GIT๋Š” ๋‘˜ ๋‹ค ํ•จ๊ป˜ ์‹คํ–‰ํ•ด ์›๊ฒฉ ์ €์žฅ์†Œ์—์„œ ์—…๋ฐ์ดํŠธ๋ฅผ ์ฐพ์•„ ๋กœ์ปฌ ์ €์žฅ์†Œ์— ๋™๊ธฐํ™”ํ•œ๋‹ค.

git fetch -> ์›๊ฒฉ ์ €์žฅ์†Œ์—์„œ ์—…๋ฐ์ดํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค์ง€๋งŒ ๋กœ์ปฌ ์ €์žฅ์†Œ๋ฅผ ๋™๊ธฐํ™”ํ•˜์ง€๋Š” ์•Š์Šต๋‹ˆ๋‹ค(git pull์ด ํ•„์š”ํ•จ).

 

 


 

9. ๊ฒฐ๋ก 

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

 


10. ์ฐธ์กฐ

 

๐Ÿ„‍โ™€๏ธ input ํƒœ๊ทธ๋กœ ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๊ฑฐ๋‚˜ ํŒŒ์ผ์˜ url์„ ๊ฐ€์ง€๊ณ  ์žˆ์„ ๊ฒฝ์šฐ ํŒŒ์ผ์˜ ํ™•์žฅ์ž๋ฅผ ์ œ๋Œ€๋กœ ์•Œ ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์•Œ์•„๋ณด์ž.

 

 

How to: ํŒŒ์ผ ์—…๋กœ๋“œ ํ›„ e.target.files์˜ name์„ ํ™œ์šฉ

<input type="file" id="avatar" name="avatar" accept="*" />

 

 

 

 

์œ„ ํŒŒ์ผ ๊ฐ์ฒด๋Š” inputํƒœ๊ทธ๋ฅผ ํ†ตํ•ด ํŒŒ์ผ์„ ์—…๋กœ๋“œ ํ•œ ํ›„ ์–ป๊ฒŒ ๋˜๋Š” ๊ฐ’์ด๋‹ค.

 

๊ทธ ์ค‘ name๊ฐ’์—๋Š” ํŒŒ์ผ์˜ ์ด๋ฆ„์ด ์กด์žฌํ•˜๋Š”๋ฐ ์ด๋ฅผ ํ™œ์šฉํ•ด ํ™•์žฅ์ž ๊ฐ’์„ ๊ตฌํ•  ์ˆ˜ ์žˆ๋‹ค.

 

<input
    type="file"
    id="upload"
    onChange={(e) => {
      const files = e.target.files;
      const filename = files[0].name;
      const splitedNameArr = filename.split('.');
      const lastSplitedVal = splitedNameArr.at(-1);

      console.log(lastSplitedVal);
    }}
  />

 

ํŒŒ์ผ name์—์„œ split์„ ํ†ตํ•ด . ์„ ๊ธฐ์ค€์œผ๋กœ ๋‚˜๋ˆˆ ๋’ค ๋งˆ์ง€๋ง‰ . ๋’ค์˜ ๊ฐ’์„ ํ™•์žฅ์ž๋กœ ์ธ์‹ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ํ™œ์šฉํ–ˆ๋‹ค.

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ํŒŒ์ผ ์ด๋ฆ„ ์‚ฌ์ด์— . ์ด ์กด์žฌํ•˜๋”๋ผ๋„ ๊ฐ€์žฅ ๋งˆ์ง€๋ง‰ . ๋’ค ๊ฐ’์„ ํ™•์žฅ์ž๋กœ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

 

* Array.prototype.at() ๊ธฐ๋Šฅ์ด ๋„ˆ๋ฌด ๋ง˜์— ๋“ค์–ด ๋งํฌ ๋‚จ๊ธด๋‹ค!

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Array/at

+ Recent posts