Merge branch 'smart-ref-spec'
This commit is contained in:
commit
0f4def92e4
19
README
19
README
@ -2,8 +2,8 @@ Josh's SVN wrapper script
|
|||||||
|
|
||||||
This wrapper script to Subversion supplements normal svn behavior by
|
This wrapper script to Subversion supplements normal svn behavior by
|
||||||
adding additional functionality or modifying the output of the default
|
adding additional functionality or modifying the output of the default
|
||||||
svn subcommands. Much of the functionality implemented here was inspired
|
svn subcommands (simplification and colorization). Much of the functionality
|
||||||
by the way that git works.
|
implemented here was inspired by the way that git works.
|
||||||
|
|
||||||
It is recommended to put this script in your $PATH as 'jsvn' or something
|
It is recommended to put this script in your $PATH as 'jsvn' or something
|
||||||
other than 'svn' and to make an alias svn='jsvn'.
|
other than 'svn' and to make an alias svn='jsvn'.
|
||||||
@ -27,6 +27,11 @@ Implemented subcommands:
|
|||||||
- with -d, delete <branch>
|
- with -d, delete <branch>
|
||||||
- otherwise, create a new branch from the current one
|
- otherwise, create a new branch from the current one
|
||||||
- also switch to the new branch if -s is given
|
- also switch to the new branch if -s is given
|
||||||
|
diff
|
||||||
|
- allow specifying ref1..ref2 syntax to show the diff between two references
|
||||||
|
- references can be tag names, branch names, or 'trunk'
|
||||||
|
- allow specifying ref1...ref2 syntax to show the diff between the common
|
||||||
|
ancestor of ref1 and ref2 and ref2's HEAD
|
||||||
tag[s] [[-d] <tag_name>] | [-m <old_tag_name> <new_tag_name>]
|
tag[s] [[-d] <tag_name>] | [-m <old_tag_name> <new_tag_name>]
|
||||||
- with no arguments, list tags
|
- with no arguments, list tags
|
||||||
- with -d, delete <tag>
|
- with -d, delete <tag>
|
||||||
@ -36,6 +41,9 @@ Implemented subcommands:
|
|||||||
- switch to 'trunk', branch name, or tag name without having to specify
|
- switch to 'trunk', branch name, or tag name without having to specify
|
||||||
the full URL
|
the full URL
|
||||||
- falls back to Subversion "switch" if <short_name> doesn't exist
|
- falls back to Subversion "switch" if <short_name> doesn't exist
|
||||||
|
log
|
||||||
|
- allow specifying ref1..ref2 syntax to show the log entries for
|
||||||
|
ref2 which are not a part of ref1
|
||||||
merge <branch>
|
merge <branch>
|
||||||
- merge branch <branch> into the current WC path
|
- merge branch <branch> into the current WC path
|
||||||
- falls back to Subversion "merge" if <branch> doesn't exist
|
- falls back to Subversion "merge" if <branch> doesn't exist
|
||||||
@ -79,13 +87,6 @@ Implemented subcommands:
|
|||||||
- delete stash object <id>
|
- delete stash object <id>
|
||||||
- <id> defaults to the newest stash object created
|
- <id> defaults to the newest stash object created
|
||||||
|
|
||||||
The following subcommands are executed using their native handler, but
|
|
||||||
have their output simplified and/or colorized:
|
|
||||||
- diff
|
|
||||||
- log
|
|
||||||
- status
|
|
||||||
- update
|
|
||||||
|
|
||||||
If the subcommand name begins with two leading underscores ("__"), the
|
If the subcommand name begins with two leading underscores ("__"), the
|
||||||
underscores will be stripped and the command will be handled by native
|
underscores will be stripped and the command will be handled by native
|
||||||
Subversion without any jsvn processing.
|
Subversion without any jsvn processing.
|
||||||
|
71
jsvn
71
jsvn
@ -320,6 +320,39 @@ def get_next_stash_idx(svn):
|
|||||||
idx = stash_ids[-1] + 1
|
idx = stash_ids[-1] + 1
|
||||||
return idx
|
return idx
|
||||||
|
|
||||||
|
# return (URL, path) tuple containing the full URL to the ref and the
|
||||||
|
# repo-relative path (ex: /branches/XXX)
|
||||||
|
# if ref is an actual file, URL is returned as an empty string
|
||||||
|
# tags resolve before branches
|
||||||
|
def resolve_reference(svn, ref):
|
||||||
|
if os.path.exists(ref):
|
||||||
|
return ('', ref)
|
||||||
|
if ref == 'trunk':
|
||||||
|
return (get_svn_root_url(svn) + '/trunk', '/trunk')
|
||||||
|
tl = get_svn_tag_list(svn)
|
||||||
|
if ref in tl:
|
||||||
|
path = '/tags/' + ref
|
||||||
|
return (get_svn_root_url(svn) + path, path)
|
||||||
|
bl = get_svn_branch_list(svn)
|
||||||
|
if ref in bl:
|
||||||
|
path = '/branches/' + ref
|
||||||
|
return (get_svn_root_url(svn) + path, path)
|
||||||
|
# ref was not an actual file, 'trunk', a tag name, or a branch name
|
||||||
|
return ('', ref)
|
||||||
|
|
||||||
|
def find_branched_revision(svn, branch_url, branch_path, base_path):
|
||||||
|
p = Popen([svn, 'log', '-v', branch_url], stdout=PIPE)
|
||||||
|
search_path = branch_path
|
||||||
|
for line in iter(p.stdout.readline, ''):
|
||||||
|
m = re.match('\s+A\s+(.*?)\s+\(from\s+(.*?):(\d+)\)\s*$', line)
|
||||||
|
if m is not None:
|
||||||
|
new_path, old_path, rev = m.group(1, 2, 3)
|
||||||
|
if new_path == search_path:
|
||||||
|
if old_path == base_path:
|
||||||
|
return int(rev)
|
||||||
|
search_path = old_path
|
||||||
|
return -1
|
||||||
|
|
||||||
###########################################################################
|
###########################################################################
|
||||||
# Subcommand Handlers #
|
# Subcommand Handlers #
|
||||||
###########################################################################
|
###########################################################################
|
||||||
@ -689,12 +722,50 @@ def lockable(argv, svn, out):
|
|||||||
return RET_OK
|
return RET_OK
|
||||||
|
|
||||||
def diff(argv, svn, out):
|
def diff(argv, svn, out):
|
||||||
|
for i, v in enumerate(argv):
|
||||||
|
m = re.match('(.*?)(\.\.\.?)(.*)$', v)
|
||||||
|
if m is not None:
|
||||||
|
ref1, operator, ref2 = m.group(1, 2, 3)
|
||||||
|
url1, path1 = resolve_reference(svn, ref1)
|
||||||
|
if url1 == '':
|
||||||
|
continue
|
||||||
|
url2, path2 = resolve_reference(svn, ref2)
|
||||||
|
if url2 == '':
|
||||||
|
continue
|
||||||
|
if operator == '...':
|
||||||
|
# amend url1 to include the pegged revision from where ref2
|
||||||
|
# originally branched from it
|
||||||
|
r = find_branched_revision(svn, url2, path2, path1)
|
||||||
|
if r < 0:
|
||||||
|
sys.stderr.write(('Could not find revision where "%s" ' +
|
||||||
|
'branched from "%s"\n') % (ref2, ref1))
|
||||||
|
return RET_ERR
|
||||||
|
url1 += '@%d' % r
|
||||||
|
argv = argv[:i] + [url1, url2] + argv[i + 1:]
|
||||||
|
break
|
||||||
pout = Popen([svn] + argv, stdout=PIPE).stdout
|
pout = Popen([svn] + argv, stdout=PIPE).stdout
|
||||||
for line in iter(pout.readline, ''):
|
for line in iter(pout.readline, ''):
|
||||||
colordiff(out, line)
|
colordiff(out, line)
|
||||||
return RET_OK
|
return RET_OK
|
||||||
|
|
||||||
def log(argv, svn, out):
|
def log(argv, svn, out):
|
||||||
|
for i, v in enumerate(argv):
|
||||||
|
m = re.match('(.*)(\.\.)(.*)$', v)
|
||||||
|
if m is not None:
|
||||||
|
ref1, operator, ref2 = m.group(1, 2, 3)
|
||||||
|
url1, path1 = resolve_reference(svn, ref1)
|
||||||
|
if url1 == '':
|
||||||
|
continue
|
||||||
|
url2, path2 = resolve_reference(svn, ref2)
|
||||||
|
if url2 == '':
|
||||||
|
continue
|
||||||
|
r = find_branched_revision(svn, url2, path2, path1)
|
||||||
|
if r < 0:
|
||||||
|
sys.stderr.write(('Could not find revision where "%s" ' +
|
||||||
|
'branched from "%s"\n') % (ref2, ref1))
|
||||||
|
return RET_ERR
|
||||||
|
argv = argv[:i] + ['-rHEAD:%d' % (r + 1), url2] + argv[i + 1:]
|
||||||
|
break
|
||||||
mode = 'normal'
|
mode = 'normal'
|
||||||
pout = Popen([svn] + argv, stdout=PIPE).stdout
|
pout = Popen([svn] + argv, stdout=PIPE).stdout
|
||||||
for line in iter(pout.readline, ''):
|
for line in iter(pout.readline, ''):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user