<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>코드 몽키의 허둥지둥 개발공부</title>
    <link>https://ingnoh.tistory.com/</link>
    <description>우끾</description>
    <language>ko</language>
    <pubDate>Fri, 8 May 2026 09:17:38 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>인쥭</managingEditor>
    <image>
      <title>코드 몽키의 허둥지둥 개발공부</title>
      <url>https://tistory1.daumcdn.net/tistory/3901211/attach/8e64f6715f1348219d119e85fb0589eb</url>
      <link>https://ingnoh.tistory.com</link>
    </image>
    <item>
      <title>[JavaScript] Iterator Helper</title>
      <link>https://ingnoh.tistory.com/238</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;마치 Java 진영의 Stream API 같은 친구들이 JavaScript 진영에도 공식적으로 추가되고 있고, 이들을 Iterator Helper라고 한다.&lt;/p&gt;
&lt;figure id=&quot;og_1747788311265&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Iterator - JavaScript | MDN&quot; data-og-description=&quot;An Iterator object is an object that conforms to the iterator protocol by providing a next() method that returns an iterator result object. All built-in iterators inherit from the Iterator class. The Iterator class provides a [Symbol.iterator]() method tha&quot; data-og-host=&quot;developer.mozilla.org&quot; data-og-source-url=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator#iterator_helpers&quot; data-og-url=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/BnWJs/hyYTg4LcbO/RbTPPpWUFhqCe4BBQln6c0/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080&quot;&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator#iterator_helpers&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Iterator#iterator_helpers&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/BnWJs/hyYTg4LcbO/RbTPPpWUFhqCe4BBQln6c0/img.png?width=1920&amp;amp;height=1080&amp;amp;face=0_0_1920_1080');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Iterator - JavaScript | MDN&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;An Iterator object is an object that conforms to the iterator protocol by providing a next() method that returns an iterator result object. All built-in iterators inherit from the Iterator class. The Iterator class provides a [Symbol.iterator]() method tha&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.mozilla.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이터레이터 헬퍼 메소드들은 종단 연산이 호출되는 시점에 평가되므로, 배열 전체를 순회하는 대신 조건에 맞는 몇 개만 찾아오고자 하는 경우에는 기존 Array.prototype 메소드들보다 훨씬 빠르게 동작한다.&lt;/p&gt;
&lt;pre id=&quot;code_1747788368317&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;const numbers = [];
for (let i = 0; i &amp;lt; 1_000_000; i++) {
    numbers.push(getRandomInt()); // 0~99 중 하나의 정수를 랜덤하게 삽입
}

/** numbers 배열에 삽입된 값 중 홀수인 값을 딱 3개만 추출하기 */

// 배열 메소드를 사용하는 방식
const result1 = (function getThreeOddNumbersV1(_numbers) {
    console.time(&quot;getThreeOddNumbersV1&quot;);
    const result = _numbers.filter((number) =&amp;gt; number % 2 === 1)
        .slice(0, 3);
    console.timeEnd(&quot;getThreeOddNumbersV1&quot;);

    return result;
})(numbers);
console.log(`result1: ${result1}`);

console.log(`--- 구분선 ---`);

// 이터레이터 메소드를 사용하는 방식
const result2 = (function getThreeOddNumbersV2(_numbers) {
    console.time(&quot;getThreeOddNumbersV2&quot;);
    const result = _numbers.values()
        .filter((number) =&amp;gt; number % 2 === 1) // 이 시점에서 filter 로직이 실행되지는 않음
        .take(3)
        .toArray(); // 종단 연산
    console.timeEnd(&quot;getThreeOddNumbersV2&quot;);

    return result;
})(numbers);
console.log(`result2: ${result2}`);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;m1 mac pro 기준으로 실행 결과는 다음과 같다!&lt;/p&gt;
&lt;pre id=&quot;code_1747788409266&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;getThreeOddNumbersV1: 15.153ms
result1: 77,67,69
--- 구분선 ---
getThreeOddNumbersV2: 0.014ms
result2: 77,67,69&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 해당 기능은 Node 22, ES 2026에 정의된 최신 문법에 속하기에 실무 도입에 있어서는 주의가 필요할 것으로 보인다. &lt;br /&gt;그나마 백엔드의 경우에는 Node 22가 LTS라 괜찮을 듯!&lt;/p&gt;</description>
      <category>Dev./Node.js</category>
      <category>javascript</category>
      <author>인쥭</author>
      <guid isPermaLink="true">https://ingnoh.tistory.com/238</guid>
      <comments>https://ingnoh.tistory.com/238#entry238comment</comments>
      <pubDate>Wed, 21 May 2025 09:49:00 +0900</pubDate>
    </item>
    <item>
      <title>[Kotlin] 인자에 따라 List를 규칙적으로 뒤섞기</title>
      <link>https://ingnoh.tistory.com/237</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;간단한 토이 프로젝트를 진행하던 중, List의 요소를 랜덤하게 뒤섞되 &lt;br /&gt;문자열 인자의 값에 따라 섞는 방법을 결정해야 하는 경우가 생겼다.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;내가 써놓고도 뭔 소리인지 모르겠다. 더 자세히 말해보면, 상술한 기능을 하는 함수 A는 다음과 같은 요구 사항을 충족해야 했다:&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;함수 A는 List&amp;lt;T&amp;gt; 인자 하나와 문자열 인자 하나를 받아 다시 List&amp;lt;T&amp;gt;를 반환해야 한다.&lt;/li&gt;
&lt;li&gt;함수 A에 의해 반환된 List는 첫 번째 인자로 전달된 List를 랜덤하게 뒤섞은 결과여야 한다.&lt;/li&gt;
&lt;li&gt;함수 A에 전달된 문자열 인자가 동일한 경우, 항상 같은 순서로 뒤섞인 List가 반환되어야 한다.&lt;br /&gt;즉, A(&quot;first&quot;)와 A(&quot;first&quot;)의 결과는 같지만 A(&quot;first&quot;)와 A(&quot;second&quot;)는 달라야 한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;아시다시피 Kotlin은 List의 요소를 랜덤하게 뒤섞는 shuffled() 확장 함수를 다음과 같이 지원한다.&lt;/p&gt;
&lt;pre id=&quot;code_1742187257023&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Playground {
    @Test
    fun `shuffled() 확장 함수는 List의 요소를 랜덤하게 뒤섞는다`() {
        val list = listOf(1, 2, 3, 4, 5)
        println(list.shuffled()) // [4, 5, 1, 3, 2]
        println(list.shuffled()) // [4, 2, 1, 5, 3]
        println(list.shuffled()) // [3, 4, 5, 1, 2]
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 shuffled() 확장 함수는 내부적으로 Java Collection의 shuffle() 메소드를 호출하며, 해당 메소드는 다시 내부적으로 Random() 인스턴스에 따라 동작하고 있는 것을 알 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, &lt;u&gt;Random() 인스턴스의 값에 따라 섞임 순서가 결정되기에 동일한 문자열에 대해 동일한 Random() 인스턴스가 생성되도록 보장하면 된다&lt;/u&gt;. 참고로, Random() 인스턴스는 생성자에 Int 인자를 전달 받으므로 함수 A의 문자열 인자를 그대로 생성자에 전달하기보다는 hashCode()를 통해 Int로 해싱한 후에 전달해야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다행히도 Kotlin은 shuffled() 확장 함수를 오버로딩하여 Random() 인스턴스를 인자로 전달 받는 친구를 이미 만들어두었다.&lt;br /&gt;이를 이용하여 나만의 확장 함수 A(아래의 코드에서, myShuffle() 확장 함수를 의미한다)를 만들어보면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1742187842939&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Playground {
    companion object {
        fun &amp;lt;T&amp;gt; List&amp;lt;T&amp;gt;.myShuffle(seed: String): List&amp;lt;T&amp;gt; = this.shuffled(Random(seed.hashCode()))
    }
    
    @Test
    fun `myShuffle() 확장 함수는 인자에 따라 List의 요소를 규칙적으로 뒤섞는다`() {
        val list = listOf(1, 2, 3, 4, 5)
        // 호출 시 인자가 항상 같으므로 동일하게 뒤섞인다.
        println(list.myShuffle(&quot;seed&quot;)) // [3, 4, 1, 5, 2]
        println(list.myShuffle(&quot;seed&quot;)) // [3, 4, 1, 5, 2]
        println(list.myShuffle(&quot;seed&quot;)) // [3, 4, 1, 5, 2]

        // 호출 시 인자가 같다면 동일하게 뒤섞이지만, uuid가 실행 시마다 변경된다는 점에 유의하자.
        val uuid = UUID.randomUUID().toString()
        println(list.myShuffle(uuid)) // [5, 1, 4, 3, 2]
        println(list.myShuffle(uuid)) // [5, 1, 4, 3, 2]
        println(list.myShuffle(uuid)) // [5, 1, 4, 3, 2]
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 동작한다.&lt;/p&gt;</description>
      <category>Dev./Kotlin</category>
      <category>kotlin</category>
      <author>인쥭</author>
      <guid isPermaLink="true">https://ingnoh.tistory.com/237</guid>
      <comments>https://ingnoh.tistory.com/237#entry237comment</comments>
      <pubDate>Mon, 17 Mar 2025 14:10:57 +0900</pubDate>
    </item>
    <item>
      <title>[Git] author 기준 코드 수 확인하기</title>
      <link>https://ingnoh.tistory.com/236</link>
      <description>&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;토스 개발 블로그를 보던 중, 아래 글을 읽게 되었다:&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1741327897777&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;레고처럼 조립하는 토스 앱&quot; data-og-description=&quot;수많은 서비스를 담고 있는 대규모 iOS 앱에 어울리는 아키텍처는 무엇일까요? 프로젝트 간의 의존성과 모듈 간의 결합도를 낮춰, 더 효율적인 서비스 개발, 관리를 이뤄낸 과정을 소개합니다.&quot; data-og-host=&quot;toss.tech&quot; data-og-source-url=&quot;https://toss.tech/article/slash23-iOS&quot; data-og-url=&quot;https://toss.tech/article/slash23-iOS&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/daW59W/hyYqTtkreT/b3d6Xdw5IJ6VrEOGTUewg0/img.png?width=5000&amp;amp;height=2501&amp;amp;face=0_0_5000_2501,https://scrap.kakaocdn.net/dn/coVlod/hyYncBe5l7/3UTjW69PCjAQXf9EKnkKD1/img.png?width=5000&amp;amp;height=2501&amp;amp;face=0_0_5000_2501,https://scrap.kakaocdn.net/dn/Xz1MX/hyYqaIKocK/Gw4fGk4K9QM9XEcYi2kHG0/img.png?width=3840&amp;amp;height=2160&amp;amp;face=0_0_3840_2160&quot;&gt;&lt;a href=&quot;https://toss.tech/article/slash23-iOS&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://toss.tech/article/slash23-iOS&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/daW59W/hyYqTtkreT/b3d6Xdw5IJ6VrEOGTUewg0/img.png?width=5000&amp;amp;height=2501&amp;amp;face=0_0_5000_2501,https://scrap.kakaocdn.net/dn/coVlod/hyYncBe5l7/3UTjW69PCjAQXf9EKnkKD1/img.png?width=5000&amp;amp;height=2501&amp;amp;face=0_0_5000_2501,https://scrap.kakaocdn.net/dn/Xz1MX/hyYqaIKocK/Gw4fGk4K9QM9XEcYi2kHG0/img.png?width=3840&amp;amp;height=2160&amp;amp;face=0_0_3840_2160');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;레고처럼 조립하는 토스 앱&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;수많은 서비스를 담고 있는 대규모 iOS 앱에 어울리는 아키텍처는 무엇일까요? 프로젝트 간의 의존성과 모듈 간의 결합도를 낮춰, 더 효율적인 서비스 개발, 관리를 이뤄낸 과정을 소개합니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;toss.tech&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;2023년 글이니 지금은 더 늘었겠지만, &lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;코드가 100만줄이라니! &lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이 글을 보고 나니, 내가 개발에 참여 중인 애플리케이션의 라인 수와 개발자 별 코드 라인 수를 확인해보고 싶었다. &lt;br /&gt;git blame 기준이기 때문에 정확히 몇 줄의 코드를 작성했는지는 알 수 없지만, &lt;br /&gt;현재 버전 기준으로 몇 줄이나 기여했는지 정도는 알 수 있으니 재미용으로는 참고할 수 있을 것 같다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;전체 코드 수 확인&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1741328090926&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git ls-files | xargs cat | wc -l&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;내가 만든 명령어는 아니고, 이 블로그에서 가져왔다.&lt;/p&gt;
&lt;figure id=&quot;og_1741328105323&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Git] 프로젝트 내부 코드 라인 수 조회하기&quot; data-og-description=&quot;현재 프로젝트 내부 전체 파일의 코드 라인 수를 조회하고 싶은 경우가 있다. git 명령어를 통해 프로젝트 내부 전체 코드 라인 수를 조회해본다. 우선 프로젝트 내부로 이동해서 아래와 같은 명&quot; data-og-host=&quot;doqtqu.tistory.com&quot; data-og-source-url=&quot;https://doqtqu.tistory.com/261&quot; data-og-url=&quot;https://doqtqu.tistory.com/261&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/o1EK0/hyYqXCuXMU/4yqdwiXMnueODhS2Wneq3k/img.png?width=395&amp;amp;height=77&amp;amp;face=0_0_395_77,https://scrap.kakaocdn.net/dn/dcx1Wb/hyYm6ugdUc/tZ69VV9WJbuGocx3dNVIAk/img.png?width=395&amp;amp;height=77&amp;amp;face=0_0_395_77&quot;&gt;&lt;a href=&quot;https://doqtqu.tistory.com/261&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://doqtqu.tistory.com/261&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/o1EK0/hyYqXCuXMU/4yqdwiXMnueODhS2Wneq3k/img.png?width=395&amp;amp;height=77&amp;amp;face=0_0_395_77,https://scrap.kakaocdn.net/dn/dcx1Wb/hyYm6ugdUc/tZ69VV9WJbuGocx3dNVIAk/img.png?width=395&amp;amp;height=77&amp;amp;face=0_0_395_77');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Git] 프로젝트 내부 코드 라인 수 조회하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;현재 프로젝트 내부 전체 파일의 코드 라인 수를 조회하고 싶은 경우가 있다. git 명령어를 통해 프로젝트 내부 전체 코드 라인 수를 조회해본다. 우선 프로젝트 내부로 이동해서 아래와 같은 명&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;doqtqu.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;개발자 별 코드 수 확인&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1741328053889&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git ls-files | while read f; do git blame --line-porcelain $f | grep '^author '; done | sort -f | uniq -ic | sort -n&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 명령어의 경우 실행이 꽤 오래 걸리는 점에 주의해야 하며, 마찬가지로 내가 만든 명령어는 아니다. &lt;br /&gt;아래 블로그에 더 자세히 작성되어 있으니 참고하시길!&lt;/p&gt;
&lt;figure id=&quot;og_1741328168833&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Git] 개발자별로 작업한 코드 줄 수 확인하기&quot; data-og-description=&quot;Git 당신이 작업하는 Git폴더에 가서 다음과 같이 다음 git 명령어를 때려보자 작업자별 작업 코드 줄 수(code line count) 확인 명령어 (조금 오래 걸린다..) git ls-files | while read f; do git blame --line-porcelain&quot; data-og-host=&quot;forgiveall.tistory.com&quot; data-og-source-url=&quot;https://forgiveall.tistory.com/555&quot; data-og-url=&quot;https://forgiveall.tistory.com/555&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/lEgJr/hyYmUOcrR7/dp6HFFptJeZ4uuZkz8GcfK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/E8GUl/hyYmPTG0e9/M5PEOMFBtouhkkoAKG2TWK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://forgiveall.tistory.com/555&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://forgiveall.tistory.com/555&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/lEgJr/hyYmUOcrR7/dp6HFFptJeZ4uuZkz8GcfK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/E8GUl/hyYmPTG0e9/M5PEOMFBtouhkkoAKG2TWK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Git] 개발자별로 작업한 코드 줄 수 확인하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Git 당신이 작업하는 Git폴더에 가서 다음과 같이 다음 git 명령어를 때려보자 작업자별 작업 코드 줄 수(code line count) 확인 명령어 (조금 오래 걸린다..) git ls-files | while read f; do git blame --line-porcelain&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;forgiveall.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;확인 결과 나는 현재 애플리케이션의 9% 정도의 코드를 개발했다고 한다. 그래도 20%는 될 줄 알았는데... 아쉽네에&lt;/p&gt;</description>
      <category>Dev.</category>
      <category>Git</category>
      <author>인쥭</author>
      <guid isPermaLink="true">https://ingnoh.tistory.com/236</guid>
      <comments>https://ingnoh.tistory.com/236#entry236comment</comments>
      <pubDate>Fri, 7 Mar 2025 15:17:13 +0900</pubDate>
    </item>
    <item>
      <title>[AWS] Edge-optimized API Gateway와 HTTP 호출시 307 응답 관련 이슈</title>
      <link>https://ingnoh.tistory.com/235</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;이슈 내용&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS API Gateway에 Edge-optimized(이하 엣지 최적화) 설정이 되어 있을 때, 임의의 리소스를 HTTP로(HTTPS 아님!) 호출한다고 가정하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우, &lt;u&gt;포스트맨으로는 정상적으로 호출이 되지만 curl로는 307 Temporary Redirect가 반환되는 기현상&lt;/u&gt;이 발생한다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, AWS API Gateway 호출 내역을 봐도 아무것도 찍히지 않는다. 즉, AWS API Gateway가 응답하지 않았음에도 누군가가 중간에 307로 반환하고 있는 것! 왜 포스트맨과 curl의 동작이 다르고, 누가 중간에서 요청을 가로채어 307 응답을 반환하고 있는 것일까?&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;원인 분석&lt;/h4&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;엣지 최적화가 설정된 AWS API Gateway는 게이트웨이 앞단에 CloudFront가 할당된다.&lt;/li&gt;
&lt;li&gt;CloudFront는 HTTP 프로토콜을 사용하는 요청에 대해 HTTPS 프로토콜 사용을 유도하도록 307로 응답한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇듯 AWS API Gateway가 처리하기 전에 CloudFront가 튕겨내기 때문에 AWS API Gateway가 호출되지 않았음에도 307 응답이 나간 것처럼 보여지게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다면 curl로는 안되는데 왜 포스트맨으로는 되었을까? 찾아보니, &lt;u&gt;포스트맨은 다음과 같은 자동 리다이렉트 옵션이 기본적으로 활성화&lt;/u&gt;되어 있다고 한다. 때문에 307에 대해 알아서 HTTPS 프로토콜 기반 엔드포인트로 리다이렉트하여 정상적으로 호출된 것처럼 보인 것!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-02-27 오후 3.20.33.png&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;1506&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bALokI/btsMx9QwBuY/hKSt9jPcIecoMAndPI9kaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bALokI/btsMx9QwBuY/hKSt9jPcIecoMAndPI9kaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bALokI/btsMx9QwBuY/hKSt9jPcIecoMAndPI9kaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbALokI%2FbtsMx9QwBuY%2FhKSt9jPcIecoMAndPI9kaK%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;653&quot; height=&quot;630&quot; data-filename=&quot;스크린샷 2025-02-27 오후 3.20.33.png&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;1506&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로, curl 역시 -L 옵션을 명시할 경우 포스트맨의 기본 설정과 같이 자동으로 리다이렉트 하게 된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;번외. 리다이렉션 없이 HTTP만으로 호출하고 싶다면?&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AWS API Gateway 설정만으로는 불가능하다. &lt;br /&gt;nginx를 올린 프록시용 EC2 인스턴스를 두는 등 다른 서비스와 함께 우회하는 방식을 택할 수 밖에 없어보인다!&lt;/p&gt;</description>
      <category>Cloud./aws</category>
      <category>AWS</category>
      <author>인쥭</author>
      <guid isPermaLink="true">https://ingnoh.tistory.com/235</guid>
      <comments>https://ingnoh.tistory.com/235#entry235comment</comments>
      <pubDate>Thu, 27 Feb 2025 15:27:46 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] 여러 레코드를 각각 다른 값으로 UPDATE하기</title>
      <link>https://ingnoh.tistory.com/234</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;UPDATE 쿼리로는 여러 레코드를 같은 값으로만 수정할 수 있기에, 여러 개를 각각 다른 값으로 수정해주어야 하는 경우에는 쿼리 한 방으로 처리할 수 없다고 생각했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러나 아래와 같은 방식을 사용하면 가능해용&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;INSERT INTO ... ON DUPLICATE KEY UPDATE &amp;amp; VALUES&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VALUES 함수는 해당 컬럼에 삽입될 값을 의미한다고 한다. 때문에 Id가 PK인 my_table이 있다고 할 때, Id가 1, 2, 3인 컬럼의 순서를 각각 0, 1, 2로 갱신하는 쿼리는 다음과 같이 작성할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1739493073128&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSERT INTO my_table (Id, `Order`) 
VALUES (1, 0), (2, 1), (3, 2) 
ON DUPLICATE KEY UPDATE my_table.`Order` = VALUES(my_table.`Order`);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당연히 테이블에 해당 레코드가 없다면 삽입될 것이고, 있다면 순서를 의미하는 Order 컬럼의 값만을 수정한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;Row Constructor 문법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MySQL 8.0부터 지원되며, 아래와 같이 레코드 생성 문법을 활용하면 여러 레코드를 서로 다른 값으로 수정할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1739493457477&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;UPDATE my_table mt
INNER JOIN (
	VALUES ROW(1, 0), ROW(2, 1), ROW(3, 2)
) expected_order (Id, `Order`) ON expected_order.Id = mt.Id
SET mt.`Order` = expected_order.`Order`;&lt;/code&gt;&lt;/pre&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;덧붙이자면 초기에는 INSERT IGNORE INTO와 REPLACE INTO를 고려했는데, 각각 다음과 같은 특징이 있기에 내가 원하는 결과와 맞지 않아 사용하지 않았다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;INSERT IGNORE INTO: Key가 겹치는 레코드의 삽입을 무시하므로 갱신되지 않는다.&lt;/li&gt;
&lt;li&gt;REPLACE INTO: 조건에 맞는 레코드들을 제거한 후 새로 생성하기 때문에 Key가 변조된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참고&lt;/h3&gt;
&lt;figure id=&quot;og_1739493602891&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[MySQL]중복 데이터를 관리하는 다양한 방법(INSERT IGNORE, ON DUPLICATED UPDATE, REPLACE INTO)&quot; data-og-description=&quot; 중복 데이터를 관리하는 다양한 방법 신규 데이터의 INSERT시 Key로 지정된 값이 중복되는 데이터가 생기는 경우가 있다. 이러한 경우에 MySQL에서는 중복 데이터를 관리하는 세 가지 방법이 있&quot; data-og-host=&quot;mooonstar.tistory.com&quot; data-og-source-url=&quot;https://mooonstar.tistory.com/entry/MySQL%EC%A4%91%EB%B3%B5-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A5%BC-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%B0%A9%EB%B2%95INSERT-IGNORE-ON-DUPLICATED-UPDATE-REPLACE-INTO&quot; data-og-url=&quot;https://mooonstar.tistory.com/entry/MySQL%EC%A4%91%EB%B3%B5-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A5%BC-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%B0%A9%EB%B2%95INSERT-IGNORE-ON-DUPLICATED-UPDATE-REPLACE-INTO&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bOZD4s/hyYf3QXtHo/TuxJA4Q9A3xckm9ytVuvcK/img.png?width=384&amp;amp;height=260&amp;amp;face=0_0_384_260,https://scrap.kakaocdn.net/dn/eIW0K/hyYfSu7xeu/Ae8Fa9tbmCTP2lxCq5zER0/img.png?width=384&amp;amp;height=260&amp;amp;face=0_0_384_260&quot;&gt;&lt;a href=&quot;https://mooonstar.tistory.com/entry/MySQL%EC%A4%91%EB%B3%B5-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A5%BC-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%B0%A9%EB%B2%95INSERT-IGNORE-ON-DUPLICATED-UPDATE-REPLACE-INTO&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mooonstar.tistory.com/entry/MySQL%EC%A4%91%EB%B3%B5-%EB%8D%B0%EC%9D%B4%ED%84%B0%EB%A5%BC-%EA%B4%80%EB%A6%AC%ED%95%98%EB%8A%94-%EB%8B%A4%EC%96%91%ED%95%9C-%EB%B0%A9%EB%B2%95INSERT-IGNORE-ON-DUPLICATED-UPDATE-REPLACE-INTO&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bOZD4s/hyYf3QXtHo/TuxJA4Q9A3xckm9ytVuvcK/img.png?width=384&amp;amp;height=260&amp;amp;face=0_0_384_260,https://scrap.kakaocdn.net/dn/eIW0K/hyYfSu7xeu/Ae8Fa9tbmCTP2lxCq5zER0/img.png?width=384&amp;amp;height=260&amp;amp;face=0_0_384_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[MySQL]중복 데이터를 관리하는 다양한 방법(INSERT IGNORE, ON DUPLICATED UPDATE, REPLACE INTO)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt; 중복 데이터를 관리하는 다양한 방법 신규 데이터의 INSERT시 Key로 지정된 값이 중복되는 데이터가 생기는 경우가 있다. 이러한 경우에 MySQL에서는 중복 데이터를 관리하는 세 가지 방법이 있&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mooonstar.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;figure id=&quot;og_1739493610322&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[MySQL8.0] row constructor 여러 레코드를 서로 다른 값으로 업데이트하는 방법&quot; data-og-description=&quot;개인 게시판 프로젝트를 진행하고 있습니다. 구현한 기술 요구사항 중, 각 게시글의 조회수를 요청마다 한 건씩 바로 업데이트 하는 것이 아니라 어딘가에 모아뒀다가 한번에 Update쿼리를 쏟아&quot; data-og-host=&quot;leezzangmin.tistory.com&quot; data-og-source-url=&quot;https://leezzangmin.tistory.com/48&quot; data-og-url=&quot;https://leezzangmin.tistory.com/48&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/D1sju/hyYfMuRLe0/JntpkOMEV8MgqaAXeuEYaK/img.png?width=800&amp;amp;height=555&amp;amp;face=0_0_800_555,https://scrap.kakaocdn.net/dn/cISWun/hyYf3wDMPr/xo9Pti3fakBG8pDiKDj0kk/img.png?width=800&amp;amp;height=555&amp;amp;face=0_0_800_555,https://scrap.kakaocdn.net/dn/zxtCa/hyYfShArtU/tquGqiUGFtevzG19DdfSNK/img.png?width=1330&amp;amp;height=1346&amp;amp;face=0_0_1330_1346&quot;&gt;&lt;a href=&quot;https://leezzangmin.tistory.com/48&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leezzangmin.tistory.com/48&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/D1sju/hyYfMuRLe0/JntpkOMEV8MgqaAXeuEYaK/img.png?width=800&amp;amp;height=555&amp;amp;face=0_0_800_555,https://scrap.kakaocdn.net/dn/cISWun/hyYf3wDMPr/xo9Pti3fakBG8pDiKDj0kk/img.png?width=800&amp;amp;height=555&amp;amp;face=0_0_800_555,https://scrap.kakaocdn.net/dn/zxtCa/hyYfShArtU/tquGqiUGFtevzG19DdfSNK/img.png?width=1330&amp;amp;height=1346&amp;amp;face=0_0_1330_1346');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[MySQL8.0] row constructor 여러 레코드를 서로 다른 값으로 업데이트하는 방법&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;개인 게시판 프로젝트를 진행하고 있습니다. 구현한 기술 요구사항 중, 각 게시글의 조회수를 요청마다 한 건씩 바로 업데이트 하는 것이 아니라 어딘가에 모아뒀다가 한번에 Update쿼리를 쏟아&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leezzangmin.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공식문서는 안 찾아보고 다른 분의 블로그 링크만 박아두는게 개발자가 할 일일까&lt;/p&gt;</description>
      <category>Dev./persistence</category>
      <category>mysql</category>
      <author>인쥭</author>
      <guid isPermaLink="true">https://ingnoh.tistory.com/234</guid>
      <comments>https://ingnoh.tistory.com/234#entry234comment</comments>
      <pubDate>Fri, 14 Feb 2025 09:40:50 +0900</pubDate>
    </item>
    <item>
      <title>[Rancher Desktop] Skipping duplicate certificate</title>
      <link>https://ingnoh.tistory.com/233</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;백만년만에 쓰는 글&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Docker Desktop 유료화에 따른 선택이건, 다른 이유에서건 Rancher Desktop을 사용하는 도중 요런 에러를 만날 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1737503632640&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Error Starting Kubernetes

Error: /Applications/Rancher Desktop.app/Contents/Resources/resources/darwin/lima/bin/limactl.ventura exited with code 1

Last command run:
/Applications/Rancher Desktop.app/Contents/Resources/resources/darwin/lima/bin/limactl.ventura --debug shell --workdir=. 0 sudo update-ca-certificates

Context:
Installing CA certificates

Logfiles:
'WARNING: Skipping duplicate certificate in file ca-cert-Comodo_AAA_Services_root.pem\n' +
'WARNING: Skipping duplicate certificate in file ca-cert-Atos_TrustedRoot_Root_CA_RSA_TLS_2021.pem\n' +
'WARNING: Skipping duplicate certificate in file ca-cert-SSL.com_Root_Certification_Authority_RSA.pem\n' +
'WARNING: Skipping duplicate certificate in file'... 508 more characters,
code: 1,
[Symbol(child-process.command)]: '/Applications/Rancher Desktop.app/Contents/Resources/resources/darwin/lima/bin/limactl.ventura --debug shell --workdir=. 0 sudo update-ca-certificates'
}
2024-11-15T08:39:10.495Z: Progress: errored Starting Backend: Error: /Applications/Rancher Desktop.app/Contents/Resources/resources/darwin/lima/bin/limactl.ventura exited with code 1&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로컬 환경에 있는 인증서와 관련된 이슈인 것 같은데, rancher-sandbox에 제출된 이슈 몇몇을 확인해보면 '상세한 로그를 제출하지 않는다면 정확한 원인을 파악할 수 없다'고 한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;해결법&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상세한 원인을 파악할 수 없어 찝찝하지만, 대부분의 경우 Rancher Desktop 자체적으로 제공되는 공장 초기화 기능을 활용하여 해결할 수 있다고 한다. 아래와 같이 공장 초기화를 진행하도록 하자.&lt;br /&gt;당연한 말이지만, &lt;u&gt;&lt;b&gt;공장 초기화기 때문에 Preference에서 기존에 적용해뒀던 설정은 모두 날라간다&lt;/b&gt;&lt;/u&gt;. 난 로컬 개발 환경에서만 적당히 Docker를 돌리고 있어서 상관 없었지만, 뭔가 자신만의 설정값을 적용해둔 분들은 꼭 이 점을 유념하고 공장 초기화를 진행하도록 하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Rancher Desktop의 main window를 열고, Troubleshooting 탭에 들어가서 공장 초기화를 진행한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-22 오전 9.01.06.png&quot; data-origin-width=&quot;1321&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNJKuS/btsLVvfkZKI/9NQ9A6nB9jN9VVMT0JEwWK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNJKuS/btsLVvfkZKI/9NQ9A6nB9jN9VVMT0JEwWK/img.png&quot; data-alt=&quot;저 버튼을 누르면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNJKuS/btsLVvfkZKI/9NQ9A6nB9jN9VVMT0JEwWK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNJKuS%2FbtsLVvfkZKI%2F9NQ9A6nB9jN9VVMT0JEwWK%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;1321&quot; height=&quot;832&quot; data-filename=&quot;스크린샷 2025-01-22 오전 9.01.06.png&quot; data-origin-width=&quot;1321&quot; data-origin-height=&quot;832&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;저 버튼을 누르면&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2025-01-22 오전 9.01.32.png&quot; data-origin-width=&quot;1321&quot; data-origin-height=&quot;832&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0PO2q/btsLWxwEqL3/yGsk8M1mrgGdv3wcAFMca0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0PO2q/btsLWxwEqL3/yGsk8M1mrgGdv3wcAFMca0/img.png&quot; data-alt=&quot;요 창이 뜬다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0PO2q/btsLWxwEqL3/yGsk8M1mrgGdv3wcAFMca0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0PO2q%2FbtsLWxwEqL3%2FyGsk8M1mrgGdv3wcAFMca0%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;1321&quot; height=&quot;832&quot; data-filename=&quot;스크린샷 2025-01-22 오전 9.01.32.png&quot; data-origin-width=&quot;1321&quot; data-origin-height=&quot;832&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;요 창이 뜬다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 쿠버네티스를 사용하고 있지 않기 때문에 'Keep cached Kubernetes images' 체크박스를 체크하지 않고 그냥 진행했다.&lt;br /&gt;공장 초기화를 진행할 경우 별도의 창 없이 수분(내 경우, 1분) 후 Rancher Desktop이 자동으로 종료되며, 다시 Rancher Desktop을 실행하는 것으로 정상 동작을 확인할 수 있다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;figure id=&quot;og_1737504314436&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;Kubernetes error when running Rancher Desktop 1.16.0 - darwin(x64) &amp;middot; Issue #7778 &amp;middot; rancher-sandbox/rancher-desktop&quot; data-og-description=&quot;Actual Behavior When starting up Rancher Desktop on my Macbook Pro (MacOS Sonoma 14.7.1) I am getting this error. Error Starting Kubernetes Error: /Applications/Rancher Desktop.app/Contents/Resourc...&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/rancher-sandbox/rancher-desktop/issues/7778&quot; data-og-url=&quot;https://github.com/rancher-sandbox/rancher-desktop/issues/7778&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/buvR8o/hyX4tv7rSf/r1tL1FDi7Eq8i0vNEh3Kk0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/RUUND/hyX4mKv3K1/v9JU3RL4N524ASJkWxDMiK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/rancher-sandbox/rancher-desktop/issues/7778&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/rancher-sandbox/rancher-desktop/issues/7778&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/buvR8o/hyX4tv7rSf/r1tL1FDi7Eq8i0vNEh3Kk0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/RUUND/hyX4mKv3K1/v9JU3RL4N524ASJkWxDMiK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Kubernetes error when running Rancher Desktop 1.16.0 - darwin(x64) &amp;middot; Issue #7778 &amp;middot; rancher-sandbox/rancher-desktop&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Actual Behavior When starting up Rancher Desktop on my Macbook Pro (MacOS Sonoma 14.7.1) I am getting this error. Error Starting Kubernetes Error: /Applications/Rancher Desktop.app/Contents/Resourc...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1737504319865&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Features | Rancher Desktop Docs&quot; data-og-description=&quot;General&quot; data-og-host=&quot;docs.rancherdesktop.io&quot; data-og-source-url=&quot;https://docs.rancherdesktop.io/1.6/getting-started/features/#factory-reset&quot; data-og-url=&quot;https://docs.rancherdesktop.io/1.6/getting-started/features&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/byGDCD/hyX4sqp9Sh/zjJnnr82LRwm0mK863E9nk/img.png?width=1150&amp;amp;height=737&amp;amp;face=0_0_1150_737&quot;&gt;&lt;a href=&quot;https://docs.rancherdesktop.io/1.6/getting-started/features/#factory-reset&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.rancherdesktop.io/1.6/getting-started/features/#factory-reset&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/byGDCD/hyX4sqp9Sh/zjJnnr82LRwm0mK863E9nk/img.png?width=1150&amp;amp;height=737&amp;amp;face=0_0_1150_737');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Features | Rancher Desktop Docs&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;General&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.rancherdesktop.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Dev./Docker</category>
      <category>Docker</category>
      <category>RancherDesktop</category>
      <author>인쥭</author>
      <guid isPermaLink="true">https://ingnoh.tistory.com/233</guid>
      <comments>https://ingnoh.tistory.com/233#entry233comment</comments>
      <pubDate>Wed, 22 Jan 2025 09:05:44 +0900</pubDate>
    </item>
    <item>
      <title>[MySQL] homebrew로 MySQL 제거 후 재설치, 포트 변경</title>
      <link>https://ingnoh.tistory.com/232</link>
      <description>&lt;pre id=&quot;code_1730098437197&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[~] brew services list # service 상태 확인
Name    Status  User         File
mysql   started ingnoh [...]
[~] brew services stop mysql # 삭제를 위해 service 중지
[~] brew uninstall mysql # mysql 삭제
# 대충 삭제 과정...
# 오래 걸리진 않는다...
[~] brew install mysql@8.4
# 대충 설치 과정...
# 이건 오래 걸린다...
[~] brew services start mysql@8.4 # mysql 8.4 서비스 시작
[~] mysql --help | grep my.cnf # 포트 번호 설정을 위한 my.cnf 파일 조회
                      order of preference, my.cnf, $MYSQL_TCP_PORT,
/etc/my.cnf /etc/mysql/my.cnf /opt/homebrew/etc/my.cnf ~/.my.cnf
[~] brew services stop mysql@8.4 # 포트 번호 설정을 위해 일단 mysql 서비스를 종료해둔다.
[~] # homebre로 설치했으니 /opt/homebrew/etc/my.cnf에 있다!
[~] cat /opt/homebrew/etc/my.cnf
# Default Homebrew MySQL server config
[mysqld]
# Only allow connections from localhost
bind-address = 127.0.0.1
[~] echo 'port=13306' &amp;gt;&amp;gt; /opt/homebrew/etc/my.cnf # 13306 자리에 원하는 포트 명을 입력한다.
[~] cat /opt/homebrew/etc/my.cnf
# Default Homebrew MySQL server config
[mysqld]
# Only allow connections from localhost
bind-address = 127.0.0.1
port=13306
[~] brew services start mysql@8.4 # 포트 번호 적용을 위해 mysql 서비스를 시작한다.
[~] lsof -i :13306 # 요 명령어로 확인 가능하다
COMMAND   PID         USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
mysqld  99999       ingnoh   21u  IPv4 0x0000000000000000      0t0  TCP localhost:13306 (LISTEN)
[~] # 끄읏&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;참고&lt;/h4&gt;
&lt;figure id=&quot;og_1730098459044&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;로컬에서 mysql 서버 셋업하고 포트 넘버 변경하기&quot; data-og-description=&quot;로컬에서 mysql 서버를 셋업해보자&quot; data-og-host=&quot;medium.com&quot; data-og-source-url=&quot;https://medium.com/@aiden.p/%EB%A1%9C%EC%BB%AC%EC%97%90%EC%84%9C-mysql-%EC%84%9C%EB%B2%84-%EC%85%8B%EC%97%85%ED%95%98%EA%B3%A0-%ED%8F%AC%ED%8A%B8-%EB%84%98%EB%B2%84-%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0-eeadaab3281&quot; data-og-url=&quot;https://medium.com/@aiden.p/%EB%A1%9C%EC%BB%AC%EC%97%90%EC%84%9C-mysql-%EC%84%9C%EB%B2%84-%EC%85%8B%EC%97%85%ED%95%98%EA%B3%A0-%ED%8F%AC%ED%8A%B8-%EB%84%98%EB%B2%84-%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0-eeadaab3281&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cusHFO/hyXpyj5rB6/ghoxRNzkL9MK1c0fCkdjKk/img.jpg?width=900&amp;amp;height=500&amp;amp;face=0_0_900_500,https://scrap.kakaocdn.net/dn/lOVsK/hyXpuWh3y2/yVwgM0iuqxEK1gkdKMywNK/img.png?width=1358&amp;amp;height=723&amp;amp;face=0_0_1358_723,https://scrap.kakaocdn.net/dn/bs2jvi/hyXpxeogQ6/OX8bWVvyylgPYReOaQptjK/img.png?width=1358&amp;amp;height=684&amp;amp;face=625_152_722_260&quot;&gt;&lt;a href=&quot;https://medium.com/@aiden.p/%EB%A1%9C%EC%BB%AC%EC%97%90%EC%84%9C-mysql-%EC%84%9C%EB%B2%84-%EC%85%8B%EC%97%85%ED%95%98%EA%B3%A0-%ED%8F%AC%ED%8A%B8-%EB%84%98%EB%B2%84-%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0-eeadaab3281&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://medium.com/@aiden.p/%EB%A1%9C%EC%BB%AC%EC%97%90%EC%84%9C-mysql-%EC%84%9C%EB%B2%84-%EC%85%8B%EC%97%85%ED%95%98%EA%B3%A0-%ED%8F%AC%ED%8A%B8-%EB%84%98%EB%B2%84-%EB%B3%80%EA%B2%BD%ED%95%98%EA%B8%B0-eeadaab3281&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cusHFO/hyXpyj5rB6/ghoxRNzkL9MK1c0fCkdjKk/img.jpg?width=900&amp;amp;height=500&amp;amp;face=0_0_900_500,https://scrap.kakaocdn.net/dn/lOVsK/hyXpuWh3y2/yVwgM0iuqxEK1gkdKMywNK/img.png?width=1358&amp;amp;height=723&amp;amp;face=0_0_1358_723,https://scrap.kakaocdn.net/dn/bs2jvi/hyXpxeogQ6/OX8bWVvyylgPYReOaQptjK/img.png?width=1358&amp;amp;height=684&amp;amp;face=625_152_722_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;로컬에서 mysql 서버 셋업하고 포트 넘버 변경하기&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;로컬에서 mysql 서버를 셋업해보자&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;medium.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Dev./persistence</category>
      <category>mysql</category>
      <author>인쥭</author>
      <guid isPermaLink="true">https://ingnoh.tistory.com/232</guid>
      <comments>https://ingnoh.tistory.com/232#entry232comment</comments>
      <pubDate>Mon, 28 Oct 2024 15:54:28 +0900</pubDate>
    </item>
    <item>
      <title>[mockk] private extension function 모킹하기</title>
      <link>https://ingnoh.tistory.com/231</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;메소드 호출시 내부 동작 과정에서 private extension function을 사용하는 MyClass라는 이름의 클래스가 있다고 하자. &lt;br /&gt;해당 클래스는 인자로 전달 받은 값에 3을 더한 후 문자열로 변환한 값을 반환하는 하나의 메소드만을 공개하고 있으며, 이러한 기능을 Kotest로 테스트한다면 다음과 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1730080262335&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class PlaygroundTest : StringSpec({
    &quot;convertToStringAfterAdd3 should return string of value after add 3&quot; {
        // given
        val input = 5
        val myClass = MyClass()

        // when
        val result = myClass.convertToStringAfterAdd3(input)

        // then
        result shouldBe &quot;${input + 3}&quot;
    }
}) {
    class MyClass {
        fun convertToStringAfterAdd3(value: Int): String
            = &quot;${value.add3()}&quot;

        private fun Int.add3(): Int
            = this + 3
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상술한 바와 같이 MyClass는 내부적으로 add3()라는 Int 확장 함수를 사용하는데, add3() 메소드는 private으로 지정되어 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 mockk를 활용하여 이러한 private extension function을 모킹해야 하는 경우가 있다고 하면, 아래와 같이 작성해주면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1730080442004&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class PlaygroundTest : StringSpec({
    &quot;convertToStringAfterAdd3 should return result of Int.add3() as string&quot; {
        // given
        val myClass = spyk(
            objToCopy = MyClass(),
            recordPrivateCalls = true,
        )

        val expected = 42
        // 이럿게
        every { myClass[&quot;add3&quot;](ofType(Int::class)) } returns expected

        // when
        val result = myClass.convertToStringAfterAdd3(3)

        // then
        result shouldBe &quot;$expected&quot;
    }
}) {
    class MyClass {
        fun convertToStringAfterAdd3(value: Int): String
            = &quot;${value.add3()}&quot;

        private fun Int.add3(): Int
            = this + 3
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이는 MyClass가 다음과 같은 java 코드로 변환되기 때문이다.&lt;/p&gt;
&lt;pre id=&quot;code_1730080760939&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static final class MyClass {
   @NotNull
   public final String convertToStringAfterAdd3(int value) {
      return String.valueOf(this.add3(value));
   }

   // 수신 객체가 첫 번째 인자로 전달된다.
   private final int add3(int $this$add3) {
      return $this$add3 + 3;
   }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;때문에 add3() 메소드가 인자를 여럿 받는 경우를 가정한다고 하면 아래처럼 모킹해주면 된다. &lt;br /&gt;항상 &lt;u&gt;&lt;b&gt;수신 객체가 첫 번째 인자에 위치&lt;/b&gt;&lt;/u&gt;한다!&lt;/p&gt;
&lt;pre id=&quot;code_1730080681531&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class PlaygroundTest : StringSpec({
    &quot;convertToStringAfterAdd3 should return result of Int.add3() as string&quot; {
        // given
        val myClass = spyk(
            objToCopy = MyClass(),
            recordPrivateCalls = true,
        )

        val expected = 42
        every { myClass[&quot;add3&quot;](ofType(Int::class), ofType(Long::class), ofType(Double::class)) } returns expected

        // when
        val result = myClass.convertToStringAfterAdd3(3)

        // then
        result shouldBe &quot;$expected&quot;
    }
}) {
    class MyClass {
        fun convertToStringAfterAdd3(value: Int): String
            = &quot;${value.add3(1L, 3.14)}&quot;

        private fun Int.add3(salt1: Long, salt2: Double): Int
            = this + salt1.toInt() + salt2.toInt() + 3
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시라곤 요딴 것 밖에 만들지 못하는 비루한 나의 상상력...&lt;/p&gt;</description>
      <category>Dev./Kotlin</category>
      <category>kotlin</category>
      <category>Mockk</category>
      <author>인쥭</author>
      <guid isPermaLink="true">https://ingnoh.tistory.com/231</guid>
      <comments>https://ingnoh.tistory.com/231#entry231comment</comments>
      <pubDate>Mon, 28 Oct 2024 11:01:08 +0900</pubDate>
    </item>
    <item>
      <title>[Docker] 이미지 태그 변경하기</title>
      <link>https://ingnoh.tistory.com/230</link>
      <description>&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;pre id=&quot;code_1726106678945&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;[~] docker image tag [기존태그]:[기존버전] [변경할태그]:[변경할버전]&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결과는 docker images 명령으로 확인할 수 있다.&lt;/p&gt;</description>
      <category>Dev./Docker</category>
      <category>Docker</category>
      <author>인쥭</author>
      <guid isPermaLink="true">https://ingnoh.tistory.com/230</guid>
      <comments>https://ingnoh.tistory.com/230#entry230comment</comments>
      <pubDate>Thu, 12 Sep 2024 11:06:05 +0900</pubDate>
    </item>
    <item>
      <title>[Git] rebase를 활용한 커밋 합치기</title>
      <link>https://ingnoh.tistory.com/229</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;협업을 위해서나, 개인적인 성향으로 인해 커밋 메시지를 예쁘게 관리하고 싶으나, &lt;br /&gt;아래와 같이 불필요한 커밋을 여러 번 남기는 경우가 있을 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1721462017323&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# git log --oneline
b719582 (HEAD -&amp;gt; master) feat: 아 validation 안 넣었다...
74c5dfb feat: app.service.ts에 delete API 추가
14d219a feat: app.service.ts에 post API 추가
1bfe513 init: 프로젝트 스캐폴딩&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 경우 커밋 b719582은 불필요하므로, 아래의 74c5dfb 커밋에 합쳐주고 싶다.&lt;br /&gt;(하술할 모든 내용은 로컬 저장소의 작업 내용을 기준으로 하며, &lt;u&gt;아직 원격 저장소에 푸시하지 않은 상황을 가정&lt;/u&gt;한다!)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;git rebase 명령어 활용하기&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;git rebase -i HEAD~[커밋개수] 명령어를 입력할 경우, 아래와 같은 편집기가 열리게 된다. &lt;br /&gt;상술한 예시에서는 b7과 74를 합치므로 커밋개수는 2가 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1721462250239&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# git rebase -i HEAD~2
pick 74c5dfb feat: app.service.ts에 delete API 추가
pick b719582 feat: 아 validation 안 넣었다...

# Rebase 14d219a..b719582 onto 14d219a (2 commands)
#
# Commands:
# p, pick &amp;lt;commit&amp;gt; = use commit
# r, reword &amp;lt;commit&amp;gt; = use commit, but edit the commit message
# e, edit &amp;lt;commit&amp;gt; = use commit, but stop for amending
# s, squash &amp;lt;commit&amp;gt; = use commit, but meld into previous commit
# f, fixup [-C | -c] &amp;lt;commit&amp;gt; = like &quot;squash&quot; but keep only the previous
#                    commit's log message, unless -C is used, in which case
#                    keep only this commit's message; -c is same as -C but&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pick은 해당 커밋을 사용한다는 의미이므로, 이전 커밋과 합치기 위해 아래와 같이 pick을 s로 바꾸고 :wq!로 저장한다.&lt;/p&gt;
&lt;pre id=&quot;code_1721462751789&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# git rebase -i HEAD~2
pick 74c5dfb feat: app.service.ts에 delete API 추가
s b719582 feat: 아 validation 안 넣었다...

# Rebase 14d219a..b719582 onto 14d219a (2 commands)
#
# Commands:
# p, pick &amp;lt;commit&amp;gt; = use commit
# r, reword &amp;lt;commit&amp;gt; = use commit, but edit the commit message
# e, edit &amp;lt;commit&amp;gt; = use commit, but stop for amending
# s, squash &amp;lt;commit&amp;gt; = use commit, but meld into previous commit
# f, fixup [-C | -c] &amp;lt;commit&amp;gt; = like &quot;squash&quot; but keep only the previous
#                    commit's log message, unless -C is used, in which case
#                    keep only this commit's message; -c is same as -C but&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래와 같이 git log를 통해 잘 합쳐진 것을 확인할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1721462949776&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# git log --oneline
74c5dfb (HEAD) feat: app.service.ts에 delete API 추가
14d219a feat: app.service.ts에 post API 추가
1bfe513 init: 프로젝트 스캐폴딩&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Dev.</category>
      <category>Git</category>
      <author>인쥭</author>
      <guid isPermaLink="true">https://ingnoh.tistory.com/229</guid>
      <comments>https://ingnoh.tistory.com/229#entry229comment</comments>
      <pubDate>Sat, 20 Jul 2024 17:09:59 +0900</pubDate>
    </item>
  </channel>
</rss>