From: Mark H Weaver <mhw@netris.org>
To: guix-devel@gnu.org
Subject: Changes made to pysqlite-2.6.3 without changing the version number
Date: Thu, 06 Feb 2014 11:41:08 -0500 [thread overview]
Message-ID: <87ha8cw5wb.fsf@netris.org> (raw)
[-- Attachment #1: Type: text/plain, Size: 394 bytes --]
Hello all,
We don't have a working pysqlite-2.6.3 package in Guix right now. The
reason is that the upstream source tarball has changed without changing
the version number. For the record, I've attached the diff here.
I mailed the author about this, but he never replied. It would be good
if someone other than me would email him too, to ask him to change the
version number.
Mark
[-- Attachment #2: Changes between two copies of pysqlite-2.6.3.tar.gz --]
[-- Type: text/x-patch, Size: 21667 bytes --]
diff -ruN pysqlite-2.6.3-OLDER/doc/default.css pysqlite-2.6.3/doc/default.css
--- pysqlite-2.6.3-OLDER/doc/default.css 1969-12-31 19:00:00.000000000 -0500
+++ pysqlite-2.6.3/doc/default.css 2013-10-18 04:32:34.000000000 -0400
@@ -0,0 +1,10 @@
+@import url(docutils.css);
+@import url(silvercity.css);
+
+div.code-block{
+margin-left: 2em ;
+margin-right: 2em ;
+background-color: #eeeeee;
+font-family: "Courier New", Courier, monospace;
+font-size: 10pt;
+}
diff -ruN pysqlite-2.6.3-OLDER/doc/docutils.css pysqlite-2.6.3/doc/docutils.css
--- pysqlite-2.6.3-OLDER/doc/docutils.css 1969-12-31 19:00:00.000000000 -0500
+++ pysqlite-2.6.3/doc/docutils.css 2013-10-18 04:32:34.000000000 -0400
@@ -0,0 +1,260 @@
+/*
+:Author: David Goodger
+:Contact: goodger@users.sourceforge.net
+:Date: $Date: 2005-04-25 22:24:49 +0200 (Mon, 25 Apr 2005) $
+:Version: $Revision: 3256 $
+:Copyright: This stylesheet has been placed in the public domain.
+
+Default cascading style sheet for the HTML output of Docutils.
+*/
+
+/* "! important" is used here to override other ``margin-top`` and
+ ``margin-bottom`` styles that are later in the stylesheet or
+ more specific. See http://www.w3.org/TR/CSS1#the-cascade */
+.first {
+ margin-top: 0 ! important }
+
+.last {
+ margin-bottom: 0 ! important }
+
+.hidden {
+ display: none }
+
+a.toc-backref {
+ text-decoration: none ;
+ color: black }
+
+blockquote.epigraph {
+ margin: 2em 5em ; }
+
+dl.docutils dd {
+ margin-bottom: 0.5em }
+
+/* Uncomment (and remove this text!) to get bold-faced definition list terms
+dl.docutils dt {
+ font-weight: bold }
+*/
+
+div.abstract {
+ margin: 2em 5em }
+
+div.abstract p.topic-title {
+ font-weight: bold ;
+ text-align: center }
+
+div.admonition, div.attention, div.caution, div.danger, div.error,
+div.hint, div.important, div.note, div.tip, div.warning {
+ margin: 2em ;
+ border: medium outset ;
+ padding: 1em }
+
+div.admonition p.admonition-title, div.hint p.admonition-title,
+div.important p.admonition-title, div.note p.admonition-title,
+div.tip p.admonition-title {
+ font-weight: bold ;
+ font-family: sans-serif }
+
+div.attention p.admonition-title, div.caution p.admonition-title,
+div.danger p.admonition-title, div.error p.admonition-title,
+div.warning p.admonition-title {
+ color: red ;
+ font-weight: bold ;
+ font-family: sans-serif }
+
+/* Uncomment (and remove this text!) to get reduced vertical space in
+ compound paragraphs.
+div.compound .compound-first, div.compound .compound-middle {
+ margin-bottom: 0.5em }
+
+div.compound .compound-last, div.compound .compound-middle {
+ margin-top: 0.5em }
+*/
+
+div.dedication {
+ margin: 2em 5em ;
+ text-align: center ;
+ font-style: italic }
+
+div.dedication p.topic-title {
+ font-weight: bold ;
+ font-style: normal }
+
+div.figure {
+ margin-left: 2em }
+
+div.footer, div.header {
+ font-size: smaller }
+
+div.line-block {
+ display: block ;
+ margin-top: 1em ;
+ margin-bottom: 1em }
+
+div.line-block div.line-block {
+ margin-top: 0 ;
+ margin-bottom: 0 ;
+ margin-left: 1.5em }
+
+div.sidebar {
+ margin-left: 1em ;
+ border: medium outset ;
+ padding: 1em ;
+ background-color: #ffffee ;
+ width: 40% ;
+ float: right ;
+ clear: right }
+
+div.sidebar p.rubric {
+ font-family: sans-serif ;
+ font-size: medium }
+
+div.system-messages {
+ margin: 5em }
+
+div.system-messages h1 {
+ color: red }
+
+div.system-message {
+ border: medium outset ;
+ padding: 1em }
+
+div.system-message p.system-message-title {
+ color: red ;
+ font-weight: bold }
+
+div.topic {
+ margin: 2em }
+
+h1.title {
+ text-align: center }
+
+h2.subtitle {
+ text-align: center }
+
+hr.docutils {
+ width: 75% }
+
+ol.simple, ul.simple {
+ margin-bottom: 1em }
+
+ol.arabic {
+ list-style: decimal }
+
+ol.loweralpha {
+ list-style: lower-alpha }
+
+ol.upperalpha {
+ list-style: upper-alpha }
+
+ol.lowerroman {
+ list-style: lower-roman }
+
+ol.upperroman {
+ list-style: upper-roman }
+
+p.attribution {
+ text-align: right ;
+ margin-left: 50% }
+
+p.caption {
+ font-style: italic }
+
+p.credits {
+ font-style: italic ;
+ font-size: smaller }
+
+p.label {
+ white-space: nowrap }
+
+p.rubric {
+ font-weight: bold ;
+ font-size: larger ;
+ color: maroon ;
+ text-align: center }
+
+p.sidebar-title {
+ font-family: sans-serif ;
+ font-weight: bold ;
+ font-size: larger }
+
+p.sidebar-subtitle {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+p.topic-title {
+ font-weight: bold }
+
+pre.address {
+ margin-bottom: 0 ;
+ margin-top: 0 ;
+ font-family: serif ;
+ font-size: 100% }
+
+pre.line-block {
+ font-family: serif ;
+ font-size: 100% }
+
+pre.literal-block, pre.doctest-block {
+ margin-left: 2em ;
+ margin-right: 2em ;
+ background-color: #eeeeee }
+
+span.classifier {
+ font-family: sans-serif ;
+ font-style: oblique }
+
+span.classifier-delimiter {
+ font-family: sans-serif ;
+ font-weight: bold }
+
+span.interpreted {
+ font-family: sans-serif }
+
+span.option {
+ white-space: nowrap }
+
+span.pre {
+ white-space: pre }
+
+span.problematic {
+ color: red }
+
+table.citation {
+ border-left: solid thin gray }
+
+table.docinfo {
+ margin: 2em 4em }
+
+table.docutils {
+ margin-top: 0.5em ;
+ margin-bottom: 0.5em }
+
+table.footnote {
+ border-left: solid thin black }
+
+table.docutils td, table.docutils th,
+table.docinfo td, table.docinfo th {
+ padding-left: 0.5em ;
+ padding-right: 0.5em ;
+ vertical-align: top }
+
+table.docutils th.field-name, table.docinfo th.docinfo-name {
+ font-weight: bold ;
+ text-align: left ;
+ white-space: nowrap ;
+ padding-left: 0 }
+
+h1 tt.docutils, h2 tt.docutils, h3 tt.docutils,
+h4 tt.docutils, h5 tt.docutils, h6 tt.docutils {
+ font-size: 100% }
+
+tt.docutils {
+ background-color: #eeeeee }
+
+ul.auto-toc {
+ list-style-type: none }
+
+body {
+ background-color: #eeeeff;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+}
diff -ruN pysqlite-2.6.3-OLDER/lib/test/regression.py pysqlite-2.6.3/lib/test/regression.py
--- pysqlite-2.6.3-OLDER/lib/test/regression.py 2010-03-04 07:36:28.000000000 -0500
+++ pysqlite-2.6.3/lib/test/regression.py 2013-10-18 04:32:34.000000000 -0400
@@ -259,6 +259,29 @@
self.assertRaises(TypeError, con.set_authorizer, var)
self.assertRaises(TypeError, con.set_progress_handler, var)
+ def CheckRecursiveCursorUse(self):
+ """
+ http://bugs.python.org/issue10811
+
+ Recursively using a cursor, such as when reusing it from a generator led to segfaults.
+ Now we catch recursive cursor usage and raise a ProgrammingError.
+ """
+ con = sqlite.connect(":memory:")
+
+ cur = con.cursor()
+ cur.execute("create table a (bar)")
+ cur.execute("create table b (baz)")
+
+ def foo():
+ cur.execute("insert into a (bar) values (?)", (1,))
+ yield 1
+
+ try:
+ cur.executemany("insert into b (baz) values (?)", ((i,) for i in foo()))
+ self.fail("should have raised ProgrammingError")
+ except sqlite.ProgrammingError:
+ pass
+
def suite():
regression_suite = unittest.makeSuite(RegressionTests, "Check")
return unittest.TestSuite((regression_suite,))
diff -ruN pysqlite-2.6.3-OLDER/lib/test/types.py pysqlite-2.6.3/lib/test/types.py
--- pysqlite-2.6.3-OLDER/lib/test/types.py 2010-03-04 11:09:40.000000000 -0500
+++ pysqlite-2.6.3/lib/test/types.py 2013-10-28 05:55:04.000000000 -0400
@@ -102,6 +102,16 @@
finally:
self.con.text_factory = orig_text_factory
+ def CheckBinaryString(self):
+ bin_string = u"foo\x00bar"
+ self.cur.execute("select ?", (bin_string,))
+ self.assertEqual(self.cur.fetchone()[0], bin_string)
+
+ def CheckBinaryByteString(self):
+ bin_string = "bla\x00bla"
+ self.cur.execute("select ?", (bin_string,))
+ self.assertEqual(self.cur.fetchone()[0], bin_string)
+
class DeclTypesTests(unittest.TestCase):
class Foo:
def __init__(self, _val):
@@ -137,6 +147,7 @@
sqlite.converters["FOO"] = DeclTypesTests.Foo
sqlite.converters["WRONG"] = lambda x: "WRONG"
sqlite.converters["NUMBER"] = float
+ sqlite.converters["TEXT"] = str
def tearDown(self):
del sqlite.converters["FLOAT"]
@@ -153,6 +164,19 @@
row = self.cur.fetchone()
self.assertEqual(row[0], "foo")
+ def CheckTextEmptyString(self):
+ """
+ Make sure that empty strings are converted to empty strings and not to None.
+ """
+ self.cur.execute("insert into test(s) values (?)", ("",))
+ self.cur.execute("insert into test(s) values (?)", (None,))
+ self.cur.execute('select s as "s [TEXT]" from test')
+ row = self.cur.fetchone()
+ self.assertEqual(row[0], "")
+ row = self.cur.fetchone()
+ self.assertEqual(row[0], None)
+
+
def CheckSmallInt(self):
# default
self.cur.execute("insert into test(i) values (?)", (42,))
diff -ruN pysqlite-2.6.3-OLDER/LICENSE pysqlite-2.6.3/LICENSE
--- pysqlite-2.6.3-OLDER/LICENSE 2009-10-19 05:19:27.000000000 -0400
+++ pysqlite-2.6.3/LICENSE 2013-10-18 04:32:34.000000000 -0400
@@ -1,4 +1,4 @@
-Copyright (c) 2004-2007 Gerhard Häring
+Copyright (c) 2004-2013 Gerhard Häring
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
diff -ruN pysqlite-2.6.3-OLDER/PKG-INFO pysqlite-2.6.3/PKG-INFO
--- pysqlite-2.6.3-OLDER/PKG-INFO 2011-02-16 06:10:37.000000000 -0500
+++ pysqlite-2.6.3/PKG-INFO 2013-10-28 05:56:05.000000000 -0400
@@ -1,12 +1,11 @@
-Metadata-Version: 1.0
+Metadata-Version: 1.1
Name: pysqlite
Version: 2.6.3
Summary: DB-API 2.0 interface for SQLite 3.x
-Home-page: http://pysqlite.googlecode.com/
+Home-page: http://github.com/ghaering/pysqlite
Author: Gerhard Haering
Author-email: gh@ghaering.de
License: zlib/libpng license
-Download-URL: http://code.google.com/p/pysqlite/downloads/list
Description: Python interface to SQLite 3
pysqlite is an interface to the SQLite 3.x embedded relational database engine.
diff -ruN pysqlite-2.6.3-OLDER/setup.py pysqlite-2.6.3/setup.py
--- pysqlite-2.6.3-OLDER/setup.py 2011-02-16 06:08:57.000000000 -0500
+++ pysqlite-2.6.3/setup.py 2013-10-28 05:55:54.000000000 -0400
@@ -1,7 +1,7 @@
#-*- coding: ISO-8859-1 -*-
# setup.py: the distutils script
#
-# Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de>
+# Copyright (C) 2004-2013 Gerhard Häring <gh@ghaering.de>
#
# This file is part of pysqlite.
#
@@ -84,35 +84,6 @@
if rc != 0:
print "Is sphinx installed? If not, try 'sudo easy_install sphinx'."
-AMALGAMATION_ROOT = "amalgamation"
-
-def get_amalgamation():
- """Download the SQLite amalgamation if it isn't there, already."""
- if os.path.exists(AMALGAMATION_ROOT):
- return
- os.mkdir(AMALGAMATION_ROOT)
- print "Downloading amalgation."
-
- # find out what's current amalgamation ZIP file
- download_page = urllib.urlopen("http://sqlite.org/download.html").read()
- pattern = re.compile("(sqlite-amalgamation.*?\.zip)")
- download_file = pattern.findall(download_page)[0]
- amalgamation_url = "http://sqlite.org/" + download_file
-
- # and download it
- urllib.urlretrieve(amalgamation_url, "tmp.zip")
-
- zf = zipfile.ZipFile("tmp.zip")
- files = ["sqlite3.c", "sqlite3.h"]
- directory = zf.namelist()[0]
- for fn in files:
- print "Extracting", fn
- outf = open(AMALGAMATION_ROOT + os.sep + fn, "wb")
- outf.write(zf.read(directory + fn))
- outf.close()
- zf.close()
- os.unlink("tmp.zip")
-
class AmalgamationBuilder(build):
description = "Build a statically built pysqlite using the amalgamtion."
@@ -125,11 +96,9 @@
def build_extension(self, ext):
if self.amalgamation:
- get_amalgamation()
ext.define_macros.append(("SQLITE_ENABLE_FTS3", "1")) # build with fulltext search enabled
ext.define_macros.append(("SQLITE_ENABLE_RTREE", "1")) # build with fulltext search enabled
- ext.sources.append(os.path.join(AMALGAMATION_ROOT, "sqlite3.c"))
- ext.include_dirs.append(AMALGAMATION_ROOT)
+ ext.sources.append("sqlite3.c")
build_ext.build_extension(self, ext)
def __setattr__(self, k, v):
@@ -173,8 +142,7 @@
author_email = "gh@ghaering.de",
license = "zlib/libpng license",
platforms = "ALL",
- url = "http://pysqlite.googlecode.com/",
- download_url = "http://code.google.com/p/pysqlite/downloads/list",
+ url = "http://github.com/ghaering/pysqlite",
# Description of the modules and packages in the distribution
package_dir = {"pysqlite2": "lib"},
diff -ruN pysqlite-2.6.3-OLDER/src/cursor.c pysqlite-2.6.3/src/cursor.c
--- pysqlite-2.6.3-OLDER/src/cursor.c 2010-03-04 07:55:00.000000000 -0500
+++ pysqlite-2.6.3/src/cursor.c 2013-10-28 05:55:04.000000000 -0400
@@ -268,29 +268,26 @@
}
}
-PyObject* pysqlite_unicode_from_string(const char* val_str, int optimize)
+static PyObject* pysqlite_unicode_from_string(const char* val_str, Py_ssize_t nbytes, int optimize)
{
- const char* check;
int is_ascii = 0;
+ int i;
if (optimize) {
is_ascii = 1;
- check = val_str;
- while (*check) {
- if (*check & 0x80) {
+ for (i = 0; i < nbytes; i++) {
+ if (val_str[i] & 0x80) {
is_ascii = 0;
break;
}
-
- check++;
}
}
if (is_ascii) {
- return PyString_FromString(val_str);
+ return PyString_FromStringAndSize(val_str, nbytes);
} else {
- return PyUnicode_DecodeUTF8(val_str, strlen(val_str), NULL);
+ return PyUnicode_DecodeUTF8(val_str, nbytes, NULL);
}
}
@@ -331,6 +328,8 @@
}
for (i = 0; i < numcols; i++) {
+ nbytes = sqlite3_column_bytes(self->statement->st, i);
+
if (self->connection->detect_types) {
converter = PyList_GetItem(self->row_cast_map, i);
if (!converter) {
@@ -341,20 +340,24 @@
}
if (converter != Py_None) {
- nbytes = sqlite3_column_bytes(self->statement->st, i);
- val_str = (const char*)sqlite3_column_blob(self->statement->st, i);
- if (!val_str) {
+ if (sqlite3_column_type(self->statement->st, i) == SQLITE_NULL) {
Py_INCREF(Py_None);
converted = Py_None;
} else {
- item = PyString_FromStringAndSize(val_str, nbytes);
- if (!item) {
- return NULL;
- }
- converted = PyObject_CallFunction(converter, "O", item);
- Py_DECREF(item);
- if (!converted) {
- break;
+ val_str = (const char*)sqlite3_column_blob(self->statement->st, i);
+ if (!val_str) {
+ Py_INCREF(Py_None);
+ converted = Py_None;
+ } else {
+ item = PyString_FromStringAndSize(val_str, nbytes);
+ if (!item) {
+ return NULL;
+ }
+ converted = PyObject_CallFunction(converter, "O", item);
+ Py_DECREF(item);
+ if (!converted) {
+ break;
+ }
}
}
} else {
@@ -378,7 +381,7 @@
if ((self->connection->text_factory == (PyObject*)&PyUnicode_Type)
|| (self->connection->text_factory == pysqlite_OptimizedUnicode)) {
- converted = pysqlite_unicode_from_string(val_str,
+ converted = pysqlite_unicode_from_string(val_str, nbytes,
self->connection->text_factory == pysqlite_OptimizedUnicode ? 1 : 0);
if (!converted) {
@@ -391,7 +394,7 @@
PyErr_SetString(pysqlite_OperationalError, buf);
}
} else if (self->connection->text_factory == (PyObject*)&PyString_Type) {
- converted = PyString_FromString(val_str);
+ converted = PyString_FromStringAndSize(val_str, nbytes);
} else {
converted = PyObject_CallFunction(self->connection->text_factory, "s", val_str);
}
@@ -441,9 +444,14 @@
if (cur->closed) {
PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed cursor.");
return 0;
- } else {
- return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection);
}
+
+ if (cur->locked) {
+ PyErr_SetString(pysqlite_ProgrammingError, "Recursive use of cursors not allowed.");
+ return 0;
+ }
+
+ return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection);
}
PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args)
@@ -466,9 +474,10 @@
int allow_8bit_chars;
if (!check_cursor(self)) {
- return NULL;
+ goto error;
}
+ self->locked = 1;
self->reset = 0;
/* Make shooting yourself in the foot with not utf-8 decodable 8-bit-strings harder */
@@ -481,12 +490,12 @@
if (multiple) {
/* executemany() */
if (!PyArg_ParseTuple(args, "OO", &operation, &second_argument)) {
- return NULL;
+ goto error;
}
if (!PyString_Check(operation) && !PyUnicode_Check(operation)) {
PyErr_SetString(PyExc_ValueError, "operation parameter must be str or unicode");
- return NULL;
+ goto error;
}
if (PyIter_Check(second_argument)) {
@@ -497,23 +506,23 @@
/* sequence */
parameters_iter = PyObject_GetIter(second_argument);
if (!parameters_iter) {
- return NULL;
+ goto error;
}
}
} else {
/* execute() */
if (!PyArg_ParseTuple(args, "O|O", &operation, &second_argument)) {
- return NULL;
+ goto error;
}
if (!PyString_Check(operation) && !PyUnicode_Check(operation)) {
PyErr_SetString(PyExc_ValueError, "operation parameter must be str or unicode");
- return NULL;
+ goto error;
}
parameters_list = PyList_New(0);
if (!parameters_list) {
- return NULL;
+ goto error;
}
if (second_argument == NULL) {
@@ -759,7 +768,8 @@
* ROLLBACK could have happened */
#ifdef SQLITE_VERSION_NUMBER
#if SQLITE_VERSION_NUMBER >= 3002002
- self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db);
+ if (self->connection && self->connection->db)
+ self->connection->inTransaction = !sqlite3_get_autocommit(self->connection->db);
#endif
#endif
@@ -768,6 +778,8 @@
Py_XDECREF(parameters_iter);
Py_XDECREF(parameters_list);
+ self->locked = 0;
+
if (PyErr_Occurred()) {
self->rowcount = -1L;
return NULL;
diff -ruN pysqlite-2.6.3-OLDER/src/cursor.h pysqlite-2.6.3/src/cursor.h
--- pysqlite-2.6.3-OLDER/src/cursor.h 2010-03-04 07:59:39.000000000 -0500
+++ pysqlite-2.6.3/src/cursor.h 2013-10-18 04:32:34.000000000 -0400
@@ -42,6 +42,7 @@
pysqlite_Statement* statement;
int closed;
int reset;
+ int locked;
int initialized;
/* the next row to be returned, NULL if no next row available */
diff -ruN pysqlite-2.6.3-OLDER/src/statement.c pysqlite-2.6.3/src/statement.c
--- pysqlite-2.6.3-OLDER/src/statement.c 2010-03-04 09:56:48.000000000 -0500
+++ pysqlite-2.6.3/src/statement.c 2013-10-18 04:32:34.000000000 -0400
@@ -167,12 +167,14 @@
break;
case TYPE_STRING:
string = PyString_AS_STRING(parameter);
- rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
+ buflen = PyString_Size(parameter);
+ rc = sqlite3_bind_text(self->st, pos, string, buflen, SQLITE_TRANSIENT);
break;
case TYPE_UNICODE:
stringval = PyUnicode_AsUTF8String(parameter);
string = PyString_AsString(stringval);
- rc = sqlite3_bind_text(self->st, pos, string, -1, SQLITE_TRANSIENT);
+ buflen = PyString_Size(stringval);
+ rc = sqlite3_bind_text(self->st, pos, string, buflen, SQLITE_TRANSIENT);
Py_DECREF(stringval);
break;
case TYPE_BUFFER:
next reply other threads:[~2014-02-06 16:42 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-02-06 16:41 Mark H Weaver [this message]
2014-02-07 23:19 ` Changes made to pysqlite-2.6.3 without changing the version number Ludovic Courtès
2014-02-08 10:44 ` Andreas Enge
2014-02-08 16:58 ` Ludovic Courtès
2014-02-09 21:09 ` Andreas Enge
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87ha8cw5wb.fsf@netris.org \
--to=mhw@netris.org \
--cc=guix-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/guix.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.