diff -Nru magit-2.99.0.git0957.ge8c7bd03/debian/changelog magit-3.3.0/debian/changelog --- magit-2.99.0.git0957.ge8c7bd03/debian/changelog 2020-07-06 15:56:39.000000000 +0000 +++ magit-3.3.0/debian/changelog 2021-10-06 12:58:32.000000000 +0000 @@ -1,3 +1,40 @@ +magit (3.3.0-1) unstable; urgency=medium + + * New upstream version + + -- Rémi Vanicat Wed, 06 Oct 2021 14:58:32 +0200 + +magit (3.2.1-2) unstable; urgency=medium + + * Team upload. + * Source-only upload for testing migration. + + -- Sean Whitton Thu, 26 Aug 2021 14:07:37 -0700 + +magit (3.2.1-1) unstable; urgency=medium + + [ Rémi Vanicat ] + * New upstream version + * Adapt watch file + * Adapt patches + - 0002-Do-not-require-async.patch not needed anymore + - 0005-Update-version-and-require-of-git-commit.patch: most is + integrated upstream, the rest in: + 0004-Signal-in-the-documentation-there-are-Debian-patches.patch + * Add an elpa-magit-section package. + It has been separated upstream. + + [ Matteo F. Vescovi ] + * New upstream version 3.2.1 + - debian/patches/: #0004 refreshed against v3.2.1 + * debian/control: + - debhelper bump 12 -> 13 + - RRR set + - S-V bump 4.1.4 -> 4.6.0 (no changes needed) + * debian/watch: version bump 3 -> 4 + + -- Rémi Vanicat Sat, 21 Aug 2021 14:48:14 +0200 + magit (2.99.0.git0957.ge8c7bd03-1) unstable; urgency=medium [ Rémi Vanicat ] diff -Nru magit-2.99.0.git0957.ge8c7bd03/debian/control magit-3.3.0/debian/control --- magit-2.99.0.git0957.ge8c7bd03/debian/control 2020-07-06 15:56:39.000000000 +0000 +++ magit-3.3.0/debian/control 2021-10-06 12:58:32.000000000 +0000 @@ -3,10 +3,11 @@ Priority: optional Maintainer: Debian Emacsen team Uploaders: Timo Juhani Lindfors , Rémi Vanicat , Barak A. Pearlmutter -Build-Depends: debhelper-compat (= 12), dh-elpa (>= 1.7), +Build-Depends: debhelper-compat (= 13), dh-elpa (>= 1.7), git, elpa-dash, elpa-with-editor, elpa-transient, elpa-ghub, texinfo, install-info -Standards-Version: 4.1.4 +Rules-Requires-Root: no +Standards-Version: 4.6.0 Homepage: https://magit.vc/ Vcs-Browser: https://salsa.debian.org/emacsen-team/magit Vcs-Git: https://salsa.debian.org/emacsen-team/magit.git @@ -31,3 +32,13 @@ Enhances: emacs, git Description: Major mode for editing git commit message A mode for editing COMMIT_MSG file from git in Emacs. + +Package: elpa-magit-section +Architecture: all +Depends: ${misc:Depends}, ${elpa:Depends} +Enhances: emacs +Description: Collapsible sections like in Magit + This package implements the main user interface of Magit — the + collapsible sections that make up its buffers. This package used + to be distributed as part of Magit but now it can also be used by + other packages that have nothing to do with Magit or Git. diff -Nru magit-2.99.0.git0957.ge8c7bd03/debian/elpa-magit-section.elpa magit-3.3.0/debian/elpa-magit-section.elpa --- magit-2.99.0.git0957.ge8c7bd03/debian/elpa-magit-section.elpa 1970-01-01 00:00:00.000000000 +0000 +++ magit-3.3.0/debian/elpa-magit-section.elpa 2021-10-06 12:58:32.000000000 +0000 @@ -0,0 +1 @@ +lisp/magit-section.el diff -Nru magit-2.99.0.git0957.ge8c7bd03/debian/.gitignore magit-3.3.0/debian/.gitignore --- magit-2.99.0.git0957.ge8c7bd03/debian/.gitignore 2020-07-06 15:56:39.000000000 +0000 +++ magit-3.3.0/debian/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,5 +0,0 @@ -/*.debhelper -/*.debhelper.log -/*.substvars -/files -/magit/ diff -Nru magit-2.99.0.git0957.ge8c7bd03/debian/patches/0002-Do-not-require-async.patch magit-3.3.0/debian/patches/0002-Do-not-require-async.patch --- magit-2.99.0.git0957.ge8c7bd03/debian/patches/0002-Do-not-require-async.patch 2020-07-06 15:56:39.000000000 +0000 +++ magit-3.3.0/debian/patches/0002-Do-not-require-async.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,29 +0,0 @@ -From: =?utf-8?q?R=C3=A9mi_Vanicat?= -Date: Tue, 3 Apr 2018 05:47:10 +0200 -Subject: Do not require async. - -It is not needed for debian package. ---- - lisp/magit-pkg.el | 11 +++++------ - 1 file changed, 5 insertions(+), 6 deletions(-) - -diff --git a/lisp/magit-pkg.el b/lisp/magit-pkg.el -index ee981ce..cef324a 100644 ---- a/lisp/magit-pkg.el -+++ b/lisp/magit-pkg.el -@@ -1,10 +1,9 @@ --(define-package "magit" "2.90.1" -+(define-package "magit" "2.99.0" - "A Git porcelain inside Emacs." - '((emacs "25.1") -- (async "20180527") -- (dash "20180910") -- (git-commit "20181104") -- (transient "20190812") -- (with-editor "20181103")) -+ (dash "2.17.0") -+ (git-commit "2.90.1") -+ (transient "0.2.0") -+ (with-editor "2.9.1")) - :keywords - '("git" "tools" "vc")) diff -Nru magit-2.99.0.git0957.ge8c7bd03/debian/patches/0003-Remove-magit-version.el-from-autogenerated-files.patch magit-3.3.0/debian/patches/0003-Remove-magit-version.el-from-autogenerated-files.patch --- magit-2.99.0.git0957.ge8c7bd03/debian/patches/0003-Remove-magit-version.el-from-autogenerated-files.patch 2020-07-06 15:56:39.000000000 +0000 +++ magit-3.3.0/debian/patches/0003-Remove-magit-version.el-from-autogenerated-files.patch 2021-10-06 12:58:32.000000000 +0000 @@ -9,10 +9,10 @@ 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/default.mk b/default.mk -index e493959..a7a5d1c 100644 +index 5118c69..48d30a9 100644 --- a/default.mk +++ b/default.mk -@@ -97,7 +97,7 @@ ELS += magit-imenu.el +@@ -99,7 +99,7 @@ ELS += magit-imenu.el ELS += magit-bookmark.el ELCS = $(ELS:.el=.elc) ELMS = magit.el $(filter-out $(addsuffix .el,$(PACKAGES)),$(ELS)) diff -Nru magit-2.99.0.git0957.ge8c7bd03/debian/patches/0004-Signal-in-the-documentation-there-are-Debian-patches.patch magit-3.3.0/debian/patches/0004-Signal-in-the-documentation-there-are-Debian-patches.patch --- magit-2.99.0.git0957.ge8c7bd03/debian/patches/0004-Signal-in-the-documentation-there-are-Debian-patches.patch 1970-01-01 00:00:00.000000000 +0000 +++ magit-3.3.0/debian/patches/0004-Signal-in-the-documentation-there-are-Debian-patches.patch 2021-10-06 12:58:32.000000000 +0000 @@ -0,0 +1,54 @@ +From: =?utf-8?q?R=C3=A9mi_Vanicat?= +Date: Thu, 19 Aug 2021 22:29:23 +0200 +Subject: Signal in the documentation there are Debian patches. + +Reviewed-by: Matteo F. Vescovi +--- + Documentation/magit.org | 4 ++-- + Documentation/magit.texi | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/Documentation/magit.org b/Documentation/magit.org +index b40ecb7..e559a4c 100644 +--- a/Documentation/magit.org ++++ b/Documentation/magit.org +@@ -8,7 +8,7 @@ + #+TEXINFO_DIR_CATEGORY: Emacs + #+TEXINFO_DIR_TITLE: Magit: (magit). + #+TEXINFO_DIR_DESC: Using Git from Emacs with Magit. +-#+SUBTITLE: for version 3.3.0 ++#+SUBTITLE: for version 3.3.0 (with Debian patches) + + #+TEXINFO_DEFFN: t + #+OPTIONS: H:4 num:3 toc:2 +@@ -25,7 +25,7 @@ + Magit and Git itself deserve to be called porcelains. + + #+TEXINFO: @noindent +-This manual is for Magit version 3.3.0. ++This manual is for Magit version 3.3.0 (with Debian patches). + + #+BEGIN_QUOTE + Copyright (C) 2015-2021 Jonas Bernoulli +diff --git a/Documentation/magit.texi b/Documentation/magit.texi +index 378956c..2df7952 100644 +--- a/Documentation/magit.texi ++++ b/Documentation/magit.texi +@@ -31,7 +31,7 @@ General Public License for more details. + @finalout + @titlepage + @title Magit User Manual +-@subtitle for version 3.3.0 ++@subtitle for version 3.3.0 (with Debian patches) + @author Jonas Bernoulli + @page + @vskip 0pt plus 1filll +@@ -53,7 +53,7 @@ directly from within Emacs. While many fine Git clients exist, only + Magit and Git itself deserve to be called porcelains. + + @noindent +-This manual is for Magit version 3.3.0. ++This manual is for Magit version 3.3.0 (with Debian patches). + + @quotation + Copyright (C) 2015-2021 Jonas Bernoulli diff -Nru magit-2.99.0.git0957.ge8c7bd03/debian/patches/0004-tramp-test-overide.patch magit-3.3.0/debian/patches/0004-tramp-test-overide.patch --- magit-2.99.0.git0957.ge8c7bd03/debian/patches/0004-tramp-test-overide.patch 2020-07-06 15:56:39.000000000 +0000 +++ magit-3.3.0/debian/patches/0004-tramp-test-overide.patch 2021-10-06 12:58:32.000000000 +0000 @@ -8,17 +8,17 @@ 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/t/magit-tests.el b/t/magit-tests.el -index 1982133..96566d2 100644 +index 523cc51..d414333 100644 --- a/t/magit-tests.el +++ b/t/magit-tests.el -@@ -71,19 +71,20 @@ - (list shell-file-name)) +@@ -83,19 +83,20 @@ + shell-file-name))) ((cdr (assq 'tramp-login-args sudo-method)) nil)) (magit-with-test-directory - (setq default-directory - (concat (format "/sudo:%s@localhost:" (user-login-name)) - default-directory)) -- (magit-git "init" "repo") +- (magit-test-init-repo "repo") - (magit-test-magit-toplevel) - (should (equal (magit-toplevel "repo/.git/") - (expand-file-name "repo/"))) @@ -32,7 +32,7 @@ + (setq default-directory + (concat (format "/sudo:%s@localhost:" (user-login-name)) + default-directory)) -+ (magit-git "init" "repo") ++ (magit-test-init-repo "repo") + (magit-test-magit-toplevel) + (should (equal (magit-toplevel "repo/.git/") + (expand-file-name "repo/"))) diff -Nru magit-2.99.0.git0957.ge8c7bd03/debian/patches/0005-Update-version-and-require-of-git-commit.patch magit-3.3.0/debian/patches/0005-Update-version-and-require-of-git-commit.patch --- magit-2.99.0.git0957.ge8c7bd03/debian/patches/0005-Update-version-and-require-of-git-commit.patch 2020-07-06 15:56:39.000000000 +0000 +++ magit-3.3.0/debian/patches/0005-Update-version-and-require-of-git-commit.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -From: =?utf-8?q?R=C3=A9mi_Vanicat?= -Date: Mon, 6 Jul 2020 15:41:00 +0200 -Subject: Update version and require of git-commit - ---- - lisp/git-commit.el | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/lisp/git-commit.el b/lisp/git-commit.el -index 4ed2072..063601e 100644 ---- a/lisp/git-commit.el -+++ b/lisp/git-commit.el -@@ -11,9 +11,10 @@ - ;; Marius Vollmer - ;; Maintainer: Jonas Bernoulli - --;; Package-Requires: ((emacs "25.1") (dash "20180910") (transient "20190812") (with-editor "20181103")) -+;; Package-Requires: ((emacs "25.1") (dash "2.17.0") (transient "0.2.0") (with-editor "2.9.1")) - ;; Keywords: git tools vc - ;; Homepage: https://github.com/magit/magit -+;; Version: 2.99.0 - - ;; This file is not part of GNU Emacs. - diff -Nru magit-2.99.0.git0957.ge8c7bd03/debian/patches/series magit-3.3.0/debian/patches/series --- magit-2.99.0.git0957.ge8c7bd03/debian/patches/series 2020-07-06 15:56:39.000000000 +0000 +++ magit-3.3.0/debian/patches/series 2021-10-06 12:58:32.000000000 +0000 @@ -1,5 +1,4 @@ 0004-tramp-test-overide.patch 0003-Remove-magit-version.el-from-autogenerated-files.patch -0002-Do-not-require-async.patch 0001-add-config.mk -0005-Update-version-and-require-of-git-commit.patch +0004-Signal-in-the-documentation-there-are-Debian-patches.patch diff -Nru magit-2.99.0.git0957.ge8c7bd03/debian/watch magit-3.3.0/debian/watch --- magit-2.99.0.git0957.ge8c7bd03/debian/watch 2020-07-06 15:56:39.000000000 +0000 +++ magit-3.3.0/debian/watch 2021-10-06 12:58:32.000000000 +0000 @@ -1,2 +1,2 @@ -version=3 -https://github.com/magit/magit/releases /magit/magit/archive/v?(\d.+).tar.gz +version=4 +https://github.com/magit/magit/releases /magit/magit/archive/refs/tags/v(\d.+).tar.gz diff -Nru magit-2.99.0.git0957.ge8c7bd03/default.mk magit-3.3.0/default.mk --- magit-2.99.0.git0957.ge8c7bd03/default.mk 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/default.mk 2021-10-06 12:51:17.000000000 +0000 @@ -54,6 +54,7 @@ ifeq "$(BUILD_MAGIT_LIBGIT)" "true" ELS += magit-libgit.el endif +ELS += magit-git.el ELS += magit-mode.el ELS += magit-margin.el ELS += magit-process.el @@ -91,6 +92,7 @@ ELS += magit-subtree.el ELS += magit-ediff.el ELS += magit-gitignore.el +ELS += magit-bundle.el ELS += magit-extras.el ELS += git-rebase.el ELS += magit-imenu.el @@ -101,28 +103,31 @@ ## Versions ########################################################## -VERSION ?= $(shell test -e $(TOP).git && git describe --tags --abbrev=0 | cut -c2-) - -ASYNC_VERSION = 1.9.3 -DASH_VERSION = 2.14.1 -GIT_COMMIT_VERSION = 3.0.0 -LIBGIT_VERSION = 0 -MAGIT_SECTION_VERSION = 3.0.0 -TRANSIENT_VERSION = 0 -WITH_EDITOR_VERSION = 2.8.0 - -ASYNC_MELPA_SNAPSHOT = 20180527 -DASH_MELPA_SNAPSHOT = 20180910 -GIT_COMMIT_MELPA_SNAPSHOT = 20181104 -LIBGIT_MELPA_SNAPSHOT = 0 -MAGIT_SECTION_MELPA_SNAPSHOT = 20200123 -TRANSIENT_MELPA_SNAPSHOT = 20190812 -WITH_EDITOR_MELPA_SNAPSHOT = 20181103 - -EMACS_VERSION = 25.1 +VERSION ?= $(shell \ + test -e $(TOP).git && \ + git describe --tags --abbrev=0 --always | cut -c2-) +TIMESTAMP = 20211004 + +DASH_VERSION = 2.19.1 +GIT_COMMIT_VERSION = $(VERSION) +LIBGIT_VERSION = 0 +MAGIT_VERSION = $(VERSION) +MAGIT_LIBGIT_VERSION = $(VERSION) +MAGIT_SECTION_VERSION = $(VERSION) +TRANSIENT_VERSION = 0.3.6 +WITH_EDITOR_VERSION = 3.0.5 + +DASH_MELPA_SNAPSHOT = 20210826 +GIT_COMMIT_MELPA_SNAPSHOT = $(TIMESTAMP) +LIBGIT_MELPA_SNAPSHOT = 0 +MAGIT_MELPA_SNAPSHOT = $(TIMESTAMP) +MAGIT_LIBGIT_MELPA_SNAPSHOT = $(TIMESTAMP) +MAGIT_SECTION_MELPA_SNAPSHOT = $(TIMESTAMP) +TRANSIENT_MELPA_SNAPSHOT = 20210920 +WITH_EDITOR_MELPA_SNAPSHOT = 20211001 +EMACS_VERSION = 25.1 LIBGIT_EMACS_VERSION = 26.1 -LIBGIT_MAGIT_VERSION = 0 EMACSOLD := $(shell $(BATCH) --eval \ "(and (version< emacs-version \"$(EMACS_VERSION)\") (princ \"true\"))") @@ -134,7 +139,15 @@ ifndef LOAD_PATH -ELPA_DIR ?= $(HOME)/.emacs.d/elpa +USER_EMACS_DIR = $(HOME)/.emacs.d +ifeq "$(wildcard $(USER_EMACS_DIR))" "" + XDG_CONFIG_DIR = $(or $(XDG_CONFIG_HOME),$(HOME)/.config) + ifneq "$(wildcard $(XDG_CONFIG_DIR)/emacs)" "" + USER_EMACS_DIR = $(XDG_CONFIG_DIR)/emacs + endif +endif + +ELPA_DIR ?= $(USER_EMACS_DIR)/elpa DASH_DIR ?= $(shell \ find -L $(ELPA_DIR) -maxdepth 1 -regex '.*/dash-[.0-9]*' 2> /dev/null | \ @@ -164,6 +177,10 @@ WITH_EDITOR_DIR = $(TOP)../with-editor endif +MAGIT_SECTION_DIR ?= $(shell \ + find -L $(ELPA_DIR) -maxdepth 1 -regex '.*/magit-section-[.0-9]*' 2> /dev/null | \ + sort | tail -n 1) + SYSTYPE := $(shell $(EMACSBIN) -Q --batch --eval "(princ system-type)") ifeq ($(SYSTYPE), windows-nt) CYGPATH := $(shell cygpath --version 2>/dev/null) @@ -172,7 +189,7 @@ LOAD_PATH = -L $(TOP)lisp # When making changes here, then don't forget to adjust "Makefile", -# ".travis.yml", ".github/ISSUE_TEMPLATE/bug_report.md", +# ".github/workflows/test.yml", ".github/ISSUE_TEMPLATE/bug_report.md", # `magit-emacs-Q-command' and the "Installing from the Git Repository" # info node accordingly. Also don't forget to "rgrep \b\b". @@ -181,11 +198,17 @@ LOAD_PATH += -L $(shell cygpath --mixed $(LIBGIT_DIR)) LOAD_PATH += -L $(shell cygpath --mixed $(TRANSIENT_DIR)) LOAD_PATH += -L $(shell cygpath --mixed $(WITH_EDITOR_DIR)) + ifneq "$(MAGIT_SECTION_DIR)" "" + LOAD_PATH += -L $(shell cygpath --mixed $(MAGIT_SECTION_DIR)) + endif else LOAD_PATH += -L $(DASH_DIR) LOAD_PATH += -L $(LIBGIT_DIR) LOAD_PATH += -L $(TRANSIENT_DIR) LOAD_PATH += -L $(WITH_EDITOR_DIR) + ifneq "$(MAGIT_SECTION_DIR)" "" + LOAD_PATH += -L $(MAGIT_SECTION_DIR) + endif endif endif # ifndef LOAD_PATH @@ -193,7 +216,7 @@ ifndef ORG_LOAD_PATH ORG_LOAD_PATH = $(LOAD_PATH) ORG_LOAD_PATH += -L ../../org/lisp -ORG_LOAD_PATH += -L ../../org/contrib/lisp +ORG_LOAD_PATH += -L ../../org-contrib/lisp ORG_LOAD_PATH += -L ../../ox-texinfo+ endif diff -Nru magit-2.99.0.git0957.ge8c7bd03/Documentation/AUTHORS.md magit-3.3.0/Documentation/AUTHORS.md --- magit-2.99.0.git0957.ge8c7bd03/Documentation/AUTHORS.md 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/Documentation/AUTHORS.md 2021-10-06 12:51:17.000000000 +0000 @@ -57,7 +57,6 @@ - Alexey Voinov - Alex Kost - Alex Ott -- Allen - Allen Li - Andreas Fuchs - Andreas Liljeqvist @@ -65,6 +64,7 @@ - Andrei Chițu - Andrew Eggenberger - Andrew Kirkpatrick +- Andrew Psaltis - Andrew Schwartzmeyer - Andrey Smirnov - Andriy Kmit' @@ -72,6 +72,7 @@ - Aria Edmonds - Arialdo Martini - Arnau Roig Ninerola +- Ashlynn Anderson - Barak A. Pearlmutter - Bar Magal - Bart Bakker @@ -81,8 +82,10 @@ - Ben North - Ben Walton - Bob Uhl +- Boruch Baum - Bradley Wright - Brandon W Maister +- Brian Leung - Brian Warner - Bryan Shell - Buster Copley @@ -103,20 +106,22 @@ - Craig Andera - Dale Hagglund - Damien Cassou +- Dan Davison - Dan Erikson - Daniel Brockman - Daniel Farina +- Daniel Fleischer - Daniel Gröber - Daniel Hackney - Daniel Kraus - Daniel Mai - Daniel Martín +- Daniel Nagy - Dan LaManna - Danny Zhu - Dato Simó - David Abrahams - David Ellison -- David Ellison - David Hull - David L. Rager - David Wallin @@ -124,10 +129,10 @@ - Dennis Paskorz - Divye Kapoor - Dominique Quatravaux -- Dominique Quatravaux - Duianto Vebotci - Eli Barzilay - Eric Davis +- Eric - Eric Prud'hommeaux - Eric Schulte - Erik Anderson @@ -139,6 +144,7 @@ - Felix Yan - Feng Li - Florian Ragwitz +- Franklin Delehelle - Fritz Grabo - Fritz Stelzer - Geoff Shannon @@ -147,12 +153,16 @@ - Graham Dobbins - Greg A. Woods - Greg Lucas +- Gregory Heytings - Greg Sexton - Guillaume Martres - Hannu Koivisto - Hans-Peter Deifel - Hussein Ait-Lahcen - Ian Eure +- Ian Milligan +- Ilya Grigoriev +- Ingmar Sittl - Ingo Lohmar - Ioan-Adrian Ratiu - Ivan Brennan @@ -165,14 +175,17 @@ - Jim Blandy - Joakim Jalap - Johannes Altmanninger -- Johann Klähn +- Johann Klähn - John Mastro - John Morris - John Wiegley - Jonas Bernoulli +- Jonas Galvão Xavier - Jonathan Arnett +- Jonathan del Strother - Jonathan Leech-Pepin - Jonathan Roes +- Jonathon McKitrick - Jon Vanderwijk - Jordan Galby - Jordan Greenberg @@ -198,7 +211,9 @@ - Lele Gaifax - Leo Liu - Leonardo Etcheverry +- Leo Vivier - Lingchao Xin +- Lin Sun - Li-Yun Chang - Lluís Vilanova - Loic Dachary @@ -220,9 +235,13 @@ - Mark Hepburn - Mark Karpov - Mark Oteiza +- Martin Joerg +- Martin Polden - Matthew Fluet +- Matthew Kraai - Matthieu Hauglustaine - Matus Goljer +- Maxim Cournoyer - Michael Fogleman - Michael Griffiths - Michael Heerdegen @@ -246,10 +265,12 @@ - Nikolay Martynov - Noam Postavsky - N. Troy de Freitas +- Ola x Nilsson - Ole Arndt - Oleh Krehel - Orivej Desh - Óscar Fuentes +- Pancho Horrillo - Paul Stadig - Pavel Holejsovsky - Pekka Pessi @@ -257,7 +278,9 @@ - Peter Jaros - Peter J. Weisberg - Peter Vasil +- Philippe Cavalaria - Philippe Vaucher +- Philipp Fehre - Philipp Haselwarter - Philipp Stephani - Philip Weaver @@ -266,6 +289,7 @@ - Pierre Neidhardt - Pieter Praet - Prathamesh Sonpatki +- Pritam Baral - rabio - Radon Rosborough - Rafael Laboissiere @@ -285,6 +309,7 @@ - Rüdiger Sonderfeld - Russell Black - Ryan C. Thompson +- Sam Cedarbaum - Samuel Bronson - Samuel W. Flint - Sanjoy Das @@ -297,7 +322,9 @@ - Sergey Pashinin - Sergey Vinokurov - Servilio Afre Puentes +- Siavash Askari Nasr - Silent Sphere +- Simon Pintarelli - Štěpán Němec - Steven Chow - Steven E. Harris @@ -307,11 +334,13 @@ - Suhail Shergill - Sylvain Rousseau - Syohei Yoshida +- Szunti - Takafumi Arakaki - Tassilo Horn +- TEC - Teemu Likonen - Teruki Shigitani -- Thierry Volpiatto +- Thierry Volpiatto - Thomas A Caswell - Thomas Fini Hansen - Thomas Frössman @@ -323,6 +352,7 @@ - Tim Wraight - Ting-Yu Lin - Tom Feist +- Toon Claes - Topi Miettinen - Troy Hinckley - Tsuyoshi Kitamoto @@ -330,12 +360,15 @@ - Vineet Naik - Vitaly Ostashov - Vladimir Panteleev +- Vladimir Sedach - Wei Huang - Wilfred Hughes - Win Treese +- Wojciech Siewierski - Wouter Bolsterlee - Xavier Noria - Xu Chunyang +- Yann Herklotz - Yann Hodique - Ynilu - York Zhao diff -Nru magit-2.99.0.git0957.ge8c7bd03/Documentation/magit.org magit-3.3.0/Documentation/magit.org --- magit-2.99.0.git0957.ge8c7bd03/Documentation/magit.org 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/Documentation/magit.org 2021-10-06 12:51:17.000000000 +0000 @@ -2,13 +2,13 @@ :PREAMBLE: #+AUTHOR: Jonas Bernoulli #+EMAIL: jonas@bernoul.li -#+DATE: 2015-2020 +#+DATE: 2015-2021 #+LANGUAGE: en #+TEXINFO_DIR_CATEGORY: Emacs #+TEXINFO_DIR_TITLE: Magit: (magit). #+TEXINFO_DIR_DESC: Using Git from Emacs with Magit. -#+SUBTITLE: for version 2.90.1 (v2.90.1-954-g509e97b7+1) +#+SUBTITLE: for version 3.3.0 #+TEXINFO_DEFFN: t #+OPTIONS: H:4 num:3 toc:2 @@ -25,10 +25,10 @@ Magit and Git itself deserve to be called porcelains. #+TEXINFO: @noindent -This manual is for Magit version 2.90.1 (v2.90.1-954-g509e97b7+1). +This manual is for Magit version 3.3.0. #+BEGIN_QUOTE -Copyright (C) 2015-2020 Jonas Bernoulli +Copyright (C) 2015-2021 Jonas Bernoulli You can redistribute this document and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -120,7 +120,7 @@ commands are implemented on top of Git plumbing commands. * Installation -** _ :ignore: +** _ Magit can be installed using Emacs' package manager or manually from its development repository. @@ -191,10 +191,10 @@ with the following content before running ~make~: #+BEGIN_SRC makefile - LOAD_PATH = -L /path/to/magit/lisp - LOAD_PATH += -L /path/to/dash - LOAD_PATH += -L /path/to/transient - LOAD_PATH += -L /path/to/with-editor + LOAD_PATH = -L ~/.emacs.d/site-lisp/magit/lisp + LOAD_PATH += -L ~/.emacs.d/site-lisp/dash + LOAD_PATH += -L ~/.emacs.d/site-lisp/transient/lisp + LOAD_PATH += -L ~/.emacs.d/site-lisp/with-editor #+END_SRC Finally add this to your init file: @@ -209,6 +209,15 @@ "~/.emacs.d/site-lisp/magit/Documentation/")) #+END_SRC +Of course if you installed the dependencies manually as well, then +you have to tell Emacs about them too, by prefixing the above with: + +#+BEGIN_SRC emacs-lisp + (add-to-list 'load-path "~/.emacs.d/site-lisp/dash") + (add-to-list 'load-path "~/.emacs.d/site-lisp/transient/lisp") + (add-to-list 'load-path "~/.emacs.d/site-lisp/with-editor") +#+END_SRC + Note that you have to add the ~lisp~ subdirectory to the ~load-path~, not the top-level of the repository, and that elements of ~load-path~ should not end with a slash, while those of ~Info-directory-list~ should. @@ -282,13 +291,8 @@ if you do that, then you should commit all uncommitted changes before proceeding. -To display information about the current Git repository, type ~M-x -magit-status RET~. You will be using this command a lot, and should -therefore give it a global key binding. This is what we recommend: - -#+BEGIN_SRC emacs-lisp - (global-set-key (kbd "C-x g") 'magit-status) -#+END_SRC +Type ~C-x g~ to display information about the current Git repository in +a dedicated buffer, called the status buffer. Most Magit commands are commonly invoked from the status buffer. It can be considered the primary interface for interacting with Git using @@ -340,7 +344,7 @@ Now two new buffers appear. One is for writing the commit message, the other shows a diff with the changes that you are about to -committed. Write a message and then type ~C-c C-c~ to actually create +commit. Write a message and then type ~C-c C-c~ to actually create the commit. You probably don't want to push the commit you just created because @@ -351,35 +355,31 @@ push-remote is not configured yet, then you would first be prompted for the remote to push to.) -So far we have mentioned the commit, push, and log transient prefix -commands. These are probably among the transients you will be using -the most, but many others exist. To show a transient that lists all -other transients (as well as the various apply commands and some other -essential commands), type ~h~. Try a few. +So far we have mentioned the commit, push, and log menu commands. +These are probably among the menus you will be using the most, but +many others exist. To show a menu that lists all other menus (as well +as the various apply commands and some other essential commands), type +~h~. Try a few. (Such menus are also called "transient prefix +commands" or just "transients".) -The key bindings in that transient correspond to the bindings in Magit +The key bindings in that menu correspond to the bindings in Magit buffers, including but not limited to the status buffer. So you could -type ~h d~ to bring up the diff transient, but once you remember that -"d" stands for "diff", you would usually do so by just typing ~d~. But -this "prefix of prefixes" is useful even once you have memorized all -the bindings, as it can provide easy access to Magit commands from -non-Magit buffers. You should create a global key binding for this -command too: - -#+BEGIN_SRC emacs-lisp - (global-set-key (kbd "C-x M-g") 'magit-dispatch) -#+END_SRC - -In the same vein, you might also want to enable ~global-magit-file-mode~ -to get some more Magit key bindings in regular file-visiting buffers -(see [[*Minor Mode for Buffers Visiting Files]]). +type ~h d~ to bring up the diff menu, but once you remember that "d" +stands for "diff", you would usually do so by just typing ~d~. But this +"prefix of prefixes" is useful even once you have memorized all the +bindings, as it can provide easy access to Magit commands from +non-Magit buffers. The global binding is ~C-x M-g~. + +In file visiting buffers ~C-c M-g~ brings up a similar menu featuring +commands that act on just the visited file, see [[*Commands for Buffers +Visiting Files]]. It is not necessary that you do so now, but if you stick with Magit, then it is highly recommended that you read the next section too. * Interface Concepts ** Modes and Buffers -*** _ :ignore: +*** _ Magit provides several major-modes. For each of these modes there usually exists only one buffer per repository. Separate modes and @@ -645,7 +645,8 @@ by adding a hook, like so: #+BEGIN_SRC emacs-lisp - (add-hook 'after-save-hook 'magit-after-save-refresh-status t) + (with-eval-after-load 'magit-mode + (add-hook 'after-save-hook 'magit-after-save-refresh-status t)) #+END_SRC Automatically refreshing Magit buffers ensures that the displayed @@ -872,7 +873,7 @@ (because it isn't modified). ** Sections -*** _ :ignore: +*** _ Magit buffers are organized into nested sections, which can be collapsed and expanded, similar to how sections are handled in Org @@ -1214,10 +1215,16 @@ Users usually do not have to worry about a section's type and value, but knowing them can be handy at times. -- Key: M-x magit-describe-section-briefly, magit-describe-section-briefly +- Key: H, magit-describe-section + + This command shows information about the section at point in a + separate buffer. - Show information about the section at point in the echo area, as - "#". +- Command: magit-describe-section-briefly + + This command shows information about the section at point in the + echo area, as ~#~. Many commands behave differently depending on the type of the section at point and/or somehow consume the value of that section. But that @@ -1363,7 +1370,7 @@ #+TEXINFO: @noindent I am afraid it gets more complicated still: -- The global diff and log arguments are set for each support mode +- The global diff and log arguments are set for each supported mode individually. The diff arguments for example have different values in ~magit-diff-mode~, ~magit-revision-mode~, ~magit-merge-preview-mode~ and ~magit-status-mode~ buffers. Setting or saving the value for one @@ -1372,7 +1379,7 @@ - When ~magit-show-commit~ is invoked directly from a log buffer, then the file filter is picked up from that buffer, not from the revision - buffer and or the mode's global diff arguments. + buffer or the mode's global diff arguments. - Even though they are suffixes of the diff prefix ~magit-show-commit~ and ~magit-stash-show~ do not use the diff buffer used by the diff @@ -1484,7 +1491,7 @@ - ~delete-pr-remote~ When deleting a branch that was created from a pull-request and if no other branches still exist on that - remote, then `magit-branch-delete' offers to delete the remote + remote, then ~magit-branch-delete~ offers to delete the remote as well. This should be safe because it only happens if no other refs exist in the remotes namespace, and you can recreate the remote if necessary. @@ -1497,6 +1504,15 @@ This action only concerns the deletion of multiple stashes at once. + - Publishing: + + - ~set-and-push~ When pushing to the upstream or the push-remote + and that isn't actually configured yet, then the user can first + set the target. If s/he confirms the default too quickly, then + s/he might end up pushing to the wrong branch and if the remote + repository is configured to disallow fixing such mistakes, then + that can be quite embarrassing and annoying. + - Edit published history: Without adding these symbols here, you will be warned before @@ -1800,11 +1816,34 @@ This command kills the process represented by the section at point. -- User Option: magit-git-debug +- Variable: magit-git-debug - When this is non-nil then the output of all calls to git are logged - in the process buffer. This is useful when debugging, otherwise it - just negatively affects performance. + This option controls whether additional reporting of git errors is + enabled. + + Magit basically calls git for one of these two reasons: for + side-effects or to do something with its standard output. + + When git is run for side-effects then its output, including error + messages, go into the process buffer which is shown when using ~$~. + + When git's output is consumed in some way, then it would be too + expensive to also insert it into this buffer, but when this + option is non-nil and git returns with a non-zero exit status, + then at least its standard error is inserted into this buffer. + + This is only intended for debugging purposes. Do not enable this + permanently, that would negatively affect performance. + +- Variable: magit-process-extreme-logging + + This option controls whether ~magit-process-file~ logs to the + ~*Messages*~ buffer. + + Only intended for temporary use when you try to figure out how + Magit uses Git behind the scene. Output that normally goes to + the magit-process buffer continues to go there. Not all output + goes to either of these two buffers. *** Git Process Status @@ -1847,6 +1886,7 @@ The string "git " is used as initial input when prompting the user for the command. It can be removed to run another command. +- Key: :, magit-git-command - Key: ! p, magit-git-command This command reads a command from the user and executes it in @@ -1892,48 +1932,65 @@ *** Git Executable -Except on MS Windows, Magit defaults to running Git without specifying -the path to the git executable. Instead the first executable found by -Emacs on ~exec-path~ is used (whose value in turn is set based on the -value of the environment variable ~$PATH~ when Emacs was started). - -This has the advantage that it continues to work even when using Tramp -to connect to a remote machine on which the executable is found in a -different place. The downside is that if you have multiple versions -of Git installed, then you might end up using another version than the -one you think you are using. +When Magit calls Git, then it may do so using the absolute path to the +~git~ executable, or using just its name. -- Key: M-x magit-version, magit-version - - This command shows the currently used versions of Magit, Git, and - Emacs in the echo area. Non-interactively this just returns the - Magit version. - -When the ~system-type~ is ~windows-nt~, then ~magit-git-executable~ is set -to an absolute path when Magit is first loaded. This is necessary -because Git on that platform comes with several wrapper scripts for -the actual git binary, which are also placed on ~$PATH~, and using one -of these wrappers instead of the binary would degrade performance -horribly. - -If Magit doesn't find the correct executable then you *can* work -around that by setting ~magit-git-executable~ to an absolute path. -But note that doing so is a kludge. It is better to make sure the -order in the environment variable ~$PATH~ is correct, and that Emacs -is started with that environment in effect. The command -~magit-debug-git-executable~ can be useful to find out where Emacs is -searching for git. If you have to connect from Windows to a -non-Windows machine, then you must change the value to "git". +When running ~git~ locally and the ~system-type~ is ~windows-nt~ (any +Windows version) or ~darwin~ (macOS) then ~magit-git-executable~ is set +to an absolute path when Magit is loaded. + +On Windows it is necessary to use an absolute path because Git comes +with several wrapper scripts for the actual ~git~ binary, which are also +placed on ~$PATH~, and using one of these wrappers instead of the binary +would degrade performance horribly. For some macOS users using just +the name of the executable also performs horribly, so we avoid doing +that on that platform as well. On other platforms, using just the +name seems to work just fine. + +Using an absolute path when running ~git~ on a remote machine over +Tramp, would be problematic to use an absolute path that is suitable +on the local machine, so a separate option is used to control the name +or path that is used on remote machines. - User Option: magit-git-executable - The git executable used by Magit, either the full path to the - executable or the string "git" to let Emacs find the executable - itself, using the standard mechanism for doing such things. + The ~git~ executable used by Magit on the local host. This should be + either the absolute path to the executable, or the string "git" to + let Emacs find the executable itself, using the standard mechanism + for doing such things. + +- User Option: magit-remote-git-executable + + The ~git~ executable used by Magit on remote machines over Tramp. + Normally this should be just the string "git". Consider customizing + ~tramp-remote-path~ instead of this option. + +If Emacs is unable to find the correct executable, then you can +work around that by explicitly setting the value of one of these two +options. Doing that should be considered a kludge; it is better to +make sure that the order in ~exec-path~ or ~tramp-remote-path~ is correct. + +Note that ~exec-path~ is set based on the value of the ~PATH~ environment +variable that is in effect when Emacs is started. If you set ~PATH~ in +your shell's init files, then that only has an effect on Emacs if you +start it from that shell (because the environment of a process is only +passed to its child processes, not to arbitrary other processes). If +that is not how you start Emacs, then the ~exec-path-from-shell~ package +can help; though honestly I consider that a kludge too. + +The command ~magit-debug-git-executable~ can be useful to find out where +Emacs is searching for ~git~. - Key: M-x magit-debug-git-executable, magit-debug-git-executable - Display a buffer with information about ~magit-git-executable~. + This command displays a buffer with information about + ~magit-git-executable~ and ~magit-remote-git-executable~. + +- Key: M-x magit-version, magit-version + + This command shows the currently used versions of Magit, Git, and + Emacs in the echo area. Non-interactively this just returns the + Magit version. *** Global Git Arguments @@ -1951,7 +2008,7 @@ used every time Magit runs Git for any purpose. * Inspecting -** _ :ignore: +** _ The functionality provided by Magit can be roughly divided into three groups: inspecting existing data, manipulating existing data or adding @@ -1970,7 +2027,7 @@ described later. ** Status Buffer -*** _ :ignore: +*** _ While other Magit buffers contain e.g. one particular diff or one particular log, the status buffer contains the diffs for staged and @@ -2039,6 +2096,34 @@ ~magit-list-repositories~. It also affects ~magit-status~ (which see) in potentially surprising ways (see above). +- Command: magit-status-quick + + This command is an alternative to ~magit-status~ that usually avoids + refreshing the status buffer. + + If the status buffer of the current Git repository exists but isn't + being displayed in the selected frame, then it is displayed without + being refreshed. + + If the status buffer is being displayed in the selected frame, + then this command refreshes it. + + Prefix arguments have the same meaning as for ~magit-status~, + and additionally cause the buffer to be refresh. + + To use this command add this to your init file: + + #+BEGIN_SRC emacs-lisp + (global-set-key (kbd "C-x g") 'magit-status-quick). + #+END_SRC + + If you do that and then for once want to redisplay the buffer and + also immediately refresh it, then type ~C-x g~ followed by ~g~. + + A possible alternative command is ~magit-display-repository-buffer~. + It supports displaying any existing Magit buffer that belongs to the + current repository; not just the status buffer. + - Command: ido-enter-magit-status From an Ido prompt used to open a file, instead drop into @@ -2413,6 +2498,12 @@ has to return a string to be inserted or nil. PROPS is an alist that supports the keys ~:right-align~ and ~:pad-right~. + You may wish to display a range of numeric columns using just one + character per column and without any padding between columns, in + which case you should use an appropriate HEADER, set WIDTH to 1, + and set ~:pad-right~ to 0. ~+~ is substituted for numbers higher + than 9. + The following functions can be added to the above option: - Function: magit-repolist-column-ident @@ -2479,7 +2570,7 @@ but not its push branch. ** Logging -*** _ :ignore: +*** _ The status buffer contains logs for the unpushed and unpulled commits, but that obviously isn't enough. The transient prefix command @@ -2534,11 +2625,10 @@ Show log for all references and ~HEAD~. - -Two additional commands that show the log for the file or blob that -is being visited in the current buffer exists, see [[*Minor Mode for -Buffers Visiting Files]]. The command ~magit-cherry~ also shows a log, -see [[*Cherries]]. +Two additional commands that show the log for the file or blob that is +being visited in the current buffer exists, see [[*Commands for Buffers +Visiting Files]]. The command ~magit-cherry~ also shows a log, see +[[*Cherries]]. *** Refreshing Logs @@ -2607,6 +2697,17 @@ first parent, but a numeric prefix can be used to specify another parent. +- Key: j, magit-log-move-to-revision + + Read a revision and move to it in current log buffer. + + If the chosen reference or revision isn't being displayed in + the current log buffer, then inform the user about that and do + nothing else. + + If invoked outside any log buffer, then display the log buffer + of the current repository first; creating it if necessary. + - Key: SPC, magit-diff-show-or-scroll-up Update the commit or diff buffer for the thing at point. @@ -2876,7 +2977,7 @@ is shown, then this specifies how much space is used to do so. ** Diffing -*** _ :ignore: +*** _ The status buffer contains diffs for the staged and unstaged commits, but that obviously isn't enough. The transient prefix command @@ -2950,7 +3051,7 @@ Show all diffs of a stash in a buffer. Two additional commands that show the diff for the file or blob that -is being visited in the current buffer exists, see [[*Minor Mode for +is being visited in the current buffer exists, see [[*Commands for Buffers Visiting Files]]. *** Refreshing Diffs @@ -3222,6 +3323,16 @@ also the foreground color. Whether the outside of the region is dimmed at all depends on ~magit-diff-highlight-hunk-region-functions~. +- User Option: magit-diff-extra-stat-arguments + + This option specifies additional arguments to be used alongside + ~--stat~. + + The value is a list of zero or more arguments or a function that + takes no argument and returns such a list. These arguments are + allowed here: ~--stat-width~, ~--stat-name-width~, + ~--stat-graph-width~ and ~--compact-summary~. Also see [[man:git-diff]] + *** Revision Buffer - User Option: magit-revision-insert-related-refs @@ -3387,7 +3498,7 @@ that were created using a Magit command. ** References Buffer -*** _ :ignore: +*** _ - Key: y, magit-show-refs @@ -3420,6 +3531,10 @@ This command lists branches and tags in a dedicated buffer. Each reference is being compared with a branch read from the user. +- Key: y r, magit-refs-set-show-commit-count + + This command changes for which refs the commit count is shown. + - User Option: magit-refs-show-commit-count Whether to show commit counts in Magit-Refs mode buffers. @@ -3661,7 +3776,10 @@ Bisecting a bug means to find the commit that introduced it. This command starts such a bisect session by asking for a known - good and a bad commit. + good commit and a known bad commit. If you're bisecting a change + that isn't a regression, you can select alternate terms that are + conceptually more fitting than "bad" and "good", but the infix + arguments to do so are disabled by default. - Key: B s, magit-bisect-run @@ -3680,6 +3798,13 @@ Mark the current commit as good. Use this after you have asserted that the commit does not contain the bug in question. +- Key: B m, magit-bisect-mark + + Mark the current commit with one of the bisect terms. This command + provides an alternative to ~magit-bisect-bad~ and + ~magit-bisect-good~ and is useful when using terms other than "bad" + and "good". This suffix is disabled by default. + - Key: B k, magit-bisect-skip Skip the current commit. Use this if for some reason the current @@ -3808,10 +3933,7 @@ Also see [[man:git-blame]] To start blaming invoke the ~magit-file-dispatch~ transient prefix -command by pressing ~C-c M-g~. (This is only the default binding and -the recommended binding is ~C-c g~. Also neither binding may be -available if you disabled ~global-magit-file-mode~. Also see [[*Minor -Mode for Buffers Visiting Files]].) +command by pressing ~C-c M-g~. The blaming suffix commands can be invoked from the dispatch transient. However if you want to set an infix argument, then you @@ -3977,7 +4099,7 @@ * Manipulating ** Creating Repository -- Key: M-x magit-init, magit-init +- Key: I, magit-init This command initializes a repository and then shows the status buffer for the new repository. @@ -4109,7 +4231,7 @@ including the name of the owner. ** Staging and Unstaging -*** _ :ignore: +*** _ Like Git, Magit can of course stage and unstage complete files. Unlike Git, it also allows users to gracefully un-/stage @@ -4255,6 +4377,10 @@ Remove the change at point from the working tree. + On a hunk or file with unresolved conflicts prompt which side to + keep (while discarding the other). If point is within the text + of a side, then keep that side without prompting. + - Key: v, magit-reverse Reverse the change at point in the working tree. @@ -4266,7 +4392,7 @@ appropriate (i.e. when ~git apply~ is used internally). ** Committing -*** _ :ignore: +*** _ When the user initiates a commit, Magit calls ~git commit~ without any arguments, so Git has to get it from the user. It creates the file @@ -4351,6 +4477,10 @@ Whether to ask to stage all unstaged changes when committing and nothing is staged. +- User Option: magit-commit-show-diff + + Whether the relevant diff is automatically shown when committing. + - User Option: magit-commit-extend-override-date Whether using ~magit-commit-extend~ changes the committer date. @@ -4368,6 +4498,44 @@ always require confirmation because making an error while using those is harder to recover from. +- User Option: magit-post-commit-hook + + Hook run after creating a commit without the user editing a message. + + This hook is run by ~magit-refresh~ if ~this-command~ is a member + of ~magit-post-stage-hook-commands~. This only includes commands + named ~magit-commit-*~ that do *not* require that the user edits + the commit message in a buffer. + + Also see ~git-commit-post-finish-hook~. + +- User Option: magit-commit-diff-inhibit-same-window + + Whether to inhibit use of same window when showing diff while + committing. + + When writing a commit, then a diff of the changes to be committed + is automatically shown. The idea is that the diff is shown in a + different window of the same frame and for most users that just + works. In other words most users can completely ignore this + option because its value doesn't make a difference for them. + + However for users who configured Emacs to never create a new + window even when the package explicitly tries to do so, then + displaying two new buffers necessarily means that the first is + immediately replaced by the second. In our case the message + buffer is immediately replaced by the diff buffer, which is of + course highly undesirable. + + A workaround is to suppress this user configuration in this + particular case. Users have to explicitly opt-in by toggling + this option. We cannot enable the workaround unconditionally + because that again causes issues for other users: if the frame + is too tiny or the relevant settings too aggressive, then the + diff buffer would end up being displayed in a new frame. + + Also see https://github.com/magit/magit/issues/4132. + *** Editing Commit Messages After initiating a commit as described in the previous section, two new @@ -4723,8 +4891,8 @@ - User Option: magit-branch-direct-configure This option controls whether the transient command ~magit-branch~ can - be used directly change the values Git variables. This defaults to - ~t~ (to avoid changing key bindings). When set to ~nil~, then no + be used to directly change the values of Git variables. This defaults + to ~t~ (to avoid changing key bindings). When set to ~nil~, then no variables are displayed by that transient command, and its suffix command ~magit-branch-configure~ has to be used instead to view and change branch related variables. @@ -4769,8 +4937,8 @@ - Key: b c, magit-branch-and-checkout - This command creates a new branch like ~magit-branch~, but then also - checks it out. + This command creates a new branch like ~magit-branch-create~, but then + also checks it out. Also see option ~magit-branch-prefer-remote-upstream~. @@ -4862,7 +5030,7 @@ - User Option: magit-branch-read-upstream-first When creating a branch, whether to read the upstream branch before - the name of the branch that is to be created. The default is ~nil~, + the name of the branch that is to be created. The default is ~t~, and I recommend you leave it at that. - User Option: magit-branch-prefer-remote-upstream @@ -4945,7 +5113,7 @@ repositories, then you might use something like: #+BEGIN_SRC emacs-lisp - (("origin/master" "master" "next" "maint")) + (("origin/master" . ("master" "next" "maint"))) #+END_SRC Or if the names of all your ephemeral branches contain a slash, @@ -4962,6 +5130,20 @@ ("origin/master" . "\\`feature/")) #+END_SRC + UPSTREAM can be a local branch: + + #+BEGIN_SRC emacs-lisp + (("master" . ("master" "next" "maint"))) + #+END_SRC + +Because the main branch is no longer almost always named "master" +you should also account for other common names: + + #+BEGIN_SRC emacs-lisp + (("main" . ("main" "master" "next" "maint")) + ("master" . ("main" "master" "next" "maint"))) + #+END_SRC + - Command: magit-branch-orphan This command creates and checks out a new orphan branch with @@ -5328,6 +5510,13 @@ stages the file when you save the buffer after resolving the last conflict. +Magit now wraps the mentioned Smerge commands, allowing you to use +these key bindings without having to go to the file-visiting buffer. +Additionally ~k~ (~magit-discard~) on a hunk with unresolved conflicts +asks which side to keep or, if point is on a side, then it keeps it +without prompting. Similarly ~k~ on a unresolved file ask which side +to keep. + Alternatively you could use Ediff, which uses separate buffers for the different versions of the file. To resolve conflicts in a file using Ediff press ~e~ while point is on such a file in the status buffer. @@ -5341,7 +5530,7 @@ truly complex conflicts, the latter is usually overkill. ** Rebasing -*** _ :ignore: +*** _ Also see [[man:git-rebase]] For information on how to resolve conflicts that occur during rebases see the preceding section. @@ -5771,7 +5960,7 @@ answer the question "Do these commits make the same change?". ** Cherry Picking -*** _ :ignore: +*** _ Also see [[man:git-cherry-pick]] @@ -5937,6 +6126,12 @@ Reset the ~HEAD~, index, and working tree to some commit read from the user and defaulting to the commit at point. +- Key: X k, magit-reset-keep + + Reset the ~HEAD~, index, and working tree to some commit read from the + user and defaulting to the commit at point. Uncommitted changes are + kept as-is. + - Key: X i, magit-reset-index Reset the index to some commit read from the user and defaulting to @@ -6376,6 +6571,16 @@ This command pushes a tag to another repository. +One of the infix arguments, ~--force-with-lease~, deserves a word of +caution. It is passed without a value, which means "permit a force +push as long as the remote-tracking branches match their counterparts +on the remote end". If you've set up a tool to do automatic fetches +(Magit itself does not provide such functionality), using +~--force-with-lease~ can be dangerous because you don't actually +control or know the state of the remote-tracking refs. In that case, +you should consider setting ~push.useForceIfIncludes~ to ~true~ +(available since Git 2.30). + Two more push commands exist, which by default are not available from the push transient. See their doc-strings for instructions on how to add them to the transient. @@ -6391,6 +6596,15 @@ ~branch..remote~, ~branch..merge~, and ~remote..push~. + If you add this suffix to a transient prefix without explicitly + specifying the description, then an attempt is made to predict + what this command will do. For example: + + #+BEGIN_SRC emacs-lisp + (transient-insert-suffix 'magit-push \"p\" + '(\"i\" magit-push-implicitly))" + #+END_SRC + - Command: magit-push-to-remote remote args This command pushes to the remote REMOTE without using an explicit @@ -6495,12 +6709,12 @@ - Key: t t, magit-tag-create This command creates a new tag with the given NAME at REV. With a - prefix argument it creates an annotate tag. + prefix argument it creates an annotated tag. - Key: t r, magit-tag-release - This commands creates an annotated release tag. It assumes that - release tags match ~magit-release-tag-regexp~. + This commands creates a release tag. It assumes that release tags + match ~magit-release-tag-regexp~. First it prompts for the name of the new tag using the highest existing tag as initial input and leaving it to the user to @@ -6509,17 +6723,13 @@ ~v1.2.3-custom.1~), you can set the ~magit-release-tag-regexp~ and ~magit-tag-version-regexp-alist~ variables. - Then it prompts for the message of the new tag. The proposed tag - message is based on the message of the highest tag, provided that - that contains the corresponding version string and substituting the - new version string for that. Otherwise it proposes something like - "Foo-Bar 1.2.3", given, for example, a TAG "v1.2.3" and a repository - located at something like "/path/to/foo-bar". - - Then it calls "git tag --annotate --sign -m MSG TAG" to create the - tag, regardless of whether these arguments are enabled in the - transient. Finally it shows the refs buffer to let the user quickly - review the result. + If ~--annotate~ is enabled then it prompts for the message of the + new tag. The proposed tag message is based on the message of the + highest tag, provided that that contains the corresponding version + string and substituting the new version string for that. Otherwise + it proposes something like "Foo-Bar 1.2.3", given, for example, a + TAG "v1.2.3" and a repository located at something like + "/path/to/foo-bar". - Key: t k, magit-tag-delete @@ -6602,7 +6812,7 @@ ~refs/notes/~ namespace (or ~**~ if some names contain slashes). ** Submodules -*** _ :ignore: +*** _ Also see [[man:git-submodule]] @@ -6611,7 +6821,7 @@ The command ~magit-list-submodules~ displays a list of the current repository's submodules in a separate buffer. It's also possible to display information about submodules directly in the status buffer of -the super-repository by adding ~magit-insert-submodules~ to the hook +the super-repository by adding ~magit-insert-modules~ to the hook ~magit-status-sections-hook~ as described in [[*Status Module Sections]]. - Command: magit-list-submodules @@ -6635,17 +6845,6 @@ has to return a string to be inserted or nil. PROPS is an alist that supports the keys ~:right-align~ and ~:pad-right~. -- Function: magit-insert-submodules - - Insert sections for all submodules. For each section insert the - path, the branch, and the output of ~git describe --tags~, - or, failing that, the abbreviated HEAD commit hash. - - Press ~RET~ on such a submodule section to show its own status buffer. - Press ~RET~ on the "Modules" section to display a list of submodules - in a separate buffer. This shows additional information not - displayed in the super-repository's status buffer. - *** Submodule Transient - Key: o, magit-submodule @@ -6770,29 +6969,29 @@ Also see [[man:git-worktree]] -- Key: %, magit-worktree +- Key: Z, magit-worktree This transient prefix command binds the following suffix commands and displays them in a temporary buffer until a suffix is invoked. -- Key: % b, magit-worktree-checkout +- Key: Z b, magit-worktree-checkout Checkout BRANCH in a new worktree at PATH. -- Key: % c, magit-worktree-branch +- Key: Z c, magit-worktree-branch Create a new BRANCH and check it out in a new worktree at PATH. -- Key: % m, magit-worktree-move +- Key: Z m, magit-worktree-move Move an existing worktree to a new PATH. -- Key: % k, magit-worktree-delete +- Key: Z k, magit-worktree-delete Delete a worktree, defaulting to the worktree at point. The primary worktree cannot be deleted. -- Key: % g, magit-worktree-status +- Key: Z g, magit-worktree-status Show the status for the worktree at point. @@ -6800,13 +6999,35 @@ If the worktree at point is the one whose status is already being displayed in the current buffer, then show it in Dired instead. +** Bundle + +Also see [[man:git-bundle]] + +- Command: magit-bundle + + This transient prefix command binds several suffix commands for + running ~git bundle~ subcommands and displays them in a temporary + buffer until a suffix is invoked. + ** Common Commands +- Command: magit-switch-to-repository-buffer +- Command: magit-switch-to-repository-buffer-other-window +- Command: magit-switch-to-repository-buffer-other-frame +- Command: magit-display-repository-buffer + + These commands read any existing Magit buffer that belongs to the + current repository from the user and then switch to the selected + buffer (without refreshing it). + + The last variant uses ~magit-display-buffer~ to do so and thus + respects ~magit-display-buffer-function~. + These are some of the commands that can be used in all buffers whose major-modes derive from ~magit-mode~. There are other common commands beside the ones below, but these didn't fit well anywhere else. -- Key: M-w, magit-copy-section-value +- Key: C-w, magit-copy-section-value This command saves the value of the current section to the ~kill-ring~, and, provided that the current section is a commit, @@ -6819,11 +7040,12 @@ When the region is active, this command saves that to the ~kill-ring~, like ~kill-ring-save~ would, instead of behaving as - described above. If a prefix argument is used and the region is - within a hunk, it strips the outer diff marker column before saving - the text. + described above. If a prefix argument is used and the region is + within a hunk, then it strips the diff marker column and keeps + only either the added or removed lines, depending on the sign of + the prefix argument. -- Key: C-w, magit-copy-buffer-revision +- Key: M-w, magit-copy-buffer-revision This command saves the revision being displayed in the current buffer to the ~kill-ring~ and also pushes it to the ~magit-revision-stack~. It @@ -6842,7 +7064,7 @@ behave like ~kill-ring-save~ instead of as described above. ** Wip Modes -*** _ :ignore: +*** _ Git keeps *committed* changes around long enough for users to recover changes they have accidentally deleted. It does so by not garbage @@ -7074,54 +7296,21 @@ Mode-line lighter for ~magit-wip-initial-backup-mode~. -** Minor Mode for Buffers Visiting Files +** Commands for Buffers Visiting Files -The minor-mode ~magit-file-mode~ enables certain Magit features in -file-visiting buffers belonging to a Git repository. The globalized -variant ~global-magit-file-mode~ enables the local mode in all such -buffers. It is enabled by default. Currently the local mode only -establishes a few key bindings, but this might be extended in the -future. - -- User Option: global-magit-file-mode - - Whether to establish certain Magit key bindings in all file-visiting - buffers belonging to any Git repository. This is enabled by default. - This globalized mode turns on the local minor-mode ~magit-file-mode~ - in all suitable buffers. - -- Variable: magit-file-mode-map - - This keymap is used by the local minor-mode ~magit-file-mode~ and - establishes the key bindings described below. - - Note that the default binding for ~magit-file-dispatch~ is very - cumbersome to use and that we recommend that you add a better - binding. - - Instead of ~C-c M-g~ I would have preferred to use ~C-c g~ because (1) - it is similar to ~C-x g~ (the recommended global binding for - ~~magit-status~), (2) we cannot use ~C-c C-g~ because we have been - recommending that that be bound to ~magit-dispatch~ for a long time, - (3) we cannot use ~C-x C-g~ because that is a convenient way of - aborting the incomplete key sequence ~C-x~, and most importantly (4) - it would make it much easier to type the next key (a suffix binding) - because most of those are letters. - - For example ~C-c g b~ is much easier to type than ~C-c M-g b~. For - suffix bindings that use uppercase letters, the default is just - horrible—having to use e.g. ~C-c M-g B~ (~Control+c Meta+g Shift+b~) - would drive anyone up the walls (or to Vim). - - However ~C-c LETTER~ bindings are reserved for users (see - [[info:elisp#Key Binding Conventions]]). Packages are forbidden from - using those. Doing so anyway is considered heresy. Therefore if - you want a better binding, you have to add it yourself: +Magit defines a few global key bindings unless the user sets +~magit-define-global-key-bindings~ to ~nil~. This includes binding ~C-c +M-g~ to ~magit-file-dispatch~. ~C-c g~ would be a much better binding +but the ~C-c ~ namespace is reserved for users, meaning that +packages are not allowed to use it. If you want to use ~C-c g~, then +you have to add that binding yourself. Also see [[*Default Bindings]] +and [[info:elisp#Key Binding Conventions]]. - #+BEGIN_SRC emacs-lisp - (define-key magit-file-mode-map - (kbd "C-c g") 'magit-file-dispatch) - #+END_SRC +If you want a better binding, you have to add it yourself: + +#+BEGIN_SRC emacs-lisp + (global-set-key (kbd "C-c g") 'magit-file-dispatch) +#+END_SRC The key bindings shown below assume that you have not improved the binding for ~magit-file-dispatch~. @@ -7131,6 +7320,9 @@ This transient prefix command binds the following suffix commands and displays them in a temporary buffer until a suffix is invoked. + When invoked in a buffer that does not visit a file, then it falls + back to regular ~magit-dispatch~. + - Key: C-c M-g s, magit-stage-file Stage all changes to the file being visited in the current buffer. @@ -7267,7 +7459,7 @@ Kill the current buffer. * Customizing -** _ :ignore: +** _ Both Git and Emacs are highly customizable. Magit is both a Git porcelain as well as an Emacs package, so it makes sense to customize @@ -7366,7 +7558,7 @@ #+END_SRC ** Essential Settings -*** _ :ignore: +*** _ The next two sections list and discuss several variables that many users might want to customize, for safety and/or performance reasons. @@ -7405,7 +7597,7 @@ Automatically]]. *** Performance -**** _ :ignore: +**** _ After Magit has run ~git~ for side-effects, it also refreshes the current Magit buffer and the respective status buffer. This is @@ -7470,7 +7662,7 @@ **** Log Performance :PROPERTIES: -:NONODE: t +:UNNUMBERED: notoc :END: When showing logs, Magit limits the number of commits initially shown @@ -7500,7 +7692,7 @@ **** Diff Performance :PROPERTIES: -:NONODE: t +:UNNUMBERED: notoc :END: If diffs are slow, then consider turning off some optional diff @@ -7527,7 +7719,7 @@ **** Refs Buffer Performance :PROPERTIES: -:NONODE: t +:UNNUMBERED: notoc :END: When refreshing the "references buffer" is slow, then that's usually @@ -7547,7 +7739,7 @@ **** Committing Performance :PROPERTIES: -:NONODE: t +:UNNUMBERED: notoc :END: When you initiate a commit, then Magit by default automatically shows @@ -7569,27 +7761,6 @@ the diff, which is useful because it increases the odds that you spot potential issues. -**** The Built-In VC Package -:PROPERTIES: -:NONODE: t -:END: - -Emacs comes with a version control interface called "VC", see -[[info:emacs#Version Control]]. It is enabled be default, and if you don't -use it in addition to Magit, then you should disable it to keep it -from performing unnecessary work: - -#+BEGIN_SRC emacs-lisp - (setq vc-handled-backends nil) -#+END_SRC - -You can also disable its use for Git but keep using it when using -another version control system: - -#+BEGIN_SRC emacs-lisp - (setq vc-handled-backends (delq 'Git vc-handled-backends)) -#+END_SRC - **** Microsoft Windows Performance In order to update the status buffer, ~git~ has to be run a few dozen @@ -7630,16 +7801,60 @@ takes about twice as long on Darwin compared to Linux.) See [fn:mac1] for more information. -On Catalina, and potentially other macOS releases, there may be a -performance problem where any action takes 20 times longer on Darwin -than on Linux. This can be fixed by setting ~magit-git-executable~ to -the absolute path of the ~git~ executable, instead of relying on -resolving the ~$PATH~. - [fn:mac1] https://lists.gnu.org/archive/html/bug-gnu-emacs/2017-04/msg00201.html +*** Default Bindings + +- User Option: magit-define-global-key-bindings + + This option controls whether some Magit commands are automatically + bound in the global keymap even before Magit is used for the first + time in the current session. + + If this variable is non-nil, which it is by default, then the + following bindings may be added to the global keymap. + + | ~C-x g~ | ~magit-status~ | + | ~C-x M-g~ | ~magit-dispatch~ | + | ~C-c M-g~ | ~magit-file-dispatch~ | + + These bindings may be added when ~after-init-hook~ is run. + Each binding is added if and only if at that time no other key + is bound to the same command and no other command is bound to + the same key. In other words we try to avoid adding bindings + that are unnecessary, as well as bindings that conflict with + other bindings. + + Adding the above bindings is delayed until ~after-init-hook~ + is called to allow users to set the variable anywhere in their + init file (without having to make sure to do so before ~magit~ + is loaded or autoloaded) and to increase the likelihood that + all the potentially conflicting user bindings have already + been added. + + To set this variable use either ~setq~ or the Custom interface. + Do not use the function ~customize-set-variable~ because doing + that would cause Magit to be loaded immediately when that form + is evaluated (this differs from ~custom-set-variables~, which + doesn't load the libraries that define the customized variables). + + Setting this variable to nil has no effect if that is done after + the key bindings have already been added. + + We recommend that you bind ~C-c g~ instead of ~C-c M-g~ to + ~magit-file-dispatch~. The former is a much better binding + but the ~C-c ~ namespace is strictly reserved for + users; preventing Magit from using it by default. + + #+BEGIN_SRC emacs-lisp + (global-set-key (kbd "C-c g") 'magit-file-dispatch) + #+END_SRC + + Also see [[*Commands for Buffers Visiting Files]] and [[info:elisp#Key + Binding Conventions]]. + * Plumbing -** _ :ignore: +** _ The following sections describe how to use several of Magit's core abstractions to extend Magit itself or implement a separate extension. @@ -7654,7 +7869,7 @@ https://github.com/magit/magit/wiki/Plugin-Dispatch-Key-Registry. ** Calling Git -*** _ :ignore: +*** _ Magit provides many specialized functions for calling Git. All of these functions are defined in either ~magit-git.el~ or ~magit-process.el~ @@ -7735,6 +7950,20 @@ add a section containing git's standard error in the current repository's process buffer. +- Function: magit-process-git destination &rest args + + Calls Git synchronously in a separate process, returning its exit + code. DESTINATION specifies how to handle the output, like for + ~call-process~, except that file handlers are supported. Enables + Cygwin's "noglob" option during the call and ensures unix eol + conversion. + +- Function: magit-process-file process &optional infile buffer display &rest args + + Processes files synchronously in a separate process. Identical to + ~process-file~ but temporarily enables Cygwin's "noglob" option during + the call and ensures unix eol conversion. + If an error occurs when using one of the above functions, then that is usually due to a bug, i.e. using an argument which is not actually supported. Such errors are usually not reported, but when @@ -7793,30 +8022,15 @@ Calls git synchronously with ARGS and then refreshes. -- Function: magit-run-git-with-input input &rest args - - Calls git synchronously with ARGS and sends it INPUT on standard - input. - - INPUT should be a buffer or the name of an existing buffer. The - content of that buffer is used as the process' standard input. - After the process returns a refresh is performed. - - As a special case, INPUT may also be nil. In that case the content - of the current buffer is used as standard input and *no* refresh is - performed. +- Function: magit-run-git-with-input &rest args - This function actually runs git asynchronously. But then it waits - for the process to return, so the function itself is synchronous. + Calls git synchronously with ARGS and sends it the content of the + current buffer on standard input. -- Function: magit-run-git-with-logfile file &rest args - - Calls git synchronously with ARGS. The process' output is saved in - FILE. This is rarely useful and so this function might be removed - in the future. - - This function actually runs git asynchronously. But then it waits - for the process to return, so the function itself is synchronous. + If the current buffer's ~default-directory~ is on a remote + filesystem, this function actually runs git asynchronously. But + then it waits for the process to return, so the function itself is + synchronous. - Function: magit-git &rest args @@ -7858,7 +8072,7 @@ current when this function was called (if it is a Magit buffer and still alive), as well as the respective Magit status buffer. -- Function: magit-start-git &rest args +- Function: magit-start-git input &rest args Start Git, prepare for refresh, and return the process object. @@ -8225,7 +8439,7 @@ of this variable and then calling this ~magit-refresh-function~. ** Conventions -*** _ :ignore: +*** _ Also see [[*Completion and Confirmation]]. @@ -8371,7 +8585,7 @@ :PROPERTIES: :APPENDIX: t :END: -** _ :ignore: +** _ The next two nodes lists frequently asked questions. For a list of frequently *and recently* asked questions, i.e. questions that haven't @@ -8381,6 +8595,24 @@ Please also use the [[*Debugging Tools]]. ** FAQ - How to ...? +*** How to pronounce Magit? + +Either ~mu[m's] git~ or ~magi{c => t}~ is fine. + +The slogan is "It's Magit! The magical Git client", so it makes sense +to pronounce Magit like magic, while taking into account that C and T +do not sound the same. + +The German "Magie" is not pronounced the same as the English "magic", +so if you speak German then you can use the above rational to justify +using the former pronunciation; ~Mag{ie => it}~. + +You can also choose to use the former pronunciation just because you +like it better. + +Also see https://magit.vc/assets/videos/magic.mp4. +Also see https://emacs.stackexchange.com/questions/13696. + *** How to show git's output? To show the output of recently run git commands, press ~$~ (or, if that @@ -8460,6 +8692,19 @@ command ~magit-ediff-resolve~ which only shows yet-to-be resolved conflicts. +*** Should I disable VC? + +If you don't use VC (the built-in version control interface) then +you might be tempted to disable it, not least because we used to +recommend that you do that. + +We no longer recommend that you disable VC. Doing so would break +useful third-party packages (such as ~diff-hl~), which depend on VC +being enabled. + +If you choose to disable VC anyway, then you can do so by changing +the value of ~vc-handled-backends~. + ** FAQ - Issues and Errors *** Magit is slow @@ -8544,18 +8789,13 @@ But doing so isn't good for performance. For more (overly optimistic) information see [[info:emacs#VC Mode Line]]. -If you don't really care about seeing that information in the -mode-line, but just don't want to see /incorrect/ information, then -consider disabling VC when using Git: +If you don't really care about seeing this information in the +mode-line, but just don't want to see /incorrect/ information, +then consider simply not displaying it in the mode-line: #+BEGIN_SRC emacs-lisp - (setq vc-handled-backends (delq 'Git vc-handled-backends)) -#+END_SRC - -Or to disable it completely: - -#+BEGIN_SRC emacs-lisp - (setq vc-handled-backends nil) + (setq-default mode-line-format + (delete '(vc-mode vc-mode) mode-line-format)) #+END_SRC *** A branch and tag sharing the same name breaks SOMETHING @@ -8628,8 +8868,8 @@ #+END_SRC This will actually end up using ~emacs~, not ~emacsclient~. If you do -this, then can still edit the commit message but ~git-commit-mode~ won't -be used and you have to exit ~emacs~ to finish the process. +this, then you can still edit the commit message but ~git-commit-mode~ +won't be used and you have to exit ~emacs~ to finish the process. Tautology ahead. If you want to be able to use ~emacsclient~ to connect to a running ~emacs~ instance, even though no ~emacs~ instance is running, @@ -8650,6 +8890,35 @@ instead use ~magit-diff-visit-file-hook~ to reveal the text, possibly using ~reveal-post-command~ or for Org buffers ~org-reveal~. +*** I am unable to stage when using Tramp from MS Windows + +Magit may be unable to stage (or otherwise apply) individual hunks +when you are connected to remote machine using Tramp and the local +machine uses MS Windows. + +There appears to be a problem with ~process-send-eof~ in this scenario, +as mentioned at the end of ~tramp-tests.el~. I have contacted the Tramp +maintainer about this. For now this unfortunately means that it just +doesn't work and we cannot do anything about it. If you have more +information, then please comment on +https://github.com/magit/magit/issues/3624. + +*** I am no longer able to save popup defaults + +Magit used to use Magit-Popup to implement the transient popup menus. +Now it used Transient instead, which is Magit-Popup's successor. + +In the older Magit-Popup menus, it was possible to save user settings +(e.g. setting the gpg signing key for commits) by using ~C-c C-c~ in the +popup buffer. This would dismiss the popup, but save the settings as +the defaults for future popups. + +When switching to Transient menus, this functionality is now available +via ~C-x C-s~ instead; the ~C-x~ prefix has other options as well when +using Transient, which will be displayed when it is typed. See +https://magit.vc/manual/transient/Saving-Values.html#Saving-Values for +more details. + * Debugging Tools Magit and its dependencies provide a few debugging tools, and we @@ -8724,13 +8993,13 @@ :INDEX: vr :END: -* _ Copying +* Copying :PROPERTIES: :COPYING: t :END: #+BEGIN_QUOTE -Copyright (C) 2015-2020 Jonas Bernoulli +Copyright (C) 2015-2021 Jonas Bernoulli You can redistribute this document and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -8743,8 +9012,6 @@ General Public License for more details. #+END_QUOTE -* _ :ignore: - # LocalWords: ARG ARGS CONDITIONs ChangeLog DNS Dired Ediff Ediffing # LocalWords: Elpa Emacsclient FUNC Flyspell Git Git's Gitk HOOK's # LocalWords: IDENT Ido Junio LocalWords Magit Magit's Magitian Magitians @@ -8770,9 +9037,8 @@ # eval: (require 'magit-utils nil t) # eval: (require 'org-man nil t) # eval: (require 'ol-man nil t) -# eval: (require 'ox-extra nil t) # eval: (require 'ox-texinfo+ nil t) -# eval: (and (featurep 'ox-extra) (ox-extras-activate '(ignore-headlines))) +# org-texinfo+-dissolve-noexport-headlines: t # indent-tabs-mode: nil # org-src-preserve-indentation: nil # End: diff -Nru magit-2.99.0.git0957.ge8c7bd03/Documentation/magit-section.org magit-3.3.0/Documentation/magit-section.org --- magit-2.99.0.git0957.ge8c7bd03/Documentation/magit-section.org 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/Documentation/magit-section.org 2021-10-06 12:51:17.000000000 +0000 @@ -2,13 +2,13 @@ :PREAMBLE: #+AUTHOR: Jonas Bernoulli #+EMAIL: jonas@bernoul.li -#+DATE: 2015-2020 +#+DATE: 2015-2021 #+LANGUAGE: en #+TEXINFO_DIR_CATEGORY: Emacs #+TEXINFO_DIR_TITLE: Magit-Section: (magit-section). #+TEXINFO_DIR_DESC: Use Magit sections in your own packages. -#+SUBTITLE: for version 2.90.1 (v2.90.1-948-ge293416ce+1) +#+SUBTITLE: for version 3.3.0 #+TEXINFO_DEFFN: t #+OPTIONS: H:4 num:3 toc:2 @@ -26,10 +26,10 @@ can use sections in your own packages. #+TEXINFO: @noindent -This manual is for Magit-Section version 2.90.1 (v2.90.1-948-ge293416ce+1). +This manual is for Magit-Section version 3.3.0. #+BEGIN_QUOTE -Copyright (C) 2015-2020 Jonas Bernoulli +Copyright (C) 2015-2021 Jonas Bernoulli You can redistribute this document and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -60,18 +60,25 @@ * Creating Sections -- Function: magit-insert-section [name] (type &optional value hide) &rest body +- Macro: magit-insert-section [name] (type &optional value hide) &rest body - Insert a section at point. - - TYPE is the section type, a symbol. Many commands that act on - the current section behave differently depending on that type. - Like functions and variables, TYPE must be prefixed with the - package name. (For historic reasons the types used by Magit - and Forge do not use a package prefix.) - - Optional VALUE is the value of the section, usually a string - that is required when acting on the section. + Create a section object of type CLASS, storing VALUE in its + ~value~ slot, and insert the section at point. CLASS is a + subclass of `magit-section' or has the form ~(eval FORM)~, in + which case FORM is evaluated at runtime and should return a + subclass. In other places a sections class is oftern referred + to as its "type". + + Many commands behave differently depending on the class of the + current section and sections of a certain class can have their + own keymap, which is specified using the `keymap' class slot. + The value of that slot should be a variable whose value is a + keymap. + + For historic reasons Magit and Forge in most cases use symbols + as CLASS that don't actually identify a class and that lack the + appropriate package prefix. This works due to some undocumented + kludges, which are not available to other packages. When optional HIDE is non-nil collapse the section body by default, i.e. when first creating the section, but not when @@ -97,12 +104,6 @@ a section by washing Git's output and Git didn't actually output anything this time around. - For historic reasons, if a variable ~magit-TYPE-section-map~ - or ~forge-TYPE-section-map~ exists, then use that as the - text-property keymap~ of all text belonging to the section (but - this may be overwritten in subsections). TYPE can also have the - form ~(eval FORM)~ in which case FORM is evaluated at runtime. - - Function: magit-insert-heading &rest args Insert the heading for the section currently being inserted. @@ -254,7 +255,7 @@ :END: #+BEGIN_QUOTE -Copyright (C) 2015-2020 Jonas Bernoulli +Copyright (C) 2015-2021 Jonas Bernoulli You can redistribute this document and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -267,8 +268,6 @@ General Public License for more details. #+END_QUOTE -* _ :ignore: - # LocalWords: ARGS CONDITIONs EVAL Git Git's IDENT # LocalWords: LocalWords MERCHANTABILITY Magit Makefile # LocalWords: alist eval featurep ident keymap magit ol @@ -279,9 +278,8 @@ # eval: (require 'magit-utils nil t) # eval: (require 'org-man nil t) # eval: (require 'ol-man nil t) -# eval: (require 'ox-extra nil t) # eval: (require 'ox-texinfo+ nil t) -# eval: (and (featurep 'ox-extra) (ox-extras-activate '(ignore-headlines))) +# org-texinfo+-dissolve-noexport-headlines: t # indent-tabs-mode: nil # org-src-preserve-indentation: nil # End: diff -Nru magit-2.99.0.git0957.ge8c7bd03/Documentation/magit-section.texi magit-3.3.0/Documentation/magit-section.texi --- magit-2.99.0.git0957.ge8c7bd03/Documentation/magit-section.texi 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/Documentation/magit-section.texi 2021-10-06 12:51:17.000000000 +0000 @@ -8,7 +8,7 @@ @copying @quotation -Copyright (C) 2015-2020 Jonas Bernoulli +Copyright (C) 2015-2021 Jonas Bernoulli You can redistribute this document and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -31,7 +31,7 @@ @finalout @titlepage @title Magit-Section Developer Manual -@subtitle for version 2.90.1 (v2.90.1-948-ge293416ce+1) +@subtitle for version 3.3.0 @author Jonas Bernoulli @page @vskip 0pt plus 1filll @@ -54,10 +54,10 @@ can use sections in your own packages. @noindent -This manual is for Magit-Section version 2.90.1 (v2.90.1-948-ge293416ce+1). +This manual is for Magit-Section version 3.3.0. @quotation -Copyright (C) 2015-2020 Jonas Bernoulli +Copyright (C) 2015-2021 Jonas Bernoulli You can redistribute this document and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -98,18 +98,25 @@ @node Creating Sections @chapter Creating Sections -@defun magit-insert-section [name] (type &optional value hide) &rest body +@defmac magit-insert-section [name] (type &optional value hide) &rest body -Insert a section at point. - -TYPE is the section type, a symbol. Many commands that act on -the current section behave differently depending on that type. -Like functions and variables, TYPE must be prefixed with the -package name. (For historic reasons the types used by Magit -and Forge do not use a package prefix.) - -Optional VALUE is the value of the section, usually a string -that is required when acting on the section. +Create a section object of type CLASS, storing VALUE in its +@code{value} slot, and insert the section at point. CLASS is a +subclass of `magit-section' or has the form @code{(eval FORM)}, in +which case FORM is evaluated at runtime and should return a +subclass. In other places a sections class is oftern referred +to as its "type". + +Many commands behave differently depending on the class of the +current section and sections of a certain class can have their +own keymap, which is specified using the `keymap' class slot. +The value of that slot should be a variable whose value is a +keymap. + +For historic reasons Magit and Forge in most cases use symbols +as CLASS that don't actually identify a class and that lack the +appropriate package prefix. This works due to some undocumented +kludges, which are not available to other packages. When optional HIDE is non-nil collapse the section body by default, i.e. when first creating the section, but not when @@ -134,13 +141,7 @@ of the partially inserted section. This can happen when creating a section by washing Git's output and Git didn't actually output anything this time around. - -For historic reasons, if a variable @code{magit-TYPE-section-map} -or @code{forge-TYPE-section-map} exists, then use that as the -text-property keymap~ of all text belonging to the section (but -this may be overwritten in subsections). TYPE can also have the -form @code{(eval FORM)} in which case FORM is evaluated at runtime. -@end defun +@end defmac @defun magit-insert-heading &rest args diff -Nru magit-2.99.0.git0957.ge8c7bd03/Documentation/magit.texi magit-3.3.0/Documentation/magit.texi --- magit-2.99.0.git0957.ge8c7bd03/Documentation/magit.texi 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/Documentation/magit.texi 2021-10-06 12:51:17.000000000 +0000 @@ -8,7 +8,7 @@ @copying @quotation -Copyright (C) 2015-2020 Jonas Bernoulli +Copyright (C) 2015-2021 Jonas Bernoulli You can redistribute this document and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -31,7 +31,7 @@ @finalout @titlepage @title Magit User Manual -@subtitle for version 2.90.1 (v2.90.1-954-g509e97b7+1) +@subtitle for version 3.3.0 @author Jonas Bernoulli @page @vskip 0pt plus 1filll @@ -53,10 +53,10 @@ Magit and Git itself deserve to be called porcelains. @noindent -This manual is for Magit version 2.90.1 (v2.90.1-954-g509e97b7+1). +This manual is for Magit version 3.3.0. @quotation -Copyright (C) 2015-2020 Jonas Bernoulli +Copyright (C) 2015-2021 Jonas Bernoulli You can redistribute this document and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -261,9 +261,10 @@ * Submodules:: * Subtree:: * Worktree:: +* Bundle:: * Common Commands:: * Wip Modes:: -* Minor Mode for Buffers Visiting Files:: +* Commands for Buffers Visiting Files:: * Minor Mode for Buffers Visiting Blobs:: Submodules @@ -287,6 +288,7 @@ * Safety:: * Performance:: +* Default Bindings:: Plumbing @@ -321,11 +323,13 @@ FAQ - How to @dots{}? +* How to pronounce Magit?:: * How to show git's output?:: * How to install the gitman info manual?:: * How to show diffs for gpg-encrypted files?:: * How does branching and pushing work?:: * Can Magit be used as @code{ediff-version-control-package}?:: +* Should I disable VC@?:: FAQ - Issues and Errors @@ -342,6 +346,8 @@ * My Git hooks work on the command-line but not inside Magit:: * @code{git-commit-mode} isn't used when committing from the command-line:: * Point ends up inside invisible text when jumping to a file-visiting buffer:: +* I am unable to stage when using Tramp from MS Windows:: +* I am no longer able to save popup defaults:: @end detailmenu @@ -512,10 +518,10 @@ with the following content before running @code{make}: @example -LOAD_PATH = -L /path/to/magit/lisp -LOAD_PATH += -L /path/to/dash -LOAD_PATH += -L /path/to/transient -LOAD_PATH += -L /path/to/with-editor +LOAD_PATH = -L ~/.emacs.d/site-lisp/magit/lisp +LOAD_PATH += -L ~/.emacs.d/site-lisp/dash +LOAD_PATH += -L ~/.emacs.d/site-lisp/transient/lisp +LOAD_PATH += -L ~/.emacs.d/site-lisp/with-editor @end example Finally add this to your init file: @@ -530,6 +536,15 @@ "~/.emacs.d/site-lisp/magit/Documentation/")) @end lisp +Of course if you installed the dependencies manually as well, then +you have to tell Emacs about them too, by prefixing the above with: + +@lisp +(add-to-list 'load-path "~/.emacs.d/site-lisp/dash") +(add-to-list 'load-path "~/.emacs.d/site-lisp/transient/lisp") +(add-to-list 'load-path "~/.emacs.d/site-lisp/with-editor") +@end lisp + Note that you have to add the @code{lisp} subdirectory to the @code{load-path}, not the top-level of the repository, and that elements of @code{load-path} should not end with a slash, while those of @code{Info-directory-list} should. @@ -605,13 +620,8 @@ if you do that, then you should commit all uncommitted changes before proceeding. -To display information about the current Git repository, type @code{M-x -magit-status RET}. You will be using this command a lot, and should -therefore give it a global key binding. This is what we recommend: - -@lisp -(global-set-key (kbd "C-x g") 'magit-status) -@end lisp +Type @code{C-x g} to display information about the current Git repository in +a dedicated buffer, called the status buffer. Most Magit commands are commonly invoked from the status buffer. It can be considered the primary interface for interacting with Git using @@ -663,7 +673,7 @@ Now two new buffers appear. One is for writing the commit message, the other shows a diff with the changes that you are about to -committed. Write a message and then type @code{C-c C-c} to actually create +commit. Write a message and then type @code{C-c C-c} to actually create the commit. You probably don't want to push the commit you just created because @@ -674,28 +684,23 @@ push-remote is not configured yet, then you would first be prompted for the remote to push to.) -So far we have mentioned the commit, push, and log transient prefix -commands. These are probably among the transients you will be using -the most, but many others exist. To show a transient that lists all -other transients (as well as the various apply commands and some other -essential commands), type @code{h}. Try a few. +So far we have mentioned the commit, push, and log menu commands. +These are probably among the menus you will be using the most, but +many others exist. To show a menu that lists all other menus (as well +as the various apply commands and some other essential commands), type +@code{h}. Try a few. (Such menus are also called "transient prefix +commands" or just "transients".) -The key bindings in that transient correspond to the bindings in Magit +The key bindings in that menu correspond to the bindings in Magit buffers, including but not limited to the status buffer. So you could -type @code{h d} to bring up the diff transient, but once you remember that -"d" stands for "diff", you would usually do so by just typing @code{d}. But -this "prefix of prefixes" is useful even once you have memorized all -the bindings, as it can provide easy access to Magit commands from -non-Magit buffers. You should create a global key binding for this -command too: +type @code{h d} to bring up the diff menu, but once you remember that "d" +stands for "diff", you would usually do so by just typing @code{d}. But this +"prefix of prefixes" is useful even once you have memorized all the +bindings, as it can provide easy access to Magit commands from +non-Magit buffers. The global binding is @code{C-x M-g}. -@lisp -(global-set-key (kbd "C-x M-g") 'magit-dispatch) -@end lisp - -In the same vein, you might also want to enable @code{global-magit-file-mode} -to get some more Magit key bindings in regular file-visiting buffers -(see @ref{Minor Mode for Buffers Visiting Files}). +In file visiting buffers @code{C-c M-g} brings up a similar menu featuring +commands that act on just the visited file, see @ref{Commands for Buffers Visiting Files}. It is not necessary that you do so now, but if you stick with Magit, then it is highly recommended that you read the next section too. @@ -1035,7 +1040,8 @@ by adding a hook, like so: @lisp -(add-hook 'after-save-hook 'magit-after-save-refresh-status t) +(with-eval-after-load 'magit-mode + (add-hook 'after-save-hook 'magit-after-save-refresh-status t)) @end lisp Automatically refreshing Magit buffers ensures that the displayed @@ -1713,14 +1719,23 @@ but knowing them can be handy at times. @table @asis -@kindex M-x magit-describe-section-briefly -@cindex magit-describe-section-briefly -@item @kbd{M-x magit-describe-section-briefly} @tie{}@tie{}@tie{}@tie{}(@code{magit-describe-section-briefly}) +@kindex H +@cindex magit-describe-section +@item @kbd{H} @tie{}@tie{}@tie{}@tie{}(@code{magit-describe-section}) + +This command shows information about the section at point in a +separate buffer. -Show information about the section at point in the echo area, as -"#". @end table +@cindex magit-describe-section-briefly +@deffn Command magit-describe-section-briefly + +This command shows information about the section at point in the +echo area, as @code{#}. +@end deffn + Many commands behave differently depending on the type of the section at point and/or somehow consume the value of that section. But that is only one of the reasons why the same key may do something different, @@ -1886,7 +1901,7 @@ @itemize @item -The global diff and log arguments are set for each support mode +The global diff and log arguments are set for each supported mode individually. The diff arguments for example have different values in @code{magit-diff-mode}, @code{magit-revision-mode}, @code{magit-merge-preview-mode} and @code{magit-status-mode} buffers. Setting or saving the value for one @@ -1897,7 +1912,7 @@ @item When @code{magit-show-commit} is invoked directly from a log buffer, then the file filter is picked up from that buffer, not from the revision -buffer and or the mode's global diff arguments. +buffer or the mode's global diff arguments. @item @@ -2067,7 +2082,7 @@ @item @code{delete-pr-remote} When deleting a branch that was created from a pull-request and if no other branches still exist on that -remote, then `magit-branch-delete' offers to delete the remote +remote, then @code{magit-branch-delete} offers to delete the remote as well. This should be safe because it only happens if no other refs exist in the remotes namespace, and you can recreate the remote if necessary. @@ -2085,6 +2100,20 @@ @item +Publishing: + +@itemize +@item +@code{set-and-push} When pushing to the upstream or the push-remote +and that isn't actually configured yet, then the user can first +set the target. If s/he confirms the default too quickly, then +s/he might end up pushing to the wrong branch and if the remote +repository is configured to disallow fixing such mistakes, then +that can be quite embarrassing and annoying. +@end itemize + + +@item Edit published history: Without adding these symbols here, you will be warned before @@ -2456,12 +2485,36 @@ @end table -@defopt magit-git-debug +@defvar magit-git-debug -When this is non-nil then the output of all calls to git are logged -in the process buffer. This is useful when debugging, otherwise it -just negatively affects performance. -@end defopt +This option controls whether additional reporting of git errors is +enabled. + +Magit basically calls git for one of these two reasons: for +side-effects or to do something with its standard output. + +When git is run for side-effects then its output, including error +messages, go into the process buffer which is shown when using @code{$}. + +When git's output is consumed in some way, then it would be too +expensive to also insert it into this buffer, but when this +option is non-nil and git returns with a non-zero exit status, +then at least its standard error is inserted into this buffer. + +This is only intended for debugging purposes. Do not enable this +permanently, that would negatively affect performance. +@end defvar + +@defvar magit-process-extreme-logging + +This option controls whether @code{magit-process-file} logs to the +@code{*Messages*} buffer. + +Only intended for temporary use when you try to figure out how +Magit uses Git behind the scene. Output that normally goes to +the magit-process buffer continues to go there. Not all output +goes to either of these two buffers. +@end defvar @node Git Process Status @subsection Git Process Status @@ -2511,6 +2564,9 @@ The string "git " is used as initial input when prompting the user for the command. It can be removed to run another command. +@kindex : +@cindex magit-git-command +@item @kbd{:} @tie{}@tie{}@tie{}@tie{}(@code{magit-git-command}) @kindex ! p @cindex magit-git-command @item @kbd{! p} @tie{}@tie{}@tie{}@tie{}(@code{magit-git-command}) @@ -2576,56 +2632,72 @@ @node Git Executable @subsection Git Executable -Except on MS Windows, Magit defaults to running Git without specifying -the path to the git executable. Instead the first executable found by -Emacs on @code{exec-path} is used (whose value in turn is set based on the -value of the environment variable @code{$PATH} when Emacs was started). - -This has the advantage that it continues to work even when using Tramp -to connect to a remote machine on which the executable is found in a -different place. The downside is that if you have multiple versions -of Git installed, then you might end up using another version than the -one you think you are using. +When Magit calls Git, then it may do so using the absolute path to the +@code{git} executable, or using just its name. -@table @asis -@kindex M-x magit-version -@cindex magit-version -@item @kbd{M-x magit-version} @tie{}@tie{}@tie{}@tie{}(@code{magit-version}) - -This command shows the currently used versions of Magit, Git, and -Emacs in the echo area. Non-interactively this just returns the -Magit version. -@end table - -When the @code{system-type} is @code{windows-nt}, then @code{magit-git-executable} is set -to an absolute path when Magit is first loaded. This is necessary -because Git on that platform comes with several wrapper scripts for -the actual git binary, which are also placed on @code{$PATH}, and using one -of these wrappers instead of the binary would degrade performance -horribly. - -If Magit doesn't find the correct executable then you @strong{can} work -around that by setting @code{magit-git-executable} to an absolute path. -But note that doing so is a kludge. It is better to make sure the -order in the environment variable @code{$PATH} is correct, and that Emacs -is started with that environment in effect. The command -@code{magit-debug-git-executable} can be useful to find out where Emacs is -searching for git. If you have to connect from Windows to a -non-Windows machine, then you must change the value to "git". +When running @code{git} locally and the @code{system-type} is @code{windows-nt} (any +Windows version) or @code{darwin} (macOS) then @code{magit-git-executable} is set +to an absolute path when Magit is loaded. + +On Windows it is necessary to use an absolute path because Git comes +with several wrapper scripts for the actual @code{git} binary, which are also +placed on @code{$PATH}, and using one of these wrappers instead of the binary +would degrade performance horribly. For some macOS users using just +the name of the executable also performs horribly, so we avoid doing +that on that platform as well. On other platforms, using just the +name seems to work just fine. + +Using an absolute path when running @code{git} on a remote machine over +Tramp, would be problematic to use an absolute path that is suitable +on the local machine, so a separate option is used to control the name +or path that is used on remote machines. @defopt magit-git-executable -The git executable used by Magit, either the full path to the -executable or the string "git" to let Emacs find the executable -itself, using the standard mechanism for doing such things. -@end defopt +The @code{git} executable used by Magit on the local host. This should be +either the absolute path to the executable, or the string "git" to +let Emacs find the executable itself, using the standard mechanism +for doing such things. +@end defopt + +@defopt magit-remote-git-executable + +The @code{git} executable used by Magit on remote machines over Tramp. +Normally this should be just the string "git". Consider customizing +@code{tramp-remote-path} instead of this option. +@end defopt + +If Emacs is unable to find the correct executable, then you can +work around that by explicitly setting the value of one of these two +options. Doing that should be considered a kludge; it is better to +make sure that the order in @code{exec-path} or @code{tramp-remote-path} is correct. + +Note that @code{exec-path} is set based on the value of the @code{PATH} environment +variable that is in effect when Emacs is started. If you set @code{PATH} in +your shell's init files, then that only has an effect on Emacs if you +start it from that shell (because the environment of a process is only +passed to its child processes, not to arbitrary other processes). If +that is not how you start Emacs, then the @code{exec-path-from-shell} package +can help; though honestly I consider that a kludge too. + +The command @code{magit-debug-git-executable} can be useful to find out where +Emacs is searching for @code{git}. @table @asis @kindex M-x magit-debug-git-executable @cindex magit-debug-git-executable @item @kbd{M-x magit-debug-git-executable} @tie{}@tie{}@tie{}@tie{}(@code{magit-debug-git-executable}) -Display a buffer with information about @code{magit-git-executable}. +This command displays a buffer with information about +@code{magit-git-executable} and @code{magit-remote-git-executable}. + +@kindex M-x magit-version +@cindex magit-version +@item @kbd{M-x magit-version} @tie{}@tie{}@tie{}@tie{}(@code{magit-version}) + +This command shows the currently used versions of Magit, Git, and +Emacs in the echo area. Non-interactively this just returns the +Magit version. @end table @node Global Git Arguments @@ -2775,6 +2847,36 @@ in potentially surprising ways (see above). @end defopt +@cindex magit-status-quick +@deffn Command magit-status-quick + +This command is an alternative to @code{magit-status} that usually avoids +refreshing the status buffer. + +If the status buffer of the current Git repository exists but isn't +being displayed in the selected frame, then it is displayed without +being refreshed. + +If the status buffer is being displayed in the selected frame, +then this command refreshes it. + +Prefix arguments have the same meaning as for @code{magit-status}, +and additionally cause the buffer to be refresh. + +To use this command add this to your init file: + +@lisp +(global-set-key (kbd "C-x g") 'magit-status-quick). +@end lisp + +If you do that and then for once want to redisplay the buffer and +also immediately refresh it, then type @code{C-x g} followed by @code{g}. + +A possible alternative command is @code{magit-display-repository-buffer}. +It supports displaying any existing Magit buffer that belongs to the +current repository; not just the status buffer. +@end deffn + @cindex ido-enter-magit-status @deffn Command ido-enter-magit-status @@ -3221,6 +3323,12 @@ @code{default-directory} bound to the toplevel of its working tree. It has to return a string to be inserted or nil. PROPS is an alist that supports the keys @code{:right-align} and @code{:pad-right}. + +You may wish to display a range of numeric columns using just one +character per column and without any padding between columns, in +which case you should use an appropriate HEADER, set WIDTH to 1, +and set @code{:pad-right} to 0. @code{+} is substituted for numbers higher +than 9. @end defopt The following functions can be added to the above option: @@ -3391,10 +3499,9 @@ Show log for all references and @code{HEAD}. @end table - -Two additional commands that show the log for the file or blob that -is being visited in the current buffer exists, see @ref{Minor Mode for Buffers Visiting Files}. The command @code{magit-cherry} also shows a log, -see @ref{Cherries}. +Two additional commands that show the log for the file or blob that is +being visited in the current buffer exists, see @ref{Commands for Buffers Visiting Files}. The command @code{magit-cherry} also shows a log, see +@ref{Cherries}. @menu * Refreshing Logs:: @@ -3497,6 +3604,19 @@ first parent, but a numeric prefix can be used to specify another parent. +@kindex j +@cindex magit-log-move-to-revision +@item @kbd{j} @tie{}@tie{}@tie{}@tie{}(@code{magit-log-move-to-revision}) + +Read a revision and move to it in current log buffer. + +If the chosen reference or revision isn't being displayed in +the current log buffer, then inform the user about that and do +nothing else. + +If invoked outside any log buffer, then display the log buffer +of the current repository first; creating it if necessary. + @kindex SPC @cindex magit-diff-show-or-scroll-up @item @kbd{SPC} @tie{}@tie{}@tie{}@tie{}(@code{magit-diff-show-or-scroll-up}) @@ -3995,7 +4115,7 @@ @end table Two additional commands that show the diff for the file or blob that -is being visited in the current buffer exists, see @ref{Minor Mode for Buffers Visiting Files}. +is being visited in the current buffer exists, see @ref{Commands for Buffers Visiting Files}. @menu * Refreshing Diffs:: @@ -4367,6 +4487,28 @@ dimmed at all depends on @code{magit-diff-highlight-hunk-region-functions}. @end defopt +@defopt magit-diff-extra-stat-arguments + +This option specifies additional arguments to be used alongside +@code{--stat}. + +The value is a list of zero or more arguments or a function that +takes no argument and returns such a list. These arguments are +allowed here: @code{--stat-width}, @code{--stat-name-width}, +@code{--stat-graph-width} and @code{--compact-summary}. Also see +@ifinfo +@ref{git-diff,,,gitman,}. +@end ifinfo +@ifhtml +@html +the git-diff(1) manpage. +@end html +@end ifhtml +@iftex +the git-diff(1) manpage. +@end iftex +@end defopt + @node Revision Buffer @subsection Revision Buffer @@ -4625,6 +4767,12 @@ This command lists branches and tags in a dedicated buffer. Each reference is being compared with a branch read from the user. +@kindex y r +@cindex magit-refs-set-show-commit-count +@item @kbd{y r} @tie{}@tie{}@tie{}@tie{}(@code{magit-refs-set-show-commit-count}) + +This command changes for which refs the commit count is shown. + @end table @defopt magit-refs-show-commit-count @@ -4957,7 +5105,10 @@ Bisecting a bug means to find the commit that introduced it. This command starts such a bisect session by asking for a known -good and a bad commit. +good commit and a known bad commit. If you're bisecting a change +that isn't a regression, you can select alternate terms that are +conceptually more fitting than "bad" and "good", but the infix +arguments to do so are disabled by default. @kindex B s @cindex magit-bisect-run @@ -4984,6 +5135,15 @@ Mark the current commit as good. Use this after you have asserted that the commit does not contain the bug in question. +@kindex B m +@cindex magit-bisect-mark +@item @kbd{B m} @tie{}@tie{}@tie{}@tie{}(@code{magit-bisect-mark}) + +Mark the current commit with one of the bisect terms. This command +provides an alternative to @code{magit-bisect-bad} and +@code{magit-bisect-good} and is useful when using terms other than "bad" +and "good". This suffix is disabled by default. + @kindex B k @cindex magit-bisect-skip @item @kbd{B k} @tie{}@tie{}@tie{}@tie{}(@code{magit-bisect-skip}) @@ -5169,9 +5329,7 @@ @end iftex To start blaming invoke the @code{magit-file-dispatch} transient prefix -command by pressing @code{C-c M-g}. (This is only the default binding and -the recommended binding is @code{C-c g}. Also neither binding may be -available if you disabled @code{global-magit-file-mode}. Also see @ref{Minor Mode for Buffers Visiting Files}.) +command by pressing @code{C-c M-g}. The blaming suffix commands can be invoked from the dispatch transient. However if you want to set an infix argument, then you @@ -5410,9 +5568,9 @@ @section Creating Repository @table @asis -@kindex M-x magit-init +@kindex I @cindex magit-init -@item @kbd{M-x magit-init} @tie{}@tie{}@tie{}@tie{}(@code{magit-init}) +@item @kbd{I} @tie{}@tie{}@tie{}@tie{}(@code{magit-init}) This command initializes a repository and then shows the status buffer for the new repository. @@ -5788,6 +5946,10 @@ Remove the change at point from the working tree. +On a hunk or file with unresolved conflicts prompt which side to +keep (while discarding the other). If point is within the text +of a side, then keep that side without prompting. + @kindex v @cindex magit-reverse @item @kbd{v} @tie{}@tie{}@tie{}@tie{}(@code{magit-reverse}) @@ -5928,6 +6090,11 @@ staged. @end defopt +@defopt magit-commit-show-diff + +Whether the relevant diff is automatically shown when committing. +@end defopt + @defopt magit-commit-extend-override-date Whether using @code{magit-commit-extend} changes the committer date. @@ -5948,6 +6115,46 @@ those is harder to recover from. @end defopt +@defopt magit-post-commit-hook + +Hook run after creating a commit without the user editing a message. + +This hook is run by @code{magit-refresh} if @code{this-command} is a member +of @code{magit-post-stage-hook-commands}. This only includes commands +named @code{magit-commit-*} that do @strong{not} require that the user edits +the commit message in a buffer. + +Also see @code{git-commit-post-finish-hook}. +@end defopt + +@defopt magit-commit-diff-inhibit-same-window + +Whether to inhibit use of same window when showing diff while +committing. + +When writing a commit, then a diff of the changes to be committed +is automatically shown. The idea is that the diff is shown in a +different window of the same frame and for most users that just +works. In other words most users can completely ignore this +option because its value doesn't make a difference for them. + +However for users who configured Emacs to never create a new +window even when the package explicitly tries to do so, then +displaying two new buffers necessarily means that the first is +immediately replaced by the second. In our case the message +buffer is immediately replaced by the diff buffer, which is of +course highly undesirable. + +A workaround is to suppress this user configuration in this +particular case. Users have to explicitly opt-in by toggling +this option. We cannot enable the workaround unconditionally +because that again causes issues for other users: if the frame +is too tiny or the relevant settings too aggressive, then the +diff buffer would end up being displayed in a new frame. + +Also see @uref{https://github.com/magit/magit/issues/4132}. +@end defopt + @node Editing Commit Messages @subsection Editing Commit Messages @@ -6389,8 +6596,8 @@ @defopt magit-branch-direct-configure This option controls whether the transient command @code{magit-branch} can -be used directly change the values Git variables. This defaults to -@code{t} (to avoid changing key bindings). When set to @code{nil}, then no +be used to directly change the values of Git variables. This defaults +to @code{t} (to avoid changing key bindings). When set to @code{nil}, then no variables are displayed by that transient command, and its suffix command @code{magit-branch-configure} has to be used instead to view and change branch related variables. @@ -6453,8 +6660,8 @@ @cindex magit-branch-and-checkout @item @kbd{b c} @tie{}@tie{}@tie{}@tie{}(@code{magit-branch-and-checkout}) -This command creates a new branch like @code{magit-branch}, but then also -checks it out. +This command creates a new branch like @code{magit-branch-create}, but then +also checks it out. Also see option @code{magit-branch-prefer-remote-upstream}. @@ -6567,7 +6774,7 @@ @defopt magit-branch-read-upstream-first When creating a branch, whether to read the upstream branch before -the name of the branch that is to be created. The default is @code{nil}, +the name of the branch that is to be created. The default is @code{t}, and I recommend you leave it at that. @end defopt @@ -6652,7 +6859,7 @@ repositories, then you might use something like: @lisp -(("origin/master" "master" "next" "maint")) +(("origin/master" . ("master" "next" "maint"))) @end lisp Or if the names of all your ephemeral branches contain a slash, @@ -6668,8 +6875,22 @@ (("origin/maint" . "\\`hotfix/") ("origin/master" . "\\`feature/")) @end lisp + +UPSTREAM can be a local branch: + +@lisp +(("master" . ("master" "next" "maint"))) +@end lisp @end defopt +Because the main branch is no longer almost always named "master" +you should also account for other common names: + +@lisp +(("main" . ("main" "master" "next" "maint")) + ("master" . ("main" "master" "next" "maint"))) +@end lisp + @cindex magit-branch-orphan @deffn Command magit-branch-orphan @@ -7160,6 +7381,13 @@ stages the file when you save the buffer after resolving the last conflict. +Magit now wraps the mentioned Smerge commands, allowing you to use +these key bindings without having to go to the file-visiting buffer. +Additionally @code{k} (@code{magit-discard}) on a hunk with unresolved conflicts +asks which side to keep or, if point is on a side, then it keeps it +without prompting. Similarly @code{k} on a unresolved file ask which side +to keep. + Alternatively you could use Ediff, which uses separate buffers for the different versions of the file. To resolve conflicts in a file using Ediff press @code{e} while point is on such a file in the status buffer. @@ -8008,6 +8236,14 @@ Reset the @code{HEAD}, index, and working tree to some commit read from the user and defaulting to the commit at point. +@kindex X k +@cindex magit-reset-keep +@item @kbd{X k} @tie{}@tie{}@tie{}@tie{}(@code{magit-reset-keep}) + +Reset the @code{HEAD}, index, and working tree to some commit read from the +user and defaulting to the commit at point. Uncommitted changes are +kept as-is. + @kindex X i @cindex magit-reset-index @item @kbd{X i} @tie{}@tie{}@tie{}@tie{}(@code{magit-reset-index}) @@ -8666,6 +8902,16 @@ This command pushes a tag to another repository. @end table +One of the infix arguments, @code{--force-with-lease}, deserves a word of +caution. It is passed without a value, which means "permit a force +push as long as the remote-tracking branches match their counterparts +on the remote end". If you've set up a tool to do automatic fetches +(Magit itself does not provide such functionality), using +@code{--force-with-lease} can be dangerous because you don't actually +control or know the state of the remote-tracking refs. In that case, +you should consider setting @code{push.useForceIfIncludes} to @code{true} +(available since Git 2.30). + Two more push commands exist, which by default are not available from the push transient. See their doc-strings for instructions on how to add them to the transient. @@ -8681,6 +8927,15 @@ @code{remote.pushDefault}, @code{branch..pushRemote}, @code{branch..remote}, @code{branch..merge}, and @code{remote..push}. + +If you add this suffix to a transient prefix without explicitly +specifying the description, then an attempt is made to predict +what this command will do. For example: + +@lisp +(transient-insert-suffix 'magit-push \"p\" + '(\"i\" magit-push-implicitly))" +@end lisp @end deffn @cindex magit-push-to-remote remote args @@ -8837,9 +9092,10 @@ * Submodules:: * Subtree:: * Worktree:: +* Bundle:: * Common Commands:: * Wip Modes:: -* Minor Mode for Buffers Visiting Files:: +* Commands for Buffers Visiting Files:: * Minor Mode for Buffers Visiting Blobs:: @end menu @@ -8873,30 +9129,29 @@ @item @kbd{t t} @tie{}@tie{}@tie{}@tie{}(@code{magit-tag-create}) This command creates a new tag with the given NAME at REV@. With a -prefix argument it creates an annotate tag. +prefix argument it creates an annotated tag. @kindex t r @cindex magit-tag-release @item @kbd{t r} @tie{}@tie{}@tie{}@tie{}(@code{magit-tag-release}) -This commands creates an annotated release tag. It assumes that -release tags match @code{magit-release-tag-regexp}. +This commands creates a release tag. It assumes that release tags +match @code{magit-release-tag-regexp}. First it prompts for the name of the new tag using the highest existing tag as initial input and leaving it to the user to -increment the desired part of the version string. - -Then it prompts for the message of the new tag. The proposed tag -message is based on the message of the highest tag, provided that -that contains the corresponding version string and substituting the -new version string for that. Otherwise it proposes something like -"Foo-Bar 1.2.3", given, for example, a TAG "v1.2.3" and a repository -located at something like "/path/to/foo-bar". - -Then it calls "git tag --annotate --sign -m MSG TAG" to create the -tag, regardless of whether these arguments are enabled in the -transient. Finally it shows the refs buffer to let the user quickly -review the result. +increment the desired part of the version string. If you use +unconventional release tags or version numbers (e.g., +@code{v1.2.3-custom.1}), you can set the @code{magit-release-tag-regexp} and +@code{magit-tag-version-regexp-alist} variables. + +If @code{--annotate} is enabled then it prompts for the message of the +new tag. The proposed tag message is based on the message of the +highest tag, provided that that contains the corresponding version +string and substituting the new version string for that. Otherwise +it proposes something like "Foo-Bar 1.2.3", given, for example, a +TAG "v1.2.3" and a repository located at something like +"/path/to/foo-bar". @kindex t k @cindex magit-tag-delete @@ -9044,7 +9299,7 @@ The command @code{magit-list-submodules} displays a list of the current repository's submodules in a separate buffer. It's also possible to display information about submodules directly in the status buffer of -the super-repository by adding @code{magit-insert-submodules} to the hook +the super-repository by adding @code{magit-insert-modules} to the hook @code{magit-status-sections-hook} as described in @ref{Status Module Sections}. @cindex magit-list-submodules @@ -9071,18 +9326,6 @@ that supports the keys @code{:right-align} and @code{:pad-right}. @end defopt -@defun magit-insert-submodules - -Insert sections for all submodules. For each section insert the -path, the branch, and the output of @code{git describe --tags}, -or, failing that, the abbreviated HEAD commit hash. - -Press @code{RET} on such a submodule section to show its own status buffer. -Press @code{RET} on the "Modules" section to display a list of submodules -in a separate buffer. This shows additional information not -displayed in the super-repository's status buffer. -@end defun - @node Submodule Transient @subsection Submodule Transient @@ -9275,41 +9518,41 @@ @end iftex @table @asis -@kindex % +@kindex Z @cindex magit-worktree -@item @kbd{%} @tie{}@tie{}@tie{}@tie{}(@code{magit-worktree}) +@item @kbd{Z} @tie{}@tie{}@tie{}@tie{}(@code{magit-worktree}) This transient prefix command binds the following suffix commands and displays them in a temporary buffer until a suffix is invoked. -@kindex % b +@kindex Z b @cindex magit-worktree-checkout -@item @kbd{% b} @tie{}@tie{}@tie{}@tie{}(@code{magit-worktree-checkout}) +@item @kbd{Z b} @tie{}@tie{}@tie{}@tie{}(@code{magit-worktree-checkout}) Checkout BRANCH in a new worktree at PATH@. -@kindex % c +@kindex Z c @cindex magit-worktree-branch -@item @kbd{% c} @tie{}@tie{}@tie{}@tie{}(@code{magit-worktree-branch}) +@item @kbd{Z c} @tie{}@tie{}@tie{}@tie{}(@code{magit-worktree-branch}) Create a new BRANCH and check it out in a new worktree at PATH@. -@kindex % m +@kindex Z m @cindex magit-worktree-move -@item @kbd{% m} @tie{}@tie{}@tie{}@tie{}(@code{magit-worktree-move}) +@item @kbd{Z m} @tie{}@tie{}@tie{}@tie{}(@code{magit-worktree-move}) Move an existing worktree to a new PATH@. -@kindex % k +@kindex Z k @cindex magit-worktree-delete -@item @kbd{% k} @tie{}@tie{}@tie{}@tie{}(@code{magit-worktree-delete}) +@item @kbd{Z k} @tie{}@tie{}@tie{}@tie{}(@code{magit-worktree-delete}) Delete a worktree, defaulting to the worktree at point. The primary worktree cannot be deleted. -@kindex % g +@kindex Z g @cindex magit-worktree-status -@item @kbd{% g} @tie{}@tie{}@tie{}@tie{}(@code{magit-worktree-status}) +@item @kbd{Z g} @tie{}@tie{}@tie{}@tie{}(@code{magit-worktree-status}) Show the status for the worktree at point. @@ -9318,17 +9561,61 @@ displayed in the current buffer, then show it in Dired instead. @end table +@node Bundle +@section Bundle + +Also see +@ifinfo +@ref{git-bundle,,,gitman,}. +@end ifinfo +@ifhtml +@html +the git-bundle(1) manpage. +@end html +@end ifhtml +@iftex +the git-bundle(1) manpage. +@end iftex + +@cindex magit-bundle +@deffn Command magit-bundle + +This transient prefix command binds several suffix commands for +running @code{git bundle} subcommands and displays them in a temporary +buffer until a suffix is invoked. +@end deffn + @node Common Commands @section Common Commands +@cindex magit-switch-to-repository-buffer +@deffn Command magit-switch-to-repository-buffer +@end deffn +@cindex magit-switch-to-repository-buffer-other-window +@deffn Command magit-switch-to-repository-buffer-other-window +@end deffn +@cindex magit-switch-to-repository-buffer-other-frame +@deffn Command magit-switch-to-repository-buffer-other-frame +@end deffn +@cindex magit-display-repository-buffer +@deffn Command magit-display-repository-buffer + +These commands read any existing Magit buffer that belongs to the +current repository from the user and then switch to the selected +buffer (without refreshing it). + +The last variant uses @code{magit-display-buffer} to do so and thus +respects @code{magit-display-buffer-function}. +@end deffn + These are some of the commands that can be used in all buffers whose major-modes derive from @code{magit-mode}. There are other common commands beside the ones below, but these didn't fit well anywhere else. @table @asis -@kindex M-w +@kindex C-w @cindex magit-copy-section-value -@item @kbd{M-w} @tie{}@tie{}@tie{}@tie{}(@code{magit-copy-section-value}) +@item @kbd{C-w} @tie{}@tie{}@tie{}@tie{}(@code{magit-copy-section-value}) This command saves the value of the current section to the @code{kill-ring}, and, provided that the current section is a commit, @@ -9341,13 +9628,14 @@ When the region is active, this command saves that to the @code{kill-ring}, like @code{kill-ring-save} would, instead of behaving as -described above. If a prefix argument is used and the region is -within a hunk, it strips the outer diff marker column before saving -the text. +described above. If a prefix argument is used and the region is +within a hunk, then it strips the diff marker column and keeps +only either the added or removed lines, depending on the sign of +the prefix argument. -@kindex C-w +@kindex M-w @cindex magit-copy-buffer-revision -@item @kbd{C-w} @tie{}@tie{}@tie{}@tie{}(@code{magit-copy-buffer-revision}) +@item @kbd{M-w} @tie{}@tie{}@tie{}@tie{}(@code{magit-copy-buffer-revision}) This command saves the revision being displayed in the current buffer to the @code{kill-ring} and also pushes it to the @code{magit-revision-stack}. It @@ -9631,57 +9919,22 @@ Mode-line lighter for @code{magit-wip-initial-backup-mode}. @end defopt -@node Minor Mode for Buffers Visiting Files -@section Minor Mode for Buffers Visiting Files +@node Commands for Buffers Visiting Files +@section Commands for Buffers Visiting Files -The minor-mode @code{magit-file-mode} enables certain Magit features in -file-visiting buffers belonging to a Git repository. The globalized -variant @code{global-magit-file-mode} enables the local mode in all such -buffers. It is enabled by default. Currently the local mode only -establishes a few key bindings, but this might be extended in the -future. - -@defopt global-magit-file-mode - -Whether to establish certain Magit key bindings in all file-visiting -buffers belonging to any Git repository. This is enabled by default. -This globalized mode turns on the local minor-mode @code{magit-file-mode} -in all suitable buffers. -@end defopt - -@defvar magit-file-mode-map - -This keymap is used by the local minor-mode @code{magit-file-mode} and -establishes the key bindings described below. - -Note that the default binding for @code{magit-file-dispatch} is very -cumbersome to use and that we recommend that you add a better -binding. - -Instead of @code{C-c M-g} I would have preferred to use @code{C-c g} because (1) -it is similar to @code{C-x g} (the recommended global binding for -@code{~magit-status}), (2) we cannot use @code{C-c C-g} because we have been -recommending that that be bound to @code{magit-dispatch} for a long time, -(3) we cannot use @code{C-x C-g} because that is a convenient way of -aborting the incomplete key sequence @code{C-x}, and most importantly (4) -it would make it much easier to type the next key (a suffix binding) -because most of those are letters. - -For example @code{C-c g b} is much easier to type than @code{C-c M-g b}. For -suffix bindings that use uppercase letters, the default is just -horrible—having to use e.g. @code{C-c M-g B} (@code{Control+c Meta+g Shift+b}) -would drive anyone up the walls (or to Vim). - -However @code{C-c LETTER} bindings are reserved for users (see -@ref{Key Binding Conventions,,,elisp,}). Packages are forbidden from -using those. Doing so anyway is considered heresy. Therefore if -you want a better binding, you have to add it yourself: +Magit defines a few global key bindings unless the user sets +@code{magit-define-global-key-bindings} to @code{nil}. This includes binding @code{C-c +M-g} to @code{magit-file-dispatch}. @code{C-c g} would be a much better binding +but the @code{C-c } namespace is reserved for users, meaning that +packages are not allowed to use it. If you want to use @code{C-c g}, then +you have to add that binding yourself. Also see @ref{Default Bindings} +and @ref{Key Binding Conventions,,,elisp,}. + +If you want a better binding, you have to add it yourself: @lisp -(define-key magit-file-mode-map - (kbd "C-c g") 'magit-file-dispatch) +(global-set-key (kbd "C-c g") 'magit-file-dispatch) @end lisp -@end defvar The key bindings shown below assume that you have not improved the binding for @code{magit-file-dispatch}. @@ -9694,6 +9947,9 @@ This transient prefix command binds the following suffix commands and displays them in a temporary buffer until a suffix is invoked. +When invoked in a buffer that does not visit a file, then it falls +back to regular @code{magit-dispatch}. + @kindex C-c M-g s @cindex magit-stage-file @item @kbd{C-c M-g s} @tie{}@tie{}@tie{}@tie{}(@code{magit-stage-file}) @@ -10023,6 +10279,7 @@ @menu * Safety:: * Performance:: +* Default Bindings:: @end menu @node Safety @@ -10125,7 +10382,8 @@ * MacOS Performance:: @end menu -@unnumberedsubsubsec Log Performance +@anchor{Log Performance} +@subsubheading Log Performance When showing logs, Magit limits the number of commits initially shown in the hope that this avoids unnecessary work. When using @code{--graph} is @@ -10152,7 +10410,8 @@ merges. For that reason @code{--color} is not enabled by default anymore. Consider leaving it at that. -@unnumberedsubsubsec Diff Performance +@anchor{Diff Performance} +@subsubheading Diff Performance If diffs are slow, then consider turning off some optional diff features by setting all or some of the following variables to @code{nil}: @@ -10175,7 +10434,8 @@ setting, see @ref{Saving Values,,,transient,}. You should do this in both the diff (@code{d}) and the diff refresh (@code{D}) transient popups. -@unnumberedsubsubsec Refs Buffer Performance +@anchor{Refs Buffer Performance} +@subsubheading Refs Buffer Performance When refreshing the "references buffer" is slow, then that's usually because several hundred refs are being displayed. The best way to @@ -10192,7 +10452,8 @@ actually all exist. You can do so by pruning branches which no longer exist using @code{f-pa}. -@unnumberedsubsubsec Committing Performance +@anchor{Committing Performance} +@subsubheading Committing Performance When you initiate a commit, then Magit by default automatically shows a diff of the changes you are about to commit. For large commits this @@ -10213,24 +10474,6 @@ the diff, which is useful because it increases the odds that you spot potential issues. -@unnumberedsubsubsec The Built-In VC Package - -Emacs comes with a version control interface called "VC", see -@ref{Version Control,,,emacs,}. It is enabled be default, and if you don't -use it in addition to Magit, then you should disable it to keep it -from performing unnecessary work: - -@lisp -(setq vc-handled-backends nil) -@end lisp - -You can also disable its use for Git but keep using it when using -another version control system: - -@lisp -(setq vc-handled-backends (delq 'Git vc-handled-backends)) -@end lisp - @node Microsoft Windows Performance @unnumberedsubsubsec Microsoft Windows Performance @@ -10273,11 +10516,61 @@ takes about twice as long on Darwin compared to Linux.) See @footnote{@uref{https://lists.gnu.org/archive/html/bug-gnu-emacs/2017-04/msg00201.html}} for more information. -On Catalina, and potentially other macOS releases, there may be a -performance problem where any action takes 20 times longer on Darwin -than on Linux. This can be fixed by setting @code{magit-git-executable} to -the absolute path of the @code{git} executable, instead of relying on -resolving the @code{$PATH}. +@node Default Bindings +@subsection Default Bindings + +@defopt magit-define-global-key-bindings + +This option controls whether some Magit commands are automatically +bound in the global keymap even before Magit is used for the first +time in the current session. + +If this variable is non-nil, which it is by default, then the +following bindings may be added to the global keymap. + +@multitable {aaaaaaaaa} {aaaaaaaaaaaaaaaaaaaaa} +@item @code{C-x g} +@tab @code{magit-status} +@item @code{C-x M-g} +@tab @code{magit-dispatch} +@item @code{C-c M-g} +@tab @code{magit-file-dispatch} +@end multitable + +These bindings may be added when @code{after-init-hook} is run. +Each binding is added if and only if at that time no other key +is bound to the same command and no other command is bound to +the same key. In other words we try to avoid adding bindings +that are unnecessary, as well as bindings that conflict with +other bindings. + +Adding the above bindings is delayed until @code{after-init-hook} +is called to allow users to set the variable anywhere in their +init file (without having to make sure to do so before @code{magit} +is loaded or autoloaded) and to increase the likelihood that +all the potentially conflicting user bindings have already +been added. + +To set this variable use either @code{setq} or the Custom interface. +Do not use the function @code{customize-set-variable} because doing +that would cause Magit to be loaded immediately when that form +is evaluated (this differs from @code{custom-set-variables}, which +doesn't load the libraries that define the customized variables). + +Setting this variable to nil has no effect if that is done after +the key bindings have already been added. + +We recommend that you bind @code{C-c g} instead of @code{C-c M-g} to +@code{magit-file-dispatch}. The former is a much better binding +but the @code{C-c } namespace is strictly reserved for +users; preventing Magit from using it by default. + +@lisp +(global-set-key (kbd "C-c g") 'magit-file-dispatch) +@end lisp + +Also see @ref{Commands for Buffers Visiting Files} and @ref{Key Binding Conventions,,,elisp,}. +@end defopt @node Plumbing @chapter Plumbing @@ -10398,6 +10691,22 @@ repository's process buffer. @end defun +@defun magit-process-git destination &rest args + +Calls Git synchronously in a separate process, returning its exit +code. DESTINATION specifies how to handle the output, like for +@code{call-process}, except that file handlers are supported. Enables +Cygwin's "noglob" option during the call and ensures unix eol +conversion. +@end defun + +@defun magit-process-file process &optional infile buffer display &rest args + +Processes files synchronously in a separate process. Identical to +@code{process-file} but temporarily enables Cygwin's "noglob" option during +the call and ensures unix eol conversion. +@end defun + If an error occurs when using one of the above functions, then that is usually due to a bug, i.e. using an argument which is not actually supported. Such errors are usually not reported, but when @@ -10462,31 +10771,15 @@ Calls git synchronously with ARGS and then refreshes. @end defun -@defun magit-run-git-with-input input &rest args - -Calls git synchronously with ARGS and sends it INPUT on standard -input. - -INPUT should be a buffer or the name of an existing buffer. The -content of that buffer is used as the process' standard input. -After the process returns a refresh is performed. +@defun magit-run-git-with-input &rest args -As a special case, INPUT may also be nil. In that case the content -of the current buffer is used as standard input and @strong{no} refresh is -performed. +Calls git synchronously with ARGS and sends it the content of the +current buffer on standard input. -This function actually runs git asynchronously. But then it waits -for the process to return, so the function itself is synchronous. -@end defun - -@defun magit-run-git-with-logfile file &rest args - -Calls git synchronously with ARGS@. The process' output is saved in -FILE@. This is rarely useful and so this function might be removed -in the future. - -This function actually runs git asynchronously. But then it waits -for the process to return, so the function itself is synchronous. +If the current buffer's @code{default-directory} is on a remote +filesystem, this function actually runs git asynchronously. But +then it waits for the process to return, so the function itself is +synchronous. @end defun @defun magit-git &rest args @@ -10533,7 +10826,7 @@ still alive), as well as the respective Magit status buffer. @end defun -@defun magit-start-git &rest args +@defun magit-start-git input &rest args Start Git, prepare for refresh, and return the process object. @@ -11115,13 +11408,34 @@ @appendixsec FAQ - How to @dots{}? @menu +* How to pronounce Magit?:: * How to show git's output?:: * How to install the gitman info manual?:: * How to show diffs for gpg-encrypted files?:: * How does branching and pushing work?:: * Can Magit be used as @code{ediff-version-control-package}?:: +* Should I disable VC@?:: @end menu +@node How to pronounce Magit? +@appendixsubsec How to pronounce Magit? + +Either @code{mu[m's] git} or @code{magi@{c => t@}} is fine. + +The slogan is "It's Magit! The magical Git client", so it makes sense +to pronounce Magit like magic, while taking into account that C and T +do not sound the same. + +The German "Magie" is not pronounced the same as the English "magic", +so if you speak German then you can use the above rational to justify +using the former pronunciation; @code{Mag@{ie => it@}}. + +You can also choose to use the former pronunciation just because you +like it better. + +Also see @uref{https://magit.vc/assets/videos/magic.mp4}. +Also see @uref{https://emacs.stackexchange.com/questions/13696}. + @node How to show git's output? @appendixsubsec How to show git's output? @@ -11206,6 +11520,20 @@ command @code{magit-ediff-resolve} which only shows yet-to-be resolved conflicts. +@node Should I disable VC@? +@appendixsubsec Should I disable VC@? + +If you don't use VC (the built-in version control interface) then +you might be tempted to disable it, not least because we used to +recommend that you do that. + +We no longer recommend that you disable VC@. Doing so would break +useful third-party packages (such as @code{diff-hl}), which depend on VC +being enabled. + +If you choose to disable VC anyway, then you can do so by changing +the value of @code{vc-handled-backends}. + @node FAQ - Issues and Errors @appendixsec FAQ - Issues and Errors @@ -11222,6 +11550,8 @@ * My Git hooks work on the command-line but not inside Magit:: * @code{git-commit-mode} isn't used when committing from the command-line:: * Point ends up inside invisible text when jumping to a file-visiting buffer:: +* I am unable to stage when using Tramp from MS Windows:: +* I am no longer able to save popup defaults:: @end menu @node Magit is slow @@ -11315,18 +11645,13 @@ But doing so isn't good for performance. For more (overly optimistic) information see @ref{VC Mode Line,,,emacs,}. -If you don't really care about seeing that information in the -mode-line, but just don't want to see @emph{incorrect} information, then -consider disabling VC when using Git: +If you don't really care about seeing this information in the +mode-line, but just don't want to see @emph{incorrect} information, +then consider simply not displaying it in the mode-line: @lisp -(setq vc-handled-backends (delq 'Git vc-handled-backends)) -@end lisp - -Or to disable it completely: - -@lisp -(setq vc-handled-backends nil) +(setq-default mode-line-format + (delete '(vc-mode vc-mode) mode-line-format)) @end lisp @node A branch and tag sharing the same name breaks SOMETHING @@ -11402,8 +11727,8 @@ @end example This will actually end up using @code{emacs}, not @code{emacsclient}. If you do -this, then can still edit the commit message but @code{git-commit-mode} won't -be used and you have to exit @code{emacs} to finish the process. +this, then you can still edit the commit message but @code{git-commit-mode} +won't be used and you have to exit @code{emacs} to finish the process. Tautology ahead. If you want to be able to use @code{emacsclient} to connect to a running @code{emacs} instance, even though no @code{emacs} instance is running, @@ -11425,6 +11750,37 @@ instead use @code{magit-diff-visit-file-hook} to reveal the text, possibly using @code{reveal-post-command} or for Org buffers @code{org-reveal}. +@node I am unable to stage when using Tramp from MS Windows +@appendixsubsec I am unable to stage when using Tramp from MS Windows + +Magit may be unable to stage (or otherwise apply) individual hunks +when you are connected to remote machine using Tramp and the local +machine uses MS Windows. + +There appears to be a problem with @code{process-send-eof} in this scenario, +as mentioned at the end of @code{tramp-tests.el}. I have contacted the Tramp +maintainer about this. For now this unfortunately means that it just +doesn't work and we cannot do anything about it. If you have more +information, then please comment on +@uref{https://github.com/magit/magit/issues/3624}. + +@node I am no longer able to save popup defaults +@appendixsubsec I am no longer able to save popup defaults + +Magit used to use Magit-Popup to implement the transient popup menus. +Now it used Transient instead, which is Magit-Popup's successor. + +In the older Magit-Popup menus, it was possible to save user settings +(e.g. setting the gpg signing key for commits) by using @code{C-c C-c} in the +popup buffer. This would dismiss the popup, but save the settings as +the defaults for future popups. + +When switching to Transient menus, this functionality is now available +via @code{C-x C-s} instead; the @code{C-x} prefix has other options as well when +using Transient, which will be displayed when it is typed. See +@uref{https://magit.vc/manual/transient/Saving-Values.html#Saving-Values} for +more details. + @node Debugging Tools @chapter Debugging Tools diff -Nru magit-2.99.0.git0957.ge8c7bd03/Documentation/Makefile magit-3.3.0/Documentation/Makefile --- magit-2.99.0.git0957.ge8c7bd03/Documentation/Makefile 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/Documentation/Makefile 2021-10-06 12:51:17.000000000 +0000 @@ -23,7 +23,8 @@ @echo $^ | xargs -n 1 $(INSTALL_INFO) --dir=$@ HTML_FIXUP_CSS = '//a\ -\ +\ +\n\ \n\ \n\ \n\ @@ -82,10 +83,9 @@ ## Release management ################################################ -ORG_ARGS = --batch -Q $(ORG_LOAD_PATH) -ORG_ARGS += -l magit-utils.el -l ox-extra -l ox-texinfo+.el +ORG_ARGS = --batch -Q $(ORG_LOAD_PATH) -l magit-utils.el -l ox-texinfo+.el ORG_ARGS += --eval "(or (require 'org-man nil t) (require 'ol-man))" -ORG_EVAL = --eval "(ox-extras-activate '(ignore-headlines))" +ORG_EVAL = --eval "(setq org-texinfo+-dissolve-noexport-headlines t)" ORG_EVAL += --eval "(setq indent-tabs-mode nil)" ORG_EVAL += --eval "(setq org-src-preserve-indentation nil)" ORG_EVAL += --funcall org-texinfo-export-to-texinfo @@ -107,7 +107,7 @@ stats: @printf "Generating statistics\n" - @gitstats -c style=/assets/stats.css -c max_authors=999 $(TOP) $(statsdir) + @gitstats -c style=https://magit.vc/assets/stats.css -c max_authors=999 $(TOP) $(statsdir) authors: AUTHORS.md diff -Nru magit-2.99.0.git0957.ge8c7bd03/Documentation/RelNotes/3.0.0.org magit-3.3.0/Documentation/RelNotes/3.0.0.org --- magit-2.99.0.git0957.ge8c7bd03/Documentation/RelNotes/3.0.0.org 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/Documentation/RelNotes/3.0.0.org 2021-10-06 12:51:17.000000000 +0000 @@ -1,4 +1,27 @@ -* Magit v3.0.0 Release Notes (unreleased) +* It's Magit! A Git Porcelain inside Emacs + +Magit is a text-based Git user interface that puts an unmatched focus +on streamlining workflows. Commands are invoked using short mnemonic +key sequences that take the cursor’s position in the highly actionable +interface into account to provide context-sensitive behavior. + +With Magit you can do nearly everything that you can do when using Git +on the command-line, but at greater speed and while taking advantage +of advanced features that previously seemed too daunting to use on a +daily basis. Many users will find that by using Magit they can become +more effective Git user. + +For more information about Magit, see https://magit.vc. + +* Magit v3.0.0 Release Notes + +Released 25th May 2021 by Jonas Bernoulli. + +I am pleased to announce the release of Magit version 3.0.0, +representing 1264 commits by 87 contributors over 2.5 years. + +Also see https://emacsair.me/2021/05/25/magit-3.0. + ** Breaking changes - Dropped support for Git v2.0 and v2.1. @@ -17,7 +40,9 @@ - The commands ~magit-branch-pull-request~, ~magit-checkout-pull-request~ and ~magit-worktree-checkout-pull-request~ were removed in favor of - improved implementations provided by the new Forge package. + improved implementations provided by the new Forge package. (See + https://emacsair.me/2018/12/19/forge-0.1 for more information about + Forge.) - ~C-c C-e~ is no longer bound to ~magit-dispatch-popup~. It is bound to ~magit-edit-thing~ now, so that Forge can add section-specific @@ -39,6 +64,24 @@ compatibility. Packages using the obsolete variable and functions should be adjusted soon. #3836 +- Magit-Section is now distributed as a separate package, as announced + here: https://emacsair.me/2020/01/23/magit-section. #4003 + +- Magit now adds three global key bindings, which can be prevented + by setting the new option ~magit-define-global-key-bindings~ before + loading ~magit~. Note that if you bind these keys to other commands + anywhere in your init file (even *after* loading ~magit~), then Magit + won't override those bindings. See the options doc-string for + more information. #4237 + +- Magit no longer depends on ~async-bytecomp~ to avoid a certain class + of mystery bugs because this effort backfired. 86eec7ba3 + +- ~global-git-commit-mode~ is no longer autoloaded. Users who commit + from the command-line but still want to use ~git-commit-mode~, might + now have to load ~git-commit~ explicitly in their init file. + 13f20763a + ** Changes since v2.90.0 - It isn't always obvious that a section can be expanded, especially @@ -85,6 +128,9 @@ to drop such commits, then you have to enable ~--autosquash~ in the popup and then invoke ~magit-rebase-interactive~. #3670 +- ~magit-rebase-remove-commit~ now supports removing the ~HEAD~ + commit. #4195 + - The option ~magit-repository-directories~ defaults to ~nil~ again because the non-nil default added in v2.90.0 led to surprising changes in behavior. The documentation of this option and the @@ -138,6 +184,10 @@ - New command ~git-rebase-break~ inserts a "break" action in the rebase to-do sequence (available as of Git v2.20). #3762 +- ~git-rebase-kill-line~ and the commands for changing the action of a + commit line (e.g., ~git-rebase-squash~) learned to work on all lines + selected by the region. #4172 + - The ~--color-moved~ diff argument is supported now, but isn't available from the diff transients by default. To enable it use "C-x l" in those transients. #3424 @@ -150,7 +200,7 @@ - ~magit-cherry~ is now available from the ~magit-dispatch~ prefix. ef311f378 -~ ~magit-cherry-spinoff~ now offers the upstream as the default +- ~magit-cherry-spinoff~ now offers the upstream as the default starting-point. e5a2a0ac2 - Added new command ~magit-branch-spinout~. #3794. @@ -175,10 +225,16 @@ - Added new option ~magit-worktree-read-directory-name-function~. #3820 -- TODO Added basic support for libgit2. #3841 +- Basic optional support for ~libgit2~ was added, but because so few + functions are currently implemented using that library, opting in + currently has almost no effect. #3841 - ~git bisect~ is now run asynchronously. #3802 +- ~magit-bisect~ now supports specifying alternate terms. The new + infixes and suffix related to this functionality are disabled by + default. + - ~magit-branch-or-commit-at-point~ now falls back to an abbreviated hash instead of something like "master~2", because the latter often leads to undesirable behavior. fd5eb5b43 @@ -331,6 +387,46 @@ available from the diff transients by default. To enable it use "C-x l" in those transients. #4056 +- Added new command ~magit-reset-keep~. 0ea8b0ef6 + +- Added new option ~magit-reshelve-since-committer-only~. #4101 + +- Added new command ~magit-commit-absorb~ as an alternative to + ~magit-commit-autofixup~. 9423edc0b + +- Added new option ~magit-status-use-buffer-arguments~. #4046 + +- Added new command ~magit-project-status~. #4173 + +- Added new variable ~magit-process-extreme-logging~ for debugging + purposes. #4217 + +- Taught Isearch and Swiper how to expand Magit sections when the + current match is inside a hidden section and how to close sections + again. #3999 + +- Added new command ~magit-commit-absorb-modules~. 10b4bec53 + +- Added new transient command ~magit-shortlog~. #4262 + +- Added new command ~magit-generate-changelog~. c5e118111 + +- The name of the main branch is no longer hard-coded to "master". + Now we use the value of ~init.defaultBranch~ if that is set and the + named branch exists. If not, then some other names that are + commonly used for the main branch are tried as a potential fallback. + c4494ac0b + +- Added new option ~magit-diff-extra-stat-arguments~. 1bd4fe26e + +- Added support for ~git-credential-manager-core~. #4318 + +- The name of the upstream remote is no longer hard-code to "origin". + See the doc-string of function ~magit-primary-remote~ to learn how to + customize this. f883b62fe + +This release also contains numerous other improvements. + ** Fixes since v2.90.0 - Bumped the minimal required version of ~git-commit~ to the correct @@ -376,6 +472,10 @@ - A regression in ~magit-log-move-to-parent~ prevented it from doing its job. #3682 +- Since v2.11.0 ~magit-log-revision-headers-format~ lines in the log + output (shown via ~++header~) weren't displayed properly when + ~--graph~ was enabled. #4129 + - ~magit-clone~ didn't run ~magit-credential-hook~. #3683 - ~magit-list-repositories~ failed if one of the repositories that it @@ -462,6 +562,18 @@ unchanged" bit, and then modifying it again triggered a failure in ~magit-wip-commit-worktree~. #4037 +- ~magit-abbrev-length~ returned an incorrect result when + ~core.abbrev~ was explicitly set to "auto". + +- Calling ~magit-status~ in a repository with a corrupt Git + configuration didn't propagate the error and instead preseted the + directory as though it was uninitialized. #4337 + +- When the status buffer is not shown in any buffer but point is on + a hunk, and editing and saving the respective file causes, that + hunk to disappear or change, then Magit ended up changing point + in the file-visiting buffer. #4196 + - Various bug fixes to ~magit-branch-delete~ (3e73ff19d), ~magit--{upstream,pushbranch}-suffix-predicate~ (0ce7fbbc2), @@ -493,6 +605,97 @@ ~magit-stash-drop~ (a4972766a), ~magit-ignore-submodules-p~ (a7699f868), ~magit-log-propertize-keywords~ (ac1ee3df5), + and then I stopped adding to this list. + +This release also contains numerous other bug fixes, typo fixes, and +documentation fixes. + +* Authors -This release also contains other minor improvements, bug fixes, typo -fixes, and documentation fixes. + 1001 Jonas Bernoulli + 120 Kyle Meyer + 10 Basil L. Contovounesios + 9 Noam Postavsky + 5 Vladimir Panteleev + 4 Damien Cassou + 4 Daniel Martín + 4 Sam Cedarbaum + 4 Štěpán Němec + 3 Adam Porter + 3 Benjamin Motz + 3 Kévin Le Gouguec + 2 Alban Gruin + 2 Allen Li + 2 Bastian Beischer + 2 Clément Pit-Claudel + 2 Daniel Fleischer + 2 Evan Torrie + 2 Ingmar Sittl + 2 Leo Vivier + 2 Martin Polden + 2 Naoya Yamashita + 2 Phil Sainty + 2 Philipp Stephani + 2 Radon Rosborough + 2 Ryan C. Thompson + 2 Szunti + 2 Tassilo Horn + 2 Thierry Volpiatto + 2 Troy Hinckley + 2 zilongshanren + 1 Adam Kruszewski + 1 Adam Spiers + 1 Alexander Miller + 1 Andrew Eggenberger + 1 Andrew Psaltis + 1 Andrew Schwartzmeyer + 1 Arnau Roig Ninerola + 1 Ashlynn Anderson + 1 Ben North + 1 Brian Leung + 1 Dan Davison + 1 Danny Zhu + 1 David Ellison + 1 Dominique Quatravaux + 1 Eric + 1 Fritz Grabo + 1 Gregory Heytings + 1 Hussein Ait-Lahcen + 1 Ian Milligan + 1 Ilya Grigoriev + 1 Johann Klähn + 1 Johannes Altmanninger + 1 Jonas Galvão Xavier + 1 Jonathan Arnett + 1 Jonathan del Strother + 1 Jordan Galby + 1 Josh Elsasser + 1 Justin Guenther + 1 Keshav Kini + 1 Kevin Brubeck Unhammer + 1 Kevin J. Foley + 1 Knut Olav Bøhmer + 1 Magnus Malm + 1 Mario Rodas + 1 Martin Joerg + 1 Matthew Kraai + 1 Maxim Cournoyer + 1 Michael Griffiths + 1 Ola x Nilsson + 1 Pancho Horrillo + 1 Philipp Fehre + 1 Pritam Baral + 1 Roey Darwish Dror + 1 Sean Whitton + 1 Simon Pintarelli + 1 Steve Purcell + 1 Thomas Fini Hansen + 1 Topi Miettinen + 1 Tsuyoshi Kitamoto + 1 Vitaly Ostashov + 1 Vladimir Sedach + 1 Wojciech Siewierski + 1 Yann Herklotz + 1 Ynilu + 1 Zhu Zihao + 1 zakora diff -Nru magit-2.99.0.git0957.ge8c7bd03/Documentation/RelNotes/3.1.0.org magit-3.3.0/Documentation/RelNotes/3.1.0.org --- magit-2.99.0.git0957.ge8c7bd03/Documentation/RelNotes/3.1.0.org 1970-01-01 00:00:00.000000000 +0000 +++ magit-3.3.0/Documentation/RelNotes/3.1.0.org 2021-10-06 12:51:17.000000000 +0000 @@ -0,0 +1,73 @@ +* It's Magit! A Git Porcelain inside Emacs + +Magit is a text-based Git user interface that puts an unmatched focus +on streamlining workflows. Commands are invoked using short mnemonic +key sequences that take the cursor’s position in the highly actionable +interface into account to provide context-sensitive behavior. + +With Magit you can do nearly everything that you can do when using Git +on the command-line, but at greater speed and while taking advantage +of advanced features that previously seemed too daunting to use on a +daily basis. Many users will find that by using Magit they can become +more effective Git user. + +For more information about Magit, see https://magit.vc. + +* Magit v3.1.0 Release Notes + +Released 1st July 2021 by Jonas Bernoulli. + +I am pleased to announce the release of Magit version 3.1.0, +representing 31 commits by 4 contributors over one month. + +Also see https://emacsair.me/2021/07/01/magit-3.1. + +** Breaking changes + +- The function signature of ~magit-completing-read-multiple~ was not + compatible with that of ~completing-read-multiple~, so we deprecate + it. Use the improved ~magit-completing-read-multiple*~ instead. + #4420 + +- The description of ~magit-merge-into~ in the merge menu was changed + to "dissolve" (from "merge into"). In the future we are going to + change the key binding from "i" to "d" as well, to keep it mnemonic. + We don't make both changes at once in the hope that this makes the + transition easier for existing users. 4c096921f + +** Changes since v3.0.0 + +- Adjusted to changes to Eieio in Emacs 28. a3626277c, 54a0019f3 + +- Added new command ~magit-log-move-to-revision~. #4418 + +- ~A m~ is now also bound to ~magit-merge-squash~. Despite the name it + fits better there. 51152fdec + +** Fixes since v3.0.0 + +- Fixed ~magit-emacs-Q-command~ and ~make build~ for ELPA users. + f50c3aa56 + +- Fixed reading choice in ~magit-process-git-credential-manager-core~. + #4396 + +- ~magit-blame~ didn't account for quoted file names when parsing + output from ~git blame~. #4400 + +- A regression in v3.0.0 prevented ~magit-bisect-run~ from executing + ~git bisect run~ unless ~magit-bisect-start~ was called beforehand. + f592e367d + +- ~magit-log-select-quit~ failed to call ~magit-log-select-quit-function~. + #4423 + +- The entry for pull-requests in ~magit-list-refs-namespaces~ did not + match the ref names used by Forge for that purpose. 4c3373f9a + +* Authors + + 24 Jonas Bernoulli + 3 Kyle Meyer + 1 Siavash Askari Nasr + 1 TEC diff -Nru magit-2.99.0.git0957.ge8c7bd03/Documentation/RelNotes/3.2.0.org magit-3.3.0/Documentation/RelNotes/3.2.0.org --- magit-2.99.0.git0957.ge8c7bd03/Documentation/RelNotes/3.2.0.org 1970-01-01 00:00:00.000000000 +0000 +++ magit-3.3.0/Documentation/RelNotes/3.2.0.org 2021-10-06 12:51:17.000000000 +0000 @@ -0,0 +1,100 @@ +* It's Magit! A Git Porcelain inside Emacs + +Magit is a text-based Git user interface that puts an unmatched focus +on streamlining workflows. Commands are invoked using short mnemonic +key sequences that take the cursor’s position in the highly actionable +interface into account to provide context-sensitive behavior. + +With Magit you can do nearly everything that you can do when using Git +on the command-line, but at greater speed and while taking advantage +of advanced features that previously seemed too daunting to use on a +daily basis. Many users will find that by using Magit they can become +more effective Git user. + +For more information about Magit, see https://magit.vc. + +* Magit v3.2.0 Release Notes + +Released 1st August 2021 by Jonas Bernoulli. + +I am pleased to announce the release of Magit version 3.2.0, +representing 84 commits by 5 contributors over one month. + +Also see https://emacsair.me/2021/08/01/magit-3.2. + +** Changes since v3.1.0 + +- The default of ~magit-bury-buffer-function~ was changed to + ~magit-mode-quit-window~. #4412 + +- Added new option ~magit-remote-git-executable~ alongside the existing + ~magit-git-executable~. Previously the latter was used for local and + remote ~git~ processes alike, now the former specifies the executable + that is used when Tramp is involved. Using a single variable was + problematic because we had to use an absolute path on Windows for + performance reasons but that path was almost certainly wrong when + using Tramp. #4447 + +- We now use an absolute path for ~magit-git-executable~ on macOS as + well because at least for some macOS users using just the name of + the executable performs horribly. #4447 + +- The section showing openpgp output in the revision buffer is now + collapsible and starts out collapsed for good signatures or when the + certificate is missing. This hopefully makes it more appealing to + enable ~--show-signature~ (and maybe even encourages some authors to + start signing commits). 1e08ac6fd + +- A mode change or rename can now be applied (un-/staged etc.) without + also applying edits to the same file and vice-versa. #4439 + +- Many commands that act on (or default to) the commit at point now + pick that up in a few more places; when the string at point is a + known hash, on a blame chunk, and on a hunk or file inside a log. + d8d3e4813, 40ad7a25c, 402112c6e + +- The default ~magit-pop-revision-stack-format~ now include the + committer date. 1f85297a3 + +- The default ~magit-log-revision-headers-format~ now includes notes. + 33bd79fd45 + +- Added new options ~magit-repolist-sort-key~ + and ~magit-submodule-list-sort-key~. #4409 + +- Added new function ~magit-repolist-column-flags~. 35067f512 + +- Added new option ~magit-ediff-use-indirect-buffers~. #4395 + +- Added new function ~magit-process-git~. fd5cf6173 + +- Added new function ~magit-git-config-p~. 60f82a323 + +** Fixes since v3.1.0 + +- In the normal case ~magit-name-tag~ failed to return the tag. + 14170b4ea + +- ~magit-completing-read-multiple*~ tried to use a variable that is + unbound if ~helm~ isn't loaded. 29b0cb489 + +- Some push commands couldn't deal with remote and branch names that + contain the percent character. #4428 + +- ~magit-git-shortlog~ got stuck in the repository in which it was first + invoked. 384610edb + +- ~magit-commit-augment~ did not support ~--allow-empty~. bbdfd4287 + +- Squash commands didn't fully take ~--author~ into account. 02d2917c6 + +- ~magit-completing-read-multiple*~ conflicted with the ~consult~ package. + #4437 + +* Authors + + 73 Jonas Bernoulli + 6 Kyle Meyer + 2 Boruch Baum + 1 Philippe Cavalaria + 1 Toon Claes diff -Nru magit-2.99.0.git0957.ge8c7bd03/Documentation/RelNotes/3.2.1.org magit-3.3.0/Documentation/RelNotes/3.2.1.org --- magit-2.99.0.git0957.ge8c7bd03/Documentation/RelNotes/3.2.1.org 1970-01-01 00:00:00.000000000 +0000 +++ magit-3.3.0/Documentation/RelNotes/3.2.1.org 2021-10-06 12:51:17.000000000 +0000 @@ -0,0 +1,27 @@ +* It's Magit! A Git Porcelain inside Emacs + +Magit is a text-based Git user interface that puts an unmatched focus +on streamlining workflows. Commands are invoked using short mnemonic +key sequences that take the cursor’s position in the highly actionable +interface into account to provide context-sensitive behavior. + +With Magit you can do nearly everything that you can do when using Git +on the command-line, but at greater speed and while taking advantage +of advanced features that previously seemed too daunting to use on a +daily basis. Many users will find that by using Magit they can become +more effective Git user. + +For more information about Magit, see https://magit.vc. + +* Magit v3.2.1 Release Notes + +Released 6st August 2021 by Jonas Bernoulli. + +I am pleased to announce the release of Magit version 3.2.1. + +This is the first release that is available from NonGNU Elpa. It is +identical to version 3.2.0 except for dependency metadata, which had +to be changed so that this package could be released on NonGNU Elpa. + +Also see https://emacsair.me/2021/08/06/nongnu-elpa +and https://elpa.nongnu.org/nongnu/magit.html. diff -Nru magit-2.99.0.git0957.ge8c7bd03/Documentation/RelNotes/3.3.0.org magit-3.3.0/Documentation/RelNotes/3.3.0.org --- magit-2.99.0.git0957.ge8c7bd03/Documentation/RelNotes/3.3.0.org 1970-01-01 00:00:00.000000000 +0000 +++ magit-3.3.0/Documentation/RelNotes/3.3.0.org 2021-10-06 12:51:17.000000000 +0000 @@ -0,0 +1,152 @@ +* It's Magit! A Git Porcelain inside Emacs + +Magit is a text-based Git user interface that puts an unmatched focus +on streamlining workflows. Commands are invoked using short mnemonic +key sequences that take the cursor’s position in the highly actionable +interface into account to provide context-sensitive behavior. + +With Magit you can do nearly everything that you can do when using Git +on the command-line, but at greater speed and while taking advantage +of advanced features that previously seemed too daunting to use on a +daily basis. Many users will find that by using Magit they can become +more effective Git user. + +For more information about Magit, see https://magit.vc. + +* Magit v3.3.0 Release Notes + +Released 4th October 2021 by Jonas Bernoulli. + +I am pleased to announce the release of Magit version 3.3.0, +representing 88 commits by 6 contributors over two month. + +Also see https://emacsair.me/2021/10/04/magit-3.3. + +** Breaking changes + +- The last remaining alphabetic keys (both lower- and uppercase) are + now bound in ~magit-mode-map~. ~H~ to ~magit-describe-section~, ~j~ to the + new ~magit-status-quick~ (or ~magit-status-jump~ in status buffers), ~J~ + to the new ~magit-display-repository-buffer~, ~Q~ to ~magit-git-command~ + and ~Z~ to ~magit-worktree~, and once Forge is loaded, then ~N~ to + ~forge-dispatch~. (~Z~ used to be bound to ~magit-stash~, which now is + only available on ~z~.) #4259, 9bec1c54a, e401bd4d3 + +- ~I~ is now bound to ~magit-init~ instead of ~magit-gitignore~, which + continues to be available on ~i~. Users of the ~magit-imerge~ package + (which previously bound ~i~) should consult its library header for a + suggestion on how to resolve the resulting conflict. b54b537db + +** Changes since v3.2.0 + +- No longer automatically add ~--full-history~ when showing a log for a + single file that isn't being tracked anymore. #4381 + +- ~magit-stash-both~ now asks before discarding merge state. #4345 + +- Several infix arguments, which previously could only be disabled + or have a numeric value, can now also be enabled without having + an explicit numeric value. #4379 + +- Added ~-Xignore-space-change~ and ~-Xignore-all-space~ to ~magit-merge~. + Like most newly added expert arguments they have to be explicitly + [[https://magit.vc/manual/transient/Enabling-and-Disabling-Suffixes.html][revealed]]. #4387 + +- Added new command ~magit-status-quick~, which shows the status buffer + but avoids refreshing it for performance reasons. #4259 + +- Added new commands ~magit-display-repository-buffer~ (bound to ~j~ in + Magit buffers) and ~magit-switch-to-repository-buffer~ (bound to ~J~) + and variants for switching to any existing Magit buffer belonging + to the current repository. #4259 + +- Added new command ~magit-dired-am-apply-patches~ for use in Dired. + #4094. + +- Rearranged ~magit-patch~ and added a binding for ~magit-am~. 8ec3a1a21, + 8cadf302b + +- Added new command ~magit-help~ (bound to ~h~ in ~magit-dispatch~), which + simply shows Magit's Info manual. 5bba62629 + +- When listing entries for Imenu, then remove entry counts from group + titles for the benefit of third-party packages that need stable + titles. #4477 + +- Include Forge's ~pullreq~ and ~issue~ sections when listing entries for + Imenu. f4016f734 + +- Bound ~imenu~ in the ~magit-status-jump~ prefix. 678df30c3 + +- Added new transient prefix command ~magit-bundle~, which provides + support for ~git bundle~. #4392 + +- When minibuffer completion allows for a branch or a commit to be + selected and the former is preferred and thus offered as default + then, if possible, offer the commit at point as the first choice + initially accessible with ~next-history-element~. #4291 + +- Bound ~magit-refs-set-show-commit-count~ in the ~magit-show-refs~ + prefix. 2fe42f63d + +- Added new option ~magit-commit-diff-inhibit-same-window~. #4132 + +- Added support for invoking Smerge's "keep" commands when point is on + a hunk in a Magit buffer. They can be invoked using the same key + bindings as in file-visiting buffers or ~RET~, ~u~, ~b~ and ~l~. #4458 + +- Added new command ~magit-remote-unshallow~. #4480 + +- Added new option ~git-commit-use-local-message-ring~. #4503 + +** Fixes since v3.2.0 + +- Make ~magit-branch-remote-head~ and ~magit-branch-current~ fall back + to ~:inverse-video~ when the ~:box~ attribute isn't support, i.e. in + a terminal. If this change does not have any effect for you then + your theme probably changes these faces and should stop doing so. + #4206 + +- In some cases refreshing a buffer caused the cursor to jump to a + different position. #4148 + +- ~magit-convert-filename-for-git~ did not expand absolute filenames, + which is necessary because Git does not understand ~~/~. de1dc8e74 + +- ~magit-rebase~ did not enable ~--autostash~ by default but the + documentation says it does. 421be65a3 + +- ~magit-clone-read-repository~ did not convert filenames before passing + them to Git. 4aa7d2928 + +- Due to a regression in v2.90.0, ~magit-wip-log~ and + ~magit-wip-log-current~ failed to extract the previous tips of the + wip refs from the reflog (which is relevant when + ~~magit-wip-merge-branch~ is nil). c327824b0 + +- An old attempt to avoid needlessly updating section highlighting + did not actually succeed. #3976 + +- An error occurred when first showing a status buffer and + ~which-function-mode~ is enabled because that caused Imenu to collect + items at a time when that is not possible yet. #4481 + +- A change in Git v2.32.0 made it necessary to explicitly filter out + directories when committing to wip worktree refs. #4499 + +- Fixed appearance of Gravatar images by forcing their size instead + relying the service to return the promised size as advertised. + 8771401d4 + +- ~git-commit-setup~ enabled the major-mode after setting local + variables, which caused non-permanent variables to be reset. + ece2cb84d + +* Authors + + 76 Jonas Bernoulli + 8 Kyle Meyer + 1 Daniel Nagy + 1 Franklin Delehelle + 1 Jonathon McKitrick + 1 Lin Sun diff -Nru magit-2.99.0.git0957.ge8c7bd03/.github/CONTRIBUTING.md magit-3.3.0/.github/CONTRIBUTING.md --- magit-2.99.0.git0957.ge8c7bd03/.github/CONTRIBUTING.md 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/.github/CONTRIBUTING.md 2021-10-06 12:51:17.000000000 +0000 @@ -1,3 +1,13 @@ +Asking for help +=============== + +To ask for help please use the **Discussions** feature. To open +a new discussion, click [here][new] and then click on Select +Category, most likely to select the **Q&A** category. + +Alternatively you can ask for help on the Emacs [StackExchange][se] +site (using the `magit` tag) or on the Emacs [subreddit]. + Reporting issues and suggesting features ======================================== @@ -33,7 +43,11 @@ [monetary donation][donations]. -[donations]: https://magit.vc/donate/ -[issues]: https://github.com/magit/magit/issues -[metadocs]: https://github.com/magit/magit/wiki/Documentation-tools-and-conventions -[pulls]: https://github.com/magit/magit/pulls +[discussions]: https://github.com/magit/magit/discussions +[donations]: https://magit.vc/donate/ +[issues]: https://github.com/magit/magit/issues +[metadocs]: https://github.com/magit/magit/wiki/Documentation-tools-and-conventions +[new]: https://github.com/magit/magit/discussions/new +[pulls]: https://github.com/magit/magit/pulls +[se]: https://emacs.stackexchange.com +[subreddit]: https://www.reddit.com/r/emacs diff -Nru magit-2.99.0.git0957.ge8c7bd03/.github/ISSUE_TEMPLATE/bug_report.md magit-3.3.0/.github/ISSUE_TEMPLATE/bug_report.md --- magit-2.99.0.git0957.ge8c7bd03/.github/ISSUE_TEMPLATE/bug_report.md 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/.github/ISSUE_TEMPLATE/bug_report.md 2021-10-06 12:51:17.000000000 +0000 @@ -1,7 +1,7 @@ --- title: name: Bug report -about: Report a defect +about: Report a defect. --- Please do not ignore these instructions. diff -Nru magit-2.99.0.git0957.ge8c7bd03/.github/ISSUE_TEMPLATE/config.yml magit-3.3.0/.github/ISSUE_TEMPLATE/config.yml --- magit-2.99.0.git0957.ge8c7bd03/.github/ISSUE_TEMPLATE/config.yml 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/.github/ISSUE_TEMPLATE/config.yml 2021-10-06 12:51:17.000000000 +0000 @@ -1,14 +1,14 @@ blank_issues_enabled: false contact_links: - - name: Emacs StackExchange - url: https://emacs.stackexchange.com/questions/tagged/magit + - name: "SUPPORT ☛ The Discussions feature of this repository" + url: https://github.com/magit/magit/discussions about: Please search, ask and answer questions here. - - name: Emacs Reddit + - name: "SUPPORT ☛ Emacs Reddit" url: https://www.reddit.com/r/emacs - about: Another place to ask questions. - - name: Magit FAQ + about: Another place to search, ask and answer questions. + - name: "Magit FAQ" url: https://magit.vc/manual/magit/FAQ.html about: It might be that many others had the same question. - - name: Magit Manual + - name: "Magit Manual" url: https://magit.vc/manual/magit/#Top about: The fine manual may also be of use. diff -Nru magit-2.99.0.git0957.ge8c7bd03/.github/ISSUE_TEMPLATE/feature_request.md magit-3.3.0/.github/ISSUE_TEMPLATE/feature_request.md --- magit-2.99.0.git0957.ge8c7bd03/.github/ISSUE_TEMPLATE/feature_request.md 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/.github/ISSUE_TEMPLATE/feature_request.md 2021-10-06 12:51:17.000000000 +0000 @@ -1,7 +1,7 @@ --- title: name: Feature request -about: Suggest a new feature +about: Suggest a new feature. ⚠ PLEASE DO NOT USE THIS FOR SUPPORT REQUESTS. ⚠ --- Before you ask for a new feature to be added to Magit or for an existing feature to be improved, please make sure that what are asking for does not already exist by consulting the documentation [1]. diff -Nru magit-2.99.0.git0957.ge8c7bd03/.github/workflows/test.yml magit-3.3.0/.github/workflows/test.yml --- magit-2.99.0.git0957.ge8c7bd03/.github/workflows/test.yml 1970-01-01 00:00:00.000000000 +0000 +++ magit-3.3.0/.github/workflows/test.yml 2021-10-06 12:51:17.000000000 +0000 @@ -0,0 +1,42 @@ +name: test +on: [ push, pull_request ] +jobs: + test: + runs-on: ubuntu-20.04 + strategy: + matrix: + emacs_version: + - 25.1 + # 25.2 is identical to 25.3 except for a critical security bug in + # enriched text mode (see Emacs Bug#28350). + - 25.3 + - 26.1 # Debian is on this version. + - 26.3 + - 27.1 + - snapshot + git_impl: + - git + # FIXME Broken due to glibc version mismatch. See #4456. + # - libgit + steps: + - uses: cachix/install-nix-action@v12 + with: + nix_path: nixpkgs=channel:nixos-unstable + - uses: cachix/cachix-action@v8 + with: + name: emacs-ci + - uses: actions/checkout@v2 + - name: Install + run: | + # Build and install Emacs (+ magit dependencies) using Nix + emacs_ci_version=$(echo "emacs-${{ matrix.emacs_version }}" | sed -e "s/\./-/g") + nix-env -f ./t/default.nix -iA $emacs_ci_version + emacs --version + + # Configure Git + git config --global user.name "A U Thor" + git config --global user.email a.u.thor@example.com + git tag 0 + - name: Test + run: | + make test-${{ matrix.git_impl }} DASH_DIR=$PWD diff -Nru magit-2.99.0.git0957.ge8c7bd03/LICENSE magit-3.3.0/LICENSE --- magit-2.99.0.git0957.ge8c7bd03/LICENSE 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/LICENSE 2021-10-06 12:51:17.000000000 +0000 @@ -1,12 +1,11 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. + Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. - Preamble + Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. @@ -69,7 +68,7 @@ The precise terms and conditions for copying, distribution and modification follow. - TERMS AND CONDITIONS + TERMS AND CONDITIONS 0. Definitions. @@ -77,7 +76,7 @@ "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. - + "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. @@ -510,7 +509,7 @@ covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. - + If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties @@ -619,9 +618,9 @@ Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. - END OF TERMS AND CONDITIONS + END OF TERMS AND CONDITIONS - How to Apply These Terms to Your New Programs + How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it @@ -646,7 +645,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program. If not, see . + along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. @@ -665,12 +664,11 @@ You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see -. +. The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read -. - +. diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/git-commit.el magit-3.3.0/lisp/git-commit.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/git-commit.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/git-commit.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,32 +1,32 @@ ;;; git-commit.el --- Edit Git commit messages -*- lexical-binding: t; -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. -;; Authors: Jonas Bernoulli -;; Sebastian Wiesner -;; Florian Ragwitz -;; Marius Vollmer +;; Author: Jonas Bernoulli +;; Sebastian Wiesner +;; Florian Ragwitz +;; Marius Vollmer ;; Maintainer: Jonas Bernoulli -;; Package-Requires: ((emacs "25.1") (dash "20180910") (transient "20190812") (with-editor "20181103")) ;; Keywords: git tools vc ;; Homepage: https://github.com/magit/magit - -;; This file is not part of GNU Emacs. +;; Package-Requires: ((emacs "25.1") (dash "2.19.1") (transient "0.3.6") (with-editor "3.0.5")) +;; Package-Version: 3.3.0 +;; SPDX-License-Identifier: GPL-3.0-or-later ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) ;; any later version. - +;; ;; This file is distributed in the hope that it will be useful, ;; but WITHOUT ANY WARRANTY; without even the implied warranty of ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ;; GNU General Public License for more details. - +;; ;; You should have received a copy of the GNU General Public License ;; along with this file. If not, see . @@ -113,17 +113,20 @@ ;;;; Dependencies (require 'dash) -(require 'log-edit) +(require 'subr-x) + (require 'magit-git nil t) +(require 'magit-mode nil t) (require 'magit-utils nil t) + +(require 'log-edit) (require 'ring) +(require 'rx) (require 'server) (require 'transient) (require 'with-editor) -(eval-when-compile - (require 'recentf) - (require 'subr-x)) +(defvar recentf-exclude) ;;;; Declarations @@ -150,13 +153,21 @@ :link '(info-link "(magit)Editing Commit Messages") :group 'tools) -;;;###autoload (define-minor-mode global-git-commit-mode "Edit Git commit messages. + This global mode arranges for `git-commit-setup' to be called when a Git commit message file is opened. That usually happens when Git uses the Emacsclient as $GIT_EDITOR to have the user -provide such a commit message." +provide such a commit message. + +Loading the library `git-commit' by default enables this mode, +but the library is not automatically loaded because doing that +would pull in many dependencies and increase startup time too +much. You can either rely on `magit' loading this library or +you can load it explicitly. Autoloading is not an alternative +because in this case autoloading would immediately trigger +full loading." :group 'git-commit :type 'boolean :global t @@ -175,7 +186,19 @@ `git-commit-mode'." :group 'git-commit :type '(choice (function-item text-mode) + (function-item markdown-mode) + (function-item org-mode) + (function-item fundamental-mode) + (function-item git-commit-elisp-text-mode) + (function :tag "Another mode") (const :tag "No major mode"))) +;;;###autoload(put 'git-commit-major-mode 'safe-local-variable +;;;###autoload (lambda (val) +;;;###autoload (memq val '(text-mode +;;;###autoload markdown-mode +;;;###autoload org-mode +;;;###autoload fundamental-mode +;;;###autoload git-commit-elisp-text-mode)))) (defcustom git-commit-setup-hook '(git-commit-save-message @@ -190,6 +213,7 @@ :get (and (featurep 'magit-utils) 'magit-hook-custom-get) :options '(git-commit-save-message git-commit-setup-changelog-support + magit-generate-changelog git-commit-turn-on-auto-fill git-commit-turn-on-flyspell git-commit-propertize-diff @@ -283,6 +307,16 @@ :safe (lambda (val) (and (listp val) (-all-p 'stringp val))) :type '(repeat string)) +(defcustom git-commit-use-local-message-ring nil + "Whether to use a local message ring instead of the global one. +This can be set globally, in which case every repository gets its +own commit message ring, or locally for a single repository. If +Magit isn't available, then setting this to a non-nil value has +no effect." + :group 'git-commit + :safe 'booleanp + :type 'boolean) + ;;;; Faces (defgroup git-commit-faces nil @@ -309,7 +343,7 @@ (defface git-commit-keyword '((t :inherit font-lock-string-face)) "Face used for keywords in commit messages. -In this context a \"keyword\" is text surrounded be brackets." +In this context a \"keyword\" is text surrounded by brackets." :group 'git-commit-faces) (define-obsolete-face-alias 'git-commit-note @@ -416,13 +450,12 @@ ;;; Hooks -;;;###autoload (defconst git-commit-filename-regexp "/\\(\ \\(\\(COMMIT\\|NOTES\\|PULLREQ\\|MERGEREQ\\|TAG\\)_EDIT\\|MERGE_\\|\\)MSG\ \\|\\(BRANCH\\|EDIT\\)_DESCRIPTION\\)\\'") -(eval-after-load 'recentf - '(add-to-list 'recentf-exclude git-commit-filename-regexp)) +(with-eval-after-load 'recentf + (add-to-list 'recentf-exclude git-commit-filename-regexp)) (add-to-list 'with-editor-file-name-history-exclude git-commit-filename-regexp) @@ -433,7 +466,6 @@ (add-hook 'after-change-major-mode-hook 'git-commit-setup-font-lock-in-buffer) -;;;###autoload (defun git-commit-setup-check-buffer () (and buffer-file-name (string-match-p git-commit-filename-regexp buffer-file-name) @@ -473,13 +505,23 @@ \\[git-commit-prev-message] and \\[git-commit-next-message] \ to recover older messages") -;;;###autoload (defun git-commit-setup () (when (fboundp 'magit-toplevel) ;; `magit-toplevel' is autoloaded and defined in magit-git.el, ;; That library declares this functions without loading ;; magit-process.el, which defines it. (require 'magit-process nil t)) + (when git-commit-major-mode + (let ((auto-mode-alist (list (cons (concat "\\`" + (regexp-quote buffer-file-name) + "\\'") + git-commit-major-mode))) + ;; The major-mode hook might want to consult these minor + ;; modes, while the minor-mode hooks might want to consider + ;; the major mode. + (git-commit-mode t) + (with-editor-mode t)) + (normal-mode t))) ;; Pretend that git-commit-mode is a major-mode, ;; so that directory-local settings can be used. (let ((default-directory @@ -496,17 +538,6 @@ (major-mode 'git-commit-mode)) ; trick dir-locals-collect-variables (hack-dir-local-variables) (hack-local-variables-apply))) - (when git-commit-major-mode - (let ((auto-mode-alist (list (cons (concat "\\`" - (regexp-quote buffer-file-name) - "\\'") - git-commit-major-mode))) - ;; The major-mode hook might want to consult these minor - ;; modes, while the minor-mode hooks might want to consider - ;; the major mode. - (git-commit-mode t) - (with-editor-mode t)) - (normal-mode t))) ;; Show our own message using our hook. (setq with-editor-show-usage nil) (setq with-editor-usage-message git-commit-usage-message) @@ -535,9 +566,9 @@ (magit-wip-maybe-add-commit-hook))) (setq with-editor-cancel-message 'git-commit-cancel-message) - (make-local-variable 'log-edit-comment-ring-index) (git-commit-mode 1) (git-commit-setup-font-lock) + (git-commit-prepare-message-ring) (when (boundp 'save-place) (setq save-place nil)) (save-excursion @@ -573,6 +604,8 @@ (defun git-commit-setup-changelog-support () "Treat ChangeLog entries as unindented paragraphs." + (when (fboundp 'log-indent-fill-entry) ; New in Emacs 27. + (setq-local fill-paragraph-function #'log-indent-fill-entry)) (setq-local fill-indent-according-to-mode t) (setq-local paragraph-start (concat paragraph-start "\\|\\*\\|("))) @@ -618,7 +651,7 @@ "Check for violations of certain basic style conventions. For each violation ask the user if she wants to proceed anyway. -Option `git-commit-check-style-conventions' controls which +Option `git-commit-style-convention-checks' controls which conventions are checked." (or force (save-excursion @@ -647,17 +680,29 @@ "Cycle backward through message history, after saving current message. With a numeric prefix ARG, go back ARG comments." (interactive "*p") - (when (and (git-commit-save-message) (> arg 0)) - (setq log-edit-comment-ring-index - (log-edit-new-comment-index - arg (ring-length log-edit-comment-ring)))) - (save-restriction - (goto-char (point-min)) - (narrow-to-region (point) - (if (re-search-forward (concat "^" comment-start) nil t) - (max 1 (- (point) 2)) - (point-max))) - (log-edit-previous-comment arg))) + (let ((len (ring-length log-edit-comment-ring))) + (if (<= len 0) + (progn (message "Empty comment ring") (ding)) + ;; Unlike `log-edit-previous-comment' we save the current + ;; non-empty and newly written comment, because otherwise + ;; it would be irreversibly lost. + (when-let ((message (git-commit-buffer-message))) + (unless (ring-member log-edit-comment-ring message) + (ring-insert log-edit-comment-ring message) + (cl-incf arg) + (setq len (ring-length log-edit-comment-ring)))) + ;; Delete the message but not the instructions at the end. + (save-restriction + (goto-char (point-min)) + (narrow-to-region + (point) + (if (re-search-forward (concat "^" comment-start) nil t) + (max 1 (- (point) 2)) + (point-max))) + (delete-region (point-min) (point))) + (setq log-edit-comment-ring-index (log-edit-new-comment-index arg len)) + (message "Comment %d" (1+ log-edit-comment-ring-index)) + (insert (ring-ref log-edit-comment-ring log-edit-comment-ring-index))))) (defun git-commit-next-message (arg) "Cycle forward through message history, after saving current message. @@ -671,7 +716,20 @@ (when-let ((message (git-commit-buffer-message))) (when-let ((index (ring-member log-edit-comment-ring message))) (ring-remove log-edit-comment-ring index)) - (ring-insert log-edit-comment-ring message))) + (ring-insert log-edit-comment-ring message) + (when (and git-commit-use-local-message-ring + (fboundp 'magit-repository-local-set)) + (magit-repository-local-set 'log-edit-comment-ring + log-edit-comment-ring)))) + +(defun git-commit-prepare-message-ring () + (make-local-variable 'log-edit-comment-ring-index) + (when (and git-commit-use-local-message-ring + (fboundp 'magit-repository-local-get)) + (setq-local log-edit-comment-ring + (magit-repository-local-get + 'log-edit-comment-ring + (make-ring log-edit-maximum-comment-ring-size))))) (defun git-commit-buffer-message () (let ((flush (concat "^" comment-start)) @@ -696,7 +754,7 @@ ;;; Headers -(define-transient-command git-commit-insert-pseudo-header () +(transient-define-prefix git-commit-insert-pseudo-header () "Insert a commit message pseudo header." [["Insert ... by yourself" ("a" "Ack" git-commit-ack) @@ -852,7 +910,8 @@ "Changes not staged for commit:" "Unmerged paths:" "Author:" - "Date:")) + "Date:") + "Also fontified outside of comments in `git-commit-font-lock-keywords-2'.") (defconst git-commit-font-lock-keywords-1 '(;; Pseudo headers @@ -860,8 +919,6 @@ (regexp-opt git-commit-known-pseudo-headers)) (1 'git-commit-known-pseudo-header) (2 'git-commit-pseudo-header))) - ("^[-a-zA-Z]+: [^<]+? <[^>]+>" - (0 'git-commit-pseudo-header)) ;; Summary (eval . `(,(git-commit-summary-regexp) (1 'git-commit-summary))) @@ -887,7 +944,13 @@ (1 'git-commit-comment-heading t))) (eval . `(,(format "^%s\t\\(?:\\([^:\n]+\\):\\s-+\\)?\\(.*\\)" comment-start) (1 'git-commit-comment-action t t) - (2 'git-commit-comment-file t))))) + (2 'git-commit-comment-file t))) + ;; "commit HASH" + (eval . `(,(rx bol "commit " (1+ alnum) eol) + (0 'git-commit-pseudo-header))) + ;; `git-commit-comment-headings' (but not in commented lines) + (eval . `(,(rx-to-string `(seq bol (or ,@git-commit-comment-headings) (1+ blank) (1+ nonl) eol)) + (0 'git-commit-pseudo-header))))) (defconst git-commit-font-lock-keywords-3 `(,@git-commit-font-lock-keywords-2 @@ -905,7 +968,7 @@ ;; Your branch is up to date with 'master'. ;; Your branch and 'master' have diverged, . `(,(format - "^%s Your branch \\(?:is up-to-date with\\|and\\) '%s'" + "^%s Your branch \\(?:is up[- ]to[- ]date with\\|and\\) '%s'" comment-start git-commit--branch-name-regexp) (1 'git-commit-comment-branch-local t) (2 'git-commit-comment-branch-remote t))) @@ -917,7 +980,7 @@ (1 'bold t) (2 'bold t))))) -(defvar git-commit-font-lock-keywords git-commit-font-lock-keywords-2 +(defvar git-commit-font-lock-keywords git-commit-font-lock-keywords-3 "Font-Lock keywords for Git-Commit mode.") (defun git-commit-setup-font-lock () @@ -930,8 +993,12 @@ (modify-syntax-entry ?` "." table) (set-syntax-table table)) (setq-local comment-start - (or (ignore-errors - (car (process-lines "git" "config" "core.commentchar"))) + (or (with-temp-buffer + (call-process "git" nil (current-buffer) nil + "config" "core.commentchar") + (unless (bobp) + (goto-char (point-min)) + (buffer-substring (point) (line-end-position)))) "#")) (setq-local comment-start-skip (format "^%s+[\s\t]*" comment-start)) (setq-local comment-end-skip "\n") @@ -945,17 +1012,14 @@ (progn ;; Make sure the below functions are available. (require 'magit) - ;; Font-Lock wants every submatch to succeed, - ;; so also match the empty string. Do not use - ;; `regexp-quote' because that is slow if there - ;; are thousands of branches outweighing the - ;; benefit of an efficient regep. - (format "\\(\\(?:%s\\)\\|\\)\\(\\(?:%s\\)\\|\\)" + ;; Font-Lock wants every submatch to succeed, so + ;; also match the empty string. Avoid listing + ;; remote branches and using `regexp-quote', + ;; because in repositories have thousands of + ;; branches that would be very slow. See #4353. + (format "\\(\\(?:%s\\)\\|\\)\\([^']+\\)" (mapconcat #'identity (magit-list-local-branch-names) - "\\|") - (mapconcat #'identity - (magit-list-remote-branch-names) "\\|"))) "\\([^']*\\)")) (setq-local font-lock-multiline t) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/git-commit-pkg.el magit-3.3.0/lisp/git-commit-pkg.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/git-commit-pkg.el 1970-01-01 00:00:00.000000000 +0000 +++ magit-3.3.0/lisp/git-commit-pkg.el 2021-10-06 12:51:17.000000000 +0000 @@ -0,0 +1,8 @@ +(define-package "git-commit" "3.3.0" + "Edit Git commit messages." + '((emacs "25.1") + (dash "2.19.1") + (transient "0.3.6") + (with-editor "3.0.5")) + :homepage "https://magit.vc" + :keywords '("git" "tools" "vc")) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/git-rebase.el magit-3.3.0/lisp/git-rebase.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/git-rebase.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/git-rebase.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; git-rebase.el --- Edit Git rebase files -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,7 +8,7 @@ ;; Author: Phil Jackson ;; Maintainer: Jonas Bernoulli -;; This file is not part of GNU Emacs. +;; SPDX-License-Identifier: GPL-3.0-or-later ;; This file is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -74,21 +74,13 @@ ;;; Code: -(require 'dash) +(require 'magit) + (require 'easymenu) (require 'server) (require 'with-editor) -(require 'magit) -(and (require 'async-bytecomp nil t) - (let ((pkgs (bound-and-true-p async-bytecomp-allowed-packages))) - (if (consp pkgs) - (cl-intersection '(all magit) pkgs) - (memq pkgs '(all t)))) - (fboundp 'async-bytecomp-package-mode) - (async-bytecomp-package-mode 1)) - -(eval-when-compile (require 'recentf)) +(defvar recentf-exclude) ;;; Options ;;;; Variables @@ -223,27 +215,32 @@ ;;; Commands (defun git-rebase-pick () - "Use commit on current line." + "Use commit on current line. +If the region is active, act on all lines touched by the region." (interactive) (git-rebase-set-action "pick")) (defun git-rebase-reword () - "Edit message of commit on current line." + "Edit message of commit on current line. +If the region is active, act on all lines touched by the region." (interactive) (git-rebase-set-action "reword")) (defun git-rebase-edit () - "Stop at the commit on the current line." + "Stop at the commit on the current line. +If the region is active, act on all lines touched by the region." (interactive) (git-rebase-set-action "edit")) (defun git-rebase-squash () - "Meld commit on current line into previous commit, edit message." + "Meld commit on current line into previous commit, edit message. +If the region is active, act on all lines touched by the region." (interactive) (git-rebase-set-action "squash")) (defun git-rebase-fixup () - "Meld commit on current line into previous commit, discard its message." + "Meld commit on current line into previous commit, discard its message. +If the region is active, act on all lines touched by the region." (interactive) (git-rebase-set-action "fixup")) @@ -287,7 +284,7 @@ "r" "reword" "s" "squash") "\\(?1:") - " \\(?3:[^ \n]+\\) \\(?4:.*\\)")) + " \\(?3:[^ \n]+\\) ?\\(?4:.*\\)")) (exec . "\\(?1:x\\|exec\\) \\(?3:.*\\)") (bare . ,(concat (regexp-opt '("b" "break" "noop") "\\(?1:") " *$")) @@ -309,11 +306,11 @@ (goto-char (line-beginning-position)) (if-let ((re-start (concat "^\\(?5:" (regexp-quote comment-start) "\\)? *")) - (type (-some (lambda (arg) - (let ((case-fold-search nil)) - (and (looking-at (concat re-start (cdr arg))) - (car arg)))) - git-rebase-line-regexps))) + (type (seq-some (lambda (arg) + (let ((case-fold-search nil)) + (and (looking-at (concat re-start (cdr arg))) + (car arg)))) + git-rebase-line-regexps))) (git-rebase-action :action-type type :action (when-let ((action (match-string-no-properties 1))) @@ -327,16 +324,40 @@ (git-rebase-action)))) (defun git-rebase-set-action (action) - (goto-char (line-beginning-position)) - (with-slots (action-type target trailer) - (git-rebase-current-line) - (if (eq action-type 'commit) - (let ((inhibit-read-only t)) - (magit-delete-line) - (insert (concat action " " target " " trailer "\n")) - (unless git-rebase-auto-advance - (forward-line -1))) - (ding)))) + "Set action of commit line to ACTION. +If the region is active, operate on all lines that it touches. +Otherwise, operate on the current line. As a special case, an +ACTION of nil comments the rebase line, regardless of its action +type." + (pcase (git-rebase-region-bounds t) + (`(,beg ,end) + (let ((end-marker (copy-marker end)) + (pt-below-p (and mark-active (< (mark) (point))))) + (set-marker-insertion-type end-marker t) + (goto-char beg) + (while (< (point) end-marker) + (with-slots (action-type target trailer comment-p) + (git-rebase-current-line) + (cond + ((and action (eq action-type 'commit)) + (let ((inhibit-read-only t)) + (magit-delete-line) + (insert (concat action " " target " " trailer "\n")))) + ((and action-type (not (or action comment-p))) + (let ((inhibit-read-only t)) + (insert comment-start " ")) + (forward-line)) + (t + ;; In the case of --rebase-merges, commit lines may have + ;; other lines with other action types, empty lines, and + ;; "Branch" comments interspersed. Move along. + (forward-line))))) + (goto-char + (if git-rebase-auto-advance + end-marker + (if pt-below-p (1- end-marker) beg))) + (goto-char (line-beginning-position)))) + (_ (ding)))) (defun git-rebase-line-p (&optional pos) (save-excursion @@ -344,15 +365,24 @@ (and (oref (git-rebase-current-line) action-type) t))) -(defun git-rebase-region-bounds () - (when (use-region-p) +(defun git-rebase-region-bounds (&optional fallback) + "Return region bounds if both ends touch rebase lines. +Each bound is extended to include the entire line touched by the +point or mark. If the region isn't active and FALLBACK is +non-nil, return the beginning and end of the current rebase line, +if any." + (cond + ((use-region-p) (let ((beg (save-excursion (goto-char (region-beginning)) (line-beginning-position))) (end (save-excursion (goto-char (region-end)) (line-end-position)))) (when (and (git-rebase-line-p beg) (git-rebase-line-p end)) - (list beg (1+ end)))))) + (list beg (1+ end))))) + ((and fallback (git-rebase-line-p)) + (list (line-beginning-position) + (1+ (line-end-position)))))) (defun git-rebase-move-line-down (n) "Move the current commit (or command) N lines down. @@ -423,16 +453,10 @@ (funcall (default-value 'redisplay-unhighlight-region-function) rol)) (defun git-rebase-kill-line () - "Kill the current action line." + "Kill the current action line. +If the region is active, act on all lines touched by the region." (interactive) - (goto-char (line-beginning-position)) - (unless (oref (git-rebase-current-line) comment-p) - (let ((inhibit-read-only t)) - (insert comment-start) - (insert " ")) - (goto-char (line-beginning-position)) - (when git-rebase-auto-advance - (forward-line)))) + (git-rebase-set-action nil)) (defun git-rebase-insert (rev) "Read an arbitrary commit and insert it below current line." @@ -794,8 +818,8 @@ (add-to-list 'with-editor-server-window-alist (cons git-rebase-filename-regexp 'switch-to-buffer)) -(eval-after-load 'recentf - '(add-to-list 'recentf-exclude git-rebase-filename-regexp)) +(with-eval-after-load 'recentf + (add-to-list 'recentf-exclude git-rebase-filename-regexp)) (add-to-list 'with-editor-file-name-history-exclude git-rebase-filename-regexp) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-apply.el magit-3.3.0/lisp/magit-apply.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-apply.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-apply.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-apply.el --- apply Git diffs -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -30,9 +32,6 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit-core) (require 'magit-diff) (require 'magit-wip) @@ -53,6 +52,7 @@ (path &optional prefer-short)) (declare-function borg--maybe-absorb-gitdir "borg" (pkg)) (declare-function borg--sort-submodule-sections "borg" (file)) +(declare-function borg-assimilate "borg" (package url &optional partially)) (defvar borg-user-emacs-directory) ;;; Options @@ -177,7 +177,7 @@ (offset (if (string-match diff-hunk-header-re-unified first-hunk) (- (string-to-number (match-string 3 first-hunk)) (string-to-number (match-string 1 first-hunk))) - (error "Hunk does not have expected header")))) + (error "Header hunks have to be applied individually")))) (if (= offset 0) hunks (mapcar (lambda (hunk) @@ -207,10 +207,15 @@ (defun magit-apply-hunk (section &rest args) (when (string-match "^diff --cc" (magit-section-parent-value section)) (user-error "Cannot un-/stage resolution hunks. Stage the whole file")) - (magit-apply-patch (oref section parent) args - (concat (magit-diff-file-header section) - (magit-apply--adjust-hunk-new-start - (magit-apply--section-content section))))) + (let* ((header (car (oref section value))) + (header (and (symbolp header) header)) + (content (magit-apply--section-content section))) + (magit-apply-patch + (oref section parent) args + (concat (magit-diff-file-header section (not (eq header 'rename))) + (if header + content + (magit-apply--adjust-hunk-new-start content)))))) (defun magit-apply-region (section &rest args) (when (string-match "^diff --cc" (magit-section-parent-value section)) @@ -231,7 +236,7 @@ (ignore-context (magit-diff-ignore-any-space-p))) (unless (magit-diff-context-p) (user-error "Not enough context to apply patch. Increase the context")) - (when (and magit-wip-before-change-mode (not inhibit-magit-refresh)) + (when (and magit-wip-before-change-mode (not magit-inhibit-refresh)) (magit-wip-commit-before-change files (concat " before " command))) (with-temp-buffer (insert patch) @@ -239,7 +244,7 @@ "apply" args "-p0" (and ignore-context "-C0") "--ignore-space-change" "-")) - (unless inhibit-magit-refresh + (unless magit-inhibit-refresh (when magit-wip-after-apply-mode (magit-wip-commit-after-apply files (concat " after " command))) (magit-refresh)))) @@ -362,28 +367,24 @@ `((file . ,repo) (untracked) (status))) start)) (let* ((topdir (magit-toplevel)) + (url (let ((default-directory + (file-name-as-directory (expand-file-name repo)))) + (or (magit-get "remote" (magit-get-some-remote) "url") + (concat (file-name-as-directory ".") repo)))) (package (and (equal (bound-and-true-p borg-user-emacs-directory) topdir) (file-name-nondirectory (directory-file-name repo))))) - (magit-submodule-add-1 - (let ((default-directory - (file-name-as-directory (expand-file-name repo)))) - (or (magit-get "remote" (magit-get-some-remote) "url") - (concat (file-name-as-directory ".") repo))) - repo - (magit-submodule-read-name-for-path repo package)) - (when package - (borg--sort-submodule-sections - (expand-file-name ".gitmodules" topdir)) - (let ((default-directory borg-user-emacs-directory)) - (borg--maybe-absorb-gitdir package)) - (when (and (y-or-n-p - (format "Also build and activate `%s' drone?" package)) - (fboundp 'borg-build) - (fboundp 'borg-activate)) - (borg-build package) - (borg-activate package)))))) + (if (and package + (y-or-n-p (format "Also assimilate `%s' drone?" package))) + (borg-assimilate package url) + (magit-submodule-add-1 + url repo (magit-submodule-read-name-for-path repo package)) + (when package + (borg--sort-submodule-sections + (expand-file-name ".gitmodules" topdir)) + (let ((default-directory borg-user-emacs-directory)) + (borg--maybe-absorb-gitdir package))))))) (magit-wip-commit-after-apply files " after stage"))) ;;;; Unstage @@ -448,6 +449,8 @@ (defun magit-unstage-all () "Remove all changes from the staging area." (interactive) + (unless (magit-anything-staged-p) + (user-error "Nothing to unstage")) (when (or (magit-anything-unstaged-p) (magit-untracked-files)) (magit-confirm 'unstage-all-changes)) @@ -458,7 +461,11 @@ ;;;; Discard (defun magit-discard () - "Remove the change at point." + "Remove the change at point. + +On a hunk or file with unresolved conflicts prompt which side to +keep (while discarding the other). If point is within the text +of a side, then keep that side without prompting." (interactive) (--when-let (magit-apply--get-selection) (pcase (list (magit-diff-type) (magit-diff-scope)) @@ -477,7 +484,10 @@ (defun magit-discard-hunk (section) (magit-confirm 'discard "Discard hunk") - (magit-discard-apply section 'magit-apply-hunk)) + (let ((file (magit-section-parent-value section))) + (pcase (cddr (car (magit-file-status file))) + (`(?U ?U) (magit-smerge-keep-current)) + (_ (magit-discard-apply section 'magit-apply-hunk))))) (defun magit-discard-apply (section apply) (if (eq (magit-diff-type section) 'unstaged) @@ -486,7 +496,7 @@ nil (if (magit-file-section-p section) (oref section value) (magit-section-parent-value section))) - (progn (let ((inhibit-magit-refresh t)) + (progn (let ((magit-inhibit-refresh t)) (funcall apply section "--reverse" "--cached") (funcall apply section "--reverse" "--reject")) (magit-refresh)) @@ -506,7 +516,7 @@ nil (if (magit-file-section-p section) (oref section value) (magit-section-parent-value section))) - (progn (let ((inhibit-magit-refresh t)) + (progn (let ((magit-inhibit-refresh t)) (funcall apply sections "--reverse" "--cached") (funcall apply sections "--reverse" "--reject")) (magit-refresh)) @@ -544,7 +554,7 @@ (`(?Y ,_ ?D ) (push file resurrect)) (`(?X ?R ,(or ? ?M ?D)) (push file rename))))) (unwind-protect - (let ((inhibit-magit-refresh t)) + (let ((magit-inhibit-refresh t)) (magit-wip-commit-before-change files " before discard") (when resolve (magit-discard-files--resolve (nreverse resolve))) @@ -734,6 +744,60 @@ (interactive) (magit-reverse (cons "--cached" args))) +;;; Smerge Support + +(defun magit-smerge-keep-current () + "Keep the current version of the conflict at point." + (interactive) + (magit-call-smerge #'smerge-keep-current)) + +(defun magit-smerge-keep-upper () + "Keep the upper/our version of the conflict at point." + (interactive) + (magit-call-smerge #'smerge-keep-upper)) + +(defun magit-smerge-keep-base () + "Keep the base version of the conflict at point." + (interactive) + (magit-call-smerge #'smerge-keep-base)) + +(defun magit-smerge-keep-lower () + "Keep the lower/their version of the conflict at point." + (interactive) + (magit-call-smerge #'smerge-keep-lower)) + +(defun magit-call-smerge (fn) + (pcase-let* ((file (magit-file-at-point t t)) + (keep (get-file-buffer file)) + (`(,buf ,pos) + (let ((magit-diff-visit-jump-to-change nil)) + (magit-diff-visit-file--noselect file)))) + (with-current-buffer buf + (save-excursion + (save-restriction + (unless (<= (point-min) pos (point-max)) + (widen)) + (goto-char pos) + (condition-case nil + (smerge-match-conflict) + (error + (if (eq fn 'smerge-keep-current) + (when (eq this-command 'magit-discard) + (re-search-forward smerge-begin-re nil t) + (setq fn + (magit-read-char-case "Keep side: " t + (?o "[o]urs/upper" #'smerge-keep-upper) + (?b "[b]ase" #'smerge-keep-base) + (?t "[t]heirs/lower" #'smerge-keep-lower)))) + (re-search-forward smerge-begin-re nil t)))) + (funcall fn))) + (when (and keep (magit-anything-unmerged-p file)) + (smerge-start-session)) + (save-buffer)) + (unless keep + (kill-buffer buf)) + (magit-refresh))) + ;;; _ (provide 'magit-apply) ;;; magit-apply.el ends here diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-autorevert.el magit-3.3.0/lisp/magit-autorevert.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-autorevert.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-autorevert.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-autorevert.el --- revert buffers when files in repository change -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -23,9 +25,6 @@ ;;; Code: -(require 'cl-lib) -(require 'dash) - (require 'magit-git) (require 'autorevert) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-bisect.el magit-3.3.0/lisp/magit-bisect.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-bisect.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-bisect.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-bisect.el --- bisect support for Magit -*- lexical-binding: t -*- -;; Copyright (C) 2011-2020 The Magit Project Contributors +;; Copyright (C) 2011-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -55,28 +57,51 @@ ;;; Commands ;;;###autoload (autoload 'magit-bisect "magit-bisect" nil t) -(define-transient-command magit-bisect () +(transient-define-prefix magit-bisect () "Narrow in on the commit that introduced a bug." :man-page "git-bisect" - ["Actions" + [:class transient-subgroups :if-not magit-bisect-in-progress-p - ("B" "Start" magit-bisect-start) - ("s" "Start script" magit-bisect-run)] + ["Arguments" + ("-n" "Don't checkout commits" "--no-checkout") + ("-p" "Follow only first parent of a merge" "--first-parent" + :if (lambda () (version<= "2.29" (magit-git-version)))) + (6 magit-bisect:--term-old + :if (lambda () (version<= "2.7" (magit-git-version)))) + (6 magit-bisect:--term-new + :if (lambda () (version<= "2.7" (magit-git-version))))] + ["Actions" + ("B" "Start" magit-bisect-start) + ("s" "Start script" magit-bisect-run)]] ["Actions" :if magit-bisect-in-progress-p ("B" "Bad" magit-bisect-bad) ("g" "Good" magit-bisect-good) + (6 "m" "Mark" magit-bisect-mark + :if (lambda () (version<= "2.7" (magit-git-version)))) ("k" "Skip" magit-bisect-skip) ("r" "Reset" magit-bisect-reset) ("s" "Run script" magit-bisect-run)]) +(transient-define-argument magit-bisect:--term-old () + :description "Old/good term" + :class 'transient-option + :key "=o" + :argument "--term-old=") + +(transient-define-argument magit-bisect:--term-new () + :description "New/bad term" + :class 'transient-option + :key "=n" + :argument "--term-new=") + ;;;###autoload -(defun magit-bisect-start (bad good) +(defun magit-bisect-start (bad good args) "Start a bisect session. Bisecting a bug means to find the commit that introduced it. -This command starts such a bisect session by asking for a know -good and a bad commit. To move the session forward use the +This command starts such a bisect session by asking for a known +good and a known bad commit. To move the session forward use the other actions from the bisect transient command (\ \\\\[magit-bisect])." (interactive (if (magit-bisect-in-progress-p) @@ -84,15 +109,27 @@ (magit-bisect-start-read-args))) (unless (magit-rev-ancestor-p good bad) (user-error - "The good revision (%s) has to be an ancestor of the bad one (%s)" - good bad)) + "The %s revision (%s) has to be an ancestor of the %s one (%s)" + (or (transient-arg-value "--term-old=" args) "good") + good + (or (transient-arg-value "--term-new=" args) "bad") + bad)) (when (magit-anything-modified-p) (user-error "Cannot bisect with uncommitted changes")) - (magit-git-bisect "start" (list bad good) t)) + (magit-git-bisect "start" (list args bad good) t)) (defun magit-bisect-start-read-args () - (let ((b (magit-read-branch-or-commit "Start bisect with bad revision"))) - (list b (magit-read-other-branch-or-commit "Good revision" b)))) + (let* ((args (transient-args 'magit-bisect)) + (bad (magit-read-branch-or-commit + (format "Start bisect with %s revision" + (or (transient-arg-value "--term-new=" args) + "bad"))))) + (list bad + (magit-read-other-branch-or-commit + (format "%s revision" (or (transient-arg-value "--term-old=" args) + "Good")) + bad) + args))) ;;;###autoload (defun magit-bisect-reset () @@ -108,7 +145,8 @@ Use this after you have asserted that the commit does not contain the bug in question." (interactive) - (magit-git-bisect "good")) + (magit-git-bisect (or (cadr (magit-bisect-terms)) + (user-error "Not bisecting")))) ;;;###autoload (defun magit-bisect-bad () @@ -116,7 +154,28 @@ Use this after you have asserted that the commit does contain the bug in question." (interactive) - (magit-git-bisect "bad")) + (magit-git-bisect (or (car (magit-bisect-terms)) + (user-error "Not bisecting")))) + +;;;###autoload +(defun magit-bisect-mark () + "While bisecting, mark the current commit with a bisect term. +During a bisect using alternate terms, commits can still be +marked with `magit-bisect-good' and `magit-bisect-bad', as those +commands map to the correct term (\"good\" to --term-old's value +and \"bad\" to --term-new's). However, in some cases, it can be +difficult to keep that mapping straight in your head; this +command provides an interface that exposes the underlying terms." + (interactive) + (magit-git-bisect + (pcase-let ((`(,term-new ,term-old) (or (magit-bisect-terms) + (user-error "Not bisecting")))) + (pcase (read-char-choice + (format "Mark HEAD as %s ([n]ew) or %s ([o]ld)" + term-new term-old) + (list ?n ?o)) + (?n term-new) + (?o term-old))))) ;;;###autoload (defun magit-bisect-skip () @@ -127,7 +186,7 @@ (magit-git-bisect "skip")) ;;;###autoload -(defun magit-bisect-run (cmdline &optional bad good) +(defun magit-bisect-run (cmdline &optional bad good args) "Bisect automatically by running commands after each step. Unlike `git bisect run' this can be used before bisecting has @@ -137,7 +196,14 @@ (magit-bisect-start-read-args)))) (cons (read-shell-command "Bisect shell command: ") args))) (when (and bad good) - (magit-bisect-start bad good)) + ;; Avoid `magit-git-bisect' because it's asynchronous, but the + ;; next `git bisect run' call requires the bisect to be started. + (magit-with-toplevel + (magit-process-git + (list :file (magit-git-dir "BISECT_CMD_OUTPUT")) + (magit-process-git-arguments + (list "bisect" "start" bad good args))) + (magit-refresh))) (magit-git-bisect "run" (list shell-file-name shell-command-switch cmdline))) (defun magit-git-bisect (subcommand &optional args no-assert) @@ -170,6 +236,9 @@ (defun magit-bisect-in-progress-p () (file-exists-p (magit-git-dir "BISECT_LOG"))) +(defun magit-bisect-terms () + (magit-file-lines (magit-git-dir "BISECT_TERMS"))) + (defun magit-insert-bisect-output () "While bisecting, insert section with output from `git bisect'." (when (magit-bisect-in-progress-p) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-blame.el magit-3.3.0/lisp/magit-blame.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-blame.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-blame.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-blame.el --- blame support for Magit -*- lexical-binding: t -*- -;; Copyright (C) 2012-2020 The Magit Project Contributors +;; Copyright (C) 2012-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -28,9 +30,6 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) ;;; Options @@ -56,7 +55,7 @@ "List of styles used to visualize blame information. Each entry has the form (IDENT (KEY . VALUE)...). IDENT has -to be a symbol uniquely identifing the style. The following +to be a symbol uniquely identifying the style. The following KEYs are recognized: `show-lines' @@ -228,25 +227,25 @@ ;; filename (orig-file))) -(defun magit-current-blame-chunk (&optional type) +(defun magit-current-blame-chunk (&optional type noerror) (or (and (not (and type (not (eq type magit-blame-type)))) (magit-blame-chunk-at (point))) (and type (let ((rev (or magit-buffer-refname magit-buffer-revision)) (file (magit-file-relative-name nil (not magit-buffer-file-name))) (line (format "%i,+1" (line-number-at-pos)))) - (unless file - (error "Buffer does not visit a tracked file")) - (with-temp-buffer - (magit-with-toplevel - (magit-git-insert - "blame" "--porcelain" - (if (memq magit-blame-type '(final removal)) - (cons "--reverse" (magit-blame-arguments)) - (magit-blame-arguments)) - "-L" line rev "--" file) - (goto-char (point-min)) - (car (magit-blame--parse-chunk type)))))))) + (cond (file (with-temp-buffer + (magit-with-toplevel + (magit-git-insert + "blame" "--porcelain" + (if (memq magit-blame-type '(final removal)) + (cons "--reverse" (magit-blame-arguments)) + (magit-blame-arguments)) + "-L" line rev "--" file) + (goto-char (point-min)) + (car (magit-blame--parse-chunk type))))) + (noerror nil) + (t (error "Buffer does not visit a tracked file"))))))) (defun magit-blame-chunk-at (pos) (--some (overlay-get it 'magit-blame-chunk) @@ -284,6 +283,7 @@ (define-key map (kbd "q") 'magit-blame-quit) (define-key map (kbd "M-w") 'magit-blame-copy-hash) (define-key map (kbd "SPC") 'magit-diff-show-or-scroll-up) + (define-key map (kbd "S-SPC") 'magit-diff-show-or-scroll-down) (define-key map (kbd "DEL") 'magit-diff-show-or-scroll-down) map) "Keymap for `magit-blame-read-only-mode'.") @@ -474,7 +474,9 @@ (defun magit-blame--parse-chunk (type) (let (chunk revinfo) - (looking-at "^\\(.\\{40\\}\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)") + (unless (looking-at "^\\(.\\{40\\}\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)") + (error "Blaming failed due to unexpected output: %s" + (buffer-substring-no-properties (point) (line-end-position)))) (with-slots (orig-rev orig-file prev-rev prev-file) (setq chunk (magit-blame-chunk :orig-rev (match-string 1) @@ -486,10 +488,10 @@ (while (not done) (cond ((looking-at "^filename \\(.+\\)") (setq done t) - (setf orig-file (match-string 1))) + (setf orig-file (magit-decode-git-path (match-string 1)))) ((looking-at "^previous \\(.\\{40\\}\\) \\(.+\\)") (setf prev-rev (match-string 1)) - (setf prev-file (match-string 2))) + (setf prev-file (magit-decode-git-path (match-string 2)))) ((looking-at "^\\([^ ]+\\) \\(.+\\)") (push (cons (match-string 1) (match-string 2)) revinfo))) @@ -673,9 +675,10 @@ (propertize (concat (propertize "\s" 'display '(space :height (2))) (propertize "\n" 'line-height t)) - 'font-lock-face (list :background - (face-attribute 'magit-blame-heading - :background nil t)))) + 'font-lock-face `(:background + ,(face-attribute 'magit-blame-heading + :background nil t) + ,@(and (>= emacs-major-version 27) '(:extend t))))) (defun magit-blame--format-time-string (time tz) (let* ((time-format (or (magit-blame--style-get 'time-format) @@ -698,9 +701,9 @@ (when (magit-blame--style-get 'show-message) (let ((message-log-max 0)) (if-let ((msg (cdr (assoc "summary" - (gethash (oref (magit-current-blame-chunk) - orig-rev) - magit-blame-cache))))) + (gethash (oref (magit-current-blame-chunk) + orig-rev) + magit-blame-cache))))) (progn (set-text-properties 0 (length msg) nil msg) (message msg)) (message "Commit data not available yet. Still blaming."))))) @@ -708,7 +711,7 @@ ;;; Commands ;;;###autoload (autoload 'magit-blame-echo "magit-blame" nil t) -(define-suffix-command magit-blame-echo (args) +(transient-define-suffix magit-blame-echo (args) "For each line show the revision in which it was added. Show the information about the chunk at point in the echo area when moving between chunks. Unlike other blaming commands, do @@ -733,7 +736,7 @@ (magit-blame--update-overlays))) ;;;###autoload (autoload 'magit-blame-addition "magit-blame" nil t) -(define-suffix-command magit-blame-addition (args) +(transient-define-suffix magit-blame-addition (args) "For each line show the revision in which it was added." (interactive (list (magit-blame-arguments))) (magit-blame--pre-blame-assert 'addition) @@ -741,7 +744,7 @@ (magit-blame--run args)) ;;;###autoload (autoload 'magit-blame-removal "magit-blame" nil t) -(define-suffix-command magit-blame-removal (args) +(transient-define-suffix magit-blame-removal (args) "For each line show the revision in which it was removed." :if-nil 'buffer-file-name (interactive (list (magit-blame-arguments))) @@ -752,7 +755,7 @@ (magit-blame--run args)) ;;;###autoload (autoload 'magit-blame-reverse "magit-blame" nil t) -(define-suffix-command magit-blame-reverse (args) +(transient-define-suffix magit-blame-reverse (args) "For each line show the last revision in which it still exists." :if-nil 'buffer-file-name (interactive (list (magit-blame-arguments))) @@ -811,7 +814,7 @@ (goto-char (point-min)) (forward-line (1- orig-line)))) -(define-suffix-command magit-blame-quit () +(transient-define-suffix magit-blame-quit () "Turn off Magit-Blame mode. If the buffer was created during a recursive blame, then also kill the buffer." @@ -885,13 +888,14 @@ ;;; Popup ;;;###autoload (autoload 'magit-blame "magit-blame" nil t) -(define-transient-command magit-blame () +(transient-define-prefix magit-blame () "Show the commits that added or removed lines in the visited file." :man-page "git-blame" :value '("-w") ["Arguments" ("-w" "Ignore whitespace" "-w") ("-r" "Do not treat root commits as boundaries" "--root") + ("-P" "Follow only first parent" "--first-parent") (magit-blame:-M) (magit-blame:-C)] ["Actions" @@ -902,21 +906,23 @@ ("q" "Quit blaming" magit-blame-quit)] ["Refresh" :if-non-nil magit-blame-mode - ("c" "Cycle style" magit-blame-cycle-style)]) + ("c" "Cycle style" magit-blame-cycle-style :transient t)]) (defun magit-blame-arguments () (transient-args 'magit-blame)) -(define-infix-argument magit-blame:-M () +(transient-define-argument magit-blame:-M () :description "Detect lines moved or copied within a file" :class 'transient-option :argument "-M" + :allow-empty t :reader 'transient-read-number-N+) -(define-infix-argument magit-blame:-C () +(transient-define-argument magit-blame:-C () :description "Detect lines moved or copied between files" :class 'transient-option :argument "-C" + :allow-empty t :reader 'transient-read-number-N+) ;;; Utilities diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-bookmark.el magit-3.3.0/lisp/magit-bookmark.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-bookmark.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-bookmark.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-bookmark.el --- bookmark support for Magit -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -10,6 +10,8 @@ ;; Inspired by an earlier implementation by Yuri Khan. +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -29,9 +31,6 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) (require 'bookmark) @@ -43,7 +42,11 @@ and the buffer-local values of the variables referenced in its `magit-bookmark-variables' property." (if (plist-member (symbol-plist major-mode) 'magit-bookmark-variables) - (let ((bookmark (bookmark-make-record-default 'no-file))) + ;; `bookmark-make-record-default's return value does not match + ;; (NAME . ALIST), even though it is used as the default value + ;; of `bookmark-make-record-function', which states that such + ;; functions must do that. See #4356. + (let ((bookmark (cons nil (bookmark-make-record-default 'no-file)))) (bookmark-prop-set bookmark 'handler 'magit--handle-bookmark) (bookmark-prop-set bookmark 'mode major-mode) (bookmark-prop-set bookmark 'filename (magit-toplevel)) @@ -87,6 +90,9 @@ hidden) (magit-section-hide child) (magit-section-show child))))) + ;; Compatibility with `bookmark+' package. See #4356. + (when (bound-and-true-p bmkp-jump-display-function) + (funcall bmkp-jump-display-function (current-buffer))) nil)) (cl-defgeneric magit-bookmark-name () diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-branch.el magit-3.3.0/lisp/magit-branch.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-branch.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-branch.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-branch.el --- branch support -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -31,9 +33,6 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) (require 'magit-reset) @@ -115,7 +114,8 @@ This option allows specifying the branch that should be used as the upstream when branching certain remote branches. The value is an alist of the form ((UPSTREAM . RULE)...). The first -matching element is used, the following elements are ignored. +element is used whose UPSTREAM exists and whose RULE matches +the name of the new branch. Subsequent elements are ignored. UPSTREAM is the branch to be used as the upstream for branches specified by RULE. It can be a local or a remote branch. @@ -129,7 +129,7 @@ If you use a finite set of non-ephemeral branches across all your repositories, then you might use something like: - ((\"origin/master\" \"master\" \"next\" \"maint\")) + ((\"origin/master\" . (\"master\" \"next\" \"maint\"))) Or if the names of all your ephemeral branches contain a slash, at least in some repositories, then a good value could be: @@ -141,6 +141,16 @@ ((\"origin/maint\" . \"\\\\\\=`hotfix/\") (\"origin/master\" . \"\\\\\\=`feature/\")) +UPSTREAM can be a local branch: + + ((\"master\" . (\"master\" \"next\" \"maint\"))) + +Because the main branch is no longer almost always named \"master\" +you should also account for other common names: + + ((\"main\" . (\"main\" \"master\" \"next\" \"maint\")) + (\"master\" . (\"main\" \"master\" \"next\" \"maint\"))) + If you use remote branches as UPSTREAM, then you might also want to set `magit-branch-prefer-remote-upstream' to a non-nil value. However, I recommend that you use local branches as UPSTREAM." @@ -201,9 +211,13 @@ ;;; Commands ;;;###autoload (autoload 'magit-branch "magit" nil t) -(define-transient-command magit-branch (branch) +(transient-define-prefix magit-branch (branch) "Add, configure or remove a branch." :man-page "git-branch" + ["Arguments" + (7 "-r" "Recurse submodules when checking out an existing branch" + "--recurse-submodules" + :if (lambda () (version<= "2.13" (magit-git-version))))] ["Variables" :if (lambda () (and magit-branch-direct-configure @@ -235,18 +249,22 @@ (interactive (list (magit-get-current-branch))) (transient-setup 'magit-branch nil nil :scope branch)) +(defun magit-branch-arguments () + (transient-args 'magit-branch)) + ;;;###autoload -(defun magit-checkout (revision) +(defun magit-checkout (revision &optional args) "Checkout REVISION, updating the index and the working tree. If REVISION is a local branch, then that becomes the current branch. If it is something else, then `HEAD' becomes detached. Checkout fails if the working tree or the staging area contain changes. \n(git checkout REVISION)." - (interactive (list (magit-read-other-branch-or-commit "Checkout"))) + (interactive (list (magit-read-other-branch-or-commit "Checkout") + (magit-branch-arguments))) (when (string-match "\\`heads/\\(.+\\)" revision) (setq revision (match-string 1 revision))) - (magit-run-git "checkout" revision)) + (magit-run-git "checkout" args revision)) ;;;###autoload (defun magit-branch-create (branch start-point) @@ -257,12 +275,13 @@ (magit-refresh)) ;;;###autoload -(defun magit-branch-and-checkout (branch start-point) +(defun magit-branch-and-checkout (branch start-point &optional args) "Create and checkout BRANCH at branch or revision START-POINT." - (interactive (magit-branch-read-args "Create and checkout branch")) + (interactive (append (magit-branch-read-args "Create and checkout branch") + (list (magit-branch-arguments)))) (if (string-match-p "^stash@{[0-9]+}$" start-point) (magit-run-git "stash" "branch" branch start-point) - (magit-call-git "checkout" "-b" branch start-point) + (magit-call-git "checkout" args "-b" branch start-point) (magit-branch-maybe-adjust-upstream branch start-point) (magit-refresh))) @@ -339,8 +358,8 @@ (t (list choice (magit-read-starting-point "Create" choice)))))) (if (not start-point) - (magit-checkout branch) - (when (magit-anything-modified-p) + (magit-checkout branch (magit-branch-arguments)) + (when (magit-anything-modified-p t) (user-error "Cannot checkout when there are uncommitted changes")) (magit-branch-and-checkout branch start-point) (when (magit-remote-branch-p start-point) @@ -356,10 +375,13 @@ (magit-get-indirect-upstream-branch start-point)) (and (magit-remote-branch-p start-point) (let ((name (cdr (magit-split-branch-name start-point)))) - (car (--first (if (listp (cdr it)) - (not (member name (cdr it))) - (string-match-p (cdr it) name)) - magit-branch-adjust-remote-upstream-alist))))) + (-some (pcase-lambda (`(,upstream . ,rule)) + (and (magit-branch-p upstream) + (if (listp rule) + (not (member name rule)) + (string-match-p rule name)) + upstream)) + magit-branch-adjust-remote-upstream-alist)))) (magit-call-git "branch" (concat "--set-upstream-to=" it) branch))) ;;;###autoload @@ -498,7 +520,7 @@ (or (and (not (equal branch atpoint)) atpoint) (magit-get-upstream-branch branch))) current-prefix-arg))) - (let ((inhibit-magit-refresh t)) + (let ((magit-inhibit-refresh t)) (if (equal branch (magit-get-current-branch)) (if (and (magit-anything-modified-p) (not (yes-or-no-p @@ -562,16 +584,32 @@ ((string-match "^refs/remotes/\\([^/]+\\)" (car refs)) (let* ((remote (match-string 1 (car refs))) (offset (1+ (length remote)))) - ;; Assume the branches actually still exists on the remote. - (magit-run-git-async - "push" - (and (or force magit-branch-delete-never-verify) "--no-verify") - remote - (--map (concat ":" (substring it offset)) branches)) - ;; If that is not the case, then this deletes the tracking branches. - (set-process-sentinel - magit-this-process - (apply-partially 'magit-delete-remote-branch-sentinel remote refs)))) + (cond + ((magit-confirm 'delete-branch-on-remote + "Delete %s on the remote (not just locally)" + "Delete %i branches on the remote (not just locally)" + 'noabort branches) + ;; The ref may actually point at another rev on the remote, + ;; but this is better than nothing. + (dolist (ref refs) + (message "Delete %s (was %s)" ref + (magit-rev-parse "--short" ref))) + ;; Assume the branches actually still exist on the remote. + (magit-run-git-async + "push" + (and (or force magit-branch-delete-never-verify) "--no-verify") + remote + (--map (concat ":" (substring it offset)) branches)) + ;; If that is not the case, then this deletes the tracking branches. + (set-process-sentinel + magit-this-process + (apply-partially 'magit-delete-remote-branch-sentinel remote refs))) + (t + (dolist (ref refs) + (message "Delete %s (was %s)" ref + (magit-rev-parse "--short" ref)) + (magit-call-git "update-ref" "-d" ref)) + (magit-refresh))))) ((> (length branches) 1) (setq branches (delete (magit-get-current-branch) branches)) (mapc 'magit-branch-maybe-delete-pr-remote branches) @@ -579,17 +617,18 @@ (magit-run-git "branch" (if force "-D" "-d") branches)) (t ; And now for something completely different. (let* ((branch (car branches)) - (prompt (format "Branch %s is checked out. " branch))) + (prompt (format "Branch %s is checked out. " branch)) + (main (magit-main-branch))) (when (equal branch (magit-get-current-branch)) - (pcase (if (or (equal branch "master") - (not (magit-rev-verify "master"))) + (pcase (if (or (equal branch main) + (not main)) (magit-read-char-case prompt nil (?d "[d]etach HEAD & delete" 'detach) (?a "[a]bort" 'abort)) (magit-read-char-case prompt nil - (?d "[d]etach HEAD & delete" 'detach) - (?c "[c]heckout master & delete" 'master) - (?a "[a]bort" 'abort))) + (?d "[d]etach HEAD & delete" 'detach) + (?c (format "[c]heckout %s & delete" main) 'main) + (?a "[a]bort" 'abort))) (`detach (unless (or (equal force '(4)) (member branch force) (magit-branch-merged-p branch t)) @@ -597,13 +636,13 @@ "Delete unmerged branch %s" "" nil (list branch))) (magit-call-git "checkout" "--detach")) - (`master (unless (or (equal force '(4)) + (`main (unless (or (equal force '(4)) (member branch force) - (magit-branch-merged-p branch "master")) + (magit-branch-merged-p branch main)) (magit-confirm 'delete-unmerged-branch "Delete unmerged branch %s" "" nil (list branch))) - (magit-call-git "checkout" "master")) + (magit-call-git "checkout" main)) (`abort (user-error "Abort"))) (setq force t)) (magit-branch-maybe-delete-pr-remote branch) @@ -686,15 +725,15 @@ (magit-call-git "branch" (if force "-M" "-m") old new) (when magit-branch-rename-push-target (let ((remote (magit-get-push-remote old)) - (old-specific (magit-get "branch" old "pushRemote")) - (new-specific (magit-get "branch" new "pushRemote"))) - (when (and old-specific (or force (not new-specific))) - ;; Keep the target setting branch specific, even if that is + (old-specified (magit-get "branch" old "pushRemote")) + (new-specified (magit-get "branch" new "pushRemote"))) + (when (and old-specified (or force (not new-specified))) + ;; Keep the target setting branch specified, even if that is ;; redundant. But if a branch by the same name existed before ;; and the rename isn't forced, then do not change a leftover ;; setting. Such a leftover setting may or may not conform to ;; what we expect here... - (magit-set old-specific "branch" new "pushRemote")) + (magit-set old-specified "branch" new "pushRemote")) (when (and (equal (magit-get-push-remote new) remote) ;; ...and if it does not, then we must abort. (not (eq magit-branch-rename-push-target 'local-only)) @@ -762,7 +801,7 @@ ;;; Configure ;;;###autoload (autoload 'magit-branch-configure "magit-branch" nil t) -(define-transient-command magit-branch-configure (branch) +(transient-define-prefix magit-branch-configure (branch) "Configure a branch." :man-page "git-branch" [:description @@ -783,7 +822,7 @@ (interactive (list (or (and (not current-prefix-arg) (not (and magit-branch-direct-configure - (eq current-transient-command 'magit-branch))) + (eq transient-current-command 'magit-branch))) (magit-get-current-branch)) (magit--read-branch-scope)))) (transient-setup 'magit-branch-configure nil nil :scope branch)) @@ -795,12 +834,12 @@ (format (oref obj variable) "")) "Configure branch"))) -(define-suffix-command magit-branch..description (branch) +(transient-define-suffix magit-branch..description (branch) "Edit the description of BRANCH." :class 'magit--git-variable :transient nil :variable "branch.%s.description" - (interactive (list (oref current-transient-prefix scope))) + (interactive (list (oref transient-current-prefix scope))) (magit-run-git-with-editor "branch" "--edit-description" branch)) (add-hook 'find-file-hook 'magit-branch-description-check-buffers) @@ -812,7 +851,7 @@ (defclass magit--git-branch:upstream (magit--git-variable) ((format :initform " %k %m %M\n %r %R"))) -(define-infix-command magit-branch..merge/remote () +(transient-define-infix magit-branch..merge/remote () :class 'magit--git-branch:upstream) (cl-defmethod transient-init-value ((obj magit--git-branch:upstream)) @@ -850,7 +889,7 @@ (propertize value 'face 'transient-argument) (propertize "unset" 'face 'transient-inactive-argument))) -(define-infix-command magit-branch..rebase () +(transient-define-infix magit-branch..rebase () :class 'magit--git-variable:choices :scope 'magit--read-branch-scope :variable "branch.%s.rebase" @@ -858,31 +897,31 @@ :choices '("true" "false") :default "false") -(define-infix-command magit-branch..pushRemote () +(transient-define-infix magit-branch..pushRemote () :class 'magit--git-variable:choices :scope 'magit--read-branch-scope :variable "branch.%s.pushRemote" :fallback "remote.pushDefault" :choices 'magit-list-remotes) -(define-infix-command magit-pull.rebase () +(transient-define-infix magit-pull.rebase () :class 'magit--git-variable:choices :variable "pull.rebase" :choices '("true" "false") :default "false") -(define-infix-command magit-remote.pushDefault () +(transient-define-infix magit-remote.pushDefault () :class 'magit--git-variable:choices :variable "remote.pushDefault" :choices 'magit-list-remotes) -(define-infix-command magit-branch.autoSetupMerge () +(transient-define-infix magit-branch.autoSetupMerge () :class 'magit--git-variable:choices :variable "branch.autoSetupMerge" :choices '("always" "true" "false") :default "true") -(define-infix-command magit-branch.autoSetupRebase () +(transient-define-infix magit-branch.autoSetupRebase () :class 'magit--git-variable:choices :variable "branch.autoSetupRebase" :choices '("always" "local" "remote" "never") diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-bundle.el magit-3.3.0/lisp/magit-bundle.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-bundle.el 1970-01-01 00:00:00.000000000 +0000 +++ magit-3.3.0/lisp/magit-bundle.el 2021-10-06 12:51:17.000000000 +0000 @@ -0,0 +1,135 @@ +;;; magit-bundle.el --- bundle support for Magit -*- lexical-binding: t -*- + +;; Copyright (C) 2011-2021 The Magit Project Contributors +;; +;; You should have received a copy of the AUTHORS.md file which +;; lists all contributors. If not, see http://magit.vc/authors. + +;; Author: Jonas Bernoulli +;; Maintainer: Jonas Bernoulli + +;; SPDX-License-Identifier: GPL-3.0-or-later + +;; Magit is free software; you can redistribute it and/or modify it +;; under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; Magit is distributed in the hope that it will be useful, but WITHOUT +;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY +;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public +;; License for more details. +;; +;; You should have received a copy of the GNU General Public License +;; along with Magit. If not, see http://www.gnu.org/licenses. + +;;; Code: + +(require 'magit) + +;;; Commands + +;;;###autoload (autoload 'magit-bundle "magit-bundle" nil t) +(transient-define-prefix magit-bundle () + "Create or verify Git bundles." + :man-page "git-bundle" + ["Actions" + ("c" "create" magit-bundle-create) + ("v" "verify" magit-bundle-verify) + ("l" "list-heads" magit-bundle-list-heads)]) + +;;;###autoload (autoload 'magit-bundle-import "magit-bundle" nil t) +(transient-define-prefix magit-bundle-create (&optional file refs args) + "Create a bundle." + :man-page "git-bundle" + ["Arguments" + ("-a" "Include all refs" "--all") + ("-b" "Include branches" "--branches=" :allow-empty t) + ("-t" "Include tags" "--tags=" :allow-empty t) + ("-r" "Include remotes" "--remotes=" :allow-empty t) + ("-g" "Include refs" "--glob=") + ("-e" "Exclude refs" "--exclude=") + (magit-log:-n) + (magit-log:--since) + (magit-log:--until)] + ["Actions" + ("c" "create regular bundle" magit-bundle-create) + ("t" "create tracked bundle" magit-bundle-create-tracked) + ("u" "update tracked bundle" magit-bundle-update-tracked)] + (interactive + (and (eq transient-current-command 'magit-bundle-create) + (list (read-file-name "Create bundle: " nil nil nil + (concat (file-name-nondirectory + (directory-file-name (magit-toplevel))) + ".bundle")) + (magit-completing-read-multiple* "Refnames (zero or more): " + (magit-list-refnames)) + (transient-args 'magit-bundle-create)))) + (if file + (magit-git-bundle "create" file refs args) + (transient-setup 'magit-bundle-create))) + +;;;###autoload +(defun magit-bundle-create-tracked (file tag branch refs args) + "Create and track a new bundle." + (interactive + (let ((tag (magit-read-tag "Track bundle using tag")) + (branch (magit-read-branch "Bundle branch")) + (refs (magit-completing-read-multiple* + "Additional refnames (zero or more): " + (magit-list-refnames)))) + (list (read-file-name "File: " nil nil nil (concat tag ".bundle")) + tag branch + (if (equal branch (magit-get-current-branch)) + (cons "HEAD" refs) + refs) + (transient-args 'magit-bundle-create)))) + (magit-git-bundle "create" file (cons branch refs) args) + (magit-git "tag" "--force" tag branch + "-m" (concat ";; git-bundle tracking\n" + (pp-to-string `((file . ,file) + (branch . ,branch) + (refs . ,refs) + (args . ,args)))))) + +;;;###autoload +(defun magit-bundle-update-tracked (tag) + "Update a bundle that is being tracked using TAG." + (interactive (list (magit-read-tag "Update bundle tracked by tag" t))) + (let (msg) + (let-alist (magit--with-temp-process-buffer + (save-excursion + (magit-git-insert "for-each-ref" "--format=%(contents)" + (concat "refs/tags/" tag))) + (setq msg (buffer-string)) + (ignore-errors (read (current-buffer)))) + (unless (and .file .branch) + (error "Tag %s does not appear to track a bundle" tag)) + (magit-git-bundle "create" .file + (cons (concat tag ".." .branch) .refs) + .args) + (magit-git "tag" "--force" tag .branch "-m" msg)))) + +;;;###autoload +(defun magit-bundle-verify (file) + "Check whether FILE is valid and applies to the current repository." + (interactive (list (magit-bundle--read-file-name "Verify bundle: "))) + (magit-process-buffer) + (magit-git-bundle "verify" file)) + +;;;###autoload +(defun magit-bundle-list-heads (file) + "List the refs in FILE." + (interactive (list (magit-bundle--read-file-name "List heads of bundle: "))) + (magit-process-buffer) + (magit-git-bundle "list-heads" file)) + +(defun magit-bundle--read-file-name (prompt) + (read-file-name prompt nil nil t (magit-file-at-point) #'file-regular-p)) + +(defun magit-git-bundle (command file &optional refs args) + (magit-git "bundle" command (magit-convert-filename-for-git file) refs args)) + +;;; _ +(provide 'magit-bundle) +;;; magit-bundle.el ends here diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-clone.el magit-3.3.0/lisp/magit-clone.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-clone.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-clone.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-clone.el --- clone a repository -*- lexical-binding: t -*- -;; Copyright (C) 2008-2020 The Magit Project Contributors +;; Copyright (C) 2008-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -104,7 +106,7 @@ ;;; Commands ;;;###autoload (autoload 'magit-clone "magit-clone" nil t) -(define-transient-command magit-clone (&optional transient) +(transient-define-prefix magit-clone (&optional transient) "Clone a repository." :man-page "git-clone" ["Fetch arguments" @@ -192,30 +194,48 @@ (magit-clone-internal repository directory (cons "--mirror" args))) (defun magit-clone-internal (repository directory args) - (run-hooks 'magit-credential-hook) - (setq directory (file-name-as-directory (expand-file-name directory))) - (magit-run-git-async "clone" args "--" repository - (magit-convert-filename-for-git directory)) - ;; Don't refresh the buffer we're calling from. - (process-put magit-this-process 'inhibit-refresh t) - (set-process-sentinel - magit-this-process - (lambda (process event) - (when (memq (process-status process) '(exit signal)) - (let ((magit-process-raise-error t)) - (magit-process-sentinel process event))) - (when (and (eq (process-status process) 'exit) - (= (process-exit-status process) 0)) - (unless (memq (car args) '("--bare" "--mirror")) - (let ((default-directory directory)) - (when (or (eq magit-clone-set-remote.pushDefault t) - (and magit-clone-set-remote.pushDefault - (y-or-n-p "Set `remote.pushDefault' to \"origin\"? "))) - (setf (magit-get "remote.pushDefault") "origin")) - (unless magit-clone-set-remote-head - (magit-remote-unset-head "origin")))) - (with-current-buffer (process-get process 'command-buf) - (magit-status-setup-buffer directory)))))) + (let* ((checkout (not (memq (car args) '("--bare" "--mirror")))) + (remote (or (transient-arg-value "--origin" args) + (magit-get "clone.defaultRemote") + "origin")) + (set-push-default + (and checkout + (or (eq magit-clone-set-remote.pushDefault t) + (and magit-clone-set-remote.pushDefault + (y-or-n-p (format "Set `remote.pushDefault' to %S? " + remote))))))) + (run-hooks 'magit-credential-hook) + (setq directory (file-name-as-directory (expand-file-name directory))) + (when (file-exists-p directory) + (if (file-directory-p directory) + (when (> (length (directory-files directory)) 2) + (let ((name (magit-clone--url-to-name repository))) + (unless (and name + (setq directory (file-name-as-directory + (expand-file-name name directory))) + (not (file-exists-p directory))) + (user-error "%s already exists" directory)))) + (user-error "%s already exists and is not a directory" directory))) + (magit-run-git-async "clone" args "--" repository + (magit-convert-filename-for-git directory)) + ;; Don't refresh the buffer we're calling from. + (process-put magit-this-process 'inhibit-refresh t) + (set-process-sentinel + magit-this-process + (lambda (process event) + (when (memq (process-status process) '(exit signal)) + (let ((magit-process-raise-error t)) + (magit-process-sentinel process event))) + (when (and (eq (process-status process) 'exit) + (= (process-exit-status process) 0)) + (when checkout + (let ((default-directory directory)) + (when set-push-default + (setf (magit-get "remote.pushDefault") remote)) + (unless magit-clone-set-remote-head + (magit-remote-unset-head remote)))) + (with-current-buffer (process-get process 'command-buf) + (magit-status-setup-buffer directory))))))) (defun magit-clone-read-args () (let ((repo (magit-clone-read-repository))) @@ -226,8 +246,7 @@ (funcall magit-clone-default-directory repo) magit-clone-default-directory) nil nil - (and (string-match "\\([^/:]+?\\)\\(/?\\.git\\)?$" repo) - (match-string 1 repo))) + (magit-clone--url-to-name repo)) (transient-args 'magit-clone)))) (defun magit-clone-read-repository () @@ -238,12 +257,22 @@ str (magit-clone--name-to-url str)))) (?p "[p]ath" - (read-directory-name "Clone repository: ")) - (?l "or [l]ocal url" - (concat "file://" (read-directory-name "Clone repository: file://"))))) + (magit-convert-filename-for-git + (read-directory-name "Clone repository: "))) + (?l "[l]ocal url" + (concat "file://" + (magit-convert-filename-for-git + (read-directory-name "Clone repository: file://")))) + (?b "or [b]undle" + (magit-convert-filename-for-git + (read-file-name "Clone from bundle: "))))) + +(defun magit-clone--url-to-name (url) + (and (string-match "\\([^/:]+?\\)\\(/?\\.git\\)?$" url) + (match-string 1 url))) (defun magit-clone--name-to-url (name) - (or (-some + (or (seq-some (pcase-lambda (`(,re ,host ,user)) (and (string-match re name) (let ((repo (match-string 1 name))) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-commit.el magit-3.3.0/lisp/magit-commit.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-commit.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-commit.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-commit.el --- create Git commits -*- lexical-binding: t -*- -;; Copyright (C) 2008-2020 The Magit Project Contributors +;; Copyright (C) 2008-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -34,12 +36,11 @@ (eval-when-compile (require 'epa)) ; for `epa-protocol' (eval-when-compile (require 'epg)) -(eval-when-compile (require 'subr-x)) ;;; Options (defcustom magit-commit-ask-to-stage 'verbose - "Whether to ask to stage all unstaged changes when committing and nothing is staged." + "Whether to ask to stage everything when committing and nothing is staged." :package-version '(magit . "2.3.0") :group 'magit-commands :type '(choice (const :tag "Ask" t) @@ -90,6 +91,34 @@ :group 'magit-commands :type 'hook) +(defcustom magit-commit-diff-inhibit-same-window nil + "Whether to inhibit use of same window when showing diff while committing. + +When writing a commit, then a diff of the changes to be committed +is automatically shown. The idea is that the diff is shown in a +different window of the same frame and for most users that just +works. In other words most users can completely ignore this +option because its value doesn't make a difference for them. + +However for users who configured Emacs to never create a new +window even when the package explicitly tries to do so, then +displaying two new buffers necessarily means that the first is +immediately replaced by the second. In our case the message +buffer is immediately replaced by the diff buffer, which is of +course highly undesirable. + +A workaround is to suppress this user configuration in this +particular case. Users have to explicitly opt-in by toggling +this option. We cannot enable the workaround unconditionally +because that again causes issues for other users: if the frame +is too tiny or the relevant settings too aggressive, then the +diff buffer would end up being displayed in a new frame. + +Also see https://github.com/magit/magit/issues/4132." + :package-version '(magit . "3.3.0") + :group 'magit-commands + :type 'boolean) + (defvar magit-post-commit-hook-commands '(magit-commit-extend magit-commit-fixup @@ -100,7 +129,7 @@ ;;; Popup ;;;###autoload (autoload 'magit-commit "magit-commit" nil t) -(define-transient-command magit-commit () +(transient-define-prefix magit-commit () "Create a new commit or replace an existing commit." :info-manual "(magit)Initiating a Commit" :man-page "git-commit" @@ -126,7 +155,8 @@ ("f" "Fixup" magit-commit-fixup) ("s" "Squash" magit-commit-squash) ("A" "Augment" magit-commit-augment) - (6 "x" "Absorb changes" magit-commit-absorb)] + (6 "x" "Absorb changes" magit-commit-autofixup) + (6 "X" "Absorb modules" magit-commit-absorb-modules)] ["" ("F" "Instant fixup" magit-commit-instant-fixup) ("S" "Instant squash" magit-commit-instant-squash)]] @@ -138,35 +168,53 @@ (defun magit-commit-arguments nil (transient-args 'magit-commit)) -(define-infix-argument magit:--gpg-sign () +(transient-define-argument magit:--gpg-sign () :description "Sign using gpg" :class 'transient-option :shortarg "-S" :argument "--gpg-sign=" :allow-empty t - :reader 'magit-read-gpg-secret-key) + :reader 'magit-read-gpg-signing-key) (defvar magit-gpg-secret-key-hist nil) -(defun magit-read-gpg-secret-key (prompt &optional initial-input history) +(defun magit-read-gpg-secret-key + (prompt &optional initial-input history predicate) (require 'epa) - (let* ((keys (mapcar - (lambda (obj) - (let ((key (epg-sub-key-id (car (epg-key-sub-key-list obj)))) - (author - (when-let ((id-obj (car (epg-key-user-id-list obj)))) - (let ((id-str (epg-user-id-string id-obj))) - (if (stringp id-str) - id-str - (epg-decode-dn id-obj)))))) - (propertize key 'display (concat key " " author)))) + (let* ((keys (mapcan + (lambda (cert) + (and (or (not predicate) + (funcall predicate cert)) + (let* ((key (car (epg-key-sub-key-list cert))) + (fpr (epg-sub-key-fingerprint key)) + (id (epg-sub-key-id key)) + (author + (when-let ((id-obj + (car (epg-key-user-id-list cert)))) + (let ((id-str (epg-user-id-string id-obj))) + (if (stringp id-str) + id-str + (epg-decode-dn id-obj)))))) + (list + (propertize fpr 'display + (concat (substring fpr 0 (- (length id))) + (propertize id 'face 'highlight) + " " author)))))) (epg-list-keys (epg-make-context epa-protocol) nil t))) (choice (completing-read prompt keys nil nil nil history nil initial-input))) (set-text-properties 0 (length choice) nil choice) choice)) -(define-infix-argument magit-commit:--reuse-message () +(defun magit-read-gpg-signing-key (prompt &optional initial-input history) + (magit-read-gpg-secret-key + prompt initial-input history + (lambda (cert) + (cl-some (lambda (key) + (memq 'sign (epg-sub-key-capability key))) + (epg-key-sub-key-list cert))))) + +(transient-define-argument magit-commit:--reuse-message () :description "Reuse commit message" :class 'transient-option :shortarg "-C" @@ -217,7 +265,7 @@ (if current-prefix-arg (not magit-commit-extend-override-date) magit-commit-extend-override-date))) - (when (setq args (magit-commit-assert args (not override-date))) + (when (setq args (magit-commit-assert args)) (magit-commit-amend-assert) (let ((process-environment process-environment)) (unless override-date @@ -263,7 +311,10 @@ With a prefix argument the target COMMIT has to be confirmed. Otherwise the commit at point may be used without confirmation -depending on the value of option `magit-commit-squash-confirm'." +depending on the value of option `magit-commit-squash-confirm'. + +If you want to immediately add a message to the squash commit, +then use `magit-commit-augment' instead of this command." (interactive (list (magit-commit-at-point) (magit-commit-arguments))) (magit-commit-squash-internal "--squash" commit args)) @@ -295,7 +346,7 @@ (defun magit-commit-squash-internal (option commit &optional args rebase edit confirmed) - (when-let ((args (magit-commit-assert args t))) + (when-let ((args (magit-commit-assert args (not edit)))) (when commit (when (and rebase (not (magit-rev-ancestor-p commit "HEAD"))) (magit-read-char-case @@ -357,7 +408,11 @@ (and (not strict) ;; ^ For amend variants that don't make sense otherwise. (or (member "--amend" args) - (member "--allow-empty" args)))) + (member "--allow-empty" args) + (member "--reset-author" args) + (member "--signoff" args) + (transient-arg-value "--author=" args) + (transient-arg-value "--date=" args)))) (or args (list "--"))) ((and (magit-rebase-in-progress-p) (not (magit-anything-unstaged-p)) @@ -386,39 +441,72 @@ (defvar magit--reshelve-history nil) ;;;###autoload -(defun magit-commit-reshelve (date) +(defun magit-commit-reshelve (date update-author &optional args) "Change the committer date and possibly the author date of `HEAD'. -If you are the author of `HEAD', then both dates are changed, -otherwise only the committer date. The current time is used -as the initial minibuffer input and the original author (if -that is you) or committer date is available as the previous -history element." +The current time is used as the initial minibuffer input and the +original author or committer date is available as the previous +history element. + +Both the author and the committer dates are changes, unless one +of the following is true, in which case only the committer date +is updated: +- You are not the author of the commit that is being reshelved. +- The command was invoked with a prefix argument. +- Non-interactively if UPDATE-AUTHOR is nil." (interactive - (let ((author-p (magit-rev-author-p "HEAD"))) - (push (magit-rev-format (if author-p "%ad" "%cd") "HEAD" + (let ((update-author (and (magit-rev-author-p "HEAD") + (not current-prefix-arg)))) + (push (magit-rev-format (if update-author "%ad" "%cd") "HEAD" (concat "--date=format:%F %T %z")) magit--reshelve-history) - (list (read-string (if author-p + (list (read-string (if update-author "Change author and committer dates to: " "Change committer date to: ") (cons (format-time-string "%F %T %z") 17) - 'magit--reshelve-history)))) + 'magit--reshelve-history) + update-author + (magit-commit-arguments)))) (let ((process-environment process-environment)) (push (concat "GIT_COMMITTER_DATE=" date) process-environment) (magit-run-git "commit" "--amend" "--no-edit" - (and (magit-rev-author-p "HEAD") - (concat "--date=" date))))) + (and update-author (concat "--date=" date)) + args))) + +;;;###autoload +(defun magit-commit-absorb-modules (phase commit) + "Spread modified modules across recent commits." + (interactive (list 'select (magit-get-upstream-branch))) + (let ((modules (magit-list-modified-modules))) + (unless modules + (user-error "There are no modified modules that could be absorbed")) + (when commit + (setq commit (magit-rebase-interactive-assert commit t))) + (if (and commit (eq phase 'run)) + (progn + (dolist (module modules) + (when-let ((msg (magit-git-string + "log" "-1" "--format=%s" + (concat commit "..") "--" module))) + (magit-git "commit" "-m" (concat "fixup! " msg) + "--only" "--" module))) + (magit-refresh) + t) + (magit-log-select + (lambda (commit) + (magit-commit-absorb-modules 'run commit)) + nil nil nil nil commit)))) ;;;###autoload (autoload 'magit-commit-absorb "magit-commit" nil t) -(define-transient-command magit-commit-absorb (phase commit args) - "Spread unstaged changes across recent commits. +(transient-define-prefix magit-commit-absorb (phase commit args) + "Spread staged changes across recent commits. With a prefix argument use a transient command to select infix -arguments. This command requires the git-autofixup script, which -is available from https://github.com/torbiak/git-autofixup." +arguments. This command requires git-absorb executable, which +is available from https://github.com/tummychow/git-absorb. +See `magit-commit-autofixup' for an alternative implementation." ["Arguments" - (magit-autofixup:--context) - (magit-autofixup:--strict)] + ("-f" "Skip safety checks" ("-f" "--force")) + ("-v" "Display more output" ("-v" "--verbose"))] ["Actions" ("x" "Absorb" magit-commit-absorb)] (interactive (if current-prefix-arg @@ -428,13 +516,54 @@ (transient-args 'magit-commit-absorb)))) (if (eq phase 'transient) (transient-setup 'magit-commit-absorb) + (unless (executable-find "git-absorb") + (user-error "This command requires the git-absorb executable, which %s" + "is available from https://github.com/tummychow/git-absorb")) + (unless (magit-anything-staged-p) + (if (magit-anything-unstaged-p) + (if (y-or-n-p "Nothing staged. Absorb all unstaged changes? ") + (magit-with-toplevel + (magit-run-git "add" "-u" ".")) + (user-error "Abort")) + (user-error "There are no changes that could be absorbed"))) + (when commit + (setq commit (magit-rebase-interactive-assert commit t))) + (if (and commit (eq phase 'run)) + (progn (magit-run-git-async "absorb" "-v" args "-b" commit) t) + (magit-log-select + (lambda (commit) + (with-no-warnings ; about non-interactive use + (magit-commit-absorb 'run commit args))) + nil nil nil nil commit)))) + +;;;###autoload (autoload 'magit-commit-autofixup "magit-commit" nil t) +(transient-define-prefix magit-commit-autofixup (phase commit args) + "Spread staged or unstaged changes across recent commits. + +If there are any staged then spread only those, otherwise +spread all unstaged changes. With a prefix argument use a +transient command to select infix arguments. + +This command requires the git-autofixup script, which is +available from https://github.com/torbiak/git-autofixup. +See `magit-commit-absorb' for an alternative implementation." + ["Arguments" + (magit-autofixup:--context) + (magit-autofixup:--strict)] + ["Actions" + ("x" "Absorb" magit-commit-autofixup)] + (interactive (if current-prefix-arg + (list 'transient nil nil) + (list 'select + (magit-get-upstream-branch) + (transient-args 'magit-commit-autofixup)))) + (if (eq phase 'transient) + (transient-setup 'magit-commit-autofixup) (unless (executable-find "git-autofixup") (user-error "This command requires the git-autofixup script, which %s" "is available from https://github.com/torbiak/git-autofixup")) - (when (magit-anything-staged-p) - (user-error "Cannot absorb when there are staged changes")) - (unless (magit-anything-unstaged-p) - (user-error "There are no unstaged changes that could be absorbed")) + (unless (magit-anything-modified-p) + (user-error "There are no changes that could be absorbed")) (when commit (setq commit (magit-rebase-interactive-assert commit t))) (if (and commit (eq phase 'run)) @@ -442,17 +571,17 @@ (magit-log-select (lambda (commit) (with-no-warnings ; about non-interactive use - (magit-commit-absorb 'run commit args))) + (magit-commit-autofixup 'run commit args))) nil nil nil nil commit)))) -(define-infix-argument magit-autofixup:--context () +(transient-define-argument magit-autofixup:--context () :description "Diff context lines" :class 'transient-option :shortarg "-c" :argument "--context=" :reader 'transient-read-number-N0) -(define-infix-argument magit-autofixup:--strict () +(transient-define-argument magit-autofixup:--strict () :description "Strictness" :class 'transient-option :shortarg "-s" @@ -472,7 +601,12 @@ (let ((args (car (magit-diff-arguments))) (magit-inhibit-save-previous-winconf 'unset) (magit-display-buffer-noselect t) - (inhibit-quit nil)) + (inhibit-quit nil) + (display-buffer-overriding-action + display-buffer-overriding-action)) + (when magit-commit-diff-inhibit-same-window + (setq display-buffer-overriding-action + '(nil (inhibit-same-window t)))) (message "Diffing changes to be committed (C-g to abort diffing)") (cl-case last-command (magit-commit @@ -491,6 +625,7 @@ ;; Mention `magit-diff-while-committing' because that's ;; always what I search for when I try to find this line. (add-hook 'server-switch-hook 'magit-commit-diff) +(add-hook 'with-editor-filter-visit-hook 'magit-commit-diff) (add-to-list 'with-editor-server-window-alist (cons git-commit-filename-regexp 'switch-to-buffer)) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-core.el magit-3.3.0/lisp/magit-core.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-core.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-core.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-core.el --- core functionality -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-diff.el magit-3.3.0/lisp/magit-diff.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-diff.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-diff.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-diff.el --- inspect Git diffs -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -28,12 +30,12 @@ ;;; Code: -(eval-when-compile - (require 'ansi-color) - (require 'subr-x)) - -(require 'git-commit) (require 'magit-core) +(require 'git-commit) + +(eval-when-compile (require 'ansi-color)) +(require 'diff-mode) +(require 'smerge-mode) ;; For `magit-diff-popup' (declare-function magit-stash-show "magit-stash" (stash &optional args files)) @@ -55,25 +57,24 @@ (declare-function magit-merge-in-progress-p "magit-merge" ()) (declare-function magit--merge-range "magit-merge" (&optional head)) ;; For `magit-diff--dwim' +(declare-function forge--pullreq-range "forge-pullreq" + (pullreq &optional endpoints)) (declare-function forge--pullreq-ref "forge-pullreq" (pullreq)) ;; For `magit-diff-wash-diff' (declare-function ansi-color-apply-on-region "ansi-color" (begin end)) (eval-when-compile - (cl-pushnew 'base-ref eieio--known-slot-names) (cl-pushnew 'orig-rev eieio--known-slot-names) (cl-pushnew 'action-type eieio--known-slot-names) (cl-pushnew 'target eieio--known-slot-names)) -(require 'diff-mode) -(require 'smerge-mode) - ;;; Options ;;;; Diff Mode (defgroup magit-diff nil "Inspect and manipulate Git diffs." :link '(info-link "(magit)Diffing") + :group 'magit-commands :group 'magit-modes) (defcustom magit-diff-mode-hook nil @@ -92,10 +93,10 @@ (defcustom magit-diff-expansion-threshold 60 "After how many seconds not to expand anymore diffs. -Except in status buffers, diffs are usually start out fully -expanded. Because that can take a long time, all diffs that -haven't been fontified during a refresh before the threshold -defined here are instead displayed with their bodies collapsed. +Except in status buffers, diffs usually start out fully expanded. +Because that can take a long time, all diffs that haven't been +fontified during a refresh before the threshold defined here are +instead displayed with their bodies collapsed. Note that this can cause sections that were previously expanded to be collapsed. So you should not pick a very low value here. @@ -281,6 +282,20 @@ :group 'magit-diff :type 'boolean) +(defcustom magit-diff-extra-stat-arguments nil + "Additional arguments to be used alongside `--stat'. + +A list of zero or more arguments or a function that takes no +argument and returns such a list. These arguments are allowed +here: `--stat-width', `--stat-name-width', `--stat-graph-width' +and `--compact-summary'. See the git-diff(1) manpage." + :package-version '(magit . "3.0.0") + :group 'magit-diff + :type '(radio (function-item magit-diff-use-window-width-as-stat-width) + function + (list string) + (const :tag "None" nil))) + ;;;; File Diff (defcustom magit-diff-buffer-file-locked t @@ -297,11 +312,14 @@ :link '(info-link "(magit)Revision Buffer") :group 'magit-modes) -(defcustom magit-revision-mode-hook '(bug-reference-mode) +(defcustom magit-revision-mode-hook + '(bug-reference-mode + goto-address-mode) "Hook run after entering Magit-Revision mode." :group 'magit-revision :type 'hook - :options '(bug-reference-mode)) + :options '(bug-reference-mode + goto-address-mode)) (defcustom magit-revision-sections-hook '(magit-insert-revision-tag @@ -744,7 +762,7 @@ (pcase-let ((`(,args ,files) (magit-diff--get-value 'magit-diff-mode magit-prefix-use-buffer-arguments))) - (unless (eq current-transient-command 'magit-dispatch) + (unless (eq transient-current-command 'magit-dispatch) (when-let ((file (magit-file-relative-name))) (setq files (list file)))) (oset obj value (if files `(("--" ,@files) ,args) args)))) @@ -765,7 +783,7 @@ (defun magit-diff-arguments (&optional mode) "Return the current diff arguments." - (if (memq current-transient-command '(magit-diff magit-diff-refresh)) + (if (memq transient-current-command '(magit-diff magit-diff-refresh)) (pcase-let ((`(,args ,alist) (-separate #'atom (transient-get-value)))) (list args (cdr (assoc "--" alist)))) @@ -816,14 +834,16 @@ ;;; Section Classes (defclass magit-file-section (magit-section) - ((source :initform nil) - (header :initform nil))) + ((keymap :initform 'magit-file-section-map) + (source :initform nil) + (header :initform nil))) (defclass magit-module-section (magit-file-section) - ()) + ((keymap :initform 'magit-hunk-section-map))) (defclass magit-hunk-section (magit-section) - ((refined :initform nil) + ((keymap :initform 'magit-hunk-section-map) + (refined :initform nil) (combined :initform nil) (from-range :initform nil) (from-ranges :initform nil) @@ -838,7 +858,7 @@ ;;;; Prefix Commands ;;;###autoload (autoload 'magit-diff "magit-diff" nil t) -(define-transient-command magit-diff () +(transient-define-prefix magit-diff () "Show changes between different versions." :man-page "git-diff" :class 'magit-diff-prefix @@ -858,6 +878,7 @@ ("-x" "Disallow external diff drivers" "--no-ext-diff") ("-s" "Show stats" "--stat") ("=g" "Show signature" "--show-signature") + (5 "-R" "Reverse sides" "-R") (5 magit-diff:--color-moved) (5 magit-diff:--color-moved-ws)] ["Actions" @@ -871,7 +892,7 @@ ("t" "Show stash" magit-stash-show)]]) ;;;###autoload (autoload 'magit-diff-refresh "magit-diff" nil t) -(define-transient-command magit-diff-refresh () +(transient-define-prefix magit-diff-refresh () "Change the arguments used for the diff(s) in the current buffer." :man-page "git-diff" :class 'magit-diff-refresh-prefix @@ -893,6 +914,8 @@ :if-derived magit-diff-mode) ("=g" "Show signature" "--show-signature" :if-derived magit-diff-mode) + (5 "-R" "Reverse sides" "-R" + :if-derived magit-diff-mode) (5 magit-diff:--color-moved) (5 magit-diff:--color-moved-ws)] [["Refresh" @@ -909,7 +932,7 @@ ("r" "switch range type" magit-diff-switch-range-type) ("f" "flip revisions" magit-diff-flip-revs)]] (interactive) - (if (not (eq current-transient-command 'magit-diff-refresh)) + (if (not (eq transient-current-command 'magit-diff-refresh)) (transient-setup 'magit-diff-refresh) (pcase-let ((`(,args ,files) (magit-diff-arguments))) (setq magit-buffer-diff-args args) @@ -918,7 +941,7 @@ ;;;; Infix Commands -(define-infix-argument magit:-- () +(transient-define-argument magit:-- () :description "Limit to files" :class 'transient-files :key "--" @@ -930,27 +953,31 @@ (defun magit-read-files (prompt initial-input history) (magit-completing-read-multiple* prompt (magit-list-files) - nil nil initial-input history)) + nil nil + (or initial-input (magit-file-at-point)) + history)) -(define-infix-argument magit-diff:-U () +(transient-define-argument magit-diff:-U () :description "Context lines" :class 'transient-option :argument "-U" - :reader 'transient-read-number-N+) + :reader 'transient-read-number-N0) -(define-infix-argument magit-diff:-M () +(transient-define-argument magit-diff:-M () :description "Detect renames" :class 'transient-option :argument "-M" + :allow-empty t :reader 'transient-read-number-N+) -(define-infix-argument magit-diff:-C () +(transient-define-argument magit-diff:-C () :description "Detect copies" :class 'transient-option :argument "-C" + :allow-empty t :reader 'transient-read-number-N+) -(define-infix-argument magit-diff:--diff-algorithm () +(transient-define-argument magit-diff:--diff-algorithm () :description "Diff algorithm" :class 'transient-option :key "-A" @@ -964,7 +991,7 @@ (?p "[p]atience" "patience") (?h "[h]istogram" "histogram"))) -(define-infix-argument magit-diff:--ignore-submodules () +(transient-define-argument magit-diff:--ignore-submodules () :description "Ignore submodules" :class 'transient-option :key "-i" @@ -977,7 +1004,7 @@ (?d "[d]irty" "dirty") (?a "[a]ll" "all"))) -(define-infix-argument magit-diff:--color-moved () +(transient-define-argument magit-diff:--color-moved () :description "Color moved lines" :class 'transient-option :key "-m" @@ -992,7 +1019,7 @@ (?z "[z]ebra" "zebra") (?Z "[Z] dimmed-zebra" "dimmed-zebra"))) -(define-infix-argument magit-diff:--color-moved-ws () +(transient-define-argument magit-diff:--color-moved-ws () :description "Whitespace treatment for --color-moved" :class 'transient-option :key "=w" @@ -1056,13 +1083,13 @@ (cons 'commit (magit-section-case (commit (oref it value)) - (file (-> it - (oref parent) - (oref value))) - (hunk (-> it - (oref parent) - (oref parent) - (oref value)))))) + (file (thread-first it + (oref parent) + (oref value))) + (hunk (thread-first it + (oref parent) + (oref parent) + (oref value)))))) ((derived-mode-p 'magit-revision-mode) (cons 'commit magit-buffer-revision)) ((derived-mode-p 'magit-diff-mode) @@ -1086,11 +1113,11 @@ (or current "HEAD") atpoint)))) (commit (cons 'commit (oref it value))) + ([file commit] (cons 'commit (oref (oref it parent) value))) + ([hunk file commit] + (cons 'commit (oref (oref (oref it parent) parent) value))) (stash (cons 'stash (oref it value))) - (pullreq (let ((pullreq (oref it value))) - (format "%s...%s" - (oref pullreq base-ref) - (forge--pullreq-ref pullreq)))))))) + (pullreq (forge--pullreq-range (oref it value) t)))))) (defun magit-diff-read-range-or-commit (prompt &optional secondary-default mbase) "Read range or revision with special diff range treatment. @@ -1265,9 +1292,8 @@ for a revision." (interactive (pcase-let* ((mcommit (magit-section-value-if 'module-commit)) - (atpoint (or (and (bound-and-true-p magit-blame-mode) - (oref (magit-current-blame-chunk) orig-rev)) - mcommit + (atpoint (or mcommit + (thing-at-point 'git-revision t) (magit-branch-or-commit-at-point))) (`(,args ,files) (magit-show-commit--arguments))) (list (or (and (not current-prefix-arg) atpoint) @@ -1301,11 +1327,12 @@ (let (hunk (hunks (oref diff children))) (cl-block nil (while (setq hunk (pop hunks)) - (pcase-let* ((`(,beg ,len) (oref hunk to-range)) - (end (+ beg len))) - (cond ((> beg line) (cl-return (list diff nil))) - ((<= beg line end) (cl-return (list hunk t))) - ((null hunks) (cl-return (list hunk nil)))))))))) + (when-let ((range (oref hunk to-range))) + (pcase-let* ((`(,beg ,len) range) + (end (+ beg len))) + (cond ((> beg line) (cl-return (list diff nil))) + ((<= beg line end) (cl-return (list hunk t))) + ((null hunks) (cl-return (list hunk nil))))))))))) (defun magit-diff--goto-position (file line column &optional parent) (when-let ((pos (magit-diff--locate-hunk file line parent))) @@ -1331,9 +1358,6 @@ (magit-section-update-highlight) t)) -(cl-defmethod magit-buffer-value (&context (major-mode magit-revision-mode)) - (cons magit-buffer-range magit-buffer-diff-files)) - ;;;; Setting Commands (defun magit-diff-switch-range-type () @@ -1378,9 +1402,7 @@ (cl-rotatef magit-buffer-diff-files magit-buffer-diff-files-suspended) (setq magit-buffer-diff-files - (magit-read-files "Limit to file(s): " - (magit-file-at-point) - nil))) + (transient-infix-read 'magit:--))) (magit-refresh))) (cond ((derived-mode-p 'magit-log-mode @@ -1397,12 +1419,12 @@ (defun magit-diff-less-context (&optional count) "Decrease the context for diff hunks by COUNT lines." (interactive "p") - (magit-diff-set-context `(lambda (cur) (max 0 (- (or cur 0) ,count))))) + (magit-diff-set-context (lambda (cur) (max 0 (- (or cur 0) count))))) (defun magit-diff-more-context (&optional count) "Increase the context for diff hunks by COUNT lines." (interactive "p") - (magit-diff-set-context `(lambda (cur) (+ (or cur 0) ,count)))) + (magit-diff-set-context (lambda (cur) (+ (or cur 0) count)))) (defun magit-diff-default-context () "Reset context for diff hunks to the default height." @@ -1488,8 +1510,8 @@ In the file-visiting buffer also go to the line that corresponds to the line that point is on in the diff. -Note that this command only works if point is inside a diff. In -other cases `magit-find-file' (which see) had to be used." +Note that this command only works if point is inside a diff. +In other cases `magit-find-file' (which see) has to be used." (interactive (list (magit-file-at-point t t) current-prefix-arg)) (magit-diff-visit-file--internal file nil (if other-window @@ -1554,7 +1576,7 @@ (defun magit-diff-visit-file--internal (file force-worktree fn) "From a diff visit the appropriate version of FILE. If FORCE-WORKTREE is non-nil, then visit the worktree version of -the file, even if the diff is about a committed change. USE FN +the file, even if the diff is about a committed change. Use FN to display the buffer in some window." (if (magit-file-accessible-directory-p file) (magit-diff-visit-directory file force-worktree) @@ -1656,11 +1678,13 @@ (not (< (point) (oref section content))) (= (char-after (line-beginning-position)) ?-))) +(defvar magit-diff-visit-jump-to-change t) + (defun magit-diff-hunk-line (section goto-from) (save-excursion (goto-char (line-beginning-position)) (with-slots (content combined from-ranges from-range to-range) section - (when (< (point) content) + (when (and magit-diff-visit-jump-to-change (< (point) content)) (goto-char content) (re-search-forward "^[-+]")) (+ (car (if goto-from from-range to-range)) @@ -1700,7 +1724,7 @@ (cdr spec) (cdr (magit-split-range spec))))) (if (and magit-diff-visit-avoid-head-blob - (magit-rev-head-p spec)) + (magit-rev-head-p rev)) 'unstaged rev)))) @@ -1828,7 +1852,7 @@ (cond ((and (--any-p (oref it hidden) children) (--any-p (oref it children) children)) (mapc 'magit-section-show-headings sections)) - ((-any-p 'magit-section-hidden-body children) + ((seq-some 'magit-section-hidden-body children) (mapc 'magit-section-show-children sections)) (t (mapc 'magit-section-hide sections))))))) @@ -1885,7 +1909,8 @@ (magit-buffer-range range) (magit-buffer-typearg typearg) (magit-buffer-diff-args args) - (magit-buffer-diff-files files))) + (magit-buffer-diff-files files) + (magit-buffer-diff-files-suspended nil))) (defun magit-diff-refresh-buffer () "Refresh the current `magit-diff-mode' buffer." @@ -1893,10 +1918,14 @@ (if (equal magit-buffer-typearg "--no-index") (apply #'format "Differences between %s and %s" magit-buffer-diff-files) (concat (if magit-buffer-range - (if (string-match-p "\\(\\.\\.\\|\\^-\\)" - magit-buffer-range) - (format "Changes in %s" magit-buffer-range) - (format "Changes from %s to working tree" magit-buffer-range)) + (cond + ((string-match-p "\\(\\.\\.\\|\\^-\\)" + magit-buffer-range) + (format "Changes in %s" magit-buffer-range)) + ((member "-R" magit-buffer-diff-args) + (format "Changes from working tree to %s" magit-buffer-range)) + (t + (format "Changes from %s to working tree" magit-buffer-range))) (if (equal magit-buffer-typearg "--cached") "Staged changes" "Unstaged changes")) @@ -1919,44 +1948,62 @@ (list 'unstaged magit-buffer-typearg))) (and magit-buffer-diff-files (cons "--" magit-buffer-diff-files)))) -(defvar magit-file-section-map +(defvar magit-diff-section-base-map (let ((map (make-sparse-keymap))) - (define-key map (kbd "C-j") 'magit-diff-visit-worktree-file) - (define-key map [C-return] 'magit-diff-visit-worktree-file) + (define-key map (kbd "C-j") 'magit-diff-visit-worktree-file) + (define-key map (kbd "C-") 'magit-diff-visit-worktree-file) + (define-key map (kbd "C-x 4 ") 'magit-diff-visit-file-other-window) + (define-key map (kbd "C-x 5 ") 'magit-diff-visit-file-other-frame) (define-key map [remap magit-visit-thing] 'magit-diff-visit-file) (define-key map [remap magit-delete-thing] 'magit-discard) (define-key map [remap magit-revert-no-commit] 'magit-reverse) (define-key map "a" 'magit-apply) - (define-key map "C" 'magit-commit-add-log) (define-key map "s" 'magit-stage) (define-key map "u" 'magit-unstage) (define-key map "&" 'magit-do-async-shell-command) - (define-key map "\C-c\C-t" 'magit-diff-trace-definition) - (define-key map "\C-c\C-e" 'magit-diff-edit-hunk-commit) + (define-key map "C" 'magit-commit-add-log) + (define-key map (kbd "C-x a") 'magit-add-change-log-entry) + (define-key map (kbd "C-x 4 a") 'magit-add-change-log-entry-other-window) + (define-key map (kbd "C-c C-t") 'magit-diff-trace-definition) + (define-key map (kbd "C-c C-e") 'magit-diff-edit-hunk-commit) + map) + "Parent of `magit-{hunk,file}-section-map'.") + +(defvar magit-file-section-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-diff-section-base-map) map) "Keymap for `file' sections.") (defvar magit-hunk-section-map (let ((map (make-sparse-keymap))) - (define-key map (kbd "C-j") 'magit-diff-visit-worktree-file) - (define-key map [C-return] 'magit-diff-visit-worktree-file) - (define-key map [remap magit-visit-thing] 'magit-diff-visit-file) - (define-key map [remap magit-delete-thing] 'magit-discard) - (define-key map [remap magit-revert-no-commit] 'magit-reverse) - (define-key map "a" 'magit-apply) - (define-key map "C" 'magit-commit-add-log) - (define-key map "s" 'magit-stage) - (define-key map "u" 'magit-unstage) - (define-key map "&" 'magit-do-async-shell-command) - (define-key map "\C-c\C-t" 'magit-diff-trace-definition) - (define-key map "\C-c\C-e" 'magit-diff-edit-hunk-commit) + (set-keymap-parent map magit-diff-section-base-map) + (let ((m (make-sparse-keymap))) + (define-key m (kbd "RET") 'magit-smerge-keep-current) + (define-key m (kbd "u") 'magit-smerge-keep-upper) + (define-key m (kbd "b") 'magit-smerge-keep-base) + (define-key m (kbd "l") 'magit-smerge-keep-lower) + (define-key map smerge-command-prefix m)) map) "Keymap for `hunk' sections.") +(defconst magit-diff-conflict-headline-re + (concat "^" (regexp-opt + ;; Defined in merge-tree.c in this order. + '("merged" + "added in remote" + "added in both" + "added in local" + "removed in both" + "changed in both" + "removed in local" + "removed in remote")))) + (defconst magit-diff-headline-re (concat "^\\(@@@?\\|diff\\|Submodule\\|" - "\\* Unmerged path\\|merged\\|changed in both\\|" - "added in remote\\|removed in remote\\)")) + "\\* Unmerged path\\|" + (substring magit-diff-conflict-headline-re 1) + "\\)")) (defconst magit-diff-statline-re (concat "^ ?" @@ -1993,28 +2040,45 @@ (defun magit--insert-diff (&rest args) (declare (indent 0)) - (let ((magit-git-global-arguments - (remove "--literal-pathspecs" magit-git-global-arguments))) - (setq args (-flatten args)) + (pcase-let ((`(,cmd . ,args) + (-flatten args)) + (magit-git-global-arguments + (remove "--literal-pathspecs" magit-git-global-arguments))) ;; As of Git 2.19.0, we need to generate diffs with ;; --ita-visible-in-index so that `magit-stage' can work with ;; intent-to-add files (see #4026). Cache the result for each ;; repo to avoid a `git version' call for every diff insertion. - (when (pcase (magit-repository-local-get 'diff-ita-kludge-p 'unset) - (`unset - (let ((val (version<= "2.19.0" (magit-git-version)))) - (magit-repository-local-set 'diff-ita-kludge-p val) - val)) - (val val)) - (push "--ita-visible-in-index" (cdr args))) + (when (and (not (equal cmd "merge-tree")) + (pcase (magit-repository-local-get 'diff-ita-kludge-p 'unset) + (`unset + (let ((val (version<= "2.19.0" (magit-git-version)))) + (magit-repository-local-set 'diff-ita-kludge-p val) + val)) + (val val))) + (push "--ita-visible-in-index" args)) + (setq args (magit-diff--maybe-add-stat-arguments args)) (when (cl-member-if (lambda (arg) (string-prefix-p "--color-moved" arg)) args) - (push "--color=always" (cdr args)) + (push "--color=always" args) (setq magit-git-global-arguments (append magit-diff--reset-non-color-moved magit-git-global-arguments))) - (magit-git-wash #'magit-diff-wash-diffs args))) + (magit-git-wash #'magit-diff-wash-diffs cmd args))) + +(defun magit-diff--maybe-add-stat-arguments (args) + (if (member "--stat" args) + (append (if (functionp magit-diff-extra-stat-arguments) + (funcall magit-diff-extra-stat-arguments) + magit-diff-extra-stat-arguments) + args) + args)) + +(defun magit-diff-use-window-width-as-stat-width () + "Use the `window-width' as the value of `--stat-width'." + (when-let ((window (get-buffer-window (current-buffer) 'visible))) + (list (format "--stat-width=%d" (window-width window))))) (defun magit-diff-wash-diffs (args &optional limit) + (run-hooks 'magit-diff-wash-diffs-hook) (when (member "--show-signature" args) (magit-diff-wash-signature)) (when (member "--stat" args) @@ -2041,10 +2105,25 @@ (defun magit-diff-wash-signature () (when (looking-at "^gpg: ") - (magit-insert-section (signature) - (while (looking-at "^gpg: ") - (forward-line)) - (insert "\n")))) + (let (title end) + (save-excursion + (while (looking-at "^gpg: ") + (cond + ((looking-at "^gpg: Good signature from") + (setq title (propertize + (buffer-substring (point) (line-end-position)) + 'face 'magit-signature-good))) + ((looking-at "^gpg: Can't check signature") + (setq title (propertize + (buffer-substring (point) (line-end-position)) + 'face '(italic bold))))) + (forward-line)) + (setq end (point-marker))) + (magit-insert-section (signature magit-buffer-revision title) + (when title + (magit-insert-heading title)) + (goto-char end) + (insert "\n"))))) (defun magit-diff-wash-diffstat () (let (heading (beg (point))) @@ -2118,14 +2197,21 @@ 'font-lock-face 'magit-diff-file-heading)) (insert ?\n)))) t) - ((looking-at (concat "^\\(merged\\|changed in both\\|" - "added in remote\\|removed in remote\\)")) - (let ((status (pcase (match-string 1) - ("merged" "merged") - ("changed in both" "conflict") - ("added in remote" "new file") - ("removed in remote" "deleted"))) - file orig base modes) + ((looking-at magit-diff-conflict-headline-re) + (let ((long-status (match-string 0)) + (status "BUG") + file orig base) + (if (equal long-status "merged") + (progn (setq status long-status) + (setq long-status nil)) + (setq status (pcase-exhaustive long-status + ("added in remote" "new file") + ("added in both" "new file") + ("added in local" "new file") + ("removed in both" "removed") + ("changed in both" "changed") + ("removed in local" "removed") + ("removed in remote" "removed")))) (magit-delete-line) (while (looking-at "^ \\([^ ]+\\) +[0-9]\\{6\\} \\([a-z0-9]\\{40\\}\\) \\(.+\\)$") @@ -2138,67 +2224,101 @@ (magit-delete-line)) (when orig (setq orig (magit-decode-git-path orig))) (when file (setq file (magit-decode-git-path file))) - (magit-diff-insert-file-section (or file base) orig status modes nil))) - ((looking-at - "^diff --\\(?:\\(git\\) \\(?:\\(.+?\\) \\2\\)?\\|\\(cc\\|combined\\) \\(.+\\)\\)") + (magit-diff-insert-file-section + (or file base) orig status nil nil nil long-status))) + ;; The files on this line may be ambiguous due to whitespace. + ;; That's okay. We can get their names from subsequent headers. + ((looking-at "^diff --\ +\\(?:\\(?1:git\\) \\(?:\\(?2:.+?\\) \\2\\)?\ +\\|\\(?:cc\\|combined\\) \\(?3:.+\\)\\)") (let ((status (cond ((equal (match-string 1) "git") "modified") ((derived-mode-p 'magit-revision-mode) "resolved") (t "unmerged"))) - (file (or (match-string 2) (match-string 4))) - (beg (point)) - orig header modes) - (save-excursion - (forward-line 1) - (setq header (buffer-substring - beg (if (re-search-forward magit-diff-headline-re nil t) - (match-beginning 0) - (point-max))))) + (orig nil) + (file (or (match-string 2) (match-string 3))) + (header (list (buffer-substring-no-properties + (line-beginning-position) (1+ (line-end-position))))) + (modes nil) + (rename nil)) (magit-delete-line) (while (not (or (eobp) (looking-at magit-diff-headline-re))) - (if (looking-at "^old mode \\([^\n]+\\)\nnew mode \\([^\n]+\\)\n") - (progn (setq modes (match-string 0)) - (magit-delete-match)) - (cond - ((looking-at "^--- \\([^/].*?\\)\t?$") ; i.e. not /dev/null - (setq orig (match-string 1))) - ((looking-at "^\\+\\+\\+ \\([^/].*?\\)\t?$") - (setq file (match-string 1))) - ((looking-at "^\\(copy\\|rename\\) from \\(.+\\)$") - (setq orig (match-string 2))) - ((looking-at "^\\(copy\\|rename\\) to \\(.+\\)$") - (setq file (match-string 2)) - (setq status (if (equal (match-string 1) "copy") "new file" "renamed"))) - ((looking-at "^\\(new file\\|deleted\\)") - (setq status (match-string 1)))) - (magit-delete-line))) + (cond + ((looking-at "old mode \\(?:[^\n]+\\)\nnew mode \\(?:[^\n]+\\)\n") + (setq modes (match-string 0))) + ((looking-at "deleted file .+\n") + (setq status "deleted")) + ((looking-at "new file .+\n") + (setq status "new file")) + ((looking-at "rename from \\(.+\\)\nrename to \\(.+\\)\n") + (setq rename (match-string 0)) + (setq orig (match-string 1)) + (setq file (match-string 2)) + (setq status "renamed")) + ((looking-at "copy from \\(.+\\)\ncopy to \\(.+\\)\n") + (setq orig (match-string 1)) + (setq file (match-string 2)) + (setq status "new file")) + ((looking-at "similarity index .+\n")) + ((looking-at "dissimilarity index .+\n")) + ((looking-at "index .+\n")) + ((looking-at "--- \\(.+?\\)\t?\n") + (unless (equal (match-string 1) "/dev/null") + (setq orig (match-string 1)))) + ((looking-at "\\+\\+\\+ \\(.+?\\)\t?\n") + (unless (equal (match-string 1) "/dev/null") + (setq file (match-string 1)))) + ((looking-at "Binary files .+ and .+ differ\n")) + ;; TODO Use all combined diff extended headers. + ((looking-at "mode .+\n")) + (t + (error "BUG: Unknown extended header: %S" + (buffer-substring (point) (line-end-position))))) + ;; These headers are treated as some sort of special hunk. + (unless (or (string-prefix-p "old mode" (match-string 0)) + (string-prefix-p "rename" (match-string 0))) + (push (match-string 0) header)) + (magit-delete-match)) + (setq header (mapconcat #'identity (nreverse header) "")) (when orig (setq orig (magit-decode-git-path orig))) (setq file (magit-decode-git-path file)) - ;; KLUDGE `git-log' ignores `--no-prefix' when `-L' is used. - (when (and (derived-mode-p 'magit-log-mode) - (--first (string-match-p "\\`-L" it) magit-buffer-log-args)) + ;; KLUDGE `git-diff' ignores `--no-prefix' for new files and renames at + ;; least. And `git-log' ignores `--no-prefix' when `-L' is used. + (when (or (and file orig + (string-prefix-p "a/" orig) + (string-prefix-p "b/" file)) + (and (derived-mode-p 'magit-log-mode) + (--first (string-match-p "\\`-L" it) + magit-buffer-log-args))) (setq file (substring file 2)) (when orig (setq orig (substring orig 2)))) - (magit-diff-insert-file-section file orig status modes header))))) + (magit-diff-insert-file-section file orig status modes rename header))))) -(defun magit-diff-insert-file-section (file orig status modes header) +(defun magit-diff-insert-file-section + (file orig status modes rename header &optional long-status) (magit-insert-section section (file file (or (equal status "deleted") (derived-mode-p 'magit-status-mode))) - (insert (propertize (format "%-10s %s\n" status + (insert (propertize (format "%-10s %s" status (if (or (not orig) (equal orig file)) file (format "%s -> %s" orig file))) 'font-lock-face 'magit-diff-file-heading)) + (when long-status + (insert (format " (%s)" long-status))) (magit-insert-heading) (unless (equal orig file) (oset section source orig)) (oset section header header) (when modes - (magit-insert-section (hunk) + (magit-insert-section (hunk '(chmod)) (insert modes) (magit-insert-heading))) + (when rename + (magit-insert-section (hunk '(rename)) + (insert rename) + (magit-insert-heading))) (magit-wash-sequence #'magit-diff-wash-hunk))) (defun magit-diff-wash-submodule () @@ -2267,7 +2387,7 @@ (when (looking-at "^@\\{2,\\} \\(.+?\\) @\\{2,\\}\\(?: \\(.*\\)\\)?") (let* ((heading (match-string 0)) (ranges (mapcar (lambda (str) - (mapcar (lambda (n) (string-to-number n)) + (mapcar #'string-to-number (split-string (substring str 1) ","))) (split-string (match-string 1)))) (about (match-string 2)) @@ -2333,18 +2453,19 @@ (magit-buffer-revision rev) (magit-buffer-range (format "%s^..%s" rev rev)) (magit-buffer-diff-args args) - (magit-buffer-diff-files files))) + (magit-buffer-diff-files files) + (magit-buffer-diff-files-suspended nil))) (defun magit-revision-refresh-buffer () + (setq magit-buffer-revision-hash (magit-rev-parse magit-buffer-revision)) (magit-set-header-line-format - (concat (capitalize (magit-object-type magit-buffer-revision)) + (concat (magit-object-type magit-buffer-revision-hash) " " magit-buffer-revision (pcase (length magit-buffer-diff-files) (0) (1 (concat " limited to file " (car magit-buffer-diff-files))) (_ (concat " limited to files " (mapconcat #'identity magit-buffer-diff-files ", ")))))) - (setq magit-buffer-revision-hash (magit-rev-parse magit-buffer-revision)) (magit-insert-section (commitbuf) (magit-run-section-hook 'magit-revision-sections-hook))) @@ -2393,8 +2514,7 @@ (re-search-forward "-----END PGP SIGNATURE-----") (delete-region beg (point))) (insert ?\n) - (process-file magit-git-executable nil t nil - "verify-tag" magit-buffer-revision)) + (magit-process-git t "verify-tag" magit-buffer-revision)) (goto-char (point-max))) (insert ?\n)))) @@ -2533,7 +2653,7 @@ (eq magit-revision-insert-related-refs 'all)) (magit--insert-related-refs magit-buffer-revision "--contains" "Contained" - (eq magit-revision-insert-related-refs '(all mixed))) + (memq magit-revision-insert-related-refs '(all mixed))) (when-let ((follows (magit-get-current-tag magit-buffer-revision t))) (let ((tag (car follows)) (cnt (cadr follows))) @@ -2590,17 +2710,18 @@ (when-let ((window (get-buffer-window))) (let* ((column (length (match-string 0))) (font-obj (query-font (font-at (point) window))) - (size (* 2 (+ (aref font-obj 4) - (aref font-obj 5)))) + (size (* 2 (aref font-obj 4))) (align-to (+ column (ceiling (/ size (aref font-obj 7) 1.0)) 1)) (gravatar-size (- size 2))) (ignore-errors ; service may be unreachable (gravatar-retrieve email 'magit-insert-revision-gravatar-cb - (list rev (point-marker) align-to column)))))))) + (list gravatar-size rev + (point-marker) + align-to column)))))))) -(defun magit-insert-revision-gravatar-cb (image rev marker align-to column) +(defun magit-insert-revision-gravatar-cb (image size rev marker align-to column) (unless (eq image 'error) (when-let ((buffer (marker-buffer marker))) (with-current-buffer buffer @@ -2614,9 +2735,11 @@ (car-safe (get-text-property (point) 'display))) 'image))) - (let ((top `((,@image :ascent center :relief 1) + (let ((top `((,@image + :ascent center :relief 1 :scale 1 :height ,size) (slice 0.0 0.0 1.0 0.5))) - (bot `((,@image :ascent center :relief 1) + (bot `((,@image + :ascent center :relief 1 :scale 1 :height ,size) (slice 0.0 0.5 1.0 1.0))) (align `((space :align-to ,align-to)))) (when magit-revision-use-gravatar-kludge @@ -2786,16 +2909,16 @@ (if (memq type '(file module)) (magit-diff-type parent) type))) - (`hunk (-> it - (oref parent) - (oref parent) - (oref type))))))) + (`hunk (thread-first it + (oref parent) + (oref parent) + (oref type))))))) ((derived-mode-p 'magit-log-mode) (if (or (and (magit-section-match 'commit section) (oref section children)) (magit-section-match [* file commit] section)) 'committed - 'undefined)) + 'undefined)) (t 'undefined)))) (cl-defun magit-diff-scope (&optional (section nil ssection) strict) @@ -2839,8 +2962,7 @@ (`(file ,_ ,_ ,_) 'file) (`(module t t nil) 'files) (`(module ,_ ,_ ,_) 'file) - (`(,(or `staged `unstaged `untracked) - nil ,_ ,_) 'list))))) + (`(,(or `staged `unstaged `untracked) nil ,_ ,_) 'list))))) (defun magit-diff-use-hunk-region-p () (and (region-active-p) @@ -3117,7 +3239,8 @@ (defun magit-diff-update-hunk-region (section) "Highlight the hunk-internal region if any." - (when (eq (magit-diff-scope section t) 'region) + (when (and (eq (oref section type) 'hunk) + (eq (magit-diff-scope section t) 'region)) (magit-diff--make-hunk-overlay (oref section start) (1- (oref section content)) @@ -3222,11 +3345,15 @@ ;;; Diff Extract -(defun magit-diff-file-header (section) +(defun magit-diff-file-header (section &optional no-rename) (when (magit-hunk-section-p section) (setq section (oref section parent))) - (when (magit-file-section-p section) - (oref section header))) + (and (magit-file-section-p section) + (let ((header (oref section header))) + (if no-rename + (replace-regexp-in-string + "^--- \\(.+\\)" (oref section value) header t t 1) + header)))) (defun magit-diff-hunk-region-header (section) (let ((patch (magit-diff-hunk-region-patch section))) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-ediff.el magit-3.3.0/lisp/magit-ediff.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-ediff.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-ediff.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-ediff.el --- Ediff extension for Magit -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -99,12 +101,18 @@ :group 'magit-ediff :type 'boolean) +(defcustom magit-ediff-use-indirect-buffers nil + "Whether to use indirect buffers." + :package-version '(magit . "3.1.0") + :group 'magit-ediff + :type 'boolean) + ;;; Commands (defvar magit-ediff-previous-winconf nil) ;;;###autoload (autoload 'magit-ediff "magit-ediff" nil) -(define-transient-command magit-ediff () +(transient-define-prefix magit-ediff () "Show differences using the Ediff package." :info-manual "(ediff)" ["Ediff" @@ -155,6 +163,45 @@ (let ((magit-ediff-previous-winconf smerge-ediff-windows)) (run-hooks 'magit-ediff-quit-hook))))))) +(defmacro magit-ediff-buffers (quit &rest spec) + (declare (indent 1)) + (let ((fn (if (= (length spec) 3) 'ediff-buffers3 'ediff-buffers)) + (char ?@) + get make kill) + (pcase-dolist (`(,g ,m) spec) + (let ((b (intern (format "buf%c" (cl-incf char))))) + (push `(,b ,g) get) + (push `(if ,b + (if magit-ediff-use-indirect-buffers + (prog1 + (make-indirect-buffer + ,b (generate-new-buffer-name (buffer-name ,b)) t) + (setq ,b nil)) + ,b) + ,m) + make) + (push `(unless ,b + (ediff-kill-buffer-carefully + ,(intern (format "ediff-buffer-%c" char)))) + kill))) + (setq get (nreverse get)) + (setq make (nreverse make)) + (setq kill (nreverse kill)) + `(magit-with-toplevel + (let ((conf (current-window-configuration)) + ,@get) + (,fn + ,@make + (list (lambda () + (setq-local + ediff-quit-hook + (list ,@(and quit (list quit)) + (lambda () + ,@kill + (let ((magit-ediff-previous-winconf conf)) + (run-hooks 'magit-ediff-quit-hook))))))) + ',fn))))) + ;;;###autoload (defun magit-ediff-stage (file) "Stage and unstage changes to FILE using Ediff. @@ -164,43 +211,34 @@ (list (magit-completing-read "Selectively stage file" files nil t nil nil (car (member (magit-current-file) files)))))) (magit-with-toplevel - (let* ((conf (current-window-configuration)) - (bufA (magit-get-revision-buffer "HEAD" file)) - (bufB (magit-get-revision-buffer "{index}" file)) - (bufBrw (and bufB (with-current-buffer bufB (not buffer-read-only)))) - (bufC (get-file-buffer file)) - (fileBufC (or bufC (find-file-noselect file))) + (let* ((bufA (magit-get-revision-buffer "HEAD" file)) + (bufB (magit-get-revision-buffer "{index}" file)) + (lockB (and bufB (buffer-local-value 'buffer-read-only bufB))) + (bufC (get-file-buffer file)) + ;; Use the same encoding for all three buffers or we + ;; may end up changing the file in an unintended way. + (bufC* (or bufC (find-file-noselect file))) (coding-system-for-read - (with-current-buffer fileBufC buffer-file-coding-system))) - (ediff-buffers3 - (or bufA (magit-find-file-noselect "HEAD" file)) - (with-current-buffer (magit-find-file-index-noselect file t) - (setq buffer-read-only nil) - (current-buffer)) - fileBufC - `((lambda () - (setq-local - ediff-quit-hook - (lambda () - (and (buffer-live-p ediff-buffer-B) - (buffer-modified-p ediff-buffer-B) - (with-current-buffer ediff-buffer-B - (magit-update-index))) - (and (buffer-live-p ediff-buffer-C) - (buffer-modified-p ediff-buffer-C) - (with-current-buffer ediff-buffer-C - (when (y-or-n-p - (format "Save file %s? " buffer-file-name)) - (save-buffer)))) - ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A))) - ,@(if bufB - (unless bufBrw '((with-current-buffer ediff-buffer-B - (setq buffer-read-only t)))) - '((ediff-kill-buffer-carefully ediff-buffer-B))) - ,@(unless bufC '((ediff-kill-buffer-carefully ediff-buffer-C))) - (let ((magit-ediff-previous-winconf ,conf)) - (run-hooks 'magit-ediff-quit-hook)))))) - 'ediff-buffers3)))) + (buffer-local-value 'buffer-file-coding-system bufC*)) + (bufA* (magit-find-file-noselect-1 "HEAD" file t)) + (bufB* (magit-find-file-index-noselect file t))) + (setf (buffer-local-value 'buffer-read-only bufB*) nil) + (magit-ediff-buffers + (lambda () + (when (buffer-live-p ediff-buffer-B) + (when lockB + (setf (buffer-local-value 'buffer-read-only bufB) t)) + (when (buffer-modified-p ediff-buffer-B) + (with-current-buffer ediff-buffer-B + (magit-update-index)))) + (when (and (buffer-live-p ediff-buffer-C) + (buffer-modified-p ediff-buffer-C)) + (with-current-buffer ediff-buffer-C + (when (y-or-n-p (format "Save file %s? " buffer-file-name)) + (save-buffer))))) + (bufA bufA*) + (bufB bufB*) + (bufC bufC*))))) ;;;###autoload (defun magit-ediff-compare (revA revB fileA fileB) @@ -220,30 +258,11 @@ nil current-prefix-arg))) (nconc (list revA revB) (magit-ediff-read-files revA revB)))) - (magit-with-toplevel - (let ((conf (current-window-configuration)) - (bufA (if revA - (magit-get-revision-buffer revA fileA) - (get-file-buffer fileA))) - (bufB (if revB - (magit-get-revision-buffer revB fileB) - (get-file-buffer fileB)))) - (ediff-buffers - (or bufA (if revA - (magit-find-file-noselect revA fileA) - (find-file-noselect fileA))) - (or bufB (if revB - (magit-find-file-noselect revB fileB) - (find-file-noselect fileB))) - `((lambda () - (setq-local - ediff-quit-hook - (lambda () - ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A))) - ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B))) - (let ((magit-ediff-previous-winconf ,conf)) - (run-hooks 'magit-ediff-quit-hook)))))) - 'ediff-revision)))) + (magit-ediff-buffers nil + ((if revA (magit-get-revision-buffer revA fileA) (get-file-buffer fileA)) + (if revA (magit-find-file-noselect revA fileA) (find-file-noselect fileA))) + ((if revB (magit-get-revision-buffer revB fileB) (get-file-buffer fileB)) + (if revB (magit-find-file-noselect revB fileB) (find-file-noselect fileB))))) (defun magit-ediff-compare--read-revisions (&optional arg mbase) (let ((input (or arg (magit-diff-read-range-or-commit @@ -358,21 +377,11 @@ (list (magit-read-file-choice "Show staged changes for file" (magit-staged-files) "No staged files"))) - (let ((conf (current-window-configuration)) - (bufA (magit-get-revision-buffer "HEAD" file)) - (bufB (get-buffer (concat file ".~{index}~")))) - (ediff-buffers - (or bufA (magit-find-file-noselect "HEAD" file)) - (or bufB (magit-find-file-index-noselect file t)) - `((lambda () - (setq-local - ediff-quit-hook - (lambda () - ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A))) - ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B))) - (let ((magit-ediff-previous-winconf ,conf)) - (run-hooks 'magit-ediff-quit-hook)))))) - 'ediff-buffers))) + (magit-ediff-buffers nil + ((magit-get-revision-buffer "HEAD" file) + (magit-find-file-noselect "HEAD" file)) + ((get-buffer (concat file ".~{index}~")) + (magit-find-file-index-noselect file t)))) ;;;###autoload (defun magit-ediff-show-unstaged (file) @@ -386,22 +395,11 @@ (list (magit-read-file-choice "Show unstaged changes for file" (magit-unstaged-files) "No unstaged files"))) - (magit-with-toplevel - (let ((conf (current-window-configuration)) - (bufA (get-buffer (concat file ".~{index}~"))) - (bufB (get-file-buffer file))) - (ediff-buffers - (or bufA (magit-find-file-index-noselect file t)) - (or bufB (find-file-noselect file)) - `((lambda () - (setq-local - ediff-quit-hook - (lambda () - ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A))) - ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B))) - (let ((magit-ediff-previous-winconf ,conf)) - (run-hooks 'magit-ediff-quit-hook)))))) - 'ediff-buffers)))) + (magit-ediff-buffers nil + ((get-buffer (concat file ".~{index}~")) + (magit-find-file-index-noselect file t)) + ((get-file-buffer file) + (find-file-noselect file)))) ;;;###autoload (defun magit-ediff-show-working-tree (file) @@ -411,22 +409,11 @@ (list (magit-read-file-choice "Show changes in file" (magit-changed-files "HEAD") "No changed files"))) - (magit-with-toplevel - (let ((conf (current-window-configuration)) - (bufA (magit-get-revision-buffer "HEAD" file)) - (bufB (get-file-buffer file))) - (ediff-buffers - (or bufA (magit-find-file-noselect "HEAD" file)) - (or bufB (find-file-noselect file)) - `((lambda () - (setq-local - ediff-quit-hook - (lambda () - ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A))) - ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B))) - (let ((magit-ediff-previous-winconf ,conf)) - (run-hooks 'magit-ediff-quit-hook)))))) - 'ediff-buffers)))) + (magit-ediff-buffers nil + ((magit-get-revision-buffer "HEAD" file) + (magit-find-file-noselect "HEAD" file)) + ((get-file-buffer file) + (find-file-noselect file)))) ;;;###autoload (defun magit-ediff-show-commit (commit) @@ -452,27 +439,13 @@ (fileB fileC)) (if (and magit-ediff-show-stash-with-index (member fileA (magit-changed-files revB revA))) - (let ((conf (current-window-configuration)) - (bufA (magit-get-revision-buffer revA fileA)) - (bufB (magit-get-revision-buffer revB fileB)) - (bufC (magit-get-revision-buffer revC fileC))) - (ediff-buffers3 - (or bufA (magit-find-file-noselect revA fileA)) - (or bufB (magit-find-file-noselect revB fileB)) - (or bufC (magit-find-file-noselect revC fileC)) - `((lambda () - (setq-local - ediff-quit-hook - (lambda () - ,@(unless bufA - '((ediff-kill-buffer-carefully ediff-buffer-A))) - ,@(unless bufB - '((ediff-kill-buffer-carefully ediff-buffer-B))) - ,@(unless bufC - '((ediff-kill-buffer-carefully ediff-buffer-C))) - (let ((magit-ediff-previous-winconf ,conf)) - (run-hooks 'magit-ediff-quit-hook)))))) - 'ediff-buffers3)) + (magit-ediff-buffers nil + ((magit-get-revision-buffer revA fileA) + (magit-find-file-noselect revA fileA)) + ((magit-get-revision-buffer revB fileB) + (magit-find-file-noselect revB fileB)) + ((magit-get-revision-buffer revC fileC) + (magit-find-file-noselect revC fileC))) (magit-ediff-compare revA revC fileA fileC)))) (defun magit-ediff-cleanup-auxiliary-buffers () diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit.el magit-3.3.0/lisp/magit.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,25 +1,27 @@ ;;; magit.el --- A Git porcelain inside Emacs -*- lexical-binding: t; coding: utf-8 -*- -;; Copyright (C) 2008-2020 The Magit Project Contributors +;; Copyright (C) 2008-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. ;; Author: Marius Vollmer +;; Jonas Bernoulli ;; Maintainer: Jonas Bernoulli -;; Kyle Meyer -;; Noam Postavsky +;; Kyle Meyer +;; Noam Postavsky ;; Former-Maintainers: -;; Nicolas Dudebout -;; Peter J. Weisberg -;; Phil Jackson -;; Rémi Vanicat -;; Yann Hodique +;; Nicolas Dudebout +;; Peter J. Weisberg +;; Phil Jackson +;; Rémi Vanicat +;; Yann Hodique ;; Keywords: git tools vc ;; Homepage: https://github.com/magit/magit - -;; Magit requires at least GNU Emacs 25.1 and Git 2.2.0. +;; Package-Requires: ((emacs "25.1") (dash "2.19.1") (git-commit "3.3.0") (magit-section "3.3.0") (transient "0.3.6") (with-editor "3.0.5")) +;; Package-Version: 3.3.0 +;; SPDX-License-Identifier: GPL-3.0-or-later ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by @@ -34,35 +36,34 @@ ;; You should have received a copy of the GNU General Public License ;; along with Magit. If not, see http://www.gnu.org/licenses. +;; Magit requires at least GNU Emacs 25.1 and Git 2.2.0. + ;;; Commentary: -;; Magit is an interface to the version control system Git, -;; implemented as an Emacs package. Magit aspires to be a complete -;; Git porcelain. While we cannot (yet) claim, that Magit wraps and -;; improves upon each and every Git command, it is complete enough to -;; allow even experienced Git users to perform almost all of their -;; daily version control tasks directly from within Emacs. While many -;; fine Git clients exist, only Magit and Git itself deserve to be -;; called porcelains. +;; Magit is a text-based Git user interface that puts an unmatched focus +;; on streamlining workflows. Commands are invoked using short mnemonic +;; key sequences that take the cursor’s position in the highly actionable +;; interface into account to provide context-sensitive behavior. + +;; With Magit you can do nearly everything that you can do when using Git +;; on the command-line, but at greater speed and while taking advantage +;; of advanced features that previously seemed too daunting to use on a +;; daily basis. Many users will find that by using Magit they can become +;; more effective Git user. ;;; Code: -(require 'cl-lib) -(require 'dash) - -(require 'subr-x) - -(require 'with-editor) -(require 'git-commit) (require 'magit-core) (require 'magit-diff) (require 'magit-log) (require 'magit-wip) (require 'magit-apply) (require 'magit-repos) +(require 'git-commit) (require 'format-spec) (require 'package nil t) ; used in `magit-version' +(require 'with-editor) (defconst magit--minimal-git "2.2.0") (defconst magit--minimal-emacs "25.1") @@ -107,8 +108,8 @@ :group 'magit-faces) (defface magit-branch-remote-head - '((((class color) (background light)) :inherit magit-branch-remote :box t) - (((class color) (background dark)) :inherit magit-branch-remote :box t)) + '((((supports (:box t))) :inherit magit-branch-remote :box t) + (t :inherit magit-branch-remote :inverse-video t)) "Face for current branch." :group 'magit-faces) @@ -119,8 +120,8 @@ :group 'magit-faces) (defface magit-branch-current - '((((class color) (background light)) :inherit magit-branch-local :box t) - (((class color) (background dark)) :inherit magit-branch-local :box t)) + '((((supports (:box t))) :inherit magit-branch-local :box t) + (t :inherit magit-branch-local :inverse-video t)) "Face for current branch." :group 'magit-faces) @@ -180,7 +181,7 @@ :group 'magit-faces) (defface magit-signature-untrusted - '((t :foreground "cyan")) + '((t :foreground "medium aquamarine")) "Face for good untrusted signatures." :group 'magit-faces) @@ -200,7 +201,7 @@ :group 'magit-faces) (defface magit-signature-error - '((t :foreground "firebrick3")) + '((t :foreground "light blue")) "Face for signatures that cannot be checked (e.g. missing key)." :group 'magit-faces) @@ -219,13 +220,86 @@ "Face for filenames." :group 'magit-faces) +;;; Global Bindings + +;;;###autoload +(define-obsolete-variable-alias 'global-magit-file-mode + 'magit-define-global-key-bindings "Magit 3.0.0") + +;;;###autoload +(defcustom magit-define-global-key-bindings t + "Whether to bind some Magit commands in the global keymap. + +If this variable is non-nil, then the following bindings may +be added to the global keymap. The default is t. + +key binding +--- ------- +C-x g magit-status +C-x M-g magit-dispatch +C-c M-g magit-file-dispatch + +These bindings may be added when `after-init-hook' is run. +Each binding is added if and only if at that time no other key +is bound to the same command and no other command is bound to +the same key. In other words we try to avoid adding bindings +that are unnecessary, as well as bindings that conflict with +other bindings. + +Adding the above bindings is delayed until `after-init-hook' +is called to allow users to set the variable anywhere in their +init file (without having to make sure to do so before `magit' +is loaded or autoloaded) and to increase the likelihood that +all the potentially conflicting user bindings have already +been added. + +To set this variable use either `setq' or the Custom interface. +Do not use the function `customize-set-variable' because doing +that would cause Magit to be loaded immediately when that form +is evaluated (this differs from `custom-set-variables', which +doesn't load the libraries that define the customized variables). + +Setting this variable to nil has no effect if that is done after +the key bindings have already been added. + +We recommend that you bind \"C-c g\" instead of \"C-c M-g\" to +`magit-file-dispatch'. The former is a much better binding +but the \"C-c \" namespace is strictly reserved for +users; preventing Magit from using it by default. + +Also see info node `(magit)Commands for Buffers Visiting Files'." + :package-version '(magit . "3.0.0") + :group 'magit-essentials + :type 'boolean) + +;;;###autoload +(progn + (defun magit-maybe-define-global-key-bindings () + (when magit-define-global-key-bindings + (let ((map (current-global-map))) + (dolist (elt '(("C-x g" . magit-status) + ("C-x M-g" . magit-dispatch) + ("C-c M-g" . magit-file-dispatch))) + (let ((key (kbd (car elt))) + (def (cdr elt))) + (unless (or (lookup-key map key) + (where-is-internal def (make-sparse-keymap) t)) + (define-key map key def))))))) + (if after-init-time + (magit-maybe-define-global-key-bindings) + (add-hook 'after-init-hook 'magit-maybe-define-global-key-bindings t))) + ;;; Dispatch Popup ;;;###autoload (autoload 'magit-dispatch "magit" nil t) -(define-transient-command magit-dispatch () +(transient-define-prefix magit-dispatch () "Invoke a Magit command from a list of available commands." + :info-manual "(magit)Top" ["Transient and dwim commands" + ;; → bound in magit-mode-map or magit-section-mode-map + ;; ↓ bound below [("A" "Apply" magit-cherry-pick) + ;; a ↓ ("b" "Branch" magit-branch) ("B" "Bisect" magit-bisect) ("c" "Commit" magit-commit) @@ -233,28 +307,51 @@ ("d" "Diff" magit-diff) ("D" "Diff (change)" magit-diff-refresh) ("e" "Ediff (dwim)" magit-ediff-dwim) - ("E" "Ediff" magit-ediff)] - [("f" "Fetch" magit-fetch) + ("E" "Ediff" magit-ediff) + ("f" "Fetch" magit-fetch) ("F" "Pull" magit-pull) + ;; g ↓ + ;; G → magit-refresh-all + ("h" "Help" magit-help) + ("H" "Section info" magit-describe-section :if-derived magit-mode)] + [("i" "Ignore" magit-gitignore) + ("I" "Init" magit-init) + ("j" "Jump to section"magit-status-jump :if-mode magit-status-mode) + ("j" "Display status" magit-status-quick :if-not-mode magit-status-mode) + ("J" "Display buffer" magit-display-repository-buffer) + ;; k ↓ + ;; K → magit-file-untrack ("l" "Log" magit-log) ("L" "Log (change)" magit-log-refresh) ("m" "Merge" magit-merge) ("M" "Remote" magit-remote) + ;; n → magit-section-forward + ;; N reserved → forge-dispatch ("o" "Submodule" magit-submodule) - ("O" "Subtree" magit-subtree)] - [("P" "Push" magit-push) - ("r" "Rebase" magit-rebase) + ("O" "Subtree" magit-subtree) + ;; p → magit-section-backward + ("P" "Push" magit-push) + ;; q → magit-mode-bury-buffer + ("Q" "Command" magit-git-command)] + [("r" "Rebase" magit-rebase) + ;; R → magit-file-rename + ;; s ↓ + ;; S ↓ ("t" "Tag" magit-tag) ("T" "Note" magit-notes) + ;; u ↓ + ;; U ↓ + ;; v ↓ ("V" "Revert" magit-revert) ("w" "Apply patches" magit-am) ("W" "Format patches" magit-patch) - ("X" "Reset" magit-reset)] - [("y" "Show Refs" magit-show-refs) + ;; x → magit-reset-quickly + ("X" "Reset" magit-reset) + ("y" "Show Refs" magit-show-refs) ("Y" "Cherries" magit-cherry) ("z" "Stash" magit-stash) - ("!" "Run" magit-run) - ("%" "Worktree" magit-worktree)]] + ("Z" "Worktree" magit-worktree) + ("!" "Run" magit-run)]] ["Applying changes" :if-derived magit-mode [("a" "Apply" magit-apply) @@ -284,7 +381,7 @@ (defvar magit-git-command-history nil) ;;;###autoload (autoload 'magit-run "magit" nil t) -(define-transient-command magit-run () +(transient-define-prefix magit-run () "Run git or another command, or launch a graphical utility." [["Run git subcommand" ("!" "in repository root" magit-git-command-topdir) @@ -350,13 +447,14 @@ (magit-process-buffer)) (defun magit-read-shell-command (&optional toplevel initial-input) - (let ((dir (abbreviate-file-name - (if (or toplevel current-prefix-arg) - (or (magit-toplevel) - (magit--not-inside-repository-error)) - default-directory)))) + (let ((default-directory + (if (or toplevel current-prefix-arg) + (or (magit-toplevel) + (magit--not-inside-repository-error)) + default-directory))) (read-shell-command (if magit-shell-command-verbose-prompt - (format "Async shell command in %s: " dir) + (format "Async shell command in %s: " + (abbreviate-file-name default-directory)) "Async shell command: ") initial-input 'magit-git-command-history))) @@ -398,9 +496,11 @@ (toplib (or load-file-name buffer-file-name)) debug) (unless (and toplib - (equal (file-name-nondirectory toplib) "magit.el")) - (setq toplib (locate-library "magit.el"))) - (setq toplib (and toplib (file-chase-links toplib))) + (member (file-name-nondirectory toplib) + '("magit.el" "magit.el.gz"))) + (let ((load-suffixes '(".el"))) + (setq toplib (locate-library "magit")))) + (setq toplib (and toplib (magit--straight-chase-links toplib))) (push toplib debug) (when toplib (let* ((topdir (file-name-directory toplib)) @@ -408,7 +508,7 @@ ".git" (file-name-directory (directory-file-name topdir)))) (static (locate-library "magit-version.el" nil (list topdir))) - (static (and static (file-chase-links static)))) + (static (and static (magit--straight-chase-links static)))) (or (progn (push 'repo debug) (when (and (file-exists-p gitdir) @@ -422,7 +522,8 @@ (ignore-errors (delete-file static))) (setq magit-version (let ((default-directory topdir)) - (magit-git-string "describe" "--tags" "--dirty"))))) + (magit-git-string "describe" + "--tags" "--dirty" "--always"))))) (progn (push 'static debug) (when (and static (file-exists-p static)) @@ -442,13 +543,35 @@ (push 'dirname debug) (let ((dirname (file-name-nondirectory (directory-file-name topdir)))) - (when (string-match "\\`magit-\\([0-9]\\{8\\}\\.[0-9]*\\)" - dirname) - (setq magit-version (match-string 1 dirname)))))))) + (when (string-match "\\`magit-\\([0-9].*\\)" dirname) + (setq magit-version (match-string 1 dirname))))) + ;; If all else fails, just report the commit hash. It's + ;; better than nothing and we cannot do better in the case + ;; of e.g. a shallow clone. + (progn + (push 'hash debug) + ;; Same check as above to see if it's really the Magit repo. + (when (and (file-exists-p gitdir) + (file-exists-p + (expand-file-name "../lisp/magit.el" gitdir))) + (setq magit-version + (let ((default-directory topdir)) + (magit-git-string "rev-parse" "HEAD")))))))) (if (stringp magit-version) (when print-dest - (princ (format "Magit %s, Git %s, Emacs %s, %s" + (princ (format "Magit %s%s, Git %s, Emacs %s, %s" (or magit-version "(unknown)") + (or (and (ignore-errors (version< "2008" magit-version)) + (ignore-errors + (require 'lisp-mnt) + (and (fboundp 'lm-header) + (format + " [>= %s]" + (with-temp-buffer + (insert-file-contents + (locate-library "magit.el" t)) + (lm-header "Package-Version")))))) + "") (or (let ((magit-git-debug (lambda (err) (display-warning '(magit git) @@ -462,7 +585,7 @@ (setq magit-version 'error) (when magit-version (push magit-version debug)) - (unless (equal (getenv "TRAVIS") "true") + (unless (equal (getenv "CI") "true") ;; The repository is a sparse clone. (message "Cannot determine Magit's version %S" debug))) magit-version)) @@ -471,11 +594,14 @@ (defun magit-debug-git-executable () "Display a buffer with information about `magit-git-executable'. +Also include information about `magit-remote-git-executable'. See info node `(magit)Debugging Tools' for more information." (interactive) (with-current-buffer (get-buffer-create "*magit-git-debug*") (pop-to-buffer (current-buffer)) (erase-buffer) + (insert (format "magit-remote-git-executable: %S\n" + magit-remote-git-executable)) (insert (concat (format "magit-git-executable: %S" magit-git-executable) (and (not (file-name-absolute-p magit-git-executable)) @@ -517,7 +643,7 @@ (let ((version (magit-git-version))) (when (and version (version< version magit--minimal-git) - (not (equal (getenv "TRAVIS") "true"))) + (not (equal (getenv "CI") "true"))) (display-warning 'magit (format "\ Magit requires Git >= %s, you are using %s. @@ -584,8 +710,8 @@ (require 'magit-imenu) (require 'magit-bookmark))) -(eval-after-load 'bookmark - '(require 'magit-bookmark)) +(with-eval-after-load 'bookmark + (require 'magit-bookmark)) (if after-init-time (progn (magit-startup-asserts) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-extras.el magit-3.3.0/lisp/magit-extras.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-extras.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-extras.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,10 +1,15 @@ ;;; magit-extras.el --- additional functionality for Magit -*- lexical-binding: t -*- -;; Copyright (C) 2008-2020 The Magit Project Contributors +;; Copyright (C) 2008-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. +;; Author: Jonas Bernoulli +;; Maintainer: Jonas Bernoulli + +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -24,15 +29,19 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) +(declare-function change-log-insert-entries "add-log" (changelogs)) +(declare-function diff-add-log-current-defuns "diff-mode" ()) (declare-function dired-read-shell-command "dired-aux" (prompt arg files)) +;; For `magit-project-status'. +(declare-function project-root "project" (project)) +(declare-function vc-git-command "vc-git" (buffer okstatus file-or-list &rest flags)) (defvar ido-exit) (defvar ido-fallback) +(defvar project-prefix-map) +(defvar project-switch-commands) (defgroup magit-extras nil "Additional functionality for Magit." @@ -56,8 +65,7 @@ (defun magit-run-git-gui () "Run `git gui' for the current git repository." (interactive) - (magit-with-toplevel - (magit-process-file magit-git-executable nil 0 nil "gui"))) + (magit-with-toplevel (magit-process-git 0 "gui"))) ;;;###autoload (defun magit-run-git-gui-blame (commit filename &optional linenum) @@ -79,10 +87,10 @@ (magit-file-relative-name buffer-file-name))) (line-number-at-pos))))) (magit-with-toplevel - (apply #'magit-process-file magit-git-executable nil 0 nil "gui" "blame" - `(,@(and linenum (list (format "--line=%d" linenum))) - ,commit - ,filename)))) + (magit-process-git 0 "gui" "blame" + (and linenum (list (format "--line=%d" linenum))) + commit + filename))) ;;;###autoload (defun magit-run-gitk () @@ -132,6 +140,30 @@ (exit-minibuffer)) ;;;###autoload +(defun magit-project-status () + "Run `magit-status' in the current project's root." + (interactive) + (magit-status-setup-buffer (project-root (project-current t)))) + +(defvar magit-bind-magit-project-status t + "Whether to bind \"m\" to `magit-project-status' in `project-prefix-map'. +If so, then an entry is added to `project-switch-commands' as +well. If you want to use another key, then you must set this +to nil before loading Magit to prevent \"m\" from being bound.") + +(with-eval-after-load 'project + ;; Only more recent versions of project.el have `project-prefix-map' and + ;; `project-switch-commands', though project.el is available in Emacs 25. + (when (and magit-bind-magit-project-status + (boundp 'project-prefix-map) + ;; Only modify if it hasn't already been modified. + (equal project-switch-commands + (eval (car (get 'project-switch-commands 'standard-value)) + t))) + (define-key project-prefix-map "m" #'magit-project-status) + (add-to-list 'project-switch-commands '(magit-project-status "Magit") t))) + +;;;###autoload (defun magit-dired-jump (&optional other-window) "Visit file at point using Dired. With a prefix argument, visit in another window. If there @@ -165,6 +197,21 @@ (magit--not-inside-repository-error))) ;;;###autoload +(defun magit-dired-am-apply-patches (repo &optional arg) + "In Dired, apply the marked (or next ARG) files as patches. +If inside a repository, then apply in that. Otherwise prompt +for a repository." + (interactive (list (or (magit-toplevel) + (magit-read-repository t)) + current-prefix-arg)) + ;; Note: The ERROR argument of `dired-get-marked-files' isn't + ;; available until Emacs 27. + (let ((files (or (dired-get-marked-files nil arg) + (user-error "No files specified")))) + (magit-status-setup-buffer repo) + (magit-am-apply-patches files))) + +;;;###autoload (defun magit-do-async-shell-command (file) "Open FILE with `dired-do-async-shell-command'. Interactively, open the file at point." @@ -250,6 +297,44 @@ ;;; ChangeLog +(defun magit-generate-changelog (&optional amending) + "Insert ChangeLog entries into the current buffer. + +The entries are generated from the diff being committed. +If prefix argument, AMENDING, is non-nil, include changes +in HEAD as well as staged changes in the diff to check." + (interactive "P") + (unless (magit-commit-message-buffer) + (user-error "No commit in progress")) + (require 'diff-mode) ; `diff-add-log-current-defuns'. + (require 'vc-git) ; `vc-git-diff'. + (require 'add-log) ; `change-log-insert-entries'. + (unless (and (fboundp 'change-log-insert-entries) + (fboundp 'diff-add-log-current-defuns)) + (user-error "`magit-generate-changelog' requires Emacs 27 or better")) + (setq default-directory + (if (and (file-regular-p "gitdir") + (not (magit-git-true "rev-parse" "--is-inside-work-tree")) + (magit-git-true "rev-parse" "--is-inside-git-dir")) + (file-name-directory (magit-file-line "gitdir")) + (magit-toplevel))) + (let ((rev1 (if amending "HEAD^1" "HEAD")) + (rev2 nil)) + ;; Magit may have updated the files without notifying vc, but + ;; `diff-add-log-current-defuns' relies on vc being up-to-date. + (mapc #'vc-file-clearprops (magit-staged-files)) + (change-log-insert-entries + (with-temp-buffer + (vc-git-command (current-buffer) 1 nil + "diff-index" "--exit-code" "--patch" + (and (magit-anything-staged-p) "--cached") + rev1 "--") + ;; `diff-find-source-location' consults these vars. + (defvar diff-vc-revisions) + (setq-local diff-vc-revisions (list rev1 rev2)) + (setq-local diff-vc-backend 'Git) + (diff-add-log-current-defuns))))) + ;;;###autoload (defun magit-add-change-log-entry (&optional whoami file-name other-window) "Find change log file and add date entry and item for current change. @@ -348,8 +433,15 @@ ;;; Reshelve +(defcustom magit-reshelve-since-committer-only nil + "Whether `magit-reshelve-since' changes only the committer dates. +Otherwise the author dates are also changed." + :package-version '(magit . "3.0.0") + :group 'magit-commands + :type 'boolean) + ;;;###autoload -(defun magit-reshelve-since (rev) +(defun magit-reshelve-since (rev keyid) "Change the author and committer dates of the commits since REV. Ask the user for the first reachable commit whose dates should @@ -359,53 +451,71 @@ on. This command is only intended for interactive use and should only -be used on highly rearranged and unpublished history." - (interactive (list nil)) - (cond - ((not rev) - (let ((backup (concat "refs/original/refs/heads/" - (magit-get-current-branch)))) +be used on highly rearranged and unpublished history. + +If KEYID is non-nil, then use that to sign all reshelved commits. +Interactively use the value of the \"--gpg-sign\" option in the +list returned by `magit-rebase-arguments'." + (interactive (list nil + (transient-arg-value "--gpg-sign=" + (magit-rebase-arguments)))) + (let* ((current (or (magit-get-current-branch) + (user-error "Refusing to reshelve detached head"))) + (backup (concat "refs/original/refs/heads/" current))) + (cond + ((not rev) (when (and (magit-ref-p backup) (not (magit-y-or-n-p - "Backup ref %s already exists. Override? " backup))) - (user-error "Abort"))) - (magit-log-select 'magit-reshelve-since - "Type %p on a commit to reshelve it and the commits above it,")) - (t - (cl-flet ((adjust (time offset) - (format-time-string - "%F %T %z" - (+ (floor time) - (* offset 60) - (- (car (decode-time time))))))) - (let* ((start (concat rev "^")) - (range (concat start ".." (magit-get-current-branch))) - (time-rev (adjust (float-time (string-to-number - (magit-rev-format "%at" start))) - 1)) - (time-now (adjust (float-time) - (- (string-to-number - (magit-git-string "rev-list" "--count" - range)))))) - (push time-rev magit--reshelve-history) - (let ((date (floor - (float-time - (date-to-time - (read-string "Date for first commit: " - time-now 'magit--reshelve-history)))))) - (magit-with-toplevel - (magit-run-git-async - "filter-branch" "--force" "--env-filter" - (format "case $GIT_COMMIT in %s\nesac" - (mapconcat (lambda (rev) - (prog1 (format "%s) \ -export GIT_AUTHOR_DATE=\"%s\"; \ -export GIT_COMMITTER_DATE=\"%s\";;" rev date date) - (cl-incf date 60))) - (magit-git-lines "rev-list" "--reverse" - range) - " ")) - range "--") + (format "Backup ref %s already exists. Override? " backup)))) + (user-error "Abort")) + (magit-log-select + (lambda (rev) + (magit-reshelve-since rev keyid)) + "Type %p on a commit to reshelve it and the commits above it,")) + (t + (cl-flet ((adjust (time offset) + (format-time-string + "%F %T %z" + (+ (floor time) + (* offset 60) + (- (car (decode-time time))))))) + (let* ((start (concat rev "^")) + (range (concat start ".." current)) + (time-rev (adjust (float-time (string-to-number + (magit-rev-format "%at" start))) + 1)) + (time-now (adjust (float-time) + (- (string-to-number + (magit-git-string "rev-list" "--count" + range)))))) + (push time-rev magit--reshelve-history) + (let ((date (floor + (float-time + (date-to-time + (read-string "Date for first commit: " + time-now 'magit--reshelve-history))))) + (process-environment process-environment)) + (push "FILTER_BRANCH_SQUELCH_WARNING=1" process-environment) + (magit-with-toplevel + (magit-run-git-async + "filter-branch" "--force" "--env-filter" + (format + "case $GIT_COMMIT in %s\nesac" + (mapconcat + (lambda (rev) + (prog1 (concat + (format "%s) " rev) + (and (not magit-reshelve-since-committer-only) + (format "export GIT_AUTHOR_DATE=\"%s\"; " date)) + (format "export GIT_COMMITTER_DATE=\"%s\";;" date)) + (cl-incf date 60))) + (magit-git-lines "rev-list" "--reverse" range) + " ")) + (and keyid + (list "--commit-filter" + (format "git commit-tree --gpg-sign=%s \"$@\";" + keyid))) + range "--")) (set-process-sentinel magit-this-process (lambda (process event) @@ -414,16 +524,16 @@ (magit-process-sentinel process event) (process-put process 'inhibit-refresh t) (magit-process-sentinel process event) - (magit-run-git "update-ref" "-d" - (concat "refs/original/refs/heads/" - (magit-get-current-branch)))))))))))))) + (magit-run-git "update-ref" "-d" backup)))))))))))) ;;; Revision Stack (defvar magit-revision-stack nil) (defcustom magit-pop-revision-stack-format - '("[%N: %h] " "%N: %H\n %s\n" "\\[\\([0-9]+\\)[]:]") + '("[%N: %h] " + "%N: %cs %H\n %s\n" + "\\[\\([0-9]+\\)[]:]") "Control how `magit-pop-revision-stack' inserts a revision. The command `magit-pop-revision-stack' inserts a representation @@ -454,7 +564,7 @@ expansion of EOB-FORMAT is inserted at the end of the buffer (if the buffer ends with a comment, then it is inserted right before that)." - :package-version '(magit . "2.3.0") + :package-version '(magit . "3.2.0") :group 'magit-commands :type '(list (choice (string :tag "Insert at point format") (cons (string :tag "Insert at point format") @@ -554,7 +664,7 @@ (kbd "C-c C-w") 'magit-pop-revision-stack) ;;;###autoload -(defun magit-copy-section-value () +(defun magit-copy-section-value (arg) "Save the value of the current section for later use. Save the section value to the `kill-ring', and, provided that @@ -572,18 +682,24 @@ When the region is active, then save that to the `kill-ring', like `kill-ring-save' would, instead of behaving as described -above. If a prefix argument is used and the region is within a -hunk, strip the outer diff marker column." - (interactive) +above. If a prefix argument is used and the region is within +a hunk, then strip the diff marker column and keep only either +the added or removed lines, depending on the sign of the prefix +argument." + (interactive "P") (cond - ((and current-prefix-arg + ((and arg (magit-section-internal-region-p) (magit-section-match 'hunk)) - (deactivate-mark) - (kill-new (replace-regexp-in-string - "^[ \\+\\-]" "" - (buffer-substring-no-properties - (region-beginning) (region-end))))) + (kill-new + (thread-last (buffer-substring-no-properties + (region-beginning) + (region-end)) + (replace-regexp-in-string + (format "^\\%c.*\n?" (if (< (prefix-numeric-value arg) 0) ?+ ?-)) + "") + (replace-regexp-in-string "^[ \\+\\-]" ""))) + (deactivate-mark)) ((use-region-p) (call-interactively #'copy-region-as-kill)) (t @@ -652,6 +768,55 @@ (push (list rev default-directory) magit-revision-stack) (kill-new (message "%s" rev)))))) +;;; Buffer Switching + +;;;###autoload +(defun magit-display-repository-buffer (buffer) + "Display a Magit buffer belonging to the current Git repository. +The buffer is displayed using `magit-display-buffer', which see." + (interactive (list (magit--read-repository-buffer + "Display magit buffer: "))) + (magit-display-buffer buffer)) + +;;;###autoload +(defun magit-switch-to-repository-buffer (buffer) + "Switch to a Magit buffer belonging to the current Git repository." + (interactive (list (magit--read-repository-buffer + "Switch to magit buffer: "))) + (switch-to-buffer buffer)) + +;;;###autoload +(defun magit-switch-to-repository-buffer-other-window (buffer) + "Switch to a Magit buffer belonging to the current Git repository." + (interactive (list (magit--read-repository-buffer + "Switch to magit buffer in another window: "))) + (switch-to-buffer-other-window buffer)) + +;;;###autoload +(defun magit-switch-to-repository-buffer-other-frame (buffer) + "Switch to a Magit buffer belonging to the current Git repository." + (interactive (list (magit--read-repository-buffer + "Switch to magit buffer in another frame: "))) + (switch-to-buffer-other-frame buffer)) + +(defun magit--read-repository-buffer (prompt) + (if-let ((topdir (magit-rev-parse-safe "--show-toplevel"))) + (read-buffer + prompt (magit-get-mode-buffer 'magit-status-mode) t + (pcase-lambda (`(,_ . ,buf)) + (and buf + (with-current-buffer buf + (and (or (derived-mode-p 'magit-mode + 'magit-repolist-mode + 'magit-submodule-list-mode + 'git-rebase-mode) + (and buffer-file-name + (string-match-p git-commit-filename-regexp + buffer-file-name))) + (equal (magit-rev-parse-safe "--show-toplevel") + topdir)))))) + (user-error "Not inside a Git repository"))) + ;;; Miscellaneous ;;;###autoload diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-fetch.el magit-3.3.0/lisp/magit-fetch.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-fetch.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-fetch.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-fetch.el --- download objects and refs -*- lexical-binding: t -*- -;; Copyright (C) 2008-2020 The Magit Project Contributors +;; Copyright (C) 2008-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -41,12 +43,13 @@ ;;; Commands ;;;###autoload (autoload 'magit-fetch "magit-fetch" nil t) -(define-transient-command magit-fetch () +(transient-define-prefix magit-fetch () "Fetch from another repository." :man-page "git-fetch" ["Arguments" ("-p" "Prune deleted branches" ("-p" "--prune")) - ("-t" "Fetch all tags" ("-t" "--tags"))] + ("-t" "Fetch all tags" ("-t" "--tags")) + (7 "-u" "Fetch full history" "--unshallow")] ["Fetch from" ("p" magit-fetch-from-pushremote) ("u" magit-fetch-from-upstream) @@ -67,7 +70,7 @@ (magit-run-git-async "fetch" remote args)) ;;;###autoload (autoload 'magit-fetch-from-pushremote "magit-fetch" nil t) -(define-suffix-command magit-fetch-from-pushremote (args) +(transient-define-suffix magit-fetch-from-pushremote (args) "Fetch from the current push-remote. With a prefix argument or when the push-remote is either not @@ -96,7 +99,7 @@ (format "%s, setting that" v))))) ;;;###autoload (autoload 'magit-fetch-from-upstream "magit-fetch" nil t) -(define-suffix-command magit-fetch-from-upstream (remote args) +(transient-define-suffix magit-fetch-from-upstream (remote args) "Fetch from the \"current\" remote, usually the upstream. If the upstream is configured for the current branch and names diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-files.el magit-3.3.0/lisp/magit-files.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-files.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-files.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-files.el --- finding files -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -30,9 +32,6 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) ;;; Find Blob @@ -206,21 +205,25 @@ (unless (equal magit-buffer-refname "{index}") (user-error "%s isn't visiting the index" file)) (if (y-or-n-p (format "Update index with contents of %s" (buffer-name))) - (let ((index (make-temp-file "index")) + (let ((index (make-temp-name (magit-git-dir "magit-update-index-"))) (buffer (current-buffer))) (when magit-wip-before-change-mode (magit-wip-commit-before-change (list file) " before un-/stage")) - (let ((coding-system-for-write buffer-file-coding-system)) - (with-temp-file index - (insert-buffer-substring buffer))) - (magit-with-toplevel - (magit-call-git "update-index" "--cacheinfo" - (substring (magit-git-string "ls-files" "-s" file) - 0 6) - (magit-git-string "hash-object" "-t" "blob" "-w" - (concat "--path=" file) - "--" index) - file)) + (unwind-protect + (progn + (let ((coding-system-for-write buffer-file-coding-system)) + (with-temp-file index + (insert-buffer-substring buffer))) + (magit-with-toplevel + (magit-call-git + "update-index" "--cacheinfo" + (substring (magit-git-string "ls-files" "-s" file) + 0 6) + (magit-git-string "hash-object" "-t" "blob" "-w" + (concat "--path=" file) + "--" (magit-convert-filename-for-git index)) + file))) + (ignore-errors (delete-file index))) (set-buffer-modified-p nil) (when magit-wip-after-apply-mode (magit-wip-commit-after-apply (list file) " after un-/stage"))) @@ -248,7 +251,7 @@ (find-file filename wildcards)) (defun magit-find-git-config-file-other-window (filename &optional wildcards) - "Edit a file located in the current repository's git directory, in another window. + "Edit a file located in the current repo's git directory, in another window. When \".git\", located at the root of the working tree, is a regular file, then that makes it cumbersome to open a file @@ -264,7 +267,7 @@ (find-file-other-window filename wildcards)) (defun magit-find-git-config-file-other-frame (filename &optional wildcards) - "Edit a file located in the current repository's git directory, in another frame. + "Edit a file located in the current repo's git directory, in another frame. When \".git\", located at the root of the working tree, is a regular file, then that makes it cumbersome to open a file @@ -279,19 +282,13 @@ (confirm-nonexistent-file-or-buffer)))) (find-file-other-frame filename wildcards)) -;;; File Mode - -(defvar magit-file-mode-map - (let ((map (make-sparse-keymap))) - (define-key map "\C-xg" 'magit-status) - (define-key map "\C-x\M-g" 'magit-dispatch) - (define-key map "\C-c\M-g" 'magit-file-dispatch) - map) - "Keymap for `magit-file-mode'.") +;;; File Dispatch ;;;###autoload (autoload 'magit-file-dispatch "magit" nil t) -(define-transient-command magit-file-dispatch () - "Invoke a Magit command that acts on the visited file." +(transient-define-prefix magit-file-dispatch () + "Invoke a Magit command that acts on the visited file. +When invoked outside a file-visiting buffer, then fall back +to `magit-dispatch'." :info-manual "(magit) Minor Mode for Buffers Visiting Files" ["Actions" [("s" "Stage" magit-stage-file) @@ -303,7 +300,8 @@ ("g" "Status" magit-status-here)] [("L" "Log..." magit-log) ("l" "Log" magit-log-buffer-file) - ("t" "Trace" magit-log-trace-definition)] + ("t" "Trace" magit-log-trace-definition) + (7 "M" "Merged" magit-log-merged)] [("B" "Blame..." magit-blame) ("b" "Blame" magit-blame-addition) ("r" "...removal" magit-blame-removal) @@ -317,39 +315,12 @@ [(5 "C-c r" "Rename file" magit-file-rename) (5 "C-c d" "Delete file" magit-file-delete) (5 "C-c u" "Untrack file" magit-file-untrack) - (5 "C-c c" "Checkout file" magit-file-checkout)]]) - -(defvar magit-file-mode-lighter "") - -(define-minor-mode magit-file-mode - "Enable some Magit features in a file-visiting buffer. - -Currently this only adds the following key bindings. -\n\\{magit-file-mode-map}" - :package-version '(magit . "2.2.0") - :lighter magit-file-mode-lighter - :keymap magit-file-mode-map) - -(defun magit-file-mode-turn-on () - (and buffer-file-name - (magit-inside-worktree-p t) - (magit-file-mode))) - -;;;###autoload -(define-globalized-minor-mode global-magit-file-mode - magit-file-mode magit-file-mode-turn-on - :package-version '(magit . "2.13.0") - :link '(info-link "(magit)Minor Mode for Buffers Visiting Files") - :group 'magit-essentials - :group 'magit-modes - :init-value t) -;; Unfortunately `:init-value t' only sets the value of the mode -;; variable but does not cause the mode function to be called, and we -;; cannot use `:initialize' to call that explicitly because the option -;; is defined before the functions, so we have to do it here. -(cl-eval-when (load eval) - (when global-magit-file-mode - (global-magit-file-mode 1))) + (5 "C-c c" "Checkout file" magit-file-checkout)]] + (interactive) + (transient-setup + (if (magit-file-relative-name) + 'magit-file-dispatch + 'magit-dispatch))) ;;; Blob Mode @@ -430,20 +401,27 @@ ;;; File Commands (defun magit-file-rename (file newname) - "Rename the FILE to NEWNAME. -If FILE isn't tracked in Git, fallback to using `rename-file'." + "Rename or move FILE to NEWNAME. +NEWNAME may be a file or directory name. If FILE isn't tracked in +Git, fallback to using `rename-file'." (interactive (let* ((file (magit-read-file "Rename file")) (dir (file-name-directory file)) - (newname (read-file-name (format "Rename %s to file: " file) + (newname (read-file-name (format "Move %s to destination: " file) (and dir (expand-file-name dir))))) (list (expand-file-name file (magit-toplevel)) (expand-file-name newname)))) - (let ((oldbuf (get-file-buffer file))) + (let ((oldbuf (get-file-buffer file)) + (dstdir (file-name-directory newname)) + (dstfile (if (directory-name-p newname) + (concat newname (file-name-nondirectory file)) + newname))) (when (and oldbuf (buffer-modified-p oldbuf)) (user-error "Save %s before moving it" file)) - (when (file-exists-p newname) - (user-error "%s already exists" newname)) + (when (file-exists-p dstfile) + (user-error "%s already exists" dstfile)) + (unless (file-exists-p dstdir) + (user-error "Destination directory %s does not exist" dstdir)) (if (magit-file-tracked-p (magit-convert-filename-for-git file)) (magit-call-git "mv" (magit-convert-filename-for-git file) @@ -452,7 +430,7 @@ (when oldbuf (with-current-buffer oldbuf (let ((buffer-read-only buffer-read-only)) - (set-visited-file-name newname nil t)) + (set-visited-file-name dstfile nil t)) (if (fboundp 'vc-refresh-state) (vc-refresh-state) (with-no-warnings diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-git.el magit-3.3.0/lisp/magit-git.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-git.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-git.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-git.el --- Git functionality -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -27,12 +29,6 @@ ;;; Code: -(require 'cl-lib) -(require 'dash) - -(eval-when-compile - (require 'subr-x)) - (require 'magit-utils) (require 'magit-section) @@ -58,6 +54,7 @@ (declare-function magit-call-git "magit-process" (&rest args)) (declare-function magit-process-buffer "magit-process" (&optional nodisplay)) (declare-function magit-process-file "magit-process" (&rest args)) +(declare-function magit-process-git "magit-process" (destination &rest args)) (declare-function magit-process-insert-section "magit-process" (pwd program args &optional errcode errlog)) (defvar magit-this-error) @@ -66,7 +63,12 @@ ;; From later in `magit-git'. (defvar magit-tramp-process-environment nil) +;; From `magit-blame'. +(declare-function magit-current-blame-chunk "magit-blame" + (&optional type noerror)) + (eval-when-compile + (cl-pushnew 'orig-rev eieio--known-slot-names) (cl-pushnew 'number eieio--known-slot-names)) ;;; Git implementations @@ -74,12 +76,12 @@ (defvar magit-inhibit-libgit nil "Whether to inhibit the use of libgit.") -(defvar magit--libgit-available-p eieio-unbound +(defvar magit--libgit-available-p 'unknown "Whether libgit is available. Use the function by the same name instead of this variable.") (defun magit--libgit-available-p () - (if (eq magit--libgit-available-p eieio-unbound) + (if (eq magit--libgit-available-p 'unknown) (setq magit--libgit-available-p (and module-file-suffix (let ((libgit (locate-library "libgit"))) @@ -131,12 +133,9 @@ successfully.") (defcustom magit-git-executable - ;; Git might be installed in a different location on a remote, so - ;; it is better not to use the full path to the executable, except - ;; on Window were we would otherwise end up using one one of the - ;; wrappers "cmd/git.exe" or "cmd/git.cmd", which are much slower - ;; than using "bin/git.exe" directly. (or (and (eq system-type 'windows-nt) + ;; Avoid the wrappers "cmd/git.exe" and "cmd/git.cmd", + ;; which are much slower than using "bin/git.exe" directly. (--when-let (executable-find "git") (ignore-errors ;; Git for Windows 2.x provides cygpath so we can @@ -163,8 +162,21 @@ (setcdr hack-entry path-hack) (push (cons core-exe path-hack) magit-git-w32-path-hack)) core-exe)))) + (and (eq system-type 'darwin) + (executable-find "git")) "git") - "The Git executable used by Magit." + "The Git executable used by Magit on the local host. +On remote machines `magit-remote-git-executable' is used instead." + :package-version '(magit . "3.2.0") + :group 'magit-process + :type 'string) + +(defcustom magit-remote-git-executable "git" + "The Git executable used by Magit on remote machines. +On the local host `magit-git-executable' is used instead. +Consider customizing `tramp-remote-path' instead of this +option." + :package-version '(magit . "3.2.0") :group 'magit-process :type 'string) @@ -210,8 +222,9 @@ then at least its standard error is inserted into this buffer. This is only intended for debugging purposes. Do not enable this -permanently, that would negatively affect performance.") +permanently, that would negatively affect performance. +Also see `magit-process-extreme-logging'.") (defcustom magit-prefer-remote-upstream nil "Whether to favor remote branches when reading the upstream branch. @@ -227,6 +240,20 @@ :group 'magit-commands :type 'boolean) +(defcustom magit-list-refs-namespaces + '("refs/heads" + "refs/remotes" + "refs/tags" + "refs/pullreqs") + "List of ref namespaces considered when reading a ref. + +This controls the order of refs returned by `magit-list-refs', +which is called by functions like `magit-list-branch-names' to +generate the collection of refs." + :package-version '(magit . "3.1.0") + :group 'magit-commands + :type '(repeat string)) + (defcustom magit-list-refs-sortby nil "How to sort the ref collection in the prompt. @@ -297,6 +324,27 @@ (with-editor* magit-with-editor-envvar ,@body))) +(defmacro magit--with-temp-process-buffer (&rest body) + "Like `with-temp-buffer', but always propagate `process-environment'. +When that var is buffer-local in the calling buffer, it is not +propagated by `with-temp-buffer', so we explicitly ensure that +happens, so that processes will be invoked consistently. BODY is +as for that macro." + (declare (indent 0) (debug (body))) + (let ((p (cl-gensym))) + `(let ((,p process-environment)) + (with-temp-buffer + (setq-local process-environment ,p) + ,@body)))) + +(defsubst magit-git-executable () + "Return value of `magit-git-executable' or `magit-remote-git-executable'. +The variable is chosen depending on whether `default-directory' +is remote." + (if (file-remote-p default-directory) + magit-remote-git-executable + magit-git-executable)) + (defun magit-process-git-arguments (args) "Prepare ARGS for a function that invokes Git. @@ -319,8 +367,7 @@ (defun magit-git-exit-code (&rest args) "Execute Git with ARGS, returning its exit code." - (apply #'magit-process-file magit-git-executable nil nil nil - (magit-process-git-arguments args))) + (magit-process-git nil args)) (defun magit-git-success (&rest args) "Execute Git with ARGS, returning t if its exit code is 0." @@ -339,9 +386,8 @@ This is an experimental replacement for `magit-git-string', and still subject to major changes." (magit--with-refresh-cache (cons default-directory args) - (with-temp-buffer - (and (zerop (apply #'magit-process-file magit-git-executable nil t nil - (magit-process-git-arguments args))) + (magit--with-temp-process-buffer + (and (zerop (magit-process-git t args)) (not (bobp)) (progn (goto-char (point-min)) @@ -359,10 +405,9 @@ still subject to major changes. Also see `magit-git-string-p'." (magit--with-refresh-cache (list default-directory 'magit-git-string-ng args) - (with-temp-buffer + (magit--with-temp-process-buffer (let* ((args (magit-process-git-arguments args)) - (status (apply #'magit-process-file magit-git-executable - nil t nil args))) + (status (magit-process-git t args))) (if (zerop status) (and (not (bobp)) (progn @@ -387,9 +432,8 @@ ignore `magit-git-debug'." (setq args (-flatten args)) (magit--with-refresh-cache (cons default-directory args) - (with-temp-buffer - (apply #'magit-process-file magit-git-executable nil (list t nil) nil - (magit-process-git-arguments args)) + (magit--with-temp-process-buffer + (magit-process-git (list t nil) args) (unless (bobp) (goto-char (point-min)) (buffer-substring-no-properties (point) (line-end-position)))))) @@ -398,9 +442,8 @@ "Execute Git with ARGS, returning its output." (setq args (-flatten args)) (magit--with-refresh-cache (cons default-directory args) - (with-temp-buffer - (apply #'magit-process-file magit-git-executable nil (list t nil) nil - (magit-process-git-arguments args)) + (magit--with-temp-process-buffer + (magit-process-git (list t nil) args) (buffer-substring-no-properties (point-min) (point-max))))) (define-error 'magit-invalid-git-boolean "Not a Git boolean") @@ -412,7 +455,7 @@ (pcase (magit-git-output args) ((or "true" "true\n") t) ((or "false" "false\n") nil) - (output (signal 'magit-invalid-git-boolean output)))) + (output (signal 'magit-invalid-git-boolean (list output))))) (defun magit-git-false (&rest args) "Execute Git with ARGS, returning t if it prints \"false\". @@ -421,7 +464,22 @@ (pcase (magit-git-output args) ((or "true" "true\n") nil) ((or "false" "false\n") t) - (output (signal 'magit-invalid-git-boolean output)))) + (output (signal 'magit-invalid-git-boolean (list output))))) + +(defun magit-git-config-p (variable &optional default) + "Return the boolean value of the Git variable VARIABLE. +VARIABLE has to be specified as a string. Return DEFAULT (which +defaults to nil) if VARIABLE is unset. If VARIABLE's value isn't +a boolean, then raise an error." + (let ((args (list "config" "--bool" "--default" (if default "true" "false") + variable))) + (magit--with-refresh-cache (cons default-directory args) + (magit--with-temp-process-buffer + (let ((status (magit-process-git t args)) + (output (buffer-substring (point-min) (1- (point-max))))) + (if (zerop status) + (equal output "true") + (signal 'magit-invalid-git-boolean (list output)))))))) (defun magit-git-insert (&rest args) "Execute Git with ARGS, inserting its output at point. @@ -434,8 +492,7 @@ (progn (setq log (make-temp-file "magit-stderr")) (delete-file log) - (let ((exit (apply #'magit-process-file magit-git-executable - nil (list t log) nil args))) + (let ((exit (magit-process-git (list t log) args))) (when (> exit 0) (let ((msg "Git failed")) (when (file-exists-p log) @@ -453,8 +510,7 @@ (message "%s" msg))) exit)) (ignore-errors (delete-file log)))) - (apply #'magit-process-file magit-git-executable - nil (list t nil) nil args))) + (magit-process-git (list t nil) args))) (defun magit--locate-error-message () (goto-char (point-max)) @@ -468,7 +524,7 @@ newline, return an empty string." (setq args (-flatten args)) (magit--with-refresh-cache (cons default-directory args) - (with-temp-buffer + (magit--with-temp-process-buffer (apply #'magit-git-insert args) (unless (bobp) (goto-char (point-min)) @@ -480,7 +536,7 @@ If Git exits with a non-zero exit status, then report show a message and add a section in the respective process buffer." - (with-temp-buffer + (magit--with-temp-process-buffer (apply #'magit-git-insert args) (split-string (buffer-string) "\n" t))) @@ -490,7 +546,7 @@ If Git exits with a non-zero exit status, then report show a message and add a section in the respective process buffer." - (with-temp-buffer + (magit--with-temp-process-buffer (apply #'magit-git-insert args) (split-string (buffer-string) "\0" t))) @@ -529,8 +585,8 @@ (gethash ;; `git config --list' downcases first and last components of the key. (--> key - (replace-regexp-in-string "\\`[^.]+" #'downcase it t t) - (replace-regexp-in-string "[^.]+\\'" #'downcase it t t)) + (replace-regexp-in-string "\\`[^.]+" #'downcase it t t) + (replace-regexp-in-string "[^.]+\\'" #'downcase it t t)) (magit--with-refresh-cache (cons (magit-toplevel) 'config) (let ((configs (make-hash-table :test 'equal))) (dolist (conf (magit-git-items "config" "--list" "-z")) @@ -556,11 +612,13 @@ (magit-git-items "config" arg "-z" "--get-all" key)))) (defun magit-get-boolean (&rest keys) - "Return the boolean value of the Git variable specified by KEYS." + "Return the boolean value of the Git variable specified by KEYS. +Also see `magit-git-config-p'." (let ((key (mapconcat 'identity keys "."))) - (if magit--refresh-cache - (equal "true" (car (last (magit-config-get-from-cached-list key)))) - (equal (magit-git-str "config" "--bool" key) "true")))) + (equal (if magit--refresh-cache + (car (last (magit-config-get-from-cached-list key))) + (magit-git-str "config" "--bool" key)) + "true"))) (defun magit-set (value &rest keys) "Set the value of the Git variable specified by KEYS to VALUE." @@ -719,7 +777,8 @@ ;; Git bug. See #2364. (not (equal wtree ".git"))) ;; Return the linked working tree. - (file-name-directory wtree)) + (concat (file-remote-p default-directory) + (file-name-directory wtree))) ;; The working directory may not be the parent directory of ;; .git if it was set up with `git init --separate-git-dir'. ;; See #2955. @@ -738,13 +797,27 @@ (magit--not-inside-repository-error))))) (define-error 'magit-outside-git-repo "Not inside Git repository") +(define-error 'magit-corrupt-git-config "Corrupt Git configuration") (define-error 'magit-git-executable-not-found "Git executable cannot be found (see https://magit.vc/goto/e6a78ed2)") +(defun magit--assert-usable-git () + (if (not (executable-find (magit-git-executable))) + (signal 'magit-git-executable-not-found (magit-git-executable)) + (let ((magit-git-debug + (lambda (err) + (signal 'magit-corrupt-git-config + (format "%s: %s" default-directory err))))) + ;; This should always succeed unless there's a corrupt config + ;; (or at least a similarly severe failing state). Note that + ;; git-config's --default is avoided because it's not available + ;; until Git 2.18. + (magit-git-string "config" "--get-color" "" "reset")) + nil)) + (defun magit--not-inside-repository-error () - (if (executable-find magit-git-executable) - (signal 'magit-outside-git-repo default-directory) - (signal 'magit-git-executable-not-found magit-git-executable))) + (magit--assert-usable-git) + (signal 'magit-outside-git-repo default-directory)) (defun magit-inside-gitdir-p (&optional noerror) "Return t if `default-directory' is below the repository directory. @@ -893,7 +966,7 @@ revA revB)))) (defun magit-file-status (&rest args) - (with-temp-buffer + (magit--with-temp-process-buffer (save-excursion (magit-git-insert "status" "-z" args)) (let ((pos (point)) status) (while (> (skip-chars-forward "[:print:]") 0) @@ -945,15 +1018,18 @@ (defun magit-convert-filename-for-git (filename) "Convert FILENAME so that it can be passed to git. -1. If it's a remote filename, then remove the remote part. -2. Deal with an `windows-nt' Emacs vs. Cygwin Git incompatibility." +1. If it's a absolute filename, then pass through `expand-file-name' + to replace things such as \"~/\" that Git does not understand. +2. If it's a remote filename, then remove the remote part. +3. Deal with an `windows-nt' Emacs vs. Cygwin Git incompatibility." (if (file-name-absolute-p filename) (-if-let ((cyg . win) (cl-rassoc filename magit-cygwin-mount-points :test (lambda (f win) (string-prefix-p win f)))) (concat cyg (substring filename (length win))) - (or (file-remote-p filename 'localname) - filename)) + (expand-file-name + (or (file-remote-p filename 'localname) + filename))) filename)) (defun magit-decode-git-path (path) @@ -1177,9 +1253,11 @@ (substring it 8)))) (defun magit-name-tag (rev &optional lax) - (--when-let (magit-rev-name rev "refs/tags/*") - (and (or lax (not (string-match-p "[~^]" it))) - (substring it 5)))) + (when-let ((name (magit-rev-name rev "refs/tags/*"))) + (when (string-suffix-p "^0" name) + (setq name (substring name 0 -2))) + (and (or lax (not (string-match-p "[~^]" name))) + (substring name 5)))) (defun magit-ref-abbrev (refname) "Return an unambiguous abbreviation of REFNAME." @@ -1233,7 +1311,7 @@ (magit-ref-equal a b))))) (defun magit-headish () - "Return \"HEAD\" or if that doesn't exist the hash of the empty tree." + "Return the `HEAD' or if that doesn't exist the hash of the empty tree." (if (magit-no-commit-p) (magit-git-string "mktree") "HEAD")) @@ -1275,15 +1353,16 @@ (defun magit-commit-at-point () (or (magit-section-value-if 'commit) + (thing-at-point 'git-revision t) + (when-let ((chunk (magit-current-blame-chunk 'addition t))) + (oref chunk orig-rev)) (and (derived-mode-p 'magit-stash-mode 'magit-merge-preview-mode 'magit-revision-mode) magit-buffer-revision))) (defun magit-branch-or-commit-at-point () - (or (and magit-buffer-file-name - magit-buffer-refname) - (magit-section-case + (or (magit-section-case (branch (magit-ref-maybe-qualify (oref it value))) (commit (or (magit--painted-branch-at-point) (let ((rev (oref it value))) @@ -1295,6 +1374,10 @@ (magit-ref-p (format "refs/pullreqs/%s" (oref (oref it value) number)))))) (thing-at-point 'git-revision t) + (when-let ((chunk (magit-current-blame-chunk 'addition t))) + (oref chunk orig-rev)) + (and magit-buffer-file-name + magit-buffer-refname) (and (derived-mode-p 'magit-stash-mode 'magit-merge-preview-mode 'magit-revision-mode) @@ -1372,12 +1455,13 @@ then return nil. I.e. return the name of an existing local or remote-tracking branch. The returned string is colorized according to the branch type." - (when-let ((branch (or branch (magit-get-current-branch))) - (upstream (magit-ref-abbrev (concat branch "@{upstream}")))) - (magit--propertize-face - upstream (if (equal (magit-get "branch" branch "remote") ".") - 'magit-branch-local - 'magit-branch-remote)))) + (magit--with-refresh-cache (list 'magit-get-upstream-branch branch) + (when-let ((branch (or branch (magit-get-current-branch))) + (upstream (magit-ref-abbrev (concat branch "@{upstream}")))) + (magit--propertize-face + upstream (if (equal (magit-get "branch" branch "remote") ".") + 'magit-branch-local + 'magit-branch-remote))))) (defun magit-get-indirect-upstream-branch (branch &optional force) (let ((remote (magit-get "branch" branch "remote"))) @@ -1430,7 +1514,7 @@ (when-let ((remotes (magit-list-remotes)) (remote (if (= (length remotes) 1) (car remotes) - (car (member "origin" remotes))))) + (magit-primary-remote)))) (magit--propertize-face remote 'magit-branch-remote)))) (defun magit-get-push-remote (&optional branch) @@ -1441,12 +1525,13 @@ (magit--propertize-face remote 'magit-branch-remote))) (defun magit-get-push-branch (&optional branch verify) - (when-let ((branch (or branch (setq branch (magit-get-current-branch)))) - (remote (magit-get-push-remote branch)) - (target (concat remote "/" branch))) - (and (or (not verify) - (magit-rev-verify target)) - (magit--propertize-face target 'magit-branch-remote)))) + (magit--with-refresh-cache (list 'magit-get-push-branch branch verify) + (when-let ((branch (or branch (setq branch (magit-get-current-branch)))) + (remote (magit-get-push-remote branch)) + (target (concat remote "/" branch))) + (and (or (not verify) + (magit-rev-verify target)) + (magit--propertize-face target 'magit-branch-remote))))) (defun magit-get-@{push}-branch (&optional branch) (let ((ref (magit-rev-parse "--symbolic-full-name" @@ -1462,11 +1547,36 @@ (defun magit-get-some-remote (&optional branch) (or (magit-get-remote branch) - (and (magit-branch-p "master") - (magit-get-remote "master")) - (let ((remotes (magit-list-remotes))) - (or (car (member "origin" remotes)) - (car remotes))))) + (when-let ((main (magit-main-branch))) + (magit-get-remote main)) + (magit-primary-remote) + (car (magit-list-remotes)))) + +(defvar magit-primary-remote-names + '("upstream" "origin")) + +(defun magit-primary-remote () + "Return the primary remote. + +The primary remote is the remote that tracks the repository that +other repositories are forked from. It often is called \"origin\" +but because many people name their own fork \"origin\", using that +term would be ambiguous. Likewise we avoid the term \"upstream\" +because a branch's @{upstream} branch may be a local branch or a +branch from a remote other than the primary remote. + +If a remote exists whose name matches `magit.primaryRemote', then +that is considered the primary remote. If no remote by that name +exists, then remotes in `magit-primary-remote-names' are tried in +order and the first remote from that list that actually exists in +the current repository is considered its primary remote." + (let ((remotes (magit-list-remotes))) + (seq-find (lambda (name) + (member name remotes)) + (delete-dups + (delq nil + (cons (magit-get "magit.primaryRemote") + magit-primary-remote-names)))))) (defun magit-branch-merged-p (branch &optional target) "Return non-nil if BRANCH is merged into its upstream and TARGET. @@ -1495,30 +1605,31 @@ the name of a remote and REF is the ref local to the remote." (when-let ((ref (magit-ref-fullname refname))) (save-match-data - (-some (lambda (line) - (and (string-match "\ + (seq-some (lambda (line) + (and (string-match "\ \\`remote\\.\\([^.]+\\)\\.fetch=\\+?\\([^:]+\\):\\(.+\\)" line) - (let ((rmt (match-string 1 line)) - (src (match-string 2 line)) - (dst (match-string 3 line))) - (and (string-match (format "\\`%s\\'" - (replace-regexp-in-string - "*" "\\(.+\\)" dst t t)) - ref) - (cons rmt (replace-regexp-in-string - "*" (match-string 1 ref) src)))))) - (magit-git-lines "config" "--local" "--list"))))) + (let ((rmt (match-string 1 line)) + (src (match-string 2 line)) + (dst (match-string 3 line))) + (and (string-match (format "\\`%s\\'" + (replace-regexp-in-string + "*" "\\(.+\\)" dst t t)) + ref) + (cons rmt (replace-regexp-in-string + "*" (match-string 1 ref) src)))))) + (magit-git-lines "config" "--local" "--list"))))) (defun magit-split-branch-name (branch) (cond ((member branch (magit-list-local-branch-names)) (cons "." branch)) ((string-match "/" branch) - (or (-some (lambda (remote) - (and (string-match (format "\\`\\(%s\\)/\\(.+\\)\\'" remote) - branch) - (cons (match-string 1 branch) - (match-string 2 branch)))) - (magit-list-remotes)) + (or (seq-some (lambda (remote) + (and (string-match + (format "\\`\\(%s\\)/\\(.+\\)\\'" remote) + branch) + (cons (match-string 1 branch) + (match-string 2 branch)))) + (magit-list-remotes)) (error "Invalid branch name %s" branch))))) (defun magit-get-current-tag (&optional rev with-distance) @@ -1557,9 +1668,6 @@ (list it (car (magit-rev-diff-count it rev))) it)))))) -(defvar magit-list-refs-namespaces - '("refs/heads" "refs/remotes" "refs/tags" "refs/pull")) - (defun magit-list-refs (&optional namespaces format sortby) "Return list of references. @@ -1568,7 +1676,7 @@ FORMAT is passed to the `--format' flag of `git for-each-ref' and defaults to \"%(refname)\". If the format is \"%(refname)\" -or \"%(refname:short)\", then drop the symbolic-ref \"HEAD\". +or \"%(refname:short)\", then drop the symbolic-ref `HEAD'. SORTBY is a key or list of keys to pass to the `--sort' flag of `git for-each-ref'. When nil, use `magit-list-refs-sortby'" @@ -1603,7 +1711,7 @@ (magit-list-related-branches "--contains" commit args)) (defun magit-list-publishing-branches (&optional commit) - (--filter (magit-rev-ancestor-p commit it) + (--filter (magit-rev-ancestor-p (or commit "HEAD") it) magit-published-branches)) (defun magit-list-merged-branches (&optional commit &rest args) @@ -1619,7 +1727,7 @@ (defun magit-list-branches-pointing-at (commit) (let ((re (format "\\`%s refs/\\(heads\\|remotes\\)/\\(.*\\)\\'" - (magit-rev-verify commit)))) + (magit-rev-verify commit)))) (--keep (and (string-match re it) (let ((name (match-string 2 it))) (and (not (string-suffix-p "HEAD" name)) @@ -1696,22 +1804,23 @@ (substring it 41)) (magit-git-lines "ls-remote" remote))) +(defun magit-list-modified-modules () + (--keep (and (string-match "\\`\\+\\([^ ]+\\) \\(.+\\) (.+)\\'" it) + (match-string 2 it)) + (magit-git-lines "submodule" "status"))) + (defun magit-list-module-paths () (--mapcat (and (string-match "^160000 [0-9a-z]\\{40\\} 0\t\\(.+\\)$" it) (list (match-string 1 it))) (magit-git-items "ls-files" "-z" "--stage"))) +(defun magit-list-module-names () + (mapcar #'magit-get-submodule-name (magit-list-module-paths))) + (defun magit-get-submodule-name (path) "Return the name of the submodule at PATH. PATH has to be relative to the super-repository." - (cadr (split-string - (car (or (magit-git-items - "config" "-z" - "-f" (expand-file-name ".gitmodules" (magit-toplevel)) - "--get-regexp" "^submodule\\..*\\.path$" - (concat "^" (regexp-quote (directory-file-name path)) "$")) - (error "No such submodule `%s'" path))) - "\n"))) + (magit-git-string "submodule--helper" "name" path)) (defun magit-list-worktrees () (let (worktrees worktree) @@ -1768,6 +1877,27 @@ (defun magit-remote-p (string) (car (member string (magit-list-remotes)))) +(defvar magit-main-branch-names + ;; These are the names that Git suggests + ;; if `init.defaultBranch' is undefined. + '("main" "master" "trunk" "development")) + +(defun magit-main-branch () + "Return the main branch. + +If a branch exists whose name matches `init.defaultBranch', then +that is considered the main branch. If no branch by that name +exists, then the branch names in `magit-main-branch-names' are +tried in order. The first branch from that list that actually +exists in the current repository is considered its main branch." + (let ((branches (magit-list-local-branch-names))) + (seq-find (lambda (name) + (member name branches)) + (delete-dups + (delq nil + (cons (magit-get "init.defaultBranch") + magit-main-branch-names)))))) + (defun magit-rev-diff-count (a b) "Return the commits in A but not B and vice versa. Return a list of two integers: (A>B B>A)." @@ -1778,15 +1908,26 @@ "\t"))) (defun magit-abbrev-length () - (--if-let (magit-get "core.abbrev") - (string-to-number it) - ;; Guess the length git will be using based on an example - ;; abbreviation. Actually HEAD's abbreviation might be an - ;; outlier, so use the shorter of the abbreviations for two - ;; commits. When a commit does not exist, then fall back - ;; to the default of 7. See #3034. - (min (--if-let (magit-rev-parse "--short" "HEAD") (length it) 7) - (--if-let (magit-rev-parse "--short" "HEAD~") (length it) 7)))) + (let ((abbrev (magit-get "core.abbrev"))) + (if (and abbrev (not (equal abbrev "auto"))) + (string-to-number abbrev) + ;; Guess the length git will be using based on an example + ;; abbreviation. Actually HEAD's abbreviation might be an + ;; outlier, so use the shorter of the abbreviations for two + ;; commits. See #3034. + (if-let ((head (magit-rev-parse "--short" "HEAD")) + (head-len (length head))) + (min head-len + (--if-let (magit-rev-parse "--short" "HEAD~") + (length it) + head-len)) + ;; We're on an unborn branch, but perhaps the repository has + ;; other commits. See #4123. + (if-let ((commits (magit-git-lines "rev-list" "-n2" "--all" + "--abbrev-commit"))) + (apply #'min (mapcar #'length commits)) + ;; A commit does not exist. Fall back to the default of 7. + 7))))) (defun magit-abbrev-arg (&optional arg) (format "--%s=%d" (or arg "abbrev") (magit-abbrev-length))) @@ -1808,10 +1949,10 @@ (cdr (split-string it)))) (defun magit-patch-id (rev) - (with-temp-buffer + (magit--with-temp-process-buffer (magit-process-file shell-file-name nil '(t nil) nil shell-command-switch - (let ((exec (shell-quote-argument magit-git-executable))) + (let ((exec (shell-quote-argument (magit-git-executable)))) (format "%s diff-tree -u %s | %s patch-id" exec rev exec))) (car (split-string (buffer-string))))) @@ -1959,7 +2100,7 @@ (defmacro magit-with-blob (commit file &rest body) (declare (indent 2) (debug (form form body))) - `(with-temp-buffer + `(magit--with-temp-process-buffer (let ((buffer-file-name ,file)) (save-excursion (magit-git-insert "cat-file" "-p" @@ -2054,20 +2195,32 @@ (--when-let (let ((c "\s\n\t~^:?*[\\")) (cl-letf (((get 'git-revision 'beginning-op) - (if (re-search-backward (format "[%s]" c) nil t) - (forward-char) - (goto-char (point-min)))) + (lambda () + (if (re-search-backward (format "[%s]" c) nil t) + (forward-char) + (goto-char (point-min))))) ((get 'git-revision 'end-op) (lambda () (re-search-forward (format "\\=[^%s]*" c) nil t)))) (bounds-of-thing-at-point 'git-revision))) (let ((text (buffer-substring-no-properties (car it) (cdr it)))) - (and (magit-commit-p text) text)))) + (and (>= (length text) 7) + (string-match-p "[a-z]" text) + (magit-commit-p text) + text)))) ;;; Completion (defvar magit-revision-history nil) +(defun magit--minibuf-default-add-commit () + (let ((fn minibuffer-default-add-function)) + (lambda () + (if-let ((commit (with-selected-window (minibuffer-selected-window) + (magit-commit-at-point)))) + (cons commit (delete commit (funcall fn))) + (funcall fn))))) + (defun magit-read-branch (prompt &optional secondary-default) (magit-completing-read prompt (magit-list-branch-names) nil t nil 'magit-revision-history @@ -2076,12 +2229,13 @@ (magit-get-current-branch)))) (defun magit-read-branch-or-commit (prompt &optional secondary-default) - (or (magit-completing-read prompt (magit-list-refnames nil t) - nil nil nil 'magit-revision-history - (or (magit-branch-or-commit-at-point) - secondary-default - (magit-get-current-branch))) - (user-error "Nothing selected"))) + (let ((minibuffer-default-add-function (magit--minibuf-default-add-commit))) + (or (magit-completing-read prompt (magit-list-refnames nil t) + nil nil nil 'magit-revision-history + (or (magit-branch-or-commit-at-point) + secondary-default + (magit-get-current-branch))) + (user-error "Nothing selected")))) (defun magit-read-range-or-commit (prompt &optional secondary-default) (magit-read-range @@ -2094,10 +2248,12 @@ (magit-get-current-branch)))) (defun magit-read-range (prompt &optional default) - (magit-completing-read-multiple prompt - (magit-list-refnames) - "\\.\\.\\.?" - default 'magit-revision-history)) + (let ((minibuffer-default-add-function (magit--minibuf-default-add-commit)) + (crm-separator "\\.\\.\\.?")) + (magit-completing-read-multiple* + (concat prompt ": ") + (magit-list-refnames) + nil nil nil 'magit-revision-history default nil t))) (defun magit-read-remote-branch (prompt &optional remote default local-branch require-match) @@ -2128,7 +2284,8 @@ (magit-get-current-branch)))) (defun magit-read-local-branch-or-commit (prompt) - (let ((choices (nconc (magit-list-local-branch-names) + (let ((minibuffer-default-add-function (magit--minibuf-default-add-commit)) + (choices (nconc (magit-list-local-branch-names) (magit-list-special-refnames))) (commit (magit-commit-at-point))) (when commit @@ -2136,7 +2293,7 @@ (or (magit-completing-read prompt choices nil nil nil 'magit-revision-history (or (magit-local-branch-at-point) commit)) - (user-error "Nothing selected")))) + (user-error "Nothing selected")))) (defun magit-read-local-branch-or-ref (prompt &optional secondary-default) (magit-completing-read prompt (nconc (magit-list-local-branch-names) @@ -2161,7 +2318,8 @@ (defun magit-read-other-branch-or-commit (prompt &optional exclude secondary-default) - (let* ((current (magit-get-current-branch)) + (let* ((minibuffer-default-add-function (magit--minibuf-default-add-commit)) + (current (magit-get-current-branch)) (atpoint (magit-branch-or-commit-at-point)) (exclude (or exclude current)) (default (or (and (not (equal atpoint exclude)) @@ -2218,9 +2376,10 @@ (or (let ((r (car (member (magit-remote-branch-at-point) branches))) (l (car (member (magit-local-branch-at-point) branches)))) (if magit-prefer-remote-upstream (or r l) (or l r))) - (let ((r (car (member "origin/master" branches))) - (l (car (member "master" branches)))) - (if magit-prefer-remote-upstream (or r l) (or l r))) + (when-let ((main (magit-main-branch))) + (let ((r (car (member (concat "origin/" main) branches))) + (l (car (member main branches)))) + (if magit-prefer-remote-upstream (or r l) (or l r)))) (car (member (magit-get-previous-branch) branches)))))) (defun magit-read-starting-point (prompt &optional branch default) @@ -2254,10 +2413,21 @@ (magit-tag-at-point))) (defun magit-read-stash (prompt) - (let ((stashes (magit-list-stashes))) - (magit-completing-read prompt stashes nil t nil nil - (magit-stash-at-point) - (car stashes)))) + (let* ((atpoint (magit-stash-at-point)) + (default (and atpoint + (concat atpoint (magit-rev-format " %s" atpoint)))) + (choices (mapcar (lambda (c) + (pcase-let ((`(,rev ,msg) (split-string c "\0"))) + (concat (propertize rev 'face 'magit-hash) + " " msg))) + (magit-list-stashes "%gd%x00%s"))) + (choice (magit-completing-read prompt choices + nil t nil nil + default + (car choices)))) + (and choice + (string-match "^\\([^ ]+\\) \\(.+\\)" choice) + (substring-no-properties (match-string 1 choice))))) (defun magit-read-remote (prompt &optional default use-only) (let ((remotes (magit-list-remotes))) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-gitignore.el magit-3.3.0/lisp/magit-gitignore.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-gitignore.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-gitignore.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-gitignore.el --- intentionally untracked files -*- lexical-binding: t -*- -;; Copyright (C) 2008-2020 The Magit Project Contributors +;; Copyright (C) 2008-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -27,15 +29,12 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) ;;; Transient ;;;###autoload (autoload 'magit-gitignore "magit-gitignore" nil t) -(define-transient-command magit-gitignore () +(transient-define-prefix magit-gitignore () "Instruct Git to ignore a file or pattern." :man-page "gitignore" ["Gitignore" @@ -71,8 +70,8 @@ ;;;###autoload (defun magit-gitignore-in-subdir (rule directory) - "Add the Git ignore RULE to a \".gitignore\" file. -Prompted the user for a directory and add the rule to the + "Add the Git ignore RULE to a \".gitignore\" file in DIRECTORY. +Prompt the user for a directory and add the rule to the \".gitignore\" file in that directory. Since such files are tracked, they are shared with other clones of the repository. Also stage the file." @@ -81,7 +80,7 @@ (magit-with-toplevel (let ((file (expand-file-name ".gitignore" directory))) (magit--gitignore rule file) - (magit-run-git "add" file)))) + (magit-run-git "add" (magit-convert-filename-for-git file))))) ;;;###autoload (defun magit-gitignore-in-gitdir (rule) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-imenu.el magit-3.3.0/lisp/magit-imenu.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-imenu.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-imenu.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-imenu.el --- Integrate Imenu in magit major modes -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Damien Cassou ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -33,9 +35,6 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) (require 'git-rebase) @@ -48,21 +47,28 @@ `imenu'. MENU-TYPES is a list of section types containing elements of -ENTRY-TYPES. Elements of MENU-TYPES are are used to categories +ENTRY-TYPES. Elements of MENU-TYPES are used to categorize elements of ENTRY-TYPES. This function is used as a helper for functions set as `imenu-create-index-function'." - (let ((entries (make-hash-table :test 'equal))) + ;; If `which-function-mode' is active, then the create-index + ;; function is called at the time the major-mode is being enabled. + ;; Modes that derive from `magit-mode' have not populated the buffer + ;; at that time yet, so we have to abort. + (when-let ((section (magit-current-section)) + (entries (make-hash-table :test 'equal))) (goto-char (point-max)) + (unless (oref section parent) + (forward-line -1)) (while (magit-section--backward-find (lambda () (let* ((section (magit-current-section)) (type (oref section type)) (parent (oref section parent)) (parent-type (oref parent type))) - (and (-contains-p entry-types type) - (-contains-p menu-types parent-type))))) + (and (memq type entry-types) + (memq parent-type menu-types))))) (let* ((section (magit-current-section)) (name (buffer-substring-no-properties (line-beginning-position) @@ -71,6 +77,8 @@ (parent-title (buffer-substring-no-properties (oref parent start) (1- (oref parent content))))) + (when (string-match " ([0-9]*)\\'" parent-title) + (setq parent-title (substring parent-title 0 (match-beginning 0)))) (puthash parent-title (cons (cons name (point)) (gethash parent-title entries (list))) @@ -134,10 +142,10 @@ This function is used as a value for `imenu-create-index-function'." (magit-imenu--index-function - '(file commit stash) - '(unpushed unstaged unpulled untracked staged stashes))) + '(file commit stash pullreq issue) + '(unpushed unstaged unpulled untracked staged stashes pullreqs issues))) -;;;; Refs mode +;;; Refs mode ;;;###autoload (defun magit-imenu--refs-create-index-function () @@ -148,7 +156,7 @@ '(branch commit tag) '(local remote tags))) -;;;; Cherry mode +;;; Cherry mode ;;;###autoload (defun magit-imenu--cherry-create-index-function () @@ -159,7 +167,7 @@ '(commit) '(cherries))) -;;;; Submodule list mode +;;; Submodule list mode ;;;###autoload (defun magit-imenu--submodule-prev-index-position-function () @@ -177,7 +185,7 @@ beginning of the line." (elt (tabulated-list-get-entry) 0)) -;;;; Repolist mode +;;; Repolist mode ;;;###autoload (defun magit-imenu--repolist-prev-index-position-function () @@ -198,7 +206,7 @@ (elt entry 0) (elt entry (1- (length entry)))))) -;;;; Process mode +;;; Process mode ;;;###autoload (defun magit-imenu--process-prev-index-position-function () @@ -218,7 +226,7 @@ (buffer-substring-no-properties (line-beginning-position) (line-end-position))) -;;;; Rebase mode +;;; Rebase mode ;;;###autoload (defun magit-imenu--rebase-prev-index-position-function () diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-libgit.el magit-3.3.0/lisp/magit-libgit.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-libgit.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-libgit.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-libgit.el --- Libgit functionality -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,9 +8,11 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli -;; Package-Requires: ((emacs "26.1") (magit "0") (libgit "0")) ;; Keywords: git tools vc ;; Homepage: https://github.com/magit/magit +;; Package-Requires: ((emacs "26.1") (libgit "0") (magit "3.3.0")) +;; Package-Version: 3.3.0 +;; SPDX-License-Identifier: GPL-3.0-or-later ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by @@ -42,9 +44,13 @@ ;;; Code: (require 'cl-lib) +(require 'dash) +(require 'eieio) +(require 'seq) (require 'subr-x) (require 'magit-git) + (require 'libgit) ;;; Utilities diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-libgit-pkg.el magit-3.3.0/lisp/magit-libgit-pkg.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-libgit-pkg.el 1970-01-01 00:00:00.000000000 +0000 +++ magit-3.3.0/lisp/magit-libgit-pkg.el 2021-10-06 12:51:17.000000000 +0000 @@ -0,0 +1,7 @@ +(define-package "magit-libgit" "3.3.0" + "." + '((emacs "25.1") + (libgit "0") + (magit "3.3.0")) + :homepage "https://magit.vc" + :keywords '("git" "tools" "vc")) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-log.el magit-3.3.0/lisp/magit-log.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-log.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-log.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-log.el --- inspect Git history -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -53,15 +55,13 @@ (require 'crm) (require 'which-func) -(eval-when-compile - (require 'subr-x)) - ;;; Options ;;;; Log Mode (defgroup magit-log nil "Inspect and manipulate Git history." :link '(info-link "(magit)Logging") + :group 'magit-commands :group 'magit-modes) (defcustom magit-log-mode-hook nil @@ -77,11 +77,11 @@ :options '("--follow" "--grep" "-G" "-S" "-L")) (defcustom magit-log-revision-headers-format "\ -%+b +%+b%+N Author: %aN <%aE> Committer: %cN <%cE>" "Additional format string used with the `++header' argument." - :package-version '(magit . "2.3.0") + :package-version '(magit . "3.2.0") :group 'magit-log :type 'string) @@ -318,7 +318,7 @@ (pcase-let ((`(,args ,files) (magit-log--get-value 'magit-log-mode magit-prefix-use-buffer-arguments))) - (unless (eq current-transient-command 'magit-dispatch) + (unless (eq transient-current-command 'magit-dispatch) (when-let ((file (magit-file-relative-name))) (setq files (list file)))) (oset obj value (if files `(("--" ,@files) ,args) args)))) @@ -339,7 +339,7 @@ (defun magit-log-arguments (&optional mode) "Return the current log arguments." - (if (memq current-transient-command '(magit-log magit-log-refresh)) + (if (memq transient-current-command '(magit-log magit-log-refresh)) (pcase-let ((`(,args ,alist) (-separate #'atom (transient-get-value)))) (list args (cdr (assoc "--" alist)))) @@ -392,7 +392,7 @@ ;;;; Prefix Commands ;;;###autoload (autoload 'magit-log "magit-log" nil t) -(define-transient-command magit-log () +(transient-define-prefix magit-log () "Show a commit or reference log." :man-page "git-log" :class 'magit-log-prefix @@ -406,10 +406,11 @@ ["Commit limiting" (magit-log:-n) (magit:--author) - (7 "=s" "Limit to commits since" "--since=" transient-read-date) - (7 "=u" "Limit to commits until" "--until=" transient-read-date) + (7 magit-log:--since) + (7 magit-log:--until) (magit-log:--grep) - (7 "-I" "Invert search pattern" "--invert-grep") + (7 "-i" "Search case-insensitive" ("-i" "--regexp-ignore-case")) + (7 "-I" "Invert search pattern" "--invert-grep") (magit-log:-G) ;2 (magit-log:-S) ;2 (magit-log:-L) ;2 @@ -450,13 +451,17 @@ ("r" "current" magit-reflog-current) ("O" "other" magit-reflog-other) ("H" "HEAD" magit-reflog-head)] - [:if magit--any-wip-mode-enabled-p + [:if (lambda () + (require 'magit-wip) + (magit--any-wip-mode-enabled-p)) :description "Wiplog" ("i" "index" magit-wip-log-index) - ("w" "worktree" magit-wip-log-worktree)]]) + ("w" "worktree" magit-wip-log-worktree)] + ["Other" + (5 "s" "shortlog" magit-shortlog)]]) ;;;###autoload (autoload 'magit-log-refresh "magit-log" nil t) -(define-transient-command magit-log-refresh () +(transient-define-prefix magit-log-refresh () "Change the arguments used for the log(s) in the current buffer." :man-page "git-log" :class 'magit-log-refresh-prefix @@ -466,7 +471,8 @@ (magit-log:-n) (magit:--author) (magit-log:--grep) - (7 "-I" "Invert search pattern" "--invert-grep") + (7 "-i" "Search case-insensitive" ("-i" "--regexp-ignore-case")) + (7 "-I" "Invert search pattern" "--invert-grep") (magit-log:-G) (magit-log:-S) (magit-log:-L)] @@ -511,7 +517,7 @@ ("b" "buffer lock" magit-toggle-buffer-lock)]] (interactive) (cond - ((not (eq current-transient-command 'magit-log-refresh)) + ((not (eq transient-current-command 'magit-log-refresh)) (pcase major-mode (`magit-reflog-mode (user-error "Cannot change log arguments in reflog buffers")) @@ -527,7 +533,7 @@ ;;;; Infix Commands -(define-infix-argument magit-log:-n () +(transient-define-argument magit-log:-n () :description "Limit number of commits" :class 'transient-option ;; For historic reasons (and because it easy to guess what "-n" @@ -537,14 +543,28 @@ :argument "-n" :reader 'transient-read-number-N+) -(define-infix-argument magit:--author () +(transient-define-argument magit:--author () :description "Limit to author" :class 'transient-option :key "-A" :argument "--author=" :reader 'magit-transient-read-person) -(define-infix-argument magit-log:--*-order () +(transient-define-argument magit-log:--since () + :description "Limit to commits since" + :class 'transient-option + :key "=s" + :argument "--since=" + :reader 'transient-read-date) + +(transient-define-argument magit-log:--until () + :description "Limit to commits until" + :class 'transient-option + :key "=u" + :argument "--until=" + :reader 'transient-read-date) + +(transient-define-argument magit-log:--*-order () :description "Order commits by" :class 'transient-switches :key "-o" @@ -552,23 +572,23 @@ :argument-regexp "\\(--\\(topo\\|author-date\\|date\\)-order\\)" :choices '("topo" "author-date" "date")) -(define-infix-argument magit-log:--grep () +(transient-define-argument magit-log:--grep () :description "Search messages" :class 'transient-option :key "-F" :argument "--grep=") -(define-infix-argument magit-log:-G () +(transient-define-argument magit-log:-G () :description "Search changes" :class 'transient-option :argument "-G") -(define-infix-argument magit-log:-S () +(transient-define-argument magit-log:-S () :description "Search occurrences" :class 'transient-option :argument "-S") -(define-infix-argument magit-log:-L () +(transient-define-argument magit-log:-L () :description "Trace line evolution" :class 'transient-option :argument "-L" @@ -589,16 +609,17 @@ (defun magit-log-read-revs (&optional use-current) (or (and use-current (--when-let (magit-get-current-branch) (list it))) - (let ((collection (magit-list-refnames nil t))) - (split-string - (magit-completing-read-multiple "Log rev,s" collection - "\\(\\.\\.\\.?\\|[, ]\\)" - (or (magit-branch-or-commit-at-point) - (unless use-current - (magit-get-previous-branch))) - 'magit-revision-history - magit-log-read-revs-map) - "[, ]" t)))) + (let ((crm-separator "\\(\\.\\.\\.?\\|[, ]\\)") + (crm-local-completion-map magit-log-read-revs-map)) + (split-string (magit-completing-read-multiple* + "Log rev,s: " + (magit-list-refnames nil t) + nil nil nil 'magit-revision-history + (or (magit-branch-or-commit-at-point) + (unless use-current + (magit-get-previous-branch))) + nil t) + "[, ]" t)))) (defun magit-log-read-pattern (option) "Read a string from the user to pass as parameter to OPTION." @@ -763,7 +784,7 @@ This command requires git-when-merged, which is available from https://github.com/mhagger/git-when-merged." (interactive - (append (let ((commit (magit-read-branch-or-commit "Commit"))) + (append (let ((commit (magit-read-branch-or-commit "Log merge of commit"))) (list commit (magit-read-other-branch "Merged into" commit))) (magit-log-arguments))) @@ -773,11 +794,9 @@ (let (exit m) (with-temp-buffer (save-excursion - (setq exit (magit-process-file - magit-git-executable nil t nil - "when-merged" "-c" - "--abbrev" (number-to-string (magit-abbrev-length)) - commit branch))) + (setq exit (magit-process-git t "when-merged" "-c" + (magit-abbrev-arg) + commit branch))) (setq m (buffer-substring-no-properties (point) (line-end-position)))) (if (zerop exit) (magit-log-setup-buffer (list (format "%s^1..%s" m m)) @@ -871,6 +890,72 @@ "\\[magit-log-double-commit-limit] first")))) (user-error "Parent %s does not exist" parent-rev)))))) +(defun magit-log-move-to-revision (rev) + "Read a revision and move to it in current log buffer. + +If the chosen reference or revision isn't being displayed in +the current log buffer, then inform the user about that and do +nothing else. + +If invoked outside any log buffer, then display the log buffer +of the current repository first; creating it if necessary." + (interactive (list (magit-read-branch-or-commit "In log, jump to"))) + (with-current-buffer + (cond ((derived-mode-p 'magit-log-mode) + (current-buffer)) + ((when-let ((buf (magit-get-mode-buffer 'magit-log-mode))) + (pop-to-buffer-same-window buf))) + (t + (apply #'magit-log-all-branches (magit-log-arguments)))) + (unless (magit-log-goto-commit-section (magit-rev-abbrev rev)) + (user-error "%s isn't visible in the current log buffer" rev)))) + +;;;; Shortlog Commands + +;;;###autoload (autoload 'magit-shortlog "magit-log" nil t) +(transient-define-prefix magit-shortlog () + "Show a history summary." + :man-page "git-shortlog" + :value '("--numbered" "--summary") + ["Arguments" + ("-n" "Sort by number of commits" ("-n" "--numbered")) + ("-s" "Show commit count summary only" ("-s" "--summary")) + ("-e" "Show email addresses" ("-e" "--email")) + ("-g" "Group commits by" "--group=" + :choices ("author" "committer" "trailer:")) + (7 "-f" "Format string" "--format=") + (7 "-w" "Linewrap" "-w" :class transient-option)] + ["Shortlog" + ("s" "since" magit-shortlog-since) + ("r" "range" magit-shortlog-range)]) + +(defun magit-git-shortlog (rev args) + (let ((dir default-directory)) + (with-current-buffer (get-buffer-create "*magit-shortlog*") + (setq default-directory dir) + (setq buffer-read-only t) + (let ((inhibit-read-only t)) + (erase-buffer) + (save-excursion + (magit-git-insert "shortlog" args rev)) + (switch-to-buffer-other-window (current-buffer)))))) + +;;;###autoload +(defun magit-shortlog-since (rev args) + "Show a history summary for commits since REV." + (interactive + (list (magit-read-branch-or-commit "Shortlog since" (magit-get-current-tag)) + (transient-args 'magit-shortlog))) + (magit-git-shortlog (concat rev "..") args)) + +;;;###autoload +(defun magit-shortlog-range (rev-or-range args) + "Show a history summary for commit or range REV-OR-RANGE." + (interactive + (list (magit-read-range-or-commit "Shortlog for revision or range") + (transient-args 'magit-shortlog))) + (magit-git-shortlog rev-or-range args)) + ;;; Log Mode (defvar magit-log-disable-graph-hack-args @@ -880,9 +965,10 @@ (defvar magit-log-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map magit-mode-map) - (define-key map "\C-c\C-b" 'magit-go-backward) - (define-key map "\C-c\C-f" 'magit-go-forward) - (define-key map "\C-c\C-n" 'magit-log-move-to-parent) + (define-key map (kbd "C-c C-b") 'magit-go-backward) + (define-key map (kbd "C-c C-f") 'magit-go-forward) + (define-key map (kbd "C-c C-n") 'magit-log-move-to-parent) + (define-key map "j" 'magit-log-move-to-revision) (define-key map "=" 'magit-log-toggle-commit-limit) (define-key map "+" 'magit-log-double-commit-limit) (define-key map "-" 'magit-log-half-commit-limit) @@ -935,9 +1021,7 @@ (files magit-buffer-log-files)) (magit-set-header-line-format (funcall magit-log-header-line-function revs args files)) - (if (= (length files) 1) - (unless (magit-file-tracked-p (car files)) - (setq args (cons "--full-history" args))) + (unless (= (length files) 1) (setq args (remove "--follow" args))) (when (and (car magit-log-remove-graph-args) (--any-p (string-match-p @@ -999,7 +1083,7 @@ (remove "--literal-pathspecs" magit-git-global-arguments))) (magit-git-wash (apply-partially #'magit-log-wash-log 'log) "log" - (format "--format=%s%%h%%x00%s%%x00%s%%x00%%aN%%x00%s%%x00%%s%s" + (format "--format=%s%%h%%x0c%s%%x0c%s%%x0c%%aN%%x0c%s%%x0c%%s%s" (if (and (member "--left-right" args) (not (member "--graph" args))) "%m " @@ -1022,6 +1106,7 @@ (setq args (cons "--decorate=full" (remove "--decorate" args)))) (when (member "--reverse" args) (setq args (remove "--graph" args))) + (setq args (magit-diff--maybe-add-stat-arguments args)) args) "--use-mailmap" "--no-prefix" revs "--" files))) @@ -1039,15 +1124,18 @@ "Keymap for `module-commit' sections.") (defconst magit-log-heading-re + ;; Note: A form feed instead of a null byte is used as the delimiter + ;; because using the latter interferes with the graph prefix when + ;; ++header is used. (concat "^" "\\(?4:[-_/|\\*o<>. ]*\\)" ; graph - "\\(?1:[0-9a-fA-F]+\\)?\0" ; sha1 - "\\(?3:[^\0\n]+\\)?\0" ; refs - "\\(?7:[BGUXYREN]\\)?\0" ; gpg - "\\(?5:[^\0\n]*\\)\0" ; author + "\\(?1:[0-9a-fA-F]+\\)? " ; sha1 + "\\(?3:[^ \n]+\\)? " ; refs + "\\(?7:[BGUXYREN]\\)? " ; gpg + "\\(?5:[^ \n]*\\) " ; author ;; Note: Date is optional because, prior to Git v2.19.0, ;; `git rebase -i --root` corrupts the root's author date. - "\\(?6:[^\0\n]*\\)\0" ; date + "\\(?6:[^ \n]*\\) " ; date "\\(?2:.*\\)$")) ; msg (defconst magit-log-cherry-re @@ -1071,7 +1159,7 @@ (defconst magit-log-bisect-log-re (concat "^# " - "\\(?3:bad:\\|skip:\\|good:\\) " ; "refs" + "\\(?3:[^: \n]+:\\) " ; "refs" "\\[\\(?1:[^]\n]+\\)\\] " ; sha1 "\\(?2:.*\\)$")) ; msg @@ -1161,6 +1249,17 @@ (`stash (oset section type 'stash)) (`module (oset section type 'module-commit)) (`bisect-log (setq hash (magit-rev-parse "--short" hash)))) + (setq hash (propertize hash 'font-lock-face + (pcase (and gpg (aref gpg 0)) + (?G 'magit-signature-good) + (?B 'magit-signature-bad) + (?U 'magit-signature-untrusted) + (?X 'magit-signature-expired) + (?Y 'magit-signature-expired-key) + (?R 'magit-signature-revoked) + (?E 'magit-signature-error) + (?N 'magit-hash) + (_ 'magit-hash)))) (when cherry (when (and (derived-mode-p 'magit-refs-mode) magit-refs-show-commit-count) @@ -1177,11 +1276,11 @@ 'magit-cherry-unmatched))) (insert ?\s)) (when align - (insert (propertize hash 'font-lock-face 'magit-hash) ?\s)) + (insert hash ?\s)) (when graph (insert graph)) (unless align - (insert (propertize hash 'font-lock-face 'magit-hash) ?\s)) + (insert hash ?\s)) (when (and refs (not magit-log-show-refname-after-summary)) (insert (magit-format-ref-labels refs) ?\s)) (when (eq style 'reflog) @@ -1190,16 +1289,6 @@ (insert (magit-reflog-format-subject (substring refsub 0 (if (string-match-p ":" refsub) -2 -1)))))) (when msg - (when gpg - (setq msg (propertize msg 'font-lock-face - (pcase (aref gpg 0) - (?G 'magit-signature-good) - (?B 'magit-signature-bad) - (?U 'magit-signature-untrusted) - (?X 'magit-signature-expired) - (?Y 'magit-signature-expired-key) - (?R 'magit-signature-revoked) - (?E 'magit-signature-error))))) (insert (funcall magit-log-format-message-function hash msg))) (when (and refs magit-log-show-refname-after-summary) (insert ?\s) @@ -1313,9 +1402,8 @@ (setq magit--update-revision-buffer (list commit buffer)) (run-with-idle-timer magit-update-other-window-delay nil - (let ((args (with-current-buffer buffer - (let ((magit-direct-use-buffer-arguments 'selected)) - (magit-show-commit--arguments))))) + (let ((args (let ((magit-direct-use-buffer-arguments 'selected)) + (magit-show-commit--arguments)))) (lambda () (pcase-let ((`(,rev ,buf) magit--update-revision-buffer)) (setq magit--update-revision-buffer nil) @@ -1395,7 +1483,8 @@ (truncate-string-to-width (or author "") details-width - nil ?\s (make-string 1 magit-ellipsis)) + nil ?\s + (if (char-displayable-p ?…) "…" ">")) 'magit-log-author) " ")) (magit--propertize-face @@ -1454,13 +1543,13 @@ (defvar magit-log-select-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map magit-log-mode-map) - (define-key map "\C-c\C-b" 'undefined) - (define-key map "\C-c\C-f" 'undefined) - (define-key map "." 'magit-log-select-pick) - (define-key map "e" 'magit-log-select-pick) - (define-key map "\C-c\C-c" 'magit-log-select-pick) - (define-key map "q" 'magit-log-select-quit) - (define-key map "\C-c\C-k" 'magit-log-select-quit) + (define-key map (kbd "C-c C-b") 'undefined) + (define-key map (kbd "C-c C-f") 'undefined) + (define-key map (kbd ".") 'magit-log-select-pick) + (define-key map (kbd "e") 'magit-log-select-pick) + (define-key map (kbd "C-c C-c") 'magit-log-select-pick) + (define-key map (kbd "q") 'magit-log-select-quit) + (define-key map (kbd "C-c C-k") 'magit-log-select-quit) map) "Keymap for `magit-log-select-mode'.") @@ -1550,11 +1639,12 @@ (funcall fun rev))) (defun magit-log-select-quit () - "Abort selecting a commit, don't act on any commit." + "Abort selecting a commit, don't act on any commit. +Call `magit-log-select-quit-function' if set." (interactive) - (magit-mode-bury-buffer 'kill) - (when magit-log-select-quit-function - (funcall magit-log-select-quit-function))) + (let ((fun magit-log-select-quit-function)) + (magit-mode-bury-buffer 'kill) + (when fun (funcall fun)))) ;;; Cherry Mode @@ -1656,12 +1746,7 @@ (defun magit-insert-unpulled-from-pushremote () "Insert commits that haven't been pulled from the push-remote yet." (--when-let (magit-get-push-branch) - (unless (and (equal (magit-rev-name it) - (magit-rev-name "@{upstream}")) - (or (memq 'magit-insert-unpulled-from-upstream - magit-status-sections-hook) - (memq 'magit-insert-unpulled-from-upstream-or-recent - magit-status-sections-hook))) + (when (magit--insert-pushremote-log-p) (magit-insert-section (unpulled (concat ".." it) t) (magit-insert-heading (format (propertize "Unpulled from %s." @@ -1725,12 +1810,7 @@ (defun magit-insert-unpushed-to-pushremote () "Insert commits that haven't been pushed to the push-remote yet." (--when-let (magit-get-push-branch) - (unless (and (equal (magit-rev-name it) - (magit-rev-name "@{upstream}")) - (or (memq 'magit-insert-unpushed-to-upstream - magit-status-sections-hook) - (memq 'magit-insert-unpushed-to-upstream-or-recent - magit-status-sections-hook))) + (when (magit--insert-pushremote-log-p) (magit-insert-section (unpushed (concat it "..") t) (magit-insert-heading (format (propertize "Unpushed to %s." @@ -1739,6 +1819,15 @@ (magit-insert-log (concat it "..") magit-buffer-log-args) (magit-log-insert-child-count))))) +(defun magit--insert-pushremote-log-p () + (magit--with-refresh-cache 'magit--insert-pushremote-log-p + (not (and (equal (magit-get-push-branch) + (magit-get-upstream-branch)) + (or (memq 'magit-insert-unpulled-from-upstream + magit-status-sections-hook) + (memq 'magit-insert-unpulled-from-upstream-or-recent + magit-status-sections-hook)))))) + (defun magit-log-insert-child-count () (when magit-section-show-child-count (let ((count (length (oref magit-insert-section--current children)))) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-margin.el magit-3.3.0/lisp/magit-margin.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-margin.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-margin.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-margin.el --- margins in Magit buffers -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -30,11 +32,6 @@ ;;; Code: -(require 'dash) - -(eval-when-compile - (require 'subr-x)) - (require 'magit-section) (require 'magit-transient) (require 'magit-mode) @@ -62,7 +59,7 @@ ;;; Commands -(define-transient-command magit-margin-settings () +(transient-define-prefix magit-margin-settings () "Change what information is displayed in the margin." :info-manual "(magit) Log Margin" ["Margin" diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-merge.el magit-3.3.0/lisp/magit-merge.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-merge.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-merge.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-merge.el --- merge functionality -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -27,9 +29,6 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) (require 'magit-diff) @@ -38,7 +37,7 @@ ;;; Commands ;;;###autoload (autoload 'magit-merge "magit" nil t) -(define-transient-command magit-merge () +(transient-define-prefix magit-merge () "Merge branches." :man-page "git-merge" :incompatible '(("--ff-only" "--no-ff")) @@ -47,7 +46,10 @@ ("-f" "Fast-forward only" "--ff-only") ("-n" "No fast-forward" "--no-ff") (magit-merge:--strategy) - (5 magit-diff:--diff-algorithm :argument "--Xdiff-algorithm=") + (5 magit-merge:--strategy-option) + (5 "-b" "Ignore changes in amount of whitespace" "-Xignore-space-change") + (5 "-w" "Ignore whitespace when comparing lines" "-Xignore-all-space") + (5 magit-diff:--diff-algorithm :argument "-Xdiff-algorithm=") (5 magit:--gpg-sign)] ["Actions" :if-not magit-merge-in-progress-p @@ -58,7 +60,7 @@ [("p" "Preview merge" magit-merge-preview) "" ("s" "Squash merge" magit-merge-squash) - ("i" "Merge into" magit-merge-into)]] + ("i" "Dissolve" magit-merge-into)]] ["Actions" :if magit-merge-in-progress-p ("m" "Commit merge" magit-commit-create) @@ -67,7 +69,7 @@ (defun magit-merge-arguments () (transient-args 'magit-merge)) -(define-infix-argument magit-merge:--strategy () +(transient-define-argument magit-merge:--strategy () :description "Strategy" :class 'transient-option ;; key for merge and rebase: "-s" @@ -78,6 +80,13 @@ :argument "--strategy=" :choices '("resolve" "recursive" "octopus" "ours" "subtree")) +(transient-define-argument magit-merge:--strategy-option () + :description "Strategy Option" + :class 'transient-option + :key "-X" + :argument "--strategy-option=" + :choices '("ours" "theirs" "patience")) + ;;;###autoload (defun magit-merge-plain (rev &optional args nocommit) "Merge commit REV into the current branch; using default message. @@ -133,15 +142,20 @@ branch, then also remove the respective remote branch." (interactive (list (magit-read-other-local-branch - (format "Merge `%s' into" (magit-get-current-branch)) + (format "Merge `%s' into" + (or (magit-get-current-branch) + (magit-rev-parse "HEAD"))) nil (when-let ((upstream (magit-get-upstream-branch)) (upstream (cdr (magit-split-branch-name upstream)))) (and (magit-branch-p upstream) upstream))) (magit-merge-arguments))) - (let ((current (magit-get-current-branch))) + (let ((current (magit-get-current-branch)) + (head (magit-rev-parse "HEAD"))) (when (zerop (magit-call-git "checkout" branch)) - (magit--merge-absorb current args)))) + (if current + (magit--merge-absorb current args) + (magit-run-git-with-editor "merge" args head))))) ;;;###autoload (defun magit-merge-absorb (branch &optional args) @@ -158,9 +172,10 @@ (magit--merge-absorb branch args)) (defun magit--merge-absorb (branch args) - (when (equal branch "master") + (when (equal branch (magit-main-branch)) (unless (yes-or-no-p - "Do you really want to merge `master' into another branch? ") + (format "Do you really want to merge `%s' into another branch? " + branch)) (user-error "Abort"))) (if-let ((target (magit-get-push-branch branch t))) (progn @@ -183,7 +198,9 @@ (format "Merge branch '%s'%s [#%s]" branch (let ((current (magit-get-current-branch))) - (if (equal current "master") "" (format " into %s" current))) + (if (equal current (magit-main-branch)) + "" + (format " into %s" current))) pr) branch) (magit-run-git-async "merge" args "--no-edit" branch)) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-mode.el magit-3.3.0/lisp/magit-mode.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-mode.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-mode.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-mode.el --- create and refresh Magit buffers -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -29,17 +31,13 @@ ;;; Code: -(require 'cl-lib) -(require 'dash) - -(eval-when-compile - (require 'subr-x)) - -(require 'transient) - (require 'magit-section) (require 'magit-git) +(require 'format-spec) +(require 'help-mode) +(require 'transient) + ;; For `magit-display-buffer-fullcolumn-most-v1' from `git-commit' (defvar git-commit-mode) ;; For `magit-refresh' @@ -57,9 +55,6 @@ ;; For `magit-mode' from `bookmark' (defvar bookmark-make-record-function) -(require 'format-spec) -(require 'help-mode) - ;;; Options (defcustom magit-mode-hook @@ -115,7 +110,7 @@ :type 'hook) (defcustom magit-display-buffer-function 'magit-display-buffer-traditional - "The function used display a Magit buffer. + "The function used to display a Magit buffer. All Magit buffers (buffers whose major-modes derive from `magit-mode') are displayed using `magit-display-buffer', @@ -202,9 +197,9 @@ :group 'magit-buffers :type 'boolean) -(defcustom magit-bury-buffer-function 'magit-restore-window-configuration +(defcustom magit-bury-buffer-function 'magit-mode-quit-window "The function used to bury or kill the current Magit buffer." - :package-version '(magit . "2.3.0") + :package-version '(magit . "3.2.0") :group 'magit-buffers :type '(radio (function-item quit-window) (function-item magit-mode-quit-window) @@ -231,10 +226,12 @@ buffer. For more information see info node `(magit)Transient Arguments -and Buffer Arguments'." +and Buffer Variables'." :package-version '(magit . "3.0.0") :group 'magit-buffers :group 'magit-commands + :group 'magit-diff + :group 'magit-log :type '(choice (const :tag "always use args from buffer" always) (const :tag "use args from buffer if displayed in frame" selected) @@ -262,10 +259,12 @@ buffer. For more information see info node `(magit)Transient Arguments -and Buffer Arguments'." +and Buffer Variables'." :package-version '(magit . "3.0.0") :group 'magit-buffers :group 'magit-commands + :group 'magit-diff + :group 'magit-log :type '(choice (const :tag "always use args from buffer" always) (const :tag "use args from buffer if displayed in frame" selected) @@ -337,22 +336,16 @@ (defvar magit-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map magit-section-mode-map) - (define-key map [C-return] 'magit-visit-thing) - (define-key map (kbd "C-m") 'magit-visit-thing) - (define-key map (kbd "C-M-i") 'magit-dired-jump) - (define-key map [M-tab] 'magit-section-cycle-diffs) - (define-key map (kbd "P") 'magit-push) - (define-key map (kbd "k") 'magit-delete-thing) - (define-key map (kbd "K") 'magit-file-untrack) - (define-key map (kbd "i") 'magit-gitignore) - (define-key map (kbd "I") 'magit-gitignore) - (define-key map (kbd "SPC") 'magit-diff-show-or-scroll-up) - (define-key map (kbd "DEL") 'magit-diff-show-or-scroll-down) - (define-key map "+" 'magit-diff-more-context) - (define-key map "-" 'magit-diff-less-context) - (define-key map "0" 'magit-diff-default-context) - (define-key map "$" 'magit-process-buffer) - (define-key map "%" 'magit-worktree) + (define-key map [C-return] 'magit-visit-thing) + (define-key map (kbd "RET") 'magit-visit-thing) + (define-key map (kbd "M-TAB") 'magit-dired-jump) + (define-key map [M-tab] 'magit-section-cycle-diffs) + (define-key map (kbd "SPC") 'magit-diff-show-or-scroll-up) + (define-key map (kbd "S-SPC") 'magit-diff-show-or-scroll-down) + (define-key map (kbd "DEL") 'magit-diff-show-or-scroll-down) + (define-key map "+" 'magit-diff-more-context) + (define-key map "-" 'magit-diff-less-context) + (define-key map "0" 'magit-diff-default-context) (define-key map "a" 'magit-cherry-apply) (define-key map "A" 'magit-cherry-pick) (define-key map "b" 'magit-branch) @@ -369,13 +362,26 @@ (define-key map "G" 'magit-refresh-all) (define-key map "h" 'magit-dispatch) (define-key map "?" 'magit-dispatch) + (define-key map "H" 'magit-describe-section) + (define-key map "i" 'magit-gitignore) + (define-key map "I" 'magit-init) + (define-key map "j" 'magit-status-quick) + (define-key map "J" 'magit-display-repository-buffer) + (define-key map "k" 'magit-delete-thing) + (define-key map "K" 'magit-file-untrack) (define-key map "l" 'magit-log) (define-key map "L" 'magit-log-refresh) (define-key map "m" 'magit-merge) (define-key map "M" 'magit-remote) + ;; section-map "n" magit-section-forward + ;; reserved "N" forge-dispatch (define-key map "o" 'magit-submodule) (define-key map "O" 'magit-subtree) + ;; section-map "p" magit-section-backward + (define-key map "P" 'magit-push) (define-key map "q" 'magit-mode-bury-buffer) + (define-key map "Q" 'magit-git-command) + (define-key map ":" 'magit-git-command) (define-key map "r" 'magit-rebase) (define-key map "R" 'magit-file-rename) (define-key map "s" 'magit-stage-file) @@ -393,15 +399,14 @@ (define-key map "y" 'magit-show-refs) (define-key map "Y" 'magit-cherry) (define-key map "z" 'magit-stash) - (define-key map "Z" 'magit-stash) - (define-key map ":" 'magit-git-command) + (define-key map "Z" 'magit-worktree) + (define-key map "%" 'magit-worktree) + (define-key map "$" 'magit-process-buffer) (define-key map "!" 'magit-run) (define-key map (kbd "C-c C-c") 'magit-dispatch) (define-key map (kbd "C-c C-e") 'magit-edit-thing) (define-key map (kbd "C-c C-o") 'magit-browse-thing) (define-key map (kbd "C-c C-w") 'magit-browse-thing) - (define-key map (kbd "C-x a") 'magit-add-change-log-entry) - (define-key map (kbd "C-x 4 a") 'magit-add-change-log-entry-other-window) (define-key map (kbd "C-w") 'magit-copy-section-value) (define-key map (kbd "M-w") 'magit-copy-buffer-revision) (define-key map [remap previous-line] 'magit-previous-line) @@ -423,7 +428,7 @@ Where applicable, section-specific keymaps bind another command which visits the thing at point." (interactive) - (if (eq current-transient-command 'magit-dispatch) + (if (eq transient-current-command 'magit-dispatch) (call-interactively (key-binding (this-command-keys))) (user-error "There is no thing at point that could be visited"))) @@ -432,7 +437,7 @@ Where applicable, section-specific keymaps bind another command which lets you edit the thing at point, likely in another buffer." (interactive) - (if (eq current-transient-command 'magit-dispatch) + (if (eq transient-current-command 'magit-dispatch) (call-interactively (key-binding (this-command-keys))) (user-error "There is no thing at point that could be edited"))) @@ -443,6 +448,11 @@ (interactive) (user-error "There is no thing at point that could be browsed")) +(defun magit-help () + "Visit the Magit manual." + (interactive) + (info "magit")) + (defvar bug-reference-map) (with-eval-after-load 'bug-reference (define-key bug-reference-map [remap magit-visit-thing] @@ -472,8 +482,8 @@ ["Cherry pick" magit-cherry-pick t] ["Revert commit" magit-revert t] "---" - ["Ignore globally" magit-gitignore-globally t] - ["Ignore locally" magit-gitignore-locally t] + ["Ignore at toplevel" magit-gitignore-in-topdir t] + ["Ignore in subdirectory" magit-gitignore-in-subdir t] ["Discard" magit-discard t] ["Reset head and index" magit-reset-mixed t] ["Stash" magit-stash-both t] @@ -513,10 +523,11 @@ Magit is documented in info node `(magit)'." :group 'magit (hack-dir-local-variables-non-file-buffer) + (face-remap-add-relative 'header-line 'magit-header-line) (setq mode-line-process (magit-repository-local-get 'mode-line-process)) - (setq-local bookmark-make-record-function 'magit--make-bookmark)) - -;;; Highlighting + (setq-local revert-buffer-function 'magit-refresh-buffer) + (setq-local bookmark-make-record-function 'magit--make-bookmark) + (setq-local isearch-filter-predicate 'magit-section--open-temporarily)) ;;; Local Variables @@ -694,7 +705,7 @@ (display-buffer buffer (if (with-current-buffer buffer (derived-mode-p 'magit-diff-mode 'magit-process-mode)) - nil ; display in another window + '(nil (inhibit-same-window . t)) '(display-buffer-same-window)))) (defun magit--display-buffer-fullframe (buffer alist) @@ -824,11 +835,11 @@ If no such buffer exists then return nil. Multiple buffers with the same major-mode may exist for a repository but only one can -exist that hasn't been looked to its value. Return that buffer +exist that hasn't been locked to its value. Return that buffer \(or nil if there is no such buffer) unless VALUE is non-nil, in -which case return the buffer that has been looked to that value. +which case return the buffer that has been locked to that value. -If FRAME nil or omitted, then consider all buffers. Otherwise +If FRAME is nil or omitted, then consider all buffers. Otherwise only consider buffers that are displayed in some live window on some frame. If `all', then consider all buffers on all frames. @@ -849,13 +860,13 @@ (w (window) (b (window-buffer window))) (f (frame) - (-some #'w (window-list frame 'no-minibuf)))) + (seq-some #'w (window-list frame 'no-minibuf)))) (pcase-exhaustive frame - (`nil (-some #'b (buffer-list))) - (`all (-some #'f (frame-list))) - (`visible (-some #'f (visible-frame-list))) - ((or `selected `t) (-some #'w (window-list (selected-frame)))) - ((guard (framep frame)) (-some #'w (window-list frame))))) + (`nil (seq-some #'b (buffer-list))) + (`all (seq-some #'f (frame-list))) + (`visible (seq-some #'f (visible-frame-list))) + ((or `selected `t) (seq-some #'w (window-list (selected-frame)))) + ((guard (framep frame)) (seq-some #'w (window-list frame))))) (magit--not-inside-repository-error))) (defun magit-mode-get-buffer (mode &optional create frame value) @@ -996,7 +1007,7 @@ ;;; Refresh Buffers -(defvar inhibit-magit-refresh nil) +(defvar magit-inhibit-refresh nil) (defun magit-refresh () "Refresh some buffers belonging to the current repository. @@ -1006,7 +1017,7 @@ Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'." (interactive) - (unless inhibit-magit-refresh + (unless magit-inhibit-refresh (unwind-protect (let ((start (current-time)) (magit--refresh-cache (or magit--refresh-cache @@ -1034,11 +1045,11 @@ (magit-run-hook-with-benchmark 'magit-post-unstage-hook))) (magit-run-hook-with-benchmark 'magit-post-refresh-hook) (when magit-refresh-verbose - (message "Refreshing magit...done (%.3fs, cached %s/%s)" - (float-time (time-subtract (current-time) start)) - (caar magit--refresh-cache) - (+ (caar magit--refresh-cache) - (cdar magit--refresh-cache))))) + (let* ((c (caar magit--refresh-cache)) + (a (+ c (cdar magit--refresh-cache)))) + (message "Refreshing magit...done (%.3fs, cached %s/%s (%.0f%%))" + (float-time (time-subtract (current-time) start)) + c a (* (/ c (* a 1.0)) 100))))) (run-hooks 'magit-unwind-refresh-hook)))) (defun magit-refresh-all () @@ -1058,7 +1069,7 @@ (defvar-local magit-refresh-start-time nil) -(defun magit-refresh-buffer () +(defun magit-refresh-buffer (&rest _ignore) "Refresh the current Magit buffer." (setq magit-refresh-start-time (current-time)) (let ((refresh (intern (format "%s-refresh-buffer" @@ -1068,18 +1079,23 @@ (when magit-refresh-verbose (message "Refreshing buffer `%s'..." (buffer-name))) (let* ((buffer (current-buffer)) - (windows - (--mapcat (with-selected-window it - (with-current-buffer buffer - (when-let ((section (magit-current-section))) - (list - (nconc (list it section) - (magit-refresh-get-relative-position)))))) - (or (get-buffer-window-list buffer nil t) - (list (selected-window)))))) + (windows (cl-mapcan + (lambda (window) + (with-selected-window window + (with-current-buffer buffer + (when-let ((section (magit-current-section))) + `(( ,window + ,section + ,@(magit-refresh-get-relative-position))))))) + ;; If it qualifies, then the selected window + ;; comes first, but we want to handle it last + ;; so that its `magit-section-movement-hook' + ;; run can override the effects of other runs. + (or (nreverse (get-buffer-window-list buffer nil t)) + (list (selected-window)))))) (deactivate-mark) + (setq magit-section-pre-command-section nil) (setq magit-section-highlight-overlays nil) - (setq magit-section-highlighted-section nil) (setq magit-section-highlighted-sections nil) (setq magit-section-unhighlight-sections nil) (magit-process-unset-mode-line-error-status) @@ -1088,9 +1104,12 @@ (save-excursion (apply refresh (with-no-warnings magit-refresh-args)))) (pcase-dolist (`(,window . ,args) windows) - (with-selected-window window + (if (eq buffer (window-buffer window)) + (with-selected-window window + (apply #'magit-section-goto-successor args)) (with-current-buffer buffer - (apply #'magit-section-goto-successor args)))) + (let ((magit-section-movement-hook nil)) + (apply #'magit-section-goto-successor args))))) (run-hooks 'magit-refresh-buffer-hook) (magit-section-update-highlight) (set-buffer-modified-p nil)) @@ -1102,7 +1121,8 @@ (defun magit-refresh-get-relative-position () (when-let ((section (magit-current-section))) (let ((start (oref section start))) - (list (count-lines start (point)) + (list (- (line-number-at-pos (point)) + (line-number-at-pos start)) (- (point) (line-beginning-position)) (and (magit-hunk-section-p section) (region-active-p) @@ -1262,7 +1282,8 @@ (defun magit-insert-xref-buttons () "Insert xref buttons." - (when (or help-xref-stack help-xref-forward-stack) + (when (and (not magit-buffer-locked-p) + (or help-xref-stack help-xref-forward-stack)) (when help-xref-stack (magit-xref-insert-button help-back-label 'magit-xref-backward)) (when help-xref-forward-stack @@ -1344,15 +1365,15 @@ (defun magit-repository-local-exists-p (key &optional repository) "Non-nil when a repository-local value exists for KEY. -Returns a (KEY . value) cons cell. +Return a (KEY . VALUE) cons cell. The KEY is matched using `equal'. Unless specified, REPOSITORY is the current buffer's repository." - (let* ((repokey (or repository (magit-repository-local-repository))) - (cache (assoc repokey magit-repository-local-cache))) - (and cache - (assoc key (cdr cache))))) + (when-let ((cache (assoc (or repository + (magit-repository-local-repository)) + magit-repository-local-cache))) + (assoc key (cdr cache)))) (defun magit-repository-local-get (key &optional default repository) "Return the repository-local value for KEY. @@ -1362,21 +1383,30 @@ The KEY is matched using `equal'. Unless specified, REPOSITORY is the current buffer's repository." - (let ((keyvalue (magit-repository-local-exists-p key repository))) - (if keyvalue - (cdr keyvalue) - default))) + (if-let ((keyvalue (magit-repository-local-exists-p key repository))) + (cdr keyvalue) + default)) (defun magit-repository-local-delete (key &optional repository) "Delete the repository-local value for KEY. Unless specified, REPOSITORY is the current buffer's repository." - (let* ((repokey (or repository (magit-repository-local-repository))) - (cache (assoc repokey magit-repository-local-cache))) - (when cache - ;; There is no `assoc-delete-all'. - (setf (cdr cache) - (cl-delete key (cdr cache) :key #'car :test #'equal))))) + (when-let ((cache (assoc (or repository + (magit-repository-local-repository)) + magit-repository-local-cache))) + ;; There is no `assoc-delete-all'. + (setf (cdr cache) + (cl-delete key (cdr cache) :key #'car :test #'equal)))) + +(defmacro magit--with-repository-local-cache (key &rest body) + (declare (indent 1) (debug (form body))) + (let ((k (cl-gensym))) + `(let ((,k ,key)) + (if-let ((kv (magit-repository-local-exists-p ,k))) + (cdr kv) + (let ((v ,(macroexp-progn body))) + (magit-repository-local-set ,k v) + v))))) (defun magit-preserve-section-visibility-cache () (when (derived-mode-p 'magit-status-mode 'magit-refs-mode) @@ -1403,7 +1433,7 @@ (dolist (buffer (magit-mode-get-buffers)) (with-current-buffer buffer (setq magit-section-visibility-cache nil))) - (setq magit--libgit-available-p eieio-unbound)) + (setq magit--libgit-available-p 'unknown)) ;;; Utilities diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-notes.el magit-3.3.0/lisp/magit-notes.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-notes.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-notes.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-notes.el --- notes support -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -32,7 +34,7 @@ ;;; Commands ;;;###autoload (autoload 'magit-notes "magit" nil t) -(define-transient-command magit-notes () +(transient-define-prefix magit-notes () "Edit notes attached to commits." :man-page "git-notes" ["Configure local settings" @@ -66,40 +68,40 @@ (and (file-directory-p dir) (directory-files dir nil "^[^.]")))) -(define-infix-command magit-core.notesRef () +(transient-define-infix magit-core.notesRef () :class 'magit--git-variable :variable "core.notesRef" :reader 'magit-notes-read-ref :prompt "Set local core.notesRef") -(define-infix-command magit-notes.displayRef () +(transient-define-infix magit-notes.displayRef () :class 'magit--git-variable :variable "notes.displayRef" :multi-value t :reader 'magit-notes-read-refs :prompt "Set local notes.displayRef") -(define-infix-command magit-global-core.notesRef () +(transient-define-infix magit-global-core.notesRef () :class 'magit--git-variable :variable "core.notesRef" :reader 'magit-notes-read-ref :prompt "Set global core.notesRef") -(define-infix-command magit-global-notes.displayRef () +(transient-define-infix magit-global-notes.displayRef () :class 'magit--git-variable :variable "notes.displayRef" :multi-value t :reader 'magit-notes-read-refs :prompt "Set global notes.displayRef") -(define-infix-argument magit-notes:--ref () - :description "Merge strategy" +(transient-define-argument magit-notes:--ref () + :description "Manipulate ref" :class 'transient-option :key "-r" :argument "--ref=" :reader 'magit-notes-read-ref) -(define-infix-argument magit-notes:--strategy () +(transient-define-argument magit-notes:--strategy () :description "Merge strategy" :class 'transient-option :shortarg "-s" @@ -174,7 +176,7 @@ it (concat "refs/notes/" it)))) -(defun magit-notes-read-refs (prompt) +(defun magit-notes-read-refs (prompt &optional _initial-input _history) (mapcar (lambda (ref) (if (string-prefix-p "refs/" ref) ref @@ -190,10 +192,10 @@ ",")))) (defun magit-notes-read-args (prompt) - (list (magit-read-branch-or-commit prompt (magit-stash-at-point)) - (--when-let (--first (string-match "^--ref=\\(.+\\)" it) - (transient-args 'magit-notes)) - (match-string 1 it)))) + (list (magit-read-branch-or-commit prompt (magit-stash-at-point)) + (--when-let (--first (string-match "^--ref=\\(.+\\)" it) + (transient-args 'magit-notes)) + (match-string 1 it)))) ;;; _ (provide 'magit-notes) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-obsolete.el magit-3.3.0/lisp/magit-obsolete.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-obsolete.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-obsolete.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-obsolete.el --- obsolete definitions -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -52,6 +54,9 @@ (define-obsolete-variable-alias 'magit-disable-line-numbers 'magit-section-disable-line-numbers "Magit 3.0.0") +(define-obsolete-variable-alias 'inhibit-magit-refresh + 'magit-inhibit-refresh "Magit 3.0.0") + (defun magit--magit-popup-warning () (display-warning 'magit "\ Magit no longer uses Magit-Popup. diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-patch.el magit-3.3.0/lisp/magit-patch.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-patch.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-patch.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-patch.el --- creating and applying patches -*- lexical-binding: t -*- -;; Copyright (C) 2008-2020 The Magit Project Contributors +;; Copyright (C) 2008-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -27,9 +29,6 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) ;;; Options @@ -55,16 +54,17 @@ ;;; Commands ;;;###autoload (autoload 'magit-patch "magit-patch" nil t) -(define-transient-command magit-patch () +(transient-define-prefix magit-patch () "Create or apply patches." ["Actions" - ("c" "Create patches" magit-patch-create) - ("a" "Apply patch" magit-patch-apply) - ("s" "Save diff as patch" magit-patch-save) - ("r" "Request pull" magit-request-pull)]) + [("c" "Create patches" magit-patch-create) + ("w" "Apply patches" magit-am)] + [("a" "Apply plain patch" magit-patch-apply) + ("s" "Save diff as patch" magit-patch-save)] + [("r" "Request pull" magit-request-pull)]]) ;;;###autoload (autoload 'magit-patch-create "magit-patch" nil t) -(define-transient-command magit-patch-create (range args files) +(transient-define-prefix magit-patch-create (range args files) "Create patches for the commits in RANGE. When a single commit is given for RANGE, create a patch for the changes introduced by that commit (unlike 'git format-patch' @@ -100,7 +100,7 @@ ["Actions" ("c" "Create patches" magit-patch-create)] (interactive - (if (not (eq current-transient-command 'magit-patch-create)) + (if (not (eq transient-current-command 'magit-patch-create)) (list nil nil nil) (cons (if-let ((revs (magit-region-values 'commit t))) (concat (car (last revs)) "^.." (car revs)) @@ -119,23 +119,21 @@ (save-match-data (find-file (expand-file-name - (concat (--some (and (string-match "\\`--reroll-count=\\(.+\\)" it) - (format "v%s-" (match-string 1 it))) - args) + (concat (when-let ((v (transient-arg-value "--reroll-count=" args))) + (format "v%s-" v)) "0000-cover-letter.patch") (let ((topdir (magit-toplevel))) - (or (--some (and (string-match "\\`--output-directory=\\(.+\\)" it) - (expand-file-name (match-string 1 it) topdir)) - args) - topdir)))))))) + (if-let ((dir (transient-arg-value "--output-directory=" args))) + (expand-file-name dir topdir) + topdir)))))))) -(define-infix-argument magit-format-patch:--in-reply-to () +(transient-define-argument magit-format-patch:--in-reply-to () :description "In reply to" :class 'transient-option :key "C-m C-r" :argument "--in-reply-to=") -(define-infix-argument magit-format-patch:--thread () +(transient-define-argument magit-format-patch:--thread () :description "Thread style" :class 'transient-option :key "C-m s " @@ -147,7 +145,7 @@ (?d "[d]eep" "deep") (?s "[s]hallow" "shallow"))) -(define-infix-argument magit-format-patch:--base () +(transient-define-argument magit-format-patch:--base () :description "Insert base commit" :class 'transient-option :key "C-m b " @@ -159,7 +157,7 @@ nil nil initial-input history "auto") (user-error "Nothing selected"))) -(define-infix-argument magit-format-patch:--reroll-count () +(transient-define-argument magit-format-patch:--reroll-count () :description "Reroll count" :class 'transient-option :key "C-m v " @@ -167,14 +165,14 @@ :argument "--reroll-count=" :reader 'transient-read-number-N+) -(define-infix-argument magit-format-patch:--interdiff () +(transient-define-argument magit-format-patch:--interdiff () :description "Insert interdiff" :class 'transient-option :key "C-m d i" :argument "--interdiff=" :reader #'magit-transient-read-revision) -(define-infix-argument magit-format-patch:--range-diff () +(transient-define-argument magit-format-patch:--range-diff () :description "Insert range-diff" :class 'transient-option :key "C-m d r" @@ -184,13 +182,13 @@ (defun magit-format-patch-select-range-diff (prompt _initial-input _history) (magit-read-range-or-commit prompt)) -(define-infix-argument magit-format-patch:--subject-prefix () +(transient-define-argument magit-format-patch:--subject-prefix () :description "Subject Prefix" :class 'transient-option :key "C-m p " :argument "--subject-prefix=") -(define-infix-argument magit-format-patch:--cover-from-description () +(transient-define-argument magit-format-patch:--cover-from-description () :description "Use branch description" :class 'transient-option :key "C-m D " @@ -204,35 +202,35 @@ (?a "[a]uto" "auto") (?n "[n]othing" "none"))) -(define-infix-argument magit-format-patch:--notes () +(transient-define-argument magit-format-patch:--notes () :description "Insert commentary from notes" :class 'transient-option :key "C-m n " :argument "--notes=" :reader #'magit-notes-read-ref) -(define-infix-argument magit-format-patch:--from () +(transient-define-argument magit-format-patch:--from () :description "From" :class 'transient-option :key "C-m C-f" :argument "--from=" :reader 'magit-transient-read-person) -(define-infix-argument magit-format-patch:--to () +(transient-define-argument magit-format-patch:--to () :description "To" :class 'transient-option :key "C-m C-t" :argument "--to=" :reader 'magit-transient-read-person) -(define-infix-argument magit-format-patch:--cc () +(transient-define-argument magit-format-patch:--cc () :description "CC" :class 'transient-option :key "C-m C-c" :argument "--cc=" :reader 'magit-transient-read-person) -(define-infix-argument magit-format-patch:--output-directory () +(transient-define-argument magit-format-patch:--output-directory () :description "Output directory" :class 'transient-option :key "C-m o " @@ -241,7 +239,7 @@ :reader 'transient-read-existing-directory) ;;;###autoload (autoload 'magit-patch-apply "magit-patch" nil t) -(define-transient-command magit-patch-apply (file &rest args) +(transient-define-prefix magit-patch-apply (file &rest args) "Apply the patch file FILE." :man-page "git-apply" ["Arguments" @@ -251,7 +249,7 @@ ["Actions" ("a" "Apply patch" magit-patch-apply)] (interactive - (if (not (eq current-transient-command 'magit-patch-apply)) + (if (not (eq transient-current-command 'magit-patch-apply)) (list nil) (list (expand-file-name (read-file-name "Apply patch: " @@ -308,7 +306,7 @@ ;;;###autoload (defun magit-request-pull (url start end) - "Request upstream to pull from you public repository. + "Request upstream to pull from your public repository. URL is the url of your publicly accessible repository. START is a commit that already is in the upstream repository. diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-pkg.el magit-3.3.0/lisp/magit-pkg.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-pkg.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-pkg.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,10 +1,10 @@ -(define-package "magit" "2.90.1" +(define-package "magit" "3.3.0" "A Git porcelain inside Emacs." '((emacs "25.1") - (async "20180527") - (dash "20180910") - (git-commit "20181104") - (transient "20190812") - (with-editor "20181103")) - :keywords - '("git" "tools" "vc")) + (dash "2.19.1") + (git-commit "3.3.0") + (magit-section "3.3.0") + (transient "0.3.6") + (with-editor "3.0.5")) + :homepage "https://magit.vc" + :keywords '("git" "tools" "vc")) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-process.el magit-3.3.0/lisp/magit-process.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-process.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-process.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-process.el --- process functionality -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -31,19 +33,14 @@ ;;; Code: -(require 'ansi-color) -(require 'cl-lib) -(require 'dash) - -(eval-when-compile - (require 'subr-x)) - -(require 'with-editor) (require 'magit-utils) (require 'magit-section) (require 'magit-git) (require 'magit-mode) +(require 'ansi-color) +(require 'with-editor) + (declare-function auth-source-search "auth-source" (&rest spec &key max require create delete &allow-other-keys)) @@ -99,6 +96,16 @@ :group 'magit-process :type '(choice (const :tag "Never remove old sections" nil) integer)) +(defvar magit-process-extreme-logging nil + "Whether `magit-process-file' logs to the *Messages* buffer. + +Only intended for temporary use when you try to figure out how +Magit uses Git behind the scene. Output that normally goes to +the magit-process buffer continues to go there. Not all output +goes to either of these two buffers. + +Also see `magit-git-debug'.") + (defcustom magit-process-error-tooltip-max-lines 20 "The number of lines for `magit-process-error-lines' to return. @@ -156,7 +163,7 @@ "\\([Nn]o?\\)" ;; OpenSSH v8 prints this. See #3969. "\\(?:/\\[fingerprint\\]\\)?" - "[\])] ?[?:] ?$") + "[\])] ?[?:]? ?$") "Regexp matching Yes-or-No prompts of Git and its subprocesses." :package-version '(magit . "2.1.0") :group 'magit-process @@ -169,11 +176,12 @@ "Please enter the passphrase for the ssh key" "Please enter the passphrase to unlock the OpenPGP secret key" "^.*'s password: ?$" + "^Token: $" ; For git-credential-manager-core (#4318). "^Yubikey for .*: ?$" "^Enter PIN for .*: ?$") "List of regexps matching password prompts of Git and its subprocesses. Also see `magit-process-find-password-functions'." - :package-version '(magit . "2.8.0") + :package-version '(magit . "3.0.0") :group 'magit-process :type '(repeat (regexp))) @@ -348,7 +356,7 @@ (defun magit-run-git (&rest args) "Call Git synchronously in a separate process, and refresh. -Option `magit-git-executable' specifies the Git executable and +Function `magit-git-executable' specifies the Git executable and option `magit-git-global-arguments' specifies constant arguments. The arguments ARGS specify arguments to Git, they are flattened before use. @@ -370,7 +378,7 @@ (defun magit-call-git (&rest args) "Call Git synchronously in a separate process. -Option `magit-git-executable' specifies the Git executable and +Function `magit-git-executable' specifies the Git executable and option `magit-git-global-arguments' specifies constant arguments. The arguments ARGS specify arguments to Git, they are flattened before use. @@ -379,7 +387,8 @@ `magit-process-buffer'." (run-hooks 'magit-pre-call-git-hook) (let ((default-process-coding-system (magit--process-coding-system))) - (apply #'magit-call-process magit-git-executable + (apply #'magit-call-process + (magit-git-executable) (magit-process-git-arguments args)))) (defun magit-call-process (program &rest args) @@ -393,11 +402,25 @@ (apply #'magit-process-file program nil process-buf nil args)) process-buf (current-buffer) default-directory section))) +(defun magit-process-git (destination &rest args) + "Call Git synchronously in a separate process, returning its exit code. +DESTINATION specifies how to handle the output, like for +`call-process', except that file handlers are supported. +Enable Cygwin's \"noglob\" option during the call and +ensure unix eol conversion." + (apply #'magit-process-file + (magit-git-executable) + nil destination nil + (magit-process-git-arguments args))) + (defun magit-process-file (process &optional infile buffer display &rest args) "Process files synchronously in a separate process. Identical to `process-file' but temporarily enable Cygwin's \"noglob\" option during the call and ensure unix eol conversion." + (when magit-process-extreme-logging + (let ((inhibit-message t)) + (message "$ %s" (magit-process--format-arguments process args)))) (let ((process-environment (magit-process-environment)) (default-process-coding-system (magit--process-coding-system))) (apply #'process-file process infile buffer display args))) @@ -426,10 +449,11 @@ "Call Git in a separate process. ARGS is flattened and then used as arguments to Git. -The current buffer's content is used as the process' standard -input. +The current buffer's content is used as the process's standard +input. The buffer is assumed to be temporary and thus OK to +modify. -Option `magit-git-executable' specifies the Git executable and +Function `magit-git-executable' specifies the Git executable and option `magit-git-global-arguments' specifies constant arguments. The remaining arguments ARGS specify arguments to Git, they are flattened before use." @@ -450,11 +474,11 @@ (default-process-coding-system (magit--process-coding-system)) (flat-args (magit-process-git-arguments args)) (`(,process-buf . ,section) - (magit-process-setup magit-git-executable flat-args)) + (magit-process-setup (magit-git-executable) flat-args)) (inhibit-read-only t)) (magit-process-finish (apply #'call-process-region (point-min) (point-max) - magit-git-executable nil process-buf nil flat-args) + (magit-git-executable) nil process-buf nil flat-args) process-buf nil default-directory section)))) ;;; Asynchronous Processes @@ -470,7 +494,7 @@ and still alive), as well as the respective Magit status buffer. See `magit-start-process' for more information." - (message "Running %s %s" magit-git-executable + (message "Running %s %s" (magit-git-executable) (let ((m (mapconcat #'identity (-flatten args) " "))) (remove-list-of-text-properties 0 (length m) '(face) m) m)) @@ -518,7 +542,7 @@ existing buffer. The buffer content becomes the processes standard input. -Option `magit-git-executable' specifies the Git executable and +Function `magit-git-executable' specifies the Git executable and option `magit-git-global-arguments' specifies constant arguments. The remaining arguments ARGS specify arguments to Git, they are flattened before use. @@ -530,7 +554,7 @@ See `magit-start-process' for more information." (run-hooks 'magit-pre-start-git-hook) (let ((default-process-coding-system (magit--process-coding-system))) - (apply #'magit-start-process magit-git-executable input + (apply #'magit-start-process (magit-git-executable) input (magit-process-git-arguments args)))) (defun magit-start-process (program &optional input &rest args) @@ -570,11 +594,11 @@ (when (eq system-type 'windows-nt) ;; On w32, git expects UTF-8 encoded input, ignore any user ;; configuration telling us otherwise. - (set-process-coding-system process 'utf-8-unix)) + (set-process-coding-system process nil 'utf-8-unix)) (process-put process 'section section) (process-put process 'command-buf (current-buffer)) (process-put process 'default-dir default-directory) - (when inhibit-magit-refresh + (when magit-inhibit-refresh (process-put process 'inhibit-refresh t)) (oset section process process) (with-current-buffer process-buf @@ -601,7 +625,7 @@ (default-process-coding-system (magit--process-coding-system))) (apply #'start-file-process "git" process-buf - magit-git-executable args)))) + (magit-git-executable) args)))) (process-put process 'command-buf command-buf) (process-put process 'parsed (point)) (setq magit-this-process process) @@ -630,25 +654,7 @@ (unless (equal (expand-file-name pwd) (expand-file-name default-directory)) (insert (file-relative-name pwd default-directory) ?\s)) - (cond - ((and args (equal program magit-git-executable)) - (setq args (-split-at (length magit-git-global-arguments) args)) - (insert (propertize (file-name-nondirectory program) - 'font-lock-face 'magit-section-heading) " ") - (insert (propertize (char-to-string magit-ellipsis) - 'font-lock-face 'magit-section-heading - 'help-echo (mapconcat #'identity (car args) " "))) - (insert " ") - (insert (propertize (mapconcat #'shell-quote-argument (cadr args) " ") - 'font-lock-face 'magit-section-heading))) - ((and args (equal program shell-file-name)) - (insert (propertize (cadr args) - 'font-lock-face 'magit-section-heading))) - (t - (insert (propertize (file-name-nondirectory program) - 'font-lock-face 'magit-section-heading) " ") - (insert (propertize (mapconcat #'shell-quote-argument args " ") - 'font-lock-face 'magit-section-heading)))) + (insert (magit-process--format-arguments program args)) (magit-insert-heading) (when errlog (if (bufferp errlog) @@ -658,6 +664,32 @@ (goto-char (1- (point-max))))) (insert "\n")))) +(defun magit-process--format-arguments (program args) + (cond + ((and args (equal program (magit-git-executable))) + (setq args (-split-at (length magit-git-global-arguments) args)) + (concat (propertize (file-name-nondirectory program) + 'font-lock-face 'magit-section-heading) + " " + (propertize (if (stringp magit-ellipsis) + magit-ellipsis + ;; For backward compatibility. + (char-to-string magit-ellipsis)) + 'font-lock-face 'magit-section-heading + 'help-echo (mapconcat #'identity (car args) " ")) + " " + (propertize (mapconcat #'shell-quote-argument (cadr args) " ") + 'font-lock-face 'magit-section-heading))) + ((and args (equal program shell-file-name)) + (propertize (cadr args) + 'font-lock-face 'magit-section-heading)) + (t + (concat (propertize (file-name-nondirectory program) + 'font-lock-face 'magit-section-heading) + " " + (propertize (mapconcat #'shell-quote-argument args " ") + 'font-lock-face 'magit-section-heading))))) + (defun magit-process-truncate-log () (let* ((head nil) (tail (oref magit-root-section children)) @@ -743,7 +775,9 @@ (let ((map (cl-gensym))) `(let ((,map (make-sparse-keymap))) (set-keymap-parent ,map minibuffer-local-map) - (define-key ,map "\C-g" + ;; Note: Leaving (kbd ...) unevaluated leads to the + ;; magit-process:password-prompt test failing. + (define-key ,map ,(kbd "C-g") (lambda () (interactive) (ignore-errors (kill-process ,proc)) @@ -775,13 +809,38 @@ 'magit-process-password-auth-source) KEY typically derives from a prompt such as: - Password for 'https://tarsius@bitbucket.org' + Password for 'https://yourname@github.com' in which case it would be the string - tarsius@bitbucket.org + yourname@github.com which matches the ~/.authinfo.gpg entry - machine bitbucket.org login tarsius password 12345 + machine github.com login yourname password 12345 or iff that is undefined, for backward compatibility - machine tarsius@bitbucket.org password 12345" + machine yourname@github.com password 12345 + +On github.com you should not use your password but a +personal access token, see [1]. For information about +the peculiarities of other forges, please consult the +respective documentation. + +After manually editing ~/.authinfo.gpg you must reset +the cache using + M-x auth-source-forget-all-cached RET + +The above will save you from having to repeatedly type +your token or password, but you might still repeatedly +be asked for your username. To prevent that, change an +URL like + https://github.com/foo/bar.git +to + https://yourname@github.com/foo/bar.git + +Instead of changing all such URLs manually, they can +be translated on the fly by doing this once + git config --global \ + url.https://yourname@github.com.insteadOf \ + https://github.com + +[1]: https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token." (require 'auth-source) (and (string-match "\\`\\(.+\\)@\\([^@]+\\)\\'" key) (let* ((user (match-string 1 key)) @@ -795,12 +854,26 @@ (funcall secret) secret)))) +(defun magit-process-git-credential-manager-core (process string) + "Authenticate using `git-credential-manager-core'. + +To use this function add it to the appropriate hook + (add-hook \\='magit-process-prompt-functions + \\='magit-process-git-credential-manager-core)" + (and (string-match "^option (enter for default): $" string) + (progn + (magit-process-buffer) + (let ((option (format "%c\n" + (read-char-choice "Option: " '(?\r ?\j ?1 ?2))))) + (insert-before-markers-and-inherit option) + (process-send-string process option))))) + (defun magit-process-password-prompt (process string) "Find a password based on prompt STRING and send it to git. Use `magit-process-password-prompt-regexps' to find a known prompt. If and only if one is found, then call functions in `magit-process-find-password-functions' until one of them returns -the password. If all function return nil, then read the password +the password. If all functions return nil, then read the password from the user." (when-let ((prompt (magit-process-match-prompt magit-process-password-prompt-regexps string))) @@ -864,7 +937,7 @@ (condition-case nil (start-process "git-credential-cache--daemon" " *git-credential-cache--daemon*" - magit-git-executable + (magit-git-executable) "credential-cache--daemon" magit-credential-cache-daemon-socket) ;; Some Git implementations (e.g. Windows) won't have @@ -907,7 +980,7 @@ (defun magit-process-set-mode-line (program args) "Display the git command (sans arguments) in the mode line." - (when (equal program magit-git-executable) + (when (equal program (magit-git-executable)) (setq args (nthcdr (length magit-git-global-arguments) args))) (let ((str (concat " " (propertize (concat (file-name-nondirectory program) @@ -956,8 +1029,8 @@ ;; The following closure captures the repokey value, and is ;; added to `pre-command-hook'. (cl-labels ((enable-magit-process-unset-mode-line - () ;; Remove ourself from the hook variable, so - ;; that we only run once. + () ;;; Remove ourself from the hook variable, so + ;;; that we only run once. (remove-hook 'pre-command-hook #'enable-magit-process-unset-mode-line) ;; Clear the inhibit flag for the repository in diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-pull.el magit-3.3.0/lisp/magit-pull.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-pull.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-pull.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-pull.el --- update local objects and refs -*- lexical-binding: t -*- -;; Copyright (C) 2008-2020 The Magit Project Contributors +;; Copyright (C) 2008-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -40,7 +42,7 @@ ;;; Commands ;;;###autoload (autoload 'magit-pull "magit-pull" nil t) -(define-transient-command magit-pull () +(transient-define-prefix magit-pull () "Pull from another repository." :man-page "git-pull" [:description @@ -77,7 +79,7 @@ (transient-args 'magit-pull)) ;;;###autoload (autoload 'magit-pull-from-pushremote "magit-pull" nil t) -(define-suffix-command magit-pull-from-pushremote (args) +(transient-define-suffix magit-pull-from-pushremote (args) "Pull from the push-remote of the current branch. With a prefix argument or when the push-remote is either not @@ -107,7 +109,7 @@ (format "%s, setting that" v))))) ;;;###autoload (autoload 'magit-pull-from-upstream "magit-pull" nil t) -(define-suffix-command magit-pull-from-upstream (args) +(transient-define-suffix magit-pull-from-upstream (args) "Pull from the upstream of the current branch. With a prefix argument or when the upstream is either not diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-push.el magit-3.3.0/lisp/magit-push.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-push.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-push.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-push.el --- update remote objects and refs -*- lexical-binding: t -*- -;; Copyright (C) 2008-2020 The Magit Project Contributors +;; Copyright (C) 2008-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -27,15 +29,12 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) ;;; Commands ;;;###autoload (autoload 'magit-push "magit-push" nil t) -(define-transient-command magit-push () +(transient-define-prefix magit-push () "Push to another repository." :man-page "git-push" ["Arguments" @@ -78,7 +77,7 @@ (format "%s:%s%s" branch namespace target)))) ;;;###autoload (autoload 'magit-push-current-to-pushremote "magit-push" nil t) -(define-suffix-command magit-push-current-to-pushremote (args) +(transient-define-suffix magit-push-current-to-pushremote (args) "Push the current branch to its push-remote. When the push-remote is not configured, then read the push-remote @@ -87,8 +86,14 @@ :if 'magit-get-current-branch :description 'magit-push--pushbranch-description (interactive (list (magit-push-arguments))) - (pcase-let ((`(,branch ,remote) + (pcase-let ((`(,branch ,remote ,changed) (magit--select-push-remote "push there"))) + (when changed + (magit-confirm 'set-and-push + (replace-regexp-in-string + "%" "%%" + (format "Really use \"%s\" as push-remote and push \"%s\" there" + remote branch)))) (run-hooks 'magit-credential-hook) (magit-run-git-async "push" "-v" args remote (format "refs/heads/%s:refs/heads/%s" @@ -111,7 +116,7 @@ (format "%s, setting that" v))))) ;;;###autoload (autoload 'magit-push-current-to-upstream "magit-push" nil t) -(define-suffix-command magit-push-current-to-upstream (args) +(transient-define-suffix magit-push-current-to-upstream (args) "Push the current branch to its upstream branch. With a prefix argument or when the upstream is either not @@ -136,16 +141,21 @@ branches nil nil nil 'magit-revision-history (or (car (member (magit-remote-branch-at-point) branches)) (car (member "origin/master" branches))))) - (upstream (or (magit-get-tracked upstream) - (magit-split-branch-name upstream)))) - (setq remote (car upstream)) - (setq merge (cdr upstream)) + (upstream* (or (magit-get-tracked upstream) + (magit-split-branch-name upstream)))) + (setq remote (car upstream*)) + (setq merge (cdr upstream*)) (unless (string-prefix-p "refs/" merge) ;; User selected a non-existent remote-tracking branch. ;; It is very likely, but not certain, that this is the ;; correct thing to do. It is even more likely that it ;; is what the user wants to happen. - (setq merge (concat "refs/heads/" merge)))) + (setq merge (concat "refs/heads/" merge))) + (magit-confirm 'set-and-push + (replace-regexp-in-string + "%" "%%" + (format "Really use \"%s\" as upstream and push \"%s\" there" + upstream branch)))) (cl-pushnew "--set-upstream" args :test #'equal)) (run-hooks 'magit-credential-hook) (magit-run-git-async "push" "-v" args remote (concat branch ":" merge)))) @@ -211,11 +221,10 @@ is used." (interactive (list (magit-read-remote "Push to remote") - (split-string (magit-completing-read-multiple - "Push refspec,s" - (cons "HEAD" (magit-list-local-branch-names)) - nil nil 'magit-push-refspecs-history) - crm-default-separator t) + (magit-completing-read-multiple* + "Push refspec,s: " + (cons "HEAD" (magit-list-local-branch-names)) + nil nil nil 'magit-push-refspecs-history) (magit-push-arguments))) (run-hooks 'magit-credential-hook) (magit-run-git-async "push" "-v" args remote refspecs)) @@ -262,8 +271,8 @@ (run-hooks 'magit-credential-hook) (magit-run-git-async "push" remote ref args)) -;;;###autoload -(defun magit-push-implicitly (args) +;;;###autoload (autoload 'magit-push-implicitly "magit-push" nil t) +(transient-define-suffix magit-push-implicitly (args) "Push somewhere without using an explicit refspec. This command simply runs \"git push -v [ARGS]\". ARGS are the @@ -273,9 +282,13 @@ `branch..pushRemote', `branch..remote', `branch..merge', and `remote..push'. -The function `magit-push-implicitly--desc' attempts to predict -what this command will do. The value it returns is displayed in -the popup buffer." +If you add this suffix to a transient prefix without explicitly +specifying the description, then an attempt is made to predict +what this command will do. For example: + + (transient-insert-suffix 'magit-push \"p\" + '(\"i\" magit-push-implicitly))" + :description 'magit-push-implicitly--desc (interactive (list (magit-push-arguments))) (run-hooks 'magit-credential-hook) (magit-run-git-async "push" "-v" args)) @@ -284,7 +297,7 @@ (let ((default (magit-get "push.default"))) (unless (equal default "nothing") (or (when-let ((remote (or (magit-get-remote) - (magit-remote-p "origin"))) + (magit-primary-remote))) (refspec (magit-get "remote" remote "push"))) (format "%s using %s" (magit--propertize-face remote 'magit-branch-remote) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-reflog.el magit-3.3.0/lisp/magit-reflog.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-reflog.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-reflog.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-reflog.el --- inspect ref history -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -30,9 +32,6 @@ (require 'magit-core) (require 'magit-log) -(eval-when-compile - (require 'subr-x)) - ;;; Options (defcustom magit-reflog-limit 256 @@ -137,8 +136,8 @@ (defvar magit-reflog-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map magit-log-mode-map) - (define-key map "\C-c\C-n" 'undefined) - (define-key map "L" 'magit-margin-settings) + (define-key map (kbd "C-c C-n") 'undefined) + (define-key map (kbd "L") 'magit-margin-settings) map) "Keymap for `magit-reflog-mode'.") diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-refs.el magit-3.3.0/lisp/magit-refs.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-refs.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-refs.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-refs.el --- listing references -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -27,9 +29,6 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) ;;; Options @@ -64,7 +63,7 @@ nil Never show counts. To change the value in an existing buffer use the command -`magit-refs-show-commit-count'" +`magit-refs-set-show-commit-count'." :package-version '(magit . "2.1.0") :group 'magit-refs :safe (lambda (val) (memq val '(all branch nil))) @@ -278,8 +277,8 @@ (defvar magit-refs-mode-map (let ((map (make-sparse-keymap))) (set-keymap-parent map magit-mode-map) - (define-key map "\C-y" 'magit-refs-set-show-commit-count) - (define-key map "L" 'magit-margin-settings) + (define-key map (kbd "C-y") 'magit-refs-set-show-commit-count) + (define-key map (kbd "L") 'magit-margin-settings) map) "Keymap for `magit-refs-mode'.") @@ -327,24 +326,24 @@ ;;; Commands ;;;###autoload (autoload 'magit-show-refs "magit-refs" nil t) -(define-transient-command magit-show-refs (&optional transient) +(transient-define-prefix magit-show-refs (&optional transient) "List and compare references in a dedicated buffer." :man-page "git-branch" :value (lambda () (magit-show-refs-arguments magit-prefix-use-buffer-arguments)) ["Arguments" (magit-for-each-ref:--contains) - ("=m" "Merged" "--merged=" magit-transient-read-revision) + ("-M" "Merged" "--merged=" magit-transient-read-revision) ("-m" "Merged to HEAD" "--merged") - ("-M" "Merged to master" "--merged=master") - ("=n" "Not merged" "--no-merged=" magit-transient-read-revision) + ("-N" "Not merged" "--no-merged=" magit-transient-read-revision) ("-n" "Not merged to HEAD" "--no-merged") - ("-N" "Not merged to master" "--no-merged=master") (magit-for-each-ref:--sort)] ["Actions" ("y" "Show refs, comparing them with HEAD" magit-show-refs-head) ("c" "Show refs, comparing them with current branch" magit-show-refs-current) - ("o" "Show refs, comparing them with other branch" magit-show-refs-other)] + ("o" "Show refs, comparing them with other branch" magit-show-refs-other) + ("r" "Show refs, changing commit count display" + magit-refs-set-show-commit-count)] (interactive (list (or (derived-mode-p 'magit-refs-mode) current-prefix-arg))) (if transient @@ -356,7 +355,7 @@ (setq use-buffer-args magit-direct-use-buffer-arguments)) (let (args) (cond - ((eq current-transient-command 'magit-show-refs) + ((eq transient-current-command 'magit-show-refs) (setq args (transient-args 'magit-show-refs))) ((eq major-mode 'magit-refs-mode) (setq args magit-buffer-arguments)) @@ -370,14 +369,14 @@ (setq args (alist-get 'magit-show-refs transient-values)))) args)) -(define-infix-argument magit-for-each-ref:--contains () +(transient-define-argument magit-for-each-ref:--contains () :description "Contains" :class 'transient-option :key "-c" :argument "--contains=" :reader 'magit-transient-read-revision) -(define-infix-argument magit-for-each-ref:--sort () +(transient-define-argument magit-for-each-ref:--sort () :description "Sort" :class 'transient-option :key "-s" @@ -530,9 +529,12 @@ (magit-insert-heading (magit-refs--format-focus-column tag 'tag) (propertize tag 'font-lock-face 'magit-tag) - (make-string (max 1 (- magit-refs-primary-column-width - (length tag))) - ?\s) + (make-string + (max 1 (- (if (consp magit-refs-primary-column-width) + (car magit-refs-primary-column-width) + magit-refs-primary-column-width) + (length tag))) + ?\s) (and msg (magit-log-propertize-keywords nil msg))) (when (and magit-refs-margin-for-tags (magit-buffer-margin-p)) (magit-refs--format-margin tag)) @@ -571,9 +573,12 @@ (magit-refs--format-focus-column branch) (magit-refs--propertize-branch abbrev ref (and headp 'magit-branch-remote-head)) - (make-string (max 1 (- magit-refs-primary-column-width - (length abbrev))) - ?\s) + (make-string + (max 1 (- (if (consp magit-refs-primary-column-width) + (car magit-refs-primary-column-width) + magit-refs-primary-column-width) + (length abbrev))) + ?\s) (and msg (magit-log-propertize-keywords nil msg)))) (when (magit-buffer-margin-p) (magit-refs--format-margin branch)) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-remote.el magit-3.3.0/lisp/magit-remote.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-remote.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-remote.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-remote.el --- transfer Git commits -*- lexical-binding: t -*- -;; Copyright (C) 2008-2020 The Magit Project Contributors +;; Copyright (C) 2008-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -64,7 +66,7 @@ ;;; Commands ;;;###autoload (autoload 'magit-remote "magit-remote" nil t) -(define-transient-command magit-remote (remote) +(transient-define-prefix magit-remote (remote) "Add, configure or remove a remote." :man-page "git-remote" :value '("-f") @@ -85,7 +87,8 @@ ("k" "Remove" magit-remote-remove)] [("C" "Configure..." magit-remote-configure) ("p" "Prune stale branches" magit-remote-prune) - ("P" "Prune stale refspecs" magit-remote-prune-refspecs)]] + ("P" "Prune stale refspecs" magit-remote-prune-refspecs) + (7 "z" "Unshallow remote" magit-remote-unshallow)]] (interactive (list (magit-get-current-remote))) (transient-setup 'magit-remote nil nil :scope remote)) @@ -98,9 +101,16 @@ ;;;###autoload (defun magit-remote-add (remote url &optional args) "Add a remote named REMOTE and fetch it." - (interactive (list (magit-read-string-ns "Remote name") - (magit-read-url "Remote url") - (transient-args 'magit-remote))) + (interactive + (let ((origin (magit-get "remote.origin.url")) + (remote (magit-read-string-ns "Remote name"))) + (list remote + (magit-read-url + "Remote url" + (and origin + (string-match "\\([^:/]+\\)/[^/]+\\(\\.git\\)?\\'" origin) + (replace-match remote t t origin 1))) + (transient-args 'magit-remote)))) (if (pcase (list magit-remote-add-set-remote.pushDefault (magit-get "remote.pushDefault")) (`(,(pred stringp) ,_) t) @@ -248,10 +258,28 @@ (interactive (list (magit-read-remote "Unset HEAD for remote"))) (magit-run-git "remote" "set-head" remote "--delete")) +;;;###autoload +(defun magit-remote-unshallow (remote) + "Convert a shallow remote into a full one. +If only a single refspec is set and it does not contain a +wildcard, then also offer to replace it with the standard +refspec." + (interactive (list (or (magit-get-current-remote) + (magit-read-remote "Delete remote")))) + (let ((refspecs (magit-get-all "remote" remote "fetch")) + (standard (format "+refs/heads/*:refs/remotes/%s/*" remote))) + (when (and (= (length refspecs) 1) + (not (string-match-p "\\*" (car refspecs))) + (yes-or-no-p (format "Also replace refspec %s with %s? " + (car refspecs) + standard))) + (magit-set standard "remote" remote "fetch")) + (magit-git-fetch "--unshallow" remote))) + ;;; Configure ;;;###autoload (autoload 'magit-remote-configure "magit-remote" nil t) -(define-transient-command magit-remote-configure (remote) +(transient-define-prefix magit-remote-configure (remote) "Configure a remote." :man-page "git-remote" [:description @@ -267,7 +295,7 @@ (interactive (list (or (and (not current-prefix-arg) (not (and magit-remote-direct-configure - (eq current-transient-command 'magit-remote))) + (eq transient-current-command 'magit-remote))) (magit-get-current-remote)) (magit--read-remote-scope)))) (transient-setup 'magit-remote-configure nil nil :scope remote)) @@ -279,20 +307,20 @@ (format (oref obj variable) "")) "Configure remote"))) -(define-infix-command magit-remote..url () +(transient-define-infix magit-remote..url () :class 'magit--git-variable:urls :scope 'magit--read-remote-scope :variable "remote.%s.url" :multi-value t :history-key 'magit-remote..*url) -(define-infix-command magit-remote..fetch () +(transient-define-infix magit-remote..fetch () :class 'magit--git-variable :scope 'magit--read-remote-scope :variable "remote.%s.fetch" :multi-value t) -(define-infix-command magit-remote..pushurl () +(transient-define-infix magit-remote..pushurl () :class 'magit--git-variable:urls :scope 'magit--read-remote-scope :variable "remote.%s.pushurl" @@ -300,12 +328,12 @@ :history-key 'magit-remote..*url :seturl-arg "--push") -(define-infix-command magit-remote..push () +(transient-define-infix magit-remote..push () :class 'magit--git-variable :scope 'magit--read-remote-scope :variable "remote.%s.push") -(define-infix-command magit-remote..tagopt () +(transient-define-infix magit-remote..tagopt () :class 'magit--git-variable:choices :scope 'magit--read-remote-scope :variable "remote.%s.tagOpt" @@ -325,16 +353,18 @@ (defun magit--select-push-remote (prompt-suffix) (let* ((branch (or (magit-get-current-branch) (user-error "No branch is checked out"))) - (remote (magit-get-push-remote branch))) + (remote (magit-get-push-remote branch)) + (changed nil)) (when (or current-prefix-arg (not remote) (not (member remote (magit-list-remotes)))) + (setq changed t) (setq remote (magit-read-remote (format "Set %s and %s" (magit--push-remote-variable) prompt-suffix))) (setf (magit-get (magit--push-remote-variable branch)) remote)) - (list branch remote))) + (list branch remote changed))) ;;; _ (provide 'magit-remote) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-repos.el magit-3.3.0/lisp/magit-repos.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-repos.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-repos.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-repos.el --- listing repositories -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -29,9 +31,6 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit-core) (declare-function magit-status-setup-buffer "magit-status" (directory)) @@ -89,10 +88,16 @@ tree. It has to return a string to be inserted or nil. PROPS is an alist that supports the keys `:right-align' and `:pad-right'. Some entries also use `:help-echo', but `tabulated-list' does not -actually support that yet." +actually support that yet. + +You may wish to display a range of numeric columns using just one +character per column and without any padding between columns, in +which case you should use an appropriat HEADER, set WIDTH to 1, +and set `:pad-right' to 0. \"+\" is substituted for numbers higher +than 9." :package-version '(magit . "2.12.0") :group 'magit-repolist - :type `(repeat (list :tag "Column" + :type '(repeat (list :tag "Column" (string :tag "Header Label") (integer :tag "Column Width") (function :tag "Inserter Function") @@ -119,6 +124,18 @@ :type '(alist :key-type (function :tag "Predicate Function") :value-type (string :tag "Flag"))) +(defcustom magit-repolist-sort-key '("Path" . nil) + "Initial sort key for buffer created by `magit-list-repositories'. +If nil, no additional sorting is performed. Otherwise, this +should be a cons cell (NAME . FLIP). NAME is a string matching +one of the column names in `magit-repolist-columns'. FLIP, if +non-nil, means to invert the resulting sort." + :package-version '(magit . "3.2.0") + :group 'magit-repolist + :type '(choice (const nil) + (cons (string :tag "Column name") + (boolean :tag "Flip order")))) + ;;; List Repositories ;;;; Command ;;;###autoload @@ -128,14 +145,7 @@ Use the options `magit-repository-directories' to control which repositories are displayed." (interactive) - (if magit-repository-directories - (with-current-buffer (get-buffer-create "*Magit Repositories*") - (magit-repolist-mode) - (magit-repolist-refresh) - (tabulated-list-print) - (switch-to-buffer (current-buffer))) - (message "You need to customize `magit-repository-directories' %s" - "before you can list repositories"))) + (magit-repolist-setup (default-value 'magit-repolist-columns))) ;;;; Mode @@ -157,43 +167,67 @@ "Major mode for browsing a list of Git repositories." (setq-local x-stretch-cursor nil) (setq tabulated-list-padding 0) - (setq tabulated-list-sort-key (cons "Path" nil)) - (setq tabulated-list-format - (vconcat (mapcar (pcase-lambda (`(,title ,width ,_fn ,props)) - (nconc (list title width t) - (-flatten props))) - magit-repolist-columns))) - (tabulated-list-init-header) (add-hook 'tabulated-list-revert-hook 'magit-repolist-refresh nil t) (setq imenu-prev-index-position-function 'magit-imenu--repolist-prev-index-position-function) (setq imenu-extract-index-name-function 'magit-imenu--repolist-extract-index-name-function)) +(defun magit-repolist-setup (columns) + (unless magit-repository-directories + (user-error "You need to customize `magit-repository-directories' %s" + "before you can list repositories")) + (with-current-buffer (get-buffer-create "*Magit Repositories*") + (magit-repolist-mode) + (setq-local magit-repolist-columns columns) + (magit-repolist-refresh) + (switch-to-buffer (current-buffer)))) + (defun magit-repolist-refresh () + (unless tabulated-list-sort-key + (setq tabulated-list-sort-key + (pcase-let ((`(,column . ,flip) magit-repolist-sort-key)) + (cons (or (car (assoc column magit-repolist-columns)) + (caar magit-repolist-columns)) + flip)))) + (setq tabulated-list-format + (vconcat (mapcar (pcase-lambda (`(,title ,width ,_fn ,props)) + (nconc (list title width t) + (-flatten props))) + magit-repolist-columns))) (setq tabulated-list-entries (mapcar (pcase-lambda (`(,id . ,path)) (let ((default-directory path)) (list path - (vconcat (--map (or (funcall (nth 2 it) id) "") - magit-repolist-columns))))) + (vconcat + (mapcar (pcase-lambda (`(,title ,width ,fn ,props)) + (or (funcall fn `((:id ,id) + (:title ,title) + (:width ,width) + ,@props)) + "")) + magit-repolist-columns))))) (magit-list-repos-uniquify (--map (cons (file-name-nondirectory (directory-file-name it)) it) - (magit-list-repos)))))) + (magit-list-repos))))) + (message "Listing repositories...") + (tabulated-list-init-header) + (tabulated-list-print) + (message "Listing repositories...done")) ;;;; Columns -(defun magit-repolist-column-ident (id) +(defun magit-repolist-column-ident (spec) "Insert the identification of the repository. Usually this is just its basename." - id) + (cadr (assq :id spec))) -(defun magit-repolist-column-path (_id) +(defun magit-repolist-column-path (_) "Insert the absolute path of the repository." (abbreviate-file-name default-directory)) -(defun magit-repolist-column-version (_id) +(defun magit-repolist-column-version (_) "Insert a description of the repository's `HEAD' revision." (when-let ((v (or (magit-git-string "describe" "--tags" "--dirty") ;; If there are no tags, use the date in MELPA format. @@ -206,15 +240,15 @@ (concat " " v) v)))) -(defun magit-repolist-column-branch (_id) +(defun magit-repolist-column-branch (_) "Insert the current branch." (magit-get-current-branch)) -(defun magit-repolist-column-upstream (_id) +(defun magit-repolist-column-upstream (_) "Insert the upstream branch of the current branch." (magit-get-upstream-branch)) -(defun magit-repolist-column-flag (_id) +(defun magit-repolist-column-flag (_) "Insert a flag as specified by `magit-repolist-column-flag-alist'. By default this indicates whether there are uncommitted changes. @@ -222,47 +256,54 @@ - U if there is at least one unstaged file. - S if there is at least one staged file. Only one letter is shown, the first that applies." - (-some (pcase-lambda (`(,fun . ,flag)) - (and (funcall fun) flag)) - magit-repolist-column-flag-alist)) + (seq-some (pcase-lambda (`(,fun . ,flag)) + (and (funcall fun) flag)) + magit-repolist-column-flag-alist)) + +(defun magit-repolist-column-flags (_) + "Insert all flags as specified by `magit-repolist-column-flag-alist'. +This is an alternative to function `magit-repolist-column-flag', +which only lists the first one found." + (mapconcat (pcase-lambda (`(,fun . ,flag)) + (if (funcall fun) flag " ")) + magit-repolist-column-flag-alist + "")) -(defun magit-repolist-column-unpulled-from-upstream (_id) +(defun magit-repolist-column-unpulled-from-upstream (spec) "Insert number of upstream commits not in the current branch." (--when-let (magit-get-upstream-branch) - (let ((n (cadr (magit-rev-diff-count "HEAD" it)))) - (magit--propertize-face - (number-to-string n) (if (> n 0) 'bold 'shadow))))) + (magit-repolist-insert-count (cadr (magit-rev-diff-count "HEAD" it)) spec))) -(defun magit-repolist-column-unpulled-from-pushremote (_id) +(defun magit-repolist-column-unpulled-from-pushremote (spec) "Insert number of commits in the push branch but not the current branch." (--when-let (magit-get-push-branch nil t) - (let ((n (cadr (magit-rev-diff-count "HEAD" it)))) - (magit--propertize-face - (number-to-string n) (if (> n 0) 'bold 'shadow))))) + (magit-repolist-insert-count (cadr (magit-rev-diff-count "HEAD" it)) spec))) -(defun magit-repolist-column-unpushed-to-upstream (_id) +(defun magit-repolist-column-unpushed-to-upstream (spec) "Insert number of commits in the current branch but not its upstream." (--when-let (magit-get-upstream-branch) - (let ((n (car (magit-rev-diff-count "HEAD" it)))) - (magit--propertize-face - (number-to-string n) (if (> n 0) 'bold 'shadow))))) + (magit-repolist-insert-count (car (magit-rev-diff-count "HEAD" it)) spec))) -(defun magit-repolist-column-unpushed-to-pushremote (_id) +(defun magit-repolist-column-unpushed-to-pushremote (spec) "Insert number of commits in the current branch but not its push branch." (--when-let (magit-get-push-branch nil t) - (let ((n (car (magit-rev-diff-count "HEAD" it)))) - (magit--propertize-face - (number-to-string n) (if (> n 0) 'bold 'shadow))))) + (magit-repolist-insert-count (car (magit-rev-diff-count "HEAD" it)) spec))) -(defun magit-repolist-column-branches (_id) +(defun magit-repolist-column-branches (spec) "Insert number of branches." - (let ((n (length (magit-list-local-branches)))) - (magit--propertize-face (number-to-string n) (if (> n 1) 'bold 'shadow)))) + (magit-repolist-insert-count (length (magit-list-local-branches)) + `((:normal-count 1) ,@spec))) -(defun magit-repolist-column-stashes (_id) +(defun magit-repolist-column-stashes (spec) "Insert number of stashes." - (let ((n (length (magit-list-stashes)))) - (magit--propertize-face (number-to-string n) (if (> n 0) 'bold 'shadow)))) + (magit-repolist-insert-count (length (magit-list-stashes)) spec)) + +(defun magit-repolist-insert-count (n spec) + (magit--propertize-face + (if (and (> n 9) (= (cadr (assq :width spec)) 1)) + "+" + (number-to-string n)) + (if (> n (or (cadr (assq :normal-count spec)) 0)) 'bold 'shadow))) ;;; Read Repository diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-reset.el magit-3.3.0/lisp/magit-reset.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-reset.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-reset.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-reset.el --- reset fuctionality -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -30,13 +32,14 @@ (require 'magit) ;;;###autoload (autoload 'magit-reset "magit" nil t) -(define-transient-command magit-reset () +(transient-define-prefix magit-reset () "Reset the `HEAD', index and/or worktree to a previous state." :man-page "git-reset" ["Reset" ("m" "mixed (HEAD and index)" magit-reset-mixed) ("s" "soft (HEAD only)" magit-reset-soft) ("h" "hard (HEAD, index and files)" magit-reset-hard) + ("k" "keep (HEAD and index, keeping uncommitted)" magit-reset-keep) ("i" "index (only)" magit-reset-index) ("w" "worktree (only)" magit-reset-worktree) "" @@ -66,6 +69,13 @@ (magit-reset-internal "--hard" commit)) ;;;###autoload +(defun magit-reset-keep (commit) + "Reset the `HEAD' and index to COMMIT, while keeping uncommitted changes. +\n(git reset --keep REVISION)" + (interactive (list (magit-reset-read-branch-or-commit "Reset %s to"))) + (magit-reset-internal "--keep" commit)) + +;;;###autoload (defun magit-reset-index (commit) "Reset the index to COMMIT. Keep the `HEAD' and working tree as-is, so if COMMIT refers to the diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-section.el magit-3.3.0/lisp/magit-section.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-section.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-section.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-section.el --- Sections for read-only buffers -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,9 +8,11 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli -;; Package-Requires: ((emacs "25.1") (dash "20180910")) ;; Keywords: tools ;; Homepage: https://github.com/magit/magit +;; Package-Requires: ((emacs "25.1") (dash "2.19.1")) +;; Package-Version: 3.3.0 +;; SPDX-License-Identifier: GPL-3.0-or-later ;; Magit-Section is free software; you can redistribute it and/or modify ;; it under the terms of the GNU General Public License as published by @@ -37,10 +39,10 @@ (require 'cl-lib) (require 'dash) (require 'eieio) +(require 'seq) +(require 'subr-x) -(eval-when-compile - (require 'benchmark) - (require 'subr-x)) +(eval-when-compile (require 'benchmark)) ;;; Hooks @@ -137,7 +139,8 @@ (defcustom magit-section-visibility-indicator (if (window-system) '(magit-fringe-bitmap> . magit-fringe-bitmapv) - '("…" . t)) + (cons (if (char-displayable-p ?…) "…" "...") + t)) "Whether and how to indicate that a section can be expanded/collapsed. If nil, then don't show any indicators. @@ -315,7 +318,7 @@ (defvar magit-section-mode-map (let ((map (make-keymap))) (suppress-keymap map t) - (define-key map (kbd "C-i") 'magit-section-toggle) + (define-key map (kbd "TAB") 'magit-section-toggle) (define-key map [C-tab] 'magit-section-cycle) (define-key map [M-tab] 'magit-section-cycle) ;; [backtab] is the most portable binding for Shift+Tab. @@ -325,10 +328,10 @@ (define-key map (kbd "n") 'magit-section-forward) (define-key map (kbd "M-p") 'magit-section-backward-sibling) (define-key map (kbd "M-n") 'magit-section-forward-sibling) - (define-key map "1" 'magit-section-show-level-1) - (define-key map "2" 'magit-section-show-level-2) - (define-key map "3" 'magit-section-show-level-3) - (define-key map "4" 'magit-section-show-level-4) + (define-key map (kbd "1") 'magit-section-show-level-1) + (define-key map (kbd "2") 'magit-section-show-level-2) + (define-key map (kbd "3") 'magit-section-show-level-3) + (define-key map (kbd "4") 'magit-section-show-level-4) (define-key map (kbd "M-1") 'magit-section-show-level-1-all) (define-key map (kbd "M-2") 'magit-section-show-level-2-all) (define-key map (kbd "M-3") 'magit-section-show-level-3-all) @@ -354,8 +357,9 @@ ;; (hack-dir-local-variables-non-file-buffer) (make-local-variable 'text-property-default-nonsticky) (push (cons 'keymap t) text-property-default-nonsticky) + (add-hook 'pre-command-hook #'magit-section-pre-command-hook nil t) (add-hook 'post-command-hook #'magit-section-update-highlight t t) - (add-hook 'deactivate-mark-hook #'magit-section-update-highlight t t) + (add-hook 'deactivate-mark-hook #'magit-section-deactivate-mark t t) (setq-local redisplay-highlight-region-function 'magit-section--highlight-region) (setq-local redisplay-unhighlight-region-function @@ -560,15 +564,15 @@ `(defun ,name (&optional expand) ,(format "\ Jump to the section \"%s\". With a prefix argument also expand it." heading) - (interactive "P") - (--if-let (magit-get-section - (cons (cons ',type ,value) - (magit-section-ident magit-root-section))) - (progn (goto-char (oref it start)) - (when expand - (with-local-quit (magit-section-show it)) - (recenter 0))) - (message ,(format "Section \"%s\" wasn't found" heading))))) + (interactive "P") + (--if-let (magit-get-section + (cons (cons ',type ,value) + (magit-section-ident magit-root-section))) + (progn (goto-char (oref it start)) + (when expand + (with-local-quit (magit-section-show it)) + (recenter 0))) + (message ,(format "Section \"%s\" wasn't found" heading))))) ;;;; Visibility @@ -684,7 +688,7 @@ (cond ((and (--any-p (oref it hidden) children) (--any-p (oref it children) children)) (magit-section-show-headings section)) - ((-any-p 'magit-section-hidden-body children) + ((seq-some 'magit-section-hidden-body children) (magit-section-show-children section)) (t (magit-section-hide section)))))) @@ -696,7 +700,7 @@ (cond ((and (--any-p (oref it hidden) children) (--any-p (oref it children) children)) (magit-section-show-headings magit-root-section)) - ((-any-p 'magit-section-hidden-body children) + ((seq-some 'magit-section-hidden-body children) (magit-section-show-children magit-root-section)) (t (mapc 'magit-section-hide children))))) @@ -781,7 +785,7 @@ With a prefix argument show the section identity instead of the section lineage. This command is intended for debugging purposes." (interactive (list (magit-current-section) current-prefix-arg)) - (let ((str (format "#<%s %S %S %s-%s>" + (let ((str (format "#<%s %S %S %s-%s%s>" (eieio-object-class section) (let ((val (oref section value))) (cond ((stringp val) @@ -796,6 +800,9 @@ (apply #'vector (magit-section-lineage section))) (when-let ((m (oref section start))) (marker-position m)) + (if-let ((m (oref section content))) + (format "[%s-]" (marker-position m)) + "") (when-let ((m (oref section end))) (marker-position m))))) (if (called-interactively-p 'any) @@ -971,9 +978,9 @@ (defun magit-section-match-assoc (section alist) "Return the value associated with SECTION's type or lineage in ALIST." - (-some (pcase-lambda (`(,key . ,val)) - (and (magit-section-match-1 key section) val)) - alist)) + (seq-some (pcase-lambda (`(,key . ,val)) + (and (magit-section-match-1 key section) val)) + alist)) ;;; Create @@ -985,14 +992,23 @@ (defmacro magit-insert-section (&rest args) "Insert a section at point. -TYPE is the section type, a symbol which is prefixed with the -name of the package. (For historic reasons the types used by -Magit and Forge do not use a package prefix.) Many commands -that act on the current section behave differently depending -on its type. - -Optional VALUE is the value of the section, usually a string -that is required when acting on the section. +Create a section object of type CLASS, storing VALUE in its +`value' slot, and insert the section at point. CLASS is a +subclass of `magit-section' or has the form `(eval FORM)', in +which case FORM is evaluated at runtime and should return a +subclass. In other places a sections class is oftern referred +to as its \"type\". + +Many commands behave differently depending on the class of the +current section and sections of a certain class can have their +own keymap, which is specified using the `keymap' class slot. +The value of that slot should be a variable whose value is a +keymap. + +For historic reasons Magit and Forge in most cases use symbols +as CLASS that don't actually identify a class and that lack the +appropriate package prefix. This works due to some undocumented +kludges, which are not available to other packages. When optional HIDE is non-nil collapse the section body by default, i.e. when first creating the section, but not when @@ -1018,16 +1034,10 @@ a section by washing Git's output and Git didn't actually output anything this time around. -For historic reasons, if a variable `magit-TYPE-section-map' -or `forge-TYPE-section-map' exists, then use that as the -text-property `keymap' of all text belonging to the section (but -this may be overwritten in subsections). TYPE can also have the -form `(eval FORM)' in which case FORM is evaluated at runtime. - -\(fn [NAME] (TYPE &optional VALUE HIDE) &rest BODY)" +\(fn [NAME] (CLASS &optional VALUE HIDE) &rest BODY)" (declare (indent defun) (debug ([&optional symbolp] - (&or [("eval" symbolp) &optional form form] + (&or [("eval" form) &optional form form] [symbolp &optional form form]) body))) (let ((tp (cl-gensym "type")) @@ -1043,30 +1053,31 @@ (or (cdr (assq ,tp magit--section-type-alist)) 'magit-section)) :type - (if (class-p ,tp) - (or (car (rassq ,tp magit--section-type-alist)) - (error "BUG: No entry for %s in %s" ,tp - 'magit--section-type-alist)) - ,tp) + (or (and (class-p ,tp) + (car (rassq ,tp magit--section-type-alist))) + ,tp) :value ,(nth 1 (car args)) :start (point-marker) :parent magit-insert-section--parent))) (oset ,s hidden - (if-let ((value (run-hook-with-args-until-success - 'magit-section-set-visibility-hook ,s))) - (eq value 'hide) - (if-let ((incarnation (and magit-insert-section--oldroot - (magit-get-section - (magit-section-ident ,s) - magit-insert-section--oldroot)))) - (oref incarnation hidden) - (if-let ((value (magit-section-match-assoc - ,s magit-section-initial-visibility-alist))) - (progn - (when (functionp value) - (setq value (funcall value ,s))) - (eq value 'hide)) - ,(nth 2 (car args)))))) + (let ((value (run-hook-with-args-until-success + 'magit-section-set-visibility-hook ,s))) + (if value + (eq value 'hide) + (let ((incarnation (and magit-insert-section--oldroot + (magit-get-section + (magit-section-ident ,s) + magit-insert-section--oldroot)))) + (if incarnation + (oref incarnation hidden) + (let ((value (magit-section-match-assoc + ,s magit-section-initial-visibility-alist))) + (if value + (progn + (when (functionp value) + (setq value (funcall value ,s))) + (eq value 'hide)) + ,(nth 2 (car args))))))))) (let ((magit-insert-section--current ,s) (magit-insert-section--parent ,s) (magit-insert-section--oldroot @@ -1230,13 +1241,20 @@ ;;; Highlight +(defvar-local magit-section-pre-command-section nil) (defvar-local magit-section-highlight-overlays nil) -(defvar-local magit-section-highlighted-section nil) (defvar-local magit-section-highlighted-sections nil) (defvar-local magit-section-unhighlight-sections nil) -(defun magit-section-update-highlight () + +(defun magit-section-pre-command-hook () + (setq magit-section-pre-command-section (magit-current-section))) + +(defun magit-section-deactivate-mark () + (magit-section-update-highlight t)) + +(defun magit-section-update-highlight (&optional force) (let ((section (magit-current-section))) - (unless (eq section magit-section-highlighted-section) + (when (or force (not (eq magit-section-pre-command-section section))) (let ((inhibit-read-only t) (deactivate-mark nil) (selection (magit-region-sections))) @@ -1251,11 +1269,7 @@ (dolist (s magit-section-unhighlight-sections) (run-hook-with-args-until-success 'magit-section-unhighlight-hook s selection)) - (restore-buffer-modified-p nil) - (unless (eq magit-section-highlighted-section section) - (setq magit-section-highlighted-section - (and (not (oref section hidden)) - section))))) + (restore-buffer-modified-p nil))) (magit-section-maybe-paint-visibility-ellipses))) (defun magit-section-highlight (section selection) @@ -1374,7 +1388,6 @@ start end window rol))) (defun magit-section--unhighlight-region (rol) - (setq magit-section-highlighted-section nil) (magit-section--delete-region-overlays) (funcall (default-value 'redisplay-unhighlight-region-function) rol)) @@ -1433,7 +1446,7 @@ (if (oref section hidden) (car magit-section-visibility-indicator) (cdr magit-section-visibility-indicator)) - (face-foreground 'fringe)))))) + 'fringe))))) ((stringp (car-safe magit-section-visibility-indicator)) (let ((ov (magit--overlay-at (1- eoh) 'magit-vis-indicator 'eoh))) (cond ((oref section hidden) @@ -1492,6 +1505,39 @@ (when (overlay-get o 'magit-vis-indicator) (delete-overlay o))))) +(defvar-local magit-section--opened-sections nil) + +(defun magit-section--open-temporarily (beg end) + (save-excursion + (goto-char beg) + (let ((section (magit-current-section))) + (while section + (let ((content (oref section content))) + (if (and (magit-section-invisible-p section) + (<= (or content (oref section start)) + beg + (oref section end))) + (progn + (when content + (magit-section-show section) + (push section magit-section--opened-sections)) + (setq section (oref section parent))) + (setq section nil)))))) + (or (eq search-invisible t) + (not (isearch-range-invisible beg end)))) + +(defun isearch-clean-overlays@magit-mode (fn) + (if (derived-mode-p 'magit-mode) + (let ((pos (point))) + (dolist (section magit-section--opened-sections) + (unless (<= (oref section content) pos (oref section end)) + (magit-section-hide section))) + (setq magit-section--opened-sections nil)) + (funcall fn))) + +(advice-add 'isearch-clean-overlays :around + 'isearch-clean-overlays@magit-mode) + ;;; Utilities (cl-defun magit-section-selected-p (section &optional (selection nil sselection)) @@ -1714,8 +1760,11 @@ magit--current-section-hook))) (unless (memq entry magit-disabled-section-inserters) (if (bound-and-true-p magit-refresh-verbose) - (message " %-50s %s" entry - (benchmark-elapse (apply entry args))) + (let ((time (benchmark-elapse (apply entry args)))) + (message " %-50s %s %s" entry time + (cond ((> time 0.03) "!!") + ((> time 0.01) "!") + (t "")))) (apply entry args))))))) (cl-defun magit--overlay-at (pos prop &optional (val nil sval) testfn) @@ -1728,6 +1777,67 @@ val))))) (overlays-at pos t))) +;;; Bitmaps + +(when (fboundp 'define-fringe-bitmap) + (define-fringe-bitmap 'magit-fringe-bitmap+ + [#b00000000 + #b00011000 + #b00011000 + #b01111110 + #b01111110 + #b00011000 + #b00011000 + #b00000000]) + (define-fringe-bitmap 'magit-fringe-bitmap- + [#b00000000 + #b00000000 + #b00000000 + #b01111110 + #b01111110 + #b00000000 + #b00000000 + #b00000000]) + + (define-fringe-bitmap 'magit-fringe-bitmap> + [#b01100000 + #b00110000 + #b00011000 + #b00001100 + #b00011000 + #b00110000 + #b01100000 + #b00000000]) + (define-fringe-bitmap 'magit-fringe-bitmapv + [#b00000000 + #b10000010 + #b11000110 + #b01101100 + #b00111000 + #b00010000 + #b00000000 + #b00000000]) + + (define-fringe-bitmap 'magit-fringe-bitmap-bold> + [#b11100000 + #b01110000 + #b00111000 + #b00011100 + #b00011100 + #b00111000 + #b01110000 + #b11100000]) + (define-fringe-bitmap 'magit-fringe-bitmap-boldv + [#b10000001 + #b11000011 + #b11100111 + #b01111110 + #b00111100 + #b00011000 + #b00000000 + #b00000000]) + ) + ;;; _ (provide 'magit-section) ;;; magit-section.el ends here diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-section-pkg.el magit-3.3.0/lisp/magit-section-pkg.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-section-pkg.el 1970-01-01 00:00:00.000000000 +0000 +++ magit-3.3.0/lisp/magit-section-pkg.el 2021-10-06 12:51:17.000000000 +0000 @@ -0,0 +1,6 @@ +(define-package "magit-section" "3.3.0" + "Sections for read-only buffers" + '((emacs "25.1") + (dash "2.19.1")) + :homepage "https://magit.vc" + :keywords '("tools")) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-sequence.el magit-3.3.0/lisp/magit-sequence.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-sequence.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-sequence.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-sequence.el --- history manipulation in Magit -*- lexical-binding: t -*- -;; Copyright (C) 2011-2020 The Magit Project Contributors +;; Copyright (C) 2011-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -29,9 +31,6 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) ;; For `magit-rebase--todo'. @@ -131,7 +130,7 @@ "The Perl executable.") ;;;###autoload (autoload 'magit-cherry-pick "magit-sequence" nil t) -(define-transient-command magit-cherry-pick () +(transient-define-prefix magit-cherry-pick () "Apply or transplant commits." :man-page "git-cherry-pick" :value '("--ff") @@ -149,7 +148,8 @@ ["Apply here" ("A" "Pick" magit-cherry-copy) ("a" "Apply" magit-cherry-apply) - ("h" "Harvest" magit-cherry-harvest)] + ("h" "Harvest" magit-cherry-harvest) + ("m" "Squash" magit-merge-squash)] ["Apply elsewhere" ("d" "Donate" magit-cherry-donate) ("n" "Spinout" magit-cherry-spinout) @@ -160,7 +160,7 @@ ("s" "Skip" magit-sequencer-skip) ("a" "Abort" magit-sequencer-abort)]) -(define-infix-argument magit-cherry-pick:--mainline () +(transient-define-argument magit-cherry-pick:--mainline () :description "Replay merge relative to parent" :class 'transient-option :shortarg "-m" @@ -174,22 +174,22 @@ (defun magit--cherry-move-read-args (verb away fn) (declare (indent defun)) - (let ((commits (or (nreverse (magit-region-values 'commit)) - (list (funcall (if away - 'magit-read-branch-or-commit - 'magit-read-other-branch-or-commit) - (format "%s cherry" (capitalize verb)))))) - (current (magit-get-current-branch))) - (unless current - (user-error "Cannot %s cherries while HEAD is detached" verb)) - (let ((reachable (magit-rev-ancestor-p (car commits) current)) - (msg "Cannot %s cherries that %s reachable from HEAD")) - (pcase (list away reachable) - (`(nil t) (user-error msg verb "are")) - (`(t nil) (user-error msg verb "are not")))) - `(,commits - ,@(funcall fn commits) - ,(transient-args 'magit-cherry-pick)))) + (let ((commits (or (nreverse (magit-region-values 'commit)) + (list (funcall (if away + 'magit-read-branch-or-commit + 'magit-read-other-branch-or-commit) + (format "%s cherry" (capitalize verb)))))) + (current (magit-get-current-branch))) + (unless current + (user-error "Cannot %s cherries while HEAD is detached" verb)) + (let ((reachable (magit-rev-ancestor-p (car commits) current)) + (msg "Cannot %s cherries that %s reachable from HEAD")) + (pcase (list away reachable) + (`(nil t) (user-error msg verb "are")) + (`(t nil) (user-error msg verb "are not")))) + `(,commits + ,@(funcall fn commits) + ,(transient-args 'magit-cherry-pick)))) (defun magit--cherry-spinoff-read-args (verb) (magit--cherry-move-read-args verb t @@ -351,7 +351,7 @@ ;;; Revert ;;;###autoload (autoload 'magit-revert "magit-sequence" nil t) -(define-transient-command magit-revert () +(transient-define-prefix magit-revert () "Revert existing commits, with or without creating new commits." :man-page "git-revert" :value '("--edit") @@ -403,7 +403,7 @@ ;;; Patch ;;;###autoload (autoload 'magit-am "magit-sequence" nil t) -(define-transient-command magit-am () +(transient-define-prefix magit-am () "Apply patches received by email." :man-page "git-am" :value '("--3way") @@ -432,10 +432,11 @@ (defun magit-am-arguments () (transient-args 'magit-am)) -(define-infix-argument magit-apply:-p () +(transient-define-argument magit-apply:-p () :description "Remove leading slashes from paths" :class 'transient-option :argument "-p" + :allow-empty t :reader 'transient-read-number-N+) ;;;###autoload @@ -495,14 +496,17 @@ ;;; Rebase ;;;###autoload (autoload 'magit-rebase "magit-sequence" nil t) -(define-transient-command magit-rebase () +(transient-define-prefix magit-rebase () "Transplant commits and/or modify existing commits." :man-page "git-rebase" + :value '("--autostash") ["Arguments" :if-not magit-rebase-in-progress-p ("-k" "Keep empty commits" "--keep-empty") ("-p" "Preserve merges" ("-p" "--preserve-merges")) (7 magit-merge:--strategy) + (7 magit-merge:--strategy-option) + (7 "=X" magit-diff:--diff-algorithm :argument "-Xdiff-algorithm=") ("-d" "Lie about committer date" "--committer-date-is-author-date") ("-a" "Autosquash" "--autosquash") ("-A" "Autostash" "--autostash") @@ -535,7 +539,7 @@ ("e" "Edit" magit-rebase-edit) ("a" "Abort" magit-rebase-abort)]) -(define-infix-argument magit-rebase:--exec () +(transient-define-argument magit-rebase:--exec () :description "Run command after commits" :class 'transient-option :shortarg "-x" @@ -554,7 +558,7 @@ (magit-run-git-sequencer "rebase" args target)) ;;;###autoload (autoload 'magit-rebase-onto-pushremote "magit-sequence" nil t) -(define-suffix-command magit-rebase-onto-pushremote (args) +(transient-define-suffix magit-rebase-onto-pushremote (args) "Rebase the current branch onto its push-remote branch. With a prefix argument or when the push-remote is either not @@ -568,7 +572,7 @@ (magit-git-rebase (concat remote "/" branch) args))) ;;;###autoload (autoload 'magit-rebase-onto-upstream "magit-sequence" nil t) -(define-suffix-command magit-rebase-onto-upstream (args) +(transient-define-suffix magit-rebase-onto-upstream (args) "Rebase the current branch onto its upstream branch. With a prefix argument or when the upstream is either not @@ -667,8 +671,13 @@ (unless (member "--root" args) commit))) (magit-log-select `(lambda (commit) - (magit-rebase-interactive-1 commit (list ,@args) - ,message ,editor ,delay-edit-confirm ,noassert)) + ;; In some cases (currently just magit-rebase-remove-commit), "-c + ;; commentChar=#" is added to the global arguments for git. Ensure + ;; that the same happens when we chose the commit via + ;; magit-log-select, below. + (let ((magit-git-global-arguments (list ,@magit-git-global-arguments))) + (magit-rebase-interactive-1 commit (list ,@args) + ,message ,editor ,delay-edit-confirm ,noassert))) message))) (defvar magit--rebase-published-symbol nil) @@ -753,10 +762,14 @@ "Remove a single older commit using rebase." (interactive (list (magit-commit-at-point) (magit-rebase-arguments))) - (magit-rebase-interactive-1 commit args - "Type %p on a commit to remove it," - (apply-partially #'magit-rebase--perl-editor 'remove) - nil nil t)) + ;; magit-rebase--perl-editor assumes that the comment character is "#". + (let ((magit-git-global-arguments + (nconc (list "-c" "core.commentChar=#") + magit-git-global-arguments))) + (magit-rebase-interactive-1 commit args + "Type %p on a commit to remove it," + (apply-partially #'magit-rebase--perl-editor 'remove) + nil nil t))) (defun magit-rebase--perl-editor (action since) (let ((commit (magit-rev-abbrev (magit-rebase--target-commit since)))) @@ -765,7 +778,7 @@ commit (cl-case action (edit "edit") - (remove "# pick") + (remove "noop\n# pick") (reword "reword") (t (error "unknown action: %s" action))) commit))) @@ -783,7 +796,8 @@ (file-exists-p (magit-git-dir "rebase-merge")) (not (member (magit-toplevel) magit--rebase-public-edit-confirmed))) - (magit-commit-amend-assert)) + (magit-commit-amend-assert + (magit-file-line (magit-git-dir "rebase-merge/orig-head")))) (if noedit (let ((process-environment process-environment)) (push "GIT_EDITOR=true" process-environment) @@ -899,8 +913,12 @@ (when (magit-rebase-in-progress-p) (let* ((interactive (file-directory-p (magit-git-dir "rebase-merge"))) (dir (if interactive "rebase-merge/" "rebase-apply/")) - (name (-> (concat dir "head-name") magit-git-dir magit-file-line)) - (onto (-> (concat dir "onto") magit-git-dir magit-file-line)) + (name (thread-first (concat dir "head-name") + magit-git-dir + magit-file-line)) + (onto (thread-first (concat dir "onto") + magit-git-dir + magit-file-line)) (onto (or (magit-rev-name onto name) (magit-rev-name onto "refs/heads/*") onto)) (name (or (magit-rev-name name "refs/heads/*") name))) @@ -1026,12 +1044,12 @@ (t (list "done" rev 'magit-sequence-done))))) (magit-sequence-insert-commit "onto" onto - (if (equal onto head) - 'magit-sequence-head - 'magit-sequence-onto)))) + (if (equal onto head) + 'magit-sequence-head + 'magit-sequence-onto)))) (defun magit-sequence-insert-commit (type hash face) - (magit-insert-section (commit hash) + (magit-insert-section (commit hash) (magit-insert-heading (propertize type 'font-lock-face face) "\s" (magit-format-rev-summary hash) "\n"))) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-stash.el magit-3.3.0/lisp/magit-stash.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-stash.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-stash.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-stash.el --- stash support for Magit -*- lexical-binding: t -*- -;; Copyright (C) 2008-2020 The Magit Project Contributors +;; Copyright (C) 2008-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -27,12 +29,12 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) (require 'magit-reflog) +;; For `magit-stash-drop'. +(defvar helm-comp-read-use-marked) + ;;; Options (defgroup magit-stash nil @@ -86,7 +88,7 @@ ;;; Commands ;;;###autoload (autoload 'magit-stash "magit-stash" nil t) -(define-transient-command magit-stash () +(transient-define-prefix magit-stash () "Stash uncommitted changes." :man-page "git-stash" ["Arguments" @@ -123,7 +125,14 @@ Untracked files are included according to infix arguments. One prefix argument is equivalent to `--include-untracked' while two prefix arguments are equivalent to `--all'." - (interactive (magit-stash-read-args)) + (interactive + (progn (when (and (magit-merge-in-progress-p) + (not (magit-y-or-n-p "\ +Stashing and resetting during a merge conflict. \ +Applying the resulting stash won't restore the merge state. \ +Proceed anyway? "))) + (user-error "Abort")) + (magit-stash-read-args))) (magit-stash-save message t t include-untracked t)) ;;;###autoload @@ -214,6 +223,7 @@ (magit-refresh) (magit-run-git "stash" "apply" stash))) +;;;###autoload (defun magit-stash-pop (stash) "Apply a stash to the working tree and remove it from stash list. Try to preserve the stash index. If that fails because there @@ -231,20 +241,15 @@ (interactive (list (--if-let (magit-region-values 'stash) (magit-confirm 'drop-stashes nil "Drop %i stashes" nil it) - (magit-read-stash "Drop stash")))) + (let ((helm-comp-read-use-marked t)) + (magit-read-stash "Drop stash"))))) (dolist (stash (if (listp stash) (nreverse (prog1 stash (setq stash (car stash)))) (list stash))) (message "Deleted refs/%s (was %s)" stash (magit-rev-parse "--short" stash)) (magit-call-git "rev-parse" stash) - (magit-call-git "reflog" "delete" "--updateref" "--rewrite" stash)) - (when-let ((ref (and (string-match "\\(.+\\)@{[0-9]+}$" stash) - (match-string 1 stash)))) - (unless (string-match "^refs/" ref) - (setq ref (concat "refs/" ref))) - (unless (magit-rev-verify (concat ref "@{0}")) - (magit-run-git "update-ref" "-d" ref))) + (magit-call-git "stash" "drop" stash)) (magit-refresh)) ;;;###autoload @@ -269,7 +274,7 @@ current branch or `HEAD' as the start-point." (interactive (list (magit-read-stash "Branch stash") (magit-read-string-ns "Branch name"))) - (let ((inhibit-magit-refresh t)) + (let ((magit-inhibit-refresh t)) (magit-branch-and-checkout branch (or (magit-get-current-branch) "HEAD"))) (magit-stash-apply stash)) @@ -375,11 +380,12 @@ (let ((verified (magit-rev-verify ref)) (autostash (and (magit-rebase-in-progress-p) - (magit-file-line - (magit-git-dir - (-> (if (file-directory-p (magit-git-dir "rebase-merge")) - "rebase-merge/autostash" - "rebase-apply/autostash"))))))) + (thread-first + (if (file-directory-p (magit-git-dir "rebase-merge")) + "rebase-merge/autostash" + "rebase-apply/autostash") + magit-git-dir + magit-file-line)))) (when (or autostash verified) (magit-insert-section (stashes ref) (magit-insert-heading heading) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-status.el magit-3.3.0/lisp/magit-status.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-status.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-status.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-status.el --- the grand overview -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -27,9 +29,6 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) ;;; Options @@ -176,6 +175,33 @@ :set-after '(magit-log-margin) :set (apply-partially #'magit-margin-set-variable 'magit-status-mode)) +(defcustom magit-status-use-buffer-arguments 'selected + "Whether `magit-status' reuses arguments when the buffer already exists. + +This option has no effect when merely refreshing the status +buffer using `magit-refresh'. + +Valid values are: + +`always': Always use the set of arguments that is currently + active in the status buffer, provided that buffer exists + of course. +`selected': Use the set of arguments from the status + buffer, but only if it is displayed in a window of the + current frame. This is the default. +`current': Use the set of arguments from the status buffer, + but only if it is the current buffer. +`never': Never use the set of arguments from the status + buffer." + :package-version '(magit . "3.0.0") + :group 'magit-buffers + :group 'magit-commands + :type '(choice + (const :tag "always use args from buffer" always) + (const :tag "use args from buffer if displayed in frame" selected) + (const :tag "use args from buffer if it is current" current) + (const :tag "never use args from buffer" never))) + ;;; Commands ;;;###autoload @@ -242,8 +268,9 @@ (interactive (let ((magit--refresh-cache (list (cons 0 0)))) (list (and (or current-prefix-arg (not (magit-toplevel))) - (magit-read-repository - (>= (prefix-numeric-value current-prefix-arg) 16))) + (progn (magit--assert-usable-git) + (magit-read-repository + (>= (prefix-numeric-value current-prefix-arg) 16)))) magit--refresh-cache))) (let ((magit--refresh-cache (or cache (list (cons 0 0))))) (if directory @@ -282,6 +309,29 @@ (put 'magit-status-here 'interactive-only 'magit-status-setup-buffer) +(defun magit-status-quick () + "Show the status of the current Git repository, maybe without refreshing. + +If the status buffer of the current Git repository exists but +isn't being displayed in the selected frame, then display it +without refreshing it. + +If the status buffer is being displayed in the selected frame, +then also refresh it. + +Prefix arguments have the same meaning as for `magit-status', +and additionally cause the buffer to be refresh. + +To use this function instead of `magit-status', add this to your +init file: (global-set-key (kbd \"C-x g\") 'magit-status-quick)." + (interactive) + (if-let ((buffer + (and (not current-prefix-arg) + (not (magit-get-mode-buffer 'magit-status-mode nil 'selected)) + (magit-get-mode-buffer 'magit-status-mode)))) + (magit-display-buffer buffer) + (call-interactively #'magit-status))) + (defvar magit--remotes-using-recent-git nil) (defun magit--tramp-asserts (directory) @@ -290,32 +340,21 @@ (if-let ((version (let ((default-directory directory)) (magit-git-version)))) (if (version<= magit--minimal-git version) - (push version magit--remotes-using-recent-git) + (push remote magit--remotes-using-recent-git) (display-warning 'magit (format "\ Magit requires Git >= %s, but on %s the version is %s. If multiple Git versions are installed on the host, then the problem might be that TRAMP uses the wrong executable. -First check the value of `magit-git-executable'. Its value is -used when running git locally as well as when running it on a -remote host. The default value is \"git\", except on Windows -where an absolute path is used for performance reasons. - -If the value already is just \"git\" but TRAMP never-the-less -doesn't use the correct executable, then consult the info node -`(tramp)Remote programs'.\n" magit--minimal-git remote version) :error)) +Check the value of `magit-remote-git-executable' and consult +the info node `(tramp)Remote programs'. +" magit--minimal-git remote version) :error)) (display-warning 'magit (format "\ Magit cannot find Git on %s. -First check the value of `magit-git-executable'. Its value is -used when running git locally as well as when running it on a -remote host. The default value is \"git\", except on Windows -where an absolute path is used for performance reasons. - -If the value already is just \"git\" but TRAMP never-the-less -doesn't find the executable, then consult the info node -`(tramp)Remote programs'.\n" remote) :error))))) +Check the value of `magit-remote-git-executable' and consult +the info node `(tramp)Remote programs'." remote) :error))))) ;;; Mode @@ -327,7 +366,7 @@ map) "Keymap for `magit-status-mode'.") -(define-transient-command magit-status-jump () +(transient-define-prefix magit-status-jump () "In a Magit-Status buffer, jump to a section." ["Jump to" [("z " "Stashes" magit-jump-to-stashes @@ -344,16 +383,23 @@ :if (lambda () (memq 'magit-insert-unpulled-from-upstream magit-status-sections-hook))) ("fp" "Unpulled from pushremote" magit-jump-to-unpulled-from-pushremote :if (lambda () (memq 'magit-insert-unpulled-from-pushremote magit-status-sections-hook))) - ("pu" "Unpushed to upstream" magit-jump-to-unpushed-to-upstream + ("pu" magit-jump-to-unpushed-to-upstream :if (lambda () (or (memq 'magit-insert-unpushed-to-upstream-or-recent magit-status-sections-hook) - (memq 'magit-insert-unpushed-to-upstream magit-status-sections-hook)))) + (memq 'magit-insert-unpushed-to-upstream magit-status-sections-hook))) + :description (lambda () + (let ((upstream (magit-get-upstream-branch))) + (if (or (not upstream) + (magit-rev-ancestor-p "HEAD" upstream)) + "Recent commits" + "Unmerged into upstream")))) ("pp" "Unpushed to pushremote" magit-jump-to-unpushed-to-pushremote :if (lambda () (memq 'magit-insert-unpushed-to-pushremote magit-status-sections-hook))) ("a " "Assumed unstaged" magit-jump-to-assume-unchanged :if (lambda () (memq 'magit-insert-assume-unchanged-files magit-status-sections-hook))) ("w " "Skip worktree" magit-jump-to-skip-worktree - :if (lambda () (memq 'magit-insert-skip-worktree-files magit-status-sections-hook)))]]) + :if (lambda () (memq 'magit-insert-skip-worktree-files magit-status-sections-hook)))] + [("i" "Using Imenu" imenu)]]) (define-derived-mode magit-status-mode magit-mode "Magit" "Mode for looking at Git status. @@ -397,8 +443,10 @@ (setq directory default-directory)) (magit--tramp-asserts directory) (let* ((default-directory directory) - (d (magit-diff--get-value 'magit-status-mode)) - (l (magit-log--get-value 'magit-status-mode)) + (d (magit-diff--get-value 'magit-status-mode + magit-status-use-buffer-arguments)) + (l (magit-log--get-value 'magit-status-mode + magit-status-use-buffer-arguments)) (file (and magit-status-goto-file-position (magit-file-relative-name))) (line (and file (line-number-at-pos))) @@ -588,12 +636,13 @@ ((magit--valid-upstream-p remote merge) (if (equal remote ".") (concat - (propertize merge 'font-lock-face 'magit-branch-local) - (propertize " does not exist" + (propertize merge 'font-lock-face 'magit-branch-local) " " + (propertize "does not exist" 'font-lock-face 'font-lock-warning-face)) - (concat + (format + "%s %s %s" (propertize merge 'font-lock-face 'magit-branch-remote) - (propertize " does not exist on " + (propertize "does not exist on" 'font-lock-face 'font-lock-warning-face) (propertize remote 'font-lock-face 'magit-branch-remote)))) (t @@ -620,11 +669,11 @@ "(no commit message)")))) (let ((remote (magit-get-push-remote branch))) (if (magit-remote-p remote) - (concat target - (propertize " does not exist" + (concat target " " + (propertize "does not exist" 'font-lock-face 'font-lock-warning-face)) - (concat remote - (propertize " remote does not exist" + (concat remote " " + (propertize "remote does not exist" 'font-lock-face 'font-lock-warning-face)))))) (insert ?\n)))) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-submodule.el magit-3.3.0/lisp/magit-submodule.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-submodule.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-submodule.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-submodule.el --- submodule support for Magit -*- lexical-binding: t -*- -;; Copyright (C) 2011-2020 The Magit Project Contributors +;; Copyright (C) 2011-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -23,12 +25,10 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit) (defvar x-stretch-cursor) + ;;; Options (defcustom magit-module-sections-hook @@ -83,9 +83,15 @@ argument, the repository identification (usually its basename), and with `default-directory' bound to the toplevel of its working tree. It has to return a string to be inserted or nil. PROPS is -an alist that supports the keys `:right-align' and `:pad-right'." +an alist that supports the keys `:right-align' and `:pad-right'. + +You may wish to display a range of numeric columns using just one +character per column and without any padding between columns, in +which case you should use an appropriat HEADER, set WIDTH to 1, +and set `:pad-right' to 0. \"+\" is substituted for numbers higher +than 9." :package-version '(magit . "2.8.0") - :group 'magit-repolist-mode + :group 'magit-repolist :type `(repeat (list :tag "Column" (string :tag "Header Label") (integer :tag "Column Width") @@ -97,6 +103,18 @@ (symbol)) (sexp :tag "Value")))))) +(defcustom magit-submodule-list-sort-key '("Path" . nil) + "Initial sort key for buffer created by `magit-list-submodules'. +If nil, no additional sorting is performed. Otherwise, this +should be a cons cell (NAME . FLIP). NAME is a string matching +one of the column names in `magit-submodule-list-columns'. FLIP, +if non-nil, means to invert the resulting sort." + :package-version '(magit . "3.2.0") + :group 'magit-repolist + :type '(choice (const nil) + (cons (string :tag "Column name") + (boolean :tag "Flip order")))) + (defcustom magit-submodule-remove-trash-gitdirs nil "Whether `magit-submodule-remove' offers to trash module gitdirs. @@ -114,7 +132,7 @@ ;;; Popup ;;;###autoload (autoload 'magit-submodule "magit-submodule" nil t) -(define-transient-command magit-submodule () +(transient-define-prefix magit-submodule () "Act on a submodule." :man-page "git-submodule" ["Arguments" @@ -161,7 +179,7 @@ (cl-call-next-method obj)))) ;;;###autoload (autoload 'magit-submodule-add "magit-submodule" nil t) -(define-suffix-command magit-submodule-add (url &optional path name args) +(transient-define-suffix magit-submodule-add (url &optional path name args) "Add the repository at URL as a module. Optional PATH is the path to the module relative to the root of @@ -225,7 +243,7 @@ (if prefer-short name path))))) ;;;###autoload (autoload 'magit-submodule-register "magit-submodule" nil t) -(define-suffix-command magit-submodule-register (modules) +(transient-define-suffix magit-submodule-register (modules) "Register MODULES. With a prefix argument act on all suitable modules. Otherwise, @@ -244,7 +262,7 @@ (magit-run-git-async "submodule" "init" "--" modules))) ;;;###autoload (autoload 'magit-submodule-populate "magit-submodule" nil t) -(define-suffix-command magit-submodule-populate (modules) +(transient-define-suffix magit-submodule-populate (modules) "Create MODULES working directories, checking out the recorded commits. With a prefix argument act on all suitable modules. Otherwise, @@ -261,7 +279,7 @@ (magit-run-git-async "submodule" "update" "--init" "--" modules))) ;;;###autoload (autoload 'magit-submodule-update "magit-submodule" nil t) -(define-suffix-command magit-submodule-update (modules args) +(transient-define-suffix magit-submodule-update (modules args) "Update MODULES by checking out the recorded commits. With a prefix argument act on all suitable modules. Otherwise, @@ -284,7 +302,7 @@ (magit-run-git-async "submodule" "update" args "--" modules))) ;;;###autoload (autoload 'magit-submodule-synchronize "magit-submodule" nil t) -(define-suffix-command magit-submodule-synchronize (modules args) +(transient-define-suffix magit-submodule-synchronize (modules args) "Synchronize url configuration of MODULES. With a prefix argument act on all suitable modules. Otherwise, @@ -300,7 +318,7 @@ (magit-run-git-async "submodule" "sync" args "--" modules))) ;;;###autoload (autoload 'magit-submodule-unpopulate "magit-submodule" nil t) -(define-suffix-command magit-submodule-unpopulate (modules args) +(transient-define-suffix magit-submodule-unpopulate (modules args) "Remove working directories of MODULES. With a prefix argument act on all suitable modules. Otherwise, @@ -327,7 +345,7 @@ "Unregister MODULES and remove their working directories. For safety reasons, do not remove the gitdirs and if a module has -uncomitted changes, then do not remove it at all. If a module's +uncommitted changes, then do not remove it at all. If a module's gitdir is located inside the working directory, then move it into the gitdir of the superproject first. @@ -584,13 +602,7 @@ (defun magit-list-submodules () "Display a list of the current repository's submodules." (interactive) - (magit-display-buffer - (or (magit-get-mode-buffer 'magit-submodule-list-mode) - (magit-with-toplevel - (magit-generate-new-buffer 'magit-submodule-list-mode)))) - (magit-submodule-list-mode) - (magit-submodule-list-refresh) - (tabulated-list-print)) + (magit-submodule-list-setup magit-submodule-list-columns)) (defvar magit-submodule-list-mode-map (let ((map (make-sparse-keymap))) @@ -601,22 +613,35 @@ (define-derived-mode magit-submodule-list-mode tabulated-list-mode "Modules" "Major mode for browsing a list of Git submodules." :group 'magit-repolist-mode - (setq-local x-stretch-cursor nil) - (setq tabulated-list-padding 0) - (setq tabulated-list-sort-key (cons "Path" nil)) - (setq tabulated-list-format - (vconcat (mapcar (pcase-lambda (`(,title ,width ,_fn ,props)) - (nconc (list title width t) - (-flatten props))) - magit-submodule-list-columns))) - (tabulated-list-init-header) + (setq-local x-stretch-cursor nil) + (setq tabulated-list-padding 0) (add-hook 'tabulated-list-revert-hook 'magit-submodule-list-refresh nil t) (setq imenu-prev-index-position-function #'magit-imenu--submodule-prev-index-position-function) (setq imenu-extract-index-name-function #'magit-imenu--submodule-extract-index-name-function)) +(defun magit-submodule-list-setup (columns) + (magit-display-buffer + (or (magit-get-mode-buffer 'magit-submodule-list-mode) + (magit-with-toplevel + (magit-generate-new-buffer 'magit-submodule-list-mode)))) + (magit-submodule-list-mode) + (setq-local magit-repolist-columns columns) + (magit-submodule-list-refresh)) + (defun magit-submodule-list-refresh () + (unless tabulated-list-sort-key + (setq tabulated-list-sort-key + (pcase-let ((`(,column . ,flip) magit-submodule-list-sort-key)) + (cons (or (car (assoc column magit-submodule-list-columns)) + (caar magit-submodule-list-columns)) + flip)))) + (setq tabulated-list-format + (vconcat (mapcar (pcase-lambda (`(,title ,width ,_fn ,props)) + (nconc (list title width t) + (-flatten props))) + magit-repolist-columns))) (setq tabulated-list-entries (-keep (lambda (module) (let ((default-directory @@ -624,13 +649,22 @@ (and (file-exists-p ".git") (list module (vconcat - (--map (or (funcall (nth 2 it) module) "") - magit-submodule-list-columns)))))) - (magit-list-module-paths)))) + (mapcar (pcase-lambda (`(,title ,width ,fn ,props)) + (or (funcall fn `((:path ,module) + (:title ,title) + (:width ,width) + ,@props)) + "")) + magit-repolist-columns)))))) + (magit-list-module-paths))) + (message "Listing submodules...") + (tabulated-list-init-header) + (tabulated-list-print) + (message "Listing submodules...done")) -(defun magit-modulelist-column-path (path) +(defun magit-modulelist-column-path (spec) "Insert the relative path of the submodule." - path) + (cadr (assq :path spec))) ;;; Utilities diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-subtree.el magit-3.3.0/lisp/magit-subtree.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-subtree.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-subtree.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-subtree.el --- subtree support for Magit -*- lexical-binding: t -*- -;; Copyright (C) 2011-2020 The Magit Project Contributors +;; Copyright (C) 2011-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -28,7 +30,7 @@ ;;; Commands ;;;###autoload (autoload 'magit-subtree "magit-subtree" nil t) -(define-transient-command magit-subtree () +(transient-define-prefix magit-subtree () "Import or export subtrees." :man-page "git-subtree" ["Actions" @@ -36,7 +38,7 @@ ("e" "Export" magit-subtree-export)]) ;;;###autoload (autoload 'magit-subtree-import "magit-subtree" nil t) -(define-transient-command magit-subtree-import () +(transient-define-prefix magit-subtree-import () "Import subtrees." :man-page "git-subtree" ["Arguments" @@ -50,7 +52,7 @@ ("f" "Pull" magit-subtree-pull)]]) ;;;###autoload (autoload 'magit-subtree-export "magit-subtree" nil t) -(define-transient-command magit-subtree-export () +(transient-define-prefix magit-subtree-export () "Export subtrees." :man-page "git-subtree" ["Arguments" @@ -64,7 +66,7 @@ ("p" "Push" magit-subtree-push) ("s" "Split" magit-subtree-split)]) -(define-infix-argument magit-subtree:--prefix () +(transient-define-argument magit-subtree:--prefix () :description "Prefix" :class 'transient-option :shortarg "-P" @@ -82,25 +84,25 @@ (user-error "%s isn't inside the repository at %s" prefix topdir)) prefix))) -(define-infix-argument magit-subtree:--message () +(transient-define-argument magit-subtree:--message () :description "Message" :class 'transient-option :shortarg "-m" :argument "--message=") -(define-infix-argument magit-subtree:--annotate () +(transient-define-argument magit-subtree:--annotate () :description "Annotate" :class 'transient-option :key "-a" :argument "--annotate=") -(define-infix-argument magit-subtree:--branch () +(transient-define-argument magit-subtree:--branch () :description "Branch" :class 'transient-option :shortarg "-b" :argument "--branch=") -(define-infix-argument magit-subtree:--onto () +(transient-define-argument magit-subtree:--onto () :description "Onto" :class 'transient-option :key "-o" diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-tag.el magit-3.3.0/lisp/magit-tag.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-tag.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-tag.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-tag.el --- tag functionality -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -29,8 +31,11 @@ (require 'magit) +;; For `magit-tag-delete'. +(defvar helm-comp-read-use-marked) + ;;;###autoload (autoload 'magit-tag "magit" nil t) -(define-transient-command magit-tag () +(transient-define-prefix magit-tag () "Create or delete a tag." :man-page "git-tag" ["Arguments" @@ -48,12 +53,12 @@ (defun magit-tag-arguments () (transient-args 'magit-tag)) -(define-infix-argument magit-tag:--local-user () +(transient-define-argument magit-tag:--local-user () :description "Sign as" :class 'transient-option :shortarg "-u" :argument "--local-user=" - :reader 'magit-read-gpg-secret-key + :reader 'magit-read-gpg-signing-key :history-key 'magit:--gpg-sign) ;;;###autoload @@ -78,7 +83,8 @@ \n(git tag -d TAGS)" (interactive (list (--if-let (magit-region-values 'tag) (magit-confirm t nil "Delete %i tags" nil it) - (magit-read-tag "Delete tag" t)))) + (let ((helm-comp-read-use-marked t)) + (magit-read-tag "Delete tag" t))))) (magit-run-git "tag" "-d" tags)) ;;;###autoload @@ -111,30 +117,32 @@ (magit-run-git-async "push" remote (--map (concat ":" it) remote-tags)))) (defvar magit-tag-version-regexp-alist - '(("^[-._+ ]?alpha\\.?$" . -3) + '(("^[-._+ ]?snapshot\\.?$" . -4) + ("^[-._+]$" . -4) + ("^[-._+ ]?\\(cvs\\|git\\|bzr\\|svn\\|hg\\|darcs\\)\\.?$" . -4) + ("^[-._+ ]?unknown\\.?$" . -4) + ("^[-._+ ]?alpha\\.?$" . -3) ("^[-._+ ]?beta\\.?$" . -2) ("^[-._+ ]?\\(pre\\|rc\\)\\.?$" . -1)) - "Value to use for `version-regexp-alist' when parsing and sorting versions. -The default value matches some common SemVer pre-release formats. + "Overrides `version-regexp-alist' for `magit-tag-release'. See also `magit-release-tag-regexp'.") (defvar magit-release-tag-regexp "\\`\ \\(?1:\\(?:v\\(?:ersion\\)?\\|r\\(?:elease\\)?\\)?[-_]?\\)?\ \\(?2:[0-9]+\\(?:\\.[0-9]+\\)*\ \\(?:-[a-zA-Z0-9-]+\\(?:\\.[a-zA-Z0-9-]+\\)*\\)?\\)\\'" - "Regexp used to parse release tag names. -The first submatch must match the prefix, if any. -The second submatch must match the version string. -The default value matches SemVer version numbers, including -pre-release versions. - -If this will match versions that are not dot separated numbers, you -also need to set `magit-tag-version-regexp-alist' to recognize them -and give them a sorting order.") + "Regexp used by `magit-tag-release' to parse release tags. + +The first submatch must match the prefix, if any. The second +submatch must match the version string. + +If this matches versions that are not dot separated numbers, +then `magit-tag-version-regexp-alist' has to contain entries +for the separators allowed here.") ;;;###autoload -(defun magit-tag-release (tag msg) - "Create an annotated release tag. +(defun magit-tag-release (tag msg &optional args) + "Create a release tag. Assume that release tags match `magit-release-tag-regexp'. @@ -142,17 +150,13 @@ existing tag as initial input and leaving it to the user to increment the desired part of the version string. -Then prompt for the message of the new tag. Base the proposed -tag message on the message of the highest tag, provided that -that contains the corresponding version string and substituting -the new version string for that. Otherwise propose something -like \"Foo-Bar 1.2.3\", given, for example, a TAG \"v1.2.3\" and a -repository located at something like \"/path/to/foo-bar\". - -Then call \"git tag --annotate --sign -m MSG TAG\" to create the, -tag, regardless of whether these arguments are enabled in the -popup. Finally show the refs buffer to let the user quickly -review the result." +If `--annotate' is enabled, then prompt for the message of the +new tag. Base the proposed tag message on the message of the +highest tag, provided that that contains the corresponding +version string and substituting the new version string for that. +Otherwise propose something like \"Foo-Bar 1.2.3\", given, for +example, a TAG \"v1.2.3\" and a repository located at something +like \"/path/to/foo-bar\"." (interactive (save-match-data (pcase-let* @@ -160,17 +164,22 @@ (tag (read-string "Create release tag: " ptag)) (ver (and (string-match magit-release-tag-regexp tag) (match-string 2 tag))) - (msg (cond ((and pver (string-match (regexp-quote pver) pmsg)) - (replace-match ver t t pmsg)) - ((and ptag (string-match (regexp-quote ptag) pmsg)) - (replace-match tag t t pmsg)) - (t (format "%s %s" - (capitalize - (file-name-nondirectory - (directory-file-name (magit-toplevel)))) - ver))))) - (list tag (read-string (format "Message for %S: " tag) msg))))) - (magit-run-git-async "tag" "--annotate" "--sign" "-m" msg tag) + (args (magit-tag-arguments))) + (list tag + (and (member "--annotate" args) + (read-string + (format "Message for %S: " tag) + (cond ((and pver (string-match (regexp-quote pver) pmsg)) + (replace-match ver t t pmsg)) + ((and ptag (string-match (regexp-quote ptag) pmsg)) + (replace-match tag t t pmsg)) + (t (format "%s %s" + (capitalize + (file-name-nondirectory + (directory-file-name (magit-toplevel)))) + ver))))) + args)))) + (magit-run-git-async "tag" args (and msg (list "-m" msg)) tag) (set-process-sentinel magit-this-process (lambda (process event) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-transient.el magit-3.3.0/lisp/magit-transient.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-transient.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-transient.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-transient.el --- support for transients -*- lexical-binding: t -*- -;; Copyright (C) 2008-2020 The Magit Project Contributors +;; Copyright (C) 2008-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -28,15 +30,12 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - -(require 'transient) - (require 'magit-git) (require 'magit-mode) (require 'magit-process) +(require 'transient) + ;;; Classes (defclass magit--git-variable (transient-variable) @@ -199,4 +198,3 @@ ;;; _ (provide 'magit-transient) ;;; magit-transient.el ends here - diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-utils.el magit-3.3.0/lisp/magit-utils.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-utils.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-utils.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-utils.el --- various utilities -*- lexical-binding: t; coding: utf-8 -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -11,6 +11,8 @@ ;; Contains code from GNU Emacs https://www.gnu.org/software/emacs, ;; released under the GNU General Public License version 3 or later. +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -40,9 +42,9 @@ (require 'cl-lib) (require 'dash) - -(eval-when-compile - (require 'subr-x)) +(require 'eieio) +(require 'seq) +(require 'subr-x) (require 'crm) @@ -100,13 +102,16 @@ (forge-browse-pullreq nil t) (forge-edit-topic-title nil t) (forge-edit-topic-state nil t) + (forge-edit-topic-milestone nil t) (forge-edit-topic-labels nil t) (forge-edit-topic-marks nil t) (forge-edit-topic-assignees nil t) (forge-edit-topic-review-requests nil t) + (forge-edit-topic-note nil t) (forge-pull-pullreq nil t) (forge-visit-issue nil t) - (forge-visit-pullreq nil t)) + (forge-visit-pullreq nil t) + (forge-visit-topic nil t)) "When not to offer alternatives and ask for confirmation. Many commands by default ask the user to select from a list of @@ -145,18 +150,34 @@ (const :tag "use default without confirmation" t))))) (defconst magit--confirm-actions - '((const reverse) (const discard) - (const rename) (const resurrect) - (const untrack) (const trash) - (const delete) (const abort-rebase) - (const abort-merge) (const merge-dirty) - (const drop-stashes) (const reset-bisect) - (const kill-process) (const delete-unmerged-branch) - (const delete-pr-branch) (const remove-modules) - (const stage-all-changes) (const unstage-all-changes) + '((const discard) + (const reverse) + (const stage-all-changes) + (const unstage-all-changes) + (const delete) + (const trash) + (const resurrect) + (const untrack) + (const rename) + (const reset-bisect) + (const abort-rebase) + (const abort-merge) + (const merge-dirty) + (const delete-unmerged-branch) + (const delete-branch-on-remote) + (const delete-pr-remote) + (const drop-stashes) + (const set-and-push) + (const amend-published) + (const rebase-published) + (const edit-published) + (const remove-modules) + (const remove-dirty-modules) + (const trash-module-gitdirs) + (const kill-process) (const safe-with-wip))) -(defcustom magit-no-confirm nil +(defcustom magit-no-confirm '(set-and-push) "A list of symbols for actions Magit should not confirm, or t. Many potentially dangerous commands by default ask the user for @@ -224,6 +245,13 @@ choice (or selecting another branch), but when a branch has not been merged yet, also make sure the user is aware of that. + `delete-branch-on-remote' Deleting a \"remote branch\" may mean + deleting the (local) \"remote-tracking\" branch only, or also + removing it from the remote itself. The latter often makes more + sense because otherwise simply fetching from the remote would + restore the remote-tracking branch, but doing that can be + surprising and hard to recover from, so we ask. + `delete-pr-remote' When deleting a branch that was created from a pull-request and if no other branches still exist on that remote, then `magit-branch-delete' offers to delete the remote @@ -239,17 +267,26 @@ This action only concerns the deletion of multiple stashes at once. +Publishing: + + `set-and-push' When pushing to the upstream or the push-remote + and that isn't actually configured yet, then the user can first + set the target. If s/he confirms the default too quickly, then + s/he might end up pushing to the wrong branch and if the remote + repository is configured to disallow fixing such mistakes, then + that can be quite embarrassing and annoying. + Edit published history: Without adding these symbols here, you will be warned before editing commits that have already been pushed to one of the branches listed in `magit-published-branches'. - `amend-published' Affects most commands that amend to \"HEAD\". + `amend-published' Affects most commands that amend to `HEAD'. `rebase-published' Affects commands that perform interactive rebases. This includes commands from the commit popup that - modify a commit other than \"HEAD\", namely the various fixup + modify a commit other than `HEAD', namely the various fixup and squash variants. `edit-published' Affects the commands `magit-edit-line-commit' @@ -353,14 +390,21 @@ :group 'magit-miscellaneous :type '(repeat string)) -(defcustom magit-ellipsis ?… - "Character used to abbreviate text. +(defcustom magit-ellipsis (if (char-displayable-p ?…) "…" "...") + "String used to abbreviate text in process buffers. -Currently this is used to abbreviate author names in the margin -and in process buffers to elide `magit-git-global-arguments'." - :package-version '(magit . "2.1.0") +Currently this is only used to elide `magit-git-global-arguments' +in process buffers. In the future it may be used in other places +as well, but not the following: + +- Author names in the log margin are always abbreviated using + \"…\" or if that is not displayable, then \">\". + +- Whether collapsed sections are indicated using ellipsis is + controlled by `magit-section-visibility-indicator'." + :package-version '(magit . "3.0.0") :group 'magit-miscellaneous - :type 'character) + :type 'string) (defcustom magit-update-other-window-delay 0.2 "Delay before automatically updating the other window. @@ -400,7 +444,9 @@ ;;; User Input (defvar helm-completion-in-region-default-sort-fn) +(defvar helm-crm-default-separator) (defvar ivy-sort-functions-alist) +(defvar ivy-sort-matches-functions-alist) (defvar magit-completing-read--silent-default nil) @@ -474,7 +520,8 @@ predicate require-match initial-input hist def))) (setq this-command command) - (if (string= reply "") + ;; Note: Avoid `string=' to support `helm-comp-read-use-marked'. + (if (equal reply "") (if require-match (user-error "Nothing selected") nil) @@ -487,21 +534,27 @@ (complete-with-action action collection string pred)))) (defun magit-builtin-completing-read - (prompt choices &optional predicate require-match initial-input hist def) + (prompt choices &optional predicate require-match initial-input hist def) "Magit wrapper for standard `completing-read' function." (unless (or (bound-and-true-p helm-mode) + (bound-and-true-p ivy-mode) + (bound-and-true-p vertico-mode) + (bound-and-true-p selectrum-mode)) + (setq prompt (magit-prompt-with-default prompt def))) + (unless (or (bound-and-true-p helm-mode) (bound-and-true-p ivy-mode)) - (setq prompt (magit-prompt-with-default prompt def)) (setq choices (magit--completion-table choices))) - (cl-letf (((symbol-function 'completion-pcm--all-completions) - #'magit-completion-pcm--all-completions)) + (cl-letf (((symbol-function 'completion-pcm--all-completions))) + (when (< emacs-major-version 26) + (fset 'completion-pcm--all-completions + 'magit-completion-pcm--all-completions)) (let ((ivy-sort-functions-alist nil)) (completing-read prompt choices predicate require-match initial-input hist def)))) (defun magit-completing-read-multiple - (prompt choices &optional sep default hist keymap) + (prompt choices &optional sep default hist keymap) "Read multiple items from CHOICES, separated by SEP. Set up the `crm' variables needed to read multiple values with @@ -514,6 +567,7 @@ Unlike `completing-read-multiple', the return value is not split into a list." + (declare (obsolete magit-completing-read-multiple* "Magit 3.1.0")) (let* ((crm-separator (or sep crm-default-separator)) (crm-completion-table (magit--completion-table choices)) (choose-completion-string-functions @@ -521,9 +575,13 @@ (minibuffer-completion-table #'crm--collection-fn) (minibuffer-completion-confirm t) (helm-completion-in-region-default-sort-fn nil) + (helm-crm-default-separator nil) + (ivy-sort-matches-functions-alist nil) (input - (cl-letf (((symbol-function 'completion-pcm--all-completions) - #'magit-completion-pcm--all-completions)) + (cl-letf (((symbol-function 'completion-pcm--all-completions))) + (when (< emacs-major-version 26) + (fset 'completion-pcm--all-completions + 'magit-completion-pcm--all-completions)) (read-from-minibuffer (concat prompt (and default (format " (%s)" default)) ": ") nil (or keymap crm-local-completion-map) @@ -535,39 +593,70 @@ (defun magit-completing-read-multiple* (prompt table &optional predicate require-match initial-input - hist def inherit-input-method) + hist def inherit-input-method + no-split) "Read multiple strings in the minibuffer, with completion. Like `completing-read-multiple' but don't mess with order of -TABLE. Also bind `helm-completion-in-region-default-sort-fn' -to nil." - (unwind-protect - (cl-letf (((symbol-function 'completion-pcm--all-completions) - #'magit-completion-pcm--all-completions)) - (add-hook 'choose-completion-string-functions - 'crm--choose-completion-string) - (let* ((minibuffer-completion-table #'crm--collection-fn) - (minibuffer-completion-predicate predicate) - ;; see completing_read in src/minibuf.c - (minibuffer-completion-confirm - (unless (eq require-match t) require-match)) - (crm-completion-table (magit--completion-table table)) - (map (if require-match - crm-local-must-match-map - crm-local-completion-map)) - (helm-completion-in-region-default-sort-fn nil) - ;; If the user enters empty input, `read-from-minibuffer' - ;; returns the empty string, not DEF. - (input (read-from-minibuffer - prompt initial-input map - nil hist def inherit-input-method))) - (and def (string-equal input "") (setq input def)) - ;; Remove empty strings in the list of read strings. - (split-string input crm-separator t))) - (remove-hook 'choose-completion-string-functions - 'crm--choose-completion-string))) +TABLE and take an additional argument NO-SPLIT, which causes +the user input to be returned as a single unmodified string. +Also work around various incompatible features of various +third-party completion frameworks." + (cl-letf* + (;; To implement NO-SPLIT we have to manipulate the respective + ;; `split-string' invocation. We cannot simply advice it to + ;; return the input string because `SELECTRUM' would choke on + ;; that string. Use a variable to pass along the raw user + ;; input string. aa5f098ab + (input nil) + (split-string (symbol-function 'split-string)) + ((symbol-function 'split-string) + (lambda (string &optional separators omit-nulls trim) + (when (and no-split + (equal separators crm-separator) + (equal omit-nulls t)) + (setq input string)) + (funcall split-string string separators omit-nulls trim))) + ;; In Emacs 25 this function has a bug, so we use a copy of the + ;; version from Emacs 26. bef9c7aa3 + ((symbol-function 'completion-pcm--all-completions) + (if (< emacs-major-version 26) + 'magit-completion-pcm--all-completions + (symbol-function 'completion-pcm--all-completions))) + ;; Prevent `BUILT-IN' completion from messing up our existing + ;; order of the completion candidates. aa5f098ab + (table (magit--completion-table table)) + ;; Prevent `IVY' from messing up our existing order. c7af78726 + (ivy-sort-matches-functions-alist nil) + ;; Prevent `HELM' from messing up our existing order. 6fcf994bd + (helm-completion-in-region-default-sort-fn nil) + ;; Prevent `HELM' from automatically appending the separator, + ;; which is counterproductive when NO-SPLIT is non-nil and/or + ;; when reading commit ranges. 798aff564 + (helm-crm-default-separator + (if no-split nil (bound-and-true-p helm-crm-default-separator))) + (values + (if (and no-split + (advice-member-p 'consult-completing-read-multiple + 'completing-read-multiple)) + ;; Our NO-SPLIT hack is not compatible with `CONSULT's + ;; implemenation so fall back to the original function. + ;; #4437 + (unwind-protect + (progn + (advice-remove 'completing-read-multiple + 'consult-completing-read-multiple) + (completing-read-multiple + prompt table predicate require-match initial-input + hist def inherit-input-method)) + (advice-add 'completing-read-multiple :override + 'consult-completing-read-multiple)) + (completing-read-multiple + prompt table predicate require-match initial-input + hist def inherit-input-method)))) + (if no-split input values))) (defun magit-ido-completing-read - (prompt choices &optional predicate require-match initial-input hist def) + (prompt choices &optional predicate require-match initial-input hist def) "Ido-based `completing-read' almost-replacement. Unfortunately `ido-completing-read' is not suitable as a @@ -655,9 +744,11 @@ (debug (form form &rest (characterp form body)))) `(prog1 (pcase (read-char-choice (concat ,prompt - ,(concat (mapconcat 'cadr clauses ", ") - (and verbose ", or [C-g] to abort") " ")) - ',(mapcar 'car clauses)) + (mapconcat #'identity + (list ,@(mapcar #'cadr clauses)) + ", ") + ,(if verbose ", or [C-g] to abort " " ")) + ',(mapcar #'car clauses)) ,@(--map `(,(car it) ,@(cddr it)) clauses)) (message ""))) @@ -754,11 +845,10 @@ "with-editor" ;; Obviously `magit' itself is needed too. "magit" - ;; While this is part of the Magit repository, - ;; it is distributed as a separate package. + ;; While these are part of the Magit repository, + ;; they are distributed as separate packages. + "magit-section" "git-commit" - ;; Even though `async' is a dependency of the - ;; `magit' package, it is not required here. )))) ;; Avoid Emacs bug#16406 by using full path. "-l" ,(file-name-sans-extension (locate-library "magit"))) @@ -780,7 +870,11 @@ (i 0)) `(let ((,s ,string)) (let ,(save-match-data - (--map (list it (list 'match-string (cl-incf i) s)) varlist)) + (cl-mapcan (lambda (sym) + (cl-incf i) + (and (not (eq (aref (symbol-name sym) 0) ?_)) + (list (list sym (list 'match-string i s))))) + varlist)) ,@body)))) (defun magit-delete-line () @@ -813,49 +907,36 @@ "Set the header-line using STRING. Propertize STRING with the `magit-header-line'. If the `face' property of any part of STRING is already set, then that takes -precedence. Also pad the left and right sides of STRING so that -it aligns with the text area." +precedence. Also pad the left side of STRING so that it aligns +with the text area." (setq header-line-format - (concat - (propertize " " 'display '(space :align-to 0)) - string - (propertize " " 'display - `(space :width - (+ left-fringe - left-margin - ,@(and (eq (car (window-current-scroll-bars)) - 'left) - '(scroll-bar))))))) - (magit--add-face-text-property 0 (1- (length header-line-format)) - 'magit-header-line t header-line-format)) + (concat (propertize " " 'display '(space :align-to 0)) + string))) (defun magit-face-property-all (face string) "Return non-nil if FACE is present in all of STRING." - (cl-loop for pos = 0 then (next-single-property-change - pos 'font-lock-face string) - unless pos - return t - for current = (get-text-property pos 'font-lock-face string) - unless (if (consp current) - (memq face current) - (eq face current)) - return nil)) + (catch 'missing + (let ((pos 0)) + (while (setq pos (next-single-property-change pos 'font-lock-face string)) + (let ((val (get-text-property pos 'font-lock-face string))) + (unless (if (consp val) + (memq face val) + (eq face val)) + (throw 'missing nil)))) + (not pos)))) (defun magit--add-face-text-property (beg end face &optional append object) "Like `add-face-text-property' but for `font-lock-face'." - (cl-loop for pos = (next-single-property-change - beg 'font-lock-face object end) - for current = (get-text-property beg 'font-lock-face object) - for newface = (if (listp current) - (if append - (append current (list face)) - (cons face current)) - (if append - (list current face) - (list face current))) - do (progn (put-text-property beg pos 'font-lock-face newface object) - (setq beg pos)) - while (< beg end))) + (while (< beg end) + (let* ((pos (next-single-property-change beg 'font-lock-face object end)) + (val (get-text-property beg 'font-lock-face object)) + (val (if (listp val) val (list val)))) + (put-text-property beg pos 'font-lock-face + (if append + (append val (list face)) + (cons face val)) + object) + (setq beg pos)))) (defun magit--propertize-face (string face) (propertize string 'face face 'font-lock-face face)) @@ -982,27 +1063,26 @@ (advice-add 'auto-revert-handler :around 'auto-revert-handler@bug21559) ) -;; `completion-pcm--all-completions' reverses the completion list. To -;; preserve the order of our pre-sorted completions, we'll temporarily -;; override it with the function below. bug#24676 -(defun magit-completion-pcm--all-completions (prefix pattern table pred) - (if (completion-pcm--pattern-trivial-p pattern) - (all-completions (concat prefix (car pattern)) table pred) - (let* ((regex (completion-pcm--pattern->regex pattern)) - (case-fold-search completion-ignore-case) - (completion-regexp-list (cons regex completion-regexp-list)) - (compl (all-completions - (concat prefix - (if (stringp (car pattern)) (car pattern) "")) - table pred))) - (if (not (functionp table)) - compl - (let ((poss ())) - (dolist (c compl) - (when (string-match-p regex c) (push c poss))) - ;; This `nreverse' call is the only code change made to the - ;; `completion-pcm--all-completions' that shipped with Emacs 25.1. - (nreverse poss)))))) +(when (< emacs-major-version 26) + ;; In Emacs 25 `completion-pcm--all-completions' reverses the + ;; completion list. This is the version from Emacs 26, which + ;; fixes that issue. bug#24676 + (defun magit-completion-pcm--all-completions (prefix pattern table pred) + (if (completion-pcm--pattern-trivial-p pattern) + (all-completions (concat prefix (car pattern)) table pred) + (let* ((regex (completion-pcm--pattern->regex pattern)) + (case-fold-search completion-ignore-case) + (completion-regexp-list (cons regex completion-regexp-list)) + (compl (all-completions + (concat prefix + (if (stringp (car pattern)) (car pattern) "")) + table pred))) + (if (not (functionp table)) + compl + (let ((poss ())) + (dolist (c compl) + (when (string-match-p regex c) (push c poss))) + (nreverse poss))))))) (defun magit-which-function () "Return current function name based on point. @@ -1104,66 +1184,22 @@ (advice-add 'org-man-export :around 'org-man-export--magit-gitman) -;;; Bitmaps +;;; Kludges for Package Managers -(when (fboundp 'define-fringe-bitmap) - (define-fringe-bitmap 'magit-fringe-bitmap+ - [#b00000000 - #b00011000 - #b00011000 - #b01111110 - #b01111110 - #b00011000 - #b00011000 - #b00000000]) - (define-fringe-bitmap 'magit-fringe-bitmap- - [#b00000000 - #b00000000 - #b00000000 - #b01111110 - #b01111110 - #b00000000 - #b00000000 - #b00000000]) - - (define-fringe-bitmap 'magit-fringe-bitmap> - [#b01100000 - #b00110000 - #b00011000 - #b00001100 - #b00011000 - #b00110000 - #b01100000 - #b00000000]) - (define-fringe-bitmap 'magit-fringe-bitmapv - [#b00000000 - #b10000010 - #b11000110 - #b01101100 - #b00111000 - #b00010000 - #b00000000 - #b00000000]) - - (define-fringe-bitmap 'magit-fringe-bitmap-bold> - [#b11100000 - #b01110000 - #b00111000 - #b00011100 - #b00011100 - #b00111000 - #b01110000 - #b11100000]) - (define-fringe-bitmap 'magit-fringe-bitmap-boldv - [#b10000001 - #b11000011 - #b11100111 - #b01111110 - #b00111100 - #b00011000 - #b00000000 - #b00000000]) - ) +(defun magit--straight-chase-links (filename) + "Chase links in FILENAME until a name that is not a link. + +This is the same as `file-chase-links', except that it also +handles fake symlinks that are created by the package manager +straight.el on Windows. + +See ." + (when (and (bound-and-true-p straight-symlink-emulation-mode) + (fboundp 'straight-chase-emulated-symlink)) + (when-let ((target (straight-chase-emulated-symlink filename))) + (unless (eq target 'broken) + (setq filename target)))) + (file-chase-links filename)) ;;; Miscellaneous @@ -1187,7 +1223,7 @@ (save-excursion (save-restriction (widen) - (goto-char ,pos) + (goto-char (or ,pos 1)) ,@body)))) ;;; _ diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-wip.el magit-3.3.0/lisp/magit-wip.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-wip.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-wip.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-wip.el --- commit snapshots to work-in-progress refs -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -30,9 +32,6 @@ ;;; Code: -(eval-when-compile - (require 'subr-x)) - (require 'magit-core) (require 'magit-log) @@ -107,6 +106,7 @@ ;;; Modes +;;;###autoload (define-minor-mode magit-wip-mode "Save uncommitted changes to work-in-progress refs. @@ -287,30 +287,35 @@ (magit-wip-update-wipref ref wipref tree parent files msg "index"))) (defun magit-wip-commit-worktree (ref files msg) - (let* ((wipref (magit--wip-wtree-ref ref)) - (parent (magit-wip-get-parent ref wipref)) - (tree (magit-with-temp-index parent (list "--reset" "-i") - (if files - ;; Note: `update-index' is used instead of `add' - ;; because `add' will fail if a file is already - ;; deleted in the temporary index. - (magit-call-git - "update-index" "--add" "--remove" - (and (pcase (magit-repository-local-get - 'update-index-has-ignore-sw-p 'unset) - (`unset - (let ((val (version<= "2.25.0" - (magit-git-version)))) - (magit-repository-local-set - 'update-index-has-ignore-sw-p val) - val)) - (val val)) - "--ignore-skip-worktree-entries") - "--" files) - (magit-with-toplevel - (magit-call-git "add" "-u" "."))) - (magit-git-string "write-tree")))) - (magit-wip-update-wipref ref wipref tree parent files msg "worktree"))) + (when (or (not files) + ;; `update-index' will either ignore (before Git v2.32.0) + ;; or fail when passed directories (relevant for the + ;; untracked files code paths). + (setq files (seq-remove #'file-directory-p files))) + (let* ((wipref (magit--wip-wtree-ref ref)) + (parent (magit-wip-get-parent ref wipref)) + (tree (magit-with-temp-index parent (list "--reset" "-i") + (if files + ;; Note: `update-index' is used instead of `add' + ;; because `add' will fail if a file is already + ;; deleted in the temporary index. + (magit-call-git + "update-index" "--add" "--remove" + (and (pcase (magit-repository-local-get + 'update-index-has-ignore-sw-p 'unset) + (`unset + (let ((val (version<= "2.25.0" + (magit-git-version)))) + (magit-repository-local-set + 'update-index-has-ignore-sw-p val) + val)) + (val val)) + "--ignore-skip-worktree-entries") + "--" files) + (magit-with-toplevel + (magit-call-git "add" "-u" "."))) + (magit-git-string "write-tree")))) + (magit-wip-update-wipref ref wipref tree parent files msg "worktree")))) (defun magit-wip-update-wipref (ref wipref tree parent files msg start-msg) (cond @@ -442,7 +447,10 @@ (when-let ((reflog (magit-git-lines "reflog" wipref))) (let (tips) (while (and reflog (> count 1)) - (setq reflog (cl-member "^[^ ]+ [^:]+: restart autosaving" + ;; "start autosaving ..." is the current message, but it used + ;; to be "restart autosaving ...", and those messages may + ;; still be around (e.g., if gc.reflogExpire is to "never"). + (setq reflog (cl-member "^[^ ]+ [^:]+: \\(?:re\\)?start autosaving" reflog :test #'string-match-p)) (when (and (cadr reflog) (string-match "^[^ ]+ \\([^:]+\\)" (cadr reflog))) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/magit-worktree.el magit-3.3.0/lisp/magit-worktree.el --- magit-2.99.0.git0957.ge8c7bd03/lisp/magit-worktree.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/magit-worktree.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-worktree.el --- worktree support -*- lexical-binding: t -*- -;; Copyright (C) 2010-2020 The Magit Project Contributors +;; Copyright (C) 2010-2021 The Magit Project Contributors ;; ;; You should have received a copy of the AUTHORS.md file which ;; lists all contributors. If not, see http://magit.vc/authors. @@ -8,6 +8,8 @@ ;; Author: Jonas Bernoulli ;; Maintainer: Jonas Bernoulli +;; SPDX-License-Identifier: GPL-3.0-or-later + ;; Magit is free software; you can redistribute it and/or modify it ;; under the terms of the GNU General Public License as published by ;; the Free Software Foundation; either version 3, or (at your option) @@ -43,7 +45,7 @@ ;;; Commands ;;;###autoload (autoload 'magit-worktree "magit-worktree" nil t) -(define-transient-command magit-worktree () +(transient-define-prefix magit-worktree () "Act on a worktree." :man-page "git-worktree" [["Create new" @@ -162,7 +164,10 @@ (pcase-lambda (`(,path ,barep ,commit ,branch)) (cons (cond (branch (propertize - branch 'font-lock-face 'magit-branch-local)) + branch 'font-lock-face + (if (equal branch (magit-get-current-branch)) + 'magit-branch-current + 'magit-branch-local))) (commit (propertize (magit-rev-abbrev commit) 'font-lock-face 'magit-hash)) (barep "(bare)")) @@ -172,7 +177,7 @@ (pcase-dolist (`(,head . ,path) cols) (magit-insert-section (worktree path) (insert head) - (indent-to align) + (insert (make-string (- align (length head)) ?\s)) (insert (let ((r (file-relative-name path)) (a (abbreviate-file-name path))) (if (< (string-width r) (string-width a)) r a))) diff -Nru magit-2.99.0.git0957.ge8c7bd03/lisp/Makefile magit-3.3.0/lisp/Makefile --- magit-2.99.0.git0957.ge8c7bd03/lisp/Makefile 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/lisp/Makefile 2021-10-06 12:51:17.000000000 +0000 @@ -61,6 +61,7 @@ magit-subtree.elc: magit.elc magit-ediff.elc: magit.elc magit-gitignore.elc: magit.elc +magit-bunlde.elc: magit.elc magit-extras.elc: magit.elc magit-merge.elc git-rebase.elc: magit.elc magit-imenu.elc: magit.elc git-rebase.elc diff -Nru magit-2.99.0.git0957.ge8c7bd03/.mailmap magit-3.3.0/.mailmap --- magit-2.99.0.git0957.ge8c7bd03/.mailmap 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/.mailmap 2021-10-06 12:51:17.000000000 +0000 @@ -1,5 +1,6 @@ Alex Dunn Alex Ott +Allen Li Andriy Kmit' Bar Magal Benjamin Motz @@ -8,9 +9,12 @@ Chillar Anand Christophe Junke Damien Cassou +Daniel Fleischer danielfleischer David Abrahams +David Ellison Dean Kariniemi <8913263+d3k4r@users.noreply.github.com> Dennis Paskorz +Dominique Quatravaux Evan Torrie Evgkeni Sampelnikof Evgkeni Sampelnikof @@ -20,6 +24,7 @@ Ivan Brennan Jesse Alama Joakim Jalap +Johann Klähn Jon Vanderwijk Jonas Bernoulli Jonas Bernoulli @@ -42,6 +47,7 @@ Natalie Weizenbaum Nathan Weizenbaum Noam Postavsky Noam Postavsky +Pancho Horrillo Peter J. Weisberg Peter Vasil Phil Sainty @@ -54,6 +60,7 @@ Sylvain Rousseau Syohei Yoshida Sébastien Gross +Thierry Volpiatto Tunc Uzlu Wei Huang Wilfred Hughes diff -Nru magit-2.99.0.git0957.ge8c7bd03/Makefile magit-3.3.0/Makefile --- magit-2.99.0.git0957.ge8c7bd03/Makefile 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/Makefile 2021-10-06 12:51:17.000000000 +0000 @@ -7,7 +7,7 @@ install install-lisp install-docs install-info \ test test-interactive magit \ clean clean-lisp clean-docs clean-archives \ - stats bump-version melpa-post-release \ + stats bump-versions bump-snapshots \ dist versionlib magit-$(VERSION).tar.gz all: lisp docs @@ -50,6 +50,8 @@ $(info ====) $(info ) $(info make test - run tests) + $(info make test-git - run tests using Git functions) + $(info make test-libgit - run tests using libgit functions) $(info make test-interactive - run tests interactively) $(info make emacs-Q - run emacs -Q plus Magit) $(info ) @@ -111,6 +113,27 @@ (load-file \"t/magit-tests.el\")\ (ert-run-tests-batch-and-exit))" +test-git: + @$(BATCH) --eval "(progn\ + $$suppress_warnings\ + (require 'magit)\ + (setq magit-inhibit-libgit t)\ + (unless (eq 'git (magit-gitimpl))\ + (message \"Git implementation not being used.\")\ + (kill-emacs 1))\ + (load-file \"t/magit-tests.el\")\ + (ert-run-tests-batch-and-exit))" + +test-libgit: + @$(BATCH) --eval "(progn\ + $$suppress_warnings\ + (require 'magit)\ + (unless (eq 'libgit (magit-gitimpl))\ + (message \"libgit not available.\")\ + (kill-emacs 1))\ + (load-file \"t/magit-tests.el\")\ + (ert-run-tests-batch-and-exit))" + test-interactive: @$(EMACSBIN) -Q $(LOAD_PATH) --eval "(progn\ (load-file \"t/magit-tests.el\")\ @@ -155,6 +178,9 @@ authors: @$(MAKE) -C Documentation authors + @git commit --gpg-sign -m "AUTHORS.md: Update list of contributors" \ + -o -- Documentation/AUTHORS.md + @git show --pretty= -p HEAD publish-stats: @$(MAKE) -C Documentation publish-stats @@ -188,7 +214,8 @@ @$(TAR) cz --mtime=./magit-$(VERSION) -f magit-$(VERSION).tar.gz magit-$(VERSION) @$(RMDIR) magit-$(VERSION) -define set_package_requires +define set_package_requires_nongnu + (with-temp-file "lisp/git-commit.el" (insert-file-contents "lisp/git-commit.el") (re-search-forward "^;; Package-Requires: ") @@ -197,63 +224,152 @@ `((emacs ,emacs-version) ;` (dash ,dash-version) (transient ,transient-version) - (with-editor ,with-editor-version))))) + (with-editor ,with-editor-version)))) + (re-search-forward "^;; Package-Version: ") + (delete-region (point) (line-end-position)) + (insert "$(GIT_COMMIT_VERSION)")) + +(with-temp-file "lisp/magit.el" + (insert-file-contents "lisp/magit.el") + (re-search-forward "^;; Package-Requires: ") + (delete-region (point) (line-end-position)) + (insert (format "%S" +`((emacs ,emacs-version) ;` + (dash ,dash-version) + (git-commit ,git-commit-version) + (magit-section ,magit-section-version) + (transient ,transient-version) + (with-editor ,with-editor-version)))) + (re-search-forward "^;; Package-Version: ") + (delete-region (point) (line-end-position)) + (insert "$(MAGIT_SECTION_VERSION)")) + (with-temp-file "lisp/magit-libgit.el" (insert-file-contents "lisp/magit-libgit.el") (re-search-forward "^;; Package-Requires: ") (delete-region (point) (line-end-position)) (insert (format "%S" `((emacs "$(LIBGIT_EMACS_VERSION)") ;` - (magit "$(LIBGIT_MAGIT_VERSION)") - (libgit ,libgit-version))))) + (libgit ,libgit-version) + (magit ,magit-version)))) + (re-search-forward "^;; Package-Version: ") + (delete-region (point) (line-end-position)) + (insert "$(MAGIT_LIBGIT_VERSION)")) + (with-temp-file "lisp/magit-section.el" (insert-file-contents "lisp/magit-section.el") (re-search-forward "^;; Package-Requires: ") (delete-region (point) (line-end-position)) (insert (format "%S" `((emacs ,emacs-version) ;` - (dash ,dash-version))))) + (dash ,dash-version)))) + (re-search-forward "^;; Package-Version: ") + (delete-region (point) (line-end-position)) + (insert "$(MAGIT_SECTION_VERSION)")) +endef +export set_package_requires_nongnu + +define set_package_requires_melpa + +(with-temp-file "lisp/git-commit-pkg.el" + (insert (format +"(define-package \"git-commit\" \"$(GIT_COMMIT_VERSION)\" + \"Edit Git commit messages.\" + '((emacs %S) + (dash %S) + (transient %S) + (with-editor %S)) + :homepage \"https://magit.vc\" + :keywords '(\"git\" \"tools\" \"vc\")) +" emacs-version + dash-version + transient-version + with-editor-version))) + (with-temp-file "lisp/magit-pkg.el" - (insert (pp-to-string -`(define-package "magit" "$(VERSION)" ;` - "A Git porcelain inside Emacs." - '((emacs ,emacs-version) ;' - (async ,async-version) - (dash ,dash-version) - (git-commit ,git-commit-version) - ;; FIXME (magit-section ,magit-section-version) - (transient ,transient-version) - (with-editor ,with-editor-version)) - :keywords '("git" "tools" "vc")))) ;' - (goto-char (point-min)) - (re-search-forward " \"A") - (goto-char (match-beginning 0)) - (insert "\n ")) + (insert (format +"(define-package \"magit\" \"$(MAGIT_VERSION)\" + \"A Git porcelain inside Emacs.\" + '((emacs %S) + (dash %S) + (git-commit %S) + (magit-section %S) + (transient %S) + (with-editor %S)) + :homepage \"https://magit.vc\" + :keywords '(\"git\" \"tools\" \"vc\")) +" emacs-version + dash-version + git-commit-version + magit-section-version + transient-version + with-editor-version))) + +(with-temp-file "lisp/magit-libgit-pkg.el" + (insert (format +"(define-package \"magit-libgit\" \"$(MAGIT_LIBGIT_VERSION)\" + \".\" + '((emacs %S) + (libgit %S) + (magit %S)) + :homepage \"https://magit.vc\" + :keywords '(\"git\" \"tools\" \"vc\")) +" emacs-version + libgit-version + magit-version))) + +(with-temp-file "lisp/magit-section-pkg.el" + (insert (format +"(define-package \"magit-section\" \"$(MAGIT_SECTION_VERSION)\" + \"Sections for read-only buffers\" + '((emacs %S) + (dash %S)) + :homepage \"https://magit.vc\" + :keywords '(\"tools\")) +" emacs-version + dash-version))) +endef +export set_package_requires_melpa + +define set_package_versions +(emacs-version "$(EMACS_VERSION)") +(dash-version "$(DASH_VERSION)") +(git-commit-version "$(GIT_COMMIT_VERSION)") +(libgit-version "$(LIBGIT_VERSION)") +(magit-version "$(MAGIT_VERSION)") +(magit-libgit-version "$(MAGIT_LIBGIT_VERSION)") +(magit-section-version "$(MAGIT_SECTION_VERSION)") +(transient-version "$(TRANSIENT_VERSION)") +(with-editor-version "$(WITH_EDITOR_VERSION)") +endef +export set_package_versions + +define set_package_snapshots +(emacs-version "$(EMACS_VERSION)") +(dash-version "$(DASH_MELPA_SNAPSHOT)") +(git-commit-version "$(GIT_COMMIT_MELPA_SNAPSHOT)") +(libgit-version "$(LIBGIT_MELPA_SNAPSHOT)") +(magit-version "$(MAGIT_MELPA_SNAPSHOT)") +(magit-libgit-version "$(MAGIT_LIBGIT_MELPA_SNAPSHOT)") +(magit-section-version "$(MAGIT_SECTION_MELPA_SNAPSHOT)") +(transient-version "$(TRANSIENT_MELPA_SNAPSHOT)") +(with-editor-version "$(WITH_EDITOR_MELPA_SNAPSHOT)") endef -export set_package_requires +export set_package_snapshots -bump-versions: bump-versions-1 texi -bump-versions-1: +bump-versions: _bump-versions texi +_bump-versions: @$(BATCH) --eval "(let (\ - (emacs-version \"$(EMACS_VERSION)\")\ - (async-version \"$(ASYNC_VERSION)\")\ - (dash-version \"$(DASH_VERSION)\")\ - (git-commit-version \"$(GIT_COMMIT_VERSION)\")\ - (libgit-version \"$(LIBGIT_VERSION)\")\ - (magit-section-version \"$(MAGIT_SECTION_VERSION)\")\ - (transient-version \"$(TRANSIENT_VERSION)\")\ - (with-editor-version \"$(WITH_EDITOR_VERSION)\"))\ - $$set_package_requires)" + $$set_package_versions)\ + $$set_package_requires_nongnu\ + $$set_package_requires_melpa)" bump-snapshots: @$(BATCH) --eval "(let (\ - (emacs-version \"$(EMACS_VERSION)\")\ - (async-version \"$(ASYNC_MELPA_SNAPSHOT)\")\ - (dash-version \"$(DASH_MELPA_SNAPSHOT)\")\ - (git-commit-version \"$(GIT_COMMIT_MELPA_SNAPSHOT)\")\ - (libgit-version \"$(LIBGIT_MELPA_SNAPSHOT)\")\ - (magit-section-version \"$(MAGIT_SECTION_MELPA_SNAPSHOT)\")\ - (transient-version \"$(TRANSIENT_MELPA_SNAPSHOT)\")\ - (with-editor-version \"$(WITH_EDITOR_MELPA_SNAPSHOT)\"))\ - $$set_package_requires)" - @git commit -a -m "Reset Package-Requires for Melpa" + $$set_package_versions)\ + $$set_package_requires_nongnu)" + @$(BATCH) --eval "(let (\ + $$set_package_snapshots)\ + $$set_package_requires_melpa)" + @git commit -a --gpg-sign -m "Reset Package-Requires for Melpa" + @git show --pretty= -p HEAD diff -Nru magit-2.99.0.git0957.ge8c7bd03/README.md magit-3.3.0/README.md --- magit-2.99.0.git0957.ge8c7bd03/README.md 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/README.md 2021-10-06 12:51:17.000000000 +0000 @@ -131,10 +131,9 @@ *** [![Paren Xkcb](https://img.shields.io/badge/%28-%20%20%20-red.svg)](https://xkcd.com/859) [![GPL v3](https://img.shields.io/badge/license-GPL_v3-green.svg)](http://www.gnu.org/licenses/gpl-3.0.txt) -[![Build Status](https://travis-ci.org/magit/magit.svg?branch=master)](https://travis-ci.org/magit/magit) +[![Build Status](https://github.com/magit/magit/workflows/test/badge.svg?branch=master)](https://github.com/magit/magit/actions) [![Melpa](https://melpa.org/packages/magit-badge.svg)](https://melpa.org/#/magit) [![Melpa Stable](https://stable.melpa.org/packages/magit-badge.svg)](https://stable.melpa.org/#/magit) -[![Git Xkcd](https://img.shields.io/badge/xkcd-git-orange.svg)](https://xkcd.com/1597) [![Eierlegende Wollmilchsau](https://img.shields.io/badge/eierlegende-Wollmilchsau-green.svg)](https://magit.vc/manual/magit) [![Swiss Made](https://img.shields.io/badge/swiss-made-red.svg?colorA=E11A27&colorB=555555)](https://magit.vc/stats/authors.html#commits_per_author) [![Netscape](https://magit.vc/assets/netscape-20px.png)](https://en.wikipedia.org/wiki/Browser_wars) diff -Nru magit-2.99.0.git0957.ge8c7bd03/RelNotes.org magit-3.3.0/RelNotes.org --- magit-2.99.0.git0957.ge8c7bd03/RelNotes.org 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/RelNotes.org 2021-10-06 12:51:17.000000000 +0000 @@ -1,498 +1,152 @@ -* Magit v3.0.0 Release Notes (unreleased) -** Breaking changes - -- Dropped support for Git v2.0 and v2.1. - -- After some users intervened I have decided to NOT drop support for - Emacs 25 in this release as I had intended to do. Emacs 25 should - remain supported for at least a few more releases. - -- Magit now uses Transient instead of Magit-Popup. In the transition - many popups gained new arguments and/or commands, most of which are - not mentioned explicitly in these release notes. Many of these - commands are hidden by default because they are only useful to a - subset of users. See https://emacsair.me/2019/02/14/transient-0.1 - for information about the new Transient library and how to enable - hidden commands, among other things. - -- The commands ~magit-branch-pull-request~, ~magit-checkout-pull-request~ - and ~magit-worktree-checkout-pull-request~ were removed in favor of - improved implementations provided by the new Forge package. - -- ~C-c C-e~ is no longer bound to ~magit-dispatch-popup~. It is bound to - ~magit-edit-thing~ now, so that Forge can add section-specific - bindings using this key. ~magit-dispatch-popup~ has been renamed to - ~magit-dispatch~ and continues to be available on ~h~, ~?~ and ~C-c C-c~. - #3659 - -- ~C-c C-b~ is no longer bound to ~magit-browse-thing~ to avoid a conflict - with ~magit-go-backward~ in diff and log buffers. ~C-c C-w~ (as in web) - is used instead now. #3659 - -- The option ~magit-display-file-buffer-function~ was removed. 8a214c9fb - -- The buffer-local variable ~magit-refresh-arguments~ was replaced with - several variables because ~(nth N magit-refresh-arguments)~ just isn't - very informative. Several related API functions had to be changed - in incompatible ways. This was done by adding new functions and - keeping the old variable and functions around for backward - compatibility. Packages using the obsolete variable and functions - should be adjusted soon. #3836 - -** Changes since v2.90.0 - -- It isn't always obvious that a section can be expanded, especially - to users who are just getting started with Magit. Mainly to make - it easier for those users, expandable and collapsible sections now - get an indicator in the fringe. - - The new option ~magit-section-visibility-indicator~ can be used to - disable this or to select the alternative style, which shows an - ellipsis at the end of the heading of each expandable section - instead. #3679 - -- The "Version" column in ~magit-submodule-list-mode~ and - ~magit-repolist-mode~ buffers now shows when a repository is dirty. - 0b86dbfd6 - -- Added new command ~magit-log-merged~. This command requires - ~git-when-merged~ (https://github.com/mhagger/git-when-merged). - It is a suffix of ~magit-log~ but is disabled by default. #3657 - -- Added new class slot ~keymap~ to allow other packages to define - section-specific keymaps without naming them ~magit-TYPE-section-map~, - which would mean using a symbol prefix (~magit-~) that does not match - the package name. - -- Added new option ~magit-diff-refine-ignore-whitespace~, overriding and - defaulting to the value of ~smerge-refine-ignore-whitespace~. #3671 - -- Added new option ~magit-diff-paint-whitespace-lines~, which controls - in what kind of lines (added/removed/context) whitespace errors are - highlighted. #3671 - -- It is now possible to show whitespace errors only in uncommitted - changes by setting ~magit-diff-paint-whitespace~ to ~uncommitted~. The - obsolete value ~status~ is treated as a synonym. The intention always - was to allow limiting to uncommitted changes and limiting to changes - shown in the status buffer was the closest approximation readily - available when this feature was first added. #3671 - -- The commands ~magit-commit-instant-fixup~, ~magit-commit-instant-squash~ - and ~magit-rebase-autosquash~ now unconditionally preserve empty - commits that were already present before the autosquash rebase - performed by these commands. This is the safe default; if you want - to drop such commits, then you have to enable ~--autosquash~ in the - popup and then invoke ~magit-rebase-interactive~. #3670 - -- The option ~magit-repository-directories~ defaults to ~nil~ again - because the non-nil default added in v2.90.0 led to surprising - changes in behavior. The documentation of this option and the - related ~magit-status~ command were made less ambiguous. #3673 - -- Renamed the face ~git-commit-note~ to ~git-commit-keyword~ because that - is what text in brackets is called elsewhere in Magit and because - the term "note" was ambiguous in this context. The old face name - is still defined as an alias, but that will be removed eventually. - -- The command ~magit-worktree-checkout~ now also offers tags and remote - branches as completion candidates. #3692 - -- The command ~magit-commit-reword~ now always uses ~--allow-empty~ - because when you reword an empty commit, then you have already - confirmed that you are okay with that commit being empty. - -- The new buffer-local variable ~git-commit-need-summary-line~ can - be of use if you want to write Git notes without separating the - first line with an empty line from the rest of the text. #3676 - -- Made ~magit-tag-release~ more flexible and added it as a suffix of - ~magit-tag~. 2d14f84b2 - -- Bound "C-c C-o" (in addition to "C-c C-w") to ~magit-browse-thing~ for - consistency with ~org-open-at-point~'s binding. 1e1193666 - -- ~magit-copy-section-value~ now supports stripping diff markers. #3716 - -- ~magit-insert-*-branch-header~ now colorizes keywords in the message. - 98e328200 - -- ~magit-unstage~ can now unstage files that were staged using - ~--intent-to-add~. #3753 - -- ~magit-read-branch-or-commit~ now offers symbolic refnames such as - ~ORIG_HEAD~ as completion candidates. #3766 - -- ~magit-stage-modified~ and ~magit-unstage-all~ now take the log file - filter into account. #3767 - -- New command ~magit-skip-worktree~ can be used to tell Git to pretend - that the working tree version is up-to-date; ~magit-no-skip-worktree~ - does the opposite. Both commands are available from the - ~magit-gitignore~ prefix but are disabled by default. #3710 - -- ~--rebase-merges~, an option available in Git version 2.18.0 and - later, is now supported. The ~--rebase-merges~ infix of - ~magit-rebase~ is disabled by default. #3762 - -- New command ~git-rebase-break~ inserts a "break" action in the - rebase to-do sequence (available as of Git v2.20). #3762 - -- The ~--color-moved~ diff argument is supported now, but isn't - available from the diff transients by default. To enable it - use "C-x l" in those transients. #3424 - -- Added new option ~magit-revision-filter-files-on-follow~ that - controls whether a revision buffer shown from a log shares the log's - file restriction despite ~--follow~ being in the log arguments. - #3680 - -- ~magit-cherry~ is now available from the ~magit-dispatch~ prefix. - ef311f378 - -~ ~magit-cherry-spinoff~ now offers the upstream as the default - starting-point. e5a2a0ac2 - -- Added new command ~magit-branch-spinout~. #3794. - -- ~magit-process-password-auth-source~ now allows the use of emails as - usernames. 05d82d501 - -- Added new option ~magit-prefer-push-default~, which controls whether - commands that configure the push-remote do so by setting the value - of ~remote.pushDefault~ or ~branch..pushRemote~. Also removed - option ~magit-remote-set-if-missing~. 07ca042b6 - -- Support for bookmarks was rewritten from scratch. #3836, cd391a035 - -- The new options ~magit-prefix-use-buffer-arguments~ and - ~magit-direct-use-buffer-arguments~ replace the old option - ~magit-use-sticky-arguments~. The default "stickiness" of arguments - has changed. #3836, 0e67ca9eb - -- Like when moving through a log, moving through a list of cherries - now automatically updates the revision or blob buffer. #3836 +* It's Magit! A Git Porcelain inside Emacs -- Added new option ~magit-worktree-read-directory-name-function~. #3820 +Magit is a text-based Git user interface that puts an unmatched focus +on streamlining workflows. Commands are invoked using short mnemonic +key sequences that take the cursor’s position in the highly actionable +interface into account to provide context-sensitive behavior. -- TODO Added basic support for libgit2. #3841 +With Magit you can do nearly everything that you can do when using Git +on the command-line, but at greater speed and while taking advantage +of advanced features that previously seemed too daunting to use on a +daily basis. Many users will find that by using Magit they can become +more effective Git user. -- ~git bisect~ is now run asynchronously. #3802 +For more information about Magit, see https://magit.vc. -- ~magit-branch-or-commit-at-point~ now falls back to an abbreviated - hash instead of something like "master~2", because the latter often - leads to undesirable behavior. fd5eb5b43 +* Magit v3.3.0 Release Notes -- ~magit-toggle-buffer-lock~ is now a suffix of both ~magit-diff~ and - ~magit-log~. c09993112 +Released 4th October 2021 by Jonas Bernoulli. -- When invoked with a prefix argument, then ~magit-clone~ now acts as a - prefix command. If the new option ~magit-clone-always-transient~ is - non-nil, then it always acts as a prefix command. #3846 +I am pleased to announce the release of Magit version 3.3.0, +representing 88 commits by 6 contributors over two month. -- Clone commands now accept repository names and similar abbreviations - in addition to complete urls. The new options ~magit-clone-name-alist~ - and ~magit-clone-url-format~ control how the translation is done. #3846 +Also see https://emacsair.me/2021/10/04/magit-3.3. -- When called from ~magit-dispatch~, then ~magit-diff~ and ~magit-log~ no - longer set the file limit to the file visited in the current buffer. - ccc72469e - -- ~RET~ (~magit-diff-visit-file~) on a committed change now always visits - the respective commit. Previously it did that for all commits - except the ~HEAD~ commit. This made it impossible to visit the ~HEAD~ - commit using this or a related command and also was inconsistent. - - Likewise ~RET~ on an uncommitted removal now visits ~HEAD~, the last - commit that still had those lines. Previously it visited the file - in the working tree, making it difficult to blame the previous - version of modified lines. - - Now ~C-RET~ (~magit-diff-visit-worktree~) has to be used to visit the - file in the working tree for any commit or uncommitted removals. - Setting the new option ~magit-diff-visit-avoid-head-blob~ to a non-nil - value restores the old behavior of ~magit-diff-visit-file~. #3848 - -- ~magit-diff-visit-worktree~ now does a much better job at jumping to - the correct location in the file. c9e5425cd - -- Added new command ~magit-find-file-other-frame~. 9a69c74ca - -- Renamed command ~magit-diff-visit-file-worktree~ to - ~magit-diff-visit-worktree-file~. 4f739cd35 - -- Added new commands ~magit-diff-visit-file-other-frame~, - ~magit-diff-visit-worktree-file-other-window~, and - ~magit-diff-visit-worktree-file-other-frame~. 756d61911, 6704b3248 - -- Added new option ~magit-process-prompt-functions~. #3845 - -- ~magit-find-file~ is now available from ~magit-file-dispatch~. - 9c587d458 - -- ~magit-find-file~ and related commands learned to visit a file from - the worktree or index. #3860 - -- ~magit-find-file~ and related commands learned to go to the position - in the visited file that corresponds to the position in the - previously current buffer. #3860 - -- ~magit-diff-buffer-file~ learned to visit a commit instead of a range - when appropriate. #3860 - -- ~magit-show-commit~ and ~magit-diff-buffer-file~ learned to go to the - position in the diff that corresponds to the position in the - previously current file-visiting buffer. #3860 - -- Added new command ~magit-blob-visit-file~. When visiting a blob, then - it goes to the same location in the respective file in the working - tree. #3860 - -- ~magit-add-change-log-entry{,-other-window}~ learned to extract the - file name from blob-visiting buffers. - -- ~magit-tag-release~ now runs ~git~ asynchronously. #3855 - -- When invoked with two prefix arguments, then ~magit-mode-burry-buffer~ - now also kills all other Magit buffers associated with the current - repository. #3863 - -- ~magit-branch-or-commit-at-point~ was taught about Forge pull-requests. - 9447edd12 - -- When merging a branch that corresponds to a Forge pull-request, then - the commit message is modified to contain the pull-request number. - 15331d7c0 - -- For consistency ~magit-file-rename~ now also renames buffers that - visit untracked files. #3916 - -- Additional history simplification arguments were added to the log - transients. Because only a minority of users will use those, they - were put on levels that are not shown by default. 8f8a2f1cf - -- Added new commands ~magit-assume-unchanged, ~magit-no-assume-unchanged~, - ~magit-jump-to-skip-worktree~ and ~magit-jump-to-assume-unchanged~, and - section inserter ~magit-insert-assume-unchanged-files~. 2d0de8614 ff - -- Magit buffers are now compatible with ~whitespace-mode~ (and other - modes which use font-lock). #3840 - -- Added new command ~magit-status-here~ available from file-visiting - buffers at ~C-c M-g g~. This command tries to go to the position in - the status buffer that corresponds to the position in the current - file-visiting buffer. Setting ~magit-status-goto-file-position~ to - a non-nil value causes ~magit-status~ to behave the same way. #3930 - -- Replaced ~magit-repolist-column-dirty~ with ~magit-repolist-column-flag~ - which allows specifying arbitrary flags and predicates in custom order - using ~magit-repolist-column-flag-alist~. #3936 #3937 - -- The buffer that shows a stash is now updated automatically when - moving through a list of stashes if the user added the new - ~magit-status-maybe-update-stash-buffer~ and/or - ~magit-stashes-maybe-update-stash-buffer~ to - ~magit-section-movement-hook~. #3943 - -- Added new commands ~magit-log-matching-branches~ and - ~magit-log-matching-tags~. #3958, #3983 - -- Added new option ~magit-disable-line-numbers~. #3971 - -- Added new option ~magit-log-margin-show-committer-date~. 1b9995238 - -- Added new command ~magit-worktree-move~ to allow you to move an - existing worktree to a new directory. #3978 - -- Introduced two new faces to customize the appearance of commit messages: - ~magit-diff-revision-summary~ and ~magit-diff-revision-summary-highlight~. - #3988 - -- Commands under the ~magit-gitignore~ prefix now include directories - that contain only untracked files as completion candidates. #3985 - -- Added new command ~magit-toggle-verbose-refresh~. c63ec3920 - -- Added new function ~magit-disable-section-inserter~, which can be used - to disable a section only in the current repository. This mechanism - is useful for exceptionally large repositories. #4017 - -- Added new transient prefix command ~magit-status-jump~ and turned the - existing jumper commands into suffixes. 655950f40 - -- Added new option ~magit-copy-revision-abbreviated~. #4014 - -- Added new transient prefix command ~git-commit-insert-pseudo-header~ - and turned the existing inserter commands into suffixes. e88242679 - -- Added new command ~magit-push-notes-ref~. dff0bca6f - -- The ~--irreversible-delete~ diff argument is supported now, but isn't - available from the diff transients by default. To enable it use - "C-x l" in those transients. #4056 - -** Fixes since v2.90.0 - -- Bumped the minimal required version of ~git-commit~ to the correct - version. e9bd33758 - -- Dropped the new "v" prefix that we started to add to release tags - starting with the previous release in places where that prefix is - undesirable. f441cf6d7 - -- Staging and unstaging submodules while ~diff.submodule~'s value is ~log~ - broke shortly before the v2.90.0 release. #3654 +** Breaking changes -- When another window is already displaying the file buffer, then - ~magit-display-file-buffer-other-window~ did additionally display - it in the current window. #3662 +- The last remaining alphabetic keys (both lower- and uppercase) are + now bound in ~magit-mode-map~. ~H~ to ~magit-describe-section~, ~j~ to the + new ~magit-status-quick~ (or ~magit-status-jump~ in status buffers), ~J~ + to the new ~magit-display-repository-buffer~, ~Q~ to ~magit-git-command~ + and ~Z~ to ~magit-worktree~, and once Forge is loaded, then ~N~ to + ~forge-dispatch~. (~Z~ used to be bound to ~magit-stash~, which now is + only available on ~z~.) #4259, 9bec1c54a, e401bd4d3 -- It was undefined whether highlighting of word-granularity - differences or of whitespace-error had higher priority. #3671 +- ~I~ is now bound to ~magit-init~ instead of ~magit-gitignore~, which + continues to be available on ~i~. Users of the ~magit-imerge~ package + (which previously bound ~i~) should consult its library header for a + suggestion on how to resolve the resulting conflict. b54b537db -- The Custom type definition of ~magit-diff-adjust-tab-width~ was - broken. #3671 +** Changes since v3.2.0 -- In the log-select buffers point was no longer placed on the same - commit as was at point in the buffer from which the command was - invoked. #3674 +- No longer automatically add ~--full-history~ when showing a log for a + single file that isn't being tracked anymore. #4381 -- ~magit-diff-type~ falsely concluded that a diff buffer showed - unstaged changes when diffing a range where the right side resolves - to the same commit as ~HEAD~. #3666 +- ~magit-stash-both~ now asks before discarding merge state. #4345 -- ~magit-log-trace-definition-function~ defaulted to ~which-function~, - which isn't reliable because it used Imenu, which uses a cache but - by default never invalidates. Now we use ~magit-which-function~, a - replacement that never uses an outdated cache. +- Several infix arguments, which previously could only be disabled + or have a numeric value, can now also be enabled without having + an explicit numeric value. #4379 -- ~magit-log-trace-definition~ didn't account for Git treating "-" - differently from e.g. "_", leading to false-positives like - "foo-suffix" being considered a match for "foo". +- Added ~-Xignore-space-change~ and ~-Xignore-all-space~ to ~magit-merge~. + Like most newly added expert arguments they have to be explicitly + [[https://magit.vc/manual/transient/Enabling-and-Disabling-Suffixes.html][revealed]]. #4387 -- ~magit-log-trace-definition~ didn't do the escaping that Git expects - for function names with colons. #4051 +- Added new command ~magit-status-quick~, which shows the status buffer + but avoids refreshing it for performance reasons. #4259 -- A regression in ~magit-log-move-to-parent~ prevented it from doing its - job. #3682 +- Added new commands ~magit-display-repository-buffer~ (bound to ~j~ in + Magit buffers) and ~magit-switch-to-repository-buffer~ (bound to ~J~) + and variants for switching to any existing Magit buffer belonging + to the current repository. #4259 -- ~magit-clone~ didn't run ~magit-credential-hook~. #3683 +- Added new command ~magit-dired-am-apply-patches~ for use in Dired. + #4094. -- ~magit-list-repositories~ failed if one of the repositories that it - tries to list is empty. #3686 +- Rearranged ~magit-patch~ and added a binding for ~magit-am~. 8ec3a1a21, + 8cadf302b -- The summary element from ~git-commit-font-lock-keyword-1~ lost against - the elements of ~git-commit-elisp-text-mode-keywords~, causing the - summary line to lose its special appearance when a "string" or - `symbol' appears in it. +- Added new command ~magit-help~ (bound to ~h~ in ~magit-dispatch~), which + simply shows Magit's Info manual. 5bba62629 -- ~magit-split-branch-name~ did not take into account that remote names - can contain slashes. #3685 +- When listing entries for Imenu, then remove entry counts from group + titles for the benefit of third-party packages that need stable + titles. #4477 -- ~magit-which-function~ now simply resets Imenu's cache and then calls - ~which-function~. The old approach that tried to outsmart Imenu was - broken. #3691 +- Include Forge's ~pullreq~ and ~issue~ sections when listing entries for + Imenu. f4016f734 -- ~magit-describe-section-briefly~ did not actually display a section - ident when called interactively, as the docstring claimed. Now it - displays the section ident, which is useful in - ~magit-status-initial-section~. +- Bound ~imenu~ in the ~magit-status-jump~ prefix. 678df30c3 -- Section movement commands got confused by type change sections being - treated as a special kind of hunk. #3698 +- Added new transient prefix command ~magit-bundle~, which provides + support for ~git bundle~. #4392 -- ~x-strech-cursor~ was set globally. #3707 +- When minibuffer completion allows for a branch or a commit to be + selected and the former is preferred and thus offered as default + then, if possible, offer the commit at point as the first choice + initially accessible with ~next-history-element~. #4291 -- ~magit-blame-echo~ was broken. #3720 +- Bound ~magit-refs-set-show-commit-count~ in the ~magit-show-refs~ + prefix. 2fe42f63d -- ~magit-rev-name~ sometimes returned ~nil~ even when it could return a - name and it returned e.g. "origin/HEAD" instead of "origin/master". - 2042957a7, d500c442 +- Added new option ~magit-commit-diff-inhibit-same-window~. #4132 -- ~magit-insert-*-branch-header~ did not account for empty commit - messages. #3719 +- Added support for invoking Smerge's "keep" commands when point is on + a hunk in a Magit buffer. They can be invoked using the same key + bindings as in file-visiting buffers or ~RET~, ~u~, ~b~ and ~l~. #4458 -- ~magit--painted-branch-at-point~ failed in some cases, causing an - error. e7e612e3c +- Added new command ~magit-remote-unshallow~. #4480 -- In newer Git versions the rebase list shown in the status buffer - could contain duplicated entries for the current commit. 1e1cd0e28 +- Added new option ~git-commit-use-local-message-ring~. #4503 -- When deleting a remote branch failed, the logic for deciding whether - to prune the local remote-tracking ref was too loose, leading to - false positives. #3650 +** Fixes since v3.2.0 -- ~magit-ediff-stage~ offered untracked files as completion candidates - even though it cannot handle those. 8dd612dfb +- Make ~magit-branch-remote-head~ and ~magit-branch-current~ fall back + to ~:inverse-video~ when the ~:box~ attribute isn't support, i.e. in + a terminal. If this change does not have any effect for you then + your theme probably changes these faces and should stop doing so. + #4206 -- Fix handling of passphrase prompts which are output with leading - carriage return, such as those produced by Openssh 8.0. #3843 +- In some cases refreshing a buffer caused the cursor to jump to a + different position. #4148 -- The default value for ~magit-view-git-manual-method~ was treated as - invalid. #3873 +- ~magit-convert-filename-for-git~ did not expand absolute filenames, + which is necessary because Git does not understand ~~/~. de1dc8e74 -- Unlike other ~magit-*-files~ functions, ~magit-ignored-files~ returned - paths relative to the current directory instead of the top-level of - the repository. 6d3f12d58 +- ~magit-rebase~ did not enable ~--autostash~ by default but the + documentation says it does. 421be65a3 -- Staging a hunk applied the change to the wrong location in rare - cases where repetitive diff context prevented ~git apply~ from - finding the correct location. #3924 +- ~magit-clone-read-repository~ did not convert filenames before passing + them to Git. 4aa7d2928 -- Staging a hunk with no context now aborts, as staging a region - within such a hunk already did, to avoid unintended and confusing - results. #3924 +- Due to a regression in v2.90.0, ~magit-wip-log~ and + ~magit-wip-log-current~ failed to extract the previous tips of the + wip refs from the reflog (which is relevant when + ~~magit-wip-merge-branch~ is nil). c327824b0 -- Adjusted many faces so that they continue to extend to the edge of - the window as intended. This was made necessary by a backward - incompatible change in Emacs 27. #3986 +- An old attempt to avoid needlessly updating section highlighting + did not actually succeed. #3976 -- The ability to stage regions from within intent-to-add files broke - for users running Git v2.19.0 or later due to a change in the - default display of these files in the diff output. #4026 +- An error occurred when first showing a status buffer and + ~which-function-mode~ is enabled because that caused Imenu to collect + items at a time when that is not possible yet. #4481 -- ~magit-stash-branch-here~ applied the stash without checking out the - new branch. d3cee7f8c +- A change in Git v2.32.0 made it necessary to explicitly filter out + directories when committing to wip worktree refs. #4499 -- A regression in v2.90.0 led to ~magit-wip-mode~ committing to "/refs/heads/HEAD" rather than "/HEAD" when on a - detached head. +- Fixed appearance of Gravatar images by forcing their size instead + relying the service to return the promised size as advertised. + 8771401d4 -- Modifying a file, marking it with a "skip-worktree" or "assume - unchanged" bit, and then modifying it again triggered a failure in - ~magit-wip-commit-worktree~. #4037 +- ~git-commit-setup~ enabled the major-mode after setting local + variables, which caused non-permanent variables to be reset. + ece2cb84d -- Various bug fixes to - ~magit-branch-delete~ (3e73ff19d), - ~magit--{upstream,pushbranch}-suffix-predicate~ (0ce7fbbc2), - ~magit-patch-create~ (470272a0f), - ~magit--cherry-spinoff-read-args~ (add276810), - ~magit-refs--insert-cherry-commits~ (3b37e6dc1), - ~magit--{pushbranch,upstream}-suffix-predicate~ (cef3b1217), - ~magit-diff-insert-file-section~ (01cf0c165), - ~magit-insert-unpushed-to-upstream-or-recent~ (02445d6e3), - ~magit-ref-equal~ (46862d9d2), - ~magit-ref-fullname~ (66b85daea), - ~magit-insert-unpulled-from-upstream~ (0363e9bac), - ~magit-git-version~ (0abc761f5), - ~auto-revert-buffers--buffer-list-filter~ (713bd64bf), - ~magit-insert-revision-gravatar~ (1f7e84c26), - ~magit-process-unset-mode-line~ (457a685e5), - ~magit-ido-completing-read~ (f52ab7977), - ~magit-file-untrack~ (0984d77fb), - ~magit-ref-p~ (8b33bc7c7), - ~git-commit-setup~ (675b75ded), - ~magit-{,no-}skip-worktree~ (34d6ac27d), - ~magit-fetch-all~ (904bb82ca), - ~magit-branch-configure~ (7246bf291), - ~magit--maybe-update-blob-buffer~ (1d57893a6), - ~magit-...-maybe-update-...-buffer~ (8d3459b55), - ~magit-read-gpg-secret-key~ (9d68a455d), - ~magit-gitignore-in-subdir~ (8c4e8ed74), - ~magit-save-repository-buffers~ (82136796f), - ~magit-stash-drop~ (a4972766a), - ~magit-ignore-submodules-p~ (a7699f868), - ~magit-log-propertize-keywords~ (ac1ee3df5), +* Authors -This release also contains other minor improvements, bug fixes, typo -fixes, and documentation fixes. + 76 Jonas Bernoulli + 8 Kyle Meyer + 1 Daniel Nagy + 1 Franklin Delehelle + 1 Jonathon McKitrick + 1 Lin Sun diff -Nru magit-2.99.0.git0957.ge8c7bd03/t/default.nix magit-3.3.0/t/default.nix --- magit-2.99.0.git0957.ge8c7bd03/t/default.nix 1970-01-01 00:00:00.000000000 +0000 +++ magit-3.3.0/t/default.nix 2021-10-06 12:51:17.000000000 +0000 @@ -0,0 +1,18 @@ +let + emacs-overlay = import (builtins.fetchTarball { url = https://github.com/nix-community/emacs-overlay/archive/master.tar.gz; }); + emacs-ci = import (builtins.fetchTarball { url = https://github.com/purcell/nix-emacs-ci/archive/master.tar.gz; }); + + pkgs = import { overlays = [ emacs-overlay ]; }; +in +builtins.mapAttrs + (version: emacs: + (pkgs.emacsPackagesGen emacs).emacsWithPackages + (emacsPackages: [ + emacsPackages.dash + emacsPackages.transient + ] ++ (with emacsPackages.melpaPackages; [ + libgit + with-editor + ]) + )) + emacs-ci diff -Nru magit-2.99.0.git0957.ge8c7bd03/t/magit-tests.el magit-3.3.0/t/magit-tests.el --- magit-2.99.0.git0957.ge8c7bd03/t/magit-tests.el 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/t/magit-tests.el 2021-10-06 12:51:17.000000000 +0000 @@ -1,6 +1,6 @@ ;;; magit-tests.el --- tests for Magit -;; Copyright (C) 2011-2018 The Magit Project Contributors +;; Copyright (C) 2011-2021 The Magit Project Contributors ;; ;; License: GPLv3 @@ -14,6 +14,12 @@ (require 'magit) +(defun magit-test-init-repo (dir &rest args) + (let ((magit-git-global-arguments + (nconc (list "-c" "init.defaultBranch=master") + magit-git-global-arguments))) + (magit-git "init" args dir))) + (defmacro magit-with-test-directory (&rest body) (declare (indent 0) (debug t)) (let ((dir (make-symbol "dir"))) @@ -23,7 +29,7 @@ (push "GIT_AUTHOR_EMAIL=a.u.thor@example.com" process-environment) (condition-case err (cl-letf (((symbol-function #'message) (lambda (&rest _)))) - (let ((default-directory ,dir)) + (let ((default-directory (file-truename ,dir))) ,@body)) (error (message "Keeping test directory:\n %s" ,dir) (signal (car err) (cdr err)))) @@ -31,7 +37,11 @@ (defmacro magit-with-test-repository (&rest body) (declare (indent 0) (debug t)) - `(magit-with-test-directory (magit-git "init" ".") ,@body)) + `(magit-with-test-directory (magit-test-init-repo ".") ,@body)) + +(defmacro magit-with-bare-test-repository (&rest body) + (declare (indent 1) (debug t)) + `(magit-with-test-directory (magit-test-init-repo "." "--bare") ,@body)) ;;; Git @@ -46,7 +56,7 @@ (ert-deftest magit-toplevel:basic () (let ((find-file-visit-truename nil)) (magit-with-test-directory - (magit-git "init" "repo") + (magit-test-init-repo "repo") (magit-test-magit-toplevel) (should (equal (magit-toplevel "repo/.git/") (expand-file-name "repo/"))) @@ -68,13 +78,15 @@ ;; require a functioning `sudo'. (sudo-method (cdr (assoc "sudo" tramp-methods))) ((cdr (assq 'tramp-login-program sudo-method)) - (list shell-file-name)) + (list (if (file-executable-p "/bin/sh") + "/bin/sh" + shell-file-name))) ((cdr (assq 'tramp-login-args sudo-method)) nil)) (magit-with-test-directory (setq default-directory (concat (format "/sudo:%s@localhost:" (user-login-name)) default-directory)) - (magit-git "init" "repo") + (magit-test-init-repo "repo") (magit-test-magit-toplevel) (should (equal (magit-toplevel "repo/.git/") (expand-file-name "repo/"))) @@ -88,10 +100,10 @@ (ert-deftest magit-toplevel:submodule () (let ((find-file-visit-truename nil)) (magit-with-test-directory - (magit-git "init" "remote") + (magit-test-init-repo "remote") (let ((default-directory (expand-file-name "remote/"))) (magit-git "commit" "-m" "init" "--allow-empty")) - (magit-git "init" "super") + (magit-test-init-repo "super") (setq default-directory (expand-file-name "super/")) (magit-git "submodule" "add" "../remote" "repo/") (magit-test-magit-toplevel) @@ -133,7 +145,7 @@ (should (equal (magit-toplevel "subdir-link-indirect") (expand-file-name "repo/"))) ;; wrap/*link - (magit-git "init" "wrap") + (magit-test-init-repo "wrap") (make-symbolic-link "../repo" "wrap/repo-link") (make-symbolic-link "../repo/subdir" "wrap/subdir-link") (make-symbolic-link "../repo/subdir/subsubdir" "wrap/subsubdir-link") @@ -154,11 +166,11 @@ (ert-deftest magit-get () (magit-with-test-directory - (magit-git "init" "remote") + (magit-test-init-repo "remote") (let ((default-directory (expand-file-name "remote/"))) (magit-git "commit" "-m" "init" "--allow-empty") (magit-git "config" "a.b" "remote-value")) - (magit-git "init" "super") + (magit-test-init-repo "super") (setq default-directory (expand-file-name "super/")) ;; Some tricky cases: ;; Multiple config values. @@ -324,6 +336,18 @@ '(unpushed . "@{upstream}..") (magit-rev-parse "--short" "master"))))) +;;; libgit + +(ert-deftest magit-in-bare-repo () + "Test `magit-bare-repo-p' in a bare repository." + (magit-with-bare-test-repository + (should (magit-bare-repo-p)))) + +(ert-deftest magit-in-non-bare-repo () + "Test `magit-bare-repo-p' in a non-bare repository." + (magit-with-test-repository + (should-not (magit-bare-repo-p)))) + ;;; Utils (ert-deftest magit-utils:add-face-text-property () diff -Nru magit-2.99.0.git0957.ge8c7bd03/.travis.yml magit-3.3.0/.travis.yml --- magit-2.99.0.git0957.ge8c7bd03/.travis.yml 2020-04-26 07:43:35.000000000 +0000 +++ magit-3.3.0/.travis.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,45 +0,0 @@ -language: generic -os: linux -dist: xenial - -env: - global: - - CURL="curl -fsSkL --retry 9 --retry-delay 9" - - GHRAW="https://raw.githubusercontent.com" - - BUILD_MAGIT_LIBGIT="false" - jobs: - - EMACS_VERSION=25.1 - # 25.2 is identical to 25.3 except for a critical security bug in - # enriched text mode (see Emacs Bug#28350). - - EMACS_VERSION=25.3 - - EMACS_VERSION=26.1 # Debian is on this version. - - EMACS_VERSION=26.3 - - EMACS_VERSION=27 # 27.0.90, emacs-27 branch, built daily - - EMACS_VERSION=master # 28.0.50, master branch, built daily - -jobs: - allow_failures: - - env: EMACS_VERSION=master - -install: - - $CURL -O https://github.com/npostavs/emacs-travis/releases/download/bins/emacs-bin-${EMACS_VERSION}.tar.gz - - tar -xaf emacs-bin-${EMACS_VERSION}.tar.gz -C / - - export EMACS=/tmp/emacs/bin/emacs - - $CURL -O ${GHRAW}/magnars/dash.el/master/dash.el - - $CURL -O ${GHRAW}/magit/transient/master/lisp/transient.el - - $CURL -O ${GHRAW}/magit/with-editor/master/with-editor.el - - $EMACS -Q --batch -L . -f batch-byte-compile dash.el transient.el with-editor.el - - $EMACS --version - -script: - - git config --global user.name "A U Thor" - - git config --global user.email a.u.thor@example.com - - git tag 0 - - make lisp EMACSBIN=$EMACS DASH_DIR=$PWD - - make test EMACSBIN=$EMACS DASH_DIR=$PWD - -notifications: - email: - # Default is change, but that includes a new branch's 1st success. - on_success: never - on_failure: always # The default.