Merge lp:~jelmer/brz/git-config-branches into lp:brz
- git-config-branches
- Merge into trunk
Proposed by
Jelmer Vernooij
Status: | Merged |
---|---|
Approved by: | Jelmer Vernooij |
Approved revision: | no longer in the source branch. |
Merge reported by: | The Breezy Bot |
Merged at revision: | not available |
Proposed branch: | lp:~jelmer/brz/git-config-branches |
Merge into: | lp:brz |
Diff against target: |
302 lines (+139/-55) 6 files modified
breezy/git/branch.py (+68/-35) breezy/git/tests/test_urls.py (+23/-4) breezy/git/urls.py (+39/-12) breezy/tests/per_branch/test_branch.py (+3/-1) breezy/tests/per_branch/test_sprout.py (+4/-1) breezy/urlutils.py (+2/-2) |
To merge this branch: | bzr merge lp:~jelmer/brz/git-config-branches |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Packman | Approve | ||
Review via email: mp+358140@code.launchpad.net |
Commit message
Support reading related branches from git configs.
Description of the change
Support reading related branches from git configs.
To post a comment you must log in.
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Merging failed
https:/
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Running landing tests failed
https:/
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Running landing tests failed
https:/
Revision history for this message
The Breezy Bot (the-breezy-bot) wrote : | # |
Running landing tests failed
https:/
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'breezy/git/branch.py' | |||
2 | --- breezy/git/branch.py 2019-01-19 17:13:53 +0000 | |||
3 | +++ breezy/git/branch.py 2019-03-04 05:19:37 +0000 | |||
4 | @@ -76,7 +76,10 @@ | |||
5 | 76 | from .unpeel_map import ( | 76 | from .unpeel_map import ( |
6 | 77 | UnpeelMap, | 77 | UnpeelMap, |
7 | 78 | ) | 78 | ) |
9 | 79 | from .urls import git_url_to_bzr_url | 79 | from .urls import ( |
10 | 80 | git_url_to_bzr_url, | ||
11 | 81 | bzr_url_to_git_url, | ||
12 | 82 | ) | ||
13 | 80 | 83 | ||
14 | 81 | 84 | ||
15 | 82 | class GitPullResult(branch.PullResult): | 85 | class GitPullResult(branch.PullResult): |
16 | @@ -464,49 +467,76 @@ | |||
17 | 464 | # Git doesn't do stacking (yet...) | 467 | # Git doesn't do stacking (yet...) |
18 | 465 | raise branch.UnstackableBranchFormat(self._format, self.base) | 468 | raise branch.UnstackableBranchFormat(self._format, self.base) |
19 | 466 | 469 | ||
20 | 470 | def _get_push_origin(self, cs): | ||
21 | 471 | """Get the name for the push origin. | ||
22 | 472 | |||
23 | 473 | The exact behaviour is documented in the git-config(1) manpage. | ||
24 | 474 | """ | ||
25 | 475 | try: | ||
26 | 476 | return cs.get((b'branch', self.name.encode('utf-8')), b'pushRemote') | ||
27 | 477 | except KeyError: | ||
28 | 478 | try: | ||
29 | 479 | return cs.get((b'branch', ), b'remote') | ||
30 | 480 | except KeyError: | ||
31 | 481 | try: | ||
32 | 482 | return cs.get((b'branch', self.name.encode('utf-8')), b'remote') | ||
33 | 483 | except KeyError: | ||
34 | 484 | return b'origin' | ||
35 | 485 | |||
36 | 486 | def _get_origin(self, cs): | ||
37 | 487 | try: | ||
38 | 488 | return cs.get((b'branch', self.name.encode('utf-8')), b'remote') | ||
39 | 489 | except KeyError: | ||
40 | 490 | return b'origin' | ||
41 | 491 | |||
42 | 492 | def _get_related_push_branch(self, cs): | ||
43 | 493 | remote = self._get_push_origin(cs) | ||
44 | 494 | try: | ||
45 | 495 | location = cs.get((b"remote", remote), b"url") | ||
46 | 496 | except KeyError: | ||
47 | 497 | return None | ||
48 | 498 | |||
49 | 499 | return git_url_to_bzr_url(location.decode('utf-8'), ref=self.ref) | ||
50 | 500 | |||
51 | 501 | def _get_related_merge_branch(self, cs): | ||
52 | 502 | remote = self._get_origin(cs) | ||
53 | 503 | try: | ||
54 | 504 | location = cs.get((b"remote", remote), b"url") | ||
55 | 505 | except KeyError: | ||
56 | 506 | return None | ||
57 | 507 | |||
58 | 508 | try: | ||
59 | 509 | ref = cs.get((b"branch", remote), b"merge") | ||
60 | 510 | except KeyError: | ||
61 | 511 | ref = self.ref | ||
62 | 512 | |||
63 | 513 | return git_url_to_bzr_url(location.decode('utf-8'), ref=ref) | ||
64 | 514 | |||
65 | 467 | def _get_parent_location(self): | 515 | def _get_parent_location(self): |
66 | 468 | """See Branch.get_parent().""" | 516 | """See Branch.get_parent().""" |
67 | 469 | # FIXME: Set "origin" url from .git/config ? | ||
68 | 470 | cs = self.repository._git.get_config_stack() | 517 | cs = self.repository._git.get_config_stack() |
88 | 471 | try: | 518 | return self._get_related_merge_branch(cs) |
89 | 472 | location = cs.get((b"remote", b'origin'), b"url") | 519 | |
90 | 473 | except KeyError: | 520 | def _write_git_config(self, cs): |
91 | 474 | return None | 521 | f = BytesIO() |
92 | 475 | 522 | cs.write_to_file(f) | |
93 | 476 | params = {} | 523 | self.repository._git._put_named_file('config', f.getvalue()) |
75 | 477 | try: | ||
76 | 478 | ref = cs.get((b"remote", b"origin"), b"merge") | ||
77 | 479 | except KeyError: | ||
78 | 480 | pass | ||
79 | 481 | else: | ||
80 | 482 | if ref != b'HEAD': | ||
81 | 483 | try: | ||
82 | 484 | params['branch'] = urlutils.escape(ref_to_branch_name(ref)) | ||
83 | 485 | except ValueError: | ||
84 | 486 | params['ref'] = urlutils.quote_from_bytes(ref) | ||
85 | 487 | |||
86 | 488 | url = git_url_to_bzr_url(location.decode('utf-8')) | ||
87 | 489 | return urlutils.join_segment_parameters(url, params) | ||
94 | 490 | 524 | ||
95 | 491 | def set_parent(self, location): | 525 | def set_parent(self, location): |
96 | 492 | # FIXME: Set "origin" url in .git/config ? | ||
97 | 493 | cs = self.repository._git.get_config() | 526 | cs = self.repository._git.get_config() |
98 | 527 | remote = self._get_origin(cs) | ||
99 | 494 | this_url = urlutils.split_segment_parameters(self.user_url)[0] | 528 | this_url = urlutils.split_segment_parameters(self.user_url)[0] |
101 | 495 | target_url, target_params = urlutils.split_segment_parameters(location) | 529 | target_url, branch, ref = bzr_url_to_git_url(location) |
102 | 496 | location = urlutils.relative_url(this_url, target_url) | 530 | location = urlutils.relative_url(this_url, target_url) |
110 | 497 | cs.set((b"remote", b"origin"), b"url", location) | 531 | cs.set((b"remote", remote), b"url", location) |
111 | 498 | if 'branch' in target_params: | 532 | if branch: |
112 | 499 | cs.set((b"remote", b"origin"), b"merge", | 533 | cs.set((b"branch", remote), b"merge", branch_name_to_ref(branch)) |
113 | 500 | branch_name_to_ref(target_params['branch'])) | 534 | elif ref: |
114 | 501 | elif 'ref' in target_params: | 535 | cs.set((b"branch", remote), b"merge", ref) |
108 | 502 | cs.set((b"remote", b"origin"), b"merge", | ||
109 | 503 | target_params['ref']) | ||
115 | 504 | else: | 536 | else: |
116 | 505 | # TODO(jelmer): Maybe unset rather than setting to HEAD? | 537 | # TODO(jelmer): Maybe unset rather than setting to HEAD? |
121 | 506 | cs.set((b"remote", b"origin"), b"merge", 'HEAD') | 538 | cs.set((b"branch", remote), b"merge", b'HEAD') |
122 | 507 | f = BytesIO() | 539 | self._write_git_config(cs) |
119 | 508 | cs.write_to_file(f) | ||
120 | 509 | self.repository._git._put_named_file('config', f.getvalue()) | ||
123 | 510 | 540 | ||
124 | 511 | def break_lock(self): | 541 | def break_lock(self): |
125 | 512 | raise NotImplementedError(self.break_lock) | 542 | raise NotImplementedError(self.break_lock) |
126 | @@ -720,7 +750,10 @@ | |||
127 | 720 | def get_push_location(self): | 750 | def get_push_location(self): |
128 | 721 | """See Branch.get_push_location.""" | 751 | """See Branch.get_push_location.""" |
129 | 722 | push_loc = self.get_config_stack().get('push_location') | 752 | push_loc = self.get_config_stack().get('push_location') |
131 | 723 | return push_loc | 753 | if push_loc is not None: |
132 | 754 | return push_loc | ||
133 | 755 | cs = self.repository._git.get_config_stack() | ||
134 | 756 | return self._get_related_push_branch(cs) | ||
135 | 724 | 757 | ||
136 | 725 | def set_push_location(self, location): | 758 | def set_push_location(self, location): |
137 | 726 | """See Branch.set_push_location.""" | 759 | """See Branch.set_push_location.""" |
138 | 727 | 760 | ||
139 | === modified file 'breezy/git/tests/test_urls.py' | |||
140 | --- breezy/git/tests/test_urls.py 2018-11-11 04:08:32 +0000 | |||
141 | +++ breezy/git/tests/test_urls.py 2019-03-04 05:19:37 +0000 | |||
142 | @@ -42,7 +42,26 @@ | |||
143 | 42 | ('git+ssh://user@foo/bar/path')) | 42 | ('git+ssh://user@foo/bar/path')) |
144 | 43 | 43 | ||
145 | 44 | def test_path(self): | 44 | def test_path(self): |
150 | 45 | self.assertEqual( | 45 | self.assertEqual(git_url_to_bzr_url('/bar/path'), ('/bar/path')) |
151 | 46 | git_url_to_bzr_url( | 46 | |
152 | 47 | '/bar/path'), | 47 | def test_with_ref(self): |
153 | 48 | ('/bar/path')) | 48 | self.assertEqual( |
154 | 49 | git_url_to_bzr_url('foo:bar/path', ref=b'HEAD'), | ||
155 | 50 | 'git+ssh://foo/bar/path') | ||
156 | 51 | self.assertEqual( | ||
157 | 52 | git_url_to_bzr_url('foo:bar/path', ref=b'refs/heads/blah'), | ||
158 | 53 | 'git+ssh://foo/bar/path,branch=blah') | ||
159 | 54 | self.assertEqual( | ||
160 | 55 | git_url_to_bzr_url('foo:bar/path', ref=b'refs/tags/blah'), | ||
161 | 56 | 'git+ssh://foo/bar/path,ref=refs%2Ftags%2Fblah') | ||
162 | 57 | |||
163 | 58 | def test_with_branch(self): | ||
164 | 59 | self.assertEqual( | ||
165 | 60 | git_url_to_bzr_url('foo:bar/path', branch=''), | ||
166 | 61 | 'git+ssh://foo/bar/path') | ||
167 | 62 | self.assertEqual( | ||
168 | 63 | git_url_to_bzr_url('foo:bar/path', branch='foo/blah'), | ||
169 | 64 | 'git+ssh://foo/bar/path,branch=foo%2Fblah') | ||
170 | 65 | self.assertEqual( | ||
171 | 66 | git_url_to_bzr_url('foo:bar/path', branch='blah'), | ||
172 | 67 | 'git+ssh://foo/bar/path,branch=blah') | ||
173 | 49 | 68 | ||
174 | === modified file 'breezy/git/urls.py' | |||
175 | --- breezy/git/urls.py 2018-11-11 14:23:06 +0000 | |||
176 | +++ breezy/git/urls.py 2019-03-04 05:19:37 +0000 | |||
177 | @@ -18,7 +18,10 @@ | |||
178 | 18 | 18 | ||
179 | 19 | from __future__ import absolute_import | 19 | from __future__ import absolute_import |
180 | 20 | 20 | ||
182 | 21 | from breezy.urlutils import URL, quote | 21 | from .. import urlutils |
183 | 22 | from .refs import ( | ||
184 | 23 | ref_to_branch_name, | ||
185 | 24 | ) | ||
186 | 22 | 25 | ||
187 | 23 | from dulwich.client import parse_rsync_url | 26 | from dulwich.client import parse_rsync_url |
188 | 24 | 27 | ||
189 | @@ -26,22 +29,46 @@ | |||
190 | 26 | KNOWN_GIT_SCHEMES = ['git+ssh', 'git', 'http', 'https', 'ftp'] | 29 | KNOWN_GIT_SCHEMES = ['git+ssh', 'git', 'http', 'https', 'ftp'] |
191 | 27 | 30 | ||
192 | 28 | 31 | ||
197 | 29 | def git_url_to_bzr_url(location): | 32 | def git_url_to_bzr_url(location, branch=None, ref=None): |
198 | 30 | url = URL.from_string(location) | 33 | if branch is not None and ref is not None: |
199 | 31 | if (url.scheme not in KNOWN_GIT_SCHEMES | 34 | raise ValueError('only specify one of branch or ref') |
200 | 32 | and not url.scheme.startswith('chroot-')): | 35 | url = urlutils.URL.from_string(location) |
201 | 36 | if (url.scheme not in KNOWN_GIT_SCHEMES and | ||
202 | 37 | not url.scheme.startswith('chroot-')): | ||
203 | 33 | try: | 38 | try: |
204 | 34 | (username, host, path) = parse_rsync_url(location) | 39 | (username, host, path) = parse_rsync_url(location) |
205 | 35 | except ValueError: | 40 | except ValueError: |
206 | 36 | return location | 41 | return location |
207 | 37 | else: | 42 | else: |
209 | 38 | url = URL( | 43 | url = urlutils.URL( |
210 | 39 | scheme='git+ssh', | 44 | scheme='git+ssh', |
212 | 40 | quoted_user=(quote(username) if username else None), | 45 | quoted_user=(urlutils.quote(username) if username else None), |
213 | 41 | quoted_password=None, | 46 | quoted_password=None, |
215 | 42 | quoted_host=quote(host), | 47 | quoted_host=urlutils.quote(host), |
216 | 43 | port=None, | 48 | port=None, |
221 | 44 | quoted_path=quote(path, safe="/~")) | 49 | quoted_path=urlutils.quote(path, safe="/~")) |
222 | 45 | return str(url) | 50 | location = str(url) |
223 | 46 | else: | 51 | if ref == b'HEAD': |
224 | 47 | return location | 52 | ref = branch = None |
225 | 53 | if ref: | ||
226 | 54 | try: | ||
227 | 55 | branch = ref_to_branch_name(ref) | ||
228 | 56 | except ValueError: | ||
229 | 57 | branch = None | ||
230 | 58 | else: | ||
231 | 59 | ref = None | ||
232 | 60 | if ref or branch: | ||
233 | 61 | params = {} | ||
234 | 62 | if ref: | ||
235 | 63 | params['ref'] = urlutils.quote_from_bytes(ref, safe='') | ||
236 | 64 | if branch: | ||
237 | 65 | params['branch'] = urlutils.escape(branch, safe='') | ||
238 | 66 | location = urlutils.join_segment_parameters(location, params) | ||
239 | 67 | return location | ||
240 | 68 | |||
241 | 69 | |||
242 | 70 | def bzr_url_to_git_url(location): | ||
243 | 71 | target_url, target_params = urlutils.split_segment_parameters(location) | ||
244 | 72 | branch = target_params.get('branch') | ||
245 | 73 | ref = target_params.get('ref') | ||
246 | 74 | return target_url, branch, ref | ||
247 | 48 | 75 | ||
248 | === modified file 'breezy/tests/per_branch/test_branch.py' | |||
249 | --- breezy/tests/per_branch/test_branch.py 2018-11-11 04:08:32 +0000 | |||
250 | +++ breezy/tests/per_branch/test_branch.py 2019-03-04 05:19:37 +0000 | |||
251 | @@ -164,7 +164,9 @@ | |||
252 | 164 | 164 | ||
253 | 165 | branch_b = wt_a.branch.controldir.sprout( | 165 | branch_b = wt_a.branch.controldir.sprout( |
254 | 166 | 'b', revision_id=rev1).open_branch() | 166 | 'b', revision_id=rev1).open_branch() |
256 | 167 | self.assertEqual(wt_a.branch.user_url, branch_b.get_parent()) | 167 | self.assertEqual( |
257 | 168 | urlutils.split_segment_parameters(wt_a.branch.user_url)[0], | ||
258 | 169 | urlutils.split_segment_parameters(branch_b.get_parent())[0]) | ||
259 | 168 | return branch_b | 170 | return branch_b |
260 | 169 | 171 | ||
261 | 170 | def test_clone_branch_nickname(self): | 172 | def test_clone_branch_nickname(self): |
262 | 171 | 173 | ||
263 | === modified file 'breezy/tests/per_branch/test_sprout.py' | |||
264 | --- breezy/tests/per_branch/test_sprout.py 2018-11-11 04:08:32 +0000 | |||
265 | +++ breezy/tests/per_branch/test_sprout.py 2019-03-04 05:19:37 +0000 | |||
266 | @@ -23,6 +23,7 @@ | |||
267 | 23 | osutils, | 23 | osutils, |
268 | 24 | revision as _mod_revision, | 24 | revision as _mod_revision, |
269 | 25 | tests, | 25 | tests, |
270 | 26 | urlutils, | ||
271 | 26 | ) | 27 | ) |
272 | 27 | from breezy.bzr import ( | 28 | from breezy.bzr import ( |
273 | 28 | branch as _mod_bzrbranch, | 29 | branch as _mod_bzrbranch, |
274 | @@ -43,7 +44,9 @@ | |||
275 | 43 | def test_sprout_branch_parent(self): | 44 | def test_sprout_branch_parent(self): |
276 | 44 | source = self.make_branch('source') | 45 | source = self.make_branch('source') |
277 | 45 | target = source.controldir.sprout(self.get_url('target')).open_branch() | 46 | target = source.controldir.sprout(self.get_url('target')).open_branch() |
279 | 46 | self.assertEqual(source.user_url, target.get_parent()) | 47 | self.assertEqual( |
280 | 48 | urlutils.split_segment_parameters(source.user_url)[0], | ||
281 | 49 | urlutils.split_segment_parameters(target.get_parent())[0]) | ||
282 | 47 | 50 | ||
283 | 48 | def test_sprout_uses_bzrdir_branch_format(self): | 51 | def test_sprout_uses_bzrdir_branch_format(self): |
284 | 49 | # branch.sprout(bzrdir) is defined as using the branch format selected | 52 | # branch.sprout(bzrdir) is defined as using the branch format selected |
285 | 50 | 53 | ||
286 | === modified file 'breezy/urlutils.py' | |||
287 | --- breezy/urlutils.py 2018-11-12 01:41:38 +0000 | |||
288 | +++ breezy/urlutils.py 2019-03-04 05:19:37 +0000 | |||
289 | @@ -162,11 +162,11 @@ | |||
290 | 162 | unquote = urlparse.unquote | 162 | unquote = urlparse.unquote |
291 | 163 | 163 | ||
292 | 164 | 164 | ||
294 | 165 | def escape(relpath): | 165 | def escape(relpath, safe='/~'): |
295 | 166 | """Escape relpath to be a valid url.""" | 166 | """Escape relpath to be a valid url.""" |
296 | 167 | if not isinstance(relpath, str) and sys.version_info[0] == 2: | 167 | if not isinstance(relpath, str) and sys.version_info[0] == 2: |
297 | 168 | relpath = relpath.encode('utf-8') | 168 | relpath = relpath.encode('utf-8') |
299 | 169 | return quote(relpath, safe='/~') | 169 | return quote(relpath, safe=safe) |
300 | 170 | 170 | ||
301 | 171 | 171 | ||
302 | 172 | def file_relpath(base, path): | 172 | def file_relpath(base, path): |
Looks good, see a couple of inline comments.