Skip to content

Commit a2adea0

Browse files
Chronialmsiemens
authored andcommitted
Only stash changes when needed (#86)
1 parent c40ee7e commit a2adea0

2 files changed

Lines changed: 100 additions & 102 deletions

File tree

PyGitUp/git_wrapper.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,21 @@ def __getattr__(self, name):
114114
###########################################################################
115115

116116
@contextmanager
117-
def stash(self):
117+
def stasher(self):
118118
"""
119119
A stashing contextmanager.
120-
It stashes all changes inside and unstashed when done.
121120
"""
122-
stashed = False
121+
# nonlocal for python2
122+
stashed = [False]
123+
clean = [False]
124+
125+
def stash():
126+
if clean[0] or not self.repo.is_dirty(submodules=False):
127+
clean[0] = True
128+
return
129+
if stashed[0]:
130+
return
123131

124-
if self.repo.is_dirty(submodules=False):
125132
if self.change_count > 1:
126133
message = 'stashing {0} changes'
127134
else:
@@ -135,11 +142,11 @@ def stash(self):
135142
except GitError as e:
136143
raise StashError(stderr=e.stderr, stdout=e.stdout)
137144

138-
stashed = True
145+
stashed[0] = True
139146

140-
yield
147+
yield stash
141148

142-
if stashed:
149+
if stashed[0]:
143150
print(colored('unstashing', 'magenta'))
144151
try:
145152
self._run('stash', 'pop')

PyGitUp/gitup.py

Lines changed: 86 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -196,9 +196,7 @@ def run(self):
196196
if self.should_fetch:
197197
self.fetch()
198198

199-
with self.git.stash():
200-
with self.returning_to_current_branch():
201-
self.rebase_all_branches()
199+
self.rebase_all_branches()
202200

203201
if self.with_bundler():
204202
self.check_bundler()
@@ -218,83 +216,97 @@ def run(self):
218216
def rebase_all_branches(self):
219217
""" Rebase all branches, if possible. """
220218
col_width = max(len(b.name) for b in self.branches) + 1
219+
if self.repo.head.is_detached:
220+
raise GitError("You're not currently on a branch. I'm exiting"
221+
" in case you're in the middle of something.")
221222
original_branch = self.repo.active_branch
222223

223-
for branch in self.branches:
224-
target = self.target_map[branch.name]
225-
226-
# Print branch name
227-
if branch.name == original_branch.name:
228-
attrs = ['bold']
229-
else:
230-
attrs = []
231-
print(colored(branch.name.ljust(col_width), attrs=attrs),
232-
end=' ')
224+
with self.git.stasher() as stasher:
225+
for branch in self.branches:
226+
target = self.target_map[branch.name]
233227

234-
# Check, if target branch exists
235-
try:
236-
if target.name.startswith('./'):
237-
# Check, if local branch exists
238-
self.git.rev_parse(target.name[2:])
228+
# Print branch name
229+
if branch.name == original_branch.name:
230+
attrs = ['bold']
239231
else:
240-
# Check, if remote branch exists
241-
_ = target.commit
242-
243-
except (ValueError, GitError):
244-
# Remote branch doesn't exist!
245-
print(colored('error: remote branch doesn\'t exist', 'red'))
246-
self.states.append('remote branch doesn\'t exist')
247-
248-
continue
249-
250-
# Get tracking branch
251-
if target.is_local:
252-
target = find(self.repo.branches,
253-
lambda b: b.name == target.name[2:])
254-
255-
# Check status and act appropriately
256-
if target.commit.hexsha == branch.commit.hexsha:
257-
print(colored('up to date', 'green'))
258-
self.states.append('up to date')
259-
260-
continue # Do not do anything
261-
262-
base = self.git.merge_base(branch.name, target.name)
263-
264-
if base == target.commit.hexsha:
265-
print(colored('ahead of upstream', 'cyan'))
266-
self.states.append('ahead')
267-
268-
continue # Do not do anything
269-
270-
fast_fastforward = False
271-
if base == branch.commit.hexsha:
272-
print(colored('fast-forwarding...', 'yellow'), end='')
273-
self.states.append('fast-forwarding')
274-
# Don't fast fast-forward the currently checked-out branch
275-
fast_fastforward = (branch.name != self.repo.active_branch.name)
276-
277-
elif not self.settings['rebase.auto']:
278-
print(colored('diverged', 'red'))
279-
self.states.append('diverged')
280-
281-
continue # Do not do anything
282-
else:
283-
print(colored('rebasing', 'yellow'), end='')
284-
self.states.append('rebasing')
232+
attrs = []
233+
print(colored(branch.name.ljust(col_width), attrs=attrs),
234+
end=' ')
235+
236+
# Check, if target branch exists
237+
try:
238+
if target.name.startswith('./'):
239+
# Check, if local branch exists
240+
self.git.rev_parse(target.name[2:])
241+
else:
242+
# Check, if remote branch exists
243+
_ = target.commit
244+
245+
except (ValueError, GitError):
246+
# Remote branch doesn't exist!
247+
print(colored('error: remote branch doesn\'t exist', 'red'))
248+
self.states.append('remote branch doesn\'t exist')
249+
250+
continue
251+
252+
# Get tracking branch
253+
if target.is_local:
254+
target = find(self.repo.branches,
255+
lambda b: b.name == target.name[2:])
256+
257+
# Check status and act appropriately
258+
if target.commit.hexsha == branch.commit.hexsha:
259+
print(colored('up to date', 'green'))
260+
self.states.append('up to date')
261+
262+
continue # Do not do anything
263+
264+
base = self.git.merge_base(branch.name, target.name)
265+
266+
if base == target.commit.hexsha:
267+
print(colored('ahead of upstream', 'cyan'))
268+
self.states.append('ahead')
269+
270+
continue # Do not do anything
271+
272+
fast_fastforward = False
273+
if base == branch.commit.hexsha:
274+
print(colored('fast-forwarding...', 'yellow'), end='')
275+
self.states.append('fast-forwarding')
276+
# Don't fast fast-forward the currently checked-out branch
277+
fast_fastforward = (branch.name !=
278+
self.repo.active_branch.name)
279+
280+
elif not self.settings['rebase.auto']:
281+
print(colored('diverged', 'red'))
282+
self.states.append('diverged')
283+
284+
continue # Do not do anything
285+
else:
286+
print(colored('rebasing', 'yellow'), end='')
287+
self.states.append('rebasing')
285288

286-
if self.settings['rebase.show-hashes']:
287-
print(' {}..{}'.format(base[0:7],
288-
target.commit.hexsha[0:7]))
289-
else:
290-
print()
289+
if self.settings['rebase.show-hashes']:
290+
print(' {}..{}'.format(base[0:7],
291+
target.commit.hexsha[0:7]))
292+
else:
293+
print()
291294

292-
self.log(branch, target)
293-
if fast_fastforward:
294-
branch.commit = target.commit
295-
else:
296-
self.git.checkout(branch.name)
297-
self.git.rebase(target)
295+
self.log(branch, target)
296+
if fast_fastforward:
297+
branch.commit = target.commit
298+
else:
299+
stasher()
300+
self.git.checkout(branch.name)
301+
self.git.rebase(target)
302+
303+
if (self.repo.head.is_detached # Only on Travis CI,
304+
# we get a detached head after doing our rebase *confused*.
305+
# Running self.repo.active_branch would fail.
306+
or not self.repo.active_branch.name == original_branch.name):
307+
print(colored('returning to {0}'.format(original_branch.name),
308+
'magenta'))
309+
original_branch.checkout()
298310

299311
def fetch(self):
300312
"""
@@ -452,27 +464,6 @@ def version_info(self):
452464
# Helpers
453465
###########################################################################
454466

455-
@contextmanager
456-
def returning_to_current_branch(self):
457-
""" A contextmanager returning to the current branch. """
458-
if self.repo.head.is_detached:
459-
raise GitError("You're not currently on a branch. I'm exiting"
460-
" in case you're in the middle of something.")
461-
462-
branch_name = self.repo.active_branch.name
463-
464-
yield
465-
466-
if (
467-
self.repo.head.is_detached # Only on Travis CI,
468-
# we get a detached head after doing our rebase *confused*.
469-
# Running self.repo.active_branch would fail.
470-
or
471-
not self.repo.active_branch.name == branch_name
472-
):
473-
print(colored('returning to {0}'.format(branch_name), 'magenta'))
474-
self.git.checkout(branch_name)
475-
476467
def load_config(self):
477468
"""
478469
Load the configuration from git config.

0 commit comments

Comments
 (0)