From: Nikita Karetnikov <nikita@karetnikov.org>
To: "Ludovic Courtès" <ludo@gnu.org>
Cc: guix-devel@gnu.org
Subject: Re: [PATCH] guix package: Add '--delete-generations'.
Date: Thu, 26 Sep 2013 06:47:23 +0400 [thread overview]
Message-ID: <87vc1oi9j8.fsf@karetnikov.org> (raw)
In-Reply-To: <87fvstm4q8.fsf@gnu.org> ("Ludovic Courtès"'s message of "Wed, 25 Sep 2013 15:05:19 +0200")
[-- Attachment #1.1: Type: text/plain, Size: 186 bytes --]
> Frankly, I don’t like it. I think the default behavior should not be to
> let the user shoot themself in the foot.
> WDYT?
OK, what about these patches? Can I push them?
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: 0002-guix-package-Add-link-to-empty-profile.patch --]
[-- Type: text/x-diff, Size: 2145 bytes --]
From 86d29a8b233d5cf6549fbcddf43b185086b7d178 Mon Sep 17 00:00:00 2001
From: Nikita Karetnikov <nikita@karetnikov.org>
Date: Wed, 25 Sep 2013 03:34:49 +0000
Subject: [PATCH 2/3] guix package: Add 'link-to-empty-profile'.
* guix/scripts/package.scm (link-to-empty-profile): New function.
(roll-back): Use it.
---
guix/scripts/package.scm | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index ed1e72c..7865027 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -214,6 +214,15 @@ all of PACKAGES, a list of name/version/output/path/deps tuples."
(compose string->number (cut match:substring <> 1)))
0))
+(define (link-to-empty-profile generation)
+ "Link GENERATION, a string, to the empty profile."
+ (let* ((drv (profile-derivation (%store) '()))
+ (prof (derivation->output-path drv "out")))
+ (when (not (build-derivations (%store) (list drv)))
+ (leave (_ "failed to build the empty profile~%")))
+
+ (switch-symlinks generation prof)))
+
(define (roll-back profile)
"Roll back to the previous generation of PROFILE."
(let* ((number (generation-number profile))
@@ -236,13 +245,8 @@ all of PACKAGES, a list of name/version/output/path/deps tuples."
(_ "nothing to do: already at the empty profile~%")))
((or (zero? previous-number) ; going to emptiness
(not (file-exists? previous-generation)))
- (let* ((drv (profile-derivation (%store) '()))
- (prof (derivation->output-path drv "out")))
- (when (not (build-derivations (%store) (list drv)))
- (leave (_ "failed to build the empty profile~%")))
-
- (switch-symlinks previous-generation prof)
- (switch-link)))
+ (link-to-empty-profile previous-generation)
+ (switch-link))
(else (switch-link))))) ; anything else
(define (generation-time profile number)
--
1.7.9.5
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.3: 0003-guix-package-Add-delete-generations.patch --]
[-- Type: text/x-diff, Size: 19187 bytes --]
From c246f4a72ade85dffa95d7c598e24539896ca5a5 Mon Sep 17 00:00:00 2001
From: Nikita Karetnikov <nikita@karetnikov.org>
Date: Thu, 26 Sep 2013 02:36:24 +0000
Subject: [PATCH 3/3] guix package: Add '--delete-generations'.
* guix/scripts/package.scm (switch-to-previous-generation): New function.
(roll-back): Use the new function instead of 'switch-link'.
(show-help): Add '--delete-generations'.
(%options): Likewise.
(guix-package)[process-actions]: Add 'current-generation-number',
'display-and-delete', and 'delete-generation'. Add support for
'--delete-generations', and reindent the code.
* tests/guix-package.sh: Test '--delete-generations'.
* doc/guix.texi (Invoking guix-package): Document '--delete-generations'.
---
doc/guix.texi | 10 ++
guix/scripts/package.scm | 256 +++++++++++++++++++++++++++++-----------------
tests/guix-package.sh | 11 ++
3 files changed, 185 insertions(+), 92 deletions(-)
diff --git a/doc/guix.texi b/doc/guix.texi
index 442cef2..2e6bdc5 100644
--- a/doc/guix.texi
+++ b/doc/guix.texi
@@ -714,6 +714,16 @@ or months by passing an integer along with the first letter of the
duration, e.g., @code{--list-generations=20d}.
@end itemize
+@item --delete-generations[=@var{pattern}]
+@itemx -d [@var{pattern}]
+Delete all generations except the current one. Note that the zeroth
+generation is never deleted.
+
+This command accepts the same patterns as @option{--list-generations}.
+When @var{pattern} is specified, delete the matching generations. If
+the current generation matches, it is deleted atomically, i.e., by
+switching to the previous available generation.
+
@end table
@node Packages with Multiple Outputs
diff --git a/guix/scripts/package.scm b/guix/scripts/package.scm
index 7865027..35a5129 100644
--- a/guix/scripts/package.scm
+++ b/guix/scripts/package.scm
@@ -223,6 +223,16 @@ all of PACKAGES, a list of name/version/output/path/deps tuples."
(switch-symlinks generation prof)))
+(define (switch-to-previous-generation profile)
+ "Atomically switch PROFILE to the previous generation."
+ (let* ((number (generation-number profile))
+ (previous-number (previous-generation-number profile number))
+ (previous-generation (format #f "~a-~a-link"
+ profile previous-number)))
+ (format #t (_ "switching from generation ~a to ~a~%")
+ number previous-number)
+ (switch-symlinks profile previous-generation)))
+
(define (roll-back profile)
"Roll back to the previous generation of PROFILE."
(let* ((number (generation-number profile))
@@ -230,24 +240,18 @@ all of PACKAGES, a list of name/version/output/path/deps tuples."
(previous-generation (format #f "~a-~a-link"
profile previous-number))
(manifest (string-append previous-generation "/manifest")))
-
- (define (switch-link)
- ;; Atomically switch PROFILE to the previous generation.
- (format #t (_ "switching from generation ~a to ~a~%")
- number previous-number)
- (switch-symlinks profile previous-generation))
-
- (cond ((not (file-exists? profile)) ; invalid profile
- (leave (_ "profile `~a' does not exist~%")
+ (cond ((not (file-exists? profile)) ; invalid profile
+ (leave (_ "profile '~a' does not exist~%")
profile))
- ((zero? number) ; empty profile
+ ((zero? number) ; empty profile
(format (current-error-port)
(_ "nothing to do: already at the empty profile~%")))
- ((or (zero? previous-number) ; going to emptiness
+ ((or (zero? previous-number) ; going to emptiness
(not (file-exists? previous-generation)))
(link-to-empty-profile previous-generation)
- (switch-link))
- (else (switch-link))))) ; anything else
+ (switch-to-previous-generation profile))
+ (else
+ (switch-to-previous-generation profile))))) ; anything else
(define (generation-time profile number)
"Return the creation time of a generation in the UTC format."
@@ -515,6 +519,9 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n"))
(display (_ "
-l, --list-generations[=PATTERN]
list generations matching PATTERN"))
+ (display (_ "
+ -d, --delete-generations[=PATTERN]
+ delete generations matching PATTERN"))
(newline)
(display (_ "
-p, --profile=PROFILE use PROFILE instead of the user's default profile"))
@@ -578,6 +585,10 @@ Install, remove, or upgrade PACKAGES in a single transaction.\n"))
(lambda (opt name arg result)
(cons `(query list-generations ,(or arg ""))
result)))
+ (option '(#\d "delete-generations") #f #t
+ (lambda (opt name arg result)
+ (alist-cons 'delete-generations (or arg "")
+ result)))
(option '("search-paths") #f #f
(lambda (opt name arg result)
(cons `(query search-paths) result)))
@@ -828,85 +839,146 @@ more information.~%"))
install))))
(_ #f)))
+ (define current-generation-number
+ (generation-number profile))
+
+ (define (display-and-delete number)
+ (let ((generation (format #f "~a-~a-link" profile number)))
+ (unless (zero? number)
+ (format #t (_ "deleting ~a~%") generation)
+ (delete-file generation))))
+
+ (define (delete-generation number)
+ (let* ((previous-number (previous-generation-number profile number))
+ (previous-generation (format #f "~a-~a-link"
+ profile previous-number)))
+ (cond ((zero? number)) ; do not delete generation 0
+ ((and (= number current-generation-number)
+ (not (file-exists? previous-generation)))
+ (link-to-empty-profile previous-generation)
+ (switch-to-previous-generation profile)
+ (display-and-delete number))
+ ((= number current-generation-number)
+ (roll-back profile)
+ (display-and-delete number))
+ (else
+ (display-and-delete number)))))
+
;; First roll back if asked to.
- (if (and (assoc-ref opts 'roll-back?) (not dry-run?))
- (begin
- (roll-back profile)
- (process-actions (alist-delete 'roll-back? opts)))
- (let* ((installed (manifest-packages (profile-manifest profile)))
- (upgrade-regexps (filter-map (match-lambda
- (('upgrade . regexp)
- (make-regexp (or regexp "")))
- (_ #f))
- opts))
- (upgrade (if (null? upgrade-regexps)
- '()
- (let ((newest (find-newest-available-packages)))
- (filter-map (match-lambda
- ((name version output path _)
- (and (any (cut regexp-exec <> name)
- upgrade-regexps)
- (upgradeable? name version path)
- (find-package name
- (or output "out"))))
- (_ #f))
- installed))))
- (install (append
- upgrade
- (filter-map (match-lambda
- (('install . (? package? p))
- (package->tuple p))
- (('install . (? store-path?))
- #f)
- (('install . package)
- (find-package package))
- (_ #f))
- opts)))
- (drv (filter-map (match-lambda
- ((name version sub-drv
- (? package? package)
- (deps ...))
- (check-package-freshness package)
- (package-derivation (%store) package))
- (_ #f))
- install))
- (install* (append
- (filter-map (match-lambda
- (('install . (? package? p))
- #f)
- (('install . (? store-path? path))
- (let-values (((name version)
- (package-name->name+version
- (store-path-package-name
- path))))
- `(,name ,version #f ,path ())))
- (_ #f))
- opts)
- (map (lambda (tuple drv)
- (match tuple
- ((name version sub-drv _ (deps ...))
- (let ((output-path
- (derivation->output-path
- drv sub-drv)))
- `(,name ,version ,sub-drv ,output-path
- ,(canonicalize-deps deps))))))
- install drv)))
- (remove (filter-map (match-lambda
- (('remove . package)
- package)
- (_ #f))
- opts))
- (remove* (filter-map (cut assoc <> installed) remove))
- (packages (append install*
- (fold (lambda (package result)
- (match package
- ((name _ out _ ...)
- (filter (negate
- (cut same-package? <>
- name out))
- result))))
- (fold alist-delete installed remove)
- install*))))
+ (cond ((and (assoc-ref opts 'roll-back?) (not dry-run?))
+ (begin
+ (roll-back profile)
+ (process-actions (alist-delete 'roll-back? opts))))
+ ((and (assoc-ref opts 'delete-generations)
+ (not dry-run?))
+ (filter-map
+ (match-lambda
+ (('delete-generations . pattern)
+ (cond ((not (file-exists? profile)) ; XXX: race condition
+ (leave (_ "profile '~a' does not exist~%")
+ profile))
+ ((string-null? pattern)
+ (let ((numbers (generation-numbers profile)))
+ (if (equal? numbers '(0))
+ (exit 0)
+ (for-each display-and-delete
+ (delete current-generation-number
+ numbers)))))
+ ;; Do not delete the zeroth generation.
+ ((equal? 0 (string->number pattern))
+ (exit 0))
+ ((matching-generations pattern profile)
+ =>
+ (lambda (numbers)
+ (if (null-list? numbers)
+ (exit 1)
+ (for-each delete-generation numbers))))
+ (else
+ (leave (_ "invalid syntax: ~a~%")
+ pattern)))
+
+ (process-actions
+ (alist-delete 'delete-generations opts)))
+ (_ #f))
+ opts))
+ (else
+ (let* ((installed (manifest-packages (profile-manifest profile)))
+ (upgrade-regexps (filter-map (match-lambda
+ (('upgrade . regexp)
+ (make-regexp (or regexp "")))
+ (_ #f))
+ opts))
+ (upgrade (if (null? upgrade-regexps)
+ '()
+ (let ((newest (find-newest-available-packages)))
+ (filter-map
+ (match-lambda
+ ((name version output path _)
+ (and (any (cut regexp-exec <> name)
+ upgrade-regexps)
+ (upgradeable? name version path)
+ (find-package name
+ (or output "out"))))
+ (_ #f))
+ installed))))
+ (install (append
+ upgrade
+ (filter-map (match-lambda
+ (('install . (? package? p))
+ (package->tuple p))
+ (('install . (? store-path?))
+ #f)
+ (('install . package)
+ (find-package package))
+ (_ #f))
+ opts)))
+ (drv (filter-map (match-lambda
+ ((name version sub-drv
+ (? package? package)
+ (deps ...))
+ (check-package-freshness package)
+ (package-derivation (%store) package))
+ (_ #f))
+ install))
+ (install*
+ (append
+ (filter-map (match-lambda
+ (('install . (? package? p))
+ #f)
+ (('install . (? store-path? path))
+ (let-values (((name version)
+ (package-name->name+version
+ (store-path-package-name
+ path))))
+ `(,name ,version #f ,path ())))
+ (_ #f))
+ opts)
+ (map (lambda (tuple drv)
+ (match tuple
+ ((name version sub-drv _ (deps ...))
+ (let ((output-path
+ (derivation->output-path
+ drv sub-drv)))
+ `(,name ,version ,sub-drv ,output-path
+ ,(canonicalize-deps deps))))))
+ install drv)))
+ (remove (filter-map (match-lambda
+ (('remove . package)
+ package)
+ (_ #f))
+ opts))
+ (remove* (filter-map (cut assoc <> installed) remove))
+ (packages
+ (append install*
+ (fold (lambda (package result)
+ (match package
+ ((name _ out _ ...)
+ (filter (negate
+ (cut same-package? <>
+ name out))
+ result))))
+ (fold alist-delete installed remove)
+ install*))))
(when (equal? profile %current-profile)
(ensure-default-profile))
@@ -950,7 +1022,7 @@ more information.~%"))
count)
count)
(display-search-paths packages
- profile))))))))))
+ profile)))))))))))
(define (process-query opts)
;; Process any query specified by OPTS. Return #t when a query was
diff --git a/tests/guix-package.sh b/tests/guix-package.sh
index 5f97aff..fc1c072 100644
--- a/tests/guix-package.sh
+++ b/tests/guix-package.sh
@@ -142,6 +142,17 @@ then
# Make sure LIBRARY_PATH gets listed by `--search-paths'.
guix package --bootstrap -p "$profile" -i guile-bootstrap -i gcc-bootstrap
guix package --search-paths -p "$profile" | grep LIBRARY_PATH
+
+ # Delete the third generation and check that it was actually deleted.
+ guix package -p "$profile" --delete-generations=3
+ test -z "`guix package -p "$profile" -l 3`"
+
+ # Exit with 1 when a generation does not exist.
+ if guix package -p "$profile" --delete-generations=42;
+ then false; else true; fi
+
+ # Exit with 0 when trying to delete the zeroth generation.
+ guix package -p "$profile" --delete-generations=0
fi
# Make sure the `:' syntax works.
--
1.7.9.5
[-- Attachment #2: Type: application/pgp-signature, Size: 835 bytes --]
next prev parent reply other threads:[~2013-09-26 2:42 UTC|newest]
Thread overview: 132+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-08-29 12:34 Goals for 0.4 Ludovic Courtès
2013-08-29 13:16 ` Nikita Karetnikov
2013-08-29 13:36 ` Ludovic Courtès
2013-08-30 17:55 ` Nikita Karetnikov
2013-08-30 18:31 ` Ludovic Courtès
2013-08-31 16:40 ` Nikita Karetnikov
2013-08-31 18:05 ` Ludovic Courtès
2013-08-31 20:34 ` Jose E. Marchesi
2013-08-31 21:07 ` Ludovic Courtès
2013-09-01 23:16 ` New ‘--list-generations’ and ‘--delete-generations’ options (was: Goals for 0.4) Nikita Karetnikov
2013-09-02 9:08 ` New ‘--list-generations’ and ‘--delete-generations’ options Ludovic Courtès
2013-09-05 1:30 ` Nikita Karetnikov
2013-09-05 20:00 ` Ludovic Courtès
2013-09-05 21:14 ` Nikita Karetnikov
2013-09-07 19:34 ` Ludovic Courtès
2013-09-08 10:59 ` Nikita Karetnikov
2013-09-08 20:22 ` Ludovic Courtès
2013-09-09 9:17 ` Nikita Karetnikov
2013-09-09 16:55 ` Ludovic Courtès
2013-09-11 5:16 ` Nikita Karetnikov
2013-09-11 21:25 ` Ludovic Courtès
2013-09-12 9:17 ` Nikita Karetnikov
2013-09-12 12:26 ` Ludovic Courtès
2013-09-13 14:44 ` Nikita Karetnikov
2013-09-13 21:29 ` Ludovic Courtès
2013-09-16 11:12 ` Nikita Karetnikov
2013-09-16 12:16 ` Ludovic Courtès
2013-09-18 0:43 ` PRELIMINARY: [PATCH] guix package: Add '--list-generations' Nikita Karetnikov
2013-09-18 17:35 ` Nikita Karetnikov
2013-09-18 21:32 ` Ludovic Courtès
2013-09-19 0:49 ` Nikita Karetnikov
2013-09-19 9:39 ` Ludovic Courtès
2013-09-19 11:48 ` Nikita Karetnikov
2013-09-19 12:13 ` Ludovic Courtès
2013-09-21 20:39 ` Ludovic Courtès
2013-09-18 21:35 ` PRELIMINARY: " Ludovic Courtès
2013-09-22 19:19 ` [PATCH] guix package: Add '--delete-generations' Nikita Karetnikov
2013-09-22 20:15 ` Generation 0 (was: [PATCH] guix package: Add '--delete-generations'.) Nikita Karetnikov
2013-09-22 21:15 ` Generation 0 Ludovic Courtès
2013-09-23 10:14 ` Nikita Karetnikov
2013-09-23 15:42 ` Ludovic Courtès
2013-09-24 0:54 ` Nikita Karetnikov
2013-09-24 5:56 ` [PATCH] guix package: Show which generation is the current one. (was: Generation 0) Nikita Karetnikov
2013-09-24 12:45 ` [PATCH] guix package: Show which generation is the current one Ludovic Courtès
2013-09-24 13:55 ` Nikita Karetnikov
2013-09-24 14:16 ` Ludovic Courtès
2013-09-25 2:10 ` Nikita Karetnikov
2013-09-25 12:51 ` Ludovic Courtès
2013-09-24 12:43 ` Generation 0 Ludovic Courtès
2013-09-24 22:29 ` Nikita Karetnikov
2013-09-25 12:50 ` Ludovic Courtès
2013-09-25 18:07 ` Nikita Karetnikov
2013-09-25 19:24 ` Ludovic Courtès
2013-09-26 2:18 ` Nikita Karetnikov
2013-09-26 9:44 ` Ludovic Courtès
2013-09-22 20:55 ` [PATCH] guix package: Add '--delete-generations' Ludovic Courtès
2013-09-23 10:11 ` Nikita Karetnikov
2013-09-23 15:41 ` Ludovic Courtès
2013-09-24 7:21 ` Nikita Karetnikov
2013-09-24 12:50 ` Ludovic Courtès
2013-09-24 13:57 ` Nikita Karetnikov
2013-09-25 4:21 ` Nikita Karetnikov
2013-09-25 13:05 ` Ludovic Courtès
2013-09-26 2:47 ` Nikita Karetnikov [this message]
2013-09-26 9:49 ` Ludovic Courtès
2013-09-27 19:04 ` Ludovic Courtès
2013-09-03 19:21 ` MIPS64/N64 support (was: Goals for 0.4) Nikita Karetnikov
2013-09-03 20:45 ` MIPS64/N64 support Ludovic Courtès
2013-09-04 0:35 ` Nikita Karetnikov
2013-09-04 12:18 ` Ludovic Courtès
2013-09-06 8:35 ` Nikita Karetnikov
2013-09-06 9:46 ` Ludovic Courtès
2013-09-07 2:45 ` Nikita Karetnikov
2013-09-07 12:57 ` Ludovic Courtès
2013-09-08 14:21 ` Nikita Karetnikov
2013-09-08 19:54 ` Ludovic Courtès
2013-09-09 5:38 ` Nikita Karetnikov
2013-09-09 16:47 ` Ludovic Courtès
2013-09-27 2:16 ` Nikita Karetnikov
2013-09-27 19:00 ` Ludovic Courtès
2013-09-29 13:27 ` Nikita Karetnikov
2013-09-29 13:31 ` Ludovic Courtès
2013-09-29 23:18 ` Nikita Karetnikov
2013-09-30 11:32 ` Nikita Karetnikov
2013-09-30 16:26 ` Ludovic Courtès
2013-09-30 21:51 ` Nikita Karetnikov
2013-10-01 7:09 ` Lluís Batlle i Rossell
2013-10-01 7:48 ` Nikita Karetnikov
2013-10-01 8:03 ` Lluís Batlle i Rossell
2013-10-01 8:55 ` Nikita Karetnikov
2013-10-01 8:59 ` Nikita Karetnikov
2013-10-01 9:30 ` Lluís Batlle i Rossell
2013-10-01 10:06 ` Nikita Karetnikov
2013-10-01 10:04 ` Lluís Batlle i Rossell
2013-10-01 11:25 ` Ludovic Courtès
2013-10-01 11:56 ` Lluís Batlle i Rossell
2013-10-07 18:47 ` Mark H Weaver
2013-10-07 19:39 ` Ludovic Courtès
2013-10-08 23:03 ` Mark H Weaver
2013-10-09 6:53 ` Mark H Weaver
2013-10-09 10:42 ` Ludovic Courtès
2013-10-09 10:39 ` Ludovic Courtès
2013-10-10 4:08 ` Mark H Weaver
2013-09-30 16:09 ` Ludovic Courtès
2013-08-29 15:49 ` Goals for 0.4 Amirouche Boubekki
2013-08-29 20:04 ` Ludovic Courtès
2013-08-30 16:09 ` Cyprien Nicolas
2013-08-30 17:40 ` Amirouche Boubekki
2013-08-30 19:31 ` Overlays Ludovic Courtès
2013-08-30 20:42 ` Overlays Nikita Karetnikov
2013-08-30 21:21 ` Overlays Ludovic Courtès
2013-08-31 10:56 ` Overlays Amirouche Boubekki
2013-08-31 15:57 ` Overlays Ludovic Courtès
2013-08-29 20:42 ` Goals for 0.4 Andreas Enge
2013-08-29 21:32 ` Ludovic Courtès
2013-09-25 8:43 ` Andreas Enge
2013-09-25 13:13 ` Ludovic Courtès
2013-09-26 11:35 ` Andreas Enge
2013-09-28 13:25 ` Ludovic Courtès
2013-09-29 21:29 ` Alex Sassmannshausen
2013-09-02 17:33 ` Cyril Roelandt
2013-09-02 19:38 ` Ludovic Courtès
2013-09-02 19:40 ` Cyril Roelandt
2013-09-02 21:35 ` Ludovic Courtès
2013-09-06 9:19 ` ‘--no-substitutes’ is ignored on i686 (was: Goals for 0.4) Nikita Karetnikov
2013-09-06 9:59 ` ‘--no-substitutes’ is ignored on i686 Ludovic Courtès
2013-09-07 8:43 ` Nikita Karetnikov
2013-09-07 13:00 ` Ludovic Courtès
2013-09-08 11:53 ` Nikita Karetnikov
2013-09-08 11:51 ` Cyril Roelandt
2013-09-08 13:22 ` Nikita Karetnikov
2013-09-24 21:59 ` Goals for 0.4 Ludovic Courtès
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
List information: https://guix.gnu.org/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87vc1oi9j8.fsf@karetnikov.org \
--to=nikita@karetnikov.org \
--cc=guix-devel@gnu.org \
--cc=ludo@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 public inbox
https://git.savannah.gnu.org/cgit/guix.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).