Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: gitpython-developers/GitPython
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 3.1.31
Choose a base ref
...
head repository: gitpython-developers/GitPython
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 3.1.32
Choose a head ref
  • 20 commits
  • 12 files changed
  • 7 contributors

Commits on Apr 10, 2023

  1. Bump cygwin/cygwin-install-action from 3 to 4

    Bumps [cygwin/cygwin-install-action](https://github.com/cygwin/cygwin-install-action) from 3 to 4.
    - [Release notes](https://github.com/cygwin/cygwin-install-action/releases)
    - [Commits](cygwin/cygwin-install-action@v3...v4)
    
    ---
    updated-dependencies:
    - dependency-name: cygwin/cygwin-install-action
      dependency-type: direct:production
      update-type: version-update:semver-major
    ...
    
    Signed-off-by: dependabot[bot] <support@github.com>
    dependabot[bot] authored Apr 10, 2023
    Copy the full SHA
    1570f3d View commit details
  2. Merge pull request #1572 from gitpython-developers/dependabot/github_…

    …actions/cygwin/cygwin-install-action-4
    
    Bump cygwin/cygwin-install-action from 3 to 4
    Byron authored Apr 10, 2023
    Copy the full SHA
    61ed7ec View commit details

Commits on Apr 21, 2023

  1. Add trailers_list and trailers_list methods to fix the commit trailer…

    …s functionality. Update trailers tests.
    itsluketwist committed Apr 21, 2023
    Copy the full SHA
    d2f7284 View commit details

Commits on Apr 22, 2023

  1. Copy the full SHA
    78424b5 View commit details
  2. Copy the full SHA
    abde3ea View commit details
  3. Copy the full SHA
    ed36bd9 View commit details

Commits on Apr 23, 2023

  1. Copy the full SHA
    9ef07a7 View commit details
  2. Merge pull request #1576 from itsluketwist/fix-trailers

    Fix up the commit trailers functionality
    Byron authored Apr 23, 2023
    Copy the full SHA
    e3bc5d1 View commit details

Commits on May 15, 2023

  1. Name top-level exceptions as private variables

    `exc` is private to the module. Naming it `_exc` eliminates a collision
    with the `exc` submodule (one which would not be observable at runtime
    due to the import failing, but which confuses linters).
    Hawk777 committed May 15, 2023
    Copy the full SHA
    2a0305b View commit details
  2. Merge pull request #1590 from Hawk777/init-exceptions

    Name top-level exceptions as private variables
    Byron authored May 15, 2023
    Copy the full SHA
    80ea0f5 View commit details

Commits on May 23, 2023

  1. Copy the full SHA
    6fc11e6 View commit details

Commits on Jul 5, 2023

  1. Copy the full SHA
    9cd7ddb View commit details
  2. Copy the full SHA
    0c543cd View commit details

Commits on Jul 6, 2023

  1. Merge pull request #1603 from eUgEntOptIc44/eugenoptic44-fix-pypi-lon…

    …g-description
    
    fix pypi long description
    Byron authored Jul 6, 2023
    Copy the full SHA
    741edb5 View commit details

Commits on Jul 7, 2023

  1. Don't rely on __del__

    r-darwish committed Jul 7, 2023
    Copy the full SHA
    8186159 View commit details
  2. fixes

    r-darwish committed Jul 7, 2023
    Copy the full SHA
    a3859ee View commit details
  3. Merge pull request #1606 from r-darwish/no-del

    Don't rely on __del__
    Byron authored Jul 7, 2023
    Copy the full SHA
    c09a71e View commit details

Commits on Jul 10, 2023

  1. Block insecure non-multi options in clone/clone_from

    Follow-up to #1521
    Beuc committed Jul 10, 2023
    Copy the full SHA
    5c59e0d View commit details
  2. Merge pull request #1609 from Beuc/block-insecure-options-clone-non-m…

    …ulti
    
    Block insecure non-multi options in clone/clone_from
    Byron authored Jul 10, 2023
    Copy the full SHA
    ca965ec View commit details
  3. prepare 3.1.32 release

    Byron committed Jul 10, 2023
    Copy the full SHA
    5d45ce2 View commit details
Showing with 202 additions and 107 deletions.
  1. +1 −1 .github/workflows/cygwin-test.yml
  2. +15 −18 README.md
  3. +1 −1 VERSION
  4. +6 −0 doc/source/changes.rst
  5. +4 −4 git/__init__.py
  6. +15 −20 git/index/base.py
  7. +13 −3 git/index/util.py
  8. +80 −22 git/objects/commit.py
  9. +2 −0 git/repo/base.py
  10. +1 −1 setup.py
  11. +41 −36 test/test_commit.py
  12. +23 −1 test/test_repo.py
2 changes: 1 addition & 1 deletion .github/workflows/cygwin-test.yml
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 9999
- uses: cygwin/cygwin-install-action@v3
- uses: cygwin/cygwin-install-action@v4
with:
packages: python39 python39-pip python39-virtualenv git
- name: Tell git to trust this repo
33 changes: 15 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -22,12 +22,8 @@ implementation of 'git' in [Rust](https://www.rust-lang.org).
GitPython is a python library used to interact with git repositories, high-level like git-porcelain,
or low-level like git-plumbing.

It provides abstractions of git objects for easy access of repository data, and additionally
allows you to access the git repository more directly using either a pure python implementation,
or the faster, but more resource intensive _git command_ implementation.

The object database implementation is optimized for handling large quantities of objects and large datasets,
which is achieved by using low-level structures and data streaming.
It provides abstractions of git objects for easy access of repository data often backed by calling the `git`
command-line program.

### DEVELOPMENT STATUS

@@ -41,8 +37,7 @@ The project is open to contributions of all kinds, as well as new maintainers.

### REQUIREMENTS

GitPython needs the `git` executable to be installed on the system and available
in your `PATH` for most operations.
GitPython needs the `git` executable to be installed on the system and available in your `PATH` for most operations.
If it is not in your `PATH`, you can help GitPython find it by setting
the `GIT_PYTHON_GIT_EXECUTABLE=<path/to/git>` environment variable.

@@ -56,17 +51,19 @@ The installer takes care of installing them for you.

If you have downloaded the source code:

python setup.py install
```bash
python setup.py install
```

or if you want to obtain a copy from the Pypi repository:

pip install GitPython
```bash
pip install GitPython
```

Both commands will install the required package dependencies.

A distribution package can be obtained for manual installation at:

http://pypi.python.org/pypi/GitPython
A distribution package can be obtained for manual installation at: <http://pypi.python.org/pypi/GitPython>.

If you like to clone from source, you can do it like so:

@@ -162,15 +159,15 @@ tarballs.
This script shows how to verify the tarball was indeed created by the authors of
this project:

```
```bash
curl https://files.pythonhosted.org/packages/09/bc/ae32e07e89cc25b9e5c793d19a1e5454d30a8e37d95040991160f942519e/GitPython-3.1.8-py3-none-any.whl > gitpython.whl
curl https://files.pythonhosted.org/packages/09/bc/ae32e07e89cc25b9e5c793d19a1e5454d30a8e37d95040991160f942519e/GitPython-3.1.8-py3-none-any.whl.asc > gitpython-signature.asc
gpg --verify gitpython-signature.asc gitpython.whl
```

which outputs

```
```bash
gpg: Signature made Fr 4 Sep 10:04:50 2020 CST
gpg: using RSA key 27C50E7F590947D7273A741E85194C08421980C9
gpg: Good signature from "Sebastian Thiel (YubiKey USB-C) <byronimo@gmail.com>" [ultimate]
@@ -180,19 +177,19 @@ gpg: aka "Sebastian Thiel (In Rust I trust) <sebastian.thiel@icl
You can verify that the keyid indeed matches the release-signature key provided in this
repository by looking at the keys details:

```
```bash
gpg --list-packets ./release-verification-key.asc
```

You can verify that the commit adding it was also signed by it using:

```
```bash
git show --show-signature ./release-verification-key.asc
```

If you would like to trust it permanently, you can import and sign it:

```
```bash
gpg --import ./release-verification-key.asc
gpg --edit-key 4C08421980C9

2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.1.31
3.1.32
6 changes: 6 additions & 0 deletions doc/source/changes.rst
Original file line number Diff line number Diff line change
@@ -2,6 +2,12 @@
Changelog
=========

3.1.32
======

See the following for all changes.
https://github.com/gitpython-developers/gitpython/milestone/62?closed=1

3.1.31
======

8 changes: 4 additions & 4 deletions git/__init__.py
Original file line number Diff line number Diff line change
@@ -56,8 +56,8 @@ def _init_externals() -> None:
Actor,
rmtree,
)
except GitError as exc:
raise ImportError("%s: %s" % (exc.__class__.__name__, exc)) from exc
except GitError as _exc:
raise ImportError("%s: %s" % (_exc.__class__.__name__, _exc)) from _exc

# } END imports

@@ -87,6 +87,6 @@ def refresh(path: Optional[PathLike] = None) -> None:
#################
try:
refresh()
except Exception as exc:
raise ImportError("Failed to initialize: {0}".format(exc)) from exc
except Exception as _exc:
raise ImportError("Failed to initialize: {0}".format(_exc)) from _exc
#################
35 changes: 15 additions & 20 deletions git/index/base.py
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
# This module is part of GitPython and is released under
# the BSD License: http://www.opensource.org/licenses/bsd-license.php

from contextlib import ExitStack
import datetime
import glob
from io import BytesIO
@@ -352,27 +353,22 @@ def from_tree(cls, repo: "Repo", *treeish: Treeish, **kwargs: Any) -> "IndexFile

# tmp file created in git home directory to be sure renaming
# works - /tmp/ dirs could be on another device
tmp_index = tempfile.mktemp("", "", repo.git_dir)
arg_list.append("--index-output=%s" % tmp_index)
arg_list.extend(treeish)

# move current index out of the way - otherwise the merge may fail
# as it considers existing entries. moving it essentially clears the index.
# Unfortunately there is no 'soft' way to do it.
# The TemporaryFileSwap assure the original file get put back
if repo.git_dir:
index_handler = TemporaryFileSwap(join_path_native(repo.git_dir, "index"))
try:
with ExitStack() as stack:
tmp_index = stack.enter_context(tempfile.NamedTemporaryFile(dir=repo.git_dir))
arg_list.append("--index-output=%s" % tmp_index.name)
arg_list.extend(treeish)

# move current index out of the way - otherwise the merge may fail
# as it considers existing entries. moving it essentially clears the index.
# Unfortunately there is no 'soft' way to do it.
# The TemporaryFileSwap assure the original file get put back

stack.enter_context(TemporaryFileSwap(join_path_native(repo.git_dir, "index")))
repo.git.read_tree(*arg_list, **kwargs)
index = cls(repo, tmp_index)
index = cls(repo, tmp_index.name)
index.entries # force it to read the file as we will delete the temp-file
del index_handler # release as soon as possible
finally:
if osp.exists(tmp_index):
os.remove(tmp_index)
# END index merge handling

return index
return index
# END index merge handling

# UTILITIES
@unbare_repo
@@ -1156,7 +1152,6 @@ def checkout(
unknown_lines = []

def handle_stderr(proc: "Popen[bytes]", iter_checked_out_files: Iterable[PathLike]) -> None:

stderr_IO = proc.stderr
if not stderr_IO:
return None # return early if stderr empty
16 changes: 13 additions & 3 deletions git/index/util.py
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@
import os
import struct
import tempfile
from types import TracebackType

from git.compat import is_win

@@ -11,7 +12,7 @@

# typing ----------------------------------------------------------------------

from typing import Any, Callable, TYPE_CHECKING
from typing import Any, Callable, TYPE_CHECKING, Optional, Type

from git.types import PathLike, _T

@@ -47,12 +48,21 @@ def __init__(self, file_path: PathLike) -> None:
except OSError:
pass

def __del__(self) -> None:
def __enter__(self) -> "TemporaryFileSwap":
return self

def __exit__(
self,
exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType],
) -> bool:
if osp.isfile(self.tmp_file_path):
if is_win and osp.exists(self.file_path):
os.remove(self.file_path)
os.rename(self.tmp_file_path, self.file_path)
# END temp file exists

return False


# { Decorators
102 changes: 80 additions & 22 deletions git/objects/commit.py
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@
import os
from io import BytesIO
import logging
from collections import defaultdict


# typing ------------------------------------------------------------------
@@ -335,8 +336,72 @@ def stats(self) -> Stats:
return Stats._list_from_string(self.repo, text)

@property
def trailers(self) -> Dict:
"""Get the trailers of the message as dictionary
def trailers(self) -> Dict[str, str]:
"""Get the trailers of the message as a dictionary
:note: This property is deprecated, please use either ``Commit.trailers_list`` or ``Commit.trailers_dict``.
:return:
Dictionary containing whitespace stripped trailer information.
Only contains the latest instance of each trailer key.
"""
return {
k: v[0] for k, v in self.trailers_dict.items()
}

@property
def trailers_list(self) -> List[Tuple[str, str]]:
"""Get the trailers of the message as a list
Git messages can contain trailer information that are similar to RFC 822
e-mail headers (see: https://git-scm.com/docs/git-interpret-trailers).
This functions calls ``git interpret-trailers --parse`` onto the message
to extract the trailer information, returns the raw trailer data as a list.
Valid message with trailer::
Subject line
some body information
another information
key1: value1.1
key1: value1.2
key2 : value 2 with inner spaces
Returned list will look like this::
[
("key1", "value1.1"),
("key1", "value1.2"),
("key2", "value 2 with inner spaces"),
]
:return:
List containing key-value tuples of whitespace stripped trailer information.
"""
cmd = ["git", "interpret-trailers", "--parse"]
proc: Git.AutoInterrupt = self.repo.git.execute(cmd, as_process=True, istream=PIPE) # type: ignore
trailer: str = proc.communicate(str(self.message).encode())[0].decode("utf8")
trailer = trailer.strip()

if not trailer:
return []

trailer_list = []
for t in trailer.split("\n"):
key, val = t.split(":", 1)
trailer_list.append((key.strip(), val.strip()))

return trailer_list

@property
def trailers_dict(self) -> Dict[str, List[str]]:
"""Get the trailers of the message as a dictionary
Git messages can contain trailer information that are similar to RFC 822
e-mail headers (see: https://git-scm.com/docs/git-interpret-trailers).
@@ -345,42 +410,35 @@ def trailers(self) -> Dict:
to extract the trailer information. The key value pairs are stripped of
leading and trailing whitespaces before they get saved into a dictionary.
Valid message with trailer:
.. code-block::
Valid message with trailer::
Subject line
some body information
another information
key1: value1
key1: value1.1
key1: value1.2
key2 : value 2 with inner spaces
dictionary will look like this:
.. code-block::
Returned dictionary will look like this::
{
"key1": "value1",
"key2": "value 2 with inner spaces"
"key1": ["value1.1", "value1.2"],
"key2": ["value 2 with inner spaces"],
}
:return: Dictionary containing whitespace stripped trailer information
:return:
Dictionary containing whitespace stripped trailer information.
Mapping trailer keys to a list of their corresponding values.
"""
d = {}
cmd = ["git", "interpret-trailers", "--parse"]
proc: Git.AutoInterrupt = self.repo.git.execute(cmd, as_process=True, istream=PIPE) # type: ignore
trailer: str = proc.communicate(str(self.message).encode())[0].decode()
if trailer.endswith("\n"):
trailer = trailer[0:-1]
if trailer != "":
for line in trailer.split("\n"):
key, value = line.split(":", 1)
d[key.strip()] = value.strip()
return d
d = defaultdict(list)
for key, val in self.trailers_list:
d[key].append(val)
return dict(d)

@classmethod
def _iter_from_process_or_stream(cls, repo: "Repo", proc_or_stream: Union[Popen, IO]) -> Iterator["Commit"]:
2 changes: 2 additions & 0 deletions git/repo/base.py
Original file line number Diff line number Diff line change
@@ -1203,6 +1203,8 @@ def _clone(

if not allow_unsafe_protocols:
Git.check_unsafe_protocols(str(url))
if not allow_unsafe_options:
Git.check_unsafe_options(options=list(kwargs.keys()), unsafe_options=cls.unsafe_git_clone_options)
if not allow_unsafe_options and multi_options:
Git.check_unsafe_options(options=multi_options, unsafe_options=cls.unsafe_git_clone_options)

2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -95,7 +95,7 @@ def build_py_modules(basedir: str, excludes: Sequence = ()) -> Sequence:
install_requires=requirements,
tests_require=requirements + test_requirements,
zip_safe=False,
long_description="""GitPython is a Python library used to interact with Git repositories""",
long_description=long_description,
long_description_content_type="text/markdown",
classifiers=[
# Picked from
Loading