Show More
@@ -0,0 +1,68 | |||||
|
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 | |||||
|
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 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 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 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 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 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 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] | |
|
170 | if rebased: | |||
|
171 | if set(repo.changelog.descendants(min(rebased))) - set(state): | |||
155 | ui.warn(_("warning: new changesets detected on source branch, " |
|
172 | ui.warn(_("warning: new changesets detected on source branch, " | |
156 | "not stripping\n")) |
|
173 | "not stripping\n")) | |
157 | else: |
|
174 | else: | |
158 |
repair.strip(ui, repo, repo[min( |
|
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,6 +277,9 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: | |
|
280 | if state[P1n] == nullmerge: | |||
|
281 | p1 = target | |||
|
282 | else: | |||
263 | p1 = state[P1n] |
|
283 | p1 = state[P1n] | |
264 | else: # P1n external |
|
284 | else: # P1n external | |
265 | p1 = target |
|
285 | p1 = target | |
@@ -379,9 +399,10 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 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 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 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] [-- |
|
504 | _('hg rebase [-s REV | -b REV] [-d REV] [--collapse] [--detach] ' | |
475 |
|
|
505 | '[--keep] [--keepbranches] | [-c] | [-a]')), | |
476 | } |
|
506 | } |
@@ -2,7 +2,7 | |||||
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 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 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 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 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 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 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 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