##// 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 from mercurial.i18n import _
22 from mercurial.i18n import _
23 import os, errno
23 import os, errno
24
24
25 nullmerge = -2
26
25 def rebase(ui, repo, **opts):
27 def rebase(ui, repo, **opts):
26 """move changeset (and descendants) to a different branch
28 """move changeset (and descendants) to a different branch
27
29
@@ -53,6 +55,7 b' def rebase(ui, repo, **opts):'
53 extrafn = opts.get('extrafn')
55 extrafn = opts.get('extrafn')
54 keepf = opts.get('keep', False)
56 keepf = opts.get('keep', False)
55 keepbranchesf = opts.get('keepbranches', False)
57 keepbranchesf = opts.get('keepbranches', False)
58 detachf = opts.get('detach', False)
56
59
57 if contf or abortf:
60 if contf or abortf:
58 if contf and abortf:
61 if contf and abortf:
@@ -62,6 +65,10 b' def rebase(ui, repo, **opts):'
62 raise error.ParseError(
65 raise error.ParseError(
63 'rebase', _('cannot use collapse with continue or abort'))
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 if srcf or basef or destf:
72 if srcf or basef or destf:
66 raise error.ParseError('rebase',
73 raise error.ParseError('rebase',
67 _('abort and continue do not allow specifying revisions'))
74 _('abort and continue do not allow specifying revisions'))
@@ -75,8 +82,16 b' def rebase(ui, repo, **opts):'
75 if srcf and basef:
82 if srcf and basef:
76 raise error.ParseError('rebase', _('cannot specify both a '
83 raise error.ParseError('rebase', _('cannot specify both a '
77 'revision and a base'))
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 cmdutil.bail_if_changed(repo)
93 cmdutil.bail_if_changed(repo)
79 result = buildstate(repo, destf, srcf, basef)
94 result = buildstate(repo, destf, srcf, basef, detachf)
80 if not result:
95 if not result:
81 # Empty state built, nothing to rebase
96 # Empty state built, nothing to rebase
82 ui.status(_('nothing to rebase\n'))
97 ui.status(_('nothing to rebase\n'))
@@ -140,10 +155,10 b' def rebase(ui, repo, **opts):'
140 state, targetancestors)
155 state, targetancestors)
141 commitmsg = 'Collapsed revision'
156 commitmsg = 'Collapsed revision'
142 for rebased in state:
157 for rebased in state:
143 if rebased not in skipped:
158 if rebased not in skipped and state[rebased] != nullmerge:
144 commitmsg += '\n* %s' % repo[rebased].description()
159 commitmsg += '\n* %s' % repo[rebased].description()
145 commitmsg = ui.edit(commitmsg, repo.ui.username())
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 extra=extrafn)
162 extra=extrafn)
148
163
149 if 'qtip' in repo.tags():
164 if 'qtip' in repo.tags():
@@ -151,11 +166,13 b' def rebase(ui, repo, **opts):'
151
166
152 if not keepf:
167 if not keepf:
153 # Remove no more useful revisions
168 # Remove no more useful revisions
154 if set(repo.changelog.descendants(min(state))) - set(state):
169 rebased = [rev for rev in state if state[rev] != nullmerge]
155 ui.warn(_("warning: new changesets detected on source branch, "
170 if rebased:
156 "not stripping\n"))
171 if set(repo.changelog.descendants(min(rebased))) - set(state):
157 else:
172 ui.warn(_("warning: new changesets detected on source branch, "
158 repair.strip(ui, repo, repo[min(state)].node(), "strip")
173 "not stripping\n"))
174 else:
175 repair.strip(ui, repo, repo[min(rebased)].node(), "strip")
159
176
160 clearstatus(repo)
177 clearstatus(repo)
161 ui.status(_("rebase completed\n"))
178 ui.status(_("rebase completed\n"))
@@ -260,7 +277,10 b' def defineparents(repo, rev, target, sta'
260 if P1n in targetancestors:
277 if P1n in targetancestors:
261 p1 = target
278 p1 = target
262 elif P1n in state:
279 elif P1n in state:
263 p1 = state[P1n]
280 if state[P1n] == nullmerge:
281 p1 = target
282 else:
283 p1 = state[P1n]
264 else: # P1n external
284 else: # P1n external
265 p1 = target
285 p1 = target
266 p2 = P1n
286 p2 = P1n
@@ -379,9 +399,10 b' def abort(repo, originalwd, target, stat'
379 clearstatus(repo)
399 clearstatus(repo)
380 repo.ui.status(_('rebase aborted\n'))
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 'Define which revisions are going to be rebased and where'
403 'Define which revisions are going to be rebased and where'
384 targetancestors = set()
404 targetancestors = set()
405 detachset = set()
385
406
386 if not dest:
407 if not dest:
387 # Destination defaults to the latest revision in the current branch
408 # Destination defaults to the latest revision in the current branch
@@ -400,6 +421,12 b' def buildstate(repo, dest, src, base):'
400 if commonbase == repo[dest]:
421 if commonbase == repo[dest]:
401 raise util.Abort(_('source is descendant of destination'))
422 raise util.Abort(_('source is descendant of destination'))
402 source = repo[src].rev()
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 else:
430 else:
404 if base:
431 if base:
405 cwd = repo[base].rev()
432 cwd = repo[base].rev()
@@ -426,6 +453,7 b' def buildstate(repo, dest, src, base):'
426
453
427 repo.ui.debug('rebase onto %d starting from %d\n' % (dest, source))
454 repo.ui.debug('rebase onto %d starting from %d\n' % (dest, source))
428 state = dict.fromkeys(repo.changelog.descendants(source), nullrev)
455 state = dict.fromkeys(repo.changelog.descendants(source), nullrev)
456 state.update(dict.fromkeys(detachset, nullmerge))
429 state[source] = nullrev
457 state[source] = nullrev
430 return repo['.'].rev(), repo[dest].rev(), state
458 return repo['.'].rev(), repo[dest].rev(), state
431
459
@@ -468,9 +496,11 b' cmdtable = {'
468 ('', 'collapse', False, _('collapse the rebased changesets')),
496 ('', 'collapse', False, _('collapse the rebased changesets')),
469 ('', 'keep', False, _('keep original changesets')),
497 ('', 'keep', False, _('keep original changesets')),
470 ('', 'keepbranches', False, _('keep original branch names')),
498 ('', 'keepbranches', False, _('keep original branch names')),
499 ('', 'detach', False, _('force detaching of source from its original '
500 'branch')),
471 ('c', 'continue', False, _('continue an interrupted rebase')),
501 ('c', 'continue', False, _('continue an interrupted rebase')),
472 ('a', 'abort', False, _('abort an interrupted rebase')),] +
502 ('a', 'abort', False, _('abort an interrupted rebase')),] +
473 templateopts,
503 templateopts,
474 _('hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--keep] '
504 _('hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--detach] '
475 '[--keepbranches] | [-c] | [-a]')),
505 '[--keep] [--keepbranches] | [-c] | [-a]')),
476 }
506 }
@@ -2,7 +2,7 b''
2
2
3 % Use continue and abort
3 % Use continue and abort
4 hg rebase: cannot use both abort and continue
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 move changeset (and descendants) to a different branch
7 move changeset (and descendants) to a different branch
8
8
@@ -21,6 +21,7 b' options:'
21 --collapse collapse the rebased changesets
21 --collapse collapse the rebased changesets
22 --keep keep original changesets
22 --keep keep original changesets
23 --keepbranches keep original branch names
23 --keepbranches keep original branch names
24 --detach force detaching of source from its original branch
24 -c --continue continue an interrupted rebase
25 -c --continue continue an interrupted rebase
25 -a --abort abort an interrupted rebase
26 -a --abort abort an interrupted rebase
26 --style display using template map file
27 --style display using template map file
@@ -30,7 +31,7 b' use "hg -v help rebase" to show global o'
30
31
31 % Use continue and collapse
32 % Use continue and collapse
32 hg rebase: cannot use collapse with continue or abort
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 move changeset (and descendants) to a different branch
36 move changeset (and descendants) to a different branch
36
37
@@ -49,6 +50,7 b' options:'
49 --collapse collapse the rebased changesets
50 --collapse collapse the rebased changesets
50 --keep keep original changesets
51 --keep keep original changesets
51 --keepbranches keep original branch names
52 --keepbranches keep original branch names
53 --detach force detaching of source from its original branch
52 -c --continue continue an interrupted rebase
54 -c --continue continue an interrupted rebase
53 -a --abort abort an interrupted rebase
55 -a --abort abort an interrupted rebase
54 --style display using template map file
56 --style display using template map file
@@ -58,7 +60,7 b' use "hg -v help rebase" to show global o'
58
60
59 % Use continue/abort and dest/source
61 % Use continue/abort and dest/source
60 hg rebase: abort and continue do not allow specifying revisions
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 move changeset (and descendants) to a different branch
65 move changeset (and descendants) to a different branch
64
66
@@ -77,6 +79,7 b' options:'
77 --collapse collapse the rebased changesets
79 --collapse collapse the rebased changesets
78 --keep keep original changesets
80 --keep keep original changesets
79 --keepbranches keep original branch names
81 --keepbranches keep original branch names
82 --detach force detaching of source from its original branch
80 -c --continue continue an interrupted rebase
83 -c --continue continue an interrupted rebase
81 -a --abort abort an interrupted rebase
84 -a --abort abort an interrupted rebase
82 --style display using template map file
85 --style display using template map file
@@ -86,7 +89,7 b' use "hg -v help rebase" to show global o'
86
89
87 % Use source and base
90 % Use source and base
88 hg rebase: cannot specify both a revision and a base
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 move changeset (and descendants) to a different branch
94 move changeset (and descendants) to a different branch
92
95
@@ -105,6 +108,7 b' options:'
105 --collapse collapse the rebased changesets
108 --collapse collapse the rebased changesets
106 --keep keep original changesets
109 --keep keep original changesets
107 --keepbranches keep original branch names
110 --keepbranches keep original branch names
111 --detach force detaching of source from its original branch
108 -c --continue continue an interrupted rebase
112 -c --continue continue an interrupted rebase
109 -a --abort abort an interrupted rebase
113 -a --abort abort an interrupted rebase
110 --style display using template map file
114 --style display using template map file
General Comments 0
You need to be logged in to leave comments. Login now