달력

52025  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

1. org.jfree.chart.JFreeChart

JFreeChart의 기본 클래스이다. 자바2D로 구현되어 있으며 현재 바 차트 , 라인 차트 , 파이 차트 , XY 플롯(시간에 따른 XY그래프)를 지원한다. JFreeChart클래스는 제목을 나타내는 AbstractTitle객체 , Legend객체 , Plot객체 그리고 DataSet객체로 이루어져 있다.

2. org.jfree.chart.AbstractTitle

차트의 제목을 나타낸다. 하위 클래스로 ImageTitle , LegendTitle , TextTitle로 구성되어 있다.

3. org.jfree.chart.Legend

 차트에 포함된 시리즈(series)의 이름과 그 표현방식을 구성한다.

4. org.jfree.chart.plot.Plot

 JFreeChart클래스는 축과 데이터를 그리는(draw) 작업을 Plot에게 위임하였다. 대표적인 하위 클래스로는
CategoryPlot , PiePlot , XYPlot등이 있다.

5. org.jfree.data.DataSet

차트의 데이터를 담당한다. 대표적인 구현 클래스로는 DefaultPieDataSet , TimeSeriesCollection등이 있다.

6. org.jfree.chart.ChartFactory

차트를 생성을 위한 메소드를 제공한다. 예를 들어 pie차트를 만들기 위해서는 creatPieChart() 메소드를 사용한다.

7. org.jfree.chart.ChartPanel

차트를 생성한 후 JFreeChart 클래스를 ChartPanel에 넣어 스윙 컴포넌트로 사용할 수 있다


#1 첫번째 방법~

- JFreeChart 의 Font를 가져와 변경하는 방법!!
차트 제목과 범례 : JFreeChart 로 부터
각 축 : JFreeChart 의  CategoryPlot 로 부터 받아온다.
x축 : getDomainAxis()
y축  : getRangeAxis()  각 축의 정보를 가지고 있다.

  /* 한글 처리 문제 */
  //차트 제목
  labelFont = jfc.getTitle().getFont();
  jfc.getTitle().setFont(new Font("굴림",labelFont.getStyle(),labelFont.getSize()));
  //X축 제목
  labelFont = cgp.getDomainAxis().getLabelFont();
  cgp.getDomainAxis().setLabelFont(new Font("돋움",labelFont.getStyle(),labelFont.getSize()));

  //X축 값에 대한 레이블
  labelFont = cgp.getDomainAxis().getTickLabelFont();
  cgp.getDomainAxis().setTickLabelFont(new Font("돋움",labelFont.getStyle(),labelFont.getSize()));

  //Y축 제목
  labelFont = cgp.getDomainAxis().getLabelFont();
  cgp.getRangeAxis().setLabelFont(new Font("돋움",labelFont.getStyle(),labelFont.getSize()));

  //Y축  값에 대한 레이블
  labelFont = cgp.getRangeAxis().getTickLabelFont();
  cgp.getRangeAxis().setTickLabelFont(new Font("돋움",labelFont.getStyle(),labelFont.getSize()));

  //범례
  //jfc.getLegend().setItemFont(new Font("돋움",Font.PLAIN,10));


# 2 두번째 방법~

 

JRE에 한글 font가 설치 되어있지 않아서 발생하는 문제

JAVA_HOME/jre/lib 폴더에 보면 fontconfig 파일들이 존재한다.
이중 fontconfig.RedHat.properties.src 파일을 fontconfig.properties파일로 복사
fontconfig.properties파일에 쓰기 권한을 주고 편집

#> cp fontconfig.RedHat.properties.src fontconfig.properties
#> chmod +w fontconfig.properties
#> vi fontconfig.properties
--------------- font.config.properties 내용 --------------------------
# 생략
.
.
.
# AWT X11 font paths
awtfontpath.chinese-tw-iso10646=/usr/share/fonts/zh_TW/TrueType
awtfontpath.chinese-cn-iso10646=/usr/share/fonts/zh_CN/TrueType
awtfontpath.japanese-iso10646=/usr/share/fonts/ja/TrueType
awtfontpath.korean-iso10646=/usr/share/fonts/ko/TrueType      <---- 이부분을 폰트 파일의 위치로 수정

서버에서 /usr/local/java...(java폴더명은 서버마다 틀릴수 있다.)/jre/lib/ 폴더에 있는

 fontconfig.RedHat.properties.src 열고  가장 밑에 부분에 있는 곳을 확인해본다.
........

# AWT X11 font paths
awtfontpath.chinese-tw-iso10646=/usr/share/fonts/zh_TW/TrueType
awtfontpath.chinese-cn-iso10646=/usr/share/fonts/zh_CN/TrueType
awtfontpath.japanese-iso10646=/usr/share/fonts/ja/TrueType
awtfontpath.korean-iso10646=/usr/share/fonts/ko/TrueType

/usr/share/fonts/ko/TrueType 디렉토리를 생성하고 그 디렉토리에
batang.ttc과 gulim.ttc파일을 복사해 넣는다.

tomcat을 재구동 시켜준다.


 

Posted by 인천총각
|

GridBagLayout~ㅎㅎ

HomeWork 2010. 1. 15. 17:34

출력된 스크린에서, 버튼들이 어떻게 여러 개의 열과 행에 걸쳐있는지 주목하자. 스크린을 리사이징 해봄으로써 GridBagLayout의 또 다른 특성에 대해서도 알 수 있다. 어느 열과 어느 행이 스크린이 확대됨에 따라 늘어난 공간을 얻을 것인지를 완전히 제어할 수 있다.

GridBagLayout로 레이아웃된 컨테이너에 추가된 각각의 컴포넌트는 컨스트레인트 오브젝트(constraints object)인 GridBagConstraints 와 반드시 연결되어있어야 한다. 이 오브젝트는 각 컴포넌트의 특정 컨스트레인트들을 레이아웃 매니저에 전달한다.

다양한 타입의 컨스트레인트들이 있는데, 각각은 연결된 컴포넌트의 레이아웃을 제어한다. 각 제약은 클래스의 퍼블릭 필드(public field)이다. 제약들은 컨스트럭터를 통해 한번에 모두 설정할 수도 있고, 또는 그 필드에 직접적인 액세스로 개별적으로 설정할 수도 있다. 이러한 필드들에는 세터(setter) 메소드나 게터(getter) 메소드는 없다.

그렇다면, 이제 각 컨스트레인트들에 대해 알아보자.

anchor

앵커(anchor)는 사용 가능한 공간보다 컴포넌트가 더 작을 경우에 컴포넌트가 드리프트(drift)될 방향을 지정한다. 디폴트 값은 CENTER 이다. .8개의 방위는 또다른 설정을 나타낸다. 각각의 설정은 필드에 지정될 수 있는 상수이다. 가능한 설정들은 다음과 같다.

   CENTER
   EAST
   NORTH
   NORTHEAST
   NORTHWEST
   SOUTH
   SOUTHEAST
   SOUTHWEST
   WEST

추가적인 컨트레인트 사항들은 현재의 ComponentOrientation에 기반을 둔 컴포넌트들의 포지션을 가능하게 하는데, 영어에서 보편적으로 쓰이는 수평이면서 왼쪽에서 오른쪽(left-to-right) 방향 맞춤을 위한 설정들은 다음과 같은 상수들로 정해지게 된다.

   FIRST_LINE_END (NORTHEAST)
   FIRST_LINE_START  (NORTHWEST)
   LAST_LINE_END (SOUTHEAST)
   LAST_LINE_START (SOUTHWEST)
   LINE_END (EAST)
   LINE_START (WEST)
   PAGE_START (NORTH)
   PAGE_END (SOUTH)

fill

fill의 값은 더 많은 공간이 사용 가능한 경우 컴포넌트의 리사이징을 제어한다. 만약 fill이 NONE(디폴트 값)으로 설정되어 있다면, GridBagLayout 매니저는 컴포넌트의 적절한 사이즈를 정해주게 된다. 만약 fill이 VERTICAL로 설정되어 있다면, 레이아웃 매니저는 (물론, 추가적인 공간이 있는 경우에만) 컴포넌트의 높이를 리사이징한다. HORIZONTAL의 경우에는 레이아웃 매니저는 폭을 리사이징할 것이고, BOTH로 설정되어 있다면 폭과 넓이에서 사용 가능한 모든 공간을 이용하게 된다.

좀 전의 예제 프로그램 GridBagSampleBOTH를 fill값으로 가진다. VERTICAL, HORIZONTAL, 또는 NONE과 같은 다른 fill 값을 넣어서 프로그램을 한 번 실행해보자. (원하는 결과를 얻기 위한 적절한 fill 설정 라인에 대해서는 설명하지 않겠다.) 예를 들어, 7개의 버튼의 fill을 모두 NONE으로 설정하면 다음과 같은 결과가 나오게 된다.

gridxgridy

gridx와 gridy는 그리드 상의 컴포넌트의 위치를 지정한다. gridx 변수는 컴포넌트의 가장 왼쪽 위치의 셀을 지정하고, gridy 변수는 컴포넌트의 상단 위치의 셀을 지정한다. Cell (0, 0)은 스크린의 초기점에 있는 셀(왼쪽 위)을 의미한다. 컴포넌트들은 다양한 셀들을 합칠 수 있기 때문에 girdx, girdy 위치는 일반적으로 컴포넌트의 시작 셀이다. 명시적으로 셀에 직접 지정할 수도 있지만, RELATIVE 상수를 사용할 수도 있다. RELATIVE 의 gridx 설정은 이전 컴포넌트의 오른쪽에 새로운 컴포넌트를 만들어낸다. girdy의 경우에는, 이전 컴포넌트 아래쪽에 새로운 컴포넌트가 새로운 열을 시작할 것이다.

gridheightgridwidth

gridheight필드와gridwidth 필드는 수평축(gridwidth)과 수직축(gridheight)에 따라 컴포넌트가 점유해야만 하는 셀들의 수를 지정한다. 행과 열에서 셀의 개수를 지정하는 것과 더불어 RELATIVEREMAINDER 클래스 상수들도 사용할 수 있다. 두 개중 어느 한 필드의 RELATIVE 설정을 지정하는 것은 컴포넌트를 행이나(gridheight) 열(gridwidth) 내에서 마지막에서 두번째(second-to-last)로 만드는 결과를 만든다. REMAINDER 설정은 각각의 행이나 열의 맨 마지막 요소를 지정하기 위해 사용한다.GridBagLayout을 사용하는 데 익숙해질 때까지는 RELATIVEREMAINDER보다는 gridx와 gridy, gridheight, gridwidth 설정들을 직접 지정해주는 편이 훨씬 쉬울 것이다. 심지어 익숙해진 단계를 넘어선 후에도, RELATIVEREMAINDER의 사용을 꺼려 하는 당신을 발견할 지도 모른다.

insets

insets 필드는 컴포넌트 주위에 있는 픽셀 내의 외부 패딩(the external padding)을 지정한다. 패딩이란 빈 공간을 뜻하는데, 컴포넌트 주위의 투명한 경계선이라고 보면 되겠다. insets 필드를 설정할 때는 top, bottom, left, right의 패딩 값을 개별적으로 지정해줘야 한다. GridBagSample 프로그램의 insets 설정이 (0, 0, 0, 0) 이었는데, 이는 일반적인 Insets 오브젝트를 위한 설정임을 주의하자.

ipadxipady

ipadx 필드와 ipady 필드는 컴포넌트의 내부 패딩을 지정해준다. ipdax 필드는 컴포넌트의 폭에 패딩을 추가하고, ipady필드는 컴포넌트의 높이에 패딩을 추가한다. 예를 들어, ipadx 설정은 컴포넌트의 양쪽 주위에 여분의 공간을 지정해준다.

weightxweighty

예를 들어 사용자가 스크린을 리사이징 하는 경우처럼, weightx와 weighty 설정을 통해 컨테이너 안에서 공간을 사용할 수 있을 때 어느 컴포넌트의 크기를 키우거나 줄일지 제어할 수 있다. weight 설정은 double이다. (insets을 제외한 다른 모든 설정들은 int 값이다.)

일반적으로, weightx와 weighty 설정은 0.0에서 1.0의 범위 안에서 정한다. 0.0으로 설정한다는 것은 컴포넌트에 여유 공간이 전혀 없음을 의미한다. 1.0으로 설정하는 것은 컴포넌트가 모든 여유 공간을 가지는 것을 의미한다. (혹은 적어도 1.0으로 설정된 다른 컴포넌트들과 그 여유 공간을 공유한다는 것을 의미한다.) 비록 설정값을 0.0에서 1.0의 범위 안에 한정하기는 하지만, 모든 설정값이 다 허용된다. 시스템은 특정 행이나 열을 위한 설정값들의 합에 비례하여 공간을 할당할 것이다. 예를 들자면, 1.0으로 설정한 4개의 컴포넌트는 여유 공간을 균일하게 공유하게 될 것이다. 0.0으로 설정한 컴포넌트 3개와 1.0으로 설정한 컴포넌트 1개의 경우에는 모든 여유 공간을 하나의 컴포넌트에 몰아주게 된다. 1개의 0.0 컴포넌트와 2개의 0.5 컴포넌트, 1개의 1.0 컴포넌트라면, 여유 공간의 절반은 1.0 컴포넌트에 할당되고, 2개의 0.5 컴포넌트가 나머지 여유 공간을 나눠가질 것이다.

스크린의 사이즈가 리사이징이 가능하다면, 어떤 weight 설정이 필요한지 고려하는 것을 잊지 말자. Anchor와 weightx/weighty를 결합하여 효과적으로 사용한다면, 리사이징 시에 컴포넌트들이 스크린의 가장자리를 "감싸안거나" , 스크린의 균형을 유지하면서 컴포넌트의 크기를 비례하여 늘릴 수가 있다.

Try changing some of the GridBagConstraints settings in the GridBagSample program and see what happens. Here's a table that lists the initial GridBagConstraints settings in the program. GridBagSample 프로그램 안에서 GridBagConstraints 설정들을 바꿔보고 어떠한 변화가 일어나는지를 살펴보자. 아래의 표는 그 프로그램의 GridBagConstraints 초기 설정값 목록이다.

Component gridx gridy gridwidth gridheight
One 0 0 1 1
Two 1 0 1 1
Three 2 0 1 1
Four 0 1 2 1
Five 2 1 1 2
Six 0 2 1 1
Seven 1 2 1 1

GridBagLayoutGridBagConstraints의 사용에 대한 더 자세한 정보는 Java Tutorial의 How to Use GridBagLayout을 참조하기 바란다.

GridBagLayout과 그것과 관련된 GridBagConstraints을 활용하기 전에, 방안지를 준비하는 것도 좋다. 여러 개의 행과 열에 걸쳐야 하는 스크린을 디자인하는 경우, 미리 방안지의 그리드에 컴포넌트들을 그려보면 도움이 될 것이다.

'HomeWork' 카테고리의 다른 글

EL & JSTL #2 (천천히 배워가자!!)  (0) 2010.01.20
초간단 JSTL 집고 넘어가자!!  (0) 2010.01.19
Thread ^^;;  (0) 2009.12.23
JSON#2(JavaScript Object Notation)  (0) 2009.12.22
JSON 데이터  (0) 2009.12.22
Posted by 인천총각
|

실전 Applet 차트 만들기!!!
--------------------------------------------------------------------------------------------------------
Graphics

clearRect(시작점x,시작점y,폭,높이);사각형으로 지운다..

drawArc(시작점x,시작점y,폭,높이,시작각도,끝나는각도);호를 그린다

drawImage(이미지,이미지시작x,이미지시작y,이미지표시되는프레임(현재프레임-this),폭,높이);
                                                                                                   toolkit을 통해서 이미지 얻어올것!!

drawLine(시작점x,시작점y,끝x,끝y);일직선으로 선을 긋는다

drawPolygon(x배열,y축배열,int);다각형

drawPolyline();

drawRect(x,y,폭,높이);사각형

drawRoundRect(x,y,폭,높이,각도);둥근사각형

drawString(문자열,x,y);문자열을 그림으로

fillRect...() 속을 채운다!!(getColor,setColor,getFont)로 지정한다.

setXORMode(Color)겹쳐지는부분 색 지정

--------------------------------------------------------------------------------------------------------

1. 차트에서의 pixel 비율로 변환하는 과정

AAA = 최대값-실제값 /(최대값-최소값)

최대값 : 200
최소값 : 100
실제값 : 150
ex) (200 - 150) / 100 = 0.5 (AAA값)

최대값 : 200
최소값 : 100
실제값 : 180
ex) (200 - 180) / 100 = 0.2

최대값 : 200
최소값 : 100
실제값 : 110
ex) (200 - 110) / 100 = 0.9

2. 차트에 그려질 Y축의 값 구하기


0
│                                                   <- 캔버스 윗단
│-----------------------------
│                                            ∧
│                                            │   <- 캔버스 사용 높이
│                                            │
│     o    o                               │
│   o                                       │
│       o                                   │
└──────────---------
300 (y축 pixel 비율)

Applet 높이 : 480
캔버스 사용 높이 : 320 (Applet 높이의 2/3만 실 차트로 사용)
캔버스 윗단 : 80

BBB(y축값)
BBB = (pixel로 변환된 값(AAA) * 캔버스 사용높이)+캔버스의 윗단(캔버스의 한토막= 캔버스 높이 / 6 )


ex) (0.5 * 320)+80 = 240 pixel(캔버스 표시 y축 좌표) 실제값 (150)
ex) (0.2 * 320)+80 = 144 pixel(캔버스 표시 y축 좌표) 실제값 (180)
ex) (0.9 * 320)+80 = 368 pixel(캔버스 표시 y축 좌표) 실제값 (110)


(for문 사용 i=0 부터...)

3. x,y 축 값을 이용하여 그래프 만들기


# 꺽은선 그래프

fillRect 사용 : g.fillRect(x축,y축,width,height);

ex) fillRect(x축(i x 30 + 20-1), y축(240), 3 ,3 );

1. i 값 증가시 x 30 을 x축 간격 조절
2. 기본 20-1 ((i==0)일때) 즉, 19간격에 위에서 구한 y축 좌표값 으로
3. 19,240 좌표에 높,넓이 3의 타원을 그린다.

----------------------------------------------------------------------------------

각 좌표값 잇기!!! (i>0) 클때

drawLine 사용 : g.drawLine(start x축, start y축, end x축, end y축);

즉, g.drawLine(이전좌표 xy, 현좌표 xy)

ex) g.drawline((i-1) x 30 + 20 , 240, i x 30 +20, 144);
 
1. 이전좌표의 (i-1) x 30 +20 은 현 좌표에서 이전좌표의 x축 값을 구하기위함
2. i x 30 +20 은 현 좌표의 x축 을 구함

 
# 막대 그래프


1. 최소값 비교 후 ex) if (Integer.parseInt((String) applet.vtSent.elementAt(i)) == applet.naxismin)

2. 최소값 일 경우

 G.drawLine(i * 30 + 20 - 10, y축 , i * 30 + 20 - 1, y축); // 선하나만 그린다

3. 최소값이 아닐 경우(g.fillRect 사용)
 
 G.fillRect(i * 30 + 20 - 10, nSent, 9, -(nSent - (int) (getSize().height * 5 / 6)));

------->G.fillRect(x축 , y축 , width, height);

 -(y축 - (int) (getSize().height * 5 / 6)) -> y축 좌표값에서 Applet 높이의 5/6을 뺀다
 
ex)

y축 240

Applet 높이 480

-(240-(480*5/6)) ---> -(240 - 400) => -(-160) => 160

 

 

'Applet' 카테고리의 다른 글

JFreeChart (한글 깨짐 현상 해결)  (0) 2010.01.18
APPLET 이란???  (0) 2009.12.29
Posted by 인천총각
|

Performizer-setting(Sever)

2010. 1. 12. 12:41

보호되어 있는 글입니다.
내용을 보시려면 비밀번호를 입력하세요.

Subversion은 소프트웨어 버전 관리 시스템입니다.

1.1 버전 관리 시스템의 필요성 #

과연 소프트웨어를 만드는데 버전관리가 왜 필요할까요? 버전 관리가 필요하게 된 이유는 공동 작업 때문입니다. 한사람이 큰 프로젝트를 진행 하는 것이 아니기 때문에 버전 관리 시스템이 필요 하게 되었습니다.

버전 관리 프로그램을 사용하게 되면 다음과 같은 장점이 있습니다.
  • 개발 버전과 릴리즈 버전이 섞이지 않고 쉽게 관리 할 수 있습니다.
  • 소스를 잘못 수정 했더라도 기록이 남고 되돌리기가 쉽습니다.(많은 파일의 경우 유용)
  • 수정, 추가, 삭제 등의 기록이 모두 남고 변경 사항을 추적하기 쉽습니다.
  • 개발자들이 따로 따로 백업을 하지 않아도 됩니다.

가장 유용한 장점은 아무래도 잘못 수정한 소스를 쉽게 되돌릴 수 있다는 것입니다. 프로젝트가 커지다보면 소스가 꼬이게 되고 골치 아픈 상황이 한두 번 발생하는 것이 아니죠. 그리고 변경 사항이 모두 기록되고 무엇을 변경 했는지 쉽게 볼 수 있습니다. 옆 사람이 수정한 것을 쉽게 볼 수 있습니다. 그리고 가장 큰 문제를 일으키는 백업을 하지 않아 소스를 분실하는 최악의 상황도 쉽게 해결 됩니다.

장점을 나열하자면 더 많습니다만 단점을 이야기 하자면 아무래도 프로그램 개발자들이 소프트웨어 버전 관리 시스템의 개념을 제대로 이해하고 기능들을 잘 사용하여 효율적인 버전 관리가 되려면 또다시 새로운 것을 배워야 한다는 것 때문에 쉽게 접근하지 않으려는 경향이 있습니다. 특히나 우리나라 프로그램 개발자들의 경우 윈도우 공유 폴더를 이용해서 개발을 하는 경우가 많습니다. 이렇게 되면 누가 무엇을 수정했는지 알 수도 없고 남이 해 놓은 소스 위에 잘못된 소스를 덮어쓰는 경우도 많이 발생하고 있습니다.

한사람이 개인적으로 진행 하는 프로젝트가 있더라도 버전 관리 프로그램을 사용하는 것이 매우 편리합니다. 앞서 말한 장점들은 여러 명이 개발 하는 것과 한사람이 개발 하는 것에 모두 해당되는 것들입니다.

소프트웨어 버전 관리 시스템을 이용하는 프로젝트들은 아주 많습니다. 대부분 Open Source로 된 프로젝트들은 CVS를 이용하여 버전 관리를 합니다. 대표적으로 *BSD, OpenOffice, Mozilla, XFree86, Apache와 SourceForge.net의 모든 프로젝트들 입니다. 비단 Open Source 뿐만이 아닌 상업 프로그램을 만드는 회사들에서도 소프트웨어 버전 관리 시스템은 필수적입니다.

1.2 버전 관리 시스템의 종류 #

현재 나와 있는 소프트웨어 버전 관리 시스템은 여러 종류가 있습니다. 각각 장단점이 있습니다.
  • CVS (Concurrent Version System) : 가장 널리 사용되며 역사가 깊은 버전 관리 시스템입니다. http://www.cvshome.org[]
  • Subversion : CVS의 단점을 개선하고 CVS를 대체할 목적으로 개발 되었습니다. 이 문서에서 설명할 버전 관리 시스템입니다. http://subversion.tigris.org[]
  • Visual Sourcesafe : Microsoft에서 만든 버전 관리 시스템입니다. CVS와는 버전 관리 관점에서 조금의 차이점이 있습니다. 윈도우 기반 소프트웨어의 버전 관리를 할 때 자주 사용됩니다. http://msdn.microsoft.com/ssafe/[]
  • Clear Case : Rational이라는 회사에서 만든 버전 관리 시스템입니다. 지금은 IBM에 합병되었습니다. 상용 소프트웨어입니다. http://www-306.ibm.com/software/rational[]
  • BitKeeper : 리눅스 커널이 BitKeeper를 이용해서 개발 하고 있습니다. 상용 소프트웨어입니다. http://www.bitkeeper.com[]

1.3 버전 관리 시스템의 용어들 #

소프트웨어 버전 관리 시스템에서 사용되는 용어들을 알아보도록 하겠습니다.


저장소 : 리포지토리(Repository)라고도 하며 모든 프로젝트의 프로그램 소스들은 이 저장소 안에 저장이 됩니다. 그리고 소스뿐만이 아니라 소스의 변경 사항도 모두 저장됩니다. 네트워크를 통해서 여러 사람이 접근 할 수 있습니다. 버전 관리 시스템 마다 각각의 저장소 포맷을 가지고 있으며 Subversion은 Berkeley DB를 사용합니다. 한 프로젝트 마다 하나의 저장소가 필요합니다.


체크아웃 : 저장소에서 소스를 받아오는 것입니다. 체크아웃을 한 소스를 보면 프로그램 소스가 아닌 다른 디렉토리와 파일들이 섞여 있는 것을 볼 수 있습니다. 이 디렉토리와 파일들은 버전 관리를 위한 파일들입니다. 임의로 지우거나 변경하면 저장소와 연결이 되지 않습니다. 이 체크아웃에는 권한을 줄 수 있습니다. 오픈 소스 프로젝트들에서는 대부분 익명 체크아웃을 허용하고 있습니다.


커밋(Commit) : 체크아웃 한 소스를 수정, 파일 추가, 삭제 등을 한 뒤 저장소에 저장하여 갱신 하는 것입니다. 커밋을 하면 CVS의 경우 수정한 파일의 리비전이 증가하고 Subversion의 경우 전체 리비전이 1 증가하게 됩니다.


업데이트(Update) : 체크아웃을 해서 소스를 가져 왔더라도 다른 사람이 커밋을 하였다면 소스가 달라졌을 것입니다. 이럴 경우 업데이트를 하여 저장소에 있는 최신 버전의 소스를 가져옵니다. 물론 바뀐 부분만 가져옵니다.


리비전(Revision) : 소스 파일등을 수정하여 커밋하게 되면 일정한 규칙에 의해 숫자가 증가 합니다. 저장소에 저장된 각각의 파일 버전이라 할 수 있습니다. Subversion의 경우 파일별로 리비전이 매겨지지 않고 한번 커밋 한 것으로 전체 리비전이 매겨 집니다. 리비전을 보고 프로젝트 진행 상황을 알 수 있습니다.


임포트(Import) : 아무것도 들어있지 않은 저장소에 맨 처음 소스를 넣는 작업입니다.


익스포트(Export) : 체크아웃과는 달리 버전 관리 파일들을 뺀 순수한 소스 파일을 받아올 수 있습니다. 오픈소스 프로젝트의 경우 소스를 압축하여 릴리즈 할 때 사용합니다.

1.4 저장소의 디렉토리 배치 #

저장소에 바로 소스를 넣어 프로젝트를 진행 할 수 있습니다. 그렇지만 버전 관리 시스템에서 권장하는 디렉토리 배치 방법이 있습니다.
-- http://svn.samplerepository.org/svn/sample
 +--+---+- branches
    |   +--+- dav-mirror
    |   |  |--- src
    |   |  |--- doc
    |   |  +--- Makefile
    |   |
    |   +--- svn-push
    |   +--- svnserve-thread-pools
    |
    +---+- tags
    |   +--- 0.10
    |   +--+- 0.10.1
    |   |  |--- src
    |   |  |--- doc
    |   |  +--- Makefile
    |   |
    |   +--- 0.20
    |   +--- 0.30
    |   +--- 0.50
    |   +--- 1.01
    |
    +---+- trunk
        |--- src
        |--- doc
        +--- Makefile

위에 보이는 구조는 보통 자주 사용되는 디렉토리 구조입니다. 저장소 디렉토리 아래 branches, tags, trunk 라는 3개의 디렉토리가 있습니다. 이 디렉토리들은 각각의 용도가 있습니다. CVS는 branch와 tag를 위한 명령이 따로 존재 하지만. Subversion의 경우 명령이 있긴 하지만 단순한 디렉토리 복사와 같은 효과를 냅니다.

trunk : 단어 자체의 뜻은 본체 부분, 나무줄기, 몸통 등 입니다. 프로젝트에서 가장 중심이 되는 디렉토리입니다. 모든 프로그램 개발 작업은 trunk 디렉토리에서 이루어집니다. 그래서 위의 구조에서 trunk 디렉토리 아래에는 바로 소스들의 파일과 디렉토리가 들어가게 됩니다.

branches : 나무줄기(trunk)에서 뻗어져 나온 나무 가지를 뜻합니다. trunk 디렉토리에서 프로그램을 개발하다 보면 큰 프로젝트에서 또 다른 작은 분류로 빼서 따로 개발해야 할 경우가 생깁니다. 프로젝트안의 작은 프로젝트라고 생각하면 됩니다. branches 디렉토리 안에 또 다른 디렉토리를 두어 그 안에서 개발하게 됩니다.

tags : tag는 꼬리표라는 뜻을 가지고 있습니다. 이 디렉토리는 프로그램을 개발하면서 정기적으로 릴리즈를 할 때 0.1, 0.2, 1.0 하는 식으로 버전을 붙여 발표하게 되는데 그때그때 발표한 소스를 따로 저장하는 공간입니다. 위에서 보면 tags 디렉토리 아래에는 버전명으로 디렉토리가 만들어져 있습니다.

2 Subversion #

Subversion은 CVS를 대체하기 위해 개발되고 있습니다. Subversion은 소스 코드는 물론 바이너리 파일 등의 여러가지 형식의 파일을 관리 할 수 있습니다.

2.1 CVS와 비교한 Subversion의 장점들 #

  • 커밋 단위가 파일이 아니라 체인지셋이라는 점입니다. CVS에서라면 여러 개의 파일을 한꺼번에 커밋하더라도 각각의 파일마다. 리비전이 따로 붙습니다. 반면 Subversion에서는 파일별 리비전이 없고 한번 커밋할 때마다 변경 사항별로 리비전이 하나씩 증가합니다.
  • CVS에 비해 엄청나게 빠른 업데이트/브랜칭/태깅 시간.
  • CVS와 거의 동일한 사용법. CVS 사용자라면 누구나 어려움 없이 금방 배울 수 있습니다.
  • 파일 이름변경, 이동, 디렉토리 버전 관리도 지원.
  • 원자적(atomic) 커밋. CVS에서는 여러 파일을 커밋하다가 어느 한 파일에서 커밋이 실패했을 경우 앞의 파일만 커밋이 적용되고 뒤의 파일들은 그대로 남아있게 됩니다. Subversion은 여러개의 파일을 커밋하더라도 커밋이 실패하면 모두 이전 상태로 되돌아 갑니다.
  • 양방향 데이터 전송으로 네트워크 소통량(트래픽) 최소화.
  • 트리별, 파일별 접근 제어 리스트. 저장소 쓰기 접근을 가진 개발자라도 아무 소스나 수정하지 못하게 조절할 수 있습니다.
  • 저장소/프로젝트별 환경 설정 가능
  • 확장성을 염두에 둔 구조, 깔끔한 소스


 

2.2 설치 준비 작업 #

이 장에서는 리눅스, 유닉스 등의 POSIX 호환 운영체제에서 소스를 컴파일하고 설치하는 방법을 다루고 있습니다.

Microsoft Windows에서의 사용은 Microsoft Windows에서 사용하기 장을 참조하십시오.

각각 리눅스 배포판 및 FreeBSD, NetBSD 등의 전용 패키지에 대해서는 운영체제별 전용 패키지 장을 참조하십시오.

설치를 위해 준비해야 할 일.

2.3 사용 할 각각의 파일들 구하기 #

위의 파일들을 /root에 받습니다.

3 설치하기 #

Subversion과 연관된 프로그램들을 컴파일 하고 설치하겠습니다.

3.1 OpenSSL 컴파일과 설치 #

# tar vxzf openssl-0.9.7c.tar.gz
# cd openssl-0.97c
openssl-0.97c# ./config
openssl-0.97c# make
openssl-0.97c# make install

3.2 Berkeley DB 컴파일과 설치 #

Berkeley DB는 bdb 형식의 저장소를 사용할 때 필요합니다. fsfs 형식의 저장소만 사용할 경우 Berkeley DB는 설치하지 않아도 됩니다.
# tar vxzf db-4.3.29.tar.gz
# cd db-4.3.29
db-4.3.29# cd build_unix
db-4.3.29/build_unix# ../dist/configure
db-4.3.29/build_unix# make
db-4.3.29/build_unix# make install
db-4.3.29/build_unix# echo "/usr/local/BerkeleyDB.4.3/lib" >> /etc/ld.so.conf
db-4.3.29/build_unix# ldconfig

3.3 Apache 컴파일과 설치 #

Apache는 설치해도 되고 안 해도 됩니다. 웹으로 저장소를 공개한다거나. http:// 프로토콜을 이용해서 subversion을 이용하고 싶다면 설치하도록 합니다.
# tar vxzf httpd-2.0.59.tar.gz
httpd-2.0.59# ./configure --prefix=/usr/local/apache2 --enable-suexec \
                          --enable-so --with-suexec-caller=bin \
                          --enable-ssl --with-ssl=/usr/local/ssl --enable-cache \
                          --enable-ext-filter --with-z=/usr/include --enable-dav \
                          --with-dbm=db4 --with-berkeley-db=/usr/local/BerkeleyDB.4.2
httpd-2.0.59# make
httpd-2.0.59# make install

Berkeley DB를 설치하지 않은 경우
# tar vxzf httpd-2.0.59.tar.gz
httpd-2.0.59# ./configure --prefix=/usr/local/apache2 --enable-suexec \
                          --enable-so --with-suexec-caller=bin \
                          --enable-ssl --with-ssl=/usr/local/ssl --enable-cache \
                          --enable-ext-filter --with-z=/usr/include --enable-dav
httpd-2.0.59# make
httpd-2.0.59# make install

3.4 Subversion 컴파일과 설치 #

데비안의 경우 zlib1g-dev, libxml2-dev, libexpat1-dev의 패키지가 필요합니다. 다른 배포판의 경우도 거의 같은 이름으로된 패키지가 있을 것입니다. 이 패키지들은 라이브러리와 헤더 파일을 포함하고 있는 것들입니다.

앞에서 Apache를 설치했을 경우
# tar vxzf subversion-1.4.2.tar.gz
# tar vxzf subversion-deps-1.4.2.tar.gz
# cd subversion-1.4.2
subversion-1.4.2# ./configure --with-zlib \
                           --with-apxs=/usr/local/apache2/bin/apxs \
                           --with-berkeley-db=/usr/local/BerkeleyDB.4.3
subversion-1.4.2# make
subversion-1.4.2# make install

앞에서 Apache를 설치했을 경우(Berkeley DB를 사용하지 않고자 하는 경우)
# tar vxzf subversion-1.4.2.tar.gz
# tar vxzf subversion-deps-1.4.2.tar.gz
# cd subversion-1.4.2
subversion-1.4.2# ./configure --with-zlib \
                           --with-apxs=/usr/local/apache2/bin/apxs \
                           --without-berkeley-db
subversion-1.4.2# make
subversion-1.4.2# make install

Apache를 설치하지 않았을 경우
# tar vxzf subversion-1.4.2.tar.gz
# tar vxzf subversion-deps-1.4.2.tar.gz
# cd subversion-1.4.2
subversion-1.4.2# ./configure --with-zlib \
                              --with-berkeley-db=/usr/local/BerkeleyDB.4.3
subversion-1.4.2# make
subversion-1.4.2# make install

Apache를 설치하지 않았을 경우(Berkeley DB를 사용하지 않고자 하는 경우)
# tar vxzf subversion-1.4.2.tar.gz
# tar vxzf subversion-deps-1.4.2.tar.gz
# cd subversion-1.4.2
subversion-1.4.2# ./configure --with-zlib \
                              --without-berkeley-db
subversion-1.4.2# make
subversion-1.4.2# make install

4 세부 설정 #

4.1 저장소 만들기 #

소스를 저장할 공간을 만들어야 합니다. 저장소(Repository)는 프로젝트 마다 하나씩 있어야 합니다. 저장소 안에 프로젝트의 소스가 다 들어가게 되며 다른 프로젝트를 진행한다면 그 프로젝트를 위한 저장소를 하나 더 만들어 주어야 합니다. /home/svn안에 저장소를 만들도록 하겠습니다. 앞으로 저장소를 추가 할 때에는 /home/svn 아래에 추가하면 됩니다. 꼭 /home/svn에 하지 않아도 되며 다른 곳에 해도 됩니다.

버클리DB를 이용한 저장소 만들기
# mkdir /home/svn
# cd /home/svn/
/home/svn# svnadmin create --fs-type bdb sample

파일시스템을 이용한 저장소 만들기
# mkdir /home/svn
# cd /home/svn/
/home/svn# svnadmin create --fs-type fsfs sample

svnadmin으로 sample이라는 저장소를 만들면 /home/svn 아래 sample이라는 디렉토리가 생깁니다. 이 디렉토리 안에는 Subversion이 제어하는 파일들이 들어있습니다. 이 디렉토리 안의 파일들은 Berkeley DB 형식으로 되어 있습니다. DB 파일들은 수정하는 일이 없도록 합니다. sample 저장소의 전체 경로는 /home/svn/sample이 됩니다.

이제부터 sample 저장소를 계속 사용하여 설명을 하겠습니다.



4.1.1 공동 작업을 위한 저장소 그룹 설정 #

svn+ssh://로 작업을 하려면 시스템 계정을 만들어야 합니다. 대부분 계정을 만들고 그룹을 하나로 묶는데. 이럴 경우 그룹에 소속된 사용자들에게도 저장소 쓰기 권한을 주어야 합니다. 그래서 저장소의 그룹 권한을 조정해주어야 합니다. 그룹 쓰기 권한을 주지 않으면 저장소를 만든 계정만 저장소에 접근이 가능하고. 그룹에 속해 있더라도 다른 사용자는 저장소에 접근 할 수 없게 됩니다.
# chmod -R g+w sample

4.2 Apache 설정 #

Apache를 설치했다면 Apache 설정을 해주어야 합니다.

Apache가 저장소에 접근할 수 있도록 소유자와 권한을 바꿉니다. Apache는 기본적으로 설치하면 nobody와 nogroup로 실행됩니다.
# cd /home/svn
/home/svn# chown -R nobody.nogroup sample

Apache를 /usr/local/apache2에 설치했으므로 설정파일은 /usr/local/apach2/conf/httpd.conf 입니다. dav, dav_svn 모듈이 설정되어 있는지 확인 합니다. 주석처리 되어 있으면 주석을 없애고 없다면 아래 두줄을 추가합니다.
LoadModule dav_module         modules/mod_dav.so
LoadModule dav_svn_module     modules/mod_dav_svn.so

httpd.conf 파일 맨 뒷부분에 아래와 같이 추가 합니다. 설정을 저장한 뒤에 Apache를 재시작 합니다.
<Location /svn/sample>
  DAV svn
  SVNPath /home/svn/sample
</Location>
이렇게 설정을 하고 웹 브라우저에서 http://(Subversion과 Apache를 설치한 IP주소 또는 도메인)/svn/sample 로 접속을 합니다.

웹 브라우저에 아래와 같은 화면이 보이면 Subversion 저장소와 아파치가 잘 동작하고 있는 것입니다. 아래와 같이 나오지 않는다면 아파치 설정과 저장소의 소유자와 그룹을 다시 한 번 살펴보시기 바랍니다.
Revision 0: /

--------------------------------------------------------------------------------
Powered by Subversion version 1.0.0.
위와 같이 설정하면 누구든지(Anonymous) 웹 브라우저로 저장소를 볼 수 있고 Subversion 클라이언트를 이용해서 소스를 체크아웃, 익스포트, 커밋을 할 수 있습니다.

이렇게 실행 시켰으면 "# svn checkout http://(Subversion서버 IP또는 도메인)/svn/sample sample"을 입력합니다. "Checked out revision 0."이 나오면 제대로 설정이 된 것입니다. 아무나(Anonymous) 저장소에 접근해서 체크아웃, 커밋 등을 할 수 있습니다.

4.2.1 Apache에서 ID로 사용자 인증 #

이제 ID를 통해 인증된 사용자만 소스를 체크아웃하고 커밋 할 수 있도록 설정 하겠습니다.
아파치에 사용할 패스워드 파일을 만듭니다. "# htpasswd -c 패스워드파일명 사용자ID"
# cd /usr/local/apache/conf
/usr/local/apache/conf# ../bin/htpasswd -c passwd sampleuser
New password:
Re-type new password:
"# htpasswd -c"는 패스워드 파일을 처음 만들 때의 옵션이고 사용자를 추가하고 싶을 때에는 "# htpasswd 패스워드파일명 사용자ID" 로 해주면 됩니다.

방금 수정했던 /usr/local/apache2/conf/httpd.conf 파일의 맨 마지막 부분에 추가한 부분을 다시 설정 합니다.
<Location /svn/sample>
  DAV svn
  SVNPath /home/svn/sample
  AuthType Basic
  AuthName "pyrasis's Repository"
  AuthUserFile /usr/local/apache2/conf/passwd
  Require valid-user
</Location>
4줄이 추가 되었습니다. AuthType Basic은 Apache 기본 패스워드 인증입니다. AuthName은 패스워드가 걸린 웹페이지에 뜨는 로그인창에 나올 문장입니다. AuthUserFile은 방금 전 만들었던 아파치 패스워드 파일입니다. 절대경로로 적어주어야 합니다. Require valid-user는 인증된 사용자만 볼 수 있게 한다는 것입니다.

이제 웹 브라우저로 다시 sample저장소로 접속해 보면 ID와 패스워드를 묻는 창이 나올 것입니다. 만든 ID와 패스워드를 입력하면 저장소를 볼 수 있습니다. 이렇게 되면 체크아웃, 커밋등을 할 때 ID와 암호를 물어보게 됩니다.

웹 브라우저로 저장소를 보는 것과 체크아웃은 아무에게나(Anonymous) 할 수 있게 하고 커밋은 지정된 사용자만 할 수 있도록 하려면 httpd.conf에서 설정한 부분을 아래와 같이 바꾸어 주면 됩니다.
<Location /svn/sample>
  DAV svn
  SVNPath /home/svn/sample
  AuthType Basic
  AuthName "pyrasis's Repository"
  AuthUserFile /usr/local/apache2/conf/passwd
  <LimitExcept GET PROPFIND OPTIONS REPORT>
    Require valid-user
  </LimitExcept>
</Location>
이렇게 하면 저장소를 보거나 체크아웃을 할 때는 ID와 패스워드를 묻지 않고 커밋이나 디렉토리. 파일복사 등의 저장소를 변경하는 작업을 할 때에는 ID와 패스워드를 물어보게 됩니다.

"# svn checkout http://(Subversion서버 IP또는 도메인)/svn/sample sample" 을 입력하면 ID와 패스워드를 물어옵니다. ID와 패스워드를 입력하고 나서 "Checked out revision 0." 이 출력되면 제대로 설정 된 것입니다.

4.3 svnserve를 사용한 서버 #

Subversion의 고유 프로토콜인 svn://을 이용할 수 있는 svnserve를 사용해서 서버 설정을 해보겠습니다. 이것을 사용하면 Apache를 사용한 것보다 체크아웃, 커밋 속도가 더 빠릅니다.

svnserve로 서버를 실행 시키면 3690번의 포트가 열립니다. sample 저장소가 /home/svn 아래에 있을 경우
# svnserve -d -r /home/svn/

이렇게 실행 시켰으면 "# svn checkout svn://(Subversion서버 IP또는 도메인)/sample sample"을 입력합니다. "Checked out revision 0."이 나오면 제대로 설정이 된 것입니다. 이것 또한 아무나(Anonymous) 저장소에 접근해서 체크아웃, 커밋 등을 할 수 있습니다.

4.3.1 svnserve에서 ID로 사용자 인증 #

Subversion 0.33.0버전 이후부터 svnserve로 ID로 사용자 인증이 가능하게 되었습니다. 그 이전 버전에서 svnadmin으로 저장소를 만들면 저장소 디렉토리 아래에 conf 디렉토리가 생기지 않지만 0.33.0 버전이후에 svnadmin으로 저장소를 만들었다면 저장소 디렉토리 아래에 conf 디렉토리가 자동으로 생성됩니다. 이전 버전에서 먼저 저장소를 만들어 두었다면 저장소 디렉토리 /home/svn/sample 아래 conf 디렉토리를 만들어 줍니다. (/home/svn/sample/conf)

이제 각 저장소 디렉토리 아래 conf 디렉토리가 있습니다. /home/svn/sample/conf/svnserve.conf 파일이 svnserve의 설정 파일입니다. 0.33.0 버전 이전 만든 저장소에는 conf 디렉토리 및 svnserve.conf 파일이 없습니다. 그럴 경우에는 conf 디렉토리와 svnserve.conf 파일을 만들어 주면 됩니다.

svnserve.conf 파일을 아래와 같이 설정 합니다.
### This file controls the configuration of the svnserve daemon, if you
### use it to allow access to this repository.  (If you only allow
### access through http: and/or file: URLs, then this file is
### irrelevant.)

### Visit http://subversion.tigris.org/ for more information.

[general]
### These options control access to the repository for unauthenticated
### and authenticated users.  Valid values are "write", "read",
### and "none".  The sample settings below are the defaults.
anon-access = none
auth-access = write
### The password-db option controls the location of the password
### database file.  Unless you specify a path starting with a /,
### the file's location is relative to the conf directory.
### The format of the password database is similar to this file.
### It contains one section labelled [users]. The name and
### password for each user follow, one account per line. The
### format is
###    USERNAME = PASSWORD
### Please note that both the user name and password are case
### sensitive. There is no default for the password file.
password-db = passwd
### This option specifies the authentication realm of the repository.
### If two repositories have the same authentication realm, they should
### have the same password database, and vice versa.  The default realm
### is repository's uuid.
realm = pyrasis's Repository

anon-access = none으로 아무에게나(Anonymous) 저장소에 접근하는 것을 막았습니다. read로 하면 읽기만 가능하며 write로 해주면 읽고 쓰기가 가능해집니다.

auth-access = write는 ID로 인증된 사용자에게 쓰기 권한을 주는 것입니다.

password-db = passwd 이 설정은 svnserve의 패스워드 파일입니다 이전의 Apache 패스워드 파일과는 별개입니다. 아래 내용으로 /home/svn/sample/conf 아래 passwd 라는 이름으로 만듭니다. ID = 패스워드 형식 입니다. 아직 암호화된 패스워드는 지원하지 않는 것 같습니다. 버전 업을 통해 개선 될 것 같습니다.

passwd
[users]
sampleuser = 02030104

이제 "# svn checkout svn://(Subversion 서버의 IP또는 도메인)/sample sample" 을 해보면 ID와 패스워드를 입력하라고 나옵니다. 위에서 설정했던 ID와 패스워드를 입력하면 체크아웃이 되며 "Checked out revision 0." 이 나오면 설정이 제대로 된 것입니다.

4.4 SSH + svnserve 서버 #

SSH2 데몬으로 svnserve을 터널링 하여 작동시킵니다. 이렇게 되면 svn+ssh:// 프로토콜을 사용하게 되며 사용자 인증은 시스템 계정으로 인증을 합니다. 구동시키는 방법은 따로 있지 않으며 SSH데몬만 떠 있으면 됩니다.

클라이언트에서 svn+ssh:// 를 사용하기

클라이언트에서 서버로 접속할 ID설정, 각 사용자 계정의 디렉토리에 .subversion이라는 디렉토리가 있습니다. 여기에 보면 config 라는 파일의 맨 마지막에 아래와 같이 추가합니다. ssh -l 서버에 접속할 ID

~/.subversion/config
[tunnels]
ssh = ssh -l sampleuser

주의할 점은 IP주소나 도메인 뒤에 저장소의 절대 경로를 적어주어야 합니다. svnserve를 띄워서 /home/svn/과 같이 지정해 주지 않았기 때문에 각 저장소의 절대경로인 /home/svn/sample로 합니다.
# svn checkout svn+ssh://(Subversion 서버의 IP주소 또는 도메인)/home/svn/sample sample

5 실제로 사용하기 #

간단한 예제 프로그램을 통해서 Subversion의 사용법을 알아보도록 하겠습니다. 커맨드 라인 클라이언트을 통해 알아보겠습니다. X 윈도우, MS 윈도우용 GUI 클라이언트 프로그램에 대해서는 뒤에 설명하도록 하겠습니다.

5.1 에디터 설정 #

Subversion에서 사용할 기본적인 에디터를 지정해야 합니다. 이것을 지정하지 않으면 커밋 등을 할 수 없게 됩니다.

각 사용자 계정의 디렉토리에는 .profile이나 .bash_profile 등의 환경 변수 등을 지정하는 파일이 있습니다. 여기에 아래와 같이 추가 합니다. 여기에서는 에디터를 vim으로 설정 하겠습니다. vim의 경로는 사용자마다 다를 수 있으므로 사용하고자 하는 시스템에 맞게 적어주십시오.
SVN_EDITOR=/usr/bin/vim
export SVN_EDITOR

5.2 기본 디렉토리 만들기 #

앞서 설명 했던 trunk, branches, tags 디렉토리를 만들어 보겠습니다.

trunk 디렉토리의 생성, 앞에서 Apache를 통해 설정 했다면 http://를 svnserve로 설정했다면 svn://로 SSH를 사용한다면 svn+ssh://로 하여 서버 설정에 맞게 주소를 적어 주십시오.
apache를 연동한 경우
# svn mkdir http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/trunk
svnserve만 실행한 경우
# svn mkdir svn://(Subversion서버 IP또는 도메인)/sample/trunk
위처럼 입력을 하면 vim이 실행되면서 아래와 같이 나올 것입니다. :q!로 빠져 나갑니다.
--This line, and those below, will be ignored--

A    http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/trunk

vim을 빠져 나왔다면 아래와 같이 나오는데(커밋 로그를 입력하지 않으면 아래와 이 나오게됩니다.) c를 누르고 엔터를 치면 디렉토리가 만들어 지게 됩니다.
Log message unchanged or not specified
a)bort, c)ontinue, e)dit

c를 입력한뒤 아래와 같이 나오면 디렉토리 생성은 성공한 것입니다. 이 방법대로 branches, tags 디렉토리도 만듭니다.
Committed revision 1.

만약 read-only에러가 나올 경우 conf/svnserve.conf에서 계정을 만들지 않아서 그렇습니다. anonymous로 사용할 경우 #general, #anon-access = read 가 주석 처리 되어 있는데 주석을 없애고 anon-access = write로 바꾸시면 됩니다.

제대로 만들어 졌는지 확인을 하려면 다음과 같이 입력 합니다. list는 저장소 안의 디렉토리와 파일들을 표시해 줍니다.
# svn list http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample
branches/
tags/
trunk/

앞으로 디렉토리 생성, 삭제, 이름변경, 파일, 추가, 삭제, 복사, 이동과 커밋, 등을 할 때 vim이 실행되면서 어떤 것들이 바뀌는지 표시가 됩니다. 커밋 로그를 입력한뒤 vim을 종료하면 커밋이 완료 됩니다. 커밋 로그를 입력하지 않았을 경우 a)bort, c)ontinue, e)dit가 나오게 되는데 c)ontinue)로 계속 하면 됩니다.
<!> 하지만! 커밋 로그 입력은 필수입니다. 소프트웨어 버전 관리에서 가장 중요한 것은 커밋 로그입니다. 어떤 코드를 어떻게 수정했고 디렉토리, 파일을 만들고 삭제 했는지를 꼼꼼히 기록해야합니다. 나중에 소스코드가 바뀌는 흐름을 따라가고자 할때나 문제점(버그)을 추적할때 커밋 로그가 아주 유용하게 이용될 것입니다.

5.3 Import #

맨 처음 프로젝트를 시작할 때 저장소에 소스들을 넣어야 합니다. 이럴 때 하는 것이 import 작업입니다. sampledir 이라는 디렉토리를 만든 뒤에 그 아래 다음과 같은 간단한 소스를 작성해 보십시오.
# mkdir sampledir
# cd sampledir
sampledir# vim sample.c
#include <stdio.h>

int main()
{
  printf("Sample Program Version 0.1\n");

  return 0;
}

이 소스를 저장소의 trunk 디렉토리에 import 하겠습니다. 아래 sampledir은 디렉토리입니다. 파일을 적으면 import되지 않습니다. 꼭 디렉토리를 만들고 그 디렉토리를 적어 주십시오. 저장소의 trunk 디렉토리에는 sampledir 디렉토리안의 sample.c 파일만 올라가게 되고 sampledir은 올라가지 않습니다. sampledir 아래 디렉토리를 만들었다면 그 디렉토리는 저장소의 trunk 디렉토리 아래에 올라가게 됩니다.
sampledir# cd ..
# svn import sampledir http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/trunk
import도 위에서 디렉토리를 만들었을 때 처럼 vim이 실행되게 됩니다. import되는 파일들이 표시됩니다. :q!로 닫고 c를 입력하면 import 되게 됩니다.

import가 제대로 되었는지 확인해 봅시다. list 명령을 이용해 trunk 디렉토리에 무엇이 있나 보겠습니다.
# svn list http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/trunk
sample.c


5.4 Checkout #

이제 부터 Subversion을 이용해서 프로그램 소스를 관리 할 수 있습니다. checkout을 해서 어디서든 소스를 받아 볼 수 있습니다. 방금 import를 하기위해 만들었던 sampledir은 지워도 됩니다.

svn checkout은 svn co로 줄일 수 있습니다. "svn checkout 저장소주소 로컬디렉토리" 의 형식 입니다.
# svn checkout http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/trunk sample
A  sample/sample.c
Checked out revision 4.

checkout을 한 디렉토리 안에는 .svn 이라는 디렉토리가 있습니다. 이 디렉토리는 Subversion 저장소 정보가 들어 있기 때문에 지우면 안 됩니다.

5.5 Update #

체크아웃 해서 받은 소스를 저장소의 최근 내용으로 업데이트 하는 명령입니다. 체크아웃 해서 받은 소스의 revision보다 저장소의 revision이 높으면 업데이트 하게 됩니다. 업데이트를 하게 되면 전부 다 받아오는 것이 아니라 변경 된 것들만 받아옵니다. 소스를 수정하기 전에 언제나 update 명령으로 소스를 가장 최신 revision으로 맞추고 작업을 해야 합니다.

svn update는 svn up로 줄여 사용할 수 있습니다.
sample# svn update

5.6 Commit #

checkout 해서 받은 소스를 수정하고 저장소에 수정된 소스를 적용해 보겠습니다. 이 작업을 커밋(Commit)이라고 합니다.

체크아웃 받은 sample.c 소스를 아래처럼 수정합니다.
#include <stdio.h>

int main()
{
  printf("Sample Program Version 0.2\n");
  printf("Hello Subversion\n");

  return 0;
}

이제 커밋을 해 봅시다 커밋 명령은 체크아웃 해서 소스를 받은 디렉토리에서 해야 됩니다. svn commit은 svn ci로 줄여 쓸 수 있습니다. 커밋 명령을 내리면 커밋 로그를 작성하는 에디터가 실행 됩니다. 커밋 로그를 입력한후 저장을 하면 커밋이 됩니다.
sample# svn commit
Sending        sample.c
Transmitting file data .
Committed revision 5.

5.7 Log #

이제 저장소에 어떠한 것들이 변경 되었는지 확인 할 수 있는 log 명령에 대해 알아보겠습니다.

log 명령은 체크아웃 받은 디렉토리 안에서 해야 합니다. revision과 날짜, 누가 커밋을 했는지 알 수 있습니다. 여기서는 (no author)로 나옵니다. 이것은 서버 설정에서 아무나 커밋 할 수 있게 하여서 이렇게 나오는 것이고 ID를 통해 인증을 하도록 설정을 했으면 ID가 표시 됩니다.
sample# svn log
------------------------------------------------------------------------
r4 | (no author) | 2003-11-23 14:40:05 +0900 (Sun, 23 Nov 2003) | 1 line


------------------------------------------------------------------------
r1 | (no author) | 2003-11-23 14:39:00 +0900 (Sun, 23 Nov 2003) | 1 line


-----------------------------------------------------------------------
--revision과 -r은 같습니다.
sample# svn log --revision 5:19    # revision 5부터 9까지의 로그를 출력합니다.
sample# svn log -r 19:5            # revision 19부터 5까지 역으로 출력합니다.
sample# svn log -r 8               # revision 8의 로그를 출력합니다.
하나의 파일이나 디렉토리 로그를 볼 수도 있습니다.
sample# svn log sample.c
sample# svn log http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/trunk/sample.c
-v 옵션은 더 자세한 정보를 얻을 수 있습니다. 아래 M은 Modify(수정)의 표시 입니다. 소스 파일을 수정하고 커밋 했기 때문입니다.
sample# svn log -r 5 -v
------------------------------------------------------------------------
r5 | (no author) | 2003-11-23 14:42:34 +0900 (Sun, 23 Nov 2003) | 1 line
Changed paths:
   M /trunk/sample.c


------------------------------------------------------------------------
A 는 Add(추가) 표시 입니다. trunk라는 디렉토리를 만들었고 sample.c 파일을 import 했기 때문에 A(추가) 표시가 나오게 되는 것입니다.
sample# svn log -v
------------------------------------------------------------------------
r4 | (no author) | 2003-11-23 14:40:05 +0900 (Sun, 23 Nov 2003) | 1 line
Changed paths:
   A /trunk/sample.c


------------------------------------------------------------------------
r1 | (no author) | 2003-11-23 14:39:00 +0900 (Sun, 23 Nov 2003) | 1 line
Changed paths:
   A /trunk


------------------------------------------------------------------------

5.8 Diff #

diff 명령을 사용하면 예전 소스 파일과 지금의 소스 파일을 비교해 볼 수 있습니다. 위에서 나온 로그와 같이 우리는 revision 4(r4)에서 sample.c를 import 했습니다. 그리고 revision 5에서 소스를 수정하고 커밋 했습니다.

최초에 import 했던 소스 sample.c의 revision 4와 수정해서 커밋한 revision 5의 차이점을 diff 명령으로 출력해 보겠습니다. --revision 4만 적으면 현재 revision 5와 비교하게 됩니다.
sample# svn diff --revision 4 sample.c
Index: sample.c
===================================================================
--- sample.c    (revision 4)
+++ sample.c    (working copy)
@@ -2,7 +2,8 @@

 int main()
 {
-  printf("Sample Program Version 0.1\n");
+  printf("Sample Program Version 0.2\n");
+  printf("Hello Subversion\n");

   return 0;
 }
revision 4와 5를 비교 하고 싶으면 --revision 4:5 (-r 4:5)로 하면 됩니다. --revision 8:10 도 가능합니다.
sample# svn diff --revision 4:5 sample.c
Index: sample.c
===================================================================
--- sample.c    (revision 4)
+++ sample.c    (revision 5)
@@ -2,7 +2,8 @@

 int main()
 {
-  printf("Sample Program Version 0.1\n");
+  printf("Sample Program Version 0.2\n");
+  printf("Hello Subversion\n");

   return 0;
 }

여기서 주의할 점은 CVS는 revision을 파일 하나하나에 다 매기지만 Subversion은 파일에 revision을 매기지 않고 소스 수정, 파일 복사, 이동, 삭제 등을 하고 그때 한 커밋으로 revision을 매깁니다. 그래서 다른 파일들이라도 같은 revision 번호를 가지게 됩니다.

5.9 Blame #

Blame은 한 소스파일을 대상으로 각 리비전 대해서 어떤 행을 누가 수정했는지 알아보기 위한 명령입니다.
리비전, 커밋한 사용자의 ID, 소스 순서입니다.
sample# svn blame sample.c
     4 sampleuser #include <stdio.h>
     4 sampleuser
     4 sampleuser int main()
     4 sampleuser {
     5 sampleuser   printf("Sample Program Version 0.2\n");
     5 sampleuser   printf("Hello Subversion\n");
     4 sampleuser
     4 sampleuser   return 0;
     4 sampleuser }
     4 sampleuser
여기서는 커밋한 사용자가 한명 밖에 없으므로 전부 똑같이 나옵니다.

한 예로 여러사람이 커밋했을 경우 아래처럼 나옵니다.
     4 sampleuser #include <stdio.h>
     4 sampleuser
     4 sampleuser int main()
     4 sampleuser {
     7 epifanes     printf("Sample Program Version 0.3\n");
     6 pyrasis      printf("Hello Subversion\n");
     4 sampleuser
     4 sampleuser   return 0;
     4 sampleuser }
     4 sampleuser

특정 리비전만 지정해서 볼 수도 있습니다. 리비전을 지정하지 않으면 현재 리비전을 대상으로 합니다.
sample# svn blame -r 4 sample.c

5.10 lock #

svn lock 명령으로 파일을 잠글 수 있습니다.
sample# svn lock hello.c
svn lock 명령으로 파일을 잠그었을 경우 왜 잠그었는지 로그를 기록할 수 있습니다.
파일을 잠그었을 경우 파일을 잠근 사용자만 수정을 해서 커밋을 할 수 있고 다른 사용자는 수정을 할 수 없습니다. 파일의 잠금을 해제할 경우에는 svn unlock 명령을 사용하면 됩니다.
파일 잠금기능은 여러명이 개발을 하고 있을 경우 한 파일에서 작업이 너무 많아 모두 끝내지 못하고 중간 중간에 커밋만 해놓았을 경우 다른 사람이 그 파일을 수정해버리면 하던 작업이 엉망이 되어 버립니다. 그래서 파일을 잠그어 작업이 끝날때 까지 한 사람만 커밋을 할 수 있도록 하는 것입니다. 작업이 끝나면 파일 잠금을 해제 하면 됩니다.

5.11 Add #

svn add 명령으로 새 파일을 추가할 수 있습니다.
sample# svn add hello.c
A         hello.c
svn add로 파일을 추가한 뒤에는 svn commit으로 커밋을 해주어야 완전히 파일이 저장소에 추가됩니다.
sample# svn commit
물론 커밋 로그도 입력해야 됩니다.

5.12 Rename #

svn rename 명령으로 파일 및 디렉토리의 이름을 바꿀 수 있습니다.
sample# svn rename hello.c world.c
sample# svn commit
svn rename 현재 파일명 바꿀 파일명 형식으로 사용합니다. svn rename 명령으로는 이름이 바로 바뀌지는 않고 svn commit 명령으로 커밋을 해줘야 완전히 바뀌게 됩니다.

5.13 Export #

체크아웃은 Subversion이 버전관리를 할 수 있도록 각종 파일이 소스 폴더 안에 함께 생깁니다. 이것과는 달리 Export는 순수하게 프로그램의 소스만 가져올 수 있습니다. 만들어진 소스를 압축하여 릴리즈 할 때 사용합니다.
sample# svn export http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample2/trunk sample
--revision (-r)으로 revision을 지정하면 지정한 revision의 소스를 받아옵니다. 지정하지 않으면 가장 최근의 revision의 것을 가져옵니다.

5.14 Branch와 Tag #

CVS에서의 Branch와 Tag는 Branch와 Tag를 위한 명령이 있습니다. CVS에서 Branch와 Tag를 하게 되면 저장소의 파일에는 Branch 또는 Tag 되었다는 표시가 함께 붙게 됩니다. 체크아웃 할 때에도 Branch와 Tag의 소스를 받아오려면 Branch, Tag를 지정하는 옵션을 주어야 했습니다.

CVS와는 달리 Subversion은 Branch와 Tag가 특별한 명령이 있는 것도 아니고 이런 것들을 한다고 해도 저장소에 특별히 Branch, Tag라고 기록이 남는 것도 아닙니다. Subversion에서 Branch와 Tag는 단순한 디렉토리 복사 명령으로 할 수 있고 Branch, Tag를 했더라도 디렉토리 복사와 같습니다.

5.14.1 Branch #

Branch를 해야 할 경우는 앞서 설명 했듯이 프로젝트중 작은 분류로 나누어 개발 하거나 소스를 따로 분리하여 실험적인 코드 를 작성할 경우 등 입니다.

Subversion에서는 Branch를 copy 명령으로 수행 합니다. trunk의 내용을 Branches안에 새로운 이름으로 복사 하는 것입니다. 체크아웃 받은 소스에서 바로 copy를 할 수도 있고 원격에서 URL로 복사를 할 수도 있습니다. 아래 체크아웃 받은 것은 trunk만 받은 것이 아니고 sample 디렉토리 아래를 전부 받는 것입니다.
svn checkout http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample sample
sample# svn copy trunk branches/sample-branch
sample# svn commit
원격에서 URL로 copy를 하면 commit도 같이 이루어집니다. 체크아웃 받은 소스에서는 update를 해주어야 합니다.
# svn copy http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/trunk \
http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/branches/sample-branch
Branch된 소스를 받기 위해서는 branches/sample-branch를 체크아웃 하면 됩니다. trunk와 branche는 따로 revision을 가지지 않습니다. Subversion의 revision은 저장소 전체의 revision입니다.
# svn checkout \
  http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/branches/sample-branch \
  sample-branch

5.14.1.1 Merge #
위와 같이 우리는 trunk를 sample-branch로 Branch 했습니다. sample-branch를 수정하다가 trunk에도 반영하고 싶다면. merge 명령을 사용하면 됩니다. 하나하나 소스 코드를 옮겨서 입력하지 않아도 됩니다. 다만 merge 한 뒤에는 꼭 사람이 확인을 해 봐야겠죠.

sample-branch를 체크아웃 합니다.
# svn checkout \
  http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/branches/sample-branch \
  sample-branch

sample-branch의 sample.c를 다음과 같이 수정 합니다. printf("Hello World\n");를 추가 했습니다. 그리고 commit을 합니다. 지금 수정된 것은 revision 7입니다.
#include <stdio.h>

int main()
{
  printf("Sample Program Version 0.2\n");
  printf("Hello Subversion\n");

  printf("Hello World\n");

  return 0;
}
이제 sample의 trunk를 체크아웃 합니다.
# svn checkout http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/trunk sample
trunk의 sample.c는 아래와 같습니다.
#include <stdio.h>

int main()
{
  printf("Sample Program Version 0.2\n");
  printf("Hello Subversion\n");

  return 0;
}
이제 sample-branch의 수정된 것을 trunk에 merge 해 보겠습니다. "svn merge -r N:N 저장소주소 체크아웃된디렉토리" 형식 입니다. 아래는 저장소 주소 하나만 입력되어 있습니다. 이렇게 되면 지금 체크아웃한 소스와 merge를 하게 됩니다. merge할 revision 번호를 주의해 주십시오. 6:7은 r 6과 r 7의 차이점을 뜻합니다. sample-branch의 r 6과 r 7의 차이점을 지금의 체크아웃된 trunk에 적용하라는 것 입니다.
sample# svn merge -r 6:7 \
        http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/branches/sample-branch
U  sample.c
sample# svn commit
sample# svn update
이제 sample.c를 열어보면 아래와 같이 sample-branch에서 수정한 것이 merge가 되어 있습니다.
#include <stdio.h>

int main()
{
  printf("Sample Program Version 0.2\n");
  printf("Hello Subversion\n");

  printf("Hello World\n");

  return 0;
}

파일 하나만 merge를 할 수도 있습니다.
# svn merge -r 6:7 sample.c

저장소 주소끼리 merge를 할 수도 있습니다.
# svn merge http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample2/trunk \
  http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample2/branches/sample-branch

5.14.2 Tag #

Tag는 만든 프로그램을 웹 사이트 등에 공개할 때 사용합니다. Tag도 Subversion에서는 Branch와 마찬가지로 디렉토리 복사(copy)와 같습니다. tags 디렉토리 안에는 일반적으로 릴리즈(발표)하는 버전별 디렉토리를 만들어 사용합니다.

0.1 버전을 발표할 때 0.1 버전의 순간을 tags 디렉토리에 복사하는 것입니다. 0.2가 되었을 때 tags아래 0.2 디렉토리로 복사합니다. 이렇게 되면 각각의 버전별로 소스를 관리 할 수 있습니다. 저장소에서는 실제로 복사가 되는 것은 아니고 변경된 점만 복사하기 때문에 저장소의 용량이 소스코드의 크기만큼 배로 늘어나지는 않습니다.

trunk의 소스를 0.1 버전으로 Tag, Branch와 마찬가지로 체크아웃 받은 소스에서도 할 수 있고 원격에서 URL로도 할 수 있습니다. 아래 체크아웃 받은 것은 trunk만 받은 것이 아니고 sample 디렉토리 아래를 전부 받는 것입니다.
# svn checkout http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample sample
sample# svn copy trunk tags/0.1
sample# svn commit

원격에서 URL로 복사합니다. 이 경우 commit도 같이 이루어집니다. 체크아웃 받은 소스는 update를 해주어야 합니다.
# svn copy http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/trunk \
  http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/tags/0.1

이제 0.1로 Tag한 소스를 Export로 받아서 압축한 뒤에 릴리즈(공개)를 하면 됩니다.
# svn export http://(Subversion 서버의 IP주소 또는 도메인)/svn/sample/tags/0.1 sample-0.1

5.15 Revert #

소스를 수정하면서 merge를 하다 보면 분명히 잘못 했을 경우가 생깁니다. 이럴 때 하는 것이 revert입니다. revert는 단어 뜻 그대로 되돌리는 명령입니다. 커밋을 하기 전에만 되돌릴 수 있습니다. 커밋 하기전의 체크아웃 받은 소스를 되돌리는 명령입니다. 원격 저장소의 것은 되돌릴 수 없습니다.
sample# svn revert sample.c

5.16 백업 및 복구 #

저장소는 가장 중요한 공간이기 때문에 백업은 필수입니다. 저장소 디렉토리를 그대로 보관할 수도 있지만 백업과 복구 명령을 사용하는것이 편리합니다.
Windows, 리눅스, BSD 등 운영체제에 관계없이 백업 및 복구가 가능합니다. Windows에서 백업한것을 리눅스에서 사용할 수도 있고 BSD에서 백업한 것을 Windows에서 사용할 수도 있습니다.
저장소의 서버를 옮길때에는 저장소 디렉토리를 옮기는 것이 아니라 저장소 백업을 한뒤 그 백업파일을 이용하여 새 서버에서 복구를 하는 방식으로 옮겨야합니다.

5.16.1 Dump #

sample 저장소를 백업합니다. 표준 입출력을 통해서 저장소의 내용을 파일로 생성합니다. svnadmin dump 명령을 사용하며 이 명령은 저장소 디렉토리 바깥에서 사용해야 합니다.
repos# ls
sample
repos# svnadmin dump sample > sample.dump

5.16.2 Load #

저장소 백업 파일을 이용해서 저장소를 복구합니다. svnadmin load 명령을 사용합니다.
빈 저장소를 생성한 뒤 백업 파일을 이용해서 복구를 합니다.
repos# svnadmin create sample
repos# ls
sample   sample.dump
repos# svnadmin load sample < sample.dump

5.17 svnsync #

svnsync는 1.4.0에서 새로 생긴 명령입니다. svnsync 명령을 이용해서 저장소를 그대로 복사해 올 수 있습니다. 단 복사해오고자 하는 원본 저장소가 Subversion 1.4 이상을 사용하고 있어야 하며 1.4 이하를 사용하고 있을 경우 svnsync 명령이 동작하지 않습니다.

먼저 빈 저장소를 만듭니다.
# cd /home/svn/
/home/svn# svnadmin create syncsample

새로 만든 빈 저장소의 hooks 디렉토리에 pre-revprop-change 파일을 만들고 아래의 내용을 입력한 뒤 저장합니다. /home/svn/syncsample/hooks/pre-revprop-change
#!/bin/sh

pre-revprop-change 파일을 실행할 수 있도록 권한을 조정합니다.
/home/svn/syncsample/hooks# chmod 777 pre-revprop-change

svnsync를 사용할 수 있도록 저장소를 초기화 합니다. file:///home/svn/syncsample은 방금 만든 빈 저장소 경로이고 http://svn.collab.net/repos/svn은 복사해 올 원본 저장소의 주소입니다. http://, svn://등 접속 가능한 저장소 주소이면 되고 trunk나 branches같은 디렉토리가 아닌 최 상위 디렉토리의 주소로 설정해줘야 합니다.
/home/svn# svnsync init file:///home/svn/syncsample http://svn.collab.net/repos/svn
Copied properties for revision 0.

이제 저장소를 복사를 시작합니다.
/home/svn# svnsync sync file:///home/svn/syncsample
Committed revision 1.
Copied properties for revision 1.
Committed revision 2.
Copied properties for revision 2.
Committed revision 3.
Copied properties for revision 3.
Committed revision 4.
Copied properties for revision 4.
Committed revision 5.
Copied properties for revision 5.
Committed revision 6.
Copied properties for revision 6.
....
최신 리비전 까지 복사해오면 svnsync 명령이 끝난 것입니다.
이제 이 저장소에서 소스를 체크아웃 하여 살펴볼 수 있습니다.

Windows의 경우는 아래와 같이 사용합니다.

저장소 생성
C:\repos>svnadmin create syncsample

새로 만든 저장소의 hooks 디렉토리에 pre-revprop-change.bat라는 빈 파일을 만듭니다.

초기화
C:\repos>svnsync init file:///c:/repos/syncsample http://svn.collab.net/repos/svn

저장소 복사
C:\repos>svnsync sync file:///c:/repos/syncsample











6 Microsoft Windows에서 사용하기 #

Microsoft Windows에서도 Subversion을 사용할 수 있습니다. 소스를 컴파일하지 않고 설치 파일을 통해 간단하게 설치해서 사용할 수 있습니다. Windows에서도 리눅스, 유닉스와 똑같은 기능을 사용할 수 있습니다. Subversion 서버를 구성하는 방법은 윈도우에서 Subversion 서버 운영하기를 참고하시기 바랍니다.

6.1 설치 파일 구하기 #

Subversion Windows 설치파일


Windows 용 설치 파일을 받습니다. ZIP으로 압축된 바이너리를 사용해도 상관없습니다.

svn-1.0.0-setup.exe

6.2 설치 #

설치 파일을 받았다면 일반적인 Windows 프로그램을 설치하듯이 설치하면 됩니다. ZIP으로 압축된 것은 적당한 디렉토리에 압축을 해제한뒤 사용하면 됩니다.

6.3 사용하기 #

지금 설치한것들은 Subversion 커맨드 라인 클라이언트와 저장소를 네트워크에서도 사용할 수 있도록 하는 서버 프로그램 들입니다. 커맨드라인 사용법은 리눅스, 유닉스와 똑같습니다. 다만 Windows에서는 명령 프롬프트(cmd.exe)에서 사용합니다.

ZIP으로 된 바이너리를 사용하려 한다면 명령 프롬프트에서 Subversion의 명령을 실행하기 위해 환경 변수의 시스템 변수 PATH에 Subversion 압축을 해제한 디렉토리를 추가합니다. 설치 파일로 설치했다면 자동으로 환경 변수에 추가됩니다.

커밋 로그를 입력할 수 있도록 환경 변수의 Administrator에 대한 사용자 변수에 변수이름 SVN_EDITOR, 값 notepad를 설정합니다. notepad가 아닌 다른 편집기를 이용하려면 편집기의 실행파일의 경로를 지정해 주면 됩니다.

저장소 만들기. C:\에 repos라는 폴더를 만들었습니다. 명령 프롬프트를 실행합니다.
C:\Documents and Settings\Administrator>cd c:\repos
버클리 DB를 이용한 저장소
C:\repos>svnadmin create --fs-type bdb sample
파일시스템을 이용한 저장소
C:\repos>svnadmin create --fs-type fsfs sample

체크아웃. svn://, http://를 이용한 체크아웃 방식은 위에서 설명한 방법과 똑같습니다.

윈도우 파티션에 있는 저장소에 직접 접근하는 방법.
C:\temp>svn checkout file:///C:/repos/sample

svnserve를 사용한 서버
C:\>svnserve -d -r C:\repos

명령행에서 일일이 실행하는 불편함을 덜어주는 SVNSERVE Manager같은 프로그램을 이용할 수도 있습니다. svnserve의 동작/정지 상태를 트레이 아이콘으로 표시해 주며 시스템 시작시 svnserve를 자동으로 실행 하게 할 수 있습니다.

Windows용 Subversion 명령도 리눅스, 유닉스에서의 명령과 똑같습니다. 하지만 Windows에서는 그래픽 클라이언트가 있기 때문에 명령 프롬프트를 사용하는 일은 많지 않습니다. TortoiseSVN을 사용하면 팝업 메뉴를 이용해서 저장소 만들기, 체크아웃, 커밋 등 매우 편리하게 사용할 수 있습니다.

7 운영체제별 전용 패키지 #

리눅스 배포판별(Redhat, Debian, SuSE) 전용 바이너리 패키지, FreeBSD 포트 컬렉션, NetBSD pkgsrc, Mac OS X 패키지 등 편리하게 설치할 수 있도록 운영체제별 전용 패키지가 제공되고 있습니다. 이것들을 사용하면 소스를 컴파일 하지 않고 바로 설치해서 사용할 수 있는 장점이 있습니다.

운영체제별 패키지는 아래 링크에서 받을 수 있습니다.
http://subversion.tigris.org/project_packages.html[]

8 GUI 클라이언트 프로그램 #

Subversion에서 기본적으로 지원하는 커맨드 라인 명령 svn은 사용하기에 불편한 점이 많습니다. 앞으로 소개할 것들은 MS Windows, X Window 등에서 사용 가능한 Subversion 클라이언트 프로그램 입니다.

8.1 TortoiseSVN #

MS Windows용 GUI 클라이언트 프로그램입니다. CVS GUI 클라이언트 프로그램으로 유명한 TortoiseCVS와 거의 같은 인터페이스를 가지고 있습니다.
http://tortoisesvn.tigris.org[]

8.2 Ankhsvn #

Visual Studio .NET 애드인 형식의 Subversion 클라이언트 프로그램입니다. VS.NET과 통합성이 매우 높습니다. VS.NET의 솔루션 뷰에서 커밋, 업데이트 등의 작업이 가능하며 솔류션 뷰의 각 파일에 수정되었거나 수정되지 않은 파일의 상태를 표시해줍니다.
http://ankhsvn.tigris.org[]

8.3 RapidSVN #

크로스 플랫폼 Subversion 클라이언트 프로그램입니다. Windows, 리눅스, BSD의 X Window에서 사용할 수 있습니다.
http://rapidsvn.tigris.org[]

9 웹 인터페이스 #

저장소를 웹브라우저로 편하게 볼 수 있는 인터페이스들입니다.

9.1 ViewVC #

Subversion괴 CVS 웹 인터페이스로 유명합니다. 아파치와 mod_python 기반으로 동작하며 Subversion 파이썬 바인딩으로 만들어져 있습니다. 유닉스, 리눅스, Windows 모두 사용할 수 있습니다. (ViewCVS에서 ViewVC로 이름이 바뀌었습니다.)
http://www.viewvc.org[]


9.2 WebSVN #

Subversion 전용 웹 인터페이스입니다. Subversion svnlook과 연동하여 웹으로 표시합니다. 아파치와 php가 필요합니다.
http://websvn.tigris.org[]

'SVN/CVS' 카테고리의 다른 글

SVN(Subversion)  (0) 2010.01.04
CVS-개념 및 리눅스 서버 설치  (0) 2010.01.04
CVS(Concurrent Versions System)  (0) 2010.01.04
Posted by 인천총각
|

SVN(Subversion)

SVN/CVS 2010. 1. 4. 10:41

SVN 이란?

Subversion의 줄임말로 소프트웨어 형상관리(SCM)를 수행하기 위한 Open Source Software 입니다.

  1. SCM 정의 (from Wikipedia)

    소프트웨어 형상 관리(SCM)은 형상관리(CM)의 일부이다. Roger Pressman은 그의 책, "소프트웨어 공학 : 실용주의자의 관점에서 (실제 번역본 제목은 다를 수 있음)"에서 소프트웨어 형상 관리란,

    "변경사항을 통제하기 위하여 만들어진 행위들의 집합으로, (1) 변경될 가능성이 있는 산출물(work product)을 찾아내고, (2) 산출물 사이의 관계를 확립하고, (3) 이러한 산출물들의 다양한 버전들을 관리하기 위한 메커니즘을 정의하고, (4) 발생한 변경사항들을 통제하고, (5) 가해진 변경사항 들에 대해서 감사(auditing)하고 보고하는 행위"

    라고 이야기하고 있다. 다른 말로, SCM이란 소프트웨어 개발 프로젝트를 통제, 관리하기 위한 방법이다.

    (후략)

    조금 어려울 수도 있겠습니다..만, 중요한 의미를 담고 있는 것입니다. 무엇보다 SCM을 한 마디로 이야기하자면,

    소프트웨어 형상관리 도구를 이용하여 개발을 프로젝트를 수행한다. (-- )

    라고 이야기할 수도 있겠습니다. (어쨌든 시작은 거기서부터인 것, 맞습니다.)

  2. 상세한 정보

    [KDLP SubVersion How-To]
    http://wiki.kldp.org/wiki.php/Subversion-HOWTO#s-1

 

SVN 사용법

용어 설명
저장소 : 리포지토리(Repository)라고도 하며 모든 프로젝트의 프로그램 소스들은 이 저장소 안에 저장이 됩니다. 그리고 소스뿐만이 아니라 소스의 변경 사항도 모두 저장됩니다. 네트워크를 통해서 여러 사람이 접근 할 수 있습니다. 버전 관리 시스템 마다 각각 다른 파일 시스템을 가지고 있으며 Subversion은 Berkeley DB를 사용합니다. 한 프로젝트 마다 하나의 저장소가 필요합니다.

리비전(Revision) : 소스 파일등을 수정하여 커밋하게 되면 일정한 규칙에 의해 숫자가 증가 합니다. 저장소에 저장된 각각의 파일 버전이라 할 수 있습니다. Subversion의 경우 파일별로 리비전이 매겨지지 않고 한번 커밋 한 것으로 전체 리비전이 매겨 집니다. 리비전을 보고 프로젝트 진행 상황을 알 수 있습니다.

trunk : 단어 자체의 뜻은 본체 부분, 나무줄기, 몸통 등 입니다. 프로젝트에서 가장 중심이 되는 디렉토리입니다. 모든 프로그램 개발 작업은 trunk 디렉토리에서 이루어집니다. 그래서 위의 구조에서 trunk 디렉토리 아래에는 바로 소스들의 파일과 디렉토리가 들어가게 됩니다.

branches : 나무줄기(trunk)에서 뻗어져 나온 나무 가지를 뜻합니다. trunk 디렉토리에서 프로그램을 개발하다 보면 큰 프로젝트에서 또 다른 작은 분류로 빼서 따로 개발해야 할 경우가 생깁니다. 프로젝트안의 작은 프로젝트라고 생각하면 됩니다. branches 디렉토리 안에 또 다른 디렉토리를 두어 그 안에서 개발하게 됩니다.

tags : tag는 꼬리표라는 뜻을 가지고 있습니다. 이 디렉토리는 프로그램을 개발하면서 정기적으로 릴리즈를 할 때 0.1, 0.2, 1.0 하는 식으로 버전을 붙여 발표하게 되는데 그때그때 발표한 소스를 따로 저장하는 공간입니다. 위에서 보면 tags 디렉토리 아래에는 버전명으로 디렉토리가 만들어져 있습니다.

명령어 의미
Import : svn import sampledir svn+ssh://svn-domain/svn/sample/trunk
맨 처음 프로젝트 시작할때 저장소에 등록하는 명령어 한 번 하고 나면 쓸일이 잘 없을 듯.

Checkout : svn checkout svn+ssh://svn-domain/svn/sample/trunk sample
저장소에서 소스를 받아 오는 명령어. 받아온 소스에는 소스 뿐만이 아니라 버젼관리를 위한 파일도 같이 받아 온다. 지우거나 변경시 저장소와 연결 불가능

Export : svn export svn+ssh://svn-domain/svn/sample2/trunk sample
체크아웃과는 달리 버젼관리 파일을 뺀 순수한 소스만 가져오는 명령어 마지막에 사용.

Commit : svn commit
체크아웃 한 소스를 수정, 파일 추가, 삭제 등을 한 뒤 저장소에 저장하여 갱신 하는 명령어. Revision이 1 증가 한다.

Update : svn update
체크아웃 해서 받은 소스를 최신의 소스로 업데이트 하는 명령어. 소스 수정이나 Commit 하기전에 한 번씩 해줘야 할 듯. 잘 못하면 소스 망치는 경우가 있을 듯.

Log : svn log
저장소에 어떠한 것들이 변경 되었는지 확인 할 수 있는 log 명령어

Diff : svn diff --revision 4 sample.c
diff 명령은 예전 소스 파일과 지금의 소스 파일을 비교해 보는 명령어

Blame : svn blame sample.c
Blame은 한 소스파일을 대상으로 각 리비전 대해서 어떤 행을 누가 수정했는지 알아보기 위한 명령어

lock : svn lock hello.c
파일에 락을 걸어 락을 건 사용자만이 수정할 수 있게 해주는 명령어. 해제는 svn unlock.
왜 파일에 락을 걸었는지 로그를 기록 할 수 있다.

Add : svn add hello.c
새 파일을 만들었을 경우에 파일을 추가 해주는 명령어. 그 뒤엔 꼭 svn commit를 꼭 해줘야 한다.
새 파일을 생성해서 올릴 때에도 꼭 add를 해줘야 함. 안해주면 commit을 해도 안 올라감.

파일 백업및 복구
dump : svnadmin dump sample > sample.dump
load : svnadmin load sample < sample.dump
새 파일을 만들었을 경우
1. svn add filename.*
2. svn ci filename.*

그냥 기존 소스 수정할 경우
1. svn ci filename.*

항상 svn update는 꼭 해주자

svn status : 자신이 수정하고 있는 파일의 상태를 알려주는 명령어

'SVN/CVS' 카테고리의 다른 글

버전관리 시스템(#1 SVN 바로알기)  (0) 2010.01.04
CVS-개념 및 리눅스 서버 설치  (0) 2010.01.04
CVS(Concurrent Versions System)  (0) 2010.01.04
Posted by 인천총각
|

1. CVS에 대한 소개

과거는 컴퓨터 시스템의 능력이 매우 제한적이였고 사용하는 유저 역시 제한적이거나 지극히 개인적인 용도로 사용하는 경우가 대부분 이였다. 때문에 소프트웨어역시 비교적 단순했으며 단지 한두명의 개발자 투입만으로도 꽤나 쓸만한 애플리케이션이 만들어지기도 했다.

도스 시절부터 컴퓨터를 다루어왔던 유저라면 "누구누구의 어떤 프로그램" 이라는 얘기를 많이 들어 보았을 것이다. 지금은 사정이 달라져서 아주 간단한 프로그램이 아니고서는 혼자 개발해서 그럭저럭 인지도 있는 프로그램을 만든다는것 자체가 매우 힘들어졌다.

요즘은 UI만 제작하는 것도 하나의 작업으로 분류된다. 인터넷이 일반적으로 보급되면서 대부분의 애플리케이션은 C/S환경하에서 작동하게 된다. 개발자는 데이터전송과 처리에 대한 부분까지 신경써야 하며 많은 경우 서버와 클라이언트가 서로 다른 운영체제하에 놓이며, 특히 서버 프로그램의 경우 여러가지의 전혀 달라보이는 운영체제를 지원해야하는 경우도 있다.

이런 이유로 왠만한 규모의 프로젝트라 할지라도 혼자서 개발을 진행한다는건 매우 힘들며, 대부분 팀단위로 프로젝트를 진행을 하게 된다. 이 팀이란건 또 어떤가 같은 사무실에서 같은 시간에 존재하면서 서로 의견교환을 통해서 프로젝트를 진행 시킬 수도 있지만 인터넷이라는 매체를 통해서 전혀 다른 공간에서 전혀 다른 시간대에 프로젝트를 진행 시켜야 하는 경우도 생긴다. 전 세계인이 참여하는 많은 오픈 프로젝트가 그러하다.

이런 경우 하나의 소스코드를 한명 이상이 접근해서 수정할 수 있는데, 프로젝트를 진행하다 보면 소스코드가 엉뚱하게 꼬일 수 있을 것이다. 같은 사무실에서 단지 몇명의 프로그래머가 작업을 한다면, 서로 의견조율을 하거나 처음부터 각각의 모듈만 담당하게 만들어서 어느정도 문제를 해결할 수 있을 거라고 생각할 수도 있을 것이다. 그러나 막상 프로젝트를 진행해보면 이게 결코 말처럼 쉬운일이 아니란걸 알게 될것이다. 프로젝트를 진행하다 보면 이쪽 시스템에서 테스트하고, 저쪽 시스템에서 테스트하고 문제가 생기면 즉각 수정을 하게 되는데, 이러다보면 소스코드가 여기저기 위치하게 되고 결국 어느 소스가 최근 소스코드인지 헷갈리는 사태가 발생하게 된다. 하물며 오픈소스와 같이 수많은 프로그래머가 느슨하게 묶여있는 경우는 더 말할 필요도 없다. 적당한 버젼관리 도구의 사용없이는 프로젝트의 진행자체가 불가능해질 것이다.

이러한 문제의 해결을 위해서 여러도구가 개발되었는데, 그중 하나가 CVS로 현재 가장 널리 사용되고 있는 버젼관리 도구이다.


2. CVS에 대한 기본지식

2.1. CVS 란?

CVS는 Concurrent Version System 의 줄임말로써 직역 하자면 공동 버젼 시스템, 의역하자면 "공동으로 진행하는 프로젝트의 버젼 관리 시스템" 정도가 될것이다.


2.2. 어떨때 CVS가 필요하죠?

CVS는 사용하기에 따라서 여러가지 용도로 사용할수 있다. 이번장에서는 CVS를 이용할수 있는 다양한 상황들에 대해서 알아보도록 하겠다.


2.2.1. 공동 프로젝트 관리

회사혹은 학교에서 프로젝트를 진행하다보면, 여러명이서 하나의 프로젝트를 진행하는 경우가 발생할것이다.

이럴경우 보통 모듈별로 개발을 하게 되겠지만, 또한 모듈은 전체 프로젝트에 영향을 미치게 되므로, 자신의 모듈버젼과 전체 프로젝트의 버젼을 컨트롤할수 있어야 한다. 그리고 코드가 충동하게 될경우(서로 같은 부분을 수정함으로써)의 문제를 해결할수 있어야 한다.

이러한 작업은 프로젝트 규모가 작고 개발 참여자 수가 적고, 개발 참여자가 가까운 지역(사무실 같은)에 모두 모여있다면, 한명의 버젼관리자(보통은 팀장)를 두고 그럭저럭 관리가 가능할것이다.

그러나 조금만 프로젝트가 커지고, 개발참여자 수가 많아지고 개발자가 지역적으로 떨어져 있는 상황에서는 거의 불가능 하다는 걸 알수 있게 될것이다. 특히 인터넷을 통해서 느슨하게 연결된 오픈 프로젝트의 경우 도구를 사용하지 않는 다면 거의 관리가 불가능 할 것이다.

CVS 를 사용하면 이러한 대규모의 프로젝트에서 각 모듈 개발자가 자신의 버젼을 유지하면서 전체 프로젝트에 참여할수 있도록 할수 있다.

실제로 KDE, GNOME, APACHE 서버 등 다양한 프로젝트가 CVS 를 이용해서 프로젝트를 관리하고 있다. 이러한 프로젝트는 규모가 작아도 수십명, 혹은 수백명이 프로젝트를 진행하게 되는데(게다가 지역적으로 멀리 떨어져 있다), CVS가 중간에서 프로젝트가 산으로 가지 않도록 중계해준다. 오픈 프로젝트를 하는데 있어서 CVS는 거의 표준적으로 사용되는 버젼관리 도구이다.


2.2.2. 프로젝트 백업

CVS 를 사용할경우 자동적으로 프로젝트 백업의 문제까지 해결이 가능하다. CVS 는 중간에 CVS 서버가 있어서, 프로젝트 데이터의 저장소 역할을하며 모든 개발자는 CVS 서버에서 최신의 프로젝트를 다운로드 받아서, 자신의 컴퓨터에서 테스트하고 코딩해서, 이걸 다시 CVS 서버에 업데이트 시키는 방식을 사용하게 된다.

그러므로 실수로 자신의 프로젝트 데이터가 날아간다고 해도 전혀 염려할 필요가 없다. 그냥 서버에서 다시 다운 받기만 하면 된다. 최악의 경우 CVS 서버가 날라갔다고 하더라도 가장 최근의 쏘쓰를 가진 개발자가 있을 것이므로 쉽게 복구 가능하다.

또한 CVS는 최신 버젼의 소스코드 뿐만 아니라 과거 버젼의 소스코드에 대한 정보를 가지고 있어서 최근의 몇개 버젼에 문제가 생겼다고 하더라도 쉽게 그이전의 소스코드를 얻어올 수 있다.


2.2.3. 데이터 동기화

요즘은 회사와 집과의 경계가 많이 허물어 졌다. (좋은 현상인지 나쁜 현상인지는 좀 생각해 봐야겠지만) 그러다 보니 회사에서 하는일을 가정에서 하기도 하고, 가정에서 했던 일을 회사로 가져가기도 한다. 그럴경우 회사의 컴터와 가정의 컴터에 있는 데이타의 동기화가 필수적이다. 이런 데이타 동기화를 위해서 "노트북", "PDA" 같은걸 사용할수 있겠지만, 이건 너무 비싸다. ftp 도 사용할수 있겠지만, 이거 잘못 사용하면 데이터가 꼬일수 있다. 또한 상당히 불편하다.

이럴때 CVS 를 사용하면 대단히 편하게 작업이 가능하다. 회사에서 작업을 마치고 CVS 서버에 등록하고, 가정으로 돌아가서 CVS 서버에 등록된 최신의 작업을 받아와서 작업을 하고 다시 CVS 서버에 등록만 하면 되기 때문이다. (물론 이왕이면 가정에까지 회사일을 가지고 가지 않으면 좋겠지만..)

또한 덤으로 자신의 중요한 자료까지 자동으로 백업된다.

필자 역시 이러한 방법으로 작업을 한다. 작업거리가 좀 남았는데, 회사에서는 일이 잘안되고(실은 일하기 싫어서겠지만 --;), 그냥 집에가서 느긋하게 TV도 보고, 웃통 벗어던지고 일하고 싶을때 매우 편하게 CVS를 이용할수 있다.


3. CVS 사용하기

3.1. CVS 서버 설치하기

지금 까지 CVS에 대한 개론적인 설명을 알아 보았다. 이제 본격적으로 CVS를 설치하고 운용하고 사용하는 방법을 알아보도록 하겠다. CVS 서버 설치는 redhat 8.x 리눅스를 기준으로 하겠다. 대부분의 redhat 리눅스 배포판은 cvs 를 기본적으로 포함하고 있다. rpm 패키지 관리자를 통해서 설치하자.

이제 Internet services daemon 에 cvs 서버를 등록 시켜주기만 하면 된다. 레드헷 7.x 버젼부터는 inetd 대신에 xinetd 가 Internet services daemon 으로 사용되어 지고 있다. /etc/xinetd.d 디렉토리 밑에 cvspserver 이란 이름으로 서비스 설정파일을 만들도록 하자. 내용은 다음과 같다.

service cvspserver
{
    disable         = no
    flags           = REUSE
    socket_type     = stream
    wait            = no
    user            = root
    server          = /usr/bin/cvs
    server_args     = --allow-root=/home/cvs pserver
    log_on_failure  += USERID
}
			
만약 inetd를 사용하는 예전 버젼의 리눅스라면 아래와같이 설정하도록 한다.
# echo "2401 stream tcp nowait root /usr/bin/cvs cvs -f \
  --allow-root=/cvsroot pserver" >> /etc/inetd.conf
			

위의 설정값들중 --allow-root를 주목하기 바란다. 프로젝트가 서버에 저장된다면 당연히 이들 프로젝트가 서버의 어디 디렉토리로 저장되어야 하는지 지정할 수 있어야 할것이다. cvs에서는 이를 repository(이하 저장소)라고 한다. --allow-root는 cvs 저장소가 /home/cvs임을 명시해 주기 위해서 사용된다. 만약 새로운 프로젝트인 hello_world를 만들었다면 이 프로젝트는 /home/cvs/hello_world 디렉토리에 저장이 된다.

이제 xinetd 데몬(혹은 inetd데몬)을 다시 실행(/etc/rc.d/init.d/xinetd restart) 시키면 cvs 서버가 작동하게 될것이다. cvs 서비스는 2401 포트를 이용해서 서비스 된다(/etc/services 참조). 제대로 cvs 서비스가 되고 있는지 알아보기 위해서 포트 스캐닝 도구인 nmap 을 사용해서 확인해 보도록 하자.

[root@cvs xinetd.d]# nmap 192.168.0.4

Starting nmap V. 2.54BETA7 ( www.insecure.org/nmap/ )
Interesting ports on localhost.localdomain (127.0.0.1):
(The 1527 ports scanned but not shown below are in state: closed)
Port       State       Service
22/tcp     open        ssh                     
25/tcp     open        smtp                    
80/tcp     open        http                    
111/tcp    open        sunrpc                  
2401/tcp   open        cvspserver              
3306/tcp   open        mysql                   
		
2401 번 포트로 cvspserver 가 서비스 되고 있음을 알수 있다. 이로써 cvs 서버의 설치및 가동을 마쳤다.

다른 배포판을 사용하더라도 설치상에 있어서 문제점은 없을것이다. 데비안 이라면 전용 패키지관리자를 이용해서 설치하면 된다. 패키지 설치가 여의치 않다면 쏘쓰를 직접 컴파일 해서 설치 하면 된다.

cvs 는 cvspserver 를 이용한 서비스 외에도 rsh, ssh 를 이용한 서비스도 가능하다. 이에 대한 내용은 CVS 사용 문서를 참고 하기 바란다. 이문서에서는 가장 널리 사용되는 cvspserver 방식에 대해서만 설명하고 있다.


3.1.1. CVS저장소 만들기

위의 설정에서 우리는 /home/cvs를 프로젝트들을 위한 저장소로 사용한다고 했는데, 저장소로 사용하기 전에 저장소 터를 다지기 위한 사전작업이 필요하다.

이러한 작업은 cvs에서 제공하는 init옵션을 통해서 가능하다.

# cvs -d /home/cvs init
			
-d를 이용해서 저장소로 사용될 디렉토리를 지정하고 init를 명시하는 정도로 어렵잖게 저장소를 생성할 수 있다.


3.1.2. CVS 유저 환경 설정

CVS 에 서버를 만들어 놓았으면 이제 CVS 자원을 사용하도록 환경설정을 해주어야 한다. 가장 중요한 건 공동으로 작업할 프로젝트 파일들이 저장될 CVS 저장 디렉토리(저장소)를 설정하는 일이다.

일단 우리는 위의 /etc/xinetd.d/cvspserver 를 설정하면서 cvs 데몬이 뜨게될경우 --allow-root 옵션을 이용해서 /home/cvs 를 홈디렉토리(프로젝트가 저장될 디렉토리)를 지정했다. 이제 /home/cvs 를 실제 프로젝트 사용자들이 사용할수 있도록 권한 설정을 해주어야 한다.

cvs 의 권한 설정을 위해서 cvs 란 그룹을 만들도록 하고 /home/cvs 디렉토리에 cvs 그룹에 대해서 읽기/쓰기/실행 권한을 부여하도록 하자.

# groupadd cvs
# mkdir cvs
# chmod 770 cvs 
			
이제 cvs 그룹에 포함된 모든 사용자는 CVS 자원을 이용할수 있는 권한을 가지게 되며, 이후로는 프로젝트를 등록시켜서 공동작업에 CVS 를 이용하기만 하면 된다.


3.1.3. CVS 사용하기

이제 CVS 서버의 설정이 끝났음으로, 클라이언트의 입장에서 어떻게 프로젝트를 등록하고 공동으로 작업을 진행시킬수 있는지에 대해서 알아보도록 하겠다. 이러한 작업들은 클라이언트에게 제공되는 "cvs" 라는 프로그램을 통해서 이루어진다.

CVS 의 사용방법은 다음과 같은 환경하에서 테스트되었다.

              +------------+
              | @cvs       | project : hello_world
              | CVS SERVER |
              +------------+
                     |
                     |
        +------------+------------+ 
        |                         | 
   +---------+               +---------+
   | @myhome |               | @one    |
   +---------+               +---------+
@cvs 는 CVS 저장소를 가지고 있는 서버이며, @myhome 은 "팀원" @one 는 "팀장" 의 개발호스트(컴퓨터) 이다. 공동으로 진행될 프로젝트는 hello_world 이다.


3.1.3.1. 익명 CVS설정하기

익명 CVS란 말그대로 일반 사용자에게 CVS를 읽고/쓸수 있는 권한을 부여하는 것이며, 많은 오픈 프로젝트들이 익명 CVS를 허용해서 가능한한 많은 개발자가 참여할 수 있도록 길을 열어 놓고 있다.

이러한 익명 CVS사용자는 보통 프로젝트에 대한 읽기권한만을 부여한다. 익명 사용자에게 쓰기권한을 주면 프로젝트의 진행이 너무 산만해 질 수 있기 때문이다. 익명 사용자(혹은 개발자)는 프로젝트에 반영해야 될 내용이 있을 때 메일등을 통해서 프로젝트 메인 개발자에게 통보하는게 보통이다.

익명 CVS를 허용하기 위해서는 우선 시스템에 anonymous계정이 만들어져 있어야 한다. 쉘을 가지지 못하도록 설정한다.

# useradd anonymous -s /bin/false 
				
그리고 /cvsroot/CVSROOT/passwd 파일에 위의 계정을 등록하면 된다.
# echo anonymous: > /cvsroot/CVSROOT/passwd
				
정확하게는 [유저아이디]:[패스워드]의 형태가 되어야겠지만 익명 CVS의 경우 패스워드를 설정하지 않는게 일반적이므로 패스워드는 생략하도록 한다. 패스워드를 부여하고 싶다면 crypt된 문자열값을 사용하도록 한다.

익명 CVS사용자의 경우 아래와 같이 설정해서 읽기만 가능하도록 권한을 제한시킨다.

# echo anonymous > /cvsroot/CVSROOT/readers
				


3.1.4. CVS 사용자 환경설정

cvs 서버에 프로젝트를 등록시키고, 프로젝트를 업데이트하고, 받아오기 위해서 우리는 "cvs" 라는 전용 클라이언트를 사용하게 된다. "cvs" 다음에 여러가지 명령행 옵션을 이용함으로써, 원하는 작업을 하게 된다.

"cvs" 프로그램을 사용하기 위해서 우리는 CVS 서버에 접근해서 지정된 디렉토리(프로젝트가 저장되는 디렉토리 다른말로 "저장소") 가 어디인지 cvs 프로그램에 알려주어야만 한다. 보통 환경변수인 CVSROOT 를 통해서 "cvs" 에게 CVS 서버의 정보를 알려준다. 그러므로 자신의 홈디렉토리의 .bash_profile 파일에 다음과 같은 내용을 추가시켜주어야 한다.

CVSROOT=:pserver:yundream@192.168.0.5:/home/cvs
				
위의 CVSROOT 에는 "pserver" 은 우리가 CVS 서버에 접근하기 위해서 pserver 방식을 사용할것이며, 서버의 IP는 192.168.0.5 접근 아이디는 yundream 그리고 프로젝트가 저장되어 있는 저장소 디렉토리는 /home/cvs 라는 정보를 가지고 있다.

환경변수 CVSROOT 를 사용하지 않고 -d 를 이용하는 방법도 있다.

cvs -d :pserver:yundream@192.168.0.5:/home/cvs [옵션]
				
그러나 이방법은 불편하므로 환경변수를 사용하도록 하자.


3.2. cvs 클라이언트 사용하기

3.2.1. 로그인 하기 : login

프로젝트를 아무나 접근해서 사용하게 해서는 당연히 안될 것이다. 그러므로 최초에 아이디와 패스워드를 이용한 인증절차를 거치게 된다.

CVS 서버에 로그인 하기 위해서는 "cvs" 다음에 옵션으로 login 을 주고 실행시키면 된다.

# cvs login
CVS password: 
				
그러면 패스워드를 묻는 프롬프트가 떨어질것이다. 자신의 패스워드를 입력하면 인증이 성공된다. 한번 인증이 성공되면 인증에 사용한 여러가지 정보가 .cvspass 에 저장되고 다음부터는 .cvspass 를 사용해서 자동적으로 인증을 하기 때문에 최초에 한번만 login 을 성공하면 된다.

물론 당연히 CVS 서버인 192.168.0.5 에는 yundream 이란 사용자가 등록되어 있어야 하며 이 사용자는 cvs 그룹에 포함되어 있어야 한다.


3.2.2. 프로젝트 만들고 등록하기 : import

가장 먼저 해야할일은 진행될 프로젝트를 만들고 등록하는 일이다. 우리가 진행하고자 하는 프로젝트는 hello_world 프로젝트이며, 여기에는 hello.c라는 하나의 파일이 포함되어 있다. 다음은 hello.c의 코드이다.

int main()
{
    printf("Hello World\n");
}
				
우리는 단지 hello.c코드가 있는 디렉토리로 이동해서 다음과 같이 import 시켜주면 된다.
# cd hello_world
# cvs -d:pserver:yundream@192.168.0.5:/home/cvs import hello_world project start
				
이 디렉토리는 프로젝트 임포트를 위해서 새로 준비된 디렉토리여야 한다. 그렇지 않고 잡다한 파일들이 있을경우 이들 파일들까지 몽땅 프로젝트에 등록되어 버린다. 만약 환경변수 CVSROOT가 설정되어 있다면 아래와 같이 간단하게 import를 실행할 수 있을 것이다.
# cvs import hello_world project start
N hello_world/hello.c

No conflicts created by this import
				
2번째 인자인 hello_world는 import할 프로젝트의 이름이며 project, start는 프로젝트의 부가 정보들이다 (별로 신경쓸 필요 없다).

이렇게 하면 cvs서버의 저장소에 hello_world란 디렉토리가 생기고 여기에 hello.c가 올라가게된다.

참고: cvs 저장소에 올라가는 파일 원래 파일이름뒤에 ',v'이 붙어서 저장된다. hello.c라면 hello.c,v라는 이름으로 저장되며 여기에는 hello.c의 원래 내용외에 버젼 관리를 위한 각종 정보가 들어가게 된다.


3.2.3. 프로젝트 가져오기 : checkout

프로젝트 관리자가 프로젝트를 만들었다면 이제 프로젝트 개발자들이 프로젝트를 받아와서 필요한 작업을 해야할 것이다. 프로젝트에 가져오는 방법은 간단하다. "cvs" 다음에 checkout(혹은 co) 옵션을 사용하면 된다. co 옵션 뒤에는 등록할 프로젝트 이름(hello_world)를 명시해 주면 된다.

 
# cvs co hello_world 
cvs server: 
Updating hello_world
U hello_world/hello.c
				
성공적으로 프로젝트가 등록되었다. 이제 ls 해보면 현재 디렉토리에 hello_world 라는 프로젝트이름을 가지는 디렉토리가 생겼음을 알 수 있다. 이와 더불어 hello.c역시 확인 가능할 것이다.


3.2.4. 프로젝트 수정후 적용(업데이트) : commit

그런데 원래의 hello.c를 보면 printf()함수가 선언되어 있는 stdio.h가 빠져있다. 대부분의 경우 문제가 없지만 컴파일러에 따라서 경고메시지를 보내거나 심한경우 컴파일 실패하는 경우도 있다. 그래서 헤더파일을 추가하기로 했다.

#include <stdio.h>

int main(int argc, char **argv)
{
    printf("Hello world");
}
				
헤더파일을 추가 시켰다. 이제 프로젝트 내용을 내가 수정한 내용으로 cvs를 업데이트 시켜야 할것이다. 이럴때는 "commit" 옵션을 이용하면 된다. -m 옵션을 이용하여 변경된 내용에 대한 간단한 로그도 남겨줄수 있다.
# cvs commit -m "stdio.h 헤더파일 인클루드" hello.c 
Checking in hello.c;
/home/cvs/hello_world/hello.c,v  <--  hello.c
new revision: 1.2; previous revision: 1.1
done
#
				
물론 cvs 업데이트를 시킬때는 반드시 컴파일이 되는지 정도는 확인하고 올려야 될것이다. 컴파일도 안되는 코드를 올렸다가는 팀원들에게 원망의 소리를 듣게 될것이다.


3.2.5. 파일 받아오기/로그 보기 : update, log

이제 여러분은 hello_world 프로젝트의 진행 일원이 되었다. 프로젝트 참여 개발자로서 여러분이 컴퓨터 앞에 앉았다면 가장 먼저 해야할일은 간밤에 누군가 프로젝트를 수정하지 않았는지 확인하고 테스트하는 일부터 해야 한다. 최근 프로젝트에 대한 변경사항은 "up"을 이용해서 확인할 수 있다.

[yundream@myhome hello_world]$ cvs up
cvs server: Updating .
P hello.c
[yundream@myhome hello_world]$ 
				
hello.c 라는 파일이 수정 돼었음을 알수 있다. hello.c 는 새로이 수정 되었음으로 누가 어떤 이유로 코드를 수정했는지 확인해볼 필요가 있을 것이다. 이럴때는 "log" 명령을 사용한다. "log"명령을 사용하면 해당 파일에 대한 간략한 로그정보를 얻어 올수 있다.
[yundream@myhome hello_world]$ cvs log hello.c
cvs server: Logging .

RCS file: /home/cvs/hello_world/hello.c,v
Working file: hello.c
head: 1.1
branch:
locks: strict
access list:
symbolic names:
keyword substitution: kv
total revisions: 1;     selected revisions: 1
description:
----------------------------
revision 1.1
date: 2002/06/07 01:36:27;  author: yundream;  state: Exp;
stdio.h 헤더파일 인클루드
=============================================================================
				
그러면 버젼정보에서 부터, 누가 수정을 했는지, 언제 수정을 했는지와 commit하면서 남긴 로그메시지 등이 표시 됨으로 hello.c 가 어떤식으로 변경되었는지 대략의 정보를 얻어올 수 있다.


3.2.6. 버젼별 차이 확인 : diff

이렇게 해서 새로운 소스 파일을 가져왔는데, 어느 코드의 어떤 라인이 수정되었는지 확인하고 싶을 때가 생길 것이다. 이러한 버젼별 코드 변경사항의 히스토리가 남게 된다면 나중에 문제가 생겼을 때 이전버젼의 코드를 쉽게 얻어낼수도 있을 것이다.

cvs는 버젼별 코드변경사항을 모두 저장하며 개발자는 이 내용을 이용해서 코드변경사항을 확인할 수 있을 뿐 아니라 문제가 생겼을시 이전 버젼의 코드를 얻어올 수도 있다.

참고: 물론 이러한 작업을 위해서는 약간의 수작업이 필요한데, 공개된 CVS프론트엔드들은 자동으로 이러한 귀찮은 일을 대신 해준다. 아마도 웹기반의 CVS프론트엔드가 가장 좋은 선택이 될 것이다.

버젼별 변경내용은 diff를 통해서 확인할 수 있다.

//hello.cc에 대해서 1.1버젼과 1.2버젼과의 변경내용을 출력하시오.
# cvs diff -r 1.2 -r 1.1 hello.cc
bash-2.04# cvs diff -r 1.2 -r 1.1 hello.c 
Index: hello.c
===================================================================
RCS file: /home/cvs/hello_world/hello.c,v
retrieving revision 1.2
retrieving revision 1.1
diff -r1.2 -r1.1
1,2d0
< #include <stdio.h>
< 
				

단지 diff만 사용하면 가장최근의 변경사항을 출력한다.

#cvs diff test.cc
				


3.2.7. 파일 추가하기 : add

이렇게 해서 프로젝트를 진행하다 보니 README파일을 추가시켜야 할 필요성을 느끼게 되었다. 이처럼 프로젝트를 진행하다 보면 중간중간 여러개의 파일을 추가해야 될건데 이럴경우 add를 이용해서 파일을 추가하면 된다.

# cvs add README
cvs server: scheduling file `README' for addition
cvs server: use 'cvs commit' to add this file permanently
				
이렇게 해서 파일을 추가하긴 했는데 이렇게 했다고해서 바로 파일이 cvs에 등록되지는 않는다. 반드시 commit 를 해서 파일이 프로젝트에 사용될것이라는것을 승인 시켜줘야 한다.

이제 다른 개발자가 cvs up을 하면 README파일이 추가된것을 확인할 수 있게 된다.

# cvs up
cvs server: Updating .
U README
				


3.2.8. 충돌의 해결

위의 경우는 "팀장"이 파일을 올리고, "팀원"이 파일을 받아서 수정하고 다시 파일을 올리는 과정을 밟고 있다. 그러나 하나의 프로젝트파일에 대해서 2명이 동시에 작업을 하다보면 충돌되는 경우가 생길수 있을것이다.

예를 들어서 "팀장"과 "팀원"이 동시에 같은 라인을 수정하고 있는데, 팀장이 먼저 commit 를 했다고 하자. 잠시 후에 팀원이 commit 하면, 같은 코드라인에 대해서 충돌이 일어나게 될것이다.

그렇지만 걱정할것 없다. cvs 가 알아서 자동적으로 관리해주기 때문이다. 팀원이 자신의 쏘쓰를 commit 하려고 하면 cvs 는 자동적으로 "코드라인에 충돌이 일어났음으로 먼저 update 를 하시오" 라는 메시지를 출력한다. 그래서 update 를 시키면 어느 부분이 충돌을 일으키는지 표시해준다.

다시 프로젝트 쏘쓰인 hello.c 로 돌아가서, 팀장이 다음과 같이 코드를 약간 수정했다고 가정하자.

#include <stdio.h>

int main(int argc, char **argv)
{
    printf("Hello World!!!!!\n");
}
				
그런데 그때 "팀원" 도 동일한 코드를 수정했다.
#include <stdio.h>

int main(int argc, char **argv)
{
    printf("Hello World??\n");
}
				
이상태에서 팀장이 commit 시키고, 잠시후에 팀원이 commit 시키려고 하면 다음과 같은 에러가 발생한다. (팀장은 아무 이상없이 commit 시킬수 있다)
[yundream@myhome hello_world]$ cvs commit -m hello.c
cvs commit: Examining .
cvs server: Up-to-date check failed for `hello.c'
cvs [server aborted]: correct above errors first!
				
이문제를 해결하기 위해서 먼저 update 명령을 이용해서 현재 CVS서버에 저장된 프로젝트 내용을 가져오도록 한다. 그러면 다음과 같은 메시지를 받아볼수 있을것이다.
# cvs up
cvs server: Updating .
RCS file: /home/cvs/hello_world/hello.c,v
retrieving revision 1.3
retrieving revision 1.4
Merging differences between 1.3 and 1.4 into hello.c
rcsmerge: warning: conflicts during merge
cvs server: conflicts found in hello.c
C hello.c
				
기존의 1.3 버젼과 지금 버젼의 프로젝트와 충돌이 생겼음을 알수 있다. 'C' 는 충돌(confilict)이 있음을 나타내는 단어이다. 이제 hello.c 쏘쓰를 보면 다음과 같이 충돌되는 부분을 표시해줄것이다.
#include <stdio.h>

int main(int main, char **argv)
{
<<<<<<< hello.c
    printf("Hello World!!!!!\n");
=======
    printf("Hello World??\n");
>>>>>>> 1.3
}
				
이럴경우는 팀장과 연락을 취해서(메일, 메신저, 전화로) 충돌되는 코드에 대해서 서로 조율해야 할것이다. 굳이 조율까지 할 필요 없이 그냥 팀장의 코드를 사용하기로 했다면 충돌된 부분을 팀장의 코드로 조정한다음에 commit시키면 된다.


3.2.9. 필요없는 파일지우기 : delete

쏘쓰파일중에 더이상 필요가 없어진 파일에 대해서는 delete 명령을 이용할수 있다. README 파일이 더이상 필요 없다면 우선 README 파일을 rm을 이용해서 지워주고.. delete한 후 commit시키면 된다.

# rm README
# cvs delete README
cvs server: scheduling `README' for removal
cvs server: use 'cvs commit' to remove this file permanently

# cvs commit -m "리드미 더이상 필요 없어서 삭제했음" README
Removing README;
/home/cvs/hello_world/README,v  <--  README
new revision: delete; previous revision: 1.1
done
				
이제 다른 프로젝트 개발자가 cvs up을 하면 다음과 같이 README가 삭제되었음을 확인할 수 있게 된다.
# cvs up
cvs server: Updating .
cvs server: README is no longer in the repository
				
이후 ls를 하면 실제 README파일이 지워져있음을 확인 할 수 있을 것이다. 그렇다면 어떤 악의적인 개발자가 중요한 파일을 지워버리면 잘못해서 해당 파일을 영원히 잃어 버리게 되는 사태가 발생하지 않을지 걱정이 될 수도 있을 것이다. 그러나 이 문제는 그리 크게 걱정할 필요가 없다. 해당 파일은 이미 다른 여러 개발자들이 가지고 있을 것이며, 설혹 그렇지 않다 하더라도 cvs 서버에는 파일이 보존이 되어 있기 때문에 언제든지 복구 가능하기 때문이다. 또한 누가 파일을 삭제 했는지 log를 통해서 쉽게 알아 낼 수 도있다.


3.2.10. 프로젝트를 완료했을때 : release

프로젝트를 완료했다면, release 옵션을 사용해서 프로젝트를 닫을수 있다. 프로젝트를 닫는다고 해서 저장소의 파일을 완전히 지우는 것은 아니다. 단지 저장소의 프로젝트에 어떠한 수정도 할수없는 상태다.


3.3. 효율적인 프로젝트 관리를 위한 CVS 사용법

CVS는 여러명의 개발자가 참여한다는 가정하게 사용되어 지므로 이를 효율적으로 프로젝트가 진행되도록 하기 위한 몇가지 지켜야할 사항이 있는데 이들에 대해서 알아보도록 하겠다.

아침에 와서 컴퓨터 앞에 앉았다면, 가장먼저 cvs up 을 이용해서 밤사이에 업데이트 된 내용이 있는지 확인을 한다. 그다음 작업에 들어간다. 공동작업을 할때 가장 중요한것은 상대편 작업자가 무슨일을 하고 있는지에 대해 알아야 하는 것이다. 습관적으로 cvs up을 해줘야 한다.

그리고 꽤 중요한 수정이 있었다고 하면 중간중간에 commit하도록 한다. commit할때도 우선 cvs up을 이용해서 수정사항이 있었는지 확인하도록 하고 당연하지만 반드시 컴파일이 되는지 확인한 후 commit 시켜야 한다.

CVS 를 제대로 사용하기 위해서는 CVS 저장소의 구성을 잘해놓아야 한다. 예를 들어 Project_A 란 프로젝트를 시작한다면 Project_A 란 디렉토리를 만들고 그 아래에 프로젝트에 필요한 각종 디렉토리, 즉 작업문서의 저장을 위한 doc 디렉토리, 실제 쏘쓰가 포함될 src 디렉토리, 인크루드 파일이 존재하게 될 src/include 디렉토리 등, 체계적으로 프로젝트를 관리할수 있도록 미리 저장소를 세팅해 놓아야한다. 물론 나중에라도 디렉토리를 추가할수도 있지만, 이왕이면 미리 프로젝트에 대한 계획을 잘 세워두는게 좋을것이다.

Project_A --+-- doc -+-- readme.txt
            |        | 
            |        +-- todo_list.txt
            |        |
            |        +-- schedule.xls 
            |
            +-- src --+-- Makefile
                      |  
                      +-- main.cc  
                      |  
                      +-- io.cc  
                      |  
                      +-- include --+-- io.h 
                      |             | 
                      |             +-- common.h 
                      +-- lib     --+-- crypt.a 
			
그리고 가능하면 모듈별로 쏘쓰코드를 나누고, 각 모듈별로 분담해서 개발을 하도록 하는게 프로젝트를 쉽게 관리 하는 방법이다. 그러면 개발자는 자신의 모듈만 신경쓰면서도, 전체의 프로젝트의 흐름에 유연하게 대처할수 있게 된다.


3.4. 기타 옵션

3.4.1. 디렉토리 upload하기

작업을 하다보면 디렉토리를 만들어서 cvs서버에 등록시켜야 하는 경우가 있다. 등록은 add와 commit를 이용해서 가능한데, 이를 upload하기 위해서는 -d 옵션을 이용해야 한다. -d 옵션을 사용하지 않을경우 일반 파일들만 upload하고 디렉토리는 upload 하지 않게 된다.

# cvs up -d
				


3.4.2. 바이너리 파일 추가하기

cvs는 일반텍스트로 이루어진 파일을 잘 관리하게끔 최적화 되어있다. 그러다 보니 바이너리 파일을 추가할경우 이를 텍스트로 인식해서 힘들게 추가했더니 파일이 깨지는 경우가 발생한다. 바이너리 파일은 다음과 같은 방법으로 추가하도록 하자.

# cvs add -kb filename.bin 
				


4. CVS 의 다른 활용들

필자는 개인 정보의 관리를 위해서 CVS 를 사용한다. 회사에서 일하다가 좋은 사이트를 찾았다거나, 중요한 메모 상황이 발생했다거나, 좋은 자료를 찾았을경우, 일정관리 까지 모두 CVS 로 저장해두고 집에 있건 회사에 있건 개인 자료를 공유할수 있도록 만들어 놓았다.

모질라의 북마킹 데이타를 CVS 로 연결시켜 놓았기 때문에, 집에 있건 회사에 있건 동일한 북마킹 데이타를 유지할수 있으며, 일정관리(Koraganizer 을 이용한다), 메모데이타(knotes) 역시 공유 가능하도록 해두어서 편하게 사용하고 있다.

이렇게 CVS를 사용함으로써 PDA, email, 노트북(돈이 좀 있어야 한다) 매체를 이용하지 않고도, 간단하게 데이타 동기화를 이루어 낼수 있다.


5. 결론

이상 CVS의 설치와 간단한 사용방법과 활용방법에 대해서 얘기 해보았다. 여기에 있는 내용은 CVS 의 많은 기능중 꼭 필요한 10% 정도의 내용만을 다루고 있다. CVS 사용에 대한 깊은 내용을 알기 원한다면 cvs 와 함께 배포되는 man 페이지를 활용하거나 CVS 이야기, CVS 사용 등의 문서를 참고하기 바란다.

'SVN/CVS' 카테고리의 다른 글

버전관리 시스템(#1 SVN 바로알기)  (0) 2010.01.04
SVN(Subversion)  (0) 2010.01.04
CVS(Concurrent Versions System)  (0) 2010.01.04
Posted by 인천총각
|

CVS는 RCS를 기반으로 작성된 버전 관리 시스템입니다. 쉽게 얘기하자면 RCS는 파일 하나하나에 대해 버전 관리를 해주는 것이고, CVS는 RCS 기능을 이용해 소스나 문서를 프로젝트/모듈 단위로 관리할 수 있도록 확장한 프로그램입니다. 이미 RCS를 쓰고 있고 익숙한 분이 아니라면 굳이 CVS를 새로 배울 필요는 없습니다. RCS로 할 수 있는 모든 것은 CVS로 할 수 있지만 그 역은 성립하지 않기 때문입니다.


형상관리(Software Configuration Management)

 

형상 관리는 하드웨어에서 출발하였지만…소스는 변경될 때마다 새로운 버전이 생성되고, 추가되고, 삭제되고, 소프트웨어 개발 시에 발생하는 모든 작업은 시스템에 영향을 미치게 되므로 시스템에 영향을 주는 모든 사건을 버전화하고 소스를 버전별로 관리하는 일이 형상관리( 버전 관리란 용어를 사용하기도 합니다.)


Source control system (version control system) – locking system을 이용해 엑세스를 직렬화함으로써 소스코드 액세르를 제어하는 것과, 모든 파일의 변경사항 히스토리를 저장함으로써 이전 버전을 다시 불러와 구성할수 있게 하는 것


Pessimistic locking – 한번에 한사람만이 수정가능한 파일 사본을 가져올 수 있다, 수정 권한을 확보한 사람이 변경한 코드를 체크인해서 제어권을 넘겨주기 전까지는 어느 누구도 수정가능한 사본을 얻을 수 없으며, 읽기 전용 사본을 가져오는 것은 가능하다.


Optimistic locking사용자는 언제든 파일을 가져와 수정할 수 있다. 파일을 repository에 다시 체크인하면 버전 컨트롤 소프트웨어는 체크인하지 않은 다른 사람의 변경사항과 충돌이 일어나지 않도록 한다. 버전 컨트롤 시스템은 자동으로 변경사항을 병합할 수 있을 경우 병합하고 그렇지 않으면 직접 충돌을 해결해야 한다고 경고한다.


수정병합(Copy Modify Merge) - 소스를 복사하여 수정한 후에 병합이 가능한 구조로 동시에 하나의 파일을 가지고 작업하고 나중에 충돌되는 부분은 확인해가며 작업자간의 의견을 조율하여 소스에 반영하는 방식이다.(CVS, Subversion)


Lock Reservation – 작업을 하는 사용자가 잠금(lock)을 걸어놓고 작업하는 방식으로 잠금이 걸린 문서나 파일은 다른 사람의 열람은 가능하지만 수정하여 반영할 수는 없다. (Vusual SourceSafe, IBM Rational사의 ClearCase)


• Eclipse에 통합된 소스 컨트롤 툴 CVS(Concurrent Versions System)은 낙관적 잠금을 지원하며 수정병합 방식을 채택한 시스템이다.


CVS(Concurrent Versions System)는 오픈 소스 프로그램으로 WinCVS와 TortoiseCVS등의 클라이언트 프로그램이 존재하고, 이클립스, NetBeans, JBuilder, Idea(inteliJ)등의 개발 툴에 기본으로 통합되어 있다.


• CVS는 혼자하는 개발, 팀을 이루는 개발, 다국적 개발등에 유용하며 클라이언트 서버 구조로 잠금 상태를 예약하지 않는 수정병합 방식으로 같은 소스의 동시 작업이 가능하다


[CVS 기능]

• History 기능 – 소스파일이 추가되고, 수정되고 삭제되었던 모든 History가 CVS 서버에 기록되며 작업 완료 시에 작업 내용을 기록에 남길 수 있다.

• 변경사항 저장 – 파일의 모든 버전을 파일로 저장하는 대신 CVS는 버전간의 변경사항만을 저장하므로 백업 용량을 적게 차지한다.

• 병합 기능 – 각 개발자가 작업을 끝마쳤을 때, 그 작업을 병합시켜줌으로써, 팀원이 하나의 공동 프로젝트를 수행하고자 할 때 도움을 준다.

• branch 기능 – 개발의 주된 흐름인 메인 줄기(trunk)의 특정 진행 시점에서 갈라져 나와 개발을 추가하거나 변경된 가지(branch)에서 소스를 변경해도 메인 줄기에는 영향을 미치지 않는다.

• tag 기능 – 개발의 특정 시점에 버전을 따는 기능으로 개발이 빌드되거나 릴리즈되는 특정 시점에서 태그를 달고, 개발을 진행해 나간다.(특정 태그가 달린 소스를 찾아서 해당 태그의 모듈을 구할 수 있다)

• diff 기능 - 버전과 버전, 태그와 태그간에 소스의 차이점을 비교해준다.


[CVS 작업 사이클]

• 프로젝트 생성

프로젝트를 생성하고, 프로젝트 매니저나 리드 개발자가 CVS 서버에 프로젝트 저장소를 만든다.(init)

초기 버전에 대한 소스나 문서, 파일 등을 서버에 올린다.(CVS 서버에 모듈을 import)

• 프로젝트 진행

팀에 속한 모든 개발자는 import된 프로젝트 모듈을 다운로드하고(Checkout), 모듈의 소스를 추가(add), 삭제(remove), 커밋(commit), 변경(update) 중에 충돌(conflict)된 것은 합병(merge)하는 등 프로젝트를 진행한다.

일정시점이나 릴리즈 시에는 tag나 branch를 정해서 태그를 붙인다.


[CVS 내에서 사용되는 용어]

• repository – CVS를 통해서 작업하는 소스, 문서 등 작업용 파일이 저장되는 서버상의 공간

• revision – 각 파일별로 commit 할 때마다 자동으로 더해지는 버전으로 CVS가 관리하는 번호로 뒤로 돌리거나, 임의로 수정할 수 없다.

• init – 저장소를 초기화하는 명령어로 프로젝트를 시작할 때 한번만 실행

• module – 하나의 저장소에 구분되어 저장되는 단위.(작은 프로젝트의 경우 하나의 모듈, 큰 프로젝트의 경우에는 컴포넌트별로 모듈을 나누거나 버전별로 나누기도 함)

• import – 하나의 모듈을 서버에 저장하늠 명령어

• checkout – 서버에 저장한 모듈 하나를 통째로 로컬에 가져오는 명령어

• update – 파일이나 디렉토리를 지정하여 최신 것이나 특정 리비전, 특정 날짜의 것을 서버에서 로컬로 가져오는 명령어

• add – 새로운 파일을 디렉토리에 추가했음을 서버에 알리는 명령어.(파일은 commit하기 전까지는 서버에 반영되지 않는다.)

• remove – 파일 삭제했음을 서버에 알리는 명령어 (commit하기 전까지는 서버에서 지워지지 않는다.)

• commit – add, remove를 마치고 서버에 반영한다는 의미의 명령어

• tag – 특정 날짜나 릴리즈 시에 태그를 붙임으로써 나중에 해당 릴리즈의 리비전으로만 가져올 수 있게 한다.

• branch – 일부분 혹은 전체에서 소스를 별도로 관리해야 되는 부분이 생길 때 사용 (리비전의 깊이가 달라진다(예:1.1 > 1.1.2.1)
--------------------------------------------------------------------------------------------------------
CVS에서 유용하게 사용되는 변화 추적(Change-tracking)

CVS(Concurrent Versioning System)는 파일의 동시 개발을 관리한다. 파일을 중앙 저장소(repository)에 저장하고, 사용자는 파일 복사본을 받아서 작업하고 변경된 것을 다시 저장소로 보내기 때문이다.

CVS는 각 파일의 변경 기록을 관리하고, 사용자들이 이전 버전으로 복귀, 병합하거나 변경사항을 추적할 수 있게 해준다. 이 변화 추적(Change-tracking) 기능은 아주 유용하기 때문에 자주 사용될 것이다.

본 기사는 CVS 소개CVS 관리라는 두 기사를 바탕으로 작성되었다. 두 기사에서 이미 논의한 바 있는 특정 내용에 대한 언급이 있겠지만 이 기사에서 다시 자세히 설명하는 것은 생략하기로 하겠다.

annotate

anontate는 저장소에 저장된 파일의 각 라인에서 가장 마지막으로 변경된 내용을 보여주는 cvs 명령어이다. 각각의 라인에 대해 이 명령어는 라인의 내용, 날짜, 사용자, 가장 마지막으로 변경된 라인에 대한 변경 번호를 보여준다. 따라서 언제, 누가, 무엇을 변경했는지 알 수 있는 빠른 방법이라고 할 수 있다.

annotate는 현재 작업 중인 디렉토리에서가 아니라 저장소에서 파일 데이터를 출력하므로, 아직 커밋(commit)되지 않은 변경 내용은 보이지 않는다.

cvs annotate의 옵션은 다음과 같다.

-f

일치하는 태그나 데이터가 그 파일에서 발견되지 않는다고 하더라도 (최신 변경 정보를 사용하여) 파일을 보여준다.

-l

현재 디렉토리만 확인하고 하위 디렉토리는 확인하지 않는다.

-R

하위 디렉토리를 확인한다(기본값).

-D date

지정된 날짜를 기준으로 가장 최근에 변경된 내용을 보여준다.

-r tag

태그(꼬리표)로 구분할 수 있는 변경된 내용을 출력한다.

Example 1

$ cvs annotate test.html
Annotations for test.html
***************
1.1 (jenn 30-Apr-02): <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
1.1 (jenn 30-Apr-02): "http://www.w3.org/TR/html4/strict.dtd">
1.1 (jenn 30-Apr-02): <html>
1.1 (jenn 30-Apr-02): <head>
1.4 (jenn 04-May-02): <title>Sample Article</title>
1.1 (jenn 30-Apr-02): </head>
1.1 (jenn 30-Apr-02): <body>
1.4 (jenn 04-May-02): <h1>Sample Article</h1>
1.1 (jenn 30-Apr-02): <p>
1.11 (jenn 07-May-02): Body text for the sample article.
1.1 (jenn 30-Apr-02): </p>

CVS Pocket Reference

참고 도서

CVS Pocket Reference
Gregor N. Purdy


diff

cvs diff는 한 파일의 두 가지의 다른 변경된 내용을 비교하여 차이점을 보여주는 명령어이다. cvs diff의 출력된 내용(output)은 표준 diff 명령어의 출력 내용과 매우 유사하다. cvs rdiff는 표준 patch 명령어를 사용하여 설치될 수 있는 패치 파일을 만드는데 사용된다.

대개 cvs diff는 적어도 하나 이상의 -r tag 파라미터(parameter)와 함께 사용된다. 만약 단일 태그와 함께 호출된다면 작업중인 디렉토리에 있는 현재 복사본은 저장소에 있는 버전과 비교된다. cvs log 명령어는 cvs diff의 파라미터로 사용될 수 있는 변경 번호를 보여준다.

Example 2

$ cvs diff -r 1.11 cvs_changes.html
Index: cvs_changes.html
===================================================================
RCS file: /home/cvs/oreilly/articles/cvs/cvs_changes.html,v
retrieving revision 1.11
diff -r1.11 cvs_changes.html
64a65
&gt; The command &lt;code&gt;cvs diff&lt;/code&gt; compares two 
revisions of a file and displays the differences.
66a68
&gt; &lt;code&gt;cvs diff&lt;/code&gt; is usually called with at 
least one &lt;code&gt;-r &lt;var&gt;tag&lt;/var&gt;&lt;/code&gt; parameter.
71a74

history

대부분의 CVS 기능과는 달리,
cvs history 는 디폴트로 셋업되지 않는다. 셋업하려면 저장소의 CVSROOT 디렉토리 안에 history 라는 파일을 생성해야 한다. CVS 사용자는 (또는 서버에서 CVS를 실행할 수 있는 사용자는 모두) 그 파일을 작성할 수 있어야 한다.

Example 3

(on the cvs repository server)
$ cd /home/cvs/CVSROOT
$ touch history
$ chmod g+w history
$ ls -la
drwxrwsr-x    4 root     src          1024 May 16 01:04 .
drwxrwsr-x   35 root     src          1024 Mar 20 18:01 ..
drwxrwsr-x    2 root     src          1024 Sep  7  2001 Attic
-rw-rw-r--    1 root     src             0 May 16 01:04 history
-r--r--r--    1 root     src           403 Sep 26  2001 loginfo

파일을 커밋하고 cvs history -c filename 실행해서 history 파일을 테스트하자(-c 플래그는 CVS 커밋을 표시함). CVS는 history 파일이 생성된 후로 하나의 커밋된 내용을 보여주는 라인을 하나 표시할 것이다.

Example 4

$ cvs history -c test.html
M 2002-05-15 15:04 +0000 jenn 1.2 test.html oreilly/articles/cvs ==  $ 

일단 셋업되면 cvs history는 저장소에 있는 파일과 모듈의 히스토리를 보여주는데 사용될 수 있다. 파일과 모듈 선택은 현재 작업 디렉토리 내에 있는 모듈들, 모듈, 특정 파일이나 파일들을 포함한다.

history 파일은 저장소 안에 저장된 파일의 커밋, 병합, 충돌, 태그(꼬리표), (작업 디렉토리에)업데이트, 추가, 삭제, 변경 등을 기록한다. 이들 각각은
cvs history 명령어로 소환되거나 표시될 수 있다.

cvs history는 사용자 요구 정보, 모든 사용자 또는 현재 작업 중인 복사본의 데이터를 표시할 것이다. 넓게 분포되어 작업하는 팀들을 위해 지정된 시간대에 맞게 시간을 표시하는 옵션을 가지고 있다.

Example 5

$ cvs history -e -w -z EST test.html
M 2002-05-15 10:04 EST jenn 1.2 test.html oreilly/articles/cvs == <remote>
M 2002-05-15 10:41 EST jenn 1.3 test.html oreilly/articles/cvs == <remote>

예제5에서 -e 는 커밋과 업데이트의 모든 타입를 표시하도록 하고, -w 는 현재 작업중인 디렉토리에서 유래하거나 영향을 받은 변경 내용만 표시하도록 한다. 그리고 -z EST는 동부 표준시간대(EST)로 표시하도록 하기 위해 시간대를 설정한다.

log

cvs log 명령어는 인자로 전달되는 파일(들)에 대한 정보를 표시한다. 만약 파일이 전달되지 않는다면 현재 작업 디렉토리와 그 하위 디렉토리의 모든 파일들에 대한 로그 정보를 표시한다.

cvs log를 위한 옵션은 보여주는 정보의 양을 줄인다. 디폴트로 log는 가지고 있는 모든 정보를 보여준다.

Example 6

$ cvs log cvs_changes.html

RCS file: /home/cvs/oreilly/articles/cvs/cvs_changes.html,v
Working file: cvs_changes.html
head: 1.3
branch:
locks: strict
access list:
symbolic names:
keyword substitution: kv
total revisions: 3;     selected revisions: 3
description:
----------------------------
revision 1.3
date: 2002/05/15 15:41:54;  author: jenn;  state: Exp;  lines: +53 -0
history mostly done. needs example.
----------------------------
revision 1.2
date: 2002/05/15 15:04:47;  author: jenn;  state: Exp;  lines: +8 -2
Adding a history file
----------------------------
revision 1.1
date: 2002/05/15 14:54:54;  author: jenn;  state: Exp;
Initial entry for both files. Also includes cvs annotate for changes.
====================================================================

예제6은 본 기사에 대한 초기 로그 히스토리를 보여준다.

Revision 1.1은 내가 두 개의 파일을 만들고 그 빈 템플릿을 체크인(check-in)하는 것을 잊어버리고 본 기사의 주석 부분을 커밋하기 위해 노력할 때 발생하였다.

사용자 정의 로깅

CVS는 확실하다고 생각하는 행동이 일어났을 때 호출되는 스크립트를 정의하는 커스터마이즈된 파일들을 가지고 있다.
loginfo(로그정보), 모듈들과 taginfo(태그정보) 파일은 로깅 스크립트들을 호출하기 위해 사용될 수 있다.

이런 파일들은 CVS 저장소의 CVSROOT 디렉토리에서 찾을 수 있고, 그곳에서 형성된다. 그 파일들은 호스트 컴퓨터에서 실행하지만 몇몇 모듈 스크립트들은 클라이언트 머신에서 실행된다. 더 자세한 내용은 다음을 참고하기 바란다.

CVSROOT 모듈 내에 있는 파일들을 편집할 때에는 CVS를 이용하라. 모든 파일을 체크아웃(† 역자 주: checkout, 가져오다)하기 위해서는 단순히
cvs -d repository checkout CVSROOT만 실행하면 된다.

loginfo와 taginfo

loginfo 파일은 cvs commit을 위한 로그 정보를 어디로 보내야 할지를 통제한다. 프로젝트 리더가 팀이 만든 변경된 내용을 유지하고 프로젝트의 진행상의 주요한 로그를 유지하는데 사용할 수 있다.

taginfotagrtag 명령어를 위한 것이지만 loginfo도 마찬가지로 사용된다. taginfologinfo와 같은 문법을 가지고 있다.

파일의 각 라인은 디렉토리에 적합한 정규 표현식을 포함해야 한다. 이 디렉토리는 스크립트 주소순으로 표준입력(stdin)과 같은 로그 정보를 예상한다.

특수한 라인들은 'ALL'과 'DEFAULT'로 시작한다. ALL은 적용되는 다른 라인들을 누적하여 실행한다. 만약 그렇지 않으면 처음으로 짝지워진 정규 표현식만 실행되고 나머지 짝지워지지 않은 것들은 DEFAULT로 된다.

예제7의
loginfo 파일은 logscript 스크립트를 통해 커밋되는 모든 것을 로그로 남길 것이다. 그리고 $CVSROOT/oreilly 디렉토리 내의 어떠한 파일이 커밋될 않을 경우, cvsscript를 실행하고 cvsadmin으로 다른 커밋을 메일로 보낼 것이다.

Example 7

ALL /usr/local/bin/logscript
^oreilly /home/jenn/scripts/cvsscript
DEFAULT Mail -s "CVS commit" cvsadmin

modules

CVSROOT/modules 파일은 각각의 모듈과 이들의 디렉토리, 파일들을 기록한다. 그 파일(CVSROOT/modules)은 또한 옵션들을 사용한다. 몇몇 옵션들은 CVS 동작이 발생할 때 실행되는 스크립트들이다.

-e script

모듈이 익스포트(export)되었을 때 script를 실행한다.

-i script

모듈이 커밋 되었을 때 실행한다.

-o script

모듈이 체크아웃 되었을 때 실행한다.

-u script

모듈이 업데이트(갱신) 되었을 때 실행한다.

-t script

rtag가 모듈에 사용되었을 때 실행한다. 이것은 tag가 사용되었을 때는 실행되지 않는다. taginfo 파일이 태그의 로그를 남기는 더 좋은 방법이다.



만약 이 파일(CVSROOT/modules)을 변경하고 싶다면 CVS 매뉴얼과 정보 파일을 읽어보기 바란다. CVS는 사용자가 모듈과 상호작용을 할 때 항상 이 파일을 사용한다.

커밋이나 업데이트를 할 때 호출되는 스크립트들은 로컬 머신에서 실행되고, 나머지 스크립트들은 서버에서 실행된다.

예제8은 oreilly 모듈이 oreilly 디렉토리에서 체크아웃될 때 /home/jenn/scripts/cvsscript를 실행하려 한다. 이것 또한 특별한 옵션 없이 CVSROOT 모듈을 정의한다.

Example 8

CVSROOT CVSROOT
oreilly -o /home/jenn/scripts/cvsscript oreilly

마지막으로

Change-tracking(변화 추적)은 CVS의 유용한 부분임에도 불구하고 현장에서 사용하는 것을 거의 보지 못했다. 처음으로 CVS를 사용하기 시작했을 때 변화 추적의 특징을 발견하고 순간 "내가 왜 전에는 이것을 사용하지 않았을까?"라고 생각하였다.

여러분도 한 번씩 해보기 바란다. 그리고 내가 그랬던 것처럼 이것의 유용한 점을 발견하길 바란다.

'SVN/CVS' 카테고리의 다른 글

버전관리 시스템(#1 SVN 바로알기)  (0) 2010.01.04
SVN(Subversion)  (0) 2010.01.04
CVS-개념 및 리눅스 서버 설치  (0) 2010.01.04
Posted by 인천총각
|

■ 기본 커맨드 패턴

1. 커맨드 객체는 특정 객체에 대한 특정 작업 요청을 함께 캡슐화한다.


[그림] 커맨드 객체 구조

실제로, 요청을 처리하는 리시버(receiver)에 대한 참조와 Execute() 메소드를 가지고 있다. Execute()에서는 리시버의 메소드를 호출함으로써 필요에 따라서는 일련의 메소드를 복수해 호출해서 비즈니스 요청을 수행한다. 커맨드 객체를 호출하는 측에서는 단지 Execute() 메소드만 호출하면 된다. 그 커맨드가 구체적으로 Execute()를 어떻게 구현하는지는 알 필요가 없다.

2. 작업을 요청하는 쪽(리모콘)과 작업을 하는 쪽(TV, CD 플레이어)을 커맨드 객체를 통해서 분리할 수 있다.

3. 캡슐화시 매개변수를 써서 여러 가지 다른 요구사항을 집어넣을 수도 있다.

ConcreteCommand(매개변수);

4. 커맨드 패턴을 사용하면 요청 내역을 큐에 저장해서 스케쥴러, 작업큐같은 프로그램을 만들거나 또는 작업 내역을 스택성 로그로 기록해서 도중에 에러가 발생하면 롤백하는 구조의 프로그램을 만들 수도 있다. 이것을 좀더 정교하게 만들면 트랜잭션 시스템을 구현하는 것도 가능하다.

레퍼런스

Head First Design Patterns 스토리가 있는 패턴 학습법

-Oreilly, 한빛 미디어

■ 커맨드 패턴 변형

앞에서는 커맨드 객체가 리시버(Receiver)에 대한 참조와 그 리시버를 이용해서 요청을 구현해야 하는 Execute()가 있어야 한다. 이런 경우는 리시버에 대한 참조를 가지고 있어야 한다는 점에서 리시버와 커맨드 객체와의 커플링이 존재하게 된다. 이런 커플링을 없애기 위해서 때로는 리시버와 Execute() 대신에 단일 이벤트 멤버로 대신할 수 있다.


[그림] 커맨드 객체

1. One handler : 하나의 이벤트 핸들러에서 여러 UI 이벤트(메뉴, 툴바)를 핸들링할 수 있다.

2. the business logic for handling the command : 그 하나의 이벤트 핸들러에 해당 명령을 핸들링할 수 있는 비즈니스 로직을 중앙 관리할 수 있다.

■ 커맨드 패턴 구현의 핵심 요소

커맨드 관리자

- 애플리케이션에서 필요로 하는 모든 커맨드들의 중앙 저장소

- 애플리케이션이 커맨드 목록을 관리할 수 있는 컬렉션용 API를 제공.

레퍼런스

Command Management
--------------------------------------------------------------------------------------------------------

Command Pattern

메소드 호출을 캡슐화 하는 패턴이다. 메소드 호출을 캡슐화하면 계산 과정의 각 부분들을 결정화 시킬 수 있기 때문에 계산하는 코드를 호출한 객체에서는 어떤 식으로 일을 처리해야 하는 지에 대해서 전혀 신경 쓰지 않아도 된다.

 

 

1.     Command Pattern의 정의

커맨드 패턴을 이용하면 요구 사항을 객체로 캡슐화 할 수 있으며, 매개변수를 써서 여러 가지 다른 요구 사항을 집어넣을 수도 있다. 또한 요청한 내역을 큐에 저장하거나 로그로 기록할 수도 있으며, 작업 취소 기능도 지원 가능하다,

 

2.     Command Pattern의 특성

커맨드 패턴을 사용하면 어떤 작업을 요청한 쪽하고 그 작업을 처리한 쪽을 분리시킬 수 있다. 커맨드 객체는 특정 객체에 대한 특정 작업 요청을 캡슐화한다. 커맨드 객체는 일련의 행동을 특정 리시버하고 연결시킴으로써 요구 사항을 캡슐화한 것이다. 행동과 리시버를 한 rorrorc 집어넣고, excute()라는 메소드 하나만 외부에 공개하여 이 메소드 호출에 의해서 리시버에서 일련의 작업이 처리된다. 외부에서 볼 때는 어떤 객체가 리시버 역할을 하는지, 그 리시버로 실제로 어떤 일을 하는지 알 수 없다. Excute()메소드를 호출하면 요구 사항이 처리된다는 것만 알 수 있을 뿐이다. 커맨드를 확장해서 여러 개의 커맨드를 한꺼번에 호출할 수 있게 해주는 매크로 커맨드 패턴도 있다.

 

3.     Command Pattern의 클래스 다이어그램



 

4.     Command Pattern의 구성

A.     클라이언트는 ConcreteCommand를 생성하고 Receiver를 설정한다.

B.     Invoker에는 명령이 들어있으며, execute()메소드를 호출함으로써 커맨드 객체에게 특정 작업을 수행해 달라는 요청을 하게 된다.

C.     Command는 모든 커맨드 객체에서 구현해야 하는 인터페이스 이다. 모든 명령은 execute()메소드 호출을 통해서 수행되며, 이 메소드에서는 리시버에 특정 작업을 처리하라는 지시를 전달한다.

D.     Execute() 메소드에서는 리시버에 있는 메소드를 호출하여 요청된 작업을 수행한다.

E.      Receiver는 요구사항을 수행하기 위해 어떤 일을 처리해야 하는지 알고 있는 객체이다.

F.      ConcreteCommand는 특정행동과 리시버 사이를 연결 해준다.

 

5.     Command Pattern의 장단점

커맨드 패턴은 작업을 요청하는 객체와 실제 작업을 수행하는 객체를 분리시켜주므로 시스템의 결합도가 낮아질 수 있으며, 두 객체가 독립적으로 변경 가능한 장점을 가진다. 커맨드 및 그 하위 클래스는 기존 클래스와 무관하게 확장이 가능하며, 확장된 클래스들은 클라이언트의 별다른 수정 없이 사용이 가능하다. Macro Command처럼 커맨드패턴에 컴포지트 패턴을 복합해서 적용할 경우 복잡한 작업을 기본적인 작업들로 구조화시켜 다룰 수 있는 장점이 있다
----------------------------------------------------------------------------------------------------

커맨드패턴
 
메소드의 호출을 캡슐화 한다는 것이 핵심입니다.
메소드 호출을 캡슐화하면 계산과정의 각 부분들을 결정화시킬수 있기 때문에 계산하는 코드를 호출한 객체에서는 어떤식으로 처리해야하는지에 대해 전혀 신경 쓰지 않아도 됩니다.
 
* 클라이언트는 ConcreateCommand를 생성하고 Receiver 를 설정합니다.
* Invoker 에는 명령이 들어 있으며 , execute() 메소드를 호출함으로써 커맨드 객체에게 특정 잡업을 수행해 달라는 요구
  를 하게 됩니다.
* Command 는 커맨드 객체에서 구현해야하는 인터페이스입니다.
* Receiver 는 요구사항을 수행하기 위해 어떤일을 처리해야 하는지 알고 있는 객체입니다.
* ConcreteCommand 는 특정행동과 리시버 사이를 연결해 줍니다. 인보커에서 execute() 호출을 통해 요청하면
  ConcreteCommand객체에서 리시버에 있는 메소드를 호출함으로써 그 작업을 처리합니다.
 
 
예제를 보면서 설명하겠습니다..
다음 코드는 전등을 켜는 리모콘을 생성하여 처리하는 과정을 보여줍니다.
 
우선은 커맨트 인터페이스를 생성합니다. 당연히 execute()메소드를 정의합니다.

 Command.java
 

public interface Command {
 public void execute();
}

 

 실제 작업을 정의한 Receiver 객체입니다. 

 Light.java
 

public class Light {
 
 public void on()
 {
  System.out.println("불 켜다");
 }
 public void off()
 {
  System.out.println("불 끄다");
 }

}

 

 실제작업을 실행할 커맨드 클래스 ConcreteCommand 를 구현한다. 

 LightOnCommand.java
 

public class LightOnCommand implements Command {
 
 Light light;
 
 public LightOnCommand(Light light)
 {
  this.light = light;

 // 생성자에서 이 커맨드 객체를 제어할 특정 정보를 전달합니다..그 객체는 light라는 인스턴스 변수에 저장되고

 // execute() 메소드가 호출되면 light 객체가 바로 그 요청에 대한 리시버가 됩니다.
 }

 public void execute() {
  light.on();
 }

}

 

버튼이 하나 밖에 없는 리모콘을 만들어 보면. 다음과 같다.

 SimpleRemoteControl.java
 

public class SimpleRemoteControl {
 Command slot;
  // 커맨드를 집어넣을 슬롯이 하나 밖에 없습니다. 이걸가지고 장비를 제어합니다.
 public SimpleRemoteControl() {}
 

 

// 슬롯을 가지고 제어할 명령을 설정하기 위한 메소드
 public void setCommand(Command command)
 {
  slot = command;
 }
 
 public void buttonWasPressed()
 {
  slot.execute();
 }
}

 

자 이제 테스트클래스를 만들고 실행해보자.

 RemoteControlTest.java
 

public class RemoteControlTest {

 public static void main(String[] args) {
  
  SimpleRemoteControl remote = new SimpleRemoteControl();

//remote 변수가 인보커(invoker)역할을 합니다.

//필요한 작업을 요청할 때 사용할 커맨드 객체를 인자로 전달 받는다.


  Light light = new Light();

//리시버 객체를 생성


  LightOnCommand lightOn = new LightOnCommand(light);

//커맨드 객체를 생성합니다. 이때 리시버를 전달합니다.
  
  remote.setCommand(lightOn);

//커맨드 객체를 인보커한테 전달합니다.
  remote.buttonWasPressed();


 }

}

 

 

커맨드 객체는 일련의 행동을 특정 리시버하고 연결시킴으로써 요구사항을 캡슐화한다.

이렇게 하기 위해서 행동과 리시버를 한 객체에 집어 넣고, execute() 라는 메소드 하나만 외부에 공개하는 방법을 사용한다. 메소드 호출에 의해서 리시버에서 일련의 작업이 처리된다. 외부에서 볼때는 어떤 객체가 리시버 역할을 하는지 그 리시버에서 실제로 어떤 일을 하는지 알 수 없습니다. 다만 execute()메소드를 호출하면 요구사항이 처리 된다는 것만 알수 있다.

 

정리하자면

커맨드 패턴을 사용하면 요청하는 객체와 그 요청을 분리시킬수 있다.

이렇게 분리시키는 과정의 중심에는 커맨드객체가 있으며 이객체가 행동이 들어있는 리시버를 캡슐화 한다.

인보커에서는 요청을 할때는 커맨드 객체의 execute()메소드만 호출하면 된다.

execute() 메소드에서는 리시버에 있는 행동을 호출한다.

 

적용예

스트러츠1.0 에서 Action클래스의 execute 메소드가 있다.

 

정의

요청내역을 객체로 캡슐화하여 클라이언트를 서로 다른 요청에 따라 매개변수화 할 수 있습니다.

Posted by 인천총각
|

APPLET 이란???

Applet 2009. 12. 29. 13:07

APPLET 이란 ?

▷ Applet은 HTML 페이지에 내장되어 Web Browser의해 download되고 수행된다.
    Applet의 수행은 application의 수행과 분명히 구분된다.
    Application은 main()문 부터 수행이 되지만, applet은 수행의 시작을 비롯한 life cycle이 좀 더 복잡하다.

Applet Security Restrictions(애플릿의 보안)

▷ applet은 다른 곳에 떨어져 있는 사이트에서 load되어 local에서 실행되도록 설계되었기 때문에 보안이 중요하다.
   만약 내 컴퓨터에 중요한 정보가 있었다면 그것을 몰래 가져갈 수도 있을 것이다. 

▷ Web browser Security Manager는 applet이 접근 규칙을 위반할 경우 SecurityException이 발생한다.

▷ 대부분의 applet에 적용되는 보안은 browser 수준에서 이루어지는데, 아래와 같은 작업을 제한하고 있다.

  -Local system상의 다른 프로그램의 수행.
  -File I/O
  -Native method 호출
  -Applet이 다운로드된 host이외의 host에 대한 소켓(socket)연결

JDK1.2에서는 URL단위로 보안을 설정할 수 있고, 보안 정책을 따로 둘 수가 있다.

Writing an Applet
Applet은 다음과 같은 형식으로 class가 만들어진다.

예)     import java.applet.*;
        public class HelloWorld extends Applet {

Applet은 반드시 public class로 되어야 하며, file의 이름이 class의 이름과 같아야 한다.
(html 파일이름은 달라도 된다.)

Applet Class Hierarchy
Applet class는 Panel class의 subclass이다. 때문에 applet은 flowlayout을 기본 layout으로 한다.

java.lang.Object

|

+--java.awt.Component

|

+--java.awt.Container

|

+--java.awt.Panel

|

+--java.applet.Applet

주요 Applet Methods

public class Simple extends java.applet.Applet {

. . .

public void init()

{ . . . }/* 애플릿이 로드되거나 재로드될 때 처음으로 수행되는 코드 */

public void start()

{ . . . }/* 애플릿이 로드되거나 사용자가 재방문했을 때 수행되는 코드 */

public void stop()

{ . . . }/* 애플릿이 있는 페이지를 떠나거나 브라우저를 중지했을 때 수행되는 코드 */

public void destroy()

{ . . . }/* 로드를 취소하였을 때(cleanup) 수행되는 코드 */

}

▷ init() - 한번만 호출된다. 애플릿이 처음 생성되고 브라우저에 load될 때 호출되는 메소드이다. 이 메소드는 애플릿에 필요한 초기화를 제공한다. 이 메소드는 생성자와 비슷하게 동작하여 자바가 애플릿을 처음 로드할때에 자동적으로 시스템에 의해 호출된다. 보통 PARAM 값을 처리하고 사용자 인터페이스를 추가한다.

▷ start() - init() 이후에 애플릿이 동작하기 시작할 때 구동되는 메소드이다. init() 메소드가 호출된 후에 자동적으로 호출된다. 그리고 사용자가 다른 페이지로부터 이 애플릿을 포함한 페이지로다시 돌아올 때마다 호출된다. 이것은 start 메소드가 init 메소드와는 달리 반복적으로 호출된다는 것을 의미한다. 그러므로 단 한번만 실행되어야 할 코드는 init 메소드에 넣어야 한다.

▷ stop() - 애플릿이 동작을 멈출 때 구동된다. 다른 URL로 접속된 경우에 호출된다. 즉, 이 메소드는 사용자가 애플릿이 있는 현재의 페이지를 나오면 자동적으로 실행된다. 그러므로, 동일한 애플릿에 대해 반복적으로 호출된다. 그 목적은 사용자가 애플릿에 관심을 두지 않을 때 시스템 속도를 저하시키는 시간 소모적인 활동을 하지 않도록 하는 기회를 제공하는 것이다.

▷ destroy() - 브라우저가 정상적으로 종료될 때에 이 메소드를 호출하도록 되어 있다. 애플릿은 HTML 파일 내부에 있도록 되어 있으므로, 이 메소드는 브라우저가 종료될때에 자동적으로 일어난다. destroy 메소드에 집어넣어야 할 것은 사용자가 소비한 윈도우 핸들러와 같은 비 메모리 의존 자원을 회수하는 코드이다. 물론, 만일 애플릿이 여전히 활동하고 있다면, 자바는 destroy 메소드를 호출하기 전에 stop 메소드를 호출한다.

Applet Display

▷ Applet은 그래픽하게 나타난다. System.out.println()은 사용할 수 없다. 대신 paint() method를 사용하여 applet's panel에 원하는 것을 그릴 수 있다. paint() method는 browser에 의해서 applet의 display가 새로고쳐질 필요가 있을 때마다 호출되어야 한다.(repaint())

Applet Painting

▷ Applet에서 painting을 하기위해서 호출되어지는 method이다. 그리고, 아래와 같은 Cycle에서 의해서 applet이 보여진다.

▶ paint(Graphics g)

▶ repaint()

▶ update(Graphics g)

Applet Attribute

▷ Appelt attribute의 예

<applet

[archive=archiveList]

code = appletfile.class

width=pixels height=pixels

[codebase=codebaseURL]

[alt=alternateText]

[name=appletInstanceName]

[align=alignment]

[vspace=pixels]

[hspace=pixels] >

[<param name =appletAttribute1 value=value>]

[<param name =appletAttribute2 value=value>]

[alternateHTML]

</applet>

▷ 위치에 관련된 applet attribute

▶ width , height - 이 속성은 반드시 해야 하며, applet의 폭과 높이를 픽셀 단위로 준다. appletviewer의 경우, 이것은 applet의 초기크기이다.

▶ align - 이 속성은 applet의 정렬방식을 지정한다. 기본적으로 두가지가 있다.

애플릿이 블록(block)인 경우 텍스트는 applet 주위에, 애플릿이 인라인(inline)인 경우에는 확대된 텍스트 문자인 것처럼 보이게된다.

▷ 코딩을 위한 applet attribute

▶ CODE - 이 태그에는 클래스 파일의 이름을 쓴다. 이 이름은 현재 HTML이 있는 곳으로부터 상대적인 값으로 취해진다.
                  이것은 local 디렉토리이거나 네트웍 URL이 될 수 있고 절대 경로 이름도 사용될 수 있다. 즉 C:/a.html

▶ CODEBASE - 이 속성은 선택적으로 사용할 수 있다. 현재 HTML문서가 위치한 디렉토리의 아래의 CODEBASE의 tag값에서 클래스 파일을 찾을 수 있음을 브라우저에 알린다. 예를 들어 아래의 코드는 MyWork/java/samples/HelloWorld.class의 바이트 코드를 읽어온다.

<applet code=HelloWorld codebase=MyWork/java/samples width=100 height=100>

▶ Archive

- 자바 1.1에서는 여러 파일을 압축하여 한번에 다운로드할 수 있도록 jar(Java ARchive)를 지원하는데 브라우저가 서버로부터 다운로드해야 할 jar 파일이 있을 때 사용한다.

archive = "mysamples.jar, morefiles.jar"

- JAR를 사용하면 파일(바이트코드)의 다운로드 속도를 상당히 개선할 수 있으며 파일의 관리도 매우 편리하게 된다. 이러한 기술은 HTTP의 요구가 많은 소용량의 파일을 포함하는 JAR 파일을 로드함이 필요함에도 불구하고 로드 프로세서의 속도를 현저하게 증가시킨다.
(100개의 파일인 경우 100번 연결을 줄일수 있다)

- Swing.jar or SwingAll.jar 파일은 1Mbyte 정도로 다운로드하기 힘들지만, 한번만 다운을 받으면 된다.

▷ PARAM 태그 - HTML 페이지로부터 애플릿에게 파라미터를 전달하는데 사용된다.

<param name=X value=ABC>

▶ value의 값은 String이어야 한다.

▶ 파라미터 값을 읽을 때에는 getParameter() 메소드를 사용한다.

String getParameter(String a)

▶ 위에서 name은 대소문자를 구분하지 않으나 (즉 섞어서 사용해도 되나) getParameter()이 리턴한 String 값은 대소문자를 구분하며 param 태그의 value에 지정된 값이 그대로 나타난다.

▶ 참고로 String 값은 해당 정수로 바꾸려면 parseInt()를 사용한다. 예를들어 파라미터 name이 AGE인 경우 이를 받아 정수값으로 변환하려면 다음과 같이 한다.

int age = 0;

age = Interger.parseInt(getParameter("AGE"));

▶ getParameter() 호출시 해당 파라미터가 HTML 페이지 내에 없으면 null-pointer exception이 발생한다.

▶ 주의: <param> 태그는 반드시 <applet>와 </applet> 사이에 와야 한다.

Applet에서의 추가 메쏘드

▷ 자바에서 애플릿 프로그램을 작성하기 위해서는 반드시 Applet 클래스로부터 계승된 클래스를 사용하여야 하는데 Applet 클래스는 java.applet 패키지에 속해 있다. Applet클래스의 주요 메소드는 다음과 같다.

URL getCodeBase();/* 코드 URL을 얻는다 */

URL getDocumentBase();/* 도큐멘트 URL을 얻는다 */

Image getImage(URL);/* URL로부터 이미지를 얻는다 */

Image getImage(URL, String); /* URL로부터 name에 해당하는 이미지를 얻는다 */

void play(URL);/* 해당 URL의 오디오 파일을 연주한다 */

void showDocument(URL);/* URL의 도큐멘트를 보여준다 */

getDocumentBase() - 현재 나타나고 있는 페이지의 HTML 문서가 있는 디렉토리를 URL 타입으로 리턴한다.

getCodeBase() - 애플릿 코드를 가져온 곳의 디렉토리를 URL 타입으로 리턴한다.

getImage(URL base, String target) - URL 위치에 있는 target이름의 image를 가져 온다.

getAudioClip(URL base, String target) - URL 위치에 있는 target 이름의 AudioClip을 가져온다.

Posted by 인천총각
|