<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발이 취미인 사람</title>
    <link>https://any-ting.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 7 May 2026 05:08:41 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>RyanSin</managingEditor>
    <image>
      <title>개발이 취미인 사람</title>
      <url>https://tistory1.daumcdn.net/tistory/4415737/attach/9cf574802ac548cc979be775367e156a</url>
      <link>https://any-ting.tistory.com</link>
    </image>
    <item>
      <title>[CSS] CSS란 무엇인가 &amp;mdash; 웹에서 스타일이 입혀지는 원리</title>
      <link>https://any-ting.tistory.com/196</link>
      <description>&lt;h2&gt;개요&lt;/h2&gt;
&lt;p&gt;CSS(Cascading Style Sheets)는 HTML로 작성된 웹 문서의 &lt;b&gt;시각적 표현&lt;/b&gt;을 담당하는 언어입니다. 이 글에서는 CSS가 왜 존재하는지, HTML과 어떤 관계인지, 브라우저가 CSS를 어떻게 처리하는지를 다룹니다.&lt;/p&gt;

&lt;br&gt;

&lt;h2&gt;1. CSS가 없는 웹&lt;/h2&gt;
&lt;p&gt;CSS를 이해하려면, 먼저 CSS가 없는 상태를 봐야 합니다.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;ko&quot;&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
  &amp;lt;title&amp;gt;CSS 없는 페이지&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;안녕하세요&amp;lt;/h1&amp;gt;
  &amp;lt;p&amp;gt;이것은 CSS가 없는 HTML 문서입니다.&amp;lt;/p&amp;gt;
  &amp;lt;a href=&quot;#&quot;&amp;gt;링크입니다&amp;lt;/a&amp;gt;
  &amp;lt;ul&amp;gt;
    &amp;lt;li&amp;gt;항목 1&amp;lt;/li&amp;gt;
    &amp;lt;li&amp;gt;항목 2&amp;lt;/li&amp;gt;
  &amp;lt;/ul&amp;gt;
  &amp;lt;button&amp;gt;버튼&amp;lt;/button&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;이 HTML을 브라우저에서 열면 아무 스타일도 작성하지 않았는데 다음과 같이 보입니다:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;&amp;lt;h1&amp;gt;&lt;/code&gt;은 크고 굵은 글씨&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;&amp;lt;p&amp;gt;&lt;/code&gt;는 위아래 여백이 있는 문단&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt;는 파란색 밑줄&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;&amp;lt;ul&amp;gt;&lt;/code&gt;은 점 마커가 있는 리스트&lt;/li&gt;
  &lt;li&gt;&lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;은 회색 테두리 버튼&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;b&gt;왜?&lt;/b&gt; 브라우저가 자체적으로 가지고 있는 &lt;b&gt;기본 스타일(User Agent Stylesheet)&lt;/b&gt; 때문입니다. CSS를 하나도 작성하지 않아도 브라우저가 HTML 태그마다 기본 CSS를 적용합니다.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;다음 편(01편)에서 태그별 기본 스타일을 상세히 다룹니다.&lt;/p&gt;&lt;/blockquote&gt;

&lt;br&gt;

&lt;h2&gt;2. CSS란 무엇인가&lt;/h2&gt;

&lt;h3&gt;한 문장 정의&lt;/h3&gt;
&lt;blockquote&gt;&lt;p&gt;&lt;b&gt;CSS는 HTML 요소의 &quot;어떻게 보일지&quot;를 정의하는 스타일 언어입니다.&lt;/b&gt;&lt;/p&gt;&lt;/blockquote&gt;

&lt;h3&gt;역할 분리&lt;/h3&gt;
&lt;p&gt;웹은 세 가지 언어가 역할을 나눠 맡습니다.&lt;/p&gt;

&lt;table style=&quot;border-collapse: collapse; width: 100%; margin: 16px 0;&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;언어&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;역할&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;비유&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;b&gt;HTML&lt;/b&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;구조 (Structure)&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;건물의 뼈대 (기둥, 벽, 방)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;b&gt;CSS&lt;/b&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;표현 (Presentation)&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;인테리어 (페인트, 가구 배치, 조명)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;b&gt;JavaScript&lt;/b&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;동작 (Behavior)&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;전기/배관 시스템 (스위치, 엘리베이터)&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;백엔드로 비유하면:&lt;/p&gt;

&lt;table style=&quot;border-collapse: collapse; width: 100%; margin: 16px 0;&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;웹&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;백엔드 비유&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;HTML&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;데이터 스키마 (테이블 구조)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;CSS&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;포맷터/시리얼라이저 (응답을 어떻게 보여줄지)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;JavaScript&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;비즈니스 로직&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;&lt;b&gt;핵심&lt;/b&gt;: HTML은 &quot;무엇이 있는지&quot;, CSS는 &quot;어떻게 보이는지&quot;를 담당합니다. 이 분리가 웹의 기본 설계 원칙입니다.&lt;/p&gt;

&lt;br&gt;

&lt;h2&gt;3. CSS의 기본 문법&lt;/h2&gt;
&lt;p&gt;CSS는 &lt;b&gt;선택자(Selector)&lt;/b&gt;와 &lt;b&gt;선언(Declaration)&lt;/b&gt;으로 구성됩니다.&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;/* 선택자 { 속성: 값; } */

h1 {
  color: #2563eb;
  font-size: 32px;
  margin-bottom: 16px;
}&lt;/code&gt;&lt;/pre&gt;

&lt;table style=&quot;border-collapse: collapse; width: 100%; margin: 16px 0;&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;구성 요소&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;예시&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;설명&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;선택자 (Selector)&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;code&gt;h1&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;어떤 요소에 스타일을 적용할지&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;속성 (Property)&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;code&gt;color&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;무엇을 바꿀지&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;값 (Value)&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;code&gt;#2563eb&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;어떻게 바꿀지&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;선언 (Declaration)&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;code&gt;color: #2563eb;&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;속성 + 값 한 쌍&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;선언 블록&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;code&gt;{ ... }&lt;/code&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;선언들의 묶음&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;백엔드 개발자에게 익숙한 형태로 비유하면:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CSS                         JSON
─────────────────           ─────────────────
h1 {                        {
  color: #2563eb;             &quot;color&quot;: &quot;#2563eb&quot;,
  font-size: 32px;            &quot;fontSize&quot;: &quot;32px&quot;,
  margin-bottom: 16px;        &quot;marginBottom&quot;: &quot;16px&quot;
}                           }&lt;/code&gt;&lt;/pre&gt;

&lt;br&gt;

&lt;h2&gt;4. CSS를 적용하는 3가지 방법&lt;/h2&gt;

&lt;h3&gt;방법 1: 인라인 스타일 (Inline)&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;h1 style=&quot;color: #2563eb; font-size: 32px;&quot;&amp;gt;제목&amp;lt;/h1&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
  &lt;li&gt;HTML 태그에 직접 작성&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;우선순위가 가장 높음&lt;/b&gt;&lt;/li&gt;
  &lt;li&gt;재사용 불가, 유지보수 어려움&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;실무에서는 거의 사용하지 않음&lt;/b&gt; (JS 프레임워크에서 동적 스타일 외)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;방법 2: 내부 스타일시트 (Internal)&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;head&amp;gt;
  &amp;lt;style&amp;gt;
    h1 {
      color: #2563eb;
      font-size: 32px;
    }
  &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code&gt;&amp;lt;style&amp;gt;&lt;/code&gt; 태그 안에 작성&lt;/li&gt;
  &lt;li&gt;해당 HTML 파일에서만 적용&lt;/li&gt;
  &lt;li&gt;소규모 페이지나 프로토타입에서 사용&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;방법 3: 외부 스타일시트 (External) — 권장&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!-- index.html --&amp;gt;
&amp;lt;head&amp;gt;
  &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;style.css&quot;&amp;gt;
&amp;lt;/head&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;/* style.css */
h1 {
  color: #2563eb;
  font-size: 32px;
}&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
  &lt;li&gt;별도 &lt;code&gt;.css&lt;/code&gt; 파일로 분리&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;여러 HTML 파일에서 재사용 가능&lt;/b&gt;&lt;/li&gt;
  &lt;li&gt;브라우저 캐싱 가능 (성능 이점)&lt;/li&gt;
  &lt;li&gt;&lt;b&gt;실무에서 표준 방식&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;비교 정리&lt;/h3&gt;

&lt;table style=&quot;border-collapse: collapse; width: 100%; margin: 16px 0;&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;방법&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: center;&quot;&gt;재사용&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: center;&quot;&gt;유지보수&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: center;&quot;&gt;캐싱&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;실무 사용&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;인라인&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px; text-align: center;&quot;&gt;❌&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px; text-align: center;&quot;&gt;❌&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px; text-align: center;&quot;&gt;❌&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;거의 안 함&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;내부&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px; text-align: center;&quot;&gt;❌&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px; text-align: center;&quot;&gt;△&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px; text-align: center;&quot;&gt;❌&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;프로토타입&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;b&gt;외부&lt;/b&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px; text-align: center;&quot;&gt;&lt;b&gt;✅&lt;/b&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px; text-align: center;&quot;&gt;&lt;b&gt;✅&lt;/b&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px; text-align: center;&quot;&gt;&lt;b&gt;✅&lt;/b&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;b&gt;표준&lt;/b&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;br&gt;

&lt;h2&gt;5. 브라우저가 CSS를 처리하는 과정&lt;/h2&gt;
&lt;p&gt;백엔드의 요청 처리 파이프라인처럼, 브라우저에도 렌더링 파이프라인이 있습니다.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;1. HTML 파싱  →  DOM 트리 생성
2. CSS 파싱   →  CSSOM 트리 생성
3. DOM + CSSOM →  Render Tree 생성
4. Layout      →  각 요소의 위치/크기 계산
5. Paint       →  픽셀로 그리기
6. Composite   →  레이어 합성 → 화면 출력&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;단계별 설명&lt;/h3&gt;

&lt;p&gt;&lt;b&gt;① HTML 파싱 → DOM 트리&lt;/b&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;body&amp;gt;
  &amp;lt;h1&amp;gt;제목&amp;lt;/h1&amp;gt;
  &amp;lt;p&amp;gt;본문&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;DOM 트리:
body
├── h1
│   └── &quot;제목&quot;
└── p
    └── &quot;본문&quot;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;② CSS 파싱 → CSSOM 트리&lt;/b&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;h1 { color: blue; font-size: 32px; }
p  { color: gray; }&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;CSSOM 트리:
h1 → { color: blue, font-size: 32px }
p  → { color: gray }&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;b&gt;③ DOM + CSSOM → Render Tree&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;DOM의 각 노드에 CSSOM의 스타일 정보가 결합됩니다. &lt;code&gt;display: none&lt;/code&gt;인 요소는 Render Tree에서 제외됩니다.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;④ Layout → Paint → Composite&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Render Tree를 기반으로 각 요소의 정확한 위치와 크기를 계산(Layout)하고, 픽셀로 그린 뒤(Paint), 레이어를 합성(Composite)하여 화면에 출력합니다.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;렌더링 파이프라인의 성능 최적화는 37편에서 자세히 다룹니다.&lt;/p&gt;&lt;/blockquote&gt;

&lt;br&gt;

&lt;h2&gt;6. CSS가 필요한 진짜 이유&lt;/h2&gt;
&lt;p&gt;&quot;HTML만으로 충분하지 않나?&quot; 라는 질문에 대한 답입니다.&lt;/p&gt;

&lt;h3&gt;이유 1: 관심사의 분리 (Separation of Concerns)&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!-- ❌ HTML에 스타일이 섞인 경우 (1990년대 방식) --&amp;gt;
&amp;lt;font size=&quot;5&quot; color=&quot;blue&quot;&amp;gt;&amp;lt;b&amp;gt;제목&amp;lt;/b&amp;gt;&amp;lt;/font&amp;gt;
&amp;lt;table width=&quot;800&quot; bgcolor=&quot;#f0f0f0&quot;&amp;gt;
  &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;내용&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
&amp;lt;/table&amp;gt;

&amp;lt;!-- ✅ HTML은 구조만, CSS는 스타일만 --&amp;gt;
&amp;lt;h1 class=&quot;title&quot;&amp;gt;제목&amp;lt;/h1&amp;gt;
&amp;lt;div class=&quot;content&quot;&amp;gt;내용&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;구조와 표현이 분리되면:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;HTML 변경 없이 디자인 변경 가능&lt;/li&gt;
  &lt;li&gt;같은 CSS를 여러 페이지에 재사용&lt;/li&gt;
  &lt;li&gt;디자이너와 개발자의 협업이 쉬워짐&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;백엔드에서 &lt;b&gt;비즈니스 로직과 프레젠테이션을 분리&lt;/b&gt;하는 것과 같은 원칙입니다.&lt;/p&gt;

&lt;h3&gt;이유 2: 일괄 변경&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;/* 이 한 줄로 사이트 전체의 primary 색상이 바뀜 */
:root {
  --color-primary: #2563eb;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;CSS 변수(Custom Properties)를 사용하면, 값 하나만 바꿔도 사이트 전체에 반영됩니다. HTML에 인라인으로 색상을 넣었다면? 모든 파일을 열어서 하나하나 바꿔야 합니다.&lt;/p&gt;

&lt;h3&gt;이유 3: 반응형 디자인&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;/* 하나의 HTML로 모바일/태블릿/데스크탑 대응 */
.container {
  width: 100%;
  max-width: 1200px;
  margin: 0 auto;
}

@media (max-width: 768px) {
  .container {
    padding: 0 16px;
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;CSS 없이는 화면 크기에 따라 레이아웃을 바꾸는 것이 불가능합니다.&lt;/p&gt;

&lt;h3&gt;이유 4: 접근성과 사용자 경험&lt;/h3&gt;

&lt;pre&gt;&lt;code class=&quot;language-css&quot;&gt;/* 다크모드 대응 */
@media (prefers-color-scheme: dark) {
  :root {
    --bg-color: #1a1a2e;
    --text-color: #e0e0e0;
  }
}

/* 모션 민감 사용자 대응 */
@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;CSS는 사용자의 시스템 설정에 따라 자동으로 스타일을 전환할 수 있습니다.&lt;/p&gt;

&lt;br&gt;

&lt;h2&gt;7. CSS로 어디까지 가능한가? (미리보기)&lt;/h2&gt;
&lt;p&gt;CSS는 단순한 색상/크기 지정을 넘어서 상당히 많은 것을 할 수 있습니다.&lt;/p&gt;

&lt;table style=&quot;border-collapse: collapse; width: 100%; margin: 16px 0;&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;가능한 것&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;설명&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;관련 챕터&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;레이아웃 배치&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;Flexbox, Grid로 자유로운 2차원 배치&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;13~18편&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;애니메이션&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;@keyframes로 로딩 스피너, 페이드 효과&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;23~25편&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;반응형 디자인&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;하나의 코드로 모바일~데스크탑 대응&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;20~22편&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;다크모드&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;CSS 변수만으로 테마 전환&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;35편&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;글래스모피즘&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;backdrop-filter로 유리 효과&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;30편&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;CSS만의 인터랙션&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;:checked, :target으로 토글/아코디언&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;31편&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;br&gt;

&lt;h3&gt;CSS의 한계&lt;/h3&gt;

&lt;table style=&quot;border-collapse: collapse; width: 100%; margin: 16px 0;&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;할 수 없는 것&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;이유&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;대안&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;서버 통신&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;CSS는 표현 언어&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;JavaScript (fetch)&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;복잡한 상태 관리&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;조건문/반복문 없음&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;JavaScript&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;DOM 조작&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;요소 생성/삭제 불가&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;JavaScript&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;사용자 입력 처리&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;이벤트 리스너 없음&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;JavaScript&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;br&gt;

&lt;p&gt;&lt;b&gt;결론&lt;/b&gt;: CSS는 &lt;b&gt;&quot;보이는 것&quot;에 대해서는 매우 강력&lt;/b&gt;하지만, &lt;b&gt;&quot;동작하는 것&quot;은 JavaScript의 영역&lt;/b&gt;입니다.&lt;/p&gt;

&lt;br&gt;

&lt;h2&gt;8. CSS의 역사 (간략)&lt;/h2&gt;

&lt;table style=&quot;border-collapse: collapse; width: 100%; margin: 16px 0;&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;연도&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;사건&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;의미&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;1996&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;CSS1 발표&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;폰트, 색상, 정렬 등 기본 스타일링&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;1998&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;CSS2 발표&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;position, z-index, media type 추가&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;2011~&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;CSS3 모듈화&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;Flexbox, Grid, Animation, 변수 등 개별 모듈로 발전&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;2020~&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;모던 CSS&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;container query, @layer, nesting, color-mix() 등&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;br&gt;

&lt;p&gt;CSS3부터는 &lt;b&gt;하나의 버전이 아니라 모듈별로 독립 발전&lt;/b&gt;합니다. &quot;CSS4&quot;는 없고, 각 모듈(Flexbox, Grid, Selectors 등)이 자체 레벨을 가집니다.&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;CSS의 발전사와 Sass→PostCSS→Tailwind 흐름은 38편에서 상세히 다룹니다.&lt;/p&gt;&lt;/blockquote&gt;

&lt;br&gt;

&lt;h2&gt;핵심 정리&lt;/h2&gt;

&lt;table style=&quot;border-collapse: collapse; width: 100%; margin: 16px 0;&quot;&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;개념&lt;/th&gt;
      &lt;th style=&quot;border: 1px solid #ddd; padding: 10px 14px; background-color: #f5f5f5; text-align: left;&quot;&gt;설명&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;b&gt;CSS의 역할&lt;/b&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;HTML의 시각적 표현을 담당하는 스타일 언어&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;b&gt;핵심 원칙&lt;/b&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;구조(HTML)와 표현(CSS)의 분리&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;b&gt;기본 문법&lt;/b&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;선택자 { 속성: 값; }&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;b&gt;적용 방법&lt;/b&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;인라인 / 내부 / &lt;b&gt;외부(권장)&lt;/b&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;b&gt;브라우저 처리&lt;/b&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;HTML→DOM, CSS→CSSOM → Render Tree → Layout → Paint&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;b&gt;CSS의 강점&lt;/b&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;레이아웃, 반응형, 애니메이션, 테마&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;&lt;b&gt;CSS의 한계&lt;/b&gt;&lt;/td&gt;
      &lt;td style=&quot;border: 1px solid #ddd; padding: 10px 14px;&quot;&gt;서버 통신, 상태 관리, DOM 조작 → JavaScript 영역&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;br&gt;

&lt;h2&gt;다음 글 예고&lt;/h2&gt;
&lt;blockquote&gt;
  &lt;p&gt;&lt;b&gt;[CSS] HTML 태그의 숨겨진 CSS — User Agent Stylesheet 파헤치기&lt;/b&gt;&lt;/p&gt;
  &lt;p&gt;브라우저가 기본으로 적용하는 스타일은 무엇인지, 왜 &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt;와 &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;이 다르게 보이는지, reset CSS가 왜 필요한지를 다룹니다.&lt;/p&gt;
&lt;/blockquote&gt;</description>
      <category>프론트 앤드(Front-End)/CSS</category>
      <category>CSS란?</category>
      <category>HTML이란?</category>
      <category>개발이취미인사람</category>
      <category>개발자</category>
      <category>웹 기초언어</category>
      <author>RyanSin</author>
      <guid isPermaLink="true">https://any-ting.tistory.com/196</guid>
      <comments>https://any-ting.tistory.com/196#entry196comment</comments>
      <pubDate>Mon, 23 Mar 2026 10:45:17 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 참조 타입의 메모리 저장 방식 - Stack과 Heap의 관계</title>
      <link>https://any-ting.tistory.com/195</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 이번 시간에는 Java의 **참조 타입(Reference Type)**이 메모리에 어떻게 저장되는지 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 글에서 리터럴에 대해 배웠는데, &quot;기본 타입은 Stack에 값이 저장되고, 문자열은 Heap에 저장된다&quot;는 말을 했었죠? 오늘은 이 개념을 확실하게 이해해볼 거예요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;Stack에 주소를 저장한다&quot;는 말이 정확히 무슨 의미인지, 왜 ==과 equals()가 다른 결과를 내는지, null은 무엇을 의미하는지 등을 메모리 관점에서 깊이 있게 다뤄보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 개념을 이해하면 Call by Value, String Pool, Garbage Collection 등의 고급 주제들이 훨씬 쉬워집니다!&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개념&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 타입 vs 참조 타입&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java의 데이터 타입은 크게 2가지로 나뉩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기본 타입 (Primitive Type)&lt;/b&gt;: 8가지&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;byte, short, int, long      // 정수
float, double                // 실수
char                         // 문자
boolean                      // 불린
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참조 타입 (Reference Type)&lt;/b&gt;: 기본 타입을 제외한 모든 것&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;String, Integer, Double      // 클래스
int[], String[]              // 배열
List, Map, Set               // 컬렉션
Person, Car, Animal          // 사용자 정의 클래스
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;핵심 차이&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구분 기본 타입 참조 타입&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;저장 위치&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;Stack에 &lt;b&gt;값 직접&lt;/b&gt; 저장&lt;/td&gt;
&lt;td&gt;Stack에 &lt;b&gt;주소&lt;/b&gt;, Heap에 &lt;b&gt;객체&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;기본값&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;타입별 다름 (0, false 등)&lt;/td&gt;
&lt;td&gt;null&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;크기&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;고정&lt;/td&gt;
&lt;td&gt;가변&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;비교&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;==로 값 비교&lt;/td&gt;
&lt;td&gt;==로 주소 비교&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 기본 타입의 메모리 저장&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;값이 직접 저장됨&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int age = 25;
double height = 175.5;
boolean isStudent = true;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리 상태:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;Stack (main 스레드)
├─ age = 25         &amp;larr; 값 25가 직접 저장
├─ height = 175.5   &amp;larr; 값 175.5가 직접 저장
└─ isStudent = true &amp;larr; 값 true가 직접 저장
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;값 자체가 Stack에 저장됩니다&lt;/li&gt;
&lt;li&gt;변수 간 복사 시 값이 복사됩니다&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 타입 복사 예제&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class PrimitiveExample {
    public static void main(String[] args) {
        int a = 10;
        int b = a;  // 값 10이 복사됨
        
        System.out.println(&quot;a = &quot; + a);  // 10
        System.out.println(&quot;b = &quot; + b);  // 10
        
        b = 20;  // b만 변경
        
        System.out.println(&quot;a = &quot; + a);  // 10 (변경 안됨!)
        System.out.println(&quot;b = &quot; + b);  // 20
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리 변화:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;[초기 상태]
Stack
├─ a = 10
└─ b = 10  (a의 값이 복사됨)

[b = 20 실행 후]
Stack
├─ a = 10  &amp;larr; 그대로!
└─ b = 20  &amp;larr; b만 변경
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결론:&lt;/b&gt; 기본 타입은 값이 독립적으로 저장되므로 서로 영향을 주지 않습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 참조 타입의 메모리 저장&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;주소를 저장함!&lt;/h3&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;String name = &quot;홍길동&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리 상태:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;Heap (String Pool)
└─ &quot;홍길동&quot; 객체 (주소: 0x1234)

Stack
└─ name = 0x1234  &amp;larr; 주소를 저장!
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;핵심 개념: 참조값(Reference)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참조값&lt;/b&gt;: Heap에 있는 객체의 메모리 주소&lt;/p&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;String str = &quot;Hello&quot;;
//     ^^^   ^^^^^^^
//     │     └─ 리터럴 &quot;Hello&quot;는 Heap에 저장
//     └─────── 변수 str은 주소를 저장
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;비유:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;택배 상자(객체) &amp;rarr; 창고(Heap)에 보관
송장 번호(주소) &amp;rarr; 내 수첩(Stack)에 기록
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 참조 타입 변수의 동작&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제 1: 객체 생성&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class Person {
    String name;
    int age;
}

public class ReferenceExample {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.name = &quot;홍길동&quot;;
        p1.age = 30;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리 상태:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Heap
└─ Person 객체 (주소: 0x1234)
   ├─ name &amp;rarr; &quot;홍길동&quot; (String 객체도 Heap)
   └─ age = 30

Stack
└─ p1 = 0x1234  &amp;larr; 주소만 저장!
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그림으로 보면:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;Stack          Heap
┌─────┐       ┌────────────┐
│ p1  │──────&amp;rarr;│Person 객체│
└─────┘       │ name: 홍길동│
              │ age: 30   │
              └────────────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제 2: 참조 복사 (중요!)&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class ReferenceExample {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.name = &quot;홍길동&quot;;
        p1.age = 30;
        
        Person p2 = p1;  // 주소가 복사됨!
        
        System.out.println(&quot;p1.name: &quot; + p1.name);  // 홍길동
        System.out.println(&quot;p2.name: &quot; + p2.name);  // 홍길동
        
        p2.name = &quot;김철수&quot;;  // p2를 통해 변경
        
        System.out.println(&quot;p1.name: &quot; + p1.name);  // 김철수 (영향받음!)
        System.out.println(&quot;p2.name: &quot; + p2.name);  // 김철수
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리 상태:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Heap
└─ Person 객체 (주소: 0x1234)
   ├─ name &amp;rarr; &quot;김철수&quot;
   └─ age = 30

Stack
├─ p1 = 0x1234  ┐
└─ p2 = 0x1234  ┘ 같은 주소!
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그림으로 보면:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;Stack          Heap
┌─────┐       ┌────────────┐
│ p1  │──┐   │Person 객체│
└─────┘  │   │ name: 김철수│
         └──&amp;rarr;│ age: 30   │
┌─────┐  │   └────────────┘
│ p2  │──┘
└─────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;p2 = p1은 &lt;b&gt;주소를 복사&lt;/b&gt;합니다&lt;/li&gt;
&lt;li&gt;p1과 p2는 &lt;b&gt;같은 객체&lt;/b&gt;를 가리킵니다&lt;/li&gt;
&lt;li&gt;둘 중 하나로 수정하면 &lt;b&gt;둘 다 영향&lt;/b&gt;받습니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제 3: 새 객체 생성&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;public class ReferenceExample {
    public static void main(String[] args) {
        Person p1 = new Person();
        p1.name = &quot;홍길동&quot;;
        p1.age = 30;
        
        Person p2 = new Person();  // 새 객체!
        p2.name = &quot;김철수&quot;;
        p2.age = 25;
        
        System.out.println(&quot;p1.name: &quot; + p1.name);  // 홍길동
        System.out.println(&quot;p2.name: &quot; + p2.name);  // 김철수
        
        p2.name = &quot;이영희&quot;;
        
        System.out.println(&quot;p1.name: &quot; + p1.name);  // 홍길동 (영향 없음!)
        System.out.println(&quot;p2.name: &quot; + p2.name);  // 이영희
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리 상태:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Heap
├─ Person 객체 (주소: 0x1234)
│  ├─ name &amp;rarr; &quot;홍길동&quot;
│  └─ age = 30
│
└─ Person 객체 (주소: 0x5678)
   ├─ name &amp;rarr; &quot;이영희&quot;
   └─ age = 25

Stack
├─ p1 = 0x1234  &amp;larr; 첫 번째 객체
└─ p2 = 0x5678  &amp;larr; 두 번째 객체 (다른 주소!)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심:&lt;/b&gt; new를 사용하면 &lt;b&gt;새 객체&lt;/b&gt;가 생성되어 &lt;b&gt;독립적&lt;/b&gt;입니다!&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. == vs equals() 완벽 이해&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;== 연산자: 주소 비교&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class ComparisonExample {
    public static void main(String[] args) {
        String s1 = &quot;Hello&quot;;      // 리터럴
        String s2 = &quot;Hello&quot;;      // 같은 리터럴
        String s3 = new String(&quot;Hello&quot;);  // new 객체
        
        System.out.println(s1 == s2);  // true
        System.out.println(s1 == s3);  // false
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리 상태:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Heap
├─ String Pool
│  └─ &quot;Hello&quot; (0x1234)
│
└─ new String 객체 (0x5678)

Stack
├─ s1 = 0x1234  ┐
├─ s2 = 0x1234  ┘ 같은 주소!
└─ s3 = 0x5678    다른 주소!
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;== 비교:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;s1 == s2  &amp;rarr;  0x1234 == 0x1234  &amp;rarr;  true
s1 == s3  &amp;rarr;  0x1234 == 0x5678  &amp;rarr;  false
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;equals() 메서드: 내용 비교&lt;/h3&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;System.out.println(s1.equals(s2));  // true
System.out.println(s1.equals(s3));  // true (내용이 같음!)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;equals() 비교:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;s1.equals(s2)  &amp;rarr;  &quot;Hello&quot;.equals(&quot;Hello&quot;)  &amp;rarr;  true
s1.equals(s3)  &amp;rarr;  &quot;Hello&quot;.equals(&quot;Hello&quot;)  &amp;rarr;  true
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;비교 정리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연산자 비교 대상 결과&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;==&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;주소 (참조값)&lt;/td&gt;
&lt;td&gt;같은 객체인가?&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;equals()&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;내용 (값)&lt;/td&gt;
&lt;td&gt;값이 같은가?&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실전 예제&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class PersonComparison {
    public static void main(String[] args) {
        Person p1 = new Person(&quot;홍길동&quot;, 30);
        Person p2 = new Person(&quot;홍길동&quot;, 30);
        Person p3 = p1;
        
        // == 비교 (주소)
        System.out.println(p1 == p2);  // false (다른 객체)
        System.out.println(p1 == p3);  // true (같은 객체)
        
        // equals 비교 (내용) - equals 오버라이드 필요
        System.out.println(p1.equals(p2));  // false (오버라이드 안 함)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;Heap
├─ Person(&quot;홍길동&quot;, 30) - 0x1234
└─ Person(&quot;홍길동&quot;, 30) - 0x5678  &amp;larr; 다른 객체!

Stack
├─ p1 = 0x1234  ┐
├─ p2 = 0x5678  │ 다른 주소!
└─ p3 = 0x1234  ┘ p1과 같은 주소!
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. null의 의미&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;null = 참조가 없음&lt;/h3&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;String str = null;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리 상태:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;axapta&quot;&gt;&lt;code&gt;Heap
(비어있음)

Stack
└─ str = null  &amp;larr; 아무것도 가리키지 않음
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;그림으로:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;Stack
┌─────┐
│ str │──X (가리키는 것 없음)
└─────┘
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;null 예제&lt;/h3&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;public class NullExample {
    public static void main(String[] args) {
        String str = null;
        
        // NullPointerException 발생!
        // System.out.println(str.length());
        
        // null 체크 필수
        if (str != null) {
            System.out.println(str.length());
        } else {
            System.out.println(&quot;str은 null입니다&quot;);
        }
        
        // null 할당
        Person p = new Person();
        p = null;  // 더 이상 객체를 참조하지 않음 &amp;rarr; GC 대상
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 타입은 null 불가!&lt;/h3&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;int x = null;      // 컴파일 에러!
boolean b = null;  // 컴파일 에러!

Integer x = null;  // OK! (참조 타입)
Boolean b = null;  // OK! (참조 타입)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 배열의 메모리 저장&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배열도 참조 타입!&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int[] arr = {10, 20, 30};
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리 상태:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Heap
└─ int[] 배열 객체 (0x1234)
   ├─ [0] = 10
   ├─ [1] = 20
   └─ [2] = 30

Stack
└─ arr = 0x1234
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배열 복사 예제&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class ArrayExample {
    public static void main(String[] args) {
        int[] arr1 = {10, 20, 30};
        int[] arr2 = arr1;  // 주소 복사!
        
        System.out.println(&quot;arr1[0]: &quot; + arr1[0]);  // 10
        System.out.println(&quot;arr2[0]: &quot; + arr2[0]);  // 10
        
        arr2[0] = 100;  // arr2를 통해 변경
        
        System.out.println(&quot;arr1[0]: &quot; + arr1[0]);  // 100 (영향받음!)
        System.out.println(&quot;arr2[0]: &quot; + arr2[0]);  // 100
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Heap
└─ int[] 배열 (0x1234)
   ├─ [0] = 100
   ├─ [1] = 20
   └─ [2] = 30

Stack
├─ arr1 = 0x1234  ┐
└─ arr2 = 0x1234  ┘ 같은 배열!
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 메서드 파라미터 전달&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 타입 전달&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class ParamExample {
    static void change(int x) {
        x = 100;
        System.out.println(&quot;메서드 내부: &quot; + x);  // 100
    }
    
    public static void main(String[] args) {
        int num = 10;
        change(num);
        System.out.println(&quot;메서드 외부: &quot; + num);  // 10 (변경 안됨!)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;[change 호출 전]
Stack (main)
└─ num = 10

[change 호출]
Stack (main)
└─ num = 10  &amp;larr; 그대로!

Stack (change)
└─ x = 10  &amp;larr; 복사된 값
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참조 타입 전달&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class ParamExample {
    static void change(Person p) {
        p.name = &quot;김철수&quot;;
        System.out.println(&quot;메서드 내부: &quot; + p.name);  // 김철수
    }
    
    public static void main(String[] args) {
        Person person = new Person();
        person.name = &quot;홍길동&quot;;
        
        change(person);
        System.out.println(&quot;메서드 외부: &quot; + person.name);  // 김철수 (변경됨!)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;Heap
└─ Person 객체 (0x1234)
   └─ name = &quot;김철수&quot;

Stack (main)
└─ person = 0x1234

Stack (change)
└─ p = 0x1234  &amp;larr; 같은 주소 복사!
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심:&lt;/b&gt; 주소가 복사되므로 같은 객체를 가리킴 &amp;rarr; 객체 내부 수정 가능!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;자세한 내용은 [Call by Value vs Call by Reference] 글을 참고하세요!&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8. 실전 예제&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제 1: 학생 정보 관리&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;class Student {
    String name;
    int score;
    
    Student(String name, int score) {
        this.name = name;
        this.score = score;
    }
}

public class StudentExample {
    public static void main(String[] args) {
        // 학생 2명 생성
        Student s1 = new Student(&quot;홍길동&quot;, 90);
        Student s2 = new Student(&quot;김철수&quot;, 85);
        
        // s3는 s1과 같은 학생
        Student s3 = s1;
        
        // s1의 점수 변경
        s1.score = 95;
        
        System.out.println(&quot;s1 점수: &quot; + s1.score);  // 95
        System.out.println(&quot;s2 점수: &quot; + s2.score);  // 85
        System.out.println(&quot;s3 점수: &quot; + s3.score);  // 95 (s1과 같음!)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;Heap
├─ Student(&quot;홍길동&quot;, 95) - 0x1234
└─ Student(&quot;김철수&quot;, 85) - 0x5678

Stack
├─ s1 = 0x1234  ┐
├─ s2 = 0x5678  │
└─ s3 = 0x1234  ┘ s1과 같은 객체!
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제 2: null 체크의 중요성&lt;/h3&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;public class NullCheckExample {
    static void printLength(String str) {
        // 나쁜 예
        // System.out.println(str.length());  // NullPointerException 위험!
        
        // 좋은 예
        if (str != null) {
            System.out.println(&quot;길이: &quot; + str.length());
        } else {
            System.out.println(&quot;str이 null입니다&quot;);
        }
    }
    
    public static void main(String[] args) {
        String s1 = &quot;Hello&quot;;
        String s2 = null;
        
        printLength(s1);  // 길이: 5
        printLength(s2);  // str이 null입니다
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제 3: 배열과 참조&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class ArrayReferenceExample {
    public static void main(String[] args) {
        int[] original = {1, 2, 3, 4, 5};
        int[] copy = original;  // 주소 복사
        
        // 진짜 복사 (새 배열 생성)
        int[] realCopy = new int[original.length];
        for (int i = 0; i &amp;lt; original.length; i++) {
            realCopy[i] = original[i];
        }
        
        // 또는 Arrays.copyOf() 사용
        // int[] realCopy = Arrays.copyOf(original, original.length);
        
        original[0] = 100;
        
        System.out.println(&quot;original[0]: &quot; + original[0]);  // 100
        System.out.println(&quot;copy[0]: &quot; + copy[0]);          // 100 (영향받음)
        System.out.println(&quot;realCopy[0]: &quot; + realCopy[0]);  // 1 (영향 없음!)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심 정리&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 기본 타입 vs 참조 타입&lt;/h3&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;기본 타입: Stack에 값 직접 저장
참조 타입: Stack에 주소, Heap에 객체
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 참조 복사의 의미&lt;/h3&gt;
&lt;pre class=&quot;smali&quot;&gt;&lt;code&gt;Person p1 = new Person();
Person p2 = p1;  // 주소 복사!
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;smali&quot;&gt;&lt;code&gt;p1과 p2는 같은 객체를 가리킴
&amp;rarr; 하나를 수정하면 둘 다 영향받음
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. == vs equals()&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연산자 기본 타입 참조 타입&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;==&lt;/td&gt;
&lt;td&gt;값 비교&lt;/td&gt;
&lt;td&gt;주소 비교&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;equals()&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;내용 비교&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. null의 의미&lt;/h3&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;String str = null;  // 아무것도 가리키지 않음
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;참조가 없다 = null
기본 타입은 null 불가!
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 메모리 구조&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;Stack (Thread별 독립)
├─ 지역 변수
│  ├─ 기본 타입: 값 직접
│  └─ 참조 타입: 주소만
└─ 메서드 호출 정보

Heap (모든 Thread 공유)
├─ 객체 (new로 생성)
├─ 배열
└─ String Pool
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 &lt;b&gt;참조 타입의 메모리 저장 방식&lt;/b&gt;에 대해 알아봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 &quot;Stack에 주소를 저장하고 Heap에 객체를 저장한다&quot;는 개념을 정확히 이해하는 것이 중요합니다. 이 개념을 알면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;==과 equals()의 차이를 이해할 수 있습니다&lt;/li&gt;
&lt;li&gt;왜 참조 복사가 위험한지 알 수 있습니다&lt;/li&gt;
&lt;li&gt;null이 무엇을 의미하는지 알 수 있습니다&lt;/li&gt;
&lt;li&gt;Call by Value의 원리를 이해할 수 있습니다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 시간에는 이 개념을 바탕으로 &lt;b&gt;String &amp;amp; String Pool&lt;/b&gt;에 대해 깊이 있게 알아보겠습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꼭 실습을 통해 학습하신 걸 추천드리겠습니다!!&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html&quot;&gt;Oracle Java Tutorials - Passing Information to a Method&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/cd/E13150_01/jrockit_jvm/jrockit/geninfo/diagnos/garbage_collect.html&quot;&gt;Java Memory Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.baeldung.com/java-variable-handles&quot;&gt;Understanding Java References&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>언어(Programming Language)/Java</category>
      <author>RyanSin</author>
      <guid isPermaLink="true">https://any-ting.tistory.com/195</guid>
      <comments>https://any-ting.tistory.com/195#entry195comment</comments>
      <pubDate>Fri, 30 Jan 2026 09:00:27 +0900</pubDate>
    </item>
    <item>
      <title>[Java] 리터럴(Literal)이란? - 변수와 값의 차이 완벽 이해</title>
      <link>https://any-ting.tistory.com/194</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 이번 시간에는 Java의 가장 기초적이지만 중요한 개념인 **리터럴(Literal)**에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;리터럴이 뭔가요?&quot;라고 물어보면 많은 개발자들이 명확하게 설명하지 못하는 경우가 많습니다. 하지만 리터럴은 Java 프로그래밍의 가장 기본이 되는 개념이에요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 String Pool, 메모리 구조, 참조 타입 등을 이해하려면 리터럴 개념을 정확히 알아야 합니다. 오늘은 &quot;코드에 직접 적는 값&quot;인 리터럴에 대해 쉽고 명확하게 정리해보겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개념&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리터럴(Literal)이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;소스 코드에 직접 입력한 값 그 자체&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다시 말해, 우리가 코드를 작성할 때 **&quot;직접 적는 데이터&quot;**를 리터럴이라고 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;쉬운 비유&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;레시피: &quot;설탕 100g을 넣으세요&quot;
        ^^^^
        이 100g이 &quot;리터럴&quot;

코드: int sugar = 100;
                  ^^^
                  이 100이 &quot;리터럴&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 리터럴 vs 변수&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 개념&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int age = 25;
//  ^^^   ^^
//  │     └─── 리터럴 (값 그 자체)
//  └───────── 변수 (값을 담는 그릇)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;변수&lt;/b&gt;: 값을 담는 그릇 (상자)&lt;br /&gt;&lt;b&gt;리터럴&lt;/b&gt;: 그릇에 담을 값 (물건)&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제로 이해하기&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class LiteralExample {
    public static void main(String[] args) {
        // 변수 선언과 리터럴 할당
        int number = 100;        // 100이 리터럴
        double pi = 3.14;        // 3.14가 리터럴
        char grade = 'A';        // 'A'가 리터럴
        String name = &quot;홍길동&quot;;   // &quot;홍길동&quot;이 리터럴
        boolean isTrue = true;   // true가 리터럴
        
        // 연산에서의 리터럴
        int sum = 10 + 20;       // 10과 20이 리터럴
        
        // 메서드 호출에서의 리터럴
        System.out.println(&quot;Hello&quot;);  // &quot;Hello&quot;가 리터럴
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;메모리 관점&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int x = 10;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Stack 메모리:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Stack
└─ x = 10  &amp;larr; 10(리터럴)이 변수 x에 저장됨
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;리터럴 10&lt;/b&gt;은 컴파일 시점에 처리되어 변수 x에 직접 저장됩니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 타입별 리터럴 표기법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. 정수 리터럴&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class IntegerLiteral {
    public static void main(String[] args) {
        // 10진수 리터럴
        int decimal = 100;
        
        // 16진수 리터럴 (0x 또는 0X로 시작)
        int hex = 0x64;          // 100과 같음
        
        // 8진수 리터럴 (0으로 시작)
        int octal = 0144;        // 100과 같음
        
        // 2진수 리터럴 (0b 또는 0B로 시작)
        int binary = 0b1100100;  // 100과 같음
        
        // long 타입 리터럴 (L 또는 l 접미사)
        long bigNumber = 100L;
        
        // 가독성을 위한 언더스코어 (Java 7+)
        int million = 1_000_000;  // 백만
        
        System.out.println(decimal);   // 100
        System.out.println(hex);       // 100
        System.out.println(octal);     // 100
        System.out.println(binary);    // 100
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의사항:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int x = 100;   // OK
int y = 100L;  // 컴파일 에러! long을 int에 넣을 수 없음
long z = 100;  // OK, 자동으로 long으로 변환됨
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. 실수 리터럴&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class FloatingLiteral {
    public static void main(String[] args) {
        // double 타입 리터럴 (기본)
        double d1 = 3.14;
        double d2 = 3.14d;      // d 접미사 (생략 가능)
        double d3 = 3.14D;
        
        // float 타입 리터럴 (f 또는 F 접미사 필수!)
        float f1 = 3.14f;
        float f2 = 3.14F;
        
        // 지수 표현
        double scientific1 = 1.23e2;   // 1.23 &amp;times; 10&amp;sup2; = 123.0
        double scientific2 = 1.23e-2;  // 1.23 &amp;times; 10⁻&amp;sup2; = 0.0123
        
        System.out.println(d1);          // 3.14
        System.out.println(scientific1); // 123.0
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의사항:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;float f = 3.14;   // 컴파일 에러! double을 float에 넣을 수 없음
float f = 3.14f;  // OK! f 접미사 필수
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-3. 문자 리터럴&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class CharLiteral {
    public static void main(String[] args) {
        // 일반 문자 리터럴 (작은따옴표 '')
        char c1 = 'A';
        char c2 = '가';
        char c3 = '1';
        
        // 유니코드 리터럴
        char unicode = '\u0041';  // 'A'와 같음
        
        // 이스케이프 시퀀스
        char newLine = '\n';      // 줄바꿈
        char tab = '\t';          // 탭
        char backslash = '\\';    // 역슬래시
        char singleQuote = '\'';  // 작은따옴표
        
        System.out.println(c1);       // A
        System.out.println(unicode);  // A
        System.out.println(&quot;Hello&quot; + newLine + &quot;World&quot;);
        // 출력:
        // Hello
        // World
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의사항:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;aspectj&quot;&gt;&lt;code&gt;char c1 = 'A';    // OK, 문자 1개
char c2 = 'AB';   // 컴파일 에러! 문자는 1개만
char c3 = &quot;A&quot;;    // 컴파일 에러! 큰따옴표는 String
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-4. 문자열 리터럴 (중요!)&lt;/h3&gt;
&lt;pre class=&quot;ceylon&quot;&gt;&lt;code&gt;public class StringLiteral {
    public static void main(String[] args) {
        // 문자열 리터럴 (큰따옴표 &quot;&quot;)
        String str1 = &quot;Hello&quot;;
        String str2 = &quot;안녕하세요&quot;;
        String str3 = &quot;123&quot;;      // 문자열!
        
        // 빈 문자열
        String empty = &quot;&quot;;
        
        // 여러 줄 문자열 (Java 13+)
        String multiLine = &quot;&quot;&quot;
            첫 번째 줄
            두 번째 줄
            세 번째 줄
            &quot;&quot;&quot;;
        
        // 이스케이프 시퀀스
        String escaped = &quot;Hello\nWorld&quot;;  // 줄바꿈
        String quoted = &quot;그가 말했다: \&quot;안녕\&quot;&quot;;  // 큰따옴표
        
        System.out.println(str1);     // Hello
        System.out.println(escaped);
        // 출력:
        // Hello
        // World
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문자 vs 문자열:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;char c = 'A';      // 문자 (작은따옴표)
String s = &quot;A&quot;;    // 문자열 (큰따옴표)

// 타입이 완전히 다름!
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-5. 불린 리터럴&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class BooleanLiteral {
    public static void main(String[] args) {
        // boolean 리터럴은 true와 false 두 개뿐!
        boolean isTrue = true;
        boolean isFalse = false;
        
        // 조건문에서 자주 사용
        if (true) {
            System.out.println(&quot;항상 실행됨&quot;);
        }
        
        // 비교 연산 결과는 boolean
        boolean result = (10 &amp;gt; 5);  // true
        
        System.out.println(isTrue);   // true
        System.out.println(result);   // true
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의사항:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;boolean b1 = true;   // OK
boolean b2 = 1;      // 컴파일 에러! Java는 1을 true로 변환 안 함
boolean b3 = &quot;true&quot;; // 컴파일 에러! 문자열은 boolean 아님
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-6. null 리터럴&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;public class NullLiteral {
    public static void main(String[] args) {
        // null은 &quot;참조가 없음&quot;을 나타내는 특별한 리터럴
        String str = null;
        Integer num = null;
        Object obj = null;
        
        // 기본 타입에는 null 사용 불가!
        // int x = null;  // 컴파일 에러!
        
        // null 체크
        if (str == null) {
            System.out.println(&quot;str은 null입니다&quot;);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3. 리터럴의 타입&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 타입 리터럴&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// 정수 리터럴의 기본 타입은 int
int i = 100;        // OK
long l = 100;       // OK, int &amp;rarr; long 자동 변환
byte b = 100;       // OK, int &amp;rarr; byte 자동 변환 (범위 내일 때)

// 실수 리터럴의 기본 타입은 double
double d = 3.14;    // OK
float f = 3.14;     // 에러! double &amp;rarr; float 불가
float f = 3.14f;    // OK, float 명시
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;타입 변환 예제&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class LiteralType {
    public static void main(String[] args) {
        // int 범위를 벗어나면 L 필수
        long big = 3000000000L;  // int 범위 초과, L 필수
        
        // byte 범위를 벗어나면 에러
        byte b1 = 127;   // OK
        // byte b2 = 128;   // 에러! byte 범위는 -128~127
        
        // float은 f 필수
        float f = 3.14f;
        
        // char는 작은따옴표
        char c = 'A';
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4. 리터럴과 메모리&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 타입 리터럴 - Stack에 저장&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;int age = 25;
double height = 175.5;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리 상태:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Stack
├─ age = 25  &amp;larr; 리터럴 25가 직접 저장
└─ height = 175.5  &amp;larr; 리터럴 175.5가 직접 저장
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문자열 리터럴 - String Pool(Heap)에 저장&lt;/h3&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;String s1 = &quot;Hello&quot;;
String s2 = &quot;Hello&quot;;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;메모리 상태:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;Heap (String Pool)
└─ &quot;Hello&quot; 객체 (0x1234)  &amp;larr; 리터럴 1개만!

Stack
├─ s1 = 0x1234  &amp;larr; 주소 저장
└─ s2 = 0x1234  &amp;larr; 같은 주소!
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심 차이:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;기본 타입 리터럴&lt;/b&gt;: 값 자체가 Stack에 저장&lt;/li&gt;
&lt;li&gt;&lt;b&gt;문자열 리터럴&lt;/b&gt;: Heap의 String Pool에 저장, Stack에는 주소만&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 부분은 다음 글 [참조 타입의 메모리 저장 방식]에서 자세히 다룹니다!&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5. 실전 예제&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제 1: 리터럴 구분하기&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class LiteralQuiz {
    public static void main(String[] args) {
        int x = 10;              // 10: 정수 리터럴
        double y = 3.14;         // 3.14: 실수 리터럴
        char c = 'A';            // 'A': 문자 리터럴
        String s = &quot;Hello&quot;;      // &quot;Hello&quot;: 문자열 리터럴
        boolean b = true;        // true: 불린 리터럴
        
        int sum = x + 20;        // 20: 정수 리터럴
        String msg = s + &quot;World&quot;;  // &quot;World&quot;: 문자열 리터럴
        
        System.out.println(&quot;결과: &quot; + sum);
        //                 ^^^^^^^
        //                 &quot;결과: &quot;: 문자열 리터럴
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제 2: 리터럴 타입 주의&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class LiteralTypeError {
    public static void main(String[] args) {
        // 올바른 예
        int i = 100;
        long l = 100L;
        float f = 3.14f;
        double d = 3.14;
        char c = 'A';
        String s = &quot;Hello&quot;;
        
        // 컴파일 에러 예
        // float f2 = 3.14;      // 에러! double을 float에
        // char c2 = &quot;A&quot;;        // 에러! String을 char에
        // char c3 = 'AB';       // 에러! 문자는 1개만
        // int x = 3000000000;   // 에러! int 범위 초과
        // boolean b = 1;        // 에러! int를 boolean으로
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제 3: 문자열 리터럴의 특별함&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class StringLiteralTest {
    public static void main(String[] args) {
        String s1 = &quot;Hello&quot;;  // 리터럴
        String s2 = &quot;Hello&quot;;  // 같은 리터럴
        String s3 = new String(&quot;Hello&quot;);  // new 객체
        
        System.out.println(s1 == s2);  // true (같은 리터럴)
        System.out.println(s1 == s3);  // false (다른 객체)
        
        System.out.println(s1.equals(s2));  // true
        System.out.println(s1.equals(s3));  // true
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실행 결과:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;true
false
true
true
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;왜 이런 결과가 나올까요?&lt;/b&gt; &amp;rarr; 다음 글 [String &amp;amp; String Pool]에서 자세히 알아봅니다!&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6. 리터럴 vs 상수 vs 변수&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개념 정리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용어 의미 예시&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;리터럴&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;코드에 직접 적은 값&lt;/td&gt;
&lt;td&gt;100, &quot;Hello&quot;, true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;변수&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;값을 저장하는 공간 (변경 가능)&lt;/td&gt;
&lt;td&gt;int x = 10;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;상수&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;값을 저장하는 공간 (변경 불가)&lt;/td&gt;
&lt;td&gt;final int MAX = 100;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;예제로 이해&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;public class LiteralVsConstant {
    // 상수 (관례: 대문자 + 언더스코어)
    static final int MAX_VALUE = 100;  // 100이 리터럴
    static final String TITLE = &quot;제목&quot;;  // &quot;제목&quot;이 리터럴
    
    public static void main(String[] args) {
        // 변수
        int x = 10;        // 10이 리터럴
        x = 20;            // 변경 가능! 20도 리터럴
        
        // 상수
        final int y = 30;  // 30이 리터럴
        // y = 40;         // 컴파일 에러! 상수는 변경 불가
        
        // 리터럴 직접 사용 (비추천)
        if (age &amp;gt; 19) {    // 19가 리터럴 (매직 넘버)
            // ...
        }
        
        // 상수 사용 (추천)
        if (age &amp;gt; MAX_AGE) {  // 의미가 명확함
            // ...
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;베스트 프랙티스:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;// 나쁜 예: 리터럴 직접 사용 (매직 넘버)
if (status == 1) { ... }
if (score &amp;gt; 90) { ... }

// 좋은 예: 상수로 정의
static final int STATUS_ACTIVE = 1;
static final int PASS_SCORE = 90;

if (status == STATUS_ACTIVE) { ... }
if (score &amp;gt; PASS_SCORE) { ... }
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7. 컴파일 타임 상수&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개념&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;컴파일 시점에 값이 결정되는 상수&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class CompileTimeConstant {
    // 컴파일 타임 상수
    static final int MAX = 100;
    static final String NAME = &quot;Java&quot;;
    
    public static void main(String[] args) {
        // 컴파일러가 직접 값으로 치환
        int x = MAX;  // int x = 100; 으로 컴파일됨
        
        // 상수 표현식도 컴파일 타임에 계산
        int result = MAX * 2;  // int result = 200; 으로 컴파일됨
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심 정리&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 리터럴이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&quot;소스 코드에 직접 입력한 값 그 자체&quot;&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;int x = 10;        // 10이 리터럴
String s = &quot;Hi&quot;;   // &quot;Hi&quot;가 리터럴
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 타입별 리터럴 표기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입 표기법 예시&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;정수&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;숫자&lt;/td&gt;
&lt;td&gt;100, 0xFF, 0b1010&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;long&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;숫자 + L&lt;/td&gt;
&lt;td&gt;100L&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;실수&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;소수점&lt;/td&gt;
&lt;td&gt;3.14&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;float&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;소수점 + f&lt;/td&gt;
&lt;td&gt;3.14f&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;문자&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;작은따옴표&lt;/td&gt;
&lt;td&gt;'A'&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;문자열&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;큰따옴표&lt;/td&gt;
&lt;td&gt;&quot;Hello&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;불린&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;true/false&lt;/td&gt;
&lt;td&gt;true&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;null&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;null&lt;/td&gt;
&lt;td&gt;null&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 메모리 저장&lt;/h3&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;기본 타입 리터럴 &amp;rarr; Stack에 값 직접 저장
문자열 리터럴 &amp;rarr; Heap의 String Pool에 저장
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 리터럴 vs 변수 vs 상수&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;리터럴: 코드에 적은 값 (100, &quot;Hello&quot;)
변수: 값을 담는 그릇 (int x = 10;)
상수: 변경 불가 그릇 (final int MAX = 100;)
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 Java의 가장 기본이 되는 &lt;b&gt;리터럴(Literal)&lt;/b&gt; 개념에 대해 알아봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리터럴은 단순해 보이지만, 메모리 구조를 이해하고 String Pool, 참조 타입 등을 학습하는 데 꼭 필요한 기초 개념입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 &lt;b&gt;문자열 리터럴은 String Pool&lt;/b&gt;이라는 특별한 공간에 저장되는데, 이에 대해서는 다음 글에서 자세히 다루겠습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기초를 탄탄히 하면 복잡한 개념도 쉽게 이해할 수 있습니다. 꼭 실습을 통해 학습하신 걸 추천드리겠습니다!!&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html&quot;&gt;Oracle Java Tutorials - Primitive Data Types&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html#jls-3.10&quot;&gt;JLS - Literals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/javase/specs/jls/se17/html/jls-3.html&quot;&gt;Java Language Specification - Lexical Structure&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>언어(Programming Language)/Java</category>
      <author>RyanSin</author>
      <guid isPermaLink="true">https://any-ting.tistory.com/194</guid>
      <comments>https://any-ting.tistory.com/194#entry194comment</comments>
      <pubDate>Thu, 29 Jan 2026 09:00:34 +0900</pubDate>
    </item>
    <item>
      <title>[Java] Call by Value와 Call by Reference 완벽 이해</title>
      <link>https://any-ting.tistory.com/193</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 이번 시간에는 Java의 인자 전달 방식인 Call by Value와 Call by Reference에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java를 공부하다 보면 &quot;함수에 객체를 넘겼는데 왜 원본이 바뀌지?&quot;, &quot;근데 왜 재할당은 안 되는 거야?&quot;라는 의문이 생기곤 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 &quot;Java는 Call by Value다&quot; vs &quot;Java는 객체는 Call by Reference다&quot;라는 논쟁은 개발자 면접에서도 자주 등장하는 단골 질문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 이 혼란스러운 개념을 명확하게 정리하고, 실제 메모리 관점에서 어떻게 동작하는지 깊이 있게 다뤄보겠습니다!&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;개념&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Call by Value란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수에 &lt;b&gt;값의 복사본&lt;/b&gt;을 전달하는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 내에서 매개변수를 변경해도 &lt;b&gt;원본 변수는 영향을 받지 않습니다&lt;/b&gt;.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;void change(int x) {
    x = 100;  // 복사본만 변경
}

int num = 5;
change(num);
System.out.println(num);  // 여전히 5
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Call by Reference란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수에 **변수의 메모리 주소(참조)**를 전달하는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수 내에서 매개변수를 변경하면 &lt;b&gt;원본 변수도 함께 변경됩니다&lt;/b&gt;.&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;// C++ 예시
void change(int &amp;amp;x) {  // &amp;amp;는 참조
    x = 100;  // 원본 변수가 100으로 변경됨!
}

int num = 5;
change(num);
cout &amp;lt;&amp;lt; num;  // 100 출력
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Java는 항상 Call by Value!&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;핵심: Java의 모든 인자 전달은 Call by Value&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;많은 사람들이 혼란스러워하는 이유는 **Java가 객체를 다룰 때 &quot;참조값 자체를 복사해서 전달&quot;**하기 때문입니다.&lt;/p&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;기본 타입: 값 자체를 복사해서 전달
참조 타입: 참조값(주소)을 복사해서 전달
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중요한 것은 &quot;복사&quot;라는 점입니다! 원본이 아닌 복사본을 전달하므로 &lt;b&gt;Call by Value&lt;/b&gt;입니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;1. 기본 타입(Primitive Type)의 전달&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;코드 예시&lt;/h3&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;public class PrimitiveExample {
    static void changeValue(int x) {
        System.out.println(&quot;함수 내부 (변경 전): &quot; + x);
        x = 100;
        System.out.println(&quot;함수 내부 (변경 후): &quot; + x);
    }
    
    public static void main(String[] args) {
        int num = 5;
        System.out.println(&quot;호출 전: &quot; + num);
        changeValue(num);
        System.out.println(&quot;호출 후: &quot; + num);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실행 결과&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;호출 전: 5
함수 내부 (변경 전): 5
함수 내부 (변경 후): 100
호출 후: 5
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;메모리 상태&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;[호출 전]
Stack (main)
└─ num = 5

[changeValue 호출]
Stack (main)
└─ num = 5

Stack (changeValue)
└─ x = 5 (복사된 값)

[x = 100 실행]
Stack (main)
└─ num = 5 (변경 안됨!)

Stack (changeValue)
└─ x = 100 (복사본만 변경)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결론&lt;/b&gt;: 기본 타입은 값 자체가 복사되므로 원본에 영향을 주지 않습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;2. 참조 타입(Reference Type)의 전달&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서부터 헷갈립니다! 차근차근 알아보겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-1. 객체 내부 속성 변경&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;class Person {
    String name;
    
    Person(String name) {
        this.name = name;
    }
}

public class ReferenceExample {
    static void changeName(Person p) {
        System.out.println(&quot;함수 내부 (변경 전): &quot; + p.name);
        p.name = &quot;김철수&quot;;
        System.out.println(&quot;함수 내부 (변경 후): &quot; + p.name);
    }
    
    public static void main(String[] args) {
        Person person = new Person(&quot;홍길동&quot;);
        System.out.println(&quot;호출 전: &quot; + person.name);
        changeName(person);
        System.out.println(&quot;호출 후: &quot; + person.name);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실행 결과&lt;/h3&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;호출 전: 홍길동
함수 내부 (변경 전): 홍길동
함수 내부 (변경 후): 김철수
호출 후: 김철수  &amp;larr; 원본이 변경됨!
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;메모리 상태&lt;/h3&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;Heap
└─ Person 객체 (주소: 0x1234)
   └─ name = &quot;홍길동&quot;

Stack (main)
└─ person = 0x1234 (참조값)

Stack (changeName)
└─ p = 0x1234 (참조값 복사!)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심&lt;/b&gt;: 참조값(0x1234)이 &lt;b&gt;복사&lt;/b&gt;되어 전달됩니다. 그래서 p와 person은 같은 객체를 가리킵니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 p.name을 변경하면 같은 객체를 가리키는 person.name도 변경됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이건 &lt;b&gt;Call by Reference가 아닙니다!&lt;/b&gt; 왜일까요?&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2-2. 객체 재할당 (핵심!)&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;class Person {
    String name;
    
    Person(String name) {
        this.name = name;
    }
}

public class ReassignExample {
    static void reassignObject(Person p) {
        System.out.println(&quot;함수 내부 (재할당 전): &quot; + p.name);
        p = new Person(&quot;이영희&quot;);  // 새 객체 생성 후 재할당
        System.out.println(&quot;함수 내부 (재할당 후): &quot; + p.name);
    }
    
    public static void main(String[] args) {
        Person person = new Person(&quot;홍길동&quot;);
        System.out.println(&quot;호출 전: &quot; + person.name);
        reassignObject(person);
        System.out.println(&quot;호출 후: &quot; + person.name);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실행 결과&lt;/h3&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;호출 전: 홍길동
함수 내부 (재할당 전): 홍길동
함수 내부 (재할당 후): 이영희
호출 후: 홍길동  &amp;larr; 원본은 그대로!
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;메모리 상태 (단계별)&lt;/h3&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;[초기 상태]
Heap
└─ Person 객체 A (주소: 0x1234)
   └─ name = &quot;홍길동&quot;

Stack (main)
└─ person = 0x1234

[reassignObject 호출]
Stack (main)
└─ person = 0x1234

Stack (reassignObject)
└─ p = 0x1234 (복사된 참조값)

[p = new Person(&quot;이영희&quot;) 실행]
Heap
├─ Person 객체 A (주소: 0x1234)
│  └─ name = &quot;홍길동&quot;
└─ Person 객체 B (주소: 0x5678)  &amp;larr; 새로 생성!
   └─ name = &quot;이영희&quot;

Stack (main)
└─ person = 0x1234 (변경 안됨!)

Stack (reassignObject)
└─ p = 0x5678 (새 객체를 가리킴)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;핵심&lt;/b&gt;:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;p는 새로운 객체(0x5678)를 가리키게 되었지만&lt;/li&gt;
&lt;li&gt;person은 여전히 원래 객체(0x1234)를 가리킵니다&lt;/li&gt;
&lt;li&gt;왜? p는 참조값의 &lt;b&gt;복사본&lt;/b&gt;이기 때문입니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 진짜 Call by Reference였다면, person도 새 객체를 가리켜야 합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;왜 Java는 Call by Value만 사용할까?&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 안정성&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;void dangerousFunction(Person p) {
    p = null;  // 만약 Call by Reference라면?
}

Person person = new Person(&quot;홍길동&quot;);
dangerousFunction(person);
// Java: person은 여전히 유효 (안전)
// C++: person이 null이 되어 크래시 위험
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 단순성&lt;/h3&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;// 모든 전달이 같은 방식
void func(int x);        // Call by Value
void func(Person p);     // Call by Value (참조값의)
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;cpp&quot;&gt;&lt;code&gt;// C++은 여러 방식을 구분해야 함
void func(int x);        // Call by Value
void func(int &amp;amp;x);       // Call by Reference
void func(int *x);       // 포인터
void func(const int &amp;amp;x); // Const Reference
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 포인터 제거&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;C++의 가장 큰 버그 원인:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;널 포인터 에러&lt;/li&gt;
&lt;li&gt;댕글링 포인터 (해제된 메모리 접근)&lt;/li&gt;
&lt;li&gt;메모리 누수&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java는 이런 문제를 원천적으로 차단했습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실전 예제: swap 함수&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;C++ (Call by Reference 가능)&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;void swap(int &amp;amp;a, int &amp;amp;b) {
    int temp = a;
    a = b;
    b = temp;
}

int x = 5, y = 10;
swap(x, y);
// x = 10, y = 5 (성공!)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Java (Call by Value만 가능)&lt;/h3&gt;
&lt;pre class=&quot;cs&quot;&gt;&lt;code&gt;// 시도 1: 실패
static void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;
}

int x = 5, y = 10;
swap(x, y);
// x = 5, y = 10 (실패!)

// 시도 2: 객체로 감싸기
class IntWrapper {
    int value;
    IntWrapper(int value) { this.value = value; }
}

static void swap(IntWrapper a, IntWrapper b) {
    int temp = a.value;
    a.value = b.value;
    b.value = temp;
}

IntWrapper x = new IntWrapper(5);
IntWrapper y = new IntWrapper(10);
swap(x, y);
// x.value = 10, y.value = 5 (성공!)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;언어별 비교&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언어 Call by Value Call by Reference 특징&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Java&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ 항상&lt;/td&gt;
&lt;td&gt;❌ 불가능&lt;/td&gt;
&lt;td&gt;단순하고 안전&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;C++&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ 가능&lt;/td&gt;
&lt;td&gt;✅ 가능 (&amp;amp; 사용)&lt;/td&gt;
&lt;td&gt;유연하지만 복잡&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;C#&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ 가능&lt;/td&gt;
&lt;td&gt;✅ 가능 (ref 사용)&lt;/td&gt;
&lt;td&gt;Java + C++ 절충&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;Python&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;독특한 방식&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;JavaScript&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;✅ 항상&lt;/td&gt;
&lt;td&gt;❌ 불가능&lt;/td&gt;
&lt;td&gt;Java와 유사&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;핵심 정리&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Java의 인자 전달 규칙&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;1. 기본 타입 (int, boolean 등)
   &amp;rarr; 값 자체를 복사해서 전달
   &amp;rarr; 원본 변경 불가능

2. 참조 타입 (객체, 배열 등)
   &amp;rarr; 참조값(주소)을 복사해서 전달
   &amp;rarr; 객체 내부는 변경 가능
   &amp;rarr; 변수 재할당은 불가능
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3줄 요약&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;Java는 모든 경우에 Call by Value다&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;객체의 경우, &quot;참조값&quot;을 값으로 전달한다&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;객체 내부 수정 가능 &amp;ne; Call by Reference&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;면접 질문 답변 예시&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;질문&lt;/b&gt;: &quot;Java는 Call by Value인가요, Call by Reference인가요?&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;정답&lt;/b&gt;:&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&quot;Java는 항상 Call by Value입니다. 기본 타입은 값 자체를 복사하고, 참조 타입은 참조값을 복사해서 전달합니다. 따라서 객체 내부를 수정할 수는 있지만, 변수 자체를 다른 객체로 재할당하는 것은 불가능합니다. 이것이 진짜 Call by Reference와의 결정적 차이입니다.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 Java의 인자 전달 방식에 대해 알아봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 &quot;객체는 참조 전달 아닌가?&quot;라고 생각하기 쉽지만, 정확히는 **&quot;참조값의 복사&quot;**라는 점을 기억하세요!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 면접에서 이 질문이 나오면:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&quot;Java는 항상 Call by Value다&quot;&lt;/li&gt;
&lt;li&gt;&quot;객체 재할당이 안 되는 이유&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 가지를 명확히 설명할 수 있다면 완벽합니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 코드를 작성하면서 &quot;이 변수는 왜 안 바뀌지?&quot;, &quot;저 객체는 왜 바뀌지?&quot;를 생각하다 보면 자연스럽게 이해가 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;꼭 실습을 통해 학습하신 걸 추천드리겠습니다!!&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;참고 자료&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html&quot;&gt;Oracle Java Documentation - Method Parameters&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.javadude.com/articles/passbyvalue.htm&quot;&gt;Java is Pass-by-Value, Dammit!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value&quot;&gt;Stack Overflow - Is Java &quot;pass-by-reference&quot; or &quot;pass-by-value&quot;?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>언어(Programming Language)/Java</category>
      <category>call by reference</category>
      <category>call by value</category>
      <category>java</category>
      <category>개발이 취미인 사람</category>
      <category>개발자</category>
      <author>RyanSin</author>
      <guid isPermaLink="true">https://any-ting.tistory.com/193</guid>
      <comments>https://any-ting.tistory.com/193#entry193comment</comments>
      <pubDate>Wed, 28 Jan 2026 10:57:52 +0900</pubDate>
    </item>
    <item>
      <title>[Git] - Git Tag - 버전 관리 및 릴리즈</title>
      <link>https://any-ting.tistory.com/192</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 이번 시간에는 Git Tag에 대해 알아보겠습니다. Tag는 특정 커밋에 버전을 표시하는 기능으로, 소프트웨어 릴리즈 관리에 필수적입니다. v1.0.0, v2.1.0과 같은 버전 번호를 Git으로 관리하는 방법을 배워보겠습니다. 혹시 이전 시간에 내용을 학습하고 오시지 못 하신 분들은 학습하고 오시는 걸 추천드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://any-ting.tistory.com/191&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Git] - Git Stash - 임시 저장 활용법&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Tag란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tag는 Git의 특정 커밋에 대한 **참조(reference)**입니다. 주로 릴리즈 버전을 표시하는 데 사용됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tag의 용도&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;✅ 주요 용도:
- 릴리즈 버전 표시 (v1.0.0, v2.1.0)
- 특정 시점의 코드 스냅샷 저장
- 배포 이력 관리
- 다운로드 가능한 릴리즈 생성

  예시:
v1.0.0 &amp;rarr; 첫 번째 정식 릴리즈
v1.1.0 &amp;rarr; 새 기능이 추가된 마이너 업데이트
v1.1.1 &amp;rarr; 버그 수정 패치&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tag의 특징&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;1. 특정 커밋을 가리킴 (브랜치와 유사)
2. 한번 만들면 이동하지 않음 (브랜치와 다름)
3. 원격 저장소와 공유 가능
4. GitHub에서 자동으로 릴리즈 페이지 생성&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;브랜치 vs Tag&lt;/h3&gt;
&lt;div&gt;항목브랜치Tag
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;이동&lt;/td&gt;
&lt;td&gt;새 커밋 생성 시 이동&lt;/td&gt;
&lt;td&gt;고정 (이동 안함)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;용도&lt;/td&gt;
&lt;td&gt;개발 작업&lt;/td&gt;
&lt;td&gt;버전 표시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;수정&lt;/td&gt;
&lt;td&gt;자주 수정됨&lt;/td&gt;
&lt;td&gt;거의 수정 안함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;예시&lt;/td&gt;
&lt;td&gt;main, develop&lt;/td&gt;
&lt;td&gt;v1.0.0, v2.0.0&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Tag의 종류&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Git에는 두 가지 종류의 Tag가 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1522&quot; data-origin-height=&quot;1544&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSvDKU/dJMcai2T7Ye/EQYKU979eFeyKJkr714Ag1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSvDKU/dJMcai2T7Ye/EQYKU979eFeyKJkr714Ag1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSvDKU/dJMcai2T7Ye/EQYKU979eFeyKJkr714Ag1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSvDKU%2FdJMcai2T7Ye%2FEQYKU979eFeyKJkr714Ag1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1522&quot; height=&quot;1544&quot; data-origin-width=&quot;1522&quot; data-origin-height=&quot;1544&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Lightweight Tag (가벼운 태그)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 특정 커밋을 가리키는 포인터입니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# Lightweight Tag 생성
git tag v1.0.0

# 특정 커밋에 Tag 생성
git tag v1.0.0 a1b2c3d&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;태그 이름만 저장&lt;/li&gt;
&lt;li&gt;추가 정보 없음&lt;/li&gt;
&lt;li&gt;빠르고 간단&lt;/li&gt;
&lt;li&gt;임시 태그나 개인용으로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Annotated Tag (주석 태그) - 권장&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;태그 작성자, 날짜, 메시지 등의 정보를 포함하는 완전한 객체입니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# Annotated Tag 생성
git tag -a v1.0.0 -m &quot;첫 번째 정식 릴리즈&quot;

# 특정 커밋에 Tag 생성
git tag -a v1.0.0 a1b2c3d -m &quot;메시지&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;특징:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;태그 작성자 정보 저장&lt;/li&gt;
&lt;li&gt;태그 생성 날짜 저장&lt;/li&gt;
&lt;li&gt;태그 메시지 저장&lt;/li&gt;
&lt;li&gt;GPG 서명 가능&lt;/li&gt;
&lt;li&gt;공식 릴리즈에 권장&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Lightweight vs Annotated 비교&lt;/h3&gt;
&lt;div&gt;항목LightweightAnnotated
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;생성&lt;/td&gt;
&lt;td&gt;git tag v1.0.0&lt;/td&gt;
&lt;td&gt;git tag -a v1.0.0 -m &quot;메시지&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;정보&lt;/td&gt;
&lt;td&gt;커밋만 가리킴&lt;/td&gt;
&lt;td&gt;작성자, 날짜, 메시지 포함&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용&lt;/td&gt;
&lt;td&gt;임시 태그&lt;/td&gt;
&lt;td&gt;공식 릴리즈&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;권장도&lt;/td&gt;
&lt;td&gt;낮음&lt;/td&gt;
&lt;td&gt;&lt;b&gt;높음 (권장)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;권장&lt;/b&gt;: 공식 릴리즈는 항상 Annotated Tag를 사용하세요!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Tag 생성하기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;현재 커밋에 Tag 생성&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# Annotated Tag 생성 (권장)
git tag -a v1.0.0 -m &quot;첫 번째 정식 릴리즈&quot;

# Lightweight Tag 생성
git tag v1.0.0

# 긴 메시지로 Tag 생성 (에디터 열림)
git tag -a v1.0.0
# 에디터에서 메시지 작성 후 저장&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;과거 커밋에 Tag 생성&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 커밋 히스토리 확인
git log --oneline

# 출력
a1b2c3d feat: 사용자 인증 기능 추가
b2c3d4e fix: 로그인 버그 수정
c3d4e5f init: 프로젝트 초기 설정

# 특정 커밋에 Tag 생성
git tag -a v1.0.0 a1b2c3d -m &quot;사용자 인증 기능 릴리즈&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실전 예시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# === 시나리오: v1.0.0 릴리즈 ===

# 1. 현재 상태 확인
git log --oneline -5

# 2. 최종 커밋에 Tag 생성
git tag -a v1.0.0 -m &quot;Release v1.0.0

주요 기능:
- 사용자 인증 (로그인/회원가입)
- 프로필 관리
- 대시보드

버그 수정:
- 로그인 세션 만료 이슈 수정
- UI 반응형 개선&quot;

# 3. Tag 확인
git tag
# v1.0.0

# 4. Tag 상세 정보 확인
git show v1.0.0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Tag 확인하기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tag 목록 보기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 모든 Tag 목록
git tag

# 출력
v1.0.0
v1.1.0
v1.1.1
v2.0.0

# 알파벳 순서로 정렬
git tag --sort=v:refname

# 패턴으로 검색
git tag -l &quot;v1.*&quot;
# v1.0.0
# v1.1.0
# v1.1.1

git tag -l &quot;v2.*&quot;
# v2.0.0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tag 정보 상세 보기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# Annotated Tag 정보 보기
git show v1.0.0

# 출력
tag v1.0.0
Tagger: RyanSin &amp;lt;ryan@example.com&amp;gt;
Date:   Mon Dec 16 10:00:00 2024 +0900

첫 번째 정식 릴리즈

commit a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0
...

# 간단하게 보기
git tag -n
# v1.0.0    첫 번째 정식 릴리즈
# v1.1.0    새 기능 추가

# 여러 줄 메시지 보기
git tag -n5&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tag가 가리키는 커밋 확인&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;gcode&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# Tag의 커밋 해시 확인
git rev-parse v1.0.0

# 출력
a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0

# Tag와 커밋 함께 보기
git log --oneline --decorate

# 출력
a1b2c3d (HEAD -&amp;gt; main, tag: v1.0.0) feat: 인증 기능 추가
b2c3d4e fix: 버그 수정&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Tag 삭제하기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;로컬 Tag 삭제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 로컬 Tag 삭제
git tag -d v1.0.0

# 출력
Deleted tag 'v1.0.0' (was a1b2c3d)

# 여러 Tag 삭제
git tag -d v1.0.0 v1.1.0 v1.1.1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;원격 Tag 삭제&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 원격 저장소의 Tag 삭제
git push origin --delete v1.0.0

# 또는
git push origin :refs/tags/v1.0.0

# 여러 Tag 삭제
git push origin --delete v1.0.0 v1.1.0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tag 수정하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tag는 한번 만들면 수정할 수 없습니다. 삭제 후 다시 만들어야 합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 잘못된 Tag 삭제
git tag -d v1.0.0

# 올바른 Tag 재생성
git tag -a v1.0.0 -m &quot;수정된 메시지&quot;

# 원격에 강제 푸시
git push origin v1.0.0 --force&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;주의&lt;/b&gt;: 이미 공개된 Tag를 수정하면 다른 사람들에게 혼란을 줄 수 있습니다!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Tag 원격 저장소에 푸시하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tag는 git push로 자동으로 전송되지 않습니다. 명시적으로 푸시해야 합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특정 Tag 푸시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 특정 Tag 하나 푸시
git push origin v1.0.0

# 출력
Total 0 (delta 0), reused 0 (delta 0)
To https://github.com/username/repo.git
 * [new tag]         v1.0.0 -&amp;gt; v1.0.0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;모든 Tag 푸시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 모든 Tag 한번에 푸시
git push origin --tags

# 출력
Total 0 (delta 0), reused 0 (delta 0)
To https://github.com/username/repo.git
 * [new tag]         v1.0.0 -&amp;gt; v1.0.0
 * [new tag]         v1.1.0 -&amp;gt; v1.1.0
 * [new tag]         v2.0.0 -&amp;gt; v2.0.0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Annotated Tag만 푸시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;applescript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# Annotated Tag만 푸시 (Lightweight 제외)
git push origin --follow-tags&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실전 워크플로우&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;mipsasm&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# === 릴리즈 배포 과정 ===

# 1. 최종 커밋 완료
git add .
git commit -m &quot;chore: v1.0.0 릴리즈 준비&quot;

# 2. Tag 생성
git tag -a v1.0.0 -m &quot;Release v1.0.0&quot;

# 3. main 브랜치 푸시
git push origin main

# 4. Tag 푸시
git push origin v1.0.0

# 또는 한번에
git push origin main --follow-tags&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Tag로 체크아웃하기&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;1844&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L1Fgx/dJMb99St9nv/BuBEk0YaREkiKjtZ2CkPO1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L1Fgx/dJMb99St9nv/BuBEk0YaREkiKjtZ2CkPO1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L1Fgx/dJMb99St9nv/BuBEk0YaREkiKjtZ2CkPO1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL1Fgx%2FdJMb99St9nv%2FBuBEk0YaREkiKjtZ2CkPO1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1490&quot; height=&quot;1844&quot; data-origin-width=&quot;1490&quot; data-origin-height=&quot;1844&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tag로 이동 (읽기 전용)&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;pf&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# Tag로 체크아웃
git checkout v1.0.0

# 경고 메시지
Note: checking out 'v1.0.0'.
You are in 'detached HEAD' state...

# 이 상태에서는 읽기만 가능
# 커밋은 가능하지만 저장되지 않음&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Tag 기반으로 브랜치 생성&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;mipsasm&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# Tag를 기반으로 새 브랜치 생성
git checkout -b hotfix-v1.0.1 v1.0.0

# 이제 이 브랜치에서 작업 가능
# ... 버그 수정 ...
git add .
git commit -m &quot;fix: 긴급 버그 수정&quot;

# 새 Tag 생성
git tag -a v1.0.1 -m &quot;핫픽스 릴리즈&quot;
git push origin hotfix-v1.0.1
git push origin v1.0.1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특정 Tag의 코드 확인&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# Tag의 파일 보기
git show v1.0.0:src/app.js

# Tag 시점의 전체 파일 목록
git ls-tree -r v1.0.0 --name-only

# Tag 시점의 코드 비교
git diff v1.0.0 v2.0.0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Semantic Versioning (유의적 버전)&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1382&quot; data-origin-height=&quot;1446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/curIvS/dJMcagc0Eq6/upVsYN62rJO7KKJD1wUGCk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/curIvS/dJMcagc0Eq6/upVsYN62rJO7KKJD1wUGCk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/curIvS/dJMcagc0Eq6/upVsYN62rJO7KKJD1wUGCk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcurIvS%2FdJMcagc0Eq6%2FupVsYN62rJO7KKJD1wUGCk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1382&quot; height=&quot;1446&quot; data-origin-width=&quot;1382&quot; data-origin-height=&quot;1446&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;SemVer 규칙&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버전 번호는 MAJOR.MINOR.PATCH 형식을 따릅니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;css&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;버전 형식: v주버전.부버전.수버전

예시: v2.4.1
      &amp;uarr; &amp;uarr; &amp;uarr;
      │ │ └─ PATCH: 버그 수정 (2.4.0 &amp;rarr; 2.4.1)
      │ └─── MINOR: 기능 추가 (2.3.0 &amp;rarr; 2.4.0)
      └───── MAJOR: 호환성 없는 변경 (1.x.x &amp;rarr; 2.0.0)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;버전 증가 규칙&lt;/h3&gt;
&lt;div&gt;버전증가 시점예시
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;MAJOR&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;기존 API와 호환되지 않는 변경&lt;/td&gt;
&lt;td&gt;v1.5.3 &amp;rarr; v2.0.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;MINOR&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;하위 호환되는 새 기능 추가&lt;/td&gt;
&lt;td&gt;v1.5.3 &amp;rarr; v1.6.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;PATCH&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;하위 호환되는 버그 수정&lt;/td&gt;
&lt;td&gt;v1.5.3 &amp;rarr; v1.5.4&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;버전 번호 예시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;mipsasm&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 첫 번째 개발 버전
v0.1.0   # 개발 초기

# 베타 버전
v0.9.0   # 거의 완성
v0.9.1   # 베타 버그 수정

# 첫 정식 릴리즈
v1.0.0   # 정식 출시!

# 버그 수정
v1.0.1   # 긴급 버그 수정
v1.0.2   # 추가 버그 수정

# 새 기능 추가
v1.1.0   # 사용자 알림 기능 추가
v1.2.0   # 검색 기능 추가

# 큰 변경
v2.0.0   # 전체 UI 개편 (호환성 깨짐)
v2.0.1   # 버그 수정
v2.1.0   # 새 기능 추가&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Pre-release 버전&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 알파 버전 (내부 테스트)
v1.0.0-alpha
v1.0.0-alpha.1

# 베타 버전 (공개 테스트)
v1.0.0-beta
v1.0.0-beta.1
v1.0.0-beta.2

# RC (Release Candidate)
v1.0.0-rc.1
v1.0.0-rc.2

# 정식 릴리즈
v1.0.0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실전 버전 관리 예시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 프로젝트 시작
git tag -a v0.1.0 -m &quot;초기 개발 버전&quot;

# 기능 추가
git tag -a v0.2.0 -m &quot;로그인 기능 추가&quot;
git tag -a v0.3.0 -m &quot;프로필 기능 추가&quot;

# 베타 테스트
git tag -a v0.9.0-beta -m &quot;베타 버전&quot;
git tag -a v0.9.1-beta -m &quot;베타 버그 수정&quot;

# 정식 출시
git tag -a v1.0.0 -m &quot;정식 출시!&quot;

# 버그 수정
git tag -a v1.0.1 -m &quot;로그인 버그 수정&quot;

# 새 기능
git tag -a v1.1.0 -m &quot;알림 기능 추가&quot;

# 큰 변경
git tag -a v2.0.0 -m &quot;새로운 UI 및 API 변경&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- GitHub Release 만들기&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;2002&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QpkKp/dJMcahJK2ld/lm76uvrFeHKeczHm5ZN34K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QpkKp/dJMcahJK2ld/lm76uvrFeHKeczHm5ZN34K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QpkKp/dJMcahJK2ld/lm76uvrFeHKeczHm5ZN34K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQpkKp%2FdJMcahJK2ld%2Flm76uvrFeHKeczHm5ZN34K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1520&quot; height=&quot;2002&quot; data-origin-width=&quot;1520&quot; data-origin-height=&quot;2002&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GitHub에서 Tag를 사용해 Release를 만들 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;방법 1: CLI로 Release 생성&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;vala&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 1. Tag 생성
git tag -a v1.0.0 -m &quot;Release v1.0.0&quot;

# 2. Tag 푸시
git push origin v1.0.0

# 3. GitHub에서 자동으로 Release 페이지 생성됨
# https://github.com/username/repo/releases/tag/v1.0.0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;방법 2: GitHub 웹에서 Release 생성&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;1. GitHub 저장소 페이지 접속
2. &quot;Releases&quot; 탭 클릭
3. &quot;Create a new release&quot; 버튼 클릭
4. Tag 선택 또는 새로 생성
5. Release title 입력 (예: v1.0.0)
6. Release notes 작성
7. 파일 첨부 (선택 사항)
8. &quot;Publish release&quot; 클릭&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Release Notes 작성 예시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;## v1.0.0 - 2024-12-16

###   새로운 기능
- 사용자 인증 시스템 (로그인/회원가입)
- 프로필 관리 페이지
- 대시보드 구현

###   버그 수정
- 로그인 세션 만료 이슈 수정
- 모바일 반응형 UI 개선
- 이메일 유효성 검사 버그 수정

###   개선 사항
- API 응답 속도 30% 향상
- 데이터베이스 쿼리 최적화
- 에러 메시지 개선

### ⚠️ Breaking Changes
- 없음

###   의존성
- React 18.2.0
- Node.js 18.x 이상 필요

###   기여자
- @ryan-sin
- @sarah-kim
- @john-lee

**Full Changelog**: https://github.com/username/repo/compare/v0.9.0...v1.0.0&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 실전 릴리즈 워크플로우&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1532&quot; data-origin-height=&quot;1858&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A5Zmn/dJMcadUPpbv/2xPnZ8G9wZKzIVEiKw7ex1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A5Zmn/dJMcadUPpbv/2xPnZ8G9wZKzIVEiKw7ex1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A5Zmn/dJMcadUPpbv/2xPnZ8G9wZKzIVEiKw7ex1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA5Zmn%2FdJMcadUPpbv%2F2xPnZ8G9wZKzIVEiKw7ex1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1532&quot; height=&quot;1858&quot; data-origin-width=&quot;1532&quot; data-origin-height=&quot;1858&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1560&quot; data-origin-height=&quot;2056&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vkjWv/dJMcad1ALBy/uXYxWgQUasleJuZgtCxbb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vkjWv/dJMcad1ALBy/uXYxWgQUasleJuZgtCxbb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vkjWv/dJMcad1ALBy/uXYxWgQUasleJuZgtCxbb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvkjWv%2FdJMcad1ALBy%2FuXYxWgQUasleJuZgtCxbb1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1560&quot; height=&quot;2056&quot; data-origin-width=&quot;1560&quot; data-origin-height=&quot;2056&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;전체 릴리즈 프로세스&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# === 1. 개발 완료 확인 ===
# 모든 기능이 develop 브랜치에 병합됨

# === 2. Release 브랜치 생성 ===
git checkout develop
git checkout -b release/v1.0.0

# === 3. 버전 번호 업데이트 ===
# package.json, version.txt 등에서 버전 번호 수정
git add .
git commit -m &quot;chore: bump version to 1.0.0&quot;

# === 4. 최종 테스트 ===
# 테스트 실행, 버그 수정

# === 5. main 브랜치로 병합 ===
git checkout main
git merge --no-ff release/v1.0.0
git push origin main

# === 6. Tag 생성 ===
git tag -a v1.0.0 -m &quot;Release v1.0.0

주요 기능:
- 사용자 인증
- 프로필 관리
- 대시보드

버그 수정:
- 로그인 세션 이슈
- UI 반응형 개선&quot;

# === 7. Tag 푸시 ===
git push origin v1.0.0

# === 8. develop 브랜치에도 병합 ===
git checkout develop
git merge --no-ff release/v1.0.0
git push origin develop

# === 9. Release 브랜치 삭제 ===
git branch -d release/v1.0.0

# === 10. GitHub에서 Release 생성 ===
# GitHub 웹 인터페이스에서 Release Notes 작성&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;핫픽스 워크플로우&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;lsl&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# === 긴급 버그 발견! v1.0.0 &amp;rarr; v1.0.1 ===

# 1. main 브랜치의 Tag에서 hotfix 브랜치 생성
git checkout -b hotfix/v1.0.1 v1.0.0

# 2. 버그 수정
# ... 코드 수정 ...
git add .
git commit -m &quot;fix: 로그인 버그 긴급 수정&quot;

# 3. 버전 번호 업데이트
git commit -m &quot;chore: bump version to 1.0.1&quot;

# 4. main에 병합
git checkout main
git merge --no-ff hotfix/v1.0.1
git push origin main

# 5. Tag 생성 및 푸시
git tag -a v1.0.1 -m &quot;핫픽스: 로그인 버그 수정&quot;
git push origin v1.0.1

# 6. develop에도 병합
git checkout develop
git merge --no-ff hotfix/v1.0.1
git push origin develop

# 7. hotfix 브랜치 삭제
git branch -d hotfix/v1.0.1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Tag 명령어 정리&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# === 생성 ===
git tag v1.0.0                           # Lightweight Tag
git tag -a v1.0.0 -m &quot;메시지&quot;             # Annotated Tag (권장)
git tag -a v1.0.0 커밋해시 -m &quot;메시지&quot;     # 특정 커밋에 Tag

# === 확인 ===
git tag                                  # Tag 목록
git tag -l &quot;v1.*&quot;                        # 패턴으로 검색
git tag -n                               # 메시지와 함께 보기
git show v1.0.0                          # Tag 상세 정보
git log --oneline --decorate             # 커밋과 Tag 함께 보기

# === 삭제 ===
git tag -d v1.0.0                        # 로컬 Tag 삭제
git push origin --delete v1.0.0          # 원격 Tag 삭제
git push origin :refs/tags/v1.0.0        # 원격 Tag 삭제 (다른 방법)

# === 푸시 ===
git push origin v1.0.0                   # 특정 Tag 푸시
git push origin --tags                   # 모든 Tag 푸시
git push origin --follow-tags            # Annotated Tag만 푸시

# === 체크아웃 ===
git checkout v1.0.0                      # Tag로 이동 (detached HEAD)
git checkout -b 브랜치명 v1.0.0           # Tag 기반 브랜치 생성

# === 비교 ===
git diff v1.0.0 v2.0.0                   # 두 Tag 비교
git log v1.0.0..v2.0.0                   # Tag 간 커밋 이력&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Tag 사용 팁&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 항상 Annotated Tag 사용&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;❌ 나쁜 예:
git tag v1.0.0

✅ 좋은 예:
git tag -a v1.0.0 -m &quot;Release v1.0.0 - 첫 번째 정식 릴리즈&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 의미있는 메시지 작성&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;css&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;❌ 나쁜 예:
git tag -a v1.0.0 -m &quot;릴리즈&quot;

✅ 좋은 예:
git tag -a v1.0.0 -m &quot;Release v1.0.0

주요 기능:
- 사용자 인증 시스템
- 프로필 관리
- 대시보드

버그 수정:
- 로그인 세션 만료 이슈
- UI 반응형 개선&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Semantic Versioning 준수&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# MAJOR: 호환성 없는 변경
v1.0.0 &amp;rarr; v2.0.0

# MINOR: 새 기능 추가
v1.0.0 &amp;rarr; v1.1.0

# PATCH: 버그 수정
v1.0.0 &amp;rarr; v1.0.1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Tag 푸시 잊지 않기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;mipsasm&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# Tag는 자동으로 푸시되지 않음!
git push origin main
git push origin v1.0.0  # Tag도 별도로 푸시

# 또는 한번에
git push origin main --follow-tags&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 공개된 Tag는 수정하지 않기&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 이미 배포된 Tag는 절대 수정하지 마세요
# 대신 새로운 버전을 만드세요

# ❌ 나쁜 예:
git tag -d v1.0.0
git tag -a v1.0.0 -m &quot;수정...&quot;
git push origin v1.0.0 --force

# ✅ 좋은 예:
git tag -a v1.0.1 -m &quot;수정 사항 포함&quot;
git push origin v1.0.1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. CHANGELOG 파일 유지&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;clean&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# CHANGELOG.md 파일에 버전별 변경 사항 기록

## [1.0.0] - 2024-12-16
### Added
- 사용자 인증 기능
- 프로필 관리

### Fixed
- 로그인 버그 수정

### Changed
- API 응답 속도 개선&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 자주 하는 실수와 해결법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실수 1: Tag를 푸시하지 않음&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제: &lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;bash&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;git tag -a v1.0.0 -m &quot;릴리즈&quot;
git push origin main
# Tag는 푸시되지 않음!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결: &lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;bash&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;mipsasm&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# Tag도 별도로 푸시해야 함
git push origin v1.0.0

# 또는 항상 함께 푸시
git push origin main --follow-tags&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실수 2: 잘못된 버전 번호&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제: &lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;bash&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;git tag v1.0.0
# 이미 v1.1.0이 있는데...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결: &lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;bash&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 항상 최신 Tag 확인
git tag | sort -V

# 올바른 버전 번호 사용
git tag -a v1.2.0 -m &quot;메시지&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실수 3: Lightweight Tag 사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제: &lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;bash&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;git tag v1.0.0  # 정보가 부족함&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결: &lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;bash&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 삭제 후 Annotated Tag 재생성
git tag -d v1.0.0
git tag -a v1.0.0 -m &quot;상세한 메시지&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실수 4: 공개된 Tag 수정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제: &lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;bash&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;git tag -d v1.0.0
git tag -a v1.0.0 -m &quot;수정&quot;
git push origin v1.0.0 --force
# 다른 사람들에게 혼란!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결: &lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;bash&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 새로운 버전 만들기
git tag -a v1.0.1 -m &quot;수정 사항&quot;
git push origin v1.0.1&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실수 5: Tag와 브랜치 이름 중복&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제: &lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;bash&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;git tag v1.0.0
git branch v1.0.0  # 혼란 발생&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결 : &lt;/b&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;bash&lt;/span&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;crmsh&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# Tag와 브랜치는 다른 이름 사용
git tag v1.0.0
git branch release/v1.0.0  # 명확한 구분&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 Git Tag를 사용한 버전 관리와 릴리즈에 대해 알아봤습니다. Tag는 소프트웨어의 특정 시점을 표시하는 중요한 기능으로, 릴리즈 관리에 필수적입니다. 항상 Annotated Tag를 사용하고, Semantic Versioning 규칙을 따르며, 의미있는 메시지를 작성하는 습관을 들이시기 바랍니다. Tag는 한번 공개하면 수정하지 않는 것이 원칙입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 시간에는 Git Reset vs Revert vs Restore에 대해 알아보겠습니다.&lt;/p&gt;</description>
      <category>컴퓨터공학/Git</category>
      <author>RyanSin</author>
      <guid isPermaLink="true">https://any-ting.tistory.com/192</guid>
      <comments>https://any-ting.tistory.com/192#entry192comment</comments>
      <pubDate>Sat, 27 Dec 2025 20:00:54 +0900</pubDate>
    </item>
    <item>
      <title>[Git] - Git Stash - 임시 저장 활용법</title>
      <link>https://any-ting.tistory.com/191</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 이번 시간에는 Git Stash에 대해 알아보겠습니다. Stash는 작업 중인 변경사항을 임시로 저장하는 기능으로, 브랜치 전환이나 긴급 작업 시 매우 유용합니다. 실무에서 자주 사용하는 필수 기능이니 꼭 익혀두시기 바랍니다. 혹시 이전 시간에 내용을 학습하고 오시지 못 하신 분들은 학습하고 오시는 걸 추천드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://any-ting.tistory.com/190&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Git] - Pull Request(PR) / Merge Request(MR) 작성법&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Stash란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Stash는 현재 작업 중인 변경사항을 임시로 저장해두는 Git의 기능입니다. 커밋하지 않은 변경사항을 안전하게 보관하고, 나중에 다시 불러올 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1614&quot; data-origin-height=&quot;1434&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Q3bAA/dJMcac9sWg4/lk4l8d8wGXBakJKzUm2e30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Q3bAA/dJMcac9sWg4/lk4l8d8wGXBakJKzUm2e30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Q3bAA/dJMcac9sWg4/lk4l8d8wGXBakJKzUm2e30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQ3bAA%2FdJMcac9sWg4%2Flk4l8d8wGXBakJKzUm2e30%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1614&quot; height=&quot;1434&quot; data-origin-width=&quot;1614&quot; data-origin-height=&quot;1434&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Stash의 필요성&lt;/h3&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;상황 1: 기능 개발 중인데 긴급 버그 수정 요청이 들어옴
- 현재 작업을 커밋하기엔 아직 완성되지 않음
- 하지만 브랜치를 전환해야 함
- 해결: Stash로 임시 저장!

상황 2: 잘못된 브랜치에서 작업함
- develop에서 작업해야 하는데 main에서 작업 중
- 변경사항을 이동시켜야 함
- 해결: Stash로 저장하고 올바른 브랜치로 이동!

상황 3: pull 전에 로컬 변경사항이 있음
- git pull을 해야 하는데 충돌 우려
- 해결: Stash로 저장하고 pull 후 복원!
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Stash 저장 위치&lt;/h3&gt;
&lt;pre class=&quot;gherkin&quot;&gt;&lt;code&gt;Working Directory    Stash Stack    Repository
 (작업 디렉토리)        (임시 저장소)      (저장소)
      |                   |               |
      | git stash save    |               |
      | ----------------&amp;gt; |               |
      |                   |               |
      | git stash pop     |               |
      | &amp;lt;---------------- |               |
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Stash는 스택(Stack) 구조로 관리됩니다. 가장 최근에 저장한 것이 가장 먼저 나옵니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Stash 기본 명령어&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 변경사항 저장하기&lt;/h3&gt;
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt;# 기본 stash 저장
git stash

# 또는
git stash save

# 메시지와 함께 저장 (권장)
git stash save &quot;작업 내용 설명&quot;

# 예시
git stash save &quot;로그인 기능 작업 중&quot;

# 출력
Saved working directory and index state On feature/login: 로그인 기능 작업 중
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Stash 목록 확인하기&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;# 저장된 stash 목록 보기
git stash list

# 출력 예시
stash@{0}: On feature/login: 로그인 기능 작업 중
stash@{1}: WIP on main: a1b2c3d Update README
stash@{2}: On develop: 결제 모듈 테스트
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;stash 번호 이해하기:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;stash@{0}: 가장 최근에 저장한 stash&lt;/li&gt;
&lt;li&gt;stash@{1}: 그 이전에 저장한 stash&lt;/li&gt;
&lt;li&gt;stash@{2}: 더 이전에 저장한 stash&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1432&quot; data-origin-height=&quot;1254&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cAwsHJ/dJMcafLVxv9/dhdEJnaAudYfDGfpQY6xN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cAwsHJ/dJMcafLVxv9/dhdEJnaAudYfDGfpQY6xN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cAwsHJ/dJMcafLVxv9/dhdEJnaAudYfDGfpQY6xN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcAwsHJ%2FdJMcafLVxv9%2FdhdEJnaAudYfDGfpQY6xN0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1432&quot; height=&quot;1254&quot; data-origin-width=&quot;1432&quot; data-origin-height=&quot;1254&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Stash 내용 확인하기&lt;/h3&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;# 가장 최근 stash의 변경사항 확인
git stash show

# 출력
 src/login.js | 15 +++++++++++++++
 src/auth.js  |  8 ++++++--
 2 files changed, 21 insertions(+), 2 deletions(-)

# 상세 변경 내용 확인 (diff)
git stash show -p

# 특정 stash 확인
git stash show stash@{1}
git stash show -p stash@{1}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Stash 복원하기&lt;/h3&gt;
&lt;pre class=&quot;perl&quot;&gt;&lt;code&gt;# 방법 1: pop (복원 후 stash 삭제) - 일반적으로 사용
git stash pop

# 특정 stash를 pop
git stash pop stash@{1}

# 방법 2: apply (복원 후 stash 유지)
git stash apply

# 특정 stash를 apply
git stash apply stash@{2}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;pop vs apply 차이:&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명령어 복원 stash 보존 사용 시점&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;pop&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌ 삭제됨&lt;/td&gt;
&lt;td&gt;일반적인 경우 (권장)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;apply&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ 유지됨&lt;/td&gt;
&lt;td&gt;여러 브랜치에 적용해야 할 때&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. Stash 삭제하기&lt;/h3&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# 가장 최근 stash 삭제
git stash drop

# 특정 stash 삭제
git stash drop stash@{1}

# 모든 stash 삭제
git stash clear

# 삭제 전 확인
git stash list
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;1792&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3NoSQ/dJMcaaDQDj4/qtSGK7ZdXf6eb8M5SQNna0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3NoSQ/dJMcaaDQDj4/qtSGK7ZdXf6eb8M5SQNna0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3NoSQ/dJMcaaDQDj4/qtSGK7ZdXf6eb8M5SQNna0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3NoSQ%2FdJMcaaDQDj4%2FqtSGK7ZdXf6eb8M5SQNna0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1376&quot; height=&quot;1792&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;1792&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Stash 고급 사용법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Untracked 파일도 함께 저장&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 stash는 추적 중인(tracked) 파일만 저장합니다.&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 새로 생성한 파일(untracked)도 함께 저장
git stash save -u &quot;메시지&quot;

# 또는
git stash save --include-untracked &quot;메시지&quot;

# 예시
echo &quot;새 파일&quot; &amp;gt; new-file.txt
git stash save -u &quot;새 파일 포함하여 저장&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 특정 파일만 Stash&lt;/h3&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;# 특정 파일만 stash (Git 2.13+)
git stash push -m &quot;메시지&quot; 파일1 파일2

# 예시
git stash push -m &quot;로그인 파일만 저장&quot; src/login.js src/auth.js
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Stash를 브랜치로 만들기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stash를 새로운 브랜치로 만들 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# stash를 새 브랜치로 생성
git stash branch 브랜치명

# 예시
git stash branch feature/stashed-work

# 결과:
# 1. 새 브랜치 생성
# 2. stash 내용이 자동으로 적용됨
# 3. stash가 자동으로 삭제됨
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Stash를 커밋으로 확인&lt;/h3&gt;
&lt;pre class=&quot;perl&quot;&gt;&lt;code&gt;# stash는 내부적으로 커밋입니다
# stash의 커밋 해시 확인
git stash list --format=&quot;%gd: %H&quot;

# 출력
stash@{0}: a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 실전 시나리오&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;1738&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHb7HH/dJMcachmyt5/fBXlkGU8PaaWlbHpy7YuMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHb7HH/dJMcachmyt5/fBXlkGU8PaaWlbHpy7YuMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHb7HH/dJMcachmyt5/fBXlkGU8PaaWlbHpy7YuMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHb7HH%2FdJMcachmyt5%2FfBXlkGU8PaaWlbHpy7YuMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1122&quot; height=&quot;1738&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;1738&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시나리오 1: 긴급 버그 수정&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 상황: feature/payment 브랜치에서 결제 기능 개발 중
# 긴급: main 브랜치의 버그를 수정해야 함

# 1. 현재 작업 저장
git stash save &quot;결제 기능 개발 중&quot;

# 2. 상태 확인 (깨끗한 상태)
git status
# On branch feature/payment
# nothing to commit, working tree clean

# 3. main 브랜치로 이동
git checkout main

# 4. 버그 수정
# ... 버그 수정 작업 ...
git add .
git commit -m &quot;fix: 긴급 버그 수정&quot;

# 5. 다시 feature/payment로 돌아가기
git checkout feature/payment

# 6. 저장했던 작업 복원
git stash pop

# 7. 계속 작업
# ... 결제 기능 개발 계속 ...
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시나리오 2: 잘못된 브랜치에서 작업&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 상황: main 브랜치에서 작업했는데, develop에서 했어야 함

# 1. 변경사항 확인
git status
# On branch main
# Changes not staged for commit:
#   modified:   src/app.js

# 2. 현재 작업 저장
git stash save &quot;develop에서 작업해야 하는 내용&quot;

# 3. 올바른 브랜치로 이동
git checkout develop

# 4. 저장했던 작업 복원
git stash pop

# 5. 이제 올바른 브랜치에서 작업 계속
git add .
git commit -m &quot;feat: 새 기능 추가&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시나리오 3: Pull 전에 로컬 변경사항 처리&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 상황: 원격 저장소를 pull 해야 하는데 로컬에 변경사항이 있음

# 1. 현재 작업 저장
git stash save &quot;pull 전 로컬 작업&quot;

# 2. 원격 저장소에서 최신 코드 가져오기
git pull origin develop

# 3. 저장했던 작업 복원
git stash pop

# 4. 충돌이 발생하면 해결
# ... 충돌 해결 ...
git add .
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시나리오 4: 여러 브랜치에 같은 수정 적용&lt;/h3&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 상황: 같은 버그 수정을 여러 브랜치에 적용해야 함

# 1. 버그 수정 작업
# ... 버그 수정 ...

# 2. 수정 내용을 stash로 저장
git stash save &quot;공통 버그 수정&quot;

# 3. 첫 번째 브랜치에 적용
git checkout feature/login
git stash apply  # apply 사용 (stash 유지)
git add .
git commit -m &quot;fix: 버그 수정&quot;

# 4. 두 번째 브랜치에 적용
git checkout feature/payment
git stash apply  # 같은 stash를 다시 apply
git add .
git commit -m &quot;fix: 버그 수정&quot;

# 5. 세 번째 브랜치에 적용
git checkout feature/profile
git stash pop    # 마지막은 pop으로 stash 삭제
git add .
git commit -m &quot;fix: 버그 수정&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Stash 워크플로우 전체 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 개발 과정에서의 stash 사용 예시입니다.&lt;/p&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# === 오전 9시: 새 기능 개발 시작 ===
git checkout -b feature/user-dashboard
# ... 코딩 ...
echo &quot;대시보드 컴포넌트&quot; &amp;gt; dashboard.js

# === 오전 11시: 긴급 회의로 인한 작업 중단 ===
git stash save &quot;대시보드 기능 개발 중 - 50% 완성&quot;

# === 오후 2시: 다른 긴급 작업 ===
git checkout develop
git checkout -b hotfix/security-issue
# ... 보안 이슈 수정 ...
git commit -m &quot;fix: 보안 취약점 수정&quot;
git checkout develop
git merge hotfix/security-issue

# === 오후 3시: 원래 작업 재개 ===
git checkout feature/user-dashboard
git stash list
# stash@{0}: On feature/user-dashboard: 대시보드 기능 개발 중 - 50% 완성

git stash pop
# ... 작업 계속 ...

# === 오후 5시: 작업 완료 ===
git add .
git commit -m &quot;feat: 사용자 대시보드 구현 완료&quot;
git push origin feature/user-dashboard
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Stash와 Commit 비교&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;1482&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QfqZX/dJMcafFahv5/4Ff0v2JduNqmOcJ0ssZIc0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QfqZX/dJMcafFahv5/4Ff0v2JduNqmOcJ0ssZIc0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QfqZX/dJMcafFahv5/4Ff0v2JduNqmOcJ0ssZIc0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQfqZX%2FdJMcafFahv5%2F4Ff0v2JduNqmOcJ0ssZIc0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1538&quot; height=&quot;1482&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;1482&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항목 Stash Commit&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;목적&lt;/td&gt;
&lt;td&gt;임시 저장&lt;/td&gt;
&lt;td&gt;영구 저장&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;공유&lt;/td&gt;
&lt;td&gt;로컬 전용&lt;/td&gt;
&lt;td&gt;원격 공유 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;히스토리&lt;/td&gt;
&lt;td&gt;포함 안됨&lt;/td&gt;
&lt;td&gt;포함됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;메시지&lt;/td&gt;
&lt;td&gt;선택 사항&lt;/td&gt;
&lt;td&gt;필수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;사용 시점&lt;/td&gt;
&lt;td&gt;작업 중단 시&lt;/td&gt;
&lt;td&gt;작업 완료 시&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;복원&lt;/td&gt;
&lt;td&gt;pop/apply&lt;/td&gt;
&lt;td&gt;checkout&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;언제 Stash를 쓸까?&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;✅ Stash 사용:
- 작업이 아직 완성되지 않았을 때
- 임시로 다른 작업을 해야 할 때
- 커밋하기에는 너무 작은 변경일 때

✅ Commit 사용:
- 작업이 완성되었을 때
- 의미있는 변경 단위일 때
- 팀원과 공유해야 할 때
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Stash 충돌 해결&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;stash를 복원할 때 충돌이 발생할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;충돌 발생 예시&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;# stash pop 시도
git stash pop

# 충돌 발생!
Auto-merging src/app.js
CONFLICT (content): Merge conflict in src/app.js
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;충돌 해결 방법&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 1. 충돌 파일 확인
git status

# 출력
Unmerged paths:
  both modified:   src/app.js

# 2. 파일 열어서 충돌 부분 수정
# src/app.js 파일 내용:
&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; Updated upstream
현재 브랜치의 내용
=======
Stash에 저장된 내용
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; Stashed changes

# 3. 충돌 해결 후 저장
# ... 원하는 내용으로 수정 ...

# 4. 스테이징
git add src/app.js

# 5. stash 충돌 해결 완료
# (자동으로 stash가 삭제됨)

# 만약 stash를 유지하고 싶다면
git stash drop  # 수동으로 삭제
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;충돌 시 안전하게 취소하기&lt;/h3&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;# 충돌이 복잡해서 취소하고 싶을 때
git reset --merge

# stash는 그대로 유지되므로 나중에 다시 시도 가능
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 자주 하는 실수와 해결법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실수 1: Stash를 까먹음&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;git stash save &quot;중요한 작업&quot;
# ... 한참 후 ...
# 어디에 저장했더라?
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 항상 의미있는 메시지와 함께 저장
git stash save &quot;로그인 기능 - 폼 유효성 검사 추가 중&quot;

# stash 목록 확인
git stash list
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실수 2: 여러 개의 Stash가 쌓임&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;git stash list
stash@{0}: WIP on main
stash@{1}: WIP on develop
stash@{2}: WIP on feature
stash@{3}: WIP on bugfix
# ... 너무 많아!
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;# 필요없는 stash 정리
git stash drop stash@{3}
git stash drop stash@{2}

# 또는 특정 stash를 최신으로 만들기
git stash apply stash@{3}
git stash drop stash@{3}
git stash save &quot;정리한 작업&quot;

# 모두 삭제하고 새로 시작
git stash clear
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실수 3: Stash 했는데 파일이 사라짐&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;gauss&quot;&gt;&lt;code&gt;git stash save
# 어? 파일이 다 사라졌어!
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;설명:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;haml&quot;&gt;&lt;code&gt;Stash는 정상 작동한 것입니다!
- stash는 변경사항을 &quot;임시 보관&quot;하고
- 작업 디렉토리를 &quot;깨끗한 상태&quot;로 만듭니다
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;복원:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;# 바로 복원하면 됩니다
git stash pop
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실수 4: Stash Pop 후 충돌 발생&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;git stash pop
# 충돌 발생... 어떻게 하지?
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;주의:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;erlang-repl&quot;&gt;&lt;code&gt;충돌이 발생하면 stash가 자동으로 삭제되지 않습니다!
수동으로 충돌을 해결한 후 drop 해야 합니다.
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 1. 충돌 해결
# ... 파일 수정 ...
git add .

# 2. stash 수동 삭제
git stash drop

# 또는 처음부터 apply 사용
git stash apply  # 충돌 해결 후에도 stash 유지
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실수 5: 잘못된 Stash를 Pop&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;git stash pop
# 어? 이게 아닌데...
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 1. 바로 다시 stash로 저장
git stash save &quot;다시 저장&quot;

# 2. 원하는 stash 찾기
git stash list

# 3. 올바른 stash 복원
git stash pop stash@{1}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Stash 명령어 정리&lt;/h2&gt;
&lt;pre class=&quot;perl&quot;&gt;&lt;code&gt;# === 저장 ===
git stash                              # 현재 변경사항 저장
git stash save &quot;메시지&quot;                 # 메시지와 함께 저장
git stash save -u &quot;메시지&quot;              # untracked 파일 포함
git stash push -m &quot;메시지&quot; 파일명       # 특정 파일만 저장

# === 확인 ===
git stash list                         # stash 목록 보기
git stash show                         # 최근 stash 변경사항
git stash show -p                      # 최근 stash 상세 내용
git stash show stash@{N}               # 특정 stash 확인

# === 복원 ===
git stash pop                          # 최근 stash 복원 및 삭제
git stash pop stash@{N}                # 특정 stash 복원 및 삭제
git stash apply                        # 최근 stash 복원 (유지)
git stash apply stash@{N}              # 특정 stash 복원 (유지)

# === 삭제 ===
git stash drop                         # 최근 stash 삭제
git stash drop stash@{N}               # 특정 stash 삭제
git stash clear                        # 모든 stash 삭제

# === 고급 ===
git stash branch 브랜치명               # stash를 브랜치로 만들기
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Stash 사용 팁&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 의미있는 메시지 작성&lt;/h3&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;❌ 나쁜 예:
git stash save &quot;임시&quot;
git stash save &quot;작업중&quot;

✅ 좋은 예:
git stash save &quot;로그인 폼 - 이메일 유효성 검사 추가 중&quot;
git stash save &quot;결제 API 연동 - 테스트 코드 작성 전&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 주기적으로 Stash 정리&lt;/h3&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# 일주일에 한 번 정도 확인
git stash list

# 필요없는 것은 삭제
git stash drop stash@{5}
git stash drop stash@{4}

# 또는 필요한 것만 남기고 모두 삭제
git stash clear
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Stash 전에 Diff 확인&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# stash 하기 전에 무엇이 저장되는지 확인
git diff

# 변경사항 확인 후 stash
git stash save &quot;확인한 변경사항&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Pop 대신 Apply 사용 고려&lt;/h3&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# 안전하게 apply로 먼저 확인
git stash apply

# 문제 없으면 수동으로 삭제
git stash drop

# 문제 있으면 다시 reset
git reset --hard
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 브랜치 전환 전에 항상 확인&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 브랜치 전환 전에
git status

# 변경사항이 있다면
git stash save &quot;브랜치 전환 전 작업&quot;

# 그 다음 브랜치 전환
git checkout other-branch
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 Git Stash의 사용법에 대해 알아봤습니다. Stash는 작업 중인 변경사항을 임시로 저장하는 매우 유용한 기능입니다. 브랜치 전환, 긴급 작업, pull 전 변경사항 처리 등 실무에서 자주 사용하게 되니 꼭 익숙해지시길 바랍니다. 특히 git stash pop과 git stash apply의 차이를 이해하고, 의미있는 메시지와 함께 저장하는 습관을 들이는 것이 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 시간에는 Git Tag - 버전 관리 및 릴리즈에 대해 알아보겠습니다.&lt;/p&gt;</description>
      <category>컴퓨터공학/Git</category>
      <author>RyanSin</author>
      <guid isPermaLink="true">https://any-ting.tistory.com/191</guid>
      <comments>https://any-ting.tistory.com/191#entry191comment</comments>
      <pubDate>Fri, 26 Dec 2025 20:00:30 +0900</pubDate>
    </item>
    <item>
      <title>[Git] - Pull Request(PR) / Merge Request(MR) 작성법</title>
      <link>https://any-ting.tistory.com/190</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 이번 시간에는 협업에서 가장 중요한 Pull Request(PR)와 Merge Request(MR) 작성법에 대해 알아보겠습니다. GitHub에서는 Pull Request, GitLab에서는 Merge Request라고 부르지만 기본 개념은 동일합니다. 혹시 이전 시간에 내용을 학습하고 오시지 못 하신 분들은 학습하고 오시는 걸 추천드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://any-ting.tistory.com/189&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Git] - Clone vs Fork 차이점&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Pull Request란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pull Request(PR)는 내가 작성한 코드를 프로젝트의 메인 브랜치에 병합해달라고 요청하는 기능입니다. 단순히 코드를 합치는 것이 아니라, 코드 리뷰를 받고 팀원들과 소통하는 협업의 핵심 도구입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;PR의 목적&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드 리뷰를 통한 품질 향상&lt;/li&gt;
&lt;li&gt;팀원들과의 코드 공유 및 토론&lt;/li&gt;
&lt;li&gt;변경 사항에 대한 문서화&lt;/li&gt;
&lt;li&gt;자동화된 테스트 실행&lt;/li&gt;
&lt;li&gt;프로젝트의 히스토리 관리&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;GitHub vs GitLab 용어 비교&lt;/h3&gt;
&lt;div&gt;GitHubGitLab의미
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pull Request (PR)&lt;/td&gt;
&lt;td&gt;Merge Request (MR)&lt;/td&gt;
&lt;td&gt;병합 요청&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Review&lt;/td&gt;
&lt;td&gt;Approval&lt;/td&gt;
&lt;td&gt;승인&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assignee&lt;/td&gt;
&lt;td&gt;Assignee&lt;/td&gt;
&lt;td&gt;담당자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reviewer&lt;/td&gt;
&lt;td&gt;Reviewer&lt;/td&gt;
&lt;td&gt;리뷰어&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  이 글에서는 GitHub 기준으로 설명하지만, GitLab도 동일한 방식으로 사용할 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- PR 생성 전 준비사항&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 브랜치 전략 이해하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PR을 만들기 전에 팀의 브랜치 전략을 이해해야 합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;1794&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bprO5y/dJMcadmY71F/IsJeMUcGefJMcc9eeKu2k1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bprO5y/dJMcadmY71F/IsJeMUcGefJMcc9eeKu2k1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bprO5y/dJMcadmY71F/IsJeMUcGefJMcc9eeKu2k1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbprO5y%2FdJMcadmY71F%2FIsJeMUcGefJMcc9eeKu2k1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1500&quot; height=&quot;1794&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;1794&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;main (또는 master)
  &amp;uarr;
  └─ develop
       &amp;uarr;
       ├─ feature/login
       ├─ feature/user-profile
       └─ bugfix/header-issue&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 다음과 같은 브랜치 구조를 사용합니다:&lt;/p&gt;
&lt;div&gt;브랜치용도예시
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;main/master&lt;/td&gt;
&lt;td&gt;배포용 안정 브랜치&lt;/td&gt;
&lt;td&gt;main&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;develop&lt;/td&gt;
&lt;td&gt;개발용 통합 브랜치&lt;/td&gt;
&lt;td&gt;develop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;feature/*&lt;/td&gt;
&lt;td&gt;새 기능 개발&lt;/td&gt;
&lt;td&gt;feature/login&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bugfix/*&lt;/td&gt;
&lt;td&gt;버그 수정&lt;/td&gt;
&lt;td&gt;bugfix/header-issue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hotfix/*&lt;/td&gt;
&lt;td&gt;긴급 수정&lt;/td&gt;
&lt;td&gt;hotfix/security-patch&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 작업 브랜치 생성 및 작업&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# develop 브랜치로 이동
git checkout develop

# 최신 상태로 업데이트
git pull origin develop

# 새 브랜치 생성 및 이동
git checkout -b feature/user-authentication

# 작업 진행...
# 파일 수정, 추가 등

# 변경사항 확인
git status

# 스테이징
git add .

# 커밋 (의미있는 메시지 작성)
git commit -m &quot;feat: 사용자 인증 기능 구현

- JWT 토큰 기반 인증 추가
- 로그인/로그아웃 API 구현
- 인증 미들웨어 추가&quot;

# 원격 저장소에 푸시
git push origin feature/user-authentication&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 커밋 정리하기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PR을 생성하기 전에 커밋을 깔끔하게 정리하는 것이 좋습니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;vala&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 최근 3개 커밋 합치기
git rebase -i HEAD~3

# 에디터에서 pick을 squash로 변경
# pick abc1234 feat: 로그인 기능 추가
# squash def5678 fix: 로그인 버그 수정
# squash ghi9012 refactor: 코드 정리

# 강제 푸시 (주의: 이미 공유된 브랜치는 피하기)
git push origin feature/user-authentication --force&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b&gt;주의&lt;/b&gt;: 다른 사람과 공유하는 브랜치에서는 force push를 피하세요!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- GitHub에서 PR 생성하기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. PR 생성 페이지 접근&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GitHub 저장소에서 PR을 생성하는 방법은 여러 가지가 있습니다:&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;1948&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oLU15/dJMcacBFQIr/3bBE3TLpk08rlRbl3nNiNK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oLU15/dJMcacBFQIr/3bBE3TLpk08rlRbl3nNiNK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oLU15/dJMcacBFQIr/3bBE3TLpk08rlRbl3nNiNK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoLU15%2FdJMcacBFQIr%2F3bBE3TLpk08rlRbl3nNiNK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1488&quot; height=&quot;1948&quot; data-origin-width=&quot;1488&quot; data-origin-height=&quot;1948&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;방법 1: 푸시 직후 노란색 배너 클릭&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;1c&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;푸시 직후 저장소 페이지에 나타나는
&quot;Compare &amp;amp; pull request&quot; 버튼 클릭&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;방법 2: Pull requests 탭에서 생성&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;lsl&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;1. Pull requests 탭 클릭
2. &quot;New pull request&quot; 버튼 클릭
3. 브랜치 선택&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;방법 3: 브랜치에서 직접 생성&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;1. Code 탭의 브랜치 드롭다운 클릭
2. 원하는 브랜치 옆 PR 아이콘 클릭&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 브랜치 선택&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PR을 생성할 때 다음을 명확히 선택해야 합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1514&quot; data-origin-height=&quot;1548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzG6z5/dJMcadgdVu7/quoOPHNd7DjVsYszQzeog1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzG6z5/dJMcadgdVu7/quoOPHNd7DjVsYszQzeog1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzG6z5/dJMcadgdVu7/quoOPHNd7DjVsYszQzeog1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzG6z5%2FdJMcadgdVu7%2FquoOPHNd7DjVsYszQzeog1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1514&quot; height=&quot;1548&quot; data-origin-width=&quot;1514&quot; data-origin-height=&quot;1548&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;cs&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;base: develop  &amp;larr; into (병합될 대상 브랜치)
compare: feature/user-authentication  &amp;larr; from (내가 작업한 브랜치)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. PR 제목 작성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋은 PR 제목 예시:&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;asciidoc&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;✅ 좋은 예시:
- feat: 사용자 인증 기능 구현
- fix: 헤더 메뉴 모바일 반응형 버그 수정
- refactor: API 호출 로직을 React Query로 개선
- docs: API 문서에 인증 엔드포인트 추가

❌ 나쁜 예시:
- 작업 완료
- 수정
- Update
- 기능 추가&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. PR 설명 작성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PR 설명은 변경 사항을 명확히 전달하는 중요한 부분입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기본 템플릿:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;## 작업 내용
이 PR에서 무엇을 했는지 간단히 설명합니다.

## 변경 사항
- JWT 기반 인증 시스템 구현
- 로그인/로그아웃 API 엔드포인트 추가
- 인증 미들웨어 추가
- 로그인 페이지 UI 구현

## 테스트 방법
1. `npm install` 실행
2. `npm run dev` 로 서버 실행
3. `/login` 페이지 접속
4. test@example.com / password123 으로 로그인
5. 대시보드 페이지로 리다이렉트 확인

## 스크린샷 (필요시)
![로그인 화면](이미지_URL)

## 관련 이슈
- Closes #123
- Related to #456

## 체크리스트
- [x] 코드 작성 완료
- [x] 로컬 테스트 완료
- [x] 코드 리뷰 준비 완료
- [ ] 문서 업데이트 필요&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;실제 작성 예시:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;## 작업 내용
사용자 인증 기능을 JWT 기반으로 구현했습니다.

## 변경 사항
### Backend
- `/api/auth/login` POST 엔드포인트 추가
- `/api/auth/logout` POST 엔드포인트 추가
- JWT 토큰 생성 및 검증 로직 구현
- 인증 미들웨어 (`authMiddleware.js`) 추가

### Frontend
- 로그인 페이지 UI 구현 (`/pages/Login.jsx`)
- 로그인 폼 유효성 검사 추가
- 토큰 저장 및 관리 (localStorage)
- Axios 인터셉터에 토큰 자동 포함

## 주요 기술 스택
- JWT (jsonwebtoken)
- bcrypt (비밀번호 암호화)
- React Hook Form (폼 관리)

## 테스트 방법
### 로컬 환경 설정
```bash
npm install
cp .env.example .env
# .env 파일에서 JWT_SECRET 설정
npm run dev
```

### 테스트 시나리오
1. http://localhost:3000/login 접속
2. 테스트 계정으로 로그인
   - Email: test@example.com
   - Password: password123
3. 로그인 성공 후 대시보드로 이동 확인
4. 로그아웃 버튼 클릭 후 로그인 페이지로 이동 확인
5. 인증 없이 /dashboard 접근 시 로그인 페이지로 리다이렉트 확인

## 관련 이슈
Closes #45

## 리뷰 요청 사항
- 보안 관련 부분 특히 신경써서 리뷰 부탁드립니다
- JWT 토큰 만료 시간이 적절한지 확인 부탁드립니다&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- PR 옵션 설정&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;1620&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ofQpZ/dJMcagYmIxb/4JNTlGZx9JFXVQvotkSscK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ofQpZ/dJMcagYmIxb/4JNTlGZx9JFXVQvotkSscK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ofQpZ/dJMcagYmIxb/4JNTlGZx9JFXVQvotkSscK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FofQpZ%2FdJMcagYmIxb%2F4JNTlGZx9JFXVQvotkSscK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1500&quot; height=&quot;1620&quot; data-origin-width=&quot;1500&quot; data-origin-height=&quot;1620&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Reviewers (리뷰어) 지정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드 리뷰를 받을 팀원을 지정합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;  팁:
- 해당 분야 전문가를 최소 1명 이상 지정
- 팀 규모에 따라 2-3명 정도가 적당
- 모든 팀원을 지정하면 책임이 분산될 수 있음&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Assignees (담당자) 지정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PR의 책임자를 지정합니다. 보통 본인을 지정합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Labels (레이블) 추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PR의 성격을 표시합니다.&lt;/p&gt;
&lt;div&gt;레이블의미예시
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;feature&lt;/td&gt;
&lt;td&gt;새 기능&lt;/td&gt;
&lt;td&gt;로그인 기능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bugfix&lt;/td&gt;
&lt;td&gt;버그 수정&lt;/td&gt;
&lt;td&gt;헤더 버그 수정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;hotfix&lt;/td&gt;
&lt;td&gt;긴급 수정&lt;/td&gt;
&lt;td&gt;보안 패치&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;documentation&lt;/td&gt;
&lt;td&gt;문서 작업&lt;/td&gt;
&lt;td&gt;README 업데이트&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;refactoring&lt;/td&gt;
&lt;td&gt;리팩토링&lt;/td&gt;
&lt;td&gt;코드 정리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;WIP&lt;/td&gt;
&lt;td&gt;작업 중&lt;/td&gt;
&lt;td&gt;Work In Progress&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;needs review&lt;/td&gt;
&lt;td&gt;리뷰 필요&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Milestone (마일스톤) 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특정 버전이나 목표와 연결합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;예시:
- v1.0.0 Release
- Q1 2024 Features
- Sprint 15&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. Projects 연결&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 보드와 연결하여 진행 상황을 추적합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 코드 리뷰 받기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 리뷰 요청 알림&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리뷰어가 지정되면 자동으로 알림이 전송됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 리뷰 유형&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GitHub에서 리뷰어가 남길 수 있는 피드백 유형:&lt;/p&gt;
&lt;div&gt;유형의미아이콘
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Comment&lt;/td&gt;
&lt;td&gt;단순 의견&lt;/td&gt;
&lt;td&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Approve&lt;/td&gt;
&lt;td&gt;승인 (머지 가능)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request changes&lt;/td&gt;
&lt;td&gt;수정 요청 (머지 불가)&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 리뷰 코멘트에 응답하기&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1496&quot; data-origin-height=&quot;1934&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6nQ8A/dJMcagKPSDQ/V49CE1VtLMSmTV3dix7HKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6nQ8A/dJMcagKPSDQ/V49CE1VtLMSmTV3dix7HKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6nQ8A/dJMcagKPSDQ/V49CE1VtLMSmTV3dix7HKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6nQ8A%2FdJMcagKPSDQ%2FV49CE1VtLMSmTV3dix7HKk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1496&quot; height=&quot;1934&quot; data-origin-width=&quot;1496&quot; data-origin-height=&quot;1934&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코멘트 확인:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;lsl&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;1. PR 페이지의 &quot;Files changed&quot; 탭 확인
2. 각 코멘트 확인 및 응답
3. 필요시 추가 커밋으로 수정&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;응답 예시:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;erlang&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;&amp;gt; 이 부분에서 에러 핸들링이 필요할 것 같습니다.

좋은 지적 감사합니다! try-catch 블록을 추가했습니다.
커밋: a1b2c3d&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 수정 후 추가 커밋&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;dockerfile&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 리뷰 반영하여 수정
git add .
git commit -m &quot;review: 에러 핸들링 로직 추가&quot;
git push origin feature/user-authentication

# 자동으로 PR에 반영됨&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 리뷰 완료 후 대응&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모든 리뷰가 Approve인 경우:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;erlang-repl&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;✅ 머지 준비 완료!&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Request changes가 있는 경우:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;haml&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;❌ 요청사항 수정 후 다시 리뷰 요청
- &quot;Re-request review&quot; 버튼 클릭&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- PR 머지하기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;머지 전 체크리스트&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;- [ ] 모든 리뷰가 Approve 상태인가?
- [ ] CI/CD 테스트가 통과했는가?
- [ ] 충돌(Conflict)이 없는가?
- [ ] 최신 base 브랜치를 merge 했는가?
- [ ] 문서가 업데이트 되었는가?&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;머지 옵션 선택&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GitHub에서는 3가지 머지 방식을 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;1446&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FyFdP/dJMcahpr2MR/F8anZEIq9EuxUacOaG7EqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FyFdP/dJMcahpr2MR/F8anZEIq9EuxUacOaG7EqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FyFdP/dJMcahpr2MR/F8anZEIq9EuxUacOaG7EqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFyFdP%2FdJMcahpr2MR%2FF8anZEIq9EuxUacOaG7EqK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1406&quot; height=&quot;1446&quot; data-origin-width=&quot;1406&quot; data-origin-height=&quot;1446&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. Create a merge commit (기본)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;livecodeserver&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 모든 커밋 이력이 보존됨
# 머지 커밋이 생성됨

git merge --no-ff feature/user-authentication&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;완전한 히스토리 보존&lt;/li&gt;
&lt;li&gt;브랜치 흐름을 명확히 볼 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;커밋 히스토리가 복잡해질 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. Squash and merge (권장)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;sql&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 여러 커밋을 하나로 합침
# 깔끔한 히스토리 유지

git merge --squash feature/user-authentication
git commit -m &quot;feat: 사용자 인증 기능 구현 (#45)&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;깔끔한 커밋 히스토리&lt;/li&gt;
&lt;li&gt;하나의 기능 = 하나의 커밋&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;세부 커밋 이력이 사라짐&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. Rebase and merge (고급)&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 커밋들을 base 브랜치 위로 재배치
# 선형 히스토리 유지

git rebase develop
git checkout develop
git merge feature/user-authentication&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;장점:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가장 깔끔한 선형 히스토리&lt;/li&gt;
&lt;li&gt;머지 커밋이 생성되지 않음&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;단점:&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;히스토리 변경으로 인한 리스크&lt;/li&gt;
&lt;li&gt;팀 전체가 이해해야 함&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;머지 방식 비교표&lt;/h3&gt;
&lt;div&gt;방식히스토리사용 시점난이도
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Merge commit&lt;/td&gt;
&lt;td&gt;복잡&lt;/td&gt;
&lt;td&gt;브랜치 흐름 유지 필요시&lt;/td&gt;
&lt;td&gt;⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Squash merge&lt;/td&gt;
&lt;td&gt;깔끔&lt;/td&gt;
&lt;td&gt;일반적인 경우 (권장)&lt;/td&gt;
&lt;td&gt;⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rebase merge&lt;/td&gt;
&lt;td&gt;매우 깔끔&lt;/td&gt;
&lt;td&gt;선형 히스토리 필요시&lt;/td&gt;
&lt;td&gt;⭐⭐⭐&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;머지 실행&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;lsl&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;1. PR 페이지 하단의 &quot;Merge pull request&quot; 버튼 클릭
2. 머지 방식 선택 (Squash and merge 권장)
3. 커밋 메시지 확인/수정
4. &quot;Confirm merge&quot; 클릭&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;머지 후 정리&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 로컬 브랜치로 이동
git checkout develop

# 최신 상태로 업데이트
git pull origin develop

# 작업 브랜치 삭제 (로컬)
git branch -d feature/user-authentication

# 작업 브랜치 삭제 (원격)
git push origin --delete feature/user-authentication&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;  &lt;b&gt;팁&lt;/b&gt;: GitHub에서 PR 머지 시 &quot;Delete branch&quot; 옵션을 체크하면 원격 브랜치가 자동 삭제됩니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- PR 작성 모범 사례&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 작은 PR이 좋은 PR&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;❌ 나쁜 예: 1000줄 변경, 10개 파일 수정
✅ 좋은 예: 200줄 변경, 3-4개 파일 수정

  이유:
- 리뷰어가 집중하기 쉬움
- 버그 발견 확률 증가
- 빠른 피드백 가능&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 명확한 제목과 설명&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;makefile&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;❌ 나쁜 예:
제목: 작업 완료
설명: 요청하신 기능 만들었습니다.

✅ 좋은 예:
제목: feat: 사용자 프로필 이미지 업로드 기능 추가
설명:
- S3 버킷 연동
- 이미지 리사이징 (최대 500x500)
- 지원 포맷: JPG, PNG (최대 5MB)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 테스트 포함&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;## 테스트
- [ ] 단위 테스트 작성 및 통과
- [ ] 통합 테스트 작성 및 통과
- [ ] 수동 테스트 완료
- [ ] 브라우저 호환성 테스트 (Chrome, Safari, Firefox)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 스크린샷/GIF 첨부&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UI 변경이 있는 경우 시각적 자료를 첨부합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;## Before / After

### Before
![기존 화면](before.png)

### After
![변경 화면](after.png)

## 동작 영상
![기능 시연](demo.gif)&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 관련 이슈/PR 연결&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;applescript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;## 관련 이슈
Closes #123
Fixes #456
Related to #789

## 관련 PR
Depends on #100
Blocks #101&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. 체크리스트 활용&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;markdown&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;## PR 체크리스트
- [x] 코드 컨벤션 준수
- [x] 테스트 코드 작성
- [x] 문서 업데이트
- [x] CHANGELOG 업데이트
- [ ] 성능 테스트 완료&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- PR 템플릿 설정하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;팀에서 일관된 PR을 작성하도록 템플릿을 설정할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;GitHub PR 템플릿 생성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트 루트에 .github 폴더를 만들고 템플릿 파일을 추가합니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;jboss-cli&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 디렉토리 생성
mkdir -p .github

# PR 템플릿 파일 생성
touch .github/PULL_REQUEST_TEMPLATE.md&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;템플릿 예시&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;xml&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;## 작업 내용
&amp;lt;!-- 이 PR에서 무엇을 했는지 간단히 설명해주세요 --&amp;gt;

## 변경 사항
&amp;lt;!-- 구체적인 변경 내용을 나열해주세요 --&amp;gt;
- 
- 

## 테스트 방법
&amp;lt;!-- 리뷰어가 테스트할 수 있는 방법을 설명해주세요 --&amp;gt;
1. 
2. 
3. 

## 스크린샷
&amp;lt;!-- UI 변경이 있다면 Before/After 스크린샷을 첨부해주세요 --&amp;gt;

## 관련 이슈
&amp;lt;!-- 관련된 이슈 번호를 적어주세요 --&amp;gt;
- Closes #
- Related to #

## 체크리스트
- [ ] 코드 리뷰 준비 완료
- [ ] 테스트 완료
- [ ] 문서 업데이트 완료
- [ ] CI/CD 테스트 통과

## 리뷰어에게
&amp;lt;!-- 특별히 확인해주었으면 하는 부분이 있다면 적어주세요 --&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;템플릿을 커밋하면 이후 모든 PR 생성 시 자동으로 적용됩니다.&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;armasm&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;git add .github/PULL_REQUEST_TEMPLATE.md
git commit -m &quot;docs: PR 템플릿 추가&quot;
git push origin main&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Draft PR 활용하기&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Draft PR이란?&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업이 완료되지 않았지만 진행 상황을 공유하고 싶을 때 사용합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1412&quot; data-origin-height=&quot;1854&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cSjjCS/dJMcafyomk0/cULqcIVBRJaszZZcwBo44K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cSjjCS/dJMcafyomk0/cULqcIVBRJaszZZcwBo44K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cSjjCS/dJMcafyomk0/cULqcIVBRJaszZZcwBo44K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcSjjCS%2FdJMcafyomk0%2FcULqcIVBRJaszZZcwBo44K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1412&quot; height=&quot;1854&quot; data-origin-width=&quot;1412&quot; data-origin-height=&quot;1854&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Draft PR 생성&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;lsl&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;1. PR 생성 시 &quot;Create pull request&quot; 드롭다운 클릭
2. &quot;Create draft pull request&quot; 선택
3. 작업 완료 후 &quot;Ready for review&quot; 버튼 클릭&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Draft PR 활용 시나리오&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;asciidoc&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;✅ 이럴 때 사용하세요:
- 작업 방향이 맞는지 미리 확인받고 싶을 때
- CI/CD 테스트를 먼저 돌려보고 싶을 때
- 팀원들에게 진행 상황을 공유하고 싶을 때
- 큰 작업을 진행하며 중간 피드백이 필요할 때

❌ 이럴 때는 피하세요:
- 이미 완성된 코드
- 긴급한 버그 수정&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 실전 예시: PR 전체 플로우&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 작업 흐름을 처음부터 끝까지 살펴보겠습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시나리오: 회원가입 기능 추가&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 1. 최신 develop 브랜치 업데이트
git checkout develop
git pull origin develop

# 2. 기능 브랜치 생성
git checkout -b feature/user-signup

# 3. 작업 진행
# ... 파일 수정 및 코드 작성 ...

# 4. 커밋
git add .
git commit -m &quot;feat: 회원가입 기능 구현

- 회원가입 폼 UI 추가
- 이메일 중복 체크 API 구현
- 비밀번호 유효성 검사 추가
- 회원가입 성공 시 이메일 발송&quot;

# 5. 원격 푸시
git push origin feature/user-signup

# 6. GitHub에서 PR 생성
# - 제목: feat: 회원가입 기능 구현
# - 설명: 템플릿에 따라 작성
# - 리뷰어: 팀 리더, 백엔드 개발자
# - 레이블: feature, needs review

# 7. 리뷰 받기 및 수정
# ... 리뷰 코멘트에 따라 수정 ...

git add .
git commit -m &quot;review: 비밀번호 정규식 수정&quot;
git push origin feature/user-signup

# 8. 승인 받고 머지
# GitHub에서 &quot;Squash and merge&quot; 선택

# 9. 정리
git checkout develop
git pull origin develop
git branch -d feature/user-signup
git push origin --delete feature/user-signup&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 자주 하는 실수와 해결법&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Base 브랜치를 잘못 선택함&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;stata&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;main으로 PR을 만들어야 하는데 develop으로 만들었다&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;armasm&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;PR 페이지에서 &quot;Edit&quot; 버튼 클릭 &amp;rarr; base 브랜치 변경&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 큰 PR 만들기&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;1000줄 변경, 20개 파일 수정
리뷰어가 리뷰하기 어려움&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;stata&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;PR을 여러 개로 분할
- PR 1: 데이터베이스 모델 추가
- PR 2: API 엔드포인트 구현
- PR 3: UI 컴포넌트 추가&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 커밋 메시지가 엉망&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;git commit -m &quot;수정&quot;
git commit -m &quot;ㅇㅇ&quot;
git commit -m &quot;aaa&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;mipsasm&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 커밋 합치고 메시지 수정
git rebase -i HEAD~3
# 에디터에서 squash 선택 및 메시지 수정
git push origin feature-branch --force&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 충돌(Conflict) 발생&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;armasm&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;base 브랜치가 업데이트되어 충돌 발생&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;bash&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;# 방법 1: Merge (권장)
git checkout feature/my-feature
git merge develop
# 충돌 해결 후
git add .
git commit -m &quot;merge: resolve conflicts with develop&quot;
git push origin feature/my-feature

# 방법 2: Rebase (고급)
git checkout feature/my-feature
git rebase develop
# 충돌 해결 후
git add .
git rebase --continue
git push origin feature/my-feature --force&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. PR을 잘못 만들어서 닫음&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;문제:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;stata&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;실수로 PR을 닫았는데 다시 열고 싶다&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;해결:&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;nginx&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;PR 페이지 하단의 &quot;Reopen&quot; 버튼 클릭&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- PR 리뷰어를 위한 팁&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;좋은 코드 리뷰 작성법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;1. 구체적으로 작성하기&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;ceylon&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;❌ 나쁜 예:
&quot;이 부분 고쳐주세요&quot;

✅ 좋은 예:
&quot;이 함수는 200줄이 넘어서 가독성이 떨어집니다.
사용자 검증 로직을 별도 함수로 분리하는 것이 어떨까요?
```javascript
function validateUser(user) {
  // 검증 로직
}
```
&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. 긍정적인 피드백도 남기기&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;1c&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;  좋은 코드 리뷰:
&quot;에러 핸들링을 꼼꼼하게 처리하셨네요!  &quot;
&quot;이 부분 리팩토링 정말 깔끔합니다!&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3. 질문으로 시작하기&lt;/b&gt;&lt;/p&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;markdown&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;autohotkey&quot; style=&quot;color: #abb2bf; text-align: left;&quot;&gt;&lt;code&gt;❌ 명령조:
&quot;이 변수명을 바꾸세요&quot;

✅ 질문형:
&quot;`userInfo` 대신 `userData`가 더 명확할 것 같은데 어떻게 생각하시나요?&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;리뷰 우선순위&lt;/h3&gt;
&lt;div&gt;우선순위항목예시
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;P0 (Critical)&lt;/td&gt;
&lt;td&gt;버그, 보안 이슈&lt;/td&gt;
&lt;td&gt;SQL 인젝션 취약점&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P1 (Important)&lt;/td&gt;
&lt;td&gt;성능 문제, 잘못된 로직&lt;/td&gt;
&lt;td&gt;N+1 쿼리 문제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P2 (Normal)&lt;/td&gt;
&lt;td&gt;코드 품질, 가독성&lt;/td&gt;
&lt;td&gt;변수명, 함수 분리&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;P3 (Nice to have)&lt;/td&gt;
&lt;td&gt;스타일, 취향&lt;/td&gt;
&lt;td&gt;코드 포맷팅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 Pull Request(PR)와 Merge Request(MR) 작성법에 대해 알아봤습니다. PR은 단순히 코드를 병합하는 도구가 아니라, 팀원들과 소통하고 코드 품질을 높이는 협업의 핵심입니다. 좋은 PR 작성 습관을 들이면 팀 전체의 생산성이 향상됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 시간에는 Git Stash - 임시 저장 활용법에 대해 알아보겠습니다.&lt;/p&gt;</description>
      <category>컴퓨터공학/Git</category>
      <author>RyanSin</author>
      <guid isPermaLink="true">https://any-ting.tistory.com/190</guid>
      <comments>https://any-ting.tistory.com/190#entry190comment</comments>
      <pubDate>Thu, 25 Dec 2025 20:00:59 +0900</pubDate>
    </item>
    <item>
      <title>[Git] - Clone vs Fork 차이점</title>
      <link>https://any-ting.tistory.com/189</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 이번 시간에는 Clone과 Fork의 차이점에 대해 알아보겠습니다. 둘 다 원격 저장소의 코드를 가져오는 방법이지만, 목적과 사용 상황이 다릅니다. 특히 오픈소스 기여를 할 때 Fork를 많이 사용하게 되는데, 정확한 개념을 이해하고 넘어가겠습니다. 혹시 이전 시간에 내용을 학습하고 오시지 못 하신 분들은 학습하고 오시는 걸 추천드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://any-ting.tistory.com/188&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Git] - push, pull, fetch 명령어 이해&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Clone vs Fork 한눈에 보기&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;1078&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3hUp9/dJMcahCXBQu/4COT0PshckWLQcOmKBD621/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3hUp9/dJMcahCXBQu/4COT0PshckWLQcOmKBD621/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3hUp9/dJMcahCXBQu/4COT0PshckWLQcOmKBD621/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3hUp9%2FdJMcahCXBQu%2F4COT0PshckWLQcOmKBD621%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1210&quot; height=&quot;1078&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;1078&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항목 Clone Fork&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;정의&lt;/td&gt;
&lt;td&gt;저장소를 로컬에 복제&lt;/td&gt;
&lt;td&gt;저장소를 내 계정에 복제&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;위치&lt;/td&gt;
&lt;td&gt;로컬 컴퓨터&lt;/td&gt;
&lt;td&gt;GitHub (원격)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;명령어&lt;/td&gt;
&lt;td&gt;git clone&lt;/td&gt;
&lt;td&gt;GitHub 웹에서 클릭&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;원본 연결&lt;/td&gt;
&lt;td&gt;origin으로 연결&lt;/td&gt;
&lt;td&gt;별도 연결 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;push 권한&lt;/td&gt;
&lt;td&gt;권한 있으면 가능&lt;/td&gt;
&lt;td&gt;내 저장소에만 가능&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;주 사용처&lt;/td&gt;
&lt;td&gt;팀 프로젝트, 개인 프로젝트&lt;/td&gt;
&lt;td&gt;오픈소스 기여&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Clone이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Clone은 원격 저장소를 로컬 컴퓨터에 복제하는 것입니다. 저장소의 모든 파일, 브랜치, 커밋 히스토리가 그대로 복사됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 사용법&lt;/h3&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;# 기본 클론
git clone https://github.com/username/repository.git

# 특정 폴더명으로 클론
git clone https://github.com/username/repository.git my-folder

# 특정 브랜치만 클론
git clone -b develop https://github.com/username/repository.git

# 최신 커밋만 클론 (히스토리 제외, 빠름)
git clone --depth 1 https://github.com/username/repository.git
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Clone 후 상태&lt;/h3&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;# 클론 실행
git clone https://github.com/username/my-project.git
cd my-project

# 원격 저장소 확인
git remote -v

# 출력
origin  https://github.com/username/my-project.git (fetch)
origin  https://github.com/username/my-project.git (push)
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Clone하면 자동으로 origin이라는 이름으로 원격 저장소가 등록됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Clone 사용 상황&lt;/h3&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;# 1. 팀 프로젝트 참여
git clone https://github.com/our-team/project.git

# 2. 내 저장소 다른 컴퓨터에서 작업
git clone https://github.com/my-username/my-repo.git

# 3. 오픈소스 코드 살펴보기 (읽기 전용)
git clone https://github.com/facebook/react.git
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Fork란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Fork는 다른 사람의 저장소를 내 GitHub 계정으로 복제하는 것입니다. 원본 저장소와 별개의 독립적인 저장소가 생성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;618&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/deJwfw/dJMcaf6dRKs/EcmffX4tKrMpxQwg0LVRS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/deJwfw/dJMcaf6dRKs/EcmffX4tKrMpxQwg0LVRS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/deJwfw/dJMcaf6dRKs/EcmffX4tKrMpxQwg0LVRS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdeJwfw%2FdJMcaf6dRKs%2FEcmffX4tKrMpxQwg0LVRS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1226&quot; height=&quot;618&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;618&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Fork 방법&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;GitHub에서 원하는 저장소 접속&lt;/li&gt;
&lt;li&gt;우측 상단 Fork 버튼 클릭&lt;/li&gt;
&lt;li&gt;내 계정 선택&lt;/li&gt;
&lt;li&gt;내 계정에 복제된 저장소 생성!&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Fork 후 작업 흐름&lt;/h3&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;# 1. Fork한 저장소를 로컬에 클론
git clone https://github.com/MY-USERNAME/forked-repo.git
cd forked-repo

# 2. 원본 저장소를 upstream으로 추가
git remote add upstream https://github.com/ORIGINAL-OWNER/original-repo.git

# 3. 원격 저장소 확인
git remote -v

# 출력
origin    https://github.com/MY-USERNAME/forked-repo.git (fetch)
origin    https://github.com/MY-USERNAME/forked-repo.git (push)
upstream  https://github.com/ORIGINAL-OWNER/original-repo.git (fetch)
upstream  https://github.com/ORIGINAL-OWNER/original-repo.git (push)
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Fork 사용 상황&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 1. 오픈소스 기여
# - 원본에 직접 push 권한이 없음
# - Fork 후 내 저장소에서 작업
# - Pull Request로 기여

# 2. 오픈소스 커스터마이징
# - 원본을 기반으로 내 버전 개발
# - 독립적으로 유지보수

# 3. 프로젝트 백업/보존
# - 원본이 삭제되어도 내 Fork는 유지
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 오픈소스 기여 워크플로우&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Fork를 활용한 오픈소스 기여 전체 과정입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;1270&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXewCQ/dJMcaf6dRLa/TzjUKKT06S17kZHR3MnUDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXewCQ/dJMcaf6dRLa/TzjUKKT06S17kZHR3MnUDk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXewCQ/dJMcaf6dRLa/TzjUKKT06S17kZHR3MnUDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXewCQ%2FdJMcaf6dRLa%2FTzjUKKT06S17kZHR3MnUDk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1224&quot; height=&quot;1270&quot; data-origin-width=&quot;1224&quot; data-origin-height=&quot;1270&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step 1: Fork &amp;amp; Clone&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 1. GitHub에서 원본 저장소 Fork (웹에서)

# 2. Fork한 저장소 클론
git clone https://github.com/MY-USERNAME/project.git
cd project

# 3. upstream 설정
git remote add upstream https://github.com/ORIGINAL-OWNER/project.git
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step 2: 브랜치 생성 및 작업&lt;/h3&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# 1. 최신 상태 동기화
git fetch upstream
git checkout main
git merge upstream/main

# 2. 작업 브랜치 생성
git checkout -b feature/my-contribution

# 3. 코드 수정 및 커밋
# ... 코드 작성 ...
git add .
git commit -m &quot;feat: 새로운 기능 추가&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step 3: Push &amp;amp; Pull Request&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 1. 내 원격 저장소에 푸시
git push origin feature/my-contribution

# 2. GitHub에서 Pull Request 생성 (웹에서)
# - 원본 저장소의 main &amp;larr; 내 저장소의 feature/my-contribution
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Step 4: 동기화 유지&lt;/h3&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# PR이 머지된 후, 또는 원본이 업데이트된 경우

# 1. upstream에서 최신 코드 가져오기
git fetch upstream

# 2. main 브랜치 업데이트
git checkout main
git merge upstream/main

# 3. 내 원격 저장소도 업데이트
git push origin main

# 4. 사용 완료된 브랜치 삭제
git branch -d feature/my-contribution
git push origin --delete feature/my-contribution
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Clone만 했을 때 vs Fork 후 Clone&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;시나리오: React에 기여하고 싶다&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Clone만 한 경우:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;subunit&quot;&gt;&lt;code&gt;git clone https://github.com/facebook/react.git
cd react

# 작업 후 push 시도
git push origin main

# 결과: 권한 없음!
ERROR: Permission denied
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Fork 후 Clone한 경우:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 1. Fork (GitHub 웹에서)

# 2. 내 저장소 Clone
git clone https://github.com/MY-USERNAME/react.git
cd react

# 3. 작업 후 push
git push origin my-branch  # 성공!

# 4. Pull Request 생성 (GitHub 웹에서)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- origin과 upstream 이해하기&lt;/h2&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# origin: 내 원격 저장소 (Fork한 것)
# - push 가능
# - 내가 소유

# upstream: 원본 저장소
# - push 불가능 (권한 없음)
# - 최신 코드 가져오는 용도
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;자주 사용하는 명령어&lt;/h3&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# 원본 저장소 최신 코드 가져오기
git fetch upstream
git merge upstream/main

# 또는 한 번에
git pull upstream main

# 내 저장소에 반영
git push origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 실습: 오픈소스 기여 시뮬레이션&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 오픈소스 기여 과정을 연습해봅시다.&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 1. 연습용 저장소 Fork (GitHub 웹에서)
# https://github.com/octocat/Spoon-Knife

# 2. Fork한 저장소 클론
git clone https://github.com/YOUR-USERNAME/Spoon-Knife.git
cd Spoon-Knife

# 3. upstream 설정
git remote add upstream https://github.com/octocat/Spoon-Knife.git

# 4. 확인
git remote -v

# 5. 브랜치 생성
git checkout -b feature/add-my-name

# 6. 파일 수정
echo &quot;YOUR-NAME was here!&quot; &amp;gt;&amp;gt; contributors.md

# 7. 커밋
git add .
git commit -m &quot;docs: Add my name to contributors&quot;

# 8. 푸시
git push origin feature/add-my-name

# 9. GitHub에서 Pull Request 생성 (웹에서)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 자주 하는 실수&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실수 1: upstream 설정 안 함&lt;/h3&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;# 문제: 원본 저장소 변경사항을 못 가져옴

# 해결
git remote add upstream https://github.com/ORIGINAL/repo.git
git fetch upstream
git merge upstream/main
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실수 2: Fork 안 하고 Clone만 함&lt;/h3&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;# 문제: push 권한 없음

# 해결
# 1. GitHub에서 Fork
# 2. 원격 저장소 URL 변경
git remote set-url origin https://github.com/MY-USERNAME/repo.git
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;실수 3: main 브랜치에서 직접 작업&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 문제: PR 관리가 어려움

# 권장: 항상 새 브랜치에서 작업
git checkout -b feature/my-work
# 작업...
git push origin feature/my-work
# PR 생성
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 명령어 정리&lt;/h2&gt;
&lt;pre class=&quot;crmsh&quot;&gt;&lt;code&gt;# Clone
git clone &amp;lt;URL&amp;gt;                    # 기본 클론
git clone &amp;lt;URL&amp;gt; &amp;lt;folder&amp;gt;           # 폴더명 지정
git clone -b &amp;lt;branch&amp;gt; &amp;lt;URL&amp;gt;        # 특정 브랜치
git clone --depth 1 &amp;lt;URL&amp;gt;          # 최신 커밋만

# Fork 후 설정
git remote add upstream &amp;lt;원본URL&amp;gt;  # upstream 추가
git remote -v                      # 확인

# 원본 동기화
git fetch upstream                 # 가져오기
git merge upstream/main            # 병합
git push origin main               # 내 저장소 반영

# 브랜치 작업
git checkout -b feature/name       # 브랜치 생성
git push origin feature/name       # 푸시
# GitHub에서 PR 생성
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 Clone과 Fork의 차이점에 대해 알아봤습니다. Clone은 저장소를 로컬에 복제하는 것이고, Fork는 저장소를 내 GitHub 계정에 복제하는 것입니다. 오픈소스에 기여할 때는 Fork &amp;rarr; Clone &amp;rarr; 작업 &amp;rarr; Push &amp;rarr; PR 순서로 진행합니다. upstream 설정을 잊지 말고 원본 저장소와 동기화를 유지하는 것이 중요합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 시간에는 Pull Request(PR) / Merge Request(MR) 작성법에 대해 알아보겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 자료&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/get-started/quickstart/fork-a-repo&quot;&gt;GitHub Docs - Fork a repo&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository&quot;&gt;GitHub Docs - Cloning a repository&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>컴퓨터공학/Git</category>
      <author>RyanSin</author>
      <guid isPermaLink="true">https://any-ting.tistory.com/189</guid>
      <comments>https://any-ting.tistory.com/189#entry189comment</comments>
      <pubDate>Wed, 24 Dec 2025 20:00:09 +0900</pubDate>
    </item>
    <item>
      <title>[Git] - push, pull, fetch 명령어 이해</title>
      <link>https://any-ting.tistory.com/188</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 이번 시간에는 Git의 push, pull, fetch 명령어에 대해 알아보겠습니다. 원격 저장소와 로컬 저장소 간에 코드를 주고받는 핵심 명령어들입니다. 각 명령어의 차이점과 사용법을 실습과 함께 살펴보겠습니다. 혹시 이전 시간에 내용을 학습하고 오시지 못 하신 분들은 학습하고 오시는 걸 추천드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://any-ting.tistory.com/187&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Git] - 충돌(Conflict) 해결 방법&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- push, pull, fetch 개념&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;710&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cWR0z1/dJMcaiu4cRH/9wxzbdj5kw2Vlb6UmZ9ySK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cWR0z1/dJMcaiu4cRH/9wxzbdj5kw2Vlb6UmZ9ySK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cWR0z1/dJMcaiu4cRH/9wxzbdj5kw2Vlb6UmZ9ySK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcWR0z1%2FdJMcaiu4cRH%2F9wxzbdj5kw2Vlb6UmZ9ySK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1246&quot; height=&quot;710&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;710&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세 명령어는 로컬과 원격 저장소 간의 동기화를 담당합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명령어 방향 설명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;push&lt;/td&gt;
&lt;td&gt;로컬 &amp;rarr; 원격&lt;/td&gt;
&lt;td&gt;내 커밋을 원격에 업로드&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;fetch&lt;/td&gt;
&lt;td&gt;원격 &amp;rarr; 로컬&lt;/td&gt;
&lt;td&gt;원격 변경사항 가져오기 (병합 X)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pull&lt;/td&gt;
&lt;td&gt;원격 &amp;rarr; 로컬&lt;/td&gt;
&lt;td&gt;fetch + merge (가져오고 병합)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- git push&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git push는 로컬 저장소의 커밋을 원격 저장소에 업로드합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 사용법&lt;/h3&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;# 기본 형식
git push &amp;lt;원격저장소&amp;gt; &amp;lt;브랜치&amp;gt;

# 예시: origin의 main 브랜치에 푸시
git push origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;첫 번째 푸시 (-u 옵션)&lt;/h3&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;# upstream 설정과 함께 푸시
git push -u origin main

# 이후부터는 간단하게
git push
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-u (또는 --set-upstream) 옵션은 로컬 브랜치와 원격 브랜치를 연결합니다. 한 번 설정하면 이후 git push만 입력해도 됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;다양한 push 옵션&lt;/h3&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;# 기본 푸시
git push origin main

# 모든 브랜치 푸시
git push origin --all

# 태그 푸시
git push origin --tags

# 특정 태그 푸시
git push origin v1.0.0

# 강제 푸시 (주의!)
git push -f origin main
git push --force origin main

# 더 안전한 강제 푸시
git push --force-with-lease origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;새 브랜치 푸시&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 로컬에서 브랜치 생성
git switch -c feature/login

# 작업 후 커밋
git add .
git commit -m &quot;feat: 로그인 기능&quot;

# 원격에 새 브랜치 푸시
git push -u origin feature/login
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;push 거부 상황&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;1260&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/biFQhi/dJMcaacLVPj/wPEkbgzwDDjdLkx1mNU4gk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/biFQhi/dJMcaacLVPj/wPEkbgzwDDjdLkx1mNU4gk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/biFQhi/dJMcaacLVPj/wPEkbgzwDDjdLkx1mNU4gk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbiFQhi%2FdJMcaacLVPj%2FwPEkbgzwDDjdLkx1mNU4gk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1242&quot; height=&quot;1260&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;1260&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- git fetch&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git fetch는 원격 저장소의 변경사항을 로컬로 가져오지만, 현재 작업 중인 브랜치에 병합하지 않습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 사용법&lt;/h3&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# 기본 형식
git fetch &amp;lt;원격저장소&amp;gt;

# origin의 모든 브랜치 가져오기
git fetch origin

# 특정 브랜치만 가져오기
git fetch origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;fetch 후 상태 확인&lt;/h3&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# fetch 실행
git fetch origin

# 출력 예시
remote: Counting objects: 3, done.
From https://github.com/username/repo
   a1b2c3d..d4e5f6g  main -&amp;gt; origin/main

# 로컬과 원격 차이 확인
git log main..origin/main --oneline

# 변경 내용 확인
git diff main origin/main
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;fetch vs pull 차이&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;884&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn55II/dJMcaiIBtnQ/MW3y7AXrgSUSfBk1ee5dx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn55II/dJMcaiIBtnQ/MW3y7AXrgSUSfBk1ee5dx1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn55II/dJMcaiIBtnQ/MW3y7AXrgSUSfBk1ee5dx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbn55II%2FdJMcaiIBtnQ%2FMW3y7AXrgSUSfBk1ee5dx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1216&quot; height=&quot;884&quot; data-origin-width=&quot;1216&quot; data-origin-height=&quot;884&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;fetch 활용 예시&lt;/h3&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;# 1. 원격 변경사항 확인하고 싶을 때
git fetch origin
git log HEAD..origin/main --oneline
# 3개의 새 커밋 확인

# 2. 확인 후 병합 결정
git merge origin/main

# 또는 rebase
git rebase origin/main
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- git pull&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git pull은 fetch + merge를 한 번에 실행합니다. 원격의 변경사항을 가져와서 현재 브랜치에 병합합니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 사용법&lt;/h3&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# 기본 형식
git pull &amp;lt;원격저장소&amp;gt; &amp;lt;브랜치&amp;gt;

# origin의 main 브랜치 풀
git pull origin main

# upstream 설정된 경우
git pull
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;pull 옵션&lt;/h3&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;# 기본 pull (merge 방식)
git pull origin main

# rebase 방식으로 pull
git pull --rebase origin main

# 충돌 시 자동 병합 전략
git pull --strategy-option theirs origin main  # 원격 우선
git pull --strategy-option ours origin main    # 로컬 우선
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;pull --rebase&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반 pull은 병합 커밋을 생성하지만, --rebase는 선형 히스토리를 유지합니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 일반 pull
git pull origin main
# 결과: 병합 커밋 생성

# rebase pull
git pull --rebase origin main
# 결과: 내 커밋이 원격 커밋 위로 이동

# 기본값으로 설정
git config --global pull.rebase true
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;일반 pull 결과:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;*   Merge branch 'main' of origin
|\
| * 원격 커밋 B
| * 원격 커밋 A
* | 내 커밋 2
* | 내 커밋 1
|/
* 공통 조상
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;pull --rebase 결과:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;gams&quot;&gt;&lt;code&gt;* 내 커밋 2 (재생성)
* 내 커밋 1 (재생성)
* 원격 커밋 B
* 원격 커밋 A
* 공통 조상
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;pull 충돌 해결&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;# pull 시 충돌 발생
git pull origin main
# CONFLICT (content): Merge conflict in file.js

# 충돌 해결
# 1. 파일 수정
# 2. 스테이징
git add file.js

# 3. 커밋 (일반 pull)
git commit -m &quot;merge: 충돌 해결&quot;

# 3. 또는 rebase 계속 (--rebase 사용 시)
git rebase --continue
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 실전 워크플로우&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;일반적인 작업 흐름&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 1. 작업 시작 전 최신 코드 가져오기
git pull origin main

# 2. 브랜치 생성
git switch -c feature/new-feature

# 3. 작업 및 커밋
git add .
git commit -m &quot;feat: 새 기능 추가&quot;

# 4. 원격에 브랜치 푸시
git push -u origin feature/new-feature

# 5. (GitHub에서 PR 생성)

# 6. PR 병합 후 로컬 정리
git switch main
git pull origin main
git branch -d feature/new-feature
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;협업 시 동기화&lt;/h3&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# 팀원의 변경사항 확인
git fetch origin

# 변경사항 있는지 확인
git status
# Your branch is behind 'origin/main' by 3 commits

# 병합
git pull origin main

# 또는 rebase로 병합
git pull --rebase origin main

# 내 작업 푸시
git push origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;장기 브랜치 동기화&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# feature 브랜치에서 작업 중
git switch feature/long-task

# main의 최신 변경사항 가져오기
git fetch origin main

# 내 브랜치에 반영 (rebase 권장)
git rebase origin/main

# 또는 merge
git merge origin/main

# 충돌 해결 후 계속 작업
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 자주 발생하는 문제&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 1: push 거부됨&lt;/h3&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;# 오류
! [rejected] main -&amp;gt; main (non-fast-forward)

# 해결
git pull origin main  # 먼저 pull
git push origin main  # 다시 push
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 2: pull 시 uncommitted changes 오류&lt;/h3&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# 오류
error: Your local changes would be overwritten by merge

# 해결 방법 1: 커밋하기
git add .
git commit -m &quot;WIP: 작업 중&quot;
git pull origin main

# 해결 방법 2: stash 사용
git stash
git pull origin main
git stash pop
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 3: fetch 했는데 브랜치가 안보임&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 원격 브랜치 목록 확인
git branch -r

# 원격 브랜치 로컬에 체크아웃
git switch -c feature/login origin/feature/login

# 또는
git checkout --track origin/feature/login
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;문제 4: 강제 푸시 후 팀원 문제&lt;/h3&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;# 내가 강제 푸시한 경우, 팀원은:
git fetch origin
git reset --hard origin/main

# 주의: 팀원의 로컬 변경사항이 사라짐!
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 명령어 비교 정리&lt;/h2&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;# PUSH: 로컬 &amp;rarr; 원격
git push origin main           # 기본
git push -u origin main        # upstream 설정
git push --force origin main   # 강제 (주의!)
git push origin --all          # 모든 브랜치
git push origin --tags         # 모든 태그

# FETCH: 원격 &amp;rarr; 로컬 (병합 X)
git fetch origin               # 모든 브랜치
git fetch origin main          # 특정 브랜치
git fetch --all                # 모든 원격 저장소

# PULL: 원격 &amp;rarr; 로컬 (fetch + merge)
git pull origin main           # 기본 (merge)
git pull --rebase origin main  # rebase 방식
git pull                       # upstream 설정된 경우
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 언제 무엇을 사용할까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상황 명령어&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;내 작업을 공유하고 싶을 때&lt;/td&gt;
&lt;td&gt;git push&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;원격 변경사항을 확인만 하고 싶을 때&lt;/td&gt;
&lt;td&gt;git fetch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;원격 변경사항을 바로 적용하고 싶을 때&lt;/td&gt;
&lt;td&gt;git pull&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;히스토리를 깔끔하게 유지하고 싶을 때&lt;/td&gt;
&lt;td&gt;git pull --rebase&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PR 전 최신 상태 동기화&lt;/td&gt;
&lt;td&gt;git fetch + git rebase&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 push, pull, fetch 명령어에 대해 알아봤습니다. 세 명령어는 원격 저장소와 협업할 때 필수적으로 사용됩니다. fetch는 안전하게 확인만, pull은 바로 병합, push는 내 작업을 업로드한다고 기억하시면 됩니다. 특히 pull --rebase는 깔끔한 히스토리 관리에 유용하니 활용해보세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 시간에는 Clone vs Fork 차이점에 대해 알아보겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 자료&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/git-push&quot;&gt;Git 공식 문서 - git push&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/git-pull&quot;&gt;Git 공식 문서 - git pull&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/docs/git-fetch&quot;&gt;Git 공식 문서 - git fetch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>컴퓨터공학/Git</category>
      <author>RyanSin</author>
      <guid isPermaLink="true">https://any-ting.tistory.com/188</guid>
      <comments>https://any-ting.tistory.com/188#entry188comment</comments>
      <pubDate>Tue, 23 Dec 2025 20:00:52 +0900</pubDate>
    </item>
    <item>
      <title>[Git] - 충돌(Conflict) 해결 방법</title>
      <link>https://any-ting.tistory.com/187</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;개요&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 이번 시간에는 Git 충돌(Conflict) 해결 방법에 대해 알아보겠습니다. 여러 사람이 협업하다 보면 같은 파일의 같은 부분을 수정하는 경우가 발생합니다. 이때 Git은 자동으로 병합하지 못하고 충돌이 발생하게 됩니다. 충돌을 두려워하지 말고, 해결 방법을 익혀두면 자신있게 대처할 수 있습니다. 혹시 이전 시간에 내용을 학습하고 오시지 못 하신 분들은 학습하고 오시는 걸 추천드리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://any-ting.tistory.com/186&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;[Git] - Rebase vs Merge 차이점&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 충돌이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;충돌(Conflict)은 Git이 자동으로 병합할 수 없는 상황을 말합니다. 두 브랜치에서 같은 파일의 같은 라인을 다르게 수정했을 때 발생합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;950&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bV9vQi/dJMcabpc2x5/udioKsnTWXsglxF3LpUmfK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bV9vQi/dJMcabpc2x5/udioKsnTWXsglxF3LpUmfK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bV9vQi/dJMcabpc2x5/udioKsnTWXsglxF3LpUmfK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbV9vQi%2FdJMcabpc2x5%2FudioKsnTWXsglxF3LpUmfK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1184&quot; height=&quot;950&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;950&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;충돌이 발생하는 상황&lt;/h3&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;main 브랜치:
파일: greeting.js
내용: console.log(&quot;Hello&quot;);  &amp;rarr;  console.log(&quot;Hello World&quot;);

feature 브랜치:
파일: greeting.js
내용: console.log(&quot;Hello&quot;);  &amp;rarr;  console.log(&quot;Hello Git&quot;);

병합 시도 시:
Git: &quot;둘 중 어떤 것을 선택해야 할지 모르겠어요!&quot; &amp;rarr; 충돌 발생!
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;충돌이 발생하지 않는 경우&lt;/h3&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;# 다른 파일 수정 &amp;rarr; 충돌 없음
main:    file1.js 수정
feature: file2.js 수정

# 같은 파일, 다른 라인 수정 &amp;rarr; 충돌 없음
main:    file.js 1번째 줄 수정
feature: file.js 10번째 줄 수정

# 같은 파일, 같은 라인 수정 &amp;rarr; 충돌 발생!
main:    file.js 5번째 줄 수정
feature: file.js 5번째 줄 수정
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 충돌 발생시키기 (실습)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;충돌 상황을 직접 만들어보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;# 1. 프로젝트 초기화
mkdir conflict-practice
cd conflict-practice
git init

# 2. 초기 파일 생성
cat &amp;lt;&amp;lt; 'EOF' &amp;gt; greeting.js
function greet() {
    console.log(&quot;Hello&quot;);
}
EOF

git add .
git commit -m &quot;init: 인사 함수 추가&quot;

# 3. feature 브랜치 생성 및 수정
git switch -c feature/update-greeting

cat &amp;lt;&amp;lt; 'EOF' &amp;gt; greeting.js
function greet() {
    console.log(&quot;Hello Git&quot;);
}
EOF

git add .
git commit -m &quot;feat: 인사말을 Hello Git으로 변경&quot;

# 4. main 브랜치에서 같은 부분 수정
git switch main

cat &amp;lt;&amp;lt; 'EOF' &amp;gt; greeting.js
function greet() {
    console.log(&quot;Hello World&quot;);
}
EOF

git add .
git commit -m &quot;feat: 인사말을 Hello World로 변경&quot;

# 5. 병합 시도 &amp;rarr; 충돌 발생!
git merge feature/update-greeting

# 출력
Auto-merging greeting.js
CONFLICT (content): Merge conflict in greeting.js
Automatic merge failed; fix conflicts and then commit the result.
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 충돌 파일 구조 이해하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;충돌이 발생한 파일을 열어보면 다음과 같은 구조를 볼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;952&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EfRBT/dJMcah32btD/ojFKUHzIVkKohC0ITu8JUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EfRBT/dJMcah32btD/ojFKUHzIVkKohC0ITu8JUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EfRBT/dJMcah32btD/ojFKUHzIVkKohC0ITu8JUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEfRBT%2FdJMcah32btD%2FojFKUHzIVkKohC0ITu8JUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1226&quot; height=&quot;952&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;952&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;function greet() {
&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD
    console.log(&quot;Hello World&quot;);
=======
    console.log(&quot;Hello Git&quot;);
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; feature/update-greeting
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;충돌 마커 설명&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마커 설명&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD&lt;/td&gt;
&lt;td&gt;현재 브랜치(HEAD)의 내용 시작&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;=======&lt;/td&gt;
&lt;td&gt;구분선&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; branch-name&lt;/td&gt;
&lt;td&gt;병합하려는 브랜치의 내용 끝&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD
현재 브랜치(main)의 코드
=======
병합하려는 브랜치(feature)의 코드
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; feature/update-greeting
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 충돌 해결 방법&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;1376&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8nMk2/dJMcafE9Gsc/XCFScVE8CUmBd33FOozIX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8nMk2/dJMcafE9Gsc/XCFScVE8CUmBd33FOozIX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8nMk2/dJMcafE9Gsc/XCFScVE8CUmBd33FOozIX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8nMk2%2FdJMcafE9Gsc%2FXCFScVE8CUmBd33FOozIX1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1220&quot; height=&quot;1376&quot; data-origin-width=&quot;1220&quot; data-origin-height=&quot;1376&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;방법 1: 수동으로 해결&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 기본적인 방법으로, 직접 파일을 편집합니다.&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;# 1. 충돌 파일 확인
git status

# 출력
On branch main
You have unmerged paths.
  (fix conflicts and run &quot;git commit&quot;)

Unmerged paths:
  (use &quot;git add &amp;lt;file&amp;gt;...&quot; to mark resolution)
        both modified:   greeting.js

# 2. 파일 열어서 수정
code greeting.js  # 또는 vim, nano 등
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;수정 전:&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;asciidoc&quot;&gt;&lt;code&gt;function greet() {
&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD
    console.log(&quot;Hello World&quot;);
=======
    console.log(&quot;Hello Git&quot;);
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; feature/update-greeting
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;수정 후 (원하는 내용으로 선택/수정):&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;function greet() {
    console.log(&quot;Hello World and Git&quot;);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;# 3. 수정 완료 후 스테이징
git add greeting.js

# 4. 커밋
git commit -m &quot;merge: feature/update-greeting 병합 및 충돌 해결&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;방법 2: 특정 브랜치 내용 선택&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한쪽 브랜치의 내용을 전체 선택할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;# 현재 브랜치(main)의 내용 선택
git checkout --ours greeting.js

# 병합 브랜치(feature)의 내용 선택
git checkout --theirs greeting.js

# 스테이징 및 커밋
git add greeting.js
git commit -m &quot;merge: feature 브랜치 내용으로 충돌 해결&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;방법 3: VS Code로 해결&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VS Code는 충돌 해결을 위한 편리한 UI를 제공합니다.&lt;/p&gt;
&lt;pre class=&quot;clean&quot;&gt;&lt;code&gt;# VS Code로 파일 열기
code greeting.js
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VS Code에서 충돌 부분에 다음 버튼이 표시됩니다:&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Accept Current Change&lt;/b&gt;: 현재 브랜치(HEAD) 선택&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Accept Incoming Change&lt;/b&gt;: 병합 브랜치 선택&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Accept Both Changes&lt;/b&gt;: 둘 다 포함&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Compare Changes&lt;/b&gt;: 변경 사항 비교&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;방법 4: Git Mergetool 사용&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Git에 설정된 병합 도구를 사용합니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# mergetool 실행
git mergetool

# 도구 설정 (VS Code)
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'

# 도구 설정 (IntelliJ)
git config --global merge.tool intellij
git config --global mergetool.intellij.cmd 'idea merge $LOCAL $REMOTE $BASE $MERGED'
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 충돌 해결 실습&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 과정을 다시 실습해보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 1. 충돌 상태 확인
git status

# 2. 충돌 파일 목록만 확인
git diff --name-only --diff-filter=U

# 3. 충돌 내용 확인
git diff

# 4. 파일 수정 (에디터로)
# greeting.js 파일에서 충돌 마커 제거하고 원하는 내용 작성

# 5. 수정 완료 확인
cat greeting.js
# function greet() {
#     console.log(&quot;Hello World and Git&quot;);
# }

# 6. 스테이징
git add greeting.js

# 7. 상태 확인
git status
# All conflicts fixed but you are still merging.

# 8. 커밋
git commit -m &quot;merge: greeting 충돌 해결&quot;

# 9. 로그 확인
git log --oneline --graph
# *   a1b2c3d (HEAD -&amp;gt; main) merge: greeting 충돌 해결
# |\
# | * b2c3d4e (feature/update-greeting) feat: 인사말을 Hello Git으로 변경
# * | c3d4e5f feat: 인사말을 Hello World로 변경
# |/
# * d4e5f6g init: 인사 함수 추가
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 병합 취소하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;충돌 해결이 복잡하거나 잘못되었을 때 병합을 취소할 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;병합 중 취소 (커밋 전)&lt;/h3&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;# 병합 취소하고 이전 상태로
git merge --abort
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;병합 후 취소 (커밋 후)&lt;/h3&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;# 방법 1: reset으로 완전히 되돌리기
git reset --hard HEAD~1

# 방법 2: revert로 되돌리기 (이력 유지)
git revert -m 1 HEAD
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- Rebase 중 충돌 해결&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rebase 중 충돌이 발생하면 각 커밋마다 해결해야 합니다.&lt;/p&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 1. Rebase 시작
git switch feature/login
git rebase main

# 충돌 발생!
# CONFLICT (content): Merge conflict in file.js

# 2. 충돌 해결
# 파일 수정...
git add file.js

# 3. Rebase 계속
git rebase --continue

# 4. 다음 커밋에서 또 충돌 발생 시 2-3 반복

# Rebase 전체 취소
git rebase --abort

# 현재 커밋 건너뛰기
git rebase --skip
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Merge vs Rebase 충돌 해결 비교&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;항목 Merge Rebase&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;충돌 해결 횟수&lt;/td&gt;
&lt;td&gt;1회&lt;/td&gt;
&lt;td&gt;커밋 개수만큼&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;취소 명령어&lt;/td&gt;
&lt;td&gt;git merge --abort&lt;/td&gt;
&lt;td&gt;git rebase --abort&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;계속 명령어&lt;/td&gt;
&lt;td&gt;git commit&lt;/td&gt;
&lt;td&gt;git rebase --continue&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 충돌 예방하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;충돌을 완전히 피할 수는 없지만, 줄일 수 있습니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 자주 동기화하기&lt;/h3&gt;
&lt;pre class=&quot;livecodeserver&quot;&gt;&lt;code&gt;# main 브랜치 변경사항을 자주 가져오기
git switch feature/my-feature
git merge main  # 또는 git rebase main
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 작은 단위로 작업하기&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# ❌ 나쁜 예: 일주일 동안 큰 기능 개발 후 병합
# ✅ 좋은 예: 작은 단위로 자주 병합
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 팀과 소통하기&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 같은 파일을 수정할 예정이라면 미리 공유
# 코드 리뷰를 통해 충돌 가능성 파악
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 파일 분리하기&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# ❌ 하나의 큰 파일에 모든 기능
# ✅ 기능별로 파일 분리
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 복잡한 충돌 해결 팁&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;충돌 파일이 많을 때&lt;/h3&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;# 충돌 파일 목록 확인
git diff --name-only --diff-filter=U

# 하나씩 해결
git add file1.js
git add file2.js
# ...

# 모든 충돌 해결 후 커밋
git commit
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특정 파일을 한쪽으로 통일&lt;/h3&gt;
&lt;pre class=&quot;vala&quot;&gt;&lt;code&gt;# 모든 충돌을 현재 브랜치로
git checkout --ours .

# 모든 충돌을 병합 브랜치로
git checkout --theirs .

# 주의: 신중하게 사용!
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;충돌 히스토리 확인&lt;/h3&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;# 충돌 원인이 된 커밋 확인
git log --merge

# 파일별 수정 이력 확인
git log -p -- greeting.js
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;- 충돌 해결 명령어 정리&lt;/h2&gt;
&lt;pre class=&quot;dsconfig&quot;&gt;&lt;code&gt;# 충돌 상태 확인
git status
git diff --name-only --diff-filter=U

# 충돌 내용 확인
git diff

# 충돌 해결 후
git add 파일명
git commit

# 특정 브랜치 선택
git checkout --ours 파일명    # 현재 브랜치
git checkout --theirs 파일명  # 병합 브랜치

# 병합 취소
git merge --abort      # Merge 중
git rebase --abort     # Rebase 중

# Rebase 계속
git rebase --continue
git rebase --skip

# 도구 사용
git mergetool
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 Git 충돌(Conflict) 해결 방법에 대해 알아봤습니다. 충돌은 협업에서 자연스럽게 발생하는 현상이니 두려워하지 마세요. 충돌 마커를 이해하고, 원하는 내용으로 수정한 뒤 커밋하면 됩니다. 자주 동기화하고 작은 단위로 작업하면 충돌을 줄일 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음 시간에는 원격 저장소(Remote) 연결 방법에 대해 알아보겠습니다.&lt;/p&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 자료&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/book/ko/v2/Git-%EB%B8%8C%EB%9E%9C%EC%B9%98-%EB%B8%8C%EB%9E%9C%EC%B9%98%EC%99%80-Merge-%EC%9D%98-%EA%B8%B0%EC%B4%88&quot;&gt;Git 공식 문서 - Basic Merge Conflicts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>컴퓨터공학/Git</category>
      <author>RyanSin</author>
      <guid isPermaLink="true">https://any-ting.tistory.com/187</guid>
      <comments>https://any-ting.tistory.com/187#entry187comment</comments>
      <pubDate>Mon, 22 Dec 2025 20:00:18 +0900</pubDate>
    </item>
  </channel>
</rss>