자~ 이번에는 "Merge Sort"에 대해서 알아보자.

한글로는 "합병 정렬" 또는 "병합 정렬"이라고 불리운다.

[출처] https://www.whatwant.com

 

세계의 모든 지식이 들어있다고 해도 과언이 아닌 위키피디아에서는

Animated GIF 이미지로 Merge Sort를 너무나 잘 설명해주고 있다.

[출처] https://en.wikipedia.org/wiki/Merge_sort

 

이 알고리즘은 그 유명한 "존 폰 노이만(John von Neumann)"님이 1945년에 개발했다고 한다.

우리의 갓 노이만 형님 !!!

 

위 Animation을 잘 지켜보면 알겠지만,

"Divide-and-Conquer (분할 및 정복)" 알고리즘의 하나이다.

[출처] https://www.whatwant.com

 

반절씩 잘라서 나누고, 합치면서 정렬을 하는 것이다.

[출처] https://www.whatwant.com

 

그런데, 실제 구현을 할 때 divide를 하기 위해서

위의 그림에 있는 모든 박스의 갯수만큼 별도의 메모리 공간을 확보해야 할까?

 

한 번에 모든 메모리 공간을 확보하는 것 보다는

한 단계씩 나눠서 그 때 그 때 필요한 값을 복사해서 사용하는 방식이 훨씬 효율적이고 똑똑한 방법이 되겠다.

 

무슨 말이냐고!?

한 단계씩 밟아나가보자 !!!

[출처] https://www.whatwant.com

 

위 그림과 같이 8개의 입력이 있다고 해보자.

인덱스(index)값의 의미로 "[ ]"로 묶은 형태로 표기해보았다.

 

우리의 명령(입력)은 다음과 같다.

 

"1번부터 8번까지의 인덱스를 갖고 있는 입력값을 merge sort 해줘 !!!"

 

이것을 1-depth 더 들어가서 살펴보면 다음과 같다.

 

"1번부터 4번까지의 값을 merge sort하고

5번부터 8번까지의 값을 merge sort한 다음에

그 2개의 결과를 merge 해줘"

 

어!? 여기에서 조금 애매한 표현이 등장했다. merge ???

[출처] https://www.whatwant.com

 

[5, 6] 과 [1, 3]을 merge 하는 과정을 보면 그냥 합치는 것이 아니라

크기를 비교해서 작은 것부터 차례대로 하나씩 넣어가는 과정이다.

 

그리고 여기에서 주의해야할 사항이 하나 더 있다.

 

[5, 6] 과 [1, 3]을 merge 할 수 있는 것은 [5, 6] 과 [1, 3]이 각각 이미 sort가 되어있기 때문이다.

 

그림으로 살펴보자.

[출처] https://www.whatwant.com

 

[2, 4, 1, 3]이라는 값을 merge 한다고 하면

반절 크기의 2개의 메모리 공간을 잡아놓고, 거기로 값들을 복사한다.

[출처] https://www.whatwant.com

 

그리고 2개 메모리 공간의 앞 부분의 값을 비교해서

작은 값 순서대로 하나씩 복사해 넣는 과정으로 정렬이 된 값으로 merge가 된다.

 

Pseudo Code는 다음과 같다.

[출처] https://www.whatwant.com

 

p, q, r 값의 정체는 다음과 같다.

[출처] https://www.whatwant.com

 

merge 작업을 할 시작 위치(p), 끝 위치(r), 그리고 divide를 할 중간값(q)이다.

그러면 pseudo code를 진행하면서 정해지는 값/상태들을 확인해보자.

 

쪼갠 값들을 저장할 메모리 공간의 크기를 계산하기 위한 n1, n2 값을 계산한다.

[출처] https://www.whatwant.com

 

divide한 값을 저장할 2개의 메모리 공간을 생성한다.

[출처] https://www.whatwant.com

 

응?! 4개가 아니라 5개씩 공간을 준비하네?!

그 다음 pseudo code들을 진행해보면 이유를 알겠지.

[출처] https://www.whatwant.com

 

이제 모든 준비는 끝났다.

[출처] https://www.whatwant.com

 

여기까지 해서 merge 과정에 대해서 살펴봤다.

이제, 전체적으로 merge sort 하기 위한 pseudo code를 알아보자.

[출처] https://www.whatwant.com

 

3번 라인은 본래 아래와 같은 notation이다.

Editor에서 사용 가능한 기호 중에서 마땅한 것을 찾지 못해서 ^^

[출처] https://www2.hawaii.edu/~suthers/courses/ics311f20/Notes/Topic-02.html

 

2로 나눈 결과의 소숫점 버림값을 취하겠다는 의미이다.

 

지금까지 살펴본 내용을 기반으로 Python으로 구현해보면 다음과 같다.

[출처] https://www.whatwant.com

 

 

Merge Sort를 어떻게 하는 것인지에 대해서는 이제 다 알아봤다.

남은 것은 Performance 측정이다.

 

먼저, Merge 과정에 소요되는 시간을 계산해보자.

[출처] https://www.whatwant.com

 

위 그림에서 보이는 것 처럼

핵심적인 부분은 move와 comapre로 구성되어 있다.

 

move는 "n1 + n2" 횟수만큼 실행이 되고

compare는 "n1 + n2" 보다 작거나 같은 횟수만큼 실행이 될 것이다.

 

그렇기 때문에, 전체적으로 2 * (n1 + n2) 횟수보다 같거나 적은 횟수만큼 실행이 된다고 봐도 무방할 것이다.

 

Merge = Θ(n1 + n2)

 

그러면, 전체 Merge Sort의 소요 시간은 얼마나 될까!?

 

[출처] https://www.whatwant.com

 

MERGE-SORT(A, p, r) 의 소요 시간을 T(n) 이라고 하면,

3번째 라인과 4번째 라인은 n의 이등분된 값을 갖게 되므로 T(n/2) 값을 갖는다고 할 수 있다.

 

5번째 라인은 바로 앞에서 살펴본 내용에서 n1 + n2 = n 이므로 Θ(n) 값으로 표현해볼 수 있다.

 

여기에서 생각해볼 것은 1번 라인이 비교문이라는 것이다.

비교문을 통과하지 못하는 경우를 생각해보면, p < r을 만족하지 못하는 경우는 n=1 일 경우일 것이다.

 

그래서 점화식으로 표현해보면 다음과 같다.

[출처] https://www.whatwant.com

 

이와 같은 경우는 'Recursion Tree Method(재귀 트리 방법)'을 통해 풀어낼 수 있는데,

중간 과정은 생략하고.... 그래서 계산한 결과는 다음과 같이 정리된다.

[출처]&nbsp;https://cs.stackexchange.com/questions/64060/mergesort-recurssion-tree-depth-logs

 

위의 이미지에서는 Big-O로 표기되었지만, Big-Theta로 할 수 있다.

 

그러면 메모리 공간은 얼마나 사용할까?

 

"n"개 만큼 더 필요로 한다.

최대 n개 공간이 있으면 그것을 이용해서 모두 계산 가능하다.

반응형


Git에 대해서 공부하다보면, 조금 답답한 것 중 하나가 용어 정리를 해주지를 않는다는 점이다.
그런 것 중 하나가 바로 [ Fast-Forward ]라는 용어다.


이 블로그에 포스팅하고 있는 내용들 모두 마찬가지이지만,
특히 이번 블로그는 절대적으로 개인적인 의견과 함께 개인적으로 정리한 내용이다.
즉, 완전 거짓말일 수 있다는 말이다. 꼭 참고하길 바란다!!! (책임지지 않아요~)



1. 합치자고~

     - Git에서 이루어지는 merge 방법은 다음의 세가지 타입이 있다.
          ▷ 3-way merge
          ▷ fast-forward merge
          ▷ cherry-pick

     - 명령어로 따지면 다음 3가지 방법이 있다.
          ▷ merge
          ▷ rebase
          ▷ cherry-pick



2. 명령어와 방식의 구분

     - 각 명령어와 merge 방식의 관계는 다음과 같다.

  merge rebase cherry-pick
3-way merge O X X
fast-forward merge O O X
cherry-pick X X O

 


     - 즉, merge 명령을 통해서는 상황에 따라 "3-way merge"가 이루어질 수도 있고,
       "fast-forward merge"가 이루어질 수도 있다.

     - rebase 명령의 경우에는 기본적으로 "fast-forward merge"가 이루어진다.
     - cherry-pick 명령은 "cherry-pick"을 위한 명령이다.




3. fast-forward merge

     - fast-forward의 본래 뜻은...!? 앞으로 감다!!! 즉, FF 버튼이나 FFWD 버튼이 바로 이것이다.
     - fast-forward merge가 이루어지는 경우는 두 가지이다.

          ▷ merge 상황에서 merge를 하는 branch에서 별도의 commit이 없는 경우
          ▷ rebase를 수행하는 경우

 


4. 3-way merge

     - 일반적인 merge 상황에서 git은 기본적으로 3-way merge를 수행한다. 
     - 양쪽 브랜치에 commit이 있는 상황에서 merge를 하면 merge commit과 함께 합쳐지는 것이다.

 

5. cherry-pick merge

     - 특정 commit만을 반영하고 싶은 경우이다. 
     - 양쪽 브랜치에 commit이 있는 상황에서 merge를 하면 merge commit과 함께 합쳐지는 것이다.

 

정말 옛날에 작성해놓고 keep 하고 있는 포스팅인데...

자세한 설명은 다음 기회에 하기로 하고... 그냥 발행한다 ^^

(잠자고 있는 포스트 발행하기 프로젝트 중이라서... ㅋㅋ)

 

반응형

Git의 가장 큰 장점인 자유로운 branch, 그 branch의 자유로운 사용의 최종 종착지는 바로 merge다.
즉, branch를 생성해서 자유롭게 작업하다가 그 결과가 쓸만해지면 master에 merge하는 것이 일반적인 경우이다.
그런데, 바로 이 자유로운 branch 때문에 repository 내부가 지저분해질 우려가 다분히 많다.

많은 사용자가 달라붙어서 작업을 하다보면 별의 별 희한한 개발습관을 보여주는 개발자가 꼭 존재하고,
이러한 개발자들로 인해서 master branch가 바보가 되어버리는 경우도 종종 발생한다.

문제는 이러한 경우로 인해서 Git의 안전성을 의심받기까지 한다는 점이다.

제대로 이해를 하고 사용하는 사용자들은 무관하지만,
어설픈 지식으로 말도 안되는 행위를 과감히 행하는 개발자들이 문제가 되는 것인데...

그렇다 하더라도 무조건 그 책임을 무지한 개발자 탓으로 할 수는 없다.

그 부분을 해결하는 것은 해당 repository를 운영하는 담당자의 몫이며,
그러한 부분에 대한 분명한 프로세스 또는 가이드를 제시해주어야 한다.

이런 막중한 책임과 임무를 가진 관리자에게 merge 명령어 외에도 또 하나의 무기를 Git에서 제공해주고 있다.
그것이 바로 rebase 이다.


1. branch

    - rebase를 설명해보기 위해서 상황을 준비해보자.


$ git checkout -b hotfix

     - 우선 branch 하나를 만들어 주고,


$ nano ./readme.txt
$ git commit -a -m "modify readme.txt in hotfix br"

     - 파일 하나 수정해서 commit까지 해보자.




2. before log

     - rebase 하기 전에 현재 log를 살펴보고 시작하자.


$ git checkout master
$ git log -3




3. rebase

     - 우선은 'hotfix branch'의 log 부터 확인하고,


$ git checkout hotfix
$ git log -3

     - merge 대신에 우리모두 rebase 하자!


$ git rebase master

     - 어?! 뭔가 rebase가 정상적으로 이루어지지 않은 것 같다!


     - 바로 뒤에 설명을 하겠지만, 위와 같은 상황에서는 rebase를 할 것이 없다.


$ git checkout master
$ nano readme1.txt
$ git commit -a -m "modify readme1.txt in master br"

     - master branch에서 commit 하나 추가해보자.


     - 위 그림과 같이 A commit에서 각 branch 별로 분기를 하도록 한 것이다.


$ git checkout hotfix
$ git rebase master

     - 다시 rebase 해보자.
     - 그런데, log를 보면 이전 master branch에서 작업한 내용까지만 있다. 뭐지?!
     - rebase 후 해야하는 것이 fast-forward 해줘야 한다.


$ git merge hotfix

     - 어?! 뭔가 이상하지 않은가?
     - merge의 다른 방법이 rebase라는데, rebase를 하고도 결국 다시 merge를 해야하다니???

     - 일단, rebase를 하고 나면 아래와 같은 상태가 된다.


     - 뭔가 다른 점을 찾았는지.....?!
     - A에서 분기를 했던 hotfix branch의 B commit이 사라지고,
       master branch의 C commit 뒤에 새로운 B` commit이 생겼다.

     - rebase는 branch로 인한 commit의 분기를 한 줄로 다시 줄을 세운다. 그것도 새로운 commit을 만들어서...
     - 더불어 신기한 것은 기존의 commit은 사라진다(실제로 물리적으로 지워지는지는 나중에 살펴보겠다).

     - 그런데, 여기서 또 하나 잡아야 하는 포인트는 rebase 후에 master branch의 위치가 기존의 위치다.
     - hotfix branch의 내용을 master branch에 반영하기 위해서는 B` commit의 위치로 master branch가 가야한다.

     - 자료들을 보면 rebase 후 fast-forward 해주면 된다는데, fast-forward가 대체 뭔지....?! ㅋ~ 정답은 merge다.


     - 위와 그림과 같이 이루어진다.



앞에서 적었던 내용에 대해서 정정을 해야할 것 같다.

별도의 branch를 만들어서 작업을 하고 그것을 합치는 방법이 merge와 rebase의 두가지가 있다고 했는데,
이 말은 조금 틀린말 같다.

branch를 만들어서 작업한 내용을 합치는 방법은
바로 (즉시 merge)를 하는 방법과 (rebase 후 merge)를 하는 두 가지 방법이 있다.

rebase를 하는 이유는 commit을 깔끔하게 정리해서 일렬로 줄을 세워서 정리를 해주는 것이다.
즉, branch의 남발로 인해서 commit들이 꼬일 우려가 있는 상황에서 단순화 할 수 있는 좋은 수단이다.


다만, rebase를 사용하는 것은 작업하는 branch가 임시일 때 유용하다.
지속적으로 개발 branch를 유지하는 개발 프로세스를 사용한다면 rebase는 적합하지 않다.



오늘 두산이 KIA의 윤석민을 잡았다~!!! ^^
즐거운 하루~~~~ 인데, 포스팅을 하다보니 새벽 1시가 다가오네.... ㅠㅠ

모두 파이팅~!!!

반응형

Remote Repository의 변경 사항이 있을 때마다 fetch 받아서 merge를 하는 것은
왠지 비효율적인 것 같고 불편한 것 같이 느껴진다.

Git이 그런 아이가 아닌데....

물론 이와는 다른 방법이 있다. 편한 방법이...
이에 대해서 하나씩 살펴보자.



1. After merge

   - 앞에서 진행한 내용이후의 상황을 살펴보자.


$ git status
$ git log -4

   - remote의 변경 사항을 fetch 받아서 지금 작업하고 있는 내용에 merge를 한 상황이다.
   - 그런데, [ git status ]를 하면 "Your branch is ahead of 'origin/master' by 2 commits" 라고 보인다.

   - 하나는 local master branch에서 push 하지 않은 commit 이고,
   - 다른 하나는 merge로 인해서 발생한 commit 이다.



2. clean

   - 일단, 다른 것을 확인해보기 위해서 위와 같이 확인을 했다면, 잠시 정리 작업을 진행하자.


$ git push
$ git status

   - local에 남아있는 commits을 remote로 밀어 넣자.
   - [ git status ] 실행 결과가 위와 같이 깔끔해야 한다.



3. pull

   - 앞의 포스팅을 따라했다면, "2nd/bare1repo" 를 만들었을 것이다.
   - 만약에 없다면, 그냥 무시~ ^^


$ git pull


   - remote repository에서 소스를 받아온 후, 아무런 작업이 없었다면 (push 안된 commit이 없는 경우)
   - 위와 같이 그냥 소스코드를 업데이트 하곤 끝이다.



4. remote repository update

   - 오늘 살펴볼 내용을 만들기 위해서 별도의 local에서 작업 후 push하여 remote를 업데이트 해보자.


   - 일단은 모두 정리를 했다면, 위 그림과 같다.


   - 작업을 한 다음에 commit을 하나 했다면 위 그림과 같다.


 

$ git status
$ nano ./readme.txt
$ git commit -a -m "modify readme.txt in master, 2nd"
$ git push


   - 파일 하나 수정 후 commit을 하고, 마지막으로 [ git push ]를 해주자.

   - 위 그림과 같이 "A" commit 상태에서 "B" commit 상태로 'master'와 'origin/master' 모두 변경되었다.



5. git pull

   - 이제 원래 작업하던 local로 변경하여보자.



   - "A" commit 상태였지만, 저 위의 작업으로 인해서 'origin/master'의 실제 상태는 "B" commit 이다.

   - 그런데, master branch에서 소스 수정 후 commit을 하게 되면 어떻게 될까?



   - 이제는 [ git pull ]을 해 볼 시간인데... 어떻게 될까?


   - [ git pull ]을 하게 되면 바로 앞의 포스팅과 같이 'merge commit'을 생성하면서 코드를 섞어준다.


   - 그림으로 살펴보면 위와 같다.



결론은, 아래와 같다.

[ git pull ] = [ git fetch ] + [ git merge origin/master ]

즉, 최신 변경된 내역을 내가 작업하고 있는 것에 반영하기 위해서는 'git pull'을 사용하는 것이 편하다!!!


더불어서, git의 merge는 "3-way merge"라는 방식이다.




헥헥~ 오늘은 내일 '근로자의 날'을 앞두고,
일요일에 진행한 "두산 vs KIA" 경기를 다시보기로 보면서 역전승이라는 드라마에 감동하면서 포스팅하고 있다.
두산 파이팅~!!!

반응형

'Work Flow'에 대해서 살펴보기 전에,
'Remote Repository'에 존재하는 'branch'와 'Local Repository'에 존재하는 'branch'의 관계에 대해서 알아보겠다.


조금 다른 일반적인(?) 용어로 이야기를 하자면,
서버에서 소스를 가져와서 작업을 하고 있던 중 서버의 내용이 변경이 되어,
이것을 내가 작업하고 있는 곳에 반영을 하고 싶은 경우에 어떻게 할 것인가? 에 대한 설명을 해보고자 한다.


1. branch -a

   - 현재 작업 공간을 한 번 점검해보도록 하겠다.



$ git branch -a


   - 오늘 진행할 내용을 위해서 잡다한 것 모두 지우고, 정리하고, push하고 해 놓았다.

   - 여기서 확인하고 싶은 것은 기본적인 branch의 내역이다. "origin/master"의 존재 !!



2. commit in master branch

   - local에서 즉, master에서 commit을 하나 해보자.



$ nano ./readme.txt
$ git commit -a -m "modify readme.txt in master br"
$ git status


   - 여기에서 잘 살펴볼 부분은 [ git status ]를 했을 때 나오는 메시지이다.
   - "Your branch is ahead of 'origin/master' by 1 commit."
   - 최근의 git은 정말 안내 메시지가 너무 잘 되어 있다~!!! 짱~!!!


3. commit in origin/master

   - remote repository에 commit을 하나 추가된 상황을 만들고자 한다.




$ cd /srv/workspace/2nd
$ git clone {계정}@localhost:/srv/repository/bare1repo
$ cd ./bare1repo


   - 별도의 commit을 만들어 remote에 넣기 위해서 다른 곳에 별도의 local repository를 clone 하자


$ nano ./readme1.txt
$ git commit -a -m "modify readme1.txt in master br, but other master"
$ git push


   - 파일 하나를 수정하고 commit 한 다음에, remote repository로 밀어넣자(push).



4. fetch & merge

   - remote repository의 변경된 내역을 local로 받아오기 위한 작업을 해보자.



$ git fetch
$ git status

   - remote repository의 정보를 얻어오기 위한 명령어는 [ git fetch ]이다.
   - [ git status ]를 해보면 이전과는 또 다른 메시지가 보일 것이다.

   - " Your branch and 'origin/master' have diverged,
        and have 1 and 1 different commit each, respectively. "

   - " diverge " 뜻을 모르는 저같은 분들을 위한 단어의 의미 :
1. (다른 방향으로) 갈라지다   2. 나뉘다, 갈리다   3. (예상・계획 등에서) 벗어나다


$ git merge origin/master

   - [ git log ]를 보면, 위의 그림대로 구성되어진 것을 확인할 수 있을 것이다.




별 것 아닌 것으로 보일 수도 있는데,
git을 혼자서가 아니라 팀으로 작업하는 경우라면 의외로 자주 발생하는 상황일 것이다.

Git에서 보여주는 메시지들을 다시 한 번 잘 살펴보고, 흐름을 잘 느끼고 생각하면 많은 것을 배울 수 있을 것이다.



이런 에잇~ 또 12시를 넘겨버렸네.... ㅠㅠ
오늘 자전거 타이어 바꾸려고 편도 15km가 넘는 거리를 달려갔지만 결국 허탕치고 오늘 자전거만 30km가 넘게 타서...
지금 허리아프고 손목아프고, 목 아프고..... 이런 상황에서 12시를 넘겨버리다니... ㅠㅠ
내일 출근해야하는데.... 흑흑.... 어여 잠자야겠다.

반응형

직전 포스팅 서두에 '잡다한 정보'를 알려준다고 해놓고는,
branch에서 가장 중요하다고 할 수 있는 conflict 이야기를 해버렸다. ㅋㅋ

이번에는 정말 branch에 대한 정말 잡스러운 이것 저것들에 대해서 포스팅하기로 하겠다.
이번 포스팅으로 branch 이야기를 마무리 지으려고 하는데... 안되면 한 두번 더 하지 뭐~ ^^



1. git branch & checkout

   - hotfix/patch branch 만들고 'hotfix branch'로 checkout을 하자.


 

$ git branch hotfix
$ git branch patch
$ git checkout hotfix



2. git branch -v

   - 각 branch 別 마지막 commit을 확인하고 싶으면 [ -v ] 옵션을 사용하면 된다.


$ git branch -v



3. commit in hotfix branch

   - 'hotfix branch'에서 파일 하나를 수정하고 commit 해보자.




$ nano ./readme.txt
$ git commit -a -m "modify readme.txt in hotfix br"


$ git checkout patch
$ nano ./readme.txt
$ git commit -a -m "modify readme.txt in patch br"



4. commit in master branch

   - 'master branch'에서 commit을 하나 해보자.



$ git checkout master
$ nano ./readme.txt
$ git commit -a -m "modify readme.txt in master br"




5. merge

   - 이번에는 드디어 merge 작업을 해보자.



$ git merge hotfix
$ git mergetool
$ rm -rf ./readme.txt.orig
$ git commit -m "merge between master and hotfix"


   - merge를 하게 되면 'hotfix branch'에 있던 commit이 'master branch'에 합쳐진다.
   - 위 그림과 위 스크린샷을 잘 살펴보기 바란다.


6. git branch --merged / --no-merged

   - branch와 관련한 잡스런(?) 정보를 보여주는 옵션들이 있다.

 
   - [ git branch --merged ] merge가 이루어진 branch 목록을 보여준다.

   - [ git branch --no-merged ] merge가 행해지지 않은 branch 목록을 보여준다.

   - 어떤 branch를 만들어서 commit이 한 번 이상 이루어졌을 경우,
     별도의 merge를 하지 않으면 위 스크린샷과 같이 그냥 삭제가 이루어지지 않는다.
   - 강제로 지우고 싶으면 [ -D ] 옵션을 사용하라고 알려주고 있다. 


   - 5번 항목의 그림을 보면 알겠지만, 'patch branch'를 삭제하게 되면,
     "3a45533" commit은 붕~뜨게 된다. 그러기에 그냥 삭제하라고 하면 경고를 하게 되는 것이다.

   - 5번 항목의 그림을 다시 한 번 보게되면, "hotfix branch"의 경우,
     기존에 가지고 있던 "7770966" commit은 "master branch"의 흐름에 같이 섞여버렸다. 

 

 



여기까지해서 Local 에서의 branch 에 대해서는 대강 다 살펴본 것 같다.

앞으로는 이러한 Git 에서의 branch 특성을 이용한 Work Flow에 대해서 간단히 알아보고,
그 다음에는 Remote Repository 를 사용하는 환경에서의 branch에 대해서 알아보도록 하겠다.


오늘은 여기까지.... (우와~ 오늘은 자정 안넘겼다~~~!!! 금일 칼퇴근의 힘~!!!)

반응형

조금은 잡스러울 수 있는 부분들에 대해서 알아보자.


1. uncommit


$ git branch patch
$ nano ./readme.txt
$ git checkout patch
$ nano ./readme.txt

   - 'patch branch'를 생성하고, 그냥 'master branch'에서 파일을 수정한 다음에,
   - commit 하지 않고 'patch branch'로 checkout을 하면...
   - 좀 전에 'master branch'에서 수정한 파일의 내용이 어떻게 될까!?

   - 결론은 변경된 내용이 그대로 'patch branch'에서도 유지가 되어 있다.
   - 위 스크린샷에서 보면, checkout을 한 뒤 나오는 메시지를 보면 [ M    readme.txt ]라는 내용이 보일 것이다.

   - 이는 변경된 파일 내용을 유지하지 않을 경우 그 변경된 내역을 저장할 방법이 없기 때문으로 보인다.
   - 파일의 변경된 사항은 commit 단위로만 기억하는 Git이라는 것을 잘 알고 있어야겠다.



2. conflict

   - branch를 만들어서 각각 다른 부분들을 수정을 했다면, merge에 문제가 없으나,
   - 같은 부분을 서로 수정을 했다면 merge에 문제가 발생을 한다.


 $ git branch patch
 $ nano ./merge.txt
 $ git commit -a -m "modify 1st line in master br"

   - 'patch branch'를 만들어 놓고,
   - 'master branch'에서 'merge.txt'라는 파일의 1번째 줄을 수정하고 commit 한다.


 $ git checkout patch
 $ nano ./merge.txt
 $ git commit -a -m "modify 1st line in patch br"

   - 'patch branch'로 checkout을 한 후 'merge.txt' 파일을 수정 후 commit 한다.
   - 'master branch' 때와 마찬가지로 1번째 줄을 수정한 것이다.


 $ git checkout master
 $ git merge patch
 $ git status

   - 'master branch'로 다시 checkout을 한 뒤에 [ git merge patch ]를 해보자.
   - 충돌이 난 것을 볼 수 있을 것이다 (같은 줄을 각자 수정을 했으니...)

   - 충돌이 난 것을 다시 한 번 보기 위해서는 [ git status ]를 해보면 된다.


 $ git mergetool

   - 머지 도구를 활용하기 위해서는 [ git mergetool ]이라고 실행하면 된다.
   - 나의 경우에는 'meld'를 사용한다고 설정을 해놓아서 기본 도구로 (meld)가 보인다.


   - 'meld'의 실행화면이다.
   - 왼쪽이 'master branch'의 파일 내용이고, 오른쪽이 'patch branch' 파일의 내용이다.


   - 수정한 내역이 있으면 위와 같은 화면이 나온다.
   - 저장하고 빠져나오자.


   - 'meld'를 빠져나오면 위 스크린샷과 같이 이상한 파일이 하나 생긴다. "merge.txt.orig"
   - 그 내용을 살펴보면 위와 같이 뭐가 어떻게 충돌이 나는지를 보여준다.


   - 뭐 별 문제가 없다면 그냥 삭제하면 된다.

   - 이제는 merge를 할 때에 충돌이 난 부분을 해결을 했으니, commit을 하면 된다.


   - 그런데, 위 스크린샷을 보면 상당히 특이한 것을 확인할 수 있다.
   - commit 하나만 했을 뿐인데, log를 보면 1개가 아닌 2개의 log가 추가된 것을 볼 수 있다.
   - 즉, patch branch에서 작성한 commit이 자동으로 따라 붙어버린 것이다.




여기까지 해서 conflict 해결하는 것까지 살펴보았다.
이제 자야겠다. 일자가 바뀌었다.
눈알이 빡~빡~
반응형

또 다시 간만에 작성하는 Git 이야기...^^

branch의 경우 설명하는 글들을 읽어도 알기 힘든 부분들이 많다.



오늘 살펴보고자 하는 것은 지난 번 포스팅한 내용 중,
merge를 하게 되면 마지막 commit을 한 내용을 그대로 가져온다고 했었다는 내용에 대해서다.


Git의 branch를 그냥 막 사용한다면 모르겠지만,
하나 하나 그 내용을 분석이 필요하다고 하면 아래 내용을 잘 따라와보면 도움이 될 것이다.



1. 준비

   - 지금 branch를 활용한 작업을 하기 전에 준비를 하자.



 $ git branch -a

   - [ git branch -a ] 명령을 통해 모든 branch 상태에 대해서 알아보자.
   - [ * ] 표시가 되어있는 branch가 지금 현재 작업을 하고 있는 branch이다.


2. branch & commit

   - branch를 하나 만들고, 'master branch'에서 commit을 하나 해보자. 



 $ git branch patch1
 $ nano ./readme.txt
 $ git commit -a -m "nano readme.txt in master br"

   - "A" 시점에서 'patch1 branch'를 생성을 하고,
   - 'master branch'에서 파일 수정 후 commit을 해서 "B" 시점으로 갔다.
   - 그래서 'master branch'는 지금 현재 "B" 위치에 있는 것이다.


3. checkout & commit

   - 작업하고 있는 branch를 바꿔보자.



 $ git checkout patch1

   - [ git checkout patch1 ]을 통해 작업하고 있는 branch를 변경했다.



 $ nano ./readme1.txt
 $ git commit -a -m "nano readme1.txt in patch1 br"

   - 'readme1.txt' 파일을 수정 후 commit 하자.

   - commit을 추가로 한 번 더 해보자.



 $ nano ./readme1.txt
 $ git commit -a -m "1 more, nano readme1.txt in patch1 br"

   - 'patch1 branch'에서 commit 2건을 추가한 것이다.



4. checkout & merge

   - 각 branch 別 상황을 좀 살펴보자.


 $ git branch -a
 $ git log -2
 $ git checkout master
 $ git log -2

   - 'patch1 branch'의 log들과 'master branch'의 log들을 잘 살펴보기 바란다.

   - 이제 merge를 실행해 보자.



 $ git merge patch1
 $ git log -4

   - 위 그림과 스크린샷을 잘 봐야 한다!!! 많은 것들이 녹아 있다.

   - "E" 지점(commit)은 별도로 만든 것이 아니라 'merge'로 만들어진 것이다.
   - 그래서 log를 보면 "Merge branch 'patch1'"이 보일 것이다.

   - 그런데, 또 하나 특이한 것은 'patch1'에서 이루어진 commit까지 모두 따라왔다.
   - 그러면, 'patch1 branch'를 지워버리면 어떻게 될까?


 $ git branch -d patch1

   - 'patch1 branch'를 그냥 지워버리면 어떻게 될까?!
   - 위에서 보는 바와 같이 그냥 'branch'만 지워지고 변화는 없다.


   - branch를 지운다고 하여도 그 branch에서 작업을 했던 commit들은 지워지지 않는다는 말 같은데...
   - merge가 되었다면 의미가 있지만, merge가 없는 상태에서 branch를 지웠다면...
   - 의미 없는 commit들이 그냥 살아있다는 말이 되는데...
   - 이 부분에 대해서는 꼭 한 번 깊이있게 살펴볼 예정이다. 개인적으로 관심있는 부분이라서....^^



여하튼, 이번 포스팅에서 확인을 한 것은,
branch에서 만든 commit들이 merge 후에도 계속 따라온다는 것이다.

commit 하나 하나에 더욱 더 신경을 써야 한다는 결론이 나온다.

반응형

+ Recent posts