123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- # stash.py
- # Copyright (C) 2018 Jelmer Vernooij <jelmer@samba.org>
- #
- # Dulwich is dual-licensed under the Apache License, Version 2.0 and the GNU
- # General Public License as public by the Free Software Foundation; version 2.0
- # or (at your option) any later version. You can redistribute it and/or
- # modify it under the terms of either of these two licenses.
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- #
- # You should have received a copy of the licenses; if not, see
- # <http://www.gnu.org/licenses/> for a copy of the GNU General Public License
- # and <http://www.apache.org/licenses/LICENSE-2.0> for a copy of the Apache
- # License, Version 2.0.
- #
- """Stash handling."""
- import os
- from .file import GitFile
- from .index import commit_tree, iter_fresh_objects
- from .reflog import drop_reflog_entry, read_reflog
- DEFAULT_STASH_REF = b"refs/stash"
- class Stash:
- """A Git stash.
- Note that this doesn't currently update the working tree.
- """
- def __init__(self, repo, ref=DEFAULT_STASH_REF) -> None:
- self._ref = ref
- self._repo = repo
- @property
- def _reflog_path(self):
- return os.path.join(self._repo.commondir(), "logs", os.fsdecode(self._ref))
- def stashes(self):
- try:
- with GitFile(self._reflog_path, "rb") as f:
- return reversed(list(read_reflog(f)))
- except FileNotFoundError:
- return []
- @classmethod
- def from_repo(cls, repo):
- """Create a new stash from a Repo object."""
- return cls(repo)
- def drop(self, index):
- """Drop entry with specified index."""
- with open(self._reflog_path, "rb+") as f:
- drop_reflog_entry(f, index, rewrite=True)
- if len(self) == 0:
- os.remove(self._reflog_path)
- del self._repo.refs[self._ref]
- return
- if index == 0:
- self._repo.refs[self._ref] = self[0].new_sha
- def pop(self, index):
- raise NotImplementedError(self.pop)
- def push(self, committer=None, author=None, message=None):
- """Create a new stash.
- Args:
- committer: Optional committer name to use
- author: Optional author name to use
- message: Optional commit message
- """
- # First, create the index commit.
- commit_kwargs = {}
- if committer is not None:
- commit_kwargs["committer"] = committer
- if author is not None:
- commit_kwargs["author"] = author
- index = self._repo.open_index()
- index_tree_id = index.commit(self._repo.object_store)
- index_commit_id = self._repo.do_commit(
- ref=None,
- tree=index_tree_id,
- message=b"Index stash",
- merge_heads=[self._repo.head()],
- no_verify=True,
- **commit_kwargs,
- )
- # Then, the working tree one.
- stash_tree_id = commit_tree(
- self._repo.object_store,
- iter_fresh_objects(
- index,
- os.fsencode(self._repo.path),
- object_store=self._repo.object_store,
- ),
- )
- if message is None:
- message = b"A stash on " + self._repo.head()
- # TODO(jelmer): Just pass parents into do_commit()?
- self._repo.refs[self._ref] = self._repo.head()
- cid = self._repo.do_commit(
- ref=self._ref,
- tree=stash_tree_id,
- message=message,
- merge_heads=[index_commit_id],
- no_verify=True,
- **commit_kwargs,
- )
- return cid
- def __getitem__(self, index):
- return list(self.stashes())[index]
- def __len__(self) -> int:
- return len(list(self.stashes()))
|