GNUEmacsManual:25

From 흡혈양파의 번역工房
Jump to: navigation, search
큰 프로그램 유지하기

큰 프로그램 유지하기

이번 장에서는 큰 프로그램을 유지하기 위한 Emacs 기능을 설명한다. 큰 규모의 Lisp 프로그램을 유지하고 있다면 여기에서 설명하는 기능 외에 ERT ("Emacs Lisp Regression Testing") 라이브러리도 유용할 것이다(Emacs Lisp Regression Testing의 "ERT"절 참고).

버전 관리

버전 관리 시스템이란 소스 파일의 여러 버전을 기록하여 각 버전의 생성 시간, 각 버전을 만든 사람, 변경된 내용의 설명에 관한 정보를 보관할 수 있다.


Emacs 버전 관리 인터페이스는 VC라고 부른다. VC 명령어는 여러 다른 버전 관리 시스템과 작업하며, 현재는 GNU Arch, Bazaar, CVS, Git, Mercurial, Monotone, RCS, SCCS/CSSC, Subversion을 지원한다. 이러한 시스템에서 GNU 프로젝트는 CVS, Arch, RCS, Bazaar를 배포한다.


VC는 사용자가 버전 관리 시스템이 관리하는 파일을 방문할 때마다 자동으로 활성화된다. VC 를 완전히 끄려면
vc-handled-backends
맞춤화 가능 변수를
nil
로 설정한다(Specialized Emacs Features 의 "Customizing VC"절을 참고).


버전 관리 소개

VC는 버전 관리 연산을 편집과 부드럽게 통합하여 Emacs 내에서 버전 관리 시스템을 사용하도록 해준다. 이는 많은 버전 관리 연산에서 공통 연산에 대해 하나의 인터페이스를 제공한다.


저장소(repository) 설정과 같은 일부 특별한 또는 복잡한 버전 관리 연산들은 VC에서 지원되지 않는다. 그러한 과제는 명령 행을 통하는 등 Emacs 밖에서 실행해야 한다.


이번 절에서는 버전 관리에 대한 일반 개요를 제공하고, VC가 지원하는 버전 관리 시스템을 설명한다. 사용하고자 하는 버전 관리 시스템에 이미 익숙하다면 이번 절을 건너뛰어도 좋다.


강조하는 문제 이해하기

버전 관리 시스템은 세 가지 중요한 기능을 제공한다:

  • 가역성(reversibility): 사용자가 수정한 내용의 일부가 실수였거나 좋은 생각이 아님을 발견했을 때 이전 상태로 돌아가는 능력.
  • 동시 실행(concurrency): 동일한 파일 집합체를 수정하는 많은 사람이 충돌하는 수정 내용을 감지하여 해결할 수 있음을 이해하는 능력.
  • 히스토리(history): 각 변경 내용에 숨은 의도에 관한 해설적 주석과 같이 데이터에 히스토리 데이터를 부착하는 능력. 혼자 작업하는 프로그래머들에게도 변경 히스토리는 메모리에 중요한 보조장치이며, 여러 명이 작업하는 프로젝트에서는 개발자들 간에 중요한 통신 형태가 된다.


지원되는 버전 관리 시스템

VCS는 현재 많은 버전 관리 시스템과 함께 작업하는데 이를 백 엔드(back end)라고 부른다:

  • SCCS는 빌드된 첫 버전 관리 시스템으로, 오래 전에 좀 더 발전된 시스템으로 대체되었다. VC는 SCCS에 누락된 특정 기능을 직접 구현함으로써 보완한다(예: release에 대한 태그명). 다중 브랜치와 같은 그 외 VC 기능들은 이용할 수 없다. SCCS는 무료가 아니므로 사용을 권하지 않는다.
  • CSSC는 SCCS의 무료 대체 상품이다. CSSC는 어떤 이유로 인해서 최신의 잘 설계된 버전 관리 시스템을 사용할 수 없을 때에만 사용해야 한다.
  • RCS는 VC가 처음 빌드될 당시 무료였던 버전 관리 시스템이다. 상대적으로 프리미티브(primitive)적이고, 네트워크 상에서 사용할 수 없으며 개별 파일의 수준에서 작동한다. RCS로 할 수 있는 거의 모든 것은 VC를 통해 실행할 수 있다.
  • CVS는 최근까지 (대략 2008년까지) 대다수 무료 소프트웨어 프로젝트에서 사용한 무료 버전 관리 시스템이다. 최근에는 서서히 최신 시스템으로 대체되고 있다. CVS는 로컬 또는 네트워크 상에서 동시에 다중 사용자 개발을 허용한다. 최신 시스템과 달리 원자적 커밋(atomic commit)과 파일 제거/재명명 지원이 되지 않는다. VC는 CVS 하에서 이루어지는 모든 기본 편집 연산을 지원한다.
  • Subversion(svn)은 CVS와 비슷하게 설계되었지만 CVS의 문제가 발견되지 않는 (예: fileset의 원자적 커밋을 비롯해 삭제, 복사, 재명명, 메타 데이터, 심볼릭 링크, 디렉터리의 버전화를 지원) 무료 버전 관리 시스템이다.
  • GNU Arch는 제일 초창기에 분산 버전 관리 시스템 중 하나다(또 다른 하나로 Monotone이 있다). 분산 버전 관리 시스템에 대한 설명은 282 페이지의 25.1.1.3절 [VCS 개념]을 참고한다. 더 이상 적극적 개발을 하지 않으며 Bazaar로 인해 중요성이 떨어져 사용이 줄어들고 있다.
  • Git은 분산 버전 관리 시스템으로 본래 Linux(그의 커널)의 개발을 지원하도록 Linus Torvalds에 의해 개발되었다. VC는 다수의 일반 Git 연산을 지원하지만 저장소 동기화와 같은 다른 기능은 명령 행에서 이루어져야 한다.
  • Mercurial (hg)는 많은 면에서 Git와 닮은 분산 버전 관리 시스템이다. VC는 저장소 동기화 연산만 제외하고 대부분의 Mercurial 명령어를 지원한다.
  • Bazaar(hg)는 저장소 기반 및 분산 버저닝을 모두 지원하는 분산 버전 관리 시스템이다. VC는 Bazaar의 기본 편집 연산을 대부분 지원한다.


버전 관리의 개념

파일이 버전 관리 하에 있을 경우 이를 버전 관리 시스템에 등록되어 있다고 말한다. 시스템에는 파일의 현재 상태와 그 변경 히스토리를 보관하는 저장소라는 것이 있는데, 이러한 자료는 현재 버전 또는 그 이전 버전을 재구성하기에 충분한 자료이다. 저장소는 각 파일에 대한 변경 사항을 설명하는 로그 엔트리와 같은 다른 정보도 포함한다.


사용자가 실제로 편집하는 버전 관리된 파일의 복사본을 작업 파일(work file)이라고 부른다. 각 작업 파일은 일반 파일처럼 변경할 수 있다. 변경 내용이 모두 완료되면 변경 내용을 커밋(또는 체크 인)하고, 이는 저장소에 설명적 로그 엔트리와 함께 변경 내용을 기록한다.


작업 파일의 디렉터리 트리를 작업 트리라고 부른다.


커밋마다 저장소에는 새로운 수정본(revision)을 생성한다. 버전 관리 시스템은 과거의 모든 수정본과 각 수정본에서 이루어진 변경 사항을 모두 추적한다. 각 수정본은 revision ID 에 의해 명명되는데, 그 포맷은 버전 관리 시스템에 따라 좌우되고, 가장 단순한 포맷은 하나의 정수로만 구성된다.


기본 개념을 넘어 버전 관리 시스템이 세 가지 면에서 다르다는 것을 이해해야 한다. 다음 세 절에서 설명하듯이 이들은 잠금 기반 또는 병합 기반, 파일 기반 또는 changeset 기반, 그리고 중앙 또는 분산으로 나뉜다. VC는 이 모든 연산 모드를 처리하지만 차이를 숨길 수는 없다.


병합 기반 vs. 잠금 기반의 버전 관리

버전 관리 시스템은 일반적으로 동일한 파일을 변경하길 원하는 사용자들 간 조정을 위한 메커니즘을 몇 가지 갖고 있다. 이를 수행하는 방법에는 두 가지가 있는데, 병합하기(merge)와 잠금(locking)이 그것이다.


병합을 이용하는 버전 관리 시스템에서 각 사용자는 언제든 작업 파일을 수정해도 좋다. 시스템은 다른 파일들이 커밋한 최신 변경 사항과 함께 커밋되지 않은 변경 사항을 포함할 수 있는 작업 파일을 병합하도록 해준다.


오래된 버전 관리 시스템은 대신 잠금 방식을 사용한다. 여기서 작업 파일은 보통 읽기 전용이다. 파일을 편집하려면 그것을 잠금으로써 사용자가 쓰기 가능하게 만들도록 버전 관리 시스템에 요청하여 사용자만 주어진 시간에 주어진 파일을 잠글 수 있다. 이러한 과정은 Emacs가 보통 파일의 동시 편집을 감지하기 위해 사용하는 잠금과 유사하지만 다르다(130 페이지의 15.3.4절 [인터로크] 참고). 변경 사항을 커밋할 때는 파일이 잠금 해제되고, 작업 파일은 다시 읽기 전용이 된다. 다른 사용자들은 파일을 잠그고 자신만의 변경 사항으로 만들 수 있다.


잠금 및 병합 시스템은 다수의 사용자가 동시에 동일한 파일의 수정을 시도하면 문제가 발생할 수 있다. 잠금 시스템은 잠금 충돌(lock conflicts)을 가지는데, 사용자는 파일의 검사를 시도하지만 잠겨 있어서 검사할 수가 없다. 병합 시스템에서 병합 충돌(merge conflicts)은 사용자가 검사 후 누군가가 커밋한 변경 사항과 충돌하는 변경 사항을 파일에서 커밋할 때 발생한다. 두 가지 종류의 충돌 모두 사람의 판단과 의사소통으로 해결해야 한다. 경험에 따르면 병합이 잠금보다 나으며, 두 가지 모두 실제로 발생하는 충돌의 정도와 횟수를 최소화하는 데에 있어 그리고 개발자에게 편리한 것으로 나타난다.


SCCS는 항상 잠금을 사용한다. RCS는 기본적으로 잠금 기반이지만 병합 스타일로 작동하도록 알려줄 수도 있다. CVS와 Subversion은 기본적으로 병합 기반이지만 잠금 모드로 작동하도록 알릴 수 있다. GNU Arch, Git, Mercurial과 같은 분산 버전 관리 시스템은 전적으로 병합 기반이다.


VC 모드는 잠금과 병합 버전 관리를 모두 지원한다. 최신 버전 관리 시스템에서는 "커밋"과 "업데이트"란 용어가 모두 사용되며, 오래된 잠금 기반의 시스템은 "체크 인"과 "체크 아웃"이란 용어를 사용한다. VC는 가능한 한 그들의 차이를 숨긴다.


Changeset 기반 vs. 파일 기반 버전 관리

SCCS, RCS, CVS, 그 외 초기의 버전 관리 시스템에서 버전 관리 연산은 파일 기반으로 이루어지고, 각 파일은 고유의 다른 모든 파일의 것과 구분된 주석과 수정본 히스토리를 갖는다. Subversion으로 시작되는 최신 시스템은 changeset 기반으로, commit은 여러 파일의 변경 사항을 포함하고, 변경 사항의 전체 집합은 하나의 단위로 처리된다. 변경 사항과 관련된 어떠한 주석도 단일 파일에 속하지 않고 changeset 자체에 속한다.


Changeset 기반의 버전 관리는 파일 기반의 버전 관리보다 유연하고 강력하며, 다중 파일에 변경 사항을 뒤바꿔야 할 때는 변경 사항을 쉽게 식별하여 모두 제거할 수 있다면 좋을 것이다.


분산 vs. 중앙집중식 저장소

초기 버전 관리 시스템은 각 프로젝트에 모든 개발자들이 사용하는 하나의 저장소만 있는 중앙집중식(centralized) 모형을 위주로 설계되었다. SCCS, RCS, CVS, Subversion은 이러한 유형의 모델을 공유한다. 그 단점 중 하나는 저장소가 신뢰성과 효율성의 요충이라는 점이다.


GNU Arch는 분산(distributed) 또는 분산화(decentralized) 버전 관리의 개념을 만들어냈는데, 이는 이후 Git, Mercurial, Bazaar에서 구현되었다. 프로젝트는 여러 다른 저장소를 가질 수 있고, 이러한 시스템들은 저장소 간에 변경 사항 히스토리의 조정을 시도하는 일종의 고급 병합(super-merge)을 지원한다. 사실상 개발자마다 하나의 저장소가 있고, 저장소 병합은 커밋 연산을 대신한다.


VC는 사용자의 개인 작업파일과 저장소 간 트래픽을 관리하도록 도와준다. 저장소가 단일 master이든 피어 저장소(peer repository)든 VC가 신경 써야 할 일은 아니다.


로그 파일의 유형

버전 관리 시스템을 사용하는 프로젝트는 변경 사항에 대한 두 가지 유형의 로그를 가진다. 하나는 버전 관리 시스템이 유지하는 로그로, 사용자가 변경 사항을 커밋할 때마다 변경 사항에 대한 로그 엔트리를 기입한다(287 페이지의 25.1.4절 [로그 버퍼] 참고). 이것을 버전 관리 로그라고 부른다.


다른 로그 유형은
ChangeLog
파일이다(297 페이지의 25.2절 [변경 로그] 참고). 이는 프로그램의 큰 부분에 일어나는 모든 변경 사항에 대해 시간 순으로 기록한 것으로, 주로 하나의 디렉터리와 그 하위디렉터리에 해당한다. 작은 프로그램은 하나의
ChangeLog
파일을 사용할 것이며, 큰 프로그램은 각 주 디렉터리에
ChangeLog
파일을 가질 것이다. 297 페이지의 25.2절 [변경 로그]를 참고한다. 프로그래머들은 버전 관리 시스템보다 오래 전부터 변경 로그를 사용해왔다.


Changeset 기반의 버전 시스템은 전체 시스템에 changeset 기반의 수정 로그를 유지하여 변경 로그 파일을 다소 불필요하게 만드는 것이 일반적이다. 그러한 유지의 한 가지 이점은 다른 디렉터리의 거래 히스토리로부터 구분된 단일 디렉터리의 거래 히스토리를 확인하기가 유용하다는 점이다. 또 다른 이점은 커밋 로그가 많은 버전 관리 시스템에서 수정될 수 없다는 사실이다.


버전 관리로 유지되는 프로젝트는 버전 관리 로그만 사용할 수 있거나 두 가지 유형의 로그를 사용할 수 있다. 일부 파일은 어떤 방식으로, 일부 파일은 다른 방식으로 처리할 수 있다. 각 프로젝트는 사용자가 따라야 하는 정책을 가진다.


두 가지를 사용하는 것이 정책이면 사용자는 보통 각 변경 사항에 대한 엔트리를 한 번만 쓰고 두 가지 로그에 넣기를 원할 것이다. 사용자는
ChangeLog
에 엔트리를 쓴 다음 변경 사항을 커밋할 때 C-c C-a 를 이용해 로그 버퍼로 복사할 수 있다(287 페이지의 25.1.4절 [로그 버퍼] 참고). 아니면 변경 사항을 커밋하는 동안 로그 버퍼에 엔트리를 쓴 후 C-x v a 명령어를 이용해
ChangeLog
로 복사할 수 있다(Specialized Emacs Features 의 "Change Logs and VC"절 참고).


버전 관리와 모드 행

버전 관리 대상의 파일을 방문할 때는 Emacs가 이것을 모드 행에 표시한다. 가령 '
Bzr-1223
' 은 Bazaar가 해당 파일에 사용되고 있으며, 현재 수정본 ID가 1223임을 나타낸다.


백 엔드 이름과 수정본 ID 사이의 문자는 작업 파일의 버전 관리 상태를 나타낸다. 병합 기반의 버전 관리 시스템에서 '
-
' 문자는 작업 파일이 수정되지 않았음을 나타내고, '
:
'는 작업 파일이 수정되었음을 나타낸다. '
!
'는 파일이 최근 병합 연산의 결과로 충돌을 포함하거나 (296 페이지의 25.1.11.3절 [병합하기] 참고) 파일이 버전 관리로부터 제거되었음을 나타낸다. 마지막으로 '
?
'는 파일이 버전 관리 대상이지만 작업 트리에서 누락되어 있음을 의미한다.


잠금 기반의 시스템에서 '
-
'는 잠기지 않은 파일을, '
:
'는 잠긴 파일을 의미하고, 파일이 다른 사용자에 의해 잠길 경우 (예: '
jim
') '
RCS:jim:1.3
'으로 표시된다. '
@
'는 파일이 로컬로 추가되었지만 master 저장소로 커밋되지 않았음을 의미한다.


그래픽 디스플레이에서 사용자는 모드 행 표시기로 마우스를 이동시켜 버전 관리 상태에 대한 상세한 설명을 표시하는 "툴팁"을 팝업시킨다. 표시기에서 Mouse-1 을 누르면 VC 명령어의 메뉴가 팝업되는데, 이는 메뉴 바의 '
Tools / Version Control
' 과 동일하다.


Auto Revert 모드가 (132 페이지의 15.4절 [되돌리기] 참고) 버전 관리 중인 버퍼를 되돌리면 모드 행에 버전 관리 정보를 업데이트한다. 하지만 버전 관리 상태가 작업 파일을 변경하지 않고 현재 Emacs 세션 밖에서 변경될 경우 Auto Revert 모드는 이 정보를 업데이트한다.
auto-revert-check-vc-info
t
로 설정하면 Auto Revert 모드는
auto-revert-interval
초마다 버전 관리 상태 정보를 업데이트하고, 작업 파일 자체가 변경되지 않는다 하더라도 마찬가지다. 결과가 되는 CPU 사용량은 버전 관리 시스템에 따라 좌우되지만 초과되지는 않는 것이 보통이다.


버전 관리 하에 기본 편집

대부분의 VC 명령어들은 VC fileset에 작업한다. VC fileset은 VC 연산이 실행되는 하나 또는 이상의 파일 집합체이다. 사용자가 버전이 제어된 파일에 방문하는 버퍼에서 VC 명령어를 입력하면 VC fileset은 단순히 그 하나의 파일이 된다. VC Directory 버퍼에서 입력하면 그 안에 있는 일부 파일이 마크되고, VC fileset은 마크된 파일들로 구성된다(292 페이지의 25.1.10절 [VC Directory 모드] 참고).


최근 changeset 기반의 버전 관리 시스템에서 (283 페이지의 25.1.1.5절 [VCS Changesets] 참고) VC 명령어들은 다중 파일 VC filesets를 그룹으로 취급한다. 가령 다중 파일 VC fileset을 커밋하면 그러한 파일 모두에 대한 변경 사항을 포함하는 단일 수정본을 생성한다. CVS와 같이 오래된 파일 기반의 버전 관리 시스템에서 다중 파일 VC fileset에 위치한 각 파일은 개별적으로 처리되는데, 가령 커밋은 변경된 파일마다 하나의 수정본을 생성한다.


C-x v v
현재 VC fileset에서 적절한 다음 버전 관리 연산을 실행한다.


주요 VC 명령어는 다용도 명령어 C-x v v (
vc-next-action
)로서 현재 fileset에서 "가장 적절한" 액션을 실행하는데, 버전 관리 시스템으로 그것을 등록하거나, 커밋하거나, 잠금 해제하거나, 변경 사항을 그곳으로 병합하는 일을 수행한다. 이러한 정밀한 액션들은 다음 절에서 상세히 설명하겠다. 파일을 방문하는 버퍼나 VC Directory 버퍼에서 C-x v v 를 사용할 수 있다.


VC filesets는 기능 그룹(functional groups)에서 파일을 보고 방문하는 데에 사용되는 "명명된 filesets"와는 구별된다는 사실을 주목한다(145 페이지의 15.17절 [Filesets] 참고). 명명된 filesets와 달리 VC filesets는 명명되지 않고 세션에 걸쳐 지속되지 않는다.


병합하기를 이용한 기본 버전 관리

병합 기반의 버전 관리 시스템에서 (예: 가장 최신 시스템; 283 페이지의 25.1.1.4절 [VCS 병합] 참고) C-x v v 는 다음과 같은 일을 수행한다:

  • VC fileset에 하나 이상의 파일이 있고 파일이 일관되지 않은 버전 관리 상태를 가질 경우 오류를 보낸다. (하지만 fileset은 "새로 추가된" 파일과 "수정된" 파일 모두 포함할 수 있음을 주목한다; 288 페이지의 25.1.5절 [등록하기] 참고).
  • VC fileset 내 어떠한 파일도 버전 관리 시스템으로 등록되지 않은 경우 VC fileset을 등록시킨다(예: 버전 관리에 위치시킨다). 관련 내용은 288 페이지의 25.1.5절 [등록하기]를 참고한다. Emacs가 등록할 시스템을 찾지 못할 경우 저장소 타입의 입력을 요하고 새로운 저장소를 생성하여 그것으로 VC fileset을 등록한다.
  • VC fileset 내 모든 작업 파일이 변경되지 않은 경우 어떠한 일도 수행하지 않는다.
  • VC fileset 내 모든 작업 파일이 수정된 경우 변경 사항을 커밋한다. 이를 위해 Emacs 는
    *vc-log*
    버퍼를 팝업시키는데, 새로운 수정본에 대해 바람직한 로그 엔트리를 입력한 다음 C-c C-c 를 입력하면 커밋된다. 287 페이지의 25.1.4절 [로그 버퍼]를 참고한다.
    공유 저장소로 커밋할 경우 사용자가 저장소를 마지막으로 업데이트한 이후로 저장소가 변경되었다면 커밋은 실패할지도 모른다. 이런 경우 사용자는 다시 시도하기 전에 업데이트를 실행해야 한다. 분산 버전 관리 시스템에서는 C-x v + (296 페이지의 25.1.11.2절 [VC Pull] 참고) 또는 C-x v m(296 페이지의 25.1.11.3절 [합치기] 참고)을 이용한다. 중앙집중식 버전 관리 시스템에서는 C-x v 를 다시 입력하여 저장소 변경 사항에 합친다.
  • 마지막으로, 중앙집중식 버전 관리 시스템을 사용 중이라면 VC fileset 내 각 작업 파일이 최신인지 확인한다. 저장소에서 변경된 파일이 있다면 업데이트할 것을 권하라.


이러한 규칙은 "비잠금(non-locking)" 모드에서 RCS를 사용 중일 때에도 적용되는데, 단 저장소로부터 변경 사항이 자동으로 병합되는 경우는 제외한다. 사용자가 편집을 시작한 이후로 다른 사용자가 동일한 파일에 변경 사항을 커밋했는지 알려줄 방도는 없으며, 사용자가 수정본을 커밋하면 다른 사용자의 변경 사항은 제거된다(하지만 저장소에는 남아 있으므로 영구적으로 손실되지는 않는다.) 따라서 사용자는 변경 사항을 commit하기 전에 현재 수정본이 변경되지 않았음을 확인해야만 한다. 또한 이 모드에서도 RCS를 이용한 잠금이 가능하므로 수정되지 않은 파일로 C-x v v 를 이용하면 일반 잠금 모드에서 RCS와 마찬가지로 파일을 잠근다(286 페이지의 25.1.3.2절 [잠금 VCS를 이용한 VC] 참고).


잠금을 이용한 기본 버전 관리

잠금 기반의 버전 관리 시스템에서 (예: SCCS, 기본 모드의 RCS) C-x v v 는 다음을 실행한다:

  • VC fileset에 하나 이상의 파일이 있고 파일이 일관되지 않은 버전 관리 상태를 가질 경우 오류를 보낸다.
  • VC fileset 내 각 파일이 버전 관리 시스템으로 등록되지 않은 경우 VC fileset을 등록한다. 288 페이지의 25.1.5절 [등록하기]를 참고한다. Emacs가 등록할 시스템을 찾을 수 없다면 저장소 타입의 입력을 요하고 새로운 저장소를 생성하여 그것으로 VC fileset을 등록한다.
  • 각 파일이 등록되어 잠금 해제된 경우 사용자가 편집을 시작할 수 있도록 그것을 잠그고 쓰기 가능하게 만든다.
  • 각 파일이 사용자에 의해 잠금 상태가 되어 있고 변경 사항을 포함한 경우 변경 사항을 커밋한다. 이를 위해 Emacs 는
    *vc-log*
    버퍼를 팝업시키고, 새로운 수정본에 바람직한 로그 엔트리를 입력한 후 C-c C-c 를 사용하면 커밋한다(287 페이지의 25.1.4절 [로그 버퍼] 참고).
  • 당신이 각 파일을 잠갔지만 변경하지는 않은 경우 잠금을 해제하고 파일을 다시 읽기 전용으로 만든다.
  • 다른 사용자가 각 파일을 잠갔을 경우, 당신에게 "steal the lock"을 원하는지 묻는다. 'yes'라고 답하면 파일은 당신이 잠근 것이 되고, 이전에 파일을 잠근 사용자에게 경고 메시지가 전송된다.


이러한 규칙은 잠금 모드에서 CVS 를 사용할 때에도 적용되는데, 단 CVS 는 stealing locks 기능은 지원하지 않는다.


C-x v v에서 고급 제어
vc-next-action
(C-u C-x v v)에 접두 인자를 제공하면 여전히 다음 논리 버전 관리 연산을 실행하지만 연산을 실행하는 정확한 방법을 명시하기 위해 추가 인자를 허용한다.
  • 버전 관리 시스템 이름을 명시할 수 있다. Fileset을 하나 이상의 버전 관리 시스템에서 관리할 수 있으며 Emacs가 올바른 시스템을 감지하지 못할 때 유용하다.
  • 그 외에 CVS 또는 RCS를 사용 중이라면 사용자가 수정본 ID를 명시할 수 있다.
    Fileset이 수정된 (또는 잠금 상태인) 경우 이것은 해당 수정본 ID로 Emacs를 커밋하게 만든다. 사용자는 적절한 수정본 ID를 제공하여 새로운 branch를 생성할 수 있다(295 페이지의 25.1.11절 [Branches] 참고).
    Fileset이 수정되지 않은 (잠금 해제된) 경우 이것은 명시된 수정본을 작업 트리로 검사한다. 수정본 또는 branch ID를 제공하여 다른 branch에 수정본을 명시할 수도 있다(295 페이지의 25.1.11.1절 [Branch 전환하기] 참고). 빈 인자는 (예: C-u C-x v v RET) 현재 branch에서 최신("head") 수정본을 확인한다.
    이는 분산 버전 관리 시스템에서 오류를 보낸다. 그러한 시스템들은 사용자 고유의 수정본 ID를 명시하도록 허용하거나 개별 파일을 "체크 아웃(checking out)"하는 개념을 사용하지 않는다.


로그 엔트리 버퍼의 기능

변경 사항을 커밋하라고 VC 에게 알리면
*vc-log*
라는 버퍼가 팝업된다. 이 버퍼에서 사용자는 본인이 변경한 내용을 설명하는 로그 엔트리를 써야 한다(281 페이지의 25.1.1.1절 [버전 관리 이유] 참고). 완료되면 C-c C-c (
log-edit-done
)을 입력하여 버퍼를 종료하고 변경 사항과 함께 로그 엔트리를 커밋한다.


*vc-log*
버퍼에 대한 주 모드는 Log Edit 모드로, Text 모드의 변형 모드이다(217 페이지의 22.7절 [텍스트 모드] 참고). Log Edit 모드에 들어가면 Emacs 는
text-mode-hook
vc-log-mode-hook
을 실행한다(422 페이지의 33.2.2절 [훅] 참고).


*vc-log*
버퍼에서는 버전 관리 시스템에 제공할 추가 정보를 명시하는 하나 또는 이상의 제목 행을 쓸 수 있다. 제목 행마다 버퍼의 상단에 하나의 행을 차지해야 하는데, 제목 행이 아닌 첫 행이 로그 엔트리의 시작으로 취급된다. 가령 다음의 제목 행은 현재 변경 내용이 당신이 작성한 것이 아니라 다른 개발자가 행한 것임을 나타낸다:
Author: J. R. Hacker <jrh@example.com>


'
Author
' 헤더 외에 Emacs 는 '
Date
'(수동으로 명시되는 커밋 시간)와 '
Fixes
'(변경 사항으로 수정된 버그의 참조) 헤더를 인식한다. 모든 버전 관리 시스템이 모든 헤더를 인식하는 것은 아닌데, Bazaar는 세 가지 헤더를 모두 인식하는 반면 Git, Mercurial, Monotone 은 '
Author
'와 '
Date
'만 인식한다. 이를 지원하지 않는 시스템에 헤더를 명시할 경우 헤더는 로그 엔트리의 일부로 취급된다.


*vc-log*
버퍼에 있는 동안 "현재 VC fileset"는 사용자가 C-c C-c 를 입력하면 커밋될 fileset 로 간주된다. VC fileset 내 파일의 목록을 확인하려면 C-c C-f (
log-edit-show-files
)를 입력한다. VC fileset 와 사용자가 편집을 시작한 버전 간 변경 사항의 diff를 확인하려면 (289 페이지의 25.1.6절 [오래된 수정본] 참고) C-c C-d (
log-edit-show-diff
)를 입력한다.


VC fileset 이 하나 또는 이상의 ChangeLog 파일을 포함할 경우 (297 페이지의 25.2절 [변경 로그] 참고) C-c C-a (
log-edit-insert-changelog
)를 입력하면
*vc-log*
버퍼로 관련 엔트리를 가져올 수 있다. 각 ChangeLog 에서 최상위 항목이 현재 일자로 당신의 사용자 이름으로 만들어졌다면 이 명령어는 커밋될 파일에 일치하는 엔트리에 대한 항목을 검색하여 삽입한다.


커밋을 취소하기 위해 해당 버퍼에서 C-c C-c 를 입력하지 말라. 버퍼를 전환하여 다른 편집을 실행할 수 있다. 다른 커밋을 시도하지 않는 이상 사용자가 편집 중이던 엔트리는
*vc-log*
버퍼에 남아 있고, 사용자는 언제든 해당 버퍼로 돌아가 커밋을 완료할 수 있다.


커밋 명령어를 중복하기 위해 이전 로그 엔트리의 히스토리를 확인할 수도 있다. 이는 사용자가 비슷한 주석을 가진 여러 개의 커밋을 만들고자 할 때 유용할 것이다. 이러한 작업에 M-n, M-p, M-s, M-r 명령어를 사용하는 것은 미니버퍼 밖에서 사용된다는 사실만 제외하면 미니버퍼 히스토리 명령어와 같다(32 페이지의 5.5절 [미니버퍼 히스토리] 참고).


파일을 버전 관리용으로 등록하기

C-x v i
방문한 파일을 버전 관리용으로 등록한다.


C-x v i (
vc-register
) 명령어는 현재 VC fileset 내 각 파일을 버전 관리용으로 등록한다. 이는 등록되지 않은 VC fileset 에서 C-x v v 를 실행하는 것과 기본적으로 동일한데 (285 페이지의 25.1.3절 [기본 VC 편집] 참고) VC fileset 이 이미 등록되어 있을 경우 C-x v i 는 오류를 보내는 반면 C-x v v 는 다른 액션을 실행한다는 점이 다르다.


파일을 등록하기 위해 Emacs 는 버전 관리 시스템을 선택해야 한다. 다중 파일 VC fileset의 경우 VC Directory 버퍼는 사용할 시스템을 명시한다(292 페이지의 25.1.10절 [VC Directory 모드] 참고). 단일 파일 VC fileset의 경우 파일의 디렉터리가 이미 버전 관리 시스템에 등록된 파일을 포함하거나 디렉터리가 버전 관리 시스템에서 관리하는 디렉터리 트리의 일부라면 Emacs는 그 시스템을 선택한다. 하나 이상의 버전 관리 시스템이 적용 가능한 경우 Emacs 는
vc-handled-backeneds
변수에 처음으로 나타나는 것을 사용한다. Emacs가 파일을 등록할 버전 관리 시스템을 찾을 수 없다면 저장소 타입의 입력을 요하고 새로운 저장소를 생성하여 그 저장소로 파일을 등록한다.


대부분의 오래된 버전 관리 시스템에서는 C-x v i 또는 C-x v v 를 이용해 파일을 등록 시 저장소가 아니라 "작업 트리"로 추가한다. 그러한 파일은 VC Directory 버퍼에서 '
added
' 로 라벨이 붙고, 모드 행에 '
@@
'의 수정본 ID를 표시한다. 저장소에서 등록의 효과를 내기 위해서는 커밋을 실행해야 한다(285 페이지의 25.1.3절 [기본 VC 편집] 참고). 한 번의 커밋으로 파일 추가와 기존 파일의 편집을 모두 포함할 수 있음을 주목한다.


잠금 기반의 버전 관리 시스템에서 (283 페이지의 25.1.1.4절 [VCS 병합하기] 참고) 파일을 등록하면 잠금이 해제되고 읽기 전용으로 남겨둔다. C-x v v 를 입력하면 편집을 시작한다.


오래된 수정본을 조사하고 비교하기

C-x v =
현재 VC fileset 의 작업 파일과 사용자가 시작한 버전을 비교한다(
vc-diff
). 접두 인자를 이용하면 현재 VC fileset 의 수정본 2개를 입력하도록 요하여 둘을 비교한다. Dired 버퍼로부터 이 명령어를 호출할 수도 있다(315 페이지의 27장 [Dired] 참고).


C-x v D
전체 작업 트리를 사용자가 시작한 수정본과 비교한다(
vc-root-diff
). 접두 인자를 이용하면 수정본 2개를 입력하도록 요하여 그 트리를 비교한다.


C-x v ~
현재 파일의 수정본을 입력하도록 요하여 그것을 별도의 버퍼에서 방문한다(
vc-revision-other-window
).


C-x v g
현재 파일의 주석 달린(annotated) 버전을 표시하고, 각 행마다 그것이 수정된 최신 수정본을 표시한다(
vc-annotate
).


C-x v = (
vc-diff
)는 현재 VC fileset 내 각 작업 파일을 사용자가 편집을 시작한 버전과 비교하는 diff를 표시한다. Diff는
*vc-diff*
라는 Diff 모드 버퍼의 다른 창에 표시된다(138 페이지의 15.9절 [Diff 모드] 참고). 일반적인 Diff 모드 명령어는 이 버퍼에서 이용할 수 있다. 특히 g (
revert-buffer
) 명령어는 다시 파일 비교를 실행하여 새로운 diff를 생성한다.


현재 VC fileset 에 대한 임의의 수정본 2개를 비교할 경우 접두 인자를 이용해
vc-diff
를 호출한다: C-u C-x v =. 이는 두 개의 수정본 ID를 입력하도록 요구하고(282 페이지의 25.1.1.3절 [VCS 개념] 참고) fileset 의 그러한 버전들 간 diff 를 표시한다. 버전 관리 시스템이 changeset 기반(예: CVS)이 아니라 파일 기반일 경우 다중 파일 VC filesets 에는 신뢰성 있게 작동하지 않을 것인데, 여러 파일에 대한 수정본 ID들이 의미 있는 방식으로 관련되지 않을 것이기 때문이다.


일부 버전 관리 시스템은 수정본 ID 대신 다른 포맷으로 수정본을 명시하도록 해준다. 가령 Bazaar에서 어제 이후로 커밋한 첫 번째 수정본을 명시하도록 할 경우 C-u C-x v = (또한 관련 명령어에서)에 대한 인자로 '
date:yesterday
'를 입력할 수 있다. 상세한 내용은 버전 관리 시스템의 문서를 참고한다.


Dired 버퍼로부터 C-x v = 또는 C-u C-x v = 를 호출할 경우 (315 페이지의 27장 [Dired] 참고), 현재 행에 열거된 파일은 현재 VC fileset 로 취급된다.


C-x v D (
vc-root-diff
)는 C-x v =와 유사하지만 현재 작업 트리 전체에서 변경 내용을 표시한다(예: 현재 VC fileset 을 포함하는 작업 트리). 이 명령어를 Dired 버퍼로부터 호출할 경우 디렉터리를 포함하는 작업 트리로 적용된다.


C-x v =C-x v D 가 diffs 를 생성하기 위해 사용하는
diff
옵션을 맞춤화할 수도 있다. 사용되는 옵션은
vc-backend-diff-switches
,
vc-diff-switches
,
diff-switches
순으로 된 변수들 중에서 처음으로 마주치는 non-
nil
값에서 취한다(137 페이지의 15.8절 [파일 비교하기] 참고). 여기서 backend 는 관련된 버전 관리 시스템을 의미하는데, 가령
bzr
는 Bazaar 를 의미한다.
nil
은 시퀀스에서 다음 변수를 검사할 것을 의미하므로 처음 두 개 중 하나가
t
값을 사용하면 어떠한 전환도 없음을 의미한다.
vc-backend-diff-switches
변수 대부분은
nil
을 기본값으로 하지만 일부는
t
를 기본값으로 하는데, 이는
diff
구현에서 Subversion 과 같은 공통된
diff
옵션을 수용하지 않는 버전 관리 시스템에 해당한다.


파일의 오래된 버전을 직접 살펴보려면 C-x v ~ re-vision RET (
vc-revision-other-window
)를 입력한다. 그러면 revision 에 해당하는 파일 버전을 찾아서
filename.~revision~
으로 저장하여 다른 창에서 그 파일로 방문한다.


많은 버전 관리 시스템들이 행별 수정본 정보로 주석이 추가된(annotated) 파일을 볼 수 있도록 허용하는데, 이는 C-x v g (
vc-annotate
)를 이용하여 이루어진다. 이는 새로운 버퍼를 생성하여 ("annotate 버퍼") 파일의 텍스트를 표시하는데, 각 행은 그것이 얼마나 오래 되었는지를 나타내는 색상으로 표시된다. 빨간색 텍스트는 새로운 텍스트, 파란색은 오래된 텍스트, 중간 색은 그 중간 정도의 기간을 의미한다. 기본적으로 색상은 전체 기간 범위로 조정되는데, 가장 오래된 변경 사항은 파란색이고 가장 최근 변경 사항은 빨간색이다.


이 명령어에 접두 인자를 제공할 경우 Emacs는 미니버퍼를 이용해 2개의 인자를 읽는데, 바로 표시할 수정본과 주석(현재 파일 내용 대신), 그리고 일자로 표시된 시간 간격과 색상 범위가 그에 해당한다.


Annotate 버퍼로부터 이것을 비롯해 그 외 색상 조정 옵션은 '
VC-Annotate
' 메뉴에서 이용할 수 있다. 이 버퍼에서는 다음과 같은 키를 이용해 과거의 수정본에 대한 주석을 살펴보고, diff를 확인하며, 로그 엔트리를 볼 수 있다:


p
이전 수정본, 가령 최근에 주석이 달린 수정본 이전의 수정본에 주석을 단다. 수치적 인자는 반복 계수이므로 C-u 10 p 는 10개 이전의 수정본으로 데려갈 것이다.


n
다음 수정본, 가령 최근에 주석이 달린 수정본 다음의 수정본에 주석을 단다. 수치적 인자는 반복 계수다.


j
현재 행에서 나타내는 수정본에 주석을 단다.


a
현재 행에서 나타내는 수정본 이전의 수정본에 주석을 단다. 현재 행을 변경하기 전에 파일이 위치하였던 상태를 확인하는 데에 유용하다.


f
현재 행에서 나타내는 파일 수정본을 버퍼에 표시한다.


d
현재 행의 수정본과 이전 수정본 간 diff 를 표시한다. 파일에서 현재 행의 수정본 중 무엇이 실제로 변경되었는지 확인하는 데에 유용하다.


D
현재 행의 수정본과 changeset 내 모든 파일에 대한 이전 수정본 간 diff를 표시한다(changesets를 지원하는 VC 시스템의 경우). 트리에서 현재 행의 수정본 중 무엇이 실제로 변경되었는지 확인하는 데에 유용하다.


l
현재 행의 수정본에 대한 로그를 표시한다. 현재 행에서 수정본에 이루어진 변경 사항에 대한 저자의 설명을 확인하는 데에 유용하다.


w
사용자가 편집 중인 작업 수정본에 주석을 단다. 다른 수정본을 보기 위해 pn 을 사용했다면 이 키를 이용해 사용자의 작업 수정본으로 돌아간다.


v
주석 표시 여부를 토글한다. 주석으로부터 방해 받지 않고 파일 내용을 보는 데에 유용하다.


VC 변경 로그

C-x v l
현재 fileset에 대한 변경 히스토리를 표시한다(
vc-print-log
).


C-x v L
현재 저장소에 대한 변경 히스토리를 표시한다(
vc-print-root-log
).


C-x v I
Pull 연산이 검색할 변경 사항을 표시한다(
vc-log-incoming
).


C-x v O
다음 push 연산이 전송할 변경 사항을 표시한다(
vc-log-outgoing
).


C-x v l (
vc-print-log
) 는
*vc-change-log*
라는 버퍼를 표시하면서 변경자, 변경 날짜, 각 변경 사항에 대한 로그 엔트리를 포함해 현재 파일에 대한 변경 사항의 히스토리를 보여준다(이는 사용자가
*vc-log*
버퍼를 통해 입력하는 것과 동일한 로그 엔트리이다; 287 페이지의 25.1.4절 [로그 버퍼]를 참고). 포인트는 현재 방문 중인 파일의 수정본에서 중앙화된다. 접두 인자를 이용해 명령어는 중앙화할 수정본과 표시할 수정본의 최대 개수를 입력하도록 요한다.


VC Directory 버퍼 (292 페이지의 25.1.10절 [VC Directory 모드] 참고) 또는 Dired 버퍼로부터 (315 페이지의 27장 [Dired] 참고) C-x v l 을 호출할 경우 현재 행에 열거된 파일로 적용된다.


C-x v L (
vc-print-root-log
)는 버전이 관리된 디렉터리 트리 전체의 히스토리를 표시하는
*vc-change-log*
버퍼를 표시한다(RCS, SCCS, CVS는 이 기능을 지원하지 않는다). 접두 인자를 이용하면 명령어는 표시할 수정본의 최대 개수를 입력하도록 요구한다.


C-x v L 히스토리는 축소 형태로 표시되는데, 주로 각 로그 엔트리의 첫 행만 표시한다. 하지만 포인트에서 수정본에 대한 전체 로그 엔트리를 표시하려면
*vc-change-log*
에서 RET (
log-view-toggle-entry-display
)를 입력한다. 두 번째로 RET 을 입력하면 다시 숨긴다.


분산 버전 관리 시스템에서 C-x v I (
vc-log-incoming
) 명령어를 사용하면 사용자가 다른 저장소로부터 새로운 수정본을 얻기 위해 버전 관리 시스템의 "pull" 명령어를 다음으로 이용할 때 적용될 변경 사항을 보여주는 로그 버퍼를 표시한다(296 페이지의 25.1.11.2절 [VC Pull] 참고). 이러한 다른 저장소는 버전 관리 시스템이 정의한 바와 같이 변경 사항이 pull 되는 기본값으로, 접두 인자를 이용해
vc-log-incoming
을 이용하면 특정 저장소를 입력하도록 요한다. 마찬가지로 C-x v O (
vc-log-outgoing
)은 사용자가 다음으로 "push" 명령어를 실행하면 다른 저장소로 전송될 변경 사항을 표시하는데, 접두 인자를 이용하면 구체적인 목적지 저장소의 입력을 요한다.


*vc-change-log*
버퍼에서는 파일의 로그와 수정본의 로그 간을 이동하고 지난 수정본을 검사 및 비교하는 데에 다음과 같은 명령어를 이용할 수 있다(289 페이지의 25.1.6절 [오래된 수정본] 참고).


p
이전 수정본 엔트리로 이동한다. (로그 버퍼에서 수정본 엔트리는 주로 역시간순으로 되어 있으므로 이전 수정본 항목이 최근 수정본에 해당한다.) 수치적 인자는 반복 계수다.


n
다음 수정본 엔트리로 이동한다. 수치적 인자는 반복 계수다.


P
다중파일 VC fileset에 대한 로그를 표시할 경우 이전 파일의 로그로 이동한다. 그 외의 경우 로그의 시작으로 이동한다. 수치적 인자는 반복 계수다.


N
다중파일 VC fileset에 대한 로그를 표시할 경우 다음 파일의 로그로 이동한다. 수치적 인자는 반복 계수다.


a
현재 행에 수정본의 주석을 단다(289 페이지의 25.1.6절 [오래된 수정본] 참고).


e
포인트에 표시된 변경 주석을 수정한다. 모든 VC 시스템이 변경 주석의 주석을 지원하지는 않음을 주목한다.


f
현재 행에 표시된 수정본을 방문한다.


d
포인트에 위치한 수정본과 구체적 파일에 대해 그보다 이전(next earlier)의 수정본 간 diff를 표시한다.


D
포인트에 위치한 수정본과 그보다 이전 수정본 간 changeset diff를 표시한다. 이는 해당 수정본에서 모든 파일에 이루어진 변경 사항을 표시한다.


RET
축소 스타일의 로그 버퍼에서 (예: C-x v L 로 생성된 로그 버퍼) 포인트에 위치한 수정본에 대한 전체 로그 엔트리의 표시와 숨김을 토글한다.


다수의 로그 엔트리를 꺼내는 작업은 느릴 수 있으므로
*vc-change-log*
버퍼는 기본적으로 2000개 이하의 수정본만 표시할 수 있다.
vc-log-show-limit
변수가 이러한 한계를 명시하는데, 값을 0으로 설정하면 한계값이 제거된다. 버퍼의 끝에 '
Show 2X entries
' 또는 '
Show unlimited entries
' 버튼을 클릭하면 기존
*vc-change-log*
버퍼에 표시된 수정본의 개수를 증가시킬 수 있다. 하지만 RCS, SCCS, CVS는 이러한 기능을 지원하지 않는다.


버전 관리 행위 실행취소하기

C-x v u
현재 VC fileset 의 작업 파일(들)을 마지막 수정본으로 되돌린다(
vc-revert
).


현재 VC fileset 에 적용된 변경 사항을 모두 제거하고 싶다면 C-x v u (
vc-revert-buffer
)를 입력한다. 그러면 작업 파일(들)과 편집을 시작한 수정본 간 diff 를 표시하면서 변경 사항을 취소할 것인지 확인을 요청한다. 이에 동의하면 fileset 은 되돌아간다. C-x v u 가 diff를 표시하지 않길 원한다면
vc-revert-show-diff
변수를
nil
로 설정한다(C-x v =를 이용해 직접 diff 를 볼 수도 있다; 289 페이지의 25.1.6절 [오래된 수정본] 참고). C-x v u 는 일반 실행취소 명령어로는 (109 페이지의 13.1절 [실행취소] 참고) 되돌릴 수 없으므로 주의하여 사용해야 한다.


잠금 기반의 버전 관리 시스템에서 C-x v u 는 파일을 잠그지 않은 상태로 남겨두므로 편집을 재개하려면 다시 잠금을 실행해야 한다. 잠근 후 변경하지 않길 원한다면 C-x v u 를 이용해 파일을 잠금 해제한다.


버전 관리 파일을 무시한다

C-x v G
현재 버전 관리 시스템에 있는 파일을 무시한다. (
vc-ignore
).


많은 소스 트리들이 에디터 백업, 객체 또는 바이트코드 파일, 빌트 프로그램과 같이 버저닝할 필요가 없는 파일을 몇 가지 포함한다. 단순히 추가를 하지 않는 방법도 있지만 그럴 경우 언젠가 알려지지 않은 파일로 나타날 것이다. 아니면 트리의 최상단에 무시할 파일을 추가함으로써 이러한 파일을 무시하도록 버전 관리 시스템에게 알려줄 수도 있다. C-x v G (
vc-ignore
)를 이용하면 된다. 접두 인자를 이용해 호출할 경우 무시한 파일 목록으로부터 파일을 제거할 수 있다.


VC Directory 모드

VC Directory 버퍼는 디렉터리 트리에서 파일의 버전 관리 상태를 확인하고, 그러한 파일에 버전 관리 연산을 실행하는 특수화된 버퍼이다. 특히 C-x v v 와 같은 명령어들이 실행될 다중 파일 VC filesets 를 명시하는 데에 사용된다(293 페이지의 25.1.10.2절 [VC Directory 명령어] 참고).


VC Directory 버퍼를 사용하려면 C-x v d (
vc-dir
)를 입력한다. 이는 미니버퍼를 이용해 디렉터리명을 읽고, 해당 디렉터리에 대한 VC Directory 버퍼로 전환한다. 기본적으로 버퍼는
*vc-dir*
로 명명된다. 그 내용은 아래에 설명하겠다.


vc-dir
명령어는 명시된 디렉터리에서 사용될 버전 관리 시스템을 자동으로 감지한다. 하나 이상의 시스템이 디렉터리에서 사용 중인 경우 사용자는 접두 인자를 이용해 C-u C-x v d 를 호출해야 하며, 그럴 경우 VC Directory 버퍼가 사용해야 하는 버전 관리 시스템을 입력하도록 요한다.


VC Directory 버퍼

VC Directory 버퍼는 버전이 관리된 파일과 그 버전 관리 상태의 목록을 포함한다. 이는 현재 디렉터리와 (C-x v d 를 호출 시 명시된) 그 하위디렉터리에 파일을 열거하지만 "noteworthy" 상태의 것만 열거한다. 최신 파일은 (예: 저장소의 것과 동일한) 누락된다. 하위디렉터리 내 모든 파일이 최신일 경우 하위디렉터리는 열거되지 않는다. 단, 파일이 VC 명령어의 직접적인 결과로 최신 파일이 되었다면 열거될 것이다.


VC Directory 버퍼 리스팅의 예를 들어보겠다:

                    ./
    edited          configure.ac
*   added           README 
    unregistered    temp.txt
                    src/
*   edited          src/main.c


2개의 작업 파일은 수정되었지만 커밋되지는 않았다: 현재 디렉터리의
configure.ac
src/
하위디렉터리의
foo.c
이다.
README
로 명명된 파일이 추가되었으나 커밋되지 않았고,
temp.txt
는 버전 관리 대상이 아니다(288 페이지의 25.1.5절 [등록하기] 참고).


README
src/main.c
에 대한 엔트리 옆에 '
*
' 문자는 사용자가 이러한 파일을 현재 VC fileset 으로 마크하였음을 나타낸다(아래 참고).


위의 예제는 Bazaar, Git, Mercurial 과 같은 분산 버전 관리 시스템에 일반적이다. 다른 시스템이라면 다른 상태를 표시할 수도 있다. 예를 들어 CVS 는 저장소가 작업 파일에 적용되지 않은 변경 사항을 가진 경우 '
needs-update
' 상태를 표시한다. RCS 와 SCCS 는 파일을 잠그는 사용자명을 그 상태로 표시한다.


VC Directory 버퍼는
vc-directory-exclusion-list
변수에 열거된 하위디렉터리는 누락한다. 그 기본값은 버전 관리 시스템에서 내부적으로 사용하는 디렉터리를 포함한다.


VC 디렉터리 명령어

Emacs 는 VC Directory 버퍼를 탐색하고 파일이 현재 VC fileset 에 속한다고 "마킹"하는 명령어를 몇 가지 제공한다.


n
SPC
다음 엔트리로 포인트를 이동한다(
vc-dir-next-line
).


p
이전 엔트리로 포인트를 이동한다(
vc-dir-previous-line
).


TAB
다음 디렉터리 엔트리로 이동한다(
vc-dir-next-directory
).


S-TAB
이전 디렉터리 엔트리로 이동한다(
vc-dir-previous-directory
).


RET
f
현재 행에 열거된 파일이나 디렉터리를 방문한다(
vc-dir-find-file
).


o
현재 행의 파일 또는 디렉터리를 별도의 창에서 방문한다(
vc-dir-find-file-other-window
).


m
현재 행의 파일 또는 디렉터리를 마크하고 (
vc-dir-mark
) 그것을 현재 VC fileset 에 넣는다. 영역이 활성화되어 있으면 영역 내 모든 파일을 마크한다.
파일이 이미 마크된 디렉터리 또는 그 하위디렉터리 중 하나에 위치할 경우 이 명령어로 파일을 마크할 수 없다. 마찬가지로 트리의 어떤 파일이든 마크되어 있다면 이 명령어를 이용해 디렉터리를 마크할 수 없다.


M
포인트가 파일 엔트리에 있다면 동일한 상태로 모든 파일을 마크하고, 포인트가 디렉터리 엔트리에 있다면 해당 디렉터리 트리 내 모든 파일을 마크한다(
vc-dir-mark-all-files
). 접두 인자를 이용해 열거된 파일과 디렉터리를 모두 마크한다.


q
VC Directory 버퍼를 종료하고 그대로 묻어버린다(
quit-window
).


u
현재 행에 파일 또는 디렉터리를 마크 해제한다. 영역이 활성화되어 있다면 영역 내 모든 파일을 마크 해제한다(
vc-dir-unmark
).


U
포인트가 파일 엔트리에 있을 경우 동일한 상태의 파일을 모두 마크 해제하고, 포인트가 디렉터리 엔트리에 있을 경우 해당 디렉터리 트리 내 모든 파일을 마크 해제한다(
vc-dir-unmark-all-files
). 접두 인자를 이용해 모든 파일과 디렉터리를 마크 해제한다.


x
'up-to-date' 상태를 이용해 파일을 숨긴다(
vc-dir-hide-up-to-date
). 접두 인자를 이용해 포인트에 위치한 항목의 상태로 된 항목을 모두 숨긴다.


VC Directory 버퍼에 있는 동안 m (
vc-dir-mark
) 또는 M (
vc-dir-mark
)을 이용해 마크한 파일은 모두 현재 VC fileset 에 있다. m 을 이용해 디렉터리 엔트리를 마크할 경우 해당 디렉터리 트리에 열거된 파일은 현재 VC fileset 이다. 현재 VC fileset 에 속하는 파일과 디렉터리는 VC Directory 버퍼에서 VC 상태 옆에 '
*
' 문자로 표시되어 있다. 이를 통해 사용자는 다중 파일 VC fileset 이 C-x v v(285 페이지의 25.1.3절 [기본 VC 편집] 참고), C-x v = (289 페이지의 25.1.6절 [오래된 수정본] 참고), C-x v u(292 페이지의 25.1.8절 [VC 실행 취소] 참고)와 같은 VC 명령어들에 의해 실행되도록 할 수 있다.


VC Directory 버퍼는 C-x v 접두어를 이용해 VC 명령어에 대한 단일 키 단축키를 몇 가지 정의하기도 한다: =, +, l, i, D, L, G, I, v.


예를 들어 파일이 '
edited
' 상태로 열거된 VC Directory 버퍼를 열고, 파일을 마크하며, v 또는 C-x v v(
vc-next-action
)을 입력하면 편집된 파일의 집합을 커밋할 수 있다. 버전 관리 시스템이 changeset 기반일 경우 Emacs 는 단일 수정본의 파일을 커밋할 것이다.


VC Directory 버퍼에 있을 때는 다음을 명령어를 이용해 현재 VC fileset 에서 검색 및 대체를 실행할 수 있다:


S
fileset 을 검색한다(
vc-dir-search
).


Q
fileset 에서 정규 표현식 쿼리 대체를 실행한다(
vc-dir-query-replace-regexp
).


M-s a C-s
fileset에 증분 검색을 실행한다(
vc-dir-isearch
).


M-s a C-M-s
fileset에 증분 정규 표현식 검색을 실행한다(
vc-dir-isearch-regexp
).


이러한 명령어들은 다수의 파일에 작업하는 것 외에도 단일 버퍼에 상응하는 명령어들과 같이 행동한다(90 페이지의 12장 [검색] 참고).


위의 명령어들은 메뉴 바를 통해, 그리고 Mouse-2 를 이용해 호출된 컨텍스트 메뉴를 통해서도 이용할 수 있다. 또한 일부 VC 백 엔드는 메뉴를 이용해 백 엔드 특정적인 명령어를 추가로 제공한다. 가령 Git 와 Bazaar 는 stashesshelves 를 조작할 수 있도록 해준다(커밋되지 않은 변경 사항을 임의로 제쳐두고 후에 다시 가져오는 방도).


버전 관리 branch

버전 관리의 한 가지 사용 용도는 branch 라고 불리는 다중 개발 행을 지원하는 데에 있다. 무엇보다 branch는 프로그램의 "안정" 버전과 "개발" 버전을 구분하여 유지하고, 관련이 없는 기능을 분리시켜 개발하는 데에 사용할 수 있다.


VC 의 branch 연산 지원은 현재 꽤 제한되어 있다. 분산 버전 관리 시스템의 경우 어떤 branch 를 다른 branch 의 내용으로 업데이트하고, 두 가지 branch로 변경 사항을 병합하는 명령어를 제공한다(296 페이지의 25.1.11.3절 [병합하기] 참고). 중앙집중식 버전 관리 시스템의 경우 여러 branch의 검사와 새로운 또는 다른 branch로의 커밋을 지원한다.


Branch 들 사이의 전환

다양한 버전 관리 시스템마다 branch가 어떻게 구현되는지 다르고, 이러한 차이는 전적으로 VC에서 숨길 수 없다.


Bazaar 와 Mercurial 의 일반 작동 모드를 포함해 일부 분산 버전 관리 시스템에서는 각 branch 마다 고유의 작업 디렉터리 트리를 가지므로 branch 들 간 전환 시 디렉터리의 전환만 수반된다. Git 에서는 branch가 보통 동일한 디렉터리에 동시 위치(co-locate)하고, branch간 전환은
git checkout
명령어를 이용하여 이루어지므로 작업 트리의 내용이 사용자가 전환하려는 branch에 일치하도록 변경된다. Barzaar 역시 동시 위치하는 branch를 지원하기 때문에
bzr switch
명령어를 이요하면 현재 디렉터리에서 branch 들 간 전환을 실행할 것이다. Subversion 에서는
svn switch
명령어를 이용해 다른 branch 로 전환이 가능하다.


현재 디렉터리에서 다른 branch 전환하기 위한 VC 명령어는 C-x v r branch-name RET (
vc-retrieve-tag
) 이다.


중앙집중식 버전 관리 시스템에서는 최신 작업 파일에서 C-u C-x v v 를 입력하고 (287 페이지의 25.1.3.3절 [고급 C-x v v] 참고) 또 다른 branch에서 수정을 위해 수정본 ID를 입력함으로써 branch들 간 전환이 가능하다. 가령 CVS에서 trunk(개발 메인 행)에 대한 수정본은 보통 1.1, 1.2, 1.3, ..., 식의 형태로 된 ID를 가지는 반면 가령 수정본 1.2로부터 생성된 첫 번째 branch는 1.2.1.1, 1.2.1.2, ..., 식으로 된 수정본 ID를 가지며, 수정본 1.2로부터 생성된 두 번째 branch는 1.2.2.1, 1.2.2.2, ..., 식으로 된 수정본 ID를 가진다. 마지막 요소가 누락된 branch 수정본 ID인 (예: 1.2.1) branch ID를 명시하면 해당 branch에서 최신 수정본으로 전환할 수 있다.


잠금 기반 시스템에서 다른 branch 로 전환하면 작업 트리를 잠금 해제하기도 한다(쓰기 보호).


Branch 로 전환하고 나면 VC 명령어는 사용자가 다시 전환할 때까지 해당 branch 에 적용될 것인데, 가령 사용자가 커밋하는 VC filesets 는 그 특정 branch 로 커밋될 것이다.


Branch로 변경 사항 가져오기
C-x v +
분산 버전 관리 시스템에서 다른 위치의 변경 사항을 "가져(pull in)"옴으로써 현재 branch를 업데이트한다.
중앙집중식 버전 관리 시스템에서는 현재 VC fileset을 업데이트한다.


분산 버전 관리 시스템에서 C-x v + (
vc-pull
) 명령어는 현재 branch 와 작업 트리를 업데이트한다. 주로 원격 branch 의 복사본을 업데이트하는 데에 사용된다. 접두 인자를 제공할 경우 명령어는 사용할 정확한 버전 관리 명령어의 입력을 요하여 사용자가 변경 사항을 가져올 곳을 명시하도록 해준다. 명시하지 않으면 버전 관리 시스템이 결정한 기본 위치로부터 가져온다.


분산 버전 관리 시스템들 사이에서는 C-x v+ 가 현재 Bazaar, Git, Mercurial 에서만 지원된다. Bazaar 에서는 일반 branch 에 대해
bzr pull
을 호출하고(master branch로부터 mirroring branch로 가져오기 위해), bound branch에 대해서는
bzr update
를 호출한다(중앙 저장소로부터 가져오기 위해). Git 에서는 원격 저장소로부터 변경 사항을 인출하여 현재 branch 로 병합하는 데에
git pull
을 호출한다. Mercurial 에서는
hg pull -u
를 호출하여 기본 원격 저장소로부터 changesets 를 인출하여 작업 디렉터리를 업데이트한다.


가져오기 전에 C-x v I (
vc-log-incoming
)을 사용하면 적용할 변경 사항의 로그 버퍼를 확인할 수 있다. 290 페이지의 25.1.7절 [VC Change Log]를 참고한다.


CVS 와 같은 중앙집중식 버전 관리 시스템에서 C-x v+ 는 저장소로부터 현재 VC fileset 을 업데이트한다.


Branch 병합하기
C-x v m
분산 버전 관리 시스템에서는 다른 branch 의 변경 사항을 현재 branch 로 병합한다.
중앙집중식 버전 관리 시스템에서는 다른 branch 의 변경 사항을 현재 VC fileset 으로 병합한다.


Branch 를 개발하는 동안 다른 branch 에 이미 이루어진 변경 사항에 병합해야 하는 경우가 종종 있다. 중복된 변경 사항이 두 개의 branch로 이루어지기 때문에 평범한 연산은 아니다.


분산 버전 관리 시스템에서 병합은 C-x v m (
vc-merge
) 명령어를 이용해 이루어진다. Bazaar 에서 이는 정확한 인자를
bzr merge
로 전달하도록 요하고, 가능하다면 분별 있는 기본값을 제공한다. Git 에서는 병합할 branch 의 이름을 입력하도록 요한다(현재 저장소에 알려진 branch 명을 기준으로). 병합 명령어를 실행하여 얻은 출력은 구분된 버퍼에 표시된다.


CVS 와 같이 중앙집중식 버전 관리 시스템에서 C-x v m 은 branch ID 또는 한 쌍의 수정본 ID의 입력을 요한 후 (295 페이지의 25.1.11.1절 [Branch 전환하기] 참고) 해당 branch 로부터 변경 사항을 찾거나 사용자가 명시한 두 개의 수정본 간에 변경 사항을 찾아 현재 VC fileset 으로 그러한 변경 사항을 병합한다. RET 을 입력하였다면 Emacs 는 마지막으로 파일을 확인한 이후로 동일한 branch 에 이루어진 변경 사항은 단순히 모두 병합할 것이다.


병합이 실행된 직후에는 작업 트리만 수정되며, 사용자는 C-x v D 와 관련 명령어를 이용해 병합으로 인해 생성된 변경 사항을 검토할 수 있다(289 페이지의 25.1.6절 [오래된 수정본] 참고). 두 개의 branch가 중복된 변경 사항을 포함할 경우 병합하면 충돌이 발생하고, 병합 명령어의 출력에 경고가 발생하며, 영향을 받는 작업 파일로 충돌 마커(conflict marker)가 삽입되어 두 개의 충돌된 변경 사항 집합을 둘러싼다. 이러한 충돌은 충돌된 파일의 편집을 통해 해결해야 한다. 편집이 완료되면 수정된 파일은 병합을 적용하려면 평소대로 커밋되어야 한다(285 페이지의 25.1.3절 [기본 VC 편집] 참고).


새로운 branch 생성하기
CVS 와 같은 중앙집중식 버전 관리 시스템에서 Emacs는 커밋 연산의 일부로 새로운 branch 의 생성을 지원한다. 수정된 VC fileset 에 커밋할 때는 C-u C-x v v (접두 인자를 이용한
vc-next-action
; 287 페이지의 25.1.3.3절 [고급 C-x v v] 참고)를 입력한다. 그러면 Emacs는 새로운 수정본에 대한 수정본 ID의 입력을 요한다. 이때 사용자는 현재 버전에서 시작되는 branch에 적절한 branch ID를 명시해야 한다. 가령 현재 버전이 2.5라면 branch ID는 당시 존재하는 branch의 개수에 따라 2.5.1, 2.5.2 식이어야 한다.


오래된 수정본에서 새 branch를 생성하려면 (branch의 헤드보다 오래된) 먼저 해당 수정본을 선택한다(295 페이지의 25.1.11.1절 [Branch 전환하기] 참고). 사용자의 프로시져는 잠금 또는 병합 기반의 VCS를 사용하는지에 따라 달라질 것이다.


잠금 VCS 에서는 C-x v v 를 이용해 오래된 수정본 branch를 잠가야 한다. 오래된 수정본을 잠그면 새로운 branch를 정말로 생성하길 원하는지 확인을 요청할 것이며, 아니라고 답하면 대신 최신 수정본을 잠글 것인지 질문할 것이다. 병합 기반의 VCS에서는 이 단계를 건너뛸 것이다.


이후 내용을 변경하고 새로운 수정본을 적용하려면 C-x v v 를 다시 입력한다. 그러면 선택된 수정본에서 시작되는 새로운 branch를 생성한다.


Branch가 생성되고 나면 잇따라 커밋을 할 때마다 해당 branch에 새로운 수정본이 생성된다. Branch를 벗어나려면 C-u C-x v v 를 이용해 다른 수정본을 명시적으로 선택해야 한다.


변경 로그

다수의 소프트웨어 프로젝트들이 변경 로그(change log)를 보관한다. 이것은 주로
ChangeLog
로 명명되는 파일로서, 프로그램이 언제 어떻게 바뀌었는지 시간별 기록을 포함한다. 이러한 파일들이 때로는 버전 관리 시스템에 보관된 변경 로그 엔트리로부터 자동으로 생성되기도 하고, 변경 로그 엔트리를 생성하는 데에 사용되기도 한다. 어떤 때는 여러 개의 변경 로그 파일이 존재하여 각각이 하나의 디렉터리 또는 디렉터리 트리에 변경 사항을 기록한다.

변경 로그 명령어

Emacs 명령어 C-x 4 a 는 사용자가 편집 중인 파일에 대한 변경 로그 파일에 새 엔트리를 추가한다(
add-change-log-entry-other-window
). 해당 파일이 사실상 백업 파일일 경우 파일의 부모에 적절한 엔트리를 만드는데, 이는 현재 버전에서 삭제된 함수들에 대한 로그 엔트리를 만드는 데에 유용하다는 의미다.


C-x 4 a 는 변경 로그 파일을 방문하여 가장 최근 엔트리가 오늘 일자에 사용자 이름으로 되어 있지 않는 이상 새로운 엔트리를 생성한다. 또한 현재 파일에 대해 새 항목을 생성하기도 한다. 많은 언어에서는 심지어 변경된 함수나 다른 객체의 이름을 짐작하기도 한다.


add-log-keep-changes-together
변수가
nil
값이 아닐 경우 C-x 4 a 는 새로운 항목을 시작하기보다는 파일에 대한 기존 항목에 추가한다.


동일한 특성을 가진 여러 변경 사항을 결합할 수도 있다. 처음에 C-x 4 a 를 사용한 이후 텍스트를 입력하지 않으면 잇따라 C-x 4 a 를 사용 시 변경 로그 엔트리에 또 다른 심볼을 추가한다.


add-log-always-start-new-record
의 값이
nil
이 아닐 경우 C-x 4 a 는 항상 새로운 엔트리를 만들며, 설사 마지막 엔트리가 사용자에 의해 동일한 일자에 만들어졌다 하더라도 마찬가지다.


변수
change-log-version-info-enabled
의 값이
nil
이 아닐 경우 C-x 4 a 는 파일의 버전 번호를 변경 로그 엔트리로 추가한다. 이는
change-log-version-number-regexp-list
변수로부터 정규 표현식을 이용하여 파일의 첫 10% 를 검색함으로써 버전 번호를 찾는다.


변경 로그 파일은 Change Log 모드에서 방문된다. 해당 주 모드에서는 그룹화된 항목들이 하나의 문단으로 취급되고, 각 엔트리는 페이지로 간주된다. 따라서 엔트리의 편집을 촉진시킨다. C-j 와 자동 채우기는 이전 행과 같이 새 행을 들여 쓰는데, 엔트리의 내용을 입력 시 편리하다.


Change Log 모드가 켜져 있을 때 Change Log 내 엔트리들 간 이동하기 위해서는
next-error
명령어를 사용할 수 있다(기본적으로 C-x '로 바인딩되어 있다). 다음 Change Log 엔트리뿐만 아니라 파일 내 변경된 실제 위치로 점프할 수도 있다.
pervious-error
를 이용하면 같은 목록으로 되돌아갈 수 있다.


M-x change-log-merge 명령어를 이용하면 엔트리의 일자 정렬을 유지하면서 다른 로그 파일을 Change Log 모드 내 버퍼로 병합할 수 있다.


버전 관리 시스템은 프로그램에 일어나는 변경 내용을 추적하고 변경 로그를 보관하는 또 다른 방법이다. VC 로그 버퍼에서 C-c C-a (
log-edit-insert-changelog
)를 입력하면 관련 Change Log 엔트리가 존재 시 그것을 삽입한다. 287 페이지의 25.1.4절 [로그 버퍼]를 참고한다.


ChangeLog 의 포맷

변경 로그 엔트리는 현재 일자와 사용자 이름(
add-log-full-name
변수에서 취한), 사용자의 이메일 주소(
add-log-mailing-address
변수에서 취한)를 포함하는 제목 행으로 시작한다. 이러한 헤더 행 외에 변경 로그의 모든 행은 스페이스(공백) 또는 탭으로 시작한다. 엔트리 대부분은 항목으로 구성되며, 각 항목은 공백이나 별표 모양으로 시작되는 행으로 시작한다. 두 가지 엔트리를 소개할 것인데, 각각 2개의 항목과 1개의 항목을 가지며 1993년 5월을 일자로 한다.
1993-05-25 Richard Stallman <rms@gnu.org>

        * man.el: Rename symbols 'man-*' to 'Man-*'.
        (manual-entry): Make prompt string clearer.

        * simple.el (blink-matching-paren-distance): 
        Change default to 12,000.


1993-05-24 Richard Stallman <rms@gnu.org>

        * vc.el (minor-mode-map-alist): Don't use it if it's void. 
        (vc-cancel-version): Doc fix.


하나의 엔트리는 여러 개의 변경 사항을 설명할 수 있고, 각 변경 사항은 고유의 항목 또는 항목 내 고유의 행을 가져야 한다. 보통은 항목들 간에 빈 행이 하나 있어야 한다. 항목이 관련되면 (다른 위치에 동일한 변경 부분) 그 사이에 빈 행을 남김으로써 그룹화한다.


변경 로그 엔트리 끝에 저작권 알림과 권한 알림을 위치시켜야 한다. 예를 들면 아래와 같다:

Copyright 1997, 1998 Free Software Foundation, Inc. 
Copying and distribution of this file, with or without modification, are
permitted provided the copyright notice and this notice are preserved.


물론 적절한 연도와 저작권 소유자는 대체해야 한다.


태그 테이블

태그(tag)는 문서나 프로그램에서 서브유닛에 대한 참조이다. 소스 코드에서 태그는 프로그램의 구문적 요소, 즉 함수, 하위루틴, 데이터 타입, 매크로 등을 의미한다. 문서에서 태그는 챕터, 섹션, 부록 등을 참조한다. 각 태그는 해당하는 서브유닛이 정의된 파일명과 해당 파일 내 서브유닛 정의의 위치를 명시한다.


태그 테이블은 특정 프로그램이나 특정 문서의 소스 코드를 스캔함으로써 추출된다. 생성된 파일로부터 추출된 태그는 태그를 추출하는 동안 스캔하였던 생성된 파일보다는 원본 파일을 참조한다. 생성된 파일의 예로는 Cweb 소스 파일, Yacc 파서, 또는 Lex 스캐너 정의로부터 생성된 C 파일,
.i
가 전처리한 C 파일,
.fpp
소스 파일을 전처리하여 생성된 Fortran 파일을 포함한다.


태그 테이블을 생성하려면 문서 또는 소스 코드 파일에서
etags
셸 명령어를 실행한다. '
etags
' 프로그램은 태그를 태그 테이블 파일 또는 간략하게 태그 파일에 쓴다. 태그 파일에 대한 전통 이름은
TAGS
이다. 301 페이지의 25.3.2절 [태그 테이블 생성하기]를 참고한다.


Emacs 는 태그 테이블에 기록된 정보를 검색하고 그 사용을 대체하는 명령어를 많이 제공한다. 예를 들어 M-. (
find-tag
)는 그 소스 파일에서 명시된 함수 정의의 위치로 점프한다. 304 페이지의 25.3.5절 [태그 찾기]를 참고한다.


Ebrowse 기능은
etags
와 유사하지만 C++ 전용으로 설계되었다. Ebrowse User's Manual 의 "Ebrowse" 절을 참고한다. Semantic 패키지는
etags
기능과 구분된 또 다른 태그 생성 및 사용 방법을 제공한다. 255 페이지의 23.10절 [구문]을 참고한다.


소스 파일 태그 구문

가장 유명한 언어에 태그 구문이 정의되는 방식은 다음과 같다:

  • C 코드에서는 어떠한 C 함수나 typedef 도 태그이며
    struct
    ,
    union
    ,
    enum
    의 정의 역시 마찬가지다. 태그 테이블을 만들 때 '
    --no-defines
    ' 를 명시하지 않는 이상
    #define
    매크로 정의,
    #undef
    enum
    상수 역시 태그이다. 이와 비슷하게 '
    --no-globals
    ' 를 명시하지 않는 이상 전역 변수도 태그이고, '
    --no-members
    ' 를 명시하지 않는 이상 구조체 멤버도 태그이다. '
    --no-globals
    ', '
    --no-defines
    ', '
    --no-members
    '를 사용하면 태그 테이블 파일을 훨씬 작게 만들 수 있다.
    '
    --declarations
    ' 옵션을
    etags
    로 제공함으로써 함수 정의에 더해 함수 선언과 외부 변수를 태그할 수 있다.
  • C++ 코드에서는 C 코드의 모든 태그 구조체에 더해 member 함수들 역시 인식되고, '
    --no-members
    ' 옵션을 사용하지 않는 이상 멤버 변수들도 인식된다. 클래스 내 변수와 함수에 대한 태그는 '
    class::variable
    '과 '
    class::function
    '로 명명된다.
    operator
    정의는 '
    operator+
    '와 같은 태그명을 가진다.
  • Java 코드에서 태그는 C++ 에서 인식되는 모든 구조체에 더해
    interface
    ,
    extends
    ,
    implements
    구조체를 포함한다. 클래스 내 변수와 함수에 대한 태그는 '
    class.variable
    '과 '
    class.function
    '으로 명명된다.
  • LaTeX 문서에서는
    \chapter
    ,
    \section
    ,
    \subsection
    ,
    \subsubsection
    ,
    \eqno
    ,
    \label
    ,
    \ref
    ,
    \cite
    ,
    \bibitem
    ,
    \part
    ,
    \appendix
    ,
    \entry
    ,
    \index
    ,
    \def
    ,
    \newcommand
    ,
    \renewcommand
    ,
    \newenvironment
    ,
    \renewenvironment
    에 대한 인자가 태그이다.
    그 외 명령어들도 사용자가
    etags
    를 호출하기 전에 환경 변수
    TEXTAGS
    에 명시하면 태그를 만들 수 있다. 이 환경 변수의 값은 명령어 이름으로 되어 있고 콜론으로 구분된 목록이어야 한다. 예를 들면 아래와 같다.
    TEXTAGS="mycommand:myothercommand" 
    export TEXTAGS
    

    위는 (Bourne 셸 구문을 이용해) '
    \mycommand
    ' 와 '
    \mycommand
    ' 명령어 역시 태그를 정의함을 명시한다.
  • Lisp 코드에서는
    defun
    으로 정의되는 함수,
    defvar
    또는
    defconst
    로 정의되는 변수, 0번 열에서 '
    (def
    '로 시작되는 표현식의 첫 번째 인자가 태그이다. 예외로,
    (defvar foo)
    형태의 표현식은 선언으로 취급되고, '
    --declarations
    ' 옵션이 주어졌을 때에만 태그된다.
  • Scheme 코드에서 코드는 '
    def
    ' 로 시작되는 이름을 가진 구조체나
    def
    를 이용해 정의되는 것은 모두 포함한다. 또한 파일 내 최상위 수준에 있는
    set!
    으로 설정된 변수도 포함한다.


그 외 여러 언어들 역시 지원된다:

  • Ada 코드에서는 함수, 프로시져, 패키지, 작업, 타입이 태그이다. 패키지 전용 태그를 생성하려면 '
    --packages-only
    '를 사용한다.
    Ada에서는 다른 유형의 개체에 대해 동일한 이름을 사용할 수 있다(예: 프로시져와 함수에 대해). 또한 패키지, 프로시져, 함수와 같은 것들의 경우 spec(예: 인터페이스)과 body(예: 구현)가 존재한다. 원하는 정의를 쉽게 고르기 위해서는 Ada 태그명에 개체의 타입을 나타내는 접미사가 있어야 한다.

    '
    /b
    ' 패키지 본문.

    '
    /f
    ' 함수.

    '
    /k
    ' 작업.

    '
    /p
    ' 프로시져.

    '
    /s
    ' 패키지 spec.

    '
    /t
    ' 타입.

    따라서 M-x find-tag RET bidule/b RET 은 패키지
    bidule
    의 본문으로 바로 이동하는 반면 M-x find-tag RET bidule RET 은 어떤 태그
    bidule
    이든 검색만 할 것이다.
  • 어셈블리 코드에서 뒤에 콜론이 따라오고 행 시작에 나타나는 라벨은 태그에 해당한다.
  • Bison 또는 Yacc 입력 파일에서 각 파일은 그것이 구성하는 비터미널을 태그로 정의한다. C 코드를 포함하는 파일의 부분은 C 코드로 파싱된다.
  • Cobol 코드에서 태그는 문단명이므로 8열에서 시작하여 뒤에 마침표가 따라오는 단어라면 뭐든 해당한다.
  • Erlang 코드에서는 파일에 정의된 함수, 레코드, 매크로가 태그이다.
  • Fortran 코드에서는 함수, 하위루틴, 블록 데이터가 태그이다.
  • HTML 입력 파일에서 태그는
    title
    h1
    ,
    h2
    ,
    h3
    헤더이다. 또한 태그는 앵커에서
    name=
    이고 모든
    id=
    의 발생이다.
  • Lua 입력 파일에서는 모든 함수가 태그이다.
  • makefile에서는 대상(target)이 태그이며, 사용자가 '
    --no-globals
    '를 명시하지 않는 이상 변수도 태그이다.
  • Objective C 코드에서 태그는 클래스, 클래스 범주, 메서드, 프로토콜에 대한 Objective C 정의를 포함한다. 클래스 내 변수와 함수에 대한 태그는 '
    class::variable
    ' 과 '
    class::function
    ' 으로 명명된다.
  • Pascal 코드에서 태그는 파일에 정의된 함수와 프로시져이다.
  • Perl 코드에서 태그는
    package
    ,
    sub
    ,
    use constant
    ,
    my
    ,
    local
    키워드가 정의한 패키지, 하위루틴, 변수이다. 전역적 변수를 태그하고 싶다면 '
    --globals
    ' 를 사용하라. 하위루틴에 대한 태그는 '
    package::sub
    ' 로 명명된다. 기본 패키지에 정의된 하위루틴에 대한 이름은 '
    main::sub
    ' 이다.
  • PHP 코드에서 태그는 함수, 클래스, 정의이다. '
    --no-members
    ' 옵션을 사용하지 않는 이상 Vars 역시 태그다.
  • PostScript 코드에서 태그는 함수이다.
  • Prolog 코드에서 태그는 행 시작에 위치한 규칙과 조건자(predicates)이다.
  • Python 코드에서 행의 시작에 위치한
    def
    또는
    class
    는 태그를 생성한다.


다른 포맷과 언어를 처리하도록 regexp 매칭을 기반으로 태그를 생성할 수도 있다(302 페이지의 25.3.3절 [Etags Regexps] 참고).


태그 테이블 생성하기

etags
프로그램은 태그 테이블 파일을 생성하는 데에 사용된다. 이것은 앞 절에서 설명한 여러 언어의 구문을 이해한다.
etags
를 실행하는 방법은 다음과 같다:
etags inputfiles...


etags
프로그램은 명시된 파일을 읽고, 현재 작업 디렉터리에
TAGS
라는 태그 테이블을 쓴다. '
--output=file
' 옵션을 사용함으로써 태그 파일에 다른 파일명을 선택적으로 명시할 수도 있는데,
-
를 파일명으로 명시하면 표준 출력에 태그 테이블을 출력한다.


명시된 파일이 존재하지 않으면
etags
는 파일의 압축 버전을 찾아 압축 해제하여 읽는다. MS-DOS 에서
etags
는 명령 행에 '
mycode.c
' 가 주어졌는데
mycode.c
가 존재하지 않으면
mycode.cgz
와 같은 파일명을 찾는다.


태그 테이블이 그에 포함된 파일의 변경 사항으로 인해 오래된 태그 테이블이 되면
etags
프로그램을 다시 실행하여 업데이트할 수 있다. 태그 테이블이 태그를 기록하지 않거나 잘못된 파일에 대해 기록하면 Emacs는 사용자가 태그 테이블을 업데이트할 때까지 그 정의를 찾을 수 없을 것이다. 하지만 태그 테이블에 기록된 위치가 약간 틀리면 (다른 편집으로 인해) Emacs는 약간 지연이 발생하지만 올바른 위치를 찾을 수 있을 것이다.


따라서 편집이 있을 때마다 태그 테이블을 업데이트할 필요는 없다. 열거하고자 하는 새로운 태그를 정의할 때나 파일의 태그 정의를 다른 파일로 이동하거나 변경 사항이 많아질 때 태그 테이블을 업데이트하면 된다.


'
--include=file
' 옵션을
etags
로 전달함으로써 태그 테이블이 다른 태그 테이블을 포함하도록 만들 수도 있다. 그러면 그 자체를 비롯해 포함된 태그 테이블에 포함되는 파일을 모두 적용한다.


사용자가
etags
를 실행할 때 상대 파일명으로 소스 파일을 명시하면 태그 파일은 태그 파일이 처음 쓰인 디렉터리를 기준으로 상대 파일명을 포함한다. 이 방식을 통해 사용자는 태그 파일과 소스 파일 모두를 포함한 전체 디렉터리 트리를 이동할 수 있고, 태그 파일은 소스 파일을 올바로 참조할 것이다. 하지만 태그 파일이
-
이거나
/dev
디렉터리에 있을 경우 파일은 현재 작업 디렉터리를 기준으로 명명된다. 이는 가령
/dev/stdout
로 태그를 쓸 때 유용하다.


상대 파일명을 사용할 때는 다른 디렉터리의 태그 파일을 가리키는 심볼릭 링크일 경우 파일명이 무효해지므로 사용해선 안 된다.


절대 파일명을
etags
에 대한 인자로 명시하면 태그 파일은 절대 파일명을 포함할 것이다. 이를 통해 태그 파일은 사용자가 그것을 이동한다 하더라도 소스 파일이 같은 위치에 남는 한 동일한 파일을 참조할 것이다. 절대 파일명은 MS-DOS 와 MS-Windows 에서 '
/
' 또는 '
device :/
'로 시작된다.


다수의 파일로부터 태그 파일을 만들고 싶을 경우 명령 행에 열거 시 문제가 발생할 수 있는데, 일부 시스템은 그 길이를 제한하기 때문이다. 다음과 같이 파일명 대신에 대시를 입력함으로써
etags
에게 표준 입력으로부터 파일명을 읽도록 알려 그러한 길이 제한을 피할 수 있다:
find . -name "*.[chCH]" -print | etags -


etags
는 파일명과 내용을 바탕으로 입력 파일에 사용된 언어를 인식한다. '
--language=name
' 옵션을 이용해 언어를 직접 명시할 수도 있다. 아니면 이 옵션과 파일명을 섞을 수 있는데, 각 옵션은 그것을 따르는 파일명에 적용된다.
etags
가 파일명과 파일 내용으로부터 언어의 짐작을 재개하도록 '
--language=auto
'를 명시하라. '
--language=none
'을 명시하면 언어 특정적 처리를 전부 끄며,
etags
는 태그를 regexp 매칭에 따라 인식한다(302 페이지의 25.3.3절 [Etags Regexps] 참고).


'
{{{1}}}
' 옵션은 대개 프로그램으로부터
etags
를 호출할 때 유용하다. 이것은 명령 행에서 파일명 대신 (한 번만) 사용된다.
etags
는 표준 입력으로부터 읽어오며, 생성된 파일을 file 파일에 속한 것으로 마크한다.


'
etags --help
'는
etags
가 이해하는 언어 목록과 언어를 짐작하는 파일명 규칙을 이해한다. 또한 이용 가능한
etags
옵션 목록과 함께 간략한 설명을 출력하기도 한다. 그 뒤에 하나 또는 그 이상의 '
{{{1}}}
' 옵션이 따라올 경우 lang 에 대한 태그가 어떻게 생성되는지에 대한 상세한 정보를 출력한다.


Etags Regexps

etags
에 대한 '
--regex
' 옵션은 정규 표현식 매칭으로 태그가 인식되도록 허용한다. 이 옵션은 파일명과 섞어서 사용할 수 있는데, 각 옵션은 그것을 따르는 소스 파일에 적용된다. 다수의 '
--regexp
' 옵션을 명시할 경우 모두 동시에 사용된다. 구문은 다음과 같다:
--regex=[{language}]/tagregexp/[nameregexp/] modifiers


옵션 값의 필수 부분은 tagregexp로, 태그를 매칭하기 위한 regexp다. 이것은 항상 앵커된 채로 사용되는데, 즉 행의 시작에서만 매칭함을 의미한다. 들여 쓴 태그를 허용하고 싶다면 첫 공백에 일치하는 regexp를 사용하고, '
[\t]*
'로 시작한다.


이러한 표현식에서 '
\
'는 다음 문자를 인용하고, 모든 GCC 문자 escape 시퀀스가 지원된다(bell에 '
\a
', 백스페이스에 '
\b
', 삭제에 '
\d
', escape에 '
\e
', 폼피드에 '
\f
', 새 행에 '
\n
', 캐리지 리턴에 '
\r
', 탭에 '
\t
', 수직 탭에 '
\v
').


tagregexp 는 태그하고자 하는 것을 인식하는 데에 필요한 것보다 더 많은 문자를 매칭해선 안 되는 것이 이상적이다. 구문에서 태그 자체보다 많은 문자를 매칭할 targregexp 를 쓰도록 요구할 경우 사용자는 태그만 골라내도록 nameregexp 를 추가해야 한다. 그러면 Emacs는 태그를 좀 더 정확하게 찾고 태그명에 좀 더 신뢰할 수 있는 완성을 실행할 수 있을 것이다. 아래에 예를 몇 가지 들겠다.


수식 키(modifiers)는
etags
가 매칭을 실행하는 방법을 수정하는 0개 또는 그 이상의 문자 시퀀스이다. 수식 키가 없는 regexp는 대, 소문자에 민감한 방식으로 입력 파일의 각 행에 순차적으로 적용된다. 수식 키와 그 의미는 다음과 같다:


'i'
해당 regexp 에서 매칭 시 대, 소문자를 무시한다.


'm'
전체 파일에 대해 이 정규 표현식을 매칭하여 다중행 매칭이 가능하다.


's'
전체 파일에 대해 이 정규 표현식을 매칭하여 targregexp 의 '.'이 새 행에 매칭하도록 허용한다.


'
-R
' 옵션은 선행하는 '
--regex
' 옵션이 정의하는 regexp 를 모두 취소한다. 이는 그 뒤에 따라오는 파일명에도 적용된다. 아래에 예를 소개하겠다:
etags --regex=/reg1/i voo.doo --regex=/reg2/m \ 
    bar.ber -R —lang=lisp los.er


여기서
etags
voo.doo
bar.ber
의 언어에 따라 그에 대한 파싱 언어를 선택한다.
etags
reg1 을 사용하여
voo.doo
에서 추가 태그를 인식하고, reg1reg2 를 모두 이용하여
bar.ber
에서 추가 태그를 인식한다.
voo.doo
bar.ber
의 각 행을 대상으로 대, 소문자에 민감한 방식으로 reg1 이 검사되고, reg2 는 다중 행 매칭을 허용하면서 대, 소문자에 민감한 방식으로
bar.ber
파일 전체를 대상으로 검사된다.
etags
los.er
에서 태그를 인식하기 위해 사용자가 명시한 regexp 매칭 없이 Lisp 태그 규칙만 사용한다.


선택적 접두어 {language} 를 이용하여 주어진 언어의 파일만 일치하도록 '
--regex
' 옵션을 제한할 수도 있다. ('
etags --help
'는
etags
가 인식하는 언어 목록을 출력한다.) 이는 특히
etags
용으로 사전에 정의된 다수의 정규 표현식을 파일에 보관 시 유용하다. 다음 예제는 C 언어용
DEFVAR
매크로만 Emacs 소스 파일에 태그한다:
--regex='{c}/[ \t]*DEFVAR_[A-Z_ \t(]+"\([^"]+\)"/'


복잡한 정규 표현식을 갖고 있을 때는 그 목록을 파일에 보관할 수 있다. 다음 옵션 구문을 이용해
etags
로 하여금 정규 표현식 두 개의 파일을 읽도록 지시한다. 두 번째 파일에 포함된 정규 표현식은 사례와 상관 없이 일치된다.
--regex=@case-sensitive-file --ignore-case-regex=@ignore-case-file


etags
에 대한 regex 파일은 행마다 하나의 정규 표현식을 포함한다. 빈 행과 스페이스나 탭으로 시작되는 행은 무시된다. 행의 첫 문자가 '
@
' 일 경우
etags
는 나머지 행이 정규 표현식의 또 다른 파일명이라고 가정하므로, 그러한 파일마다 하나의 파일만 포함할 수 있다. 나머지 행들은 모두 정규 표현식으로 취급된다. 행에서 공백이 아닌 첫 번째 텍스트가 '
--
'일 경우, 그 행이 주석이다.


예를 들어 다음 내용으로 '
emacs.tags
' 라는 파일을 생성할 수 있다:
        -- This is for GNU Emacs C source files 
{c}/[ \t]*DEFVAR_[A-Z_ \t(]+"\([^"]+\)"/\1/


그리고 다음과 같이 사용한다:

etags --regex=@emacs.tags *.[ch] */*.[ch]


몇 가지 예를 더 들어보겠다. regexps 는 셸 해석으로부터 보호하도록 인용 부호를 이용해 표기된다:

  • Tag Octave 파일:
    etags  --language=none \
           --regex='/[ \t]*function.*=[ \t]*\([" \t]*\)[ \t]*(/\1/' \
           --regex='/###key \(.*\)/\1/' \ 
           --regex='/[ \t]*global[ \t].*/' \ 
           *.m
    

    스크립트에 대해 태그가 생성되지 않으므로 사용자는 '
    ###key scriptname
    '으로 점프하고 싶다면 스스로 그 형태로 된 행을 추가해야 한다.
  • Tag Tcl 파일:
    etags --language=none --regex='/proc[ \t]+\([^ \t]+\)/\1/' *.tcl
    
  • Tag VHDL 파일:
    etags --language=none \
      --regex='/[ \t]*\(ARCHITECTURE\|CONFIGURATION\) + [^ ]* +OF/' \
      --regex='/[ \t]*\(ATTRIBUTE\|ENTITY\|FUNCTION\|PACKAGE\
      \( BODY\)?\|PROCEDURE\|PROCESS\|TYPE\)[ \t]+\([^ \t(]+\)/\3/'
    


태그 테이블 선택하기

Emacs는 한 번에 하나의 선택된 태그 테이블을 가질 수 있다. 태그 테이블에 작업하는 모든 명령어는 선택된 태그 테이블을 사용한다. 태그 테이블을 선택하려면 태그 테이블 파일명을 인자로 읽는 M-x visit-tags-table 을 입력하는데, 기본 디렉터리에
TAGS
를 기본값으로 가진다.


Emacs 는 사용자가 사용을 시도하기 전에는 태그 테이블에서 사실상 읽지 않으며,
visit-tags-table
이 하는 일은
tags-file-name
변수에 파일명을 보관하는 것으로, 사용자 스스로 변수를 설정하는 것도 좋다. 변수의 초기값은 nil이며, 이 값은 태그 테이블에 작업하는 모든 명령어들에게 사용할 태그 테이블 파일명을 요청해야 한다는 사실을 알린다.


태그 테이블이 이미 로딩되어 있을 때
visit-tags-table
을 사용하면 사용자에게 현재 태그 테이블의 목록으로 새로운 태그 테이블을 추가하거나 새로운 목록을 시작할 수 있는 선택권을 준다. 태그 명령어는 현재 목록에 모든 태그 테이블을 사용한다. 새로운 목록을 시작하면 새로운 태그 테이블이 대신 사용된다. 현재 목록에 새 테이블을 추가할 경우 다른 테이블과 함께 사용된다.


다음과 같이
tags-table-list
변수를 문자열의 목록으로 설정하면 상세한 태그 테이블의 목록을 명시할 수 있다:
(setq tags-table-list
      '("~/emacs" "/usr/local/lib/emacs/src"))


이는 태그 명령어들에게 사용자의
~/emacs
디렉터리와
/usr/local/lib/emacs/src
디렉터리에서
TAGS
파일을 살펴보라고 말한다. 순서는 위에서 설명한 바와 같이 사용자가 위치한 파일, 그리고 어떤 태그 테이블이 해당 파일을 명시하는지에 따라 좌우된다.


tags-file-name
tags-table-list
를 모두 설정하지는 말라.


태그 찾기

태그 테이블의 가장 중요한 용도는 특정 태그의 정의를 찾는 것이다.


M-. tag RET
tag의 첫 번째 정의를 찾는다(
find-tag
).


C-u M-.
명시된 마지막 태그의 다음 alternate 정의를 찾는다.


C-u - M-.
발견된 태그 중에서 이전 태그로 돌아간다.


C-M-. pattern RET
이름이 패턴에 일치하는 태그를 찾는다(
find-tag-regexp
).


C-u C-M-.
사용된 마지막 패턴에 일치하는 이름을 가진 다음 태그를 찾는다.


C-x 4 . tag RET
tag의 첫 번째 정의를 찾아 다른 창에 표시한다(
find-tag-other-window
).


C-x 5 . tag RET
tag의 첫 번째 정의를 찾고 새로운 프레임을 생성하여 버퍼를 선택한다({{RoundTitleNavy|find-tag-other-frame{{).


M-*
이전에 M- 과 friends를 호출한 곳으로 되돌아간다(pop back).


M-. (
find-tag
)는 태그명의 입력을 요하고, 그 소스 정의로 점프한다. 이는 태그 파일과 근사 문자 위치에 대한 태그 테이블을 검색하고, 그 파일을 방문하며, 기록된 근사 위치로부터 계속 멀어지는 거리에 있는 태그 정의를 검색함으로써 작동한다.


M-. 으로 태그 인자를 입력할 때는 선택된 태그 테이블에서 태그명을 완성 대안(candidates)으로 하여 일반적 미니버퍼 완성 명령어가 사용될 수 있다(28 페이지의 5.4절 [완성] 참고). 빈 인자를 명시할 경우 포인트 이전이나 주위 버퍼에서 균형이 맞는 표현식이 기본 인자이다. 246 페이지의 23.4.1절 [표현식]을 참고한다.


M-. 으로 태그의 전체 이름을 제공할 필요는 없으며, 부분만으로 충분하다. M-. 은 해당 인자를 하위문자열로서 포함한 태그를 찾는다. 하지만 하위문자열 일치 결과보다는 정확한 일치 결과를 선호한다. 동일한 하위문자열에 일치하는 다른 태그를 찾으려면 C-u M-. 또는 M-0 M-.; 처럼
find-tag
에 수치적 인자를 제공해야 하는데, 그럴 경우 태그명을 읽지는 않지만 마지막으로 사용된 것과 동일한 하위문자열을 포함한 다른 태그를 태그 테이블의 텍스트에서 계속 검색한다.


버퍼를 전환할 수 있는 대부분의 명령어와 마찬가지로
find-tag
는 다른 창에 새로운 버퍼를 표시하는 변형체를 가지며, 그에 대한 새로운 프레임을 만드는 변형체도 가진다. 전자는 C-x 4 . (
find-tag-other-window
)이고, 후자는 C-x 5 . (
find-tag-other-frame
)이다.


이전 태그 정의로 돌아가기 위해서는 C-u - M-. 를 사용하는데, 좀 더 일반적으로는 음의 수치적 인자를 이용한 M-. 이다. 이와 비슷하게 음의 인자를 이용한 C-x 4 . 는 이전 태그 위치를 다른 창에서 찾는다.


최근에 태그를 찾은 장소로 되돌아갈 뿐 아니라 M-* (
pop-tag-mark
)를 이용해 그것을 발견한 곳에서부터 장소로 되돌아갈 수도 있다. 따라서 M-. 를 이용해 어떤 대상의 정의를 찾고 조사한 후 M-* 를 이용해 이전에 있었던 위치로 돌아갈 수 있다.


C-u - M-.M-* 명령어는
find-tag-marker-ring-length
변수로 결정되는 깊이까지 단계를 추적하도록 해준다.


C-M-. (
find-tag-regexp
) 명령어는 명시된 정규 표현식에 일치하는 태그를 방문한다. 하위문자열 매칭 대신 regexp 매칭을 실행한다는 점만 제외하면 M-. 와 동일하다.


태그 테이블을 검색하여 대체하기

이번 절에 실린 명령어는 선택된 태그 테이블에 열거된 파일을 하나씩 방문하고 검색한다. 이러한 명령어에 있어서 태그 테이블은 검색할 파일 시퀀스를 명시하는 역할만 수행한다. 이러한 명령어들은 현재 파일을 설명하는 첫 번째 태그 테이블(존재 시)부터 시작해 태그 테이블 목록을 스캔하여 목록 끝까지 진행한 후 목록 내 모든 테이블을 살펴볼 때까지 목록 시작부터 스캔한다.


M-x tags-search RET regexp RET
선택된 태그 테이블 내 파일에서 regexp를 검색한다.


M-x tags-query-replace RET regexp RET replacement RET
선택된 태그 테이블 내 파일마다
query-replace-regexp
를 실행한다.


M-,
위 명령어 중 하나를 포인트의 현재 위치에서 재시작한다(
tags-loop-continue
).


M-x tags-search 는 미니버퍼를 이용해 regexp 를 읽고, 선택된 태그 테이블 내 모든 파일을 한 번에 하나씩 일치 결과를 검색한다. 이는 사용자가 진행 과정을 따라갈 수 있도록 검색 중인 파일명을 표시한다. 발생 결과를 찾을 때마다
tags-search
가 리턴된다.


하나의 일치 결과를 찾았다면 나머지도 찾길 원할 것이다. M-, (
tags-loop-continue
)를 입력하여 tags-search를 재개하고 일치 결과를 하나 더 찾는다. 이는 나머지 현재 버퍼를 찾고 나서 태그 테이블의 나머지 파일을 찾는다.


M-x tags-query-replace 는 태그 테이블 내 모든 파일에 대해 단일
query-replace-regexp
를 실행한다. 이는 M-x query-replace-regexp 와 마찬가지로 검색할 regexp 와 대체할 문자열을 읽는다. M-x tags-search 와 비슷하게 검색을 실행하나, 다시 말하지만 처리는 사용자의 입력 값에 따라 일치 결과를 처리한다. 쿼리 대체에 관한 추가 정보는 105 페이지의 12.10.4절 [쿼리 대체]를 참고한다.


tags-case-fold-search
변수 값을 맞춤화하여 태그 검색 명령어의 대, 소문자 민감성을 관리한다. 기본값은
case-fold-search
의 값과 동일한 설정을 사용하는 것이다(102 페이지의 12.9절 [검색과 대, 소문자] 참고).


M-x tags-query-replace 를 한 번만 호출하여도 태그 테이블의 모든 파일을 통과할 수 있다. 하지만 임시적으로 종료하는 방법이 유용할 때도 있는데, 이는 특별한 쿼리 대체의 의미가 없는 입력 이벤트를 이용하면 된다. M-, 를 입력하면 쿼리 대체를 잇따라 재개할 수 있는데, 이 명령어는 사용자가 실행한 마지막 태그 검색 또는 대체 명령어를 재개한다. 가령 M-> M-, 를 입력하면 현재 파일의 나머지를 건너뛴다.


이번 절에 소개된 명령어들은
find-tag
family 보다 더 광범위한 검색을 실행한다.
find-tag
명령어는 사용자의 하위문자열이나 regexp 에 일치하는 태그의 정의만 검색한다.
tags-search
tags-query-replace
명령어는 현재 버퍼에서 일반적인 검색 명령어와 대체 명령어가 하듯이 regexp의 모든 발생을 찾는다.


이러한 명령어들은 검색해야 하는 파일에 대해 임시적으로만 버퍼를 생성한다(Emacs 버퍼에서 이미 방문하지 않은 파일에 대해). 어떤 일치 결과도 발견되지 않는 버퍼는 빨리 제거되고, 그 외는 계속해서 존재한다.


tags-search
대신
grep
를 하위프로세스로서 실행하고 Emacs로 하여금 일치하는 행을 하나씩 표시하도록 지시할 수 있다. 이와 관련된 내용은 264 페이지의 24.4절 [Grep 검색]을 참고한다.


태그 테이블 질의

C-M-i
M-TAB
선택된 태그 테이블 중 하나가 로딩되어 있다면 선택된 태그 테이블을 이용해 포인트 주위의 텍스트에 완성을 실행한다(
completion-at-point
).


M-x list-tags RET file RET
file 프로그램 파일에 정의된 태그 목록을 표시한다.


M-x tags-apropos RET regexp RET
regexp 에 일치하는 모든 태그의 목록을 표시한다.


대부분 프로그래밍 언어 모드에서는 C-M-i 또는 M-TAB (
completion-at-point
)를 입력하여 포인트에 심볼을 완성할 수 있다. 선택된 태그 테이블이 있다면 이 명령어는 완성 대안(candidate)을 생성하는 데에 사용할 수 있다. 254 페이지의 23.8절 [심볼 완성]을 참고한다.


M-x list-tags 는 선택된 태그 테이블에 포함된 파일 중 하나의 이름을 읽고, 해당 파일에 정의된 태그 목록을 표시한다. 태그 테이블에 기록된 파일명이 디렉터리를 포함하지 않는 이상 디렉터리를 파일명의 일부로 포함하지 않는다.


M-x tags-apropos 는 태그에 대한
apropos
와 같다(40 페이지의 7.3절 [Apropos] 참고). 이는 선택된 태그 테이블에서 엔트리가 regexp 에 일치하는 태그 목록을 표시한다.
tags-apropos-verbose
변수가
nil
이 아닐 경우 태그명과 함께 태그 파일명을 표시한다.
tags-tag-face
변수를
face
로 설정하면 출력의 외관을 맞춤화할 수 있다. 또한
tags-apropos-additional-actions
변수를 맞춤화하면 추가 출력을 표시할 수 있는데, 상세한 내용은 관련 문서를 참고한다.


M-x next-file 은 선택된 태그 테이블에 포함된 파일을 방문한다. 처음 호출되면 테이블에 포함된 첫 파일을 방문한다. 이후 호출할 때마다 다음으로 포함된 파일을 방문하는데, 접두 인자가 제공되는 경우 첫 번째 파일로 리턴한다.


Emacs 개발 환경

EDE(Emacs 개발 환경Emacs Development Environment)는 Emacs 를 이용해 큰 프로그램을 생성, 빌드, 디버깅하는 작업을 단순화하는 패키지이다. 이는 IDE (또는 통합 개발 환경)의 기능 중 일부를 Emacs 에서 제공한다.


이번 절에서는 EDE 사용을 간략하게 설명한다. EDE 에 대한 전체적인 내용은 C-h i 를 입력한 후 EDE 매뉴얼을 선택한다.


EDE 는 전역적 부 모드로서 구현된다(200 페이지의 20.2절 [부 모드] 참고). 이 모드를 활성화하려면 M-x global-ede-mode 를 입력하거나 'Tools' 메뉴에서 '
Project Support (EDE)
'를 클릭한다. Emacs 를 시작할 때마다 초기화 파일에 다음 행을 추가함으로써 EDE 를 활성화할 수 있다:
(global-ede-mode t)


EDE 를 활성화하면 '
Development
' 라는 메뉴가 메뉴 바에 추가된다. 아래 설명한 명령어를 비롯해 다수의 EDE 명령어들을 이 메뉴에서 호출할 수 있다.


EDE는 파일을 디렉터리 트리에 일치하는 프로젝트로 조직한다. 프로젝트 루트는 프로젝트에서 최상위 디렉터리에 해당한다. 새 프로젝트를 정의하려면 원하는 프로젝트 루트의 파일로 방문하여 M-x edge-new 를 입력한다. 이 명령어는 프로젝트 타입을 입력하도록 요청하는데, 이는 EDE가 프로젝트를 관리하기 위해 사용하게 될 기본 방법을 의미한다(Emacs Development Environment 의 "Creating a project"절 참고). 가장 자주 사용되는 프로젝트 타입은 Makefiles를 사용하는 'Make'와 GNU Automake(Automake 참고)를 사용하는 '
Automake
' 이다. 두 경우 모두 EDE 는 프로젝트에 관한 정보를 보관하는
Project.ede
라는 파일을 생성한다.


프로젝트는 하나 또는 이상의 대상(targets)을 포함할 수 있다. 대상이란 객체 파일, 실행 가능한 프로그램, 또는 프로젝트 내에 하나 또는 그 이상의 파일로부터 "빌드"된 다른 파일 타입이 될 수 있다.


새로운 대상을 프로젝트로 추가하려면 C-c . t (M-x ede-new-target)를 입력한다. 이 명령어는 현재 파일 역시 대상으로 "추가"하길 원하는지, 즉 대상이 해당 파일로부터 빌드되길 원하는지 질문하기도 한다. 대상을 정의하고 나면 C-c . a (
ede-add-file
입력하여 그곳으로 더 많은 파일을 추가할 수 있다.


대상을 빌드하기 위해서는 C-c . c (
ede-compile-target
입력한다. 프로젝트에 모든 대상을 빌드하려면 C-c . C ({{RoundTitleNavy|ede-compile-project} 를 입력한다. EDE 는 파일 타입을 이용해 어떤 대상을 빌드해야 하는지를 짐작한다.


Notes