8 from ..git
import STDOUT
9 from ..interaction
import Interaction
13 def __init__(self
, context
):
14 self
.context
= context
15 self
.git
= context
.git
16 self
.model
= model
= context
.model
17 if not model
.initialized
:
20 def stash_list(self
, *args
):
21 return self
.git
.stash('list', *args
)[STDOUT
].splitlines()
24 return bool(self
.model
.staged
)
28 return bool(model
.modified
or model
.staged
)
30 def stash_info(self
, revids
=False, names
=False):
31 """Parses "git stash list" and returns a list of stashes."""
32 stashes
= self
.stash_list(r
'--format=%gd/%aD/%gs')
33 split_stashes
= [s
.split('/', 2) for s
in stashes
if s
]
34 stashes
= [f
'{s[0]}: {s[2]}' for s
in split_stashes
]
35 revids
= [s
[0] for s
in split_stashes
]
36 author_dates
= [s
[1] for s
in split_stashes
]
37 names
= [s
[2] for s
in split_stashes
]
39 return stashes
, revids
, author_dates
, names
41 def stash_diff(self
, rev
):
43 diffstat
= git
.stash('show', rev
)[STDOUT
]
44 diff
= git
.stash('show', '-p', '--no-ext-diff', rev
)[STDOUT
]
45 return diffstat
+ '\n\n' + diff
48 class ApplyStash(cmds
.ContextCommand
):
49 def __init__(self
, context
, stash_index
, index
, pop
):
50 super().__init
__(context
)
51 self
.stash_ref
= 'refs/' + stash_index
63 args
= [action
, '--index', ref
]
66 status
, out
, err
= self
.git
.stash(*args
)
68 Interaction
.log_status(status
, out
, err
)
71 cmdargs
= core
.list2cmdline(args
)
72 Interaction
.command_error(title
, 'git stash ' + cmdargs
, status
, out
, err
)
73 self
.model
.update_status()
76 class DropStash(cmds
.ContextCommand
):
77 def __init__(self
, context
, stash_index
):
78 super().__init
__(context
)
79 self
.stash_ref
= 'refs/' + stash_index
83 status
, out
, err
= git
.stash('drop', self
.stash_ref
)
85 Interaction
.log_status(status
, out
, err
)
86 match
= re
.search(r
'\((.*)\)', out
)
91 Interaction
.command_error(
92 title
, 'git stash drop ' + self
.stash_ref
, status
, out
, err
97 class SaveStash(cmds
.ContextCommand
):
98 def __init__(self
, context
, stash_name
, keep_index
):
99 super().__init
__(context
)
100 self
.stash_name
= stash_name
101 self
.keep_index
= keep_index
105 args
= ['push', '--keep-index', '-m', self
.stash_name
]
107 args
= ['push', '-m', self
.stash_name
]
108 status
, out
, err
= self
.git
.stash(*args
)
110 Interaction
.log_status(status
, out
, err
)
113 cmdargs
= core
.list2cmdline(args
)
114 Interaction
.command_error(title
, 'git stash ' + cmdargs
, status
, out
, err
)
116 self
.model
.update_status()
119 class RenameStash(cmds
.ContextCommand
):
120 """Rename the stash"""
122 def __init__(self
, context
, stash_index
, stash_name
):
123 super().__init
__(context
)
124 self
.context
= context
125 self
.stash_index
= stash_index
126 self
.stash_name
= stash_name
129 # Drop the stash first and get the returned ref
130 ref
= DropStash(self
.context
, self
.stash_index
).do()
131 # Store the stash with a new name
133 args
= ['store', '-m', self
.stash_name
, ref
]
134 status
, out
, err
= self
.git
.stash(*args
)
136 Interaction
.log_status(status
, out
, err
)
139 cmdargs
= core
.list2cmdline(args
)
140 Interaction
.command_error(
141 title
, 'git stash ' + cmdargs
, status
, out
, err
144 title
= N_('Error Renaming Stash')
145 msg
= N_('"git stash drop" did not return a ref to rename.')
146 Interaction
.critical(title
, message
=msg
)
148 self
.model
.update_status()
151 class StashIndex(cmds
.ContextCommand
):
152 """Stash the index away"""
154 def __init__(self
, context
, stash_name
):
155 super().__init
__(context
)
156 self
.stash_name
= stash_name
159 # Manually create a stash representing the index state
160 context
= self
.context
162 name
= self
.stash_name
163 branch
= gitcmds
.current_branch(context
)
164 head
= gitcmds
.rev_parse(context
, 'HEAD')
165 message
= f
'On {branch}: {name}'
167 # Get the message used for the "index" commit
168 status
, out
, err
= git
.rev_list('HEAD', '--', oneline
=True, n
=1)
170 stash_error('rev-list', status
, out
, err
)
172 head_msg
= out
.strip()
174 # Create a commit representing the index
175 status
, out
, err
= git
.write_tree()
177 stash_error('write-tree', status
, out
, err
)
179 index_tree
= out
.strip()
181 status
, out
, err
= git
.commit_tree(
182 '-m', f
'index on {branch}: {head_msg}', '-p', head
, index_tree
185 stash_error('commit-tree', status
, out
, err
)
187 index_commit
= out
.strip()
189 # Create a commit representing the worktree
190 status
, out
, err
= git
.commit_tree(
191 '-p', head
, '-p', index_commit
, '-m', message
, index_tree
194 stash_error('commit-tree', status
, out
, err
)
196 worktree_commit
= out
.strip()
198 # Record the stash entry
199 status
, out
, err
= git
.update_ref(
200 '-m', message
, 'refs/stash', worktree_commit
, create_reflog
=True
203 stash_error('update-ref', status
, out
, err
)
206 # Sync the worktree with the post-stash state. We've created the
207 # stash ref, so now we have to remove the staged changes from the
208 # worktree. We do this by applying a reverse diff of the staged
209 # changes. The diff from stash->HEAD is a reverse diff of the stash.
210 patch
= utils
.tmp_filename('stash')
211 with core
.xopen(patch
, mode
='wb') as patch_fd
:
212 status
, out
, err
= git
.diff_tree(
213 'refs/stash', 'HEAD', '--', binary
=True, _stdout
=patch_fd
216 stash_error('diff-tree', status
, out
, err
)
220 status
, out
, err
= git
.apply(patch
)
224 # Finally, clear the index we just stashed
227 stash_error('apply', status
, out
, err
)
229 self
.model
.update_status()
232 def stash_error(cmd
, status
, out
, err
):
233 title
= N_('Error creating stash')
234 Interaction
.command_error(title
, cmd
, status
, out
, err
)