Linux SVN的安装使用
SVN简介、下载、安装
SVN简介
The goal of the Subversion project is to build a version control system that is a compelling replacement for CVS in the open source
community. The software is released under an Apache/BSD-style open source license.
SVN是一个版本控制软件,类似CVS,但是SVN的的有点是开源的,而且SVN的版本控制能力给CVS还要强多。
SVN可以用于项目管理,还可以用于版本同步,功能可是十分强呢:)
下载:http://subversion.tigris.org
当前日期稳定版SVN1.32 http://subversion.tigris.org/downloads/subversion-1.3.2.tar.gz
安装:
解压:#: tar zxvf subversion-1.3.2.tar.gz
依次输入./configure , make , make install 进行编译安装完成。
开启SVN服务:svnserve -d
检测服务是否开启:netstat -ntlp如果看到3690的端口正常开放了,证明SVN启动了。
正式使用:
首先我们得建立一个SVN的项目,一般人都认为建立项目就只需要一个文件,在我第一次使用SVN之前都有这样的看法,SVN建立项目需要建立文件夹
建立项目命令:svnadmin create project_name project_name 为你的project名字,可以任意取。
建立完毕后,project_name是一个文件夹,进入文件夹,可以看到一个conf的文件夹。进入文件夹可以看到2个文件(如果没有passwd文件,可以用vi创建)
,编辑 svnserve.conf 把anon-access = read ,auth_access = write
还有password-db = passwd 的注释去掉,还有[general]的注释也要去掉。
vi passwd文件,如果是新文件,则输入:
[user]
your_name = your_password
这里设置的your_name是你的用户名,your_password是你的密码,这个是访问SVN必要的通行证。
好了,现在终于把准备功夫做完了,下面可以正是使用了。
【注意】:
建好svn服务器后第一件事情当然是把本机上的代码放到svn服务器上,假设我要把当前目录下的目录mgqwcode上传到svn服务器
运行命令:
svn import -m "New import" mgqwcode http://192.168.1.88:8080/svn/mgqwcode 不需要mkdir新建目录,svn import会递归的为你创建目录。如果正常的
话,输出如下:
增加 mgqwcode/abc.h
………………………………(省略n个文件)
提交后的版本为 2。
作为客户端,首先找到你创建的项目文件夹,现在你可以在客户机上使用以下命令获得你想要的项目源代码文件了,使用下面命令:
执行命令:
svn co http://192.168.1.88:8080/svn/mgqwcode --username = your_name --password=your_password【checkout 简写 co】
它会把源代码文件下载到你创建的项目文件夹中.
【注意】:
运行命令:svn checkout http://192.168.1.88:8080/svn/mgqwcode命令后,如果有用户名和密码会在命令输入后提示你输入。
还可以在checkout命令里加上选项 --username = your_name --password = your_password 其中your_name 和your_password 就是你的用户名和密码了。只
要第一次输入用户名和密码正确,后面就不需要再次输入。
新增一个文件到svn库分为两步:
1.把增加的svn文件添加入svn库:
命令:svn add ./新增文件名
2.提交文件:
命令:svn ci -m "commit a new version" 新增文件名 【这里的命令是:svn ci -m 提交的注释 文件名】
删除文件分为两步:
1. 先删除文件
命令:svn rm 文件名
2.提交删除信息:
命令:svn ci -m "rm 文件名" 文件名
更新文件:
命令:svn update
当然你可以编辑一个脚本文件来一次完成所有的操作:
vi svnupdate.sh
#!/bin/sh
svn add http://192.168.1.88:8080/svn/mgqwcode/*.* --username=your_name --password = your_password
svn commit http://192.168.1.88:8080/svn/mgqwcode/*.* --username=your_name --password=your_password
svn update http://192.168.1.88:8080/svn/mgqwcode/*.* --username=your_name --password=your_password
chmod +x svnupdate.sh
Finish
//svn add http://192.168.1.88:8080/svn/mgqwcode/m --username=zhaoxiaofei --password = xiaofei
*************************************************
在使用中我们可能会碰到 Subversion提交时提示svn客户端版本太旧的问题
从另外一台计算机上拷贝了一份subversion的版本库,完成修改后提交时,出现如下错误:
$ svn ci -m "commit a new version"
svn: This client is too old to work with working copy '/home/easwy/subversion/'; please get a newer Subversion client 以前也遇到过这个问
题,当时是升级了subversion的版本。这次因为升级计算机比较麻烦,所以打算用其它的方法绕过。
在网上搜索了一下,找到了subversion的FAQ,里面提到有时svn的工作拷贝在不同subversion版本间会存在不兼容,所以由新版本svn导出的版本库,就不能
使用旧版本svn来提交,此时就会提交客户端版本太老。不过subversion的开发人员提供了一个python脚本,可以对工作拷贝的格式进行转换,转换后就可以
commit了。
这个脚本在这里下载:http://svn.collab.net/repos/svn/trunk/tools/client-side/change-svn-wc-format.py
下载后,在工作拷贝所在的目录中执行:
命令:change-svn-wc-format.py . 1.4
上面的命令,会把working copy的格式转换成subversion 1.4的格式,转换后再提交就可以成功了。
如果下载不了可以直接用下面的方法:
把下面脚本内容写入文件名为chang-svn-wc-format.py的脚本 修改权限
用svn help 可以查看到当前版本号
执行命令:./change-svn-wc-format.py[空格].[空格]当前版本号
这时再执行 checkout, update, commit 就可以了
#!/usr/bin/env python
#
# change-svn-wc-format.py: Change the format of a Subversion working copy.
#
# ====================================================================
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ====================================================================
import sys
import os
import getopt
try:
my_getopt = getopt.gnu_getopt
except AttributeError:
my_getopt = getopt.getopt
### The entries file parser in subversion/tests/cmdline/svntest/entry.py
### handles the XML-based WC entries file format used by Subversion
### 1.3 and lower. It could be rolled into this script.
LATEST_FORMATS = { "1.4" : 8,
"1.5" : 9,
"1.6" : 10,
# Do NOT add format 11 here. See comment in must_retain_fields
# for why.
}
def usage_and_exit(error_msg=None):
"""Write usage information and exit. If ERROR_MSG is provide, that
error message is printed first (to stderr), the usage info goes to
stderr, and the script exits with a non-zero status. Otherwise,
usage info goes to stdout and the script exits with a zero status."""
progname = os.path.basename(sys.argv[0])
stream = error_msg and sys.stderr or sys.stdout
if error_msg:
stream.write("ERROR: %s/n/n" % error_msg)
stream.write("""/
usage: %s WC_PATH SVN_VERSION [--verbose] [--force] [--skip-unknown-format]
%s --help
Change the format of a Subversion working copy to that of SVN_VERSION.
--skip-unknown-format : skip directories with unknown working copy
format and continue the update
""" % (progname, progname))
stream.flush()
sys.exit(error_msg and 1 or 0)
def get_adm_dir():
"""Return the name of Subversion's administrative directory,
adjusted for the SVN_ASP_DOT_NET_HACK environment variable. See
<http://svn.apache.org/repos/asf/subversion/trunk/notes/asp-dot-net-hack.txt>
for details."""
return "SVN_ASP_DOT_NET_HACK" in os.environ and "_svn" or ".svn"
class WCFormatConverter:
"Performs WC format conversions."
root_path = None
error_on_unrecognized = True
force = False
verbosity = 0
def write_dir_format(self, format_nbr, dirname, paths):
"""Attempt to write the WC format FORMAT_NBR to the entries file
for DIRNAME. Throws LossyConversionException when not in --force
mode, and unconvertable WC data is encountered."""
# Avoid iterating in unversioned directories.
if not (get_adm_dir() in paths):
del paths[:]
return
# Process the entries file for this versioned directory.
if self.verbosity:
print("Processing directory '%s'" % dirname)
entries = Entries(os.path.join(dirname, get_adm_dir(), "entries"))
entries_parsed = True
if self.verbosity:
print("Parsing file '%s'" % entries.path)
try:
entries.parse(self.verbosity)
except UnrecognizedWCFormatException, e:
if self.error_on_unrecognized:
raise
sys.stderr.write("%s, skipping/n" % e)
sys.stderr.flush()
entries_parsed = False
if entries_parsed:
format = Format(os.path.join(dirname, get_adm_dir(), "format"))
if self.verbosity:
print("Updating file '%s'" % format.path)
format.write_format(format_nbr, self.verbosity)
else:
if self.verbosity:
print("Skipping file '%s'" % format.path)
if self.verbosity:
print("Checking whether WC format can be converted")
try:
entries.assert_valid_format(format_nbr, self.verbosity)
except LossyConversionException, e:
# In --force mode, ignore complaints about lossy conversion.
if self.force:
print("WARNING: WC format conversion will be lossy. Dropping "/
"field(s) %s " % ", ".join(e.lossy_fields))
else:
raise
if self.verbosity:
print("Writing WC format")
entries.write_format(format_nbr)
def change_wc_format(self, format_nbr):
"""Walk all paths in a WC tree, and change their format to
FORMAT_NBR. Throw LossyConversionException or NotImplementedError
if the WC format should not be converted, or is unrecognized."""
for dirpath, dirs, files in os.walk(self.root_path):
self.write_dir_format(format_nbr, dirpath, dirs + files)
class Entries:
"""Represents a .svn/entries file.
'The entries file' section in subversion/libsvn_wc/README is a
useful reference."""
# The name and index of each field composing an entry's record.
entry_fields = (
"name",
"kind",
"revision",
"url",
"repos",
"schedule",
"text-time",
"checksum",
"committed-date",
"committed-rev",
"last-author",
"has-props",
"has-prop-mods",
"cachable-props",
"present-props",
"conflict-old",
"conflict-new",
"conflict-wrk",
"prop-reject-file",
"copied",
"copyfrom-url",
"copyfrom-rev",
"deleted",
"absent",
"incomplete",
"uuid",
"lock-token",
"lock-owner",
"lock-comment",
"lock-creation-date",
"changelist",
"keep-local",
"working-size",
"depth",
"tree-conflicts",
"file-external",
)
# The format number.
format_nbr = -1
# How many bytes the format number takes in the file. (The format number
# may have leading zeroes after using this script to convert format 10 to
# format 9 -- which would write the format number as '09'.)
format_nbr_bytes = -1
def __init__(self, path):
self.path = path
self.entries = []
def parse(self, verbosity=0):
"""Parse the entries file. Throw NotImplementedError if the WC
format is unrecognized."""
input = open(self.path, "r")
# Read WC format number from INPUT. Validate that it
# is a supported format for conversion.
format_line = input.readline()
try:
self.format_nbr = int(format_line)
self.format_nbr_bytes = len(format_line.rstrip()) # remove '/n'
except ValueError:
self.format_nbr = -1
self.format_nbr_bytes = -1
if not self.format_nbr in LATEST_FORMATS.values():
raise UnrecognizedWCFormatException(self.format_nbr, self.path)
# Parse file into individual entries, to later inspect for
# non-convertable data.
entry = None
while True:
entry = self.parse_entry(input, verbosity)
if entry is None:
break
self.entries.append(entry)
input.close()
def assert_valid_format(self, format_nbr, verbosity=0):
if verbosity >= 2:
print("Validating format for entries file '%s'" % self.path)
for entry in self.entries:
if verbosity >= 3:
print("Validating format for entry '%s'" % entry.get_name())
try:
entry.assert_valid_format(format_nbr)
except LossyConversionException:
if verbosity >= 3:
sys.stderr.write("Offending entry:/n%s/n" % entry)
sys.stderr.flush()
raise
def parse_entry(self, input, verbosity=0):
"Read an individual entry from INPUT stream."
entry = None
while True:
line = input.readline()
if line in ("", "/x0c/n"):
# EOF or end of entry terminator encountered.
break
if entry is None:
entry = Entry()
# Retain the field value, ditching its field terminator ("/x0a").
entry.fields.append(line[:-1])
if entry is not None and verbosity >= 3:
sys.stdout.write(str(entry))
print("-" * 76)
return entry
def write_format(self, format_nbr):
# Overwrite all bytes of the format number (which are the first bytes in
# the file). Overwrite format '10' by format '09', which will be converted
# to '9' by Subversion when it rewrites the file. (Subversion 1.4 and later
# ignore leading zeroes in the format number.)
assert len(str(format_nbr)) <= self.format_nbr_bytes
format_string = '%0' + str(self.format_nbr_bytes) + 'd'
os.chmod(self.path, 0600)
output = open(self.path, "r+", 0)
output.write(format_string % format_nbr)
output.close()
os.chmod(self.path, 0400)
class Entry:
"Describes an entry in a WC."
# Maps format numbers to indices of fields within an entry's record that must
# be retained when downgrading to that format.
must_retain_fields = {
# Not in 1.4: changelist, keep-local, depth, tree-conflicts, file-externals
8 : (30, 31, 33, 34, 35),
# Not in 1.5: tree-conflicts, file-externals
9 : (34, 35),
10 : (),
# Downgrading from format 11 (1.7-dev) to format 10 is not possible,
# because 11 does not use has-props and cachable-props (but 10 does).
# Naively downgrading in that situation causes properties to disappear
# from the wc.
#
# Downgrading from the 1.7 SQLite-based format to format 10 is not
# implemented.
}
def __init__(self):
self.fields = []
def assert_valid_format(self, format_nbr):
"Assure that conversion will be non-lossy by examining fields."
# Check whether lossy conversion is being attempted.
lossy_fields = []
for field_index in self.must_retain_fields[format_nbr]:
if len(self.fields) - 1 >= field_index and self.fields[field_index]:
lossy_fields.append(Entries.entry_fields[field_index])
if lossy_fields:
raise LossyConversionException(lossy_fields,
"Lossy WC format conversion requested for entry '%s'/n"
"Data for the following field(s) is unsupported by older versions "
"of/nSubversion, and is likely to be subsequently discarded, and/or "
"have/nunexpected side-effects: %s/n/n"
"WC format conversion was cancelled, use the --force option to "
"override/nthe default behavior."
% (self.get_name(), ", ".join(lossy_fields)))
def get_name(self):
"Return the name of this entry."
return len(self.fields) > 0 and self.fields[0] or ""
def __str__(self):
"Return all fields from this entry as a multi-line string."
rep = ""
for i in range(0, len(self.fields)):
rep += "[%s] %s/n" % (Entries.entry_fields[i], self.fields[i])
return rep
class Format:
"""Represents a .svn/format file."""
def __init__(self, path):
self.path = path
def write_format(self, format_nbr, verbosity=0):
format_string = '%d/n'
if os.path.exists(self.path):
if verbosity >= 1:
print("%s will be updated." % self.path)
os.chmod(self.path,0600)
else:
if verbosity >= 1:
print("%s does not exist, creating it." % self.path)
format = open(self.path, "w")
format.write(format_string % format_nbr)
format.close()
os.chmod(self.path, 0400)
class LocalException(Exception):
"""Root of local exception class hierarchy."""
pass
class LossyConversionException(LocalException):
"Exception thrown when a lossy WC format conversion is requested."
def __init__(self, lossy_fields, str):
self.lossy_fields = lossy_fields
self.str = str
def __str__(self):
return self.str
class UnrecognizedWCFormatException(LocalException):
def __init__(self, format, path):
self.format = format
self.path = path
def __str__(self):
return ("Unrecognized WC format %d in '%s'; "
"only formats 8, 9, and 10 can be supported") % (self.format, self.path)
def main():
try:
opts, args = my_getopt(sys.argv[1:], "vh?",
["debug", "force", "skip-unknown-format",
"verbose", "help"])
except:
usage_and_exit("Unable to process arguments/options")
converter = WCFormatConverter()
# Process arguments.
if len(args) == 2:
converter.root_path = args[0]
svn_version = args[1]
else:
usage_and_exit()
# Process options.
debug = False
for opt, value in opts:
if opt in ("--help", "-h", "-?"):
usage_and_exit()
elif opt == "--force":
converter.force = True
elif opt == "--skip-unknown-format":
converter.error_on_unrecognized = False
elif opt in ("--verbose", "-v"):
converter.verbosity += 1
elif opt == "--debug":
debug = True
else:
usage_and_exit("Unknown option '%s'" % opt)
try:
new_format_nbr = LATEST_FORMATS[svn_version]
except KeyError:
usage_and_exit("Unsupported version number '%s'; "
"only 1.4, 1.5, and 1.6 can be supported" % svn_version)
try:
converter.change_wc_format(new_format_nbr)
except LocalException, e:
if debug:
raise
sys.stderr.write("%s/n" % e)
sys.stderr.flush()
sys.exit(1)
print("Converted WC at '%s' into format %d for Subversion %s" % /
(converter.root_path, new_format_nbr, svn_version))
if __name__ == "__main__":
main()