Mercurial 을 콘솔에서 사용하면서 출력 포맷을 지정하거나, 블링블링하게 만드는 법.




Mercurial을 콘솔에서 사용할 때 사용자가 출력을 지정할 수 있는 건 아래와 같은 log-like 명령어이다.

(hg help template 에서 발췌)

log

outgoing

incoming

tip

parents

heads

glog




스타일

Mercurial에는 기본적으로 5가지 스타일 포맷이 지정되어 있다.

아래는 그 리스트와 예제이다.



# default: 기본 스타일이다. --style 옵션을 따로 지정하지 않으면 이 스타일대로 출력된다.
C:\rep> hg log -l 5 --style default
changeset:   11:4febaf552e0a
branch:      b2
tag:         tip
user:        cdbaek <cdbaek@example.com>
date:        Tue Aug 05 23:27:25 2014 +0900
summary:     진짜 마지막

changeset:   10:12ecd17038d0
user:        cdbaek <cdbaek@example.com>
date:        Tue Aug 05 23:12:57 2014 +0900
summary:     parent

changeset:   9:23ad1b50f7da
parent:      4:679d16c3aaed
user:        cdbaek <cdbaek@example.com>
date:        Tue Aug 05 22:45:53 2014 +0900
summary:     main: 3

changeset:   8:730830fd4786
bookmark:    task-1
user:        cdbaek <cdbaek@example.com>
date:        Tue Aug 05 22:41:35 2014 +0900
summary:     task-1: 5

changeset:   7:4565898b0b45
user:        cdbaek <cdbaek@example.com>
date:        Tue Aug 05 22:38:16 2014 +0900
summary:     task-1: 4



# compact: 딱 필요한 내용만 간략하게 보여준다.
C:\rep> hg log -l 5 --style compact
11[tip]   4febaf552e0a   2014-08-05 23:27 +0900   cdbaek
  진짜 마지막

10   12ecd17038d0   2014-08-05 23:12 +0900   cdbaek
  parent

9:4   23ad1b50f7da   2014-08-05 22:45 +0900   cdbaek
  main: 3

8[task-1]   730830fd4786   2014-08-05 22:41 +0900   cdbaek
  task-1: 5

7   4565898b0b45   2014-08-05 22:38 +0900   cdbaek
  task-1: 4




# changelog: GNU project의 changelog 스타일
C:\rep> hg log -l 5 --style changelog
2014-08-05  cdbaek  <cdbaek@example.com>

        * test.txt:
        진짜 마지막
        [4febaf552e0a] [tip] <b2>

        * test.txt:
        parent
        [12ecd17038d0]

        * test.txt:
        main: 3
        [23ad1b50f7da]

        * test.txt:
        task-1: 5
        [730830fd4786]

        * test.txt:
        task-1: 4
        [4565898b0b45]



# phases: default 스타일과 같으나 항목에 phase가 포함
C:\rep> hg log -l 5 --style phases
changeset:   11:4febaf552e0a
branch:      b2
tag:         tip
phase:       draft
user:        cdbaek <cdbaek@example.com>
date:        Tue Aug 05 23:27:25 2014 +0900
summary:     진짜 마지막

changeset:   10:12ecd17038d0
phase:       draft
user:        cdbaek <cdbaek@example.com>
date:        Tue Aug 05 23:12:57 2014 +0900
summary:     parent

changeset:   9:23ad1b50f7da
phase:       public
parent:      4:679d16c3aaed
user:        cdbaek <cdbaek@example.com>
date:        Tue Aug 05 22:45:53 2014 +0900
summary:     main: 3

changeset:   8:730830fd4786
bookmark:    task-1
phase:       draft
user:        cdbaek <cdbaek@example.com>
date:        Tue Aug 05 22:41:35 2014 +0900
summary:     task-1: 5

changeset:   7:4565898b0b45
phase:       draft
user:        cdbaek <cdbaek@example.com>
date:        Tue Aug 05 22:38:16 2014 +0900
summary:     task-1: 4



# xml: xml 형식으로 출력
<?xml version="1.0"?>                                                      
<log>                                                                      
<logentry revision="11" node="4febaf552e0a6b97918e0672eb0a77f2b21d0b91">   
<branch>b2</branch>                                                        
<tag>tip</tag>                                                             
<author email="cdbaek@example.com">cdbaek</author>                        
<date>2014-08-05T23:27:25+09:00</date>                                     
<msg xml:space="preserve">진짜 마지막</msg>                                     
</logentry>                                                                
<logentry revision="10" node="12ecd17038d08b35f830051ce20643db34b0c4ce">   
<author email="cdbaek@example.com">cdbaek</author>                        
<date>2014-08-05T23:12:57+09:00</date>                                     
<msg xml:space="preserve">parent</msg>                                     
</logentry>                                                                
<logentry revision="9" node="23ad1b50f7da0c5cc24c1e1042a772b8729c66d3">    
<parent revision="4" node="679d16c3aaed2bdada7e1fbd2565243c6e57b9a3" />    
<author email="cdbaek@example.com">cdbaek</author>                        
<date>2014-08-05T22:45:53+09:00</date>                                     
<msg xml:space="preserve">main: 3</msg>                                    
</logentry>                                                                
<logentry revision="8" node="730830fd4786bfd95353153ad23a82df3077ac78">    
<bookmark>task-1</bookmark>                                                
<author email="cdbaek@example.com">cdbaek</author>                        
<date>2014-08-05T22:41:35+09:00</date>                                     
<msg xml:space="preserve">task-1: 5</msg>                                  
</logentry>                                                                
<logentry revision="7" node="4565898b0b459147bde609ae9fff160343208b4b">    
<author email="cdbaek@example.com">cdbaek</author>                        
<date>2014-08-05T22:38:16+09:00</date>                                     
<msg xml:space="preserve">task-1: 4</msg>                                  
</logentry>                                                                
</log>                                                                     






템플릿

Mercurial에서 제공해주는 markup 변수(?)를 이용하여 마음대로 출력포맷을 설정할 수 있다.

아래는 template의 markup 리스트. (hg help template의 내용)



# markup 리스트
author        String. 작성자.
bisect        String. changeset의 bisection 상태.
bookmarks     List of strings. changeset과 연관된 bookmark 리스트.
branch        String. commit이 이루어진 branch의 이름.
children      List of strings. 자식들 리스트.
date          Date information. commit된 날짜정보.
desc          String. commit 메세지.
diffstat      String. 아래와 같은 포맷의 변경내역 통계수치: 
	  "modified files: +added/-removed lines"
extras        List of dicts with key, changeset의 extras 필드값.
file_adds     List of strings. 추가된 파일 리스트.
file_copies   List of strings. 복사된 파일 리스트.
file_copies_switch
	  List of strings. "file_copies"와 같으나 --copied 옵션이 있을때만 출력.
file_dels     List of strings. 삭제된 파일 리스트.
file_mods     List of strings. 수정된 파일 리스트.
files         List of strings. 수정, 추가, 삭제된 파일 리스트.
latesttag     String. changeset의 조상중 가장 최근의 전역 tag.
latesttagdistance Integer. 가장 멀리 있는 최신 태그와의 거리.
node          String. changeset의 id hash
p1node        String. 첫번째 부모 리비전의 id hash. 부모가 없으면 0으로 만땅.
p1rev         Integer. 첫번째 부모 리비전의 로컬 리비전 번호. 부모가 없으면 -1.
p2node        String. 두번째 부모 리비전의 id hahs. 없으면 0으로 만땅.
p2rev         Integer. 두번째 부모 리비전의 로컬 리비전 번호. 부모가 없으면 -1.
parents       List of strings. "rev:node" 포맷의 부모 리스트. 만약 changeset이 부모 하나만 있다면 아무것도 출력되지 않음.
phase         String. phase 이름.
phaseidx      Integer. phase 인덱스 번호.
rev           Integer. 로컬 리비전 번호.
tags          List of strings. changeset과 연관된 모든 tag 리스트.




/************************************************
date 키워드는 더이상 사람이 읽기 편한(human-readable) 출력을 해주지 않는다.
만약 그런걸 원하면 filter를 사용해야 한다.
filter는 키워드 뒤에 붙여서 사용하는 형태의 함수같은 것이다.
filter는 문자열 기반으로 동작하므로 만약 list 형태의 변수에 사용하게 될 경우 먼저 문자열화(stringify) 한 다음 사용해야 한다.
filter는 원하는 포맷을 뽑아내기 위해 여러개를 연결해서(chain) 사용이 가능하다.

ex) 아래는 {date}를 isodate 형태로 출력해주는 filter를 사용하는 예제
C:\rep> hg tip --template "{date|isodate}\n"
2014-08-06 23:27 +0900
************************************************/

# 아래는 filter 리스트
addbreaks     Any text. 맨 마지막 라인을 제외한 모든 라인의 끝에 <br /> 태그를 붙여준다.
age           Date. 매개변수로 넘긴 date/time과 현재 date/time 사이의 date/time을 human-readable 포맷으로 출력.
basename      Any text. 넘겨받은 매개변수가 경로명(path)이라 가정하고 마지막 문자열을 반환. 예를 들어 "foo/bar/baz"일 경우 "baz"를 반환.
date          Date. timezone을 포함하는 유닉스 date 포맷형태 반환. ex) "Wed Aug 06 23:43:13 2014 0900"
domain        Any text. 문자열에서 이메일 형태의 문자열을 찾아 도메인 부분만 추출하여 반환. ex) "User <user@example.com>"일 경우 "example.com" 반환.
email         Any text. 문자열에서 이메일 주소를 추출하여 반환. ex) "User <user@example.com>"일 경우 "user@example.com" 반환.
emailuser     Any text. 이메일 주소에서 사용자명만 추출하여 반환.
escape        Any text. &, <, > 문자를 XML entity로 변환. NUL 문자는 필터링.
fill68        Any text. 문자열을 68칸으로 wrapping.
fill76        Any text. 문자열을 76칸으로 wrapping.
firstline     Any text. 문자열의 첫번째 라인 반환.
hex           Any text. 노드의 hash id를 긴 hexadecimal 형태로 변환.
hgdate        Date. date를 Unix timestamp, timezone 형태로 반환.
isodate       Date. date를 ISO 8601 포맷으로 반환. ex) "2014-08-06 23:53 +0900"
isodatesec    Date. date를 초(sec)까지 포함한 ISO 8601 포맷으로 반환. ex) "2014-08-06 23:53:57 +0900"
localdate     Date. date를 지역시간(local date)로 변환.
nonempty      Any text. 지정된 문자열이 비어있는 값이면 '(none)'을 반환.
obfuscate     Any text. 지정된 문자열을 XML entity 시퀀스로 렌더링하여 반환.
person        Any text. 이메일 주소 앞 부분의 이름을 반환.
rfc3339date   Date. date를 RFC 3339에 정의된 Internet date 포맷으로 반환. ex) "2014-08-06T23:59:13+09:00"
rfc822date    Date. date를 이메일 헤더 포맷으로 반환. ex)"Web, 06 Aug 2014 23:59:33 +0900"
short         Changeset hash. 노드의 hash id를 12자 길이의 짧은 포맷으로 반환.
shortbisect   Any text. 넘겨진 문자열을 bisect 상태라 간주하고 1자짜리 짧은 상태값으로 반환. (G: good, B: bad, S: skipped, U: untested, I: ignored). 넘겨진 문자열이 올바른 bisect 상태값이 아니면 빈칸 반환.
shortdate     Date. date를 짧은 형태로 반환. ex) "2014-08-07" 
stringify     Any type. 넘겨진 값을 문자열 형태로 변환(stringify)해서 반환.
strip         Any text. 넘겨진 문자열 앞뒤 공백문자 제거 후 반환. (trim)
stripdir      넘겨진 문자열을 경로명(path)이라 간주하고 만약 가능하다면 디렉토리명만 추출하여 반환.
tabindent     Any text. 넘겨진 문자열의 비어있는 라인을 제외한 모든 라인을 시작부분의 공백문자를 제거한 상태로 반환.
urlescape     Any text. 넘겨진 문자열을 urlencode하여 반환. ex) "foo bar" -> "foo%20bar"
user          Any text. 사용자명이나 이메일을 짧은 사용자명 형태로 반환.




# filter에 덧붙여서 기본 제공되는 함수들도 있음.
- date(date[, fmt])                   
- fill(text[, width])                 
- get(dict, key)                      
- if(expr, then[, else])              
- ifcontains(expr, expr, then[, else])
- ifeq(expr, expr, then[, else])      
- join(list, sep)                     
- label(label, expr)                  
- revset(query[, formatargs])         
- rstdoc(text, style)                 
- shortest(node)                      
- strip(text[, chars])                
- sub(pat, repl, expr)                




# list operator로 반복출력 형태로 사용이 가능하다.
expr % {template} 
# 파일리스트 출력
C:\rep> hg log -r 0 --template "files:\n{files % '  {file}\n'}"
files:
    file1.txt
    file2.txt

# 반대로 join도 가능함.
C:\rep> hg log -r 0 --template "files: {join(files, ', ')}\n"
files: file1.txt, file2.txt

# 날짜를 포맷을 지정하여 출력.
C:\rep> hg log -r 0 --template "{date(date, '%Y%m%d')}\n"
20140807

# 가로로 30자 채워서 출력
C:\rep> hg log -r 0 --template "{fill(desc, 30)}"

# 조건문도 걸 수 있음.
# 만약 브랜치가 default이면 'on main branch', 아니면 'on branch 브랜치명' 출력
C:\rep> hg log -r 0 --template "{ifeq(branch, 'default', 'on the main branch', 'on branch {branch}')}\n"

# 만약 문자열이 비어있지 않으면 \n 붙이기
C:\rep> hg tip --template "{if(author, '{author}\n')}"

# color extension에서 지정한 색깔 지정
C:\rep> hg log -r 0 --template "{label('changeset.{phase}', node|short)}\n"

# 북마크 리스트를 출력하는데 현재 북마크라면 * 붙이기
C:\rep> hg log --template "{bookmarks % '{bookmark}{ifeq(bookmark, current, \"*\")} '}\n"

# working copy의 parent라면 @ 붙이기
C:\rep> hg log --template "{rev}|{node} {ifcontains(rev, revset('.'), '@')}\n"





색깔

우선 Mercurial에 기본 탑재된 color라는 extension이 있는데 이걸로 기본적인 블링블링은 가능하다.

참고: http://bloodguy.tistory.com/869


여기서 좀 더 심화학습 해보자면, 

--template 옵션은 ANSI escape code를 사용할 수 있다.



# 다음은 노드의 hash id는 빨간색, 리비전 번호는 초록색, 작성자는 파란색으로 표시하는 예제
C:\rep> hg log --template "\x1B[4m{node|short} \x1B[0;2m{rev} \x1B[0;1m{author}\x1B[0m\n"


ANSI escape code의 자세한 사항은 아래 링크 참조.

http://en.wikipedia.org/wiki/ANSI_escape_codes





아래 예제가 모든 출력 꾸미기의 종합판



# hgrc에 아래와 같이 설정한다.
# color extension을 이용하여 나만의 출력포맷 지정
[extensions]
color = 

[color]
# label 함수를 이용하여 custom.important 를 지정하면 빨간색 굵은글씨로 출력
custom.important = bold red

[alias]
# blingblinglog 라는 alias 등록
# ANSI escape code와 color extension을 조합
blingblinglog = log --template "\x1B[4m{node|short} \x1B[0;2m{rev} \x1B[0;1m{author}\x1B[0m {label('custom.important', desc)}\n"

# 아래처럼 실행하면 블링블링하게 나옴
C:\rep> hg blinglog -l 5









Posted by bloodguy
,