##// END OF EJS Templates
rebase: add --detach option to detach intermediate revisions (issue1950)...
Stefano Tortarolo -
r10352:66d954e7 default
parent child Browse files
Show More
@@ -0,0 +1,68 b''
1 #!/bin/sh
2
3 echo "[extensions]" >> $HGRCPATH
4 echo "graphlog=" >> $HGRCPATH
5 echo "rebase=" >> $HGRCPATH
6
7 BASE=`pwd`
8
9 addcommit () {
10 echo $1 > $1
11 hg add $1
12 hg commit -d "${2} 0" -m $1
13 }
14
15 commit () {
16 hg commit -d "${2} 0" -m $1
17 }
18
19 createrepo () {
20 cd $BASE
21 rm -rf a
22 hg init a
23 cd a
24 addcommit "A" 0
25 addcommit "B" 1
26 addcommit "C" 2
27 addcommit "D" 3
28
29 hg update -C 0
30 addcommit "E" 4
31 }
32
33 createrepo > /dev/null 2>&1
34 hg glog --template '{rev}: {desc}\n'
35 echo '% Rebasing D onto E detaching from C'
36 hg rebase --detach -s 3 -d 4 2>&1 | sed 's/\(saving bundle to \).*/\1/'
37 hg glog --template '{rev}: {desc}\n'
38 echo "Expected A, D, E"
39 hg manifest
40
41 echo
42 createrepo > /dev/null 2>&1
43 hg glog --template '{rev}: {desc}\n'
44 echo '% Rebasing C onto E detaching from B'
45 hg rebase --detach -s 2 -d 4 2>&1 | sed 's/\(saving bundle to \).*/\1/'
46 hg glog --template '{rev}: {desc}\n'
47 echo "Expected A, C, D, E"
48 hg manifest
49
50 echo
51 createrepo > /dev/null 2>&1
52 hg glog --template '{rev}: {desc}\n'
53 echo '% Rebasing B onto E using detach (same as not using it)'
54 hg rebase --detach -s 1 -d 4 2>&1 | sed 's/\(saving bundle to \).*/\1/'
55 hg glog --template '{rev}: {desc}\n'
56 echo "Expected A, B, C, D, E"
57 hg manifest
58
59 echo
60 createrepo > /dev/null 2>&1
61 hg glog --template '{rev}: {desc}\n'
62 echo '% Rebasing C onto E detaching from B and collapsing'
63 hg rebase --detach --collapse -s 2 -d 4 2>&1 | sed 's/\(saving bundle to \).*/\1/'
64 hg glog --template '{rev}: {desc}\n'
65 echo "Expected A, C, D, E"
66 hg manifest
67
68 exit 0
@@ -0,0 +1,134 b''
1 @ 4: E
2 |
3 | o 3: D
4 | |
5 | o 2: C
6 | |
7 | o 1: B
8 |/
9 o 0: A
10
11 % Rebasing D onto E detaching from C
12 saving bundle to
13 adding branch
14 adding changesets
15 adding manifests
16 adding file changes
17 added 2 changesets with 2 changes to 2 files (+1 heads)
18 rebase completed
19 @ 4: D
20 |
21 o 3: E
22 |
23 | o 2: C
24 | |
25 | o 1: B
26 |/
27 o 0: A
28
29 Expected A, D, E
30 A
31 D
32 E
33
34 @ 4: E
35 |
36 | o 3: D
37 | |
38 | o 2: C
39 | |
40 | o 1: B
41 |/
42 o 0: A
43
44 % Rebasing C onto E detaching from B
45 saving bundle to
46 adding branch
47 adding changesets
48 adding manifests
49 adding file changes
50 added 3 changesets with 3 changes to 3 files (+1 heads)
51 rebase completed
52 @ 4: D
53 |
54 o 3: C
55 |
56 o 2: E
57 |
58 | o 1: B
59 |/
60 o 0: A
61
62 Expected A, C, D, E
63 A
64 C
65 D
66 E
67
68 @ 4: E
69 |
70 | o 3: D
71 | |
72 | o 2: C
73 | |
74 | o 1: B
75 |/
76 o 0: A
77
78 % Rebasing B onto E using detach (same as not using it)
79 saving bundle to
80 adding branch
81 adding changesets
82 adding manifests
83 adding file changes
84 added 4 changesets with 4 changes to 4 files
85 rebase completed
86 @ 4: D
87 |
88 o 3: C
89 |
90 o 2: B
91 |
92 o 1: E
93 |
94 o 0: A
95
96 Expected A, B, C, D, E
97 A
98 B
99 C
100 D
101 E
102
103 @ 4: E
104 |
105 | o 3: D
106 | |
107 | o 2: C
108 | |
109 | o 1: B
110 |/
111 o 0: A
112
113 % Rebasing C onto E detaching from B and collapsing
114 saving bundle to
115 adding branch
116 adding changesets
117 adding manifests
118 adding file changes
119 added 2 changesets with 3 changes to 3 files (+1 heads)
120 rebase completed
121 @ 3: Collapsed revision
122 | * C
123 | * D
124 o 2: E
125 |
126 | o 1: B
127 |/
128 o 0: A
129
130 Expected A, C, D, E
131 A
132 C
133 D
134 E
@@ -22,6 +22,8 b' from mercurial.lock import release'
22 22 from mercurial.i18n import _
23 23 import os, errno
24 24
25 nullmerge = -2
26
25 27 def rebase(ui, repo, **opts):
26 28 """move changeset (and descendants) to a different branch
27 29
@@ -53,6 +55,7 b' def rebase(ui, repo, **opts):'
53 55 extrafn = opts.get('extrafn')
54 56 keepf = opts.get('keep', False)
55 57 keepbranchesf = opts.get('keepbranches', False)
58 detachf = opts.get('detach', False)
56 59
57 60 if contf or abortf:
58 61 if contf and abortf:
@@ -62,6 +65,10 b' def rebase(ui, repo, **opts):'
62 65 raise error.ParseError(
63 66 'rebase', _('cannot use collapse with continue or abort'))
64 67
68 if detachf:
69 raise error.ParseError(
70 'rebase', _('cannot use detach with continue or abort'))
71
65 72 if srcf or basef or destf:
66 73 raise error.ParseError('rebase',
67 74 _('abort and continue do not allow specifying revisions'))
@@ -75,8 +82,16 b' def rebase(ui, repo, **opts):'
75 82 if srcf and basef:
76 83 raise error.ParseError('rebase', _('cannot specify both a '
77 84 'revision and a base'))
85 if detachf:
86 if not srcf:
87 raise error.ParseError(
88 'rebase', _('detach requires a revision to be specified'))
89 if basef:
90 raise error.ParseError(
91 'rebase', _('cannot specify a base with detach'))
92
78 93 cmdutil.bail_if_changed(repo)
79 result = buildstate(repo, destf, srcf, basef)
94 result = buildstate(repo, destf, srcf, basef, detachf)
80 95 if not result:
81 96 # Empty state built, nothing to rebase
82 97 ui.status(_('nothing to rebase\n'))
@@ -140,10 +155,10 b' def rebase(ui, repo, **opts):'
140 155 state, targetancestors)
141 156 commitmsg = 'Collapsed revision'
142 157 for rebased in state:
143 if rebased not in skipped:
158 if rebased not in skipped and state[rebased] != nullmerge:
144 159 commitmsg += '\n* %s' % repo[rebased].description()
145 160 commitmsg = ui.edit(commitmsg, repo.ui.username())
146 concludenode(repo, rev, p1, external, commitmsg=commitmsg,
161 newrev = concludenode(repo, rev, p1, external, commitmsg=commitmsg,
147 162 extra=extrafn)
148 163
149 164 if 'qtip' in repo.tags():
@@ -151,11 +166,13 b' def rebase(ui, repo, **opts):'
151 166
152 167 if not keepf:
153 168 # Remove no more useful revisions
154 if set(repo.changelog.descendants(min(state))) - set(state):
155 ui.warn(_("warning: new changesets detected on source branch, "
156 "not stripping\n"))
157 else:
158 repair.strip(ui, repo, repo[min(state)].node(), "strip")
169 rebased = [rev for rev in state if state[rev] != nullmerge]
170 if rebased:
171 if set(repo.changelog.descendants(min(rebased))) - set(state):
172 ui.warn(_("warning: new changesets detected on source branch, "
173 "not stripping\n"))
174 else:
175 repair.strip(ui, repo, repo[min(rebased)].node(), "strip")
159 176
160 177 clearstatus(repo)
161 178 ui.status(_("rebase completed\n"))
@@ -260,7 +277,10 b' def defineparents(repo, rev, target, sta'
260 277 if P1n in targetancestors:
261 278 p1 = target
262 279 elif P1n in state:
263 p1 = state[P1n]
280 if state[P1n] == nullmerge:
281 p1 = target
282 else:
283 p1 = state[P1n]
264 284 else: # P1n external
265 285 p1 = target
266 286 p2 = P1n
@@ -379,9 +399,10 b' def abort(repo, originalwd, target, stat'
379 399 clearstatus(repo)
380 400 repo.ui.status(_('rebase aborted\n'))
381 401
382 def buildstate(repo, dest, src, base):
402 def buildstate(repo, dest, src, base, detach):
383 403 'Define which revisions are going to be rebased and where'
384 404 targetancestors = set()
405 detachset = set()
385 406
386 407 if not dest:
387 408 # Destination defaults to the latest revision in the current branch
@@ -400,6 +421,12 b' def buildstate(repo, dest, src, base):'
400 421 if commonbase == repo[dest]:
401 422 raise util.Abort(_('source is descendant of destination'))
402 423 source = repo[src].rev()
424 if detach:
425 # We need to keep track of source's ancestors up to the common base
426 srcancestors = set(repo.changelog.ancestors(source))
427 baseancestors = set(repo.changelog.ancestors(commonbase.rev()))
428 detachset = srcancestors - baseancestors
429 detachset.remove(commonbase.rev())
403 430 else:
404 431 if base:
405 432 cwd = repo[base].rev()
@@ -426,6 +453,7 b' def buildstate(repo, dest, src, base):'
426 453
427 454 repo.ui.debug('rebase onto %d starting from %d\n' % (dest, source))
428 455 state = dict.fromkeys(repo.changelog.descendants(source), nullrev)
456 state.update(dict.fromkeys(detachset, nullmerge))
429 457 state[source] = nullrev
430 458 return repo['.'].rev(), repo[dest].rev(), state
431 459
@@ -468,9 +496,11 b' cmdtable = {'
468 496 ('', 'collapse', False, _('collapse the rebased changesets')),
469 497 ('', 'keep', False, _('keep original changesets')),
470 498 ('', 'keepbranches', False, _('keep original branch names')),
499 ('', 'detach', False, _('force detaching of source from its original '
500 'branch')),
471 501 ('c', 'continue', False, _('continue an interrupted rebase')),
472 502 ('a', 'abort', False, _('abort an interrupted rebase')),] +
473 503 templateopts,
474 _('hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--keep] '
475 '[--keepbranches] | [-c] | [-a]')),
504 _('hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--detach] '
505 '[--keep] [--keepbranches] | [-c] | [-a]')),
476 506 }
@@ -2,7 +2,7 b''
2 2
3 3 % Use continue and abort
4 4 hg rebase: cannot use both abort and continue
5 hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--keep] [--keepbranches] | [-c] | [-a]
5 hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--detach] [--keep] [--keepbranches] | [-c] | [-a]
6 6
7 7 move changeset (and descendants) to a different branch
8 8
@@ -21,6 +21,7 b' options:'
21 21 --collapse collapse the rebased changesets
22 22 --keep keep original changesets
23 23 --keepbranches keep original branch names
24 --detach force detaching of source from its original branch
24 25 -c --continue continue an interrupted rebase
25 26 -a --abort abort an interrupted rebase
26 27 --style display using template map file
@@ -30,7 +31,7 b' use "hg -v help rebase" to show global o'
30 31
31 32 % Use continue and collapse
32 33 hg rebase: cannot use collapse with continue or abort
33 hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--keep] [--keepbranches] | [-c] | [-a]
34 hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--detach] [--keep] [--keepbranches] | [-c] | [-a]
34 35
35 36 move changeset (and descendants) to a different branch
36 37
@@ -49,6 +50,7 b' options:'
49 50 --collapse collapse the rebased changesets
50 51 --keep keep original changesets
51 52 --keepbranches keep original branch names
53 --detach force detaching of source from its original branch
52 54 -c --continue continue an interrupted rebase
53 55 -a --abort abort an interrupted rebase
54 56 --style display using template map file
@@ -58,7 +60,7 b' use "hg -v help rebase" to show global o'
58 60
59 61 % Use continue/abort and dest/source
60 62 hg rebase: abort and continue do not allow specifying revisions
61 hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--keep] [--keepbranches] | [-c] | [-a]
63 hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--detach] [--keep] [--keepbranches] | [-c] | [-a]
62 64
63 65 move changeset (and descendants) to a different branch
64 66
@@ -77,6 +79,7 b' options:'
77 79 --collapse collapse the rebased changesets
78 80 --keep keep original changesets
79 81 --keepbranches keep original branch names
82 --detach force detaching of source from its original branch
80 83 -c --continue continue an interrupted rebase
81 84 -a --abort abort an interrupted rebase
82 85 --style display using template map file
@@ -86,7 +89,7 b' use "hg -v help rebase" to show global o'
86 89
87 90 % Use source and base
88 91 hg rebase: cannot specify both a revision and a base
89 hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--keep] [--keepbranches] | [-c] | [-a]
92 hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--detach] [--keep] [--keepbranches] | [-c] | [-a]
90 93
91 94 move changeset (and descendants) to a different branch
92 95
@@ -105,6 +108,7 b' options:'
105 108 --collapse collapse the rebased changesets
106 109 --keep keep original changesets
107 110 --keepbranches keep original branch names
111 --detach force detaching of source from its original branch
108 112 -c --continue continue an interrupted rebase
109 113 -a --abort abort an interrupted rebase
110 114 --style display using template map file
General Comments 0
You need to be logged in to leave comments. Login now