2014년 2월 6일 목요일

클래스 다이어그램(Class Diagram)

어떻게 된게 항상 헷갈리는지.... 아무래도 잘 사용하지 않아서 그런지도 모르겠다. 소스를 작성할때 설계를 먼저하고 코딩을 해야 되는데...물론 설계는 먼저하고 소스 코딩을 작성하긴한다. 하지만 정형화된 형식인 아닌 방법을 사용하다보니 개선에 의지가 필요해서 이글을 작성한다. 클래스 다이어그램(Class Diagram)은 시스템의 정적인 상태인 논리적인 구조(클래스)를 표현합니다. Class, Interface, Collaboration 간의 관계를 나타내며, 객체지향 개발에서 가장 공통적으로 많이 사용합니다. 클래스 다이어그램을 구성하는 것은 클래스와 관계입니다.

클래스 다이어그램은 다음과 같은 특징을 가집니다.

  1. 시스템의 요구사항에 표현된 작업 즉, 시스템이 처리해야 하는 작업에 대한 책임을 분할
  2. 모델은 점점 증가되며 관련된 클래스들 끼리 패키지화
  3. 클래스를 너무 작게 쪼개거나 기능을 너무 많이 포함하면 안되며 적절한 방법으로 구현
클래스다이어그램은 시스템의 정적 설계도인 Class Diagram과 시스템의 프로세스도인 Acticle Class Diagram으로 구분할 수 있습니다.

클래스(Class)

 클래스를 구성하는 것은 클래스명, 속성, 메소드입니다. 모든 클래스는 다른 클래스들과 구별되는 유일한 이름을 갖습니다. 클래스명은 단순명과 경로명 두 가지 중 하나를 선택할 수 있습니다. 단순명(Simple Name)은 클래스 이름만 표기하는 방법이고, 경로명(Path Name)은 패키지명을 포함하여 표기하는 방식입니다.
속성은 의미 있는 명사형으로 표현합니다. Visibility Name: Type= Default Value + variableName: byte Visibility는 접근제한자를 나타내며 표기법은 다음과 같습니다.

+ : public

- : private

# : protection

메소드는 의미 있는 동사형으로 표현하며 표기법은 다음과 같습니다.

Visibility Name(Parameter-List): Return-Type Expression

 예)

+ methodName (int param): int

Image 클래스 표기법에 스테레오 타입(Stereo-Type)을 붙일 수 있는데, 스테레오 타입이란 UML의 한정된 모델 요소를 가지고 새로운 어휘를 표현하기 위한 방법입니다. 메소드 명 위에 아래의 예처럼 스테레오 타입을 붙이면 해당 메소드는 생성자라는 것을 표기하는 것입니다.
<<constructor>>
이런 방법으로 클래스명 위에 인터페이스나 추상 클래스임을 나타낼 수 있습니다.

관계(RelationShip)

관계는 모델 요소 간의 논리적 또는 물리적인 연결을 의미하며, 여러 객체의 유기적인 관계를 통해 시스템이 실행됩니다.

1. 의존관계(Dependency)

'Using' 관계를 나타내며, 하나의 모델 요소가 다른 모델 요소를 사용하는 관계를 말합니다. 사용되는 모델 요소가 변경되면 사용하는 요소가 영향을 받지만, 역은 성립되지 않습니다. UML 표기법은 점선으로 된 화살표로 표현합니다. 화살표의 방향은 사용하는 쪽에서 사용되는 쪽으로 향합니다. Image 예제는 프로그래머 클래스가 사용하는 쪽이고 컴퓨터 클래스가 사용되는 쪽입니다. 사용되는 클래스가 사용하는 클래스의 메소드 파라미터로 사용되는 경우, 사용되는 클래스가 사용하는 클래스의 메소드 로컬 변수로 사용되는 경우, 사용되는 클래스가 사용하는 클래스의 전역 변수로 사용되는 경우입니다. 의존 관계는 has a 관계를 가지는 클래스들 간에 변수나, 메소드의 파라미터의 사용을 가지는 클래스의 관계를 표시합니다.

2. 일반화(Generalization)

여러 클래스가 가진 공통적인 특징을 추출하여 공통적인 클래스를 일반화시키는 것을 의미하며, 반드시 클래스간의 'is a' 관계이어야 합니다. 객체지향의 상속 관계를 의미합니다. Image 추상클래스(Abstract) 는 이탤릭체나 스테레오 타입으로 표시합니다.

3. 연관관계(Association)

클래스로부터 생성된 인스턴스들 간의 관계를 표현합니다. 의존관계와 일반화 관계는 단순히 클래스들 간의 관계를 나타내며, Classifire로부터 생성된 인스턴스 사이의 관계를 나타냅니다. 상대방의 인스턴스를 가리킬 수 있는 속성을 가지며, 참조할 수 있는 속성은 UML 상에서 표현하지 않습니다. 표현하고자 할 경우 Role name을 사용합니다. 연관관계가 가리킬 수 있는 방향의 종류는 양방향과 단방향이 있습니다. Image [인스턴스의 표기법]
표기법 인스턴스의 수
1 1개
0..1 0개 또는 1개
* 다수
1..* 1개 또는 다수

4. 집합연관관계(Aggregation)

전체와 부분을 나타내는 모델요소(whole-part)로 전체를 나타내는 클래스와 이를 이루고 있는 부분 클래스의 관계를 나타냅니다.'has a' 관계를 나타내며 집합연관관계는 전체와 부분은 서로 독립적인 관계를 나타냅니다. Image

5. 복합연관관계(Composition)

전체와 부분을 나타내며(Whole-part), 젠체를 나타내는 클래스와 이를 이루고 있는 부분 클래스 관계를 나타냅니다. 연관관계를 맺고 있는 클래스는 생명주기기 같다. 'has a'관계입니다. Image

6. 실체화, 권력화(Realization)

인터페이스는 컴포넌트 간의 결합력을 느슨하게 합니다.(Loose Coupling) 인터페이스는 프로그램의 수정 없이 쉽게 소프트웨어를 확장할 수 있습니다. Image

※ 클래스 다이어그램 UML 작성시 주의점

  1. 클래스 다이어그램은 'is a'관계를 나타냅니다.
  2. 일반화 관계는 균형있게 유지해야 합니다.
  3. 선들이 교차하지 않도록 주의해야 합니다.
  4. 이해하기 쉬운 정도로 간략하게 표시합니다.
  5. 관련 있는 클래스들은 가까운 곳에 배치합니다.

TDD, BDD 비교

Posted: May 18, 2013 | Author:  | Filed under: 소프트웨어개발이야기애자일이야기 |Leave a comment »

마소에 기고한 TDD와 BDD 내용 중, 코드 작성에 관한 부분을 옮겨 왔다.

bdd

그 전에 앞서 약간의 의견을 담아내자면, BDD에 대해서는 다소 회의적이다. 둘 간의 차이가 크지 않고 BDD가 가진 철학이 이미 충분히 TDD에 반영되어 있을 수 있다. 그런 철학은 꼭 BDD만의 것이라고 하기에는 다소 민망하다. 그럼에도 불구하고 차이를 언급했던 것은, 혹시나 차이를 설명하는 과정에서 TDD/BDD에 익숙하지 않은 사람들이 아이디어를 얻어갈 수 있지 않을까 하는 막연한 기대 때문이었다. 아래는 기고 당시의 일부 내용이다.

 

- 아래 -

이제부터는 간단하게 친구신청/확인 기능을 TDD와 BDD로 작성해보며 이 둘을 살펴보려 한다. 제한된 공간안에 TDD와 BDD를 설명해야 하기 때문에, 바로 구현으로 들어가도 될 만큼 작은 기능을 대상으로 선정했지만, 간단히 기능 정의를 하고 시작하도록 한다.

 

기능 정의

친구 신청/확인에 필요한 기능은 다음과 같다.

  • 사용자는 친구를 맺기 위해, 상대방에게 친구 신청을 할 수 있다.
  • 사용자는 다른 사용자와의 친구 여부를 확인할 수 있다.

 간단하게 클래스로 만들어 볼 수 있는 대상은 2개 정도가 될 것 같다.

  • 사용자
  • 친구신청/확인

하지만 기능이 크지 않으므로, 사용자 클래스 하나를 두고 이 안에서 친구 신청 및 확인 기능을 함께 구현하도록 한다. 정리하면, 사용자 클래스 하나에 친구신청, 친구확인 기능이 필요하다.

 

TDD

우선, TDD로 이 내용을 구현해보도록 한다. 가장 먼저 무엇을 테스트해보는게 좋을까? 친구 여부를 확인하기 위해서는 친구 신청을 먼저 구현해야 할 것 같다. 그런데 잠깐, 친구 신청을 했는지 확인하려면 친구 여부 확인이 먼저 필요한 것 아닐까? 이런 경우는 그냥 둘다 함께 확인 가능한 테스트 코드를 작성하면 된다.

먼저 위에서 정의한 기능을 User 클래스의 메서드로 선언한다.

User.java

@Getter
 @Setter
 public class User {
  private String name;
  public User(String name) {
     // TODO
    }
  public void sendFriendRequestTo(User receiver) {
     // TODO
   }
  
  public boolean isFriendWith(User receiver) {
     // TODO
   }
} 

그리고 이를 확인하기 위해 작성한 코드는 다음과 같다.

UserTest.java

public class UserTest {
   @Test
   public void sendRequestTo() {
       // Given
       User userA = new User("A");
       User userB = new User("B");
       // When
       userA.sendFriendRequestTo(userB);
       // Then
       userA.isFriendWith(userB);
   }
}

A라는 이름의 사용자와, B라는 이름의 사용자가 전제조건(Given)으로 주어져 있고, A가 B에게 친구 요청을 던진 경우(When), A가 B와 친구가 되었는지를 확인(Then)하고 있다. 이제 User의 내부를 빠르게 구현해보면, 다음과 같은 코드가 나온다.

@Getter
@Setter
public class User {
   private String name;
   private List<User> friends;
   public User(String name) {
       this.name = name;
       this.friends = new ArrayList<User>();
   }
   public void sendFriendRequestTo(User receiver) {
       friends.add(receiver);
   }
   public boolean isFriendWith(User receiver) {
       return friends.contains(receiver);
   }
}

대부분 금방 눈치 챘겠지만, 코드를 보면 B의 입장에서 A가 친구인지의 여부가 의심이 될 것이다. 이런 경우라면 다음과 같이 Test 케이스를 추가해 확인해 볼 수 있다.

UserTest.java

public class UserTest {
   ... 생략
   @Test
   public void sendRequestTo_상대방에게_요청을_받은_경우() {
       // Given
       User userA = new User("A");
       User userB = new User("B");
       // When
       userB.sendFriendRequestTo(userA);
       // Then
       Assert.assertTrue("친구 요청을 받으면 친구가 되야 한다.", userA.isFriendWith(userB));
   }
}

필요하다면 다음과 같이 메서드에 설명을 붙여 케이스를 추가해 나갈 수 있다.

  • isFriendWith_친구신청_하지_않은_경우
  • sendRequestTo_중복으로_친구신청을_한_경우

그런데 잠깐, 새롭게 추가한 테스트 케이스가 실패함을 확인할 수 있다. 이는 단방향이 아니라 양방향의 관계를 작성하는 것이 익숙치 않은 경우 종종 발생하는 문제이다. User 클래스는 아래와 같이 고쳐서 Test 코드를 성공으로 돌려놓을 수 있다.

User.java

public class User {
   ... 생략
   public void sendFriendRequestTo(User receiver) {
       friends.add(receiver);
       receiver.getFriends().add(this); // 동기화 코드가 필요함
   }
   ... 생략
}

위의 코드는 친구 중복에 관한 처리 등을 비롯해 테스트 케이스 추가와 코드 보완, 리팩토링이 필요하지만 코드 소개의 목적이 TDD와 BDD의 비교이므로, 일단 이것으로 TDD에 대한 간단한 소개를 마치도록 한다.

 

BDD

 이번에는 똑같은 기능을 BDD로 작성해보도록 하자. BDD를 작성하는데 사용한 프레임웍은 JBehave 이다. 총 5계의 단계를 거쳐 작성을 하게 되는데 이 순서는 다음과 같다.

  1. 스토리 작성
  2. 시나리오를 실행시킬 Step 클래스(POJO)를 작성한다.
  3. Embeddable 클래스를 작성하여 관련된 설정을 지정한다.
  4. 시나리오를 실행시킨다.
  5. 결과를 확인한다.

 

스토리 작성

가장 먼저 스토리를 작성한다. 위에서 정의한 기능을 토대로 다음과 같이 작성해볼 수 있다. 

friend_request_story.story

Narrative:
사용자는,
친구를 맺기 위해,
다른 사용자에게 친구 신청을 할 수 있다.
Scenario: 친구 요청
Given ‘A’라는 사용자가 있다.
And ‘B’라는 사용자가 있다.
When 'A'가 'B'에게 친구 신청을 한다.
Then 'A'는 'B'와 친구가 된다.
Scenario: 친구 요청 (받는 경우)
Given ‘A’라는 사용자가 있다.
And ‘B’라는 사용자가 있다.
When 'B'가 'A'에게 친구 신청을 한다.
Then 'A'는 'B'와 친구가 된다.
And ‘B’는 ‘A’와 친구가 된다.

*두꺼운 글씨로 작성된 부분은 꼭 지켜줘야 하는 문법(JBehave 혹은 Grekin Language)이다.

 크게 2가지로 구성되는데, Narrative 부분은 테스트 대상이 되는 스토리를 설명하는 부분이다. 이 형식은 애자일 개발 방법에서 많이 사용하는 사용자 스토리(User Story) 작성 템플릿으로, 역할(Role) – 기능(Feature) – 목적(Benefit)의 요소로 구성되어 있다.

  • As a [역할]
  • I want [기능]
  • So that [목적]

 위의 형식이 기본 템플릿인데, 한글로 작성하였기 때문에 순서를 바꾸어 작성하였다.

 다음으로 Scenario 부분이다. Given에 주어진 조건을 적고, When에 테스트 하고 싶은 어떤 행위를 기술하면 된다. 그리고 마지막 Then에는 기대하는 결과를 작성하면 된다. 기본적인 형식은 다음과 같다.

  • Given [주어진 조건]
  • And [주어진 다른 조건] …
  • When [행위 또는 사건]
  • Then [결과]
  • And [다른 결과] …

스토리를 작성하는 방법에 대해서 자세히 알고 싶으면 다음의 글을 참조하도록 한다.http://dannorth.net/whats-in-a-story

 

Step 클래스 작성

 friend_request_story와 이름 구조를 맞춰 주어야 하므로, FriendRequestStep이라는 이름으로 다음과 같은 Step클래스를 작성하였다.

FriendRequestStep.java

public class FriendRequestStep {
   private UserRepository repository;
   @BeforeStories
   public void setUp() {
       repository = new UserRepository();
   }
   @Given("'$userName'라는 사용자가 있다.")
   public void givenThereIsUser(String userName) {
       User user = new User(userName);
       repository.save(user);
   }
   @When("'$senderName'가 '$receiverName'에게 친구 신청을 한다.")
   public void whenSendFriendRequest(String senderName, String receiverName) {
       User sender = repository.findByName(senderName);
       User receiver = repository.findByName(receiverName);
       sender.sendFriendRequestTo(receiver);
   }
   @Then("'$senderName'는 '$receiverName'와 친구가 된다.")
   public void thenTheyAreFriend(String senderName, String receiverName) {
       User sender = repository.findByName(senderName);
       User receiver = repository.findByName(receiverName);
       Assert.assertTrue(sender.isFriendWith(receiver));
   }
   // DB 관련된 사항이 결정되지 않았다고 가정하고 도우미 클래스를 만든다.
   private class UserRepository {
       private final List<User> userList;
       public UserRepository() {
           userList = new ArrayList<User>();
       }
       public void save(User user) {
           userList.add(user);
       }
       public User findByName(String userName) {
           for (User user : userList) {
               if (user.getName().equals(userName)) {
                   return user;
               }
           }
           return null;
       }
   }
}

우선, User 데이터들을 관리하는 모듈이 필요한데, 여기서는 DB Access(DAO, Repository 사용 여부 등) 관련 사항이 결정되지 않아서 UserRepository라는 Mock을 사용하였다. 이런 식으로, 아직 구현되지 않은 모듈이 있는 경우에도, 원래 구현하려던 기능에 집중하여 코드를 작성할 수 있다. 추후 DB관련 사항이 결정되면 UserRepository를 실제 모듈로 대체할 수 있을 것이다.

 @BeforeStory 부분은 시나리오를 실행하기 전에 환경적인 부분을 설정하는 곳이다. 물론, 데이터를 미리 설정하는 공간으로 활용할 수도 있지만, 필자는 주로 환경적인 부분을 만드는데 이를 활용하여 @Given과의 용도를 구분한다.

 @Given, @When, @Then은 story 파일에서 Given, When, Then을 매핑하는 애노테이션이다. 그리고 각 애노테이션 안에 story의 각 문장을 매핑하는 값들이 있다. 달러($)표시로 시작하는 부분은 story 파일에서 마음대로 값을 지정할 수 있는 부분을 의미한다. 이런 특징으로 인해, 하나의 매핑 메서드에 여러개의 문장을 다양한 값으로 대응시킬 수 있는데, 이는 JBehave가 주는 꽤나 좋은 이점이다. 프레임웍 없이 작성했다고 하면, 우리는 일일이 똑같은 테스트 메서드를 추가하여 그 안에 Given이나 When등을 작성해야 했을 것이다.

 실제로 Given에서 표현한 2개의 문장은, 하나의 메서드로 모두 수행 가능하다.

  • Step 메서드: givenThereIsUser
  • Scenario 문장
  • Given ‘A’라는 사용자가 있다.
  • And ‘B’라는 사용자가 있다.

만약, 한 명의 사용자를 더 두어 시나리오를 테스트하고 싶거나, 또 다른 시나리오를 추가하려는 경우 이러한 재사용은 점점 이점으로 다가올 것이다. 흔히, Step 클래스는 Story의 Type이며, Story는 이 시스템의 구체적 행위이자 인스턴스라고 표현하기도 한다.

 

Embeddable 클래스를 작성

여기서 설정 코드를 작성하는 것은 생략하도록 한다. 이 설정에서는 story를 step에 매핑하는 방식이라던지, 결과를 어떤 형태로 보여줄 것인지 등을 결정할 수 있다.

 

시나리오 실행

JUnit을 통해 우리는 결과를 확인할 수 있는데, 위의 경우 다음과 같은 결과를 확인할 수 있다.

 

결과 확인

(BeforeStories)Running story friends/friend_request_story.story(friends/friend_request_story.story)Scenario: 친구 요청Given 'Jobs'라는 사용자가 있다.And 'Gates'라는 사용자가 있다.When 'Jobs'가 'Gates'에게 친구 신청을 한다.Then 'Jobs'는 'Gates'와 친구가 된다.
 

코드를 통해 느껴본 TDD와 TDD

지금까지 친구 신청/확인 기능을 구현하는 TDD와 BDD에 대해서 살펴보았다. 위에서 살펴본 것처럼, TDD와 BDD의 의미 있는 차이라고 한다면, story 파일의 존재이다. 이것은 비 개발자와 소통하는 동시에 시스템의 행위를 보존해주는 도구로 사용될 수도 있다. 분명, 도표나 그림등을 통해서 더 많은 것을 쉽게 표현할 수도 있기 때문에, 시나리오로 모든 것을 표현하는 데에는 한계가 있다. 그럼에도 불구하고 필자는 코드를 작성하기 전에 이런 시나리오들을 간단히 작성해 보는 것을 좋은 개발 시작 지점으로 삼을 수 있었다. JBehave는 이것을 프레임웍에서 지원해주며, 이것이 BDD가 가진 주요 철학 중 하나이다.

더불어, 프레임웍을 통해서 TDD의 반복되는 코드 작업을 줄여주는 이점을 취할 수도 있다. 프레임웍을 사용하지 않는 경우, 여러 케이스를 표현하기 위해 중복되는 코드들이 나오기 마련이다. 이를 SetUp(JUnit에서는 @Before 애노테이션 사용)부분에 넣으면, 반복 작업은 줄지만 가독성이 떨어지고 점점 코드가 복잡해질 여지가 있다. 해서, 어느 정도의 반복작업을 하게 되는 것이다. 그런데 JBehave는 위에서 보듯 Step을 Type으로 작성하여, 여러 시나리오들을 좀 더 수월하게 테스트해볼 수 있었다. 이는 테스트 코드 관리의 부담을 줄여주는 하나의 방법이 될 수 있다고 본다.

그 외에, In-Out 방식과 시나리오 형태로 테스트 주도 개발을 할 수 있다는 점은 BDD(정확히는 JBehave 프레임웍이)가 강제하는 형식이다. 물론, Out-In 방식이 유리한 경우도 있고, 시나리오가 아닌 단순 스펙 확인 방식이 좋은 경우도 있다. BDD 프레임웍이 이런 유연성을 제한하는 것은 분명 한계일 것이다. 그럼에도 불구하고, BDD가 가진 철학들은 한 번은 적용해볼 만한 내용일 것이다.

IntelliJ Mac에서 Eclipse 단축키 그대로 사용하기(change Ctrl to Command)

1 - Grab this xml file (Eclipse on Mac):

https://github.com/thatha/IntelliJ-IDEA-Eclipse-on-Mac-Keymap/blob/master/Eclipse%20on%20Mac.xml

2 - Save the file to this directory:

~/Library/Preferences/IntelliJIdea11/keymaps/

note - this directory may vary depending on your system/version of IntelliJ. According to this link:

http://www.jetbrains.com/idea/webhelp/configuring-keyboard-shortcuts.html

It should be of the form: ~/Library/Preferences/.IntelliJ IDEA/keymaps/

Dig around and you will find it!

3 - Open IntelliJ, navigate to Preferences ( cmd + , ). Under IDE Settings > Keymap, select "Eclipse on Mac" from the Keymaps drop down list.

svn 사용자 변경

  1. - Win XP
    • 시작 - 실행 - %HOMEPATH%\Application Data\Subversion\auth\svn.simple 폴더의 파일 삭제
  2. - Win 7
    • C:\Users\%사용자계정%\AppData\Roaming\Subversion\auth\svn.simple 파일 삭제

 

TDD Test Double이란...

1. Test Double

- 테스트를 수행하기 위해서 실제 컴포넌트 역할을 대체하는 기능을 가진 객체나 컴포넌트를 말한다.

2. Test Double 분류

  • Dummy Object : 가장 기본적인 유형으로, 매개 변수 값과 같이 작업을 수행하는 메소드가 없는, 값 전달만을 위한 객체를 말한다.
  • Test Stub : 아직 개발되지 않은 클래스나 메소드가 처리 후 리턴해야 하는 값을 전달해주는 역할을 한다. 대부분 그 값은 하드 코딩되어 있다. 
  • Test Spy : Stub과 비슷하지만, 어떤 작업을 수행했는지에 대한 이력을 남긴다는 점이 다르다. Stub과 같은 역할을 하는 척하지만 이름 그대로 스파이 같은 행동을 한다. 
  • Mock Object : Dummy, Stub, Spy를 통합해 놓은 것과 비슷하다 볼수 있다. 보통 라이브러리를 사용하여 동적으로 데이터를 처리해줄 부분을 생성한다. 즉, Stub기능에 검증(assertion) 기능을 추가한 형태라고 생각하면 된다. 
  • Fake Object : 테스트에 직접적인 연관은 없지만, 테스트하고자 하는 시스템과 연계되는 시스템이 너무 느리거나, DB가 아직 구성되지 않았을 경우에 해당 부분이 실제 존재하는 것처럼 하는 부분을 말한다. 

 

프로그래머란..

1. 꾸준히 한다.

.프로그래밍언어도 언어(?)라서, 하루에 몰아서 하는 것보다 매일 꾸준히 하는 것이 중요하다. 경력이 많은 프로그래머들도 몇달만 코딩을 안해도 감이 많이 떨어지는 것을 느낀다. .특히 프로그래밍을 처음 배우는 사람이라면, 꼭 컴퓨터 앞에 앉지 않더라도 책을 항상 가까이해서 문법 및 표현에 익숙해지도록 하는 것이 중요하다. 자주보는 것이 중요하다.

2. 반복해서 한다.

.단지 태권도교본을 잘이해했다고 해서 멋진 발차기를 기대할수 없는 것처럼, 책의 내용을 잘 이해했다고 해서 하루아침에 프로그래밍을 잘할수 있는 것은 아니다. .이해한 내용을 바탕으로 수많은 반복연습을 통해서만 지식을 진정한 자신의 것으로 만들 수 있다. (같은 예제를 공부하더라도 이리저리 조금씩 변경해서 공부하는 것이 좋다.) .처음 2~3번은 자세히 보고, 그 다음 부터는 하루에 10분간 10페이지를 훑어보는 식으로 반복하자. 몇달안에 책에 있는 모든 목차와 예제의 위치와 주요내용을 모두 파악할수 있을 것이다. (적어도 언어책 한권, 데이터베이스책한권 정도는 이렇게 할 필요가 있다.)

3. 좋은코드를 많이 보고 따라한다.

.이미 수많은 선배들이 여러문제들에 대한 코딩을 다 작성해 놓았다. 새로운 방법으로 문제를 풀겠다고 도전하는 것은 별 의미가 없다. "이럴때는 이렇게 하는 구나..."라는 것을 배우고 유사한 상황에서 활용하면 되는 것이다. 여러분들이 해야할일은 이러한 경험들을 많이 쌓아 나가는 일이지, 기존과는 다른 새로운 코딩방식을 만들어 내는 것이 아니다. .좋은 코드는 보기에도 좋다. 잘정리되어 있고, 별로 특별한 것이 없다. 프로그래밍의 각요소들을 잘이해하고, 각 요소들을 적재적소에 바르게 사용하면 되는 것이다. 단지 소스의 라인수를 줄인다고해서 좋은 코딩이 아닌것이다. 로직이 소스코드에 잘드러날수있게 쉽고 평범하게 작성하는 것이 좋은 코드인 것이다. 이창호의 바둑이 평범하듯이...

4. 기본에 충실한다.

.빨리 프로그래밍을 배워서 뭔가 해보고 싶은 여러분들의 마음을 이해하지 못하는 것은 아니다. 그러나, 프로그래밍 하루이틀 할 것도 아니고... 처음에 기본을 잘배워놓지 않으면, 그 이후에는 기회가 잘 없다. 실무에서는 매일 개발하기 바쁘고, 새로운 기술 배우기 바쁘고... .배울것이 많다고 생각할지 모르나, 실제로 원리는 모두 같다고 해도 과언이 아니다. 하나를 깊이있게 파고들면 나머지는 다 여러분 손에 있을 것이다.

5. 코드를 작성하기전에 순서도를 그린다.

."프로그래밍 = 코딩"이 아니라 "프로그래밍 = 로직설계 + 코딩"이다. 필자가 생각하는 로직설계 와 코딩간의 비율은 8:2정도이다. .포토샵만 잘한다고 디자이너가 아니라는것은 여러분들도 잘알고 있을 것이다. 새로운 기술이나 프로그램을 공부하는 것도 중요하지만,  어떤 과제가 주어졌을때 이를 잘 분석하고 설계하는 능력을 장기적으로 키워나가도록 노력해야할 것이다.(다양한 주제에 대해서 문제를 풀어보고 다양한 종류의 책을 읽자.) .문제를 구성하고 있는 주인공들을 찾아서 나열해보라. 그리고 이들간의 관계는 무엇이고, 규칙은 무엇인지 적어보라.(머릿속으로만 생각하지말고!!!)

6. 주석을 가능한한 많이 적는다.

.주석은 매우 유용하고도 중요한 요소이다. 그럼에도 불구하고 많은 사람들이 이를 소홀히 한다. 자신이 작성한 코드도 몇일만 지나면 이해가 안되는 경우가 많다. 적어도 이해하는데 시간이 걸린다. 주석은 이러한 시간들을 절약해줄것이며, 보다 에러가 적은 코드를 작성하는데 도움을 줄 것이다. 특히 여러사람이 공동작업을 하는 경우에는 더욱 더 중요하다. 서로를 위해서... .작업과 관련된 가능한한 많은 정보를 주석에 담도록 하자.

7. 작업일지를 작성한다.

.과학자들이 매일 연구한 내용을 일지로 적듯이 여러분들도 일지를 적어보자. 오늘은 이렇게 저렇게 해봤는데 잘안되었다... xxx.java의 코드를 이렇게 바꾸었다. 몇시몇분에 xx로 백업받아 놓았다... 라는 식으로 가능한한 자세히 적도록 한다. 이렇게 함으로써 여러분들의 경험을 기록 으로 쉽게 보관할수 있으며, 문제해결에 많은 도움이 된다.

8. 자신의 소스를 가꾼다.

.보통 코딩을 마치고 나면, 모든 것을 덮어두곤 한다. 원하는 결과를 얻었다고 거기서 그치지말고 이제 로직과 코드를 보다 효율적으로 개선할 방법이 없는지 고민해보자. 글을 써놓고 좋은 글로 만들기 위해 읽고 또 읽고 다듬듯이 코드를 다듬어보자. 여러분들의 코드를 구사하는 능력이 보다 향상되어가는 것을 느낄 수 있을 것이다. .여러분들을 위한 제안은 작은 프로그램을 만들어서 오랜기간동안 점차 발전시켜 나가는 것이다. 새로운 기능들을 하나씩 추가해가고, 기능을 발전시켜나가보자. 이과정을 통해서 여러분들의 실력 은 몰라보게 향상될 것이다.

9. 생각하라.

.항상 머릿속에 한 가지 문제를 준비하라. 지하철을 기다리거나, 화장실에서 볼일 볼때 문제를 풀어 보자. 유레카를 외치고 뛰어나올지도...^^;

10. 좋은 책을 선택한다.

.공부를 시작할때 제일 먼저 하는 일은 아마도 책을 고르는 일일 것이다. 보통 책하나에 수십시간을 학습하게 되는데, 책을 잘못선택한 경우 수십시간과 노력을 허비하는 셈이다. 바른 책을 고르는 일은 쉬운일이 아니지만, 최소한 몇시간을 투자해서 최선의 선택을 하도록 노력 해야 수십시간을 허비하는 일이 없을 것이다. .책을 고르는 법은 여러가지가 있겠으나, 가장 중요한 것은 본인이다. 서점에서 같은 종류의 몇가지 책을 놓고 서로 비교해보면, 시간을 들인 만큼 보다 나은 선택을 할 가능성이 높아진다. .많은 컴퓨터 서적이 독자들의 선택을 어렵게 하고, 컴퓨터 업계 특성상 좋은책을 만들기 보다 빨리찍어서 파는 것이 더 중요해진 요즘. 독자들의 바른 선택이 보다 나은 책이 출판되는 것을 가능하게 한다는 것을 알았으면 한다

코드잘 짜기

1. 설계는 프로그래밍에 있어 가장 중요하다.
2. 만들려는 것을 그림으로 그려라
3. 80%의 머리를 쓰면 20%의 비용이 절약되고 20%의 머리를 쓰면 80%의 추가 비용이 들어간다.
4. 프로그램 개발 속도를 좌우하는 것은 사람수도 잡다한 지식도 아닌 기본적인 문법이다.
5. 모듈적(Component)으로 개발하고 다른 시스템에 대한 영향은 최대한 줄여라
6. 메모리 문제는 메모리 관리를 고려해야 발생하지 않는다( pool, smart_ptr )
7. 기본적인 규칙은 지켜라. 특히 CQS(command query separator)는 특히 중요하다.
8. NVI(non virtual interface)는 매우 유용하다.
9. 개발을 위한 개발 환경을 만들어라. Log System, Bug Traps(LIB X), Reload 등의 기능들은 유용하다.
10. 버그의 85%는 잘못된 읽기와 쓰기 그리고 알고리즘에서 나온다( 트랩을 설치하자 )
11. C++ 에서 meta programming(template), pure programming(functor - pure function)은 능률을 높이고 버그를 줄여준다.
12. 데이터와 컨트롤 객체(interface)는 분리하라.
13. 다양한 프로그램들이 사용하는 기법은 언제든지 내가 만드는 프로그램에 적용될 수 있다. - 이벤트 드리븐, 데이터지향 드리븐, 파이프라인, 메세지드리븐 아키텍쳐, 가비지컬렉션 등
14. 버그를 유발할만한 데이타라면 코드가 아닌 데이터로 만들고 내가 아닌 다른 사람이 컨트롤하도록 하라.
15. 라이브러리를 사용하라.
16. 자기자신이 만든 코드를 기억하기 힘들고 사용하기 힘들다면 남들이 이해할 것이란 확신을 가지지 마라.
17. 파이프라인, 컴포넌트 레이아웃 등의 기법은 버그를 보다 쉽게 찾을 수 있도록 도와준다.
18. 코드는 반드시 재사용하도록 만들고 고려한다.
19. 코드가 주석이며 코드로는 이해하기 힘든 곳은 반드시 주석을 남긴다.

2014년 2월 5일 수요일

Linux apache-tomcat 설치

apache Tomcat Donwload : Apache 홈페이지 바로가기


아파치 홈페이지 에서 Tomcat 7.0 을 선택하고 tar.gz를 다운 받습니다.

그리고 FTP로 Linux에 카피 하겠습니다.
참고 사항 - FTP 설정



압축을 tar zxvf apache-tomcat-7.0.30.tar.gz 명령어로 압축을 해제 하겠습니다.





압축을 해제 한후 /usr/local/ 로 이동 시키겠습니다.
(※ /usr/local/은 window에서 program files 와 같은 개념의 폴더입니다.)




옮긴 것을 확인 합니다. 그리고 심볼릭 링크 설정을 하겠습니다.
ln -s apache-tomcat-7.0.30 tomcat




그리고 etc 에 있는 profile 설정을 하겠습니다. 항상 설정 후에는 source profile 로 적용을 시키겠습니다.





export CATALINA_HOME=/usr/local/tomcat
export PATH=$PATH:$CATALINA_HOME/bin

다시 tomcat 으로 돌아와서 폴더 안의 bin 폴더 안의 catalina 쉘을 실행 시킵니다.
명령어는 ./catalina.sh start 입니다.






결과 화면 입니다.






8080 포트로 확인하면 접속이 확인 되겠습니다. (현재 80은 httpd 가 사용 중입니다.)

추가로 부팅할때 자동으로 Tomcat이 떠오르게 만드는 배치 파일을 만들겠습니다.
명령어 vi /etc/init.d/tomcat 파일을 생성하겠습니다.






#!/bin/bash
#description: Tomcat
#processname: tomcat
#chkconfig: 234 20 80
JAVA_HOME=/usr/local/java
export JAVA_HOME
export PATH
CATALINA_HOME=/usr/local/tomcat
case $1 in
start)
sh $CATALINA_HOME/bin/startup.sh
;;
stop)
sh $CATALINA_HOME/bin/shutdown.sh
;;
esac
exit 0


마지막으로 권한 설정을 바꾸겠습니다.
chmod 755 tomcat







chkconfig --add tomcat 으로 등록하고
chkconfig --list 로 확인하겠습니다.






서비스 실행

- 서비스 시작
#service tomcat start

- 서비스 종료
#service tomcat stop

- 서비스 재시작
#service tomcat restart


2014년 2월 4일 화요일

Linux 하드 디스크 상태 확인

자주 있는 일은 아니지만 가끔씩 시스템에 장착되어 있는 하드디스크의 용량 확인이 필요할 때가 있다.

 시스템 구축시 하드웨어에 대한 정보를 가지고있다면야 전~혀 문제될게 없겠지만, 그렇지 않은 경우가 왕왕있어서..;;

 게다가 그 시스템이 원격지에 있을 경우!! 갈 수도 없고~

 그래서 각종 정보를 리눅스 운영체제 하에서 찾아보자구요~

 아래에 이어서 나오는 정보를 가지고 알아낼 수 있는 모든 정보를 알아내보자.


★ fdisk 를 이용해서 정보 찾아내기


[root@dev-test ~]# fdisk -l

Disk /dev/hda: 160.0 GB, 160041885696 bytes
255 heads, 63 sectors/track, 19457 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks   Id  System
/dev/hda1   *           1          33      265041   83  Linux
/dev/hda2              34        2644    20972857+  83  Linux
/dev/hda3            2645        2905     2096482+  82  Linux swap / Solaris
/dev/hda4            2906       19457   132953940    5  Extended
/dev/hda5            2906        3166     2096451   82  Linux swap / Solaris
/dev/hda6            3167        3427     2096451   83  Linux
/dev/hda7            3428        3491      514048+  83  Linux
/dev/hda8            3492       19457   128246863+  83  Linux

Disk /dev/hdb: 250.0 GB, 250059350016 bytes
255 heads, 63 sectors/track, 30401 cylinders
Units = cylinders of 16065 * 512 = 8225280 bytes

   Device Boot      Start         End      Blocks   Id  System
/dev/hdb1   *           1       30401   244196001   83  Linux



1. 몇 개의 하드디스크가 설치되어 있을까?

 : 2개
  
   "Disk /dev/hda"이랑 "Disk /dev/hdb"라는 정보를 토대로 2개가 설치되었다는 것이다.

2. 장치 타입은?

 : E-IDE 타입

3. 용량은?

 : /dev/hda는 160.0GB, /dev/hdb는 250.0GB

 위의 경우에는 친절히 용량을 확인시켜주고 있는 상태이다.
 하지만 가끔씩 운영체제의 버전에 따라서 불친절한 리눅스씨도 있으니깐 직접 계산하는 방법도 알고 가자.

maven profile 설정(3rd party jar파일을 로컬레파지토리에 저장)

집에서 환경 셋팅하는데 자꾸 pom.xml에서 에러가 발생
즉 사용자 임의 jar파일을(3rdParty) 로컬레파지토리에 저장해 불러올때 초기에 로컬레파지토리에 저장하지 않아서 에러가 남
그래서 우선 cmd > pom.xml파일 위치에서 mvn -Pinstall-3rd install을 실행하니 BUILD FAILURE..ㅠ.ㅠ
한시간 삽질해서 알아낸 결과는 아주 간단했다.
우선 pom.xml 파일에 들어가서 현재 로컬에 저장되지 않은 dependency를 주석처리하고 mvn -Pinstall-3rd install하니 성공
그리고 나서 pom.xml파일로 다시 와서 방금 주석했던 파일을 주석 해제..


-------------------------참고----------------------------------------------------------------------------------------------
환경에 따라 설정을 다르게 해야 하는 경우 profile을 이용하면 수정없이 쉽게 사용이 가능하다.
case에 따라 변경되어지는 키값을 설정해 둔다.

<project>
...
<profiles>
<profile>
<id>appserverConfig-dev</id>
<activation>
<property>
<name>env</name>
<value>dev</value>
</property>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<appserver.home>/path/to/dev/appserver</appserver.home>
</properties>
</profile>
<profile>
<id>appserverConfig-dev-2</id>
<activation>
<property>
<name>env</name>
<value>dev-2</value>
</property>
<activeByDefault>false</activeByDefault>
</activation>
<properties>
<appserver.home>/path/to/another/dev/appserver2</appserver.home>
</properties>
</profile>
</profiles>
..
</project>


명령
mvn -P[profile id] [phase]
예제
mvn -PappserverConfig-dev test
mvn -Denv=dev-2 integration-test <-- activation property를 이용한 방법
"activeByDefault" 이 값을 true로 하면 명령 실행시 특정 값을 지정하지 않은 경우 true인 id를 실행한다.
참고 링크 : http://maven.apache.org/guides/introduction/introduction-to-profiles.html
프로파일을 통해 개발, 로컬, 운영버전을 각각 패키징하여 처리하고 있습니다.
알아두면 좋은점이 많은거 같습니다.

[동기부여]적절한 난이도란 무엇인가?

Image

 

출처 : 김창준님의 "당신이 제자리 걸음인 이유: 지루하거나 불안하거나(http://agile.egloos.com/5749946)" 글을 필요할 때 마다 매 번 읽으면 좋겠지만, 보다 수시로 볼 수 있도록 책상 주변에 붙여놓기 위해 아래 이미지를 한 장 만들어본다.

[동기부여]일잘하는법!!!

1. 한 번에 하나씩 하라. 2. 문제가 뭔지 알아라. 3. 듣는 법을 배워라. 4. 질문하는 법을 배워라. 5. 합리적인 것과 합리적이지 않은 것들을 구별하라. 6. 피할 수 없을 때는 변화를 받아들여라. 7. 실수를 인정하라. 8. 간단하게 말하라. 9. 침착하라. 10. 웃어라. 11. 한단계 높은 사고를 하라.

– 항상 본인이 하는 일의 전략적인 의미를 음미 – 큰 그림없이 큰 성과 없다. – 입체적이고 복합적인 사고는 당장의 성과에도 영향을 미치지만, 장기적인 업무역량개발에 분명히 필요하다.

12. Output 중심의 업무를 하라.

– 최종 Outcome 도 중요하지만, Process Output 이 더 중요하다. – 단위 업무의 추진 로드맵을 그리고, 중간 Process 에서 어떤 Output 을 생성해 낼지를 미리 그려보아야 함.

Clean Code

Image 나에게 어떤 지식을 줄수 있을까? 클린코드 제대로 한번 배워보자!! 리뷰는 다 읽어보고 적어야지 [ch1] 좋은 문구가 있어 적어본다.
나중은 결코 오지 않는다...
##총 500페이지가 넘는 분량을 드디어 다읽었다. 근데 다 읽은것은 의미가 없다 이책은 한번 읽고 그만보는 그런 책이 아니다. 책을 보면서 정말 많은 것을 느끼게 해준 그런 책인 것은 분명했다. 지금까지는 돌아가는 코드를 만들려고 노력했지만 정말중요한것은 남의 이해할수 있는 코드를 작성하는것이 얼마나 중요한 것인지 느끼게되었다.늘바쁘다는 핑계로 리펙토링을 하지않고 꾸역꾸역 돌아가게만 작성한 내자신이 너무 부끄러웠다. 이제부터라도 테스트 주도 방식으로 개발을 진행하며 남들이 이해하기 쉬운 코드를 작성하기 위해 노력할 것이다. 비록 코드 작성에 극한 된것이 아니라 무슨일을 할때는 작은 일을 쪼개서 작은 단위의 일을 집중해서 하나씩 완성해나가다 보면 내가 바라던 그 이상의 작업물이 될거라 믿는다. 끝으로 이책을 다봤다고 그만 볼게 아니구 출퇴근하면서 늘 손에 끼면서 자연적을 몸에 밸때까지 책을 손에 놓지 말아야 겠다. ##자신이 의사라고 가정하자. 어느 환자가 수술전에 시간이 오래 걸리니 손을 씻지 말라고 요구한다. 확실히 환자는 상사다. 하지만 의사는 단호하게 거부한다. 왜? 질병과 간염의 위험은 환자보다 의사가 더 잘아니까. 환자 말을 그대로 따르는 행동은 전문가 답지 못하니까

Mac OS에서 hosts파일 수정하기

1.  sudo vim /private/etc/hosts 입력

2.  hosts파일 수정후 저장

3.  DNS cache를 갱신한다.

- $ dscacheutil -flushcache

개발자가 반드시 정복해야 할 객체지향과 디자인 패턴

Image

오랜만에 전공서적을 읽게 되었다. 

요즘 매일 게임만하다가 2014년 새해를 맞이해 이러면 안될 거 같아 최범균씨가 새로 작성한 객체지향과 디자인 패턴책을 보게 되었다.

지금까지 최범균씨 책을 많이 읽고 나름 가이드로 생각하고 있었는데 이책은 생각보다 확 와닿는 부분이 없어서 아쉬웠다.

너무 개념적으로만 접근한 것이 아닌가? 내용이 빈약하다고 할까...

아직 읽을 페이지가 조금 남기는 했는데 끝까지 읽어보고 다시 리뷰를 작성해야 겠다.

자주 사용하는 Intellij 단축키 [계속 업데이트중...]

IntelliJ 단축키

단어 일괄 변경 : Shift + F6
  1. Run
    • window : Ctrt + Shift + D (debugging)
    • window : Ctrt + Shift + R (runtime)
    • mac : Command + Shift + D (debugging)
    • mac : Command + Shift + R (runtime)
  2. surround snippet : alt + command + T (자동으로 for, try, while..생성) -- Mac에서 alt + Command는 오른손으로 누르고 T는 왼손
  3. code generate : Command + n
  4. split상태에서 task창 전환 : Command + Shift + T
  5. 소스코드 정렬(reformat code) : option + Command + L
  6. 영역 지정 : Ctrl + Shift + ↑

GIT 유용합 팁

1. 취소하기

작업하다보면 수정한 사항에 대해서 취소하고 싶은 경우가 생기는데, 아래 방법이 유용하다.

1.1 git add 를 통해 index 에 반영한 내용 즉, add 취소 git reset 을 통해 index의 내용을 HEAD로 되돌리고, working directory는 그대로 유지한다. $ git reset 대표적인 사용 예가 잘못 해서 git add -u 로 모든 tracked files를 add 했을 때 특정 파일만 add 취소할 때 좋다. $ git reset <path> i.e) $ git reset ./a.txt 다시 얘기하지만 add에 대한 취소는 reset이다. rm 이 아니다. rm을 이용하면 git tracking에서 제외하는 엄청난 결과를 초래할 수 있다. 1.2 git commit 을 통해 local repo 에 반영한 내용 즉, commit 취소 여러 가지 경우가 있을 수 있는데, 우선 수정할 경우을 알아보면 commit --amend가 있다. 직전 commit에 대한 Log를 잘못 작성해서 Log만 수정하거나, commit 이후에 같은 내용의 변경에 대해서 새 commit을 만들지 않고 직전 commit에 합칠 경우 유용하다. 아래와 같이 git --amend 를 통해 이전 commit과 합칠 수 있다. $ git commit --amend $ git commit --amend -C HEAD 그밖에 직전 commit을 취소할 경우 git reset 을 통해 직전 commit을 local repo.에서 삭제할 수 있다. 이때 HEAD가 직전 commit을 가리키므로 HEAD^로 reset 하면 된다. $ git reset --hard HEAD^ 이때 주의할 것은 --hard 옵션은 working directory 의 내용에서도 직전 commit을 삭제하고, 복구할 수 없다는 것이다. 만약 local repo에서의 commit만 삭제하고 working directory는 유지하고자 한다면, --hard 대신 --soft 혹은 --mixed 를 사용해야 한다. --soft와 --mixed의 차이는 index에도 삭제 여부이며, --soft는 index에 유지한다.

2. 이전 상태로 복구(roll back)하기

여러 commit을 하다보면 이전 commit 상태로 돌아가고 싶은 때가 있다. 이런 개념을 소위 check out 이라고 하는데, 이전 commit 에 대해서 check out 하면 그때 상태로 working directory가 복구된다. git를 이용할 때는 복구하고자 하는 상태 이후에 변경한 사항을 유지할 것인가에 따라  checkout  혹은 reset 를 잘 사용해야 한다.

2.1 변경 사항을 유지할 경우 checkout을 이용한다.

git checkout 에 특정 commit을 주어 해당 commit으로 working direcotory를 변경할 수 있다. $ git checkout <commit> 단, 이때는 임시 branch 상태이므로 잠시 이용할 사항이 아니라 이 상태에서 추가적으로 commit을 하려면 임시 branch가 아니라 새 branch를 생성해야 한다. $ git checkout -b <new branch name> 애초에 checkout 이후에 commit 할 생각이면 특정 commit 에서 새 branch를 만드는 것이 좋다. $ git checkout -b <new branch name> <commit> 위의 경우 복구 후에 다시 변경 사항을 그대로 유지한 branch로 checkout 할 수 있다.

2.2 변경 사항을 유지 하지 않을 경우 reset 한다.

git reset 에는 --soft, --hard, --mixed 등 옵션이 많은데, working directory까지 해당 commit으로 복구하려면, --hard를 사용하면 되는데 해당 commit 이후의 commit은 복구할 수 없으니 주의해야 한다. $ git reset --hard <commit>

2.3 특정 파일만 이전 상태로 변경할 경우에도 checkout 을 한다.

git checkout 에 file을 명시하지 않고 commit을 주면 전체 commit을 반영하지만, file까지 추가하면 해당 file만 반영한다. 이때는 임시 branch를 만들지 않고 해당 file만 변경하며 필요시 git commit 하면 된다. $ git checkout <commit> <file>

3. rebase 이용하기

rebase을 이용하면 기존 commit 에 대해서 합치고, 나누고, 순서를 바꾸는 등의 다양한 기능을 할 수 있다. 거시적으로 다른 branch와의 rebase와 현재 branch에 대한 rebase로 구분할 수 있다.

3.1 다른 branch에 대한 rebase 만약 기존의 branch에서 분리하여 새 branch에서 작업하고 있었는데, 기존 branch의 추가 commit을 새 branch에 반영하고 싶다면 merge 혹은 rebase를 해야 한다.

최종 결과의 working directory를 보면 차이가 없을 수도 있지만, gitk 와 같은 GUI로 보면 merge 와 rebase의 차이를 확연히 볼 수 있는데, rebase는 우선적으로 기존 branch의 commit을 모두 적용한 이후에 새 branch의 commit을 적용하는 차이가 있다. 물론 rebase도 변경 사항에 따라 merge error가 발생할 수 있다. $ git rebase <other branch>

3.2 현재 branch에 대한 rebase 현재 branch에서의 commit 에 대해서 합치고, 나누고, 순서를 바꿀 수 있다.

이때는 -i, interactive 옵션이 필요하며, 아래와 같이 변경할 범위를 지정한 후에 변경할 수 있다. $ git rebase -i <commit> i.e) git rebase -i HEAD~5 위 명령을 입력하면 commit 목록이 보이며, 위에서부터 commit 을 다시 적용하게 되는데 이 순서를 변경할 수 있고, 필요에 따라 edit, reword, fixup, squash 등으로 합치거나 log를 변경할 수 있다.

GIT commit 데이터 취소하기

 

Assuming you are sitting on that commit, then this command will wack it...

git reset --hard HEAD~1

The HEAD~1 means the commit before head.

Or, you could look at the output of git log, find the commit id of the commit you want to back up to, and then do this:

git reset --hard <sha1-commit-id>

If you already pushed it, you will need to do a force push to get rid of it...

git push origin HEAD --force

However, if others may have pulled it, then you would be better off starting a new branch. Because when they pull, it will just merge it into their work, and you will get it pushed back up again.

If you already pushed, it may be better to use git revert, to create a "mirror image" commit that will undo the changes. However, both commits will both be in the log.

VIM 단축키 정리

vi 편집기 명령 vi 편집기에서는 커서이동모드와 텍스트 모드 명령모드가 있습니다.
입력키의 종류 (커서 이동모드 에서 텍스트 모드로 전환할때 사용)
a  -  커서 위치의 다음 칸부터 입력하기 A  -  커서가 있는 줄의 끝부터 입력하기 i  -  커서 위치부터 입력하기 (키보드의 insert도 같은 기능) I  -  커서가 있는 줄의 맨 앞에서부터 입력하기 o  -  커서 바로 아래에 줄을 만들고 입력하기 (open line) O  -  커서 바로 위에 줄을 만들고 입력하기 s  -  커서가 있는 단어를 지우고 입력하기 S  -  커서가 있는 행을 지우고 입력하기
C - 커서가 위치한 지점부터 끝 지점까지 지우고 입력하기

○ 커서이동 모드에서는

  • 글자단위이동 h  -  한 칸 왼쪽으로 이동하기 l  -  한 칸 오른쪽으로 이동하기 j  -  한 줄 아래로 이동하기 k  -  한 줄 위로 이동하기 (number) + G - 해당 번호로 이동
  • 단어단위이동 w  -  다음 단어의 첫 글자로 이동 W  -  다음 단어의 첫 글자로 이동하기 b  -  이전 단어의 첫 글자로 이동 B  -  이전 단어의 첫 글자로 이동하기 e  -  단어의 마지막 글자로 이동 E  -  단어의 마지막 글자로 이동하기 (이동과 이동하기의 차이점은 해보면 약간있는데 별차이 없는듯)
  • 줄단위이동 ^  -  그 줄의 첫 글자로 이동, shift와 함께 사용 $  -  그 줄의 마지막 글자로 이동하기, shift와 함께 사용 0  -  그 줄의 처음으로 이동 enter -  다음 줄의 첫 글자로 이동하기 +  -  다음 줄의 첫 글자로 이동 -  -  윗줄의 첫 글자로 이동하기
  • 삭제 키의 종류 x  -  dl 커서 위치의 글자 삭제 X  -  dh 커서 바로 앞의 글자 삭제 dw -  한 단어를 삭제 d0 -  커서 위치부터 줄의 처음까지 삭제 D  -  d$ 커서 위치부터 줄의 끝까지 삭제 dd -  커서가 있는 줄을 삭제 dj -  커서가 있는 줄과 그 다음 줄을 삭제 dk -  커서가 있는 줄과 그 앞줄을 삭제
  • 수정 키의 종류 r  -  커서 위치의 한 글자 수정하기 R  -  커서 위치부터 esc를 누를 때까지 다른 글자로 수정하기. 단, 같은 줄에만 해당 s  -  커서 위치의 한 글자를 여러 글자로 수정하기 ch -  커서 바로 앞의 한 글자를 여러 글자로 수정하기 cw -  커서 위치의 한 단어를 수정하기 c0 -  커서 위치부터 줄의 처음까지 수정하기 C  -  커서 위치부터 줄의 끝까지 수정하기 cc -  커서가 있는 줄을 수정하기 cj -  커서가 있는 줄과 그 다음 줄을 수정하기 ck -  커서가 있는 줄과 그 앞줄을 수정하기
  • 복사와 붙여넣기 yw  -  커서 위치부터 단어의 끝까지 복사하기 y0  -  커서 위치부터 줄의 처음까지 복사하기 y$  -  커서 위치부터 줄의 끝까지 복사하기 yy  -  커서가 있는 줄을 복사하기 yj  -  커서가 있는 줄과 그 다음 줄을 복사하기 yk  -  커서가 있는 줄과 그 앞줄을 복사하기 p   -  커서의 다음 위치에 붙여넣기 P   -  커서가 있는 위치에 붙여넣기
  • 작업취소명령 u  -  작업 취소하기(undo) U  -  그 줄에 행해진 작업 모두 취소하기 .   -  조금 전에 했던 명령을 반복하기
  • 검색 및 교체 :s/reg/req/ - 현재행 첫번째로 일치하는 단어 변경 :s/reg/req/g - 현재행 일치하는 모든 단어 변경 :%s/reg/req/ - 확인하지 않고 전역 변경

○ 저장 및 종료키의 종류 ( 커서이동모드에서 명령모드로)

:q   -  아무런 변경을 하지 않았을 때 종료하기 :q!  -  변경된 내용을 저장하지 않고 강제 종료하기 :wq  -  저장하고 종료하기(write and quit) :x   -  wq와 같은 기능

행번호 보기 :set number  -  행번호 보기( = :se nu) :set nonumber - 행번호 보기 해제( = :se nonu)
:w - 문서 저장하기 :q - 현재 문서 닫기 :q! - 저장하지 않고 닫기 :wq - 저장하고 닫기 :숫자 - 지정한 라인넘버로 이동 :new - 가로로 분할된 창 열기 :vs - 세로로 분할된 창 열기 Ctrl + w - 분할창 간에 이동하기 :tabnew - 새로운 탭 열기 :gt - 다음 탭으로 이동하기 :gT - 이전 탭으로 이동하기 :e ./ - 현재 탭에 오픈할 파일 탐색하기( ./ 는 현재위치에서 탐색 시작) :colorscheme 스키마명 - VIM의 칼라스키마를 변경함(blue, desert, evening 등.. 스키마명에서 탭누르면 자동완성됨) zc - 코드 접기(fold) zo - 접힌 코드 펼치기 zd - fold 지우기 zR - 접힌 코드 모두 펼치기 zM - 코드 모두 접기 zD - 모든 fold 지우기 :buffers - 현재 Vim에서 여러 파일을 열었을때 버퍼에 있는 목록 확인 :buffer 숫자 - 버퍼 목록에 나온 숫자를 입력하면 해당 파일을 오픈함 ( :buffer 대신 :b 도 가능) :bnext - 버퍼에 있는 다음 파일로 이동 ( :bn 도 가능) :bprevious - 버퍼에 있는 이전 파일로 이동 ( :bp 도 가능) :ball - 버퍼 목록에 있는 파일들이 가로로 분할된 창에 열림
단축키가 너무 방대에서 일단 쓰는것 위주로만 정리해 봅니다. 더 자세한 내용은 Vim Documentation을 참고하세요. 처음에는 많이 힘들었는데 IDE의 도움을 많이 받지 못하는 개발을 할때는 VIM을 쓸때도 아주 많이 부족하지 않아서 슬슬 사용할만한 정도는 되더군요.(아직도 화살표키로 손이 자꾸 가기는 하지만요 ㅎㅎㅎ)
차례
1. vim 이란
2. VIM의 기본사용법 익히기
2.1. vim 모드
2.2. 명령어모드의 사용
2.2.1. 커서 이동
2.2.2. 화면 스크롤
2.2.3. 마크 이동
2.2.4. 입력 명령
2.2.5. 편집명령
2.2.5.1. 편집(none visual block 모드)
2.2.5.2. Undo (되돌리기)
2.2.5.3. 블럭 지정
2.2.5.4. 편집(visual block 모드)
2.3. ex 모드
2.3.1. 찾기/치환
2.3.2. 파일 저장, 열기, 종료
3. 개발자를 위한 vim 사용팁
3.1. 화면 나누기
3.1.1. 화면 이동
3.1.2. 파일 네비게이션
3.2. 파일 네비게이션 바 만들기
3.3. 여러개의 파일 편집하기
3.4. 잠시 쉘로 나가기
3.5. 선택된 block 를 다른 이름으로 저장하기
3.6. 빠른 괄호 이동
3.7. 위치 마크(mark)하기
3.8. 폴더(접기) 기능이용하기
3.9. 간단한 man 페이지 참조
3.10. 함수/변수명 자동완성
3.11. ctags 를 이용한 쏘쓰 분석
3.12. 자동들여쓰기
3.13. 탭사이즈 조정하기
3.14. 라인 넘버링
3.15. 코드를 HTML로 저장하기
3.16. vim 설정파일 만들기

1. vim 이란

vim 은 유닉스 계열에서 전통적으로 널리 사용도던 vi 의 improve 즉 undo, syntax coloring, split windows 등의 기능을 포함시킨 vi 의 보강된 프로그램이다. 이 문서는 vim 의 기본적인 사용법과, 프로그래밍을 위한 여러가지 팁을 담고 있다. vim 버젼은 6.0 을 기준으로 한다. vim(vi)에 대한 자세한 사용방법은 여기에서는 제시하지 않을것이다. 가장 기본적인 사항만 언급할것이며, 자세한 사용법은 vi 사용자그룹 사이트를 참고하기 바란다.

2. VIM의 기본사용법 익히기

이번장에서는 vim의 기본적인 사용법에 대해서 알아보도록 하겠다. 위에서 언급했듯이, 이문서는 VIM의 레퍼런스 가이드는 아니다. 기본적인 사용이 가능하도록 가장 기초적인 내용들만 다룰것이다.

2.1. vim 모드

다른 에디터를 사용하던 유저가 vim을 처음 접하면서 가장 난감해 하는 부분이 vim의 상태(mode)개념이다.vim은 다른 에디터들과 달리, 실행을 시켰다고 해서 즉시 입력이 이루어지지 않는다. 많은 vim을 처음 접하는 유저는 어떻게 글을 입력할지 몰라서 vim의 사용을 접게되는 경우가 발생하는데, 여기에 그 이유가 있다. vi 는 크게 세가지 상태로 나뉘어진다. 첫번째가 명령어 모드로 키입력이 바로 실행되는 상태이며, 다음은 상태모드로 실제 문서를 편집하는 모드 마지막이 ex 상태로 ex 명령을 실행시키는 상태이다. vi 를 처음실행시키면 입력모드가 아닌 명령모드 상태에 놓이게 된다. 이 상태에서는 문자의 입력이 이루어지지 않으며, 찾기등과 같은 간단한 문서관련 명령을 실행할 수 있다. 이 명령모드 상태에서 ":" 키를 누르면 ex 상태로 a, i, o 키 등을 누르면 입력 상태로 넘어가게 된다. 일단 입력상태로 들어가게 되면 문서 편집을 할수 있게 되는데, 이때 ESC 키를 누르면 명령모드 상태로 넘어가게 된다.
표 1. vim의 상태(mode)
명령 상태 처음 vim을 실행했을때, 입력상태/명령상태에서 ESC입력시 간단한 찾기, 커서 이동, ex 상태로 넘어가기
ex 상태 명령 상태에서 (":") 각종 치환, 저장, 파일읽기, vim설정등과 같은 대부분의 작업들
입력 상태 명령 상태에서 (a,i,o 키 입력) 내용 입력

2.2. 명령어모드의 사용

우리는 명령모드에서 여러가지 명령을 입력함으로써, 복사, 붙이기, 삭제 문서입력, 문서저장, 문서불러오기, 커서이동 등의 작업을 할수 있다. 이번 장에서는 이러한 명령모드에서 사용되는 각종 명령어에 대해서 알아보도록 하겠다.

2.2.1. 커서 이동

기본적으로 vi 는 입력모드에서 방향키를 이용해서 커서 이동을 하지 못하도록 되어있다. 비록 최근의 vim 이 입력모드에서 방향키를 이용한 커서 이동을 지원하고 있기는 하지만, 명령모드에서의 키이동이 훨씬 빠르고 편하므로, 처음에는 좀 어색하더라도 명령모드에서의 키 이동을 익히도록 하자.
표 2. 커서 이동
k 커서를 위로 움직임
j 커서를 아래로 움직임
h 커서를 왼쪽으로 움직임
l 커서를 오른쪽으로 움직임
- 커서를 줄의 처음으로 옮김
e, E 다음단어의 끝으로, 문자단위 이동
w, W 다음단어의 처음으로, 문자단위 이동
$ 줄의 마지막으로
0 줄의 처음으로
^ 줄의 처음으로(공백이 아닌 처음시작되는 문자)
Shift+g 문서의 마지막으로 이동한다.
gg, 1g 문서의 처음으로 이동한다. 1대신 다른 숫자를 입력하면 해당 숫자의 라인으로 이동한다.
), ( 다음, 이전 문장의 처음으로
}, { 다음, 이전문단의 처음으로
]], [[ 다음, 이전 구절의 처음으로

2.2.2. 화면 스크롤

위의 커서명령 이동이 매우 편하기는 하지만, 만약 페이지가 한 2000라인 될경우, 위의 커서를 이용해서 한줄씩 이동하는데에는 너무 많은 시간이 걸릴것이다. 그래서 vi 에서는 화면 단위의 스크롤이 가능한 명령들을 제공한다. 아래의 화면 스크롤 명령어들을 익히면 빠른 위치이동을 위해 매우 유용하게 사용할수 있다. ^F 는 CTRL+F 를 의미한다.
표 3. 화면 스크롤
^F 한 화면 을 앞으로 스크롤
^B 한 화면 을 뒤로 스크롤
^D 반 화면 을 앞으로 스크롤
^U 반 화면 을 뒤로 스크롤
^E 한줄 앞으로 스크롤
^Y 한줄 뒤로 스크롤
Shift + h 화면의 맨 윗줄로
Shift + m 화면의 중간줄로
Shift + l 화면의 맨 아랫줄로

2.2.3. 마크 이동

일종의 책갈피 기능이라고 보면 된다. 자주 참조해야할 라인에 마크를 해놓고 필요할때 곧바로 마크된 영역으로 이동하기 위해서 사용한다. 마크는 mx 형식으로 사용할수 있다. x 는 (a~z)까지의 문자로 마크된 영역의 이름을 지정하기 위해서 사용한다. 마크된 영역으로 이동하기 위해서는 'x 와 `x 를 사용한다. 'x 는 마크된 라인의 가장 앞으로 이동하고, `x 는 마크된 라인의 정확한 위치로 이동한다.

2.2.4. 입력 명령

지금 vi 를 실행시켜보자. vi 는 기본적으로 명령모드로 실행되므로, 지금상태에서는 문서 작성을 할수 없을것이다. 우리는 다음과 같은 키입력을 통해서 입력모드 상태로 전환할수 있다.
표 4. 입력 명령
i 현재위치에서 삽입
I 현재줄의 처음위치에서 삽입
a 현재위치에서 한칸앞으로 이동해서 삽입
A 현재줄의 마지막위치에서 삽입
o 새로운 줄을 커서 아래에 연다
O 새로운 줄을 커서 위연다
s 현재 위치의 문자를 지우고 입력모드로 들어간다.
S 현재위치의 라인을 지우고 입력모드로 들어간다.

2.2.5. 편집명령

여기에서는 vi의 편집기능인 복사, 붙이기, 삭제에 대해서 알아 보도록 하겠다. 다른 에디터들은 보통 마우스를 이용해서 블럭을 지정해서 편집을 하는 반면, vi 는 명령어 모드에서 키보드 만을 이용해서 편집이 가능하므로, 매우 편리하고 빠르게 편집작업들이 가능하다. 또한 라인단위 블럭, 블럭단위 블럭등의 선택 모드를 지원함으로써, 문서에서 원하는 부분에 대한 작업을 좀더 쉽게 할수 있다.

2.2.5.1. 편집(none visual block 모드)

visual block 모드가 아닌 상태에서이 편집에 관한 내용이다.
표 5. 복사,삭제,붙이기
y 한줄 복사
yn 현재 라인에서부터 n라인만큼을 복사
p 복사된 내용 붙이기
dd 한줄삭제
dw 한단어 삭제
Shift+d, d$ 현재커서 위치에서 마지막까지 삭제
Shift+j 현재 행의 개행문자를 제거한다. 즉 아래라인을 현재라인에 덧붙인다.

2.2.5.2. Undo (되돌리기)

vim 은 다중의 undo 기능을 지원한다. 뒤로 되돌리고 싶다면 단지 'u'키만 입력하면 된다.

2.2.5.3. 블럭 지정

이번엔 블럭지정, 그중에서도 vim 에서 지원하는 visual 블럭 지정에 대해서 알아보겠다. vim visual 블럭 지정 기능을 사용할경우 지정범위가 반전되면서 눈에 보이기 때문에, 효과적인 블럭지정이 가능하도록 도와준다. 범위지정을 위해서 'hjkl', 'Shift+g,GG' 과 같은 이동명령 과 화면스크롤 명령을 사용해서 범위지정을 좀더 빠르게 할수 있다.
표 6. 블럭지정
v 단어단위로 블럭지정이 가능하다. 블럭범위는 이동명령인 'hjkl' 로 원하는 범위 만큼 지정할수 있다.
Shift+v 라인단위 블럭지정이다. 라인전체가 선택되며, 위아래 이동명령 'hj' 으로 범위 지정이 가능하다.
Ctrl+v 블럭단위 블럭지정이다. 4각형의 블럭지정이 가능하며 이동명령인 'hjkl' 로 원하는 범위를 지정할수 있다.
Shift+v 와 같이 블럭지정을 한후 Shift+G 를 입력하면 현재라인부터 마지막 라인까지가 블럭 지정이 될것이다.

2.2.5.4. 편집(visual block 모드)

일단 vim 의 visual 블럭 지정 기능을 이용해서 편집하기 원하는 블럭을 지정했다면, 각종 편집명령을 이용해서 복사, 붙이기, 삭제 작업이 가능하다. 블럭을 지정한 상태에서 아래의 명령을 이용해서 편집을 하면 된다. 명령어는 기본적으로 none visual block 모드의 편집 명령어과 같다.
표 7. 편집(복사, 삭제, 붙이기)
y 지정된 블럭을 복사한다.
p 복사된 블럭을 현재라인(커서) 아래에 붙인다.
d 지정된 블럭을 삭제한다.
dd 현재라인을 삭제한다.

2.3. ex 모드

2.3.1. 찾기/치환

vim 의 기능중 가장편리한 기능으리면 뭐니뭐니 해도, 정규표현식을 이용한 강력한 찾기기능과 치환기능이라고 할수 있을것이다. 물론 다른 대부분의 에디터들도 찾기기능과 치환기능을 제공하긴 하지만, vim 의 기능은 다른 에디터들에 비해서 정말로 독보적인 편리함과 강력함을 제공한다. vi 사용자가 다른 에디터로 넘어가기 힘든이유중 가장큰 이유가, 바로 "키를 이용한 방향입력" 과 "찾기 및 치환" 기능 때문이다. 사실 찾기 치환의 기능을 제대로 이해하고 사용하기 위해서는 정규표현식(regular expression) 에 대한 이해가 필요로 하는데, 이것은 다음의 사이트를 참조하기 바란다. 정규 표현식의 간략한 소개 먼저 찾기 기능에 대해서 알아보겠다. 찾기기능은 ':/패턴/' 를 이용 하면된다. 찾기 원하는 문자혹은 패턴을 입력하고 엔터키를 누르면 현재 커서위치에서 가장 가까운 곳에 위치한 문자열로 커서를 이동시킨다(문서 아래방향으로). 다음 문자열을 찾기를 원한다면 'n'키를 누르면 된다. 문서에서 가장 마지막에 이르르게 되면, 문서의 가장처음부터 다시 찾기 시작한다. 'Shift+n' 을 이력하면 반대 방향(문서의 위쪽으로)으로 찾기를 시작한다. 치환이야 말로 vim 의 꽃이라고 할수 있다. :[범위]s/[oldpattern]/[newpattern]/ 의 형식으로 사용하면 된다. 범위 지정은 visual block 을 이용할수도 있으며, 직접 범위를 입력할수도 있다. visual block 를 이용한 치환은 visual block 를 지정한다음 ':' 를 입력해서 ex 모드로 넘어가면 된다. 그리고나서 ':'<,'>s/[oldpattern]/[newpattern/' 과 같은 방법으로 치환하면 된다. visual block 를 사용하지 않고 직접범위를 입력할수도 있다. :[시작],[마지막]s/[old]/[new]/ 식으로 범위를 지정하면 된다. 여기에는 몇가지 지정된 범위를 위한 특수 기호들이 있다. '%' 는 전체문서(처음부터 끝까지), '.' 은 현재, '$' 은 마지막 을 나타낸다. 숫자를 입력할경우 숫자는 라인을 나타낸다. 다음은 간단한 사용예이다.
# 문서 처음부터 마지막까지의 char 를 _char_ 로 치환한다. 
:%s/char/_&_/g

# 현재(커서위치)부터 마지막까지의 char 를 _char_ 로 치환한다.
:.,$s/char/_&_/g

# buf_.*[255], buf_in[255], buf_get[255] 와 같은 문자열을 hello 로 변경한다.  
:1,10s/buf_.*\[255\]/hello/g
마지막에 쓰인 'g' 는 global 이다. 즉 해당 라인 전체에 걸쳐서 검색후 치환한다. 'g' 를 사용하지 않을경우 라인에서 처음에 검색된 문자만 치환하고 다음 라인으로 넘어간다.

2.3.2. 파일 저장, 열기, 종료

파일열기의 경우 vi 를 실행시킬대 명령행 옵션으로 열기가 가능하다. 또한 vi 를 이미 실행 시킨후에도 명령모드에서 명령을 입력함으로 파일을 열수 있다. 열고자 하는 파일이 이미 존재할경우에는 존재하는 파일이 열리고, 열고자 하는 파일이 존재하지 않을경우 새로운 파일이 만들어진다.
표 8. 저장,열기,종료
:e [filename] filename 으로 파일열기
:q, :q!, :wq 종료, 강제종료, 저장후 종료
:w, :w [filename] 현재파일명으로 저장, filename 로 저장
:<범위>w [filename] 지정한 범위만 다른 파일로 저장
:e [filename] filename 을 편집하기 위해서 연다
ZZ 지금파일을 저장하고 vim 을 종료한다.
:f 현재 작업중인 파일의 이름과, 라인수를 출력한다

3. 개발자를 위한 vim 사용팁

3.1. 화면 나누기

vim 은 수평나누기와 수직나누기를 제공한다. 수평나누기는 ":split [파일이름]" 수직나누기는 "vs [파일이름]" 으로 나눌수 있다. 파일이름을 지정한 경우, 새로 만들어진 창에는 파일이름 을 가지는 파일이 열리고, 파일이름을 지정하지 않을경우 똑같은 파일이 열린다. 이 기능은 현재 파일의 다른 부분을 참조하고 싶을때 유용하게 사용할수 있다(참조하는 부분으로 이동하기 위해서 왔다갔다 하지 않아도 되므로). 또한 ":10split [파일이름]", "10vs [파일이름]" 등으로 창의 크기를 조절해 줄수도 있다. 창 나누기는 2개 이상 나누기도 가능하다. 이렇게 창을 분할시켜 놓으면 쏘쓰를 참조하기도 편하고, 무엇보다 편집(삭제,복사,붙이기)가 가능하므로 훨씬더 작업을 수월하게 할수 있다.

3.1.1. 화면 이동

명령 모드에서 CTRL+ww 를 입력하면 된다. 그러면 아래창으로 이동한다. 임의로 이동하기 위해서는 Ctrl+w 를 입력한 상태에서 이동명령[hjkl]를 이용하면 원하는 방향으로 창이동이 가능하다.

3.1.2. 파일 네비게이션

vim 6.0 부터는 파일네비게이션 기능이 존재합니다. 예를들어 vi 로 파일을 열때 파일을 디렉토리로 지정하면 해당디렉토리의 내용이 네비게이션 되고, 디렉토리 이동및 파일 선택이 가능하다.
 
vi ./   # 현재 디렉토리내용을 네비게이션 해준다.

3.2. 파일 네비게이션 바 만들기

윈도우의 울트라 에디트와 같은 프로그램을 보면 왼쪽에 파일네비게이션이 있어서 원하는 파일을 바로 선택해서 편집하는 기능이 있다. vim 으로도 이러한 기능을 구현할수 있다. 이것은 vim 의 file navigation 기능과 창나누기 기능을 이용해서 구현하면 된다. vi 가 실행되 상태에서 수직창 나누기 기능을 이용해서 ":20vs ./" 명령을 내려보자 그럼 그림과 같이 오른쪽에 파일 네비게이션 바가 생김을 알수 있다.
그림 1. 파일네비게이션을 만든 화면
이제 열기를 원하는 파일위치에 가서 shift+o 를 입력해보자, 그럼 옆의 편집창에 새로운 파일이 열리는것을 알수 잇을것이다. 여기에 더해서 편집장을 split 로 나누면, 여러개의 파일을 오가면서 편집이 가능해질 것이다. [vim 7에서는 shift+p로 단축키가 변경됐다]

3.3. 여러개의 파일 편집하기

위에서는 창나누기를 이용한 여러개의 파일편집에 대해서 알아봤는데, 또다른 방법이 있다. 처음에 vim 을 통하여 여러개의 파일을 open 하고 여러개의 열린 파일을 이동하면서 편집하는 방법이다. 먼저 vim을 다음과 같이 실행시킨다.
 
[yundream@localhost test]# vim file1.txt file2.txt ...
그러면 처음 화면은 file1.txt 편집화면일것이다. 2번째 파일인 file2.txt 편집화면으로 넘어가길 원한다면(앞에 있는 파일 편집)
:n
file2.txt 에서 file1.txt 를 편집하길 원한다면(뒤에 있는 파일편집)
:e#
split 를 이용해서 여러개의 파일을 편집할때와 마찬가지로, 각종 편집기능(복사,삭제,붙이기)이 서로 공유되므로 편하게 작업이 가능하다.

3.4. 잠시 쉘로 나가기

보통 vim상에서 쉘명령어를 실행시키기 위해서 :![명령어] 를 사용하는데, 이것 보다는 Ctrl+z 를 이용해서 쉘로 빠져나가서 작업하는게 더 편하다. shell 이 job control 기능을 이용한것으로, 쉘에서 원하는 작업을 수행하후 fg 명령을 이용해서 다시 vi 편집 상태로 되돌아 올수 있다. vim 사용자를 보면 가끔 쉘작업을 하기 위해서 vim 을 아예 종료 시켜서 쉘로 빠져나간 다음에 작업을 하고 vim 을 다시 실행시키는 경우가 있는데, 이제는 그럴필요가 없이 좀더 편하게 작업을 할수 있을것이다.

3.5. 선택된 block 를 다른 이름으로 저장하기

split 기능을 이용해서 창을 나누고, 원하는 블럭을 선택해서 복사한다음에, 새로만든창에 가져다 붙이기를 하면 된다. 그러나 이방법은 조금 복잡한 감이 없잖아 있다. 이럴때는 블럭을 선택해서 :'<,'>w [파일명] 하면 좀더 간단하게 원하는 작업을 수행할수 있다.

3.6. 빠른 괄호 이동

C나 C++ 을 사용하다보면 제어문이나 함수에서 많은 괄호('{','(')를 만나게 된다. 이때 괄호의 제일 마지막으로 이동하고 싶을때가 있을것이다. 이럴때는 ']}' 를 사용하면 된다. '[{' 를 사용하면 괄호의 처음으로 이동한다.

3.7. 위치 마크(mark)하기

일종의 북마크기능으로 자주참조할만한 라인을 마킹해두고 필요할때 간단히 해당 마킹지역으로 이동하기 위해서 사용한다. 마킹을 위해서는 명령모드에서 m키를 눌러서 마킹모드로 들어가면 된다. 그리고 영문 [a-zA-Z]키중 아무거나 눌러주면 된다. 만약 a를 눌러주었다면, 현재라인은 a이름으로 마킹된다. 이후 작업을하다가 a마킹라인으로 가고 싶다면 'a 해주면된다. 이 상태에서 원래 라인으로 되돌아가고 싶다면 ''를 눌려주면 된다. 물론 다중마킹도 허용한다. 마킹할수 있는 문자는 단일영문자이다. 마킹에 사용되는 영문자는 대소문자를 구분함으로 최대마킹가능한 수는 27*2가 될것이다.

3.8. 폴더(접기) 기능이용하기

vim 6.0 에 새로이 포함된 좋은 기능으로 코드의 특정영역을 접을수 있다. 그럼으로 코드를 분석할때 쓸데 없는 부분을 감춰줘서 좀더 편하게 분석이 가능합니다. visual block 를 이용해서 원하는 영역을 선택한다음 :zf 를 이용하면 해당영역이 접힌다. :zo 를 사용하면 접힌영영을 원상태로 복구할수 있고 :zc 를 사용하면 해당영역을 다시 접을수 있다. 또한 다중 접기를 허용해서 접근구역을 다시 접을수도 있다.

3.9. 간단한 man 페이지 참조

vim 을 이용 코딩중에 함수의 프로토 타입이 생각나지 않을때 주로 man page 를 참조하게 된다. 보통은 창을 하나따로 띄워서 그곳에서 man page 를 보는데, 코딩중에 간단하게 해당 함수에 대한 man page 를 볼수 있다. man page 를 원하는 함수 위로 커서를 옮긴다음 Shift + k 를 입력하면 함수의 man page 가 뜰것이다. 'q' 를 입력해서 man page 를 종료시키면 원래의 vim 화면으로 되돌아온다.

3.10. 함수/변수명 자동완성

코딩중에 가장 범하기 쉬운 잘못중의 하나가 변수명및 함수명 오타일것이다. 또 변수명이 기억이 잘 나지 않아서 처음 선언한곳을 다시 확인하는 작업역시 코딩을 매우 번거롭게 한다. 이때 함수 자동완성 기능을 이용하면 이러한 염려들을 줄일수 있다. int client_sockfd 라고 변수 선언을 했다고 하자. 코딩중에 client_sockfd 를 쓸일이 있다면 cli^p 를 입력해보자. 그러면 변수 이름이 자동으로 완성되는것을 볼수 있을것이다. ^p는 Ctrl+p 이다.

3.11. ctags 를 이용한 쏘쓰 분석

쏘쓰를 분석하는데 있어서 가장 중요한 것은 역시 함수를 분석해서, 함수가 어떤일을 하는지 알아내는 것이다. ctags 를 이용하면 이러한 쏘쓰 분석작업을 좀더 수월하게 할수 있다. ctags 와 관련된문서는 ctags 를 이용한 쏘쓰 분석 을 참고하기 바란다.

3.12. 자동들여쓰기

프로그래밍 할때 indent 는 쏘쓰코드를 보기좋게 만들기 위한 필수 사항이다. 보통 tab 을 주로 쓰는데,
:set ai
명령을 이용하면 자동적으로 indent (auto indent) 를 적용시켜주므로, 좀더 코딩에만 집중할수 있도록 도와준다.
:set noai
명령을 사용해서 auto indent 상태를 해제할수 있다. 요즘의 vim 은 기본적으로 auto indent 상태이므로, 별다른 설정없이 편하게 사용가능하다. 그러나 웹에서 가져다 붙이기를 할때 여기에 auto indent 가 적용되어서 걷잡을 수 없이 tab 이 들어가는 경우가 생길때도 있는데, 이럴때 set noai 를 이용해서 auto indent 를 해제하고 가져다 붙이기를 하면 된다.

3.13. 탭사이즈 조정하기

쏘쓰에서 indent 를 위해서 주로 탭을 사용하는데, 보통 이 탭 사이즈는 8로 되어 있다. 그런데 8이란 탭사이즈가 때로는 너무 커서, 쏘쓰가 화면밖으로 나가서 오히려 쏘쓰 보기를 어렵게 만들때도 있다. 이럴때 는 탭사이즈를 줄여야 하는데 다음과 같은 명령을 통해서 탭사이즈 변경이 가능하다.
:set ts=4

3.14. 라인 넘버링

코딩하다보면 라인넘버가 있으면 할때가 있다. 그럴때는
:set nu
하면 된다.
그림 2. 라인 넘버링
라인넘버를 없애고 싶다면,
:set nonu
하면 된다.

3.15. 코드를 HTML로 저장하기

vim 은 또한 코드를 HTML 형태로 저장하는 기능을 가지고 있다. 이 기능을 이용하면 syntax highlight 된 상태 그대로 HTML로 변환이 가능하다. 쏘쓰코드의 예제를 만들어서 웹상에 올리고자 할때 유용하게 사용할수 있는 기능이다.
:so $VIMRUNTIME/syntax/2html.vim

3.16. vim 설정파일 만들기

지금까지 우리는 다양한 설정을 통해서 vim 을 좀더 쉽게 사용하는 방법을 알아 보았다. 그런데, 탭사이즈를 적용하기 위해서 vim 을 실행시킬때 마다 ":set ts=4" 이런식으로 하면 작업이 매우 귀찮을것이다. 이럴때는 vim 을 위한 설정파일을 만들어서, vim 이 시작할때 설정파일을 읽어들여서 환경이 자동으로 설정되도록 하면된다. 자기의 계정(Home) 디렉토리에 보면, .vimrc 라는 파일이 존재 할것이다. (존재하지 않는다면 만들도록한다) 이것이 설정파일로 아래와 같은 방법으로 자기가 원하는 내용을 설정하면 된다.
set ts=4
set nu

linux 서버에 메일서버 설정

1. sendMail을 설치하기전에 postfix가 설치되어 있는지 확인

 

2. #service postfix status

 

3. 만약 postfix가 설치 되어 있으면 sendmail 설치하지 말것

 

4. sendmail을 설치해도 이전에 postfix가 먼저 설치가 되어 있기 때문에 우선권이 postfix에게 있음.

 

5. 설치 #yum install postfix*

 

6. # yum install postfix*

 

7. # vi /etc/postfix/main.cf

myhostname = mail.neulwon.com        // 현재 사용중인 메일 서버 호스트
mydomain = neulwon.com        // 메일 주소에 사용할 도메인
inet_interfaces = all        // 모든 IP에서 25번 포트 접근 허용
mydestination = neulwon.com        // 메일을 수신 받을 도메인 도메인
mynetworks = 0.0.0.0/0        // 릴레이 설정하는 부분입니다. outlook 등으로 메일 발송하려면 IP를 등록해야 하는데, 불특정 IP나 유동 IP로 인해 모든 IP를 허용한 상태 입니다.스팸발송 방지를 위해 메일 발송 인증 설정은 꼭 해두어야 합니다.

8. 구동 #/etc/init.d/postfix start

java sendmail에서 smtp 포트를 587포트로 변경하기

sendmail에서 smtp 포트를 587포트로 변경하기

sendmail 에서 submission port를 변경 하는 방법을 아래와 같이 알려드립니다.

1. sendmail 폴더 이동

# cd /etc/mail/

2. sendmail.mc 내용 수정

# vi sendmail.mc dnl 주석해제 변경전) dnl DAEMON_OPTIONS(`Port=submission, Name=MSA, M=Ea')dnl 변경후) DAEMON_OPTIONS(`Port=submission, Name=MSA, M=Ea')dnl m4 sendmail.mc > sendmail.cf

3. 센드메일 리스타트

# /etc/init.d/sendmail restart Shutting down sendmail: [  OK  ] Starting sendmail: [  OK  ]

4. Listen 포트들중 587 포트를 확인

# netstat -anp | grep LISTEN  

5. How to enable port 587 (submission) in postfix

Some internet access providers have port 25 disabled in their routers to prevent spam. If you run your own mailserver in a datacenter, you might have to enable the submission port (587) in postfix to be able to send emails from your local email client to your own mailserver. To enable port 587, edit the file /etc/postfix/master.cf vi /etc/postfix/master.cf and remove the # in front of the line: #submission inet n – n – – smtpd so that it looks like this: submission inet n – n – – smtpd and restart postfix: /etc/init.d/postfix restart
Be Sociable, Share!

Git 브랜치 - 브랜치와 Merge의 기초

3.2 Git 브랜치 - 브랜치와 Merge의 기초

브랜치와 Merge의 기초

실제 개발과정에서 겪을 만한 예제를 하나 살펴보자. 브랜치와 Merge는 보통 이런 식으로 진행한다:
  1. 작업 중인 웹사이트가 있다.
  2. 새로운 이슈를 처리할 새 Branch를 하나 생성.
  3. 새로 만든 Branch에서 작업 중.
이때 중요한 문제가 생겨서 그것을 해결하는 Hotfix를 먼저 만들어야 한다. 그러면 다음과 같이 할 수 있다:
  1. 새로운 이슈를 처리하기 이전의 운영(Production) 브랜치로 복원.
  2. Hotfix 브랜치를 새로 하나 생성.
  3. 수정한 Hotfix 테스트를 마치고 운영 브랜치로 Merge.
  4. 다시 작업하던 브랜치로 옮겨가서 하던 일 진행.

브랜치의 기초

먼저 커밋을 몇 번 했다고 가정하자.


그림 3-10 현재 커밋 히스토리

이슈 관리 시스템에 등록된 53번 이슈를 처리한다고 하면 이 이슈에 집중할 수 있는 브랜치를 새로 하나 만든다. Git은 어떤 이슈 관리 시스템에도 종속돼 있지 않다. 브랜치를 만들면서 Checkout까지 한 번에 하려면git checkout 명령에 -b라는 옵션을 준다.
$ git checkout -b iss53
Switched to a new branch 'iss53'
위 명령은 아래 명령을 줄여놓은 것이다:
$ git branch iss53
$ git checkout iss53
그림 3-11은 위 명령의 결과를 나타낸다.


그림 3-11 브랜치 포인터를 새로 만듦

iss53 브랜치를 Checkout했기 때문에(즉, HEAD는 iss53 브랜치를 가리킨다) 뭔가 일을 하고 커밋하면 iss53 브랜치가 앞으로 진행한다:
$ vim index.html
$ git commit -a -m 'added a new footer [issue 53]'


그림 3-12 진행 중인 iss53 브랜치

다른 상황을 가정해보자. 만드는 사이트에 문제가 생겨서 즉시 고쳐야 한다. 버그를 해결한 Hotfix에 'iss53'이 섞이는 것을 방지하기 위해 'iss53'와 관련된 코드를 어딘가에 저장해두고 원래 운영 환경의 소스로 복구해야 한다. Git을 사용하면 이런 노력을 들일 필요 없이 그냥 master 브랜치로 옮기면 된다.
그렇지만, 브랜치를 이동하려면 해야 할 일이 있다. 아직 커밋하지 않은 파일이 Checkout할 브랜치와 충돌 나면 브랜치를 변경할 수 없다. 브랜치를 변경할 때에는 워킹 디렉토리를 정리하는 것이 좋다. 이런 문제를 다루는 방법은(주로, Stash이나 커밋 Amend에 대해) 나중에 다룰 것이다. 지금은 작업하던 것을 모두 커밋하고 master 브랜치로 옮긴다:
$ git checkout master
Switched to branch 'master'
이때 워킹 디렉토리는 53번 이슈를 시작하기 이전 모습으로 되돌려지기 때문에 새로운 문제에 집중할 수 있는 환경이 만들어진다. Git은 자동으로 워킹 디렉토리에 파일들을 추가하고, 지우고, 수정해서 Checkout한 브랜치의 스냅샷으로 되돌려 놓는다는 것을 기억해야 한다.
hotfix라는 브랜치를 만들고 새로운 이슈를 해결할 때까지 사용한다:
$ git checkout -b hotfix
Switched to a new branch 'hotfix'
$ vim index.html
$ git commit -a -m 'fixed the broken email address'
[hotfix]: created 3a0874c: 'fixed the broken email address'
 1 files changed, 0 insertions(+), 1 deletions(-)


그림 3-13 master 브랜치에서 갈라져 나온 hotfix 브랜치

운영 환경에 적용하려면 문제를 제대로 고쳤는지 테스트하고 master 브랜치에 합쳐야 한다. git merge 명령으로 다음과 같이 한다:
$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast forward
 README |    1 -
 1 files changed, 0 insertions(+), 1 deletions(-)
Merge 메시지에서 'Fast forward'가 보이는가? Merge할 브랜치가 가리키고 있던 커밋이 현 브랜치가 가리키는 것보다 '앞으로 진행한' 커밋이기 때문에 master 브랜치 포인터는 최신 커밋으로 이동한다. 이런 Merge 방식을 'Fast forward'라고 부른다. 다시 말해서 A 브랜치에서 다른 B 브랜치를 Merge할 때 B가 A 이후의 커밋을 가리키고 있으면 그저 A가 B의 커밋을 가리키게 할 뿐이다.
이제 hotfix는 master 브랜치에 포함됐고 운영환경에 적용할 수 있다(그림 3-14).


그림 3-14 Merge 후 hotfix 브랜치와 같은 것을 가리키는 master 브랜치

문제를 급히 해결하고 master 브랜치에 적용하고 나면 다시 일하던 브랜치로 돌아가야 한다. 하지만, 그전에 필요없는 hotfix 브랜치를 삭제한다. git branch 명령에 -d 옵션을 주고 브랜치를 삭제한다.
$ git branch -d hotfix
Deleted branch hotfix (3a0874c).
자 이제 이슈 53번을 처리하던 환경으로 되돌아가서 하던 일을 계속 하자(그림 3-15):
$ git checkout iss53
Switched to branch 'iss53'
$ vim index.html
$ git commit -a -m 'finished the new footer [issue 53]'
[iss53]: created ad82d7a: 'finished the new footer [issue 53]'
 1 files changed, 1 insertions(+), 0 deletions(-)


그림 3-15 master와 별개로 진행하는 iss53 브랜치

위에서 작업한 hotfix가 iss53 브랜치에 영향을 끼치지 않는다는 점을 이해하는 것이 중요하다. git merge master 명령으로 master 브랜치를 iss53 브랜치에 Merge하면 iss53 브랜치에 hotfix가 적용된다. 아니면 iss53 브랜치가 master에 Merge할 수 있는 수준이 될 때까지 기다렸다가 Merge하면 hotfix와 iss53가 합쳐진다.

Merge의 기초

53번 이슈를 다 구현하고 master 브랜치에 Merge하는 과정을 살펴보자. master 브랜치에 Merge하는 것은 앞서 살펴본 hotfix 브랜치를 Merge하는 것과 비슷하다. git merge 명령으로 합칠 브랜치에서 합쳐질 브랜치를 Merge하면 된다:
$ git checkout master
$ git merge iss53
Merge made by recursive.
 README |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
hotfix를 Merge했을 때와 메시지가 다르다. 현 브랜치가 가리키는 커밋이 Merge할 브랜치의 조상이 아니므로 Git은 'Fast-forward'로 Merge하지 않는다. 이러면 Git은 각 브랜치가 가리키는 커밋 두 개와 공통 조상 하나를 사용하여 3-way Merge를 한다. 그림 3-16에 이 Merge에서 사용하는 커밋 세 개가 표시된다.


그림 3-16 Git은 Merge에 필요한 공통 커밋을 자동으로 찾음

단순히 브랜치 포인터를 최신 커밋으로 옮기는 게 아니라 3-way Merge의 결과를 별도의 커밋으로 만들고 나서 해당 브랜치가 그 커밋을 가리키도록 이동시킨다(그림 3-17). 그래서 이런 커밋은 부모가 여러 개고 Merge 커밋이라고 부른다.
Git은 Merge하는데 필요한 최적의 공통 조상을 자동으로 찾는다. 이런 기능도 Git이 다른 버전 관리 시스템보다 나은 점이다. CVS나 Subversion 같은 버전 관리 시스템은 개발자가 직접 공통 조상을 찾아서 Merge해야 한다. Git은 다른 시스템보다 Merge가 대단히 쉽다.


그림 3-17 Git은 Merge할 때 Merge에 대한 정보가 들어 있는 커밋를 하나 만든다.

iss53 브랜치를 master에 Merge하고 나면 더는 iss53 브랜치가 필요 없다. 다음 명령으로 브랜치를 삭제하고 이슈의 상태를 처리 완료로 표시한다:
$ git branch -d iss53

충돌의 기초

가끔씩 3-way Merge가 실패할 때도 있다. Merge하는 두 브랜치에서 같은 파일의 한 부분을 동시에 수정하고 Merge하면 Git은 해당 부분을 Merge하지 못한다. 예를 들어, 53번 이슈와 hotfix가 같은 부분을 수정했다면 Git은 Merge하지 못하고 다음과 같은 충돌(Conflict) 메시지를 출력한다:
$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.
Git은 자동으로 Merge하지 못해서 새 커밋이 생기지 않는다. 변경사항의 충돌을 개발자가 해결하지 않는 한 Merge 과정을 진행할 수 없다. Merge 충돌이 일어났을 때 Git이 어떤 파일을 Merge할 수 없었는지 살펴보려면 git status 명령을 이용한다:
[master*]$ git status
index.html: needs merge
# On branch master
# Changes not staged for commit:
#   (use 'git add <file>...' to update what will be committed)
#   (use 'git checkout -- <file>...' to discard changes in working directory)
#
#   unmerged:   index.html
#
충돌이 일어난 파일은 unmerged 상태로 표시된다. Git은 충돌이 난 부분을 표준 형식에 따라 표시해준다. 그러면 개발자는 해당 부분을 수동으로 해결한다. 충돌 난 부분은 다음과 같이 표시된다.
<<<<<<< HEAD:index.html
<div id='footer'>contact : email.support@github.com</div>
=======
<div id='footer'>
  please contact us at support@github.com
</div>
>>>>>>> iss53:index.html
======= 위쪽의 내용은 HEAD 버전(merge 명령을 실행할 때 작업하던 master 브랜치)의 내용이고 아래쪽은 iss53 브랜치의 내용이다. 충돌을 해결하려면 위쪽이나 아래쪽 내용 중에서 고르거나 새로 작성하여 Merge한다. 다음은 아예 새로 작성하여 충돌을 해결하는 예제다:
<div id='footer'>
please contact us at email.support@github.com
</div>
충돌한 양쪽에서 조금씩 가져와서 새로 수정했다. 그리고 <<<<<<<=======>>>>>>> 가 포함된 행을 삭제하였다. 이렇게 충돌한 부분을 해결하고 git add 명령으로 다시 Git에 저장한다. 충돌을 쉽게 해결하기 위해 다른 Merge 도구도 이용할 수 있다. git mergetool 명령으로 실행한다:
$ git mergetool
merge tool candidates: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff
Merging the files: index.html

Normal merge conflict for 'index.html':
  {local}: modified
  {remote}: modified
Hit return to start merge resolution tool (opendiff):
Mac에서는 opendiff가 실행된다. 기본 도구 말고 사용할 수 있는 다른 Merge 도구도 있는데, 'merge tool candidates' 부분에 보여준다. 여기에 표시된 도구 중 하나를 고를 수 있다. Merge 도구를 변경하는 방법은 7장에서 다룬다.
Merge 도구를 종료하면 Git은 잘 Merge했는지 물어본다. 잘 마쳤다고 입력하면 자동으로 git add가 수행되고 해당 파일이 Staging Area에 저장된다.
git status 명령으로 충돌이 해결된 상태인지 다시 한번 확인해볼 수 있다.
$ git status
# On branch master
# Changes to be committed:
#   (use 'git reset HEAD <file>...' to unstage)
#
#   modified:   index.html
#
충돌을 해결하고 나서 해당 파일이 Staging Area에 저장됐는지 확인했으면 git commit 명령으로 Merge 한 것을 커밋한다. 충돌을 해결하고 Merge할 때에는 커밋 메시지가 아래와 같다.
Merge branch 'iss53'

Conflicts:
  index.html
#
# It looks like you may be committing a MERGE.
# If this is not correct, please remove the file
# .git/MERGE_HEAD
# and try again.
#
어떻게 충돌을 해결했고 좀 더 확인해야 하는 부분은 무엇을 어떻게 했는지 자세하게 기록한다. 자세한 기록은 나중에 이 Merge 커밋을 이해하는데 도움을 줄 것이다.

Git 브랜치 - 브랜치란 무엇인가?

3.1 Git 브랜치 - 브랜치란 무엇인가?

브랜치란 무엇인가?

Git이 브랜치하는 과정을 이해하려면 우선 Git이 데이터를 어떻게 저장하는지 알아야 한다. Git은 데이터를Change Set이나 변경사항(Diff)으로 기록하지 않고 일련의 스냅샷으로 기록한다는 것을 1장에서 보여줬다. 커밋하면 Git은 현 Staging Area에 있는 데이터의 스냅샷에 대한 포인터, 저자나 커밋 메시지 같은 메타데이터, 이전 커밋에 대한 포인터 등을 포함하는 커밋 개체(커밋 Object)를 저장한다. 이전 커밋 포인터가 있어서 현재 커밋이 무엇을 기준으로 바뀌었는지를 알 수 있다. 최초 커밋을 제외한 나머지 커밋은 이전 커밋 포인터가 적어도 하나씩 있고 브랜치를 합친 Merge 커밋 같은 경우에는 이전 커밋 포인터가 여러 개 있다. 예제를 보자. 파일이 3개 있는 디렉토리가 하나 있고 이 파일을 Staging Area에 저장하고 커밋해 보자. 파일을 Stage하면 Git 저장소에 파일을 저장하고(Git은 이것을 Blob이라고 부른다) Staging Area에 해당 파일의 체크섬을 저장한다(1장에서 살펴본 SHA-1을 사용한다).
$ git add README test.rb LICENSE
$ git commit -m 'initial commit of my project'
'git commit'으로 커밋하면 먼저 루트 디렉토리와 각 하위 디렉토리의 트리 개체를 체크섬과 함께 저장소에 저장한다. 그다음에 커밋 개체를 만들고 메타데이터와 루트 디렉토리 트리 개체를 가리키는 포인터 정보를 커밋 개체에 넣어 저장한다. 그래서 필요하면 언제든지 스냅샷을 다시 만들 수 있다. 이 작업을 마치고 나면 Git 저장소에는 다섯 개의 데이터 개체가 생긴다. 각 파일에 대한 Blob 세 개, 파일과 디렉토리 구조가 들어 있는 트리 개체 하나, 메타데이터와 루트 트리를 가리키는 포인터가 담긴 커밋 개체 하나이다. 이것을 그림으로 그리면 그림 3-1과 같다. 그림 3-1 저장소의 커밋 데이터 다시 파일을 수정하고 커밋하면 이전 커밋이 무엇인지도 저장한다. 커밋을 두 번 더 하면 그림 3-2과 같이 저장된다. 그림 3-2 Git 커밋의 개체 데이터 Git의 브랜치는 커밋 사이를 가볍게 이동할 수 있는 어떤 포인터 같은 것이다. 기본적으로 Git은 master 브랜치를 만든다. 최초로 커밋하면 Git은 master라는 이름의 브랜치를 만들어서 자동으로 가장 마지막 커밋을 가리키게 한다. 그림 3-3 가장 최근 커밋 정보를 가리키는 브랜치 브랜치를 하나 새로 만들면 어떨까? 브랜치를 하나 만들어서 놀자. 다음과 같이 git branch 명령으로 testing 브랜치를 만든다.
$ git branch testing
새로 만든 브랜치도 지금 작업하고 있던 마지막 커밋을 가리킨다(그림 3-4). 그림 3-4 커밋 개체를 가리키는 두 브랜치 지금 작업 중인 브랜치가 무엇인지 Git은 어떻게 파악할까? 다른 버전 관리 시스템과는 달리 Git은 'HEAD'라는 특수한 포인터가 있다. 이 포인터는 지금 작업하는 로컬 브랜치를 가리킨다. 브랜치를 새로 만들었지만, Git은 아직 master 브랜치를 가리키고 있다. git branch 명령은 브랜치를 만들기만 하고 브랜치를 옮기지 않는다. 그림 3-5 HEAD는 현재 작업 중인 브랜치를 가리킴 git checkout 명령으로 새로 만든 브랜치로 이동할 수 있다. testing 브랜치로 이동하려면 다음과 같이 한다:
$ git checkout testing
이렇게 하면 HEAD는 testing 브랜치를 가리킨다. 그림 3-6 HEAD는 옮겨간 다른 브랜치를 가리킨다 자, 이제 핵심이 보일 거다! 커밋을 새로 한 번 해보면:
$ vim test.rb
$ git commit -a -m 'made a change'
결과는 그림 3-7과 같다. 그림 3-7 HEAD가 가리키는 testing 브랜치가 새 커밋을 가리킨다 이 부분이 흥미롭다. 새로 커밋해서 testing 브랜치는 앞으로 이동했다. 하지만, master 브랜치는 여전히 이전 커밋을 가리킨다. master 브랜치로 되돌아가면:
$ git checkout master
결과는 그림 3-8과 같다. 그림 3-8 HEAD가 Checkout한 브랜치로 이동함 방금 실행한 명령이 한 일은 두 가지다. master 브랜치가 가리키는 커밋을 HEAD가 가리키게 하고 워킹 디렉토리의 파일도 그 시점으로 되돌려 놓았다. 앞으로 커밋을 하면 다른 브랜치의 작업들과 별개로 진행되기 때문에 testing 브랜치에서 임시로 작업하고 원래 master 브랜치로 돌아와서 하던 일을 계속할 수 있다. 파일을 수정하고 다시 커밋을 해보자:
$ vim test.rb
$ git commit -a -m 'made other changes'
프로젝트 히스토리는 분리돼 진행한다(그림 3-9). 우리는 브랜치를 하나 만들어 그 브랜치에서 일을 좀 하고, 다시 원래 브랜치로 되돌아와서 다른 일을 했다. 두 작업 내용은 서로 독립적으로 각 브랜치에 존재한다. 커밋 사이를 자유롭게 이동하다가 때가 되면 두 브랜치를 Merge한다. 간단히 branch와 checkout 명령을 써서 말이다. 그림 3-9 브랜치 히스토리가 서로 독립적임 실제로 Git의 브랜치는 어떤 한 커밋을 가리키는 40글자의 SHA-1 체크섬 파일에 불과하기 때문에 만들기도 쉽고 지우기도 쉽다. 새로 브랜치를 하나 만드는 것은 41바이트 크기의 파일을(40자와 줄 바꿈 문자) 하나 만드는 것에 불과하다. 브랜치를 만들어야 하면 프로젝트를 통째로 복사해야 하는 다른 버전 관리 도구와 Git의 차이는 극명하다. 통째로 복사하는 작업은 프로젝트 크기에 따라 다르겠지만 수십 초에서 수십 분까지 걸린다. 그에 비해 Git은 순식간이다. 게다가 커밋을 할 때마다 이전 커밋의 정보를 저장하기 때문에 Merge할 때 어디서부터(Merge Base) 합쳐야 하는지 안다. 이런 특징은 개발자들이 수시로 브랜치를 만들어 사용하게 한다. 이제 왜 그렇게 브랜치를 수시로 만들고 사용해야 하는지 알아보자.

Intellij 프로퍼티 파일 Ascii로 변경시 key값이 대문자로 변경되는 문제

intellij에서 properties파일 name명 자동으로 앞글자 대문자로 변경되는 문제 [MAC] application > intellij 패키지보기 > bin > idea.properties 에 idea.native2ascii.lowercase=true 추가 [WIN] C:\Program Files (x86)\JetBrains\IntelliJ IDEA 12.1.4\bin에 idea.native2ascii.lowercase=true 추가

GIT 실전 사용 방법 - 1. git 기본편

GIT 실전 사용 방법 - 1. git 기본편

2012/01/26 12:41
git를 설치하였다는 가정 이후 부터 설명을 진행한다. 이후에 툴 사용하는 방법도 설명하겠지만 git를 이해하기 위해서 command를 사용해 보는 것이 좋다. 우선 command 사용법을 익히고 툴 사용법을 살펴보자. (원격 저장소에 관한 주소는 하이브레인넷 부설연구소와 창원대학교 데이터베이스 연구실에서 실습을 하기 위한 목적으로 비공개 되어 있는 원격 저장소 입니다. 공개용 원격 저장소를 활용한 예제는 추가 적으로 포스팅 할 예정입니다. 원격 저장소를 제외한 예제들은 모두 동일하게 테스트 하실 수 있습니다.)1. 로컬 환경 설정 git는 리눅스 소스를 관리하기 위해서 나온만큼 리눅스 명령어와 매우 비슷하다. 윈도우즈 용 git 역시 git-sh를 사용해서 git 명령어를 그대로 사용할수 있고 리눅스 명령어를 상용할 수 있다. 우선 현재 설정된 목록을 출력해보자.
git config --list
기존에 git를 사용하던 사용자라면 다음과 비슷한 내용이 출력이 될 것이다.
(1) 사용자 정보 추가 git를 사용하기 위해서는 기본적으로 이름과 이메일 주소가 필요하다.
git config --global user.name "{이름}" git config --global user.email "{이메일주소}"
(2) 칼라 설정 터미널에서 git명령에 color를 지정하는 것이 좋다. 그래야 나중에 변환된 소스가 추가,수정,삭제 되었는지를 쉽게 판별할 수 있기 때문이다. --global 옵션은 전역으로 설정한다는 뜻이다.
git config --global color.ui "auto"
(3) 인코딩 설정 맥이나 리눅스에서는 디폴트가 UTF-8이기 때문에 이 설정이 필요 없지만 윈도우 환경일 경우에는 cp949로 인코딩을 설정해줘야 한글이 깨어지지 않는다.
git config --global i18n.commitEncoding cp949 git config --global i18n.logOutputEncoding cp949
2. 인증 (1) 로컬 PC에서 SSH-Key 생성 git를 사용하기 위해서는 RSA로 된 공개키가 필요하다. 이때 RSA 공개키는 ssh 공개키로 인증하는 방법과 같으며 ssh-keygen을 이용하여 공개키를 생성한다. ssh의 공개키가 ~/.ssh 폴더 밑에 생긴다. 키를 생성할때 다른 경로로 지정할 수 있으나 통상 ~/.ssh 밑에 id_rsa.pub와 같이 생성이 된다.
ssh-keygen -t rsa
라고 물어보는데 특별한 경로를 지정하지 않을 때는 엔터를 치면 된다. 공개키가 생성되었는지 확인해보자.
cat ~/.ssh/id_rsa.pub
다음과 같이 공개키가 ssh-rsa로 만들어진 것을 확인할 수 있다. 이것을 이용해서 git-server에 접근할때 인증하는 공개키로 사용할 것이다.
 ssh-rsa AAAAB3..........NP/iiw== Saltfactory@Saltfactory.local
윈도우 사용자일 경우 Git Bash 프로그램을 실행 시켜서 동일하게 게 사용하면 된다.
(2) git 호스팅 서비스나 git 서버에 SSH-key를 추가 https://git.hibrainapps.net 으로 접근하면 초청받은 사용자는 git 서비스를 받을 수 있는데 dashboard 메뉴에 들어 가면 다음과 같이 Manage SSH Keys라는 메뉴에서 생성한 공개키를 등록할 수 있다. 인증받지 않은 PC에서 작업을하거나 ssh-keygen으로 다시 키를 생성했다면 Manage SSH Keys에서 키를 새로 등록해줘야한다. ( 하이브레인넷 부설 연구소 팀과 창원대학교 데이터베이스 연구실 학부생 및 대학원 생은 @hibrainapps 나@saltfactory 트위터로 DM으로 요청하시거나 apps@hibrain.net 으로 메일주소와 이름으로 요청하시면 바로 git 서버 계정 발급해드립니다.)
Manage SSH Keys 메뉴를 눌러보면 다음과 같이 SSH Key를 관리하고 있는 것을 볼수 있다.
새로 SSH Key를 등록하기 이해서는 Add SSH key를 누른다. 그리고 다음과 같이 생성한 ssh-rsa 키를 복사해서 붙여 넣고 Save를 누른다.
이제 git 서버에서 관리자가 권한을 열어주면 원격 저장소에 소스코드를 fetch, pull, push를 할 수 있게 된다. 3. git 프로젝트 만들기 (1) 저장소 생성 프로젝트가 진행되거나 소스를 포함할 디렉토리를 하나 만든다. 우리는 이것을 하나의 저장소로 생각할 것이다. SimpleProject라는 폴더를 만들고 난후 SimpleProject 폴더 안으로 이동해서 git init을 사용하여 초기화 한다. 간단하게 git 저장소가 생긴 것이다.
mkdir SimpleProject cd SimpleProject
git init
(2) 파일 추가 git 는 관례적으로 git 저장소 바로 밑에 README 파일을 만든다. 이것이 이후에 git 호스팅 서비스에서 소개글이나 도움말 기능을 하게 된다.
touch README
(3) 저장소에 파일 추가 이제부터 우리는 파일을 추적하면서 소스의 이력을 관리할 것이다. git에서는 이 작업을 하기 위해서 두단계 과정이 있는데 add와 commit이라는 기능이다. 추가한 파일을 stage 영역에 올리기 위해서 git add를 상용하고 이것을 commit 객체로 만들기 위해서 git commit을 사용한다. 다시 말해서 README 파일을 실제로 이력을 관리하기 위해서 이 두가지 과정을 거쳐야 한다는 것이다.
git add README
git add README 를 한후 stage 의 상태를 확인하면 다음과 같이 stage에 새로운 파일 README가 추가 되었다는 것을 알 수 있다.
git commit -m "{커밋 내용, 파일의 수정 내용을 상세하게 적어둔다}"
커밋을 진행하고 나면 stage에 있던 내용을 커밋 객체로 만들고 stage 영역을 다시 비우게 된다.
변경된 이력을 살펴보기 위해서는 git log를 이용해서 살펴볼 수 있다.
git log
이때 commit 객체는 Hash 값을 가지고 있는데 이것은 두명이 동시에 코드를 작성하다 충돌이 났을때 리비전할때 상요한다. 이 해시값이 중복되면 commit 구별이 어려워지지만 SHA-1해시로 만들경우 동일한 값이 나울 경우는 9,223,372,036,854,775,808분의 1의 확률을 가지고 있다.
git에서 코드는 세곳에 저장한다. 1. 파일을 작업할때 직접 이용하는 작업 트리 2. 스테이징 (stage)라는 인덱스이며 이 공간은 작업 트리와 저장소 사이의 buffer이다. 3. 최종 코드가 저장되는 저장소이다. 이 세가지를 기억하면서 간단한 query를 포함한 demo.sql 파일을 저장소 내에서 추가해보자.
echo "select * from student;" > demo.sql
demo.sql 라는 파일이 작업 트리에 추가되면서  git의 스테이징에 추적할 수 있는 파일이 하나 있으니 추가하라고 메세지가 나온다. 빨갛게 표시된 것은 아직 스테이징(stage)영역에 들어가지 않은 작업 트리에만 있는 것이다. 이것을 rm -rf로 삭제하면 작업트리에서 사라지기 때문에 git 스테이징 영역과 저장소에 전혀 반영되지 않는다.
git add demo.sql
git add를 해서 stage 영역에 추가를 하였다.
(4) 파일 삭제 여기서 만약 스테이징 영여게서 삭제하려면 다음과 같이 하면 된다.
git rm --cached demo.sql
이것은 스태이징 영역에 인덱스되어진 것을 버퍼에서 내려서 작업 트리에만 존재하게 하는것이다.
demo.sql을 아직 스테이징 영역에 올리지 말고 README  파일을 수정해보자.
echo "하이브레인넷 부설연구소 GIT 세미나" > README
앞에 demo.sql 파일이 추가된 것과 작업트리 영역에서 README 파일이 변경된 것을 알 수 있다. 우리는 이 변경된 두가지 모두를 한번에 스테이징 영역에 올릴고 싶다. 이렇게 여러개의 파일을 한번에 올릴 경우는 "." 을 상용하면 된다.
git add .
READE 파일이 변경된 것과 demo.sql이 새로 추가된 것을 스태이징 영역에 반영하였다.
이제 git commit을  저장소에 파일을 저장하자.
git commit -m "README 파일 수정과 demo.sql 파일 추가"
(5) 파일 이름 변경 파일 삭제를 git rm으로 하듯 파일 이름 변경은 git mv로 하면 된다.
git mv demo.sql sample.sql
(6) 다른점 찾기 git는 코드를 세가지 저장 공간을 갖는다고 했다. (작업트리, 스태이징, 저장소) 현재 변경한 파일이 이들 사이에 어떻게 변경되었지 확인하는 방법을 알아보자. README 파일 열어서 다음과 같이 수정해보자.
vi README
2012년 1월 20일 GIT 세미나 주체 : 하이브레인넷 부설연구소 대상 : 하이브레인넷 부설연구소, 데이터베이스 연구실
git diff를 이용해서 저장공간의 차이점을 비교할 수 있다. 이때 git diff는 작업트리와 스태이징 사이의 차이점을 비교하고, git diff --cahced는 스태이징 영역과 저장소 사이의 차이점을 비교한다. 마지막으로 HEAD는 작업트리, 스태이징, 저장소의 변경사항을 모두 보여준다.
git add .
이 때 HEAD는 현재 작업중인 브랜치에서 가장 최신의 커밋을 나타내는 일종의 포인트와 같은 키워드이다. branch 를 이야기 할때 다시 언급하겠다. (7) 추적하지 않을 파일 설정하기 git를 무엇을 관리할 것인지 물어보면 대답은 모든 것을 다 관리한다고 생각하면 된다. 실제 git 파일이 BLOB으로 저장되어 어떠한 파일이든지 추적관리를 할 수 있다. 그런데 반대로 반드시 하지 않아야하는 파일들이 있다. 예를 들어서 보안에 민감한 파일이나 툴 환경 설정에 관련된 파일 등 작업 폴더안에서 어떤 특수한 파일을 제외하고 싶을때 git에서는 .gitighore라는파일을 만들어서 그 안에 제외할 패턴을 넣어주면 된다. 앞에서 만든 공개키와 같은 것은 노출되면 보안상 좋지가 않다. 그렇기 때문에 .pub로 끝나는 파일은 git 관리에서 제외 시키고 싶을 경우 다음과  같이하면 된다.
echo "*.pub" > .gitingnore
4. branch 사용 git의 젤 중요한 기능중에 하나가 branch를 사용하는 것이다. 프로그램을 구현할때 항상 요구사항이 변경되는 것 때문에 코드가 여러가지 형태로 각각 소스를 관리할 필요가 있게 된다. 특히 여러가지 업무를 동시에 할때 이 branch라는 기능은 매우 명확하고 편리하게 개발 할 수 있게 만들어준다. branch를 언제 분기 시킬것을 결정하기는 어려운 문제이다. "Git 분산 서버 관리 시스템"이라는 책에서는 다음과 같은 경우 branch를 만들라고 말하고 있다.
첫째, 실험적인 변경 사항이 일아날 때 둘째, 새로운 기능이 추가 될 때 셋째, 버그 수정을 할 때
현재 저장소에 branch들을 확이하려면 다음과 같이하면 확인할 수 있다.
git branch
(1) branch 생성 새로운 branch를 생성하기 이해서는 간단하게 git branch {브랜치명}으로 만들면 된다.
git branch dev-1.0M1
이렇게 생성한 branch 와 master 간에 이동을 할 수 있는데 이때 checkout을 이용해서 서로 branch를 변경할 수 있다.
git checkout dev-1.0M1
dev-1.0M1 브랜치에서 sample.sql를 수정해보자.
select s.name, d.name from student s, department d where s.deptno = d.deptno;
그리고 파일을 하나 추가하자
touch index.html
그리고 모두 commit을 한다.
git add . ; git commit -m "쿼리 추가, index.html 파일 추가"
현재 HEAD가 dev-1.0M1 브랜치를 가르키로 있을 때이다.
HEAD가 master 브랜치를 가르키게 할 경우 다음과 같아 진다. dev-1.0M1에서 추가한 index.hml 파일은 보이지 않고 sample.sql에 추가한 쿼리문도 보이지 않게 된다.
두 branch간의 차이점을 git diff로 확인 할 수 있다.
  git diff dev-1.0M1
(2) branch 삭제 현재 HEAD가 master인데 우리는 dev-1.0M2라는 branch를 하나 더 만들고 dev-1.0M1 branch를 삭제하고 싶다.
git checkout -tb "dev-1.0M2"
git branch -d  "dev-1.0M1"
하지만 에러가 발생한다. 왜냐면 master에서 분기되어져 나와서 작업을 진행했는데 변경된것을 무시하고 삭제를 하려고하기 때문이다. 그래서 강제로 삭제하고 싶으면 git branch -D 옵션을 사용해서 강제로 삭제하라고 한다. 우리는 새로 만든 dev-1.0M2에다가 dev-1.0M1을 합치고 난 후 dev-1.0M1 브랜치를 삭제 하기로 한다. 현재 HEAD가 가리키는 것은 dev-1.0M2 이다. 현재 branch에서다 dev-1.0M1의 내용을 merge하기 위해서 다음과 같이 한다.
git merge dev-1.0M1
이제 다시 dev-1.0M1을 삭제해보자
git branch -d "dev-1.0M1"
4. 원격지에 있는 저장소 사용 https://git.hibrainapps.net/hbn-tutorials 사이트에 가면 테스트할 저장소가 다음과 같이 있을 것이다 (이 저장소 주소는 접근 권한을 받은 연구소와 연구실 팀만 사용 가능합니다. 테스트를 위해 다른 원격지 저장소 URI를 사용하셔도 상관 없습니다.) git@git.hibrainapps.net:hbn-tutorials/java-tutorial.git (1) 원격지 저장소 로컬로 복제하기 원격 저장소에 있는것을 복제하기 위해서는 git clone을 사용한다.
cd ..
git clone git@git.hibrainapps.net:hbn-tutorials/java-tutorial.git
우리는 각자 새로운 branch를 만들어서 작업을 한다고 가정하자. 중복되지 않는 branch를 만들기 위해서 "{git사이트 계정}-dev-1.0.M1" 이라고 branch 이름을 만들자.
git checkout -b "saltfactory-dev-1.0M1"
(2) IDE와 git 상호 연동 이제 IntelliJ로 이 프로젝트 파일을 열어보자.
IntelliJ를 시작하면 프로젝트를 선택하는 다이얼로가 나타나는데 우리는 원격 저장소에서 git로 관리되는 IntelliJ 소스 파일을 복제 하였고 새로운 개발을 하기 위해서 saltfactory-dev-1.0M1 이라는 branch도 만들었다. 그렇게 때문에 이미 IntelliJ 포르젝트가 존재하는 이유로 존재하는 소스를 가지고 프로젝트를 생성한다고 체크한다.
우리가 clone 받은 소스는 java-tutorial 이라는 git 폴더이고 그 안에 IntelliJ로 만든 프로젝트로 폴더 SimpleJavaProject가 있는데 이 것을 선택하도록 한다.
이제 IntelliJ가 열리면서 모든 프로젝트가 세팅되고 소스가 보이게 된다.
우리는 단지 저장소를 복사하고 branch를 추가하고 프로젝트를 열었을 뿐인데 프로젝트 메니저가 샘플 소스 코드를 만들어 주었다는 것을 확인 할 수 있다. IntelliJ에서 git를 사용하기 위해서 VCS 메뉴에서 Enable Version Controller을 활성화 해줘야한다. (1)맥 용 IntelliJ의 VCS 버전 컨트롤러 활성화
(2) 윈도우 용 IntelliJ의 VCS 버전 컨트롤러 활성화
예제 소스는 IntelliJ와 git을 이용해서 Java와 SQL을 개발할 수 있는 예제이다. 데이터베이스에 커넥션하여 SQL을 실행하기 위해서는 다음과 같이 새로은 커넥션을 만든다. (IntelliJ의 Database Navigator 플러그인을 설치해야 .sql 파일에서 바로 쿼리를 실행할 수 있다. 디폴트로는 이 플러그인이 빠져 있기 때문에 Database Navigator 플러그 인을 설치하길 권장한다.)
이때 데이터베이스에 커넥션하기 위해서 JDBC 드라이버를 사용한다. 오라클 사이트에서 Oracle 10g/11g Client를 다운 받아서 사용하면 된다. JDBC 드라이버만 있으면 가능하기 때문에 Oracle 10g/11g Instant Client를 다운 받아도 상관 없다. instant client는 소스 컴파일 과정이 필요없기 때문에 간단히 라이브러리와 드리아버를 사용할 수 있다. 이 예제는 instant client를 이용해서 만들어져 있다.  Driver library에 이제 JDBC 라이브러리 경로를 입력하면 된다. 예를 들어 /Projects/Servers/Oracle/instantclient/instantclient_10_2/ojdbc14.jar 과 같이 입력한다. 다음은 Driver를 선택할 수 있는데 oracle.jdbc.driver.OracleDriver와 oracle.jdbc.OracleDriver를 선택할 수 있는데 oracle.jdbc.driver.OracleDriver를 선택한다. 다음은 URL은 jdbc의 thin 모드 커넥션을 이용할 것이다. 간단한 테스트 과정이기 때문에 개발용으로 thin 모드로 연결해서 사용하면 충분하다. jdbc:oracle:thin@{오라클서버호스트}/{오라클SID} 모든 설정후 test 버턴을 클릭해서 연결 상태를 확인한다. 만약 연결 상태가 양호하면 다음과 같은 메세지를 볼 수 있다.
이제 .sql 파일에서 특정 statement를 선택해서 Run을 시키면 그 결과가 table 구조로 다음과 같이 바로 확인이 될 것이다. 이제 query를 터미널에서 열어서 vi 로 작성하거나 하지 않고 IDE를 이용해서 좀더 효율적이고 효과적으로 개발할 수 있게 되었다.
또한 Database Navigator 플러그인을 사용하면 코드 어시스턴스를 사용할 수 있게 된다. 테이블이나 컬럼을 코드 어시스턴스를 이용해서 쉽게 코드를 완성할 수 있게 된다.
students.sql 파일을 열어서 다음 코드를 추가하였다.
select * from student s, department d where s.deptno = d.deptno;
git로 소스를 관리하고 있는 이 저장소에서 파일이 변경 되어 지면 변경된 파일은 다음과 같이 파란색으로 변경이 된다. 만약 새로운 파일이 추가가 되면 녹색이 되고, git 스테이징 영역에서 삭제되거나 제외될 경우에는 빨간색으로 나타난다.
변경된 student.sql 파일 위에서 오른쪽 마우스를 클릭해서 컨텍스트 메뉴를 열어서 Git 메뉴중에서 commit 메뉴를 선택해보자. 우리가 앞에서 같이 했던 git commit -m 이라는 명령어 대신에 마우스를 이용해서 이 작업을 대신하는 거시다. comment에 메세지를 넣고 커밋 후에 바로 원격지에 소스를 push 할 것인지를 선택하는 commit 버턴이 있다. commit은 단순히 로컬에 복제한 소스 저장소에 commit을 하는 것이고 commit and push는 commit을 완료하고 원격 저장소에 변경된 로컬의 commit을 원격지에 push하는 것을 의미한다. (create patch를 unix에서 자주 자용하는 patch 파일을 만드는 것이다. 이것은 git를 사용하지 않는 곳이라도 patch 파일을 만들어서 소스를 변경 사항을 적용 시킬때 사용할 수 있다.)
단순히 로컬 저장소에 commit만 완료해 보자. Commit을 선택한다. 그리고 student.sql 파일에 오른쪽 마우스를 클릭해서 컨텍스트 메뉴를 열어서 Git > Show History 메뉴를 선택해보자. 그러면 방금 커밋한 이력 정보를 확인 할 수 있게 된다.
소스를 다시 돌리기 위해서는 이 이력정로를 더블클릭해보자.
녹색으로 select 문장 하나가 추가된 것을 확인 할 수 있다. 이제 이 코드 이전으로 돌아가기 위해서 show history 이력에서 이 변경 바로 전의 commit 위에서 마우스 오른쪽을 클릭한다. 해시 값은 c89ddab 이다. 그리고 Get을 선택한다.
이 작업은 이젠 commit 시점으로 코드를 변경한 작업을 한 것이다. 소스코드들은 이전 시점으로 돌아가게 되고 변경된 파일은 다시 파란색으로 표시가 된다. 이렇게 변경된 것을 다시 반영하려면 commit을 하면 된다.
이번에는 commit과 동시에 push를 해보자. 로컬 저장소에 commit이 완료 됨과 동시에 push를 위한 다이얼로그가 하나 더 나타나는데 이데 puch할 branch를 선택할 수 있고 커멧 메세지를 다시 확인 할 수 도 있다. 보통 revert 시키는 작업은 commit 해시 값을 입력해주는 것이 좋다.
이제 원격지에 push를 하기 위해서 인증을 한다. git 서버에서 인증받았던 비밀번호를 입력하면 된다. Remember the passphrase를 체크하면 인증해시 값이나 비밀번호가 변경되기 전까지는 묵시적으로 자동인증이 가능하다.
이렇게 push된 소스는 http://git.hibrainapps.net 에서 웹으로 확인이 가능하다. 이 예제에서 사용한 저장소는 https://git.hibrainapps.net/hbn-tutorials/java-tutorial 과 같다. 그리고 방금 commit 한 메세지와 blame 정보를 확인 할 수 있다.
5. 요약 이 포스트는 git를 사용해서 로컬 저장소를 활용하는 방법을 소개하고 있다. 그리고 git.hibrainapps.net의 원격 저장소에서 저장소를 복제하고 IntelliJ를 이용해서 git를 사용하는 방법을 간단히 소개하고 있다. 이 포스트는 "하이브레인넷 부설연구소"와 "창원대학교 데이터베이스 연구실"의 세미나 목적으로 만들어진 포스트로 비공개 원격 저장소를 사용했지만 공개용 원격 저장소를 사용할 경우도 방법은 동일하다. 다만 원격 저장소의 주소만 다르게 사용하면 된다. 또한 공개용 원격저장소를 이용하는 방법은 이후에 다른 공개 튜토리얼을 작성하면서 사용 예제를 같이 포스팅 할 예정이다. git는 중앙 집중식으로 버전을 관리하던 SVN과 달리 중앙 집중식 뿐만 아니라 로컬에서도 코드를 관리할 수 있다는 것을 보았다. 또한 git는 작업트리 영역과 스테이징 영역 그리고 저장소 영역을 나누어서 코드를 관리하는 것도 설명했다. 또한 터미널에서 사용하던 명령어를 IDE와 연동해서 프로그램을 작성하면서 바로 git를 사용하는 방법도 살펴보았다.  이렇게 git의 실전 사용법 - 기본편을 살펴보았다. 6. 결론 우리는 프로젝트를 진행하면서 코드의 관리를 위해서 버전관리시스템을 이용해왔다. 기존에는 SVN을 사용했으나 이는 서버중심의 중앙 집중식 버전 관리 시스템이기 때문에 로컬에서 버전 관리를 할 수 없었던 반면에 git를 이용하면 로컬 작업도 버전 관리가 가능하게 되었다. 이러한 이유로 네트워크가 없는 상황에서도 작업을 지속적으로 버전 관리를 하면서 할 수 있게 된다는 것을 알게 되었다. 또한 git는 branch 기능을 사용해서 여러가지 소스를 병렬작업 할 수 있는 기능도 살펴보았다. 이 branch를 이용해서 다양한 버전으로 코드를 테스트하거나 프로젝트의 개발에 테스트와 소스코드의 분기를 할용해서 코드의 품질을 높이는 방법도 살펴보았다. 기본편에서는 원격저장소를 사용하는 설명이 세미나에서는 이루어지지 않았는데 다음 세미나에서 원격저장소를 사용해서 좀더 공동작업하는 방법과 분산버전 관리하는 방법에 대해서 실전편으로 살펴볼 에정이다. git를 사용해서 좀더 고품질의 소스코드를 만들수 있고, 분산버전을 활용하고, 공동 작업을 효율적으로 효과적으로 할 수 있게 되기를 바래본다. git를 윈도우 환경에서 DA#과 함께 이용하여 sql을 개발하는 방법과 IDE를 이용하여 웹 프로젝트, 모바일 프로젝트를 개발하는 내용을 git 실전편에서 계속될 예정입니다. 작성자 : 하이브레인넷 부설연구소, 송성광 개발 연구원 ( @saltfactory )