-
-
Notifications
You must be signed in to change notification settings - Fork 969
Add trailer support for commit creation #2116
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -570,6 +570,7 @@ def create_from_tree( | |||||||||||||||||||||||||||
| committer: Union[None, Actor] = None, | ||||||||||||||||||||||||||||
| author_date: Union[None, str, datetime.datetime] = None, | ||||||||||||||||||||||||||||
| commit_date: Union[None, str, datetime.datetime] = None, | ||||||||||||||||||||||||||||
| trailers: Union[None, Dict[str, str], List[Tuple[str, str]]] = None, | ||||||||||||||||||||||||||||
| ) -> "Commit": | ||||||||||||||||||||||||||||
| """Commit the given tree, creating a :class:`Commit` object. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
|
|
@@ -609,6 +610,14 @@ def create_from_tree( | |||||||||||||||||||||||||||
| :param commit_date: | ||||||||||||||||||||||||||||
| The timestamp for the committer field. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| :param trailers: | ||||||||||||||||||||||||||||
| Optional trailer key-value pairs to append to the commit message. | ||||||||||||||||||||||||||||
| Can be a dictionary mapping trailer keys to values, or a list of | ||||||||||||||||||||||||||||
| ``(key, value)`` tuples (useful when the same key appears multiple | ||||||||||||||||||||||||||||
| times, e.g. multiple ``Signed-off-by`` trailers). Trailers are | ||||||||||||||||||||||||||||
| appended using ``git interpret-trailers``. | ||||||||||||||||||||||||||||
| See :manpage:`git-interpret-trailers(1)`. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| :return: | ||||||||||||||||||||||||||||
| :class:`Commit` object representing the new commit. | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
|
|
@@ -678,6 +687,29 @@ def create_from_tree( | |||||||||||||||||||||||||||
| tree = repo.tree(tree) | ||||||||||||||||||||||||||||
| # END tree conversion | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| # APPLY TRAILERS | ||||||||||||||||||||||||||||
| if trailers: | ||||||||||||||||||||||||||||
| trailer_args: List[str] = [] | ||||||||||||||||||||||||||||
| if isinstance(trailers, dict): | ||||||||||||||||||||||||||||
| for key, val in trailers.items(): | ||||||||||||||||||||||||||||
| trailer_args.append("--trailer") | ||||||||||||||||||||||||||||
| trailer_args.append(f"{key}: {val}") | ||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||
| for key, val in trailers: | ||||||||||||||||||||||||||||
| trailer_args.append("--trailer") | ||||||||||||||||||||||||||||
| trailer_args.append(f"{key}: {val}") | ||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||
| cmd = [repo.git.GIT_PYTHON_GIT_EXECUTABLE, "interpret-trailers"] + trailer_args | ||||||||||||||||||||||||||||
| proc: Git.AutoInterrupt = repo.git.execute( # type: ignore[call-overload] | ||||||||||||||||||||||||||||
| cmd, | ||||||||||||||||||||||||||||
| as_process=True, | ||||||||||||||||||||||||||||
| istream=PIPE, | ||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||
| stdout_bytes, _ = proc.communicate(str(message).encode()) | ||||||||||||||||||||||||||||
| finalize_process(proc) | ||||||||||||||||||||||||||||
|
Comment on lines
+707
to
+709
|
||||||||||||||||||||||||||||
| ) | |
| stdout_bytes, _ = proc.communicate(str(message).encode()) | |
| finalize_process(proc) | |
| stderr=PIPE, | |
| ) | |
| stdout_bytes, stderr_bytes = proc.communicate(str(message).encode()) | |
| finalize_process(proc) | |
| if proc.returncode: | |
| stderr = stderr_bytes.decode("utf8", errors="replace") if stderr_bytes else "" | |
| raise RuntimeError( | |
| "git interpret-trailers failed with exit code " | |
| f"{proc.returncode}: {stderr or 'no error output'}" | |
| ) |
Copilot
AI
Apr 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
interpret-trailers I/O is hard-coded to UTF-8 (.encode() default + .decode('utf8')), but this method already resolves conf_encoding for the commit’s declared encoding. If i18n.commitencoding is not UTF-8, this can raise decode errors or corrupt non-ASCII characters; use the resolved encoding for both encoding stdin and decoding stdout (and consider an explicit error strategy).
| stdout_bytes, _ = proc.communicate(str(message).encode()) | |
| finalize_process(proc) | |
| message = stdout_bytes.decode("utf8") | |
| stdout_bytes, _ = proc.communicate(str(message).encode(conf_encoding, errors="strict")) | |
| finalize_process(proc) | |
| message = stdout_bytes.decode(conf_encoding, errors="strict") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The command uses
repo.git.GIT_PYTHON_GIT_EXECUTABLEhere, butCommit.trailers_list/trailers_dictcurrently invokeinterpret-trailersvia a hard-coded['git', ...]. If a caller overridesGIT_PYTHON_GIT_EXECUTABLE, trailer creation and trailer parsing can end up using different Git binaries; consider aligning both paths on the same executable selection approach for consistent round-trips.