From: Andreas Gerler Date: Mon, 17 Jan 2022 10:57:28 +0000 (+0100) Subject: update magit X-Git-Url: http://git.bundesbrandschatzamt.de/?a=commitdiff_plain;h=5a8c729bce3ee5681e2906bae2c954375388da6f;p=emacsconfig.git update magit Signed-off-by: Andreas Gerler --- diff --git a/bba.org b/bba.org index feeb5c46..d7157b94 100644 --- a/bba.org +++ b/bba.org @@ -302,11 +302,7 @@ Keep track of your important stuff! (package-initialize) (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/")) (add-to-list 'package-archives '("org" . "http://orgmode.org/elpa/")) - ) - (progn - (add-to-list 'load-path "~/.emacs.d/elpa/cl-lib-0.5") - (add-to-list 'load-path "~/.emacs.d/elpa/magit-1.2.0") - )) + )) #+END_SRC * calendar @@ -4323,7 +4319,7 @@ function to convert groups of spaces to hard tabs. ) ) (define-key global-map "\M-g\M-b" 'magit-branch-manager) - (define-key global-map "\M-gb" 'magit-blame-popup) + (define-key global-map "\M-gb" 'magit-blame) (define-key global-map "\C-cm" 'magit-status) (global-set-key (kbd "C-c s-m") 'magit-list-repositories) diff --git a/custom.el b/custom.el index 0110f4d3..03c3c9c9 100644 --- a/custom.el +++ b/custom.el @@ -20,13 +20,13 @@ '(grep-template "grep -i -nH -e ") '(helm-comint-mode-list '(comint-mode slime-repl-mode sql-interactive-mode)) '(history-length 1000) - '(magit-commit-arguments (quote ("--signoff" "--gpg-sign=43BA01102D205F88"))) + '(magit-commit-arguments '("--signoff" "--gpg-sign=43BA01102D205F88")) '(magit-commit-signoff t) - '(magit-git-global-arguments (quote ("--no-pager"))) - '(magit-log-arguments (quote ("--graph" "--decorate" "-n256"))) - '(magit-log-margin (quote (t "%Y-%m-%d %H:%M " magit-log-margin-width t 18))) + '(magit-git-global-arguments '("--no-pager")) + '(magit-log-arguments '("--graph" "--decorate" "-n256")) + '(magit-log-margin '(t "%Y-%m-%d %H:%M " magit-log-margin-width t 18)) '(magit-pull-arguments nil) - '(magit-repo-dirs (quote ("~/git"))) + '(magit-repo-dirs '("~/git")) '(org-agenda-files (quote ("~/workorg/work.org" "~/org/notes.org" "~/org/emacs.org" "~/org/it.org" "~/org/refile.org" "~/org/workhours.org"))) diff --git a/elpa/magit-20210802.1524/AUTHORS.md b/elpa/magit-20210802.1524/AUTHORS.md deleted file mode 100644 index 7f70f7a6..00000000 --- a/elpa/magit-20210802.1524/AUTHORS.md +++ /dev/null @@ -1,374 +0,0 @@ -Authors -======= - -The following people have contributed to Magit, including the -libraries `git-commit.el`, `magit-popup.el`, and `with-editor.el` -which are distributed as separate Elpa packages. - -For statistics see https://magit.vc/stats/authors.html. - -Names below are sorted alphabetically. - -Author ------- - -- Marius Vollmer - -Maintainer ----------- - -- Jonas Bernoulli - -Developers ----------- - -- Kyle Meyer -- Noam Postavsky - -Retired Maintainers and Developers ----------------------------------- - -- Nicolas Dudebout -- Peter J. Weisberg -- Pieter Praet -- Phil Jackson -- Rémi Vanicat -- Yann Hodique - -Contributors ------------- - -- Aaron Culich -- Aaron Madlon-Kay -- Abdo Roig-Maranges -- Adam Benanti <0entropy@protonmail.com> -- Adam Kruszewski -- Adam Porter -- Adam Spiers -- Adeodato Simó -- Ævar Arnfjörð Bjarmason -- Alan Falloon -- Alban Gruin -- Aleksey Uimanov -- Alexander Gramiak -- Alexander Miller -- Alex Branham -- Alex Dunn -- Alexey Voinov -- Alex Kost -- Alex Ott -- Allen Li -- Andreas Fuchs -- Andreas Liljeqvist -- Andreas Rottmann -- Andrei Chițu -- Andrew Eggenberger -- Andrew Kirkpatrick -- Andrew Psaltis -- Andrew Schwartzmeyer -- Andrey Smirnov -- Andriy Kmit' -- Andy Sawyer -- Aria Edmonds -- Arialdo Martini -- Arnau Roig Ninerola -- Ashlynn Anderson -- Barak A. Pearlmutter -- Bar Magal -- Bart Bakker -- Basil L. Contovounesios -- Bastian Beischer -- Benjamin Motz -- Ben North -- Ben Walton -- Bob Uhl -- Bradley Wright -- Brandon W Maister -- Brian Leung -- Brian Warner -- Bryan Shell -- Buster Copley -- Carl Lieberman -- Chillar Anand -- Chris Bernard -- Chris Done -- Chris LaRose -- Chris Moore -- Chris Ring -- Chris Shoemaker -- Christian Dietrich -- Christian Kluge -- Christophe Junke -- Christopher Monsanto -- Clément Pit-Claudel -- Cornelius Mika -- 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 -- Dan LaManna -- Danny Zhu -- Dato Simó -- David Abrahams -- David Ellison -- David Hull -- David L. Rager -- David Wallin -- Dean Kariniemi <8913263+d3k4r@users.noreply.github.com> -- Dennis Paskorz -- Divye Kapoor -- Dominique Quatravaux -- Duianto Vebotci -- Eli Barzilay -- Eric Davis -- Eric -- Eric Prud'hommeaux -- Eric Schulte -- Erik Anderson -- Evan Torrie -- Evgkeni Sampelnikof -- Eyal Lotem -- Fabian Wiget -- Felix Geller -- Felix Yan -- Feng Li -- Florian Ragwitz -- Fritz Grabo -- Fritz Stelzer -- Geoff Shannon -- George Kadianakis -- Graham Clark -- 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 -- Jan Tatarik -- Jasper St. Pierre -- Jeff Bellegarde -- Jeff Dairiki -- Jeremy Meng -- Jesse Alama -- Jim Blandy -- Joakim Jalap -- Johannes Altmanninger -- 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 -- Jon Vanderwijk -- Jordan Galby -- Jordan Greenberg -- Josh Elsasser -- Josiah Schwab -- Julien Danjou -- Justin Burkett -- Justin Caratzas -- Justin Guenther -- Justin Thomas -- Kan-Ru Chen -- Kenny Ballou -- Keshav Kini -- Kevin Brubeck Unhammer -- Kevin J. Foley -- Kévin Le Gouguec -- Kimberly Wolk -- Knut Olav Bøhmer -- Kyle Meyer -- Laurent Laffont -- Laverne Schrock -- Leandro Facchinetti -- Lele Gaifax -- Leo Liu -- Leonardo Etcheverry -- Leo Vivier -- Lingchao Xin -- Li-Yun Chang -- Lluís Vilanova -- Loic Dachary -- Louis Roché -- Luís Oliveira -- Luke Amdor -- Magnus Malm -- Mak Kolybabi -- Manuel Vázquez Acosta -- Marcel Wolf -- Marc Herbert -- Marcin Bachry -- Marco Craveiro -- Marco Wahl -- Marc Sherry -- Marian Schubert -- Mario Rodas -- Marius Vollmer -- 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 -- Michal Sojka -- Miciah Masters -- Miles Bader -- Miloš Mošić -- Mitchel Humpherys -- Moritz Bunkus -- Naoya Yamashita -- Natalie Weizenbaum -- Nguyễn Tuấn Anh -- Nic Ferier -- Nick Alcock -- Nick Alexander -- Nick Dimiduk -- Nicklas Lindgren -- Nicolas Dudebout -- Nicolas Petton -- Nicolas Richard -- 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 -- Peter Eisentraut -- Peter Jaros -- Peter J. Weisberg -- Peter Vasil -- Philippe Cavalaria -- Philippe Vaucher -- Philipp Fehre -- Philipp Haselwarter -- Philipp Stephani -- Philip Weaver -- Phil Jackson -- Phil Sainty -- Pierre Neidhardt -- Pieter Praet -- Prathamesh Sonpatki -- Pritam Baral -- rabio -- Radon Rosborough -- Rafael Laboissiere -- Raimon Grau -- Ramkumar Ramachandra -- Remco van 't Veer -- Rémi Vanicat -- René Stadler -- Richard Kim -- Robert Boone -- Robin Green -- Roey Darwish Dror -- Roger Crew -- Romain Francoise -- Ron Parker -- Roy Crihfield -- Rüdiger Sonderfeld -- Russell Black -- Ryan C. Thompson -- Sam Cedarbaum -- Samuel Bronson -- Samuel W. Flint -- Sanjoy Das -- Sean Allred -- Sean Bryant -- Sean Whitton -- Sebastian Wiesner -- Sébastien Gross -- Seong-Kook Shin -- Sergey Pashinin -- Sergey Vinokurov -- Servilio Afre Puentes -- Siavash Askari Nasr -- Silent Sphere -- Simon Pintarelli -- Štěpán Němec -- Steven Chow -- Steven E. Harris -- Steven Thomas -- Steven Vancoillie -- Steve Purcell -- Suhail Shergill -- Sylvain Rousseau -- Syohei Yoshida -- Szunti -- Takafumi Arakaki -- Tassilo Horn -- TEC -- Teemu Likonen -- Teruki Shigitani -- Thierry Volpiatto -- Thomas A Caswell -- Thomas Fini Hansen -- Thomas Frössman -- Thomas Jost -- Thomas Riccardi -- Tibor Simko -- Timo Juhani Lindfors -- Tim Perkins -- Tim Wraight -- Ting-Yu Lin -- Tom Feist -- Topi Miettinen -- Troy Hinckley -- Tsuyoshi Kitamoto -- Tunc Uzlu -- 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 -- Yuichi Higashi -- Yuri Khan -- Zach Latta -- zakora -- Zhu Zihao -- zilongshanren diff --git a/elpa/magit-20210802.1524/LICENSE b/elpa/magit-20210802.1524/LICENSE deleted file mode 100644 index f288702d..00000000 --- a/elpa/magit-20210802.1524/LICENSE +++ /dev/null @@ -1,674 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - 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 - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "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. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -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 -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - 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 -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program 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 of the License, or - (at your option) any later version. - - This program 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 program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - 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 --git a/elpa/magit-20210802.1524/dir b/elpa/magit-20210802.1524/dir deleted file mode 100644 index dfdbd715..00000000 --- a/elpa/magit-20210802.1524/dir +++ /dev/null @@ -1,18 +0,0 @@ -This is the file .../info/dir, which contains the -topmost node of the Info hierarchy, called (dir)Top. -The first time you invoke Info you start off looking at this node. - -File: dir, Node: Top This is the top of the INFO tree - - This (the Directory node) gives a menu of major topics. - Typing "q" exits, "H" lists all Info commands, "d" returns here, - "h" gives a primer for first-timers, - "mEmacs" visits the Emacs manual, etc. - - In Emacs, you can click mouse button 2 on a menu item or cross reference - to select it. - -* Menu: - -Emacs -* Magit: (magit). Using Git from Emacs with Magit. diff --git a/elpa/magit-20210802.1524/git-rebase.el b/elpa/magit-20210802.1524/git-rebase.el deleted file mode 100644 index 6a8a7775..00000000 --- a/elpa/magit-20210802.1524/git-rebase.el +++ /dev/null @@ -1,828 +0,0 @@ -;;; git-rebase.el --- Edit Git rebase files -*- lexical-binding: t -*- - -;; 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. - -;; Author: Phil Jackson -;; Maintainer: Jonas Bernoulli - -;; 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 . - -;;; Commentary: - -;; This package assists the user in editing the list of commits to be -;; rewritten during an interactive rebase. - -;; When the user initiates an interactive rebase, e.g. using "r e" in -;; a Magit buffer or on the command line using "git rebase -i REV", -;; Git invokes the `$GIT_SEQUENCE_EDITOR' (or if that is undefined -;; `$GIT_EDITOR' or even `$EDITOR') letting the user rearrange, drop, -;; reword, edit, and squash commits. - -;; This package provides the major-mode `git-rebase-mode' which makes -;; doing so much more fun, by making the buffer more colorful and -;; providing the following commands: -;; -;; C-c C-c Tell Git to make it happen. -;; C-c C-k Tell Git that you changed your mind, i.e. abort. -;; -;; p Move point to previous line. -;; n Move point to next line. -;; -;; M-p Move the commit at point up. -;; M-n Move the commit at point down. -;; -;; k Drop the commit at point. -;; c Don't drop the commit at point. -;; r Change the message of the commit at point. -;; e Edit the commit at point. -;; s Squash the commit at point, into the one above. -;; f Like "s" but don't also edit the commit message. -;; b Break for editing at this point in the sequence. -;; x Add a script to be run with the commit at point -;; being checked out. -;; z Add noop action at point. -;; -;; SPC Show the commit at point in another buffer. -;; RET Show the commit at point in another buffer and -;; select its window. -;; C-/ Undo last change. -;; -;; Commands for --rebase-merges: -;; l Associate label with current HEAD in sequence. -;; MM Merge specified revisions into HEAD. -;; Mt Toggle whether the merge will invoke an editor -;; before committing. -;; t Reset HEAD to the specified label. - -;; You should probably also read the `git-rebase' manpage. - -;;; Code: - -(require 'magit) - -(require 'easymenu) -(require 'server) -(require 'with-editor) - -(defvar recentf-exclude) - -;;; Options -;;;; Variables - -(defgroup git-rebase nil - "Edit Git rebase sequences." - :link '(info-link "(magit)Editing Rebase Sequences") - :group 'tools) - -(defcustom git-rebase-auto-advance t - "Whether to move to next line after changing a line." - :group 'git-rebase - :type 'boolean) - -(defcustom git-rebase-show-instructions t - "Whether to show usage instructions inside the rebase buffer." - :group 'git-rebase - :type 'boolean) - -(defcustom git-rebase-confirm-cancel t - "Whether confirmation is required to cancel." - :group 'git-rebase - :type 'boolean) - -;;;; Faces - -(defgroup git-rebase-faces nil - "Faces used by Git-Rebase mode." - :group 'faces - :group 'git-rebase) - -(defface git-rebase-hash '((t (:inherit magit-hash))) - "Face for commit hashes." - :group 'git-rebase-faces) - -(defface git-rebase-label '((t (:inherit magit-refname))) - "Face for labels in label, merge, and reset lines." - :group 'git-rebase-faces) - -(defface git-rebase-description nil - "Face for commit descriptions." - :group 'git-rebase-faces) - -(defface git-rebase-killed-action - '((t (:inherit font-lock-comment-face :strike-through t))) - "Face for commented commit action lines." - :group 'git-rebase-faces) - -(defface git-rebase-comment-hash - '((t (:inherit git-rebase-hash :weight bold))) - "Face for commit hashes in commit message comments." - :group 'git-rebase-faces) - -(defface git-rebase-comment-heading - '((t :inherit font-lock-keyword-face)) - "Face for headings in rebase message comments." - :group 'git-commit-faces) - -;;; Keymaps - -(defvar git-rebase-mode-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map special-mode-map) - (define-key map (kbd "C-m") 'git-rebase-show-commit) - (define-key map (kbd "p") 'git-rebase-backward-line) - (define-key map (kbd "n") 'forward-line) - (define-key map (kbd "M-p") 'git-rebase-move-line-up) - (define-key map (kbd "M-n") 'git-rebase-move-line-down) - (define-key map (kbd "c") 'git-rebase-pick) - (define-key map (kbd "k") 'git-rebase-kill-line) - (define-key map (kbd "C-k") 'git-rebase-kill-line) - (define-key map (kbd "b") 'git-rebase-break) - (define-key map (kbd "e") 'git-rebase-edit) - (define-key map (kbd "l") 'git-rebase-label) - (define-key map (kbd "MM") 'git-rebase-merge) - (define-key map (kbd "Mt") 'git-rebase-merge-toggle-editmsg) - (define-key map (kbd "m") 'git-rebase-edit) - (define-key map (kbd "f") 'git-rebase-fixup) - (define-key map (kbd "q") 'undefined) - (define-key map (kbd "r") 'git-rebase-reword) - (define-key map (kbd "w") 'git-rebase-reword) - (define-key map (kbd "s") 'git-rebase-squash) - (define-key map (kbd "t") 'git-rebase-reset) - (define-key map (kbd "x") 'git-rebase-exec) - (define-key map (kbd "y") 'git-rebase-insert) - (define-key map (kbd "z") 'git-rebase-noop) - (define-key map (kbd "SPC") 'git-rebase-show-or-scroll-up) - (define-key map (kbd "DEL") 'git-rebase-show-or-scroll-down) - (define-key map (kbd "C-x C-t") 'git-rebase-move-line-up) - (define-key map [M-up] 'git-rebase-move-line-up) - (define-key map [M-down] 'git-rebase-move-line-down) - (define-key map [remap undo] 'git-rebase-undo) - map) - "Keymap for Git-Rebase mode.") - -(put 'git-rebase-reword :advertised-binding (kbd "r")) -(put 'git-rebase-move-line-up :advertised-binding (kbd "M-p")) -(put 'git-rebase-kill-line :advertised-binding (kbd "k")) - -(easy-menu-define git-rebase-mode-menu git-rebase-mode-map - "Git-Rebase mode menu" - '("Rebase" - ["Pick" git-rebase-pick t] - ["Reword" git-rebase-reword t] - ["Edit" git-rebase-edit t] - ["Squash" git-rebase-squash t] - ["Fixup" git-rebase-fixup t] - ["Kill" git-rebase-kill-line t] - ["Noop" git-rebase-noop t] - ["Execute" git-rebase-exec t] - ["Move Down" git-rebase-move-line-down t] - ["Move Up" git-rebase-move-line-up t] - "---" - ["Cancel" with-editor-cancel t] - ["Finish" with-editor-finish t])) - -(defvar git-rebase-command-descriptions - '((with-editor-finish . "tell Git to make it happen") - (with-editor-cancel . "tell Git that you changed your mind, i.e. abort") - (git-rebase-backward-line . "move point to previous line") - (forward-line . "move point to next line") - (git-rebase-move-line-up . "move the commit at point up") - (git-rebase-move-line-down . "move the commit at point down") - (git-rebase-show-or-scroll-up . "show the commit at point in another buffer") - (git-rebase-show-commit - . "show the commit at point in another buffer and select its window") - (undo . "undo last change") - (git-rebase-kill-line . "drop the commit at point") - (git-rebase-insert . "insert a line for an arbitrary commit") - (git-rebase-noop . "add noop action at point"))) - -;;; Commands - -(defun git-rebase-pick () - "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. -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. -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. -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. -If the region is active, act on all lines touched by the region." - (interactive) - (git-rebase-set-action "fixup")) - -(defvar-local git-rebase-comment-re nil) - -(defvar git-rebase-short-options - '((?b . "break") - (?e . "edit") - (?f . "fixup") - (?l . "label") - (?m . "merge") - (?p . "pick") - (?r . "reword") - (?s . "squash") - (?t . "reset") - (?x . "exec")) - "Alist mapping single key of an action to the full name.") - -(defclass git-rebase-action () - (;; action-type: commit, exec, bare, label, merge - (action-type :initarg :action-type :initform nil) - ;; Examples for each action type: - ;; | action | action options | target | trailer | - ;; |--------+----------------+---------+---------| - ;; | pick | | hash | subject | - ;; | exec | | command | | - ;; | noop | | | | - ;; | reset | | name | subject | - ;; | merge | -C hash | name | subject | - (action :initarg :action :initform nil) - (action-options :initarg :action-options :initform nil) - (target :initarg :target :initform nil) - (trailer :initarg :trailer :initform nil) - (comment-p :initarg :comment-p :initform nil))) - -(defvar git-rebase-line-regexps - `((commit . ,(concat - (regexp-opt '("e" "edit" - "f" "fixup" - "p" "pick" - "r" "reword" - "s" "squash") - "\\(?1:") - " \\(?3:[^ \n]+\\) ?\\(?4:.*\\)")) - (exec . "\\(?1:x\\|exec\\) \\(?3:.*\\)") - (bare . ,(concat (regexp-opt '("b" "break" "noop") "\\(?1:") - " *$")) - (label . ,(concat (regexp-opt '("l" "label" - "t" "reset") - "\\(?1:") - " \\(?3:[^ \n]+\\) ?\\(?4:.*\\)")) - (merge . ,(concat "\\(?1:m\\|merge\\) " - "\\(?:\\(?2:-[cC] [^ \n]+\\) \\)?" - "\\(?3:[^ \n]+\\)" - " ?\\(?4:.*\\)")))) - -;;;###autoload -(defun git-rebase-current-line () - "Parse current line into a `git-rebase-action' instance. -If the current line isn't recognized as a rebase line, an -instance with all nil values is returned." - (save-excursion - (goto-char (line-beginning-position)) - (if-let ((re-start (concat "^\\(?5:" (regexp-quote comment-start) - "\\)? *")) - (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))) - (or (cdr (assoc action git-rebase-short-options)) - action)) - :action-options (match-string-no-properties 2) - :target (match-string-no-properties 3) - :trailer (match-string-no-properties 4) - :comment-p (and (match-string 5) t)) - ;; Use default empty class rather than nil to ease handling. - (git-rebase-action)))) - -(defun git-rebase-set-action (action) - "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 - (when pos (goto-char pos)) - (and (oref (git-rebase-current-line) action-type) - t))) - -(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))))) - ((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. -If N is negative, move the commit up instead. With an active -region, move all the lines that the region touches, not just the -current line." - (interactive "p") - (pcase-let* ((`(,beg ,end) - (or (git-rebase-region-bounds) - (list (line-beginning-position) - (1+ (line-end-position))))) - (pt-offset (- (point) beg)) - (mark-offset (and mark-active (- (mark) beg)))) - (save-restriction - (narrow-to-region - (point-min) - (1- - (if git-rebase-show-instructions - (save-excursion - (goto-char (point-min)) - (while (or (git-rebase-line-p) - ;; The output for --rebase-merges has empty - ;; lines and "Branch" comments interspersed. - (looking-at-p "^$") - (looking-at-p (concat git-rebase-comment-re - " Branch"))) - (forward-line)) - (line-beginning-position)) - (point-max)))) - (if (or (and (< n 0) (= beg (point-min))) - (and (> n 0) (= end (point-max))) - (> end (point-max))) - (ding) - (goto-char (if (< n 0) beg end)) - (forward-line n) - (atomic-change-group - (let ((inhibit-read-only t)) - (insert (delete-and-extract-region beg end))) - (let ((new-beg (- (point) (- end beg)))) - (when (use-region-p) - (setq deactivate-mark nil) - (set-mark (+ new-beg mark-offset))) - (goto-char (+ new-beg pt-offset)))))))) - -(defun git-rebase-move-line-up (n) - "Move the current commit (or command) N lines up. -If N is negative, move the commit down instead. With an active -region, move all the lines that the region touches, not just the -current line." - (interactive "p") - (git-rebase-move-line-down (- n))) - -(defun git-rebase-highlight-region (start end window rol) - (let ((inhibit-read-only t) - (deactivate-mark nil) - (bounds (git-rebase-region-bounds))) - (mapc #'delete-overlay magit-section-highlight-overlays) - (when bounds - (magit-section-make-overlay (car bounds) (cadr bounds) - 'magit-section-heading-selection)) - (if (and bounds (not magit-keep-region-overlay)) - (funcall (default-value 'redisplay-unhighlight-region-function) rol) - (funcall (default-value 'redisplay-highlight-region-function) - start end window rol)))) - -(defun git-rebase-unhighlight-region (rol) - (mapc #'delete-overlay magit-section-highlight-overlays) - (funcall (default-value 'redisplay-unhighlight-region-function) rol)) - -(defun git-rebase-kill-line () - "Kill the current action line. -If the region is active, act on all lines touched by the region." - (interactive) - (git-rebase-set-action nil)) - -(defun git-rebase-insert (rev) - "Read an arbitrary commit and insert it below current line." - (interactive (list (magit-read-branch-or-commit "Insert revision"))) - (forward-line) - (--if-let (magit-rev-format "%h %s" rev) - (let ((inhibit-read-only t)) - (insert "pick " it ?\n)) - (user-error "Unknown revision"))) - -(defun git-rebase-set-noncommit-action (action value-fn arg) - (goto-char (line-beginning-position)) - (pcase-let* ((inhibit-read-only t) - (`(,initial ,trailer ,comment-p) - (and (not arg) - (with-slots ((ln-action action) - target trailer comment-p) - (git-rebase-current-line) - (and (equal ln-action action) - (list target trailer comment-p))))) - (value (funcall value-fn initial))) - (pcase (list value initial comment-p) - (`("" nil ,_) - (ding)) - (`("" ,_ ,_) - (magit-delete-line)) - (_ - (if initial - (magit-delete-line) - (forward-line)) - (insert (concat action " " value - (and (equal value initial) - trailer - (concat " " trailer)) - "\n")) - (unless git-rebase-auto-advance - (forward-line -1)))))) - -(defun git-rebase-exec (arg) - "Insert a shell command to be run after the current commit. - -If there already is such a command on the current line, then edit -that instead. With a prefix argument insert a new command even -when there already is one on the current line. With empty input -remove the command on the current line, if any." - (interactive "P") - (git-rebase-set-noncommit-action - "exec" - (lambda (initial) (read-shell-command "Execute: " initial)) - arg)) - -(defun git-rebase-label (arg) - "Add a label after the current commit. -If there already is a label on the current line, then edit that -instead. With a prefix argument, insert a new label even when -there is already a label on the current line. With empty input, -remove the label on the current line, if any." - (interactive "P") - (git-rebase-set-noncommit-action - "label" - (lambda (initial) - (read-from-minibuffer - "Label: " initial magit-minibuffer-local-ns-map)) - arg)) - -(defun git-rebase-buffer-labels () - (let (labels) - (save-excursion - (goto-char (point-min)) - (while (re-search-forward "^\\(?:l\\|label\\) \\([^ \n]+\\)" nil t) - (push (match-string-no-properties 1) labels))) - (nreverse labels))) - -(defun git-rebase-reset (arg) - "Reset the current HEAD to a label. -If there already is a reset command on the current line, then -edit that instead. With a prefix argument, insert a new reset -line even when point is already on a reset line. With empty -input, remove the reset command on the current line, if any." - (interactive "P") - (git-rebase-set-noncommit-action - "reset" - (lambda (initial) - (or (magit-completing-read "Label" (git-rebase-buffer-labels) - nil t initial) - "")) - arg)) - -(defun git-rebase-merge (arg) - "Add a merge command after the current commit. -If there is already a merge command on the current line, then -replace that command instead. With a prefix argument, insert a -new merge command even when there is already one on the current -line. With empty input, remove the merge command on the current -line, if any." - (interactive "P") - (git-rebase-set-noncommit-action - "merge" - (lambda (_) - (or (magit-completing-read "Merge" (git-rebase-buffer-labels)) - "")) - arg)) - -(defun git-rebase-merge-toggle-editmsg () - "Toggle whether an editor is invoked when performing the merge at point. -When a merge command uses a lower-case -c, the message for the -specified commit will be opened in an editor before creating the -commit. For an upper-case -C, the message will be used as is." - (interactive) - (with-slots (action-type target action-options trailer) - (git-rebase-current-line) - (if (eq action-type 'merge) - (let ((inhibit-read-only t)) - (magit-delete-line) - (insert - (format "merge %s %s %s\n" - (replace-regexp-in-string - "-[cC]" (lambda (c) - (if (equal c "-c") "-C" "-c")) - action-options t t) - target - trailer))) - (ding)))) - -(defun git-rebase-set-bare-action (action arg) - (goto-char (line-beginning-position)) - (with-slots ((ln-action action) comment-p) - (git-rebase-current-line) - (let ((same-action-p (equal action ln-action)) - (inhibit-read-only t)) - (when (or arg - (not ln-action) - (not same-action-p) - (and same-action-p comment-p)) - (unless (or arg (not same-action-p)) - (magit-delete-line)) - (insert action ?\n) - (unless git-rebase-auto-advance - (forward-line -1)))))) - -(defun git-rebase-noop (&optional arg) - "Add noop action at point. - -If the current line already contains a noop action, leave it -unchanged. If there is a commented noop action present, remove -the comment. Otherwise add a new noop action. With a prefix -argument insert a new noop action regardless of what is already -present on the current line. - -A noop action can be used to make git perform a rebase even if -no commits are selected. Without the noop action present, git -would see an empty file and therefore do nothing." - (interactive "P") - (git-rebase-set-bare-action "noop" arg)) - -(defun git-rebase-break (&optional arg) - "Add break action at point. - -If there is a commented break action present, remove the comment. -If the current line already contains a break action, add another -break action only if a prefix argument is given. - -A break action can be used to interrupt the rebase at the -specified point. It is particularly useful for pausing before -the first commit in the sequence. For other cases, the -equivalent behavior can be achieved with `git-rebase-edit'." - (interactive "P") - (git-rebase-set-bare-action "break" arg)) - -(defun git-rebase-undo (&optional arg) - "Undo some previous changes. -Like `undo' but works in read-only buffers." - (interactive "P") - (let ((inhibit-read-only t)) - (undo arg))) - -(defun git-rebase--show-commit (&optional scroll) - (let ((disable-magit-save-buffers t)) - (save-excursion - (goto-char (line-beginning-position)) - (--if-let (with-slots (action-type target) (git-rebase-current-line) - (and (eq action-type 'commit) - target)) - (pcase scroll - (`up (magit-diff-show-or-scroll-up)) - (`down (magit-diff-show-or-scroll-down)) - (_ (apply #'magit-show-commit it - (magit-diff-arguments 'magit-revision-mode)))) - (ding))))) - -(defun git-rebase-show-commit () - "Show the commit on the current line if any." - (interactive) - (git-rebase--show-commit)) - -(defun git-rebase-show-or-scroll-up () - "Update the commit buffer for commit on current line. - -Either show the commit at point in the appropriate buffer, or if -that buffer is already being displayed in the current frame and -contains information about that commit, then instead scroll the -buffer up." - (interactive) - (git-rebase--show-commit 'up)) - -(defun git-rebase-show-or-scroll-down () - "Update the commit buffer for commit on current line. - -Either show the commit at point in the appropriate buffer, or if -that buffer is already being displayed in the current frame and -contains information about that commit, then instead scroll the -buffer down." - (interactive) - (git-rebase--show-commit 'down)) - -(defun git-rebase-backward-line (&optional n) - "Move N lines backward (forward if N is negative). -Like `forward-line' but go into the opposite direction." - (interactive "p") - (forward-line (- (or n 1)))) - -;;; Mode - -;;;###autoload -(define-derived-mode git-rebase-mode special-mode "Git Rebase" - "Major mode for editing of a Git rebase file. - -Rebase files are generated when you run 'git rebase -i' or run -`magit-interactive-rebase'. They describe how Git should perform -the rebase. See the documentation for git-rebase (e.g., by -running 'man git-rebase' at the command line) for details." - :group 'git-rebase - (setq comment-start (or (magit-get "core.commentChar") "#")) - (setq git-rebase-comment-re (concat "^" (regexp-quote comment-start))) - (setq font-lock-defaults (list (git-rebase-mode-font-lock-keywords) t t)) - (unless git-rebase-show-instructions - (let ((inhibit-read-only t)) - (flush-lines git-rebase-comment-re))) - (unless with-editor-mode - ;; Maybe already enabled when using `shell-command' or an Emacs shell. - (with-editor-mode 1)) - (when git-rebase-confirm-cancel - (add-hook 'with-editor-cancel-query-functions - 'git-rebase-cancel-confirm nil t)) - (setq-local redisplay-highlight-region-function 'git-rebase-highlight-region) - (setq-local redisplay-unhighlight-region-function 'git-rebase-unhighlight-region) - (add-hook 'with-editor-pre-cancel-hook 'git-rebase-autostash-save nil t) - (add-hook 'with-editor-post-cancel-hook 'git-rebase-autostash-apply nil t) - (setq imenu-prev-index-position-function - #'magit-imenu--rebase-prev-index-position-function) - (setq imenu-extract-index-name-function - #'magit-imenu--rebase-extract-index-name-function) - (when (boundp 'save-place) - (setq save-place nil))) - -(defun git-rebase-cancel-confirm (force) - (or (not (buffer-modified-p)) - force - (magit-confirm 'abort-rebase "Abort this rebase" nil 'noabort))) - -(defun git-rebase-autostash-save () - (--when-let (magit-file-line (magit-git-dir "rebase-merge/autostash")) - (push (cons 'stash it) with-editor-cancel-alist))) - -(defun git-rebase-autostash-apply () - (--when-let (cdr (assq 'stash with-editor-cancel-alist)) - (magit-stash-apply it))) - -(defun git-rebase-match-comment-line (limit) - (re-search-forward (concat git-rebase-comment-re ".*") limit t)) - -(defun git-rebase-mode-font-lock-keywords () - "Font lock keywords for Git-Rebase mode." - `((,(concat "^" (cdr (assq 'commit git-rebase-line-regexps))) - (1 'font-lock-keyword-face) - (3 'git-rebase-hash) - (4 'git-rebase-description)) - (,(concat "^" (cdr (assq 'exec git-rebase-line-regexps))) - (1 'font-lock-keyword-face) - (3 'git-rebase-description)) - (,(concat "^" (cdr (assq 'bare git-rebase-line-regexps))) - (1 'font-lock-keyword-face)) - (,(concat "^" (cdr (assq 'label git-rebase-line-regexps))) - (1 'font-lock-keyword-face) - (3 'git-rebase-label) - (4 'font-lock-comment-face)) - ("^\\(m\\(?:erge\\)?\\) -[Cc] \\([^ \n]+\\) \\([^ \n]+\\)\\( #.*\\)?" - (1 'font-lock-keyword-face) - (2 'git-rebase-hash) - (3 'git-rebase-label) - (4 'font-lock-comment-face)) - ("^\\(m\\(?:erge\\)?\\) \\([^ \n]+\\)" - (1 'font-lock-keyword-face) - (2 'git-rebase-label)) - (,(concat git-rebase-comment-re " *" - (cdr (assq 'commit git-rebase-line-regexps))) - 0 'git-rebase-killed-action t) - (git-rebase-match-comment-line 0 'font-lock-comment-face) - ("\\[[^[]*\\]" - 0 'magit-keyword t) - ("\\(?:fixup!\\|squash!\\)" - 0 'magit-keyword-squash t) - (,(format "^%s Rebase \\([^ ]*\\) onto \\([^ ]*\\)" comment-start) - (1 'git-rebase-comment-hash t) - (2 'git-rebase-comment-hash t)) - (,(format "^%s \\(Commands:\\)" comment-start) - (1 'git-rebase-comment-heading t)) - (,(format "^%s Branch \\(.*\\)" comment-start) - (1 'git-rebase-label t)))) - -(defun git-rebase-mode-show-keybindings () - "Modify the \"Commands:\" section of the comment Git generates -at the bottom of the file so that in place of the one-letter -abbreviation for the command, it shows the command's keybinding. -By default, this is the same except for the \"pick\" command." - (let ((inhibit-read-only t)) - (save-excursion - (goto-char (point-min)) - (when (and git-rebase-show-instructions - (re-search-forward - (concat git-rebase-comment-re "\\s-+p, pick") - nil t)) - (goto-char (line-beginning-position)) - (pcase-dolist (`(,cmd . ,desc) git-rebase-command-descriptions) - (insert (format "%s %-8s %s\n" - comment-start - (substitute-command-keys (format "\\[%s]" cmd)) - desc))) - (while (re-search-forward (concat git-rebase-comment-re - "\\( ?\\)\\([^\n,],\\) " - "\\([^\n ]+\\) ") - nil t) - (let ((cmd (intern (concat "git-rebase-" (match-string 3))))) - (if (not (fboundp cmd)) - (delete-region (line-beginning-position) (1+ (line-end-position))) - (replace-match " " t t nil 1) - (replace-match - (format "%-8s" - (mapconcat #'key-description - (--remove (eq (elt it 0) 'menu-bar) - (reverse (where-is-internal - cmd git-rebase-mode-map))) - ", ")) - t t nil 2)))))))) - -(add-hook 'git-rebase-mode-hook 'git-rebase-mode-show-keybindings t) - -(defun git-rebase-mode-disable-before-save-hook () - (set (make-local-variable 'before-save-hook) nil)) - -(add-hook 'git-rebase-mode-hook 'git-rebase-mode-disable-before-save-hook) - -;;;###autoload -(defconst git-rebase-filename-regexp "/git-rebase-todo\\'") -;;;###autoload -(add-to-list 'auto-mode-alist - (cons git-rebase-filename-regexp 'git-rebase-mode)) - -(add-to-list 'with-editor-server-window-alist - (cons git-rebase-filename-regexp 'switch-to-buffer)) - -(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) - -;;; _ -(provide 'git-rebase) -;;; git-rebase.el ends here diff --git a/elpa/magit-20210802.1524/magit-apply.el b/elpa/magit-20210802.1524/magit-apply.el deleted file mode 100644 index 1feeddf3..00000000 --- a/elpa/magit-20210802.1524/magit-apply.el +++ /dev/null @@ -1,740 +0,0 @@ -;;; magit-apply.el --- apply Git diffs -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements commands for applying Git diffs or parts -;; of such a diff. The supported "apply variants" are apply, stage, -;; unstage, discard, and reverse - more than Git itself knows about, -;; at least at the porcelain level. - -;;; Code: - -(require 'magit-core) -(require 'magit-diff) -(require 'magit-wip) - -(require 'transient) ; See #3732. - -;; For `magit-apply' -(declare-function magit-am "magit-sequence" ()) -(declare-function magit-patch-apply "magit-files" ()) -;; For `magit-discard-files' -(declare-function magit-checkout-stage "magit-merge" (file arg)) -(declare-function magit-checkout-read-stage "magit-merge" (file)) -(defvar auto-revert-verbose) -;; For `magit-stage-untracked' -(declare-function magit-submodule-add-1 "magit-submodule" - (url &optional path name args)) -(declare-function magit-submodule-read-name-for-path "magit-submodule" - (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 - -(defcustom magit-delete-by-moving-to-trash t - "Whether Magit uses the system's trash can. - -You should absolutely not disable this and also remove `discard' -from `magit-no-confirm'. You shouldn't do that even if you have -all of the Magit-Wip modes enabled, because those modes do not -track any files that are not tracked in the proper branch." - :package-version '(magit . "2.1.0") - :group 'magit-essentials - :type 'boolean) - -(defcustom magit-unstage-committed t - "Whether unstaging a committed change reverts it instead. - -A committed change cannot be unstaged, because staging and -unstaging are actions that are concerned with the differences -between the index and the working tree, not with committed -changes. - -If this option is non-nil (the default), then typing \"u\" -\(`magit-unstage') on a committed change, causes it to be -reversed in the index but not the working tree. For more -information see command `magit-reverse-in-index'." - :package-version '(magit . "2.4.1") - :group 'magit-commands - :type 'boolean) - -(defcustom magit-reverse-atomically nil - "Whether to reverse changes atomically. - -If some changes can be reversed while others cannot, then nothing -is reversed if the value of this option is non-nil. But when it -is nil, then the changes that can be reversed are reversed and -for the other changes diff files are created that contain the -rejected reversals." - :package-version '(magit . "2.7.0") - :group 'magit-commands - :type 'boolean) - -(defcustom magit-post-stage-hook nil - "Hook run after staging changes. -This hook is run by `magit-refresh' if `this-command' -is a member of `magit-post-stage-hook-commands'." - :package-version '(magit . "2.90.0") - :group 'magit-commands - :type 'hook) - -(defvar magit-post-stage-hook-commands - '(magit-stage magit-stage-file magit-stage-modified)) - -(defcustom magit-post-unstage-hook nil - "Hook run after unstaging changes. -This hook is run by `magit-refresh' if `this-command' -is a member of `magit-post-unstage-hook-commands'." - :package-version '(magit . "2.90.0") - :group 'magit-commands - :type 'hook) - -(defvar magit-post-unstage-hook-commands - '(magit-unstage magit-unstage-file magit-unstage-all)) - -;;; Commands -;;;; Apply - -(defun magit-apply (&rest args) - "Apply the change at point to the working tree. -With a prefix argument fallback to a 3-way merge. Doing -so causes the change to be applied to the index as well." - (interactive (and current-prefix-arg (list "--3way"))) - (--when-let (magit-apply--get-selection) - (pcase (list (magit-diff-type) (magit-diff-scope)) - (`(,(or `unstaged `staged) ,_) - (user-error "Change is already in the working tree")) - (`(untracked ,(or `file `files)) - (call-interactively 'magit-am)) - (`(,_ region) (magit-apply-region it args)) - (`(,_ hunk) (magit-apply-hunk it args)) - (`(,_ hunks) (magit-apply-hunks it args)) - (`(rebase-sequence file) - (call-interactively 'magit-patch-apply)) - (`(,_ file) (magit-apply-diff it args)) - (`(,_ files) (magit-apply-diffs it args))))) - -(defun magit-apply--section-content (section) - (buffer-substring-no-properties (if (magit-hunk-section-p section) - (oref section start) - (oref section content)) - (oref section end))) - -(defun magit-apply-diffs (sections &rest args) - (setq sections (magit-apply--get-diffs sections)) - (magit-apply-patch sections args - (mapconcat - (lambda (s) - (concat (magit-diff-file-header s) - (magit-apply--section-content s))) - sections ""))) - -(defun magit-apply-diff (section &rest args) - (setq section (car (magit-apply--get-diffs (list section)))) - (magit-apply-patch section args - (concat (magit-diff-file-header section) - (magit-apply--section-content section)))) - -(defun magit-apply--adjust-hunk-new-starts (hunks) - "Adjust new line numbers in headers of HUNKS for partial application. -HUNKS should be a list of ordered, contiguous hunks to be applied -from a file. For example, if there is a sequence of hunks with -the headers - - @@ -2,6 +2,7 @@ - @@ -10,6 +11,7 @@ - @@ -18,6 +20,7 @@ - -and only the second and third are to be applied, they would be -adjusted as \"@@ -10,6 +10,7 @@\" and \"@@ -18,6 +19,7 @@\"." - (let* ((first-hunk (car hunks)) - (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 "Header hunks have to be applied individually")))) - (if (= offset 0) - hunks - (mapcar (lambda (hunk) - (if (string-match diff-hunk-header-re-unified hunk) - (replace-match (number-to-string - (- (string-to-number (match-string 3 hunk)) - offset)) - t t hunk 3) - (error "Hunk does not have expected header"))) - hunks)))) - -(defun magit-apply--adjust-hunk-new-start (hunk) - (car (magit-apply--adjust-hunk-new-starts (list hunk)))) - -(defun magit-apply-hunks (sections &rest args) - (let ((section (oref (car sections) parent))) - (when (string-match "^diff --cc" (oref section value)) - (user-error "Cannot un-/stage resolution hunks. Stage the whole file")) - (magit-apply-patch - section args - (concat (oref section header) - (mapconcat #'identity - (magit-apply--adjust-hunk-new-starts - (mapcar #'magit-apply--section-content sections)) - ""))))) - -(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")) - (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)) - (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-diff-hunk-region-patch section args))))) - -(defun magit-apply-patch (section:s args patch) - (let* ((files (if (atom section:s) - (list (oref section:s value)) - (--map (oref it value) section:s))) - (command (symbol-name this-command)) - (command (if (and command (string-match "^magit-\\([^-]+\\)" command)) - (match-string 1 command) - "apply")) - (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 magit-inhibit-refresh)) - (magit-wip-commit-before-change files (concat " before " command))) - (with-temp-buffer - (insert patch) - (magit-run-git-with-input - "apply" args "-p0" - (and ignore-context "-C0") - "--ignore-space-change" "-")) - (unless magit-inhibit-refresh - (when magit-wip-after-apply-mode - (magit-wip-commit-after-apply files (concat " after " command))) - (magit-refresh)))) - -(defun magit-apply--get-selection () - (or (magit-region-sections '(hunk file module) t) - (let ((section (magit-current-section))) - (pcase (oref section type) - ((or `hunk `file `module) section) - ((or `staged `unstaged `untracked - `stashed-index `stashed-worktree `stashed-untracked) - (oref section children)) - (_ (user-error "Cannot apply this, it's not a change")))))) - -(defun magit-apply--get-diffs (sections) - (magit-section-case - ([file diffstat] - (--map (or (magit-get-section - (append `((file . ,(oref it value))) - (magit-section-ident magit-root-section))) - (error "Cannot get required diff headers")) - sections)) - (t sections))) - -(defun magit-apply--diff-ignores-whitespace-p () - (and (cl-intersection magit-buffer-diff-args - '("--ignore-space-at-eol" - "--ignore-space-change" - "--ignore-all-space" - "--ignore-blank-lines") - :test #'equal) - t)) - -;;;; Stage - -(defun magit-stage (&optional intent) - "Add the change at point to the staging area. -With a prefix argument, INTENT, and an untracked file (or files) -at point, stage the file but not its content." - (interactive "P") - (--if-let (and (derived-mode-p 'magit-mode) (magit-apply--get-selection)) - (pcase (list (magit-diff-type) - (magit-diff-scope) - (magit-apply--diff-ignores-whitespace-p)) - (`(untracked ,_ ,_) (magit-stage-untracked intent)) - (`(unstaged region ,_) (magit-apply-region it "--cached")) - (`(unstaged hunk ,_) (magit-apply-hunk it "--cached")) - (`(unstaged hunks ,_) (magit-apply-hunks it "--cached")) - (`(unstaged file t) (magit-apply-diff it "--cached")) - (`(unstaged files t) (magit-apply-diffs it "--cached")) - (`(unstaged list t) (magit-apply-diffs it "--cached")) - (`(unstaged file nil) (magit-stage-1 "-u" (list (oref it value)))) - (`(unstaged files nil) (magit-stage-1 "-u" (magit-region-values nil t))) - (`(unstaged list nil) (magit-stage-modified)) - (`(staged ,_ ,_) (user-error "Already staged")) - (`(committed ,_ ,_) (user-error "Cannot stage committed changes")) - (`(undefined ,_ ,_) (user-error "Cannot stage this change"))) - (call-interactively 'magit-stage-file))) - -;;;###autoload -(defun magit-stage-file (file) - "Stage all changes to FILE. -With a prefix argument or when there is no file at point ask for -the file to be staged. Otherwise stage the file at point without -requiring confirmation." - (interactive - (let* ((atpoint (magit-section-value-if 'file)) - (current (magit-file-relative-name)) - (choices (nconc (magit-unstaged-files) - (magit-untracked-files))) - (default (car (member (or atpoint current) choices)))) - (list (if (or current-prefix-arg (not default)) - (magit-completing-read "Stage file" choices - nil t nil nil default) - default)))) - (magit-with-toplevel - (magit-stage-1 nil (list file)))) - -;;;###autoload -(defun magit-stage-modified (&optional all) - "Stage all changes to files modified in the worktree. -Stage all new content of tracked files and remove tracked files -that no longer exist in the working tree from the index also. -With a prefix argument also stage previously untracked (but not -ignored) files." - (interactive "P") - (when (magit-anything-staged-p) - (magit-confirm 'stage-all-changes)) - (magit-with-toplevel - (magit-stage-1 (if all "--all" "-u") magit-buffer-diff-files))) - -(defun magit-stage-1 (arg &optional files) - (magit-wip-commit-before-change files " before stage") - (magit-run-git "add" arg (if files (cons "--" files) ".")) - (when magit-auto-revert-mode - (mapc #'magit-turn-on-auto-revert-mode-if-desired files)) - (magit-wip-commit-after-apply files " after stage")) - -(defun magit-stage-untracked (&optional intent) - (let* ((section (magit-current-section)) - (files (pcase (magit-diff-scope) - (`file (list (oref section value))) - (`files (magit-region-values nil t)) - (`list (magit-untracked-files)))) - plain repos) - (dolist (file files) - (if (and (not (file-symlink-p file)) - (magit-git-repo-p file t)) - (push file repos) - (push file plain))) - (magit-wip-commit-before-change files " before stage") - (when plain - (magit-run-git "add" (and intent "--intent-to-add") - "--" plain) - (when magit-auto-revert-mode - (mapc #'magit-turn-on-auto-revert-mode-if-desired plain))) - (dolist (repo repos) - (save-excursion - (goto-char (oref (magit-get-section - `((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))))) - (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 - -(defun magit-unstage () - "Remove the change at point from the staging area." - (interactive) - (--when-let (magit-apply--get-selection) - (pcase (list (magit-diff-type) - (magit-diff-scope) - (magit-apply--diff-ignores-whitespace-p)) - (`(untracked ,_ ,_) (user-error "Cannot unstage untracked changes")) - (`(unstaged file ,_) (magit-unstage-intent (list (oref it value)))) - (`(unstaged files ,_) (magit-unstage-intent (magit-region-values nil t))) - (`(unstaged ,_ ,_) (user-error "Already unstaged")) - (`(staged region ,_) (magit-apply-region it "--reverse" "--cached")) - (`(staged hunk ,_) (magit-apply-hunk it "--reverse" "--cached")) - (`(staged hunks ,_) (magit-apply-hunks it "--reverse" "--cached")) - (`(staged file t) (magit-apply-diff it "--reverse" "--cached")) - (`(staged files t) (magit-apply-diffs it "--reverse" "--cached")) - (`(staged list t) (magit-apply-diffs it "--reverse" "--cached")) - (`(staged file nil) (magit-unstage-1 (list (oref it value)))) - (`(staged files nil) (magit-unstage-1 (magit-region-values nil t))) - (`(staged list nil) (magit-unstage-all)) - (`(committed ,_ ,_) (if magit-unstage-committed - (magit-reverse-in-index) - (user-error "Cannot unstage committed changes"))) - (`(undefined ,_ ,_) (user-error "Cannot unstage this change"))))) - -;;;###autoload -(defun magit-unstage-file (file) - "Unstage all changes to FILE. -With a prefix argument or when there is no file at point ask for -the file to be unstaged. Otherwise unstage the file at point -without requiring confirmation." - (interactive - (let* ((atpoint (magit-section-value-if 'file)) - (current (magit-file-relative-name)) - (choices (magit-staged-files)) - (default (car (member (or atpoint current) choices)))) - (list (if (or current-prefix-arg (not default)) - (magit-completing-read "Unstage file" choices - nil t nil nil default) - default)))) - (magit-with-toplevel - (magit-unstage-1 (list file)))) - -(defun magit-unstage-1 (files) - (magit-wip-commit-before-change files " before unstage") - (if (magit-no-commit-p) - (magit-run-git "rm" "--cached" "--" files) - (magit-run-git "reset" "HEAD" "--" files)) - (magit-wip-commit-after-apply files " after unstage")) - -(defun magit-unstage-intent (files) - (if-let ((staged (magit-staged-files)) - (intent (--filter (member it staged) files))) - (magit-unstage-1 intent) - (user-error "Already unstaged"))) - -;;;###autoload -(defun magit-unstage-all () - "Remove all changes from the staging area." - (interactive) - (when (or (magit-anything-unstaged-p) - (magit-untracked-files)) - (magit-confirm 'unstage-all-changes)) - (magit-wip-commit-before-change nil " before unstage") - (magit-run-git "reset" "HEAD" "--" magit-buffer-diff-files) - (magit-wip-commit-after-apply nil " after unstage")) - -;;;; Discard - -(defun magit-discard () - "Remove the change at point." - (interactive) - (--when-let (magit-apply--get-selection) - (pcase (list (magit-diff-type) (magit-diff-scope)) - (`(committed ,_) (user-error "Cannot discard committed changes")) - (`(undefined ,_) (user-error "Cannot discard this change")) - (`(,_ region) (magit-discard-region it)) - (`(,_ hunk) (magit-discard-hunk it)) - (`(,_ hunks) (magit-discard-hunks it)) - (`(,_ file) (magit-discard-file it)) - (`(,_ files) (magit-discard-files it)) - (`(,_ list) (magit-discard-files it))))) - -(defun magit-discard-region (section) - (magit-confirm 'discard "Discard region") - (magit-discard-apply section 'magit-apply-region)) - -(defun magit-discard-hunk (section) - (magit-confirm 'discard "Discard hunk") - (magit-discard-apply section 'magit-apply-hunk)) - -(defun magit-discard-apply (section apply) - (if (eq (magit-diff-type section) 'unstaged) - (funcall apply section "--reverse") - (if (magit-anything-unstaged-p - nil (if (magit-file-section-p section) - (oref section value) - (magit-section-parent-value section))) - (progn (let ((magit-inhibit-refresh t)) - (funcall apply section "--reverse" "--cached") - (funcall apply section "--reverse" "--reject")) - (magit-refresh)) - (funcall apply section "--reverse" "--index")))) - -(defun magit-discard-hunks (sections) - (magit-confirm 'discard (format "Discard %s hunks from %s" - (length sections) - (magit-section-parent-value (car sections)))) - (magit-discard-apply-n sections 'magit-apply-hunks)) - -(defun magit-discard-apply-n (sections apply) - (let ((section (car sections))) - (if (eq (magit-diff-type section) 'unstaged) - (funcall apply sections "--reverse") - (if (magit-anything-unstaged-p - nil (if (magit-file-section-p section) - (oref section value) - (magit-section-parent-value section))) - (progn (let ((magit-inhibit-refresh t)) - (funcall apply sections "--reverse" "--cached") - (funcall apply sections "--reverse" "--reject")) - (magit-refresh)) - (funcall apply sections "--reverse" "--index"))))) - -(defun magit-discard-file (section) - (magit-discard-files (list section))) - -(defun magit-discard-files (sections) - (let ((auto-revert-verbose nil) - (type (magit-diff-type (car sections))) - (status (magit-file-status)) - files delete resurrect rename discard discard-new resolve) - (dolist (section sections) - (let ((file (oref section value))) - (push file files) - (pcase (cons (pcase type - (`staged ?X) - (`unstaged ?Y) - (`untracked ?Z)) - (cddr (assoc file status))) - (`(?Z) (dolist (f (magit-untracked-files nil file)) - (push f delete))) - ((or `(?Z ?? ??) `(?Z ?! ?!)) (push file delete)) - ((or `(?Z ?D ? ) `(,_ ?D ?D)) (push file delete)) - ((or `(,_ ?U ,_) `(,_ ,_ ?U)) (push file resolve)) - (`(,_ ?A ?A) (push file resolve)) - (`(?X ?M ,(or ? ?M ?D)) (push section discard)) - (`(?Y ,_ ?M ) (push section discard)) - (`(?X ?A ?M ) (push file discard-new)) - (`(?X ?C ?M ) (push file discard-new)) - (`(?X ?A ,(or ? ?D)) (push file delete)) - (`(?X ?C ,(or ? ?D)) (push file delete)) - (`(?X ?D ,(or ? ?M )) (push file resurrect)) - (`(?Y ,_ ?D ) (push file resurrect)) - (`(?X ?R ,(or ? ?M ?D)) (push file rename))))) - (unwind-protect - (let ((magit-inhibit-refresh t)) - (magit-wip-commit-before-change files " before discard") - (when resolve - (magit-discard-files--resolve (nreverse resolve))) - (when resurrect - (magit-discard-files--resurrect (nreverse resurrect))) - (when delete - (magit-discard-files--delete (nreverse delete) status)) - (when rename - (magit-discard-files--rename (nreverse rename) status)) - (when (or discard discard-new) - (magit-discard-files--discard (nreverse discard) - (nreverse discard-new))) - (magit-wip-commit-after-apply files " after discard")) - (magit-refresh)))) - -(defun magit-discard-files--resolve (files) - (if-let ((arg (and (cdr files) - (magit-read-char-case - (format "For these %i files\n%s\ncheckout:\n" - (length files) - (mapconcat (lambda (file) - (concat " " file)) - files "\n")) - t - (?o "[o]ur stage" "--ours") - (?t "[t]heir stage" "--theirs") - (?c "[c]onflict" "--merge") - (?i "decide [i]ndividually" nil))))) - (dolist (file files) - (magit-checkout-stage file arg)) - (dolist (file files) - (magit-checkout-stage file (magit-checkout-read-stage file))))) - -(defun magit-discard-files--resurrect (files) - (magit-confirm-files 'resurrect files) - (if (eq (magit-diff-type) 'staged) - (magit-call-git "reset" "--" files) - (magit-call-git "checkout" "--" files))) - -(defun magit-discard-files--delete (files status) - (magit-confirm-files (if magit-delete-by-moving-to-trash 'trash 'delete) - files) - (let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash)) - (dolist (file files) - (when (string-match-p "\\`\\\\?~" file) - (error "Refusing to delete %S, too dangerous" file)) - (pcase (nth 3 (assoc file status)) - ((guard (memq (magit-diff-type) '(unstaged untracked))) - (dired-delete-file file dired-recursive-deletes - magit-delete-by-moving-to-trash) - (dired-clean-up-after-deletion file)) - (?\s (delete-file file t) - (magit-call-git "rm" "--cached" "--" file)) - (?M (let ((temp (magit-git-string "checkout-index" "--temp" file))) - (string-match - (format "\\(.+?\\)\t%s" (regexp-quote file)) temp) - (rename-file (match-string 1 temp) - (setq temp (concat file ".~{index}~"))) - (delete-file temp t)) - (magit-call-git "rm" "--cached" "--force" "--" file)) - (?D (magit-call-git "checkout" "--" file) - (delete-file file t) - (magit-call-git "rm" "--cached" "--force" "--" file)))))) - -(defun magit-discard-files--rename (files status) - (magit-confirm 'rename "Undo rename %s" "Undo %i renames" nil - (mapcar (lambda (file) - (setq file (assoc file status)) - (format "%s -> %s" (cadr file) (car file))) - files)) - (dolist (file files) - (let ((orig (cadr (assoc file status)))) - (if (file-exists-p file) - (progn - (--when-let (file-name-directory orig) - (make-directory it t)) - (magit-call-git "mv" file orig)) - (magit-call-git "rm" "--cached" "--" file) - (magit-call-git "reset" "--" orig))))) - -(defun magit-discard-files--discard (sections new-files) - (let ((files (--map (oref it value) sections))) - (magit-confirm-files 'discard (append files new-files) - (format "Discard %s changes in" (magit-diff-type))) - (if (eq (magit-diff-type (car sections)) 'unstaged) - (magit-call-git "checkout" "--" files) - (when new-files - (magit-call-git "add" "--" new-files) - (magit-call-git "reset" "--" new-files)) - (let ((binaries (magit-binary-files "--cached"))) - (when binaries - (setq sections - (--remove (member (oref it value) binaries) - sections))) - (cond ((= (length sections) 1) - (magit-discard-apply (car sections) 'magit-apply-diff)) - (sections - (magit-discard-apply-n sections 'magit-apply-diffs))) - (when binaries - (let ((modified (magit-unstaged-files t))) - (setq binaries (--separate (member it modified) binaries))) - (when (cadr binaries) - (magit-call-git "reset" "--" (cadr binaries))) - (when (car binaries) - (user-error - (concat - "Cannot discard staged changes to binary files, " - "which also have unstaged changes. Unstage instead.")))))))) - -;;;; Reverse - -(defun magit-reverse (&rest args) - "Reverse the change at point in the working tree. -With a prefix argument fallback to a 3-way merge. Doing -so causes the change to be applied to the index as well." - (interactive (and current-prefix-arg (list "--3way"))) - (--when-let (magit-apply--get-selection) - (pcase (list (magit-diff-type) (magit-diff-scope)) - (`(untracked ,_) (user-error "Cannot reverse untracked changes")) - (`(unstaged ,_) (user-error "Cannot reverse unstaged changes")) - (`(,_ region) (magit-reverse-region it args)) - (`(,_ hunk) (magit-reverse-hunk it args)) - (`(,_ hunks) (magit-reverse-hunks it args)) - (`(,_ file) (magit-reverse-file it args)) - (`(,_ files) (magit-reverse-files it args)) - (`(,_ list) (magit-reverse-files it args))))) - -(defun magit-reverse-region (section args) - (magit-confirm 'reverse "Reverse region") - (magit-reverse-apply section 'magit-apply-region args)) - -(defun magit-reverse-hunk (section args) - (magit-confirm 'reverse "Reverse hunk") - (magit-reverse-apply section 'magit-apply-hunk args)) - -(defun magit-reverse-hunks (sections args) - (magit-confirm 'reverse - (format "Reverse %s hunks from %s" - (length sections) - (magit-section-parent-value (car sections)))) - (magit-reverse-apply sections 'magit-apply-hunks args)) - -(defun magit-reverse-file (section args) - (magit-reverse-files (list section) args)) - -(defun magit-reverse-files (sections args) - (pcase-let ((`(,binaries ,sections) - (let ((bs (magit-binary-files - (cond ((derived-mode-p 'magit-revision-mode) - magit-buffer-range) - ((derived-mode-p 'magit-diff-mode) - magit-buffer-range) - (t - "--cached"))))) - (--separate (member (oref it value) bs) - sections)))) - (magit-confirm-files 'reverse (--map (oref it value) sections)) - (cond ((= (length sections) 1) - (magit-reverse-apply (car sections) 'magit-apply-diff args)) - (sections - (magit-reverse-apply sections 'magit-apply-diffs args))) - (when binaries - (user-error "Cannot reverse binary files")))) - -(defun magit-reverse-apply (section:s apply args) - (funcall apply section:s "--reverse" args - (and (not magit-reverse-atomically) - (not (member "--3way" args)) - "--reject"))) - -(defun magit-reverse-in-index (&rest args) - "Reverse the change at point in the index but not the working tree. - -Use this command to extract a change from `HEAD', while leaving -it in the working tree, so that it can later be committed using -a separate commit. A typical workflow would be: - -0. Optionally make sure that there are no uncommitted changes. -1. Visit the `HEAD' commit and navigate to the change that should - not have been included in that commit. -2. Type \"u\" (`magit-unstage') to reverse it in the index. - This assumes that `magit-unstage-committed-changes' is non-nil. -3. Type \"c e\" to extend `HEAD' with the staged changes, - including those that were already staged before. -4. Optionally stage the remaining changes using \"s\" or \"S\" - and then type \"c c\" to create a new commit." - (interactive) - (magit-reverse (cons "--cached" args))) - -;;; _ -(provide 'magit-apply) -;;; magit-apply.el ends here diff --git a/elpa/magit-20210802.1524/magit-autoloads.el b/elpa/magit-20210802.1524/magit-autoloads.el deleted file mode 100644 index e17bf129..00000000 --- a/elpa/magit-20210802.1524/magit-autoloads.el +++ /dev/null @@ -1,2502 +0,0 @@ -;;; magit-autoloads.el --- automatically extracted autoloads -;; -;;; Code: - -(add-to-list 'load-path (directory-file-name - (or (file-name-directory #$) (car load-path)))) - - -;;;### (autoloads nil "git-rebase" "git-rebase.el" (0 0 0 0)) -;;; Generated autoloads from git-rebase.el - -(autoload 'git-rebase-current-line "git-rebase" "\ -Parse current line into a `git-rebase-action' instance. -If the current line isn't recognized as a rebase line, an -instance with all nil values is returned." nil nil) - -(autoload 'git-rebase-mode "git-rebase" "\ -Major mode for editing of a Git rebase file. - -Rebase files are generated when you run 'git rebase -i' or run -`magit-interactive-rebase'. They describe how Git should perform -the rebase. See the documentation for git-rebase (e.g., by -running 'man git-rebase' at the command line) for details. - -\(fn)" t nil) - -(defconst git-rebase-filename-regexp "/git-rebase-todo\\'") - -(add-to-list 'auto-mode-alist (cons git-rebase-filename-regexp 'git-rebase-mode)) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "git-rebase" '("git-rebase-"))) - -;;;*** - -;;;### (autoloads nil "magit" "magit.el" (0 0 0 0)) -;;; Generated autoloads from magit.el - -(define-obsolete-variable-alias 'global-magit-file-mode 'magit-define-global-key-bindings "Magit 3.0.0") - -(defvar 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'.") - -(custom-autoload 'magit-define-global-key-bindings "magit" t) - -(defun magit-maybe-define-global-key-bindings nil (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)) - (autoload 'magit-dispatch "magit" nil t) - (autoload 'magit-run "magit" nil t) - -(autoload 'magit-git-command "magit" "\ -Execute COMMAND asynchronously; display output. - -Interactively, prompt for COMMAND in the minibuffer. \"git \" is -used as initial input, but can be deleted to run another command. - -With a prefix argument COMMAND is run in the top-level directory -of the current working tree, otherwise in `default-directory'. - -\(fn COMMAND)" t nil) - -(autoload 'magit-git-command-topdir "magit" "\ -Execute COMMAND asynchronously; display output. - -Interactively, prompt for COMMAND in the minibuffer. \"git \" is -used as initial input, but can be deleted to run another command. - -COMMAND is run in the top-level directory of the current -working tree. - -\(fn COMMAND)" t nil) - -(autoload 'magit-shell-command "magit" "\ -Execute COMMAND asynchronously; display output. - -Interactively, prompt for COMMAND in the minibuffer. With a -prefix argument COMMAND is run in the top-level directory of -the current working tree, otherwise in `default-directory'. - -\(fn COMMAND)" t nil) - -(autoload 'magit-shell-command-topdir "magit" "\ -Execute COMMAND asynchronously; display output. - -Interactively, prompt for COMMAND in the minibuffer. COMMAND -is run in the top-level directory of the current working tree. - -\(fn COMMAND)" t nil) - -(autoload 'magit-version "magit" "\ -Return the version of Magit currently in use. -If optional argument PRINT-DEST is non-nil, output -stream (interactively, the echo area, or the current buffer with -a prefix argument), also print the used versions of Magit, Git, -and Emacs to it. - -\(fn &optional PRINT-DEST)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-apply" "magit-apply.el" (0 0 0 0)) -;;; Generated autoloads from magit-apply.el - -(autoload 'magit-stage-file "magit-apply" "\ -Stage all changes to FILE. -With a prefix argument or when there is no file at point ask for -the file to be staged. Otherwise stage the file at point without -requiring confirmation. - -\(fn FILE)" t nil) - -(autoload 'magit-stage-modified "magit-apply" "\ -Stage all changes to files modified in the worktree. -Stage all new content of tracked files and remove tracked files -that no longer exist in the working tree from the index also. -With a prefix argument also stage previously untracked (but not -ignored) files. - -\(fn &optional ALL)" t nil) - -(autoload 'magit-unstage-file "magit-apply" "\ -Unstage all changes to FILE. -With a prefix argument or when there is no file at point ask for -the file to be unstaged. Otherwise unstage the file at point -without requiring confirmation. - -\(fn FILE)" t nil) - -(autoload 'magit-unstage-all "magit-apply" "\ -Remove all changes from the staging area." t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-apply" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-autorevert" "magit-autorevert.el" (0 -;;;;;; 0 0 0)) -;;; Generated autoloads from magit-autorevert.el - -(put 'magit-auto-revert-mode 'globalized-minor-mode t) - -(defvar magit-auto-revert-mode (not (or global-auto-revert-mode noninteractive)) "\ -Non-nil if Magit-Auto-Revert mode is enabled. -See the `magit-auto-revert-mode' command -for a description of this minor mode. -Setting this variable directly does not take effect; -either customize it (see the info node `Easy Customization') -or call the function `magit-auto-revert-mode'.") - -(custom-autoload 'magit-auto-revert-mode "magit-autorevert" nil) - -(autoload 'magit-auto-revert-mode "magit-autorevert" "\ -Toggle Auto-Revert mode in all buffers. -With prefix ARG, enable Magit-Auto-Revert mode if ARG is positive; -otherwise, disable it. If called from Lisp, enable the mode if -ARG is omitted or nil. - -Auto-Revert mode is enabled in all buffers where -`magit-turn-on-auto-revert-mode-if-desired' would do it. -See `auto-revert-mode' for more information on Auto-Revert mode. - -\(fn &optional ARG)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-autorevert" '("auto-revert-buffer" "magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-bisect" "magit-bisect.el" (0 0 0 0)) -;;; Generated autoloads from magit-bisect.el - (autoload 'magit-bisect "magit-bisect" nil t) - -(autoload 'magit-bisect-start "magit-bisect" "\ -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 known -good and a known bad commit. To move the session forward use the -other actions from the bisect transient command (\\\\[magit-bisect]). - -\(fn BAD GOOD ARGS)" t nil) - -(autoload 'magit-bisect-reset "magit-bisect" "\ -After bisecting, cleanup bisection state and return to original `HEAD'." t nil) - -(autoload 'magit-bisect-good "magit-bisect" "\ -While bisecting, mark the current commit as good. -Use this after you have asserted that the commit does not contain -the bug in question." t nil) - -(autoload 'magit-bisect-bad "magit-bisect" "\ -While bisecting, mark the current commit as bad. -Use this after you have asserted that the commit does contain the -bug in question." t nil) - -(autoload 'magit-bisect-mark "magit-bisect" "\ -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." t nil) - -(autoload 'magit-bisect-skip "magit-bisect" "\ -While bisecting, skip the current commit. -Use this if for some reason the current commit is not a good one -to test. This command lets Git choose a different one." t nil) - -(autoload 'magit-bisect-run "magit-bisect" "\ -Bisect automatically by running commands after each step. - -Unlike `git bisect run' this can be used before bisecting has -begun. In that case it behaves like `git bisect start; git -bisect run'. - -\(fn CMDLINE &optional BAD GOOD ARGS)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-bisect" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-blame" "magit-blame.el" (0 0 0 0)) -;;; Generated autoloads from magit-blame.el - (autoload 'magit-blame-echo "magit-blame" nil t) - (autoload 'magit-blame-addition "magit-blame" nil t) - (autoload 'magit-blame-removal "magit-blame" nil t) - (autoload 'magit-blame-reverse "magit-blame" nil t) - (autoload 'magit-blame "magit-blame" nil t) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-blame" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-bookmark" "magit-bookmark.el" (0 0 0 -;;;;;; 0)) -;;; Generated autoloads from magit-bookmark.el - -(autoload 'magit--handle-bookmark "magit-bookmark" "\ -Open a bookmark created by `magit--make-bookmark'. -Call the `magit-*-setup-buffer' function of the the major-mode -with the variables' values as arguments, which were recorded by -`magit--make-bookmark'. Ignore `magit-display-buffer-function'. - -\(fn BOOKMARK)" nil nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-bookmark" '("magit--make-bookmark"))) - -;;;*** - -;;;### (autoloads nil "magit-branch" "magit-branch.el" (0 0 0 0)) -;;; Generated autoloads from magit-branch.el - (autoload 'magit-branch "magit" nil t) - -(autoload 'magit-checkout "magit-branch" "\ -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. - -\(git checkout REVISION). - -\(fn REVISION &optional ARGS)" t nil) - -(autoload 'magit-branch-create "magit-branch" "\ -Create BRANCH at branch or revision START-POINT. - -\(fn BRANCH START-POINT)" t nil) - -(autoload 'magit-branch-and-checkout "magit-branch" "\ -Create and checkout BRANCH at branch or revision START-POINT. - -\(fn BRANCH START-POINT &optional ARGS)" t nil) - -(autoload 'magit-branch-or-checkout "magit-branch" "\ -Hybrid between `magit-checkout' and `magit-branch-and-checkout'. - -Ask the user for an existing branch or revision. If the user -input actually can be resolved as a branch or revision, then -check that out, just like `magit-checkout' would. - -Otherwise create and checkout a new branch using the input as -its name. Before doing so read the starting-point for the new -branch. This is similar to what `magit-branch-and-checkout' -does. - -\(fn ARG &optional START-POINT)" t nil) - -(autoload 'magit-branch-checkout "magit-branch" "\ -Checkout an existing or new local branch. - -Read a branch name from the user offering all local branches and -a subset of remote branches as candidates. Omit remote branches -for which a local branch by the same name exists from the list -of candidates. The user can also enter a completely new branch -name. - -- If the user selects an existing local branch, then check that - out. - -- If the user selects a remote branch, then create and checkout - a new local branch with the same name. Configure the selected - remote branch as push target. - -- If the user enters a new branch name, then create and check - that out, after also reading the starting-point from the user. - -In the latter two cases the upstream is also set. Whether it is -set to the chosen START-POINT or something else depends on the -value of `magit-branch-adjust-remote-upstream-alist', just like -when using `magit-branch-and-checkout'. - -\(fn BRANCH &optional START-POINT)" t nil) - -(autoload 'magit-branch-orphan "magit-branch" "\ -Create and checkout an orphan BRANCH with contents from revision START-POINT. - -\(fn BRANCH START-POINT)" t nil) - -(autoload 'magit-branch-spinout "magit-branch" "\ -Create new branch from the unpushed commits. -Like `magit-branch-spinoff' but remain on the current branch. -If there are any uncommitted changes, then behave exactly like -`magit-branch-spinoff'. - -\(fn BRANCH &optional FROM)" t nil) - -(autoload 'magit-branch-spinoff "magit-branch" "\ -Create new branch from the unpushed commits. - -Create and checkout a new branch starting at and tracking the -current branch. That branch in turn is reset to the last commit -it shares with its upstream. If the current branch has no -upstream or no unpushed commits, then the new branch is created -anyway and the previously current branch is not touched. - -This is useful to create a feature branch after work has already -began on the old branch (likely but not necessarily \"master\"). - -If the current branch is a member of the value of option -`magit-branch-prefer-remote-upstream' (which see), then the -current branch will be used as the starting point as usual, but -the upstream of the starting-point may be used as the upstream -of the new branch, instead of the starting-point itself. - -If optional FROM is non-nil, then the source branch is reset -to `FROM~', instead of to the last commit it shares with its -upstream. Interactively, FROM is only ever non-nil, if the -region selects some commits, and among those commits, FROM is -the commit that is the fewest commits ahead of the source -branch. - -The commit at the other end of the selection actually does not -matter, all commits between FROM and `HEAD' are moved to the new -branch. If FROM is not reachable from `HEAD' or is reachable -from the source branch's upstream, then an error is raised. - -\(fn BRANCH &optional FROM)" t nil) - -(autoload 'magit-branch-reset "magit-branch" "\ -Reset a branch to the tip of another branch or any other commit. - -When the branch being reset is the current branch, then do a -hard reset. If there are any uncommitted changes, then the user -has to confirm the reset because those changes would be lost. - -This is useful when you have started work on a feature branch but -realize it's all crap and want to start over. - -When resetting to another branch and a prefix argument is used, -then also set the target branch as the upstream of the branch -that is being reset. - -\(fn BRANCH TO &optional SET-UPSTREAM)" t nil) - -(autoload 'magit-branch-delete "magit-branch" "\ -Delete one or multiple branches. -If the region marks multiple branches, then offer to delete -those, otherwise prompt for a single branch to be deleted, -defaulting to the branch at point. - -\(fn BRANCHES &optional FORCE)" t nil) - -(autoload 'magit-branch-rename "magit-branch" "\ -Rename the branch named OLD to NEW. - -With a prefix argument FORCE, rename even if a branch named NEW -already exists. - -If `branch.OLD.pushRemote' is set, then unset it. Depending on -the value of `magit-branch-rename-push-target' (which see) maybe -set `branch.NEW.pushRemote' and maybe rename the push-target on -the remote. - -\(fn OLD NEW &optional FORCE)" t nil) - -(autoload 'magit-branch-shelve "magit-branch" "\ -Shelve a BRANCH. -Rename \"refs/heads/BRANCH\" to \"refs/shelved/BRANCH\", -and also rename the respective reflog file. - -\(fn BRANCH)" t nil) - -(autoload 'magit-branch-unshelve "magit-branch" "\ -Unshelve a BRANCH -Rename \"refs/shelved/BRANCH\" to \"refs/heads/BRANCH\", -and also rename the respective reflog file. - -\(fn BRANCH)" t nil) - (autoload 'magit-branch-configure "magit-branch" nil t) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-branch" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-clone" "magit-clone.el" (0 0 0 0)) -;;; Generated autoloads from magit-clone.el - (autoload 'magit-clone "magit-clone" nil t) - -(autoload 'magit-clone-regular "magit-clone" "\ -Create a clone of REPOSITORY in DIRECTORY. -Then show the status buffer for the new repository. - -\(fn REPOSITORY DIRECTORY ARGS)" t nil) - -(autoload 'magit-clone-shallow "magit-clone" "\ -Create a shallow clone of REPOSITORY in DIRECTORY. -Then show the status buffer for the new repository. -With a prefix argument read the DEPTH of the clone; -otherwise use 1. - -\(fn REPOSITORY DIRECTORY ARGS DEPTH)" t nil) - -(autoload 'magit-clone-shallow-since "magit-clone" "\ -Create a shallow clone of REPOSITORY in DIRECTORY. -Then show the status buffer for the new repository. -Exclude commits before DATE, which is read from the -user. - -\(fn REPOSITORY DIRECTORY ARGS DATE)" t nil) - -(autoload 'magit-clone-shallow-exclude "magit-clone" "\ -Create a shallow clone of REPOSITORY in DIRECTORY. -Then show the status buffer for the new repository. -Exclude commits reachable from EXCLUDE, which is a -branch or tag read from the user. - -\(fn REPOSITORY DIRECTORY ARGS EXCLUDE)" t nil) - -(autoload 'magit-clone-bare "magit-clone" "\ -Create a bare clone of REPOSITORY in DIRECTORY. -Then show the status buffer for the new repository. - -\(fn REPOSITORY DIRECTORY ARGS)" t nil) - -(autoload 'magit-clone-mirror "magit-clone" "\ -Create a mirror of REPOSITORY in DIRECTORY. -Then show the status buffer for the new repository. - -\(fn REPOSITORY DIRECTORY ARGS)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-clone" '("magit-clone-"))) - -;;;*** - -;;;### (autoloads nil "magit-commit" "magit-commit.el" (0 0 0 0)) -;;; Generated autoloads from magit-commit.el - (autoload 'magit-commit "magit-commit" nil t) - -(autoload 'magit-commit-create "magit-commit" "\ -Create a new commit on `HEAD'. -With a prefix argument, amend to the commit at `HEAD' instead. - -\(git commit [--amend] ARGS) - -\(fn &optional ARGS)" t nil) - -(autoload 'magit-commit-amend "magit-commit" "\ -Amend the last commit. - -\(git commit --amend ARGS) - -\(fn &optional ARGS)" t nil) - -(autoload 'magit-commit-extend "magit-commit" "\ -Amend the last commit, without editing the message. - -With a prefix argument keep the committer date, otherwise change -it. The option `magit-commit-extend-override-date' can be used -to inverse the meaning of the prefix argument. -\(git commit ---amend --no-edit) - -\(fn &optional ARGS OVERRIDE-DATE)" t nil) - -(autoload 'magit-commit-reword "magit-commit" "\ -Reword the last commit, ignoring staged changes. - -With a prefix argument keep the committer date, otherwise change -it. The option `magit-commit-reword-override-date' can be used -to inverse the meaning of the prefix argument. - -Non-interactively respect the optional OVERRIDE-DATE argument -and ignore the option. - -\(git commit --amend --only) - -\(fn &optional ARGS OVERRIDE-DATE)" t nil) - -(autoload 'magit-commit-fixup "magit-commit" "\ -Create a fixup commit. - -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'. - -\(fn &optional COMMIT ARGS)" t nil) - -(autoload 'magit-commit-squash "magit-commit" "\ -Create a squash commit, without editing the squash message. - -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'. - -If you want to immediately add a message to the squash commit, -then use `magit-commit-augment' instead of this command. - -\(fn &optional COMMIT ARGS)" t nil) - -(autoload 'magit-commit-augment "magit-commit" "\ -Create a squash commit, editing the squash message. - -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'. - -\(fn &optional COMMIT ARGS)" t nil) - -(autoload 'magit-commit-instant-fixup "magit-commit" "\ -Create a fixup commit targeting COMMIT and instantly rebase. - -\(fn &optional COMMIT ARGS)" t nil) - -(autoload 'magit-commit-instant-squash "magit-commit" "\ -Create a squash commit targeting COMMIT and instantly rebase. - -\(fn &optional COMMIT ARGS)" t nil) - -(autoload 'magit-commit-reshelve "magit-commit" "\ -Change the committer date and possibly the author date of `HEAD'. - -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. - -\(fn DATE UPDATE-AUTHOR &optional ARGS)" t nil) - -(autoload 'magit-commit-absorb-modules "magit-commit" "\ -Spread modified modules across recent commits. - -\(fn PHASE COMMIT)" t nil) - (autoload 'magit-commit-absorb "magit-commit" nil t) - (autoload 'magit-commit-autofixup "magit-commit" nil t) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-commit" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-diff" "magit-diff.el" (0 0 0 0)) -;;; Generated autoloads from magit-diff.el - (autoload 'magit-diff "magit-diff" nil t) - (autoload 'magit-diff-refresh "magit-diff" nil t) - -(autoload 'magit-diff-dwim "magit-diff" "\ -Show changes for the thing at point. - -\(fn &optional ARGS FILES)" t nil) - -(autoload 'magit-diff-range "magit-diff" "\ -Show differences between two commits. - -REV-OR-RANGE should be a range or a single revision. If it is a -revision, then show changes in the working tree relative to that -revision. If it is a range, but one side is omitted, then show -changes relative to `HEAD'. - -If the region is active, use the revisions on the first and last -line of the region as the two sides of the range. With a prefix -argument, instead of diffing the revisions, choose a revision to -view changes along, starting at the common ancestor of both -revisions (i.e., use a \"...\" range). - -\(fn REV-OR-RANGE &optional ARGS FILES)" t nil) - -(autoload 'magit-diff-working-tree "magit-diff" "\ -Show changes between the current working tree and the `HEAD' commit. -With a prefix argument show changes between the working tree and -a commit read from the minibuffer. - -\(fn &optional REV ARGS FILES)" t nil) - -(autoload 'magit-diff-staged "magit-diff" "\ -Show changes between the index and the `HEAD' commit. -With a prefix argument show changes between the index and -a commit read from the minibuffer. - -\(fn &optional REV ARGS FILES)" t nil) - -(autoload 'magit-diff-unstaged "magit-diff" "\ -Show changes between the working tree and the index. - -\(fn &optional ARGS FILES)" t nil) - -(autoload 'magit-diff-unmerged "magit-diff" "\ -Show changes that are being merged. - -\(fn &optional ARGS FILES)" t nil) - -(autoload 'magit-diff-while-committing "magit-diff" "\ -While committing, show the changes that are about to be committed. -While amending, invoking the command again toggles between -showing just the new changes or all the changes that will -be committed. - -\(fn &optional ARGS)" t nil) - -(autoload 'magit-diff-buffer-file "magit-diff" "\ -Show diff for the blob or file visited in the current buffer. - -When the buffer visits a blob, then show the respective commit. -When the buffer visits a file, then show the differenced between -`HEAD' and the working tree. In both cases limit the diff to -the file or blob." t nil) - -(autoload 'magit-diff-paths "magit-diff" "\ -Show changes between any two files on disk. - -\(fn A B)" t nil) - -(autoload 'magit-show-commit "magit-diff" "\ -Visit the revision at point in another buffer. -If there is no revision at point or with a prefix argument prompt -for a revision. - -\(fn REV &optional ARGS FILES MODULE)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-diff" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-ediff" "magit-ediff.el" (0 0 0 0)) -;;; Generated autoloads from magit-ediff.el - (autoload 'magit-ediff "magit-ediff" nil) - -(autoload 'magit-ediff-resolve "magit-ediff" "\ -Resolve outstanding conflicts in FILE using Ediff. -FILE has to be relative to the top directory of the repository. - -In the rare event that you want to manually resolve all -conflicts, including those already resolved by Git, use -`ediff-merge-revisions-with-ancestor'. - -\(fn FILE)" t nil) - -(autoload 'magit-ediff-stage "magit-ediff" "\ -Stage and unstage changes to FILE using Ediff. -FILE has to be relative to the top directory of the repository. - -\(fn FILE)" t nil) - -(autoload 'magit-ediff-compare "magit-ediff" "\ -Compare REVA:FILEA with REVB:FILEB using Ediff. - -FILEA and FILEB have to be relative to the top directory of the -repository. If REVA or REVB is nil, then this stands for the -working tree state. - -If the region is active, use the revisions on the first and last -line of the region. With a prefix argument, instead of diffing -the revisions, choose a revision to view changes along, starting -at the common ancestor of both revisions (i.e., use a \"...\" -range). - -\(fn REVA REVB FILEA FILEB)" t nil) - -(autoload 'magit-ediff-dwim "magit-ediff" "\ -Compare, stage, or resolve using Ediff. -This command tries to guess what file, and what commit or range -the user wants to compare, stage, or resolve using Ediff. It -might only be able to guess either the file, or range or commit, -in which case the user is asked about the other. It might not -always guess right, in which case the appropriate `magit-ediff-*' -command has to be used explicitly. If it cannot read the user's -mind at all, then it asks the user for a command to run." t nil) - -(autoload 'magit-ediff-show-staged "magit-ediff" "\ -Show staged changes using Ediff. - -This only allows looking at the changes; to stage, unstage, -and discard changes using Ediff, use `magit-ediff-stage'. - -FILE must be relative to the top directory of the repository. - -\(fn FILE)" t nil) - -(autoload 'magit-ediff-show-unstaged "magit-ediff" "\ -Show unstaged changes using Ediff. - -This only allows looking at the changes; to stage, unstage, -and discard changes using Ediff, use `magit-ediff-stage'. - -FILE must be relative to the top directory of the repository. - -\(fn FILE)" t nil) - -(autoload 'magit-ediff-show-working-tree "magit-ediff" "\ -Show changes between `HEAD' and working tree using Ediff. -FILE must be relative to the top directory of the repository. - -\(fn FILE)" t nil) - -(autoload 'magit-ediff-show-commit "magit-ediff" "\ -Show changes introduced by COMMIT using Ediff. - -\(fn COMMIT)" t nil) - -(autoload 'magit-ediff-show-stash "magit-ediff" "\ -Show changes introduced by STASH using Ediff. -`magit-ediff-show-stash-with-index' controls whether a -three-buffer Ediff is used in order to distinguish changes in the -stash that were staged. - -\(fn STASH)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-ediff" '("magit-ediff-"))) - -;;;*** - -;;;### (autoloads nil "magit-extras" "magit-extras.el" (0 0 0 0)) -;;; Generated autoloads from magit-extras.el - -(autoload 'magit-run-git-gui "magit-extras" "\ -Run `git gui' for the current git repository." t nil) - -(autoload 'magit-run-git-gui-blame "magit-extras" "\ -Run `git gui blame' on the given FILENAME and COMMIT. -Interactively run it for the current file and the `HEAD', with a -prefix or when the current file cannot be determined let the user -choose. When the current buffer is visiting FILENAME instruct -blame to center around the line point is on. - -\(fn COMMIT FILENAME &optional LINENUM)" t nil) - -(autoload 'magit-run-gitk "magit-extras" "\ -Run `gitk' in the current repository." t nil) - -(autoload 'magit-run-gitk-branches "magit-extras" "\ -Run `gitk --branches' in the current repository." t nil) - -(autoload 'magit-run-gitk-all "magit-extras" "\ -Run `gitk --all' in the current repository." t nil) - -(autoload 'ido-enter-magit-status "magit-extras" "\ -Drop into `magit-status' from file switching. - -This command does not work in Emacs 26.1. -See https://github.com/magit/magit/issues/3634 -and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31707. - -To make this command available use something like: - - (add-hook \\='ido-setup-hook - (lambda () - (define-key ido-completion-map - (kbd \"C-x g\") \\='ido-enter-magit-status))) - -Starting with Emacs 25.1 the Ido keymaps are defined just once -instead of every time Ido is invoked, so now you can modify it -like pretty much every other keymap: - - (define-key ido-common-completion-map - (kbd \"C-x g\") \\='ido-enter-magit-status)" t nil) - -(autoload 'magit-project-status "magit-extras" "\ -Run `magit-status' in the current project's root." t nil) - -(autoload 'magit-dired-jump "magit-extras" "\ -Visit file at point using Dired. -With a prefix argument, visit in another window. If there -is no file at point, then instead visit `default-directory'. - -\(fn &optional OTHER-WINDOW)" t nil) - -(autoload 'magit-dired-log "magit-extras" "\ -Show log for all marked files, or the current file. - -\(fn &optional FOLLOW)" t nil) - -(autoload 'magit-do-async-shell-command "magit-extras" "\ -Open FILE with `dired-do-async-shell-command'. -Interactively, open the file at point. - -\(fn FILE)" t nil) - -(autoload 'magit-previous-line "magit-extras" "\ -Like `previous-line' but with Magit-specific shift-selection. - -Magit's selection mechanism is based on the region but selects an -area that is larger than the region. This causes `previous-line' -when invoked while holding the shift key to move up one line and -thereby select two lines. When invoked inside a hunk body this -command does not move point on the first invocation and thereby -it only selects a single line. Which inconsistency you prefer -is a matter of preference. - -\(fn &optional ARG TRY-VSCROLL)" t nil) - -(function-put 'magit-previous-line 'interactive-only '"use `forward-line' with negative argument instead.") - -(autoload 'magit-next-line "magit-extras" "\ -Like `next-line' but with Magit-specific shift-selection. - -Magit's selection mechanism is based on the region but selects -an area that is larger than the region. This causes `next-line' -when invoked while holding the shift key to move down one line -and thereby select two lines. When invoked inside a hunk body -this command does not move point on the first invocation and -thereby it only selects a single line. Which inconsistency you -prefer is a matter of preference. - -\(fn &optional ARG TRY-VSCROLL)" t nil) - -(function-put 'magit-next-line 'interactive-only 'forward-line) - -(autoload 'magit-clean "magit-extras" "\ -Remove untracked files from the working tree. -With a prefix argument also remove ignored files, -with two prefix arguments remove ignored files only. - -\(git clean -f -d [-x|-X]) - -\(fn &optional ARG)" t nil) - -(autoload 'magit-add-change-log-entry "magit-extras" "\ -Find change log file and add date entry and item for current change. -This differs from `add-change-log-entry' (which see) in that -it acts on the current hunk in a Magit buffer instead of on -a position in a file-visiting buffer. - -\(fn &optional WHOAMI FILE-NAME OTHER-WINDOW)" t nil) - -(autoload 'magit-add-change-log-entry-other-window "magit-extras" "\ -Find change log file in other window and add entry and item. -This differs from `add-change-log-entry-other-window' (which see) -in that it acts on the current hunk in a Magit buffer instead of -on a position in a file-visiting buffer. - -\(fn &optional WHOAMI FILE-NAME)" t nil) - -(autoload 'magit-edit-line-commit "magit-extras" "\ -Edit the commit that added the current line. - -With a prefix argument edit the commit that removes the line, -if any. The commit is determined using `git blame' and made -editable using `git rebase --interactive' if it is reachable -from `HEAD', or by checking out the commit (or a branch that -points at it) otherwise. - -\(fn &optional TYPE)" t nil) - -(autoload 'magit-diff-edit-hunk-commit "magit-extras" "\ -From a hunk, edit the respective commit and visit the file. - -First visit the file being modified by the hunk at the correct -location using `magit-diff-visit-file'. This actually visits a -blob. When point is on a diff header, not within an individual -hunk, then this visits the blob the first hunk is about. - -Then invoke `magit-edit-line-commit', which uses an interactive -rebase to make the commit editable, or if that is not possible -because the commit is not reachable from `HEAD' by checking out -that commit directly. This also causes the actual worktree file -to be visited. - -Neither the blob nor the file buffer are killed when finishing -the rebase. If that is undesirable, then it might be better to -use `magit-rebase-edit-command' instead of this command. - -\(fn FILE)" t nil) - -(autoload 'magit-reshelve-since "magit-extras" "\ -Change the author and committer dates of the commits since REV. - -Ask the user for the first reachable commit whose dates should -be changed. Then read the new date for that commit. The initial -minibuffer input and the previous history element offer good -values. The next commit will be created one minute later and so -on. - -This command is only intended for interactive use and should only -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'. - -\(fn REV KEYID)" t nil) - -(autoload 'magit-pop-revision-stack "magit-extras" "\ -Insert a representation of a revision into the current buffer. - -Pop a revision from the `magit-revision-stack' and insert it into -the current buffer according to `magit-pop-revision-stack-format'. -Revisions can be put on the stack using `magit-copy-section-value' -and `magit-copy-buffer-revision'. - -If the stack is empty or with a prefix argument, instead read a -revision in the minibuffer. By using the minibuffer history this -allows selecting an item which was popped earlier or to insert an -arbitrary reference or revision without first pushing it onto the -stack. - -When reading the revision from the minibuffer, then it might not -be possible to guess the correct repository. When this command -is called inside a repository (e.g. while composing a commit -message), then that repository is used. Otherwise (e.g. while -composing an email) then the repository recorded for the top -element of the stack is used (even though we insert another -revision). If not called inside a repository and with an empty -stack, or with two prefix arguments, then read the repository in -the minibuffer too. - -\(fn REV TOPLEVEL)" t nil) - -(autoload 'magit-copy-section-value "magit-extras" "\ -Save the value of the current section for later use. - -Save the section value to the `kill-ring', and, provided that -the current section is a commit, branch, or tag section, push -the (referenced) revision to the `magit-revision-stack' for use -with `magit-pop-revision-stack'. - -When `magit-copy-revision-abbreviated' is non-nil, save the -abbreviated revision to the `kill-ring' and the -`magit-revision-stack'. - -When the current section is a branch or a tag, and a prefix -argument is used, then save the revision at its tip to the -`kill-ring' instead of the reference name. - -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, then strip the diff marker column and keep only either -the added or removed lines, depending on the sign of the prefix -argument. - -\(fn ARG)" t nil) - -(autoload 'magit-copy-buffer-revision "magit-extras" "\ -Save the revision of the current buffer for later use. - -Save the revision shown in the current buffer to the `kill-ring' -and push it to the `magit-revision-stack'. - -This command is mainly intended for use in `magit-revision-mode' -buffers, the only buffers where it is always unambiguous exactly -which revision should be saved. - -Most other Magit buffers usually show more than one revision, in -some way or another, so this command has to select one of them, -and that choice might not always be the one you think would have -been the best pick. - -In such buffers it is often more useful to save the value of -the current section instead, using `magit-copy-section-value'. - -When the region is active, then save that to the `kill-ring', -like `kill-ring-save' would, instead of behaving as described -above. - -When `magit-copy-revision-abbreviated' is non-nil, save the -abbreviated revision to the `kill-ring' and the -`magit-revision-stack'." t nil) - -(autoload 'magit-abort-dwim "magit-extras" "\ -Abort current operation. -Depending on the context, this will abort a merge, a rebase, a -patch application, a cherry-pick, a revert, or a bisect." t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-extras" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-fetch" "magit-fetch.el" (0 0 0 0)) -;;; Generated autoloads from magit-fetch.el - (autoload 'magit-fetch "magit-fetch" nil t) - (autoload 'magit-fetch-from-pushremote "magit-fetch" nil t) - (autoload 'magit-fetch-from-upstream "magit-fetch" nil t) - -(autoload 'magit-fetch-other "magit-fetch" "\ -Fetch from another repository. - -\(fn REMOTE ARGS)" t nil) - -(autoload 'magit-fetch-branch "magit-fetch" "\ -Fetch a BRANCH from a REMOTE. - -\(fn REMOTE BRANCH ARGS)" t nil) - -(autoload 'magit-fetch-refspec "magit-fetch" "\ -Fetch a REFSPEC from a REMOTE. - -\(fn REMOTE REFSPEC ARGS)" t nil) - -(autoload 'magit-fetch-all "magit-fetch" "\ -Fetch from all remotes. - -\(fn ARGS)" t nil) - -(autoload 'magit-fetch-all-prune "magit-fetch" "\ -Fetch from all remotes, and prune. -Prune remote tracking branches for branches that have been -removed on the respective remote." t nil) - -(autoload 'magit-fetch-all-no-prune "magit-fetch" "\ -Fetch from all remotes." t nil) - -(autoload 'magit-fetch-modules "magit-fetch" "\ -Fetch all submodules. - -Option `magit-fetch-modules-jobs' controls how many submodules -are being fetched in parallel. Also fetch the super-repository, -because `git-fetch' does not support not doing that. With a -prefix argument fetch all remotes. - -\(fn &optional ALL)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-fetch" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-files" "magit-files.el" (0 0 0 0)) -;;; Generated autoloads from magit-files.el - -(autoload 'magit-find-file "magit-files" "\ -View FILE from REV. -Switch to a buffer visiting blob REV:FILE, creating one if none -already exists. If prior to calling this command the current -buffer and/or cursor position is about the same file, then go -to the line and column corresponding to that location. - -\(fn REV FILE)" t nil) - -(autoload 'magit-find-file-other-window "magit-files" "\ -View FILE from REV, in another window. -Switch to a buffer visiting blob REV:FILE, creating one if none -already exists. If prior to calling this command the current -buffer and/or cursor position is about the same file, then go to -the line and column corresponding to that location. - -\(fn REV FILE)" t nil) - -(autoload 'magit-find-file-other-frame "magit-files" "\ -View FILE from REV, in another frame. -Switch to a buffer visiting blob REV:FILE, creating one if none -already exists. If prior to calling this command the current -buffer and/or cursor position is about the same file, then go to -the line and column corresponding to that location. - -\(fn REV FILE)" t nil) - (autoload 'magit-file-dispatch "magit" nil t) - -(autoload 'magit-blob-visit-file "magit-files" "\ -View the file from the worktree corresponding to the current blob. -When visiting a blob or the version from the index, then go to -the same location in the respective file in the working tree." t nil) - -(autoload 'magit-file-checkout "magit-files" "\ -Checkout FILE from REV. - -\(fn REV FILE)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-files" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-git" "magit-git.el" (0 0 0 0)) -;;; Generated autoloads from magit-git.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-git" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-gitignore" "magit-gitignore.el" (0 0 -;;;;;; 0 0)) -;;; Generated autoloads from magit-gitignore.el - (autoload 'magit-gitignore "magit-gitignore" nil t) - -(autoload 'magit-gitignore-in-topdir "magit-gitignore" "\ -Add the Git ignore RULE to the top-level \".gitignore\" file. -Since this file is tracked, it is shared with other clones of the -repository. Also stage the file. - -\(fn RULE)" t nil) - -(autoload 'magit-gitignore-in-subdir "magit-gitignore" "\ -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. - -\(fn RULE DIRECTORY)" t nil) - -(autoload 'magit-gitignore-in-gitdir "magit-gitignore" "\ -Add the Git ignore RULE to \"$GIT_DIR/info/exclude\". -Rules in that file only affects this clone of the repository. - -\(fn RULE)" t nil) - -(autoload 'magit-gitignore-on-system "magit-gitignore" "\ -Add the Git ignore RULE to the file specified by `core.excludesFile'. -Rules that are defined in that file affect all local repositories. - -\(fn RULE)" t nil) - -(autoload 'magit-skip-worktree "magit-gitignore" "\ -Call \"git update-index --skip-worktree -- FILE\". - -\(fn FILE)" t nil) - -(autoload 'magit-no-skip-worktree "magit-gitignore" "\ -Call \"git update-index --no-skip-worktree -- FILE\". - -\(fn FILE)" t nil) - -(autoload 'magit-assume-unchanged "magit-gitignore" "\ -Call \"git update-index --assume-unchanged -- FILE\". - -\(fn FILE)" t nil) - -(autoload 'magit-no-assume-unchanged "magit-gitignore" "\ -Call \"git update-index --no-assume-unchanged -- FILE\". - -\(fn FILE)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-gitignore" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-imenu" "magit-imenu.el" (0 0 0 0)) -;;; Generated autoloads from magit-imenu.el - -(autoload 'magit-imenu--log-prev-index-position-function "magit-imenu" "\ -Move point to previous line in current buffer. -This function is used as a value for -`imenu-prev-index-position-function'." nil nil) - -(autoload 'magit-imenu--log-extract-index-name-function "magit-imenu" "\ -Return imenu name for line at point. -This function is used as a value for -`imenu-extract-index-name-function'. Point should be at the -beginning of the line." nil nil) - -(autoload 'magit-imenu--diff-prev-index-position-function "magit-imenu" "\ -Move point to previous file line in current buffer. -This function is used as a value for -`imenu-prev-index-position-function'." nil nil) - -(autoload 'magit-imenu--diff-extract-index-name-function "magit-imenu" "\ -Return imenu name for line at point. -This function is used as a value for -`imenu-extract-index-name-function'. Point should be at the -beginning of the line." nil nil) - -(autoload 'magit-imenu--status-create-index-function "magit-imenu" "\ -Return an alist of all imenu entries in current buffer. -This function is used as a value for -`imenu-create-index-function'." nil nil) - -(autoload 'magit-imenu--refs-create-index-function "magit-imenu" "\ -Return an alist of all imenu entries in current buffer. -This function is used as a value for -`imenu-create-index-function'." nil nil) - -(autoload 'magit-imenu--cherry-create-index-function "magit-imenu" "\ -Return an alist of all imenu entries in current buffer. -This function is used as a value for -`imenu-create-index-function'." nil nil) - -(autoload 'magit-imenu--submodule-prev-index-position-function "magit-imenu" "\ -Move point to previous line in magit-submodule-list buffer. -This function is used as a value for -`imenu-prev-index-position-function'." nil nil) - -(autoload 'magit-imenu--submodule-extract-index-name-function "magit-imenu" "\ -Return imenu name for line at point. -This function is used as a value for -`imenu-extract-index-name-function'. Point should be at the -beginning of the line." nil nil) - -(autoload 'magit-imenu--repolist-prev-index-position-function "magit-imenu" "\ -Move point to previous line in magit-repolist buffer. -This function is used as a value for -`imenu-prev-index-position-function'." nil nil) - -(autoload 'magit-imenu--repolist-extract-index-name-function "magit-imenu" "\ -Return imenu name for line at point. -This function is used as a value for -`imenu-extract-index-name-function'. Point should be at the -beginning of the line." nil nil) - -(autoload 'magit-imenu--process-prev-index-position-function "magit-imenu" "\ -Move point to previous process in magit-process buffer. -This function is used as a value for -`imenu-prev-index-position-function'." nil nil) - -(autoload 'magit-imenu--process-extract-index-name-function "magit-imenu" "\ -Return imenu name for line at point. -This function is used as a value for -`imenu-extract-index-name-function'. Point should be at the -beginning of the line." nil nil) - -(autoload 'magit-imenu--rebase-prev-index-position-function "magit-imenu" "\ -Move point to previous commit in git-rebase buffer. -This function is used as a value for -`imenu-prev-index-position-function'." nil nil) - -(autoload 'magit-imenu--rebase-extract-index-name-function "magit-imenu" "\ -Return imenu name for line at point. -This function is used as a value for -`imenu-extract-index-name-function'. Point should be at the -beginning of the line." nil nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-imenu" '("magit-imenu--index-function"))) - -;;;*** - -;;;### (autoloads nil "magit-log" "magit-log.el" (0 0 0 0)) -;;; Generated autoloads from magit-log.el - (autoload 'magit-log "magit-log" nil t) - (autoload 'magit-log-refresh "magit-log" nil t) - -(autoload 'magit-log-current "magit-log" "\ -Show log for the current branch. -When `HEAD' is detached or with a prefix argument show log for -one or more revs read from the minibuffer. - -\(fn REVS &optional ARGS FILES)" t nil) - -(autoload 'magit-log-other "magit-log" "\ -Show log for one or more revs read from the minibuffer. -The user can input any revision or revisions separated by a -space, or even ranges, but only branches and tags, and a -representation of the commit at point, are available as -completion candidates. - -\(fn REVS &optional ARGS FILES)" t nil) - -(autoload 'magit-log-head "magit-log" "\ -Show log for `HEAD'. - -\(fn &optional ARGS FILES)" t nil) - -(autoload 'magit-log-branches "magit-log" "\ -Show log for all local branches and `HEAD'. - -\(fn &optional ARGS FILES)" t nil) - -(autoload 'magit-log-matching-branches "magit-log" "\ -Show log for all branches matching PATTERN and `HEAD'. - -\(fn PATTERN &optional ARGS FILES)" t nil) - -(autoload 'magit-log-matching-tags "magit-log" "\ -Show log for all tags matching PATTERN and `HEAD'. - -\(fn PATTERN &optional ARGS FILES)" t nil) - -(autoload 'magit-log-all-branches "magit-log" "\ -Show log for all local and remote branches and `HEAD'. - -\(fn &optional ARGS FILES)" t nil) - -(autoload 'magit-log-all "magit-log" "\ -Show log for all references and `HEAD'. - -\(fn &optional ARGS FILES)" t nil) - -(autoload 'magit-log-buffer-file "magit-log" "\ -Show log for the blob or file visited in the current buffer. -With a prefix argument or when `--follow' is an active log -argument, then follow renames. When the region is active, -restrict the log to the lines that the region touches. - -\(fn &optional FOLLOW BEG END)" t nil) - -(autoload 'magit-log-trace-definition "magit-log" "\ -Show log for the definition at point. - -\(fn FILE FN REV)" t nil) - -(autoload 'magit-log-merged "magit-log" "\ -Show log for the merge of COMMIT into BRANCH. - -More precisely, find merge commit M that brought COMMIT into -BRANCH, and show the log of the range \"M^1..M\". If COMMIT is -directly on BRANCH, then show approximately twenty surrounding -commits instead. - -This command requires git-when-merged, which is available from -https://github.com/mhagger/git-when-merged. - -\(fn COMMIT BRANCH &optional ARGS FILES)" t nil) - -(autoload 'magit-log-move-to-parent "magit-log" "\ -Move to the Nth parent of the current commit. - -\(fn &optional N)" t nil) - (autoload 'magit-shortlog "magit-log" nil t) - -(autoload 'magit-shortlog-since "magit-log" "\ -Show a history summary for commits since REV. - -\(fn REV ARGS)" t nil) - -(autoload 'magit-shortlog-range "magit-log" "\ -Show a history summary for commit or range REV-OR-RANGE. - -\(fn REV-OR-RANGE ARGS)" t nil) - -(autoload 'magit-cherry "magit-log" "\ -Show commits in a branch that are not merged in the upstream branch. - -\(fn HEAD UPSTREAM)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-log" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-margin" "magit-margin.el" (0 0 0 0)) -;;; Generated autoloads from magit-margin.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-margin" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-merge" "magit-merge.el" (0 0 0 0)) -;;; Generated autoloads from magit-merge.el - (autoload 'magit-merge "magit" nil t) - -(autoload 'magit-merge-plain "magit-merge" "\ -Merge commit REV into the current branch; using default message. - -Unless there are conflicts or a prefix argument is used create a -merge commit using a generic commit message and without letting -the user inspect the result. With a prefix argument pretend the -merge failed to give the user the opportunity to inspect the -merge. - -\(git merge --no-edit|--no-commit [ARGS] REV) - -\(fn REV &optional ARGS NOCOMMIT)" t nil) - -(autoload 'magit-merge-editmsg "magit-merge" "\ -Merge commit REV into the current branch; and edit message. -Perform the merge and prepare a commit message but let the user -edit it. - -\(git merge --edit --no-ff [ARGS] REV) - -\(fn REV &optional ARGS)" t nil) - -(autoload 'magit-merge-nocommit "magit-merge" "\ -Merge commit REV into the current branch; pretending it failed. -Pretend the merge failed to give the user the opportunity to -inspect the merge and change the commit message. - -\(git merge --no-commit --no-ff [ARGS] REV) - -\(fn REV &optional ARGS)" t nil) - -(autoload 'magit-merge-into "magit-merge" "\ -Merge the current branch into BRANCH and remove the former. - -Before merging, force push the source branch to its push-remote, -provided the respective remote branch already exists, ensuring -that the respective pull-request (if any) won't get stuck on some -obsolete version of the commits that are being merged. Finally -if `forge-branch-pullreq' was used to create the merged branch, -branch, then also remove the respective remote branch. - -\(fn BRANCH &optional ARGS)" t nil) - -(autoload 'magit-merge-absorb "magit-merge" "\ -Merge BRANCH into the current branch and remove the former. - -Before merging, force push the source branch to its push-remote, -provided the respective remote branch already exists, ensuring -that the respective pull-request (if any) won't get stuck on some -obsolete version of the commits that are being merged. Finally -if `forge-branch-pullreq' was used to create the merged branch, -then also remove the respective remote branch. - -\(fn BRANCH &optional ARGS)" t nil) - -(autoload 'magit-merge-squash "magit-merge" "\ -Squash commit REV into the current branch; don't create a commit. - -\(git merge --squash REV) - -\(fn REV)" t nil) - -(autoload 'magit-merge-preview "magit-merge" "\ -Preview result of merging REV into the current branch. - -\(fn REV)" t nil) - -(autoload 'magit-merge-abort "magit-merge" "\ -Abort the current merge operation. - -\(git merge --abort)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-merge" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-mode" "magit-mode.el" (0 0 0 0)) -;;; Generated autoloads from magit-mode.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-mode" '("disable-magit-save-buffers" "magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-notes" "magit-notes.el" (0 0 0 0)) -;;; Generated autoloads from magit-notes.el - (autoload 'magit-notes "magit" nil t) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-notes" '("magit-notes-"))) - -;;;*** - -;;;### (autoloads nil "magit-obsolete" "magit-obsolete.el" (0 0 0 -;;;;;; 0)) -;;; Generated autoloads from magit-obsolete.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-obsolete" '("magit--magit-popup-warning"))) - -;;;*** - -;;;### (autoloads nil "magit-patch" "magit-patch.el" (0 0 0 0)) -;;; Generated autoloads from magit-patch.el - (autoload 'magit-patch "magit-patch" nil t) - (autoload 'magit-patch-create "magit-patch" nil t) - (autoload 'magit-patch-apply "magit-patch" nil t) - -(autoload 'magit-patch-save "magit-patch" "\ -Write current diff into patch FILE. - -What arguments are used to create the patch depends on the value -of `magit-patch-save-arguments' and whether a prefix argument is -used. - -If the value is the symbol `buffer', then use the same arguments -as the buffer. With a prefix argument use no arguments. - -If the value is a list beginning with the symbol `exclude', then -use the same arguments as the buffer except for those matched by -entries in the cdr of the list. The comparison is done using -`string-prefix-p'. With a prefix argument use the same arguments -as the buffer. - -If the value is a list of strings (including the empty list), -then use those arguments. With a prefix argument use the same -arguments as the buffer. - -Of course the arguments that are required to actually show the -same differences as those shown in the buffer are always used. - -\(fn FILE &optional ARG)" t nil) - -(autoload 'magit-request-pull "magit-patch" "\ -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. -END is the last commit, usually a branch name, which upstream -is asked to pull. START has to be reachable from that commit. - -\(fn URL START END)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-patch" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-process" "magit-process.el" (0 0 0 0)) -;;; Generated autoloads from magit-process.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-process" '("magit-" "tramp-sh-handle-"))) - -;;;*** - -;;;### (autoloads nil "magit-pull" "magit-pull.el" (0 0 0 0)) -;;; Generated autoloads from magit-pull.el - (autoload 'magit-pull "magit-pull" nil t) - (autoload 'magit-pull-from-pushremote "magit-pull" nil t) - (autoload 'magit-pull-from-upstream "magit-pull" nil t) - -(autoload 'magit-pull-branch "magit-pull" "\ -Pull from a branch read in the minibuffer. - -\(fn SOURCE ARGS)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-pull" '("magit-pull-"))) - -;;;*** - -;;;### (autoloads nil "magit-push" "magit-push.el" (0 0 0 0)) -;;; Generated autoloads from magit-push.el - (autoload 'magit-push "magit-push" nil t) - (autoload 'magit-push-current-to-pushremote "magit-push" nil t) - (autoload 'magit-push-current-to-upstream "magit-push" nil t) - -(autoload 'magit-push-current "magit-push" "\ -Push the current branch to a branch read in the minibuffer. - -\(fn TARGET ARGS)" t nil) - -(autoload 'magit-push-other "magit-push" "\ -Push an arbitrary branch or commit somewhere. -Both the source and the target are read in the minibuffer. - -\(fn SOURCE TARGET ARGS)" t nil) - -(autoload 'magit-push-refspecs "magit-push" "\ -Push one or multiple REFSPECS to a REMOTE. -Both the REMOTE and the REFSPECS are read in the minibuffer. To -use multiple REFSPECS, separate them with commas. Completion is -only available for the part before the colon, or when no colon -is used. - -\(fn REMOTE REFSPECS ARGS)" t nil) - -(autoload 'magit-push-matching "magit-push" "\ -Push all matching branches to another repository. -If multiple remotes exist, then read one from the user. -If just one exists, use that without requiring confirmation. - -\(fn REMOTE &optional ARGS)" t nil) - -(autoload 'magit-push-tags "magit-push" "\ -Push all tags to another repository. -If only one remote exists, then push to that. Otherwise prompt -for a remote, offering the remote configured for the current -branch as default. - -\(fn REMOTE &optional ARGS)" t nil) - -(autoload 'magit-push-tag "magit-push" "\ -Push a tag to another repository. - -\(fn TAG REMOTE &optional ARGS)" t nil) - -(autoload 'magit-push-notes-ref "magit-push" "\ -Push a notes ref to another repository. - -\(fn REF REMOTE &optional ARGS)" t nil) - (autoload 'magit-push-implicitly "magit-push" nil t) - -(autoload 'magit-push-to-remote "magit-push" "\ -Push to REMOTE without using an explicit refspec. -The REMOTE is read in the minibuffer. - -This command simply runs \"git push -v [ARGS] REMOTE\". ARGS -are the arguments specified in the popup buffer. No refspec -arguments are used. Instead the behavior depends on at least -these Git variables: `push.default', `remote.pushDefault', -`branch..pushRemote', `branch..remote', -`branch..merge', and `remote..push'. - -\(fn REMOTE ARGS)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-push" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-reflog" "magit-reflog.el" (0 0 0 0)) -;;; Generated autoloads from magit-reflog.el - -(autoload 'magit-reflog-current "magit-reflog" "\ -Display the reflog of the current branch. -If `HEAD' is detached, then show the reflog for that instead." t nil) - -(autoload 'magit-reflog-other "magit-reflog" "\ -Display the reflog of a branch or another ref. - -\(fn REF)" t nil) - -(autoload 'magit-reflog-head "magit-reflog" "\ -Display the `HEAD' reflog." t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-reflog" '("magit-reflog-"))) - -;;;*** - -;;;### (autoloads nil "magit-refs" "magit-refs.el" (0 0 0 0)) -;;; Generated autoloads from magit-refs.el - (autoload 'magit-show-refs "magit-refs" nil t) - -(autoload 'magit-show-refs-head "magit-refs" "\ -List and compare references in a dedicated buffer. -Compared with `HEAD'. - -\(fn &optional ARGS)" t nil) - -(autoload 'magit-show-refs-current "magit-refs" "\ -List and compare references in a dedicated buffer. -Compare with the current branch or `HEAD' if it is detached. - -\(fn &optional ARGS)" t nil) - -(autoload 'magit-show-refs-other "magit-refs" "\ -List and compare references in a dedicated buffer. -Compared with a branch read from the user. - -\(fn &optional REF ARGS)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-refs" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-remote" "magit-remote.el" (0 0 0 0)) -;;; Generated autoloads from magit-remote.el - (autoload 'magit-remote "magit-remote" nil t) - -(autoload 'magit-remote-add "magit-remote" "\ -Add a remote named REMOTE and fetch it. - -\(fn REMOTE URL &optional ARGS)" t nil) - -(autoload 'magit-remote-rename "magit-remote" "\ -Rename the remote named OLD to NEW. - -\(fn OLD NEW)" t nil) - -(autoload 'magit-remote-remove "magit-remote" "\ -Delete the remote named REMOTE. - -\(fn REMOTE)" t nil) - -(autoload 'magit-remote-prune "magit-remote" "\ -Remove stale remote-tracking branches for REMOTE. - -\(fn REMOTE)" t nil) - -(autoload 'magit-remote-prune-refspecs "magit-remote" "\ -Remove stale refspecs for REMOTE. - -A refspec is stale if there no longer exists at least one branch -on the remote that would be fetched due to that refspec. A stale -refspec is problematic because its existence causes Git to refuse -to fetch according to the remaining non-stale refspecs. - -If only stale refspecs remain, then offer to either delete the -remote or to replace the stale refspecs with the default refspec. - -Also remove the remote-tracking branches that were created due to -the now stale refspecs. Other stale branches are not removed. - -\(fn REMOTE)" t nil) - -(autoload 'magit-remote-set-head "magit-remote" "\ -Set the local representation of REMOTE's default branch. -Query REMOTE and set the symbolic-ref refs/remotes//HEAD -accordingly. With a prefix argument query for the branch to be -used, which allows you to select an incorrect value if you fancy -doing that. - -\(fn REMOTE &optional BRANCH)" t nil) - -(autoload 'magit-remote-unset-head "magit-remote" "\ -Unset the local representation of REMOTE's default branch. -Delete the symbolic-ref \"refs/remotes//HEAD\". - -\(fn REMOTE)" t nil) - (autoload 'magit-remote-configure "magit-remote" nil t) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-remote" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-repos" "magit-repos.el" (0 0 0 0)) -;;; Generated autoloads from magit-repos.el - -(autoload 'magit-list-repositories "magit-repos" "\ -Display a list of repositories. - -Use the options `magit-repository-directories' to control which -repositories are displayed." t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-repos" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-reset" "magit-reset.el" (0 0 0 0)) -;;; Generated autoloads from magit-reset.el - (autoload 'magit-reset "magit" nil t) - -(autoload 'magit-reset-mixed "magit-reset" "\ -Reset the `HEAD' and index to COMMIT, but not the working tree. - -\(git reset --mixed COMMIT) - -\(fn COMMIT)" t nil) - -(autoload 'magit-reset-soft "magit-reset" "\ -Reset the `HEAD' to COMMIT, but not the index and working tree. - -\(git reset --soft REVISION) - -\(fn COMMIT)" t nil) - -(autoload 'magit-reset-hard "magit-reset" "\ -Reset the `HEAD', index, and working tree to COMMIT. - -\(git reset --hard REVISION) - -\(fn COMMIT)" t nil) - -(autoload 'magit-reset-keep "magit-reset" "\ -Reset the `HEAD' and index to COMMIT, while keeping uncommitted changes. - -\(git reset --keep REVISION) - -\(fn COMMIT)" t nil) - -(autoload 'magit-reset-index "magit-reset" "\ -Reset the index to COMMIT. -Keep the `HEAD' and working tree as-is, so if COMMIT refers to the -head this effectively unstages all changes. - -\(git reset COMMIT .) - -\(fn COMMIT)" t nil) - -(autoload 'magit-reset-worktree "magit-reset" "\ -Reset the worktree to COMMIT. -Keep the `HEAD' and index as-is. - -\(fn COMMIT)" t nil) - -(autoload 'magit-reset-quickly "magit-reset" "\ -Reset the `HEAD' and index to COMMIT, and possibly the working tree. -With a prefix argument reset the working tree otherwise don't. - -\(git reset --mixed|--hard COMMIT) - -\(fn COMMIT &optional HARD)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-reset" '("magit-reset-"))) - -;;;*** - -;;;### (autoloads nil "magit-sequence" "magit-sequence.el" (0 0 0 -;;;;;; 0)) -;;; Generated autoloads from magit-sequence.el - -(autoload 'magit-sequencer-continue "magit-sequence" "\ -Resume the current cherry-pick or revert sequence." t nil) - -(autoload 'magit-sequencer-skip "magit-sequence" "\ -Skip the stopped at commit during a cherry-pick or revert sequence." t nil) - -(autoload 'magit-sequencer-abort "magit-sequence" "\ -Abort the current cherry-pick or revert sequence. -This discards all changes made since the sequence started." t nil) - (autoload 'magit-cherry-pick "magit-sequence" nil t) - -(autoload 'magit-cherry-copy "magit-sequence" "\ -Copy COMMITS from another branch onto the current branch. -Prompt for a commit, defaulting to the commit at point. If -the region selects multiple commits, then pick all of them, -without prompting. - -\(fn COMMITS &optional ARGS)" t nil) - -(autoload 'magit-cherry-apply "magit-sequence" "\ -Apply the changes in COMMITS but do not commit them. -Prompt for a commit, defaulting to the commit at point. If -the region selects multiple commits, then apply all of them, -without prompting. - -\(fn COMMITS &optional ARGS)" t nil) - -(autoload 'magit-cherry-harvest "magit-sequence" "\ -Move COMMITS from another BRANCH onto the current branch. -Remove the COMMITS from BRANCH and stay on the current branch. -If a conflict occurs, then you have to fix that and finish the -process manually. - -\(fn COMMITS BRANCH &optional ARGS)" t nil) - -(autoload 'magit-cherry-donate "magit-sequence" "\ -Move COMMITS from the current branch onto another existing BRANCH. -Remove COMMITS from the current branch and stay on that branch. -If a conflict occurs, then you have to fix that and finish the -process manually. - -\(fn COMMITS BRANCH &optional ARGS)" t nil) - -(autoload 'magit-cherry-spinout "magit-sequence" "\ -Move COMMITS from the current branch onto a new BRANCH. -Remove COMMITS from the current branch and stay on that branch. -If a conflict occurs, then you have to fix that and finish the -process manually. - -\(fn COMMITS BRANCH START-POINT &optional ARGS)" t nil) - -(autoload 'magit-cherry-spinoff "magit-sequence" "\ -Move COMMITS from the current branch onto a new BRANCH. -Remove COMMITS from the current branch and checkout BRANCH. -If a conflict occurs, then you have to fix that and finish -the process manually. - -\(fn COMMITS BRANCH START-POINT &optional ARGS)" t nil) - (autoload 'magit-revert "magit-sequence" nil t) - -(autoload 'magit-revert-and-commit "magit-sequence" "\ -Revert COMMIT by creating a new commit. -Prompt for a commit, defaulting to the commit at point. If -the region selects multiple commits, then revert all of them, -without prompting. - -\(fn COMMIT &optional ARGS)" t nil) - -(autoload 'magit-revert-no-commit "magit-sequence" "\ -Revert COMMIT by applying it in reverse to the worktree. -Prompt for a commit, defaulting to the commit at point. If -the region selects multiple commits, then revert all of them, -without prompting. - -\(fn COMMIT &optional ARGS)" t nil) - (autoload 'magit-am "magit-sequence" nil t) - -(autoload 'magit-am-apply-patches "magit-sequence" "\ -Apply the patches FILES. - -\(fn &optional FILES ARGS)" t nil) - -(autoload 'magit-am-apply-maildir "magit-sequence" "\ -Apply the patches from MAILDIR. - -\(fn &optional MAILDIR ARGS)" t nil) - -(autoload 'magit-am-continue "magit-sequence" "\ -Resume the current patch applying sequence." t nil) - -(autoload 'magit-am-skip "magit-sequence" "\ -Skip the stopped at patch during a patch applying sequence." t nil) - -(autoload 'magit-am-abort "magit-sequence" "\ -Abort the current patch applying sequence. -This discards all changes made since the sequence started." t nil) - (autoload 'magit-rebase "magit-sequence" nil t) - (autoload 'magit-rebase-onto-pushremote "magit-sequence" nil t) - (autoload 'magit-rebase-onto-upstream "magit-sequence" nil t) - -(autoload 'magit-rebase-branch "magit-sequence" "\ -Rebase the current branch onto a branch read in the minibuffer. -All commits that are reachable from `HEAD' but not from the -selected branch TARGET are being rebased. - -\(fn TARGET ARGS)" t nil) - -(autoload 'magit-rebase-subset "magit-sequence" "\ -Rebase a subset of the current branch's history onto a new base. -Rebase commits from START to `HEAD' onto NEWBASE. -START has to be selected from a list of recent commits. - -\(fn NEWBASE START ARGS)" t nil) - -(autoload 'magit-rebase-interactive "magit-sequence" "\ -Start an interactive rebase sequence. - -\(fn COMMIT ARGS)" t nil) - -(autoload 'magit-rebase-autosquash "magit-sequence" "\ -Combine squash and fixup commits with their intended targets. - -\(fn ARGS)" t nil) - -(autoload 'magit-rebase-edit-commit "magit-sequence" "\ -Edit a single older commit using rebase. - -\(fn COMMIT ARGS)" t nil) - -(autoload 'magit-rebase-reword-commit "magit-sequence" "\ -Reword a single older commit using rebase. - -\(fn COMMIT ARGS)" t nil) - -(autoload 'magit-rebase-remove-commit "magit-sequence" "\ -Remove a single older commit using rebase. - -\(fn COMMIT ARGS)" t nil) - -(autoload 'magit-rebase-continue "magit-sequence" "\ -Restart the current rebasing operation. -In some cases this pops up a commit message buffer for you do -edit. With a prefix argument the old message is reused as-is. - -\(fn &optional NOEDIT)" t nil) - -(autoload 'magit-rebase-skip "magit-sequence" "\ -Skip the current commit and restart the current rebase operation." t nil) - -(autoload 'magit-rebase-edit "magit-sequence" "\ -Edit the todo list of the current rebase operation." t nil) - -(autoload 'magit-rebase-abort "magit-sequence" "\ -Abort the current rebase operation, restoring the original branch." t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-sequence" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-stash" "magit-stash.el" (0 0 0 0)) -;;; Generated autoloads from magit-stash.el - (autoload 'magit-stash "magit-stash" nil t) - -(autoload 'magit-stash-both "magit-stash" "\ -Create a stash of the index and working tree. -Untracked files are included according to infix arguments. -One prefix argument is equivalent to `--include-untracked' -while two prefix arguments are equivalent to `--all'. - -\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil) - -(autoload 'magit-stash-index "magit-stash" "\ -Create a stash of the index only. -Unstaged and untracked changes are not stashed. The stashed -changes are applied in reverse to both the index and the -worktree. This command can fail when the worktree is not clean. -Applying the resulting stash has the inverse effect. - -\(fn MESSAGE)" t nil) - -(autoload 'magit-stash-worktree "magit-stash" "\ -Create a stash of unstaged changes in the working tree. -Untracked files are included according to infix arguments. -One prefix argument is equivalent to `--include-untracked' -while two prefix arguments are equivalent to `--all'. - -\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil) - -(autoload 'magit-stash-keep-index "magit-stash" "\ -Create a stash of the index and working tree, keeping index intact. -Untracked files are included according to infix arguments. -One prefix argument is equivalent to `--include-untracked' -while two prefix arguments are equivalent to `--all'. - -\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil) - -(autoload 'magit-snapshot-both "magit-stash" "\ -Create a snapshot of the index and working tree. -Untracked files are included according to infix arguments. -One prefix argument is equivalent to `--include-untracked' -while two prefix arguments are equivalent to `--all'. - -\(fn &optional INCLUDE-UNTRACKED)" t nil) - -(autoload 'magit-snapshot-index "magit-stash" "\ -Create a snapshot of the index only. -Unstaged and untracked changes are not stashed." t nil) - -(autoload 'magit-snapshot-worktree "magit-stash" "\ -Create a snapshot of unstaged changes in the working tree. -Untracked files are included according to infix arguments. -One prefix argument is equivalent to `--include-untracked' -while two prefix arguments are equivalent to `--all'. - -\(fn &optional INCLUDE-UNTRACKED)" t nil) - -(autoload 'magit-stash-apply "magit-stash" "\ -Apply a stash to the working tree. -Try to preserve the stash index. If that fails because there -are staged changes, apply without preserving the stash index. - -\(fn STASH)" t nil) - -(autoload 'magit-stash-drop "magit-stash" "\ -Remove a stash from the stash list. -When the region is active offer to drop all contained stashes. - -\(fn STASH)" t nil) - -(autoload 'magit-stash-clear "magit-stash" "\ -Remove all stashes saved in REF's reflog by deleting REF. - -\(fn REF)" t nil) - -(autoload 'magit-stash-branch "magit-stash" "\ -Create and checkout a new BRANCH from STASH. - -\(fn STASH BRANCH)" t nil) - -(autoload 'magit-stash-branch-here "magit-stash" "\ -Create and checkout a new BRANCH and apply STASH. -The branch is created using `magit-branch-and-checkout', using the -current branch or `HEAD' as the start-point. - -\(fn STASH BRANCH)" t nil) - -(autoload 'magit-stash-format-patch "magit-stash" "\ -Create a patch from STASH - -\(fn STASH)" t nil) - -(autoload 'magit-stash-list "magit-stash" "\ -List all stashes in a buffer." t nil) - -(autoload 'magit-stash-show "magit-stash" "\ -Show all diffs of a stash in a buffer. - -\(fn STASH &optional ARGS FILES)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-stash" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-status" "magit-status.el" (0 0 0 0)) -;;; Generated autoloads from magit-status.el - -(autoload 'magit-init "magit-status" "\ -Initialize a Git repository, then show its status. - -If the directory is below an existing repository, then the user -has to confirm that a new one should be created inside. If the -directory is the root of the existing repository, then the user -has to confirm that it should be reinitialized. - -Non-interactively DIRECTORY is (re-)initialized unconditionally. - -\(fn DIRECTORY)" t nil) - -(autoload 'magit-status "magit-status" "\ -Show the status of the current Git repository in a buffer. - -If the current directory isn't located within a Git repository, -then prompt for an existing repository or an arbitrary directory, -depending on option `magit-repository-directories', and show the -status of the selected repository instead. - -* If that option specifies any existing repositories, then offer - those for completion and show the status buffer for the - selected one. - -* Otherwise read an arbitrary directory using regular file-name - completion. If the selected directory is the top-level of an - existing working tree, then show the status buffer for that. - -* Otherwise offer to initialize the selected directory as a new - repository. After creating the repository show its status - buffer. - -These fallback behaviors can also be forced using one or more -prefix arguments: - -* With two prefix arguments (or more precisely a numeric prefix - value of 16 or greater) read an arbitrary directory and act on - it as described above. The same could be accomplished using - the command `magit-init'. - -* With a single prefix argument read an existing repository, or - if none can be found based on `magit-repository-directories', - then fall back to the same behavior as with two prefix - arguments. - -\(fn &optional DIRECTORY CACHE)" t nil) - -(defalias 'magit 'magit-status "\ -An alias for `magit-status' for better discoverability. - -Instead of invoking this alias for `magit-status' using -\"M-x magit RET\", you should bind a key to `magit-status' -and read the info node `(magit)Getting Started', which -also contains other useful hints.") - -(autoload 'magit-status-here "magit-status" "\ -Like `magit-status' but with non-nil `magit-status-goto-file-position'." t nil) - -(autoload 'magit-status-setup-buffer "magit-status" "\ - - -\(fn &optional DIRECTORY)" nil nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-status" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-submodule" "magit-submodule.el" (0 0 -;;;;;; 0 0)) -;;; Generated autoloads from magit-submodule.el - (autoload 'magit-submodule "magit-submodule" nil t) - (autoload 'magit-submodule-add "magit-submodule" nil t) - -(autoload 'magit-submodule-read-name-for-path "magit-submodule" "\ - - -\(fn PATH &optional PREFER-SHORT)" nil nil) - (autoload 'magit-submodule-register "magit-submodule" nil t) - (autoload 'magit-submodule-populate "magit-submodule" nil t) - (autoload 'magit-submodule-update "magit-submodule" nil t) - (autoload 'magit-submodule-synchronize "magit-submodule" nil t) - (autoload 'magit-submodule-unpopulate "magit-submodule" nil t) - -(autoload 'magit-submodule-remove "magit-submodule" "\ -Unregister MODULES and remove their working directories. - -For safety reasons, do not remove the gitdirs and if a module has -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. - -With the \"--force\" argument offer to remove dirty working -directories and with a prefix argument offer to delete gitdirs. -Both actions are very dangerous and have to be confirmed. There -are additional safety precautions in place, so you might be able -to recover from making a mistake here, but don't count on it. - -\(fn MODULES ARGS TRASH-GITDIRS)" t nil) - -(autoload 'magit-insert-modules "magit-submodule" "\ -Insert submodule sections. -Hook `magit-module-sections-hook' controls which module sections -are inserted, and option `magit-module-sections-nested' controls -whether they are wrapped in an additional section." nil nil) - -(autoload 'magit-insert-modules-overview "magit-submodule" "\ -Insert sections for all modules. -For each section insert the path and the output of `git describe --tags', -or, failing that, the abbreviated HEAD commit hash." nil nil) - -(autoload 'magit-insert-modules-unpulled-from-upstream "magit-submodule" "\ -Insert sections for modules that haven't been pulled from the upstream. -These sections can be expanded to show the respective commits." nil nil) - -(autoload 'magit-insert-modules-unpulled-from-pushremote "magit-submodule" "\ -Insert sections for modules that haven't been pulled from the push-remote. -These sections can be expanded to show the respective commits." nil nil) - -(autoload 'magit-insert-modules-unpushed-to-upstream "magit-submodule" "\ -Insert sections for modules that haven't been pushed to the upstream. -These sections can be expanded to show the respective commits." nil nil) - -(autoload 'magit-insert-modules-unpushed-to-pushremote "magit-submodule" "\ -Insert sections for modules that haven't been pushed to the push-remote. -These sections can be expanded to show the respective commits." nil nil) - -(autoload 'magit-list-submodules "magit-submodule" "\ -Display a list of the current repository's submodules." t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-submodule" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-subtree" "magit-subtree.el" (0 0 0 0)) -;;; Generated autoloads from magit-subtree.el - (autoload 'magit-subtree "magit-subtree" nil t) - (autoload 'magit-subtree-import "magit-subtree" nil t) - (autoload 'magit-subtree-export "magit-subtree" nil t) - -(autoload 'magit-subtree-add "magit-subtree" "\ -Add REF from REPOSITORY as a new subtree at PREFIX. - -\(fn PREFIX REPOSITORY REF ARGS)" t nil) - -(autoload 'magit-subtree-add-commit "magit-subtree" "\ -Add COMMIT as a new subtree at PREFIX. - -\(fn PREFIX COMMIT ARGS)" t nil) - -(autoload 'magit-subtree-merge "magit-subtree" "\ -Merge COMMIT into the PREFIX subtree. - -\(fn PREFIX COMMIT ARGS)" t nil) - -(autoload 'magit-subtree-pull "magit-subtree" "\ -Pull REF from REPOSITORY into the PREFIX subtree. - -\(fn PREFIX REPOSITORY REF ARGS)" t nil) - -(autoload 'magit-subtree-push "magit-subtree" "\ -Extract the history of the subtree PREFIX and push it to REF on REPOSITORY. - -\(fn PREFIX REPOSITORY REF ARGS)" t nil) - -(autoload 'magit-subtree-split "magit-subtree" "\ -Extract the history of the subtree PREFIX. - -\(fn PREFIX COMMIT ARGS)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-subtree" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-tag" "magit-tag.el" (0 0 0 0)) -;;; Generated autoloads from magit-tag.el - (autoload 'magit-tag "magit" nil t) - -(autoload 'magit-tag-create "magit-tag" "\ -Create a new tag with the given NAME at REV. -With a prefix argument annotate the tag. - -\(git tag [--annotate] NAME REV) - -\(fn NAME REV &optional ARGS)" t nil) - -(autoload 'magit-tag-delete "magit-tag" "\ -Delete one or more tags. -If the region marks multiple tags (and nothing else), then offer -to delete those, otherwise prompt for a single tag to be deleted, -defaulting to the tag at point. - -\(git tag -d TAGS) - -\(fn TAGS)" t nil) - -(autoload 'magit-tag-prune "magit-tag" "\ -Offer to delete tags missing locally from REMOTE, and vice versa. - -\(fn TAGS REMOTE-TAGS REMOTE)" t nil) - -(autoload 'magit-tag-release "magit-tag" "\ -Create a release tag. - -Assume that release tags match `magit-release-tag-regexp'. - -First prompt 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. - -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\". - -\(fn TAG MSG &optional ARGS)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-tag" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-transient" "magit-transient.el" (0 0 -;;;;;; 0 0)) -;;; Generated autoloads from magit-transient.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-transient" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-utils" "magit-utils.el" (0 0 0 0)) -;;; Generated autoloads from magit-utils.el - -(autoload 'magit-emacs-Q-command "magit-utils" "\ -Show a shell command that runs an uncustomized Emacs with only Magit loaded. -See info node `(magit)Debugging Tools' for more information." t nil) - -(autoload 'Info-follow-nearest-node--magit-gitman "magit-utils" "\ - - -\(fn FN &optional FORK)" nil nil) - -(advice-add 'Info-follow-nearest-node :around 'Info-follow-nearest-node--magit-gitman) - -(autoload 'org-man-export--magit-gitman "magit-utils" "\ - - -\(fn FN LINK DESCRIPTION FORMAT)" nil nil) - -(advice-add 'org-man-export :around 'org-man-export--magit-gitman) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-utils" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-wip" "magit-wip.el" (0 0 0 0)) -;;; Generated autoloads from magit-wip.el - -(defvar magit-wip-mode nil "\ -Non-nil if Magit-Wip mode is enabled. -See the `magit-wip-mode' command -for a description of this minor mode. -Setting this variable directly does not take effect; -either customize it (see the info node `Easy Customization') -or call the function `magit-wip-mode'.") - -(custom-autoload 'magit-wip-mode "magit-wip" nil) - -(autoload 'magit-wip-mode "magit-wip" "\ -Save uncommitted changes to work-in-progress refs. - -If called interactively, enable Magit-Wip mode if ARG is -positive, and disable it if ARG is zero or negative. If called -from Lisp, also enable the mode if ARG is omitted or nil, and -toggle it if ARG is `toggle'; disable the mode otherwise. - -Whenever appropriate (i.e. when dataloss would be a possibility -otherwise) this mode causes uncommitted changes to be committed -to dedicated work-in-progress refs. - -For historic reasons this mode is implemented on top of four -other `magit-wip-*' modes, which can also be used individually, -if you want finer control over when the wip refs are updated; -but that is discouraged. - -\(fn &optional ARG)" t nil) - -(put 'magit-wip-after-save-mode 'globalized-minor-mode t) - -(defvar magit-wip-after-save-mode nil "\ -Non-nil if Magit-Wip-After-Save mode is enabled. -See the `magit-wip-after-save-mode' command -for a description of this minor mode. -Setting this variable directly does not take effect; -either customize it (see the info node `Easy Customization') -or call the function `magit-wip-after-save-mode'.") - -(custom-autoload 'magit-wip-after-save-mode "magit-wip" nil) - -(autoload 'magit-wip-after-save-mode "magit-wip" "\ -Toggle Magit-Wip-After-Save-Local mode in all buffers. -With prefix ARG, enable Magit-Wip-After-Save mode if ARG is positive; -otherwise, disable it. If called from Lisp, enable the mode if -ARG is omitted or nil. - -Magit-Wip-After-Save-Local mode is enabled in all buffers where -`magit-wip-after-save-local-mode-turn-on' would do it. -See `magit-wip-after-save-local-mode' for more information on Magit-Wip-After-Save-Local mode. - -\(fn &optional ARG)" t nil) - -(defvar magit-wip-after-apply-mode nil "\ -Non-nil if Magit-Wip-After-Apply mode is enabled. -See the `magit-wip-after-apply-mode' command -for a description of this minor mode.") - -(custom-autoload 'magit-wip-after-apply-mode "magit-wip" nil) - -(autoload 'magit-wip-after-apply-mode "magit-wip" "\ -Commit to work-in-progress refs. - -If called interactively, enable Magit-Wip-After-Apply mode if ARG -is positive, and disable it if ARG is zero or negative. If -called from Lisp, also enable the mode if ARG is omitted or nil, -and toggle it if ARG is `toggle'; disable the mode otherwise. - -After applying a change using any \"apply variant\" -command (apply, stage, unstage, discard, and reverse) commit the -affected files to the current wip refs. For each branch there -may be two wip refs; one contains snapshots of the files as found -in the worktree and the other contains snapshots of the entries -in the index. - -\(fn &optional ARG)" t nil) - -(defvar magit-wip-before-change-mode nil "\ -Non-nil if Magit-Wip-Before-Change mode is enabled. -See the `magit-wip-before-change-mode' command -for a description of this minor mode.") - -(custom-autoload 'magit-wip-before-change-mode "magit-wip" nil) - -(autoload 'magit-wip-before-change-mode "magit-wip" "\ -Commit to work-in-progress refs before certain destructive changes. - -If called interactively, enable Magit-Wip-Before-Change mode if -ARG is positive, and disable it if ARG is zero or negative. If -called from Lisp, also enable the mode if ARG is omitted or nil, -and toggle it if ARG is `toggle'; disable the mode otherwise. - -Before invoking a revert command or an \"apply variant\" -command (apply, stage, unstage, discard, and reverse) commit the -affected tracked files to the current wip refs. For each branch -there may be two wip refs; one contains snapshots of the files -as found in the worktree and the other contains snapshots of the -entries in the index. - -Only changes to files which could potentially be affected by the -command which is about to be called are committed. - -\(fn &optional ARG)" t nil) - -(autoload 'magit-wip-commit-initial-backup "magit-wip" "\ -Before saving, commit current file to a worktree wip ref. - -The user has to add this function to `before-save-hook'. - -Commit the current state of the visited file before saving the -current buffer to that file. This backs up the same version of -the file as `backup-buffer' would, but stores the backup in the -worktree wip ref, which is also used by the various Magit Wip -modes, instead of in a backup file as `backup-buffer' would. - -This function ignores the variables that affect `backup-buffer' -and can be used along-side that function, which is recommended -because this function only backs up files that are tracked in -a Git repository." nil nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-wip" '("magit-"))) - -;;;*** - -;;;### (autoloads nil "magit-worktree" "magit-worktree.el" (0 0 0 -;;;;;; 0)) -;;; Generated autoloads from magit-worktree.el - (autoload 'magit-worktree "magit-worktree" nil t) - -(autoload 'magit-worktree-checkout "magit-worktree" "\ -Checkout BRANCH in a new worktree at PATH. - -\(fn PATH BRANCH)" t nil) - -(autoload 'magit-worktree-branch "magit-worktree" "\ -Create a new BRANCH and check it out in a new worktree at PATH. - -\(fn PATH BRANCH START-POINT &optional FORCE)" t nil) - -(autoload 'magit-worktree-move "magit-worktree" "\ -Move WORKTREE to PATH. - -\(fn WORKTREE PATH)" t nil) - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-worktree" '("magit-"))) - -;;;*** - -;;;### (autoloads nil nil ("magit-core.el" "magit-pkg.el") (0 0 0 -;;;;;; 0)) - -;;;*** - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; coding: utf-8 -;; End: -;;; magit-autoloads.el ends here diff --git a/elpa/magit-20210802.1524/magit-autorevert.el b/elpa/magit-20210802.1524/magit-autorevert.el deleted file mode 100644 index 75e88d8e..00000000 --- a/elpa/magit-20210802.1524/magit-autorevert.el +++ /dev/null @@ -1,268 +0,0 @@ -;;; magit-autorevert.el --- revert buffers when files in repository change -*- lexical-binding: t -*- - -;; 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. - -;; 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-git) - -(require 'autorevert) - -;;; Options - -(defgroup magit-auto-revert nil - "Revert buffers when files in repository change." - :link '(custom-group-link auto-revert) - :link '(info-link "(magit)Automatic Reverting of File-Visiting Buffers") - :group 'auto-revert - :group 'magit-essentials - :group 'magit-modes) - -(defcustom auto-revert-buffer-list-filter nil - "Filter that determines which buffers `auto-revert-buffers' reverts. - -This option is provided by Magit, which also advises -`auto-revert-buffers' to respect it. Magit users who do not turn -on the local mode `auto-revert-mode' themselves, are best served -by setting the value to `magit-auto-revert-repository-buffer-p'. - -However the default is nil, so as not to disturb users who do use -the local mode directly. If you experience delays when running -Magit commands, then you should consider using one of the -predicates provided by Magit - especially if you also use Tramp. - -Users who do turn on `auto-revert-mode' in buffers in which Magit -doesn't do that for them, should likely not use any filter. -Users who turn on `global-auto-revert-mode', do not have to worry -about this option, because it is disregarded if the global mode -is enabled." - :package-version '(magit . "2.4.2") - :group 'auto-revert - :group 'magit-auto-revert - :group 'magit-related - :type '(radio (const :tag "No filter" nil) - (function-item magit-auto-revert-buffer-p) - (function-item magit-auto-revert-repository-buffer-p) - function)) - -(defcustom magit-auto-revert-tracked-only t - "Whether `magit-auto-revert-mode' only reverts tracked files." - :package-version '(magit . "2.4.0") - :group 'magit-auto-revert - :type 'boolean - :set (lambda (var val) - (set var val) - (when (and (bound-and-true-p magit-auto-revert-mode) - (featurep 'magit-autorevert)) - (magit-auto-revert-mode -1) - (magit-auto-revert-mode)))) - -(defcustom magit-auto-revert-immediately t - "Whether Magit reverts buffers immediately. - -If this is non-nil and either `global-auto-revert-mode' or -`magit-auto-revert-mode' is enabled, then Magit immediately -reverts buffers by explicitly calling `auto-revert-buffers' -after running Git for side-effects. - -If `auto-revert-use-notify' is non-nil (and file notifications -are actually supported), then `magit-auto-revert-immediately' -does not have to be non-nil, because the reverts happen -immediately anyway. - -If `magit-auto-revert-immediately' and `auto-revert-use-notify' -are both nil, then reverts happen after `auto-revert-interval' -seconds of user inactivity. That is not desirable." - :package-version '(magit . "2.4.0") - :group 'magit-auto-revert - :type 'boolean) - -;;; Mode - -(defun magit-turn-on-auto-revert-mode-if-desired (&optional file) - (if file - (--when-let (find-buffer-visiting file) - (with-current-buffer it - (magit-turn-on-auto-revert-mode-if-desired))) - (when (and buffer-file-name - (file-readable-p buffer-file-name) - (or (< emacs-major-version 27) - (with-no-warnings - (condition-case nil - (executable-find magit-git-executable t) ; see #3684 - (wrong-number-of-arguments t)))) ; very old 27 built - (magit-toplevel) - (or (not magit-auto-revert-tracked-only) - (magit-file-tracked-p buffer-file-name)) - (not auto-revert-mode) ; see #3014 - (not global-auto-revert-mode)) ; see #3460 - (auto-revert-mode 1)))) - -;;;###autoload -(define-globalized-minor-mode magit-auto-revert-mode auto-revert-mode - magit-turn-on-auto-revert-mode-if-desired - :package-version '(magit . "2.4.0") - :link '(info-link "(magit)Automatic Reverting of File-Visiting Buffers") - :group 'magit-auto-revert - :group 'magit-essentials - ;; - When `global-auto-revert-mode' is enabled, then this mode is - ;; redundant. - ;; - In all other cases enable the mode because if buffers are not - ;; automatically reverted that would make many very common tasks - ;; much more cumbersome. - :init-value (not (or global-auto-revert-mode - noninteractive))) -;; - Unfortunately `:init-value t' only sets the value of the mode -;; variable but does not cause the mode function to be called. -;; - I don't think it works like this on purpose, but since one usually -;; should not enable global modes by default, it is understandable. -;; - If the user has set the variable `magit-auto-revert-mode' to nil -;; after loading magit (instead of doing so before loading magit or -;; by using the function), then we should still respect that setting. -;; - If the user sets one of these variables after loading magit and -;; after `after-init-hook' has run, then that won't have an effect -;; and there is nothing we can do about it. -(defun magit-auto-revert-mode--init-kludge () - "This is an internal kludge to be used on `after-init-hook'. -Do not use this function elsewhere, and don't remove it from -the `after-init-hook'. For more information see the comments -and code surrounding the definition of this function." - (if magit-auto-revert-mode - (let ((start (current-time))) - (magit-message "Turning on magit-auto-revert-mode...") - (magit-auto-revert-mode 1) - (magit-message - "Turning on magit-auto-revert-mode...done%s" - (let ((elapsed (float-time (time-subtract nil start)))) - (if (> elapsed 0.2) - (format " (%.3fs, %s buffers checked)" elapsed - (length (buffer-list))) - "")))) - (magit-auto-revert-mode -1))) -(if after-init-time - ;; Since `after-init-hook' has already been - ;; run, turn the mode on or off right now. - (magit-auto-revert-mode--init-kludge) - ;; By the time the init file has been fully loaded the - ;; values of the relevant variables might have changed. - (add-hook 'after-init-hook #'magit-auto-revert-mode--init-kludge t)) - -(put 'magit-auto-revert-mode 'function-documentation - "Toggle Magit Auto Revert mode. -If called interactively, enable Magit Auto Revert mode if ARG is -positive, and disable it if ARG is zero or negative. If called -from Lisp, also enable the mode if ARG is omitted or nil, and -toggle it if ARG is `toggle'; disable the mode otherwise. - -Magit Auto Revert mode is a global minor mode that reverts -buffers associated with a file that is located inside a Git -repository when the file changes on disk. Use `auto-revert-mode' -to revert a particular buffer. Or use `global-auto-revert-mode' -to revert all file-visiting buffers, not just those that visit -a file located inside a Git repository. - -This global mode works by turning on the buffer-local mode -`auto-revert-mode' at the time a buffer is first created. The -local mode is turned on if the visited file is being tracked in -a Git repository at the time when the buffer is created. - -If `magit-auto-revert-tracked-only' is non-nil (the default), -then only tracked files are reverted. But if you stage a -previously untracked file using `magit-stage', then this mode -notices that. - -Unlike `global-auto-revert-mode', this mode never reverts any -buffers that are not visiting files. - -The behavior of this mode can be customized using the options -in the `autorevert' and `magit-autorevert' groups. - -This function calls the hook `magit-auto-revert-mode-hook'. - -Like nearly every mode, this mode should be enabled or disabled -by calling the respective mode function, the reason being that -changing the state of a mode involves more than merely toggling -a single switch, so setting the mode variable is not enough. -Also, you should not use `after-init-hook' to disable this mode.") - -(defun magit-auto-revert-buffers () - (when (and magit-auto-revert-immediately - (or global-auto-revert-mode - (and magit-auto-revert-mode auto-revert-buffer-list))) - (let ((auto-revert-buffer-list-filter - (or auto-revert-buffer-list-filter - #'magit-auto-revert-repository-buffer-p))) - (auto-revert-buffers)))) - -(defvar magit-auto-revert-toplevel nil) - -(defvar magit-auto-revert-counter 1 - "Incremented each time `auto-revert-buffers' is called.") - -(defun magit-auto-revert-buffer-p (buffer) - "Return non-nil if BUFFER visits a file inside the current repository. -The current repository is the one containing `default-directory'. -If there is no current repository, then return t for any BUFFER." - (magit-auto-revert-repository-buffer-p buffer t)) - -(defun magit-auto-revert-repository-buffer-p (buffer &optional fallback) - "Return non-nil if BUFFER visits a file inside the current repository. -The current repository is the one containing `default-directory'. -If there is no current repository, then return FALLBACK (which -defaults to nil) for any BUFFER." - ;; Call `magit-toplevel' just once per cycle. - (unless (and magit-auto-revert-toplevel - (= (cdr magit-auto-revert-toplevel) - magit-auto-revert-counter)) - (setq magit-auto-revert-toplevel - (cons (or (magit-toplevel) 'no-repo) - magit-auto-revert-counter))) - (let ((top (car magit-auto-revert-toplevel))) - (if (eq top 'no-repo) - fallback - (let ((dir (buffer-local-value 'default-directory buffer))) - (and (equal (file-remote-p dir) - (file-remote-p top)) - ;; ^ `tramp-handle-file-in-directory-p' lacks this optimization. - (file-in-directory-p dir top)))))) - -(defun auto-revert-buffers--buffer-list-filter (fn) - (cl-incf magit-auto-revert-counter) - (if (or global-auto-revert-mode - (not auto-revert-buffer-list) - (not auto-revert-buffer-list-filter)) - (funcall fn) - (let ((auto-revert-buffer-list - (-filter auto-revert-buffer-list-filter - auto-revert-buffer-list))) - (funcall fn)) - (unless auto-revert-timer - (auto-revert-set-timer)))) - -(advice-add 'auto-revert-buffers :around - 'auto-revert-buffers--buffer-list-filter) - -;;; _ -(provide 'magit-autorevert) -;;; magit-autorevert.el ends here diff --git a/elpa/magit-20210802.1524/magit-bisect.el b/elpa/magit-20210802.1524/magit-bisect.el deleted file mode 100644 index 8efe1af3..00000000 --- a/elpa/magit-20210802.1524/magit-bisect.el +++ /dev/null @@ -1,308 +0,0 @@ -;;; magit-bisect.el --- bisect 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. - -;;; Commentary: - -;; Use a binary search to find the commit that introduced a bug. - -;;; Code: - -(require 'magit) - -;;; Options - -(defcustom magit-bisect-show-graph t - "Whether to use `--graph' in the log showing commits yet to be bisected." - :package-version '(magit . "2.8.0") - :group 'magit-status - :type 'boolean) - -(defface magit-bisect-good - '((t :foreground "DarkOliveGreen")) - "Face for good bisect revisions." - :group 'magit-faces) - -(defface magit-bisect-skip - '((t :foreground "DarkGoldenrod")) - "Face for skipped bisect revisions." - :group 'magit-faces) - -(defface magit-bisect-bad - '((t :foreground "IndianRed4")) - "Face for bad bisect revisions." - :group 'magit-faces) - -;;; Commands - -;;;###autoload (autoload 'magit-bisect "magit-bisect" nil t) -(transient-define-prefix magit-bisect () - "Narrow in on the commit that introduced a bug." - :man-page "git-bisect" - [:class transient-subgroups - :if-not magit-bisect-in-progress-p - ["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 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 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) - (user-error "Already bisecting") - (magit-bisect-start-read-args))) - (unless (magit-rev-ancestor-p good bad) - (user-error - "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 args bad good) t)) - -(defun magit-bisect-start-read-args () - (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 () - "After bisecting, cleanup bisection state and return to original `HEAD'." - (interactive) - (magit-confirm 'reset-bisect) - (magit-run-git "bisect" "reset") - (ignore-errors (delete-file (magit-git-dir "BISECT_CMD_OUTPUT")))) - -;;;###autoload -(defun magit-bisect-good () - "While bisecting, mark the current commit as good. -Use this after you have asserted that the commit does not contain -the bug in question." - (interactive) - (magit-git-bisect (or (cadr (magit-bisect-terms)) - (user-error "Not bisecting")))) - -;;;###autoload -(defun magit-bisect-bad () - "While bisecting, mark the current commit as bad. -Use this after you have asserted that the commit does contain the -bug in question." - (interactive) - (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 () - "While bisecting, skip the current commit. -Use this if for some reason the current commit is not a good one -to test. This command lets Git choose a different one." - (interactive) - (magit-git-bisect "skip")) - -;;;###autoload -(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 -begun. In that case it behaves like `git bisect start; git -bisect run'." - (interactive (let ((args (and (not (magit-bisect-in-progress-p)) - (magit-bisect-start-read-args)))) - (cons (read-shell-command "Bisect shell command: ") args))) - (when (and 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) - (unless (or no-assert (magit-bisect-in-progress-p)) - (user-error "Not bisecting")) - (message "Bisecting...") - (magit-with-toplevel - (magit-run-git-async "bisect" subcommand args)) - (set-process-sentinel - magit-this-process - (lambda (process event) - (when (memq (process-status process) '(exit signal)) - (if (> (process-exit-status process) 0) - (magit-process-sentinel process event) - (process-put process 'inhibit-refresh t) - (magit-process-sentinel process event) - (when (buffer-live-p (process-buffer process)) - (with-current-buffer (process-buffer process) - (when-let ((section (get-text-property (point) 'magit-section)) - (output (buffer-substring-no-properties - (oref section content) - (oref section end)))) - (with-temp-file (magit-git-dir "BISECT_CMD_OUTPUT") - (insert output))))) - (magit-refresh)) - (message "Bisecting...done"))))) - -;;; Sections - -(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) - (let* ((lines - (or (magit-file-lines (magit-git-dir "BISECT_CMD_OUTPUT")) - (list "Bisecting: (no saved bisect output)" - "It appears you have invoked `git bisect' from a shell." - "There is nothing wrong with that, we just cannot display" - "anything useful here. Consult the shell output instead."))) - (done-re "^\\([a-z0-9]\\{40\\}\\) is the first bad commit$") - (bad-line (or (and (string-match done-re (car lines)) - (pop lines)) - (--first (string-match done-re it) lines)))) - (magit-insert-section ((eval (if bad-line 'commit 'bisect-output)) - (and bad-line (match-string 1 bad-line))) - (magit-insert-heading - (propertize (or bad-line (pop lines)) - 'font-lock-face 'magit-section-heading)) - (dolist (line lines) - (insert line "\n")))) - (insert "\n"))) - -(defun magit-insert-bisect-rest () - "While bisecting, insert section visualizing the bisect state." - (when (magit-bisect-in-progress-p) - (magit-insert-section (bisect-view) - (magit-insert-heading "Bisect Rest:") - (magit-git-wash (apply-partially 'magit-log-wash-log 'bisect-vis) - "bisect" "visualize" "git" "log" - "--format=%h%x00%D%x00%s" "--decorate=full" - (and magit-bisect-show-graph "--graph"))))) - -(defun magit-insert-bisect-log () - "While bisecting, insert section logging bisect progress." - (when (magit-bisect-in-progress-p) - (magit-insert-section (bisect-log) - (magit-insert-heading "Bisect Log:") - (magit-git-wash #'magit-wash-bisect-log "bisect" "log") - (insert ?\n)))) - -(defun magit-wash-bisect-log (_args) - (let (beg) - (while (progn (setq beg (point-marker)) - (re-search-forward "^\\(git bisect [^\n]+\n\\)" nil t)) - (magit-bind-match-strings (heading) nil - (magit-delete-match) - (save-restriction - (narrow-to-region beg (point)) - (goto-char (point-min)) - (magit-insert-section (bisect-item heading t) - (insert (propertize heading 'font-lock-face - 'magit-section-secondary-heading)) - (magit-insert-heading) - (magit-wash-sequence - (apply-partially 'magit-log-wash-rev 'bisect-log - (magit-abbrev-length))) - (insert ?\n))))) - (when (re-search-forward - "# first bad commit: \\[\\([a-z0-9]\\{40\\}\\)\\] [^\n]+\n" nil t) - (magit-bind-match-strings (hash) nil - (magit-delete-match) - (magit-insert-section (bisect-item) - (insert hash " is the first bad commit\n")))))) - -;;; _ -(provide 'magit-bisect) -;;; magit-bisect.el ends here diff --git a/elpa/magit-20210802.1524/magit-blame.el b/elpa/magit-20210802.1524/magit-blame.el deleted file mode 100644 index 91e71a0c..00000000 --- a/elpa/magit-20210802.1524/magit-blame.el +++ /dev/null @@ -1,947 +0,0 @@ -;;; magit-blame.el --- blame support for Magit -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; Annotates each line in file-visiting buffer with information from -;; the revision which last modified the line. - -;;; Code: - -(require 'magit) - -;;; Options - -(defgroup magit-blame nil - "Blame support for Magit." - :link '(info-link "(magit)Blaming") - :group 'magit-modes) - -(defcustom magit-blame-styles - '((headings - (heading-format . "%-20a %C %s\n")) - (margin - (margin-format . (" %s%f" " %C %a" " %H")) - (margin-width . 42) - (margin-face . magit-blame-margin) - (margin-body-face . (magit-blame-dimmed))) - (highlight - (highlight-face . magit-blame-highlight)) - (lines - (show-lines . t) - (show-message . t))) - "List of styles used to visualize blame information. - -Each entry has the form (IDENT (KEY . VALUE)...). IDENT has -to be a symbol uniquely identifying the style. The following -KEYs are recognized: - - `show-lines' - Whether to prefix each chunk of lines with a thin line. - This has no effect if `heading-format' is non-nil. - `show-message' - Whether to display a commit's summary line in the echo area - when crossing chunks. - `highlight-face' - Face used to highlight the first line of each chunk. - If this is nil, then those lines are not highlighted. - `heading-format' - String specifying the information to be shown above each - chunk of lines. It must end with a newline character. - `margin-format' - String specifying the information to be shown in the left - buffer margin. It must NOT end with a newline character. - This can also be a list of formats used for the lines at - the same positions within the chunk. If the chunk has - more lines than formats are specified, then the last is - repeated. - `margin-width' - Width of the margin, provided `margin-format' is non-nil. - `margin-face' - Face used in the margin, provided `margin-format' is - non-nil. This face is used in combination with the faces - that are specific to the used %-specs. If this is nil, - then `magit-blame-margin' is used. - `margin-body-face' - Face used in the margin for all but first line of a chunk. - This face is used in combination with the faces that are - specific to the used %-specs. This can also be a list of - faces (usually one face), in which case only these faces - are used and the %-spec faces are ignored. A good value - might be `(magit-blame-dimmed)'. If this is nil, then - the same face as for the first line is used. - -The following %-specs can be used in `heading-format' and -`margin-format': - - %H hash using face `magit-blame-hash' - %s summary using face `magit-blame-summary' - %a author using face `magit-blame-name' - %A author time using face `magit-blame-date' - %c committer using face `magit-blame-name' - %C committer time using face `magit-blame-date' - -Additionally if `margin-format' ends with %f, then the string -that is displayed in the margin is made at least `margin-width' -characters wide, which may be desirable if the used face sets -the background color. - -The style used in the current buffer can be cycled from the blame -popup. Blame commands (except `magit-blame-echo') use the first -style as the initial style when beginning to blame in a buffer." - :package-version '(magit . "2.13.0") - :group 'magit-blame - :type 'string) - -(defcustom magit-blame-echo-style 'lines - "The blame visualization style used by `magit-blame-echo'. -A symbol that has to be used as the identifier for one of the -styles defined in `magit-blame-styles'." - :package-version '(magit . "2.13.0") - :group 'magit-blame - :type 'symbol) - -(defcustom magit-blame-time-format "%F %H:%M" - "Format for time strings in blame headings." - :group 'magit-blame - :type 'string) - -(defcustom magit-blame-read-only t - "Whether to initially make the blamed buffer read-only." - :package-version '(magit . "2.13.0") - :group 'magit-blame - :type 'boolean) - -(defcustom magit-blame-disable-modes '(fci-mode yascroll-bar-mode) - "List of modes not compatible with Magit-Blame mode. -This modes are turned off when Magit-Blame mode is turned on, -and then turned on again when turning off the latter." - :group 'magit-blame - :type '(repeat (symbol :tag "Mode"))) - -(defcustom magit-blame-mode-lighter " Blame" - "The mode-line lighter of the Magit-Blame mode." - :group 'magit-blame - :type '(choice (const :tag "No lighter" "") string)) - -(defcustom magit-blame-goto-chunk-hook - '(magit-blame-maybe-update-revision-buffer - magit-blame-maybe-show-message) - "Hook run after point entered another chunk." - :package-version '(magit . "2.13.0") - :group 'magit-blame - :type 'hook - :get 'magit-hook-custom-get - :options '(magit-blame-maybe-update-revision-buffer - magit-blame-maybe-show-message)) - -;;; Faces - -(defface magit-blame-highlight - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "grey80" - :foreground "black") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "grey25" - :foreground "white")) - "Face used for highlighting when blaming. -Also see option `magit-blame-styles'." - :group 'magit-faces) - -(defface magit-blame-margin - '((t :inherit magit-blame-highlight - :weight normal - :slant normal)) - "Face used for the blame margin by default when blaming. -Also see option `magit-blame-styles'." - :group 'magit-faces) - -(defface magit-blame-dimmed - '((t :inherit magit-dimmed - :weight normal - :slant normal)) - "Face used for the blame margin in some cases when blaming. -Also see option `magit-blame-styles'." - :group 'magit-faces) - -(defface magit-blame-heading - `((t ,@(and (>= emacs-major-version 27) '(:extend t)) - :inherit magit-blame-highlight - :weight normal - :slant normal)) - "Face used for blame headings by default when blaming. -Also see option `magit-blame-styles'." - :group 'magit-faces) - -(defface magit-blame-summary nil - "Face used for commit summaries when blaming." - :group 'magit-faces) - -(defface magit-blame-hash nil - "Face used for commit hashes when blaming." - :group 'magit-faces) - -(defface magit-blame-name nil - "Face used for author and committer names when blaming." - :group 'magit-faces) - -(defface magit-blame-date nil - "Face used for dates when blaming." - :group 'magit-faces) - -;;; Chunks - -(defclass magit-blame-chunk () - (;; - (orig-rev :initarg :orig-rev) - (orig-line :initarg :orig-line) - (final-line :initarg :final-line) - (num-lines :initarg :num-lines) - ;; previous - (prev-rev :initform nil) - (prev-file :initform nil) - ;; filename - (orig-file))) - -(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)))) - (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) - (overlays-at pos))) - -(defun magit-blame--overlay-at (&optional pos key) - (unless pos - (setq pos (point))) - (--first (overlay-get it (or key 'magit-blame-chunk)) - (nconc (overlays-at pos) - (overlays-in pos pos)))) - -;;; Keymaps - -(defvar magit-blame-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "C-c C-q") 'magit-blame-quit) - map) - "Keymap for `magit-blame-mode'. -Note that most blaming key bindings are defined -in `magit-blame-read-only-mode-map' instead.") - -(defvar magit-blame-read-only-mode-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd "C-m") 'magit-show-commit) - (define-key map (kbd "p") 'magit-blame-previous-chunk) - (define-key map (kbd "P") 'magit-blame-previous-chunk-same-commit) - (define-key map (kbd "n") 'magit-blame-next-chunk) - (define-key map (kbd "N") 'magit-blame-next-chunk-same-commit) - (define-key map (kbd "b") 'magit-blame-addition) - (define-key map (kbd "r") 'magit-blame-removal) - (define-key map (kbd "f") 'magit-blame-reverse) - (define-key map (kbd "B") 'magit-blame) - (define-key map (kbd "c") 'magit-blame-cycle-style) - (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'.") - -;;; Modes -;;;; Variables - -(defvar-local magit-blame-buffer-read-only nil) -(defvar-local magit-blame-cache nil) -(defvar-local magit-blame-disabled-modes nil) -(defvar-local magit-blame-process nil) -(defvar-local magit-blame-recursive-p nil) -(defvar-local magit-blame-type nil) -(defvar-local magit-blame-separator nil) -(defvar-local magit-blame-previous-chunk nil) - -(defvar-local magit-blame--style nil) - -(defsubst magit-blame--style-get (key) - (cdr (assoc key (cdr magit-blame--style)))) - -;;;; Base Mode - -(define-minor-mode magit-blame-mode - "Display blame information inline." - :lighter magit-blame-mode-lighter - (cond (magit-blame-mode - (when (called-interactively-p 'any) - (setq magit-blame-mode nil) - (user-error - (concat "Don't call `magit-blame-mode' directly; " - "instead use `magit-blame'"))) - (add-hook 'after-save-hook 'magit-blame--refresh t t) - (add-hook 'post-command-hook 'magit-blame-goto-chunk-hook t t) - (add-hook 'before-revert-hook 'magit-blame--remove-overlays t t) - (add-hook 'after-revert-hook 'magit-blame--refresh t t) - (add-hook 'read-only-mode-hook 'magit-blame-toggle-read-only t t) - (setq magit-blame-buffer-read-only buffer-read-only) - (when (or magit-blame-read-only magit-buffer-file-name) - (read-only-mode 1)) - (dolist (mode magit-blame-disable-modes) - (when (and (boundp mode) (symbol-value mode)) - (funcall mode -1) - (push mode magit-blame-disabled-modes))) - (setq magit-blame-separator (magit-blame--format-separator)) - (unless magit-blame--style - (setq magit-blame--style (car magit-blame-styles))) - (magit-blame--update-margin)) - (t - (when (process-live-p magit-blame-process) - (kill-process magit-blame-process) - (while magit-blame-process - (sit-for 0.01))) ; avoid racing the sentinel - (remove-hook 'after-save-hook 'magit-blame--refresh t) - (remove-hook 'post-command-hook 'magit-blame-goto-chunk-hook t) - (remove-hook 'before-revert-hook 'magit-blame--remove-overlays t) - (remove-hook 'after-revert-hook 'magit-blame--refresh t) - (remove-hook 'read-only-mode-hook 'magit-blame-toggle-read-only t) - (unless magit-blame-buffer-read-only - (read-only-mode -1)) - (magit-blame-read-only-mode -1) - (dolist (mode magit-blame-disabled-modes) - (funcall mode 1)) - (kill-local-variable 'magit-blame-disabled-modes) - (kill-local-variable 'magit-blame-type) - (kill-local-variable 'magit-blame--style) - (magit-blame--update-margin) - (magit-blame--remove-overlays)))) - -(defun magit-blame--refresh () - (magit-blame--run (magit-blame-arguments))) - -(defun magit-blame-goto-chunk-hook () - (let ((chunk (magit-blame-chunk-at (point)))) - (when (cl-typep chunk 'magit-blame-chunk) - (unless (eq chunk magit-blame-previous-chunk) - (run-hooks 'magit-blame-goto-chunk-hook)) - (setq magit-blame-previous-chunk chunk)))) - -(defun magit-blame-toggle-read-only () - (magit-blame-read-only-mode (if buffer-read-only 1 -1))) - -;;;; Read-Only Mode - -(define-minor-mode magit-blame-read-only-mode - "Provide keybindings for Magit-Blame mode. - -This minor-mode provides the key bindings for Magit-Blame mode, -but only when Read-Only mode is also enabled because these key -bindings would otherwise conflict badly with regular bindings. - -When both Magit-Blame mode and Read-Only mode are enabled, then -this mode gets automatically enabled too and when one of these -modes is toggled, then this mode also gets toggled automatically. - -\\{magit-blame-read-only-mode-map}") - -;;;; Kludges - -(defun magit-blame-put-keymap-before-view-mode () - "Put `magit-blame-read-only-mode' ahead of `view-mode' in `minor-mode-map-alist'." - (--when-let (assq 'magit-blame-read-only-mode - (cl-member 'view-mode minor-mode-map-alist :key #'car)) - (setq minor-mode-map-alist - (cons it (delq it minor-mode-map-alist)))) - (remove-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode)) - -(add-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode) - -;;; Process - -(defun magit-blame--run (args) - (magit-with-toplevel - (unless magit-blame-mode - (magit-blame-mode 1)) - (message "Blaming...") - (magit-blame-run-process - (or magit-buffer-refname magit-buffer-revision) - (magit-file-relative-name nil (not magit-buffer-file-name)) - (if (memq magit-blame-type '(final removal)) - (cons "--reverse" args) - args) - (list (line-number-at-pos (window-start)) - (line-number-at-pos (1- (window-end nil t))))) - (set-process-sentinel magit-this-process - 'magit-blame-process-quickstart-sentinel))) - -(defun magit-blame-run-process (revision file args &optional lines) - (let ((process (magit-parse-git-async - "blame" "--incremental" args - (and lines (list "-L" (apply #'format "%s,%s" lines))) - revision "--" file))) - (set-process-filter process 'magit-blame-process-filter) - (set-process-sentinel process 'magit-blame-process-sentinel) - (process-put process 'arguments (list revision file args)) - (setq magit-blame-cache (make-hash-table :test 'equal)) - (setq magit-blame-process process))) - -(defun magit-blame-process-quickstart-sentinel (process event) - (when (memq (process-status process) '(exit signal)) - (magit-blame-process-sentinel process event t) - (magit-blame-assert-buffer process) - (with-current-buffer (process-get process 'command-buf) - (when magit-blame-mode - (let ((default-directory (magit-toplevel))) - (apply #'magit-blame-run-process - (process-get process 'arguments))))))) - -(defun magit-blame-process-sentinel (process _event &optional quiet) - (let ((status (process-status process))) - (when (memq status '(exit signal)) - (kill-buffer (process-buffer process)) - (if (and (eq status 'exit) - (zerop (process-exit-status process))) - (unless quiet - (message "Blaming...done")) - (magit-blame-assert-buffer process) - (with-current-buffer (process-get process 'command-buf) - (if magit-blame-mode - (progn (magit-blame-mode -1) - (message "Blaming...failed")) - (message "Blaming...aborted")))) - (kill-local-variable 'magit-blame-process)))) - -(defun magit-blame-process-filter (process string) - (internal-default-process-filter process string) - (let ((buf (process-get process 'command-buf)) - (pos (process-get process 'parsed)) - (mark (process-mark process)) - type cache) - (with-current-buffer buf - (setq type magit-blame-type) - (setq cache magit-blame-cache)) - (with-current-buffer (process-buffer process) - (goto-char pos) - (while (and (< (point) mark) - (save-excursion (re-search-forward "^filename .+\n" nil t))) - (pcase-let* ((`(,chunk ,revinfo) - (magit-blame--parse-chunk type)) - (rev (oref chunk orig-rev))) - (if revinfo - (puthash rev revinfo cache) - (setq revinfo - (or (gethash rev cache) - (puthash rev (magit-blame--commit-alist rev) cache)))) - (magit-blame--make-overlays buf chunk revinfo)) - (process-put process 'parsed (point)))))) - -(defun magit-blame--parse-chunk (type) - (let (chunk revinfo) - (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) - :orig-line (string-to-number (match-string 2)) - :final-line (string-to-number (match-string 3)) - :num-lines (string-to-number (match-string 4)))) - (forward-line) - (let (done) - (while (not done) - (cond ((looking-at "^filename \\(.+\\)") - (setq done t) - (setf orig-file (magit-decode-git-path (match-string 1)))) - ((looking-at "^previous \\(.\\{40\\}\\) \\(.+\\)") - (setf prev-rev (match-string 1)) - (setf prev-file (magit-decode-git-path (match-string 2)))) - ((looking-at "^\\([^ ]+\\) \\(.+\\)") - (push (cons (match-string 1) - (match-string 2)) revinfo))) - (forward-line))) - (when (and (eq type 'removal) prev-rev) - (cl-rotatef orig-rev prev-rev) - (cl-rotatef orig-file prev-file) - (setq revinfo nil))) - (list chunk revinfo))) - -(defun magit-blame--commit-alist (rev) - (cl-mapcar 'cons - '("summary" - "author" "author-time" "author-tz" - "committer" "committer-time" "committer-tz") - (split-string (magit-rev-format "%s\v%an\v%ad\v%cn\v%cd" rev - "--date=format:%s\v%z") - "\v"))) - -(defun magit-blame-assert-buffer (process) - (unless (buffer-live-p (process-get process 'command-buf)) - (kill-process process) - (user-error "Buffer being blamed has been killed"))) - -;;; Display - -(defun magit-blame--make-overlays (buf chunk revinfo) - (with-current-buffer buf - (save-excursion - (save-restriction - (widen) - (goto-char (point-min)) - (forward-line (1- (oref chunk final-line))) - (let ((beg (point)) - (end (save-excursion - (forward-line (oref chunk num-lines)) - (point)))) - (magit-blame--remove-overlays beg end) - (magit-blame--make-margin-overlays chunk revinfo beg end) - (magit-blame--make-heading-overlay chunk revinfo beg end) - (magit-blame--make-highlight-overlay chunk beg)))))) - -(defun magit-blame--make-margin-overlays (chunk revinfo _beg end) - (save-excursion - (let ((line 0)) - (while (< (point) end) - (magit-blame--make-margin-overlay chunk revinfo line) - (forward-line) - (cl-incf line))))) - -(defun magit-blame--make-margin-overlay (chunk revinfo line) - (let* ((end (line-end-position)) - ;; If possible avoid putting this on the first character - ;; of the line to avoid a conflict with the line overlay. - (beg (min (1+ (line-beginning-position)) end)) - (ov (make-overlay beg end))) - (overlay-put ov 'magit-blame-chunk chunk) - (overlay-put ov 'magit-blame-revinfo revinfo) - (overlay-put ov 'magit-blame-margin line) - (magit-blame--update-margin-overlay ov))) - -(defun magit-blame--make-heading-overlay (chunk revinfo beg end) - (let ((ov (make-overlay beg end))) - (overlay-put ov 'magit-blame-chunk chunk) - (overlay-put ov 'magit-blame-revinfo revinfo) - (overlay-put ov 'magit-blame-heading t) - (magit-blame--update-heading-overlay ov))) - -(defun magit-blame--make-highlight-overlay (chunk beg) - (let ((ov (make-overlay beg (1+ (line-end-position))))) - (overlay-put ov 'magit-blame-chunk chunk) - (overlay-put ov 'magit-blame-highlight t) - (magit-blame--update-highlight-overlay ov))) - -(defun magit-blame--update-margin () - (setq left-margin-width (or (magit-blame--style-get 'margin-width) 0)) - (set-window-buffer (selected-window) (current-buffer))) - -(defun magit-blame--update-overlays () - (save-restriction - (widen) - (dolist (ov (overlays-in (point-min) (point-max))) - (cond ((overlay-get ov 'magit-blame-heading) - (magit-blame--update-heading-overlay ov)) - ((overlay-get ov 'magit-blame-margin) - (magit-blame--update-margin-overlay ov)) - ((overlay-get ov 'magit-blame-highlight) - (magit-blame--update-highlight-overlay ov)))))) - -(defun magit-blame--update-margin-overlay (ov) - (overlay-put - ov 'before-string - (and (magit-blame--style-get 'margin-width) - (propertize - "o" 'display - (list (list 'margin 'left-margin) - (let ((line (overlay-get ov 'magit-blame-margin)) - (format (magit-blame--style-get 'margin-format)) - (face (magit-blame--style-get 'margin-face))) - (magit-blame--format-string - ov - (or (and (atom format) - format) - (nth line format) - (car (last format))) - (or (and (not (zerop line)) - (magit-blame--style-get 'margin-body-face)) - face - 'magit-blame-margin)))))))) - -(defun magit-blame--update-heading-overlay (ov) - (overlay-put - ov 'before-string - (--if-let (magit-blame--style-get 'heading-format) - (magit-blame--format-string ov it 'magit-blame-heading) - (and (magit-blame--style-get 'show-lines) - (or (not (magit-blame--style-get 'margin-format)) - (save-excursion - (goto-char (overlay-start ov)) - ;; Special case of the special case described in - ;; `magit-blame--make-margin-overlay'. For empty - ;; lines it is not possible to show both overlays - ;; without the line being to high. - (not (= (point) (line-end-position))))) - magit-blame-separator)))) - -(defun magit-blame--update-highlight-overlay (ov) - (overlay-put ov 'font-lock-face (magit-blame--style-get 'highlight-face))) - -(defun magit-blame--format-string (ov format face) - (let* ((chunk (overlay-get ov 'magit-blame-chunk)) - (revinfo (overlay-get ov 'magit-blame-revinfo)) - (key (list format face)) - (string (cdr (assoc key revinfo)))) - (unless string - (setq string - (and format - (magit-blame--format-string-1 (oref chunk orig-rev) - revinfo format face))) - (nconc revinfo (list (cons key string)))) - string)) - -(defun magit-blame--format-string-1 (rev revinfo format face) - (let ((str - (if (equal rev "0000000000000000000000000000000000000000") - (propertize (concat (if (string-prefix-p "\s" format) "\s" "") - "Not Yet Committed" - (if (string-suffix-p "\n" format) "\n" "")) - 'font-lock-face face) - (magit--format-spec - (propertize format 'font-lock-face face) - (cl-flet* ((p0 (s f) - (propertize s 'font-lock-face - (if face - (if (listp face) - face - (list f face)) - f))) - (p1 (k f) - (p0 (cdr (assoc k revinfo)) f)) - (p2 (k1 k2 f) - (p0 (magit-blame--format-time-string - (cdr (assoc k1 revinfo)) - (cdr (assoc k2 revinfo))) - f))) - `((?H . ,(p0 rev 'magit-blame-hash)) - (?s . ,(p1 "summary" 'magit-blame-summary)) - (?a . ,(p1 "author" 'magit-blame-name)) - (?c . ,(p1 "committer" 'magit-blame-name)) - (?A . ,(p2 "author-time" "author-tz" 'magit-blame-date)) - (?C . ,(p2 "committer-time" "committer-tz" 'magit-blame-date)) - (?f . ""))))))) - (if-let ((width (and (string-suffix-p "%f" format) - (magit-blame--style-get 'margin-width)))) - (concat str - (propertize (make-string (max 0 (- width (length str))) ?\s) - 'font-lock-face face)) - str))) - -(defun magit-blame--format-separator () - (propertize - (concat (propertize "\s" 'display '(space :height (2))) - (propertize "\n" 'line-height 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) - magit-blame-time-format)) - (tz-in-second (and (string-match "%z" time-format) - (car (last (parse-time-string tz)))))) - (format-time-string time-format - (seconds-to-time (string-to-number time)) - tz-in-second))) - -(defun magit-blame--remove-overlays (&optional beg end) - (save-restriction - (widen) - (dolist (ov (overlays-in (or beg (point-min)) - (or end (point-max)))) - (when (overlay-get ov 'magit-blame-chunk) - (delete-overlay ov))))) - -(defun magit-blame-maybe-show-message () - (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))))) - (progn (set-text-properties 0 (length msg) nil msg) - (message msg)) - (message "Commit data not available yet. Still blaming."))))) - -;;; Commands - -;;;###autoload (autoload 'magit-blame-echo "magit-blame" nil t) -(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 -not turn on `read-only-mode'." - :if (lambda () - (and buffer-file-name - (or (not magit-blame-mode) - buffer-read-only))) - (interactive (list (magit-blame-arguments))) - (when magit-buffer-file-name - (user-error "Blob buffers aren't supported")) - (setq-local magit-blame--style - (assq magit-blame-echo-style magit-blame-styles)) - (setq-local magit-blame-disable-modes - (cons 'eldoc-mode magit-blame-disable-modes)) - (if (not magit-blame-mode) - (let ((magit-blame-read-only nil)) - (magit-blame--pre-blame-assert 'addition) - (magit-blame--pre-blame-setup 'addition) - (magit-blame--run args)) - (read-only-mode -1) - (magit-blame--update-overlays))) - -;;;###autoload (autoload 'magit-blame-addition "magit-blame" nil t) -(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) - (magit-blame--pre-blame-setup 'addition) - (magit-blame--run args)) - -;;;###autoload (autoload 'magit-blame-removal "magit-blame" nil t) -(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))) - (unless magit-buffer-file-name - (user-error "Only blob buffers can be blamed in reverse")) - (magit-blame--pre-blame-assert 'removal) - (magit-blame--pre-blame-setup 'removal) - (magit-blame--run args)) - -;;;###autoload (autoload 'magit-blame-reverse "magit-blame" nil t) -(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))) - (unless magit-buffer-file-name - (user-error "Only blob buffers can be blamed in reverse")) - (magit-blame--pre-blame-assert 'final) - (magit-blame--pre-blame-setup 'final) - (magit-blame--run args)) - -(defun magit-blame--pre-blame-assert (type) - (unless (magit-toplevel) - (magit--not-inside-repository-error)) - (if (and magit-blame-mode - (eq type magit-blame-type)) - (if-let ((chunk (magit-current-blame-chunk))) - (unless (oref chunk prev-rev) - (user-error "Chunk has no further history")) - (user-error "Commit data not available yet. Still blaming.")) - (unless (magit-file-relative-name nil (not magit-buffer-file-name)) - (if buffer-file-name - (user-error "Buffer isn't visiting a tracked file") - (user-error "Buffer isn't visiting a file"))))) - -(defun magit-blame--pre-blame-setup (type) - (when magit-blame-mode - (if (eq type magit-blame-type) - (let ((style magit-blame--style)) - (magit-blame-visit-other-file) - (setq-local magit-blame--style style) - (setq-local magit-blame-recursive-p t) - ;; Set window-start for the benefit of quickstart. - (redisplay)) - (magit-blame--remove-overlays))) - (setq magit-blame-type type)) - -(defun magit-blame-visit-other-file () - "Visit another blob related to the current chunk." - (interactive) - (with-slots (prev-rev prev-file orig-line) - (magit-current-blame-chunk) - (unless prev-rev - (user-error "Chunk has no further history")) - (magit-with-toplevel - (magit-find-file prev-rev prev-file)) - ;; TODO Adjust line like magit-diff-visit-file. - (goto-char (point-min)) - (forward-line (1- orig-line)))) - -(defun magit-blame-visit-file () - "Visit the blob related to the current chunk." - (interactive) - (with-slots (orig-rev orig-file orig-line) - (magit-current-blame-chunk) - (magit-with-toplevel - (magit-find-file orig-rev orig-file)) - (goto-char (point-min)) - (forward-line (1- orig-line)))) - -(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." - :if-non-nil 'magit-blame-mode - (interactive) - (magit-blame-mode -1) - (when magit-blame-recursive-p - (kill-buffer))) - -(defun magit-blame-next-chunk () - "Move to the next chunk." - (interactive) - (--if-let (next-single-char-property-change (point) 'magit-blame-chunk) - (goto-char it) - (user-error "No more chunks"))) - -(defun magit-blame-previous-chunk () - "Move to the previous chunk." - (interactive) - (--if-let (previous-single-char-property-change (point) 'magit-blame-chunk) - (goto-char it) - (user-error "No more chunks"))) - -(defun magit-blame-next-chunk-same-commit (&optional previous) - "Move to the next chunk from the same commit.\n\n(fn)" - (interactive) - (if-let ((rev (oref (magit-current-blame-chunk) orig-rev))) - (let ((pos (point)) ov) - (save-excursion - (while (and (not ov) - (not (= pos (if previous (point-min) (point-max)))) - (setq pos (funcall - (if previous - 'previous-single-char-property-change - 'next-single-char-property-change) - pos 'magit-blame-chunk))) - (--when-let (magit-blame--overlay-at pos) - (when (equal (oref (magit-blame-chunk-at pos) orig-rev) rev) - (setq ov it))))) - (if ov - (goto-char (overlay-start ov)) - (user-error "No more chunks from same commit"))) - (user-error "This chunk hasn't been blamed yet"))) - -(defun magit-blame-previous-chunk-same-commit () - "Move to the previous chunk from the same commit." - (interactive) - (magit-blame-next-chunk-same-commit 'previous-single-char-property-change)) - -(defun magit-blame-cycle-style () - "Change how blame information is visualized. -Cycle through the elements of option `magit-blame-styles'." - (interactive) - (setq magit-blame--style - (or (cadr (cl-member (car magit-blame--style) - magit-blame-styles :key #'car)) - (car magit-blame-styles))) - (magit-blame--update-margin) - (magit-blame--update-overlays)) - -(defun magit-blame-copy-hash () - "Save hash of the current chunk's commit to the kill ring. - -When the region is active, then save the region's content -instead of the hash, like `kill-ring-save' would." - (interactive) - (if (use-region-p) - (call-interactively #'copy-region-as-kill) - (kill-new (message "%s" (oref (magit-current-blame-chunk) orig-rev))))) - -;;; Popup - -;;;###autoload (autoload 'magit-blame "magit-blame" nil t) -(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" - ("b" "Show commits adding lines" magit-blame-addition) - ("r" "Show commits removing lines" magit-blame-removal) - ("f" "Show last commits that still have lines" magit-blame-reverse) - ("m" "Blame echo" magit-blame-echo) - ("q" "Quit blaming" magit-blame-quit)] - ["Refresh" - :if-non-nil magit-blame-mode - ("c" "Cycle style" magit-blame-cycle-style :transient t)]) - -(defun magit-blame-arguments () - (transient-args 'magit-blame)) - -(transient-define-argument magit-blame:-M () - :description "Detect lines moved or copied within a file" - :class 'transient-option - :argument "-M" - :reader 'transient-read-number-N+) - -(transient-define-argument magit-blame:-C () - :description "Detect lines moved or copied between files" - :class 'transient-option - :argument "-C" - :reader 'transient-read-number-N+) - -;;; Utilities - -(defun magit-blame-maybe-update-revision-buffer () - (when-let ((chunk (magit-current-blame-chunk)) - (commit (oref chunk orig-rev)) - (buffer (magit-get-mode-buffer 'magit-revision-mode nil t))) - (if magit--update-revision-buffer - (setq magit--update-revision-buffer (list commit buffer)) - (setq magit--update-revision-buffer (list commit buffer)) - (run-with-idle-timer - magit-update-other-window-delay nil - (lambda () - (pcase-let ((`(,rev ,buf) magit--update-revision-buffer)) - (setq magit--update-revision-buffer nil) - (when (buffer-live-p buf) - (let ((magit-display-buffer-noselect t)) - (apply #'magit-show-commit rev - (magit-diff-arguments 'magit-revision-mode)))))))))) - -;;; _ -(provide 'magit-blame) -;;; magit-blame.el ends here diff --git a/elpa/magit-20210802.1524/magit-bookmark.el b/elpa/magit-20210802.1524/magit-bookmark.el deleted file mode 100644 index 22f022e6..00000000 --- a/elpa/magit-20210802.1524/magit-bookmark.el +++ /dev/null @@ -1,209 +0,0 @@ -;;; magit-bookmark.el --- bookmark support for Magit -*- lexical-binding: t -*- - -;; 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. - -;; Author: Jonas Bernoulli -;; Maintainer: Jonas Bernoulli - -;; 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) -;; 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. - -;;; Commentary: - -;; Support for bookmarks for most Magit buffers. - -;;; Code: - -(require 'magit) -(require 'bookmark) - -;;; Core - -(defun magit--make-bookmark () - "Create a bookmark for the current Magit buffer. -Input values are the major-mode's `magit-bookmark-name' method, -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) - ;; `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)) - (bookmark-prop-set bookmark 'defaults (list (magit-bookmark-name))) - (dolist (var (get major-mode 'magit-bookmark-variables)) - (bookmark-prop-set bookmark var (symbol-value var))) - (bookmark-prop-set - bookmark 'magit-hidden-sections - (--keep (and (oref it hidden) - (cons (oref it type) - (if (derived-mode-p 'magit-stash-mode) - (replace-regexp-in-string - (regexp-quote magit-buffer-revision) - magit-buffer-revision-hash - (oref it value)) - (oref it value)))) - (oref magit-root-section children))) - bookmark) - (user-error "Bookmarking is not implemented for %s buffers" major-mode))) - -;;;###autoload -(defun magit--handle-bookmark (bookmark) - "Open a bookmark created by `magit--make-bookmark'. -Call the `magit-*-setup-buffer' function of the the major-mode -with the variables' values as arguments, which were recorded by -`magit--make-bookmark'. Ignore `magit-display-buffer-function'." - (let ((buffer (let ((default-directory (bookmark-get-filename bookmark)) - (mode (bookmark-prop-get bookmark 'mode)) - (magit-display-buffer-function #'identity) - (magit-display-buffer-noselect t)) - (apply (intern (format "%s-setup-buffer" - (substring (symbol-name mode) 0 -5))) - (--map (bookmark-prop-get bookmark it) - (get mode 'magit-bookmark-variables)))))) - (set-buffer buffer) ; That is the interface we have to adhere to. - (when-let ((hidden (bookmark-prop-get bookmark 'magit-hidden-sections))) - (with-current-buffer buffer - (dolist (child (oref magit-root-section children)) - (if (member (cons (oref child type) - (oref child value)) - 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 () - "Return name for bookmark to current buffer." - (format "%s%s" - (substring (symbol-name major-mode) 0 -5) - (if-let ((vars (get major-mode 'magit-bookmark-variables))) - (cl-mapcan (lambda (var) - (let ((val (symbol-value var))) - (if (and val (atom val)) - (list val) - val))) - vars) - ""))) - -;;; Diff -;;;; Diff - -(put 'magit-diff-mode 'magit-bookmark-variables - '(magit-buffer-range-hashed - magit-buffer-typearg - magit-buffer-diff-args - magit-buffer-diff-files)) - -(cl-defmethod magit-bookmark-name (&context (major-mode magit-diff-mode)) - (format "magit-diff(%s%s)" - (pcase (magit-diff-type) - (`staged "staged") - (`unstaged "unstaged") - (`committed magit-buffer-range) - (`undefined - (delq nil (list magit-buffer-typearg magit-buffer-range-hashed)))) - (if magit-buffer-diff-files - (concat " -- " (mapconcat #'identity magit-buffer-diff-files " ")) - ""))) - -;;;; Revision - -(put 'magit-revision-mode 'magit-bookmark-variables - '(magit-buffer-revision-hash - magit-buffer-diff-args - magit-buffer-diff-files)) - -(cl-defmethod magit-bookmark-name (&context (major-mode magit-revision-mode)) - (format "magit-revision(%s %s)" - (magit-rev-abbrev magit-buffer-revision) - (if magit-buffer-diff-files - (mapconcat #'identity magit-buffer-diff-files " ") - (magit-rev-format "%s" magit-buffer-revision)))) - -;;;; Stash - -(put 'magit-stash-mode 'magit-bookmark-variables - '(magit-buffer-revision-hash - magit-buffer-diff-args - magit-buffer-diff-files)) - -(cl-defmethod magit-bookmark-name (&context (major-mode magit-stash-mode)) - (format "magit-stash(%s %s)" - (magit-rev-abbrev magit-buffer-revision) - (if magit-buffer-diff-files - (mapconcat #'identity magit-buffer-diff-files " ") - (magit-rev-format "%s" magit-buffer-revision)))) - -;;; Log -;;;; Log - -(put 'magit-log-mode 'magit-bookmark-variables - '(magit-buffer-revisions - magit-buffer-log-args - magit-buffer-log-files)) - -(cl-defmethod magit-bookmark-name (&context (major-mode magit-log-mode)) - (format "magit-log(%s%s)" - (mapconcat #'identity magit-buffer-revisions " ") - (if magit-buffer-log-files - (concat " -- " (mapconcat #'identity magit-buffer-log-files " ")) - ""))) - -;;;; Cherry - -(put 'magit-cherry-mode 'magit-bookmark-variables - '(magit-buffer-refname - magit-buffer-upstream)) - -(cl-defmethod magit-bookmark-name (&context (major-mode magit-cherry-mode)) - (format "magit-cherry(%s > %s)" - magit-buffer-refname - magit-buffer-upstream)) - -;;;; Reflog - -(put 'magit-reflog-mode 'magit-bookmark-variables - '(magit-buffer-refname)) - -(cl-defmethod magit-bookmark-name (&context (major-mode magit-reflog-mode)) - (format "magit-reflog(%s)" magit-buffer-refname)) - -;;; Misc - -(put 'magit-status-mode 'magit-bookmark-variables nil) - -(put 'magit-refs-mode 'magit-bookmark-variables - '(magit-buffer-upstream - magit-buffer-arguments)) - -(put 'magit-stashes-mode 'magit-bookmark-variables nil) - -(cl-defmethod magit-bookmark-name (&context (major-mode magit-stashes-mode)) - (format "magit-states(%s)" magit-buffer-refname)) - -;;; _ -(provide 'magit-bookmark) -;;; magit-bookmark.el ends here diff --git a/elpa/magit-20210802.1524/magit-branch.el b/elpa/magit-20210802.1524/magit-branch.el deleted file mode 100644 index 1b5f0882..00000000 --- a/elpa/magit-20210802.1524/magit-branch.el +++ /dev/null @@ -1,932 +0,0 @@ -;;; magit-branch.el --- branch support -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements support for branches. It defines commands -;; for creating, checking out, manipulating, and configuring branches. -;; Commands defined here are mainly concerned with branches as -;; pointers, commands that deal with what a branch points at, are -;; defined elsewhere. - -;;; Code: - -(require 'magit) -(require 'magit-reset) - -;;; Options - -(defcustom magit-branch-read-upstream-first t - "Whether to read upstream before name of new branch when creating a branch. - -`nil' Read the branch name first. -`t' Read the upstream first. -`fallback' Read the upstream first, but if it turns out that the chosen - value is not a valid upstream (because it cannot be resolved - as an existing revision), then treat it as the name of the - new branch and continue by reading the upstream next." - :package-version '(magit . "2.2.0") - :group 'magit-commands - :type '(choice (const :tag "read branch name first" nil) - (const :tag "read upstream first" t) - (const :tag "read upstream first, with fallback" fallback))) - -(defcustom magit-branch-prefer-remote-upstream nil - "Whether to favor remote upstreams when creating new branches. - -When a new branch is created, then the branch, commit, or stash -at point is suggested as the default starting point of the new -branch, or if there is no such revision at point the current -branch. In either case the user may choose another starting -point. - -If the chosen starting point is a branch, then it may also be set -as the upstream of the new branch, depending on the value of the -Git variable `branch.autoSetupMerge'. By default this is done -for remote branches, but not for local branches. - -You might prefer to always use some remote branch as upstream. -If the chosen starting point is (1) a local branch, (2) whose -name matches a member of the value of this option, (3) the -upstream of that local branch is a remote branch with the same -name, and (4) that remote branch can be fast-forwarded to the -local branch, then the chosen branch is used as starting point, -but its own upstream is used as the upstream of the new branch. - -Members of this option's value are treated as branch names that -have to match exactly unless they contain a character that makes -them invalid as a branch name. Recommended characters to use -to trigger interpretation as a regexp are \"*\" and \"^\". Some -other characters which you might expect to be invalid, actually -are not, e.g. \".+$\" are all perfectly valid. More precisely, -if `git check-ref-format --branch STRING' exits with a non-zero -status, then treat STRING as a regexp. - -Assuming the chosen branch matches these conditions you would end -up with with e.g.: - - feature --upstream--> origin/master - -instead of - - feature --upstream--> master --upstream--> origin/master - -Which you prefer is a matter of personal preference. If you do -prefer the former, then you should add branches such as \"master\", -\"next\", and \"maint\" to the value of this options." - :package-version '(magit . "2.4.0") - :group 'magit-commands - :type '(repeat string)) - -(defcustom magit-branch-adjust-remote-upstream-alist nil - "Alist of upstreams to be used when branching from remote branches. - -When creating a local branch from an ephemeral branch located -on a remote, e.g. a feature or hotfix branch, then that remote -branch should usually not be used as the upstream branch, since -the push-remote already allows accessing it and having both the -upstream and the push-remote reference the same related branch -would be wasteful. Instead a branch like \"maint\" or \"master\" -should be used as the upstream. - -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 -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. - -RULE can either be a regular expression, matching branches whose -upstream should be the one specified by UPSTREAM. Or it can be -a list of the only branches that should *not* use UPSTREAM; all -other branches will. Matching is done after stripping the remote -part of the name of the branch that is being branched from. - -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\"))) - -Or if the names of all your ephemeral branches contain a slash, -at least in some repositories, then a good value could be: - - ((\"origin/master\" . \"/\")) - -Of course you can also fine-tune: - - ((\"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." - :package-version '(magit . "2.9.0") - :group 'magit-commands - :type '(repeat (cons (string :tag "Use upstream") - (choice :tag "for branches" - (regexp :tag "matching") - (repeat :tag "except" - (string :tag "branch")))))) - -(defcustom magit-branch-rename-push-target t - "Whether the push-remote setup is preserved when renaming a branch. - -The command `magit-branch-rename' renames a branch named OLD to -NEW. This option controls how much of the push-remote setup is -preserved when doing so. - -When nil, then preserve nothing and unset `branch.OLD.pushRemote'. - -When `local-only', then first set `branch.NEW.pushRemote' to the - same value as `branch.OLD.pushRemote', provided the latter is - actually set and unless the former already has another value. - -When t, then rename the branch named OLD on the remote specified - by `branch.OLD.pushRemote' to NEW, provided OLD exists on that - remote and unless NEW already exists on the remote. - -When `forge-only' and the `forge' package is available, then - behave like `t' if the remote points to a repository on a forge - (currently Github or Gitlab), otherwise like `local-only'. - -Another supported but obsolete value is `github-only'. It is a - misnomer because it now treated as an alias for `forge-only'." - :package-version '(magit . "2.90.0") - :group 'magit-commands - :type '(choice - (const :tag "Don't preserve push-remote setup" nil) - (const :tag "Preserve push-remote setup" local-only) - (const :tag "... and rename corresponding branch on remote" t) - (const :tag "... but only if remote is on a forge" forge-only))) - -(defcustom magit-branch-direct-configure t - "Whether the command `magit-branch' shows Git variables. -When set to nil, no variables are displayed by this transient -command, instead the sub-transient `magit-branch-configure' -has to be used to view and change branch related variables." - :package-version '(magit . "2.7.0") - :group 'magit-commands - :type 'boolean) - -(defcustom magit-published-branches '("origin/master") - "List of branches that are considered to be published." - :package-version '(magit . "2.13.0") - :group 'magit-commands - :type '(repeat string)) - -;;; Commands - -;;;###autoload (autoload 'magit-branch "magit" nil t) -(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 - (oref transient--prefix scope))) - ("d" magit-branch..description) - ("u" magit-branch..merge/remote) - ("r" magit-branch..rebase) - ("p" magit-branch..pushRemote)] - [["Checkout" - ("b" "branch/revision" magit-checkout) - ("l" "local branch" magit-branch-checkout) - (6 "o" "new orphan" magit-branch-orphan)] - ["" - ("c" "new branch" magit-branch-and-checkout) - ("s" "new spin-off" magit-branch-spinoff) - (5 "w" "new worktree" magit-worktree-checkout)] - ["Create" - ("n" "new branch" magit-branch-create) - ("S" "new spin-out" magit-branch-spinout) - (5 "W" "new worktree" magit-worktree-branch)] - ["Do" - ("C" "configure..." magit-branch-configure) - ("m" "rename" magit-branch-rename) - ("x" "reset" magit-branch-reset) - ("k" "delete" magit-branch-delete)] - ["" - (7 "h" "shelve" magit-branch-shelve) - (7 "H" "unshelve" magit-branch-unshelve)]] - (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 &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") - (magit-branch-arguments))) - (when (string-match "\\`heads/\\(.+\\)" revision) - (setq revision (match-string 1 revision))) - (magit-run-git "checkout" args revision)) - -;;;###autoload -(defun magit-branch-create (branch start-point) - "Create BRANCH at branch or revision START-POINT." - (interactive (magit-branch-read-args "Create branch")) - (magit-call-git "branch" branch start-point) - (magit-branch-maybe-adjust-upstream branch start-point) - (magit-refresh)) - -;;;###autoload -(defun magit-branch-and-checkout (branch start-point &optional args) - "Create and checkout BRANCH at branch or revision START-POINT." - (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" args "-b" branch start-point) - (magit-branch-maybe-adjust-upstream branch start-point) - (magit-refresh))) - -;;;###autoload -(defun magit-branch-or-checkout (arg &optional start-point) - "Hybrid between `magit-checkout' and `magit-branch-and-checkout'. - -Ask the user for an existing branch or revision. If the user -input actually can be resolved as a branch or revision, then -check that out, just like `magit-checkout' would. - -Otherwise create and checkout a new branch using the input as -its name. Before doing so read the starting-point for the new -branch. This is similar to what `magit-branch-and-checkout' -does." - (interactive - (let ((arg (magit-read-other-branch-or-commit "Checkout"))) - (list arg - (and (not (magit-commit-p arg)) - (magit-read-starting-point "Create and checkout branch" arg))))) - (when (string-match "\\`heads/\\(.+\\)" arg) - (setq arg (match-string 1 arg))) - (if start-point - (magit-branch-and-checkout arg start-point) - (magit-checkout arg))) - -;;;###autoload -(defun magit-branch-checkout (branch &optional start-point) - "Checkout an existing or new local branch. - -Read a branch name from the user offering all local branches and -a subset of remote branches as candidates. Omit remote branches -for which a local branch by the same name exists from the list -of candidates. The user can also enter a completely new branch -name. - -- If the user selects an existing local branch, then check that - out. - -- If the user selects a remote branch, then create and checkout - a new local branch with the same name. Configure the selected - remote branch as push target. - -- If the user enters a new branch name, then create and check - that out, after also reading the starting-point from the user. - -In the latter two cases the upstream is also set. Whether it is -set to the chosen START-POINT or something else depends on the -value of `magit-branch-adjust-remote-upstream-alist', just like -when using `magit-branch-and-checkout'." - (interactive - (let* ((current (magit-get-current-branch)) - (local (magit-list-local-branch-names)) - (remote (--filter (and (string-match "[^/]+/" it) - (not (member (substring it (match-end 0)) - (cons "HEAD" local)))) - (magit-list-remote-branch-names))) - (choices (nconc (delete current local) remote)) - (atpoint (magit-branch-at-point)) - (choice (magit-completing-read - "Checkout branch" choices - nil nil nil 'magit-revision-history - (or (car (member atpoint choices)) - (and atpoint - (car (member (and (string-match "[^/]+/" atpoint) - (substring atpoint (match-end 0))) - choices))))))) - (cond ((member choice remote) - (list (and (string-match "[^/]+/" choice) - (substring choice (match-end 0))) - choice)) - ((member choice local) - (list choice)) - (t - (list choice (magit-read-starting-point "Create" choice)))))) - (if (not start-point) - (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) - (pcase-let ((`(,remote . ,remote-branch) - (magit-split-branch-name start-point))) - (when (and (equal branch remote-branch) - (not (equal remote (magit-get "remote.pushDefault")))) - (magit-set remote "branch" branch "pushRemote")))))) - -(defun magit-branch-maybe-adjust-upstream (branch start-point) - (--when-let - (or (and (magit-get-upstream-branch branch) - (magit-get-indirect-upstream-branch start-point)) - (and (magit-remote-branch-p start-point) - (let ((name (cdr (magit-split-branch-name start-point)))) - (-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 -(defun magit-branch-orphan (branch start-point) - "Create and checkout an orphan BRANCH with contents from revision START-POINT." - (interactive (magit-branch-read-args "Create and checkout orphan branch")) - (magit-run-git "checkout" "--orphan" branch start-point)) - -(defun magit-branch-read-args (prompt &optional default-start) - (if magit-branch-read-upstream-first - (let ((choice (magit-read-starting-point prompt nil default-start))) - (if (magit-rev-verify choice) - (list (magit-read-string-ns - (if magit-completing-read--silent-default - (format "%s (starting at `%s')" prompt choice) - "Name for new branch") - (let ((def (mapconcat #'identity - (cdr (split-string choice "/")) - "/"))) - (and (member choice (magit-list-remote-branch-names)) - (not (member def (magit-list-local-branch-names))) - def))) - choice) - (if (eq magit-branch-read-upstream-first 'fallback) - (list choice - (magit-read-starting-point prompt choice default-start)) - (user-error "Not a valid starting-point: %s" choice)))) - (let ((branch (magit-read-string-ns (concat prompt " named")))) - (list branch (magit-read-starting-point prompt branch default-start))))) - -;;;###autoload -(defun magit-branch-spinout (branch &optional from) - "Create new branch from the unpushed commits. -Like `magit-branch-spinoff' but remain on the current branch. -If there are any uncommitted changes, then behave exactly like -`magit-branch-spinoff'." - (interactive (list (magit-read-string-ns "Spin out branch") - (car (last (magit-region-values 'commit))))) - (magit--branch-spinoff branch from nil)) - -;;;###autoload -(defun magit-branch-spinoff (branch &optional from) - "Create new branch from the unpushed commits. - -Create and checkout a new branch starting at and tracking the -current branch. That branch in turn is reset to the last commit -it shares with its upstream. If the current branch has no -upstream or no unpushed commits, then the new branch is created -anyway and the previously current branch is not touched. - -This is useful to create a feature branch after work has already -began on the old branch (likely but not necessarily \"master\"). - -If the current branch is a member of the value of option -`magit-branch-prefer-remote-upstream' (which see), then the -current branch will be used as the starting point as usual, but -the upstream of the starting-point may be used as the upstream -of the new branch, instead of the starting-point itself. - -If optional FROM is non-nil, then the source branch is reset -to `FROM~', instead of to the last commit it shares with its -upstream. Interactively, FROM is only ever non-nil, if the -region selects some commits, and among those commits, FROM is -the commit that is the fewest commits ahead of the source -branch. - -The commit at the other end of the selection actually does not -matter, all commits between FROM and `HEAD' are moved to the new -branch. If FROM is not reachable from `HEAD' or is reachable -from the source branch's upstream, then an error is raised." - (interactive (list (magit-read-string-ns "Spin off branch") - (car (last (magit-region-values 'commit))))) - (magit--branch-spinoff branch from t)) - -(defun magit--branch-spinoff (branch from checkout) - (when (magit-branch-p branch) - (user-error "Cannot spin off %s. It already exists" branch)) - (when (and (not checkout) - (magit-anything-modified-p)) - (message "Staying on HEAD due to uncommitted changes") - (setq checkout t)) - (if-let ((current (magit-get-current-branch))) - (let ((tracked (magit-get-upstream-branch current)) - base) - (when from - (unless (magit-rev-ancestor-p from current) - (user-error "Cannot spin off %s. %s is not reachable from %s" - branch from current)) - (when (and tracked - (magit-rev-ancestor-p from tracked)) - (user-error "Cannot spin off %s. %s is ancestor of upstream %s" - branch from tracked))) - (let ((magit-process-raise-error t)) - (if checkout - (magit-call-git "checkout" "-b" branch current) - (magit-call-git "branch" branch current))) - (--when-let (magit-get-indirect-upstream-branch current) - (magit-call-git "branch" "--set-upstream-to" it branch)) - (when (and tracked - (setq base - (if from - (concat from "^") - (magit-git-string "merge-base" current tracked))) - (not (magit-rev-eq base current))) - (if checkout - (magit-call-git "update-ref" "-m" - (format "reset: moving to %s" base) - (concat "refs/heads/" current) base) - (magit-call-git "reset" "--hard" base)))) - (if checkout - (magit-call-git "checkout" "-b" branch) - (magit-call-git "branch" branch))) - (magit-refresh)) - -;;;###autoload -(defun magit-branch-reset (branch to &optional set-upstream) - "Reset a branch to the tip of another branch or any other commit. - -When the branch being reset is the current branch, then do a -hard reset. If there are any uncommitted changes, then the user -has to confirm the reset because those changes would be lost. - -This is useful when you have started work on a feature branch but -realize it's all crap and want to start over. - -When resetting to another branch and a prefix argument is used, -then also set the target branch as the upstream of the branch -that is being reset." - (interactive - (let* ((atpoint (magit-local-branch-at-point)) - (branch (magit-read-local-branch "Reset branch" atpoint))) - (list branch - (magit-completing-read (format "Reset %s to" branch) - (delete branch (magit-list-branch-names)) - nil nil nil 'magit-revision-history - (or (and (not (equal branch atpoint)) atpoint) - (magit-get-upstream-branch branch))) - current-prefix-arg))) - (let ((magit-inhibit-refresh t)) - (if (equal branch (magit-get-current-branch)) - (if (and (magit-anything-modified-p) - (not (yes-or-no-p - "Uncommitted changes will be lost. Proceed? "))) - (user-error "Abort") - (magit-reset-hard to)) - (magit-call-git "update-ref" - "-m" (format "reset: moving to %s" to) - (magit-git-string "rev-parse" "--symbolic-full-name" - branch) - to)) - (when (and set-upstream (magit-branch-p to)) - (magit-set-upstream-branch branch to) - (magit-branch-maybe-adjust-upstream branch to))) - (magit-refresh)) - -(defvar magit-branch-delete-never-verify nil - "Whether `magit-branch-delete' always pushes with \"--no-verify\".") - -;;;###autoload -(defun magit-branch-delete (branches &optional force) - "Delete one or multiple branches. -If the region marks multiple branches, then offer to delete -those, otherwise prompt for a single branch to be deleted, -defaulting to the branch at point." - ;; One would expect this to be a command as simple as, for example, - ;; `magit-branch-rename'; but it turns out everyone wants to squeeze - ;; a bit of extra functionality into this one, including myself. - (interactive - (let ((branches (magit-region-values 'branch t)) - (force current-prefix-arg)) - (if (> (length branches) 1) - (magit-confirm t nil "Delete %i branches" nil branches) - (setq branches - (list (magit-read-branch-prefer-other - (if force "Force delete branch" "Delete branch"))))) - (unless force - (when-let ((unmerged (-remove #'magit-branch-merged-p branches))) - (if (magit-confirm 'delete-unmerged-branch - "Delete unmerged branch %s" - "Delete %i unmerged branches" - 'noabort unmerged) - (setq force branches) - (or (setq branches (-difference branches unmerged)) - (user-error "Abort"))))) - (list branches force))) - (let* ((refs (mapcar #'magit-ref-fullname branches)) - (ambiguous (--remove it refs))) - (when ambiguous - (user-error - "%s ambiguous. Please cleanup using git directly." - (let ((len (length ambiguous))) - (cond - ((= len 1) - (format "%s is" (-first #'magit-ref-ambiguous-p branches))) - ((= len (length refs)) - (format "These %s names are" len)) - (t - (format "%s of these names are" len)))))) - (cond - ((string-match "^refs/remotes/\\([^/]+\\)" (car refs)) - (let* ((remote (match-string 1 (car refs))) - (offset (1+ (length remote)))) - (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) - (mapc 'magit-branch-unset-pushRemote branches) - (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)) - (main (magit-main-branch))) - (when (equal branch (magit-get-current-branch)) - (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 (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)) - (magit-confirm 'delete-unmerged-branch - "Delete unmerged branch %s" "" - nil (list branch))) - (magit-call-git "checkout" "--detach")) - (`main (unless (or (equal force '(4)) - (member branch force) - (magit-branch-merged-p branch main)) - (magit-confirm 'delete-unmerged-branch - "Delete unmerged branch %s" "" - nil (list branch))) - (magit-call-git "checkout" main)) - (`abort (user-error "Abort"))) - (setq force t)) - (magit-branch-maybe-delete-pr-remote branch) - (magit-branch-unset-pushRemote branch) - (magit-run-git "branch" (if force "-D" "-d") branch)))))) - -(put 'magit-branch-delete 'interactive-only t) - -(defun magit-branch-maybe-delete-pr-remote (branch) - (when-let ((remote (magit-get "branch" branch "pullRequestRemote"))) - (let* ((variable (format "remote.%s.fetch" remote)) - (refspecs (magit-get-all variable))) - (unless (member (format "+refs/heads/*:refs/remotes/%s/*" remote) - refspecs) - (let ((refspec - (if (equal (magit-get "branch" branch "pushRemote") remote) - (format "+refs/heads/%s:refs/remotes/%s/%s" - branch remote branch) - (let ((merge (magit-get "branch" branch "merge"))) - (and merge - (string-prefix-p "refs/heads/" merge) - (setq merge (substring merge 11)) - (format "+refs/heads/%s:refs/remotes/%s/%s" - merge remote merge)))))) - (when (member refspec refspecs) - (if (and (= (length refspecs) 1) - (magit-confirm 'delete-pr-remote - (format "Also delete remote %s (%s)" remote - "no pull-request branch remains") - nil t)) - (magit-call-git "remote" "rm" remote) - (magit-call-git "config" "--unset-all" variable - (format "^%s$" (regexp-quote refspec)))))))))) - -(defun magit-branch-unset-pushRemote (branch) - (magit-set nil "branch" branch "pushRemote")) - -(defun magit-delete-remote-branch-sentinel (remote refs process event) - (when (memq (process-status process) '(exit signal)) - (if (= (process-exit-status process) 1) - (if-let ((on-remote (--map (concat "refs/remotes/" remote "/" it) - (magit-remote-list-branches remote))) - (rest (--filter (and (not (member it on-remote)) - (magit-ref-exists-p it)) - refs))) - (progn - (process-put process 'inhibit-refresh t) - (magit-process-sentinel process event) - (setq magit-this-error nil) - (message "Some remote branches no longer exist. %s" - "Deleting just the local tracking refs instead...") - (dolist (ref rest) - (magit-call-git "update-ref" "-d" ref)) - (magit-refresh) - (message "Deleting local remote-tracking refs...done")) - (magit-process-sentinel process event)) - (magit-process-sentinel process event)))) - -;;;###autoload -(defun magit-branch-rename (old new &optional force) - "Rename the branch named OLD to NEW. - -With a prefix argument FORCE, rename even if a branch named NEW -already exists. - -If `branch.OLD.pushRemote' is set, then unset it. Depending on -the value of `magit-branch-rename-push-target' (which see) maybe -set `branch.NEW.pushRemote' and maybe rename the push-target on -the remote." - (interactive - (let ((branch (magit-read-local-branch "Rename branch"))) - (list branch - (magit-read-string-ns (format "Rename branch '%s' to" branch) - nil 'magit-revision-history) - current-prefix-arg))) - (when (string-match "\\`heads/\\(.+\\)" old) - (setq old (match-string 1 old))) - (when (equal old new) - (user-error "Old and new branch names are the same")) - (magit-call-git "branch" (if force "-M" "-m") old new) - (when magit-branch-rename-push-target - (let ((remote (magit-get-push-remote old)) - (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-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)) - (or (not (memq magit-branch-rename-push-target - '(forge-only github-only))) - (and (require (quote forge) nil t) - (fboundp 'forge--forge-remote-p) - (forge--forge-remote-p remote)))) - (let ((old-target (magit-get-push-branch old t)) - (new-target (magit-get-push-branch new t)) - (remote (magit-get-push-remote new))) - (when (and old-target - (not new-target) - (magit-y-or-n-p (format "Also rename %S to %S on \"%s\"" - old new remote))) - ;; Rename on (i.e. within) the remote, but only if the - ;; destination ref doesn't exist yet. If that ref already - ;; exists, then it probably is of some value and we better - ;; not touch it. Ignore what the local ref points at, - ;; i.e. if the local and the remote ref didn't point at - ;; the same commit before the rename then keep it that way. - (magit-call-git "push" "-v" remote - (format "%s:refs/heads/%s" old-target new) - (format ":refs/heads/%s" old))))))) - (magit-branch-unset-pushRemote old) - (magit-refresh)) - -;;;###autoload -(defun magit-branch-shelve (branch) - "Shelve a BRANCH. -Rename \"refs/heads/BRANCH\" to \"refs/shelved/BRANCH\", -and also rename the respective reflog file." - (interactive (list (magit-read-other-local-branch "Shelve branch"))) - (let ((old (concat "refs/heads/" branch)) - (new (concat "refs/shelved/" branch))) - (magit-git "update-ref" new old "") - (magit--rename-reflog-file old new) - (magit-branch-unset-pushRemote branch) - (magit-run-git "branch" "-D" branch))) - -;;;###autoload -(defun magit-branch-unshelve (branch) - "Unshelve a BRANCH -Rename \"refs/shelved/BRANCH\" to \"refs/heads/BRANCH\", -and also rename the respective reflog file." - (interactive - (list (magit-completing-read - "Unshelve branch" - (--map (substring it 8) - (magit-list-refnames "refs/shelved")) - nil t))) - (let ((old (concat "refs/shelved/" branch)) - (new (concat "refs/heads/" branch))) - (magit-git "update-ref" new old "") - (magit--rename-reflog-file old new) - (magit-run-git "update-ref" "-d" old))) - -(defun magit--rename-reflog-file (old new) - (let ((old (magit-git-dir (concat "logs/" old))) - (new (magit-git-dir (concat "logs/" new)))) - (when (file-exists-p old) - (make-directory (file-name-directory new) t) - (rename-file old new t)))) - -;;; Configure - -;;;###autoload (autoload 'magit-branch-configure "magit-branch" nil t) -(transient-define-prefix magit-branch-configure (branch) - "Configure a branch." - :man-page "git-branch" - [:description - (lambda () - (concat - (propertize "Configure " 'face 'transient-heading) - (propertize (oref transient--prefix scope) 'face 'magit-branch-local))) - ("d" magit-branch..description) - ("u" magit-branch..merge/remote) - ("r" magit-branch..rebase) - ("p" magit-branch..pushRemote)] - ["Configure repository defaults" - ("R" magit-pull.rebase) - ("P" magit-remote.pushDefault)] - ["Configure branch creation" - ("a m" magit-branch.autoSetupMerge) - ("a r" magit-branch.autoSetupRebase)] - (interactive - (list (or (and (not current-prefix-arg) - (not (and magit-branch-direct-configure - (eq transient-current-command 'magit-branch))) - (magit-get-current-branch)) - (magit--read-branch-scope)))) - (transient-setup 'magit-branch-configure nil nil :scope branch)) - -(defun magit--read-branch-scope (&optional obj) - (magit-read-local-branch - (if obj - (format "Set %s for branch" - (format (oref obj variable) "")) - "Configure 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 transient-current-prefix scope))) - (magit-run-git-with-editor "branch" "--edit-description" branch)) - -(add-hook 'find-file-hook 'magit-branch-description-check-buffers) - -(defun magit-branch-description-check-buffers () - (and buffer-file-name - (string-match-p "/\\(BRANCH\\|EDIT\\)_DESCRIPTION\\'" buffer-file-name))) - -(defclass magit--git-branch:upstream (magit--git-variable) - ((format :initform " %k %m %M\n %r %R"))) - -(transient-define-infix magit-branch..merge/remote () - :class 'magit--git-branch:upstream) - -(cl-defmethod transient-init-value ((obj magit--git-branch:upstream)) - (when-let ((branch (oref transient--prefix scope)) - (remote (magit-get "branch" branch "remote")) - (merge (magit-get "branch" branch "merge"))) - (oset obj value (list remote merge)))) - -(cl-defmethod transient-infix-read ((obj magit--git-branch:upstream)) - (if (oref obj value) - (oset obj value nil) - (magit-read-upstream-branch (oref transient--prefix scope) "Upstream"))) - -(cl-defmethod transient-infix-set ((obj magit--git-branch:upstream) refname) - (magit-set-upstream-branch (oref transient--prefix scope) refname) - (oset obj value - (let ((branch (oref transient--prefix scope))) - (when-let ((r (magit-get "branch" branch "remote")) - (m (magit-get "branch" branch "merge"))) - (list r m)))) - (magit-refresh)) - -(cl-defmethod transient-format ((obj magit--git-branch:upstream)) - (let ((branch (oref transient--prefix scope))) - (format-spec - (oref obj format) - `((?k . ,(transient-format-key obj)) - (?r . ,(format "branch.%s.remote" branch)) - (?m . ,(format "branch.%s.merge" branch)) - (?R . ,(transient-format-value obj #'car)) - (?M . ,(transient-format-value obj #'cadr)))))) - -(cl-defmethod transient-format-value ((obj magit--git-branch:upstream) key) - (if-let ((value (funcall key (oref obj value)))) - (propertize value 'face 'transient-argument) - (propertize "unset" 'face 'transient-inactive-argument))) - -(transient-define-infix magit-branch..rebase () - :class 'magit--git-variable:choices - :scope 'magit--read-branch-scope - :variable "branch.%s.rebase" - :fallback "pull.rebase" - :choices '("true" "false") - :default "false") - -(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) - -(transient-define-infix magit-pull.rebase () - :class 'magit--git-variable:choices - :variable "pull.rebase" - :choices '("true" "false") - :default "false") - -(transient-define-infix magit-remote.pushDefault () - :class 'magit--git-variable:choices - :variable "remote.pushDefault" - :choices 'magit-list-remotes) - -(transient-define-infix magit-branch.autoSetupMerge () - :class 'magit--git-variable:choices - :variable "branch.autoSetupMerge" - :choices '("always" "true" "false") - :default "true") - -(transient-define-infix magit-branch.autoSetupRebase () - :class 'magit--git-variable:choices - :variable "branch.autoSetupRebase" - :choices '("always" "local" "remote" "never") - :default "never") - -;;; _ -(provide 'magit-branch) -;;; magit-branch.el ends here diff --git a/elpa/magit-20210802.1524/magit-clone.el b/elpa/magit-20210802.1524/magit-clone.el deleted file mode 100644 index 3b30e477..00000000 --- a/elpa/magit-20210802.1524/magit-clone.el +++ /dev/null @@ -1,292 +0,0 @@ -;;; magit-clone.el --- clone a repository -*- lexical-binding: t -*- - -;; 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) -;; 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. - -;;; Commentary: - -;; This library implements clone commands. - -;;; Code: - -(require 'magit) - -;;; Options - -(defcustom magit-clone-set-remote-head nil - "Whether cloning creates the symbolic-ref `/HEAD'." - :package-version '(magit . "2.4.2") - :group 'magit-commands - :type 'boolean) - -(defcustom magit-clone-set-remote.pushDefault 'ask - "Whether to set the value of `remote.pushDefault' after cloning. - -If t, then set without asking. If nil, then don't set. If -`ask', then ask." - :package-version '(magit . "2.4.0") - :group 'magit-commands - :type '(choice (const :tag "set" t) - (const :tag "ask" ask) - (const :tag "don't set" nil))) - -(defcustom magit-clone-default-directory nil - "Default directory to use when `magit-clone' reads destination. -If nil (the default), then use the value of `default-directory'. -If a directory, then use that. If a function, then call that -with the remote url as only argument and use the returned value." - :package-version '(magit . "2.90.0") - :group 'magit-commands - :type '(choice (const :tag "value of default-directory") - (directory :tag "constant directory") - (function :tag "function's value"))) - -(defcustom magit-clone-always-transient nil - "Whether `magit-clone' always acts as a transient prefix command. -If nil, then a prefix argument has to be used to show the transient -popup instead of invoking the default suffix `magit-clone-regular' -directly." - :package-version '(magit . "3.0.0") - :group 'magit-commands - :type 'boolean) - -(defcustom magit-clone-name-alist - '(("\\`\\(?:github:\\|gh:\\)?\\([^:]+\\)\\'" "github.com" "github.user") - ("\\`\\(?:gitlab:\\|gl:\\)\\([^:]+\\)\\'" "gitlab.com" "gitlab.user")) - "Alist mapping repository names to repository urls. - -Each element has the form (REGEXP HOSTNAME USER). When the user -enters a name when a cloning command asks for a name or url, then -that is looked up in this list. The first element whose REGEXP -matches is used. - -The format specified by option `magit-clone-url-format' is used -to turn the name into an url, using HOSTNAME and the repository -name. If the provided name contains a slash, then that is used. -Otherwise if the name omits the owner of the repository, then the -default user specified in the matched entry is used. - -If USER contains a dot, then it is treated as a Git variable and -the value of that is used as the username. Otherwise it is used -as the username itself." - :package-version '(magit . "3.0.0") - :group 'magit-commands - :type '(repeat (list regexp - (string :tag "hostname") - (string :tag "user name or git variable")))) - -(defcustom magit-clone-url-format "git@%h:%n.git" - "Format used when turning repository names into urls. -%h is the hostname and %n is the repository name, including -the name of the owner. Also see `magit-clone-name-alist'." - :package-version '(magit . "3.0.0") - :group 'magit-commands - :type 'regexp) - -;;; Commands - -;;;###autoload (autoload 'magit-clone "magit-clone" nil t) -(transient-define-prefix magit-clone (&optional transient) - "Clone a repository." - :man-page "git-clone" - ["Fetch arguments" - ("-B" "Clone a single branch" "--single-branch") - ("-n" "Do not clone tags" "--no-tags") - ("-S" "Clones submodules" "--recurse-submodules" :level 6) - ("-l" "Do not optimize" "--no-local" :level 7)] - ["Setup arguments" - ("-o" "Set name of remote" ("-o" "--origin=")) - ("-b" "Set HEAD branch" ("-b" "--branch=")) - ("-g" "Separate git directory" "--separate-git-dir=" - transient-read-directory :level 7) - ("-t" "Use template directory" "--template=" - transient-read-existing-directory :level 6)] - ["Local sharing arguments" - ("-s" "Share objects" ("-s" "--shared" :level 7)) - ("-h" "Do not use hardlinks" "--no-hardlinks")] - ["Clone" - ("C" "regular" magit-clone-regular) - ("s" "shallow" magit-clone-shallow) - ("d" "shallow since date" magit-clone-shallow-since :level 7) - ("e" "shallow excluding" magit-clone-shallow-exclude :level 7) - ("b" "bare" magit-clone-bare) - ("m" "mirror" magit-clone-mirror)] - (interactive (list (or magit-clone-always-transient current-prefix-arg))) - (if transient - (transient-setup #'magit-clone) - (call-interactively #'magit-clone-regular))) - -;;;###autoload -(defun magit-clone-regular (repository directory args) - "Create a clone of REPOSITORY in DIRECTORY. -Then show the status buffer for the new repository." - (interactive (magit-clone-read-args)) - (magit-clone-internal repository directory args)) - -;;;###autoload -(defun magit-clone-shallow (repository directory args depth) - "Create a shallow clone of REPOSITORY in DIRECTORY. -Then show the status buffer for the new repository. -With a prefix argument read the DEPTH of the clone; -otherwise use 1." - (interactive (append (magit-clone-read-args) - (list (if current-prefix-arg - (read-number "Depth: " 1) - 1)))) - (magit-clone-internal repository directory - (cons (format "--depth=%s" depth) args))) - -;;;###autoload -(defun magit-clone-shallow-since (repository directory args date) - "Create a shallow clone of REPOSITORY in DIRECTORY. -Then show the status buffer for the new repository. -Exclude commits before DATE, which is read from the -user." - (interactive (append (magit-clone-read-args) - (list (transient-read-date "Exclude commits before: " - nil nil)))) - (magit-clone-internal repository directory - (cons (format "--shallow-since=%s" date) args))) - -;;;###autoload -(defun magit-clone-shallow-exclude (repository directory args exclude) - "Create a shallow clone of REPOSITORY in DIRECTORY. -Then show the status buffer for the new repository. -Exclude commits reachable from EXCLUDE, which is a -branch or tag read from the user." - (interactive (append (magit-clone-read-args) - (list (read-string "Exclude commits reachable from: ")))) - (magit-clone-internal repository directory - (cons (format "--shallow-exclude=%s" exclude) args))) - -;;;###autoload -(defun magit-clone-bare (repository directory args) - "Create a bare clone of REPOSITORY in DIRECTORY. -Then show the status buffer for the new repository." - (interactive (magit-clone-read-args)) - (magit-clone-internal repository directory (cons "--bare" args))) - -;;;###autoload -(defun magit-clone-mirror (repository directory args) - "Create a mirror of REPOSITORY in DIRECTORY. -Then show the status buffer for the new repository." - (interactive (magit-clone-read-args)) - (magit-clone-internal repository directory (cons "--mirror" args))) - -(defun magit-clone-internal (repository directory args) - (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))) - (list repo - (read-directory-name - "Clone to: " - (if (functionp magit-clone-default-directory) - (funcall magit-clone-default-directory repo) - magit-clone-default-directory) - nil nil - (magit-clone--url-to-name repo)) - (transient-args 'magit-clone)))) - -(defun magit-clone-read-repository () - (magit-read-char-case "Clone from " nil - (?u "[u]rl or name" - (let ((str (magit-read-string-ns "Clone from url or name"))) - (if (string-match-p "\\(://\\|@\\)" str) - 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://"))))) - -(defun magit-clone--url-to-name (url) - (and (string-match "\\([^/:]+?\\)\\(/?\\.git\\)?$" url) - (match-string 1 url))) - -(defun magit-clone--name-to-url (name) - (or (seq-some - (pcase-lambda (`(,re ,host ,user)) - (and (string-match re name) - (let ((repo (match-string 1 name))) - (magit-clone--format-url host user repo)))) - magit-clone-name-alist) - (user-error "Not an url and no matching entry in `%s'" - 'magit-clone-name-alist))) - -(defun magit-clone--format-url (host user repo) - (format-spec - magit-clone-url-format - `((?h . ,host) - (?n . ,(if (string-match-p "/" repo) - repo - (if (string-match-p "\\." user) - (if-let ((user (magit-get user))) - (concat user "/" repo) - (user-error "Set %S or specify owner explicitly" user)) - (concat user "/" repo))))))) - -;;; _ -(provide 'magit-clone) -;;; magit-clone.el ends here diff --git a/elpa/magit-20210802.1524/magit-commit.el b/elpa/magit-20210802.1524/magit-commit.el deleted file mode 100644 index 51f64057..00000000 --- a/elpa/magit-20210802.1524/magit-commit.el +++ /dev/null @@ -1,673 +0,0 @@ -;;; magit-commit.el --- create Git commits -*- lexical-binding: t -*- - -;; 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) -;; 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. - -;;; Commentary: - -;; This library implements commands for creating Git commits. These -;; commands just initiate the commit, support for writing the commit -;; messages is implemented in `git-commit.el'. - -;;; Code: - -(require 'magit) -(require 'magit-sequence) - -(eval-when-compile (require 'epa)) ; for `epa-protocol' -(eval-when-compile (require 'epg)) - -;;; Options - -(defcustom magit-commit-ask-to-stage 'verbose - "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) - (const :tag "Ask showing diff" verbose) - (const :tag "Stage without confirmation" stage) - (const :tag "Don't ask" nil))) - -(defcustom magit-commit-show-diff t - "Whether the relevant diff is automatically shown when committing." - :package-version '(magit . "2.3.0") - :group 'magit-commands - :type 'boolean) - -(defcustom magit-commit-extend-override-date t - "Whether using `magit-commit-extend' changes the committer date." - :package-version '(magit . "2.3.0") - :group 'magit-commands - :type 'boolean) - -(defcustom magit-commit-reword-override-date t - "Whether using `magit-commit-reword' changes the committer date." - :package-version '(magit . "2.3.0") - :group 'magit-commands - :type 'boolean) - -(defcustom magit-commit-squash-confirm t - "Whether the commit targeted by squash and fixup has to be confirmed. -When non-nil then the commit at point (if any) is used as default -choice, otherwise it has to be confirmed. This option only -affects `magit-commit-squash' and `magit-commit-fixup'. The -\"instant\" variants always require confirmation because making -an error while using those is harder to recover from." - :package-version '(magit . "2.1.0") - :group 'magit-commands - :type 'boolean) - -(defcustom magit-post-commit-hook nil - "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 and then finishes by pressing -\\\\[with-editor-finish]. - -Also see `git-commit-post-finish-hook'." - :package-version '(magit . "2.90.0") - :group 'magit-commands - :type 'hook) - -(defvar magit-post-commit-hook-commands - '(magit-commit-extend - magit-commit-fixup - magit-commit-augment - magit-commit-instant-fixup - magit-commit-instant-squash)) - -;;; Popup - -;;;###autoload (autoload 'magit-commit "magit-commit" nil t) -(transient-define-prefix magit-commit () - "Create a new commit or replace an existing commit." - :info-manual "(magit)Initiating a Commit" - :man-page "git-commit" - ["Arguments" - ("-a" "Stage all modified and deleted files" ("-a" "--all")) - ("-e" "Allow empty commit" "--allow-empty") - ("-v" "Show diff of changes to be committed" ("-v" "--verbose")) - ("-n" "Disable hooks" ("-n" "--no-verify")) - ("-R" "Claim authorship and reset author date" "--reset-author") - (magit:--author :description "Override the author") - (7 "-D" "Override the author date" "--date=" transient-read-date) - ("-s" "Add Signed-off-by line" ("-s" "--signoff")) - (5 magit:--gpg-sign) - (magit-commit:--reuse-message)] - [["Create" - ("c" "Commit" magit-commit-create)] - ["Edit HEAD" - ("e" "Extend" magit-commit-extend) - ("w" "Reword" magit-commit-reword) - ("a" "Amend" magit-commit-amend) - (6 "n" "Reshelve" magit-commit-reshelve)] - ["Edit" - ("f" "Fixup" magit-commit-fixup) - ("s" "Squash" magit-commit-squash) - ("A" "Augment" magit-commit-augment) - (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)]] - (interactive) - (if-let ((buffer (magit-commit-message-buffer))) - (switch-to-buffer buffer) - (transient-setup 'magit-commit))) - -(defun magit-commit-arguments nil - (transient-args 'magit-commit)) - -(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-signing-key) - -(defvar magit-gpg-secret-key-hist nil) - -(defun magit-read-gpg-secret-key - (prompt &optional initial-input history predicate) - (require 'epa) - (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)) - -(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" - :argument "--reuse-message=" - :reader 'magit-read-reuse-message - :history-key 'magit-revision-history) - -(defun magit-read-reuse-message (prompt &optional default history) - (magit-completing-read prompt (magit-list-refnames) - nil nil nil history - (or default - (and (magit-rev-verify "ORIG_HEAD") - "ORIG_HEAD")))) - -;;; Commands - -;;;###autoload -(defun magit-commit-create (&optional args) - "Create a new commit on `HEAD'. -With a prefix argument, amend to the commit at `HEAD' instead. -\n(git commit [--amend] ARGS)" - (interactive (if current-prefix-arg - (list (cons "--amend" (magit-commit-arguments))) - (list (magit-commit-arguments)))) - (when (member "--all" args) - (setq this-command 'magit-commit-all)) - (when (setq args (magit-commit-assert args)) - (let ((default-directory (magit-toplevel))) - (magit-run-git-with-editor "commit" args)))) - -;;;###autoload -(defun magit-commit-amend (&optional args) - "Amend the last commit. -\n(git commit --amend ARGS)" - (interactive (list (magit-commit-arguments))) - (magit-commit-amend-assert) - (magit-run-git-with-editor "commit" "--amend" args)) - -;;;###autoload -(defun magit-commit-extend (&optional args override-date) - "Amend the last commit, without editing the message. - -With a prefix argument keep the committer date, otherwise change -it. The option `magit-commit-extend-override-date' can be used -to inverse the meaning of the prefix argument. \n(git commit ---amend --no-edit)" - (interactive (list (magit-commit-arguments) - (if current-prefix-arg - (not magit-commit-extend-override-date) - magit-commit-extend-override-date))) - (when (setq args (magit-commit-assert args)) - (magit-commit-amend-assert) - (let ((process-environment process-environment)) - (unless override-date - (push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment)) - (magit-run-git-with-editor "commit" "--amend" "--no-edit" args)))) - -;;;###autoload -(defun magit-commit-reword (&optional args override-date) - "Reword the last commit, ignoring staged changes. - -With a prefix argument keep the committer date, otherwise change -it. The option `magit-commit-reword-override-date' can be used -to inverse the meaning of the prefix argument. - -Non-interactively respect the optional OVERRIDE-DATE argument -and ignore the option. -\n(git commit --amend --only)" - (interactive (list (magit-commit-arguments) - (if current-prefix-arg - (not magit-commit-reword-override-date) - magit-commit-reword-override-date))) - (magit-commit-amend-assert) - (let ((process-environment process-environment)) - (unless override-date - (push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment)) - (cl-pushnew "--allow-empty" args :test #'equal) - (magit-run-git-with-editor "commit" "--amend" "--only" args))) - -;;;###autoload -(defun magit-commit-fixup (&optional commit args) - "Create a fixup commit. - -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'." - (interactive (list (magit-commit-at-point) - (magit-commit-arguments))) - (magit-commit-squash-internal "--fixup" commit args)) - -;;;###autoload -(defun magit-commit-squash (&optional commit args) - "Create a squash commit, without editing the squash message. - -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'. - -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)) - -;;;###autoload -(defun magit-commit-augment (&optional commit args) - "Create a squash commit, editing the squash message. - -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'." - (interactive (list (magit-commit-at-point) - (magit-commit-arguments))) - (magit-commit-squash-internal "--squash" commit args nil t)) - -;;;###autoload -(defun magit-commit-instant-fixup (&optional commit args) - "Create a fixup commit targeting COMMIT and instantly rebase." - (interactive (list (magit-commit-at-point) - (magit-commit-arguments))) - (magit-commit-squash-internal "--fixup" commit args t)) - -;;;###autoload -(defun magit-commit-instant-squash (&optional commit args) - "Create a squash commit targeting COMMIT and instantly rebase." - (interactive (list (magit-commit-at-point) - (magit-commit-arguments))) - (magit-commit-squash-internal "--squash" commit args t)) - -(defun magit-commit-squash-internal - (option commit &optional args rebase edit confirmed) - (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 - (format "%s isn't an ancestor of HEAD. " commit) nil - (?c "[c]reate without rebasing" (setq rebase nil)) - (?s "[s]elect other" (setq commit nil)) - (?a "[a]bort" (user-error "Quit"))))) - (when commit - (setq commit (magit-rebase-interactive-assert commit t))) - (if (and commit - (or confirmed - (not (or rebase - current-prefix-arg - magit-commit-squash-confirm)))) - (let ((magit-commit-show-diff nil)) - (push (concat option "=" commit) args) - (unless edit - (push "--no-edit" args)) - (if rebase - (magit-with-editor - (magit-call-git - "commit" "--no-gpg-sign" - (-remove-first - (apply-partially #'string-match-p "\\`--gpg-sign=") - args))) - (magit-run-git-with-editor "commit" args)) - t) ; The commit was created; used by below lambda. - (magit-log-select - (lambda (commit) - (when (and (magit-commit-squash-internal option commit args - rebase edit t) - rebase) - (magit-commit-amend-assert commit) - (magit-rebase-interactive-1 commit - (list "--autosquash" "--autostash" "--keep-empty") - "" "true" nil t))) - (format "Type %%p on a commit to %s into it," - (substring option 2)) - nil nil nil commit) - (when magit-commit-show-diff - (let ((magit-display-buffer-noselect t)) - (apply #'magit-diff-staged nil (magit-diff-arguments))))))) - -(defun magit-commit-amend-assert (&optional commit) - (--when-let (magit-list-publishing-branches commit) - (let ((m1 "This commit has already been published to ") - (m2 ".\nDo you really want to modify it")) - (magit-confirm 'amend-published - (concat m1 "%s" m2) - (concat m1 "%i public branches" m2) - nil it)))) - -(defun magit-commit-assert (args &optional strict) - (cond - ((or (magit-anything-staged-p) - (and (magit-anything-unstaged-p) - ;; ^ Everything of nothing is still nothing. - (member "--all" args)) - (and (not strict) - ;; ^ For amend variants that don't make sense otherwise. - (or (member "--amend" 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)) - (y-or-n-p "Nothing staged. Continue in-progress rebase? ")) - (setq this-command 'magit-rebase-continue) - (magit-run-git-sequencer "rebase" "--continue") - nil) - ((and (file-exists-p (magit-git-dir "MERGE_MSG")) - (not (magit-anything-unstaged-p))) - (or args (list "--"))) - ((not (magit-anything-unstaged-p)) - (user-error "Nothing staged (or unstaged)")) - (magit-commit-ask-to-stage - (when (eq magit-commit-ask-to-stage 'verbose) - (magit-diff-unstaged)) - (prog1 (when (or (eq magit-commit-ask-to-stage 'stage) - (y-or-n-p "Nothing staged. Stage and commit all unstaged changes? ")) - (magit-run-git "add" "-u" ".") - (or args (list "--"))) - (when (and (eq magit-commit-ask-to-stage 'verbose) - (derived-mode-p 'magit-diff-mode)) - (magit-mode-bury-buffer)))) - (t - (user-error "Nothing staged")))) - -(defvar magit--reshelve-history nil) - -;;;###autoload -(defun magit-commit-reshelve (date update-author &optional args) - "Change the committer date and possibly the author date of `HEAD'. - -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 ((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 update-author - "Change author and committer dates to: " - "Change committer date to: ") - (cons (format-time-string "%F %T %z") 17) - '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 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) -(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 git-absorb executable, which -is available from https://github.com/tummychow/git-absorb. -See `magit-commit-autofixup' for an alternative implementation." - ["Arguments" - ("-f" "Skip safety checks" ("-f" "--force")) - ("-v" "Display more output" ("-v" "--verbose"))] - ["Actions" - ("x" "Absorb" magit-commit-absorb)] - (interactive (if current-prefix-arg - (list 'transient nil nil) - (list 'select - (magit-get-upstream-branch) - (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")) - (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)) - (progn (magit-run-git-async "autofixup" "-vv" args commit) t) - (magit-log-select - (lambda (commit) - (with-no-warnings ; about non-interactive use - (magit-commit-autofixup 'run commit args))) - nil nil nil nil commit)))) - -(transient-define-argument magit-autofixup:--context () - :description "Diff context lines" - :class 'transient-option - :shortarg "-c" - :argument "--context=" - :reader 'transient-read-number-N0) - -(transient-define-argument magit-autofixup:--strict () - :description "Strictness" - :class 'transient-option - :shortarg "-s" - :argument "--strict=" - :reader 'transient-read-number-N0) - -;;; Pending Diff - -(defun magit-commit-diff () - (when (and git-commit-mode magit-commit-show-diff) - (when-let ((diff-buffer (magit-get-mode-buffer 'magit-diff-mode))) - ;; This window just started displaying the commit message - ;; buffer. Without this that buffer would immediately be - ;; replaced with the diff buffer. See #2632. - (unrecord-window-buffer nil diff-buffer)) - (condition-case nil - (let ((args (car (magit-diff-arguments))) - (magit-inhibit-save-previous-winconf 'unset) - (magit-display-buffer-noselect t) - (inhibit-quit nil) - (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 - (magit-diff-staged nil args)) - (magit-commit-all - (magit-diff-working-tree nil args)) - ((magit-commit-amend - magit-commit-reword - magit-rebase-reword-commit) - (magit-diff-while-amending args)) - (t (if (magit-anything-staged-p) - (magit-diff-staged nil args) - (magit-diff-while-amending args))))) - (quit)))) - -;; 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)) - -;;; Message Utilities - -(defun magit-commit-message-buffer () - (let* ((find-file-visit-truename t) ; git uses truename of COMMIT_EDITMSG - (topdir (magit-toplevel))) - (--first (equal topdir (with-current-buffer it - (and git-commit-mode (magit-toplevel)))) - (append (buffer-list (selected-frame)) - (buffer-list))))) - -(defvar magit-commit-add-log-insert-function 'magit-commit-add-log-insert - "Used by `magit-commit-add-log' to insert a single entry.") - -(defun magit-commit-add-log () - "Add a stub for the current change into the commit message buffer. -If no commit is in progress, then initiate it. Use the function -specified by variable `magit-commit-add-log-insert-function' to -actually insert the entry." - (interactive) - (pcase-let* ((hunk (and (magit-section-match 'hunk) - (magit-current-section))) - (log (magit-commit-message-buffer)) - (`(,buf ,pos) (magit-diff-visit-file--noselect))) - (unless log - (unless (magit-commit-assert nil) - (user-error "Abort")) - (magit-commit-create) - (while (not (setq log (magit-commit-message-buffer))) - (sit-for 0.01))) - (magit--with-temp-position buf pos - (funcall magit-commit-add-log-insert-function log - (magit-file-relative-name) - (and hunk (add-log-current-defun)))))) - -(defun magit-commit-add-log-insert (buffer file defun) - (with-current-buffer buffer - (undo-boundary) - (goto-char (point-max)) - (while (re-search-backward (concat "^" comment-start) nil t)) - (save-restriction - (narrow-to-region (point-min) (point)) - (cond ((re-search-backward (format "* %s\\(?: (\\([^)]+\\))\\)?: " file) - nil t) - (when (equal (match-string 1) defun) - (setq defun nil)) - (re-search-forward ": ")) - (t - (when (re-search-backward "^[\\*(].+\n" nil t) - (goto-char (match-end 0))) - (while (re-search-forward "^[^\\*\n].*\n" nil t)) - (if defun - (progn (insert (format "* %s (%s): \n" file defun)) - (setq defun nil)) - (insert (format "* %s: \n" file))) - (backward-char) - (unless (looking-at "\n[\n\\']") - (insert ?\n) - (backward-char)))) - (when defun - (forward-line) - (let ((limit (save-excursion - (and (re-search-forward "^\\*" nil t) - (point))))) - (unless (or (looking-back (format "(%s): " defun) - (line-beginning-position)) - (re-search-forward (format "^(%s): " defun) limit t)) - (while (re-search-forward "^[^\\*\n].*\n" limit t)) - (insert (format "(%s): \n" defun)) - (backward-char))))))) - -;;; _ -(provide 'magit-commit) -;;; magit-commit.el ends here diff --git a/elpa/magit-20210802.1524/magit-core.el b/elpa/magit-20210802.1524/magit-core.el deleted file mode 100644 index 3d19d6c3..00000000 --- a/elpa/magit-20210802.1524/magit-core.el +++ /dev/null @@ -1,130 +0,0 @@ -;;; magit-core.el --- core functionality -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library requires several other libraries, so that yet other -;; libraries can just require this one, instead of having to require -;; all the other ones. In other words this separates the low-level -;; stuff from the rest. It also defines some Custom groups. - -;;; Code: - -(require 'magit-utils) -(require 'magit-section) -(require 'magit-git) -(require 'magit-mode) -(require 'magit-margin) -(require 'magit-process) -(require 'magit-transient) -(require 'magit-autorevert) - -(when (magit--libgit-available-p) - (condition-case err - (require 'magit-libgit) - (error - (setq magit-inhibit-libgit 'error) - (message "Error while loading `magit-libgit': %S" err) - (message "That is not fatal. The `libegit2' module just won't be used.")))) - -(defgroup magit nil - "Controlling Git from Emacs." - :link '(url-link "https://magit.vc") - :link '(info-link "(magit)FAQ") - :link '(info-link "(magit)") - :group 'tools) - -(defgroup magit-essentials nil - "Options that every Magit user should briefly think about. - -Each of these options falls into one or more of these categories: - -* Options that affect Magit's behavior in fundamental ways. -* Options that affect safety. -* Options that affect performance. -* Options that are of a personal nature." - :link '(info-link "(magit)Essential Settings") - :group 'magit) - -(defgroup magit-miscellaneous nil - "Miscellaneous Magit options." - :group 'magit) - -(defgroup magit-commands nil - "Options controlling behavior of certain commands." - :group 'magit) - -(defgroup magit-modes nil - "Modes used or provided by Magit." - :group 'magit) - -(defgroup magit-buffers nil - "Options concerning Magit buffers." - :link '(info-link "(magit)Modes and Buffers") - :group 'magit) - -(defgroup magit-refresh nil - "Options controlling how Magit buffers are refreshed." - :link '(info-link "(magit)Automatic Refreshing of Magit Buffers") - :group 'magit - :group 'magit-buffers) - -(defgroup magit-faces nil - "Faces used by Magit." - :group 'magit - :group 'faces) - -(defgroup magit-extensions nil - "Extensions to Magit." - :group 'magit) - -(custom-add-to-group 'magit-modes 'git-commit 'custom-group) -(custom-add-to-group 'magit-faces 'git-commit-faces 'custom-group) -(custom-add-to-group 'magit-modes 'git-rebase 'custom-group) -(custom-add-to-group 'magit-faces 'git-rebase-faces 'custom-group) -(custom-add-to-group 'magit 'magit-section 'custom-group) -(custom-add-to-group 'magit-faces 'magit-section-faces 'custom-group) -(custom-add-to-group 'magit-process 'with-editor 'custom-group) - -(defgroup magit-related nil - "Options that are relevant to Magit but that are defined elsewhere." - :link '(custom-group-link vc) - :link '(custom-group-link smerge) - :link '(custom-group-link ediff) - :link '(custom-group-link auto-revert) - :group 'magit - :group 'magit-extensions - :group 'magit-essentials) - -(custom-add-to-group 'magit-related 'auto-revert-check-vc-info 'custom-variable) -(custom-add-to-group 'magit-auto-revert 'auto-revert-check-vc-info 'custom-variable) - -(custom-add-to-group 'magit-related 'ediff-window-setup-function 'custom-variable) -(custom-add-to-group 'magit-related 'smerge-refine-ignore-whitespace 'custom-variable) -(custom-add-to-group 'magit-related 'vc-follow-symlinks 'custom-variable) - -;;; _ -(provide 'magit-core) -;;; magit-core.el ends here diff --git a/elpa/magit-20210802.1524/magit-diff.el b/elpa/magit-20210802.1524/magit-diff.el deleted file mode 100644 index 004cb173..00000000 --- a/elpa/magit-20210802.1524/magit-diff.el +++ /dev/null @@ -1,3377 +0,0 @@ -;;; magit-diff.el --- inspect Git diffs -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements support for looking at Git diffs and -;; commits. - -;;; Code: - -(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)) -;; For `magit-diff-visit-file' -(declare-function dired-jump "dired-x" (&optional other-window file-name)) -(declare-function magit-find-file-noselect "magit-files" (rev file)) -(declare-function magit-status-setup-buffer "magit-status" (directory)) -;; For `magit-diff-while-committing' -(declare-function magit-commit-message-buffer "magit-commit" ()) -;; For `magit-insert-revision-gravatar' -(defvar gravatar-size) -;; For `magit-show-commit' and `magit-diff-show-or-scroll' -(declare-function magit-current-blame-chunk "magit-blame" ()) -(declare-function magit-blame-mode "magit-blame" (&optional arg)) -(defvar magit-blame-mode) -;; For `magit-diff-show-or-scroll' -(declare-function git-rebase-current-line "git-rebase" ()) -;; For `magit-diff-unmerged' -(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 'orig-rev eieio--known-slot-names) - (cl-pushnew 'action-type eieio--known-slot-names) - (cl-pushnew 'target eieio--known-slot-names)) - -;;; 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 - "Hook run after entering Magit-Diff mode." - :group 'magit-diff - :type 'hook) - -(defcustom magit-diff-sections-hook - '(magit-insert-diff - magit-insert-xref-buttons) - "Hook run to insert sections into a `magit-diff-mode' buffer." - :package-version '(magit . "2.3.0") - :group 'magit-diff - :type 'hook) - -(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. - -Note that this can cause sections that were previously expanded -to be collapsed. So you should not pick a very low value here. - -The hook function `magit-diff-expansion-threshold' has to be a -member of `magit-section-set-visibility-hook' for this option -to have any effect." - :package-version '(magit . "2.9.0") - :group 'magit-diff - :type 'float) - -(defcustom magit-diff-highlight-hunk-body t - "Whether to highlight bodies of selected hunk sections. -This only has an effect if `magit-diff-highlight' is a -member of `magit-section-highlight-hook', which see." - :package-version '(magit . "2.1.0") - :group 'magit-diff - :type 'boolean) - -(defcustom magit-diff-highlight-hunk-region-functions - '(magit-diff-highlight-hunk-region-dim-outside - magit-diff-highlight-hunk-region-using-overlays) - "The functions used to highlight the hunk-internal region. - -`magit-diff-highlight-hunk-region-dim-outside' overlays the outside -of the hunk internal selection with a face that causes the added and -removed lines to have the same background color as context lines. -This function should not be removed from the value of this option. - -`magit-diff-highlight-hunk-region-using-overlays' and -`magit-diff-highlight-hunk-region-using-underline' emphasize the -region by placing delimiting horizontal lines before and after it. -The underline variant was implemented because Eli said that is -how we should do it. However the overlay variant actually works -better. Also see https://github.com/magit/magit/issues/2758. - -Instead of, or in addition to, using delimiting horizontal lines, -to emphasize the boundaries, you may which to emphasize the text -itself, using `magit-diff-highlight-hunk-region-using-face'. - -In terminal frames it's not possible to draw lines as the overlay -and underline variants normally do, so there they fall back to -calling the face function instead." - :package-version '(magit . "2.9.0") - :set-after '(magit-diff-show-lines-boundaries) - :group 'magit-diff - :type 'hook - :options '(magit-diff-highlight-hunk-region-dim-outside - magit-diff-highlight-hunk-region-using-underline - magit-diff-highlight-hunk-region-using-overlays - magit-diff-highlight-hunk-region-using-face)) - -(defcustom magit-diff-unmarked-lines-keep-foreground t - "Whether `magit-diff-highlight-hunk-region-dim-outside' preserves foreground. -When this is set to nil, then that function only adjusts the -foreground color but added and removed lines outside the region -keep their distinct foreground colors." - :package-version '(magit . "2.9.0") - :group 'magit-diff - :type 'boolean) - -(defcustom magit-diff-refine-hunk nil - "Whether to show word-granularity differences within diff hunks. - -nil Never show fine differences. -t Show fine differences for the current diff hunk only. -`all' Show fine differences for all displayed diff hunks." - :group 'magit-diff - :safe (lambda (val) (memq val '(nil t all))) - :type '(choice (const :tag "Never" nil) - (const :tag "Current" t) - (const :tag "All" all))) - -(defcustom magit-diff-refine-ignore-whitespace smerge-refine-ignore-whitespace - "Whether to ignore whitespace changes in word-granularity differences." - :package-version '(magit . "3.0.0") - :set-after '(smerge-refine-ignore-whitespace) - :group 'magit-diff - :safe 'booleanp - :type 'boolean) - -(put 'magit-diff-refine-hunk 'permanent-local t) - -(defcustom magit-diff-adjust-tab-width nil - "Whether to adjust the width of tabs in diffs. - -Determining the correct width can be expensive if it requires -opening large and/or many files, so the widths are cached in -the variable `magit-diff--tab-width-cache'. Set that to nil -to invalidate the cache. - -nil Never adjust tab width. Use `tab-width's value from - the Magit buffer itself instead. - -t If the corresponding file-visiting buffer exits, then - use `tab-width's value from that buffer. Doing this is - cheap, so this value is used even if a corresponding - cache entry exists. - -`always' If there is no such buffer, then temporarily visit the - file to determine the value. - -NUMBER Like `always', but don't visit files larger than NUMBER - bytes." - :package-version '(magit . "2.12.0") - :group 'magit-diff - :type '(choice (const :tag "Never" nil) - (const :tag "If file-visiting buffer exists" t) - (integer :tag "If file isn't larger than N bytes") - (const :tag "Always" always))) - -(defcustom magit-diff-paint-whitespace t - "Specify where to highlight whitespace errors. - -nil Never highlight whitespace errors. -t Highlight whitespace errors everywhere. -`uncommitted' Only highlight whitespace errors in diffs - showing uncommitted changes. - -For backward compatibility `status' is treated as a synonym -for `uncommitted'. - -The option `magit-diff-paint-whitespace-lines' controls for -what lines (added/remove/context) errors are highlighted. - -The options `magit-diff-highlight-trailing' and -`magit-diff-highlight-indentation' control what kind of -whitespace errors are highlighted." - :group 'magit-diff - :safe (lambda (val) (memq val '(t nil uncommitted status))) - :type '(choice (const :tag "In all diffs" t) - (const :tag "Only in uncommitted changes" uncommitted) - (const :tag "Never" nil))) - -(defcustom magit-diff-paint-whitespace-lines t - "Specify in what kind of lines to highlight whitespace errors. - -t Highlight only in added lines. -`both' Highlight in added and removed lines. -`all' Highlight in added, removed and context lines." - :package-version '(magit . "3.0.0") - :group 'magit-diff - :safe (lambda (val) (memq val '(t both all))) - :type '(choice (const :tag "in added lines" t) - (const :tag "in added and removed lines" both) - (const :tag "in added, removed and context lines" all))) - -(defcustom magit-diff-highlight-trailing t - "Whether to highlight whitespace at the end of a line in diffs. -Used only when `magit-diff-paint-whitespace' is non-nil." - :group 'magit-diff - :safe 'booleanp - :type 'boolean) - -(defcustom magit-diff-highlight-indentation nil - "Highlight the \"wrong\" indentation style. -Used only when `magit-diff-paint-whitespace' is non-nil. - -The value is an alist of the form ((REGEXP . INDENT)...). The -path to the current repository is matched against each element -in reverse order. Therefore if a REGEXP matches, then earlier -elements are not tried. - -If the used INDENT is `tabs', highlight indentation with tabs. -If INDENT is an integer, highlight indentation with at least -that many spaces. Otherwise, highlight neither." - :group 'magit-diff - :type `(repeat (cons (string :tag "Directory regexp") - (choice (const :tag "Tabs" tabs) - (integer :tag "Spaces" :value ,tab-width) - (const :tag "Neither" nil))))) - -(defcustom magit-diff-hide-trailing-cr-characters - (and (memq system-type '(ms-dos windows-nt)) t) - "Whether to hide ^M characters at the end of a line in diffs." - :package-version '(magit . "2.6.0") - :group 'magit-diff - :type 'boolean) - -(defcustom magit-diff-highlight-keywords t - "Whether to highlight bracketed keywords in commit messages." - :package-version '(magit . "2.12.0") - :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 - "Whether `magit-diff-buffer-file' uses a dedicated buffer." - :package-version '(magit . "2.7.0") - :group 'magit-commands - :group 'magit-diff - :type 'boolean) - -;;;; Revision Mode - -(defgroup magit-revision nil - "Inspect and manipulate Git commits." - :link '(info-link "(magit)Revision Buffer") - :group 'magit-modes) - -(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 - goto-address-mode)) - -(defcustom magit-revision-sections-hook - '(magit-insert-revision-tag - magit-insert-revision-headers - magit-insert-revision-message - magit-insert-revision-notes - magit-insert-revision-diff - magit-insert-xref-buttons) - "Hook run to insert sections into a `magit-revision-mode' buffer." - :package-version '(magit . "2.3.0") - :group 'magit-revision - :type 'hook) - -(defcustom magit-revision-headers-format "\ -Author: %aN <%aE> -AuthorDate: %ad -Commit: %cN <%cE> -CommitDate: %cd -" - "Format string used to insert headers in revision buffers. - -All headers in revision buffers are inserted by the section -inserter `magit-insert-revision-headers'. Some of the headers -are created by calling `git show --format=FORMAT' where FORMAT -is the format specified here. Other headers are hard coded or -subject to option `magit-revision-insert-related-refs'." - :package-version '(magit . "2.3.0") - :group 'magit-revision - :type 'string) - -(defcustom magit-revision-insert-related-refs t - "Whether to show related branches in revision buffers - -`nil' Don't show any related branches. -`t' Show related local branches. -`all' Show related local and remote branches. -`mixed' Show all containing branches and local merged branches." - :package-version '(magit . "2.1.0") - :group 'magit-revision - :type '(choice (const :tag "don't" nil) - (const :tag "local only" t) - (const :tag "all related" all) - (const :tag "all containing, local merged" mixed))) - -(defcustom magit-revision-use-hash-sections 'quicker - "Whether to turn hashes inside the commit message into sections. - -If non-nil, then hashes inside the commit message are turned into -`commit' sections. There is a trade off to be made between -performance and reliability: - -- `slow' calls git for every word to be absolutely sure. -- `quick' skips words less than seven characters long. -- `quicker' additionally skips words that don't contain a number. -- `quickest' uses all words that are at least seven characters - long and which contain at least one number as well as at least - one letter. - -If nil, then no hashes are turned into sections, but you can -still visit the commit at point using \"RET\"." - :package-version '(magit . "2.12.0") - :group 'magit-revision - :type '(choice (const :tag "Use sections, quickest" quickest) - (const :tag "Use sections, quicker" quicker) - (const :tag "Use sections, quick" quick) - (const :tag "Use sections, slow" slow) - (const :tag "Don't use sections" nil))) - -(defcustom magit-revision-show-gravatars nil - "Whether to show gravatar images in revision buffers. - -If nil, then don't insert any gravatar images. If t, then insert -both images. If `author' or `committer', then insert only the -respective image. - -If you have customized the option `magit-revision-header-format' -and want to insert the images then you might also have to specify -where to do so. In that case the value has to be a cons-cell of -two regular expressions. The car specifies where to insert the -author's image. The top half of the image is inserted right -after the matched text, the bottom half on the next line in the -same column. The cdr specifies where to insert the committer's -image, accordingly. Either the car or the cdr may be nil." - :package-version '(magit . "2.3.0") - :group 'magit-revision - :type '(choice (const :tag "Don't show gravatars" nil) - (const :tag "Show gravatars" t) - (const :tag "Show author gravatar" author) - (const :tag "Show committer gravatar" committer) - (cons :tag "Show gravatars using custom pattern." - (regexp :tag "Author regexp" "^Author: ") - (regexp :tag "Committer regexp" "^Commit: ")))) - -(defcustom magit-revision-use-gravatar-kludge nil - "Whether to work around a bug which affects display of gravatars. - -Gravatar images are spliced into two halves which are then -displayed on separate lines. On OS X the splicing has a bug in -some Emacs builds, which causes the top and bottom halves to be -interchanged. Enabling this option works around this issue by -interchanging the halves once more, which cancels out the effect -of the bug. - -See https://github.com/magit/magit/issues/2265 -and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=7847. - -Starting with Emacs 26.1 this kludge should not be required for -any build." - :package-version '(magit . "2.3.0") - :group 'magit-revision - :type 'boolean) - -(defcustom magit-revision-fill-summary-line nil - "Whether to fill excessively long summary lines. - -If this is an integer, then the summary line is filled if it is -longer than either the limit specified here or `window-width'. - -You may want to only set this locally in \".dir-locals-2.el\" for -repositories known to contain bad commit messages. - -The body of the message is left alone because (a) most people who -write excessively long summary lines usually don't add a body and -(b) even people who have the decency to wrap their lines may have -a good reason to include a long line in the body sometimes." - :package-version '(magit . "2.90.0") - :group 'magit-revision - :type '(choice (const :tag "Don't fill" nil) - (integer :tag "Fill if longer than"))) - -(defcustom magit-revision-filter-files-on-follow nil - "Whether to honor file filter if log arguments include --follow. - -When a commit is displayed from a log buffer, the resulting -revision buffer usually shares the log's file arguments, -restricting the diff to those files. However, there's a -complication when the log arguments include --follow: if the log -follows a file across a rename event, keeping the file -restriction would mean showing an empty diff in revision buffers -for commits before the rename event. - -When this option is nil, the revision buffer ignores the log's -filter if the log arguments include --follow. If non-nil, the -log's file filter is always honored." - :package-version '(magit . "3.0.0") - :group 'magit-revision - :type 'boolean) - -;;;; Visit Commands - -(defcustom magit-diff-visit-previous-blob t - "Whether `magit-diff-visit-file' may visit the previous blob. - -When this is t and point is on a removed line in a diff for a -committed change, then `magit-diff-visit-file' visits the blob -from the last revision which still had that line. - -Currently this is only supported for committed changes, for -staged and unstaged changes `magit-diff-visit-file' always -visits the file in the working tree." - :package-version '(magit . "2.9.0") - :group 'magit-diff - :type 'boolean) - -(defcustom magit-diff-visit-avoid-head-blob nil - "Whether `magit-diff-visit-file' avoids visiting a blob from `HEAD'. - -By default `magit-diff-visit-file' always visits the blob that -added the current line, while `magit-diff-visit-worktree-file' -visits the respective file in the working tree. For the `HEAD' -commit, the former command used to visit the worktree file too, -but that made it impossible to visit a blob from `HEAD'. - -When point is on a removed line and that change has not been -committed yet, then `magit-diff-visit-file' now visits the last -blob that still had that line, which is a blob from `HEAD'. -Previously this function used to visit the worktree file not -only for added lines but also for such removed lines. - -If you prefer the old behaviors, then set this to t." - :package-version '(magit . "3.0.0") - :group 'magit-diff - :type 'boolean) - -;;; Faces - -(defface magit-diff-file-heading - `((t ,@(and (>= emacs-major-version 27) '(:extend t)) - :weight bold)) - "Face for diff file headings." - :group 'magit-faces) - -(defface magit-diff-file-heading-highlight - `((t ,@(and (>= emacs-major-version 27) '(:extend t)) - :inherit magit-section-highlight)) - "Face for current diff file headings." - :group 'magit-faces) - -(defface magit-diff-file-heading-selection - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :inherit magit-diff-file-heading-highlight - :foreground "salmon4") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :inherit magit-diff-file-heading-highlight - :foreground "LightSalmon3")) - "Face for selected diff file headings." - :group 'magit-faces) - -(defface magit-diff-hunk-heading - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "grey80" - :foreground "grey30") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "grey25" - :foreground "grey70")) - "Face for diff hunk headings." - :group 'magit-faces) - -(defface magit-diff-hunk-heading-highlight - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "grey75" - :foreground "grey30") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "grey35" - :foreground "grey70")) - "Face for current diff hunk headings." - :group 'magit-faces) - -(defface magit-diff-hunk-heading-selection - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :inherit magit-diff-hunk-heading-highlight - :foreground "salmon4") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :inherit magit-diff-hunk-heading-highlight - :foreground "LightSalmon3")) - "Face for selected diff hunk headings." - :group 'magit-faces) - -(defface magit-diff-hunk-region - `((t :inherit bold - ,@(and (>= emacs-major-version 27) - (list :extend (ignore-errors (face-attribute 'region :extend)))))) - "Face used by `magit-diff-highlight-hunk-region-using-face'. - -This face is overlaid over text that uses other hunk faces, -and those normally set the foreground and background colors. -The `:foreground' and especially the `:background' properties -should be avoided here. Setting the latter would cause the -loss of information. Good properties to set here are `:weight' -and `:slant'." - :group 'magit-faces) - -(defface magit-diff-revision-summary - '((t :inherit magit-diff-hunk-heading)) - "Face for commit message summaries." - :group 'magit-faces) - -(defface magit-diff-revision-summary-highlight - '((t :inherit magit-diff-hunk-heading-highlight)) - "Face for highlighted commit message summaries." - :group 'magit-faces) - -(defface magit-diff-lines-heading - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :inherit magit-diff-hunk-heading-highlight - :background "LightSalmon3") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :inherit magit-diff-hunk-heading-highlight - :foreground "grey80" - :background "salmon4")) - "Face for diff hunk heading when lines are marked." - :group 'magit-faces) - -(defface magit-diff-lines-boundary - `((t ,@(and (>= emacs-major-version 27) '(:extend t)) ; !important - :inherit magit-diff-lines-heading)) - "Face for boundary of marked lines in diff hunk." - :group 'magit-faces) - -(defface magit-diff-conflict-heading - '((t :inherit magit-diff-hunk-heading)) - "Face for conflict markers." - :group 'magit-faces) - -(defface magit-diff-added - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "#ddffdd" - :foreground "#22aa22") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "#335533" - :foreground "#ddffdd")) - "Face for lines in a diff that have been added." - :group 'magit-faces) - -(defface magit-diff-removed - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "#ffdddd" - :foreground "#aa2222") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "#553333" - :foreground "#ffdddd")) - "Face for lines in a diff that have been removed." - :group 'magit-faces) - -(defface magit-diff-our - '((t :inherit magit-diff-removed)) - "Face for lines in a diff for our side in a conflict." - :group 'magit-faces) - -(defface magit-diff-base - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "#ffffcc" - :foreground "#aaaa11") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "#555522" - :foreground "#ffffcc")) - "Face for lines in a diff for the base side in a conflict." - :group 'magit-faces) - -(defface magit-diff-their - '((t :inherit magit-diff-added)) - "Face for lines in a diff for their side in a conflict." - :group 'magit-faces) - -(defface magit-diff-context - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :foreground "grey50") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :foreground "grey70")) - "Face for lines in a diff that are unchanged." - :group 'magit-faces) - -(defface magit-diff-added-highlight - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "#cceecc" - :foreground "#22aa22") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "#336633" - :foreground "#cceecc")) - "Face for lines in a diff that have been added." - :group 'magit-faces) - -(defface magit-diff-removed-highlight - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "#eecccc" - :foreground "#aa2222") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "#663333" - :foreground "#eecccc")) - "Face for lines in a diff that have been removed." - :group 'magit-faces) - -(defface magit-diff-our-highlight - '((t :inherit magit-diff-removed-highlight)) - "Face for lines in a diff for our side in a conflict." - :group 'magit-faces) - -(defface magit-diff-base-highlight - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "#eeeebb" - :foreground "#aaaa11") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "#666622" - :foreground "#eeeebb")) - "Face for lines in a diff for the base side in a conflict." - :group 'magit-faces) - -(defface magit-diff-their-highlight - '((t :inherit magit-diff-added-highlight)) - "Face for lines in a diff for their side in a conflict." - :group 'magit-faces) - -(defface magit-diff-context-highlight - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "grey95" - :foreground "grey50") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "grey20" - :foreground "grey70")) - "Face for lines in the current context in a diff." - :group 'magit-faces) - -(defface magit-diff-whitespace-warning - '((t :inherit trailing-whitespace)) - "Face for highlighting whitespace errors added lines." - :group 'magit-faces) - -(defface magit-diffstat-added - '((((class color) (background light)) :foreground "#22aa22") - (((class color) (background dark)) :foreground "#448844")) - "Face for plus sign in diffstat." - :group 'magit-faces) - -(defface magit-diffstat-removed - '((((class color) (background light)) :foreground "#aa2222") - (((class color) (background dark)) :foreground "#aa4444")) - "Face for minus sign in diffstat." - :group 'magit-faces) - -;;; Arguments -;;;; Prefix Classes - -(defclass magit-diff-prefix (transient-prefix) - ((history-key :initform 'magit-diff) - (major-mode :initform 'magit-diff-mode))) - -(defclass magit-diff-refresh-prefix (magit-diff-prefix) - ((history-key :initform 'magit-diff) - (major-mode :initform nil))) - -;;;; Prefix Methods - -(cl-defmethod transient-init-value ((obj magit-diff-prefix)) - (pcase-let ((`(,args ,files) - (magit-diff--get-value 'magit-diff-mode - magit-prefix-use-buffer-arguments))) - (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)))) - -(cl-defmethod transient-init-value ((obj magit-diff-refresh-prefix)) - (oset obj value (if magit-buffer-diff-files - `(("--" ,@magit-buffer-diff-files) - ,magit-buffer-diff-args) - magit-buffer-diff-args))) - -(cl-defmethod transient-set-value ((obj magit-diff-prefix)) - (magit-diff--set-value obj)) - -(cl-defmethod transient-save-value ((obj magit-diff-prefix)) - (magit-diff--set-value obj 'save)) - -;;;; Argument Access - -(defun magit-diff-arguments (&optional mode) - "Return the current diff arguments." - (if (memq transient-current-command '(magit-diff magit-diff-refresh)) - (pcase-let ((`(,args ,alist) - (-separate #'atom (transient-get-value)))) - (list args (cdr (assoc "--" alist)))) - (magit-diff--get-value (or mode 'magit-diff-mode)))) - -(defun magit-diff--get-value (mode &optional use-buffer-args) - (unless use-buffer-args - (setq use-buffer-args magit-direct-use-buffer-arguments)) - (let (args files) - (cond - ((and (memq use-buffer-args '(always selected current)) - (eq major-mode mode)) - (setq args magit-buffer-diff-args) - (setq files magit-buffer-diff-files)) - ((and (memq use-buffer-args '(always selected)) - (when-let ((buffer (magit-get-mode-buffer - mode nil - (eq use-buffer-args 'selected)))) - (setq args (buffer-local-value 'magit-buffer-diff-args buffer)) - (setq files (buffer-local-value 'magit-buffer-diff-files buffer)) - t))) - ((plist-member (symbol-plist mode) 'magit-diff-current-arguments) - (setq args (get mode 'magit-diff-current-arguments))) - ((when-let ((elt (assq (intern (format "magit-diff:%s" mode)) - transient-values))) - (setq args (cdr elt)) - t)) - (t - (setq args (get mode 'magit-diff-default-arguments)))) - (list args files))) - -(defun magit-diff--set-value (obj &optional save) - (pcase-let* ((obj (oref obj prototype)) - (mode (or (oref obj major-mode) major-mode)) - (key (intern (format "magit-diff:%s" mode))) - (`(,args ,alist) - (-separate #'atom (transient-get-value))) - (files (cdr (assoc "--" alist)))) - (put mode 'magit-diff-current-arguments args) - (when save - (setf (alist-get key transient-values) args) - (transient-save-values)) - (transient--history-push obj) - (setq magit-buffer-diff-args args) - (setq magit-buffer-diff-files files) - (magit-refresh))) - -;;; Section Classes - -(defclass magit-file-section (magit-section) - ((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) - ((keymap :initform 'magit-hunk-section-map) - (refined :initform nil) - (combined :initform nil) - (from-range :initform nil) - (from-ranges :initform nil) - (to-range :initform nil) - (about :initform nil))) - -(setf (alist-get 'hunk magit--section-type-alist) 'magit-hunk-section) -(setf (alist-get 'module magit--section-type-alist) 'magit-module-section) -(setf (alist-get 'file magit--section-type-alist) 'magit-file-section) - -;;; Commands -;;;; Prefix Commands - -;;;###autoload (autoload 'magit-diff "magit-diff" nil t) -(transient-define-prefix magit-diff () - "Show changes between different versions." - :man-page "git-diff" - :class 'magit-diff-prefix - ["Limit arguments" - (magit:--) - (magit-diff:--ignore-submodules) - ("-b" "Ignore whitespace changes" ("-b" "--ignore-space-change")) - ("-w" "Ignore all whitespace" ("-w" "--ignore-all-space")) - (5 "-D" "Omit preimage for deletes" ("-D" "--irreversible-delete"))] - ["Context arguments" - (magit-diff:-U) - ("-W" "Show surrounding functions" ("-W" "--function-context"))] - ["Tune arguments" - (magit-diff:--diff-algorithm) - (magit-diff:-M) - (magit-diff:-C) - ("-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" - [("d" "Dwim" magit-diff-dwim) - ("r" "Diff range" magit-diff-range) - ("p" "Diff paths" magit-diff-paths)] - [("u" "Diff unstaged" magit-diff-unstaged) - ("s" "Diff staged" magit-diff-staged) - ("w" "Diff worktree" magit-diff-working-tree)] - [("c" "Show commit" magit-show-commit) - ("t" "Show stash" magit-stash-show)]]) - -;;;###autoload (autoload 'magit-diff-refresh "magit-diff" nil t) -(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 - ["Limit arguments" - (magit:--) - (magit-diff:--ignore-submodules) - ("-b" "Ignore whitespace changes" ("-b" "--ignore-space-change")) - ("-w" "Ignore all whitespace" ("-w" "--ignore-all-space")) - (5 "-D" "Omit preimage for deletes" ("-D" "--irreversible-delete"))] - ["Context arguments" - (magit-diff:-U) - ("-W" "Show surrounding functions" ("-W" "--function-context"))] - ["Tune arguments" - (magit-diff:--diff-algorithm) - (magit-diff:-M) - (magit-diff:-C) - ("-x" "Disallow external diff drivers" "--no-ext-diff") - ("-s" "Show stats" "--stat" - :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" - ("g" "buffer" magit-diff-refresh) - ("s" "buffer and set defaults" transient-set :transient nil) - ("w" "buffer and save defaults" transient-save :transient nil)] - ["Toggle" - ("t" "hunk refinement" magit-diff-toggle-refine-hunk) - ("F" "file filter" magit-diff-toggle-file-filter) - ("b" "buffer lock" magit-toggle-buffer-lock - :if-mode (magit-diff-mode magit-revision-mode magit-stash-mode))] - [:if-mode magit-diff-mode - :description "Do" - ("r" "switch range type" magit-diff-switch-range-type) - ("f" "flip revisions" magit-diff-flip-revs)]] - (interactive) - (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) - (setq magit-buffer-diff-files files)) - (magit-refresh))) - -;;;; Infix Commands - -(transient-define-argument magit:-- () - :description "Limit to files" - :class 'transient-files - :key "--" - :argument "--" - :prompt "Limit to file(s): " - :reader 'magit-read-files - :multi-value t) - -(defun magit-read-files (prompt initial-input history) - (magit-completing-read-multiple* prompt - (magit-list-files) - nil nil - (or initial-input (magit-file-at-point)) - history)) - -(transient-define-argument magit-diff:-U () - :description "Context lines" - :class 'transient-option - :argument "-U" - :reader 'transient-read-number-N0) - -(transient-define-argument magit-diff:-M () - :description "Detect renames" - :class 'transient-option - :argument "-M" - :reader 'transient-read-number-N+) - -(transient-define-argument magit-diff:-C () - :description "Detect copies" - :class 'transient-option - :argument "-C" - :reader 'transient-read-number-N+) - -(transient-define-argument magit-diff:--diff-algorithm () - :description "Diff algorithm" - :class 'transient-option - :key "-A" - :argument "--diff-algorithm=" - :reader 'magit-diff-select-algorithm) - -(defun magit-diff-select-algorithm (&rest _ignore) - (magit-read-char-case nil t - (?d "[d]efault" "default") - (?m "[m]inimal" "minimal") - (?p "[p]atience" "patience") - (?h "[h]istogram" "histogram"))) - -(transient-define-argument magit-diff:--ignore-submodules () - :description "Ignore submodules" - :class 'transient-option - :key "-i" - :argument "--ignore-submodules=" - :reader 'magit-diff-select-ignore-submodules) - -(defun magit-diff-select-ignore-submodules (&rest _ignored) - (magit-read-char-case "Ignore submodules " t - (?u "[u]ntracked" "untracked") - (?d "[d]irty" "dirty") - (?a "[a]ll" "all"))) - -(transient-define-argument magit-diff:--color-moved () - :description "Color moved lines" - :class 'transient-option - :key "-m" - :argument "--color-moved=" - :reader 'magit-diff-select-color-moved-mode) - -(defun magit-diff-select-color-moved-mode (&rest _ignore) - (magit-read-char-case "Color moved " t - (?d "[d]efault" "default") - (?p "[p]lain" "plain") - (?b "[b]locks" "blocks") - (?z "[z]ebra" "zebra") - (?Z "[Z] dimmed-zebra" "dimmed-zebra"))) - -(transient-define-argument magit-diff:--color-moved-ws () - :description "Whitespace treatment for --color-moved" - :class 'transient-option - :key "=w" - :argument "--color-moved-ws=" - :reader 'magit-diff-select-color-moved-ws-mode) - -(defun magit-diff-select-color-moved-ws-mode (&rest _ignore) - (magit-read-char-case "Ignore whitespace " t - (?i "[i]ndentation" "allow-indentation-change") - (?e "[e]nd of line" "ignore-space-at-eol") - (?s "[s]pace change" "ignore-space-change") - (?a "[a]ll space" "ignore-all-space") - (?n "[n]o" "no"))) - -;;;; Setup Commands - -;;;###autoload -(defun magit-diff-dwim (&optional args files) - "Show changes for the thing at point." - (interactive (magit-diff-arguments)) - (pcase (magit-diff--dwim) - (`unmerged (magit-diff-unmerged args files)) - (`unstaged (magit-diff-unstaged args files)) - (`staged - (let ((file (magit-file-at-point))) - (if (and file (equal (cddr (car (magit-file-status file))) '(?D ?U))) - ;; File was deleted by us and modified by them. Show the latter. - (magit-diff-unmerged args (list file)) - (magit-diff-staged nil args files)))) - (`(commit . ,value) - (magit-diff-range (format "%s^..%s" value value) args files)) - (`(stash . ,value) (magit-stash-show value args)) - ((and range (pred stringp)) - (magit-diff-range range args files)) - (_ - (call-interactively #'magit-diff-range)))) - -(defun magit-diff--dwim () - "Return information for performing DWIM diff. - -The information can be in three forms: -1. TYPE - A symbol describing a type of diff where no additional information - is needed to generate the diff. Currently, this includes `staged', - `unstaged' and `unmerged'. -2. (TYPE . VALUE) - Like #1 but the diff requires additional information, which is - given by VALUE. Currently, this includes `commit' and `stash', - where VALUE is the given commit or stash, respectively. -3. RANGE - A string indicating a diff range. - -If no DWIM context is found, nil is returned." - (cond - ((--when-let (magit-region-values '(commit branch) t) - (deactivate-mark) - (concat (car (last it)) ".." (car it)))) - (magit-buffer-refname - (cons 'commit magit-buffer-refname)) - ((derived-mode-p 'magit-stash-mode) - (cons 'commit - (magit-section-case - (commit (oref it 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) - magit-buffer-range) - (t - (magit-section-case - ([* unstaged] 'unstaged) - ([* staged] 'staged) - (unmerged 'unmerged) - (unpushed (oref it value)) - (unpulled (oref it value)) - (branch (let ((current (magit-get-current-branch)) - (atpoint (oref it value))) - (if (equal atpoint current) - (--if-let (magit-get-upstream-branch) - (format "%s...%s" it current) - (if (magit-anything-modified-p) - current - (cons 'commit current))) - (format "%s...%s" - (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 (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. -If MBASE is non-nil, prompt for which rev to place at the end of -a \"revA...revB\" range. Otherwise, always construct -\"revA..revB\" range." - (--if-let (magit-region-values '(commit branch) t) - (let ((revA (car (last it))) - (revB (car it))) - (deactivate-mark) - (if mbase - (let ((base (magit-git-string "merge-base" revA revB))) - (cond - ((string= (magit-rev-parse revA) base) - (format "%s..%s" revA revB)) - ((string= (magit-rev-parse revB) base) - (format "%s..%s" revB revA)) - (t - (let ((main (magit-completing-read "View changes along" - (list revA revB) - nil t nil nil revB))) - (format "%s...%s" - (if (string= main revB) revA revB) main))))) - (format "%s..%s" revA revB))) - (magit-read-range prompt - (or (pcase (magit-diff--dwim) - (`(commit . ,value) - (format "%s^..%s" value value)) - ((and range (pred stringp)) - range)) - secondary-default - (magit-get-current-branch))))) - -;;;###autoload -(defun magit-diff-range (rev-or-range &optional args files) - "Show differences between two commits. - -REV-OR-RANGE should be a range or a single revision. If it is a -revision, then show changes in the working tree relative to that -revision. If it is a range, but one side is omitted, then show -changes relative to `HEAD'. - -If the region is active, use the revisions on the first and last -line of the region as the two sides of the range. With a prefix -argument, instead of diffing the revisions, choose a revision to -view changes along, starting at the common ancestor of both -revisions (i.e., use a \"...\" range)." - (interactive (cons (magit-diff-read-range-or-commit "Diff for range" - nil current-prefix-arg) - (magit-diff-arguments))) - (magit-diff-setup-buffer rev-or-range nil args files)) - -;;;###autoload -(defun magit-diff-working-tree (&optional rev args files) - "Show changes between the current working tree and the `HEAD' commit. -With a prefix argument show changes between the working tree and -a commit read from the minibuffer." - (interactive - (cons (and current-prefix-arg - (magit-read-branch-or-commit "Diff working tree and commit")) - (magit-diff-arguments))) - (magit-diff-setup-buffer (or rev "HEAD") nil args files)) - -;;;###autoload -(defun magit-diff-staged (&optional rev args files) - "Show changes between the index and the `HEAD' commit. -With a prefix argument show changes between the index and -a commit read from the minibuffer." - (interactive - (cons (and current-prefix-arg - (magit-read-branch-or-commit "Diff index and commit")) - (magit-diff-arguments))) - (magit-diff-setup-buffer rev "--cached" args files)) - -;;;###autoload -(defun magit-diff-unstaged (&optional args files) - "Show changes between the working tree and the index." - (interactive (magit-diff-arguments)) - (magit-diff-setup-buffer nil nil args files)) - -;;;###autoload -(defun magit-diff-unmerged (&optional args files) - "Show changes that are being merged." - (interactive (magit-diff-arguments)) - (unless (magit-merge-in-progress-p) - (user-error "No merge is in progress")) - (magit-diff-setup-buffer (magit--merge-range) nil args files)) - -;;;###autoload -(defun magit-diff-while-committing (&optional args) - "While committing, show the changes that are about to be committed. -While amending, invoking the command again toggles between -showing just the new changes or all the changes that will -be committed." - (interactive (list (car (magit-diff-arguments)))) - (unless (magit-commit-message-buffer) - (user-error "No commit in progress")) - (let ((magit-display-buffer-noselect t)) - (if-let ((diff-buf (magit-get-mode-buffer 'magit-diff-mode 'selected))) - (with-current-buffer diff-buf - (cond ((and (equal magit-buffer-range "HEAD^") - (equal magit-buffer-typearg "--cached")) - (magit-diff-staged nil args)) - ((and (equal magit-buffer-range nil) - (equal magit-buffer-typearg "--cached")) - (magit-diff-while-amending args)) - ((magit-anything-staged-p) - (magit-diff-staged nil args)) - (t - (magit-diff-while-amending args)))) - (if (magit-anything-staged-p) - (magit-diff-staged nil args) - (magit-diff-while-amending args))))) - -(define-key git-commit-mode-map - (kbd "C-c C-d") 'magit-diff-while-committing) - -(defun magit-diff-while-amending (&optional args) - (magit-diff-setup-buffer "HEAD^" "--cached" args nil)) - -;;;###autoload -(defun magit-diff-buffer-file () - "Show diff for the blob or file visited in the current buffer. - -When the buffer visits a blob, then show the respective commit. -When the buffer visits a file, then show the differenced between -`HEAD' and the working tree. In both cases limit the diff to -the file or blob." - (interactive) - (require 'magit) - (if-let ((file (magit-file-relative-name))) - (if magit-buffer-refname - (magit-show-commit magit-buffer-refname - (car (magit-show-commit--arguments)) - (list file)) - (save-buffer) - (let ((line (line-number-at-pos)) - (col (current-column))) - (with-current-buffer - (magit-diff-setup-buffer (or (magit-get-current-branch) "HEAD") - nil - (car (magit-diff-arguments)) - (list file) - magit-diff-buffer-file-locked) - (magit-diff--goto-position file line col)))) - (user-error "Buffer isn't visiting a file"))) - -;;;###autoload -(defun magit-diff-paths (a b) - "Show changes between any two files on disk." - (interactive (list (read-file-name "First file: " nil nil t) - (read-file-name "Second file: " nil nil t))) - (magit-diff-setup-buffer nil "--no-index" - nil (list (magit-convert-filename-for-git - (expand-file-name a)) - (magit-convert-filename-for-git - (expand-file-name b))))) - -(defun magit-show-commit--arguments () - (pcase-let ((`(,args ,diff-files) - (magit-diff-arguments 'magit-revision-mode))) - (list args (if (derived-mode-p 'magit-log-mode) - (and (or magit-revision-filter-files-on-follow - (not (member "--follow" magit-buffer-log-args))) - magit-buffer-log-files) - diff-files)))) - -;;;###autoload -(defun magit-show-commit (rev &optional args files module) - "Visit the revision at point in another buffer. -If there is no revision at point or with a prefix argument prompt -for a revision." - (interactive - (pcase-let* ((mcommit (magit-section-value-if 'module-commit)) - (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) - (magit-read-branch-or-commit "Show commit" atpoint)) - args - files - (and mcommit - (magit-section-parent-value (magit-current-section)))))) - (require 'magit) - (let ((file (magit-file-relative-name))) - (magit-with-toplevel - (when module - (setq default-directory - (expand-file-name (file-name-as-directory module)))) - (unless (magit-commit-p rev) - (user-error "%s is not a commit" rev)) - (let ((buf (magit-revision-setup-buffer rev args files))) - (when file - (save-buffer) - (let ((line (magit-diff-visit--offset file (list "-R" rev) - (line-number-at-pos))) - (col (current-column))) - (with-current-buffer buf - (magit-diff--goto-position file line col)))))))) - -(defun magit-diff--locate-hunk (file line &optional parent) - (when-let ((diff (cl-find-if (lambda (section) - (and (cl-typep section 'magit-file-section) - (equal (oref section value) file))) - (oref (or parent magit-root-section) children)))) - (let (hunk (hunks (oref diff children))) - (cl-block nil - (while (setq hunk (pop hunks)) - (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))) - (pcase-let ((`(,section ,exact) pos)) - (cond ((cl-typep section 'magit-file-section) - (goto-char (oref section start))) - (exact - (goto-char (oref section content)) - (let ((pos (car (oref section to-range)))) - (while (or (< pos line) - (= (char-after) ?-)) - (unless (= (char-after) ?-) - (cl-incf pos)) - (forward-line))) - (forward-char (1+ column))) - (t - (goto-char (oref section start)) - (setq section (oref section parent)))) - (while section - (when (oref section hidden) - (magit-section-show section)) - (setq section (oref section parent)))) - (magit-section-update-highlight) - t)) - -;;;; Setting Commands - -(defun magit-diff-switch-range-type () - "Convert diff range type. -Change \"revA..revB\" to \"revA...revB\", or vice versa." - (interactive) - (if (and magit-buffer-range - (derived-mode-p 'magit-diff-mode) - (string-match magit-range-re magit-buffer-range)) - (setq magit-buffer-range - (replace-match (if (string= (match-string 2 magit-buffer-range) "..") - "..." - "..") - t t magit-buffer-range 2)) - (user-error "No range to change")) - (magit-refresh)) - -(defun magit-diff-flip-revs () - "Swap revisions in diff range. -Change \"revA..revB\" to \"revB..revA\"." - (interactive) - (if (and magit-buffer-range - (derived-mode-p 'magit-diff-mode) - (string-match magit-range-re magit-buffer-range)) - (progn - (setq magit-buffer-range - (concat (match-string 3 magit-buffer-range) - (match-string 2 magit-buffer-range) - (match-string 1 magit-buffer-range))) - (magit-refresh)) - (user-error "No range to swap"))) - -(defun magit-diff-toggle-file-filter () - "Toggle the file restriction of the current buffer's diffs. -If the current buffer's mode is derived from `magit-log-mode', -toggle the file restriction in the repository's revision buffer -instead." - (interactive) - (cl-flet ((toggle () - (if (or magit-buffer-diff-files - magit-buffer-diff-files-suspended) - (cl-rotatef magit-buffer-diff-files - magit-buffer-diff-files-suspended) - (setq magit-buffer-diff-files - (transient-infix-read 'magit:--))) - (magit-refresh))) - (cond - ((derived-mode-p 'magit-log-mode - 'magit-cherry-mode - 'magit-reflog-mode) - (if-let ((buffer (magit-get-mode-buffer 'magit-revision-mode))) - (with-current-buffer buffer (toggle)) - (message "No revision buffer"))) - ((local-variable-p 'magit-buffer-diff-files) - (toggle)) - (t - (user-error "Cannot toggle file filter in this buffer"))))) - -(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))))) - -(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)))) - -(defun magit-diff-default-context () - "Reset context for diff hunks to the default height." - (interactive) - (magit-diff-set-context #'ignore)) - -(defun magit-diff-set-context (fn) - (let* ((def (--if-let (magit-get "diff.context") (string-to-number it) 3)) - (val magit-buffer-diff-args) - (arg (--first (string-match "^-U\\([0-9]+\\)?$" it) val)) - (num (--if-let (and arg (match-string 1 arg)) (string-to-number it) def)) - (val (delete arg val)) - (num (funcall fn num)) - (arg (and num (not (= num def)) (format "-U%i" num))) - (val (if arg (cons arg val) val))) - (setq magit-buffer-diff-args val)) - (magit-refresh)) - -(defun magit-diff-context-p () - (if-let ((arg (--first (string-match "^-U\\([0-9]+\\)$" it) - magit-buffer-diff-args))) - (not (equal arg "-U0")) - t)) - -(defun magit-diff-ignore-any-space-p () - (--any-p (member it magit-buffer-diff-args) - '("--ignore-cr-at-eol" - "--ignore-space-at-eol" - "--ignore-space-change" "-b" - "--ignore-all-space" "-w" - "--ignore-blank-space"))) - -(defun magit-diff-toggle-refine-hunk (&optional style) - "Turn diff-hunk refining on or off. - -If hunk refining is currently on, then hunk refining is turned off. -If hunk refining is off, then hunk refining is turned on, in -`selected' mode (only the currently selected hunk is refined). - -With a prefix argument, the \"third choice\" is used instead: -If hunk refining is currently on, then refining is kept on, but -the refining mode (`selected' or `all') is switched. -If hunk refining is off, then hunk refining is turned on, in -`all' mode (all hunks refined). - -Customize variable `magit-diff-refine-hunk' to change the default mode." - (interactive "P") - (setq-local magit-diff-refine-hunk - (if style - (if (eq magit-diff-refine-hunk 'all) t 'all) - (not magit-diff-refine-hunk))) - (magit-diff-update-hunk-refinement)) - -;;;; Visit Commands -;;;;; Dwim Variants - -(defun magit-diff-visit-file (file &optional other-window) - "From a diff visit the appropriate version of FILE. - -Display the buffer in the selected window. With a prefix -argument OTHER-WINDOW display the buffer in another window -instead. - -Visit the worktree version of the appropriate file. The location -of point inside the diff determines which file is being visited. -The visited version depends on what changes the diff is about. - -1. If the diff shows uncommitted changes (i.e. stage or unstaged - changes), then visit the file in the working tree (i.e. the - same \"real\" file that `find-file' would visit. In all other - cases visit a \"blob\" (i.e. the version of a file as stored - in some commit). - -2. If point is on a removed line, then visit the blob for the - first parent of the commit that removed that line, i.e. the - last commit where that line still exists. - -3. If point is on an added or context line, then visit the blob - that adds that line, or if the diff shows from more than a - single commit, then visit the blob from the last of these - commits. - -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) 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 - #'switch-to-buffer-other-window - #'pop-to-buffer-same-window))) - -(defun magit-diff-visit-file-other-window (file) - "From a diff visit the appropriate version of FILE in another window. -Like `magit-diff-visit-file' but use -`switch-to-buffer-other-window'." - (interactive (list (magit-file-at-point t t))) - (magit-diff-visit-file--internal file nil #'switch-to-buffer-other-window)) - -(defun magit-diff-visit-file-other-frame (file) - "From a diff visit the appropriate version of FILE in another frame. -Like `magit-diff-visit-file' but use -`switch-to-buffer-other-frame'." - (interactive (list (magit-file-at-point t t))) - (magit-diff-visit-file--internal file nil #'switch-to-buffer-other-frame)) - -;;;;; Worktree Variants - -(defun magit-diff-visit-worktree-file (file &optional other-window) - "From a diff visit the worktree version of FILE. - -Display the buffer in the selected window. With a prefix -argument OTHER-WINDOW display the buffer in another window -instead. - -Visit the worktree version of the appropriate file. The location -of point inside the diff determines which file is being visited. - -Unlike `magit-diff-visit-file' always visits the \"real\" file in -the working tree, i.e the \"current version\" of the file. - -In the file-visiting buffer also go to the line that corresponds -to the line that point is on in the diff. Lines that were added -or removed in the working tree, the index and other commits in -between are automatically accounted for." - (interactive (list (magit-file-at-point t t) current-prefix-arg)) - (magit-diff-visit-file--internal file t - (if other-window - #'switch-to-buffer-other-window - #'pop-to-buffer-same-window))) - -(defun magit-diff-visit-worktree-file-other-window (file) - "From a diff visit the worktree version of FILE in another window. -Like `magit-diff-visit-worktree-file' but use -`switch-to-buffer-other-window'." - (interactive (list (magit-file-at-point t t))) - (magit-diff-visit-file--internal file t #'switch-to-buffer-other-window)) - -(defun magit-diff-visit-worktree-file-other-frame (file) - "From a diff visit the worktree version of FILE in another frame. -Like `magit-diff-visit-worktree-file' but use -`switch-to-buffer-other-frame'." - (interactive (list (magit-file-at-point t t))) - (magit-diff-visit-file--internal file t #'switch-to-buffer-other-frame)) - -;;;;; Internal - -(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 -to display the buffer in some window." - (if (magit-file-accessible-directory-p file) - (magit-diff-visit-directory file force-worktree) - (pcase-let ((`(,buf ,pos) - (magit-diff-visit-file--noselect file force-worktree))) - (funcall fn buf) - (magit-diff-visit-file--setup buf pos) - buf))) - -(defun magit-diff-visit-directory (directory &optional other-window) - "Visit DIRECTORY in some window. -Display the buffer in the selected window unless OTHER-WINDOW is -non-nil. If DIRECTORY is the top-level directory of the current -repository, then visit the containing directory using Dired and -in the Dired buffer put point on DIRECTORY. Otherwise display -the Magit-Status buffer for DIRECTORY." - (if (equal (magit-toplevel directory) - (magit-toplevel)) - (dired-jump other-window (concat directory "/.")) - (let ((display-buffer-overriding-action - (if other-window - '(nil (inhibit-same-window t)) - '(display-buffer-same-window)))) - (magit-status-setup-buffer directory)))) - -(defun magit-diff-visit-file--setup (buf pos) - (if-let ((win (get-buffer-window buf 'visible))) - (with-selected-window win - (when pos - (unless (<= (point-min) pos (point-max)) - (widen)) - (goto-char pos)) - (when (and buffer-file-name - (magit-anything-unmerged-p buffer-file-name)) - (smerge-start-session)) - (run-hooks 'magit-diff-visit-file-hook)) - (error "File buffer is not visible"))) - -(defun magit-diff-visit-file--noselect (&optional file goto-worktree) - (unless file - (setq file (magit-file-at-point t t))) - (let* ((hunk (magit-diff-visit--hunk)) - (goto-from (and hunk - (magit-diff-visit--goto-from-p hunk goto-worktree))) - (line (and hunk (magit-diff-hunk-line hunk goto-from))) - (col (and hunk (magit-diff-hunk-column hunk goto-from))) - (spec (magit-diff--dwim)) - (rev (if goto-from - (magit-diff-visit--range-from spec) - (magit-diff-visit--range-to spec))) - (buf (if (or goto-worktree - (and (not (stringp rev)) - (or magit-diff-visit-avoid-head-blob - (not goto-from)))) - (or (get-file-buffer file) - (find-file-noselect file)) - (magit-find-file-noselect (if (stringp rev) rev "HEAD") - file)))) - (if line - (with-current-buffer buf - (cond ((eq rev 'staged) - (setq line (magit-diff-visit--offset file nil line))) - ((and goto-worktree - (stringp rev)) - (setq line (magit-diff-visit--offset file rev line)))) - (list buf (save-restriction - (widen) - (goto-char (point-min)) - (forward-line (1- line)) - (move-to-column col) - (point)))) - (list buf nil)))) - -(defun magit-diff-visit--hunk () - (when-let ((scope (magit-diff-scope))) - (let ((section (magit-current-section))) - (cl-case scope - ((file files) - (setq section (car (oref section children)))) - (list - (setq section (car (oref section children))) - (when section - (setq section (car (oref section children)))))) - (and - ;; Unmerged files appear in the list of staged changes - ;; but unlike in the list of unstaged changes no diffs - ;; are shown here. In that case `section' is nil. - section - ;; Currently the `hunk' type is also abused for file - ;; mode changes, which we are not interested in here. - ;; Such sections have no value. - (oref section value) - section)))) - -(defun magit-diff-visit--goto-from-p (section in-worktree) - (and magit-diff-visit-previous-blob - (not in-worktree) - (not (oref section combined)) - (not (< (point) (oref section content))) - (= (char-after (line-beginning-position)) ?-))) - -(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) - (goto-char content) - (re-search-forward "^[-+]")) - (+ (car (if goto-from from-range to-range)) - (let ((prefix (if combined (length from-ranges) 1)) - (target (point)) - (offset 0)) - (goto-char content) - (while (< (point) target) - (unless (string-match-p - (if goto-from "\\+" "-") - (buffer-substring (point) (+ (point) prefix))) - (cl-incf offset)) - (forward-line)) - offset))))) - -(defun magit-diff-hunk-column (section goto-from) - (if (or (< (point) - (oref section content)) - (and (not goto-from) - (= (char-after (line-beginning-position)) ?-))) - 0 - (max 0 (- (+ (current-column) 2) - (length (oref section value)))))) - -(defun magit-diff-visit--range-from (spec) - (cond ((consp spec) - (concat (cdr spec) "^")) - ((stringp spec) - (car (magit-split-range spec))) - (t - spec))) - -(defun magit-diff-visit--range-to (spec) - (if (symbolp spec) - spec - (let ((rev (if (consp spec) - (cdr spec) - (cdr (magit-split-range spec))))) - (if (and magit-diff-visit-avoid-head-blob - (magit-rev-head-p rev)) - 'unstaged - rev)))) - -(defun magit-diff-visit--offset (file rev line) - (let ((offset 0)) - (with-temp-buffer - (save-excursion - (magit-with-toplevel - (magit-git-insert "diff" rev "--" file))) - (catch 'found - (while (re-search-forward - "^@@ -\\([0-9]+\\),\\([0-9]+\\) \\+\\([0-9]+\\),\\([0-9]+\\) @@.*\n" - nil t) - (let ((from-beg (string-to-number (match-string 1))) - (from-len (string-to-number (match-string 2))) - ( to-len (string-to-number (match-string 4)))) - (if (<= from-beg line) - (if (< (+ from-beg from-len) line) - (cl-incf offset (- to-len from-len)) - (let ((rest (- line from-beg))) - (while (> rest 0) - (pcase (char-after) - (?\s (cl-decf rest)) - (?- (cl-decf offset) (cl-decf rest)) - (?+ (cl-incf offset))) - (forward-line)))) - (throw 'found nil)))))) - (+ line offset))) - -;;;; Scroll Commands - -(defun magit-diff-show-or-scroll-up () - "Update the commit or diff buffer for the thing at point. - -Either show the commit or stash at point in the appropriate -buffer, or if that buffer is already being displayed in the -current frame and contains information about that commit or -stash, then instead scroll the buffer up. If there is no -commit or stash at point, then prompt for a commit." - (interactive) - (magit-diff-show-or-scroll 'scroll-up)) - -(defun magit-diff-show-or-scroll-down () - "Update the commit or diff buffer for the thing at point. - -Either show the commit or stash at point in the appropriate -buffer, or if that buffer is already being displayed in the -current frame and contains information about that commit or -stash, then instead scroll the buffer down. If there is no -commit or stash at point, then prompt for a commit." - (interactive) - (magit-diff-show-or-scroll 'scroll-down)) - -(defun magit-diff-show-or-scroll (fn) - (let (rev cmd buf win) - (cond - (magit-blame-mode - (setq rev (oref (magit-current-blame-chunk) orig-rev)) - (setq cmd 'magit-show-commit) - (setq buf (magit-get-mode-buffer 'magit-revision-mode))) - ((derived-mode-p 'git-rebase-mode) - (with-slots (action-type target) - (git-rebase-current-line) - (if (not (eq action-type 'commit)) - (user-error "No commit on this line") - (setq rev target) - (setq cmd 'magit-show-commit) - (setq buf (magit-get-mode-buffer 'magit-revision-mode))))) - (t - (magit-section-case - (branch - (setq rev (magit-ref-maybe-qualify (oref it value))) - (setq cmd 'magit-show-commit) - (setq buf (magit-get-mode-buffer 'magit-revision-mode))) - (commit - (setq rev (oref it value)) - (setq cmd 'magit-show-commit) - (setq buf (magit-get-mode-buffer 'magit-revision-mode))) - (stash - (setq rev (oref it value)) - (setq cmd 'magit-stash-show) - (setq buf (magit-get-mode-buffer 'magit-stash-mode)))))) - (if rev - (if (and buf - (setq win (get-buffer-window buf)) - (with-current-buffer buf - (and (equal rev magit-buffer-revision) - (equal (magit-rev-parse rev) - magit-buffer-revision-hash)))) - (with-selected-window win - (condition-case nil - (funcall fn) - (error - (goto-char (pcase fn - (`scroll-up (point-min)) - (`scroll-down (point-max))))))) - (let ((magit-display-buffer-noselect t)) - (if (eq cmd 'magit-show-commit) - (apply #'magit-show-commit rev (magit-show-commit--arguments)) - (funcall cmd rev)))) - (call-interactively #'magit-show-commit)))) - -;;;; Section Commands - -(defun magit-section-cycle-diffs () - "Cycle visibility of diff-related sections in the current buffer." - (interactive) - (when-let ((sections - (cond ((derived-mode-p 'magit-status-mode) - (--mapcat - (when it - (when (oref it hidden) - (magit-section-show it)) - (oref it children)) - (list (magit-get-section '((staged) (status))) - (magit-get-section '((unstaged) (status)))))) - ((derived-mode-p 'magit-diff-mode) - (-filter #'magit-file-section-p - (oref magit-root-section children)))))) - (if (--any-p (oref it hidden) sections) - (dolist (s sections) - (magit-section-show s) - (magit-section-hide-children s)) - (let ((children (--mapcat (oref it children) sections))) - (cond ((and (--any-p (oref it hidden) children) - (--any-p (oref it children) children)) - (mapc 'magit-section-show-headings sections)) - ((seq-some 'magit-section-hidden-body children) - (mapc 'magit-section-show-children sections)) - (t - (mapc 'magit-section-hide sections))))))) - -;;; Diff Mode - -(defvar magit-diff-mode-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map magit-mode-map) - (define-key map (kbd "C-c C-d") 'magit-diff-while-committing) - (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 "SPC") 'scroll-up) - (define-key map (kbd "DEL") 'scroll-down) - (define-key map (kbd "j") 'magit-jump-to-diffstat-or-diff) - (define-key map [remap write-file] 'magit-patch-save) - map) - "Keymap for `magit-diff-mode'.") - -(define-derived-mode magit-diff-mode magit-mode "Magit Diff" - "Mode for looking at a Git diff. - -This mode is documented in info node `(magit)Diff Buffer'. - -\\\ -Type \\[magit-refresh] to refresh the current buffer. -Type \\[magit-section-toggle] to expand or hide the section at point. -Type \\[magit-visit-thing] to visit the hunk or file at point. - -Staging and applying changes is documented in info node -`(magit)Staging and Unstaging' and info node `(magit)Applying'. - -\\Type \ -\\[magit-apply] to apply the change at point, \ -\\[magit-stage] to stage, -\\[magit-unstage] to unstage, \ -\\[magit-discard] to discard, or \ -\\[magit-reverse] to reverse it. - -\\{magit-diff-mode-map}" - :group 'magit-diff - (hack-dir-local-variables-non-file-buffer) - (setq imenu-prev-index-position-function - 'magit-imenu--diff-prev-index-position-function) - (setq imenu-extract-index-name-function - 'magit-imenu--diff-extract-index-name-function)) - -(put 'magit-diff-mode 'magit-diff-default-arguments - '("--stat" "--no-ext-diff")) - -(defun magit-diff-setup-buffer (range typearg args files &optional locked) - (require 'magit) - (magit-setup-buffer #'magit-diff-mode locked - (magit-buffer-range range) - (magit-buffer-typearg typearg) - (magit-buffer-diff-args args) - (magit-buffer-diff-files files) - (magit-buffer-diff-files-suspended nil))) - -(defun magit-diff-refresh-buffer () - "Refresh the current `magit-diff-mode' buffer." - (magit-set-header-line-format - (if (equal magit-buffer-typearg "--no-index") - (apply #'format "Differences between %s and %s" magit-buffer-diff-files) - (concat (if 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")) - (pcase (length magit-buffer-diff-files) - (0) - (1 (concat " in file " (car magit-buffer-diff-files))) - (_ (concat " in files " - (mapconcat #'identity magit-buffer-diff-files ", "))))))) - (setq magit-buffer-range-hashed - (and magit-buffer-range (magit-hash-range magit-buffer-range))) - (magit-insert-section (diffbuf) - (magit-run-section-hook 'magit-diff-sections-hook))) - -(cl-defmethod magit-buffer-value (&context (major-mode magit-diff-mode)) - (nconc (cond (magit-buffer-range - (delq nil (list magit-buffer-range magit-buffer-typearg))) - ((equal magit-buffer-typearg "--cached") - (list 'staged)) - (t - (list 'unstaged magit-buffer-typearg))) - (and magit-buffer-diff-files (cons "--" magit-buffer-diff-files)))) - -(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 (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 "s" 'magit-stage) - (define-key map "u" 'magit-unstage) - (define-key map "&" 'magit-do-async-shell-command) - (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))) - (set-keymap-parent map magit-diff-section-base-map) - 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\\|" - (substring magit-diff-conflict-headline-re 1) - "\\)")) - -(defconst magit-diff-statline-re - (concat "^ ?" - "\\(.*\\)" ; file - "\\( +| +\\)" ; separator - "\\([0-9]+\\|Bin\\(?: +[0-9]+ -> [0-9]+ bytes\\)?$\\) ?" - "\\(\\+*\\)" ; add - "\\(-*\\)$")) ; del - -(defvar magit-diff--reset-non-color-moved - (list - "-c" "color.diff.context=normal" - "-c" "color.diff.plain=normal" ; historical synonym for context - "-c" "color.diff.meta=normal" - "-c" "color.diff.frag=normal" - "-c" "color.diff.func=normal" - "-c" "color.diff.old=normal" - "-c" "color.diff.new=normal" - "-c" "color.diff.commit=normal" - "-c" "color.diff.whitespace=normal" - ;; "git-range-diff" does not support "--color-moved", so we don't - ;; need to reset contextDimmed, oldDimmed, newDimmed, contextBold, - ;; oldBold, and newBold. - )) - -(defun magit-insert-diff () - "Insert the diff into this `magit-diff-mode' buffer." - (magit--insert-diff - "diff" magit-buffer-range "-p" "--no-prefix" - (and (member "--stat" magit-buffer-diff-args) "--numstat") - magit-buffer-typearg - magit-buffer-diff-args "--" - magit-buffer-diff-files)) - -(defun magit--insert-diff (&rest args) - (declare (indent 0)) - (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 (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" args) - (setq magit-git-global-arguments - (append magit-diff--reset-non-color-moved - magit-git-global-arguments))) - (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) - (magit-diff-wash-diffstat)) - (when (re-search-forward magit-diff-headline-re limit t) - (goto-char (line-beginning-position)) - (magit-wash-sequence (apply-partially 'magit-diff-wash-diff args)) - (insert ?\n))) - -(defun magit-jump-to-diffstat-or-diff () - "Jump to the diffstat or diff. -When point is on a file inside the diffstat section, then jump -to the respective diff section, otherwise jump to the diffstat -section or a child thereof." - (interactive) - (--if-let (magit-get-section - (append (magit-section-case - ([file diffstat] `((file . ,(oref it value)))) - (file `((file . ,(oref it value)) (diffstat))) - (t '((diffstat)))) - (magit-section-ident magit-root-section))) - (magit-section-goto it) - (user-error "No diffstat in this buffer"))) - -(defun magit-diff-wash-signature () - (when (looking-at "^gpg: ") - (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))) - (when (re-search-forward "^ ?\\([0-9]+ +files? change[^\n]*\n\\)" nil t) - (setq heading (match-string 1)) - (magit-delete-match) - (goto-char beg) - (magit-insert-section (diffstat) - (insert (propertize heading 'font-lock-face 'magit-diff-file-heading)) - (magit-insert-heading) - (let (files) - (while (looking-at "^[-0-9]+\t[-0-9]+\t\\(.+\\)$") - (push (magit-decode-git-path - (let ((f (match-string 1))) - (cond - ((string-match "\\`\\([^{]+\\){\\(.+\\) => \\(.+\\)}\\'" f) - (concat (match-string 1 f) - (match-string 3 f))) - ((string-match " => " f) - (substring f (match-end 0))) - (t f)))) - files) - (magit-delete-line)) - (setq files (nreverse files)) - (while (looking-at magit-diff-statline-re) - (magit-bind-match-strings (file sep cnt add del) nil - (magit-delete-line) - (when (string-match " +$" file) - (setq sep (concat (match-string 0 file) sep)) - (setq file (substring file 0 (match-beginning 0)))) - (let ((le (length file)) ld) - (setq file (magit-decode-git-path file)) - (setq ld (length file)) - (when (> le ld) - (setq sep (concat (make-string (- le ld) ?\s) sep)))) - (magit-insert-section (file (pop files)) - (insert (propertize file 'font-lock-face 'magit-filename) - sep cnt " ") - (when add - (insert (propertize add 'font-lock-face - 'magit-diffstat-added))) - (when del - (insert (propertize del 'font-lock-face - 'magit-diffstat-removed))) - (insert "\n"))))) - (if (looking-at "^$") (forward-line) (insert "\n")))))) - -(defun magit-diff-wash-diff (args) - (when (cl-member-if (lambda (arg) (string-prefix-p "--color-moved" arg)) args) - (require 'ansi-color) - (ansi-color-apply-on-region (point-min) (point-max))) - (cond - ((looking-at "^Submodule") - (magit-diff-wash-submodule)) - ((looking-at "^\\* Unmerged path \\(.*\\)") - (let ((file (magit-decode-git-path (match-string 1)))) - (magit-delete-line) - (unless (and (derived-mode-p 'magit-status-mode) - (not (member "--cached" args))) - (magit-insert-section (file file) - (insert (propertize - (format "unmerged %s%s" file - (pcase (cddr (car (magit-file-status file))) - (`(?D ?D) " (both deleted)") - (`(?D ?U) " (deleted by us)") - (`(?U ?D) " (deleted by them)") - (`(?A ?A) " (both added)") - (`(?A ?U) " (added by us)") - (`(?U ?A) " (added by them)") - (`(?U ?U) ""))) - 'font-lock-face 'magit-diff-file-heading)) - (insert ?\n)))) - t) - ((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\\}\\) \\(.+\\)$") - (magit-bind-match-strings (side _blob name) nil - (pcase side - ("result" (setq file name)) - ("our" (setq orig name)) - ("their" (setq file name)) - ("base" (setq base name)))) - (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 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"))) - (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))) - (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-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 rename 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" 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 '(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 () - ;; See `show_submodule_summary' in submodule.c and "this" commit. - (when (looking-at "^Submodule \\([^ ]+\\)") - (let ((module (match-string 1)) - untracked modified) - (when (looking-at "^Submodule [^ ]+ contains untracked content$") - (magit-delete-line) - (setq untracked t)) - (when (looking-at "^Submodule [^ ]+ contains modified content$") - (magit-delete-line) - (setq modified t)) - (cond - ((and (looking-at "^Submodule \\([^ ]+\\) \\([^ :]+\\)\\( (rewind)\\)?:$") - (equal (match-string 1) module)) - (magit-bind-match-strings (_module range rewind) nil - (magit-delete-line) - (while (looking-at "^ \\([<>]\\) \\(.+\\)$") - (magit-delete-line)) - (when rewind - (setq range (replace-regexp-in-string "[^.]\\(\\.\\.\\)[^.]" - "..." range t t 1))) - (magit-insert-section (magit-module-section module t) - (magit-insert-heading - (propertize (concat "modified " module) - 'font-lock-face 'magit-diff-file-heading) - " (" - (cond (rewind "rewind") - ((string-match-p "\\.\\.\\." range) "non-ff") - (t "new commits")) - (and (or modified untracked) - (concat ", " - (and modified "modified") - (and modified untracked " and ") - (and untracked "untracked") - " content")) - ")") - (let ((default-directory - (file-name-as-directory - (expand-file-name module (magit-toplevel))))) - (magit-git-wash (apply-partially 'magit-log-wash-log 'module) - "log" "--oneline" "--left-right" range) - (delete-char -1))))) - ((and (looking-at "^Submodule \\([^ ]+\\) \\([^ ]+\\) (\\([^)]+\\))$") - (equal (match-string 1) module)) - (magit-bind-match-strings (_module _range msg) nil - (magit-delete-line) - (magit-insert-section (magit-module-section module) - (magit-insert-heading - (propertize (concat "submodule " module) - 'font-lock-face 'magit-diff-file-heading) - " (" msg ")")))) - (t - (magit-insert-section (magit-module-section module) - (magit-insert-heading - (propertize (concat "modified " module) - 'font-lock-face 'magit-diff-file-heading) - " (" - (and modified "modified") - (and modified untracked " and ") - (and untracked "untracked") - " content)"))))))) - -(defun magit-diff-wash-hunk () - (when (looking-at "^@\\{2,\\} \\(.+?\\) @\\{2,\\}\\(?: \\(.*\\)\\)?") - (let* ((heading (match-string 0)) - (ranges (mapcar (lambda (str) - (mapcar #'string-to-number - (split-string (substring str 1) ","))) - (split-string (match-string 1)))) - (about (match-string 2)) - (combined (= (length ranges) 3)) - (value (cons about ranges))) - (magit-delete-line) - (magit-insert-section section (hunk value) - (insert (propertize (concat heading "\n") - 'font-lock-face 'magit-diff-hunk-heading)) - (magit-insert-heading) - (while (not (or (eobp) (looking-at "^[^-+\s\\]"))) - (forward-line)) - (oset section end (point)) - (oset section washer 'magit-diff-paint-hunk) - (oset section combined combined) - (if combined - (oset section from-ranges (butlast ranges)) - (oset section from-range (car ranges))) - (oset section to-range (car (last ranges))) - (oset section about about))) - t)) - -(defun magit-diff-expansion-threshold (section) - "Keep new diff sections collapsed if washing takes too long." - (and (magit-file-section-p section) - (> (float-time (time-subtract (current-time) magit-refresh-start-time)) - magit-diff-expansion-threshold) - 'hide)) - -(add-hook 'magit-section-set-visibility-hook #'magit-diff-expansion-threshold) - -;;; Revision Mode - -(define-derived-mode magit-revision-mode magit-diff-mode "Magit Rev" - "Mode for looking at a Git commit. - -This mode is documented in info node `(magit)Revision Buffer'. - -\\\ -Type \\[magit-refresh] to refresh the current buffer. -Type \\[magit-section-toggle] to expand or hide the section at point. -Type \\[magit-visit-thing] to visit the hunk or file at point. - -Staging and applying changes is documented in info node -`(magit)Staging and Unstaging' and info node `(magit)Applying'. - -\\Type \ -\\[magit-apply] to apply the change at point, \ -\\[magit-stage] to stage, -\\[magit-unstage] to unstage, \ -\\[magit-discard] to discard, or \ -\\[magit-reverse] to reverse it. - -\\{magit-revision-mode-map}" - :group 'magit-revision - (hack-dir-local-variables-non-file-buffer)) - -(put 'magit-revision-mode 'magit-diff-default-arguments - '("--stat" "--no-ext-diff")) - -(defun magit-revision-setup-buffer (rev args files) - (magit-setup-buffer #'magit-revision-mode nil - (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-suspended nil))) - -(defun magit-revision-refresh-buffer () - (setq magit-buffer-revision-hash (magit-rev-parse magit-buffer-revision)) - (magit-set-header-line-format - (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 ", ")))))) - (magit-insert-section (commitbuf) - (magit-run-section-hook 'magit-revision-sections-hook))) - -(cl-defmethod magit-buffer-value (&context (major-mode magit-revision-mode)) - (cons magit-buffer-revision magit-buffer-diff-files)) - -(defun magit-insert-revision-diff () - "Insert the diff into this `magit-revision-mode' buffer." - (magit--insert-diff - "show" "-p" "--cc" "--format=" "--no-prefix" - (and (member "--stat" magit-buffer-diff-args) "--numstat") - magit-buffer-diff-args - (concat magit-buffer-revision "^{commit}") - "--" magit-buffer-diff-files)) - -(defun magit-insert-revision-tag () - "Insert tag message and headers into a revision buffer. -This function only inserts anything when `magit-show-commit' is -called with a tag as argument, when that is called with a commit -or a ref which is not a branch, then it inserts nothing." - (when (equal (magit-object-type magit-buffer-revision) "tag") - (magit-insert-section (taginfo) - (let ((beg (point))) - ;; "git verify-tag -v" would output what we need, but the gpg - ;; output is send to stderr and we have no control over the - ;; order in which stdout and stderr are inserted, which would - ;; make parsing hard. We are forced to use "git cat-file tag" - ;; instead, which inserts the signature instead of verifying - ;; it. We remove that later and then insert the verification - ;; output using "git verify-tag" (without the "-v"). - (magit-git-insert "cat-file" "tag" magit-buffer-revision) - (goto-char beg) - (forward-line 3) - (delete-region beg (point))) - (looking-at "^tagger \\([^<]+\\) <\\([^>]+\\)") - (let ((heading (format "Tagger: %s <%s>" - (match-string 1) - (match-string 2)))) - (magit-delete-line) - (insert (propertize heading 'font-lock-face - 'magit-section-secondary-heading))) - (magit-insert-heading) - (if (re-search-forward "-----BEGIN PGP SIGNATURE-----" nil t) - (progn - (let ((beg (match-beginning 0))) - (re-search-forward "-----END PGP SIGNATURE-----") - (delete-region beg (point))) - (insert ?\n) - (magit-process-git t "verify-tag" magit-buffer-revision)) - (goto-char (point-max))) - (insert ?\n)))) - -(defvar magit-commit-message-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-visit-thing] 'magit-show-commit) - map) - "Keymap for `commit-message' sections.") - -(defun magit-insert-revision-message () - "Insert the commit message into a revision buffer." - (magit-insert-section section (commit-message) - (oset section heading-highlight-face 'magit-diff-revision-summary-highlight) - (let ((beg (point)) - (rev magit-buffer-revision)) - (insert (with-temp-buffer - (magit-rev-insert-format "%B" rev) - (magit-revision--wash-message))) - (if (= (point) (+ beg 2)) - (progn (backward-delete-char 2) - (insert "(no message)\n")) - (goto-char beg) - (save-excursion - (while (search-forward "\r\n" nil t) ; Remove trailing CRs. - (delete-region (match-beginning 0) (1+ (match-beginning 0))))) - (when magit-revision-fill-summary-line - (let ((fill-column (min magit-revision-fill-summary-line - (window-width)))) - (fill-region (point) (line-end-position)))) - (when magit-revision-use-hash-sections - (save-excursion - (while (not (eobp)) - (re-search-forward "\\_<" nil 'move) - (let ((beg (point))) - (re-search-forward "\\_>" nil t) - (when (> (point) beg) - (let ((text (buffer-substring-no-properties beg (point)))) - (when (pcase magit-revision-use-hash-sections - (`quickest ; false negatives and positives - (and (>= (length text) 7) - (string-match-p "[0-9]" text) - (string-match-p "[a-z]" text))) - (`quicker ; false negatives (number-less hashes) - (and (>= (length text) 7) - (string-match-p "[0-9]" text) - (magit-commit-p text))) - (`quick ; false negatives (short hashes) - (and (>= (length text) 7) - (magit-commit-p text))) - (`slow - (magit-commit-p text))) - (put-text-property beg (point) - 'font-lock-face 'magit-hash) - (let ((end (point))) - (goto-char beg) - (magit-insert-section (commit text) - (goto-char end)))))))))) - (save-excursion - (forward-line) - (magit--add-face-text-property - beg (point) 'magit-diff-revision-summary) - (magit-insert-heading)) - (when magit-diff-highlight-keywords - (save-excursion - (while (re-search-forward "\\[[^[]*\\]" nil t) - (let ((beg (match-beginning 0)) - (end (match-end 0))) - (put-text-property - beg end 'font-lock-face - (if-let ((face (get-text-property beg 'font-lock-face))) - (list face 'magit-keyword) - 'magit-keyword)))))) - (goto-char (point-max)))))) - -(defun magit-insert-revision-notes () - "Insert commit notes into a revision buffer." - (let* ((var "core.notesRef") - (def (or (magit-get var) "refs/notes/commits"))) - (dolist (ref (or (magit-list-active-notes-refs))) - (magit-insert-section section (notes ref (not (equal ref def))) - (oset section heading-highlight-face 'magit-diff-hunk-heading-highlight) - (let ((beg (point)) - (rev magit-buffer-revision)) - (insert (with-temp-buffer - (magit-git-insert "-c" (concat "core.notesRef=" ref) - "notes" "show" rev) - (magit-revision--wash-message))) - (if (= (point) beg) - (magit-cancel-section) - (goto-char beg) - (end-of-line) - (insert (format " (%s)" - (propertize (if (string-prefix-p "refs/notes/" ref) - (substring ref 11) - ref) - 'font-lock-face 'magit-refname))) - (forward-char) - (magit--add-face-text-property beg (point) 'magit-diff-hunk-heading) - (magit-insert-heading) - (goto-char (point-max)) - (insert ?\n))))))) - -(defun magit-revision--wash-message () - (let ((major-mode 'git-commit-mode)) - (hack-dir-local-variables) - (hack-local-variables-apply)) - (unless (memq git-commit-major-mode '(nil text-mode)) - (funcall git-commit-major-mode) - (font-lock-ensure)) - (buffer-string)) - -(defun magit-insert-revision-headers () - "Insert headers about the commit into a revision buffer." - (magit-insert-section (headers) - (--when-let (magit-rev-format "%D" magit-buffer-revision "--decorate=full") - (insert (magit-format-ref-labels it) ?\s)) - (insert (propertize - (magit-rev-parse (concat magit-buffer-revision "^{commit}")) - 'font-lock-face 'magit-hash)) - (magit-insert-heading) - (let ((beg (point))) - (magit-rev-insert-format magit-revision-headers-format - magit-buffer-revision) - (magit-insert-revision-gravatars magit-buffer-revision beg)) - (when magit-revision-insert-related-refs - (dolist (parent (magit-commit-parents magit-buffer-revision)) - (magit-insert-section (commit parent) - (let ((line (magit-rev-format "%h %s" parent))) - (string-match "^\\([^ ]+\\) \\(.*\\)" line) - (magit-bind-match-strings (hash msg) line - (insert "Parent: ") - (insert (propertize hash 'font-lock-face 'magit-hash)) - (insert " " msg "\n"))))) - (magit--insert-related-refs - magit-buffer-revision "--merged" "Merged" - (eq magit-revision-insert-related-refs 'all)) - (magit--insert-related-refs - magit-buffer-revision "--contains" "Contained" - (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))) - (magit-insert-section (tag tag) - (insert - (format "Follows: %s (%s)\n" - (propertize tag 'font-lock-face 'magit-tag) - (propertize (number-to-string cnt) - 'font-lock-face 'magit-branch-local)))))) - (when-let ((precedes (magit-get-next-tag magit-buffer-revision t))) - (let ((tag (car precedes)) - (cnt (cadr precedes))) - (magit-insert-section (tag tag) - (insert (format "Precedes: %s (%s)\n" - (propertize tag 'font-lock-face 'magit-tag) - (propertize (number-to-string cnt) - 'font-lock-face 'magit-tag)))))) - (insert ?\n)))) - -(defun magit--insert-related-refs (rev arg title remote) - (when-let ((refs (magit-list-related-branches arg rev (and remote "-a")))) - (insert title ":" (make-string (- 10 (length title)) ?\s)) - (dolist (branch refs) - (if (<= (+ (current-column) 1 (length branch)) - (window-width)) - (insert ?\s) - (insert ?\n (make-string 12 ?\s))) - (magit-insert-section (branch branch) - (insert (propertize branch 'font-lock-face - (if (string-prefix-p "remotes/" branch) - 'magit-branch-remote - 'magit-branch-local))))) - (insert ?\n))) - -(defun magit-insert-revision-gravatars (rev beg) - (when (and magit-revision-show-gravatars - (window-system)) - (require 'gravatar) - (pcase-let ((`(,author . ,committer) - (pcase magit-revision-show-gravatars - (`t '("^Author: " . "^Commit: ")) - (`author '("^Author: " . nil)) - (`committer '(nil . "^Commit: ")) - (_ magit-revision-show-gravatars)))) - (--when-let (and author (magit-rev-format "%aE" rev)) - (magit-insert-revision-gravatar beg rev it author)) - (--when-let (and committer (magit-rev-format "%cE" rev)) - (magit-insert-revision-gravatar beg rev it committer))))) - -(defun magit-insert-revision-gravatar (beg rev email regexp) - (save-excursion - (goto-char beg) - (when (re-search-forward regexp nil t) - (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)))) - (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)))))))) - -(defun magit-insert-revision-gravatar-cb (image rev marker align-to column) - (unless (eq image 'error) - (when-let ((buffer (marker-buffer marker))) - (with-current-buffer buffer - (save-excursion - (goto-char marker) - ;; The buffer might display another revision by now or - ;; it might have been refreshed, in which case another - ;; process might already have inserted the image. - (when (and (equal rev magit-buffer-revision) - (not (eq (car-safe - (car-safe - (get-text-property (point) 'display))) - 'image))) - (let ((top `((,@image :ascent center :relief 1) - (slice 0.0 0.0 1.0 0.5))) - (bot `((,@image :ascent center :relief 1) - (slice 0.0 0.5 1.0 1.0))) - (align `((space :align-to ,align-to)))) - (when magit-revision-use-gravatar-kludge - (cl-rotatef top bot)) - (let ((inhibit-read-only t)) - (insert (propertize " " 'display top)) - (insert (propertize " " 'display align)) - (forward-line) - (forward-char column) - (insert (propertize " " 'display bot)) - (insert (propertize " " 'display align)))))))))) - -;;; Merge-Preview Mode - -(define-derived-mode magit-merge-preview-mode magit-diff-mode "Magit Merge" - "Mode for previewing a merge." - :group 'magit-diff - (hack-dir-local-variables-non-file-buffer)) - -(put 'magit-merge-preview-mode 'magit-diff-default-arguments - '("--no-ext-diff")) - -(defun magit-merge-preview-setup-buffer (rev) - (magit-setup-buffer #'magit-merge-preview-mode nil - (magit-buffer-revision rev) - (magit-buffer-range (format "%s^..%s" rev rev)))) - -(defun magit-merge-preview-refresh-buffer () - (let* ((branch (magit-get-current-branch)) - (head (or branch (magit-rev-verify "HEAD")))) - (magit-set-header-line-format (format "Preview merge of %s into %s" - magit-buffer-revision - (or branch "HEAD"))) - (magit-insert-section (diffbuf) - (magit--insert-diff - "merge-tree" (magit-git-string "merge-base" head magit-buffer-revision) - head magit-buffer-revision)))) - -(cl-defmethod magit-buffer-value (&context (major-mode magit-merge-preview-mode)) - magit-buffer-revision) - -;;; Diff Sections - -(defun magit-hunk-set-window-start (section) - "When SECTION is a `hunk', ensure that its beginning is visible. -It the SECTION has a different type, then do nothing." - (when (magit-hunk-section-p section) - (magit-section-set-window-start section))) - -(add-hook 'magit-section-movement-hook #'magit-hunk-set-window-start) - -(defun magit-hunk-goto-successor (section arg) - (and (magit-hunk-section-p section) - (when-let ((parent (magit-get-section - (magit-section-ident - (oref section parent))))) - (let* ((children (oref parent children)) - (siblings (magit-section-siblings section 'prev)) - (previous (nth (length siblings) children))) - (if (not arg) - (--when-let (or previous (car (last children))) - (magit-section-goto it) - t) - (when previous - (magit-section-goto previous)) - (if (and (stringp arg) - (re-search-forward arg (oref parent end) t)) - (goto-char (match-beginning 0)) - (goto-char (oref (car (last children)) end)) - (forward-line -1) - (while (looking-at "^ ") (forward-line -1)) - (while (looking-at "^[-+]") (forward-line -1)) - (forward-line))))))) - -(add-hook 'magit-section-goto-successor-hook #'magit-hunk-goto-successor) - -(defvar magit-unstaged-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-visit-thing] 'magit-diff-unstaged) - (define-key map [remap magit-delete-thing] 'magit-discard) - (define-key map "s" 'magit-stage) - (define-key map "u" 'magit-unstage) - map) - "Keymap for the `unstaged' section.") - -(magit-define-section-jumper magit-jump-to-unstaged "Unstaged changes" unstaged) - -(defun magit-insert-unstaged-changes () - "Insert section showing unstaged changes." - (magit-insert-section (unstaged) - (magit-insert-heading "Unstaged changes:") - (magit--insert-diff - "diff" magit-buffer-diff-args "--no-prefix" - "--" magit-buffer-diff-files))) - -(defvar magit-staged-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-visit-thing] 'magit-diff-staged) - (define-key map [remap magit-delete-thing] 'magit-discard) - (define-key map [remap magit-revert-no-commit] 'magit-reverse) - (define-key map "s" 'magit-stage) - (define-key map "u" 'magit-unstage) - map) - "Keymap for the `staged' section.") - -(magit-define-section-jumper magit-jump-to-staged "Staged changes" staged) - -(defun magit-insert-staged-changes () - "Insert section showing staged changes." - ;; Avoid listing all files as deleted when visiting a bare repo. - (unless (magit-bare-repo-p) - (magit-insert-section (staged) - (magit-insert-heading "Staged changes:") - (magit--insert-diff - "diff" "--cached" magit-buffer-diff-args "--no-prefix" - "--" magit-buffer-diff-files)))) - -;;; Diff Type - -(defun magit-diff-type (&optional section) - "Return the diff type of SECTION. - -The returned type is one of the symbols `staged', `unstaged', -`committed', or `undefined'. This type serves a similar purpose -as the general type common to all sections (which is stored in -the `type' slot of the corresponding `magit-section' struct) but -takes additional information into account. When the SECTION -isn't related to diffs and the buffer containing it also isn't -a diff-only buffer, then return nil. - -Currently the type can also be one of `tracked' and `untracked' -but these values are not handled explicitly everywhere they -should be and a possible fix could be to just return nil here. - -The section has to be a `diff' or `hunk' section, or a section -whose children are of type `diff'. If optional SECTION is nil, -return the diff type for the current section. In buffers whose -major mode is `magit-diff-mode' SECTION is ignored and the type -is determined using other means. In `magit-revision-mode' -buffers the type is always `committed'. - -Do not confuse this with `magit-diff-scope' (which see)." - (--when-let (or section (magit-current-section)) - (cond ((derived-mode-p 'magit-revision-mode 'magit-stash-mode) 'committed) - ((derived-mode-p 'magit-diff-mode) - (let ((range magit-buffer-range) - (const magit-buffer-typearg)) - (cond ((equal const "--no-index") 'undefined) - ((or (not range) - (magit-rev-eq range "HEAD")) - (if (equal const "--cached") - 'staged - 'unstaged)) - ((equal const "--cached") - (if (magit-rev-head-p range) - 'staged - 'undefined)) ; i.e. committed and staged - (t 'committed)))) - ((derived-mode-p 'magit-status-mode) - (let ((stype (oref it type))) - (if (memq stype '(staged unstaged tracked untracked)) - stype - (pcase stype - ((or `file `module) - (let* ((parent (oref it parent)) - (type (oref parent type))) - (if (memq type '(file module)) - (magit-diff-type parent) - 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)) - (t 'undefined)))) - -(cl-defun magit-diff-scope (&optional (section nil ssection) strict) - "Return the diff scope of SECTION or the selected section(s). - -A diff's \"scope\" describes what part of a diff is selected, it is -a symbol, one of `region', `hunk', `hunks', `file', `files', or -`list'. Do not confuse this with the diff \"type\", as returned by -`magit-diff-type'. - -If optional SECTION is non-nil, then return the scope of that, -ignoring the sections selected by the region. Otherwise return -the scope of the current section, or if the region is active and -selects a valid group of diff related sections, the type of these -sections, i.e. `hunks' or `files'. If SECTION, or if that is nil -the current section, is a `hunk' section; and the region region -starts and ends inside the body of a that section, then the type -is `region'. If the region is empty after a mouse click, then -`hunk' is returned instead of `region'. - -If optional STRICT is non-nil, then return nil if the diff type of -the section at point is `untracked' or the section at point is not -actually a `diff' but a `diffstat' section." - (let ((siblings (and (not ssection) (magit-region-sections nil t)))) - (setq section (or section (car siblings) (magit-current-section))) - (when (and section - (or (not strict) - (and (not (eq (magit-diff-type section) 'untracked)) - (not (eq (--when-let (oref section parent) - (oref it type)) - 'diffstat))))) - (pcase (list (oref section type) - (and siblings t) - (magit-diff-use-hunk-region-p) - ssection) - (`(hunk nil t ,_) - (if (magit-section-internal-region-p section) 'region 'hunk)) - (`(hunk t t nil) 'hunks) - (`(hunk ,_ ,_ ,_) 'hunk) - (`(file t t nil) 'files) - (`(file ,_ ,_ ,_) 'file) - (`(module t t nil) 'files) - (`(module ,_ ,_ ,_) 'file) - (`(,(or `staged `unstaged `untracked) - nil ,_ ,_) 'list))))) - -(defun magit-diff-use-hunk-region-p () - (and (region-active-p) - ;; TODO implement this from first principals - ;; currently it's trial-and-error - (not (and (or (eq this-command 'mouse-drag-region) - (eq last-command 'mouse-drag-region) - ;; When another window was previously - ;; selected then the last-command is - ;; some byte-code function. - (byte-code-function-p last-command)) - (eq (region-end) (region-beginning)))))) - -;;; Diff Highlight - -(add-hook 'magit-section-unhighlight-hook #'magit-diff-unhighlight) -(add-hook 'magit-section-highlight-hook #'magit-diff-highlight) - -(defun magit-diff-unhighlight (section selection) - "Remove the highlighting of the diff-related SECTION." - (when (magit-hunk-section-p section) - (magit-diff-paint-hunk section selection nil) - t)) - -(defun magit-diff-highlight (section selection) - "Highlight the diff-related SECTION. -If SECTION is not a diff-related section, then do nothing and -return nil. If SELECTION is non-nil, then it is a list of sections -selected by the region, including SECTION. All of these sections -are highlighted." - (if (and (magit-section-match 'commit section) - (oref section children)) - (progn (if selection - (dolist (section selection) - (magit-diff-highlight-list section selection)) - (magit-diff-highlight-list section)) - t) - (when-let ((scope (magit-diff-scope section t))) - (cond ((eq scope 'region) - (magit-diff-paint-hunk section selection t)) - (selection - (dolist (section selection) - (magit-diff-highlight-recursive section selection))) - (t - (magit-diff-highlight-recursive section))) - t))) - -(defun magit-diff-highlight-recursive (section &optional selection) - (pcase (magit-diff-scope section) - (`list (magit-diff-highlight-list section selection)) - (`file (magit-diff-highlight-file section selection)) - (`hunk (magit-diff-highlight-heading section selection) - (magit-diff-paint-hunk section selection t)) - (_ (magit-section-highlight section nil)))) - -(defun magit-diff-highlight-list (section &optional selection) - (let ((beg (oref section start)) - (cnt (oref section content)) - (end (oref section end))) - (when (or (eq this-command 'mouse-drag-region) - (not selection)) - (unless (and (region-active-p) - (<= (region-beginning) beg)) - (magit-section-make-overlay beg cnt 'magit-section-highlight)) - (unless (oref section hidden) - (dolist (child (oref section children)) - (when (or (eq this-command 'mouse-drag-region) - (not (and (region-active-p) - (<= (region-beginning) - (oref child start))))) - (magit-diff-highlight-recursive child selection))))) - (when magit-diff-highlight-hunk-body - (magit-section-make-overlay (1- end) end 'magit-section-highlight)))) - -(defun magit-diff-highlight-file (section &optional selection) - (magit-diff-highlight-heading section selection) - (unless (oref section hidden) - (dolist (child (oref section children)) - (magit-diff-highlight-recursive child selection)))) - -(defun magit-diff-highlight-heading (section &optional selection) - (magit-section-make-overlay - (oref section start) - (or (oref section content) - (oref section end)) - (pcase (list (oref section type) - (and (member section selection) - (not (eq this-command 'mouse-drag-region)))) - (`(file t) 'magit-diff-file-heading-selection) - (`(file nil) 'magit-diff-file-heading-highlight) - (`(module t) 'magit-diff-file-heading-selection) - (`(module nil) 'magit-diff-file-heading-highlight) - (`(hunk t) 'magit-diff-hunk-heading-selection) - (`(hunk nil) 'magit-diff-hunk-heading-highlight)))) - -;;; Hunk Paint - -(cl-defun magit-diff-paint-hunk - (section &optional selection - (highlight (magit-section-selected-p section selection))) - (let (paint) - (unless magit-diff-highlight-hunk-body - (setq highlight nil)) - (cond (highlight - (unless (oref section hidden) - (add-to-list 'magit-section-highlighted-sections section) - (cond ((memq section magit-section-unhighlight-sections) - (setq magit-section-unhighlight-sections - (delq section magit-section-unhighlight-sections))) - (magit-diff-highlight-hunk-body - (setq paint t))))) - (t - (cond ((and (oref section hidden) - (memq section magit-section-unhighlight-sections)) - (add-to-list 'magit-section-highlighted-sections section) - (setq magit-section-unhighlight-sections - (delq section magit-section-unhighlight-sections))) - (t - (setq paint t))))) - (when paint - (save-excursion - (goto-char (oref section start)) - (let ((end (oref section end)) - (merging (looking-at "@@@")) - (diff-type (magit-diff-type)) - (stage nil) - (tab-width (magit-diff-tab-width - (magit-section-parent-value section)))) - (forward-line) - (while (< (point) end) - (when (and magit-diff-hide-trailing-cr-characters - (char-equal ?\r (char-before (line-end-position)))) - (put-text-property (1- (line-end-position)) (line-end-position) - 'invisible t)) - (put-text-property - (point) (1+ (line-end-position)) 'font-lock-face - (cond - ((looking-at "^\\+\\+?\\([<=|>]\\)\\{7\\}") - (setq stage (pcase (list (match-string 1) highlight) - (`("<" nil) 'magit-diff-our) - (`("<" t) 'magit-diff-our-highlight) - (`("|" nil) 'magit-diff-base) - (`("|" t) 'magit-diff-base-highlight) - (`("=" nil) 'magit-diff-their) - (`("=" t) 'magit-diff-their-highlight) - (`(">" nil) nil))) - 'magit-diff-conflict-heading) - ((looking-at (if merging "^\\(\\+\\| \\+\\)" "^\\+")) - (magit-diff-paint-tab merging tab-width) - (magit-diff-paint-whitespace merging 'added diff-type) - (or stage - (if highlight 'magit-diff-added-highlight 'magit-diff-added))) - ((looking-at (if merging "^\\(-\\| -\\)" "^-")) - (magit-diff-paint-tab merging tab-width) - (magit-diff-paint-whitespace merging 'removed diff-type) - (if highlight 'magit-diff-removed-highlight 'magit-diff-removed)) - (t - (magit-diff-paint-tab merging tab-width) - (magit-diff-paint-whitespace merging 'context diff-type) - (if highlight 'magit-diff-context-highlight 'magit-diff-context)))) - (forward-line)))))) - (magit-diff-update-hunk-refinement section)) - -(defvar magit-diff--tab-width-cache nil) - -(defun magit-diff-tab-width (file) - (setq file (expand-file-name file)) - (cl-flet ((cache (value) - (let ((elt (assoc file magit-diff--tab-width-cache))) - (if elt - (setcdr elt value) - (setq magit-diff--tab-width-cache - (cons (cons file value) - magit-diff--tab-width-cache)))) - value)) - (cond - ((not magit-diff-adjust-tab-width) - tab-width) - ((--when-let (find-buffer-visiting file) - (cache (buffer-local-value 'tab-width it)))) - ((--when-let (assoc file magit-diff--tab-width-cache) - (or (cdr it) - tab-width))) - ((or (eq magit-diff-adjust-tab-width 'always) - (and (numberp magit-diff-adjust-tab-width) - (>= magit-diff-adjust-tab-width - (nth 7 (file-attributes file))))) - (cache (buffer-local-value 'tab-width (find-file-noselect file)))) - (t - (cache nil) - tab-width)))) - -(defun magit-diff-paint-tab (merging width) - (save-excursion - (forward-char (if merging 2 1)) - (while (= (char-after) ?\t) - (put-text-property (point) (1+ (point)) - 'display (list (list 'space :width width))) - (forward-char)))) - -(defun magit-diff-paint-whitespace (merging line-type diff-type) - (when (and magit-diff-paint-whitespace - (or (not (memq magit-diff-paint-whitespace '(uncommitted status))) - (memq diff-type '(staged unstaged))) - (cl-case line-type - (added t) - (removed (memq magit-diff-paint-whitespace-lines '(all both))) - (context (memq magit-diff-paint-whitespace-lines '(all))))) - (let ((prefix (if merging "^[-\\+\s]\\{2\\}" "^[-\\+\s]")) - (indent - (if (local-variable-p 'magit-diff-highlight-indentation) - magit-diff-highlight-indentation - (setq-local - magit-diff-highlight-indentation - (cdr (--first (string-match-p (car it) default-directory) - (nreverse - (default-value - 'magit-diff-highlight-indentation)))))))) - (when (and magit-diff-highlight-trailing - (looking-at (concat prefix ".*?\\([ \t]+\\)$"))) - (let ((ov (make-overlay (match-beginning 1) (match-end 1) nil t))) - (overlay-put ov 'font-lock-face 'magit-diff-whitespace-warning) - (overlay-put ov 'priority 2) - (overlay-put ov 'evaporate t))) - (when (or (and (eq indent 'tabs) - (looking-at (concat prefix "\\( *\t[ \t]*\\)"))) - (and (integerp indent) - (looking-at (format "%s\\([ \t]* \\{%s,\\}[ \t]*\\)" - prefix indent)))) - (let ((ov (make-overlay (match-beginning 1) (match-end 1) nil t))) - (overlay-put ov 'font-lock-face 'magit-diff-whitespace-warning) - (overlay-put ov 'priority 2) - (overlay-put ov 'evaporate t)))))) - -(defun magit-diff-update-hunk-refinement (&optional section) - (if section - (unless (oref section hidden) - (pcase (list magit-diff-refine-hunk - (oref section refined) - (eq section (magit-current-section))) - ((or `(all nil ,_) `(t nil t)) - (oset section refined t) - (save-excursion - (goto-char (oref section start)) - ;; `diff-refine-hunk' does not handle combined diffs. - (unless (looking-at "@@@") - (let ((smerge-refine-ignore-whitespace - magit-diff-refine-ignore-whitespace) - ;; Avoid fsyncing many small temp files - (write-region-inhibit-fsync t)) - (diff-refine-hunk))))) - ((or `(nil t ,_) `(t t nil)) - (oset section refined nil) - (remove-overlays (oref section start) - (oref section end) - 'diff-mode 'fine)))) - (cl-labels ((recurse (section) - (if (magit-section-match 'hunk section) - (magit-diff-update-hunk-refinement section) - (dolist (child (oref section children)) - (recurse child))))) - (recurse magit-root-section)))) - - -;;; Hunk Region - -(defun magit-diff-hunk-region-beginning () - (save-excursion (goto-char (region-beginning)) - (line-beginning-position))) - -(defun magit-diff-hunk-region-end () - (save-excursion (goto-char (region-end)) - (line-end-position))) - -(defun magit-diff-update-hunk-region (section) - "Highlight the hunk-internal region if any." - (when (eq (magit-diff-scope section t) 'region) - (magit-diff--make-hunk-overlay - (oref section start) - (1- (oref section content)) - 'font-lock-face 'magit-diff-lines-heading - 'display (magit-diff-hunk-region-header section) - 'after-string (magit-diff--hunk-after-string 'magit-diff-lines-heading)) - (run-hook-with-args 'magit-diff-highlight-hunk-region-functions section) - t)) - -(defun magit-diff-highlight-hunk-region-dim-outside (section) - "Dim the parts of the hunk that are outside the hunk-internal region. -This is done by using the same foreground and background color -for added and removed lines as for context lines." - (let ((face (if magit-diff-highlight-hunk-body - 'magit-diff-context-highlight - 'magit-diff-context))) - (when magit-diff-unmarked-lines-keep-foreground - (setq face `(,@(and (>= emacs-major-version 27) '(:extend t)) - :background ,(face-attribute face :background)))) - (magit-diff--make-hunk-overlay (oref section content) - (magit-diff-hunk-region-beginning) - 'font-lock-face face - 'priority 2) - (magit-diff--make-hunk-overlay (1+ (magit-diff-hunk-region-end)) - (oref section end) - 'font-lock-face face - 'priority 2))) - -(defun magit-diff-highlight-hunk-region-using-face (_section) - "Highlight the hunk-internal region by making it bold. -Or rather highlight using the face `magit-diff-hunk-region', though -changing only the `:weight' and/or `:slant' is recommended for that -face." - (magit-diff--make-hunk-overlay (magit-diff-hunk-region-beginning) - (1+ (magit-diff-hunk-region-end)) - 'font-lock-face 'magit-diff-hunk-region)) - -(defun magit-diff-highlight-hunk-region-using-overlays (section) - "Emphasize the hunk-internal region using delimiting horizontal lines. -This is implemented as single-pixel newlines places inside overlays." - (if (window-system) - (let ((beg (magit-diff-hunk-region-beginning)) - (end (magit-diff-hunk-region-end)) - (str (propertize - (concat (propertize "\s" 'display '(space :height (1))) - (propertize "\n" 'line-height t)) - 'font-lock-face 'magit-diff-lines-boundary))) - (magit-diff--make-hunk-overlay beg (1+ beg) 'before-string str) - (magit-diff--make-hunk-overlay end (1+ end) 'after-string str)) - (magit-diff-highlight-hunk-region-using-face section))) - -(defun magit-diff-highlight-hunk-region-using-underline (section) - "Emphasize the hunk-internal region using delimiting horizontal lines. -This is implemented by overlining and underlining the first and -last (visual) lines of the region." - (if (window-system) - (let* ((beg (magit-diff-hunk-region-beginning)) - (end (magit-diff-hunk-region-end)) - (beg-eol (save-excursion (goto-char beg) - (end-of-visual-line) - (point))) - (end-bol (save-excursion (goto-char end) - (beginning-of-visual-line) - (point))) - (color (face-background 'magit-diff-lines-boundary nil t))) - (cl-flet ((ln (b e &rest face) - (magit-diff--make-hunk-overlay - b e 'font-lock-face face 'after-string - (magit-diff--hunk-after-string face)))) - (if (= beg end-bol) - (ln beg beg-eol :overline color :underline color) - (ln beg beg-eol :overline color) - (ln end-bol end :underline color)))) - (magit-diff-highlight-hunk-region-using-face section))) - -(defun magit-diff--make-hunk-overlay (start end &rest args) - (let ((ov (make-overlay start end nil t))) - (overlay-put ov 'evaporate t) - (while args (overlay-put ov (pop args) (pop args))) - (push ov magit-section--region-overlays) - ov)) - -(defun magit-diff--hunk-after-string (face) - (propertize "\s" - 'font-lock-face face - 'display (list 'space :align-to - `(+ (0 . right) - ,(min (window-hscroll) - (- (line-end-position) - (line-beginning-position))))) - ;; This prevents the cursor from being rendered at the - ;; edge of the window. - 'cursor t)) - -;;; Hunk Utilities - -(defun magit-diff-inside-hunk-body-p () - "Return non-nil if point is inside the body of a hunk." - (and (magit-section-match 'hunk) - (when-let ((content (oref (magit-current-section) content))) - (> (point) content)))) - -;;; Diff Extract - -(defun magit-diff-file-header (section &optional no-rename) - (when (magit-hunk-section-p section) - (setq section (oref section parent))) - (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))) - (string-match "\n" patch) - (substring patch 0 (1- (match-end 0))))) - -(defun magit-diff-hunk-region-patch (section &optional args) - (let ((op (if (member "--reverse" args) "+" "-")) - (sbeg (oref section start)) - (rbeg (magit-diff-hunk-region-beginning)) - (rend (region-end)) - (send (oref section end)) - (patch nil)) - (save-excursion - (goto-char sbeg) - (while (< (point) send) - (looking-at "\\(.\\)\\([^\n]*\n\\)") - (cond ((or (string-match-p "[@ ]" (match-string-no-properties 1)) - (and (>= (point) rbeg) - (<= (point) rend))) - (push (match-string-no-properties 0) patch)) - ((equal op (match-string-no-properties 1)) - (push (concat " " (match-string-no-properties 2)) patch))) - (forward-line))) - (let ((buffer-list-update-hook nil)) ; #3759 - (with-temp-buffer - (insert (mapconcat #'identity (reverse patch) "")) - (diff-fixup-modifs (point-min) (point-max)) - (setq patch (buffer-string)))) - patch)) - -;;; _ -(provide 'magit-diff) -;;; magit-diff.el ends here diff --git a/elpa/magit-20210802.1524/magit-ediff.el b/elpa/magit-20210802.1524/magit-ediff.el deleted file mode 100644 index 58c47f5f..00000000 --- a/elpa/magit-20210802.1524/magit-ediff.el +++ /dev/null @@ -1,482 +0,0 @@ -;;; magit-ediff.el --- Ediff extension for Magit -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library provides basic support for Ediff. - -;;; Code: - -(require 'magit) - -(require 'ediff) -(require 'smerge-mode) - -(defvar smerge-ediff-buf) -(defvar smerge-ediff-windows) - -;;; Options - -(defgroup magit-ediff nil - "Ediff support for Magit." - :link '(info-link "(magit)Ediffing") - :group 'magit-extensions) - -(defcustom magit-ediff-quit-hook - '(magit-ediff-cleanup-auxiliary-buffers - magit-ediff-restore-previous-winconf) - "Hooks to run after finishing Ediff, when that was invoked using Magit. -The hooks are run in the Ediff control buffer. This is similar -to `ediff-quit-hook' but takes the needs of Magit into account. -The `ediff-quit-hook' is ignored by Ediff sessions which were -invoked using Magit." - :package-version '(magit . "2.2.0") - :group 'magit-ediff - :type 'hook - :get 'magit-hook-custom-get - :options '(magit-ediff-cleanup-auxiliary-buffers - magit-ediff-restore-previous-winconf)) - -(defcustom magit-ediff-dwim-show-on-hunks nil - "Whether `magit-ediff-dwim' runs show variants on hunks. -If non-nil, `magit-ediff-show-staged' or -`magit-ediff-show-unstaged' are called based on what section the -hunk is in. Otherwise, `magit-ediff-dwim' runs -`magit-ediff-stage' when point is on an uncommitted hunk." - :package-version '(magit . "2.2.0") - :group 'magit-ediff - :type 'boolean) - -(defcustom magit-ediff-show-stash-with-index t - "Whether `magit-ediff-show-stash' shows the state of the index. - -If non-nil, use a third Ediff buffer to distinguish which changes -in the stash were staged. In cases where the stash contains no -staged changes, fall back to a two-buffer Ediff. - -More specifically, a stash is a merge commit, stash@{N}, with -potentially three parents. - -* stash@{N}^1 represents the `HEAD' commit at the time the stash - was created. - -* stash@{N}^2 records any changes that were staged when the stash - was made. - -* stash@{N}^3, if it exists, contains files that were untracked - when stashing. - -If this option is non-nil, `magit-ediff-show-stash' will run -Ediff on a file using three buffers: one for stash@{N}, another -for stash@{N}^1, and a third for stash@{N}^2. - -Otherwise, Ediff uses two buffers, comparing -stash@{N}^1..stash@{N}. Along with any unstaged changes, changes -in the index commit, stash@{N}^2, will be shown in this -comparison unless they conflicted with changes in the working -tree at the time of stashing." - :package-version '(magit . "2.6.0") - :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) -(transient-define-prefix magit-ediff () - "Show differences using the Ediff package." - :info-manual "(ediff)" - ["Ediff" - [("E" "Dwim" magit-ediff-dwim) - ("s" "Stage" magit-ediff-stage) - ("m" "Resolve" magit-ediff-resolve)] - [("u" "Show unstaged" magit-ediff-show-unstaged) - ("i" "Show staged" magit-ediff-show-staged) - ("w" "Show worktree" magit-ediff-show-working-tree)] - [("c" "Show commit" magit-ediff-show-commit) - ("r" "Show range" magit-ediff-compare) - ("z" "Show stash" magit-ediff-show-stash)]]) - -;;;###autoload -(defun magit-ediff-resolve (file) - "Resolve outstanding conflicts in FILE using Ediff. -FILE has to be relative to the top directory of the repository. - -In the rare event that you want to manually resolve all -conflicts, including those already resolved by Git, use -`ediff-merge-revisions-with-ancestor'." - (interactive - (let ((current (magit-current-file)) - (unmerged (magit-unmerged-files))) - (unless unmerged - (user-error "There are no unresolved conflicts")) - (list (magit-completing-read "Resolve file" unmerged nil t nil nil - (car (member current unmerged)))))) - (magit-with-toplevel - (with-current-buffer (find-file-noselect file) - (smerge-ediff) - (setq-local - ediff-quit-hook - (lambda () - (let ((bufC ediff-buffer-C) - (bufS smerge-ediff-buf)) - (with-current-buffer bufS - (when (yes-or-no-p (format "Conflict resolution finished; save %s? " - buffer-file-name)) - (erase-buffer) - (insert-buffer-substring bufC) - (save-buffer)))) - (when (buffer-live-p ediff-buffer-A) (kill-buffer ediff-buffer-A)) - (when (buffer-live-p ediff-buffer-B) (kill-buffer ediff-buffer-B)) - (when (buffer-live-p ediff-buffer-C) (kill-buffer ediff-buffer-C)) - (when (buffer-live-p ediff-ancestor-buffer) - (kill-buffer ediff-ancestor-buffer)) - (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. -FILE has to be relative to the top directory of the repository." - (interactive - (let ((files (magit-tracked-files))) - (list (magit-completing-read "Selectively stage file" files nil t nil nil - (car (member (magit-current-file) files)))))) - (magit-with-toplevel - (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 - (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) - "Compare REVA:FILEA with REVB:FILEB using Ediff. - -FILEA and FILEB have to be relative to the top directory of the -repository. If REVA or REVB is nil, then this stands for the -working tree state. - -If the region is active, use the revisions on the first and last -line of the region. With a prefix argument, instead of diffing -the revisions, choose a revision to view changes along, starting -at the common ancestor of both revisions (i.e., use a \"...\" -range)." - (interactive - (pcase-let ((`(,revA ,revB) (magit-ediff-compare--read-revisions - nil current-prefix-arg))) - (nconc (list revA revB) - (magit-ediff-read-files revA revB)))) - (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 - "Compare range or commit" - nil mbase)))) - (--if-let (magit-split-range input) - (-cons-to-list it) - (list input nil)))) - -(defun magit-ediff-read-files (revA revB &optional fileB) - "Read file in REVB, return it and the corresponding file in REVA. -When FILEB is non-nil, use this as REVB's file instead of -prompting for it." - (unless fileB - (setq fileB (magit-read-file-choice - (format "File to compare between %s and %s" - revA (or revB "the working tree")) - (magit-changed-files revA revB) - (format "No changed files between %s and %s" - revA (or revB "the working tree"))))) - (list (or (car (member fileB (magit-revision-files revA))) - (cdr (assoc fileB (magit-renamed-files revB revA))) - (magit-read-file-choice - (format "File in %s to compare with %s in %s" - revA fileB (or revB "the working tree")) - (magit-changed-files revB revA) - (format "No files have changed between %s and %s" - revA revB))) - fileB)) - -;;;###autoload -(defun magit-ediff-dwim () - "Compare, stage, or resolve using Ediff. -This command tries to guess what file, and what commit or range -the user wants to compare, stage, or resolve using Ediff. It -might only be able to guess either the file, or range or commit, -in which case the user is asked about the other. It might not -always guess right, in which case the appropriate `magit-ediff-*' -command has to be used explicitly. If it cannot read the user's -mind at all, then it asks the user for a command to run." - (interactive) - (magit-section-case - (hunk (save-excursion - (goto-char (oref (oref it parent) start)) - (magit-ediff-dwim))) - (t - (let ((range (magit-diff--dwim)) - (file (magit-current-file)) - command revA revB) - (pcase range - ((and (guard (not magit-ediff-dwim-show-on-hunks)) - (or `unstaged `staged)) - (setq command (if (magit-anything-unmerged-p) - #'magit-ediff-resolve - #'magit-ediff-stage))) - (`unstaged (setq command #'magit-ediff-show-unstaged)) - (`staged (setq command #'magit-ediff-show-staged)) - (`(commit . ,value) - (setq command #'magit-ediff-show-commit) - (setq revB value)) - (`(stash . ,value) - (setq command #'magit-ediff-show-stash) - (setq revB value)) - ((pred stringp) - (pcase-let ((`(,a ,b) (magit-ediff-compare--read-revisions range))) - (setq command #'magit-ediff-compare) - (setq revA a) - (setq revB b))) - (_ - (when (derived-mode-p 'magit-diff-mode) - (pcase (magit-diff-type) - (`committed (pcase-let ((`(,a ,b) - (magit-ediff-compare--read-revisions - magit-buffer-range))) - (setq revA a) - (setq revB b))) - ((guard (not magit-ediff-dwim-show-on-hunks)) - (setq command #'magit-ediff-stage)) - (`unstaged (setq command #'magit-ediff-show-unstaged)) - (`staged (setq command #'magit-ediff-show-staged)) - (`undefined (setq command nil)) - (_ (setq command nil)))))) - (cond ((not command) - (call-interactively - (magit-read-char-case - "Failed to read your mind; do you want to " t - (?c "[c]ommit" 'magit-ediff-show-commit) - (?r "[r]ange" 'magit-ediff-compare) - (?s "[s]tage" 'magit-ediff-stage) - (?v "resol[v]e" 'magit-ediff-resolve)))) - ((eq command 'magit-ediff-compare) - (apply 'magit-ediff-compare revA revB - (magit-ediff-read-files revA revB file))) - ((eq command 'magit-ediff-show-commit) - (magit-ediff-show-commit revB)) - ((eq command 'magit-ediff-show-stash) - (magit-ediff-show-stash revB)) - (file - (funcall command file)) - (t - (call-interactively command))))))) - -;;;###autoload -(defun magit-ediff-show-staged (file) - "Show staged changes using Ediff. - -This only allows looking at the changes; to stage, unstage, -and discard changes using Ediff, use `magit-ediff-stage'. - -FILE must be relative to the top directory of the repository." - (interactive - (list (magit-read-file-choice "Show staged changes for file" - (magit-staged-files) - "No staged files"))) - (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) - "Show unstaged changes using Ediff. - -This only allows looking at the changes; to stage, unstage, -and discard changes using Ediff, use `magit-ediff-stage'. - -FILE must be relative to the top directory of the repository." - (interactive - (list (magit-read-file-choice "Show unstaged changes for file" - (magit-unstaged-files) - "No unstaged files"))) - (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) - "Show changes between `HEAD' and working tree using Ediff. -FILE must be relative to the top directory of the repository." - (interactive - (list (magit-read-file-choice "Show changes in file" - (magit-changed-files "HEAD") - "No changed files"))) - (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) - "Show changes introduced by COMMIT using Ediff." - (interactive (list (magit-read-branch-or-commit "Revision"))) - (let ((revA (concat commit "^")) - (revB commit)) - (apply #'magit-ediff-compare - revA revB - (magit-ediff-read-files revA revB (magit-current-file))))) - -;;;###autoload -(defun magit-ediff-show-stash (stash) - "Show changes introduced by STASH using Ediff. -`magit-ediff-show-stash-with-index' controls whether a -three-buffer Ediff is used in order to distinguish changes in the -stash that were staged." - (interactive (list (magit-read-stash "Stash"))) - (pcase-let* ((revA (concat stash "^1")) - (revB (concat stash "^2")) - (revC stash) - (`(,fileA ,fileC) (magit-ediff-read-files revA revC)) - (fileB fileC)) - (if (and magit-ediff-show-stash-with-index - (member fileA (magit-changed-files revB revA))) - (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 () - (let* ((ctl-buf ediff-control-buffer) - (ctl-win (ediff-get-visible-buffer-window ctl-buf)) - (ctl-frm ediff-control-frame) - (main-frame (cond ((window-live-p ediff-window-A) - (window-frame ediff-window-A)) - ((window-live-p ediff-window-B) - (window-frame ediff-window-B))))) - (ediff-kill-buffer-carefully ediff-diff-buffer) - (ediff-kill-buffer-carefully ediff-custom-diff-buffer) - (ediff-kill-buffer-carefully ediff-fine-diff-buffer) - (ediff-kill-buffer-carefully ediff-tmp-buffer) - (ediff-kill-buffer-carefully ediff-error-buffer) - (ediff-kill-buffer-carefully ediff-msg-buffer) - (ediff-kill-buffer-carefully ediff-debug-buffer) - (when (boundp 'ediff-patch-diagnostics) - (ediff-kill-buffer-carefully ediff-patch-diagnostics)) - (cond ((and (ediff-window-display-p) - (frame-live-p ctl-frm)) - (delete-frame ctl-frm)) - ((window-live-p ctl-win) - (delete-window ctl-win))) - (ediff-kill-buffer-carefully ctl-buf) - (when (frame-live-p main-frame) - (select-frame main-frame)))) - -(defun magit-ediff-restore-previous-winconf () - (set-window-configuration magit-ediff-previous-winconf)) - -;;; _ -(provide 'magit-ediff) -;;; magit-ediff.el ends here diff --git a/elpa/magit-20210802.1524/magit-extras.el b/elpa/magit-20210802.1524/magit-extras.el deleted file mode 100644 index a7f1cbe9..00000000 --- a/elpa/magit-20210802.1524/magit-extras.el +++ /dev/null @@ -1,772 +0,0 @@ -;;; magit-extras.el --- additional functionality for Magit -*- lexical-binding: t -*- - -;; 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) -;; 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. - -;;; Commentary: - -;; Additional functionality for Magit. - -;;; Code: - -(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." - :group 'magit-extensions) - -;;; External Tools - -(defcustom magit-gitk-executable - (or (and (eq system-type 'windows-nt) - (let ((exe (magit-git-string - "-c" "alias.X=!x() { which \"$1\" | cygpath -mf -; }; x" - "X" "gitk.exe"))) - (and exe (file-executable-p exe) exe))) - (executable-find "gitk") "gitk") - "The Gitk executable." - :group 'magit-extras - :set-after '(magit-git-executable) - :type 'string) - -;;;###autoload -(defun magit-run-git-gui () - "Run `git gui' for the current git repository." - (interactive) - (magit-with-toplevel (magit-process-git 0 "gui"))) - -;;;###autoload -(defun magit-run-git-gui-blame (commit filename &optional linenum) - "Run `git gui blame' on the given FILENAME and COMMIT. -Interactively run it for the current file and the `HEAD', with a -prefix or when the current file cannot be determined let the user -choose. When the current buffer is visiting FILENAME instruct -blame to center around the line point is on." - (interactive - (let (revision filename) - (when (or current-prefix-arg - (not (setq revision "HEAD" - filename (magit-file-relative-name nil 'tracked)))) - (setq revision (magit-read-branch-or-commit "Blame from revision")) - (setq filename (magit-read-file-from-rev revision "Blame file"))) - (list revision filename - (and (equal filename - (ignore-errors - (magit-file-relative-name buffer-file-name))) - (line-number-at-pos))))) - (magit-with-toplevel - (magit-process-git 0 "gui" "blame" - (and linenum (list (format "--line=%d" linenum))) - commit - filename))) - -;;;###autoload -(defun magit-run-gitk () - "Run `gitk' in the current repository." - (interactive) - (magit-process-file magit-gitk-executable nil 0)) - -;;;###autoload -(defun magit-run-gitk-branches () - "Run `gitk --branches' in the current repository." - (interactive) - (magit-process-file magit-gitk-executable nil 0 nil "--branches")) - -;;;###autoload -(defun magit-run-gitk-all () - "Run `gitk --all' in the current repository." - (interactive) - (magit-process-file magit-gitk-executable nil 0 nil "--all")) - -;;; Emacs Tools - -;;;###autoload -(defun ido-enter-magit-status () - "Drop into `magit-status' from file switching. - -This command does not work in Emacs 26.1. -See https://github.com/magit/magit/issues/3634 -and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31707. - -To make this command available use something like: - - (add-hook \\='ido-setup-hook - (lambda () - (define-key ido-completion-map - (kbd \"C-x g\") \\='ido-enter-magit-status))) - -Starting with Emacs 25.1 the Ido keymaps are defined just once -instead of every time Ido is invoked, so now you can modify it -like pretty much every other keymap: - - (define-key ido-common-completion-map - (kbd \"C-x g\") \\='ido-enter-magit-status)" - (interactive) - (setq ido-exit 'fallback) - (setq ido-fallback 'magit-status) ; for Emacs >= 26.2 - (with-no-warnings (setq fallback 'magit-status)) ; for Emacs 25 - (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 -is no file at point, then instead visit `default-directory'." - (interactive "P") - (dired-jump other-window - (when-let ((file (magit-file-at-point))) - (expand-file-name (if (file-directory-p file) - (file-name-as-directory file) - file))))) - -;;;###autoload -(defun magit-dired-log (&optional follow) - "Show log for all marked files, or the current file." - (interactive "P") - (if-let ((topdir (magit-toplevel default-directory))) - (let ((args (car (magit-log-arguments))) - (files (dired-get-marked-files nil nil #'magit-file-tracked-p))) - (unless files - (user-error "No marked file is being tracked by Git")) - (when (and follow - (not (member "--follow" args)) - (not (cdr files))) - (push "--follow" args)) - (magit-log-setup-buffer - (list (or (magit-get-current-branch) "HEAD")) - args - (let ((default-directory topdir)) - (mapcar #'file-relative-name files)) - magit-log-buffer-file-locked)) - (magit--not-inside-repository-error))) - -;;;###autoload -(defun magit-do-async-shell-command (file) - "Open FILE with `dired-do-async-shell-command'. -Interactively, open the file at point." - (interactive (list (or (magit-file-at-point) - (completing-read "Act on file: " - (magit-list-files))))) - (require 'dired-aux) - (dired-do-async-shell-command - (dired-read-shell-command "& on %s: " current-prefix-arg (list file)) - nil (list file))) - -;;; Shift Selection - -(defun magit--turn-on-shift-select-mode-p () - (and shift-select-mode - this-command-keys-shift-translated - (not mark-active) - (not (eq (car-safe transient-mark-mode) 'only)))) - -;;;###autoload -(defun magit-previous-line (&optional arg try-vscroll) - "Like `previous-line' but with Magit-specific shift-selection. - -Magit's selection mechanism is based on the region but selects an -area that is larger than the region. This causes `previous-line' -when invoked while holding the shift key to move up one line and -thereby select two lines. When invoked inside a hunk body this -command does not move point on the first invocation and thereby -it only selects a single line. Which inconsistency you prefer -is a matter of preference." - (declare (interactive-only - "use `forward-line' with negative argument instead.")) - (interactive "p\np") - (unless arg (setq arg 1)) - (let ((stay (or (magit-diff-inside-hunk-body-p) - (magit-section-position-in-heading-p)))) - (if (and stay (= arg 1) (magit--turn-on-shift-select-mode-p)) - (push-mark nil nil t) - (with-no-warnings - (handle-shift-selection) - (previous-line (if stay (max (1- arg) 1) arg) try-vscroll))))) - -;;;###autoload -(defun magit-next-line (&optional arg try-vscroll) - "Like `next-line' but with Magit-specific shift-selection. - -Magit's selection mechanism is based on the region but selects -an area that is larger than the region. This causes `next-line' -when invoked while holding the shift key to move down one line -and thereby select two lines. When invoked inside a hunk body -this command does not move point on the first invocation and -thereby it only selects a single line. Which inconsistency you -prefer is a matter of preference." - (declare (interactive-only forward-line)) - (interactive "p\np") - (unless arg (setq arg 1)) - (let ((stay (or (magit-diff-inside-hunk-body-p) - (magit-section-position-in-heading-p)))) - (if (and stay (= arg 1) (magit--turn-on-shift-select-mode-p)) - (push-mark nil nil t) - (with-no-warnings - (handle-shift-selection) - (next-line (if stay (max (1- arg) 1) arg) try-vscroll))))) - -;;; Clean - -;;;###autoload -(defun magit-clean (&optional arg) - "Remove untracked files from the working tree. -With a prefix argument also remove ignored files, -with two prefix arguments remove ignored files only. -\n(git clean -f -d [-x|-X])" - (interactive "p") - (when (yes-or-no-p (format "Remove %s files? " - (pcase arg - (1 "untracked") - (4 "untracked and ignored") - (_ "ignored")))) - (magit-wip-commit-before-change) - (magit-run-git "clean" "-f" "-d" (pcase arg (4 "-x") (16 "-X"))))) - -(put 'magit-clean 'disabled t) - -;;; 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. -This differs from `add-change-log-entry' (which see) in that -it acts on the current hunk in a Magit buffer instead of on -a position in a file-visiting buffer." - (interactive (list current-prefix-arg - (prompt-for-change-log-name))) - (pcase-let ((`(,buf ,pos) (magit-diff-visit-file--noselect))) - (magit--with-temp-position buf pos - (let ((add-log-buffer-file-name-function - (lambda () - (or magit-buffer-file-name - (buffer-file-name))))) - (add-change-log-entry whoami file-name other-window))))) - -;;;###autoload -(defun magit-add-change-log-entry-other-window (&optional whoami file-name) - "Find change log file in other window and add entry and item. -This differs from `add-change-log-entry-other-window' (which see) -in that it acts on the current hunk in a Magit buffer instead of -on a position in a file-visiting buffer." - (interactive (and current-prefix-arg - (list current-prefix-arg - (prompt-for-change-log-name)))) - (magit-add-change-log-entry whoami file-name t)) - -;;; Edit Line Commit - -;;;###autoload -(defun magit-edit-line-commit (&optional type) - "Edit the commit that added the current line. - -With a prefix argument edit the commit that removes the line, -if any. The commit is determined using `git blame' and made -editable using `git rebase --interactive' if it is reachable -from `HEAD', or by checking out the commit (or a branch that -points at it) otherwise." - (interactive (list (and current-prefix-arg 'removal))) - (let* ((chunk (magit-current-blame-chunk (or type 'addition))) - (rev (oref chunk orig-rev))) - (if (equal rev "0000000000000000000000000000000000000000") - (message "This line has not been committed yet") - (let ((rebase (magit-rev-ancestor-p rev "HEAD")) - (file (expand-file-name (oref chunk orig-file) - (magit-toplevel)))) - (if rebase - (let ((magit--rebase-published-symbol 'edit-published)) - (magit-rebase-edit-commit rev (magit-rebase-arguments))) - (magit-checkout (or (magit-rev-branch rev) rev))) - (unless (and buffer-file-name - (file-equal-p file buffer-file-name)) - (let ((blame-type (and magit-blame-mode magit-blame-type))) - (if rebase - (set-process-sentinel - magit-this-process - (lambda (process event) - (magit-sequencer-process-sentinel process event) - (when (eq (process-status process) 'exit) - (find-file file) - (when blame-type - (magit-blame--pre-blame-setup blame-type) - (magit-blame--run (magit-blame-arguments)))))) - (find-file file) - (when blame-type - (magit-blame--pre-blame-setup blame-type) - (magit-blame--run (magit-blame-arguments)))))))))) - -(put 'magit-edit-line-commit 'disabled t) - -;;;###autoload -(defun magit-diff-edit-hunk-commit (file) - "From a hunk, edit the respective commit and visit the file. - -First visit the file being modified by the hunk at the correct -location using `magit-diff-visit-file'. This actually visits a -blob. When point is on a diff header, not within an individual -hunk, then this visits the blob the first hunk is about. - -Then invoke `magit-edit-line-commit', which uses an interactive -rebase to make the commit editable, or if that is not possible -because the commit is not reachable from `HEAD' by checking out -that commit directly. This also causes the actual worktree file -to be visited. - -Neither the blob nor the file buffer are killed when finishing -the rebase. If that is undesirable, then it might be better to -use `magit-rebase-edit-command' instead of this command." - (interactive (list (magit-file-at-point t t))) - (let ((magit-diff-visit-previous-blob nil)) - (with-current-buffer - (magit-diff-visit-file--internal file nil #'pop-to-buffer-same-window) - (magit-edit-line-commit)))) - -(put 'magit-diff-edit-hunk-commit 'disabled t) - -;;; 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 keyid) - "Change the author and committer dates of the commits since REV. - -Ask the user for the first reachable commit whose dates should -be changed. Then read the new date for that commit. The initial -minibuffer input and the previous history element offer good -values. The next commit will be created one minute later and so -on. - -This command is only intended for interactive use and should only -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 - (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) - (when (memq (process-status process) '(exit signal)) - (if (> (process-exit-status process) 0) - (magit-process-sentinel process event) - (process-put process 'inhibit-refresh t) - (magit-process-sentinel process event) - (magit-run-git "update-ref" "-d" backup)))))))))))) - -;;; Revision Stack - -(defvar magit-revision-stack nil) - -(defcustom magit-pop-revision-stack-format - '("[%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 -of the revision last pushed to the `magit-revision-stack' into -the current buffer. It inserts text at point and/or near the end -of the buffer, and removes the consumed revision from the stack. - -The entries on the stack have the format (HASH TOPLEVEL) and this -option has the format (POINT-FORMAT EOB-FORMAT INDEX-REGEXP), all -of which may be nil or a string (though either one of EOB-FORMAT -or POINT-FORMAT should be a string, and if INDEX-REGEXP is -non-nil, then the two formats should be too). - -First INDEX-REGEXP is used to find the previously inserted entry, -by searching backward from point. The first submatch must match -the index number. That number is incremented by one, and becomes -the index number of the entry to be inserted. If you don't want -to number the inserted revisions, then use nil for INDEX-REGEXP. - -If INDEX-REGEXP is non-nil, then both POINT-FORMAT and EOB-FORMAT -should contain \"%N\", which is replaced with the number that was -determined in the previous step. - -Both formats, if non-nil and after removing %N, are then expanded -using `git show --format=FORMAT ...' inside TOPLEVEL. - -The expansion of POINT-FORMAT is inserted at point, and the -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 . "3.2.0") - :group 'magit-commands - :type '(list (choice (string :tag "Insert at point format") - (cons (string :tag "Insert at point format") - (repeat (string :tag "Argument to git show"))) - (const :tag "Don't insert at point" nil)) - (choice (string :tag "Insert at eob format") - (cons (string :tag "Insert at eob format") - (repeat (string :tag "Argument to git show"))) - (const :tag "Don't insert at eob" nil)) - (choice (regexp :tag "Find index regexp") - (const :tag "Don't number entries" nil)))) - -(defcustom magit-copy-revision-abbreviated nil - "Whether to save abbreviated revision to `kill-ring' and `magit-revision-stack'." - :package-version '(magit . "3.0.0") - :group 'magit-miscellaneous - :type 'boolean) - -;;;###autoload -(defun magit-pop-revision-stack (rev toplevel) - "Insert a representation of a revision into the current buffer. - -Pop a revision from the `magit-revision-stack' and insert it into -the current buffer according to `magit-pop-revision-stack-format'. -Revisions can be put on the stack using `magit-copy-section-value' -and `magit-copy-buffer-revision'. - -If the stack is empty or with a prefix argument, instead read a -revision in the minibuffer. By using the minibuffer history this -allows selecting an item which was popped earlier or to insert an -arbitrary reference or revision without first pushing it onto the -stack. - -When reading the revision from the minibuffer, then it might not -be possible to guess the correct repository. When this command -is called inside a repository (e.g. while composing a commit -message), then that repository is used. Otherwise (e.g. while -composing an email) then the repository recorded for the top -element of the stack is used (even though we insert another -revision). If not called inside a repository and with an empty -stack, or with two prefix arguments, then read the repository in -the minibuffer too." - (interactive - (if (or current-prefix-arg (not magit-revision-stack)) - (let ((default-directory - (or (and (not (= (prefix-numeric-value current-prefix-arg) 16)) - (or (magit-toplevel) - (cadr (car magit-revision-stack)))) - (magit-read-repository)))) - (list (magit-read-branch-or-commit "Insert revision") - default-directory)) - (push (caar magit-revision-stack) magit-revision-history) - (pop magit-revision-stack))) - (if rev - (pcase-let ((`(,pnt-format ,eob-format ,idx-format) - magit-pop-revision-stack-format)) - (let ((default-directory toplevel) - (idx (and idx-format - (save-excursion - (if (re-search-backward idx-format nil t) - (number-to-string - (1+ (string-to-number (match-string 1)))) - "1")))) - pnt-args eob-args) - (when (listp pnt-format) - (setq pnt-args (cdr pnt-format)) - (setq pnt-format (car pnt-format))) - (when (listp eob-format) - (setq eob-args (cdr eob-format)) - (setq eob-format (car eob-format))) - (when pnt-format - (when idx-format - (setq pnt-format - (replace-regexp-in-string "%N" idx pnt-format t t))) - (magit-rev-insert-format pnt-format rev pnt-args) - (backward-delete-char 1)) - (when eob-format - (when idx-format - (setq eob-format - (replace-regexp-in-string "%N" idx eob-format t t))) - (save-excursion - (goto-char (point-max)) - (skip-syntax-backward ">s-") - (beginning-of-line) - (if (and comment-start (looking-at comment-start)) - (while (looking-at comment-start) - (forward-line -1)) - (forward-line) - (unless (= (current-column) 0) - (insert ?\n))) - (insert ?\n) - (magit-rev-insert-format eob-format rev eob-args) - (backward-delete-char 1))))) - (user-error "Revision stack is empty"))) - -(define-key git-commit-mode-map - (kbd "C-c C-w") 'magit-pop-revision-stack) - -;;;###autoload -(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 -the current section is a commit, branch, or tag section, push -the (referenced) revision to the `magit-revision-stack' for use -with `magit-pop-revision-stack'. - -When `magit-copy-revision-abbreviated' is non-nil, save the -abbreviated revision to the `kill-ring' and the -`magit-revision-stack'. - -When the current section is a branch or a tag, and a prefix -argument is used, then save the revision at its tip to the -`kill-ring' instead of the reference name. - -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, 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 arg - (magit-section-internal-region-p) - (magit-section-match 'hunk)) - (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 - (when-let ((section (magit-current-section)) - (value (oref section value))) - (magit-section-case - ((branch commit module-commit tag) - (let ((default-directory default-directory) ref) - (magit-section-case - ((branch tag) - (setq ref value)) - (module-commit - (setq default-directory - (file-name-as-directory - (expand-file-name (magit-section-parent-value section) - (magit-toplevel)))))) - (setq value (magit-rev-parse - (and magit-copy-revision-abbreviated "--short") - value)) - (push (list value default-directory) magit-revision-stack) - (kill-new (message "%s" (or (and current-prefix-arg ref) - value))))) - (t (kill-new (message "%s" value)))))))) - -;;;###autoload -(defun magit-copy-buffer-revision () - "Save the revision of the current buffer for later use. - -Save the revision shown in the current buffer to the `kill-ring' -and push it to the `magit-revision-stack'. - -This command is mainly intended for use in `magit-revision-mode' -buffers, the only buffers where it is always unambiguous exactly -which revision should be saved. - -Most other Magit buffers usually show more than one revision, in -some way or another, so this command has to select one of them, -and that choice might not always be the one you think would have -been the best pick. - -In such buffers it is often more useful to save the value of -the current section instead, using `magit-copy-section-value'. - -When the region is active, then save that to the `kill-ring', -like `kill-ring-save' would, instead of behaving as described -above. - -When `magit-copy-revision-abbreviated' is non-nil, save the -abbreviated revision to the `kill-ring' and the -`magit-revision-stack'." - (interactive) - (if (use-region-p) - (call-interactively #'copy-region-as-kill) - (when-let ((rev (or magit-buffer-revision - (cl-case major-mode - (magit-diff-mode - (if (string-match "\\.\\.\\.?\\(.+\\)" - magit-buffer-range) - (match-string 1 magit-buffer-range) - magit-buffer-range)) - (magit-status-mode "HEAD"))))) - (when (magit-commit-p rev) - (setq rev (magit-rev-parse - (and magit-copy-revision-abbreviated "--short") - rev)) - (push (list rev default-directory) magit-revision-stack) - (kill-new (message "%s" rev)))))) - -;;; Miscellaneous - -;;;###autoload -(defun magit-abort-dwim () - "Abort current operation. -Depending on the context, this will abort a merge, a rebase, a -patch application, a cherry-pick, a revert, or a bisect." - (interactive) - (cond ((magit-merge-in-progress-p) (magit-merge-abort)) - ((magit-rebase-in-progress-p) (magit-rebase-abort)) - ((magit-am-in-progress-p) (magit-am-abort)) - ((magit-sequencer-in-progress-p) (magit-sequencer-abort)) - ((magit-bisect-in-progress-p) (magit-bisect-reset)))) - -;;; _ -(provide 'magit-extras) -;;; magit-extras.el ends here diff --git a/elpa/magit-20210802.1524/magit-fetch.el b/elpa/magit-20210802.1524/magit-fetch.el deleted file mode 100644 index e4006150..00000000 --- a/elpa/magit-20210802.1524/magit-fetch.el +++ /dev/null @@ -1,189 +0,0 @@ -;;; magit-fetch.el --- download objects and refs -*- lexical-binding: t -*- - -;; 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) -;; 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. - -;;; Commentary: - -;; This library implements fetch commands. - -;;; Code: - -(require 'magit) - -;;; Options - -(defcustom magit-fetch-modules-jobs 4 - "Number of submodules to fetch in parallel. -Ignored for Git versions before v2.8.0." - :package-version '(magit . "2.12.0") - :group 'magit-commands - :type '(choice (const :tag "one at a time" nil) number)) - -;;; Commands - -;;;###autoload (autoload 'magit-fetch "magit-fetch" nil t) -(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")) - (7 "-u" "Fetch full history" "--unshallow")] - ["Fetch from" - ("p" magit-fetch-from-pushremote) - ("u" magit-fetch-from-upstream) - ("e" "elsewhere" magit-fetch-other) - ("a" "all remotes" magit-fetch-all)] - ["Fetch" - ("o" "another branch" magit-fetch-branch) - ("r" "explicit refspec" magit-fetch-refspec) - ("m" "submodules" magit-fetch-modules)] - ["Configure" - ("C" "variables..." magit-branch-configure)]) - -(defun magit-fetch-arguments () - (transient-args 'magit-fetch)) - -(defun magit-git-fetch (remote args) - (run-hooks 'magit-credential-hook) - (magit-run-git-async "fetch" remote args)) - -;;;###autoload (autoload 'magit-fetch-from-pushremote "magit-fetch" nil t) -(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 -configured or unusable, then let the user first configure the -push-remote." - :description 'magit-fetch--pushremote-description - (interactive (list (magit-fetch-arguments))) - (let ((remote (magit-get-push-remote))) - (when (or current-prefix-arg - (not (member remote (magit-list-remotes)))) - (let ((var (magit--push-remote-variable))) - (setq remote - (magit-read-remote (format "Set %s and fetch from there" var))) - (magit-set remote var))) - (magit-git-fetch remote args))) - -(defun magit-fetch--pushremote-description () - (let* ((branch (magit-get-current-branch)) - (remote (magit-get-push-remote branch)) - (v (magit--push-remote-variable branch t))) - (cond - ((member remote (magit-list-remotes)) remote) - (remote - (format "%s, replacing invalid" v)) - (t - (format "%s, setting that" v))))) - -;;;###autoload (autoload 'magit-fetch-from-upstream "magit-fetch" nil t) -(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 -an existing remote, then use that. Otherwise try to use another -remote: If only a single remote is configured, then use that. -Otherwise if a remote named \"origin\" exists, then use that. - -If no remote can be determined, then this command is not available -from the `magit-fetch' transient prefix and invoking it directly -results in an error." - :if (lambda () (magit-get-current-remote t)) - :description (lambda () (magit-get-current-remote t)) - (interactive (list (magit-get-current-remote t) - (magit-fetch-arguments))) - (unless remote - (error "The \"current\" remote could not be determined")) - (magit-git-fetch remote args)) - -;;;###autoload -(defun magit-fetch-other (remote args) - "Fetch from another repository." - (interactive (list (magit-read-remote "Fetch remote") - (magit-fetch-arguments))) - (magit-git-fetch remote args)) - -;;;###autoload -(defun magit-fetch-branch (remote branch args) - "Fetch a BRANCH from a REMOTE." - (interactive - (let ((remote (magit-read-remote-or-url "Fetch from remote or url"))) - (list remote - (magit-read-remote-branch "Fetch branch" remote) - (magit-fetch-arguments)))) - (magit-git-fetch remote (cons branch args))) - -;;;###autoload -(defun magit-fetch-refspec (remote refspec args) - "Fetch a REFSPEC from a REMOTE." - (interactive - (let ((remote (magit-read-remote-or-url "Fetch from remote or url"))) - (list remote - (magit-read-refspec "Fetch using refspec" remote) - (magit-fetch-arguments)))) - (magit-git-fetch remote (cons refspec args))) - -;;;###autoload -(defun magit-fetch-all (args) - "Fetch from all remotes." - (interactive (list (magit-fetch-arguments))) - (magit-git-fetch nil (cons "--all" args))) - -;;;###autoload -(defun magit-fetch-all-prune () - "Fetch from all remotes, and prune. -Prune remote tracking branches for branches that have been -removed on the respective remote." - (interactive) - (run-hooks 'magit-credential-hook) - (magit-run-git-async "remote" "update" "--prune")) - -;;;###autoload -(defun magit-fetch-all-no-prune () - "Fetch from all remotes." - (interactive) - (run-hooks 'magit-credential-hook) - (magit-run-git-async "remote" "update")) - -;;;###autoload -(defun magit-fetch-modules (&optional all) - "Fetch all submodules. - -Option `magit-fetch-modules-jobs' controls how many submodules -are being fetched in parallel. Also fetch the super-repository, -because `git-fetch' does not support not doing that. With a -prefix argument fetch all remotes." - (interactive "P") - (magit-with-toplevel - (magit-run-git-async - "fetch" "--verbose" "--recurse-submodules" - (and magit-fetch-modules-jobs - (version<= "2.8.0" (magit-git-version)) - (list "-j" (number-to-string magit-fetch-modules-jobs))) - (and all "--all")))) - -;;; _ -(provide 'magit-fetch) -;;; magit-fetch.el ends here diff --git a/elpa/magit-20210802.1524/magit-files.el b/elpa/magit-20210802.1524/magit-files.el deleted file mode 100644 index 160de383..00000000 --- a/elpa/magit-20210802.1524/magit-files.el +++ /dev/null @@ -1,529 +0,0 @@ -;;; magit-files.el --- finding files -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements support for finding blobs, staged files, -;; and Git configuration files. It also implements modes useful in -;; buffers visiting files and blobs, and the commands used by those -;; modes. - -;;; Code: - -(require 'magit) - -;;; Find Blob - -(defvar magit-find-file-hook nil) -(add-hook 'magit-find-file-hook #'magit-blob-mode) - -;;;###autoload -(defun magit-find-file (rev file) - "View FILE from REV. -Switch to a buffer visiting blob REV:FILE, creating one if none -already exists. If prior to calling this command the current -buffer and/or cursor position is about the same file, then go -to the line and column corresponding to that location." - (interactive (magit-find-file-read-args "Find file")) - (magit-find-file--internal rev file #'pop-to-buffer-same-window)) - -;;;###autoload -(defun magit-find-file-other-window (rev file) - "View FILE from REV, in another window. -Switch to a buffer visiting blob REV:FILE, creating one if none -already exists. If prior to calling this command the current -buffer and/or cursor position is about the same file, then go to -the line and column corresponding to that location." - (interactive (magit-find-file-read-args "Find file in other window")) - (magit-find-file--internal rev file #'switch-to-buffer-other-window)) - -;;;###autoload -(defun magit-find-file-other-frame (rev file) - "View FILE from REV, in another frame. -Switch to a buffer visiting blob REV:FILE, creating one if none -already exists. If prior to calling this command the current -buffer and/or cursor position is about the same file, then go to -the line and column corresponding to that location." - (interactive (magit-find-file-read-args "Find file in other frame")) - (magit-find-file--internal rev file #'switch-to-buffer-other-frame)) - -(defun magit-find-file-read-args (prompt) - (let ((pseudo-revs '("{worktree}" "{index}"))) - (if-let ((rev (magit-completing-read "Find file from revision" - (append pseudo-revs - (magit-list-refnames nil t)) - nil nil nil 'magit-revision-history - (or (magit-branch-or-commit-at-point) - (magit-get-current-branch))))) - (list rev (magit-read-file-from-rev (if (member rev pseudo-revs) - "HEAD" - rev) - prompt)) - (user-error "Nothing selected")))) - -(defun magit-find-file--internal (rev file fn) - (let ((buf (magit-find-file-noselect rev file)) - line col) - (when-let ((visited-file (magit-file-relative-name))) - (setq line (line-number-at-pos)) - (setq col (current-column)) - (cond - ((not (equal visited-file file))) - ((equal magit-buffer-revision rev)) - ((equal rev "{worktree}") - (setq line (magit-diff-visit--offset file magit-buffer-revision line))) - ((equal rev "{index}") - (setq line (magit-diff-visit--offset file nil line))) - (magit-buffer-revision - (setq line (magit-diff-visit--offset - file (concat magit-buffer-revision ".." rev) line))) - (t - (setq line (magit-diff-visit--offset file (list "-R" rev) line))))) - (funcall fn buf) - (when line - (with-current-buffer buf - (widen) - (goto-char (point-min)) - (forward-line (1- line)) - (move-to-column col))) - buf)) - -(defun magit-find-file-noselect (rev file) - "Read FILE from REV into a buffer and return the buffer. -REV is a revision or one of \"{worktree}\" or \"{index}\". -FILE must be relative to the top directory of the repository." - (magit-find-file-noselect-1 rev file)) - -(defun magit-find-file-noselect-1 (rev file &optional revert) - "Read FILE from REV into a buffer and return the buffer. -REV is a revision or one of \"{worktree}\" or \"{index}\". -FILE must be relative to the top directory of the repository. -Non-nil REVERT means to revert the buffer. If `ask-revert', -then only after asking. A non-nil value for REVERT is ignored if REV is -\"{worktree}\"." - (if (equal rev "{worktree}") - (find-file-noselect (expand-file-name file (magit-toplevel))) - (let ((topdir (magit-toplevel))) - (when (file-name-absolute-p file) - (setq file (file-relative-name file topdir))) - (with-current-buffer (magit-get-revision-buffer-create rev file) - (when (or (not magit-buffer-file-name) - (if (eq revert 'ask-revert) - (y-or-n-p (format "%s already exists; revert it? " - (buffer-name)))) - revert) - (setq magit-buffer-revision - (if (equal rev "{index}") - "{index}" - (magit-rev-format "%H" rev))) - (setq magit-buffer-refname rev) - (setq magit-buffer-file-name (expand-file-name file topdir)) - (setq default-directory - (let ((dir (file-name-directory magit-buffer-file-name))) - (if (file-exists-p dir) dir topdir))) - (setq-local revert-buffer-function #'magit-revert-rev-file-buffer) - (revert-buffer t t) - (run-hooks (if (equal rev "{index}") - 'magit-find-index-hook - 'magit-find-file-hook))) - (current-buffer))))) - -(defun magit-get-revision-buffer-create (rev file) - (magit-get-revision-buffer rev file t)) - -(defun magit-get-revision-buffer (rev file &optional create) - (funcall (if create 'get-buffer-create 'get-buffer) - (format "%s.~%s~" file (subst-char-in-string ?/ ?_ rev)))) - -(defun magit-revert-rev-file-buffer (_ignore-auto noconfirm) - (when (or noconfirm - (and (not (buffer-modified-p)) - (catch 'found - (dolist (regexp revert-without-query) - (when (string-match regexp magit-buffer-file-name) - (throw 'found t))))) - (yes-or-no-p (format "Revert buffer from Git %s? " - (if (equal magit-buffer-refname "{index}") - "index" - (concat "revision " magit-buffer-refname))))) - (let* ((inhibit-read-only t) - (default-directory (magit-toplevel)) - (file (file-relative-name magit-buffer-file-name)) - (coding-system-for-read (or coding-system-for-read 'undecided))) - (erase-buffer) - (magit-git-insert "cat-file" "-p" - (if (equal magit-buffer-refname "{index}") - (concat ":" file) - (concat magit-buffer-refname ":" file))) - (setq buffer-file-coding-system last-coding-system-used)) - (let ((buffer-file-name magit-buffer-file-name) - (after-change-major-mode-hook - (remq 'global-diff-hl-mode-enable-in-buffers - after-change-major-mode-hook))) - (normal-mode t)) - (setq buffer-read-only t) - (set-buffer-modified-p nil) - (goto-char (point-min)))) - -;;; Find Index - -(defvar magit-find-index-hook nil) - -(defun magit-find-file-index-noselect (file &optional revert) - "Read FILE from the index into a buffer and return the buffer. -FILE must to be relative to the top directory of the repository." - (magit-find-file-noselect-1 "{index}" file (or revert 'ask-revert))) - -(defun magit-update-index () - "Update the index with the contents of the current buffer. -The current buffer has to be visiting a file in the index, which -is done using `magit-find-index-noselect'." - (interactive) - (let ((file (magit-file-relative-name))) - (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-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")) - (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"))) - (message "Abort"))) - (--when-let (magit-get-mode-buffer 'magit-status-mode) - (with-current-buffer it (magit-refresh))) - t) - -;;; Find Config File - -(defun magit-find-git-config-file (filename &optional wildcards) - "Edit a file located in the current repository's git directory. - -When \".git\", located at the root of the working tree, is a -regular file, then that makes it cumbersome to open a file -located in the actual git directory. - -This command is like `find-file', except that it temporarily -binds `default-directory' to the actual git directory, while -reading the FILENAME." - (interactive - (let ((default-directory (magit-git-dir))) - (find-file-read-args "Find file: " - (confirm-nonexistent-file-or-buffer)))) - (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. - -When \".git\", located at the root of the working tree, is a -regular file, then that makes it cumbersome to open a file -located in the actual git directory. - -This command is like `find-file-other-window', except that it -temporarily binds `default-directory' to the actual git -directory, while reading the FILENAME." - (interactive - (let ((default-directory (magit-git-dir))) - (find-file-read-args "Find file in other window: " - (confirm-nonexistent-file-or-buffer)))) - (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. - -When \".git\", located at the root of the working tree, is a -regular file, then that makes it cumbersome to open a file -located in the actual git directory. - -This command is like `find-file-other-frame', except that it -temporarily binds `default-directory' to the actual git -directory, while reading the FILENAME." - (interactive - (let ((default-directory (magit-git-dir))) - (find-file-read-args "Find file in other frame: " - (confirm-nonexistent-file-or-buffer)))) - (find-file-other-frame filename wildcards)) - -;;; File Dispatch - -;;;###autoload (autoload 'magit-file-dispatch "magit" nil t) -(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) - ("u" "Unstage" magit-unstage-file) - ("c" "Commit" magit-commit) - ("e" "Edit line" magit-edit-line-commit)] - [("D" "Diff..." magit-diff) - ("d" "Diff" magit-diff-buffer-file) - ("g" "Status" magit-status-here)] - [("L" "Log..." magit-log) - ("l" "Log" magit-log-buffer-file) - ("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) - ("f" "...reverse" magit-blame-reverse) - ("m" "Blame echo" magit-blame-echo) - ("q" "Quit blame" magit-blame-quit)] - [("p" "Prev blob" magit-blob-previous) - ("n" "Next blob" magit-blob-next) - ("v" "Goto blob" magit-find-file) - ("V" "Goto file" magit-blob-visit-file)] - [(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)]] - (interactive) - (transient-setup - (if (magit-file-relative-name) - 'magit-file-dispatch - 'magit-dispatch))) - -;;; Blob Mode - -(defvar magit-blob-mode-map - (let ((map (make-sparse-keymap))) - (define-key map "p" 'magit-blob-previous) - (define-key map "n" 'magit-blob-next) - (define-key map "b" 'magit-blame-addition) - (define-key map "r" 'magit-blame-removal) - (define-key map "f" 'magit-blame-reverse) - (define-key map "q" 'magit-kill-this-buffer) - map) - "Keymap for `magit-blob-mode'.") - -(define-minor-mode magit-blob-mode - "Enable some Magit features in blob-visiting buffers. - -Currently this only adds the following key bindings. -\n\\{magit-blob-mode-map}" - :package-version '(magit . "2.3.0")) - -(defun magit-blob-next () - "Visit the next blob which modified the current file." - (interactive) - (if magit-buffer-file-name - (magit-blob-visit (or (magit-blob-successor magit-buffer-revision - magit-buffer-file-name) - magit-buffer-file-name)) - (if (buffer-file-name (buffer-base-buffer)) - (user-error "You have reached the end of time") - (user-error "Buffer isn't visiting a file or blob")))) - -(defun magit-blob-previous () - "Visit the previous blob which modified the current file." - (interactive) - (if-let ((file (or magit-buffer-file-name - (buffer-file-name (buffer-base-buffer))))) - (--if-let (magit-blob-ancestor magit-buffer-revision file) - (magit-blob-visit it) - (user-error "You have reached the beginning of time")) - (user-error "Buffer isn't visiting a file or blob"))) - -;;;###autoload -(defun magit-blob-visit-file () - "View the file from the worktree corresponding to the current blob. -When visiting a blob or the version from the index, then go to -the same location in the respective file in the working tree." - (interactive) - (if-let ((file (magit-file-relative-name))) - (magit-find-file--internal "{worktree}" file #'pop-to-buffer-same-window) - (user-error "Not visiting a blob"))) - -(defun magit-blob-visit (blob-or-file) - (if (stringp blob-or-file) - (find-file blob-or-file) - (pcase-let ((`(,rev ,file) blob-or-file)) - (magit-find-file rev file) - (apply #'message "%s (%s %s ago)" - (magit-rev-format "%s" rev) - (magit--age (magit-rev-format "%ct" rev)))))) - -(defun magit-blob-ancestor (rev file) - (let ((lines (magit-with-toplevel - (magit-git-lines "log" "-2" "--format=%H" "--name-only" - "--follow" (or rev "HEAD") "--" file)))) - (if rev (cddr lines) (butlast lines 2)))) - -(defun magit-blob-successor (rev file) - (let ((lines (magit-with-toplevel - (magit-git-lines "log" "--format=%H" "--name-only" "--follow" - "HEAD" "--" file)))) - (catch 'found - (while lines - (if (equal (nth 2 lines) rev) - (throw 'found (list (nth 0 lines) (nth 1 lines))) - (setq lines (nthcdr 2 lines))))))) - -;;; File Commands - -(defun magit-file-rename (file newname) - "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 "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)) - (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 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) - (magit-convert-filename-for-git newname)) - (rename-file file newname current-prefix-arg)) - (when oldbuf - (with-current-buffer oldbuf - (let ((buffer-read-only buffer-read-only)) - (set-visited-file-name dstfile nil t)) - (if (fboundp 'vc-refresh-state) - (vc-refresh-state) - (with-no-warnings - (vc-find-file-hook)))))) - (magit-refresh)) - -(defun magit-file-untrack (files &optional force) - "Untrack the selected FILES or one file read in the minibuffer. - -With a prefix argument FORCE do so even when the files have -staged as well as unstaged changes." - (interactive (list (or (--if-let (magit-region-values 'file t) - (progn - (unless (magit-file-tracked-p (car it)) - (user-error "Already untracked")) - (magit-confirm-files 'untrack it "Untrack")) - (list (magit-read-tracked-file "Untrack file")))) - current-prefix-arg)) - (magit-with-toplevel - (magit-run-git "rm" "--cached" (and force "--force") "--" files))) - -(defun magit-file-delete (files &optional force) - "Delete the selected FILES or one file read in the minibuffer. - -With a prefix argument FORCE do so even when the files have -uncommitted changes. When the files aren't being tracked in -Git, then fallback to using `delete-file'." - (interactive (list (--if-let (magit-region-values 'file t) - (magit-confirm-files 'delete it "Delete") - (list (magit-read-file "Delete file"))) - current-prefix-arg)) - (if (magit-file-tracked-p (car files)) - (magit-call-git "rm" (and force "--force") "--" files) - (let ((topdir (magit-toplevel))) - (dolist (file files) - (delete-file (expand-file-name file topdir) t)))) - (magit-refresh)) - -;;;###autoload -(defun magit-file-checkout (rev file) - "Checkout FILE from REV." - (interactive - (let ((rev (magit-read-branch-or-commit - "Checkout from revision" magit-buffer-revision))) - (list rev (magit-read-file-from-rev rev "Checkout file")))) - (magit-with-toplevel - (magit-run-git "checkout" rev "--" file))) - -;;; Read File - -(defvar magit-read-file-hist nil) - -(defun magit-read-file-from-rev (rev prompt &optional default) - (let ((files (magit-revision-files rev))) - (magit-completing-read - prompt files nil t nil 'magit-read-file-hist - (car (member (or default (magit-current-file)) files))))) - -(defun magit-read-file (prompt &optional tracked-only) - (let ((choices (nconc (magit-list-files) - (unless tracked-only (magit-untracked-files))))) - (magit-completing-read - prompt choices nil t nil nil - (car (member (or (magit-section-value-if '(file submodule)) - (magit-file-relative-name nil tracked-only)) - choices))))) - -(defun magit-read-tracked-file (prompt) - (magit-read-file prompt t)) - -(defun magit-read-file-choice (prompt files &optional error default) - "Read file from FILES. - -If FILES has only one member, return that instead of prompting. -If FILES has no members, give a user error. ERROR can be given -to provide a more informative error. - -If DEFAULT is non-nil, use this as the default value instead of -`magit-current-file'." - (pcase (length files) - (0 (user-error (or error "No file choices"))) - (1 (car files)) - (_ (magit-completing-read - prompt files nil t nil 'magit-read-file-hist - (car (member (or default (magit-current-file)) files)))))) - -(defun magit-read-changed-file (rev-or-range prompt &optional default) - (magit-read-file-choice - prompt - (magit-changed-files rev-or-range) - default - (concat "No file changed in " rev-or-range))) - -;;; _ -(provide 'magit-files) -;;; magit-files.el ends here diff --git a/elpa/magit-20210802.1524/magit-git.el b/elpa/magit-20210802.1524/magit-git.el deleted file mode 100644 index 68f9ff1f..00000000 --- a/elpa/magit-20210802.1524/magit-git.el +++ /dev/null @@ -1,2464 +0,0 @@ -;;; magit-git.el --- Git functionality -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements wrappers for various Git plumbing commands. - -;;; Code: - -(require 'magit-utils) -(require 'magit-section) - -;; From `magit-branch'. -(defvar magit-branch-prefer-remote-upstream) -(defvar magit-published-branches) - -;; From `magit-margin'. -(declare-function magit-maybe-make-margin-overlay "magit-margin" ()) - -;; From `magit-mode'. -(declare-function magit-get-mode-buffer "magit-mode" - (mode &optional value frame)) -(declare-function magit-refresh "magit-mode" ()) -(defvar magit-buffer-diff-args) -(defvar magit-buffer-file-name) -(defvar magit-buffer-log-args) -(defvar magit-buffer-log-files) -(defvar magit-buffer-refname) -(defvar magit-buffer-revision) - -;; From `magit-process'. -(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) -(defvar magit-process-error-message-regexps) - -;; 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 - -(defvar magit-inhibit-libgit nil - "Whether to inhibit the use of libgit.") - -(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 'unknown) - (setq magit--libgit-available-p - (and module-file-suffix - (let ((libgit (locate-library "libgit"))) - (and libgit - (or (locate-library "libegit2") - (let ((load-path - (cons (expand-file-name - (convert-standard-filename "build") - (file-name-directory libgit)) - load-path))) - (locate-library "libegit2"))))))) - magit--libgit-available-p)) - -(defun magit-gitimpl () - "Return the Git implementation used in this repository." - (if (and (not magit-inhibit-libgit) - (not (file-remote-p default-directory)) - (magit--libgit-available-p)) - 'libgit - 'git)) - -;;; Options - -;; For now this is shared between `magit-process' and `magit-git'. -(defgroup magit-process nil - "Git and other external processes used by Magit." - :group 'magit) - -(defvar magit-git-environment - (list (format "INSIDE_EMACS=%s,magit" emacs-version)) - "Prepended to `process-environment' while running git.") - -(defcustom magit-git-output-coding-system - (and (eq system-type 'windows-nt) 'utf-8) - "Coding system for receiving output from Git. - -If non-nil, the Git config value `i18n.logOutputEncoding' should -be set via `magit-git-global-arguments' to value consistent with -this." - :package-version '(magit . "2.9.0") - :group 'magit-process - :type '(choice (coding-system :tag "Coding system to decode Git output") - (const :tag "Use system default" nil))) - -(defvar magit-git-w32-path-hack nil - "Alist of (EXE . (PATHENTRY)). -This specifies what additional PATH setting needs to be added to -the environment in order to run the non-wrapper git executables -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 where we would otherwise end up using 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) - (--when-let (executable-find "git") - (ignore-errors - ;; Git for Windows 2.x provides cygpath so we can - ;; ask it for native paths. - (let* ((core-exe - (car - (process-lines - it "-c" - "alias.X=!x() { which \"$1\" | cygpath -mf -; }; x" - "X" "git"))) - (hack-entry (assoc core-exe magit-git-w32-path-hack)) - ;; Running the libexec/git-core executable - ;; requires some extra PATH entries. - (path-hack - (list (concat "PATH=" - (car (process-lines - it "-c" - "alias.P=!cygpath -wp \"$PATH\"" - "P")))))) - ;; The defcustom STANDARD expression can be - ;; evaluated many times, so make sure it is - ;; idempotent. - (if hack-entry - (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 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." - :package-version '(magit . "3.2.0") - :group 'magit-process - :type 'string) - -(defcustom magit-git-global-arguments - `("--no-pager" "--literal-pathspecs" - "-c" "core.preloadindex=true" - "-c" "log.showSignature=false" - "-c" "color.ui=false" - "-c" "color.diff=false" - ,@(and (eq system-type 'windows-nt) - (list "-c" "i18n.logOutputEncoding=UTF-8"))) - "Global Git arguments. - -The arguments set here are used every time the git executable is -run as a subprocess. They are placed right after the executable -itself and before the git command - as in `git HERE... COMMAND -REST'. See the manpage `git(1)' for valid arguments. - -Be careful what you add here, especially if you are using Tramp -to connect to servers with ancient Git versions. Never remove -anything that is part of the default value, unless you really -know what you are doing. And think very hard before adding -something; it will be used every time Magit runs Git for any -purpose." - :package-version '(magit . "2.9.0") - :group 'magit-commands - :group 'magit-process - :type '(repeat string)) - -(defvar magit-git-debug nil - "Whether to enable additional reporting of git errors. - -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 \ -\\\\[magit-process]. - -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.") - - -(defcustom magit-prefer-remote-upstream nil - "Whether to favor remote branches when reading the upstream branch. - -This controls whether commands that read a branch from the user -and then set it as the upstream branch, offer a local or a remote -branch as default completion candidate, when they have the choice. - -This affects all commands that use `magit-read-upstream-branch' -or `magit-read-starting-point', which includes most commands -that change the upstream and many that create new branches." - :package-version '(magit . "2.4.2") - :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. - -This affects commands that read a ref. More specifically, it -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. By default, refs are sorted according to -their full refname (i.e., 'refs/...'). - -Any value accepted by the `--sort' flag of `git for-each-ref' can -be used. For example, \"-creatordate\" places refs with more -recent committer or tagger dates earlier in the list. A list of -strings can also be given in order to pass multiple sort keys to -`git for-each-ref'. - -Note that, depending on the completion framework you use, this -may not be sufficient to change the order in which the refs are -displayed. It only controls the order of the collection passed -to `magit-completing-read' or, for commands that support reading -multiple strings, `read-from-minibuffer'. The completion -framework ultimately determines how the collection is displayed." - :package-version '(magit . "2.11.0") - :group 'magit-miscellaneous - :type '(choice string (repeat string))) - -;;; Git - -(defvar magit--refresh-cache nil) - -(defmacro magit--with-refresh-cache (key &rest body) - (declare (indent 1) (debug (form body))) - (let ((k (cl-gensym))) - `(if magit--refresh-cache - (let ((,k ,key)) - (--if-let (assoc ,k (cdr magit--refresh-cache)) - (progn (cl-incf (caar magit--refresh-cache)) - (cdr it)) - (cl-incf (cdar magit--refresh-cache)) - (let ((value ,(macroexp-progn body))) - (push (cons ,k value) - (cdr magit--refresh-cache)) - value))) - ,@body))) - -(defvar magit-with-editor-envvar "GIT_EDITOR" - "The environment variable exported by `magit-with-editor'. -Set this to \"GIT_SEQUENCE_EDITOR\" if you do not want to use -Emacs to edit commit messages but would like to do so to edit -rebase sequences.") - -(defmacro magit-with-editor (&rest body) - "Like `with-editor' but let-bind some more variables. -Also respect the value of `magit-with-editor-envvar'." - (declare (indent 0) (debug (body))) - `(let ((magit-process-popup-time -1) - ;; The user may have customized `shell-file-name' to - ;; something which results in `w32-shell-dos-semantics' nil - ;; (which changes the quoting style used by - ;; `shell-quote-argument'), but Git for Windows expects shell - ;; quoting in the dos style. - (shell-file-name (if (and (eq system-type 'windows-nt) - ;; If we have Cygwin mount points, - ;; the git flavor is cygwin, so dos - ;; shell quoting is probably wrong. - (not magit-cygwin-mount-points)) - "cmdproxy" - shell-file-name))) - (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. - -Magit has many specialized functions for running Git; they all -pass arguments through this function before handing them to Git, -to do the following. - -* Flatten ARGS, removing nil arguments. -* Prepend `magit-git-global-arguments' to ARGS. -* On w32 systems, encode to `w32-ansi-code-page'." - (setq args (append magit-git-global-arguments (-flatten args))) - (if (and (eq system-type 'windows-nt) (boundp 'w32-ansi-code-page)) - ;; On w32, the process arguments *must* be encoded in the - ;; current code-page (see #3250). - (mapcar (lambda (arg) - (encode-coding-string - arg (intern (format "cp%d" w32-ansi-code-page)))) - args) - args)) - -(defun magit-git-exit-code (&rest args) - "Execute Git with ARGS, returning its exit code." - (magit-process-git nil args)) - -(defun magit-git-success (&rest args) - "Execute Git with ARGS, returning t if its exit code is 0." - (= (magit-git-exit-code args) 0)) - -(defun magit-git-failure (&rest args) - "Execute Git with ARGS, returning t if its exit code is 1." - (= (magit-git-exit-code args) 1)) - -(defun magit-git-string-p (&rest args) - "Execute Git with ARGS, returning the first line of its output. -If the exit code isn't zero or if there is no output, then return -nil. Neither of these results is considered an error; if that is -what you want, then use `magit-git-string-ng' instead. - -This is an experimental replacement for `magit-git-string', and -still subject to major changes." - (magit--with-refresh-cache (cons default-directory args) - (magit--with-temp-process-buffer - (and (zerop (magit-process-git t args)) - (not (bobp)) - (progn - (goto-char (point-min)) - (buffer-substring-no-properties (point) (line-end-position))))))) - -(defun magit-git-string-ng (&rest args) - "Execute Git with ARGS, returning the first line of its output. -If the exit code isn't zero or if there is no output, then that -is considered an error, but instead of actually signaling an -error, return nil. Additionally the output is put in the process -buffer (creating it if necessary) and the error message is shown -in the status buffer (provided it exists). - -This is an experimental replacement for `magit-git-string', and -still subject to major changes. Also see `magit-git-string-p'." - (magit--with-refresh-cache - (list default-directory 'magit-git-string-ng args) - (magit--with-temp-process-buffer - (let* ((args (magit-process-git-arguments args)) - (status (magit-process-git t args))) - (if (zerop status) - (and (not (bobp)) - (progn - (goto-char (point-min)) - (buffer-substring-no-properties - (point) (line-end-position)))) - (let ((buf (current-buffer))) - (with-current-buffer (magit-process-buffer t) - (magit-process-insert-section default-directory - magit-git-executable args - status buf))) - (when-let ((status-buf (magit-get-mode-buffer 'magit-status-mode))) - (let ((msg (magit--locate-error-message))) - (with-current-buffer status-buf - (setq magit-this-error msg)))) - nil))))) - -(defun magit-git-str (&rest args) - "Execute Git with ARGS, returning the first line of its output. -If there is no output, return nil. If the output begins with a -newline, return an empty string. Like `magit-git-string' but -ignore `magit-git-debug'." - (setq args (-flatten args)) - (magit--with-refresh-cache (cons default-directory 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)))))) - -(defun magit-git-output (&rest args) - "Execute Git with ARGS, returning its output." - (setq args (-flatten args)) - (magit--with-refresh-cache (cons default-directory 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") - -(defun magit-git-true (&rest args) - "Execute Git with ARGS, returning t if it prints \"true\". -If it prints \"false\", then return nil. For any other output -signal `magit-invalid-git-boolean'." - (pcase (magit-git-output args) - ((or "true" "true\n") t) - ((or "false" "false\n") nil) - (output (signal 'magit-invalid-git-boolean (list output))))) - -(defun magit-git-false (&rest args) - "Execute Git with ARGS, returning t if it prints \"false\". -If it prints \"true\", then return nil. For any other output -signal `magit-invalid-git-boolean'." - (pcase (magit-git-output args) - ((or "true" "true\n") nil) - ((or "false" "false\n") t) - (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. -If Git exits with a non-zero exit status, then show a message and -add a section in the respective process buffer." - (setq args (magit-process-git-arguments args)) - (if magit-git-debug - (let (log) - (unwind-protect - (progn - (setq log (make-temp-file "magit-stderr")) - (delete-file log) - (let ((exit (magit-process-git (list t log) args))) - (when (> exit 0) - (let ((msg "Git failed")) - (when (file-exists-p log) - (setq msg (with-temp-buffer - (insert-file-contents log) - (goto-char (point-max)) - (if (functionp magit-git-debug) - (funcall magit-git-debug (buffer-string)) - (magit--locate-error-message)))) - (let ((magit-git-debug nil)) - (with-current-buffer (magit-process-buffer t) - (magit-process-insert-section default-directory - magit-git-executable - args exit log)))) - (message "%s" msg))) - exit)) - (ignore-errors (delete-file log)))) - (magit-process-git (list t nil) args))) - -(defun magit--locate-error-message () - (goto-char (point-max)) - (and (run-hook-wrapped 'magit-process-error-message-regexps - (lambda (re) (re-search-backward re nil t))) - (match-string-no-properties 1))) - -(defun magit-git-string (&rest args) - "Execute Git with ARGS, returning the first line of its output. -If there is no output, return nil. If the output begins with a -newline, return an empty string." - (setq args (-flatten args)) - (magit--with-refresh-cache (cons default-directory args) - (magit--with-temp-process-buffer - (apply #'magit-git-insert args) - (unless (bobp) - (goto-char (point-min)) - (buffer-substring-no-properties (point) (line-end-position)))))) - -(defun magit-git-lines (&rest args) - "Execute Git with ARGS, returning its output as a list of lines. -Empty lines anywhere in the output are omitted. - -If Git exits with a non-zero exit status, then report show a -message and add a section in the respective process buffer." - (magit--with-temp-process-buffer - (apply #'magit-git-insert args) - (split-string (buffer-string) "\n" t))) - -(defun magit-git-items (&rest args) - "Execute Git with ARGS, returning its null-separated output as a list. -Empty items anywhere in the output are omitted. - -If Git exits with a non-zero exit status, then report show a -message and add a section in the respective process buffer." - (magit--with-temp-process-buffer - (apply #'magit-git-insert args) - (split-string (buffer-string) "\0" t))) - -(defun magit-git-wash (washer &rest args) - "Execute Git with ARGS, inserting washed output at point. -Actually first insert the raw output at point. If there is no -output, call `magit-cancel-section'. Otherwise temporarily narrow -the buffer to the inserted text, move to its beginning, and then -call function WASHER with ARGS as its sole argument." - (declare (indent 1)) - (let ((beg (point))) - (setq args (-flatten args)) - (magit-git-insert args) - (if (= (point) beg) - (magit-cancel-section) - (unless (bolp) - (insert "\n")) - (save-restriction - (narrow-to-region beg (point)) - (goto-char beg) - (funcall washer args)) - (when (or (= (point) beg) - (= (point) (1+ beg))) - (magit-cancel-section)) - (magit-maybe-make-margin-overlay)))) - -(defun magit-git-version (&optional raw) - (--when-let (let (magit-git-global-arguments) - (ignore-errors (substring (magit-git-string "version") 12))) - (if raw it (and (string-match "\\`\\([0-9]+\\(\\.[0-9]+\\)\\{1,2\\}\\)" it) - (match-string 1 it))))) - -;;; Variables - -(defun magit-config-get-from-cached-list (key) - (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)) - (magit--with-refresh-cache (cons (magit-toplevel) 'config) - (let ((configs (make-hash-table :test 'equal))) - (dolist (conf (magit-git-items "config" "--list" "-z")) - (let* ((nl-pos (cl-position ?\n conf)) - (key (substring conf 0 nl-pos)) - (val (if nl-pos (substring conf (1+ nl-pos)) ""))) - (puthash key (nconc (gethash key configs) (list val)) configs))) - configs)))) - -(defun magit-get (&rest keys) - "Return the value of the Git variable specified by KEYS." - (car (last (apply 'magit-get-all keys)))) - -(defun magit-get-all (&rest keys) - "Return all values of the Git variable specified by KEYS." - (let ((magit-git-debug nil) - (arg (and (or (null (car keys)) - (string-prefix-p "--" (car keys))) - (pop keys))) - (key (mapconcat 'identity keys "."))) - (if (and magit--refresh-cache (not arg)) - (magit-config-get-from-cached-list key) - (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. -Also see `magit-git-config-p'." - (let ((key (mapconcat 'identity keys "."))) - (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." - (let ((arg (and (or (null (car keys)) - (string-prefix-p "--" (car keys))) - (pop keys))) - (key (mapconcat 'identity keys "."))) - (if value - (magit-git-success "config" arg key value) - (magit-git-success "config" arg "--unset" key)) - value)) - -(gv-define-setter magit-get (val &rest keys) - `(magit-set ,val ,@keys)) - -(defun magit-set-all (values &rest keys) - "Set all values of the Git variable specified by KEYS to VALUES." - (let ((arg (and (or (null (car keys)) - (string-prefix-p "--" (car keys))) - (pop keys))) - (var (mapconcat 'identity keys "."))) - (when (magit-get var) - (magit-call-git "config" arg "--unset-all" var)) - (dolist (v values) - (magit-call-git "config" arg "--add" var v)))) - -;;; Files - -(defun magit--safe-default-directory (&optional file) - (catch 'unsafe-default-dir - (let ((dir (file-name-as-directory - (expand-file-name (or file default-directory)))) - (previous nil)) - (while (not (magit-file-accessible-directory-p dir)) - (setq dir (file-name-directory (directory-file-name dir))) - (when (equal dir previous) - (throw 'unsafe-default-dir nil)) - (setq previous dir)) - dir))) - -(defmacro magit--with-safe-default-directory (file &rest body) - (declare (indent 1) (debug (form body))) - `(when-let ((default-directory (magit--safe-default-directory ,file))) - ,@body)) - -(defun magit-gitdir (&optional directory) - "Return the absolute and resolved path of the .git directory. - -If the `GIT_DIR' environment variable is define then return that. -Otherwise return the .git directory for DIRECTORY, or if that is -nil, then for `default-directory' instead. If the directory is -not located inside a Git repository, then return nil." - (let ((default-directory (or directory default-directory))) - (magit-git-dir))) - -(defun magit-git-dir (&optional path) - "Return the absolute and resolved path of the .git directory. - -If the `GIT_DIR' environment variable is define then return that. -Otherwise return the .git directory for `default-directory'. If -the directory is not located inside a Git repository, then return -nil." - (magit--with-refresh-cache (list default-directory 'magit-git-dir path) - (magit--with-safe-default-directory nil - (when-let ((dir (magit-rev-parse-safe "--git-dir"))) - (setq dir (file-name-as-directory (magit-expand-git-file-name dir))) - (unless (file-remote-p dir) - (setq dir (concat (file-remote-p default-directory) dir))) - (if path (expand-file-name (convert-standard-filename path) dir) dir))))) - -(defvar magit--separated-gitdirs nil) - -(defun magit--record-separated-gitdir () - (let ((topdir (magit-toplevel)) - (gitdir (magit-git-dir))) - ;; Kludge: git-annex converts submodule gitdirs to symlinks. See #3599. - (when (file-symlink-p (directory-file-name gitdir)) - (setq gitdir (file-truename gitdir))) - ;; We want to delete the entry for `topdir' here, rather than within - ;; (unless ...), in case a `--separate-git-dir' repository was switched to - ;; the standard structure (i.e., "topdir/.git/"). - (setq magit--separated-gitdirs (cl-delete topdir - magit--separated-gitdirs - :key #'car :test #'equal)) - (unless (equal (file-name-as-directory (expand-file-name ".git" topdir)) - gitdir) - (push (cons topdir gitdir) magit--separated-gitdirs)))) - -(defun magit-toplevel (&optional directory) - "Return the absolute path to the toplevel of the current repository. - -From within the working tree or control directory of a repository -return the absolute path to the toplevel directory of the working -tree. As a special case, from within a bare repository return -the control directory instead. When called outside a repository -then return nil. - -When optional DIRECTORY is non-nil then return the toplevel for -that directory instead of the one for `default-directory'. - -Try to respect the option `find-file-visit-truename', i.e. when -the value of that option is nil, then avoid needlessly returning -the truename. When a symlink to a sub-directory of the working -tree is involved, or when called from within a sub-directory of -the gitdir or from the toplevel of a gitdir, which itself is not -located within the working tree, then it is not possible to avoid -returning the truename." - (magit--with-refresh-cache - (cons (or directory default-directory) 'magit-toplevel) - (magit--with-safe-default-directory directory - (if-let ((topdir (magit-rev-parse-safe "--show-toplevel"))) - (let (updir) - (setq topdir (magit-expand-git-file-name topdir)) - (if (and - ;; Always honor these settings. - (not find-file-visit-truename) - (not (getenv "GIT_WORK_TREE")) - ;; `--show-cdup' is the relative path to the toplevel - ;; from `(file-truename default-directory)'. Here we - ;; pretend it is relative to `default-directory', and - ;; go to that directory. Then we check whether - ;; `--show-toplevel' still returns the same value and - ;; whether `--show-cdup' now is the empty string. If - ;; both is the case, then we are at the toplevel of - ;; the same working tree, but also avoided needlessly - ;; following any symlinks. - (progn - (setq updir (file-name-as-directory - (magit-rev-parse-safe "--show-cdup"))) - (setq updir (if (file-name-absolute-p updir) - (concat (file-remote-p default-directory) updir) - (expand-file-name updir))) - (let ((default-directory updir)) - (and (string-equal (magit-rev-parse-safe "--show-cdup") "") - (--when-let (magit-rev-parse-safe "--show-toplevel") - (string-equal (magit-expand-git-file-name it) - topdir)))))) - updir - (concat (file-remote-p default-directory) - (file-name-as-directory topdir)))) - (when-let ((gitdir (magit-rev-parse-safe "--git-dir"))) - (setq gitdir (file-name-as-directory - (if (file-name-absolute-p gitdir) - ;; We might have followed a symlink. - (concat (file-remote-p default-directory) - (magit-expand-git-file-name gitdir)) - (expand-file-name gitdir)))) - (if (magit-bare-repo-p) - gitdir - (let* ((link (expand-file-name "gitdir" gitdir)) - (wtree (and (file-exists-p link) - (magit-file-line link)))) - (cond - ((and wtree - ;; Ignore .git/gitdir files that result from a - ;; Git bug. See #2364. - (not (equal wtree ".git"))) - ;; Return the linked working tree. - (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. - ((car (rassoc gitdir magit--separated-gitdirs))) - (t - ;; Step outside the control directory to enter the working tree. - (file-name-directory (directory-file-name gitdir))))))))))) - -(defmacro magit-with-toplevel (&rest body) - (declare (indent defun) (debug (body))) - (let ((toplevel (cl-gensym "toplevel"))) - `(let ((,toplevel (magit-toplevel))) - (if ,toplevel - (let ((default-directory ,toplevel)) - ,@body) - (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 () - (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. -If it is below the working directory, then return nil. -If it isn't below either, then signal an error unless NOERROR -is non-nil, in which case return nil." - (and (magit--assert-default-directory noerror) - ;; Below a repository directory that is not located below the - ;; working directory "git rev-parse --is-inside-git-dir" prints - ;; "false", which is wrong. - (let ((gitdir (magit-git-dir))) - (cond (gitdir (file-in-directory-p default-directory gitdir)) - (noerror nil) - (t (signal 'magit-outside-git-repo default-directory)))))) - -(defun magit-inside-worktree-p (&optional noerror) - "Return t if `default-directory' is below the working directory. -If it is below the repository directory, then return nil. -If it isn't below either, then signal an error unless NOERROR -is non-nil, in which case return nil." - (and (magit--assert-default-directory noerror) - (condition-case nil - (magit-rev-parse-true "--is-inside-work-tree") - (magit-invalid-git-boolean - (and (not noerror) - (signal 'magit-outside-git-repo default-directory)))))) - -(cl-defgeneric magit-bare-repo-p (&optional noerror) - "Return t if the current repository is bare. -If it is non-bare, then return nil. If `default-directory' -isn't below a Git repository, then signal an error unless -NOERROR is non-nil, in which case return nil." - (and (magit--assert-default-directory noerror) - (condition-case nil - (magit-rev-parse-true "--is-bare-repository") - (magit-invalid-git-boolean - (and (not noerror) - (signal 'magit-outside-git-repo default-directory)))))) - -(defun magit--assert-default-directory (&optional noerror) - (or (file-directory-p default-directory) - (and (not noerror) - (let ((exists (file-exists-p default-directory))) - (signal (if exists 'file-error 'file-missing) - (list "Running git in directory" - (if exists - "Not a directory" - "No such file or directory") - default-directory)))))) - -(defun magit-git-repo-p (directory &optional non-bare) - "Return t if DIRECTORY is a Git repository. -When optional NON-BARE is non-nil also return nil if DIRECTORY is -a bare repository." - (and (file-directory-p directory) ; Avoid archives, see #3397. - (or (file-regular-p (expand-file-name ".git" directory)) - (file-directory-p (expand-file-name ".git" directory)) - (and (not non-bare) - (file-regular-p (expand-file-name "HEAD" directory)) - (file-directory-p (expand-file-name "refs" directory)) - (file-directory-p (expand-file-name "objects" directory)))))) - -(defun magit-file-relative-name (&optional file tracked) - "Return the path of FILE relative to the repository root. - -If optional FILE is nil or omitted, return the relative path of -the file being visited in the current buffer, if any, else nil. -If the file is not inside a Git repository, then return nil. - -If TRACKED is non-nil, return the path only if it matches a -tracked file." - (unless file - (with-current-buffer (or (buffer-base-buffer) - (current-buffer)) - (setq file (or magit-buffer-file-name buffer-file-name - (and (derived-mode-p 'dired-mode) default-directory))))) - (when (and file (or (not tracked) - (magit-file-tracked-p (file-relative-name file)))) - (--when-let (magit-toplevel - (magit--safe-default-directory - (directory-file-name (file-name-directory file)))) - (file-relative-name file it)))) - -(defun magit-file-tracked-p (file) - (magit-git-success "ls-files" "--error-unmatch" file)) - -(defun magit-list-files (&rest args) - (apply #'magit-git-items "ls-files" "-z" "--full-name" args)) - -(defun magit-tracked-files () - (magit-list-files "--cached")) - -(defun magit-untracked-files (&optional all files) - (magit-list-files "--other" (unless all "--exclude-standard") "--" files)) - -(defun magit-unstaged-files (&optional nomodules files) - (magit-git-items "diff-files" "-z" "--name-only" - (and nomodules "--ignore-submodules") - "--" files)) - -(defun magit-staged-files (&optional nomodules files) - (magit-git-items "diff-index" "-z" "--name-only" "--cached" - (and nomodules "--ignore-submodules") - (magit-headish) "--" files)) - -(defun magit-binary-files (&rest args) - (--mapcat (and (string-match "^-\t-\t\\(.+\\)" it) - (list (match-string 1 it))) - (apply #'magit-git-items - "diff" "-z" "--numstat" "--ignore-submodules" - args))) - -(defun magit-unmerged-files () - (magit-git-items "diff-files" "-z" "--name-only" "--diff-filter=U")) - -(defun magit-ignored-files () - (magit-git-items "ls-files" "-z" "--others" "--ignored" - "--exclude-standard" "--directory")) - -(defun magit-skip-worktree-files () - (--keep (and (and (= (aref it 0) ?S) - (substring it 2))) - (magit-list-files "-t"))) - -(defun magit-assume-unchanged-files () - (--keep (and (and (memq (aref it 0) '(?h ?s ?m ?r ?c ?k)) - (substring it 2))) - (magit-list-files "-v"))) - -(defun magit-revision-files (rev) - (magit-with-toplevel - (magit-git-items "ls-tree" "-z" "-r" "--name-only" rev))) - -(defun magit-changed-files (rev-or-range &optional other-rev) - "Return list of files the have changed between two revisions. -If OTHER-REV is non-nil, REV-OR-RANGE should be a revision, not a -range. Otherwise, it can be any revision or range accepted by -\"git diff\" (i.e., , .., or ...)." - (magit-with-toplevel - (magit-git-items "diff" "-z" "--name-only" rev-or-range other-rev))) - -(defun magit-renamed-files (revA revB) - (--map (cons (nth 1 it) (nth 2 it)) - (-partition 3 (magit-git-items - "diff-tree" "-r" "--diff-filter=R" "-z" "-M" - revA revB)))) - -(defun magit-file-status (&rest args) - (magit--with-temp-process-buffer - (save-excursion (magit-git-insert "status" "-z" args)) - (let ((pos (point)) status) - (while (> (skip-chars-forward "[:print:]") 0) - (let ((x (char-after pos)) - (y (char-after (1+ pos))) - (file (buffer-substring (+ pos 3) (point)))) - (forward-char) - (if (memq x '(?R ?C)) - (progn - (setq pos (point)) - (skip-chars-forward "[:print:]") - (push (list file (buffer-substring pos (point)) x y) status) - (forward-char)) - (push (list file nil x y) status))) - (setq pos (point))) - status))) - -(defcustom magit-cygwin-mount-points - (when (eq system-type 'windows-nt) - (cl-sort (--map (if (string-match "^\\(.*\\) on \\(.*\\) type" it) - (cons (file-name-as-directory (match-string 2 it)) - (file-name-as-directory (match-string 1 it))) - (lwarn '(magit) :error - "Failed to parse Cygwin mount: %S" it)) - ;; If --exec-path is not a native Windows path, - ;; then we probably have a cygwin git. - (let ((process-environment - (append magit-git-environment process-environment))) - (and (not (string-match-p - "\\`[a-zA-Z]:" - (car (process-lines - magit-git-executable "--exec-path")))) - (ignore-errors (process-lines "mount"))))) - #'> :key (pcase-lambda (`(,cyg . ,_win)) (length cyg)))) - "Alist of (CYGWIN . WIN32) directory names. -Sorted from longest to shortest CYGWIN name." - :package-version '(magit . "2.3.0") - :group 'magit-process - :type '(alist :key-type string :value-type directory)) - -(defun magit-expand-git-file-name (filename) - (unless (file-name-absolute-p filename) - (setq filename (expand-file-name filename))) - (-if-let ((cyg . win) - (cl-assoc filename magit-cygwin-mount-points - :test (lambda (f cyg) (string-prefix-p cyg f)))) - (concat win (substring filename (length cyg))) - filename)) - -(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." - (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)) - filename)) - -(defun magit-decode-git-path (path) - (if (eq (aref path 0) ?\") - (decode-coding-string (read path) - (or magit-git-output-coding-system - (car default-process-coding-system)) - t) - path)) - -(defun magit-file-at-point (&optional expand assert) - (if-let ((file (magit-section-case - (file (oref it value)) - (hunk (magit-section-parent-value it))))) - (if expand - (expand-file-name file (magit-toplevel)) - file) - (when assert - (user-error "No file at point")))) - -(defun magit-current-file () - (or (magit-file-relative-name) - (magit-file-at-point) - (and (derived-mode-p 'magit-log-mode) - (car magit-buffer-log-files)))) - -;;; Predicates - -(defun magit-no-commit-p () - "Return t if there is no commit in the current Git repository." - (not (magit-rev-verify "HEAD"))) - -(defun magit-merge-commit-p (commit) - "Return t if COMMIT is a merge commit." - (> (length (magit-commit-parents commit)) 1)) - -(defun magit-anything-staged-p (&optional ignore-submodules &rest files) - "Return t if there are any staged changes. -If optional FILES is non-nil, then only changes to those files -are considered." - (magit-git-failure "diff" "--quiet" "--cached" - (and ignore-submodules "--ignore-submodules") - "--" files)) - -(defun magit-anything-unstaged-p (&optional ignore-submodules &rest files) - "Return t if there are any unstaged changes. -If optional FILES is non-nil, then only changes to those files -are considered." - (magit-git-failure "diff" "--quiet" - (and ignore-submodules "--ignore-submodules") - "--" files)) - -(defun magit-anything-modified-p (&optional ignore-submodules &rest files) - "Return t if there are any staged or unstaged changes. -If optional FILES is non-nil, then only changes to those files -are considered." - (or (apply 'magit-anything-staged-p ignore-submodules files) - (apply 'magit-anything-unstaged-p ignore-submodules files))) - -(defun magit-anything-unmerged-p (&rest files) - "Return t if there are any merge conflicts. -If optional FILES is non-nil, then only conflicts in those files -are considered." - (and (magit-git-string "ls-files" "--unmerged" files) t)) - -(defun magit-module-worktree-p (module) - (magit-with-toplevel - (file-exists-p (expand-file-name (expand-file-name ".git" module))))) - -(defun magit-module-no-worktree-p (module) - (not (magit-module-worktree-p module))) - -(defun magit-ignore-submodules-p (&optional return-argument) - (or (cl-find-if (lambda (arg) - (string-prefix-p "--ignore-submodules" arg)) - magit-buffer-diff-args) - (when-let ((value (magit-get "diff.ignoreSubmodules"))) - (if return-argument - (concat "--ignore-submodules=" value) - (concat "diff.ignoreSubmodules=" value))))) - -;;; Revisions and References - -(defun magit-rev-parse (&rest args) - "Execute `git rev-parse ARGS', returning first line of output. -If there is no output, return nil." - (apply #'magit-git-string "rev-parse" args)) - -(defun magit-rev-parse-safe (&rest args) - "Execute `git rev-parse ARGS', returning first line of output. -If there is no output, return nil. Like `magit-rev-parse' but -ignore `magit-git-debug'." - (apply #'magit-git-str "rev-parse" args)) - -(defun magit-rev-parse-true (&rest args) - "Execute `git rev-parse ARGS', returning t if it prints \"true\". -If it prints \"false\", then return nil. For any other output -signal an error." - (magit-git-true "rev-parse" args)) - -(defun magit-rev-parse-false (&rest args) - "Execute `git rev-parse ARGS', returning t if it prints \"false\". -If it prints \"true\", then return nil. For any other output -signal an error." - (magit-git-false "rev-parse" args)) - -(defun magit-rev-parse-p (&rest args) - "Execute `git rev-parse ARGS', returning t if it prints \"true\". -Return t if the first (and usually only) output line is the -string \"true\", otherwise return nil." - (equal (magit-git-str "rev-parse" args) "true")) - -(defun magit-rev-verify (rev) - (magit-git-string-p "rev-parse" "--verify" rev)) - -(defun magit-commit-p (rev) - "Return full hash for REV if it names an existing commit." - (magit-rev-verify (concat rev "^{commit}"))) - -(defalias 'magit-rev-verify-commit 'magit-commit-p) - -(defalias 'magit-rev-hash 'magit-commit-p) - -(defun magit-rev-equal (a b) - "Return t if there are no differences between the commits A and B." - (magit-git-success "diff" "--quiet" a b)) - -(defun magit-rev-eq (a b) - "Return t if A and B refer to the same commit." - (let ((a (magit-commit-p a)) - (b (magit-commit-p b))) - (and a b (equal a b)))) - -(defun magit-rev-ancestor-p (a b) - "Return non-nil if commit A is an ancestor of commit B." - (magit-git-success "merge-base" "--is-ancestor" a b)) - -(defun magit-rev-head-p (rev) - (or (equal rev "HEAD") - (and rev - (not (string-match-p "\\.\\." rev)) - (equal (magit-rev-parse rev) - (magit-rev-parse "HEAD"))))) - -(defun magit-rev-author-p (rev) - "Return t if the user is the author of REV. -More precisely return t if `user.name' is equal to the author -name of REV and/or `user.email' is equal to the author email -of REV." - (or (equal (magit-get "user.name") (magit-rev-format "%an" rev)) - (equal (magit-get "user.email") (magit-rev-format "%ae" rev)))) - -(defun magit-rev-name (rev &optional pattern not-anchored) - "Return a symbolic name for REV using `git-name-rev'. - -PATTERN can be used to limit the result to a matching ref. -Unless NOT-ANCHORED is non-nil, the beginning of the ref must -match PATTERN. - -An anchored lookup is done using the arguments -\"--exclude=*/ --exclude=*/HEAD\" in addition to -\"--refs=\", provided at least version v2.13 of Git is -used. Older versions did not support the \"--exclude\" argument. -When \"--exclude\" cannot be used and `git-name-rev' returns a -ref that should have been excluded, then that is discarded and -this function returns nil instead. This is unfortunate because -there might be other refs that do match. To fix that, update -Git." - (if (version< (magit-git-version) "2.13") - (when-let - ((ref (magit-git-string "name-rev" "--name-only" "--no-undefined" - (and pattern (concat "--refs=" pattern)) - rev))) - (if (and pattern - (string-match-p "\\`refs/[^/]+/\\*\\'" pattern)) - (let ((namespace (substring pattern 0 -1))) - (and (not (or (string-suffix-p "HEAD" ref) - (and (string-match-p namespace ref) - (not (magit-rev-verify - (concat namespace ref)))))) - ref)) - ref)) - (magit-git-string "name-rev" "--name-only" "--no-undefined" - (and pattern (concat "--refs=" pattern)) - (and pattern - (not not-anchored) - (list "--exclude=*/HEAD" - (concat "--exclude=*/" pattern))) - rev))) - -(defun magit-rev-branch (rev) - (--when-let (magit-rev-name rev "refs/heads/*") - (unless (string-match-p "[~^]" it) it))) - -(defun magit-get-shortname (rev) - (let* ((fn (apply-partially 'magit-rev-name rev)) - (name (or (funcall fn "refs/tags/*") - (funcall fn "refs/heads/*") - (funcall fn "refs/remotes/*")))) - (cond ((not name) - (magit-rev-parse "--short" rev)) - ((string-match "^\\(?:tags\\|remotes\\)/\\(.+\\)" name) - (if (magit-ref-ambiguous-p (match-string 1 name)) - name - (match-string 1 name))) - (t (magit-ref-maybe-qualify name))))) - -(defun magit-name-branch (rev &optional lax) - (or (magit-name-local-branch rev) - (magit-name-remote-branch rev) - (and lax (or (magit-name-local-branch rev t) - (magit-name-remote-branch rev t))))) - -(defun magit-name-local-branch (rev &optional lax) - (--when-let (magit-rev-name rev "refs/heads/*") - (and (or lax (not (string-match-p "[~^]" it))) it))) - -(defun magit-name-remote-branch (rev &optional lax) - (--when-let (magit-rev-name rev "refs/remotes/*") - (and (or lax (not (string-match-p "[~^]" it))) - (substring it 8)))) - -(defun magit-name-tag (rev &optional lax) - (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." - (magit-rev-parse "--verify" "--abbrev-ref" refname)) - -(defun magit-ref-fullname (refname) - "Return fully qualified refname for REFNAME. -If REFNAME is ambiguous, return nil." - (magit-rev-parse "--verify" "--symbolic-full-name" refname)) - -(defun magit-ref-ambiguous-p (refname) - (save-match-data - (if (string-match "\\`\\([^^~]+\\)\\(.*\\)" refname) - (not (magit-ref-fullname (match-string 1 refname))) - (error "%S has an unrecognized format" refname)))) - -(defun magit-ref-maybe-qualify (refname &optional prefix) - "If REFNAME is ambiguous, try to disambiguate it by prepend PREFIX to it. -Return an unambiguous refname, either REFNAME or that prefixed -with PREFIX, nil otherwise. If REFNAME has an offset suffix -such as \"~1\", then that is preserved. If optional PREFIX is -nil, then use \"heads/\". " - (if (magit-ref-ambiguous-p refname) - (let ((refname (concat (or prefix "heads/") refname))) - (and (not (magit-ref-ambiguous-p refname)) refname)) - refname)) - -(defun magit-ref-exists-p (ref) - (magit-git-success "show-ref" "--verify" ref)) - -(defun magit-ref-equal (a b) - "Return t if the refnames A and B are `equal'. -A symbolic-ref pointing to some ref, is `equal' to that ref, -as are two symbolic-refs pointing to the same ref. Refnames -may be abbreviated." - (let ((a (magit-ref-fullname a)) - (b (magit-ref-fullname b))) - (and a b (equal a b)))) - -(defun magit-ref-eq (a b) - "Return t if the refnames A and B are `eq'. -A symbolic-ref is `eq' to itself, but not to the ref it points -to, or to some other symbolic-ref that points to the same ref." - (let ((symbolic-a (magit-symbolic-ref-p a)) - (symbolic-b (magit-symbolic-ref-p b))) - (or (and symbolic-a - symbolic-b - (equal a b)) - (and (not symbolic-a) - (not symbolic-b) - (magit-ref-equal a b))))) - -(defun magit-headish () - "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")) - -(defun magit-branch-at-point () - (magit-section-case - (branch (oref it value)) - (commit (or (magit--painted-branch-at-point) - (magit-name-branch (oref it value)))))) - -(defun magit--painted-branch-at-point (&optional type) - (or (and (not (eq type 'remote)) - (memq (get-text-property (point) 'font-lock-face) - (list 'magit-branch-local - 'magit-branch-current)) - (when-let ((branch (thing-at-point 'git-revision t))) - (cdr (magit-split-branch-name branch)))) - (and (not (eq type 'local)) - (memq (get-text-property (point) 'font-lock-face) - (list 'magit-branch-remote - 'magit-branch-remote-head)) - (thing-at-point 'git-revision t)))) - -(defun magit-local-branch-at-point () - (magit-section-case - (branch (let ((branch (magit-ref-maybe-qualify (oref it value)))) - (when (member branch (magit-list-local-branch-names)) - branch))) - (commit (or (magit--painted-branch-at-point 'local) - (magit-name-local-branch (oref it value)))))) - -(defun magit-remote-branch-at-point () - (magit-section-case - (branch (let ((branch (oref it value))) - (when (member branch (magit-list-remote-branch-names)) - branch))) - (commit (or (magit--painted-branch-at-point 'remote) - (magit-name-remote-branch (oref it value)))))) - -(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 (magit-section-case - (branch (magit-ref-maybe-qualify (oref it value))) - (commit (or (magit--painted-branch-at-point) - (let ((rev (oref it value))) - (or (magit-name-branch rev) rev)))) - (tag (magit-ref-maybe-qualify (oref it value) "tags/")) - (pullreq (or (and (fboundp 'forge--pullreq-branch) - (magit-branch-p - (forge--pullreq-branch (oref it value)))) - (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) - magit-buffer-revision))) - -(defun magit-tag-at-point () - (magit-section-case - (tag (oref it value)) - (commit (magit-name-tag (oref it value))))) - -(defun magit-stash-at-point () - (magit-section-value-if 'stash)) - -(defun magit-remote-at-point () - (magit-section-case - (remote (oref it value)) - (branch (magit-section-parent-value it)))) - -(defun magit-module-at-point (&optional predicate) - (when (magit-section-match 'magit-module-section) - (let ((module (oref (magit-current-section) value))) - (and (or (not predicate) - (funcall predicate module)) - module)))) - -(defun magit-get-current-branch () - "Return the refname of the currently checked out branch. -Return nil if no branch is currently checked out." - (magit-git-string "symbolic-ref" "--short" "HEAD")) - -(defvar magit-get-previous-branch-timeout 0.5 - "Maximum time to spend in `magit-get-previous-branch'. -Given as a number of seconds.") - -(defun magit-get-previous-branch () - "Return the refname of the previously checked out branch. -Return nil if no branch can be found in the `HEAD' reflog -which is different from the current branch and still exists. -The amount of time spent searching is limited by -`magit-get-previous-branch-timeout'." - (let ((t0 (float-time)) - (current (magit-get-current-branch)) - (i 1) prev) - (while (if (> (- (float-time) t0) magit-get-previous-branch-timeout) - (setq prev nil) ;; Timed out. - (and (setq prev (magit-rev-verify (format "@{-%i}" i))) - (or (not (setq prev (magit-rev-branch prev))) - (equal prev current)))) - (cl-incf i)) - prev)) - -(defun magit-set-upstream-branch (branch upstream) - "Set UPSTREAM as the upstream of BRANCH. -If UPSTREAM is nil, then unset BRANCH's upstream. -Otherwise UPSTREAM has to be an existing branch." - (if upstream - (magit-call-git "branch" "--set-upstream-to" upstream branch) - (magit-call-git "branch" "--unset-upstream" branch))) - -(defun magit-get-upstream-ref (&optional branch) - "Return the upstream branch of BRANCH as a fully qualified ref. -It BRANCH is nil, then return the upstream of the current branch, -if any, nil otherwise. If the upstream is not configured, the -configured remote is an url, or the named branch does not exist, -then return nil. I.e. return an existing local or -remote-tracking branch ref." - (when-let ((branch (or branch (magit-get-current-branch)))) - (magit-ref-fullname (concat branch "@{upstream}")))) - -(defun magit-get-upstream-branch (&optional branch) - "Return the name of the upstream branch of BRANCH. -It BRANCH is nil, then return the upstream of the current branch -if any, nil otherwise. If the upstream is not configured, the -configured remote is an url, or the named branch does not exist, -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." - (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"))) - (and remote (not (equal remote ".")) - ;; The user has opted in... - (or force - (--some (if (magit-git-success "check-ref-format" "--branch" it) - (equal it branch) - (string-match-p it branch)) - magit-branch-prefer-remote-upstream)) - ;; and local BRANCH tracks a remote branch... - (let ((upstream (magit-get-upstream-branch branch))) - ;; whose upstream... - (and upstream - ;; has the same name as BRANCH... - (equal (substring upstream (1+ (length remote))) branch) - ;; and can be fast-forwarded to BRANCH. - (magit-rev-ancestor-p upstream branch) - upstream))))) - -(defun magit-get-upstream-remote (&optional branch allow-unnamed) - (when-let ((branch (or branch (magit-get-current-branch))) - (remote (magit-get "branch" branch "remote"))) - (and (not (equal remote ".")) - (cond ((member remote (magit-list-remotes)) - (magit--propertize-face remote 'magit-branch-remote)) - ((and allow-unnamed - (string-match-p "\\(\\`.\\{0,2\\}/\\|[:@]\\)" remote)) - (magit--propertize-face remote 'bold)))))) - -(defun magit-get-unnamed-upstream (&optional branch) - (when-let ((branch (or branch (magit-get-current-branch))) - (remote (magit-get "branch" branch "remote")) - (merge (magit-get "branch" branch "merge"))) - (and (magit--unnamed-upstream-p remote merge) - (list (magit--propertize-face remote 'bold) - (magit--propertize-face merge 'magit-branch-remote))))) - -(defun magit--unnamed-upstream-p (remote merge) - (and remote (string-match-p "\\(\\`\\.\\{0,2\\}/\\|[:@]\\)" remote) - merge (string-prefix-p "refs/" merge))) - -(defun magit--valid-upstream-p (remote merge) - (and (or (equal remote ".") - (member remote (magit-list-remotes))) - (string-prefix-p "refs/" merge))) - -(defun magit-get-current-remote (&optional allow-unnamed) - (or (magit-get-upstream-remote nil allow-unnamed) - (when-let ((remotes (magit-list-remotes)) - (remote (if (= (length remotes) 1) - (car remotes) - (magit-primary-remote)))) - (magit--propertize-face remote 'magit-branch-remote)))) - -(defun magit-get-push-remote (&optional branch) - (when-let ((remote - (or (and (or branch (setq branch (magit-get-current-branch))) - (magit-get "branch" branch "pushRemote")) - (magit-get "remote.pushDefault")))) - (magit--propertize-face remote 'magit-branch-remote))) - -(defun magit-get-push-branch (&optional branch verify) - (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" - (concat branch "@{push}")))) - (when (and ref (string-prefix-p "refs/remotes/" ref)) - (substring ref 13)))) - -(defun magit-get-remote (&optional branch) - (when (or branch (setq branch (magit-get-current-branch))) - (let ((remote (magit-get "branch" branch "remote"))) - (unless (equal remote ".") - remote)))) - -(defun magit-get-some-remote (&optional branch) - (or (magit-get-remote branch) - (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. - -TARGET defaults to the current branch. If `HEAD' is detached and -TARGET is nil, then always return nil. As a special case, if -TARGET is t, then return non-nil if BRANCH is merged into any one -of the other local branches. - -If, and only if, BRANCH has an upstream, then only return non-nil -if BRANCH is merged into both TARGET (as described above) as well -as into its upstream." - (and (--if-let (and (magit-branch-p branch) - (magit-get-upstream-branch branch)) - (magit-git-success "merge-base" "--is-ancestor" branch it) - t) - (if (eq target t) - (delete (magit-name-local-branch branch) - (magit-list-containing-branches branch)) - (--when-let (or target (magit-get-current-branch)) - (magit-git-success "merge-base" "--is-ancestor" branch it))))) - -(defun magit-get-tracked (refname) - "Return the remote branch tracked by the remote-tracking branch REFNAME. -The returned value has the form (REMOTE . REF), where REMOTE is -the name of a remote and REF is the ref local to the remote." - (when-let ((ref (magit-ref-fullname refname))) - (save-match-data - (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"))))) - -(defun magit-split-branch-name (branch) - (cond ((member branch (magit-list-local-branch-names)) - (cons "." branch)) - ((string-match "/" branch) - (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) - "Return the closest tag reachable from REV. - -If optional REV is nil, then default to `HEAD'. -If optional WITH-DISTANCE is non-nil then return (TAG COMMITS), -if it is `dirty' return (TAG COMMIT DIRTY). COMMITS is the number -of commits in `HEAD' but not in TAG and DIRTY is t if there are -uncommitted changes, nil otherwise." - (--when-let (magit-git-str "describe" "--long" "--tags" - (and (eq with-distance 'dirty) "--dirty") rev) - (save-match-data - (string-match - "\\(.+\\)-\\(?:0[0-9]*\\|\\([0-9]+\\)\\)-g[0-9a-z]+\\(-dirty\\)?$" it) - (if with-distance - `(,(match-string 1 it) - ,(string-to-number (or (match-string 2 it) "0")) - ,@(and (match-string 3 it) (list t))) - (match-string 1 it))))) - -(defun magit-get-next-tag (&optional rev with-distance) - "Return the closest tag from which REV is reachable. - -If optional REV is nil, then default to `HEAD'. -If no such tag can be found or if the distance is 0 (in which -case it is the current tag, not the next), return nil instead. -If optional WITH-DISTANCE is non-nil, then return (TAG COMMITS) -where COMMITS is the number of commits in TAG but not in REV." - (--when-let (magit-git-str "describe" "--contains" (or rev "HEAD")) - (save-match-data - (when (string-match "^[^^~]+" it) - (setq it (match-string 0 it)) - (unless (equal it (magit-get-current-tag rev)) - (if with-distance - (list it (car (magit-rev-diff-count it rev))) - it)))))) - -(defun magit-list-refs (&optional namespaces format sortby) - "Return list of references. - -When NAMESPACES is non-nil, list refs from these namespaces -rather than those from `magit-list-refs-namespaces'. - -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'. - -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'" - (unless format - (setq format "%(refname)")) - (let ((refs (magit-git-lines "for-each-ref" - (concat "--format=" format) - (--map (concat "--sort=" it) - (pcase (or sortby magit-list-refs-sortby) - ((and val (pred stringp)) (list val)) - ((and val (pred listp)) val))) - (or namespaces magit-list-refs-namespaces)))) - (if (member format '("%(refname)" "%(refname:short)")) - (--remove (string-match-p "\\(\\`\\|/\\)HEAD\\'" it) refs) - refs))) - -(defun magit-list-branches () - (magit-list-refs (list "refs/heads" "refs/remotes"))) - -(defun magit-list-local-branches () - (magit-list-refs "refs/heads")) - -(defun magit-list-remote-branches (&optional remote) - (magit-list-refs (concat "refs/remotes/" remote))) - -(defun magit-list-related-branches (relation &optional commit &rest args) - (--remove (string-match-p "\\(\\`(HEAD\\|HEAD -> \\)" it) - (--map (substring it 2) - (magit-git-lines "branch" args relation commit)))) - -(defun magit-list-containing-branches (&optional commit &rest args) - (magit-list-related-branches "--contains" commit args)) - -(defun magit-list-publishing-branches (&optional commit) - (--filter (magit-rev-ancestor-p (or commit "HEAD") it) - magit-published-branches)) - -(defun magit-list-merged-branches (&optional commit &rest args) - (magit-list-related-branches "--merged" commit args)) - -(defun magit-list-unmerged-branches (&optional commit &rest args) - (magit-list-related-branches "--no-merged" commit args)) - -(defun magit-list-unmerged-to-upstream-branches () - (--filter (when-let ((upstream (magit-get-upstream-branch it))) - (member it (magit-list-unmerged-branches upstream))) - (magit-list-local-branch-names))) - -(defun magit-list-branches-pointing-at (commit) - (let ((re (format "\\`%s refs/\\(heads\\|remotes\\)/\\(.*\\)\\'" - (magit-rev-verify commit)))) - (--keep (and (string-match re it) - (let ((name (match-string 2 it))) - (and (not (string-suffix-p "HEAD" name)) - name))) - (magit-git-lines "show-ref")))) - -(defun magit-list-refnames (&optional namespaces include-special) - (nconc (magit-list-refs namespaces "%(refname:short)") - (and include-special - (magit-list-special-refnames)))) - -(defvar magit-special-refnames - '("HEAD" "ORIG_HEAD" "FETCH_HEAD" "MERGE_HEAD" "CHERRY_PICK_HEAD")) - -(defun magit-list-special-refnames () - (let ((gitdir (magit-gitdir))) - (cl-mapcan (lambda (name) - (and (file-exists-p (expand-file-name name gitdir)) - (list name))) - magit-special-refnames))) - -(defun magit-list-branch-names () - (magit-list-refnames (list "refs/heads" "refs/remotes"))) - -(defun magit-list-local-branch-names () - (magit-list-refnames "refs/heads")) - -(defun magit-list-remote-branch-names (&optional remote relative) - (if (and remote relative) - (let ((regexp (format "^refs/remotes/%s/\\(.+\\)" remote))) - (--mapcat (when (string-match regexp it) - (list (match-string 1 it))) - (magit-list-remote-branches remote))) - (magit-list-refnames (concat "refs/remotes/" remote)))) - -(defun magit-format-refs (format &rest args) - (let ((lines (magit-git-lines - "for-each-ref" (concat "--format=" format) - (or args (list "refs/heads" "refs/remotes" "refs/tags"))))) - (if (string-match-p "\f" format) - (--map (split-string it "\f") lines) - lines))) - -(defun magit-list-remotes () - (magit-git-lines "remote")) - -(defun magit-list-tags () - (magit-git-lines "tag")) - -(defun magit-list-stashes (&optional format) - (magit-git-lines "stash" "list" (concat "--format=" (or format "%gd")))) - -(defun magit-list-active-notes-refs () - "Return notes refs according to `core.notesRef' and `notes.displayRef'." - (magit-git-lines "for-each-ref" "--format=%(refname)" - (or (magit-get "core.notesRef") "refs/notes/commits") - (magit-get-all "notes.displayRef"))) - -(defun magit-list-notes-refnames () - (--map (substring it 6) (magit-list-refnames "refs/notes"))) - -(defun magit-remote-list-tags (remote) - (--keep (and (not (string-match-p "\\^{}$" it)) - (substring it 51)) - (magit-git-lines "ls-remote" "--tags" remote))) - -(defun magit-remote-list-branches (remote) - (--keep (and (not (string-match-p "\\^{}$" it)) - (substring it 52)) - (magit-git-lines "ls-remote" "--heads" remote))) - -(defun magit-remote-list-refs (remote) - (--keep (and (not (string-match-p "\\^{}$" it)) - (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." - (magit-git-string "submodule--helper" "name" path)) - -(defun magit-list-worktrees () - (let (worktrees worktree) - (dolist (line (let ((magit-git-global-arguments - ;; KLUDGE At least in v2.8.3 this triggers a segfault. - (remove "--no-pager" magit-git-global-arguments))) - (magit-git-lines "worktree" "list" "--porcelain"))) - (cond ((string-prefix-p "worktree" line) - (push (setq worktree (list (substring line 9) nil nil nil)) - worktrees)) - ((string-equal line "bare") - (let* ((default-directory (car worktree)) - (wt (and (not (magit-get-boolean "core.bare")) - (magit-get "core.worktree")))) - (if (and wt (file-exists-p (expand-file-name wt))) - (progn (setf (nth 0 worktree) (expand-file-name wt)) - (setf (nth 2 worktree) (magit-rev-parse "HEAD")) - (setf (nth 3 worktree) (magit-get-current-branch))) - (setf (nth 1 worktree) t)))) - ((string-prefix-p "HEAD" line) - (setf (nth 2 worktree) (substring line 5))) - ((string-prefix-p "branch" line) - (setf (nth 3 worktree) (substring line 18))) - ((string-equal line "detached")))) - (nreverse worktrees))) - -(defun magit-symbolic-ref-p (name) - (magit-git-success "symbolic-ref" "--quiet" name)) - -(defun magit-ref-p (rev) - (or (car (member rev (magit-list-refs "refs/"))) - (car (member rev (magit-list-refnames "refs/"))))) - -(defun magit-branch-p (rev) - (or (car (member rev (magit-list-branches))) - (car (member rev (magit-list-branch-names))))) - -(defun magit-local-branch-p (rev) - (or (car (member rev (magit-list-local-branches))) - (car (member rev (magit-list-local-branch-names))))) - -(defun magit-remote-branch-p (rev) - (or (car (member rev (magit-list-remote-branches))) - (car (member rev (magit-list-remote-branch-names))))) - -(defun magit-branch-set-face (branch) - (magit--propertize-face branch (if (magit-local-branch-p branch) - 'magit-branch-local - 'magit-branch-remote))) - -(defun magit-tag-p (rev) - (car (member rev (magit-list-tags)))) - -(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)." - (mapcar 'string-to-number - (split-string (magit-git-string "rev-list" - "--count" "--left-right" - (concat a "..." b)) - "\t"))) - -(defun magit-abbrev-length () - (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))) - -(defun magit-rev-abbrev (rev) - (magit-rev-parse (magit-abbrev-arg "short") rev)) - -(defun magit-commit-children (commit &optional args) - (mapcar #'car - (--filter (member commit (cdr it)) - (--map (split-string it " ") - (magit-git-lines - "log" "--format=%H %P" - (or args (list "--branches" "--tags" "--remotes")) - "--not" commit))))) - -(defun magit-commit-parents (commit) - (--when-let (magit-git-string "rev-list" "-1" "--parents" commit) - (cdr (split-string it)))) - -(defun magit-patch-id (rev) - (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)))) - (format "%s diff-tree -u %s | %s patch-id" exec rev exec))) - (car (split-string (buffer-string))))) - -(defun magit-rev-format (format &optional rev args) - (let ((str (magit-git-string "show" "--no-patch" - (concat "--format=" format) args - (if rev (concat rev "^{commit}") "HEAD") "--"))) - (unless (string-equal str "") - str))) - -(defun magit-rev-insert-format (format &optional rev args) - (magit-git-insert "show" "--no-patch" - (concat "--format=" format) args - (if rev (concat rev "^{commit}") "HEAD") "--")) - -(defun magit-format-rev-summary (rev) - (--when-let (magit-rev-format "%h %s" rev) - (string-match " " it) - (magit--put-face 0 (match-beginning 0) 'magit-hash it) - it)) - -(defvar magit-ref-namespaces - '(("\\`HEAD\\'" . magit-head) - ("\\`refs/tags/\\(.+\\)" . magit-tag) - ("\\`refs/heads/\\(.+\\)" . magit-branch-local) - ("\\`refs/remotes/\\(.+\\)" . magit-branch-remote) - ("\\`refs/bisect/\\(bad\\)" . magit-bisect-bad) - ("\\`refs/bisect/\\(skip.*\\)" . magit-bisect-skip) - ("\\`refs/bisect/\\(good.*\\)" . magit-bisect-good) - ("\\`refs/stash$" . magit-refname-stash) - ("\\`refs/wip/\\(.+\\)" . magit-refname-wip) - ("\\`refs/pullreqs/\\(.+\\)" . magit-refname-pullreq) - ("\\`\\(bad\\):" . magit-bisect-bad) - ("\\`\\(skip\\):" . magit-bisect-skip) - ("\\`\\(good\\):" . magit-bisect-good) - ("\\`\\(.+\\)" . magit-refname)) - "How refs are formatted for display. - -Each entry controls how a certain type of ref is displayed, and -has the form (REGEXP . FACE). REGEXP is a regular expression -used to match full refs. The first entry whose REGEXP matches -the reference is used. - -In log and revision buffers the first regexp submatch becomes the -\"label\" that represents the ref and is propertized with FONT. -In refs buffers the displayed text is controlled by other means -and this option only controls what face is used.") - -(defun magit-format-ref-labels (string) - (save-match-data - (let ((regexp "\\(, \\|tag: \\|HEAD -> \\)") - names) - (if (and (derived-mode-p 'magit-log-mode) - (member "--simplify-by-decoration" magit-buffer-log-args)) - (let ((branches (magit-list-local-branch-names)) - (re (format "^%s/.+" (regexp-opt (magit-list-remotes))))) - (setq names - (--map (cond ((string-equal it "HEAD") it) - ((string-prefix-p "refs/" it) it) - ((member it branches) (concat "refs/heads/" it)) - ((string-match re it) (concat "refs/remotes/" it)) - (t (concat "refs/" it))) - (split-string - (replace-regexp-in-string "tag: " "refs/tags/" string) - regexp t)))) - (setq names (split-string string regexp t))) - (let (state head upstream tags branches remotes other combined) - (dolist (ref names) - (let* ((face (cdr (--first (string-match (car it) ref) - magit-ref-namespaces))) - (name (magit--propertize-face - (or (match-string 1 ref) ref) face))) - (cl-case face - ((magit-bisect-bad magit-bisect-skip magit-bisect-good) - (setq state name)) - (magit-head - (setq head (magit--propertize-face "@" 'magit-head))) - (magit-tag (push name tags)) - (magit-branch-local (push name branches)) - (magit-branch-remote (push name remotes)) - (t (push name other))))) - (setq remotes - (-keep - (lambda (name) - (if (string-match "\\`\\([^/]*\\)/\\(.*\\)\\'" name) - (let ((r (match-string 1 name)) - (b (match-string 2 name))) - (and (not (equal b "HEAD")) - (if (equal (concat "refs/remotes/" name) - (magit-git-string - "symbolic-ref" - (format "refs/remotes/%s/HEAD" r))) - (magit--propertize-face - name 'magit-branch-remote-head) - name))) - name)) - remotes)) - (let* ((current (magit-get-current-branch)) - (target (magit-get-upstream-branch current))) - (dolist (name branches) - (let ((push (car (member (magit-get-push-branch name) remotes)))) - (when push - (setq remotes (delete push remotes)) - (string-match "^[^/]*/" push) - (setq push (substring push 0 (match-end 0)))) - (cond - ((equal name current) - (setq head - (concat push - (magit--propertize-face - name 'magit-branch-current)))) - ((equal name target) - (setq upstream - (concat push - (magit--propertize-face - name '(magit-branch-upstream - magit-branch-local))))) - (t - (push (concat push name) combined))))) - (when (and target (not upstream)) - (if (member target remotes) - (progn - (magit--add-face-text-property - 0 (length target) 'magit-branch-upstream nil target) - (setq upstream target) - (setq remotes (delete target remotes))) - (when-let ((target (car (member target combined)))) - (magit--add-face-text-property - 0 (length target) 'magit-branch-upstream nil target) - (setq upstream target) - (setq combined (delete target combined)))))) - (mapconcat #'identity - (-flatten `(,state - ,head - ,upstream - ,@(nreverse tags) - ,@(nreverse combined) - ,@(nreverse remotes) - ,@other)) - " "))))) - -(defun magit-object-type (object) - (magit-git-string "cat-file" "-t" object)) - -(defmacro magit-with-blob (commit file &rest body) - (declare (indent 2) - (debug (form form body))) - `(magit--with-temp-process-buffer - (let ((buffer-file-name ,file)) - (save-excursion - (magit-git-insert "cat-file" "-p" - (concat ,commit ":" buffer-file-name))) - (decode-coding-inserted-region - (point-min) (point-max) buffer-file-name t nil nil t) - ,@body))) - -(defmacro magit-with-temp-index (tree arg &rest body) - (declare (indent 2) (debug (form form body))) - (let ((file (cl-gensym "file"))) - `(let ((magit--refresh-cache nil) - (,file (magit-convert-filename-for-git - (make-temp-name (magit-git-dir "index.magit."))))) - (unwind-protect - (magit-with-toplevel - (--when-let ,tree - (or (magit-git-success "read-tree" ,arg it - (concat "--index-output=" ,file)) - (error "Cannot read tree %s" it))) - (if (file-remote-p default-directory) - (let ((magit-tramp-process-environment - (cons (concat "GIT_INDEX_FILE=" ,file) - magit-tramp-process-environment))) - ,@body) - (let ((process-environment - (cons (concat "GIT_INDEX_FILE=" ,file) - process-environment))) - ,@body))) - (ignore-errors - (delete-file (concat (file-remote-p default-directory) ,file))))))) - -(defun magit-commit-tree (message &optional tree &rest parents) - (magit-git-string "commit-tree" "--no-gpg-sign" "-m" message - (--mapcat (list "-p" it) (delq nil parents)) - (or tree - (magit-git-string "write-tree") - (error "Cannot write tree")))) - -(defun magit-commit-worktree (message &optional arg &rest other-parents) - (magit-with-temp-index "HEAD" arg - (and (magit-update-files (magit-unstaged-files)) - (apply #'magit-commit-tree message nil "HEAD" other-parents)))) - -(defun magit-update-files (files) - (magit-git-success "update-index" "--add" "--remove" "--" files)) - -(defun magit-update-ref (ref message rev &optional stashish) - (let ((magit--refresh-cache nil)) - (or (if (not (version< (magit-git-version) "2.6.0")) - (zerop (magit-call-git "update-ref" "--create-reflog" - "-m" message ref rev - (or (magit-rev-verify ref) ""))) - ;; `--create-reflog' didn't exist before v2.6.0 - (let ((oldrev (magit-rev-verify ref)) - (logfile (magit-git-dir (concat "logs/" ref)))) - (unless (file-exists-p logfile) - (when oldrev - (magit-git-success "update-ref" "-d" ref oldrev)) - (make-directory (file-name-directory logfile) t) - (with-temp-file logfile) - (when (and oldrev (not stashish)) - (magit-git-success "update-ref" "-m" "enable reflog" - ref oldrev "")))) - (magit-git-success "update-ref" "-m" message ref rev - (or (magit-rev-verify ref) ""))) - (error "Cannot update %s with %s" ref rev)))) - -(defconst magit-range-re - (concat "\\`\\([^ \t]*[^.]\\)?" ; revA - "\\(\\.\\.\\.?\\)" ; range marker - "\\([^.][^ \t]*\\)?\\'")) ; revB - -(defun magit-split-range (range) - (and (string-match magit-range-re range) - (let ((beg (or (match-string 1 range) "HEAD")) - (end (or (match-string 3 range) "HEAD"))) - (cons (if (string-equal (match-string 2 range) "...") - (magit-git-string "merge-base" beg end) - beg) - end)))) - -(defun magit-hash-range (range) - (if (string-match magit-range-re range) - (concat (magit-rev-hash (match-string 1 range)) - (match-string 2 range) - (magit-rev-hash (match-string 3 range))) - (magit-rev-hash range))) - -(put 'git-revision 'thing-at-point 'magit-thingatpt--git-revision) -(defun magit-thingatpt--git-revision () - (--when-let - (let ((c "\s\n\t~^:?*[\\")) - (cl-letf (((get 'git-revision 'beginning-op) - (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 (>= (length text) 7) - (string-match-p "[a-z]" text) - (magit-commit-p text) - text)))) - -;;; Completion - -(defvar magit-revision-history nil) - -(defun magit-read-branch (prompt &optional secondary-default) - (magit-completing-read prompt (magit-list-branch-names) - nil t nil 'magit-revision-history - (or (magit-branch-at-point) - secondary-default - (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"))) - -(defun magit-read-range-or-commit (prompt &optional secondary-default) - (magit-read-range - prompt - (or (--when-let (magit-region-values '(commit branch) t) - (deactivate-mark) - (concat (car (last it)) ".." (car it))) - (magit-branch-or-commit-at-point) - secondary-default - (magit-get-current-branch)))) - -(defun magit-read-range (prompt &optional default) - (let ((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) - (let ((choice (magit-completing-read - prompt - (-union (and local-branch - (if remote - (concat remote "/" local-branch) - (--map (concat it "/" local-branch) - (magit-list-remotes)))) - (magit-list-remote-branch-names remote t)) - nil require-match nil 'magit-revision-history default))) - (if (or remote (string-match "\\`\\([^/]+\\)/\\(.+\\)" choice)) - choice - (user-error "`%s' doesn't have the form REMOTE/BRANCH" choice)))) - -(defun magit-read-refspec (prompt remote) - (magit-completing-read prompt - (prog2 (message "Determining available refs...") - (magit-remote-list-refs remote) - (message "Determining available refs...done")))) - -(defun magit-read-local-branch (prompt &optional secondary-default) - (magit-completing-read prompt (magit-list-local-branch-names) - nil t nil 'magit-revision-history - (or (magit-local-branch-at-point) - secondary-default - (magit-get-current-branch)))) - -(defun magit-read-local-branch-or-commit (prompt) - (let ((choices (nconc (magit-list-local-branch-names) - (magit-list-special-refnames))) - (commit (magit-commit-at-point))) - (when commit - (push commit choices)) - (or (magit-completing-read prompt choices - nil nil nil 'magit-revision-history - (or (magit-local-branch-at-point) commit)) - (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) - (magit-list-refs "refs/")) - nil t nil 'magit-revision-history - (or (magit-local-branch-at-point) - secondary-default - (magit-get-current-branch)))) - -(defun magit-read-other-branch - (prompt &optional exclude secondary-default no-require-match) - (let* ((current (magit-get-current-branch)) - (atpoint (magit-branch-at-point)) - (exclude (or exclude current)) - (default (or (and (not (equal atpoint exclude)) atpoint) - (and (not (equal current exclude)) current) - secondary-default - (magit-get-previous-branch)))) - (magit-completing-read prompt (delete exclude (magit-list-branch-names)) - nil (not no-require-match) - nil 'magit-revision-history default))) - -(defun magit-read-other-branch-or-commit - (prompt &optional exclude secondary-default) - (let* ((current (magit-get-current-branch)) - (atpoint (magit-branch-or-commit-at-point)) - (exclude (or exclude current)) - (default (or (and (not (equal atpoint exclude)) - (not (and (not current) - (magit-rev-equal atpoint "HEAD"))) - atpoint) - (and (not (equal current exclude)) current) - secondary-default - (magit-get-previous-branch)))) - (or (magit-completing-read prompt (delete exclude (magit-list-refnames)) - nil nil nil 'magit-revision-history default) - (user-error "Nothing selected")))) - -(defun magit-read-other-local-branch - (prompt &optional exclude secondary-default no-require-match) - (let* ((current (magit-get-current-branch)) - (atpoint (magit-local-branch-at-point)) - (exclude (or exclude current)) - (default (or (and (not (equal atpoint exclude)) atpoint) - (and (not (equal current exclude)) current) - secondary-default - (magit-get-previous-branch)))) - (magit-completing-read prompt - (delete exclude (magit-list-local-branch-names)) - nil (not no-require-match) - nil 'magit-revision-history default))) - -(defun magit-read-branch-prefer-other (prompt) - (let* ((current (magit-get-current-branch)) - (commit (magit-commit-at-point)) - (atrev (and commit (magit-list-branches-pointing-at commit))) - (atpoint (magit--painted-branch-at-point))) - (magit-completing-read prompt (magit-list-branch-names) - nil t nil 'magit-revision-history - (or (magit-section-value-if 'branch) - atpoint - (and (not (cdr atrev)) (car atrev)) - (--first (not (equal it current)) atrev) - (magit-get-previous-branch) - (car atrev))))) - -(defun magit-read-upstream-branch (&optional branch prompt) - "Read the upstream for BRANCH using PROMPT. -If optional BRANCH is nil, then read the upstream for the -current branch, or raise an error if no branch is checked -out. Only existing branches can be selected." - (unless branch - (setq branch (or (magit-get-current-branch) - (error "Need a branch to set its upstream")))) - (let ((branches (delete branch (magit-list-branch-names)))) - (magit-completing-read - (or prompt (format "Change upstream of %s to" branch)) - branches nil t nil 'magit-revision-history - (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))) - (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) - (or (magit-completing-read - (concat prompt - (and branch - (if (bound-and-true-p ivy-mode) - ;; Ivy-mode strips faces from prompt. - (format " `%s'" branch) - (concat " " (magit--propertize-face - branch 'magit-branch-local)))) - " starting at") - (nconc (list "HEAD") - (magit-list-refnames) - (directory-files (magit-git-dir) nil "_HEAD\\'")) - nil nil nil 'magit-revision-history - (or default (magit--default-starting-point))) - (user-error "Nothing selected"))) - -(defun magit--default-starting-point () - (or (let ((r (magit-remote-branch-at-point)) - (l (magit-local-branch-at-point))) - (if magit-prefer-remote-upstream (or r l) (or l r))) - (magit-commit-at-point) - (magit-stash-at-point) - (magit-get-current-branch))) - -(defun magit-read-tag (prompt &optional require-match) - (magit-completing-read prompt (magit-list-tags) nil - require-match nil 'magit-revision-history - (magit-tag-at-point))) - -(defun magit-read-stash (prompt) - (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))) - (if (and use-only (= (length remotes) 1)) - (car remotes) - (magit-completing-read prompt remotes - nil t nil nil - (or default - (magit-remote-at-point) - (magit-get-remote)))))) - -(defun magit-read-remote-or-url (prompt &optional default) - (magit-completing-read prompt - (nconc (magit-list-remotes) - (list "https://" "git://" "git@")) - nil nil nil nil - (or default - (magit-remote-at-point) - (magit-get-remote)))) - -(defun magit-read-module-path (prompt &optional predicate) - (magit-completing-read prompt (magit-list-module-paths) - predicate t nil nil - (magit-module-at-point predicate))) - -(defun magit-module-confirm (verb &optional predicate) - (let (modules) - (if current-prefix-arg - (progn - (setq modules (magit-list-module-paths)) - (when predicate - (setq modules (-filter predicate modules))) - (unless modules - (if predicate - (user-error "No modules satisfying %s available" predicate) - (user-error "No modules available")))) - (setq modules (magit-region-values 'magit-module-section)) - (when modules - (when predicate - (setq modules (-filter predicate modules))) - (unless modules - (user-error "No modules satisfying %s selected" predicate)))) - (if (> (length modules) 1) - (magit-confirm t nil (format "%s %%i modules" verb) nil modules) - (list (magit-read-module-path (format "%s module" verb) predicate))))) - -;;; _ -(provide 'magit-git) -;;; magit-git.el ends here diff --git a/elpa/magit-20210802.1524/magit-gitignore.el b/elpa/magit-20210802.1524/magit-gitignore.el deleted file mode 100644 index da4101e2..00000000 --- a/elpa/magit-20210802.1524/magit-gitignore.el +++ /dev/null @@ -1,196 +0,0 @@ -;;; magit-gitignore.el --- intentionally untracked files -*- lexical-binding: t -*- - -;; 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) -;; 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. - -;;; Commentary: - -;; This library implements gitignore commands. - -;;; Code: - -(require 'magit) - -;;; Transient - -;;;###autoload (autoload 'magit-gitignore "magit-gitignore" nil t) -(transient-define-prefix magit-gitignore () - "Instruct Git to ignore a file or pattern." - :man-page "gitignore" - ["Gitignore" - ("t" "shared at toplevel (.gitignore)" - magit-gitignore-in-topdir) - ("s" "shared in subdirectory (path/to/.gitignore)" - magit-gitignore-in-subdir) - ("p" "privately (.git/info/exclude)" - magit-gitignore-in-gitdir) - ("g" magit-gitignore-on-system - :if (lambda () (magit-get "core.excludesfile")) - :description (lambda () - (format "privately for all repositories (%s)" - (magit-get "core.excludesfile"))))] - ["Skip worktree" - (7 "w" "do skip worktree" magit-skip-worktree) - (7 "W" "do not skip worktree" magit-no-skip-worktree)] - ["Assume unchanged" - (7 "u" "do assume unchanged" magit-assume-unchanged) - (7 "U" "do not assume unchanged" magit-no-assume-unchanged)]) - -;;; Gitignore Commands - -;;;###autoload -(defun magit-gitignore-in-topdir (rule) - "Add the Git ignore RULE to the top-level \".gitignore\" file. -Since this file is tracked, it is shared with other clones of the -repository. Also stage the file." - (interactive (list (magit-gitignore-read-pattern))) - (magit-with-toplevel - (magit--gitignore rule ".gitignore") - (magit-run-git "add" ".gitignore"))) - -;;;###autoload -(defun magit-gitignore-in-subdir (rule directory) - "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." - (interactive (list (magit-gitignore-read-pattern) - (read-directory-name "Limit rule to files in: "))) - (magit-with-toplevel - (let ((file (expand-file-name ".gitignore" directory))) - (magit--gitignore rule file) - (magit-run-git "add" (magit-convert-filename-for-git file))))) - -;;;###autoload -(defun magit-gitignore-in-gitdir (rule) - "Add the Git ignore RULE to \"$GIT_DIR/info/exclude\". -Rules in that file only affects this clone of the repository." - (interactive (list (magit-gitignore-read-pattern))) - (magit--gitignore rule (magit-git-dir "info/exclude")) - (magit-refresh)) - -;;;###autoload -(defun magit-gitignore-on-system (rule) - "Add the Git ignore RULE to the file specified by `core.excludesFile'. -Rules that are defined in that file affect all local repositories." - (interactive (list (magit-gitignore-read-pattern))) - (magit--gitignore rule - (or (magit-get "core.excludesFile") - (error "Variable `core.excludesFile' isn't set"))) - (magit-refresh)) - -(defun magit--gitignore (rule file) - (when-let ((directory (file-name-directory file))) - (make-directory directory t)) - (with-temp-buffer - (when (file-exists-p file) - (insert-file-contents file)) - (goto-char (point-max)) - (unless (bolp) - (insert "\n")) - (insert (replace-regexp-in-string "\\(\\\\*\\)" "\\1\\1" rule)) - (insert "\n") - (write-region nil nil file))) - -(defun magit-gitignore-read-pattern () - (let* ((default (magit-current-file)) - (base (car magit-buffer-diff-files)) - (base (and base (file-directory-p base) base)) - (choices - (delete-dups - (--mapcat - (cons (concat "/" it) - (when-let ((ext (file-name-extension it))) - (list (concat "/" (file-name-directory it) "*." ext) - (concat "*." ext)))) - (sort (nconc - (magit-untracked-files nil base) - ;; The untracked section of the status buffer lists - ;; directories containing only untracked files. - ;; Add those as candidates. - (-filter #'directory-name-p - (magit-list-files - "--other" "--exclude-standard" "--directory" - "--no-empty-directory" "--" base))) - #'string-lessp))))) - (when default - (setq default (concat "/" default)) - (unless (member default choices) - (setq default (concat "*." (file-name-extension default))) - (unless (member default choices) - (setq default nil)))) - (magit-completing-read "File or pattern to ignore" - choices nil nil nil nil default))) - -;;; Skip Worktree Commands - -;;;###autoload -(defun magit-skip-worktree (file) - "Call \"git update-index --skip-worktree -- FILE\"." - (interactive - (list (magit-read-file-choice "Skip worktree for" - (magit-with-toplevel - (cl-set-difference - (magit-list-files) - (magit-skip-worktree-files)))))) - (magit-with-toplevel - (magit-run-git "update-index" "--skip-worktree" "--" file))) - -;;;###autoload -(defun magit-no-skip-worktree (file) - "Call \"git update-index --no-skip-worktree -- FILE\"." - (interactive - (list (magit-read-file-choice "Do not skip worktree for" - (magit-with-toplevel - (magit-skip-worktree-files))))) - (magit-with-toplevel - (magit-run-git "update-index" "--no-skip-worktree" "--" file))) - -;;; Assume Unchanged Commands - -;;;###autoload -(defun magit-assume-unchanged (file) - "Call \"git update-index --assume-unchanged -- FILE\"." - (interactive - (list (magit-read-file-choice "Assume file to be unchanged" - (magit-with-toplevel - (cl-set-difference - (magit-list-files) - (magit-assume-unchanged-files)))))) - (magit-with-toplevel - (magit-run-git "update-index" "--assume-unchanged" "--" file))) - -;;;###autoload -(defun magit-no-assume-unchanged (file) - "Call \"git update-index --no-assume-unchanged -- FILE\"." - (interactive - (list (magit-read-file-choice "Do not assume file to be unchanged" - (magit-with-toplevel - (magit-assume-unchanged-files))))) - (magit-with-toplevel - (magit-run-git "update-index" "--no-assume-unchanged" "--" file))) - -;;; _ -(provide 'magit-gitignore) -;;; magit-gitignore.el ends here diff --git a/elpa/magit-20210802.1524/magit-imenu.el b/elpa/magit-20210802.1524/magit-imenu.el deleted file mode 100644 index 774d302d..00000000 --- a/elpa/magit-20210802.1524/magit-imenu.el +++ /dev/null @@ -1,244 +0,0 @@ -;;; magit-imenu.el --- Integrate Imenu in magit major modes -*- lexical-binding: t -*- - -;; 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. - -;; 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) -;; 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. - -;;; Commentary: - -;; Emacs' major modes can facilitate navigation in their buffers by -;; supporting Imenu. In such major modes, launching Imenu (M-x imenu) -;; makes Emacs display a list of items (e.g., function definitions in -;; a programming major mode). Selecting an item from this list moves -;; point to this item. - -;; magit-imenu.el adds Imenu support to every major mode in Magit. - -;;; Code: - -(require 'magit) -(require 'git-rebase) - -;;; Core - -(defun magit-imenu--index-function (entry-types menu-types) - "Return an alist of imenu entries in current buffer. - -ENTRY-TYPES is a list of section types to be selected through -`imenu'. - -MENU-TYPES is a list of section types containing elements of -ENTRY-TYPES. Elements of MENU-TYPES are are used to categories -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))) - (goto-char (point-max)) - (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))))) - (let* ((section (magit-current-section)) - (name (buffer-substring-no-properties - (line-beginning-position) - (line-end-position))) - (parent (oref section parent)) - (parent-title (buffer-substring-no-properties - (oref parent start) - (1- (oref parent content))))) - (puthash parent-title - (cons (cons name (point)) - (gethash parent-title entries (list))) - entries))) - (mapcar (lambda (menu-title) - (cons menu-title (gethash menu-title entries))) - (hash-table-keys entries)))) - -;;; Log mode - -;;;###autoload -(defun magit-imenu--log-prev-index-position-function () - "Move point to previous line in current buffer. -This function is used as a value for -`imenu-prev-index-position-function'." - (magit-section--backward-find - (lambda () - (-contains-p '(commit stash) - (oref (magit-current-section) type))))) - -;;;###autoload -(defun magit-imenu--log-extract-index-name-function () - "Return imenu name for line at point. -This function is used as a value for -`imenu-extract-index-name-function'. Point should be at the -beginning of the line." - (save-match-data - (looking-at "\\([^ ]+\\)[ *|]+\\(.+\\)$") - (format "%s: %s" - (match-string-no-properties 1) - (match-string-no-properties 2)))) - -;;; Diff mode - -;;;###autoload -(defun magit-imenu--diff-prev-index-position-function () - "Move point to previous file line in current buffer. -This function is used as a value for -`imenu-prev-index-position-function'." - (magit-section--backward-find - (lambda () - (let ((section (magit-current-section))) - (and (magit-file-section-p section) - (not (equal (oref (oref section parent) type) - 'diffstat))))))) - -;;;###autoload -(defun magit-imenu--diff-extract-index-name-function () - "Return imenu name for line at point. -This function is used as a value for -`imenu-extract-index-name-function'. Point should be at the -beginning of the line." - (buffer-substring-no-properties (line-beginning-position) - (line-end-position))) - -;;; Status mode - -;;;###autoload -(defun magit-imenu--status-create-index-function () - "Return an alist of all imenu entries in current buffer. -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))) - -;;;; Refs mode - -;;;###autoload -(defun magit-imenu--refs-create-index-function () - "Return an alist of all imenu entries in current buffer. -This function is used as a value for -`imenu-create-index-function'." - (magit-imenu--index-function - '(branch commit tag) - '(local remote tags))) - -;;;; Cherry mode - -;;;###autoload -(defun magit-imenu--cherry-create-index-function () - "Return an alist of all imenu entries in current buffer. -This function is used as a value for -`imenu-create-index-function'." - (magit-imenu--index-function - '(commit) - '(cherries))) - -;;;; Submodule list mode - -;;;###autoload -(defun magit-imenu--submodule-prev-index-position-function () - "Move point to previous line in magit-submodule-list buffer. -This function is used as a value for -`imenu-prev-index-position-function'." - (unless (bobp) - (forward-line -1))) - -;;;###autoload -(defun magit-imenu--submodule-extract-index-name-function () - "Return imenu name for line at point. -This function is used as a value for -`imenu-extract-index-name-function'. Point should be at the -beginning of the line." - (elt (tabulated-list-get-entry) 0)) - -;;;; Repolist mode - -;;;###autoload -(defun magit-imenu--repolist-prev-index-position-function () - "Move point to previous line in magit-repolist buffer. -This function is used as a value for -`imenu-prev-index-position-function'." - (unless (bobp) - (forward-line -1))) - -;;;###autoload -(defun magit-imenu--repolist-extract-index-name-function () - "Return imenu name for line at point. -This function is used as a value for -`imenu-extract-index-name-function'. Point should be at the -beginning of the line." - (let ((entry (tabulated-list-get-entry))) - (format "%s (%s)" - (elt entry 0) - (elt entry (1- (length entry)))))) - -;;;; Process mode - -;;;###autoload -(defun magit-imenu--process-prev-index-position-function () - "Move point to previous process in magit-process buffer. -This function is used as a value for -`imenu-prev-index-position-function'." - (magit-section--backward-find - (lambda () - (eq (oref (magit-current-section) type) 'process)))) - -;;;###autoload -(defun magit-imenu--process-extract-index-name-function () - "Return imenu name for line at point. -This function is used as a value for -`imenu-extract-index-name-function'. Point should be at the -beginning of the line." - (buffer-substring-no-properties (line-beginning-position) - (line-end-position))) - -;;;; Rebase mode - -;;;###autoload -(defun magit-imenu--rebase-prev-index-position-function () - "Move point to previous commit in git-rebase buffer. -This function is used as a value for -`imenu-prev-index-position-function'." - (catch 'found - (while (not (bobp)) - (git-rebase-backward-line) - (when (git-rebase-line-p) - (throw 'found t))))) - -;;;###autoload -(defun magit-imenu--rebase-extract-index-name-function () - "Return imenu name for line at point. -This function is used as a value for -`imenu-extract-index-name-function'. Point should be at the -beginning of the line." - (buffer-substring-no-properties (line-beginning-position) - (line-end-position))) - -;;; _ -(provide 'magit-imenu) -;;; magit-imenu.el ends here diff --git a/elpa/magit-20210802.1524/magit-log.el b/elpa/magit-20210802.1524/magit-log.el deleted file mode 100644 index 887232ca..00000000 --- a/elpa/magit-20210802.1524/magit-log.el +++ /dev/null @@ -1,1859 +0,0 @@ -;;; magit-log.el --- inspect Git history -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements support for looking at Git logs, including -;; special logs like cherry-logs, as well as for selecting a commit -;; from a log. - -;;; Code: - -(require 'magit-core) -(require 'magit-diff) - -(declare-function magit-blob-visit "magit-files" (blob-or-file line)) -(declare-function magit-insert-head-branch-header "magit-status" - (&optional branch)) -(declare-function magit-insert-upstream-branch-header "magit-status" - (&optional branch pull keyword)) -(declare-function magit-read-file-from-rev "magit-files" - (rev prompt &optional default)) -(declare-function magit-show-commit "magit-diff" - (arg1 &optional arg2 arg3 arg4)) -(declare-function magit-reflog-format-subject "magit-reflog" (subject)) -(defvar magit-refs-focus-column-width) -(defvar magit-refs-margin) -(defvar magit-refs-show-commit-count) -(defvar magit-buffer-margin) -(defvar magit-status-margin) -(defvar magit-status-sections-hook) - -(require 'ansi-color) -(require 'crm) -(require 'which-func) - -;;; 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 - "Hook run after entering Magit-Log mode." - :group 'magit-log - :type 'hook) - -(defcustom magit-log-remove-graph-args '("--follow" "--grep" "-G" "-S" "-L") - "The log arguments that cause the `--graph' argument to be dropped." - :package-version '(magit . "2.3.0") - :group 'magit-log - :type '(repeat (string :tag "Argument")) - :options '("--follow" "--grep" "-G" "-S" "-L")) - -(defcustom magit-log-revision-headers-format "\ -%+b%+N -Author: %aN <%aE> -Committer: %cN <%cE>" - "Additional format string used with the `++header' argument." - :package-version '(magit . "3.2.0") - :group 'magit-log - :type 'string) - -(defcustom magit-log-auto-more nil - "Insert more log entries automatically when moving past the last entry. -Only considered when moving past the last entry with -`magit-goto-*-section' commands." - :group 'magit-log - :type 'boolean) - -(defcustom magit-log-margin '(t age magit-log-margin-width t 18) - "Format of the margin in `magit-log-mode' buffers. - -The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). - -If INIT is non-nil, then the margin is shown initially. -STYLE controls how to format the author or committer date. - It can be one of `age' (to show the age of the commit), - `age-abbreviated' (to abbreviate the time unit to a character), - or a string (suitable for `format-time-string') to show the - actual date. Option `magit-log-margin-show-committer-date' - controls which date is being displayed. -WIDTH controls the width of the margin. This exists for forward - compatibility and currently the value should not be changed. -AUTHOR controls whether the name of the author is also shown by - default. -AUTHOR-WIDTH has to be an integer. When the name of the author - is shown, then this specifies how much space is used to do so." - :package-version '(magit . "2.9.0") - :group 'magit-log - :group 'magit-margin - :type magit-log-margin--custom-type - :initialize 'magit-custom-initialize-reset - :set (apply-partially #'magit-margin-set-variable 'magit-log-mode)) - -(defcustom magit-log-margin-show-committer-date nil - "Whether to show the committer date in the margin. - -This option only controls whether the committer date is displayed -instead of the author date. Whether some date is displayed in -the margin and whether the margin is displayed at all is -controlled by other options." - :package-version '(magit . "3.0.0") - :group 'magit-log - :group 'magit-margin - :type 'boolean) - -(defcustom magit-log-show-refname-after-summary nil - "Whether to show refnames after commit summaries. -This is useful if you use really long branch names." - :package-version '(magit . "2.2.0") - :group 'magit-log - :type 'boolean) - -(defcustom magit-log-highlight-keywords t - "Whether to highlight bracketed keywords in commit summaries." - :package-version '(magit . "2.12.0") - :group 'magit-log - :type 'boolean) - -(defcustom magit-log-header-line-function 'magit-log-header-line-sentence - "Function used to generate text shown in header line of log buffers." - :package-version '(magit . "2.12.0") - :group 'magit-log - :type '(choice (function-item magit-log-header-line-arguments) - (function-item magit-log-header-line-sentence) - function)) - -(defcustom magit-log-trace-definition-function 'magit-which-function - "Function used to determine the function at point. -This is used by the command `magit-log-trace-definition'. -You should prefer `magit-which-function' over `which-function' -because the latter may make use of Imenu's outdated cache." - :package-version '(magit . "3.0.0") - :group 'magit-log - :type '(choice (function-item magit-which-function) - (function-item which-function) - (function-item add-log-current-defun) - function)) - -(defface magit-log-graph - '((((class color) (background light)) :foreground "grey30") - (((class color) (background dark)) :foreground "grey80")) - "Face for the graph part of the log output." - :group 'magit-faces) - -(defface magit-log-author - '((((class color) (background light)) - :foreground "firebrick" - :slant normal - :weight normal) - (((class color) (background dark)) - :foreground "tomato" - :slant normal - :weight normal)) - "Face for the author part of the log output." - :group 'magit-faces) - -(defface magit-log-date - '((((class color) (background light)) - :foreground "grey30" - :slant normal - :weight normal) - (((class color) (background dark)) - :foreground "grey80" - :slant normal - :weight normal)) - "Face for the date part of the log output." - :group 'magit-faces) - -(defface magit-header-line-log-select - '((t :inherit bold)) - "Face for the `header-line' in `magit-log-select-mode'." - :group 'magit-faces) - -;;;; File Log - -(defcustom magit-log-buffer-file-locked t - "Whether `magit-log-buffer-file-quick' uses a dedicated buffer." - :package-version '(magit . "2.7.0") - :group 'magit-commands - :group 'magit-log - :type 'boolean) - -;;;; Select Mode - -(defcustom magit-log-select-show-usage 'both - "Whether to show usage information when selecting a commit from a log. -The message can be shown in the `echo-area' or the `header-line', or in -`both' places. If the value isn't one of these symbols, then it should -be nil, in which case no usage information is shown." - :package-version '(magit . "2.1.0") - :group 'magit-log - :type '(choice (const :tag "in echo-area" echo-area) - (const :tag "in header-line" header-line) - (const :tag "in both places" both) - (const :tag "nowhere"))) - -(defcustom magit-log-select-margin - (list (nth 0 magit-log-margin) - (nth 1 magit-log-margin) - 'magit-log-margin-width t - (nth 4 magit-log-margin)) - "Format of the margin in `magit-log-select-mode' buffers. - -The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). - -If INIT is non-nil, then the margin is shown initially. -STYLE controls how to format the author or committer date. - It can be one of `age' (to show the age of the commit), - `age-abbreviated' (to abbreviate the time unit to a character), - or a string (suitable for `format-time-string') to show the - actual date. Option `magit-log-margin-show-committer-date' - controls which date is being displayed. -WIDTH controls the width of the margin. This exists for forward - compatibility and currently the value should not be changed. -AUTHOR controls whether the name of the author is also shown by - default. -AUTHOR-WIDTH has to be an integer. When the name of the author - is shown, then this specifies how much space is used to do so." - :package-version '(magit . "2.9.0") - :group 'magit-log - :group 'magit-margin - :type magit-log-margin--custom-type - :initialize 'magit-custom-initialize-reset - :set-after '(magit-log-margin) - :set (apply-partially #'magit-margin-set-variable 'magit-log-select-mode)) - -;;;; Cherry Mode - -(defcustom magit-cherry-sections-hook - '(magit-insert-cherry-headers - magit-insert-cherry-commits) - "Hook run to insert sections into the cherry buffer." - :package-version '(magit . "2.1.0") - :group 'magit-log - :type 'hook) - -(defcustom magit-cherry-margin - (list (nth 0 magit-log-margin) - (nth 1 magit-log-margin) - 'magit-log-margin-width t - (nth 4 magit-log-margin)) - "Format of the margin in `magit-cherry-mode' buffers. - -The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). - -If INIT is non-nil, then the margin is shown initially. -STYLE controls how to format the author or committer date. - It can be one of `age' (to show the age of the commit), - `age-abbreviated' (to abbreviate the time unit to a character), - or a string (suitable for `format-time-string') to show the - actual date. Option `magit-log-margin-show-committer-date' - controls which date is being displayed. -WIDTH controls the width of the margin. This exists for forward - compatibility and currently the value should not be changed. -AUTHOR controls whether the name of the author is also shown by - default. -AUTHOR-WIDTH has to be an integer. When the name of the author - is shown, then this specifies how much space is used to do so." - :package-version '(magit . "2.9.0") - :group 'magit-log - :group 'magit-margin - :type magit-log-margin--custom-type - :initialize 'magit-custom-initialize-reset - :set-after '(magit-log-margin) - :set (apply-partially #'magit-margin-set-variable 'magit-cherry-mode)) - -;;;; Log Sections - -(defcustom magit-log-section-commit-count 10 - "How many recent commits to show in certain log sections. -How many recent commits `magit-insert-recent-commits' and -`magit-insert-unpulled-from-upstream-or-recent' (provided -the upstream isn't ahead of the current branch) show." - :package-version '(magit . "2.1.0") - :group 'magit-status - :type 'number) - -;;; Arguments -;;;; Prefix Classes - -(defclass magit-log-prefix (transient-prefix) - ((history-key :initform 'magit-log) - (major-mode :initform 'magit-log-mode))) - -(defclass magit-log-refresh-prefix (magit-log-prefix) - ((history-key :initform 'magit-log) - (major-mode :initform nil))) - -;;;; Prefix Methods - -(cl-defmethod transient-init-value ((obj magit-log-prefix)) - (pcase-let ((`(,args ,files) - (magit-log--get-value 'magit-log-mode - magit-prefix-use-buffer-arguments))) - (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)))) - -(cl-defmethod transient-init-value ((obj magit-log-refresh-prefix)) - (oset obj value (if magit-buffer-log-files - `(("--" ,@magit-buffer-log-files) - ,magit-buffer-log-args) - magit-buffer-log-args))) - -(cl-defmethod transient-set-value ((obj magit-log-prefix)) - (magit-log--set-value obj)) - -(cl-defmethod transient-save-value ((obj magit-log-prefix)) - (magit-log--set-value obj 'save)) - -;;;; Argument Access - -(defun magit-log-arguments (&optional mode) - "Return the current log arguments." - (if (memq transient-current-command '(magit-log magit-log-refresh)) - (pcase-let ((`(,args ,alist) - (-separate #'atom (transient-get-value)))) - (list args (cdr (assoc "--" alist)))) - (magit-log--get-value (or mode 'magit-log-mode)))) - -(defun magit-log--get-value (mode &optional use-buffer-args) - (unless use-buffer-args - (setq use-buffer-args magit-direct-use-buffer-arguments)) - (let (args files) - (cond - ((and (memq use-buffer-args '(always selected current)) - (eq major-mode mode)) - (setq args magit-buffer-log-args) - (setq files magit-buffer-log-files)) - ((and (memq use-buffer-args '(always selected)) - (when-let ((buffer (magit-get-mode-buffer - mode nil - (eq use-buffer-args 'selected)))) - (setq args (buffer-local-value 'magit-buffer-log-args buffer)) - (setq files (buffer-local-value 'magit-buffer-log-files buffer)) - t))) - ((plist-member (symbol-plist mode) 'magit-log-current-arguments) - (setq args (get mode 'magit-log-current-arguments))) - ((when-let ((elt (assq (intern (format "magit-log:%s" mode)) - transient-values))) - (setq args (cdr elt)) - t)) - (t - (setq args (get mode 'magit-log-default-arguments)))) - (list args files))) - -(defun magit-log--set-value (obj &optional save) - (pcase-let* ((obj (oref obj prototype)) - (mode (or (oref obj major-mode) major-mode)) - (key (intern (format "magit-log:%s" mode))) - (`(,args ,alist) - (-separate #'atom (transient-get-value))) - (files (cdr (assoc "--" alist)))) - (put mode 'magit-log-current-arguments args) - (when save - (setf (alist-get key transient-values) args) - (transient-save-values)) - (transient--history-push obj) - (setq magit-buffer-log-args args) - (unless (derived-mode-p 'magit-log-select-mode) - (setq magit-buffer-log-files files)) - (magit-refresh))) - -;;; Commands -;;;; Prefix Commands - -;;;###autoload (autoload 'magit-log "magit-log" nil t) -(transient-define-prefix magit-log () - "Show a commit or reference log." - :man-page "git-log" - :class 'magit-log-prefix - ;; The grouping in git-log(1) appears to be guided by implementation - ;; details, so our logical grouping only follows it to an extend. - ;; Arguments that are "misplaced" here: - ;; 1. From "Commit Formatting". - ;; 2. From "Common Diff Options". - ;; 3. From unnamed first group. - ;; 4. Implemented by Magit. - ["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) - (magit-log:--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 - (7 "=m" "Omit merges" "--no-merges") - (7 "=p" "First parent" "--first-parent")] - ["History simplification" - ( "-D" "Simplify by decoration" "--simplify-by-decoration") - (magit:--) - ( "-f" "Follow renames when showing single-file log" "--follow") ;3 - (6 "/s" "Only commits changing given paths" "--sparse") - (7 "/d" "Only selected commits plus meaningful history" "--dense") - (7 "/a" "Only commits existing directly on ancestry path" "--ancestry-path") - (6 "/f" "Do not prune history" "--full-history") - (7 "/m" "Prune some history" "--simplify-merges")] - ["Commit ordering" - (magit-log:--*-order) - ("-r" "Reverse order" "--reverse")] - ["Formatting" - ("-g" "Show graph" "--graph") ;1 - ("-c" "Show graph in color" "--color") ;2 - ("-d" "Show refnames" "--decorate") ;3 - ("=S" "Show signatures" "--show-signature") ;1 - ("-h" "Show header" "++header") ;4 - ("-p" "Show diffs" ("-p" "--patch")) ;2 - ("-s" "Show diffstats" "--stat")] ;2 - [["Log" - ("l" "current" magit-log-current) - ("o" "other" magit-log-other) - ("h" "HEAD" magit-log-head)] - ["" - ("L" "local branches" magit-log-branches) - (7 "B" "matching branches" magit-log-matching-branches) - (7 "T" "matching tags" magit-log-matching-tags) - ("b" "all branches" magit-log-all-branches) - ("a" "all references" magit-log-all) - (7 "m" "merged" magit-log-merged)] - ["Reflog" - ("r" "current" magit-reflog-current) - ("O" "other" magit-reflog-other) - ("H" "HEAD" magit-reflog-head)] - [: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)] - ["Other" - (5 "s" "shortlog" magit-shortlog)]]) - -;;;###autoload (autoload 'magit-log-refresh "magit-log" nil t) -(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 - [:if-mode magit-log-mode - :class transient-subgroups - ["Commit limiting" - (magit-log:-n) - (magit:--author) - (magit-log:--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)] - ["History simplification" - ( "-D" "Simplify by decoration" "--simplify-by-decoration") - (magit:--) - ( "-f" "Follow renames when showing single-file log" "--follow") ;3 - (6 "/s" "Only commits changing given paths" "--sparse") - (7 "/d" "Only selected commits plus meaningful history" "--dense") - (7 "/a" "Only commits existing directly on ancestry path" "--ancestry-path") - (6 "/f" "Do not prune history" "--full-history") - (7 "/m" "Prune some history" "--simplify-merges")] - ["Commit ordering" - (magit-log:--*-order) - ("-r" "Reverse order" "--reverse")] - ["Formatting" - ("-g" "Show graph" "--graph") - ("-c" "Show graph in color" "--color") - ("-d" "Show refnames" "--decorate") - ("=S" "Show signatures" "--show-signature") - ("-h" "Show header" "++header") - ("-p" "Show diffs" ("-p" "--patch")) - ("-s" "Show diffstats" "--stat")]] - [:if-not-mode magit-log-mode - :description "Arguments" - (magit-log:-n) - (magit-log:--*-order) - ("-g" "Show graph" "--graph") - ("-c" "Show graph in color" "--color") - ("-d" "Show refnames" "--decorate")] - [["Refresh" - ("g" "buffer" magit-log-refresh) - ("s" "buffer and set defaults" transient-set :transient nil) - ("w" "buffer and save defaults" transient-save :transient nil)] - ["Margin" - ("L" "toggle visibility" magit-toggle-margin) - ("l" "cycle style" magit-cycle-margin-style) - ("d" "toggle details" magit-toggle-margin-details) - ("x" "toggle shortstat" magit-toggle-log-margin-style)] - [:if-mode magit-log-mode - :description "Toggle" - ("b" "buffer lock" magit-toggle-buffer-lock)]] - (interactive) - (cond - ((not (eq transient-current-command 'magit-log-refresh)) - (pcase major-mode - (`magit-reflog-mode - (user-error "Cannot change log arguments in reflog buffers")) - (`magit-cherry-mode - (user-error "Cannot change log arguments in cherry buffers"))) - (transient-setup 'magit-log-refresh)) - (t - (pcase-let ((`(,args ,files) (magit-log-arguments))) - (setq magit-buffer-log-args args) - (unless (derived-mode-p 'magit-log-select-mode) - (setq magit-buffer-log-files files))) - (magit-refresh)))) - -;;;; Infix Commands - -(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" - ;; stands for) this is the only argument where we do not use the - ;; long argument ("--max-count"). - :shortarg "-n" - :argument "-n" - :reader 'transient-read-number-N+) - -(transient-define-argument magit:--author () - :description "Limit to author" - :class 'transient-option - :key "-A" - :argument "--author=" - :reader 'magit-transient-read-person) - -(transient-define-argument magit-log:--*-order () - :description "Order commits by" - :class 'transient-switches - :key "-o" - :argument-format "--%s-order" - :argument-regexp "\\(--\\(topo\\|author-date\\|date\\)-order\\)" - :choices '("topo" "author-date" "date")) - -(transient-define-argument magit-log:--grep () - :description "Search messages" - :class 'transient-option - :key "-F" - :argument "--grep=") - -(transient-define-argument magit-log:-G () - :description "Search changes" - :class 'transient-option - :argument "-G") - -(transient-define-argument magit-log:-S () - :description "Search occurrences" - :class 'transient-option - :argument "-S") - -(transient-define-argument magit-log:-L () - :description "Trace line evolution" - :class 'transient-option - :argument "-L" - :reader 'magit-read-file-trace) - -(defun magit-read-file-trace (&rest _ignored) - (let ((file (magit-read-file-from-rev "HEAD" "File")) - (trace (magit-read-string "Trace"))) - (concat trace ":" file))) - -;;;; Setup Commands - -(defvar magit-log-read-revs-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map crm-local-completion-map) - (define-key map "\s" 'self-insert-command) - map)) - -(defun magit-log-read-revs (&optional use-current) - (or (and use-current (--when-let (magit-get-current-branch) (list it))) - (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." - (magit-read-string (format "Type a pattern to pass to %s" option))) - -;;;###autoload -(defun magit-log-current (revs &optional args files) - "Show log for the current branch. -When `HEAD' is detached or with a prefix argument show log for -one or more revs read from the minibuffer." - (interactive (cons (magit-log-read-revs t) - (magit-log-arguments))) - (magit-log-setup-buffer revs args files)) - -;;;###autoload -(defun magit-log-other (revs &optional args files) - "Show log for one or more revs read from the minibuffer. -The user can input any revision or revisions separated by a -space, or even ranges, but only branches and tags, and a -representation of the commit at point, are available as -completion candidates." - (interactive (cons (magit-log-read-revs) - (magit-log-arguments))) - (magit-log-setup-buffer revs args files)) - -;;;###autoload -(defun magit-log-head (&optional args files) - "Show log for `HEAD'." - (interactive (magit-log-arguments)) - (magit-log-setup-buffer (list "HEAD") args files)) - -;;;###autoload -(defun magit-log-branches (&optional args files) - "Show log for all local branches and `HEAD'." - (interactive (magit-log-arguments)) - (magit-log-setup-buffer (if (magit-get-current-branch) - (list "--branches") - (list "HEAD" "--branches")) - args files)) - -;;;###autoload -(defun magit-log-matching-branches (pattern &optional args files) - "Show log for all branches matching PATTERN and `HEAD'." - (interactive (cons (magit-log-read-pattern "--branches") (magit-log-arguments))) - (magit-log-setup-buffer - (list "HEAD" (format "--branches=%s" pattern)) - args files)) - -;;;###autoload -(defun magit-log-matching-tags (pattern &optional args files) - "Show log for all tags matching PATTERN and `HEAD'." - (interactive (cons (magit-log-read-pattern "--tags") (magit-log-arguments))) - (magit-log-setup-buffer - (list "HEAD" (format "--tags=%s" pattern)) - args files)) - -;;;###autoload -(defun magit-log-all-branches (&optional args files) - "Show log for all local and remote branches and `HEAD'." - (interactive (magit-log-arguments)) - (magit-log-setup-buffer (if (magit-get-current-branch) - (list "--branches" "--remotes") - (list "HEAD" "--branches" "--remotes")) - args files)) - -;;;###autoload -(defun magit-log-all (&optional args files) - "Show log for all references and `HEAD'." - (interactive (magit-log-arguments)) - (magit-log-setup-buffer (if (magit-get-current-branch) - (list "--all") - (list "HEAD" "--all")) - args files)) - -;;;###autoload -(defun magit-log-buffer-file (&optional follow beg end) - "Show log for the blob or file visited in the current buffer. -With a prefix argument or when `--follow' is an active log -argument, then follow renames. When the region is active, -restrict the log to the lines that the region touches." - (interactive - (cons current-prefix-arg - (and (region-active-p) - (magit-file-relative-name) - (save-restriction - (widen) - (list (line-number-at-pos (region-beginning)) - (line-number-at-pos - (let ((end (region-end))) - (if (char-after end) - end - ;; Ensure that we don't get the line number - ;; of a trailing newline. - (1- end))))))))) - (require 'magit) - (if-let ((file (magit-file-relative-name))) - (magit-log-setup-buffer - (list (or magit-buffer-refname - (magit-get-current-branch) - "HEAD")) - (let ((args (car (magit-log-arguments)))) - (when (and follow (not (member "--follow" args))) - (push "--follow" args)) - (when (and (file-regular-p - (expand-file-name file (magit-toplevel))) - beg end) - (setq args (cons (format "-L%s,%s:%s" beg end file) - (cl-delete "-L" args :test - 'string-prefix-p))) - (setq file nil)) - args) - (and file (list file)) - magit-log-buffer-file-locked) - (user-error "Buffer isn't visiting a file"))) - -;;;###autoload -(defun magit-log-trace-definition (file fn rev) - "Show log for the definition at point." - (interactive (list (or (magit-file-relative-name) - (user-error "Buffer isn't visiting a file")) - (or (funcall magit-log-trace-definition-function) - (user-error "No function at point found")) - (or magit-buffer-refname - (magit-get-current-branch) - "HEAD"))) - (require 'magit) - (magit-log-setup-buffer - (list rev) - (cons (format "-L:%s%s:%s" - (replace-regexp-in-string ":" "\\:" (regexp-quote fn) nil t) - (if (derived-mode-p 'lisp-mode 'emacs-lisp-mode) - ;; Git doesn't treat "-" the same way as - ;; "_", leading to false-positives such as - ;; "foo-suffix" being considered a match - ;; for "foo". Wing it. - "\\( \\|$\\)" - ;; We could use "\\b" here, but since Git - ;; already does something equivalent, that - ;; isn't necessary. - "") - file) - (cl-delete "-L" (car (magit-log-arguments)) - :test 'string-prefix-p)) - nil magit-log-buffer-file-locked)) - -(defun magit-diff-trace-definition () - "Show log for the definition at point in a diff." - (interactive) - (pcase-let ((`(,buf ,pos) (magit-diff-visit-file--noselect))) - (magit--with-temp-position buf pos - (call-interactively #'magit-log-trace-definition)))) - -;;;###autoload -(defun magit-log-merged (commit branch &optional args files) - "Show log for the merge of COMMIT into BRANCH. - -More precisely, find merge commit M that brought COMMIT into -BRANCH, and show the log of the range \"M^1..M\". If COMMIT is -directly on BRANCH, then show approximately twenty surrounding -commits instead. - -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 "Log merge of commit"))) - (list commit - (magit-read-other-branch "Merged into" commit))) - (magit-log-arguments))) - (unless (executable-find "git-when-merged") - (user-error "This command requires git-when-merged (%s)" - "https://github.com/mhagger/git-when-merged")) - (let (exit m) - (with-temp-buffer - (save-excursion - (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)) - args files nil commit) - (setq m (string-trim-left (substring m (string-match " " m)))) - (if (equal m "Commit is directly on this branch.") - (let* ((from (concat commit "~10")) - (to (- (car (magit-rev-diff-count branch commit)) 10)) - (to (if (<= to 0) - branch - (format "%s~%s" branch to)))) - (unless (magit-rev-verify-commit from) - (setq from (magit-git-string "rev-list" "--max-parents=0" - commit))) - (magit-log-setup-buffer (list (concat from ".." to)) - (cons "--first-parent" args) - files nil commit)) - (user-error "Could not find when %s was merged into %s: %s" - commit branch m))))) - -;;;; Limit Commands - -(defun magit-log-toggle-commit-limit () - "Toggle the number of commits the current log buffer is limited to. -If the number of commits is currently limited, then remove that -limit. Otherwise set it to 256." - (interactive) - (magit-log-set-commit-limit (lambda (&rest _) nil))) - -(defun magit-log-double-commit-limit () - "Double the number of commits the current log buffer is limited to." - (interactive) - (magit-log-set-commit-limit '*)) - -(defun magit-log-half-commit-limit () - "Half the number of commits the current log buffer is limited to." - (interactive) - (magit-log-set-commit-limit '/)) - -(defun magit-log-set-commit-limit (fn) - (let* ((val magit-buffer-log-args) - (arg (--first (string-match "^-n\\([0-9]+\\)?$" it) val)) - (num (and arg (string-to-number (match-string 1 arg)))) - (num (if num (funcall fn num 2) 256))) - (setq val (delete arg val)) - (setq magit-buffer-log-args - (if (and num (> num 0)) - (cons (format "-n%i" num) val) - val))) - (magit-refresh)) - -(defun magit-log-get-commit-limit () - (--when-let (--first (string-match "^-n\\([0-9]+\\)?$" it) - magit-buffer-log-args) - (string-to-number (match-string 1 it)))) - -;;;; Mode Commands - -(defun magit-log-bury-buffer (&optional arg) - "Bury the current buffer or the revision buffer in the same frame. -Like `magit-mode-bury-buffer' (which see) but with a negative -prefix argument instead bury the revision buffer, provided it -is displayed in the current frame." - (interactive "p") - (if (< arg 0) - (let* ((buf (magit-get-mode-buffer 'magit-revision-mode)) - (win (and buf (get-buffer-window buf (selected-frame))))) - (if win - (with-selected-window win - (with-current-buffer buf - (magit-mode-bury-buffer (> (abs arg) 1)))) - (user-error "No revision buffer in this frame"))) - (magit-mode-bury-buffer (> arg 1)))) - -;;;###autoload -(defun magit-log-move-to-parent (&optional n) - "Move to the Nth parent of the current commit." - (interactive "p") - (when (derived-mode-p 'magit-log-mode) - (when (magit-section-match 'commit) - (let* ((section (magit-current-section)) - (parent-rev (format "%s^%s" (oref section value) (or n 1)))) - (if-let ((parent-hash (magit-rev-parse "--short" parent-rev))) - (if-let ((parent (--first (equal (oref it value) - parent-hash) - (magit-section-siblings section 'next)))) - (magit-section-goto parent) - (user-error - (substitute-command-keys - (concat "Parent " parent-hash " not found. Try typing " - "\\[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 - '("-G" "--grep" "--author") - "Arguments which disable the graph speedup hack.") - -(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 "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) - (define-key map "q" 'magit-log-bury-buffer) - map) - "Keymap for `magit-log-mode'.") - -(define-derived-mode magit-log-mode magit-mode "Magit Log" - "Mode for looking at Git log. - -This mode is documented in info node `(magit)Log Buffer'. - -\\\ -Type \\[magit-refresh] to refresh the current buffer. -Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \ -to visit the commit at point. - -Type \\[magit-branch] to see available branch commands. -Type \\[magit-merge] to merge the branch or commit at point. -Type \\[magit-cherry-pick] to apply the commit at point. -Type \\[magit-reset] to reset `HEAD' to the commit at point. - -\\{magit-log-mode-map}" - :group 'magit-log - (hack-dir-local-variables-non-file-buffer) - (setq imenu-prev-index-position-function - 'magit-imenu--log-prev-index-position-function) - (setq imenu-extract-index-name-function - 'magit-imenu--log-extract-index-name-function)) - -(put 'magit-log-mode 'magit-log-default-arguments - '("--graph" "-n256" "--decorate")) - -(defun magit-log-setup-buffer (revs args files &optional locked focus) - (require 'magit) - (with-current-buffer - (magit-setup-buffer #'magit-log-mode locked - (magit-buffer-revisions revs) - (magit-buffer-log-args args) - (magit-buffer-log-files files)) - (when (if focus - (magit-log-goto-commit-section focus) - (magit-log-goto-same-commit)) - (magit-section-update-highlight)) - (current-buffer))) - -(defun magit-log-refresh-buffer () - (let ((revs magit-buffer-revisions) - (args magit-buffer-log-args) - (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))) - (setq args (remove "--follow" args))) - (when (and (car magit-log-remove-graph-args) - (--any-p (string-match-p - (concat "^" (regexp-opt magit-log-remove-graph-args)) it) - args)) - (setq args (remove "--graph" args))) - (unless (member "--graph" args) - (setq args (remove "--color" args))) - (when-let ((limit (magit-log-get-commit-limit)) - (limit (* 2 limit)) ; increase odds for complete graph - (count (and (= (length revs) 1) - (> limit 1024) ; otherwise it's fast enough - (setq revs (car revs)) - (not (string-match-p "\\.\\." revs)) - (not (member revs '("--all" "--branches"))) - (-none-p (lambda (arg) - (--any-p (string-prefix-p it arg) - magit-log-disable-graph-hack-args)) - args) - (magit-git-string "rev-list" "--count" - "--first-parent" args revs)))) - (setq revs (if (< (string-to-number count) limit) - revs - (format "%s~%s..%s" revs limit revs)))) - (magit-insert-section (logbuf) - (magit-insert-log revs args files)))) - -(cl-defmethod magit-buffer-value (&context (major-mode magit-log-mode)) - (append magit-buffer-revisions - (if (and magit-buffer-revisions magit-buffer-log-files) - (cons "--" magit-buffer-log-files) - magit-buffer-log-files))) - -(defun magit-log-header-line-arguments (revs args files) - "Return string describing some of the used arguments." - (mapconcat (lambda (arg) - (if (string-match-p " " arg) - (prin1 arg) - arg)) - `("git" "log" ,@args ,@revs "--" ,@files) - " ")) - -(defun magit-log-header-line-sentence (revs args files) - "Return string containing all arguments." - (concat "Commits in " - (mapconcat #'identity revs " ") - (and (member "--reverse" args) - " in reverse") - (and files (concat " touching " - (mapconcat 'identity files " "))) - (--some (and (string-prefix-p "-L" it) - (concat " " it)) - args))) - -(defun magit-insert-log (revs &optional args files) - "Insert a log section. -Do not add this to a hook variable." - (let ((magit-git-global-arguments - (remove "--literal-pathspecs" magit-git-global-arguments))) - (magit-git-wash (apply-partially #'magit-log-wash-log 'log) - "log" - (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 " - "") - (if (member "--decorate" args) "%D" "") - (if (member "--show-signature" args) - (progn (setq args (remove "--show-signature" args)) "%G?") - "") - (if magit-log-margin-show-committer-date "%ct" "%at") - (if (member "++header" args) - (if (member "--graph" (setq args (remove "++header" args))) - (concat "\n" magit-log-revision-headers-format "\n") - (concat "\n" magit-log-revision-headers-format "\n")) - "")) - (progn - (--when-let (--first (string-match "^\\+\\+order=\\(.+\\)$" it) args) - (setq args (cons (format "--%s-order" (match-string 1 it)) - (remove it args)))) - (when (member "--decorate" args) - (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))) - -(defvar magit-commit-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-visit-thing] 'magit-show-commit) - (define-key map "a" 'magit-cherry-apply) - map) - "Keymap for `commit' sections.") - -(defvar magit-module-commit-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-visit-thing] 'magit-show-commit) - map) - "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]+\\)? " ; 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:[^ \n]*\\) " ; date - "\\(?2:.*\\)$")) ; msg - -(defconst magit-log-cherry-re - (concat "^" - "\\(?8:[-+]\\) " ; cherry - "\\(?1:[0-9a-fA-F]+\\) " ; sha1 - "\\(?2:.*\\)$")) ; msg - -(defconst magit-log-module-re - (concat "^" - "\\(?:\\(?11:[<>]\\) \\)?" ; side - "\\(?1:[0-9a-fA-F]+\\) " ; sha1 - "\\(?2:.*\\)$")) ; msg - -(defconst magit-log-bisect-vis-re - (concat "^" - "\\(?4:[-_/|\\*o<>. ]*\\)" ; graph - "\\(?1:[0-9a-fA-F]+\\)?\0" ; sha1 - "\\(?3:[^\0\n]+\\)?\0" ; refs - "\\(?2:.*\\)$")) ; msg - -(defconst magit-log-bisect-log-re - (concat "^# " - "\\(?3:[^: \n]+:\\) " ; "refs" - "\\[\\(?1:[^]\n]+\\)\\] " ; sha1 - "\\(?2:.*\\)$")) ; msg - -(defconst magit-log-reflog-re - (concat "^" - "\\(?1:[^\0\n]+\\)\0" ; sha1 - "\\(?5:[^\0\n]*\\)\0" ; author - "\\(?:\\(?:[^@\n]+@{\\(?6:[^}\n]+\\)}\0" ; date - "\\(?10:merge \\|autosave \\|restart \\|[^:\n]+: \\)?" ; refsub - "\\(?2:.*\\)?\\)\\|\0\\)$")) ; msg - -(defconst magit-reflog-subject-re - (concat "\\(?1:[^ ]+\\) ?" ; command - "\\(?2:\\(?: ?-[^ ]+\\)+\\)?" ; option - "\\(?: ?(\\(?3:[^)]+\\))\\)?")) ; type - -(defconst magit-log-stash-re - (concat "^" - "\\(?1:[^\0\n]+\\)\0" ; "sha1" - "\\(?5:[^\0\n]*\\)\0" ; author - "\\(?6:[^\0\n]+\\)\0" ; date - "\\(?2:.*\\)$")) ; msg - -(defvar magit-log-count nil) - -(defvar magit-log-format-message-function 'magit-log-propertize-keywords) - -(defun magit-log-wash-log (style args) - (setq args (-flatten args)) - (when (and (member "--graph" args) - (member "--color" args)) - (let ((ansi-color-apply-face-function - (lambda (beg end face) - (put-text-property beg end 'font-lock-face - (or face 'magit-log-graph))))) - (ansi-color-apply-on-region (point-min) (point-max)))) - (when (eq style 'cherry) - (reverse-region (point-min) (point-max))) - (let ((magit-log-count 0)) - (when (looking-at "^\\.\\.\\.") - (magit-delete-line)) - (magit-wash-sequence (apply-partially 'magit-log-wash-rev style - (magit-abbrev-length))) - (if (derived-mode-p 'magit-log-mode 'magit-reflog-mode) - (when (eq magit-log-count (magit-log-get-commit-limit)) - (magit-insert-section (longer) - (insert-text-button - (substitute-command-keys - (format "Type \\<%s>\\[%s] to show more history" - 'magit-log-mode-map - 'magit-log-double-commit-limit)) - 'action (lambda (_button) - (magit-log-double-commit-limit)) - 'follow-link t - 'mouse-face 'magit-section-highlight))) - (insert ?\n)))) - -(cl-defun magit-log-wash-rev (style abbrev) - (when (derived-mode-p 'magit-log-mode 'magit-reflog-mode) - (cl-incf magit-log-count)) - (looking-at (pcase style - (`log magit-log-heading-re) - (`cherry magit-log-cherry-re) - (`module magit-log-module-re) - (`reflog magit-log-reflog-re) - (`stash magit-log-stash-re) - (`bisect-vis magit-log-bisect-vis-re) - (`bisect-log magit-log-bisect-log-re))) - (magit-bind-match-strings - (hash msg refs graph author date gpg cherry _ refsub side) nil - (setq msg (substring-no-properties msg)) - (when refs - (setq refs (substring-no-properties refs))) - (let ((align (or (eq style 'cherry) - (not (member "--stat" magit-buffer-log-args)))) - (non-graph-re (if (eq style 'bisect-vis) - magit-log-bisect-vis-re - magit-log-heading-re))) - (magit-delete-line) - ;; If the reflog entries have been pruned, the output of `git - ;; reflog show' includes a partial line that refers to the hash - ;; of the youngest expired reflog entry. - (when (and (eq style 'reflog) (not date)) - (cl-return-from magit-log-wash-rev t)) - (magit-insert-section section (commit hash) - (pcase style - (`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) - (insert (make-string (1- magit-refs-focus-column-width) ?\s))) - (insert (propertize cherry 'font-lock-face - (if (string= cherry "-") - 'magit-cherry-equivalent - 'magit-cherry-unmatched))) - (insert ?\s)) - (when side - (insert (propertize side 'font-lock-face - (if (string= side "<") - 'magit-cherry-equivalent - 'magit-cherry-unmatched))) - (insert ?\s)) - (when align - (insert hash ?\s)) - (when graph - (insert graph)) - (unless align - (insert hash ?\s)) - (when (and refs (not magit-log-show-refname-after-summary)) - (insert (magit-format-ref-labels refs) ?\s)) - (when (eq style 'reflog) - (insert (format "%-2s " (1- magit-log-count))) - (when refsub - (insert (magit-reflog-format-subject - (substring refsub 0 (if (string-match-p ":" refsub) -2 -1)))))) - (when msg - (insert (funcall magit-log-format-message-function hash msg))) - (when (and refs magit-log-show-refname-after-summary) - (insert ?\s) - (insert (magit-format-ref-labels refs))) - (insert ?\n) - (when (memq style '(log reflog stash)) - (goto-char (line-beginning-position)) - (when (and refsub - (string-match "\\`\\([^ ]\\) \\+\\(..\\)\\(..\\)" date)) - (setq date (+ (string-to-number (match-string 1 date)) - (* (string-to-number (match-string 2 date)) 60 60) - (* (string-to-number (match-string 3 date)) 60)))) - (save-excursion - (backward-char) - (magit-log-format-margin hash author date))) - (when (and (eq style 'cherry) - (magit-buffer-margin-p)) - (save-excursion - (backward-char) - (apply #'magit-log-format-margin hash - (split-string (magit-rev-format "%aN%x00%ct" hash) "\0")))) - (when (and graph - (not (eobp)) - (not (looking-at non-graph-re))) - (when (looking-at "") - (magit-insert-heading) - (delete-char 1) - (magit-insert-section (commit-header) - (forward-line) - (magit-insert-heading) - (re-search-forward "") - (backward-delete-char 1) - (forward-char) - (insert ?\n)) - (delete-char 1)) - (if (looking-at "^\\(---\\|\n\s\\|\ndiff\\)") - (let ((limit (save-excursion - (and (re-search-forward non-graph-re nil t) - (match-beginning 0))))) - (unless (oref magit-insert-section--current content) - (magit-insert-heading)) - (delete-char (if (looking-at "\n") 1 4)) - (magit-diff-wash-diffs (list "--stat") limit)) - (when align - (setq align (make-string (1+ abbrev) ? ))) - (when (and (not (eobp)) (not (looking-at non-graph-re))) - (when align - (setq align (make-string (1+ abbrev) ? ))) - (while (and (not (eobp)) (not (looking-at non-graph-re))) - (when align - (save-excursion (insert align))) - (magit-make-margin-overlay) - (forward-line)) - ;; When `--format' is used and its value isn't one of the - ;; predefined formats, then `git-log' does not insert a - ;; separator line. - (save-excursion - (forward-line -1) - (looking-at "[-_/|\\*o<>. ]*")) - (setq graph (match-string 0)) - (unless (string-match-p "[/\\.]" graph) - (insert graph ?\n)))))))) - t) - -(defun magit-log-propertize-keywords (_rev msg) - (let ((boundary 0)) - (when (string-match "^\\(?:squash\\|fixup\\)! " msg boundary) - (setq boundary (match-end 0)) - (magit--put-face (match-beginning 0) (1- boundary) - 'magit-keyword-squash msg)) - (when magit-log-highlight-keywords - (while (string-match "\\[[^[]*?]" msg boundary) - (setq boundary (match-end 0)) - (magit--put-face (match-beginning 0) boundary - 'magit-keyword msg)))) - msg) - -(defun magit-log-maybe-show-more-commits (section) - "When point is at the end of a log buffer, insert more commits. - -Log buffers end with a button \"Type + to show more history\". -When the use of a section movement command puts point on that -button, then automatically show more commits, without the user -having to press \"+\". - -This function is called by `magit-section-movement-hook' and -exists mostly for backward compatibility reasons." - (when (and (eq (oref section type) 'longer) - magit-log-auto-more) - (magit-log-double-commit-limit) - (forward-line -1) - (magit-section-forward))) - -(add-hook 'magit-section-movement-hook #'magit-log-maybe-show-more-commits) - -(defvar magit--update-revision-buffer nil) - -(defun magit-log-maybe-update-revision-buffer (&optional _) - "When moving in a log or cherry buffer, update the revision buffer. -If there is no revision buffer in the same frame, then do nothing." - (when (derived-mode-p 'magit-log-mode 'magit-cherry-mode 'magit-reflog-mode) - (magit--maybe-update-revision-buffer))) - -(add-hook 'magit-section-movement-hook #'magit-log-maybe-update-revision-buffer) - -(defun magit--maybe-update-revision-buffer () - (when-let ((commit (magit-section-value-if 'commit)) - (buffer (magit-get-mode-buffer 'magit-revision-mode nil t))) - (if magit--update-revision-buffer - (setq magit--update-revision-buffer (list commit buffer)) - (setq magit--update-revision-buffer (list commit buffer)) - (run-with-idle-timer - magit-update-other-window-delay nil - (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) - (when (buffer-live-p buf) - (let ((magit-display-buffer-noselect t)) - (apply #'magit-show-commit rev args)))) - (setq magit--update-revision-buffer nil))))))) - -(defvar magit--update-blob-buffer nil) - -(defun magit-log-maybe-update-blob-buffer (&optional _) - "When moving in a log or cherry buffer, update the blob buffer. -If there is no blob buffer in the same frame, then do nothing." - (when (derived-mode-p 'magit-log-mode 'magit-cherry-mode 'magit-reflog-mode) - (magit--maybe-update-blob-buffer))) - -(defun magit--maybe-update-blob-buffer () - (when-let ((commit (magit-section-value-if 'commit)) - (buffer (--first (with-current-buffer it - (eq revert-buffer-function - 'magit-revert-rev-file-buffer)) - (mapcar #'window-buffer (window-list))))) - (if magit--update-blob-buffer - (setq magit--update-blob-buffer (list commit buffer)) - (setq magit--update-blob-buffer (list commit buffer)) - (run-with-idle-timer - magit-update-other-window-delay nil - (lambda () - (pcase-let ((`(,rev ,buf) magit--update-blob-buffer)) - (setq magit--update-blob-buffer nil) - (when (buffer-live-p buf) - (with-selected-window (get-buffer-window buf) - (with-current-buffer buf - (save-excursion - (magit-blob-visit (list (magit-rev-parse rev) - (magit-file-relative-name - magit-buffer-file-name)) - (line-number-at-pos)))))))))))) - -(defun magit-log-goto-commit-section (rev) - (let ((abbrev (magit-rev-format "%h" rev))) - (when-let ((section (--first (equal (oref it value) abbrev) - (oref magit-root-section children)))) - (goto-char (oref section start))))) - -(defun magit-log-goto-same-commit () - (when (and magit-previous-section - (magit-section-match '(commit branch) - magit-previous-section)) - (magit-log-goto-commit-section (oref magit-previous-section value)))) - -;;; Log Margin - -(defvar-local magit-log-margin-show-shortstat nil) - -(defun magit-toggle-log-margin-style () - "Toggle between the regular and the shortstat margin style. -The shortstat style is experimental and rather slow." - (interactive) - (setq magit-log-margin-show-shortstat - (not magit-log-margin-show-shortstat)) - (magit-set-buffer-margin nil t)) - -(defun magit-log-format-margin (rev author date) - (when (magit-margin-option) - (if magit-log-margin-show-shortstat - (magit-log-format-shortstat-margin rev) - (magit-log-format-author-margin author date)))) - -(defun magit-log-format-author-margin (author date &optional previous-line) - (pcase-let ((`(,_ ,style ,width ,details ,details-width) - (or magit-buffer-margin - (symbol-value (magit-margin-option))))) - (magit-make-margin-overlay - (concat (and details - (concat (magit--propertize-face - (truncate-string-to-width - (or author "") - details-width - nil ?\s - (if (char-displayable-p ?…) "…" ">")) - 'magit-log-author) - " ")) - (magit--propertize-face - (if (stringp style) - (format-time-string - style - (seconds-to-time (string-to-number date))) - (pcase-let* ((abbr (eq style 'age-abbreviated)) - (`(,cnt ,unit) (magit--age date abbr))) - (format (format (if abbr "%%2i%%-%ic" "%%2i %%-%is") - (- width (if details (1+ details-width) 0))) - cnt unit))) - 'magit-log-date)) - previous-line))) - -(defun magit-log-format-shortstat-margin (rev) - (magit-make-margin-overlay - (if-let ((line (and rev (magit-git-string - "show" "--format=" "--shortstat" rev)))) - (if (string-match "\ -\\([0-9]+\\) files? changed, \ -\\(?:\\([0-9]+\\) insertions?(\\+)\\)?\ -\\(?:\\(?:, \\)?\\([0-9]+\\) deletions?(-)\\)?\\'" line) - (magit-bind-match-strings (files add del) line - (format - "%5s %5s%4s" - (if add - (magit--propertize-face (format "%s+" add) - 'magit-diffstat-added) - "") - (if del - (magit--propertize-face (format "%s-" del) - 'magit-diffstat-removed) - "") - files)) - "") - ""))) - -(defun magit-log-margin-width (style details details-width) - (if magit-log-margin-show-shortstat - 16 - (+ (if details (1+ details-width) 0) - (if (stringp style) - (length (format-time-string style)) - (+ 2 ; two digits - 1 ; trailing space - (if (eq style 'age-abbreviated) - 1 ; single character - (+ 1 ; gap after digits - (apply #'max (--map (max (length (nth 1 it)) - (length (nth 2 it))) - magit--age-spec))))))))) - -;;; Select Mode - -(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) - map) - "Keymap for `magit-log-select-mode'.") - -(put 'magit-log-select-pick :advertised-binding [?\C-c ?\C-c]) -(put 'magit-log-select-quit :advertised-binding [?\C-c ?\C-k]) - -(define-derived-mode magit-log-select-mode magit-log-mode "Magit Select" - "Mode for selecting a commit from history. - -This mode is documented in info node `(magit)Select from Log'. - -\\\ -Type \\[magit-refresh] to refresh the current buffer. -Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \ -to visit the commit at point. - -\\\ -Type \\[magit-log-select-pick] to select the commit at point. -Type \\[magit-log-select-quit] to abort without selecting a commit." - :group 'magit-log - (hack-dir-local-variables-non-file-buffer)) - -(put 'magit-log-select-mode 'magit-log-default-arguments - '("--graph" "-n256" "--decorate")) - -(defun magit-log-select-setup-buffer (revs args) - (magit-setup-buffer #'magit-log-select-mode nil - (magit-buffer-revisions revs) - (magit-buffer-log-args args))) - -(defun magit-log-select-refresh-buffer () - (magit-insert-section (logbuf) - (magit-insert-log magit-buffer-revisions - magit-buffer-log-args))) - -(cl-defmethod magit-buffer-value (&context (major-mode magit-log-select-mode)) - magit-buffer-revisions) - -(defvar-local magit-log-select-pick-function nil) -(defvar-local magit-log-select-quit-function nil) - -(defun magit-log-select (pick &optional msg quit branch args initial) - (declare (indent defun)) - (unless initial - (setq initial (magit-commit-at-point))) - (magit-log-select-setup-buffer - (or branch (magit-get-current-branch) "HEAD") - (append args - (car (magit-log--get-value 'magit-log-select-mode - magit-direct-use-buffer-arguments)))) - (when initial - (magit-log-goto-commit-section initial)) - (setq magit-log-select-pick-function pick) - (setq magit-log-select-quit-function quit) - (when magit-log-select-show-usage - (let ((pick (propertize (substitute-command-keys - "\\[magit-log-select-pick]") - 'font-lock-face - 'magit-header-line-key)) - (quit (propertize (substitute-command-keys - "\\[magit-log-select-quit]") - 'font-lock-face - 'magit-header-line-key))) - (setq msg (format-spec - (if msg - (if (string-suffix-p "," msg) - (concat msg " or %q to abort") - msg) - "Type %p to select commit at point, or %q to abort") - `((?p . ,pick) - (?q . ,quit))))) - (magit--add-face-text-property - 0 (length msg) 'magit-header-line-log-select t msg) - (when (memq magit-log-select-show-usage '(both header-line)) - (magit-set-header-line-format msg)) - (when (memq magit-log-select-show-usage '(both echo-area)) - (message "%s" (substring-no-properties msg))))) - -(defun magit-log-select-pick () - "Select the commit at point and act on it. -Call `magit-log-select-pick-function' with the selected -commit as argument." - (interactive) - (let ((fun magit-log-select-pick-function) - (rev (magit-commit-at-point))) - (magit-mode-bury-buffer 'kill) - (funcall fun rev))) - -(defun magit-log-select-quit () - "Abort selecting a commit, don't act on any commit. -Call `magit-log-select-quit-function' if set." - (interactive) - (let ((fun magit-log-select-quit-function)) - (magit-mode-bury-buffer 'kill) - (when fun (funcall fun)))) - -;;; Cherry Mode - -(defvar magit-cherry-mode-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map magit-mode-map) - (define-key map "q" 'magit-log-bury-buffer) - (define-key map "L" 'magit-margin-settings) - map) - "Keymap for `magit-cherry-mode'.") - -(define-derived-mode magit-cherry-mode magit-mode "Magit Cherry" - "Mode for looking at commits not merged upstream. - -\\\ -Type \\[magit-refresh] to refresh the current buffer. -Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \ -to visit the commit at point. - -Type \\[magit-cherry-pick] to apply the commit at point. - -\\{magit-cherry-mode-map}" - :group 'magit-log - (hack-dir-local-variables-non-file-buffer) - (setq imenu-create-index-function - 'magit-imenu--cherry-create-index-function)) - -(defun magit-cherry-setup-buffer (head upstream) - (magit-setup-buffer #'magit-cherry-mode nil - (magit-buffer-refname head) - (magit-buffer-upstream upstream) - (magit-buffer-range (concat upstream ".." head)))) - -(defun magit-cherry-refresh-buffer () - (magit-insert-section (cherry) - (magit-run-section-hook 'magit-cherry-sections-hook))) - -(cl-defmethod magit-buffer-value (&context (major-mode magit-cherry-mode)) - magit-buffer-range) - -;;;###autoload -(defun magit-cherry (head upstream) - "Show commits in a branch that are not merged in the upstream branch." - (interactive - (let ((head (magit-read-branch "Cherry head"))) - (list head (magit-read-other-branch "Cherry upstream" head - (magit-get-upstream-branch head))))) - (require 'magit) - (magit-cherry-setup-buffer head upstream)) - -(defun magit-insert-cherry-headers () - "Insert headers appropriate for `magit-cherry-mode' buffers." - (let ((branch (propertize magit-buffer-refname - 'font-lock-face 'magit-branch-local)) - (upstream (propertize magit-buffer-upstream 'font-lock-face - (if (magit-local-branch-p magit-buffer-upstream) - 'magit-branch-local - 'magit-branch-remote)))) - (magit-insert-head-branch-header branch) - (magit-insert-upstream-branch-header branch upstream "Upstream: ") - (insert ?\n))) - -(defun magit-insert-cherry-commits () - "Insert commit sections into a `magit-cherry-mode' buffer." - (magit-insert-section (cherries) - (magit-insert-heading "Cherry commits:") - (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry) - "cherry" "-v" "--abbrev" - magit-buffer-upstream - magit-buffer-refname))) - -;;; Log Sections -;;;; Standard Log Sections - -(defvar magit-unpulled-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-visit-thing] 'magit-diff-dwim) - map) - "Keymap for `unpulled' sections.") - -(magit-define-section-jumper magit-jump-to-unpulled-from-upstream - "Unpulled from @{upstream}" unpulled "..@{upstream}") - -(defun magit-insert-unpulled-from-upstream () - "Insert commits that haven't been pulled from the upstream yet." - (when-let ((upstream (magit-get-upstream-branch))) - (magit-insert-section (unpulled "..@{upstream}" t) - (magit-insert-heading - (format (propertize "Unpulled from %s." - 'font-lock-face 'magit-section-heading) - upstream)) - (magit-insert-log "..@{upstream}" magit-buffer-log-args) - (magit-log-insert-child-count)))) - -(magit-define-section-jumper magit-jump-to-unpulled-from-pushremote - "Unpulled from " unpulled - (concat ".." (magit-get-push-branch))) - -(defun magit-insert-unpulled-from-pushremote () - "Insert commits that haven't been pulled from the push-remote yet." - (--when-let (magit-get-push-branch) - (when (magit--insert-pushremote-log-p) - (magit-insert-section (unpulled (concat ".." it) t) - (magit-insert-heading - (format (propertize "Unpulled from %s." - 'font-lock-face 'magit-section-heading) - (propertize it 'font-lock-face 'magit-branch-remote))) - (magit-insert-log (concat ".." it) magit-buffer-log-args) - (magit-log-insert-child-count))))) - -(defvar magit-unpushed-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-visit-thing] 'magit-diff-dwim) - map) - "Keymap for `unpushed' sections.") - -(magit-define-section-jumper magit-jump-to-unpushed-to-upstream - "Unpushed to @{upstream}" unpushed "@{upstream}..") - -(defun magit-insert-unpushed-to-upstream-or-recent () - "Insert section showing unpushed or other recent commits. -If an upstream is configured for the current branch and it is -behind of the current branch, then show the commits that have -not yet been pushed into the upstream branch. If no upstream is -configured or if the upstream is not behind of the current branch, -then show the last `magit-log-section-commit-count' commits." - (let ((upstream (magit-get-upstream-branch))) - (if (or (not upstream) - (magit-rev-ancestor-p "HEAD" upstream)) - (magit-insert-recent-commits 'unpushed "@{upstream}..") - (magit-insert-unpushed-to-upstream)))) - -(defun magit-insert-unpushed-to-upstream () - "Insert commits that haven't been pushed to the upstream yet." - (when (magit-git-success "rev-parse" "@{upstream}") - (magit-insert-section (unpushed "@{upstream}..") - (magit-insert-heading - (format (propertize "Unmerged into %s." - 'font-lock-face 'magit-section-heading) - (magit-get-upstream-branch))) - (magit-insert-log "@{upstream}.." magit-buffer-log-args) - (magit-log-insert-child-count)))) - -(defun magit-insert-recent-commits (&optional type value) - "Insert section showing recent commits. -Show the last `magit-log-section-commit-count' commits." - (let* ((start (format "HEAD~%s" magit-log-section-commit-count)) - (range (and (magit-rev-verify start) - (concat start "..HEAD")))) - (magit-insert-section ((eval (or type 'recent)) - (or value range) - t) - (magit-insert-heading "Recent commits") - (magit-insert-log range - (cons (format "-n%d" magit-log-section-commit-count) - (--remove (string-prefix-p "-n" it) - magit-buffer-log-args)))))) - -(magit-define-section-jumper magit-jump-to-unpushed-to-pushremote - "Unpushed to " unpushed - (concat (magit-get-push-branch) "..")) - -(defun magit-insert-unpushed-to-pushremote () - "Insert commits that haven't been pushed to the push-remote yet." - (--when-let (magit-get-push-branch) - (when (magit--insert-pushremote-log-p) - (magit-insert-section (unpushed (concat it "..") t) - (magit-insert-heading - (format (propertize "Unpushed to %s." - 'font-lock-face 'magit-section-heading) - (propertize it 'font-lock-face 'magit-branch-remote))) - (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)))) - (when (> count 0) - (when (= count (magit-log-get-commit-limit)) - (setq count (format "%s+" count))) - (save-excursion - (goto-char (- (oref magit-insert-section--current content) 2)) - (insert (format " (%s)" count)) - (delete-char 1)))))) - -;;;; Auxiliary Log Sections - -(defun magit-insert-unpulled-cherries () - "Insert section showing unpulled commits. -Like `magit-insert-unpulled-from-upstream' but prefix each commit -which has not been applied yet (i.e. a commit with a patch-id -not shared with any local commit) with \"+\", and all others with -\"-\"." - (when (magit-git-success "rev-parse" "@{upstream}") - (magit-insert-section (unpulled "..@{upstream}") - (magit-insert-heading "Unpulled commits:") - (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry) - "cherry" "-v" (magit-abbrev-arg) - (magit-get-current-branch) "@{upstream}")))) - -(defun magit-insert-unpushed-cherries () - "Insert section showing unpushed commits. -Like `magit-insert-unpushed-to-upstream' but prefix each commit -which has not been applied to upstream yet (i.e. a commit with -a patch-id not shared with any upstream commit) with \"+\", and -all others with \"-\"." - (when (magit-git-success "rev-parse" "@{upstream}") - (magit-insert-section (unpushed "@{upstream}..") - (magit-insert-heading "Unpushed commits:") - (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry) - "cherry" "-v" (magit-abbrev-arg) "@{upstream}")))) - -;;; _ -(provide 'magit-log) -;;; magit-log.el ends here diff --git a/elpa/magit-20210802.1524/magit-margin.el b/elpa/magit-20210802.1524/magit-margin.el deleted file mode 100644 index 2889238d..00000000 --- a/elpa/magit-20210802.1524/magit-margin.el +++ /dev/null @@ -1,238 +0,0 @@ -;;; magit-margin.el --- margins in Magit buffers -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements support for showing additional information -;; in the margins of Magit buffers. Currently this is only used for -;; commits, for which the committer date or age, and optionally the -;; author name are shown. - -;;; Code: - -(require 'magit-section) -(require 'magit-transient) -(require 'magit-mode) - -(defgroup magit-margin nil - "Information Magit displays in the margin. - -You can change the STYLE and AUTHOR-WIDTH of all `magit-*-margin' -options to the same values by customizing `magit-log-margin' -*before* `magit' is loaded. If you do that, then the respective -values for the other options will default to what you have set -for that variable. Likewise if you set `magit-log-margin's INIT -to nil, then that is used in the default of all other options. But -setting it to t, i.e. re-enforcing the default for that option, -does not carry to other options." - :link '(info-link "(magit)Log Margin") - :group 'magit-log) - -(defvar-local magit-buffer-margin nil) -(put 'magit-buffer-margin 'permanent-local t) - -(defvar-local magit-set-buffer-margin-refresh nil) - -(defvar magit--age-spec) - -;;; Commands - -(transient-define-prefix magit-margin-settings () - "Change what information is displayed in the margin." - :info-manual "(magit) Log Margin" - ["Margin" - ("L" "Toggle visibility" magit-toggle-margin) - ("l" "Cycle style" magit-cycle-margin-style) - ("d" "Toggle details" magit-toggle-margin-details) - ("v" "Change verbosity" magit-refs-set-show-commit-count - :if-derived magit-refs-mode)]) - -(defun magit-toggle-margin () - "Show or hide the Magit margin." - (interactive) - (unless (magit-margin-option) - (user-error "Magit margin isn't supported in this buffer")) - (setcar magit-buffer-margin (not (magit-buffer-margin-p))) - (magit-set-buffer-margin)) - -(defun magit-cycle-margin-style () - "Cycle style used for the Magit margin." - (interactive) - (unless (magit-margin-option) - (user-error "Magit margin isn't supported in this buffer")) - ;; This is only suitable for commit margins (there are not others). - (setf (cadr magit-buffer-margin) - (pcase (cadr magit-buffer-margin) - (`age 'age-abbreviated) - (`age-abbreviated - (let ((default (cadr (symbol-value (magit-margin-option))))) - (if (stringp default) default "%Y-%m-%d %H:%M "))) - (_ 'age))) - (magit-set-buffer-margin nil t)) - -(defun magit-toggle-margin-details () - "Show or hide details in the Magit margin." - (interactive) - (unless (magit-margin-option) - (user-error "Magit margin isn't supported in this buffer")) - (setf (nth 3 magit-buffer-margin) - (not (nth 3 magit-buffer-margin))) - (magit-set-buffer-margin nil t)) - -;;; Core - -(defun magit-buffer-margin-p () - (car magit-buffer-margin)) - -(defun magit-margin-option () - (pcase major-mode - (`magit-cherry-mode 'magit-cherry-margin) - (`magit-log-mode 'magit-log-margin) - (`magit-log-select-mode 'magit-log-select-margin) - (`magit-reflog-mode 'magit-reflog-margin) - (`magit-refs-mode 'magit-refs-margin) - (`magit-stashes-mode 'magit-stashes-margin) - (`magit-status-mode 'magit-status-margin) - (`forge-notifications-mode 'magit-status-margin))) - -(defun magit-set-buffer-margin (&optional reset refresh) - (when-let ((option (magit-margin-option))) - (let* ((default (symbol-value option)) - (default-width (nth 2 default))) - (when (or reset (not magit-buffer-margin)) - (setq magit-buffer-margin (copy-sequence default))) - (pcase-let ((`(,enable ,style ,_width ,details ,details-width) - magit-buffer-margin)) - (when (functionp default-width) - (setf (nth 2 magit-buffer-margin) - (funcall default-width style details details-width))) - (dolist (window (get-buffer-window-list nil nil 0)) - (with-selected-window window - (magit-set-window-margin window) - (if enable - (add-hook 'window-configuration-change-hook - 'magit-set-window-margin nil t) - (remove-hook 'window-configuration-change-hook - 'magit-set-window-margin t)))) - (when (and enable (or refresh magit-set-buffer-margin-refresh)) - (magit-refresh-buffer)))))) - -(defun magit-set-window-margin (&optional window) - (when (or window (setq window (get-buffer-window))) - (with-selected-window window - (set-window-margins - nil (car (window-margins)) - (and (magit-buffer-margin-p) - (nth 2 magit-buffer-margin)))))) - -(defun magit-make-margin-overlay (&optional string previous-line) - (if previous-line - (save-excursion - (forward-line -1) - (magit-make-margin-overlay string)) - ;; Don't put the overlay on the complete line to work around #1880. - (let ((o (make-overlay (1+ (line-beginning-position)) - (line-end-position) - nil t))) - (overlay-put o 'evaporate t) - (overlay-put o 'before-string - (propertize "o" 'display - (list (list 'margin 'right-margin) - (or string " "))))))) - -(defun magit-maybe-make-margin-overlay () - (when (or (magit-section-match - '(unpulled unpushed recent stashes local cherries) - magit-insert-section--current) - (and (eq major-mode 'magit-refs-mode) - (magit-section-match - '(remote commit tags) - magit-insert-section--current))) - (magit-make-margin-overlay nil t))) - -;;; Custom Support - -(defun magit-margin-set-variable (mode symbol value) - (set-default symbol value) - (message "Updating margins in %s buffers..." mode) - (dolist (buffer (buffer-list)) - (with-current-buffer buffer - (when (eq major-mode mode) - (magit-set-buffer-margin t) - (magit-refresh)))) - (message "Updating margins in %s buffers...done" mode)) - -(defconst magit-log-margin--custom-type - '(list (boolean :tag "Show margin initially") - (choice :tag "Show committer" - (string :tag "date using time-format" "%Y-%m-%d %H:%M ") - (const :tag "date's age" age) - (const :tag "date's age (abbreviated)" age-abbreviated)) - (const :tag "Calculate width using magit-log-margin-width" - magit-log-margin-width) - (boolean :tag "Show author name by default") - (integer :tag "Show author name using width"))) - -;;; Time Utilities - -(defvar magit--age-spec - `((?Y "year" "years" ,(round (* 60 60 24 365.2425))) - (?M "month" "months" ,(round (* 60 60 24 30.436875))) - (?w "week" "weeks" ,(* 60 60 24 7)) - (?d "day" "days" ,(* 60 60 24)) - (?h "hour" "hours" ,(* 60 60)) - (?m "minute" "minutes" 60) - (?s "second" "seconds" 1)) - "Time units used when formatting relative commit ages. - -The value is a list of time units, beginning with the longest. -Each element has the form (CHAR UNIT UNITS SECONDS). UNIT is the -time unit, UNITS is the plural of that unit. CHAR is a character -abbreviation. And SECONDS is the number of seconds in one UNIT. - -This is defined as a variable to make it possible to use time -units for a language other than English. It is not defined -as an option, because most other parts of Magit are always in -English.") - -(defun magit--age (date &optional abbreviate) - (cl-labels ((fn (age spec) - (pcase-let ((`(,char ,unit ,units ,weight) (car spec))) - (let ((cnt (round (/ age weight 1.0)))) - (if (or (not (cdr spec)) - (>= (/ age weight) 1)) - (list cnt (cond (abbreviate char) - ((= cnt 1) unit) - (t units))) - (fn age (cdr spec))))))) - (fn (abs (- (float-time) - (if (stringp date) - (string-to-number date) - date))) - magit--age-spec))) - -;;; _ -(provide 'magit-margin) -;;; magit-margin.el ends here diff --git a/elpa/magit-20210802.1524/magit-merge.el b/elpa/magit-20210802.1524/magit-merge.el deleted file mode 100644 index a50ca3dd..00000000 --- a/elpa/magit-20210802.1524/magit-merge.el +++ /dev/null @@ -1,317 +0,0 @@ -;;; magit-merge.el --- merge functionality -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements merge commands. - -;;; Code: - -(require 'magit) -(require 'magit-diff) - -(declare-function magit-git-push "magit-push" (branch target args)) - -;;; Commands - -;;;###autoload (autoload 'magit-merge "magit" nil t) -(transient-define-prefix magit-merge () - "Merge branches." - :man-page "git-merge" - :incompatible '(("--ff-only" "--no-ff")) - ["Arguments" - :if-not magit-merge-in-progress-p - ("-f" "Fast-forward only" "--ff-only") - ("-n" "No fast-forward" "--no-ff") - (magit-merge:--strategy) - (5 magit-merge:--strategy-option) - (5 magit-diff:--diff-algorithm :argument "-Xdiff-algorithm=") - (5 magit:--gpg-sign)] - ["Actions" - :if-not magit-merge-in-progress-p - [("m" "Merge" magit-merge-plain) - ("e" "Merge and edit message" magit-merge-editmsg) - ("n" "Merge but don't commit" magit-merge-nocommit) - ("a" "Absorb" magit-merge-absorb)] - [("p" "Preview merge" magit-merge-preview) - "" - ("s" "Squash merge" magit-merge-squash) - ("i" "Dissolve" magit-merge-into)]] - ["Actions" - :if magit-merge-in-progress-p - ("m" "Commit merge" magit-commit-create) - ("a" "Abort merge" magit-merge-abort)]) - -(defun magit-merge-arguments () - (transient-args 'magit-merge)) - -(transient-define-argument magit-merge:--strategy () - :description "Strategy" - :class 'transient-option - ;; key for merge and rebase: "-s" - ;; key for cherry-pick and revert: "=s" - ;; shortarg for merge and rebase: "-s" - ;; shortarg for cherry-pick and revert: none - :key "-s" - :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. - -Unless there are conflicts or a prefix argument is used create a -merge commit using a generic commit message and without letting -the user inspect the result. With a prefix argument pretend the -merge failed to give the user the opportunity to inspect the -merge. - -\(git merge --no-edit|--no-commit [ARGS] REV)" - (interactive (list (magit-read-other-branch-or-commit "Merge") - (magit-merge-arguments) - current-prefix-arg)) - (magit-merge-assert) - (magit-run-git-async "merge" (if nocommit "--no-commit" "--no-edit") args rev)) - -;;;###autoload -(defun magit-merge-editmsg (rev &optional args) - "Merge commit REV into the current branch; and edit message. -Perform the merge and prepare a commit message but let the user -edit it. -\n(git merge --edit --no-ff [ARGS] REV)" - (interactive (list (magit-read-other-branch-or-commit "Merge") - (magit-merge-arguments))) - (magit-merge-assert) - (cl-pushnew "--no-ff" args :test #'equal) - (apply #'magit-run-git-with-editor "merge" "--edit" - (append (delete "--ff-only" args) - (list rev)))) - -;;;###autoload -(defun magit-merge-nocommit (rev &optional args) - "Merge commit REV into the current branch; pretending it failed. -Pretend the merge failed to give the user the opportunity to -inspect the merge and change the commit message. -\n(git merge --no-commit --no-ff [ARGS] REV)" - (interactive (list (magit-read-other-branch-or-commit "Merge") - (magit-merge-arguments))) - (magit-merge-assert) - (cl-pushnew "--no-ff" args :test #'equal) - (magit-run-git-async "merge" "--no-commit" args rev)) - -;;;###autoload -(defun magit-merge-into (branch &optional args) - "Merge the current branch into BRANCH and remove the former. - -Before merging, force push the source branch to its push-remote, -provided the respective remote branch already exists, ensuring -that the respective pull-request (if any) won't get stuck on some -obsolete version of the commits that are being merged. Finally -if `forge-branch-pullreq' was used to create the merged branch, -branch, then also remove the respective remote branch." - (interactive - (list (magit-read-other-local-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)) - (head (magit-rev-parse "HEAD"))) - (when (zerop (magit-call-git "checkout" branch)) - (if current - (magit--merge-absorb current args) - (magit-run-git-with-editor "merge" args head))))) - -;;;###autoload -(defun magit-merge-absorb (branch &optional args) - "Merge BRANCH into the current branch and remove the former. - -Before merging, force push the source branch to its push-remote, -provided the respective remote branch already exists, ensuring -that the respective pull-request (if any) won't get stuck on some -obsolete version of the commits that are being merged. Finally -if `forge-branch-pullreq' was used to create the merged branch, -then also remove the respective remote branch." - (interactive (list (magit-read-other-local-branch "Absorb branch") - (magit-merge-arguments))) - (magit--merge-absorb branch args)) - -(defun magit--merge-absorb (branch args) - (when (equal branch (magit-main-branch)) - (unless (yes-or-no-p - (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 - (magit-git-push branch target (list "--force-with-lease")) - (set-process-sentinel - magit-this-process - (lambda (process event) - (when (memq (process-status process) '(exit signal)) - (if (not (zerop (process-exit-status process))) - (magit-process-sentinel process event) - (process-put process 'inhibit-refresh t) - (magit-process-sentinel process event) - (magit--merge-absorb-1 branch args)))))) - (magit--merge-absorb-1 branch args))) - -(defun magit--merge-absorb-1 (branch args) - (if-let ((pr (magit-get "branch" branch "pullRequest"))) - (magit-run-git-async - "merge" args "-m" - (format "Merge branch '%s'%s [#%s]" - branch - (let ((current (magit-get-current-branch))) - (if (equal current (magit-main-branch)) - "" - (format " into %s" current))) - pr) - branch) - (magit-run-git-async "merge" args "--no-edit" branch)) - (set-process-sentinel - magit-this-process - (lambda (process event) - (when (memq (process-status process) '(exit signal)) - (if (> (process-exit-status process) 0) - (magit-process-sentinel process event) - (process-put process 'inhibit-refresh t) - (magit-process-sentinel process event) - (magit-branch-maybe-delete-pr-remote branch) - (magit-branch-unset-pushRemote branch) - (magit-run-git "branch" "-D" branch)))))) - -;;;###autoload -(defun magit-merge-squash (rev) - "Squash commit REV into the current branch; don't create a commit. -\n(git merge --squash REV)" - (interactive (list (magit-read-other-branch-or-commit "Squash"))) - (magit-merge-assert) - (magit-run-git-async "merge" "--squash" rev)) - -;;;###autoload -(defun magit-merge-preview (rev) - "Preview result of merging REV into the current branch." - (interactive (list (magit-read-other-branch-or-commit "Preview merge"))) - (magit-merge-preview-setup-buffer rev)) - -;;;###autoload -(defun magit-merge-abort () - "Abort the current merge operation. -\n(git merge --abort)" - (interactive) - (unless (file-exists-p (magit-git-dir "MERGE_HEAD")) - (user-error "No merge in progress")) - (magit-confirm 'abort-merge) - (magit-run-git-async "merge" "--abort")) - -(defun magit-checkout-stage (file arg) - "During a conflict checkout and stage side, or restore conflict." - (interactive - (let ((file (magit-completing-read "Checkout file" - (magit-tracked-files) nil nil nil - 'magit-read-file-hist - (magit-current-file)))) - (cond ((member file (magit-unmerged-files)) - (list file (magit-checkout-read-stage file))) - ((yes-or-no-p (format "Restore conflicts in %s? " file)) - (list file "--merge")) - (t - (user-error "Quit"))))) - (pcase (cons arg (cddr (car (magit-file-status file)))) - ((or `("--ours" ?D ,_) - `("--theirs" ,_ ?D)) - (magit-run-git "rm" "--" file)) - (_ (if (equal arg "--merge") - ;; This fails if the file was deleted on one - ;; side. And we cannot do anything about it. - (magit-run-git "checkout" "--merge" "--" file) - (magit-call-git "checkout" arg "--" file) - (magit-run-git "add" "-u" "--" file))))) - -;;; Utilities - -(defun magit-merge-in-progress-p () - (file-exists-p (magit-git-dir "MERGE_HEAD"))) - -(defun magit--merge-range (&optional head) - (unless head - (setq head (magit-get-shortname - (car (magit-file-lines (magit-git-dir "MERGE_HEAD")))))) - (and head - (concat (magit-git-string "merge-base" "--octopus" "HEAD" head) - ".." head))) - -(defun magit-merge-assert () - (or (not (magit-anything-modified-p t)) - (magit-confirm 'merge-dirty - "Merging with dirty worktree is risky. Continue"))) - -(defun magit-checkout-read-stage (file) - (magit-read-char-case (format "For %s checkout: " file) t - (?o "[o]ur stage" "--ours") - (?t "[t]heir stage" "--theirs") - (?c "[c]onflict" "--merge"))) - -;;; Sections - -(defvar magit-unmerged-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-visit-thing] 'magit-diff-dwim) - map) - "Keymap for `unmerged' sections.") - -(defun magit-insert-merge-log () - "Insert section for the on-going merge. -Display the heads that are being merged. -If no merge is in progress, do nothing." - (when (magit-merge-in-progress-p) - (let* ((heads (mapcar #'magit-get-shortname - (magit-file-lines (magit-git-dir "MERGE_HEAD")))) - (range (magit--merge-range (car heads)))) - (magit-insert-section (unmerged range) - (magit-insert-heading - (format "Merging %s:" (mapconcat #'identity heads ", "))) - (magit-insert-log - range - (let ((args magit-buffer-log-args)) - (unless (member "--decorate=full" magit-buffer-log-args) - (push "--decorate=full" args)) - args)))))) - -;;; _ -(provide 'magit-merge) -;;; magit-merge.el ends here diff --git a/elpa/magit-20210802.1524/magit-mode.el b/elpa/magit-20210802.1524/magit-mode.el deleted file mode 100644 index efa1614e..00000000 --- a/elpa/magit-20210802.1524/magit-mode.el +++ /dev/null @@ -1,1448 +0,0 @@ -;;; magit-mode.el --- create and refresh Magit buffers -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements the abstract major-mode `magit-mode' from -;; which almost all other Magit major-modes derive. The code in here -;; is mostly concerned with creating and refreshing Magit buffers. - -;;; Code: - -(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' -(defvar magit-post-commit-hook-commands) -(defvar magit-post-stage-hook-commands) -(defvar magit-post-unstage-hook-commands) -;; For `magit-refresh' and `magit-refresh-all' -(declare-function magit-auto-revert-buffers "magit-autorevert" ()) -;; For `magit-refresh-buffer' -(declare-function magit-process-unset-mode-line-error-status "magit-process" ()) -;; For `magit-refresh-get-relative-position' -(declare-function magit-hunk-section-p "magit-diff" (obj)) -;; For `magit-mode-setup-internal' -(declare-function magit-status-goto-initial-section "magit-status" ()) -;; For `magit-mode' from `bookmark' -(defvar bookmark-make-record-function) - -;;; Options - -(defcustom magit-mode-hook - '(magit-load-config-extensions) - "Hook run when entering a mode derived from Magit mode." - :package-version '(magit . "3.0.0") - :group 'magit-modes - :type 'hook - :options '(magit-load-config-extensions - bug-reference-mode)) - -(defcustom magit-setup-buffer-hook - '(magit-maybe-save-repository-buffers - magit-set-buffer-margin) - "Hook run by `magit-setup-buffer'. - -This is run right after displaying the buffer and right before -generating or updating its content. `magit-mode-hook' and other, -more specific, `magit-mode-*-hook's on the other hand are run -right before displaying the buffer. Usually one of these hooks -should be used instead of this one." - :package-version '(magit . "2.3.0") - :group 'magit-modes - :type 'hook - :options '(magit-maybe-save-repository-buffers - magit-set-buffer-margin)) - -(defcustom magit-pre-refresh-hook '(magit-maybe-save-repository-buffers) - "Hook run before refreshing in `magit-refresh'. - -This hook, or `magit-post-refresh-hook', should be used -for functions that are not tied to a particular buffer. - -To run a function with a particular buffer current, use -`magit-refresh-buffer-hook' and use `derived-mode-p' -inside your function." - :package-version '(magit . "2.4.0") - :group 'magit-refresh - :type 'hook - :options '(magit-maybe-save-repository-buffers)) - -(defcustom magit-post-refresh-hook nil - "Hook run after refreshing in `magit-refresh'. - -This hook, or `magit-pre-refresh-hook', should be used -for functions that are not tied to a particular buffer. - -To run a function with a particular buffer current, use -`magit-refresh-buffer-hook' and use `derived-mode-p' -inside your function." - :package-version '(magit . "2.4.0") - :group 'magit-refresh - :type 'hook) - -(defcustom magit-display-buffer-function 'magit-display-buffer-traditional - "The function used display a Magit buffer. - -All Magit buffers (buffers whose major-modes derive from -`magit-mode') are displayed using `magit-display-buffer', -which in turn uses the function specified here." - :package-version '(magit . "2.3.0") - :group 'magit-buffers - :type '(radio (function-item magit-display-buffer-traditional) - (function-item magit-display-buffer-same-window-except-diff-v1) - (function-item magit-display-buffer-fullframe-status-v1) - (function-item magit-display-buffer-fullframe-status-topleft-v1) - (function-item magit-display-buffer-fullcolumn-most-v1) - (function-item display-buffer) - (function :tag "Function"))) - -(defcustom magit-pre-display-buffer-hook '(magit-save-window-configuration) - "Hook run by `magit-display-buffer' before displaying the buffer." - :package-version '(magit . "2.3.0") - :group 'magit-buffers - :type 'hook - :get 'magit-hook-custom-get - :options '(magit-save-window-configuration)) - -(defcustom magit-post-display-buffer-hook '(magit-maybe-set-dedicated) - "Hook run by `magit-display-buffer' after displaying the buffer." - :package-version '(magit . "2.3.0") - :group 'magit-buffers - :type 'hook - :get 'magit-hook-custom-get - :options '(magit-maybe-set-dedicated)) - -(defcustom magit-generate-buffer-name-function - 'magit-generate-buffer-name-default-function - "The function used to generate the name for a Magit buffer." - :package-version '(magit . "2.3.0") - :group 'magit-buffers - :type '(radio (function-item magit-generate-buffer-name-default-function) - (function :tag "Function"))) - -(defcustom magit-buffer-name-format "%x%M%v: %t%x" - "The format string used to name Magit buffers. - -The following %-sequences are supported: - -`%m' The name of the major-mode, but with the `-mode' suffix - removed. - -`%M' Like \"%m\" but abbreviate `magit-status-mode' as `magit'. - -`%v' The value the buffer is locked to, in parentheses, or an - empty string if the buffer is not locked to a value. - -`%V' Like \"%v\", but the string is prefixed with a space, unless - it is an empty string. - -`%t' The top-level directory of the working tree of the - repository, or if `magit-uniquify-buffer-names' is non-nil - an abbreviation of that. - -`%x' If `magit-uniquify-buffer-names' is nil \"*\", otherwise the - empty string. Due to limitations of the `uniquify' package, - buffer names must end with the path. - -`%T' Obsolete, use \"%t%x\" instead. Like \"%t\", but append an - asterisk if and only if `magit-uniquify-buffer-names' is nil. - -The value should always contain \"%m\" or \"%M\", \"%v\" or -\"%V\", and \"%t\" (or the obsolete \"%T\"). - -If `magit-uniquify-buffer-names' is non-nil, then the value must -end with \"%t\" or \"%t%x\" (or the obsolete \"%T\"). See issue -#2841. - -This is used by `magit-generate-buffer-name-default-function'. -If another `magit-generate-buffer-name-function' is used, then -it may not respect this option, or on the contrary it may -support additional %-sequences." - :package-version '(magit . "2.12.0") - :group 'magit-buffers - :type 'string) - -(defcustom magit-uniquify-buffer-names t - "Whether to uniquify the names of Magit buffers." - :package-version '(magit . "2.3.0") - :group 'magit-buffers - :type 'boolean) - -(defcustom magit-bury-buffer-function 'magit-mode-quit-window - "The function used to bury or kill the current Magit buffer." - :package-version '(magit . "3.2.0") - :group 'magit-buffers - :type '(radio (function-item quit-window) - (function-item magit-mode-quit-window) - (function-item magit-restore-window-configuration) - (function :tag "Function"))) - -(defcustom magit-prefix-use-buffer-arguments 'selected - "Whether certain prefix commands reuse arguments active in relevant buffer. - -This affects the transient prefix commands `magit-diff', -`magit-log' and `magit-show-refs'. - -Valid values are: - -`always': Always use the set of arguments that is currently - active in the respective buffer, provided that buffer exists - of course. -`selected': Use the set of arguments from the respective - 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 respective buffer, - but only if it is the current buffer. -`never': Never use the set of arguments from the respective - buffer. - -For more information see info node `(magit)Transient Arguments -and Buffer Arguments'." - :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) - (const :tag "use args from buffer if it is current" current) - (const :tag "never use args from buffer" never))) - -(defcustom magit-direct-use-buffer-arguments 'selected - "Whether certain commands reuse arguments active in relevant buffer. - -This affects certain commands such as `magit-show-commit' that -are suffixes of the diff or log transient prefix commands, but -only if they are invoked directly, i.e. *not* as a suffix. - -Valid values are: - -`always': Always use the set of arguments that is currently - active in the respective buffer, provided that buffer exists - of course. -`selected': Use the set of arguments from the respective - 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 respective buffer, - but only if it is the current buffer. -`never': Never use the set of arguments from the respective - buffer. - -For more information see info node `(magit)Transient Arguments -and Buffer Arguments'." - :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) - (const :tag "use args from buffer if it is current" current) - (const :tag "never use args from buffer" never))) - -(defcustom magit-region-highlight-hook '(magit-diff-update-hunk-region) - "Functions used to highlight the region. - -Each function is run with the current section as only argument -until one of them returns non-nil. If all functions return nil, -then fall back to regular region highlighting." - :package-version '(magit . "2.1.0") - :group 'magit-refresh - :type 'hook - :options '(magit-diff-update-hunk-region)) - -(defcustom magit-create-buffer-hook nil - "Normal hook run after creating a new `magit-mode' buffer." - :package-version '(magit . "2.90.0") - :group 'magit-refresh - :type 'hook) - -(defcustom magit-refresh-buffer-hook nil - "Normal hook for `magit-refresh-buffer' to run after refreshing." - :package-version '(magit . "2.1.0") - :group 'magit-refresh - :type 'hook) - -(defcustom magit-refresh-status-buffer t - "Whether the status buffer is refreshed after running git. - -When this is non-nil, then the status buffer is automatically -refreshed after running git for side-effects, in addition to the -current Magit buffer, which is always refreshed automatically. - -Only set this to nil after exhausting all other options to -improve performance." - :package-version '(magit . "2.4.0") - :group 'magit-refresh - :group 'magit-status - :type 'boolean) - -(defcustom magit-refresh-verbose nil - "Whether to revert Magit buffers verbosely." - :package-version '(magit . "2.1.0") - :group 'magit-refresh - :type 'boolean) - -(defcustom magit-save-repository-buffers t - "Whether to save file-visiting buffers when appropriate. - -If non-nil, then all modified file-visiting buffers belonging -to the current repository may be saved before running Magit -commands and before creating or refreshing Magit buffers. -If `dontask', then this is done without user intervention, for -any other non-nil value the user has to confirm each save. - -The default is t to avoid surprises, but `dontask' is the -recommended value." - :group 'magit-essentials - :group 'magit-buffers - :type '(choice (const :tag "Never" nil) - (const :tag "Ask" t) - (const :tag "Save without asking" dontask))) - -;;; Key Bindings - -(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 "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 "$" 'magit-process-buffer) - (define-key map "%" 'magit-worktree) - (define-key map "a" 'magit-cherry-apply) - (define-key map "A" 'magit-cherry-pick) - (define-key map "b" 'magit-branch) - (define-key map "B" 'magit-bisect) - (define-key map "c" 'magit-commit) - (define-key map "C" 'magit-clone) - (define-key map "d" 'magit-diff) - (define-key map "D" 'magit-diff-refresh) - (define-key map "e" 'magit-ediff-dwim) - (define-key map "E" 'magit-ediff) - (define-key map "f" 'magit-fetch) - (define-key map "F" 'magit-pull) - (define-key map "g" 'magit-refresh) - (define-key map "G" 'magit-refresh-all) - (define-key map "h" 'magit-dispatch) - (define-key map "?" 'magit-dispatch) - (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) - (define-key map "o" 'magit-submodule) - (define-key map "O" 'magit-subtree) - (define-key map "q" 'magit-mode-bury-buffer) - (define-key map "r" 'magit-rebase) - (define-key map "R" 'magit-file-rename) - (define-key map "s" 'magit-stage-file) - (define-key map "S" 'magit-stage-modified) - (define-key map "t" 'magit-tag) - (define-key map "T" 'magit-notes) - (define-key map "u" 'magit-unstage-file) - (define-key map "U" 'magit-unstage-all) - (define-key map "v" 'magit-revert-no-commit) - (define-key map "V" 'magit-revert) - (define-key map "w" 'magit-am) - (define-key map "W" 'magit-patch) - (define-key map "x" 'magit-reset-quickly) - (define-key map "X" 'magit-reset) - (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 "!" '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-w") 'magit-copy-section-value) - (define-key map (kbd "M-w") 'magit-copy-buffer-revision) - (define-key map [remap previous-line] 'magit-previous-line) - (define-key map [remap next-line] 'magit-next-line) - (define-key map [remap evil-previous-line] 'evil-previous-visual-line) - (define-key map [remap evil-next-line] 'evil-next-visual-line) - map) - "Parent keymap for all keymaps of modes derived from `magit-mode'.") - -(defun magit-delete-thing () - "This is a placeholder command. -Where applicable, section-specific keymaps bind another command -which deletes the thing at point." - (interactive) - (user-error "There is no thing at point that could be deleted")) - -(defun magit-visit-thing () - "This is a placeholder command. -Where applicable, section-specific keymaps bind another command -which visits the thing at point." - (interactive) - (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"))) - -(defun magit-edit-thing () - "This is a placeholder command. -Where applicable, section-specific keymaps bind another command -which lets you edit the thing at point, likely in another buffer." - (interactive) - (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"))) - -(defun magit-browse-thing () - "This is a placeholder command. -Where applicable, section-specific keymaps bind another command -which visits the thing at point using `browse-url'." - (interactive) - (user-error "There is no thing at point that could be browsed")) - -(defvar bug-reference-map) -(with-eval-after-load 'bug-reference - (define-key bug-reference-map [remap magit-visit-thing] - 'bug-reference-push-button)) - -(easy-menu-define magit-mode-menu magit-mode-map - "Magit menu" - '("Magit" - ["Refresh" magit-refresh t] - ["Refresh all" magit-refresh-all t] - "---" - ["Stage" magit-stage t] - ["Stage modified" magit-stage-modified t] - ["Unstage" magit-unstage t] - ["Reset index" magit-reset-index t] - ["Commit" magit-commit t] - ["Add log entry" magit-commit-add-log t] - ["Tag" magit-tag-create t] - "---" - ["Diff working tree" magit-diff-working-tree t] - ["Diff" magit-diff t] - ("Log" - ["Log" magit-log-other t] - ["Reflog" magit-reflog-other t] - ["Extended..." magit-log t]) - "---" - ["Cherry pick" magit-cherry-pick t] - ["Revert commit" magit-revert 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] - ["Snapshot" magit-snapshot-both t] - "---" - ["Branch..." magit-checkout t] - ["Merge" magit-merge t] - ["Ediff resolve" magit-ediff-resolve t] - ["Rebase..." magit-rebase t] - "---" - ["Push" magit-push t] - ["Pull" magit-pull-branch t] - ["Remote update" magit-fetch-all t] - ("Submodule" - ["Submodule update" magit-submodule-update t] - ["Submodule update and init" magit-submodule-setup t] - ["Submodule init" magit-submodule-init t] - ["Submodule sync" magit-submodule-sync t]) - "---" - ("Extensions") - "---" - ["Display Git output" magit-process-buffer t] - ["Quit Magit" magit-mode-bury-buffer t])) - -;;; Mode - -(defun magit-load-config-extensions () - "Load Magit extensions that are defined at the Git config layer." - (dolist (ext (magit-get-all "magit.extension")) - (let ((sym (intern (format "magit-%s-mode" ext)))) - (when (fboundp sym) - (funcall sym 1))))) - -(define-derived-mode magit-mode magit-section-mode "Magit" - "Parent major mode from which Magit major modes inherit. - -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 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 - -(defvar-local magit-buffer-arguments nil) -(defvar-local magit-buffer-diff-args nil) -(defvar-local magit-buffer-diff-files nil) -(defvar-local magit-buffer-diff-files-suspended nil) -(defvar-local magit-buffer-file-name nil) -(defvar-local magit-buffer-files nil) -(defvar-local magit-buffer-log-args nil) -(defvar-local magit-buffer-log-files nil) -(defvar-local magit-buffer-range nil) -(defvar-local magit-buffer-range-hashed nil) -(defvar-local magit-buffer-refname nil) -(defvar-local magit-buffer-revision nil) -(defvar-local magit-buffer-revision-hash nil) -(defvar-local magit-buffer-revisions nil) -(defvar-local magit-buffer-typearg nil) -(defvar-local magit-buffer-upstream nil) - -;; These variables are also used in file-visiting buffers. -;; Because the user may change the major-mode, they have -;; to be permanent buffer-local. -(put 'magit-buffer-file-name 'permanent-local t) -(put 'magit-buffer-refname 'permanent-local t) -(put 'magit-buffer-revision 'permanent-local t) -(put 'magit-buffer-revision-hash 'permanent-local t) - -;; `magit-status' re-enables mode function but its refresher -;; function does not reinstate this. -(put 'magit-buffer-diff-files-suspended 'permanent-local t) - -(defvar-local magit-refresh-args nil - "Obsolete. Possibly the arguments used to refresh the current buffer. -Some third-party packages might still use this, but Magit does not.") -(put 'magit-refresh-args 'permanent-local t) -(make-obsolete-variable 'magit-refresh-args nil "Magit 3.0.0") - -(defvar magit-buffer-lock-functions nil - "Obsolete buffer-locking support for third-party modes. -Implement the generic function `magit-buffer-value' for -your mode instead of adding an entry to this variable.") -(make-obsolete-variable 'magit-buffer-lock-functions nil "Magit 3.0.0") - -(cl-defgeneric magit-buffer-value () - (when-let ((fn (cdr (assq major-mode magit-buffer-lock-functions)))) - (funcall fn (with-no-warnings magit-refresh-args)))) - -(defvar-local magit-previous-section nil) -(put 'magit-previous-section 'permanent-local t) - -;;; Setup Buffer - -(defmacro magit-setup-buffer (mode &optional locked &rest bindings) - (declare (indent 2)) - `(magit-setup-buffer-internal - ,mode ,locked - ,(cons 'list (mapcar (pcase-lambda (`(,var ,form)) - `(list ',var ,form)) - bindings)))) - -(defun magit-setup-buffer-internal (mode locked bindings) - (let* ((value (and locked - (with-temp-buffer - (pcase-dolist (`(,var ,val) bindings) - (set (make-local-variable var) val)) - (let ((major-mode mode)) - (magit-buffer-value))))) - (buffer (magit-get-mode-buffer mode value)) - (section (and buffer (magit-current-section))) - (created (not buffer))) - (unless buffer - (setq buffer (magit-with-toplevel - (magit-generate-new-buffer mode value)))) - (with-current-buffer buffer - (setq magit-previous-section section) - (funcall mode) - (magit-xref-setup 'magit-setup-buffer-internal bindings) - (pcase-dolist (`(,var ,val) bindings) - (set (make-local-variable var) val)) - (when created - (magit-status-goto-initial-section) - (run-hooks 'magit-create-buffer-hook))) - (magit-display-buffer buffer) - (with-current-buffer buffer - (run-hooks 'magit-setup-buffer-hook) - (magit-refresh-buffer)) - buffer)) - -(defun magit-mode-setup (mode &rest args) - "Setup up a MODE buffer using ARGS to generate its content." - (declare (obsolete magit-setup-buffer "Magit 3.0.0")) - (with-no-warnings - (magit-mode-setup-internal mode args))) - -(defun magit-mode-setup-internal (mode args &optional locked) - "Setup up a MODE buffer using ARGS to generate its content. -When optional LOCKED is non-nil, then create a buffer that is -locked to its value, which is derived from MODE and ARGS." - (declare (obsolete magit-setup-buffer "Magit 3.0.0")) - (let* ((value (and locked - (with-temp-buffer - (with-no-warnings - (setq magit-refresh-args args)) - (let ((major-mode mode)) - (magit-buffer-value))))) - (buffer (magit-get-mode-buffer mode value)) - (section (and buffer (magit-current-section))) - (created (not buffer))) - (unless buffer - (setq buffer (magit-with-toplevel - (magit-generate-new-buffer mode value)))) - (with-current-buffer buffer - (setq magit-previous-section section) - (with-no-warnings - (setq magit-refresh-args args)) - (funcall mode) - (magit-xref-setup 'magit-mode-setup-internal args) - (when created - (magit-status-goto-initial-section) - (run-hooks 'magit-create-buffer-hook))) - (magit-display-buffer buffer) - (with-current-buffer buffer - (run-hooks 'magit-mode-setup-hook) - (magit-refresh-buffer)))) - -;;; Display Buffer - -(defvar magit-display-buffer-noselect nil - "If non-nil, then `magit-display-buffer' doesn't call `select-window'.") - -(defun magit-display-buffer (buffer &optional display-function) - "Display BUFFER in some window and maybe select it. - -If optional DISPLAY-FUNCTION is non-nil, then use that to display -the buffer. Otherwise use `magit-display-buffer-function', which -is the normal case. - -Then, unless `magit-display-buffer-noselect' is non-nil, select -the window which was used to display the buffer. - -Also run the hooks `magit-pre-display-buffer-hook' -and `magit-post-display-buffer-hook'." - (with-current-buffer buffer - (run-hooks 'magit-pre-display-buffer-hook)) - (let ((window (funcall (or display-function magit-display-buffer-function) - buffer))) - (unless magit-display-buffer-noselect - (let* ((old-frame (selected-frame)) - (new-frame (window-frame window))) - (select-window window) - (unless (eq old-frame new-frame) - (select-frame-set-input-focus new-frame))))) - (with-current-buffer buffer - (run-hooks 'magit-post-display-buffer-hook))) - -(defun magit-display-buffer-traditional (buffer) - "Display BUFFER the way this has traditionally been done." - (display-buffer - buffer (if (and (derived-mode-p 'magit-mode) - (not (memq (with-current-buffer buffer major-mode) - '(magit-process-mode - magit-revision-mode - magit-diff-mode - magit-stash-mode - magit-status-mode)))) - '(display-buffer-same-window) - nil))) ; display in another window - -(defun magit-display-buffer-same-window-except-diff-v1 (buffer) - "Display BUFFER in the selected window except for some modes. -If a buffer's `major-mode' derives from `magit-diff-mode' or -`magit-process-mode', display it in another window. Display all -other buffers in the selected window." - (display-buffer - buffer (if (with-current-buffer buffer - (derived-mode-p 'magit-diff-mode 'magit-process-mode)) - '(nil (inhibit-same-window . t)) - '(display-buffer-same-window)))) - -(defun magit--display-buffer-fullframe (buffer alist) - (when-let ((window (or (display-buffer-reuse-window buffer alist) - (display-buffer-same-window buffer alist) - (display-buffer-pop-up-window buffer alist) - (display-buffer-use-some-window buffer alist)))) - (delete-other-windows window) - window)) - -(defun magit-display-buffer-fullframe-status-v1 (buffer) - "Display BUFFER, filling entire frame if BUFFER is a status buffer. -Otherwise, behave like `magit-display-buffer-traditional'." - (if (eq (with-current-buffer buffer major-mode) - 'magit-status-mode) - (display-buffer buffer '(magit--display-buffer-fullframe)) - (magit-display-buffer-traditional buffer))) - -(defun magit--display-buffer-topleft (buffer alist) - (or (display-buffer-reuse-window buffer alist) - (when-let ((window2 (display-buffer-pop-up-window buffer alist))) - (let ((window1 (get-buffer-window)) - (buffer1 (current-buffer)) - (buffer2 (window-buffer window2)) - (w2-quit-restore (window-parameter window2 'quit-restore))) - (set-window-buffer window1 buffer2) - (set-window-buffer window2 buffer1) - (select-window window2) - ;; Swap some window state that `magit-mode-quit-window' and - ;; `quit-restore-window' inspect. - (set-window-prev-buffers window2 (cdr (window-prev-buffers window1))) - (set-window-prev-buffers window1 nil) - (set-window-parameter window2 'magit-dedicated - (window-parameter window1 'magit-dedicated)) - (set-window-parameter window1 'magit-dedicated t) - (set-window-parameter window1 'quit-restore - (list 'window 'window - (nth 2 w2-quit-restore) - (nth 3 w2-quit-restore))) - (set-window-parameter window2 'quit-restore nil) - window1)))) - -(defun magit-display-buffer-fullframe-status-topleft-v1 (buffer) - "Display BUFFER, filling entire frame if BUFFER is a status buffer. -When BUFFER derives from `magit-diff-mode' or -`magit-process-mode', try to display BUFFER to the top or left of -the current buffer rather than to the bottom or right, as -`magit-display-buffer-fullframe-status-v1' would. Whether the -split is made vertically or horizontally is determined by -`split-window-preferred-function'." - (display-buffer - buffer - (cond ((eq (with-current-buffer buffer major-mode) - 'magit-status-mode) - '(magit--display-buffer-fullframe)) - ((with-current-buffer buffer - (derived-mode-p 'magit-diff-mode 'magit-process-mode)) - '(magit--display-buffer-topleft)) - (t - '(display-buffer-same-window))))) - -(defun magit--display-buffer-fullcolumn (buffer alist) - (when-let ((window (or (display-buffer-reuse-window buffer alist) - (display-buffer-same-window buffer alist) - (display-buffer-below-selected buffer alist)))) - (delete-other-windows-vertically window) - window)) - -(defun magit-display-buffer-fullcolumn-most-v1 (buffer) - "Display BUFFER using the full column except in some cases. -For most cases where BUFFER's `major-mode' derives from -`magit-mode', display it in the selected window and grow that -window to the full height of the frame, deleting other windows in -that column as necessary. However, display BUFFER in another -window if 1) BUFFER's mode derives from `magit-process-mode', or -2) BUFFER's mode derives from `magit-diff-mode', provided that -the mode of the current buffer derives from `magit-log-mode' or -`magit-cherry-mode'." - (display-buffer - buffer - (cond ((and (or git-commit-mode - (derived-mode-p 'magit-log-mode - 'magit-cherry-mode - 'magit-reflog-mode)) - (with-current-buffer buffer - (derived-mode-p 'magit-diff-mode))) - nil) - ((with-current-buffer buffer - (derived-mode-p 'magit-process-mode)) - nil) - (t - '(magit--display-buffer-fullcolumn))))) - -(defun magit-maybe-set-dedicated () - "Mark the selected window as dedicated if appropriate. - -If a new window was created to display the buffer, then remember -that fact. That information is used by `magit-mode-quit-window', -to determine whether the window should be deleted when its last -Magit buffer is buried." - (let ((window (get-buffer-window (current-buffer)))) - (when (and (window-live-p window) - (not (window-prev-buffers window))) - (set-window-parameter window 'magit-dedicated t)))) - -;;; Get Buffer - -(defvar-local magit--default-directory nil - "Value of `default-directory' when buffer is generated. -This exists to prevent a let-bound `default-directory' from -tricking `magit-get-mode-buffer' or `magit-mode-get-buffers' -into thinking a buffer belongs to a repo that it doesn't.") -(put 'magit--default-directory 'permanent-local t) - -(defun magit-mode-get-buffers () - (let ((topdir (magit-toplevel))) - (--filter (with-current-buffer it - (and (derived-mode-p 'magit-mode) - (equal magit--default-directory topdir))) - (buffer-list)))) - -(defvar-local magit-buffer-locked-p nil) -(put 'magit-buffer-locked-p 'permanent-local t) - -(defun magit-get-mode-buffer (mode &optional value frame) - "Return buffer belonging to the current repository whose major-mode is MODE. - -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 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 locked to that value. - -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. -If `visible', then only consider buffers on all visible frames. -If `selected' or t, then only consider buffers on the selected - frame. -If a frame, then only consider buffers on that frame." - (if-let ((topdir (magit-toplevel))) - (cl-flet* ((b (buffer) - (with-current-buffer buffer - (and (eq major-mode mode) - (equal magit--default-directory topdir) - (if value - (and magit-buffer-locked-p - (equal (magit-buffer-value) value)) - (not magit-buffer-locked-p)) - buffer))) - (w (window) - (b (window-buffer window))) - (f (frame) - (seq-some #'w (window-list frame 'no-minibuf)))) - (pcase-exhaustive 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) - (declare (obsolete magit-get-mode-buffer "Magit 3.0.0")) - (when create - (error "`magit-mode-get-buffer's CREATE argument is obsolete")) - (if-let ((topdir (magit-toplevel))) - (--first (with-current-buffer it - (and (eq major-mode mode) - (equal magit--default-directory topdir) - (if value - (and magit-buffer-locked-p - (equal (magit-buffer-value) value)) - (not magit-buffer-locked-p)))) - (if frame - (mapcar #'window-buffer - (window-list (unless (eq frame t) frame))) - (buffer-list))) - (magit--not-inside-repository-error))) - -(defun magit-generate-new-buffer (mode &optional value) - (let* ((name (funcall magit-generate-buffer-name-function mode value)) - (buffer (generate-new-buffer name))) - (with-current-buffer buffer - (setq magit--default-directory default-directory) - (setq magit-buffer-locked-p (and value t)) - (magit-restore-section-visibility-cache mode)) - (when magit-uniquify-buffer-names - (add-to-list 'uniquify-list-buffers-directory-modes mode) - (with-current-buffer buffer - (setq list-buffers-directory (abbreviate-file-name default-directory))) - (let ((uniquify-buffer-name-style - (if (memq uniquify-buffer-name-style '(nil forward)) - 'post-forward-angle-brackets - uniquify-buffer-name-style))) - (uniquify-rationalize-file-buffer-names - name (file-name-directory (directory-file-name default-directory)) - buffer))) - buffer)) - -(defun magit-generate-buffer-name-default-function (mode &optional value) - "Generate buffer name for a MODE buffer in the current repository. -The returned name is based on `magit-buffer-name-format' and -takes `magit-uniquify-buffer-names' and VALUE, if non-nil, into -account." - (let ((m (substring (symbol-name mode) 0 -5)) - (v (and value (format "%s" (if (listp value) value (list value))))) - (n (if magit-uniquify-buffer-names - (file-name-nondirectory - (directory-file-name default-directory)) - (abbreviate-file-name default-directory)))) - (format-spec - magit-buffer-name-format - `((?m . ,m) - (?M . ,(if (eq mode 'magit-status-mode) "magit" m)) - (?v . ,(or v "")) - (?V . ,(if v (concat " " v) "")) - (?t . ,n) - (?x . ,(if magit-uniquify-buffer-names "" "*")) - (?T . ,(if magit-uniquify-buffer-names n (concat n "*"))))))) - -;;; Buffer Lock - -(defun magit-toggle-buffer-lock () - "Lock the current buffer to its value or unlock it. - -Locking a buffer to its value prevents it from being reused to -display another value. The name of a locked buffer contains its -value, which allows telling it apart from other locked buffers -and the unlocked buffer. - -Not all Magit buffers can be locked to their values, for example -it wouldn't make sense to lock a status buffer. - -There can only be a single unlocked buffer using a certain -major-mode per repository. So when a buffer is being unlocked -and another unlocked buffer already exists for that mode and -repository, then the former buffer is instead deleted and the -latter is displayed in its place." - (interactive) - (if magit-buffer-locked-p - (if-let ((unlocked (magit-get-mode-buffer major-mode))) - (let ((locked (current-buffer))) - (switch-to-buffer unlocked nil t) - (kill-buffer locked)) - (setq magit-buffer-locked-p nil) - (rename-buffer (funcall magit-generate-buffer-name-function - major-mode))) - (if-let ((value (magit-buffer-value))) - (if-let ((locked (magit-get-mode-buffer major-mode value))) - (let ((unlocked (current-buffer))) - (switch-to-buffer locked nil t) - (kill-buffer unlocked)) - (setq magit-buffer-locked-p t) - (rename-buffer (funcall magit-generate-buffer-name-function - major-mode value))) - (user-error "Buffer has no value it could be locked to")))) - -;;; Bury Buffer - -(defun magit-mode-bury-buffer (&optional kill-buffer) - "Bury the current buffer. -With a prefix argument, kill the buffer instead. -With two prefix arguments, also kill all Magit buffers associated -with this repository. -This is done using `magit-bury-buffer-function'." - (interactive "P") - ;; Kill all associated Magit buffers when a double prefix arg is given. - (when (>= (prefix-numeric-value kill-buffer) 16) - (let ((current (current-buffer))) - (dolist (buf (magit-mode-get-buffers)) - (unless (eq buf current) - (kill-buffer buf))))) - (funcall magit-bury-buffer-function kill-buffer)) - -(defun magit-mode-quit-window (kill-buffer) - "Quit the selected window and bury its buffer. - -This behaves similar to `quit-window', but when the window -was originally created to display a Magit buffer and the -current buffer is the last remaining Magit buffer that was -ever displayed in the selected window, then delete that -window." - (if (or (one-window-p) - (--first (let ((buffer (car it))) - (and (not (eq buffer (current-buffer))) - (buffer-live-p buffer) - (or (not (window-parameter nil 'magit-dedicated)) - (with-current-buffer buffer - (derived-mode-p 'magit-mode - 'magit-process-mode))))) - (window-prev-buffers))) - (quit-window kill-buffer) - (let ((window (selected-window))) - (quit-window kill-buffer) - (when (window-live-p window) - (delete-window window))))) - -;;; Refresh Buffers - -(defvar magit-inhibit-refresh nil) - -(defun magit-refresh () - "Refresh some buffers belonging to the current repository. - -Refresh the current buffer if its major mode derives from -`magit-mode', and refresh the corresponding status buffer. - -Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'." - (interactive) - (unless magit-inhibit-refresh - (unwind-protect - (let ((start (current-time)) - (magit--refresh-cache (or magit--refresh-cache - (list (cons 0 0))))) - (when magit-refresh-verbose - (message "Refreshing magit...")) - (magit-run-hook-with-benchmark 'magit-pre-refresh-hook) - (cond ((derived-mode-p 'magit-mode) - (magit-refresh-buffer)) - ((derived-mode-p 'tabulated-list-mode) - (revert-buffer))) - (--when-let (and magit-refresh-status-buffer - (not (derived-mode-p 'magit-status-mode)) - (magit-get-mode-buffer 'magit-status-mode)) - (with-current-buffer it - (magit-refresh-buffer))) - (magit-auto-revert-buffers) - (cond - ((and (not this-command) - (memq last-command magit-post-commit-hook-commands)) - (magit-run-hook-with-benchmark 'magit-post-commit-hook)) - ((memq this-command magit-post-stage-hook-commands) - (magit-run-hook-with-benchmark 'magit-post-stage-hook)) - ((memq this-command magit-post-unstage-hook-commands) - (magit-run-hook-with-benchmark 'magit-post-unstage-hook))) - (magit-run-hook-with-benchmark 'magit-post-refresh-hook) - (when magit-refresh-verbose - (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 () - "Refresh all buffers belonging to the current repository. - -Refresh all Magit buffers belonging to the current repository, -and revert buffers that visit files located inside the current -repository. - -Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'." - (interactive) - (magit-run-hook-with-benchmark 'magit-pre-refresh-hook) - (dolist (buffer (magit-mode-get-buffers)) - (with-current-buffer buffer (magit-refresh-buffer))) - (magit-auto-revert-buffers) - (magit-run-hook-with-benchmark 'magit-post-refresh-hook)) - -(defvar-local magit-refresh-start-time nil) - -(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" - (substring (symbol-name major-mode) 0 -5)))) - (magit--refresh-cache (or magit--refresh-cache (list (cons 0 0))))) - (when (functionp refresh) - (when magit-refresh-verbose - (message "Refreshing buffer `%s'..." (buffer-name))) - (let* ((buffer (current-buffer)) - (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-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) - (let ((inhibit-read-only t)) - (erase-buffer) - (save-excursion - (apply refresh (with-no-warnings magit-refresh-args)))) - (pcase-dolist (`(,window . ,args) windows) - (if (eq buffer (window-buffer window)) - (with-selected-window window - (apply #'magit-section-goto-successor args)) - (with-current-buffer buffer - (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)) - (when magit-refresh-verbose - (message "Refreshing buffer `%s'...done (%.3fs)" (buffer-name) - (float-time (time-subtract (current-time) - magit-refresh-start-time))))))) - -(defun magit-refresh-get-relative-position () - (when-let ((section (magit-current-section))) - (let ((start (oref section start))) - (list (count-lines start (point)) - (- (point) (line-beginning-position)) - (and (magit-hunk-section-p section) - (region-active-p) - (progn (goto-char (line-beginning-position)) - (when (looking-at "^[-+]") (forward-line)) - (while (looking-at "^[ @]") (forward-line)) - (let ((beg (point))) - (cond ((looking-at "^[-+]") - (forward-line) - (while (looking-at "^[-+]") (forward-line)) - (while (looking-at "^ ") (forward-line)) - (forward-line -1) - (regexp-quote (buffer-substring-no-properties - beg (line-end-position)))) - (t t))))))))) - -;;; Save File-Visiting Buffers - -(defvar disable-magit-save-buffers nil) - -(defun magit-pre-command-hook () - (setq disable-magit-save-buffers nil)) -(add-hook 'pre-command-hook #'magit-pre-command-hook) - -(defvar magit-after-save-refresh-buffers nil) - -(defun magit-after-save-refresh-buffers () - (dolist (buffer magit-after-save-refresh-buffers) - (when (buffer-live-p buffer) - (with-current-buffer buffer - (magit-refresh-buffer)))) - (setq magit-after-save-refresh-buffers nil) - (remove-hook 'post-command-hook 'magit-after-save-refresh-buffers)) - -(defun magit-after-save-refresh-status () - "Refresh the status buffer of the current repository. - -This function is intended to be added to `after-save-hook'. - -If the status buffer does not exist or the file being visited in -the current buffer isn't inside the working tree of a repository, -then do nothing. - -Note that refreshing a Magit buffer is done by re-creating its -contents from scratch, which can be slow in large repositories. -If you are not satisfied with Magit's performance, then you -should obviously not add this function to that hook." - (when (and (not disable-magit-save-buffers) - (magit-inside-worktree-p t)) - (--when-let (ignore-errors (magit-get-mode-buffer 'magit-status-mode)) - (add-to-list 'magit-after-save-refresh-buffers it) - (add-hook 'post-command-hook 'magit-after-save-refresh-buffers)))) - -(defun magit-maybe-save-repository-buffers () - "Maybe save file-visiting buffers belonging to the current repository. -Do so if `magit-save-repository-buffers' is non-nil. You should -not remove this from any hooks, instead set that variable to nil -if you so desire." - (when (and magit-save-repository-buffers - (not disable-magit-save-buffers)) - (setq disable-magit-save-buffers t) - (let ((msg (current-message))) - (magit-save-repository-buffers - (eq magit-save-repository-buffers 'dontask)) - (when (and msg - (current-message) - (not (equal msg (current-message)))) - (message "%s" msg))))) - -(add-hook 'magit-pre-refresh-hook #'magit-maybe-save-repository-buffers) -(add-hook 'magit-pre-call-git-hook #'magit-maybe-save-repository-buffers) -(add-hook 'magit-pre-start-git-hook #'magit-maybe-save-repository-buffers) - -(defvar-local magit-inhibit-refresh-save nil) - -(defun magit-save-repository-buffers (&optional arg) - "Save file-visiting buffers belonging to the current repository. -After any buffer where `buffer-save-without-query' is non-nil -is saved without asking, the user is asked about each modified -buffer which visits a file in the current repository. Optional -argument (the prefix) non-nil means save all with no questions." - (interactive "P") - (when-let ((topdir (magit-rev-parse-safe "--show-toplevel"))) - (let ((remote (file-remote-p topdir)) - (save-some-buffers-action-alist - `((?Y (lambda (buffer) - (with-current-buffer buffer - (setq buffer-save-without-query t) - (save-buffer))) - "to save the current buffer and remember choice") - (?N (lambda (buffer) - (with-current-buffer buffer - (setq magit-inhibit-refresh-save t))) - "to skip the current buffer and remember choice") - ,@save-some-buffers-action-alist))) - (save-some-buffers - arg (lambda () - (and (not magit-inhibit-refresh-save) - buffer-file-name - ;; Avoid needlessly connecting to unrelated remotes. - (equal (file-remote-p buffer-file-name) - remote) - ;; For remote files this makes network requests and - ;; therefore has to come after the above to avoid - ;; unnecessarily waiting for unrelated hosts. - (file-exists-p (file-name-directory buffer-file-name)) - (string-prefix-p topdir (file-truename buffer-file-name)) - (equal (magit-rev-parse-safe "--show-toplevel") - topdir))))))) - -;;; Restore Window Configuration - -(defvar magit-inhibit-save-previous-winconf nil) - -(defvar-local magit-previous-window-configuration nil) -(put 'magit-previous-window-configuration 'permanent-local t) - -(defun magit-save-window-configuration () - "Save the current window configuration. - -Later, when the buffer is buried, it may be restored by -`magit-restore-window-configuration'." - (if magit-inhibit-save-previous-winconf - (when (eq magit-inhibit-save-previous-winconf 'unset) - (setq magit-previous-window-configuration nil)) - (unless (get-buffer-window (current-buffer) (selected-frame)) - (setq magit-previous-window-configuration - (current-window-configuration))))) - -(defun magit-restore-window-configuration (&optional kill-buffer) - "Bury or kill the current buffer and restore previous window configuration." - (let ((winconf magit-previous-window-configuration) - (buffer (current-buffer)) - (frame (selected-frame))) - (quit-window kill-buffer (selected-window)) - (when (and winconf (equal frame (window-configuration-frame winconf))) - (set-window-configuration winconf) - (when (buffer-live-p buffer) - (with-current-buffer buffer - (setq magit-previous-window-configuration nil)))))) - -;;; Buffer History - -(defun magit-go-backward () - "Move backward in current buffer's history." - (interactive) - (if help-xref-stack - (help-xref-go-back (current-buffer)) - (user-error "No previous entry in buffer's history"))) - -(defun magit-go-forward () - "Move forward in current buffer's history." - (interactive) - (if help-xref-forward-stack - (help-xref-go-forward (current-buffer)) - (user-error "No next entry in buffer's history"))) - -(defun magit-insert-xref-buttons () - "Insert xref buttons." - (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 - (when help-xref-stack - (insert " ")) - (magit-xref-insert-button help-forward-label 'magit-xref-forward)))) - -(defun magit-xref-insert-button (label type) - (magit-insert-section (button label) - (insert-text-button label 'type type - 'help-args (list (current-buffer))))) - -(define-button-type 'magit-xref-backward - :supertype 'help-back - 'mouse-face 'magit-section-highlight - 'help-echo (purecopy "mouse-2, RET: go back to previous history entry")) - -(define-button-type 'magit-xref-forward - :supertype 'help-forward - 'mouse-face 'magit-section-highlight - 'help-echo (purecopy "mouse-2, RET: go back to next history entry")) - -(defvar magit-xref-modes - '(magit-log-mode - magit-reflog-mode - magit-diff-mode - magit-revision-mode) - "List of modes for which to insert navigation buttons.") - -(defun magit-xref-setup (fn args) - (when (memq major-mode magit-xref-modes) - (when help-xref-stack-item - (push (cons (point) help-xref-stack-item) help-xref-stack) - (setq help-xref-forward-stack nil)) - (when (called-interactively-p 'interactive) - (--when-let (nthcdr 10 help-xref-stack) - (setcdr it nil))) - (setq help-xref-stack-item - (list 'magit-xref-restore fn default-directory args)))) - -(defun magit-xref-restore (fn dir args) - (setq default-directory dir) - (funcall fn major-mode nil args) - (magit-refresh-buffer)) - -;;; Repository-Local Cache - -(defvar magit-repository-local-cache nil - "Alist mapping `magit-toplevel' paths to alists of key/value pairs.") - -(defun magit-repository-local-repository () - "Return the key for the current repository." - (or (bound-and-true-p magit--default-directory) - (magit-toplevel))) - -(defun magit-repository-local-set (key value &optional repository) - "Set the repository-local VALUE for KEY. - -Unless specified, REPOSITORY is the current buffer's repository. - -If REPOSITORY is nil (meaning there is no current repository), -then the value is not cached, and we return nil." - (let* ((repokey (or repository (magit-repository-local-repository))) - (cache (assoc repokey magit-repository-local-cache))) - ;; Don't cache values for a nil REPOSITORY, as the 'set' and 'get' - ;; calls for some KEY may happen in unrelated contexts. - (when repokey - (if cache - (let ((keyvalue (assoc key (cdr cache)))) - (if keyvalue - ;; Update pre-existing value for key. - (setcdr keyvalue value) - ;; No such key in repository-local cache. - (push (cons key value) (cdr cache)))) - ;; No cache for this repository. - (push (cons repokey (list (cons key value))) - magit-repository-local-cache))))) - -(defun magit-repository-local-exists-p (key &optional repository) - "Non-nil when a repository-local value exists for KEY. - -Return a (KEY . VALUE) cons cell. - -The KEY is matched using `equal'. - -Unless specified, REPOSITORY is the current buffer's repository." - (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. - -Return DEFAULT if no value for KEY exists. - -The KEY is matched using `equal'. - -Unless specified, REPOSITORY is the current buffer's repository." - (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." - (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) - (magit-repository-local-set - (cons major-mode 'magit-section-visibility-cache) - magit-section-visibility-cache))) - -(defun magit-restore-section-visibility-cache (mode) - (setq magit-section-visibility-cache - (magit-repository-local-get - (cons mode 'magit-section-visibility-cache)))) - -(defun magit-zap-caches () - "Zap caches for the current repository. -Remove the repository's entry from `magit-repository-local-cache' -and set `magit-section-visibility-cache' to nil in all of the -repository's Magit buffers." - (interactive) - (magit-with-toplevel - (setq magit-repository-local-cache - (cl-delete default-directory - magit-repository-local-cache - :key #'car :test #'equal))) - (dolist (buffer (magit-mode-get-buffers)) - (with-current-buffer buffer - (setq magit-section-visibility-cache nil))) - (setq magit--libgit-available-p 'unknown)) - -;;; Utilities - -(defun magit-toggle-verbose-refresh () - "Toggle whether Magit refreshes buffers verbosely. -Enabling this helps figuring out which sections are bottlenecks. -The additional output can be found in the *Messages* buffer." - (interactive) - (setq magit-refresh-verbose (not magit-refresh-verbose)) - (message "%s verbose refreshing" - (if magit-refresh-verbose "Enabled" "Disabled"))) - -(defun magit-run-hook-with-benchmark (hook) - (when hook - (if magit-refresh-verbose - (let ((start (current-time))) - (message "Running %s..." hook) - (run-hooks hook) - (message "Running %s...done (%.3fs)" hook - (float-time (time-subtract (current-time) start)))) - (run-hooks hook)))) - -;;; _ -(provide 'magit-mode) -;;; magit-mode.el ends here diff --git a/elpa/magit-20210802.1524/magit-notes.el b/elpa/magit-20210802.1524/magit-notes.el deleted file mode 100644 index a541b032..00000000 --- a/elpa/magit-20210802.1524/magit-notes.el +++ /dev/null @@ -1,202 +0,0 @@ -;;; magit-notes.el --- notes support -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements support for `git-notes'. - -;;; Code: - -(require 'magit) - -;;; Commands - -;;;###autoload (autoload 'magit-notes "magit" nil t) -(transient-define-prefix magit-notes () - "Edit notes attached to commits." - :man-page "git-notes" - ["Configure local settings" - ("c" magit-core.notesRef) - ("d" magit-notes.displayRef)] - ["Configure global settings" - ("C" magit-global-core.notesRef) - ("D" magit-global-notes.displayRef)] - ["Arguments for prune" - :if-not magit-notes-merging-p - ("-n" "Dry run" ("-n" "--dry-run"))] - ["Arguments for edit and remove" - :if-not magit-notes-merging-p - (magit-notes:--ref)] - ["Arguments for merge" - :if-not magit-notes-merging-p - (magit-notes:--strategy)] - ["Actions" - :if-not magit-notes-merging-p - ("T" "Edit" magit-notes-edit) - ("r" "Remove" magit-notes-remove) - ("m" "Merge" magit-notes-merge) - ("p" "Prune" magit-notes-prune)] - ["Actions" - :if magit-notes-merging-p - ("c" "Commit merge" magit-notes-merge-commit) - ("a" "Abort merge" magit-notes-merge-abort)]) - -(defun magit-notes-merging-p () - (let ((dir (magit-git-dir "NOTES_MERGE_WORKTREE"))) - (and (file-directory-p dir) - (directory-files dir nil "^[^.]")))) - -(transient-define-infix magit-core.notesRef () - :class 'magit--git-variable - :variable "core.notesRef" - :reader 'magit-notes-read-ref - :prompt "Set local core.notesRef") - -(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") - -(transient-define-infix magit-global-core.notesRef () - :class 'magit--git-variable - :variable "core.notesRef" - :reader 'magit-notes-read-ref - :prompt "Set global core.notesRef") - -(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") - -(transient-define-argument magit-notes:--ref () - :description "Manipulate ref" - :class 'transient-option - :key "-r" - :argument "--ref=" - :reader 'magit-notes-read-ref) - -(transient-define-argument magit-notes:--strategy () - :description "Merge strategy" - :class 'transient-option - :shortarg "-s" - :argument "--strategy=" - :choices '("manual" "ours" "theirs" "union" "cat_sort_uniq")) - -(defun magit-notes-edit (commit &optional ref) - "Edit the note attached to COMMIT. -REF is the notes ref used to store the notes. - -Interactively or when optional REF is nil use the value of Git -variable `core.notesRef' or \"refs/notes/commits\" if that is -undefined." - (interactive (magit-notes-read-args "Edit notes")) - (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref)) - "edit" commit)) - -(defun magit-notes-remove (commit &optional ref) - "Remove the note attached to COMMIT. -REF is the notes ref from which the note is removed. - -Interactively or when optional REF is nil use the value of Git -variable `core.notesRef' or \"refs/notes/commits\" if that is -undefined." - (interactive (magit-notes-read-args "Remove notes")) - (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref)) - "remove" commit)) - -(defun magit-notes-merge (ref) - "Merge the notes ref REF into the current notes ref. - -The current notes ref is the value of Git variable -`core.notesRef' or \"refs/notes/commits\" if that is undefined. - -When there are conflicts, then they have to be resolved in the -temporary worktree \".git/NOTES_MERGE_WORKTREE\". When -done use `magit-notes-merge-commit' to finish. To abort -use `magit-notes-merge-abort'." - (interactive (list (magit-read-string-ns "Merge reference"))) - (magit-run-git-with-editor "notes" "merge" ref)) - -(defun magit-notes-merge-commit () - "Commit the current notes ref merge. -Also see `magit-notes-merge'." - (interactive) - (magit-run-git-with-editor "notes" "merge" "--commit")) - -(defun magit-notes-merge-abort () - "Abort the current notes ref merge. -Also see `magit-notes-merge'." - (interactive) - (magit-run-git-with-editor "notes" "merge" "--abort")) - -(defun magit-notes-prune (&optional dry-run) - "Remove notes about unreachable commits." - (interactive (list (and (member "--dry-run" (transient-args 'magit-notes)) t))) - (when dry-run - (magit-process-buffer)) - (magit-run-git-with-editor "notes" "prune" (and dry-run "--dry-run"))) - -;;; Readers - -(defun magit-notes-read-ref (prompt _initial-input history) - (--when-let (magit-completing-read - prompt (magit-list-notes-refnames) nil nil - (--when-let (magit-get "core.notesRef") - (if (string-prefix-p "refs/notes/" it) - (substring it 11) - it)) - history) - (if (string-prefix-p "refs/" it) - it - (concat "refs/notes/" it)))) - -(defun magit-notes-read-refs (prompt &optional _initial-input _history) - (mapcar (lambda (ref) - (if (string-prefix-p "refs/" ref) - ref - (concat "refs/notes/" ref))) - (completing-read-multiple - (concat prompt ": ") - (magit-list-notes-refnames) nil nil - (mapconcat (lambda (ref) - (if (string-prefix-p "refs/notes/" ref) - (substring ref 11) - ref)) - (magit-get-all "notes.displayRef") - ",")))) - -(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)))) - -;;; _ -(provide 'magit-notes) -;;; magit-notes.el ends here diff --git a/elpa/magit-20210802.1524/magit-obsolete.el b/elpa/magit-20210802.1524/magit-obsolete.el deleted file mode 100644 index f49f149b..00000000 --- a/elpa/magit-20210802.1524/magit-obsolete.el +++ /dev/null @@ -1,114 +0,0 @@ -;;; magit-obsolete.el --- obsolete definitions -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library defines aliases for obsolete variables and functions. - -;;; Code: - -(require 'magit) - -;;; Obsolete since v3.0.0 - -(define-obsolete-function-alias 'magit-diff-visit-file-worktree - 'magit-diff-visit-worktree-file "Magit 3.0.0") - -(define-obsolete-function-alias 'magit-status-internal - 'magit-status-setup-buffer "Magit 3.0.0") - -(define-obsolete-variable-alias 'magit-mode-setup-hook - 'magit-setup-buffer-hook "Magit 3.0.0") - -(define-obsolete-variable-alias 'magit-branch-popup-show-variables - 'magit-branch-direct-configure "Magit 3.0.0") - -(define-obsolete-function-alias 'magit-dispatch-popup - 'magit-dispatch "Magit 3.0.0") - -(define-obsolete-function-alias 'magit-repolist-column-dirty - 'magit-repolist-column-flag "Magit 3.0.0") - -(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. -It now uses Transient. -See https://emacsair.me/2019/02/14/transient-0.1. - -However your configuration and/or some third-party package that -you use still depends on the `magit-popup' package. But because -`magit' no longer depends on that, `package' has removed it from -your system. - -If some package that you use still depends on `magit-popup' but -does not declare it as a dependency, then please contact its -maintainer about that and install `magit-popup' explicitly. - -If you yourself use functions that are defined in `magit-popup' -in your configuration, then the next step depends on what you use -that for. - -* If you use `magit-popup' to define your own popups but do not - modify any of Magit's old popups, then you have to install - `magit-popup' explicitly. (You can also migrate to Transient, - but there is no need to rush that.) - -* If you add additional arguments and/or actions to Magit's popups, - then you have to port that to modify the new \"transients\" instead. - See https://github.com/magit/magit/wiki/\ -Converting-popup-modifications-to-transient-modifications - -To find installed packages that still use `magit-popup' you can -use e.g. \"M-x rgrep RET magit-popup RET RET ~/.emacs.d/ RET\".")) -(cl-eval-when (eval load) - (unless (require (quote magit-popup) nil t) - (defun magit-define-popup-switch (&rest _) - (magit--magit-popup-warning)) - (defun magit-define-popup-option (&rest _) - (magit--magit-popup-warning)) - (defun magit-define-popup-variable (&rest _) - (magit--magit-popup-warning)) - (defun magit-define-popup-action (&rest _) - (magit--magit-popup-warning)) - (defun magit-define-popup-sequence-action (&rest _) - (magit--magit-popup-warning)) - (defun magit-define-popup-key (&rest _) - (magit--magit-popup-warning)) - (defun magit-define-popup-keys-deferred (&rest _) - (magit--magit-popup-warning)) - (defun magit-change-popup-key (&rest _) - (magit--magit-popup-warning)) - (defun magit-remove-popup-key (&rest _) - (magit--magit-popup-warning)))) - -;;; _ -(provide 'magit-obsolete) -;;; magit-obsolete.el ends here diff --git a/elpa/magit-20210802.1524/magit-patch.el b/elpa/magit-20210802.1524/magit-patch.el deleted file mode 100644 index c49e104b..00000000 --- a/elpa/magit-20210802.1524/magit-patch.el +++ /dev/null @@ -1,328 +0,0 @@ -;;; magit-patch.el --- creating and applying patches -*- lexical-binding: t -*- - -;; 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) -;; 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. - -;;; Commentary: - -;; This library implements patch commands. - -;;; Code: - -(require 'magit) - -;;; Options - -(defcustom magit-patch-save-arguments '(exclude "--stat") - "Control arguments used by the command `magit-patch-save'. - -`magit-patch-save' (which see) saves a diff for the changes -shown in the current buffer in a patch file. It may use the -same arguments as used in the buffer or a subset thereof, or -a constant list of arguments, depending on this option and -the prefix argument." - :package-version '(magit . "2.12.0") - :group 'magit-diff - :type '(choice (const :tag "use buffer arguments" buffer) - (cons :tag "use buffer arguments except" - (const :format "" exclude) - (repeat :format "%v%i\n" - (string :tag "Argument"))) - (repeat :tag "use constant arguments" - (string :tag "Argument")))) - -;;; Commands - -;;;###autoload (autoload 'magit-patch "magit-patch" nil t) -(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)]) - -;;;###autoload (autoload 'magit-patch-create "magit-patch" nil t) -(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' -which creates patches for all commits that are reachable from -`HEAD' but not from the specified commit)." - :man-page "git-format-patch" - :incompatible '(("--subject-prefix=" "--rfc")) - ["Mail arguments" - (6 magit-format-patch:--in-reply-to) - (6 magit-format-patch:--thread) - (6 magit-format-patch:--from) - (6 magit-format-patch:--to) - (6 magit-format-patch:--cc)] - ["Patch arguments" - (magit-format-patch:--base) - (magit-format-patch:--reroll-count) - (5 magit-format-patch:--interdiff) - (magit-format-patch:--range-diff) - (magit-format-patch:--subject-prefix) - ("C-m r " "RFC subject prefix" "--rfc") - ("C-m l " "Add cover letter" "--cover-letter") - (5 magit-format-patch:--cover-from-description) - (5 magit-format-patch:--notes) - (magit-format-patch:--output-directory)] - ["Diff arguments" - (magit-diff:-U) - (magit-diff:-M) - (magit-diff:-C) - (magit-diff:--diff-algorithm) - (magit:--) - (7 "-b" "Ignore whitespace changes" ("-b" "--ignore-space-change")) - (7 "-w" "Ignore all whitespace" ("-w" "--ignore-all-space"))] - ["Actions" - ("c" "Create patches" magit-patch-create)] - (interactive - (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)) - (let ((range (magit-read-range-or-commit - "Format range or commit"))) - (if (string-match-p "\\.\\." range) - range - (format "%s~..%s" range range)))) - (let ((args (transient-args 'magit-patch-create))) - (list (-filter #'stringp args) - (cdr (assoc "--" args))))))) - (if (not range) - (transient-setup 'magit-patch-create) - (magit-run-git "format-patch" range args "--" files) - (when (member "--cover-letter" args) - (save-match-data - (find-file - (expand-file-name - (concat (when-let ((v (transient-arg-value "--reroll-count=" args))) - (format "v%s-" v)) - "0000-cover-letter.patch") - (let ((topdir (magit-toplevel))) - (if-let ((dir (transient-arg-value "--output-directory=" args))) - (expand-file-name dir topdir) - topdir)))))))) - -(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=") - -(transient-define-argument magit-format-patch:--thread () - :description "Thread style" - :class 'transient-option - :key "C-m s " - :argument "--thread=" - :reader #'magit-format-patch-select-thread-style) - -(defun magit-format-patch-select-thread-style (&rest _ignore) - (magit-read-char-case "Thread style " t - (?d "[d]eep" "deep") - (?s "[s]hallow" "shallow"))) - -(transient-define-argument magit-format-patch:--base () - :description "Insert base commit" - :class 'transient-option - :key "C-m b " - :argument "--base=" - :reader #'magit-format-patch-select-base) - -(defun magit-format-patch-select-base (prompt initial-input history) - (or (magit-completing-read prompt (cons "auto" (magit-list-refnames)) - nil nil initial-input history "auto") - (user-error "Nothing selected"))) - -(transient-define-argument magit-format-patch:--reroll-count () - :description "Reroll count" - :class 'transient-option - :key "C-m v " - :shortarg "-v" - :argument "--reroll-count=" - :reader 'transient-read-number-N+) - -(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) - -(transient-define-argument magit-format-patch:--range-diff () - :description "Insert range-diff" - :class 'transient-option - :key "C-m d r" - :argument "--range-diff=" - :reader #'magit-format-patch-select-range-diff) - -(defun magit-format-patch-select-range-diff (prompt _initial-input _history) - (magit-read-range-or-commit prompt)) - -(transient-define-argument magit-format-patch:--subject-prefix () - :description "Subject Prefix" - :class 'transient-option - :key "C-m p " - :argument "--subject-prefix=") - -(transient-define-argument magit-format-patch:--cover-from-description () - :description "Use branch description" - :class 'transient-option - :key "C-m D " - :argument "--cover-from-description=" - :reader #'magit-format-patch-select-description-mode) - -(defun magit-format-patch-select-description-mode (&rest _ignore) - (magit-read-char-case "Use description as " t - (?m "[m]essage" "message") - (?s "[s]ubject" "subject") - (?a "[a]uto" "auto") - (?n "[n]othing" "none"))) - -(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) - -(transient-define-argument magit-format-patch:--from () - :description "From" - :class 'transient-option - :key "C-m C-f" - :argument "--from=" - :reader 'magit-transient-read-person) - -(transient-define-argument magit-format-patch:--to () - :description "To" - :class 'transient-option - :key "C-m C-t" - :argument "--to=" - :reader 'magit-transient-read-person) - -(transient-define-argument magit-format-patch:--cc () - :description "CC" - :class 'transient-option - :key "C-m C-c" - :argument "--cc=" - :reader 'magit-transient-read-person) - -(transient-define-argument magit-format-patch:--output-directory () - :description "Output directory" - :class 'transient-option - :key "C-m o " - :shortarg "-o" - :argument "--output-directory=" - :reader 'transient-read-existing-directory) - -;;;###autoload (autoload 'magit-patch-apply "magit-patch" nil t) -(transient-define-prefix magit-patch-apply (file &rest args) - "Apply the patch file FILE." - :man-page "git-apply" - ["Arguments" - ("-i" "Also apply to index" "--index") - ("-c" "Only apply to index" "--cached") - ("-3" "Fall back on 3way merge" ("-3" "--3way"))] - ["Actions" - ("a" "Apply patch" magit-patch-apply)] - (interactive - (if (not (eq transient-current-command 'magit-patch-apply)) - (list nil) - (list (expand-file-name - (read-file-name "Apply patch: " - default-directory nil nil - (when-let ((file (magit-file-at-point))) - (file-relative-name file)))) - (transient-args 'magit-patch-apply)))) - (if (not file) - (transient-setup 'magit-patch-apply) - (magit-run-git "apply" args "--" (magit-convert-filename-for-git file)))) - -;;;###autoload -(defun magit-patch-save (file &optional arg) - "Write current diff into patch FILE. - -What arguments are used to create the patch depends on the value -of `magit-patch-save-arguments' and whether a prefix argument is -used. - -If the value is the symbol `buffer', then use the same arguments -as the buffer. With a prefix argument use no arguments. - -If the value is a list beginning with the symbol `exclude', then -use the same arguments as the buffer except for those matched by -entries in the cdr of the list. The comparison is done using -`string-prefix-p'. With a prefix argument use the same arguments -as the buffer. - -If the value is a list of strings (including the empty list), -then use those arguments. With a prefix argument use the same -arguments as the buffer. - -Of course the arguments that are required to actually show the -same differences as those shown in the buffer are always used." - (interactive (list (read-file-name "Write patch file: " default-directory) - current-prefix-arg)) - (unless (derived-mode-p 'magit-diff-mode) - (user-error "Only diff buffers can be saved as patches")) - (let ((rev magit-buffer-range) - (typearg magit-buffer-typearg) - (args magit-buffer-diff-args) - (files magit-buffer-diff-files)) - (cond ((eq magit-patch-save-arguments 'buffer) - (when arg - (setq args nil))) - ((eq (car-safe magit-patch-save-arguments) 'exclude) - (unless arg - (setq args (-difference args (cdr magit-patch-save-arguments))))) - ((not arg) - (setq args magit-patch-save-arguments))) - (with-temp-file file - (magit-git-insert "diff" rev "-p" typearg args "--" files))) - (magit-refresh)) - -;;;###autoload -(defun magit-request-pull (url start end) - "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. -END is the last commit, usually a branch name, which upstream -is asked to pull. START has to be reachable from that commit." - (interactive - (list (magit-get "remote" (magit-read-remote "Remote") "url") - (magit-read-branch-or-commit "Start" (magit-get-upstream-branch)) - (magit-read-branch-or-commit "End"))) - (let ((dir default-directory)) - ;; mu4e changes default-directory - (compose-mail) - (setq default-directory dir)) - (message-goto-body) - (magit-git-insert "request-pull" start url end) - (set-buffer-modified-p nil)) - -;;; _ -(provide 'magit-patch) -;;; magit-patch.el ends here diff --git a/elpa/magit-20210802.1524/magit-pkg.el b/elpa/magit-20210802.1524/magit-pkg.el deleted file mode 100644 index 9c98e797..00000000 --- a/elpa/magit-20210802.1524/magit-pkg.el +++ /dev/null @@ -1,18 +0,0 @@ -(define-package "magit" "20210802.1524" "A Git porcelain inside Emacs." - '((emacs "25.1") - (dash "20210330") - (git-commit "20210801") - (magit-section "20210801") - (transient "20210701") - (with-editor "20210524")) - :commit "7b46191dedba053f1c44d5f13d4283860e26cbd6" :authors - '(("Marius Vollmer" . "marius.vollmer@gmail.com") - ("Jonas Bernoulli" . "jonas@bernoul.li")) - :maintainer - '("Jonas Bernoulli" . "jonas@bernoul.li") - :keywords - '("git" "tools" "vc") - :url "https://github.com/magit/magit") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/elpa/magit-20210802.1524/magit-process.el b/elpa/magit-20210802.1524/magit-process.el deleted file mode 100644 index 7fef19fd..00000000 --- a/elpa/magit-20210802.1524/magit-process.el +++ /dev/null @@ -1,1224 +0,0 @@ -;;; magit-process.el --- process functionality -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements the tools used to run Git for side-effects. - -;; Note that the functions used to run Git and then consume its -;; output, are defined in `magit-git.el'. There's a bit of overlap -;; though. - -;;; Code: - -(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)) - -;;; Options - -(defcustom magit-process-connection-type (not (eq system-type 'cygwin)) - "Connection type used for the Git process. - -If nil, use pipes: this is usually more efficient, and works on Cygwin. -If t, use ptys: this enables Magit to prompt for passphrases when needed." - :group 'magit-process - :type '(choice (const :tag "pipe" nil) - (const :tag "pty" t))) - -(defcustom magit-need-cygwin-noglob - (and (eq system-type 'windows-nt) - (with-temp-buffer - (let ((process-environment - (append magit-git-environment process-environment))) - (condition-case e - (process-file magit-git-executable - nil (current-buffer) nil - "-c" "alias.echo=!echo" "echo" "x{0}") - (file-error - (lwarn 'magit-process :warning - "Could not run Git: %S" e)))) - (equal "x0\n" (buffer-string)))) - "Whether to use a workaround for Cygwin's globbing behavior. - -If non-nil, add environment variables to `process-environment' to -prevent the git.exe distributed by Cygwin and MSYS2 from -attempting to perform glob expansion when called from a native -Windows build of Emacs. See #2246." - :package-version '(magit . "2.3.0") - :group 'magit-process - :type '(choice (const :tag "Yes" t) - (const :tag "No" nil))) - -(defcustom magit-process-popup-time -1 - "Popup the process buffer if a command takes longer than this many seconds." - :group 'magit-process - :type '(choice (const :tag "Never" -1) - (const :tag "Immediately" 0) - (integer :tag "After this many seconds"))) - -(defcustom magit-process-log-max 32 - "Maximum number of sections to keep in a process log buffer. -When adding a new section would go beyond the limit set here, -then the older half of the sections are remove. Sections that -belong to processes that are still running are never removed. -When this is nil, no sections are ever removed." - :package-version '(magit . "2.1.0") - :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 *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.") - -(defcustom magit-process-error-tooltip-max-lines 20 - "The number of lines for `magit-process-error-lines' to return. - -These are displayed in a tooltip for `mode-line-process' errors. - -If `magit-process-error-tooltip-max-lines' is nil, the tooltip -displays the text of `magit-process-error-summary' instead." - :package-version '(magit . "2.12.0") - :group 'magit-process - :type '(choice (const :tag "Use summary line" nil) - integer)) - -(defcustom magit-credential-cache-daemon-socket - (--some (pcase-let ((`(,prog . ,args) (split-string it))) - (if (and prog - (string-match-p - "\\`\\(?:\\(?:/.*/\\)?git-credential-\\)?cache\\'" prog)) - (or (cl-loop for (opt val) on args - if (string= opt "--socket") - return val) - (expand-file-name "~/.git-credential-cache/socket")))) - ;; Note: `magit-process-file' is not yet defined when - ;; evaluating this form, so we use `process-lines'. - (ignore-errors - (let ((process-environment - (append magit-git-environment process-environment))) - (process-lines magit-git-executable - "config" "--get-all" "credential.helper")))) - "If non-nil, start a credential cache daemon using this socket. - -When using Git's cache credential helper in the normal way, Emacs -sends a SIGHUP to the credential daemon after the git subprocess -has exited, causing the daemon to also quit. This can be avoided -by starting the `git-credential-cache--daemon' process directly -from Emacs. - -The function `magit-maybe-start-credential-cache-daemon' takes -care of starting the daemon if necessary, using the value of this -option as the socket. If this option is nil, then it does not -start any daemon. Likewise if another daemon is already running, -then it starts no new daemon. This function has to be a member -of the hook variable `magit-credential-hook' for this to work. -If an error occurs while starting the daemon, most likely because -the necessary executable is missing, then the function removes -itself from the hook, to avoid further futile attempts." - :package-version '(magit . "2.3.0") - :group 'magit-process - :type '(choice (file :tag "Socket") - (const :tag "Don't start a cache daemon" nil))) - -(defcustom magit-process-yes-or-no-prompt-regexp - (concat " [\[(]" - "\\([Yy]\\(?:es\\)?\\)" - "[/|]" - "\\([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 - :type 'regexp) - -(defcustom magit-process-password-prompt-regexps - '("^\\(Enter \\)?[Pp]assphrase\\( for \\(RSA \\)?key '.*'\\)?: ?$" - ;; Match-group 99 is used to identify the "user@host" part. - "^\\(Enter \\)?[Pp]assword\\( for '?\\(https?://\\)?\\(?99:[^']*\\)'?\\)?: ?$" - "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 . "3.0.0") - :group 'magit-process - :type '(repeat (regexp))) - -(defcustom magit-process-find-password-functions nil - "List of functions to try in sequence to get a password. - -These functions may be called when git asks for a password, which -is detected using `magit-process-password-prompt-regexps'. They -are called if and only if matching the prompt resulted in the -value of the 99th submatch to be non-nil. Therefore users can -control for which prompts these functions should be called by -putting the host name in the 99th submatch, or not. - -If the functions are called, then they are called in the order -given, with the host name as only argument, until one of them -returns non-nil. If they are not called or none of them returns -non-nil, then the password is read from the user instead." - :package-version '(magit . "2.3.0") - :group 'magit-process - :type 'hook - :options '(magit-process-password-auth-source)) - -(defcustom magit-process-username-prompt-regexps - '("^Username for '.*': ?$") - "List of regexps matching username prompts of Git and its subprocesses." - :package-version '(magit . "2.1.0") - :group 'magit-process - :type '(repeat (regexp))) - -(defcustom magit-process-prompt-functions nil - "List of functions used to forward arbitrary questions to the user. - -Magit has dedicated support for forwarding username and password -prompts and Yes-or-No questions asked by Git and its subprocesses -to the user. This can be customized using other options in the -`magit-process' customization group. - -If you encounter a new question that isn't handled by default, -then those options should be used instead of this hook. - -However subprocesses may also ask questions that differ too much -from what the code related to the above options assume, and this -hook allows users to deal with such questions explicitly. - -Each function is called with the process and the output string -as arguments until one of the functions returns non-nil. The -function is responsible for asking the user the appropriate -question using e.g. `read-char-choice' and then forwarding the -answer to the process using `process-send-string'. - -While functions such as `magit-process-yes-or-no-prompt' may not -be sufficient to handle some prompt, it may still be of benefit -to look at the implementations to gain some insights on how to -implement such functions." - :package-version '(magit . "3.0.0") - :group 'magit-process - :type 'hook) - -(defcustom magit-process-ensure-unix-line-ending t - "Whether Magit should ensure a unix coding system when talking to Git." - :package-version '(magit . "2.6.0") - :group 'magit-process - :type 'boolean) - -(defcustom magit-process-display-mode-line-error t - "Whether Magit should retain and highlight process errors in the mode line." - :package-version '(magit . "2.12.0") - :group 'magit-process - :type 'boolean) - -(defface magit-process-ok - '((t :inherit magit-section-heading :foreground "green")) - "Face for zero exit-status." - :group 'magit-faces) - -(defface magit-process-ng - '((t :inherit magit-section-heading :foreground "red")) - "Face for non-zero exit-status." - :group 'magit-faces) - -(defface magit-mode-line-process - '((t :inherit mode-line-emphasis)) - "Face for `mode-line-process' status when Git is running for side-effects." - :group 'magit-faces) - -(defface magit-mode-line-process-error - '((t :inherit error)) - "Face for `mode-line-process' error status. - -Used when `magit-process-display-mode-line-error' is non-nil." - :group 'magit-faces) - -;;; Process Mode - -(defvar magit-process-mode-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map magit-mode-map) - map) - "Keymap for `magit-process-mode'.") - -(define-derived-mode magit-process-mode magit-mode "Magit Process" - "Mode for looking at Git process output." - :group 'magit-process - (hack-dir-local-variables-non-file-buffer) - (setq imenu-prev-index-position-function - 'magit-imenu--process-prev-index-position-function) - (setq imenu-extract-index-name-function - 'magit-imenu--process-extract-index-name-function)) - -(defun magit-process-buffer (&optional nodisplay) - "Display the current repository's process buffer. - -If that buffer doesn't exist yet, then create it. -Non-interactively return the buffer and unless -optional NODISPLAY is non-nil also display it." - (interactive) - (let ((topdir (magit-toplevel))) - (unless topdir - (magit--with-safe-default-directory nil - (setq topdir default-directory) - (let (prev) - (while (not (equal topdir prev)) - (setq prev topdir) - (setq topdir (file-name-directory (directory-file-name topdir))))))) - (let ((buffer (or (--first (with-current-buffer it - (and (eq major-mode 'magit-process-mode) - (equal default-directory topdir))) - (buffer-list)) - (let ((default-directory topdir)) - (magit-generate-new-buffer 'magit-process-mode))))) - (with-current-buffer buffer - (if magit-root-section - (when magit-process-log-max - (magit-process-truncate-log)) - (magit-process-mode) - (let ((inhibit-read-only t) - (magit-insert-section--parent nil) - (magit-insert-section--oldroot nil)) - (make-local-variable 'text-property-default-nonsticky) - (magit-insert-section (processbuf) - (insert "\n"))))) - (unless nodisplay - (magit-display-buffer buffer)) - buffer))) - -(defun magit-process-kill () - "Kill the process at point." - (interactive) - (when-let ((process (magit-section-value-if 'process))) - (unless (eq (process-status process) 'run) - (user-error "Process isn't running")) - (magit-confirm 'kill-process) - (kill-process process))) - -;;; Synchronous Processes - -(defvar magit-process-raise-error nil) - -(defun magit-git (&rest args) - "Call Git synchronously in a separate process, for side-effects. - -Option `magit-git-executable' specifies the Git executable. -The arguments ARGS specify arguments to Git, they are flattened -before use. - -Process output goes into a new section in the buffer returned by -`magit-process-buffer'. If Git exits with a non-zero status, -then raise an error." - (let ((magit-process-raise-error t)) - (magit-call-git args))) - -(defun magit-run-git (&rest args) - "Call Git synchronously in a separate process, and refresh. - -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. - -After Git returns, the current buffer (if it is a Magit buffer) -as well as the current repository's status buffer are refreshed. - -Process output goes into a new section in the buffer returned by -`magit-process-buffer'." - (let ((magit--refresh-cache (list (cons 0 0)))) - (magit-call-git args) - (when (member (car args) '("init" "clone")) - ;; Creating a new repository invalidates the cache. - (setq magit--refresh-cache nil)) - (magit-refresh))) - -(defvar magit-pre-call-git-hook nil) - -(defun magit-call-git (&rest args) - "Call Git synchronously in a separate process. - -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. - -Process output goes into a new section in the buffer returned by -`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) - (magit-process-git-arguments args)))) - -(defun magit-call-process (program &rest args) - "Call PROGRAM synchronously in a separate process. -Process output goes into a new section in the buffer returned by -`magit-process-buffer'." - (pcase-let ((`(,process-buf . ,section) - (magit-process-setup program args))) - (magit-process-finish - (let ((inhibit-read-only t)) - (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))) - -(defun magit-process-environment () - ;; The various w32 hacks are only applicable when running on the - ;; local machine. As of Emacs 25.1, a local binding of - ;; process-environment different from the top-level value affects - ;; the environment used in - ;; tramp-sh-handle-{start-file-process,process-file}. - (let ((local (not (file-remote-p default-directory)))) - (append magit-git-environment - (and local - (cdr (assoc magit-git-executable magit-git-w32-path-hack))) - (and local magit-need-cygwin-noglob - (mapcar (lambda (var) - (concat var "=" (--if-let (getenv var) - (concat it " noglob") - "noglob"))) - '("CYGWIN" "MSYS"))) - process-environment))) - -(defvar magit-this-process nil) - -(defun magit-run-git-with-input (&rest args) - "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's standard -input. The buffer is assumed to be temporary and thus OK to -modify. - -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." - (when (eq system-type 'windows-nt) - ;; On w32, git expects UTF-8 encoded input, ignore any user - ;; configuration telling us otherwise (see #3250). - (encode-coding-region (point-min) (point-max) 'utf-8-unix)) - (if (file-remote-p default-directory) - ;; We lack `process-file-region', so fall back to asynch + - ;; waiting in remote case. - (progn - (magit-start-git (current-buffer) args) - (while (and magit-this-process - (eq (process-status magit-this-process) 'run)) - (sleep-for 0.005))) - (run-hooks 'magit-pre-call-git-hook) - (pcase-let* ((process-environment (magit-process-environment)) - (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)) - (inhibit-read-only t)) - (magit-process-finish - (apply #'call-process-region (point-min) (point-max) - (magit-git-executable) nil process-buf nil flat-args) - process-buf nil default-directory section)))) - -;;; Asynchronous Processes - -(defun magit-run-git-async (&rest args) - "Start Git, prepare for refresh, and return the process object. -ARGS is flattened and then used as arguments to Git. - -Display the command line arguments in the echo area. - -After Git returns some buffers are refreshed: the buffer that was -current when this function was called (if it is a Magit buffer -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) - (let ((m (mapconcat #'identity (-flatten args) " "))) - (remove-list-of-text-properties 0 (length m) '(face) m) - m)) - (magit-start-git nil args)) - -(defun magit-run-git-with-editor (&rest args) - "Export GIT_EDITOR and start Git. -Also prepare for refresh and return the process object. -ARGS is flattened and then used as arguments to Git. - -Display the command line arguments in the echo area. - -After Git returns some buffers are refreshed: the buffer that was -current when this function was called (if it is a Magit buffer -and still alive), as well as the respective Magit status buffer. - -See `magit-start-process' and `with-editor' for more information." - (magit--record-separated-gitdir) - (magit-with-editor (magit-run-git-async args))) - -(defun magit-run-git-sequencer (&rest args) - "Export GIT_EDITOR and start Git. -Also prepare for refresh and return the process object. -ARGS is flattened and then used as arguments to Git. - -Display the command line arguments in the echo area. - -After Git returns some buffers are refreshed: the buffer that was -current when this function was called (if it is a Magit buffer -and still alive), as well as the respective Magit status buffer. -If the sequence stops at a commit, make the section representing -that commit the current section by moving `point' there. - -See `magit-start-process' and `with-editor' for more information." - (apply #'magit-run-git-with-editor args) - (set-process-sentinel magit-this-process #'magit-sequencer-process-sentinel) - magit-this-process) - -(defvar magit-pre-start-git-hook nil) - -(defun magit-start-git (input &rest args) - "Start Git, prepare for refresh, and return the process object. - -If INPUT is non-nil, it has to be a buffer or the name of an -existing buffer. The buffer content becomes the processes -standard input. - -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. - -After Git returns some buffers are refreshed: the buffer that was -current when this function was called (if it is a Magit buffer -and still alive), as well as the respective Magit status buffer. - -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 - (magit-process-git-arguments args)))) - -(defun magit-start-process (program &optional input &rest args) - "Start PROGRAM, prepare for refresh, and return the process object. - -If optional argument INPUT is non-nil, it has to be a buffer or -the name of an existing buffer. The buffer content becomes the -processes standard input. - -The process is started using `start-file-process' and then setup -to use the sentinel `magit-process-sentinel' and the filter -`magit-process-filter'. Information required by these functions -is stored in the process object. When this function returns the -process has not started to run yet so it is possible to override -the sentinel and filter. - -After the process returns, `magit-process-sentinel' refreshes the -buffer that was current when `magit-start-process' was called (if -it is a Magit buffer and still alive), as well as the respective -Magit status buffer." - (pcase-let* - ((`(,process-buf . ,section) - (magit-process-setup program args)) - (process - (let ((process-connection-type - ;; Don't use a pty, because it would set icrnl - ;; which would modify the input (issue #20). - (and (not input) magit-process-connection-type)) - (process-environment (magit-process-environment)) - (default-process-coding-system (magit--process-coding-system))) - (apply #'start-file-process - (file-name-nondirectory program) - process-buf program args)))) - (with-editor-set-process-filter process #'magit-process-filter) - (set-process-sentinel process #'magit-process-sentinel) - (set-process-buffer process process-buf) - (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 nil 'utf-8-unix)) - (process-put process 'section section) - (process-put process 'command-buf (current-buffer)) - (process-put process 'default-dir default-directory) - (when magit-inhibit-refresh - (process-put process 'inhibit-refresh t)) - (oset section process process) - (with-current-buffer process-buf - (set-marker (process-mark process) (point))) - (when input - (with-current-buffer input - (process-send-region process (point-min) (point-max)) - (process-send-eof process))) - (setq magit-this-process process) - (oset section value process) - (magit-process-display-buffer process) - process)) - -(defun magit-parse-git-async (&rest args) - (setq args (magit-process-git-arguments args)) - (let ((command-buf (current-buffer)) - (process-buf (generate-new-buffer " *temp*")) - (toplevel (magit-toplevel))) - (with-current-buffer process-buf - (setq default-directory toplevel) - (let ((process - (let ((process-connection-type nil) - (process-environment (magit-process-environment)) - (default-process-coding-system - (magit--process-coding-system))) - (apply #'start-file-process "git" process-buf - (magit-git-executable) args)))) - (process-put process 'command-buf command-buf) - (process-put process 'parsed (point)) - (setq magit-this-process process) - process)))) - -;;; Process Internals - -(defun magit-process-setup (program args) - (magit-process-set-mode-line program args) - (let ((pwd default-directory) - (buf (magit-process-buffer t))) - (cons buf (with-current-buffer buf - (prog1 (magit-process-insert-section pwd program args nil nil) - (backward-char 1)))))) - -(defun magit-process-insert-section (pwd program args &optional errcode errlog) - (let ((inhibit-read-only t) - (magit-insert-section--parent magit-root-section) - (magit-insert-section--oldroot nil)) - (goto-char (1- (point-max))) - (magit-insert-section (process) - (insert (if errcode - (format "%3s " (propertize (number-to-string errcode) - 'font-lock-face 'magit-process-ng)) - "run ")) - (unless (equal (expand-file-name pwd) - (expand-file-name default-directory)) - (insert (file-relative-name pwd default-directory) ?\s)) - (insert (magit-process--format-arguments program args)) - (magit-insert-heading) - (when errlog - (if (bufferp errlog) - (insert (with-current-buffer errlog - (buffer-substring-no-properties (point-min) (point-max)))) - (insert-file-contents errlog) - (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)) - (count (length tail))) - (when (> (1+ count) magit-process-log-max) - (while (and (cdr tail) - (> count (/ magit-process-log-max 2))) - (let* ((inhibit-read-only t) - (section (car tail)) - (process (oref section process))) - (cond ((not process)) - ((memq (process-status process) '(exit signal)) - (delete-region (oref section start) - (1+ (oref section end))) - (cl-decf count)) - (t - (push section head)))) - (pop tail)) - (oset magit-root-section children - (nconc (reverse head) tail))))) - -(defun magit-process-sentinel (process event) - "Default sentinel used by `magit-start-process'." - (when (memq (process-status process) '(exit signal)) - (setq event (substring event 0 -1)) - (when (string-match "^finished" event) - (message (concat (capitalize (process-name process)) " finished"))) - (magit-process-finish process) - (when (eq process magit-this-process) - (setq magit-this-process nil)) - (unless (process-get process 'inhibit-refresh) - (let ((command-buf (process-get process 'command-buf))) - (if (buffer-live-p command-buf) - (with-current-buffer command-buf - (magit-refresh)) - (with-temp-buffer - (setq default-directory (process-get process 'default-dir)) - (magit-refresh))))))) - -(defun magit-sequencer-process-sentinel (process event) - "Special sentinel used by `magit-run-git-sequencer'." - (when (memq (process-status process) '(exit signal)) - (magit-process-sentinel process event) - (when-let ((process-buf (process-buffer process))) - (when (buffer-live-p process-buf) - (when-let ((status-buf (with-current-buffer process-buf - (magit-get-mode-buffer 'magit-status-mode)))) - (with-current-buffer status-buf - (--when-let - (magit-get-section - `((commit . ,(magit-rev-parse "HEAD")) - (,(pcase (car (cadr (-split-at - (1+ (length magit-git-global-arguments)) - (process-command process)))) - ((or "rebase" "am") 'rebase-sequence) - ((or "cherry-pick" "revert") 'sequence))) - (status))) - (goto-char (oref it start)) - (magit-section-update-highlight)))))))) - -(defun magit-process-filter (proc string) - "Default filter used by `magit-start-process'." - (with-current-buffer (process-buffer proc) - (let ((inhibit-read-only t)) - (goto-char (process-mark proc)) - ;; Find last ^M in string. If one was found, ignore - ;; everything before it and delete the current line. - (when-let ((ret-pos (cl-position ?\r string :from-end t))) - (cl-callf substring string (1+ ret-pos)) - (delete-region (line-beginning-position) (point))) - (insert (propertize string 'magit-section - (process-get proc 'section))) - (set-marker (process-mark proc) (point)) - ;; Make sure prompts are matched after removing ^M. - (magit-process-yes-or-no-prompt proc string) - (magit-process-username-prompt proc string) - (magit-process-password-prompt proc string) - (run-hook-with-args-until-success 'magit-process-prompt-functions - proc string)))) - -(defmacro magit-process-kill-on-abort (proc &rest body) - (declare (indent 1) (debug (form body))) - (let ((map (cl-gensym))) - `(let ((,map (make-sparse-keymap))) - (set-keymap-parent ,map minibuffer-local-map) - (define-key ,map "\C-g" - (lambda () - (interactive) - (ignore-errors (kill-process ,proc)) - (abort-recursive-edit))) - (let ((minibuffer-local-map ,map)) - ,@body)))) - -(defun magit-process-yes-or-no-prompt (process string) - "Forward Yes-or-No prompts to the user." - (when-let ((beg (string-match magit-process-yes-or-no-prompt-regexp string))) - (let ((max-mini-window-height 30)) - (process-send-string - process - (downcase - (concat - (match-string - (if (save-match-data - (magit-process-kill-on-abort process - (yes-or-no-p (substring string 0 beg)))) 1 2) - string) - "\n")))))) - -(defun magit-process-password-auth-source (key) - "Use `auth-source-search' to get a password. -If found, return the password. Otherwise, return nil. - -To use this function add it to the appropriate hook - (add-hook 'magit-process-find-password-functions - 'magit-process-password-auth-source) - -KEY typically derives from a prompt such as: - Password for 'https://yourname@github.com' -in which case it would be the string - yourname@github.com -which matches the ~/.authinfo.gpg entry - machine github.com login yourname password 12345 -or iff that is undefined, for backward compatibility - 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)) - (host (match-string 2 key)) - (secret - (plist-get - (car (or (auth-source-search :max 1 :host host :user user) - (auth-source-search :max 1 :host key))) - :secret))) - (if (functionp secret) - (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 -from the user." - (when-let ((prompt (magit-process-match-prompt - magit-process-password-prompt-regexps string))) - (process-send-string - process (magit-process-kill-on-abort process - (concat (or (when-let ((key (match-string 99 string))) - (run-hook-with-args-until-success - 'magit-process-find-password-functions key)) - (read-passwd prompt)) - "\n"))))) - -(defun magit-process-username-prompt (process string) - "Forward username prompts to the user." - (--when-let (magit-process-match-prompt - magit-process-username-prompt-regexps string) - (process-send-string - process (magit-process-kill-on-abort process - (concat (read-string it nil nil (user-login-name)) "\n"))))) - -(defun magit-process-match-prompt (prompts string) - "Match STRING against PROMPTS and set match data. -Return the matched string suffixed with \": \", if needed." - (when (--any-p (string-match it string) prompts) - (let ((prompt (match-string 0 string))) - (cond ((string-suffix-p ": " prompt) prompt) - ((string-suffix-p ":" prompt) (concat prompt " ")) - (t (concat prompt ": ")))))) - -(defun magit--process-coding-system () - (let ((fro (or magit-git-output-coding-system - (car default-process-coding-system))) - (to (cdr default-process-coding-system))) - (if magit-process-ensure-unix-line-ending - (cons (coding-system-change-eol-conversion fro 'unix) - (coding-system-change-eol-conversion to 'unix)) - (cons fro to)))) - -(defvar magit-credential-hook nil - "Hook run before Git needs credentials.") - -(defvar magit-credential-cache-daemon-process nil) - -(defun magit-maybe-start-credential-cache-daemon () - "Maybe start a `git-credential-cache--daemon' process. - -If such a process is already running or if the value of option -`magit-credential-cache-daemon-socket' is nil, then do nothing. -Otherwise start the process passing the value of that options -as argument." - (unless (or (not magit-credential-cache-daemon-socket) - (process-live-p magit-credential-cache-daemon-process) - (memq magit-credential-cache-daemon-process - (list-system-processes))) - (setq magit-credential-cache-daemon-process - (or (--first (let* ((attr (process-attributes it)) - (comm (cdr (assq 'comm attr))) - (user (cdr (assq 'user attr)))) - (and (string= comm "git-credential-cache--daemon") - (string= user user-login-name))) - (list-system-processes)) - (condition-case nil - (start-process "git-credential-cache--daemon" - " *git-credential-cache--daemon*" - (magit-git-executable) - "credential-cache--daemon" - magit-credential-cache-daemon-socket) - ;; Some Git implementations (e.g. Windows) won't have - ;; this program; if we fail the first time, stop trying. - ((debug error) - (remove-hook 'magit-credential-hook - #'magit-maybe-start-credential-cache-daemon))))))) - -(add-hook 'magit-credential-hook #'magit-maybe-start-credential-cache-daemon) - -(defun tramp-sh-handle-start-file-process--magit-tramp-process-environment - (fn name buffer program &rest args) - (if magit-tramp-process-environment - (apply fn name buffer - (car magit-tramp-process-environment) - (append (cdr magit-tramp-process-environment) - (cons program args))) - (apply fn name buffer program args))) - -(advice-add 'tramp-sh-handle-start-file-process :around - 'tramp-sh-handle-start-file-process--magit-tramp-process-environment) - -(defun tramp-sh-handle-process-file--magit-tramp-process-environment - (fn program &optional infile destination display &rest args) - (if magit-tramp-process-environment - (apply fn "env" infile destination display - (append magit-tramp-process-environment - (cons program args))) - (apply fn program infile destination display args))) - -(advice-add 'tramp-sh-handle-process-file :around - 'tramp-sh-handle-process-file--magit-tramp-process-environment) - -(defvar magit-mode-line-process-map - (let ((map (make-sparse-keymap))) - (define-key map (kbd " ") - 'magit-process-buffer) - map) - "Keymap for `mode-line-process'.") - -(defun magit-process-set-mode-line (program args) - "Display the git command (sans arguments) in the mode line." - (when (equal program (magit-git-executable)) - (setq args (nthcdr (length magit-git-global-arguments) args))) - (let ((str (concat " " (propertize - (concat (file-name-nondirectory program) - (and args (concat " " (car args)))) - 'mouse-face 'highlight - 'keymap magit-mode-line-process-map - 'help-echo "mouse-1: Show process buffer" - 'font-lock-face 'magit-mode-line-process)))) - (magit-repository-local-set 'mode-line-process str) - (dolist (buf (magit-mode-get-buffers)) - (with-current-buffer buf - (setq mode-line-process str))) - (force-mode-line-update t))) - -(defun magit-process-set-mode-line-error-status (&optional error str) - "Apply an error face to the string set by `magit-process-set-mode-line'. - -If ERROR is supplied, include it in the `mode-line-process' tooltip. - -If STR is supplied, it replaces the `mode-line-process' text." - (setq str (or str (magit-repository-local-get 'mode-line-process))) - (when str - (setq error (format "%smouse-1: Show process buffer" - (if (stringp error) - (concat error "\n\n") - ""))) - (setq str (concat " " (propertize - (substring-no-properties str 1) - 'mouse-face 'highlight - 'keymap magit-mode-line-process-map - 'help-echo error - 'font-lock-face 'magit-mode-line-process-error))) - (magit-repository-local-set 'mode-line-process str) - (dolist (buf (magit-mode-get-buffers)) - (with-current-buffer buf - (setq mode-line-process str))) - (force-mode-line-update t) - ;; We remove any error status from the mode line when a magit - ;; buffer is refreshed (see `magit-refresh-buffer'), but we must - ;; ensure that we ignore any refreshes during the remainder of the - ;; current command -- otherwise a newly-set error status would be - ;; removed before it was seen. We set a flag which prevents the - ;; status from being removed prior to the next command, so that - ;; the error status is guaranteed to remain visible until then. - (let ((repokey (magit-repository-local-repository))) - ;; 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-hook 'pre-command-hook - #'enable-magit-process-unset-mode-line) - ;; Clear the inhibit flag for the repository in - ;; which we set it. - (magit-repository-local-set - 'inhibit-magit-process-unset-mode-line nil repokey))) - ;; Set the inhibit flag until the next command is invoked. - (magit-repository-local-set - 'inhibit-magit-process-unset-mode-line t repokey) - (add-hook 'pre-command-hook - #'enable-magit-process-unset-mode-line))))) - -(defun magit-process-unset-mode-line-error-status () - "Remove any current error status from the mode line." - (let ((status (or mode-line-process - (magit-repository-local-get 'mode-line-process)))) - (when (and status - (eq (get-text-property 1 'font-lock-face status) - 'magit-mode-line-process-error)) - (magit-process-unset-mode-line)))) - -(defun magit-process-unset-mode-line (&optional directory) - "Remove the git command from the mode line." - (let ((default-directory (or directory default-directory))) - (unless (magit-repository-local-get 'inhibit-magit-process-unset-mode-line) - (magit-repository-local-set 'mode-line-process nil) - (dolist (buf (magit-mode-get-buffers)) - (with-current-buffer buf (setq mode-line-process nil))) - (force-mode-line-update t)))) - -(defvar magit-process-error-message-regexps - (list "^\\*ERROR\\*: Canceled by user$" - "^\\(?:error\\|fatal\\|git\\): \\(.*\\)$" - "^\\(Cannot rebase:.*\\)$")) - -(define-error 'magit-git-error "Git error") - -(defun magit-process-error-summary (process-buf section) - "A one-line error summary from the given SECTION." - (or (and (buffer-live-p process-buf) - (with-current-buffer process-buf - (and (oref section content) - (save-excursion - (goto-char (oref section end)) - (run-hook-wrapped - 'magit-process-error-message-regexps - (lambda (re) - (save-excursion - (and (re-search-backward - re (oref section start) t) - (or (match-string-no-properties 1) - (and (not magit-process-raise-error) - 'suppressed)))))))))) - "Git failed")) - -(defun magit-process-error-tooltip (process-buf section) - "Returns the text from SECTION of the PROCESS-BUF buffer. - -Limited by `magit-process-error-tooltip-max-lines'." - (and (integerp magit-process-error-tooltip-max-lines) - (> magit-process-error-tooltip-max-lines 0) - (buffer-live-p process-buf) - (with-current-buffer process-buf - (save-excursion - (goto-char (or (oref section content) - (oref section start))) - (buffer-substring-no-properties - (point) - (save-excursion - (forward-line magit-process-error-tooltip-max-lines) - (goto-char - (if (> (point) (oref section end)) - (oref section end) - (point))) - ;; Remove any trailing whitespace. - (when (re-search-backward "[^[:space:]\n]" - (oref section start) t) - (forward-char 1)) - (point))))))) - -(defvar-local magit-this-error nil) - -(defvar magit-process-finish-apply-ansi-colors nil) - -(defun magit-process-finish (arg &optional process-buf command-buf - default-dir section) - (unless (integerp arg) - (setq process-buf (process-buffer arg)) - (setq command-buf (process-get arg 'command-buf)) - (setq default-dir (process-get arg 'default-dir)) - (setq section (process-get arg 'section)) - (setq arg (process-exit-status arg))) - (when (fboundp 'dired-uncache) - (dired-uncache default-dir)) - (when (buffer-live-p process-buf) - (with-current-buffer process-buf - (let ((inhibit-read-only t) - (marker (oref section start))) - (goto-char marker) - (save-excursion - (delete-char 3) - (set-marker-insertion-type marker nil) - (insert (propertize (format "%3s" arg) - 'magit-section section - 'font-lock-face (if (= arg 0) - 'magit-process-ok - 'magit-process-ng))) - (set-marker-insertion-type marker t)) - (when magit-process-finish-apply-ansi-colors - (ansi-color-apply-on-region (oref section content) - (oref section end))) - (if (= (oref section end) - (+ (line-end-position) 2)) - (save-excursion - (goto-char (1+ (line-end-position))) - (delete-char -1) - (oset section content nil)) - (let ((buf (magit-process-buffer t))) - (when (and (= arg 0) - (not (--any-p (eq (window-buffer it) buf) - (window-list)))) - (magit-section-hide section))))))) - (if (= arg 0) - ;; Unset the `mode-line-process' value upon success. - (magit-process-unset-mode-line default-dir) - ;; Otherwise process the error. - (let ((msg (magit-process-error-summary process-buf section))) - ;; Change `mode-line-process' to an error face upon failure. - (if magit-process-display-mode-line-error - (magit-process-set-mode-line-error-status - (or (magit-process-error-tooltip process-buf section) - msg)) - (magit-process-unset-mode-line default-dir)) - ;; Either signal the error, or else display the error summary in - ;; the status buffer and with a message in the echo area. - (cond - (magit-process-raise-error - (signal 'magit-git-error (list (format "%s (in %s)" msg default-dir)))) - ((not (eq msg 'suppressed)) - (when (buffer-live-p process-buf) - (with-current-buffer process-buf - (when-let ((status-buf (magit-get-mode-buffer 'magit-status-mode))) - (with-current-buffer status-buf - (setq magit-this-error msg))))) - (message "%s ... [%s buffer %s for details]" msg - (if-let ((key (and (buffer-live-p command-buf) - (with-current-buffer command-buf - (car (where-is-internal - 'magit-process-buffer)))))) - (format "Hit %s to see" (key-description key)) - "See") - (buffer-name process-buf)))))) - arg) - -(defun magit-process-display-buffer (process) - (when (process-live-p process) - (let ((buf (process-buffer process))) - (cond ((not (buffer-live-p buf))) - ((= magit-process-popup-time 0) - (if (minibufferp) - (switch-to-buffer-other-window buf) - (pop-to-buffer buf))) - ((> magit-process-popup-time 0) - (run-with-timer magit-process-popup-time nil - (lambda (p) - (when (eq (process-status p) 'run) - (let ((buf (process-buffer p))) - (when (buffer-live-p buf) - (if (minibufferp) - (switch-to-buffer-other-window buf) - (pop-to-buffer buf)))))) - process)))))) - -(defun magit--log-action (summary line list) - (let (heading lines) - (if (cdr list) - (progn (setq heading (funcall summary list)) - (setq lines (mapcar line list))) - (setq heading (funcall line (car list)))) - (with-current-buffer (magit-process-buffer t) - (goto-char (1- (point-max))) - (let ((inhibit-read-only t)) - (magit-insert-section (message) - (magit-insert-heading (concat " * " heading)) - (when lines - (dolist (line lines) - (insert line "\n")) - (insert "\n")))) - (let ((inhibit-message t)) - (when heading - (setq lines (cons heading lines))) - (message (mapconcat #'identity lines "\n")))))) - -;;; _ -(provide 'magit-process) -;;; magit-process.el ends here diff --git a/elpa/magit-20210802.1524/magit-pull.el b/elpa/magit-20210802.1524/magit-pull.el deleted file mode 100644 index 333cb3ed..00000000 --- a/elpa/magit-20210802.1524/magit-pull.el +++ /dev/null @@ -1,166 +0,0 @@ -;;; magit-pull.el --- update local objects and refs -*- lexical-binding: t -*- - -;; 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) -;; 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. - -;;; Commentary: - -;; This library implements pull commands. - -;;; Code: - -(require 'magit) - -;;; Options - -(defcustom magit-pull-or-fetch nil - "Whether `magit-pull' also offers some fetch suffixes." - :package-version '(magit . "3.0.0") - :group 'magit-commands - :type 'boolean) - -;;; Commands - -;;;###autoload (autoload 'magit-pull "magit-pull" nil t) -(transient-define-prefix magit-pull () - "Pull from another repository." - :man-page "git-pull" - [:description - (lambda () (if magit-pull-or-fetch "Pull arguments" "Arguments")) - ("-r" "Rebase local commits" ("-r" "--rebase")) - ("-A" "Autostash" "--autostash" :level 7)] - [:description - (lambda () - (if-let ((branch (magit-get-current-branch))) - (concat - (propertize "Pull into " 'face 'transient-heading) - (propertize branch 'face 'magit-branch-local) - (propertize " from" 'face 'transient-heading)) - (propertize "Pull from" 'face 'transient-heading))) - ("p" magit-pull-from-pushremote) - ("u" magit-pull-from-upstream) - ("e" "elsewhere" magit-pull-branch)] - ["Fetch from" - :if-non-nil magit-pull-or-fetch - ("f" "remotes" magit-fetch-all-no-prune) - ("F" "remotes and prune" magit-fetch-all-prune)] - ["Fetch" - :if-non-nil magit-pull-or-fetch - ("o" "another branch" magit-fetch-branch) - ("s" "explicit refspec" magit-fetch-refspec) - ("m" "submodules" magit-fetch-modules)] - ["Configure" - ("r" magit-branch..rebase :if magit-get-current-branch) - ("C" "variables..." magit-branch-configure)] - (interactive) - (transient-setup 'magit-pull nil nil :scope (magit-get-current-branch))) - -(defun magit-pull-arguments () - (transient-args 'magit-pull)) - -;;;###autoload (autoload 'magit-pull-from-pushremote "magit-pull" nil t) -(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 -configured or unusable, then let the user first configure the -push-remote." - :if 'magit-get-current-branch - :description 'magit-pull--pushbranch-description - (interactive (list (magit-pull-arguments))) - (pcase-let ((`(,branch ,remote) - (magit--select-push-remote "pull from there"))) - (run-hooks 'magit-credential-hook) - (magit-run-git-async "pull" args remote branch))) - -(defun magit-pull--pushbranch-description () - ;; Also used by `magit-rebase-onto-pushremote'. - (let* ((branch (magit-get-current-branch)) - (target (magit-get-push-branch branch t)) - (remote (magit-get-push-remote branch)) - (v (magit--push-remote-variable branch t))) - (cond - (target) - ((member remote (magit-list-remotes)) - (format "%s, replacing non-existent" v)) - (remote - (format "%s, replacing invalid" v)) - (t - (format "%s, setting that" v))))) - -;;;###autoload (autoload 'magit-pull-from-upstream "magit-pull" nil t) -(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 -configured or unusable, then let the user first configure -the upstream." - :if 'magit-get-current-branch - :description 'magit-pull--upstream-description - (interactive (list (magit-pull-arguments))) - (let* ((branch (or (magit-get-current-branch) - (user-error "No branch is checked out"))) - (remote (magit-get "branch" branch "remote")) - (merge (magit-get "branch" branch "merge"))) - (when (or current-prefix-arg - (not (or (magit-get-upstream-branch branch) - (magit--unnamed-upstream-p remote merge)))) - (magit-set-upstream-branch - branch (magit-read-upstream-branch - branch (format "Set upstream of %s and pull from there" branch))) - (setq remote (magit-get "branch" branch "remote")) - (setq merge (magit-get "branch" branch "merge"))) - (run-hooks 'magit-credential-hook) - (magit-run-git-with-editor "pull" args remote merge))) - -(defun magit-pull--upstream-description () - (when-let ((branch (magit-get-current-branch))) - (or (magit-get-upstream-branch branch) - (let ((remote (magit-get "branch" branch "remote")) - (merge (magit-get "branch" branch "merge")) - (u (magit--propertize-face "@{upstream}" 'bold))) - (cond - ((magit--unnamed-upstream-p remote merge) - (format "%s of %s" - (magit--propertize-face merge 'magit-branch-remote) - (magit--propertize-face remote 'bold))) - ((magit--valid-upstream-p remote merge) - (concat u ", replacing non-existent")) - ((or remote merge) - (concat u ", replacing invalid")) - (t - (concat u ", setting that"))))))) - -;;;###autoload -(defun magit-pull-branch (source args) - "Pull from a branch read in the minibuffer." - (interactive (list (magit-read-remote-branch "Pull" nil nil nil t) - (magit-pull-arguments))) - (run-hooks 'magit-credential-hook) - (pcase-let ((`(,remote . ,branch) - (magit-get-tracked source))) - (magit-run-git-with-editor "pull" args remote branch))) - -;;; _ -(provide 'magit-pull) -;;; magit-pull.el ends here diff --git a/elpa/magit-20210802.1524/magit-push.el b/elpa/magit-20210802.1524/magit-push.el deleted file mode 100644 index aae8d8ce..00000000 --- a/elpa/magit-20210802.1524/magit-push.el +++ /dev/null @@ -1,344 +0,0 @@ -;;; magit-push.el --- update remote objects and refs -*- lexical-binding: t -*- - -;; 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) -;; 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. - -;;; Commentary: - -;; This library implements push commands. - -;;; Code: - -(require 'magit) - -;;; Commands - -;;;###autoload (autoload 'magit-push "magit-push" nil t) -(transient-define-prefix magit-push () - "Push to another repository." - :man-page "git-push" - ["Arguments" - ("-f" "Force with lease" (nil "--force-with-lease")) - ("-F" "Force" ("-f" "--force")) - ("-h" "Disable hooks" "--no-verify") - ("-n" "Dry run" ("-n" "--dry-run")) - (5 "-u" "Set upstream" "--set-upstream") - (7 "-t" "Follow tags" "--follow-tags")] - [:if magit-get-current-branch - :description (lambda () - (format (propertize "Push %s to" 'face 'transient-heading) - (propertize (magit-get-current-branch) - 'face 'magit-branch-local))) - ("p" magit-push-current-to-pushremote) - ("u" magit-push-current-to-upstream) - ("e" "elsewhere" magit-push-current)] - ["Push" - [("o" "another branch" magit-push-other) - ("r" "explicit refspecs" magit-push-refspecs) - ("m" "matching branches" magit-push-matching)] - [("T" "a tag" magit-push-tag) - ("t" "all tags" magit-push-tags) - (6 "n" "a note ref" magit-push-notes-ref)]] - ["Configure" - ("C" "Set variables..." magit-branch-configure)]) - -(defun magit-push-arguments () - (transient-args 'magit-push)) - -(defun magit-git-push (branch target args) - (run-hooks 'magit-credential-hook) - ;; If the remote branch already exists, then we do not have to - ;; qualify the target, which we prefer to avoid doing because - ;; using the default namespace is wrong in obscure cases. - (pcase-let ((namespace (if (magit-get-tracked target) "" "refs/heads/")) - (`(,remote . ,target) - (magit-split-branch-name target))) - (magit-run-git-async "push" "-v" args remote - (format "%s:%s%s" branch namespace target)))) - -;;;###autoload (autoload 'magit-push-current-to-pushremote "magit-push" nil t) -(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 -from the user, set it, and then push to it. With a prefix -argument the push-remote can be changed before pushed to it." - :if 'magit-get-current-branch - :description 'magit-push--pushbranch-description - (interactive (list (magit-push-arguments))) - (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" - branch branch)))) ; see #3847 and #3872 - -(defun magit-push--pushbranch-description () - (let* ((branch (magit-get-current-branch)) - (target (magit-get-push-branch branch t)) - (remote (magit-get-push-remote branch)) - (v (magit--push-remote-variable branch t))) - (cond - (target) - ((member remote (magit-list-remotes)) - (format "%s, creating it" - (magit--propertize-face (concat remote "/" branch) - 'magit-branch-remote))) - (remote - (format "%s, replacing invalid" v)) - (t - (format "%s, setting that" v))))) - -;;;###autoload (autoload 'magit-push-current-to-upstream "magit-push" nil t) -(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 -configured or unusable, then let the user first configure -the upstream." - :if 'magit-get-current-branch - :description 'magit-push--upstream-description - (interactive (list (magit-push-arguments))) - (let* ((branch (or (magit-get-current-branch) - (user-error "No branch is checked out"))) - (remote (magit-get "branch" branch "remote")) - (merge (magit-get "branch" branch "merge"))) - (when (or current-prefix-arg - (not (or (magit-get-upstream-branch branch) - (magit--unnamed-upstream-p remote merge) - (magit--valid-upstream-p remote merge)))) - (let* ((branches (-union (--map (concat it "/" branch) - (magit-list-remotes)) - (magit-list-remote-branch-names))) - (upstream (magit-completing-read - (format "Set upstream of %s and push there" branch) - 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*)) - (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))) - (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)))) - -(defun magit-push--upstream-description () - (when-let ((branch (magit-get-current-branch))) - (or (magit-get-upstream-branch branch) - (let ((remote (magit-get "branch" branch "remote")) - (merge (magit-get "branch" branch "merge")) - (u (magit--propertize-face "@{upstream}" 'bold))) - (cond - ((magit--unnamed-upstream-p remote merge) - (format "%s as %s" - (magit--propertize-face remote 'bold) - (magit--propertize-face merge 'magit-branch-remote))) - ((magit--valid-upstream-p remote merge) - (format "%s creating %s" - (magit--propertize-face remote 'magit-branch-remote) - (magit--propertize-face merge 'magit-branch-remote))) - ((or remote merge) - (concat u ", creating it and replacing invalid")) - (t - (concat u ", creating it"))))))) - -;;;###autoload -(defun magit-push-current (target args) - "Push the current branch to a branch read in the minibuffer." - (interactive - (--if-let (magit-get-current-branch) - (list (magit-read-remote-branch (format "Push %s to" it) - nil nil it 'confirm) - (magit-push-arguments)) - (user-error "No branch is checked out"))) - (magit-git-push (magit-get-current-branch) target args)) - -;;;###autoload -(defun magit-push-other (source target args) - "Push an arbitrary branch or commit somewhere. -Both the source and the target are read in the minibuffer." - (interactive - (let ((source (magit-read-local-branch-or-commit "Push"))) - (list source - (magit-read-remote-branch - (format "Push %s to" source) nil - (if (magit-local-branch-p source) - (or (magit-get-push-branch source) - (magit-get-upstream-branch source)) - (and (magit-rev-ancestor-p source "HEAD") - (or (magit-get-push-branch) - (magit-get-upstream-branch)))) - source 'confirm) - (magit-push-arguments)))) - (magit-git-push source target args)) - -(defvar magit-push-refspecs-history nil) - -;;;###autoload -(defun magit-push-refspecs (remote refspecs args) - "Push one or multiple REFSPECS to a REMOTE. -Both the REMOTE and the REFSPECS are read in the minibuffer. To -use multiple REFSPECS, separate them with commas. Completion is -only available for the part before the colon, or when no colon -is used." - (interactive - (list (magit-read-remote "Push to remote") - (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)) - -;;;###autoload -(defun magit-push-matching (remote &optional args) - "Push all matching branches to another repository. -If multiple remotes exist, then read one from the user. -If just one exists, use that without requiring confirmation." - (interactive (list (magit-read-remote "Push matching branches to" nil t) - (magit-push-arguments))) - (run-hooks 'magit-credential-hook) - (magit-run-git-async "push" "-v" args remote ":")) - -;;;###autoload -(defun magit-push-tags (remote &optional args) - "Push all tags to another repository. -If only one remote exists, then push to that. Otherwise prompt -for a remote, offering the remote configured for the current -branch as default." - (interactive (list (magit-read-remote "Push tags to remote" nil t) - (magit-push-arguments))) - (run-hooks 'magit-credential-hook) - (magit-run-git-async "push" remote "--tags" args)) - -;;;###autoload -(defun magit-push-tag (tag remote &optional args) - "Push a tag to another repository." - (interactive - (let ((tag (magit-read-tag "Push tag"))) - (list tag (magit-read-remote (format "Push %s to remote" tag) nil t) - (magit-push-arguments)))) - (run-hooks 'magit-credential-hook) - (magit-run-git-async "push" remote tag args)) - -;;;###autoload -(defun magit-push-notes-ref (ref remote &optional args) - "Push a notes ref to another repository." - (interactive - (let ((note (magit-notes-read-ref "Push notes" nil nil))) - (list note - (magit-read-remote (format "Push %s to remote" note) nil t) - (magit-push-arguments)))) - (run-hooks 'magit-credential-hook) - (magit-run-git-async "push" remote ref 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 -arguments specified in the popup buffer. No explicit refspec -arguments are used. Instead the behavior depends on at least -these Git variables: `push.default', `remote.pushDefault', -`branch..pushRemote', `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: - - (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)) - -(defun magit-push-implicitly--desc () - (let ((default (magit-get "push.default"))) - (unless (equal default "nothing") - (or (when-let ((remote (or (magit-get-remote) - (magit-primary-remote))) - (refspec (magit-get "remote" remote "push"))) - (format "%s using %s" - (magit--propertize-face remote 'magit-branch-remote) - (magit--propertize-face refspec 'bold))) - (--when-let (and (not (magit-get-push-branch)) - (magit-get-upstream-branch)) - (format "%s aka %s\n" - (magit-branch-set-face it) - (magit--propertize-face "@{upstream}" 'bold))) - (--when-let (magit-get-push-branch) - (format "%s aka %s\n" - (magit-branch-set-face it) - (magit--propertize-face "pushRemote" 'bold))) - (--when-let (magit-get-@{push}-branch) - (format "%s aka %s\n" - (magit-branch-set-face it) - (magit--propertize-face "@{push}" 'bold))) - (format "using %s (%s is %s)\n" - (magit--propertize-face "git push" 'bold) - (magit--propertize-face "push.default" 'bold) - (magit--propertize-face default 'bold)))))) - -;;;###autoload -(defun magit-push-to-remote (remote args) - "Push to REMOTE without using an explicit refspec. -The REMOTE is read in the minibuffer. - -This command simply runs \"git push -v [ARGS] REMOTE\". ARGS -are the arguments specified in the popup buffer. No refspec -arguments are used. Instead the behavior depends on at least -these Git variables: `push.default', `remote.pushDefault', -`branch..pushRemote', `branch..remote', -`branch..merge', and `remote..push'." - (interactive (list (magit-read-remote "Push to remote") - (magit-push-arguments))) - (run-hooks 'magit-credential-hook) - (magit-run-git-async "push" "-v" args remote)) - -(defun magit-push-to-remote--desc () - (format "using %s\n" (magit--propertize-face "git push " 'bold))) - -;;; _ -(provide 'magit-push) -;;; magit-push.el ends here diff --git a/elpa/magit-20210802.1524/magit-reflog.el b/elpa/magit-20210802.1524/magit-reflog.el deleted file mode 100644 index 384cfa40..00000000 --- a/elpa/magit-20210802.1524/magit-reflog.el +++ /dev/null @@ -1,212 +0,0 @@ -;;; magit-reflog.el --- inspect ref history -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements support for looking at Git reflogs. - -;;; Code: - -(require 'magit-core) -(require 'magit-log) - -;;; Options - -(defcustom magit-reflog-limit 256 - "Maximal number of entries initially shown in reflog buffers. -The limit in the current buffer can be changed using \"+\" -and \"-\"." - :package-version '(magit . "3.0.0") - :group 'magit-commands - :type 'number) - -(defcustom magit-reflog-margin - (list (nth 0 magit-log-margin) - (nth 1 magit-log-margin) - 'magit-log-margin-width nil - (nth 4 magit-log-margin)) - "Format of the margin in `magit-reflog-mode' buffers. - -The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). - -If INIT is non-nil, then the margin is shown initially. -STYLE controls how to format the author or committer date. - It can be one of `age' (to show the age of the commit), - `age-abbreviated' (to abbreviate the time unit to a character), - or a string (suitable for `format-time-string') to show the - actual date. Option `magit-log-margin-show-committer-date' - controls which date is being displayed. -WIDTH controls the width of the margin. This exists for forward - compatibility and currently the value should not be changed. -AUTHOR controls whether the name of the author is also shown by - default. -AUTHOR-WIDTH has to be an integer. When the name of the author - is shown, then this specifies how much space is used to do so." - :package-version '(magit . "2.9.0") - :group 'magit-log - :group 'magit-margin - :type magit-log-margin--custom-type - :initialize 'magit-custom-initialize-reset - :set-after '(magit-log-margin) - :set (apply-partially #'magit-margin-set-variable 'magit-reflog-mode)) - -;;; Faces - -(defface magit-reflog-commit '((t :foreground "green")) - "Face for commit commands in reflogs." - :group 'magit-faces) - -(defface magit-reflog-amend '((t :foreground "magenta")) - "Face for amend commands in reflogs." - :group 'magit-faces) - -(defface magit-reflog-merge '((t :foreground "green")) - "Face for merge, checkout and branch commands in reflogs." - :group 'magit-faces) - -(defface magit-reflog-checkout '((t :foreground "blue")) - "Face for checkout commands in reflogs." - :group 'magit-faces) - -(defface magit-reflog-reset '((t :foreground "red")) - "Face for reset commands in reflogs." - :group 'magit-faces) - -(defface magit-reflog-rebase '((t :foreground "magenta")) - "Face for rebase commands in reflogs." - :group 'magit-faces) - -(defface magit-reflog-cherry-pick '((t :foreground "green")) - "Face for cherry-pick commands in reflogs." - :group 'magit-faces) - -(defface magit-reflog-remote '((t :foreground "cyan")) - "Face for pull and clone commands in reflogs." - :group 'magit-faces) - -(defface magit-reflog-other '((t :foreground "cyan")) - "Face for other commands in reflogs." - :group 'magit-faces) - -;;; Commands - -;;;###autoload -(defun magit-reflog-current () - "Display the reflog of the current branch. -If `HEAD' is detached, then show the reflog for that instead." - (interactive) - (magit-reflog-setup-buffer (or (magit-get-current-branch) "HEAD"))) - -;;;###autoload -(defun magit-reflog-other (ref) - "Display the reflog of a branch or another ref." - (interactive (list (magit-read-local-branch-or-ref "Show reflog for"))) - (magit-reflog-setup-buffer ref)) - -;;;###autoload -(defun magit-reflog-head () - "Display the `HEAD' reflog." - (interactive) - (magit-reflog-setup-buffer "HEAD")) - -;;; Mode - -(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) - map) - "Keymap for `magit-reflog-mode'.") - -(define-derived-mode magit-reflog-mode magit-mode "Magit Reflog" - "Mode for looking at Git reflog. - -This mode is documented in info node `(magit)Reflog'. - -\\\ -Type \\[magit-refresh] to refresh the current buffer. -Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \ -to visit the commit at point. - -Type \\[magit-cherry-pick] to apply the commit at point. -Type \\[magit-reset] to reset `HEAD' to the commit at point. - -\\{magit-reflog-mode-map}" - :group 'magit-log - (hack-dir-local-variables-non-file-buffer)) - -(defun magit-reflog-setup-buffer (ref) - (require 'magit) - (magit-setup-buffer #'magit-reflog-mode nil - (magit-buffer-refname ref) - (magit-buffer-log-args (list (format "-n%s" magit-reflog-limit))))) - -(defun magit-reflog-refresh-buffer () - (magit-set-header-line-format (concat "Reflog for " magit-buffer-refname)) - (magit-insert-section (reflogbuf) - (magit-git-wash (apply-partially 'magit-log-wash-log 'reflog) - "reflog" "show" "--format=%h%x00%aN%x00%gd%x00%gs" "--date=raw" - magit-buffer-log-args magit-buffer-refname "--"))) - -(cl-defmethod magit-buffer-value (&context (major-mode magit-reflog-mode)) - magit-buffer-refname) - -(defvar magit-reflog-labels - '(("commit" . magit-reflog-commit) - ("amend" . magit-reflog-amend) - ("merge" . magit-reflog-merge) - ("checkout" . magit-reflog-checkout) - ("branch" . magit-reflog-checkout) - ("reset" . magit-reflog-reset) - ("rebase" . magit-reflog-rebase) - ("cherry-pick" . magit-reflog-cherry-pick) - ("initial" . magit-reflog-commit) - ("pull" . magit-reflog-remote) - ("clone" . magit-reflog-remote) - ("autosave" . magit-reflog-commit) - ("restart" . magit-reflog-reset))) - -(defun magit-reflog-format-subject (subject) - (let* ((match (string-match magit-reflog-subject-re subject)) - (command (and match (match-string 1 subject))) - (option (and match (match-string 2 subject))) - (type (and match (match-string 3 subject))) - (label (if (string= command "commit") - (or type command) - command)) - (text (if (string= command "commit") - label - (mapconcat #'identity - (delq nil (list command option type)) - " ")))) - (format "%-16s " - (magit--propertize-face - text (or (cdr (assoc label magit-reflog-labels)) - 'magit-reflog-other))))) - -;;; _ -(provide 'magit-reflog) -;;; magit-reflog.el ends here diff --git a/elpa/magit-20210802.1524/magit-refs.el b/elpa/magit-20210802.1524/magit-refs.el deleted file mode 100644 index 13ceec79..00000000 --- a/elpa/magit-20210802.1524/magit-refs.el +++ /dev/null @@ -1,761 +0,0 @@ -;;; magit-refs.el --- listing references -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements support for listing references in a buffer. - -;;; Code: - -(require 'magit) - -;;; Options - -(defgroup magit-refs nil - "Inspect and manipulate Git branches and tags." - :link '(info-link "(magit)References Buffer") - :group 'magit-modes) - -(defcustom magit-refs-mode-hook nil - "Hook run after entering Magit-Refs mode." - :package-version '(magit . "2.1.0") - :group 'magit-refs - :type 'hook) - -(defcustom magit-refs-sections-hook - '(magit-insert-error-header - magit-insert-branch-description - magit-insert-local-branches - magit-insert-remote-branches - magit-insert-tags) - "Hook run to insert sections into a references buffer." - :package-version '(magit . "2.1.0") - :group 'magit-refs - :type 'hook) - -(defcustom magit-refs-show-commit-count nil - "Whether to show commit counts in Magit-Refs mode buffers. - -all Show counts for branches and tags. -branch Show counts for branches only. -nil Never show counts. - -To change the value in an existing buffer use the command -`magit-refs-show-commit-count'" - :package-version '(magit . "2.1.0") - :group 'magit-refs - :safe (lambda (val) (memq val '(all branch nil))) - :type '(choice (const all :tag "For branches and tags") - (const branch :tag "For branches only") - (const nil :tag "Never"))) -(put 'magit-refs-show-commit-count 'safe-local-variable 'symbolp) -(put 'magit-refs-show-commit-count 'permanent-local t) - -(defcustom magit-refs-pad-commit-counts nil - "Whether to pad all counts on all sides in `magit-refs-mode' buffers. - -If this is nil, then some commit counts are displayed right next -to one of the branches that appear next to the count, without any -space in between. This might look bad if the branch name faces -look too similar to `magit-dimmed'. - -If this is non-nil, then spaces are placed on both sides of all -commit counts." - :package-version '(magit . "2.12.0") - :group 'magit-refs - :type 'boolean) - -(defvar magit-refs-show-push-remote nil - "Whether to show the push-remotes of local branches. -Also show the commits that the local branch is ahead and behind -the push-target. Unfortunately there is a bug in Git that makes -this useless (the commits ahead and behind the upstream are -shown), so this isn't enabled yet.") - -(defcustom magit-refs-show-remote-prefix nil - "Whether to show the remote prefix in lists of remote branches. - -This is redundant because the name of the remote is already shown -in the heading preceding the list of its branches." - :package-version '(magit . "2.12.0") - :group 'magit-refs - :type 'boolean) - -(defcustom magit-refs-margin - (list nil - (nth 1 magit-log-margin) - 'magit-log-margin-width nil - (nth 4 magit-log-margin)) - "Format of the margin in `magit-refs-mode' buffers. - -The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). - -If INIT is non-nil, then the margin is shown initially. -STYLE controls how to format the author or committer date. - It can be one of `age' (to show the age of the commit), - `age-abbreviated' (to abbreviate the time unit to a character), - or a string (suitable for `format-time-string') to show the - actual date. Option `magit-log-margin-show-committer-date' - controls which date is being displayed. -WIDTH controls the width of the margin. This exists for forward - compatibility and currently the value should not be changed. -AUTHOR controls whether the name of the author is also shown by - default. -AUTHOR-WIDTH has to be an integer. When the name of the author - is shown, then this specifies how much space is used to do so." - :package-version '(magit . "2.9.0") - :group 'magit-refs - :group 'magit-margin - :safe (lambda (val) (memq val '(all branch nil))) - :type magit-log-margin--custom-type - :initialize 'magit-custom-initialize-reset - :set-after '(magit-log-margin) - :set (apply-partially #'magit-margin-set-variable 'magit-refs-mode)) - -(defcustom magit-refs-margin-for-tags nil - "Whether to show information about tags in the margin. - -This is disabled by default because it is slow if there are many -tags." - :package-version '(magit . "2.9.0") - :group 'magit-refs - :group 'magit-margin - :type 'boolean) - -(defcustom magit-refs-primary-column-width (cons 16 32) - "Width of the focus column in `magit-refs-mode' buffers. - -The primary column is the column that contains the name of the -branch that the current row is about. - -If this is an integer, then the column is that many columns wide. -Otherwise it has to be a cons-cell of two integers. The first -specifies the minimal width, the second the maximal width. In that -case the actual width is determined using the length of the names -of the shown local branches. (Remote branches and tags are not -taken into account when calculating to optimal width.)" - :package-version '(magit . "2.12.0") - :group 'magit-refs - :type '(choice (integer :tag "Constant wide") - (cons :tag "Wide constrains" - (integer :tag "Minimum") - (integer :tag "Maximum")))) - -(defcustom magit-refs-focus-column-width 5 - "Width of the focus column in `magit-refs-mode' buffers. - -The focus column is the first column, which marks one -branch (usually the current branch) as the focused branch using -\"*\" or \"@\". For each other reference, this column optionally -shows how many commits it is ahead of the focused branch and \"<\", or -if it isn't ahead then the commits it is behind and \">\", or if it -isn't behind either, then a \"=\". - -This column may also display only \"*\" or \"@\" for the focused -branch, in which case this option is ignored. Use \"L v\" to -change the verbosity of this column." - :package-version '(magit . "2.12.0") - :group 'magit-refs - :type 'integer) - -(defcustom magit-refs-filter-alist nil - "Alist controlling which refs are omitted from `magit-refs-mode' buffers. - -The purpose of this option is to forgo displaying certain refs -based on their name. If you want to not display any refs of a -certain type, then you should remove the appropriate function -from `magit-refs-sections-hook' instead. - -All keys are tried in order until one matches. Then its value -is used and subsequent elements are ignored. If the value is -non-nil, then the reference is displayed, otherwise it is not. -If no element matches, then the reference is displayed. - -A key can either be a regular expression that the refname has to -match, or a function that takes the refname as only argument and -returns a boolean. A remote branch such as \"origin/master\" is -displayed as just \"master\", however for this comparison the -former is used." - :package-version '(magit . "2.12.0") - :group 'magit-refs - :type '(alist :key-type (choice :tag "Key" regexp function) - :value-type (boolean :tag "Value" - :on "show (non-nil)" - :off "omit (nil)"))) - -(defcustom magit-visit-ref-behavior nil - "Control how `magit-visit-ref' behaves in `magit-refs-mode' buffers. - -By default `magit-visit-ref' behaves like `magit-show-commit', -in all buffers, including `magit-refs-mode' buffers. When the -type of the section at point is `commit' then \"RET\" is bound to -`magit-show-commit', and when the type is either `branch' or -`tag' then it is bound to `magit-visit-ref'. - -\"RET\" is one of Magit's most essential keys and at least by -default it should behave consistently across all of Magit, -especially because users quickly learn that it does something -very harmless; it shows more information about the thing at point -in another buffer. - -However \"RET\" used to behave differently in `magit-refs-mode' -buffers, doing surprising things, some of which cannot really be -described as \"visit this thing\". If you have grown accustomed -to such inconsistent, but to you useful, behavior, then you can -restore that by adding one or more of the below symbols to the -value of this option. But keep in mind that by doing so you -don't only introduce inconsistencies, you also lose some -functionality and might have to resort to `M-x magit-show-commit' -to get it back. - -`magit-visit-ref' looks for these symbols in the order in which -they are described here. If the presence of a symbol applies to -the current situation, then the symbols that follow do not affect -the outcome. - -`focus-on-ref' - - With a prefix argument update the buffer to show commit counts - and lists of cherry commits relative to the reference at point - instead of relative to the current buffer or `HEAD'. - - Instead of adding this symbol, consider pressing \"C-u y o RET\". - -`create-branch' - - If point is on a remote branch, then create a new local branch - with the same name, use the remote branch as its upstream, and - then check out the local branch. - - Instead of adding this symbol, consider pressing \"b c RET RET\", - like you would do in other buffers. - -`checkout-any' - - Check out the reference at point. If that reference is a tag - or a remote branch, then this results in a detached `HEAD'. - - Instead of adding this symbol, consider pressing \"b b RET\", - like you would do in other buffers. - -`checkout-branch' - - Check out the local branch at point. - - Instead of adding this symbol, consider pressing \"b b RET\", - like you would do in other buffers." - :package-version '(magit . "2.9.0") - :group 'magit-refs - :group 'magit-commands - :options '(focus-on-ref create-branch checkout-any checkout-branch) - :type '(list :convert-widget custom-hook-convert-widget)) - -;;; Mode - -(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) - map) - "Keymap for `magit-refs-mode'.") - -(define-derived-mode magit-refs-mode magit-mode "Magit Refs" - "Mode which lists and compares references. - -This mode is documented in info node `(magit)References Buffer'. - -\\\ -Type \\[magit-refresh] to refresh the current buffer. -Type \\[magit-section-toggle] to expand or hide the section at point. -Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \ -to visit the commit or branch at point. - -Type \\[magit-branch] to see available branch commands. -Type \\[magit-merge] to merge the branch or commit at point. -Type \\[magit-cherry-pick] to apply the commit at point. -Type \\[magit-reset] to reset `HEAD' to the commit at point. - -\\{magit-refs-mode-map}" - :group 'magit-refs - (hack-dir-local-variables-non-file-buffer) - (setq imenu-create-index-function - #'magit-imenu--refs-create-index-function)) - -(defun magit-refs-setup-buffer (ref args) - (magit-setup-buffer #'magit-refs-mode nil - (magit-buffer-upstream ref) - (magit-buffer-arguments args))) - -(defun magit-refs-refresh-buffer () - (setq magit-set-buffer-margin-refresh (not (magit-buffer-margin-p))) - (unless (magit-rev-verify magit-buffer-upstream) - (setq magit-refs-show-commit-count nil)) - (magit-set-header-line-format - (format "%s %s" magit-buffer-upstream - (mapconcat #'identity magit-buffer-arguments " "))) - (magit-insert-section (branchbuf) - (magit-run-section-hook 'magit-refs-sections-hook)) - (add-hook 'kill-buffer-hook 'magit-preserve-section-visibility-cache)) - -(cl-defmethod magit-buffer-value (&context (major-mode magit-refs-mode)) - (cons magit-buffer-upstream magit-buffer-arguments)) - -;;; Commands - -;;;###autoload (autoload 'magit-show-refs "magit-refs" nil t) -(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 to HEAD" "--merged") - ("-N" "Not merged" "--no-merged=" magit-transient-read-revision) - ("-n" "Not merged to HEAD" "--no-merged") - (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)] - (interactive (list (or (derived-mode-p 'magit-refs-mode) - current-prefix-arg))) - (if transient - (transient-setup 'magit-show-refs) - (magit-refs-setup-buffer "HEAD" (magit-show-refs-arguments)))) - -(defun magit-show-refs-arguments (&optional use-buffer-args) - (unless use-buffer-args - (setq use-buffer-args magit-direct-use-buffer-arguments)) - (let (args) - (cond - ((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)) - ((and (memq use-buffer-args '(always selected)) - (when-let ((buffer (magit-get-mode-buffer - 'magit-refs-mode nil - (eq use-buffer-args 'selected)))) - (setq args (buffer-local-value 'magit-buffer-arguments buffer)) - t))) - (t - (setq args (alist-get 'magit-show-refs transient-values)))) - args)) - -(transient-define-argument magit-for-each-ref:--contains () - :description "Contains" - :class 'transient-option - :key "-c" - :argument "--contains=" - :reader 'magit-transient-read-revision) - -(transient-define-argument magit-for-each-ref:--sort () - :description "Sort" - :class 'transient-option - :key "-s" - :argument "--sort=" - :reader 'magit-read-ref-sort) - -(defun magit-read-ref-sort (prompt initial-input _history) - (magit-completing-read prompt - '("-committerdate" "-authordate" - "committerdate" "authordate") - nil nil initial-input)) - -;;;###autoload -(defun magit-show-refs-head (&optional args) - "List and compare references in a dedicated buffer. -Compared with `HEAD'." - (interactive (list (magit-show-refs-arguments))) - (magit-refs-setup-buffer "HEAD" args)) - -;;;###autoload -(defun magit-show-refs-current (&optional args) - "List and compare references in a dedicated buffer. -Compare with the current branch or `HEAD' if it is detached." - (interactive (list (magit-show-refs-arguments))) - (magit-refs-setup-buffer (magit-get-current-branch) args)) - -;;;###autoload -(defun magit-show-refs-other (&optional ref args) - "List and compare references in a dedicated buffer. -Compared with a branch read from the user." - (interactive (list (magit-read-other-branch "Compare with") - (magit-show-refs-arguments))) - (magit-refs-setup-buffer ref args)) - -(defun magit-refs-set-show-commit-count () - "Change for which refs the commit count is shown." - (interactive) - (setq-local magit-refs-show-commit-count - (magit-read-char-case "Show commit counts for " nil - (?a "[a]ll refs" 'all) - (?b "[b]ranches only" t) - (?n "[n]othing" nil))) - (magit-refresh)) - -(defun magit-visit-ref () - "Visit the reference or revision at point in another buffer. -If there is no revision at point or with a prefix argument prompt -for a revision. - -This command behaves just like `magit-show-commit', except if -point is on a reference in a `magit-refs-mode' buffer (a buffer -listing branches and tags), in which case the behavior may be -different, but only if you have customized the option -`magit-visit-ref-behavior' (which see)." - (interactive) - (if (and (derived-mode-p 'magit-refs-mode) - (magit-section-match '(branch tag))) - (let ((ref (oref (magit-current-section) value))) - (cond (current-prefix-arg - (cond ((memq 'focus-on-ref magit-visit-ref-behavior) - (magit-refs-setup-buffer ref (magit-show-refs-arguments))) - (magit-visit-ref-behavior - ;; Don't prompt for commit to visit. - (let ((current-prefix-arg nil)) - (call-interactively #'magit-show-commit))))) - ((and (memq 'create-branch magit-visit-ref-behavior) - (magit-section-match [branch remote])) - (let ((branch (cdr (magit-split-branch-name ref)))) - (if (magit-branch-p branch) - (if (magit-rev-eq branch ref) - (magit-call-git "checkout" branch) - (setq branch (propertize branch 'face 'magit-branch-local)) - (setq ref (propertize ref 'face 'magit-branch-remote)) - (pcase (prog1 (read-char-choice (format (propertize "\ -Branch %s already exists. - [c]heckout %s as-is - [r]reset %s to %s and checkout %s - [a]bort " 'face 'minibuffer-prompt) branch branch branch ref branch) - '(?c ?r ?a)) - (message "")) ; otherwise prompt sticks - (?c (magit-call-git "checkout" branch)) - (?r (magit-call-git "checkout" "-B" branch ref)) - (?a (user-error "Abort")))) - (magit-call-git "checkout" "-b" branch ref)) - (setq magit-buffer-upstream branch) - (magit-refresh))) - ((or (memq 'checkout-any magit-visit-ref-behavior) - (and (memq 'checkout-branch magit-visit-ref-behavior) - (magit-section-match [branch local]))) - (magit-call-git "checkout" ref) - (setq magit-buffer-upstream ref) - (magit-refresh)) - (t - (call-interactively #'magit-show-commit)))) - (call-interactively #'magit-show-commit))) - -;;; Sections - -(defvar magit-remote-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-delete-thing] 'magit-remote-remove) - (define-key map "R" 'magit-remote-rename) - map) - "Keymap for `remote' sections.") - -(defvar magit-branch-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-visit-thing] 'magit-visit-ref) - (define-key map [remap magit-delete-thing] 'magit-branch-delete) - (define-key map "R" 'magit-branch-rename) - map) - "Keymap for `branch' sections.") - -(defvar magit-tag-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-visit-thing] 'magit-visit-ref) - (define-key map [remap magit-delete-thing] 'magit-tag-delete) - map) - "Keymap for `tag' sections.") - -(defun magit-insert-branch-description () - "Insert header containing the description of the current branch. -Insert a header line with the name and description of the -current branch. The description is taken from the Git variable -`branch..description'; if that is undefined then no header -line is inserted at all." - (when-let ((branch (magit-get-current-branch)) - (desc (magit-get "branch" branch "description")) - (desc (split-string desc "\n"))) - (when (equal (car (last desc)) "") - (setq desc (butlast desc))) - (magit-insert-section (branchdesc branch t) - (magit-insert-heading branch ": " (car desc)) - (when (cdr desc) - (insert (mapconcat 'identity (cdr desc) "\n")) - (insert "\n\n"))))) - -(defun magit-insert-tags () - "Insert sections showing all tags." - (when-let ((tags (magit-git-lines "tag" "--list" "-n" magit-buffer-arguments))) - (let ((_head (magit-rev-parse "HEAD"))) - (magit-insert-section (tags) - (magit-insert-heading "Tags:") - (dolist (tag tags) - (string-match "^\\([^ \t]+\\)[ \t]+\\([^ \t\n].*\\)?" tag) - (let ((tag (match-string 1 tag)) - (msg (match-string 2 tag))) - (when (magit-refs--insert-refname-p tag) - (magit-insert-section (tag tag t) - (magit-insert-heading - (magit-refs--format-focus-column tag 'tag) - (propertize tag 'font-lock-face 'magit-tag) - (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)) - (magit-refs--insert-cherry-commits tag))))) - (insert ?\n) - (magit-make-margin-overlay nil t))))) - -(defun magit-insert-remote-branches () - "Insert sections showing all remote-tracking branches." - (dolist (remote (magit-list-remotes)) - (magit-insert-section (remote remote) - (magit-insert-heading - (let ((pull (magit-get "remote" remote "url")) - (push (magit-get "remote" remote "pushurl"))) - (format (propertize "Remote %s (%s):" - 'font-lock-face 'magit-section-heading) - (propertize remote 'font-lock-face 'magit-branch-remote) - (concat pull (and pull push ", ") push)))) - (let (head) - (dolist (line (magit-git-lines "for-each-ref" "--format=\ -%(symref:short)%00%(refname:short)%00%(refname)%00%(subject)" - (concat "refs/remotes/" remote) - magit-buffer-arguments)) - (pcase-let ((`(,head-branch ,branch ,ref ,msg) - (-replace "" nil (split-string line "\0")))) - (if head-branch - (progn (cl-assert (equal branch (concat remote "/HEAD"))) - (setq head head-branch)) - (when (magit-refs--insert-refname-p branch) - (magit-insert-section (branch branch t) - (let ((headp (equal branch head)) - (abbrev (if magit-refs-show-remote-prefix - branch - (substring branch (1+ (length remote)))))) - (magit-insert-heading - (magit-refs--format-focus-column branch) - (magit-refs--propertize-branch - abbrev ref (and headp 'magit-branch-remote-head)) - (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)) - (magit-refs--insert-cherry-commits branch))))))) - (insert ?\n) - (magit-make-margin-overlay nil t)))) - -(defun magit-insert-local-branches () - "Insert sections showing all local branches." - (magit-insert-section (local nil) - (magit-insert-heading "Branches:") - (dolist (line (magit-refs--format-local-branches)) - (pcase-let ((`(,branch . ,strings) line)) - (magit-insert-section - ((eval (if branch 'branch 'commit)) - (or branch (magit-rev-parse "HEAD")) - t) - (apply #'magit-insert-heading strings) - (when (magit-buffer-margin-p) - (magit-refs--format-margin branch)) - (magit-refs--insert-cherry-commits branch)))) - (insert ?\n) - (magit-make-margin-overlay nil t))) - -(defun magit-refs--format-local-branches () - (let ((lines (-keep 'magit-refs--format-local-branch - (magit-git-lines - "for-each-ref" - (concat "--format=\ -%(HEAD)%00%(refname:short)%00%(refname)%00\ -%(upstream:short)%00%(upstream)%00%(upstream:track)%00" - (if magit-refs-show-push-remote "\ -%(push:remotename)%00%(push)%00%(push:track)%00%(subject)" - "%00%00%00%(subject)")) - "refs/heads" - magit-buffer-arguments)))) - (unless (magit-get-current-branch) - (push (magit-refs--format-local-branch - (concat "*\0\0\0\0\0\0\0\0" (magit-rev-format "%s"))) - lines)) - (setq-local magit-refs-primary-column-width - (let ((def (default-value 'magit-refs-primary-column-width))) - (if (atom def) - def - (pcase-let ((`(,min . ,max) def)) - (min max (apply #'max min (mapcar #'car lines))))))) - (mapcar (pcase-lambda (`(,_ ,branch ,focus ,branch-desc ,u:ahead ,p:ahead - ,u:behind ,upstream ,p:behind ,push ,msg)) - (list branch focus branch-desc u:ahead p:ahead - (make-string (max 1 (- magit-refs-primary-column-width - (length (concat branch-desc - u:ahead - p:ahead - u:behind)))) - ?\s) - u:behind upstream p:behind push - msg)) - lines))) - -(defun magit-refs--format-local-branch (line) - (pcase-let ((`(,head ,branch ,ref ,upstream ,u:ref ,u:track - ,push ,p:ref ,p:track ,msg) - (-replace "" nil (split-string line "\0")))) - (when (or (not branch) - (magit-refs--insert-refname-p branch)) - (let* ((headp (equal head "*")) - (pushp (and push - magit-refs-show-push-remote - (magit-rev-verify p:ref) - (not (equal p:ref u:ref)))) - (branch-desc - (if branch - (magit-refs--propertize-branch - branch ref (and headp 'magit-branch-current)) - (magit--propertize-face "(detached)" - 'font-lock-warning-face))) - (u:ahead (and u:track - (string-match "ahead \\([0-9]+\\)" u:track) - (magit--propertize-face - (concat (and magit-refs-pad-commit-counts " ") - (match-string 1 u:track) - ">") - 'magit-dimmed))) - (u:behind (and u:track - (string-match "behind \\([0-9]+\\)" u:track) - (magit--propertize-face - (concat "<" - (match-string 1 u:track) - (and magit-refs-pad-commit-counts " ")) - 'magit-dimmed))) - (p:ahead (and pushp p:track - (string-match "ahead \\([0-9]+\\)" p:track) - (magit--propertize-face - (concat (match-string 1 p:track) - ">" - (and magit-refs-pad-commit-counts " ")) - 'magit-branch-remote))) - (p:behind (and pushp p:track - (string-match "behind \\([0-9]+\\)" p:track) - (magit--propertize-face - (concat "<" - (match-string 1 p:track) - (and magit-refs-pad-commit-counts " ")) - 'magit-dimmed)))) - (list (1+ (length (concat branch-desc u:ahead p:ahead u:behind))) - branch - (magit-refs--format-focus-column branch headp) - branch-desc u:ahead p:ahead u:behind - (and upstream - (concat (if (equal u:track "[gone]") - (magit--propertize-face upstream 'error) - (magit-refs--propertize-branch upstream u:ref)) - " ")) - (and pushp - (concat p:behind - (magit--propertize-face - push 'magit-branch-remote) - " ")) - (and msg (magit-log-propertize-keywords nil msg))))))) - -(defun magit-refs--format-focus-column (ref &optional type) - (let ((focus magit-buffer-upstream) - (width (if magit-refs-show-commit-count - magit-refs-focus-column-width - 1))) - (format - (format "%%%ss " width) - (cond ((or (equal ref focus) - (and (eq type t) - (equal focus "HEAD"))) - (magit--propertize-face (concat (if (equal focus "HEAD") "@" "*") - (make-string (1- width) ?\s)) - 'magit-section-heading)) - ((if (eq type 'tag) - (eq magit-refs-show-commit-count 'all) - magit-refs-show-commit-count) - (pcase-let ((`(,behind ,ahead) - (magit-rev-diff-count magit-buffer-upstream ref))) - (magit--propertize-face - (cond ((> ahead 0) (concat "<" (number-to-string ahead))) - ((> behind 0) (concat (number-to-string behind) ">")) - (t "=")) - 'magit-dimmed))) - (t ""))))) - -(defun magit-refs--propertize-branch (branch ref &optional head-face) - (let ((face (cdr (cl-find-if (pcase-lambda (`(,re . ,_)) - (string-match-p re ref)) - magit-ref-namespaces)))) - (magit--propertize-face - branch (if head-face (list face head-face) face)))) - -(defun magit-refs--insert-refname-p (refname) - (--if-let (-first (pcase-lambda (`(,key . ,_)) - (if (functionp key) - (funcall key refname) - (string-match-p key refname))) - magit-refs-filter-alist) - (cdr it) - t)) - -(defun magit-refs--insert-cherry-commits (ref) - (magit-insert-section-body - (let ((start (point)) - (magit-insert-section--current nil)) - (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry) - "cherry" "-v" (magit-abbrev-arg) magit-buffer-upstream ref) - (if (= (point) start) - (message "No cherries for %s" ref) - (magit-make-margin-overlay nil t))))) - -(defun magit-refs--format-margin (commit) - (save-excursion - (goto-char (line-beginning-position 0)) - (let ((line (magit-rev-format "%ct%cN" commit))) - (magit-log-format-margin commit - (substring line 10) - (substring line 0 10))))) - -;;; _ -(provide 'magit-refs) -;;; magit-refs.el ends here diff --git a/elpa/magit-20210802.1524/magit-remote.el b/elpa/magit-20210802.1524/magit-remote.el deleted file mode 100644 index a2dd42cb..00000000 --- a/elpa/magit-20210802.1524/magit-remote.el +++ /dev/null @@ -1,352 +0,0 @@ -;;; magit-remote.el --- transfer Git commits -*- lexical-binding: t -*- - -;; 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) -;; 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. - -;;; Commentary: - -;; This library implements remote commands. - -;;; Code: - -(require 'magit) - -;;; Options - -(defcustom magit-remote-add-set-remote.pushDefault 'ask-if-unset - "Whether to set the value of `remote.pushDefault' after adding a remote. - -If `ask', then always ask. If `ask-if-unset', then ask, but only -if the variable isn't set already. If nil, then don't ever set. -If the value is a string, then set without asking, provided that -the name of the added remote is equal to that string and the -variable isn't already set." - :package-version '(magit . "2.4.0") - :group 'magit-commands - :type '(choice (const :tag "ask if unset" ask-if-unset) - (const :tag "always ask" ask) - (string :tag "set if named") - (const :tag "don't set"))) - -(defcustom magit-remote-direct-configure t - "Whether the command `magit-remote' shows Git variables. -When set to nil, no variables are displayed by this transient -command, instead the sub-transient `magit-remote-configure' -has to be used to view and change remote related variables." - :package-version '(magit . "2.12.0") - :group 'magit-commands - :type 'boolean) - -(defcustom magit-prefer-push-default nil - "Whether to prefer `remote.pushDefault' over per-branch variables." - :package-version '(magit . "3.0.0") - :group 'magit-commands - :type 'boolean) - -;;; Commands - -;;;###autoload (autoload 'magit-remote "magit-remote" nil t) -(transient-define-prefix magit-remote (remote) - "Add, configure or remove a remote." - :man-page "git-remote" - :value '("-f") - ["Variables" - :if (lambda () - (and magit-remote-direct-configure - (oref transient--prefix scope))) - ("u" magit-remote..url) - ("U" magit-remote..fetch) - ("s" magit-remote..pushurl) - ("S" magit-remote..push) - ("O" magit-remote..tagopt)] - ["Arguments for add" - ("-f" "Fetch after add" "-f")] - ["Actions" - [("a" "Add" magit-remote-add) - ("r" "Rename" magit-remote-rename) - ("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)]] - (interactive (list (magit-get-current-remote))) - (transient-setup 'magit-remote nil nil :scope remote)) - -(defun magit-read-url (prompt &optional initial-input) - (let ((url (magit-read-string-ns prompt initial-input))) - (if (string-prefix-p "~" url) - (expand-file-name url) - url))) - -;;;###autoload -(defun magit-remote-add (remote url &optional args) - "Add a remote named REMOTE and fetch it." - (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) - ((or `(ask ,_) `(ask-if-unset nil)) - (y-or-n-p (format "Set `remote.pushDefault' to \"%s\"? " remote)))) - (progn (magit-call-git "remote" "add" args remote url) - (setf (magit-get "remote.pushDefault") remote) - (magit-refresh)) - (magit-run-git-async "remote" "add" args remote url))) - -;;;###autoload -(defun magit-remote-rename (old new) - "Rename the remote named OLD to NEW." - (interactive - (let ((remote (magit-read-remote "Rename remote"))) - (list remote (magit-read-string-ns (format "Rename %s to" remote))))) - (unless (string= old new) - (magit-call-git "remote" "rename" old new) - (magit-remote--cleanup-push-variables old new) - (magit-refresh))) - -;;;###autoload -(defun magit-remote-remove (remote) - "Delete the remote named REMOTE." - (interactive (list (magit-read-remote "Delete remote"))) - (magit-call-git "remote" "rm" remote) - (magit-remote--cleanup-push-variables remote) - (magit-refresh)) - -(defun magit-remote--cleanup-push-variables (remote &optional new-name) - (magit-with-toplevel - (when (equal (magit-get "remote.pushDefault") remote) - (magit-set new-name "remote.pushDefault")) - (dolist (var (magit-git-lines "config" "--name-only" - "--get-regexp" "^branch\.[^.]*\.pushRemote" - (format "^%s$" remote))) - (magit-call-git "config" (and (not new-name) "--unset") var new-name)))) - -(defconst magit--refspec-re "\\`\\(\\+\\)?\\([^:]+\\):\\(.*\\)\\'") - -;;;###autoload -(defun magit-remote-prune (remote) - "Remove stale remote-tracking branches for REMOTE." - (interactive (list (magit-read-remote "Prune stale branches of remote"))) - (magit-run-git-async "remote" "prune" remote)) - -;;;###autoload -(defun magit-remote-prune-refspecs (remote) - "Remove stale refspecs for REMOTE. - -A refspec is stale if there no longer exists at least one branch -on the remote that would be fetched due to that refspec. A stale -refspec is problematic because its existence causes Git to refuse -to fetch according to the remaining non-stale refspecs. - -If only stale refspecs remain, then offer to either delete the -remote or to replace the stale refspecs with the default refspec. - -Also remove the remote-tracking branches that were created due to -the now stale refspecs. Other stale branches are not removed." - (interactive (list (magit-read-remote "Prune refspecs of remote"))) - (let* ((tracking-refs (magit-list-remote-branches remote)) - (remote-refs (magit-remote-list-refs remote)) - (variable (format "remote.%s.fetch" remote)) - (refspecs (magit-get-all variable)) - stale) - (dolist (refspec refspecs) - (when (string-match magit--refspec-re refspec) - (let ((theirs (match-string 2 refspec)) - (ours (match-string 3 refspec))) - (unless (if (string-match "\\*" theirs) - (let ((re (replace-match ".*" t t theirs))) - (--some (string-match-p re it) remote-refs)) - (member theirs remote-refs)) - (push (cons refspec - (if (string-match "\\*" ours) - (let ((re (replace-match ".*" t t ours))) - (--filter (string-match-p re it) tracking-refs)) - (list (car (member ours tracking-refs))))) - stale))))) - (if (not stale) - (message "No stale refspecs for remote %S" remote) - (if (= (length stale) - (length refspecs)) - (magit-read-char-case - (format "All of %s's refspecs are stale. " remote) nil - (?s "replace with [d]efault refspec" - (magit-set-all - (list (format "+refs/heads/*:refs/remotes/%s/*" remote)) - variable)) - (?r "[r]emove remote" - (magit-call-git "remote" "rm" remote)) - (?a "or [a]abort" - (user-error "Abort"))) - (if (if (= (length stale) 1) - (pcase-let ((`(,refspec . ,refs) (car stale))) - (magit-confirm 'prune-stale-refspecs - (format "Prune stale refspec %s and branch %%s" refspec) - (format "Prune stale refspec %s and %%i branches" refspec) - nil refs)) - (magit-confirm 'prune-stale-refspecs nil - (format "Prune %%i stale refspecs and %i branches" - (length (cl-mapcan (lambda (s) (copy-sequence (cdr s))) - stale))) - nil - (mapcar (pcase-lambda (`(,refspec . ,refs)) - (concat refspec "\n" - (mapconcat (lambda (b) (concat " " b)) - refs "\n"))) - stale))) - (pcase-dolist (`(,refspec . ,refs) stale) - (magit-call-git "config" "--unset" variable - (regexp-quote refspec)) - (magit--log-action - (lambda (refs) - (format "Deleting %i branches" (length refs))) - (lambda (ref) - (format "Deleting branch %s (was %s)" ref - (magit-rev-parse "--short" ref))) - refs) - (dolist (ref refs) - (magit-call-git "update-ref" "-d" ref))) - (user-error "Abort"))) - (magit-refresh)))) - -;;;###autoload -(defun magit-remote-set-head (remote &optional branch) - "Set the local representation of REMOTE's default branch. -Query REMOTE and set the symbolic-ref refs/remotes//HEAD -accordingly. With a prefix argument query for the branch to be -used, which allows you to select an incorrect value if you fancy -doing that." - (interactive - (let ((remote (magit-read-remote "Set HEAD for remote"))) - (list remote - (and current-prefix-arg - (magit-read-remote-branch (format "Set %s/HEAD to" remote) - remote nil nil t))))) - (magit-run-git "remote" "set-head" remote (or branch "--auto"))) - -;;;###autoload -(defun magit-remote-unset-head (remote) - "Unset the local representation of REMOTE's default branch. -Delete the symbolic-ref \"refs/remotes//HEAD\"." - (interactive (list (magit-read-remote "Unset HEAD for remote"))) - (magit-run-git "remote" "set-head" remote "--delete")) - -;;; Configure - -;;;###autoload (autoload 'magit-remote-configure "magit-remote" nil t) -(transient-define-prefix magit-remote-configure (remote) - "Configure a remote." - :man-page "git-remote" - [:description - (lambda () - (concat - (propertize "Configure " 'face 'transient-heading) - (propertize (oref transient--prefix scope) 'face 'magit-branch-remote))) - ("u" magit-remote..url) - ("U" magit-remote..fetch) - ("s" magit-remote..pushurl) - ("S" magit-remote..push) - ("O" magit-remote..tagopt)] - (interactive - (list (or (and (not current-prefix-arg) - (not (and magit-remote-direct-configure - (eq transient-current-command 'magit-remote))) - (magit-get-current-remote)) - (magit--read-remote-scope)))) - (transient-setup 'magit-remote-configure nil nil :scope remote)) - -(defun magit--read-remote-scope (&optional obj) - (magit-read-remote - (if obj - (format "Set %s for remote" - (format (oref obj variable) "")) - "Configure remote"))) - -(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) - -(transient-define-infix magit-remote..fetch () - :class 'magit--git-variable - :scope 'magit--read-remote-scope - :variable "remote.%s.fetch" - :multi-value t) - -(transient-define-infix magit-remote..pushurl () - :class 'magit--git-variable:urls - :scope 'magit--read-remote-scope - :variable "remote.%s.pushurl" - :multi-value t - :history-key 'magit-remote..*url - :seturl-arg "--push") - -(transient-define-infix magit-remote..push () - :class 'magit--git-variable - :scope 'magit--read-remote-scope - :variable "remote.%s.push") - -(transient-define-infix magit-remote..tagopt () - :class 'magit--git-variable:choices - :scope 'magit--read-remote-scope - :variable "remote.%s.tagOpt" - :choices '("--no-tags" "--tags")) - -;;; Transfer Utilities - -(defun magit--push-remote-variable (&optional branch short) - (unless branch - (setq branch (magit-get-current-branch))) - (magit--propertize-face - (if (or (not branch) magit-prefer-push-default) - (if short "pushDefault" "remote.pushDefault") - (if short "pushRemote" (format "branch.%s.pushRemote" branch))) - 'bold)) - -(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)) - (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 changed))) - -;;; _ -(provide 'magit-remote) -;;; magit-remote.el ends here diff --git a/elpa/magit-20210802.1524/magit-repos.el b/elpa/magit-20210802.1524/magit-repos.el deleted file mode 100644 index 271b80a7..00000000 --- a/elpa/magit-20210802.1524/magit-repos.el +++ /dev/null @@ -1,379 +0,0 @@ -;;; magit-repos.el --- listing repositories -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements support for listing repositories. This -;; includes getting a Lisp list of known repositories as well as a -;; mode for listing repositories in a buffer. - -;;; Code: - -(require 'magit-core) - -(declare-function magit-status-setup-buffer "magit-status" (directory)) - -(defvar x-stretch-cursor) - -;;; Options - -(defcustom magit-repository-directories nil - "List of directories that are or contain Git repositories. - -Each element has the form (DIRECTORY . DEPTH). DIRECTORY has -to be a directory or a directory file-name, a string. DEPTH, -an integer, specifies the maximum depth to look for Git -repositories. If it is 0, then only add DIRECTORY itself. - -This option controls which repositories are being listed by -`magit-list-repositories'. It also affects `magit-status' -\(which see) in potentially surprising ways." - :package-version '(magit . "3.0.0") - :group 'magit-essentials - :type '(repeat (cons directory (integer :tag "Depth")))) - -(defgroup magit-repolist nil - "List repositories in a buffer." - :link '(info-link "(magit)Repository List") - :group 'magit-modes) - -(defcustom magit-repolist-mode-hook '(hl-line-mode) - "Hook run after entering Magit-Repolist mode." - :package-version '(magit . "2.9.0") - :group 'magit-repolist - :type 'hook - :get 'magit-hook-custom-get - :options '(hl-line-mode)) - -(defcustom magit-repolist-columns - '(("Name" 25 magit-repolist-column-ident nil) - ("Version" 25 magit-repolist-column-version nil) - ("BU" 3 magit-repolist-column-unpushed-to-upstream - ((:right-align t) - (:help-echo "Local changes not in upstream"))) - ("Path" 99 magit-repolist-column-path nil)) - "List of columns displayed by `magit-list-repositories'. - -Each element has the form (HEADER WIDTH FORMAT PROPS). - -HEADER is the string displayed in the header. WIDTH is the width -of the column. FORMAT is a function that is called with one -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'. -Some entries also use `:help-echo', but `tabulated-list' does not -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" - (string :tag "Header Label") - (integer :tag "Column Width") - (function :tag "Inserter Function") - (repeat :tag "Properties" - (list (choice :tag "Property" - (const :right-align) - (const :pad-right) - (symbol)) - (sexp :tag "Value")))))) - -(defcustom magit-repolist-column-flag-alist - '((magit-untracked-files . "N") - (magit-unstaged-files . "U") - (magit-staged-files . "S")) - "Association list of predicates and flags for `magit-repolist-column-flag'. - -Each element is of the form (FUNCTION . FLAG). Each FUNCTION is -called with no arguments, with `default-directory' bound to the -top level of a repository working tree, until one of them returns -a non-nil value. FLAG corresponding to that function is returned -as the value of `magit-repolist-column-flag'." - :package-version '(magit . "3.0.0") - :group 'magit-repolist - :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 -(defun magit-list-repositories () - "Display a list of repositories. - -Use the options `magit-repository-directories' to control which -repositories are displayed." - (interactive) - (magit-repolist-setup (default-value 'magit-repolist-columns))) - -;;;; Mode - -(defvar magit-repolist-mode-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map tabulated-list-mode-map) - (define-key map (kbd "C-m") 'magit-repolist-status) - map) - "Local keymap for Magit-Repolist mode buffers.") - -(defun magit-repolist-status (&optional _button) - "Show the status for the repository at point." - (interactive) - (--if-let (tabulated-list-get-id) - (magit-status-setup-buffer (expand-file-name it)) - (user-error "There is no repository at point"))) - -(define-derived-mode magit-repolist-mode tabulated-list-mode "Repos" - "Major mode for browsing a list of Git repositories." - (setq-local x-stretch-cursor nil) - (setq tabulated-list-padding 0) - (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 - (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))))) - (message "Listing repositories...") - (tabulated-list-init-header) - (tabulated-list-print) - (message "Listing repositories...done")) - -;;;; Columns - -(defun magit-repolist-column-ident (spec) - "Insert the identification of the repository. -Usually this is just its basename." - (cadr (assq :id spec))) - -(defun magit-repolist-column-path (_) - "Insert the absolute path of the repository." - (abbreviate-file-name default-directory)) - -(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. - (magit-git-string "show" "--no-patch" "--format=%cd-g%h" - "--date=format:%Y%m%d.%H%M")))) - (save-match-data - (when (string-match "-dirty\\'" v) - (magit--put-face (1+ (match-beginning 0)) (length v) 'error v)) - (if (and v (string-match "\\`[0-9]" v)) - (concat " " v) - v)))) - -(defun magit-repolist-column-branch (_) - "Insert the current branch." - (magit-get-current-branch)) - -(defun magit-repolist-column-upstream (_) - "Insert the upstream branch of the current branch." - (magit-get-upstream-branch)) - -(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. -- N if there is at least one untracked file. -- 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." - (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 (spec) - "Insert number of upstream commits not in the current branch." - (--when-let (magit-get-upstream-branch) - (magit-repolist-insert-count (cadr (magit-rev-diff-count "HEAD" it)) spec))) - -(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) - (magit-repolist-insert-count (cadr (magit-rev-diff-count "HEAD" it)) spec))) - -(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) - (magit-repolist-insert-count (car (magit-rev-diff-count "HEAD" it)) spec))) - -(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) - (magit-repolist-insert-count (car (magit-rev-diff-count "HEAD" it)) spec))) - -(defun magit-repolist-column-branches (spec) - "Insert number of branches." - (magit-repolist-insert-count (length (magit-list-local-branches)) - `((:normal-count 1) ,@spec))) - -(defun magit-repolist-column-stashes (spec) - "Insert number of stashes." - (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 - -(defun magit-read-repository (&optional read-directory-name) - "Read a Git repository in the minibuffer, with completion. - -The completion choices are the basenames of top-levels of -repositories found in the directories specified by option -`magit-repository-directories'. In case of name conflicts -the basenames are prefixed with the name of the respective -parent directories. The returned value is the actual path -to the selected repository. - -If READ-DIRECTORY-NAME is non-nil or no repositories can be -found based on the value of `magit-repository-directories', -then read an arbitrary directory using `read-directory-name' -instead." - (if-let ((repos (and (not read-directory-name) - magit-repository-directories - (magit-repos-alist)))) - (let ((reply (magit-completing-read "Git repository" repos))) - (file-name-as-directory - (or (cdr (assoc reply repos)) - (if (file-directory-p reply) - (expand-file-name reply) - (user-error "Not a repository or a directory: %s" reply))))) - (file-name-as-directory - (read-directory-name "Git repository: " - (or (magit-toplevel) default-directory))))) - -(defun magit-list-repos () - (cl-mapcan (pcase-lambda (`(,dir . ,depth)) - (magit-list-repos-1 dir depth)) - magit-repository-directories)) - -(defun magit-list-repos-1 (directory depth) - (cond ((file-readable-p (expand-file-name ".git" directory)) - (list (file-name-as-directory directory))) - ((and (> depth 0) (magit-file-accessible-directory-p directory)) - (--mapcat (and (file-directory-p it) - (magit-list-repos-1 it (1- depth))) - (directory-files directory t - directory-files-no-dot-files-regexp t))))) - -(defun magit-list-repos-uniquify (alist) - (let (result (dict (make-hash-table :test 'equal))) - (dolist (a (delete-dups alist)) - (puthash (car a) (cons (cdr a) (gethash (car a) dict)) dict)) - (maphash - (lambda (key value) - (if (= (length value) 1) - (push (cons key (car value)) result) - (setq result - (append result - (magit-list-repos-uniquify - (--map (cons (concat - key "\\" - (file-name-nondirectory - (directory-file-name - (substring it 0 (- (1+ (length key))))))) - it) - value)))))) - dict) - result)) - -(defun magit-repos-alist () - (magit-list-repos-uniquify - (--map (cons (file-name-nondirectory (directory-file-name it)) it) - (magit-list-repos)))) - -;;; _ -(provide 'magit-repos) -;;; magit-repos.el ends here diff --git a/elpa/magit-20210802.1524/magit-reset.el b/elpa/magit-20210802.1524/magit-reset.el deleted file mode 100644 index 830e27e6..00000000 --- a/elpa/magit-20210802.1524/magit-reset.el +++ /dev/null @@ -1,137 +0,0 @@ -;;; magit-reset.el --- reset fuctionality -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements reset commands. - -;;; Code: - -(require 'magit) - -;;;###autoload (autoload 'magit-reset "magit" nil t) -(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) - "" - ("f" "a file" magit-file-checkout)]) - -;;;###autoload -(defun magit-reset-mixed (commit) - "Reset the `HEAD' and index to COMMIT, but not the working tree. -\n(git reset --mixed COMMIT)" - (interactive (list (magit-reset-read-branch-or-commit "Reset %s to"))) - (magit-reset-internal "--mixed" commit)) - -;;;###autoload -(defun magit-reset-soft (commit) - "Reset the `HEAD' to COMMIT, but not the index and working tree. -\n(git reset --soft REVISION)" - (interactive (list (magit-reset-read-branch-or-commit "Soft reset %s to"))) - (magit-reset-internal "--soft" commit)) - -;;;###autoload -(defun magit-reset-hard (commit) - "Reset the `HEAD', index, and working tree to COMMIT. -\n(git reset --hard REVISION)" - (interactive (list (magit-reset-read-branch-or-commit - (concat (magit--propertize-face "Hard" 'bold) - " reset %s to")))) - (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 -head this effectively unstages all changes. -\n(git reset COMMIT .)" - (interactive (list (magit-read-branch-or-commit "Reset index to"))) - (magit-reset-internal nil commit ".")) - -;;;###autoload -(defun magit-reset-worktree (commit) - "Reset the worktree to COMMIT. -Keep the `HEAD' and index as-is." - (interactive (list (magit-read-branch-or-commit "Reset worktree to"))) - (magit-wip-commit-before-change nil " before reset") - (magit-with-temp-index commit nil - (magit-call-git "checkout-index" "--all" "--force")) - (magit-wip-commit-after-apply nil " after reset") - (magit-refresh)) - -;;;###autoload -(defun magit-reset-quickly (commit &optional hard) - "Reset the `HEAD' and index to COMMIT, and possibly the working tree. -With a prefix argument reset the working tree otherwise don't. -\n(git reset --mixed|--hard COMMIT)" - (interactive (list (magit-reset-read-branch-or-commit - (if current-prefix-arg - (concat (magit--propertize-face "Hard" 'bold) - " reset %s to") - "Reset %s to")) - current-prefix-arg)) - (magit-reset-internal (if hard "--hard" "--mixed") commit)) - -(defun magit-reset-read-branch-or-commit (prompt) - "Prompt for and return a ref to reset HEAD to. - -PROMPT is a format string, where either the current branch name -or \"detached head\" will be substituted for %s." - (magit-read-branch-or-commit - (format prompt (or (magit-get-current-branch) "detached head")))) - -(defun magit-reset-internal (arg commit &optional path) - (when (and (not (member arg '("--hard" nil))) - (equal (magit-rev-parse commit) - (magit-rev-parse "HEAD~"))) - (with-temp-buffer - (magit-git-insert "show" "-s" "--format=%B" "HEAD") - (when git-commit-major-mode - (funcall git-commit-major-mode)) - (git-commit-setup-font-lock) - (git-commit-save-message))) - (let ((cmd (if (and (equal commit "HEAD") (not arg)) "unstage" "reset"))) - (magit-wip-commit-before-change nil (concat " before " cmd)) - (magit-run-git "reset" arg commit "--" path) - (when (equal cmd "unstage") - (magit-wip-commit-after-apply nil " after unstage")))) - -;;; _ -(provide 'magit-reset) -;;; magit-reset.el ends here diff --git a/elpa/magit-20210802.1524/magit-sequence.el b/elpa/magit-20210802.1524/magit-sequence.el deleted file mode 100644 index 79407594..00000000 --- a/elpa/magit-20210802.1524/magit-sequence.el +++ /dev/null @@ -1,1057 +0,0 @@ -;;; magit-sequence.el --- history manipulation in 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. - -;;; Commentary: - -;; Support for Git commands that replay commits and help the user make -;; changes along the way. Supports `cherry-pick', `revert', `rebase', -;; `rebase--interactive' and `am'. - -;;; Code: - -(require 'magit) - -;; For `magit-rebase--todo'. -(declare-function git-rebase-current-line "git-rebase" ()) -(eval-when-compile - (cl-pushnew 'action-type eieio--known-slot-names) - (cl-pushnew 'action eieio--known-slot-names) - (cl-pushnew 'action-options eieio--known-slot-names) - (cl-pushnew 'target eieio--known-slot-names)) - -;;; Options -;;;; Faces - -(defface magit-sequence-pick - '((t :inherit default)) - "Face used in sequence sections." - :group 'magit-faces) - -(defface magit-sequence-stop - '((((class color) (background light)) :foreground "DarkOliveGreen4") - (((class color) (background dark)) :foreground "DarkSeaGreen2")) - "Face used in sequence sections." - :group 'magit-faces) - -(defface magit-sequence-part - '((((class color) (background light)) :foreground "Goldenrod4") - (((class color) (background dark)) :foreground "LightGoldenrod2")) - "Face used in sequence sections." - :group 'magit-faces) - -(defface magit-sequence-head - '((((class color) (background light)) :foreground "SkyBlue4") - (((class color) (background dark)) :foreground "LightSkyBlue1")) - "Face used in sequence sections." - :group 'magit-faces) - -(defface magit-sequence-drop - '((((class color) (background light)) :foreground "IndianRed") - (((class color) (background dark)) :foreground "IndianRed")) - "Face used in sequence sections." - :group 'magit-faces) - -(defface magit-sequence-done - '((t :inherit magit-hash)) - "Face used in sequence sections." - :group 'magit-faces) - -(defface magit-sequence-onto - '((t :inherit magit-sequence-done)) - "Face used in sequence sections." - :group 'magit-faces) - -(defface magit-sequence-exec - '((t :inherit magit-hash)) - "Face used in sequence sections." - :group 'magit-faces) - -;;; Common - -;;;###autoload -(defun magit-sequencer-continue () - "Resume the current cherry-pick or revert sequence." - (interactive) - (if (magit-sequencer-in-progress-p) - (if (magit-anything-unstaged-p t) - (user-error "Cannot continue due to unstaged changes") - (magit-run-git-sequencer - (if (magit-revert-in-progress-p) "revert" "cherry-pick") "--continue")) - (user-error "No cherry-pick or revert in progress"))) - -;;;###autoload -(defun magit-sequencer-skip () - "Skip the stopped at commit during a cherry-pick or revert sequence." - (interactive) - (if (magit-sequencer-in-progress-p) - (progn (magit-call-git "reset" "--hard") - (magit-sequencer-continue)) - (user-error "No cherry-pick or revert in progress"))) - -;;;###autoload -(defun magit-sequencer-abort () - "Abort the current cherry-pick or revert sequence. -This discards all changes made since the sequence started." - (interactive) - (if (magit-sequencer-in-progress-p) - (magit-run-git-sequencer - (if (magit-revert-in-progress-p) "revert" "cherry-pick") "--abort") - (user-error "No cherry-pick or revert in progress"))) - -(defun magit-sequencer-in-progress-p () - (or (magit-cherry-pick-in-progress-p) - (magit-revert-in-progress-p))) - -;;; Cherry-Pick - -(defvar magit-perl-executable "perl" - "The Perl executable.") - -;;;###autoload (autoload 'magit-cherry-pick "magit-sequence" nil t) -(transient-define-prefix magit-cherry-pick () - "Apply or transplant commits." - :man-page "git-cherry-pick" - :value '("--ff") - :incompatible '(("--ff" "-x")) - ["Arguments" - :if-not magit-sequencer-in-progress-p - (magit-cherry-pick:--mainline) - ("=s" magit-merge:--strategy) - ("-F" "Attempt fast-forward" "--ff") - ("-x" "Reference cherry in commit message" "-x") - ("-e" "Edit commit messages" ("-e" "--edit")) - ("-s" "Add Signed-off-by lines" ("-s" "--signoff")) - (5 magit:--gpg-sign)] - [:if-not magit-sequencer-in-progress-p - ["Apply here" - ("A" "Pick" magit-cherry-copy) - ("a" "Apply" magit-cherry-apply) - ("h" "Harvest" magit-cherry-harvest) - ("m" "Squash" magit-merge-squash)] - ["Apply elsewhere" - ("d" "Donate" magit-cherry-donate) - ("n" "Spinout" magit-cherry-spinout) - ("s" "Spinoff" magit-cherry-spinoff)]] - ["Actions" - :if magit-sequencer-in-progress-p - ("A" "Continue" magit-sequencer-continue) - ("s" "Skip" magit-sequencer-skip) - ("a" "Abort" magit-sequencer-abort)]) - -(transient-define-argument magit-cherry-pick:--mainline () - :description "Replay merge relative to parent" - :class 'transient-option - :shortarg "-m" - :argument "--mainline=" - :reader 'transient-read-number-N+) - -(defun magit-cherry-pick-read-args (prompt) - (list (or (nreverse (magit-region-values 'commit)) - (magit-read-other-branch-or-commit prompt)) - (transient-args 'magit-cherry-pick))) - -(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)))) - -(defun magit--cherry-spinoff-read-args (verb) - (magit--cherry-move-read-args verb t - (lambda (commits) - (magit-branch-read-args - (format "Create branch from %s cherries" (length commits)) - (magit-get-upstream-branch))))) - -;;;###autoload -(defun magit-cherry-copy (commits &optional args) - "Copy COMMITS from another branch onto the current branch. -Prompt for a commit, defaulting to the commit at point. If -the region selects multiple commits, then pick all of them, -without prompting." - (interactive (magit-cherry-pick-read-args "Cherry-pick")) - (magit--cherry-pick commits args)) - -;;;###autoload -(defun magit-cherry-apply (commits &optional args) - "Apply the changes in COMMITS but do not commit them. -Prompt for a commit, defaulting to the commit at point. If -the region selects multiple commits, then apply all of them, -without prompting." - (interactive (magit-cherry-pick-read-args "Apply changes from commit")) - (magit--cherry-pick commits (cons "--no-commit" (remove "--ff" args)))) - -;;;###autoload -(defun magit-cherry-harvest (commits branch &optional args) - "Move COMMITS from another BRANCH onto the current branch. -Remove the COMMITS from BRANCH and stay on the current branch. -If a conflict occurs, then you have to fix that and finish the -process manually." - (interactive - (magit--cherry-move-read-args "harvest" nil - (lambda (commits) - (list (let ((branches (magit-list-containing-branches (car commits)))) - (pcase (length branches) - (0 nil) - (1 (car branches)) - (_ (magit-completing-read - (format "Remove %s cherries from branch" (length commits)) - branches nil t)))))))) - (magit--cherry-move commits branch (magit-get-current-branch) args nil t)) - -;;;###autoload -(defun magit-cherry-donate (commits branch &optional args) - "Move COMMITS from the current branch onto another existing BRANCH. -Remove COMMITS from the current branch and stay on that branch. -If a conflict occurs, then you have to fix that and finish the -process manually." - (interactive - (magit--cherry-move-read-args "donate" t - (lambda (commits) - (list (magit-read-other-branch (format "Move %s cherries to branch" - (length commits))))))) - (magit--cherry-move commits (magit-get-current-branch) branch args)) - -;;;###autoload -(defun magit-cherry-spinout (commits branch start-point &optional args) - "Move COMMITS from the current branch onto a new BRANCH. -Remove COMMITS from the current branch and stay on that branch. -If a conflict occurs, then you have to fix that and finish the -process manually." - (interactive (magit--cherry-spinoff-read-args "spinout")) - (magit--cherry-move commits (magit-get-current-branch) branch args - start-point)) - -;;;###autoload -(defun magit-cherry-spinoff (commits branch start-point &optional args) - "Move COMMITS from the current branch onto a new BRANCH. -Remove COMMITS from the current branch and checkout BRANCH. -If a conflict occurs, then you have to fix that and finish -the process manually." - (interactive (magit--cherry-spinoff-read-args "spinoff")) - (magit--cherry-move commits (magit-get-current-branch) branch args - start-point t)) - -(defun magit--cherry-move (commits src dst args - &optional start-point checkout-dst) - (let ((current (magit-get-current-branch))) - (unless (magit-branch-p dst) - (let ((magit-process-raise-error t)) - (magit-call-git "branch" dst start-point)) - (--when-let (magit-get-indirect-upstream-branch start-point) - (magit-call-git "branch" "--set-upstream-to" it dst))) - (unless (equal dst current) - (let ((magit-process-raise-error t)) - (magit-call-git "checkout" dst))) - (if (not src) ; harvest only - (magit--cherry-pick commits args) - (let ((tip (car (last commits))) - (keep (concat (car commits) "^"))) - (magit--cherry-pick commits args) - (set-process-sentinel - magit-this-process - (lambda (process event) - (when (memq (process-status process) '(exit signal)) - (if (> (process-exit-status process) 0) - (magit-process-sentinel process event) - (process-put process 'inhibit-refresh t) - (magit-process-sentinel process event) - (cond - ((magit-rev-equal tip src) - (magit-call-git "update-ref" - "-m" (format "reset: moving to %s" keep) - (magit-ref-fullname src) - keep tip) - (if (not checkout-dst) - (magit-run-git "checkout" src) - (magit-refresh))) - (t - (magit-git "checkout" src) - (let ((process-environment process-environment)) - (push (format "%s=%s -i -ne '/^pick (%s)/ or print'" - "GIT_SEQUENCE_EDITOR" - magit-perl-executable - (mapconcat #'magit-rev-abbrev commits "|")) - process-environment) - (magit-run-git-sequencer "rebase" "-i" keep)) - (when checkout-dst - (set-process-sentinel - magit-this-process - (lambda (process event) - (when (memq (process-status process) '(exit signal)) - (if (> (process-exit-status process) 0) - (magit-process-sentinel process event) - (process-put process 'inhibit-refresh t) - (magit-process-sentinel process event) - (magit-run-git "checkout" dst)))))))))))))))) - -(defun magit--cherry-pick (commits args &optional revert) - (let ((command (if revert "revert" "cherry-pick"))) - (when (stringp commits) - (setq commits (if (string-match-p "\\.\\." commits) - (split-string commits "\\.\\.") - (list commits)))) - (magit-run-git-sequencer - (if revert "revert" "cherry-pick") - (pcase-let ((`(,merge ,non-merge) - (-separate 'magit-merge-commit-p commits))) - (cond - ((not merge) - (--remove (string-prefix-p "--mainline=" it) args)) - (non-merge - (user-error "Cannot %s merge and non-merge commits at once" - command)) - ((--first (string-prefix-p "--mainline=" it) args) - args) - (t - (cons (format "--mainline=%s" - (read-number "Replay merges relative to parent: ")) - args)))) - commits))) - -(defun magit-cherry-pick-in-progress-p () - ;; .git/sequencer/todo does not exist when there is only one commit left. - (file-exists-p (magit-git-dir "CHERRY_PICK_HEAD"))) - -;;; Revert - -;;;###autoload (autoload 'magit-revert "magit-sequence" nil t) -(transient-define-prefix magit-revert () - "Revert existing commits, with or without creating new commits." - :man-page "git-revert" - :value '("--edit") - ["Arguments" - :if-not magit-sequencer-in-progress-p - (magit-cherry-pick:--mainline) - ("-e" "Edit commit message" ("-e" "--edit")) - ("-E" "Don't edit commit message" "--no-edit") - ("=s" magit-merge:--strategy) - ("-s" "Add Signed-off-by lines" ("-s" "--signoff")) - (5 magit:--gpg-sign)] - ["Actions" - :if-not magit-sequencer-in-progress-p - ("V" "Revert commit(s)" magit-revert-and-commit) - ("v" "Revert changes" magit-revert-no-commit)] - ["Actions" - :if magit-sequencer-in-progress-p - ("V" "Continue" magit-sequencer-continue) - ("s" "Skip" magit-sequencer-skip) - ("a" "Abort" magit-sequencer-abort)]) - -(defun magit-revert-read-args (prompt) - (list (or (magit-region-values 'commit) - (magit-read-branch-or-commit prompt)) - (transient-args 'magit-revert))) - -;;;###autoload -(defun magit-revert-and-commit (commit &optional args) - "Revert COMMIT by creating a new commit. -Prompt for a commit, defaulting to the commit at point. If -the region selects multiple commits, then revert all of them, -without prompting." - (interactive (magit-revert-read-args "Revert commit")) - (magit--cherry-pick commit args t)) - -;;;###autoload -(defun magit-revert-no-commit (commit &optional args) - "Revert COMMIT by applying it in reverse to the worktree. -Prompt for a commit, defaulting to the commit at point. If -the region selects multiple commits, then revert all of them, -without prompting." - (interactive (magit-revert-read-args "Revert changes")) - (magit--cherry-pick commit (cons "--no-commit" args) t)) - -(defun magit-revert-in-progress-p () - ;; .git/sequencer/todo does not exist when there is only one commit left. - (file-exists-p (magit-git-dir "REVERT_HEAD"))) - -;;; Patch - -;;;###autoload (autoload 'magit-am "magit-sequence" nil t) -(transient-define-prefix magit-am () - "Apply patches received by email." - :man-page "git-am" - :value '("--3way") - ["Arguments" - :if-not magit-am-in-progress-p - ("-3" "Fall back on 3way merge" ("-3" "--3way")) - (magit-apply:-p) - ("-c" "Remove text before scissors line" ("-c" "--scissors")) - ("-k" "Inhibit removal of email cruft" ("-k" "--keep")) - ("-b" "Limit removal of email cruft" "--keep-non-patch") - ("-d" "Use author date as committer date" "--committer-date-is-author-date") - ("-D" "Use committer date as author date" "--ignore-date") - ("-s" "Add Signed-off-by lines" ("-s" "--signoff")) - (5 magit:--gpg-sign)] - ["Apply" - :if-not magit-am-in-progress-p - ("m" "maildir" magit-am-apply-maildir) - ("w" "patches" magit-am-apply-patches) - ("a" "plain patch" magit-patch-apply)] - ["Actions" - :if magit-am-in-progress-p - ("w" "Continue" magit-am-continue) - ("s" "Skip" magit-am-skip) - ("a" "Abort" magit-am-abort)]) - -(defun magit-am-arguments () - (transient-args 'magit-am)) - -(transient-define-argument magit-apply:-p () - :description "Remove leading slashes from paths" - :class 'transient-option - :argument "-p" - :reader 'transient-read-number-N+) - -;;;###autoload -(defun magit-am-apply-patches (&optional files args) - "Apply the patches FILES." - (interactive (list (or (magit-region-values 'file) - (list (let ((default (magit-file-at-point))) - (read-file-name - (if default - (format "Apply patch (%s): " default) - "Apply patch: ") - nil default)))) - (magit-am-arguments))) - (magit-run-git-sequencer "am" args "--" - (--map (magit-convert-filename-for-git - (expand-file-name it)) - files))) - -;;;###autoload -(defun magit-am-apply-maildir (&optional maildir args) - "Apply the patches from MAILDIR." - (interactive (list (read-file-name "Apply mbox or Maildir: ") - (magit-am-arguments))) - (magit-run-git-sequencer "am" args (magit-convert-filename-for-git - (expand-file-name maildir)))) - -;;;###autoload -(defun magit-am-continue () - "Resume the current patch applying sequence." - (interactive) - (if (magit-am-in-progress-p) - (if (magit-anything-unstaged-p t) - (error "Cannot continue due to unstaged changes") - (magit-run-git-sequencer "am" "--continue")) - (user-error "Not applying any patches"))) - -;;;###autoload -(defun magit-am-skip () - "Skip the stopped at patch during a patch applying sequence." - (interactive) - (if (magit-am-in-progress-p) - (magit-run-git-sequencer "am" "--skip") - (user-error "Not applying any patches"))) - -;;;###autoload -(defun magit-am-abort () - "Abort the current patch applying sequence. -This discards all changes made since the sequence started." - (interactive) - (if (magit-am-in-progress-p) - (magit-run-git "am" "--abort") - (user-error "Not applying any patches"))) - -(defun magit-am-in-progress-p () - (file-exists-p (magit-git-dir "rebase-apply/applying"))) - -;;; Rebase - -;;;###autoload (autoload 'magit-rebase "magit-sequence" nil t) -(transient-define-prefix magit-rebase () - "Transplant commits and/or modify existing commits." - :man-page "git-rebase" - ["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") - ("-i" "Interactive" ("-i" "--interactive")) - ("-h" "Disable hooks" "--no-verify") - (7 magit-rebase:--exec) - (5 magit:--gpg-sign) - (5 "-r" "Rebase merges" "--rebase-merges=" magit-rebase-merges-select-mode)] - [:if-not magit-rebase-in-progress-p - :description (lambda () - (format (propertize "Rebase %s onto" 'face 'transient-heading) - (propertize (or (magit-get-current-branch) "HEAD") - 'face 'magit-branch-local))) - ("p" magit-rebase-onto-pushremote) - ("u" magit-rebase-onto-upstream) - ("e" "elsewhere" magit-rebase-branch)] - ["Rebase" - :if-not magit-rebase-in-progress-p - [("i" "interactively" magit-rebase-interactive) - ("s" "a subset" magit-rebase-subset)] - [("m" "to modify a commit" magit-rebase-edit-commit) - ("w" "to reword a commit" magit-rebase-reword-commit) - ("k" "to remove a commit" magit-rebase-remove-commit) - ("f" "to autosquash" magit-rebase-autosquash) - (6 "t" "to change dates" magit-reshelve-since)]] - ["Actions" - :if magit-rebase-in-progress-p - ("r" "Continue" magit-rebase-continue) - ("s" "Skip" magit-rebase-skip) - ("e" "Edit" magit-rebase-edit) - ("a" "Abort" magit-rebase-abort)]) - -(transient-define-argument magit-rebase:--exec () - :description "Run command after commits" - :class 'transient-option - :shortarg "-x" - :argument "--exec=" - :reader #'read-shell-command) - -(defun magit-rebase-merges-select-mode (&rest _ignore) - (magit-read-char-case nil t - (?n "[n]o-rebase-cousins" "no-rebase-cousins") - (?r "[r]ebase-cousins" "rebase-cousins"))) - -(defun magit-rebase-arguments () - (transient-args 'magit-rebase)) - -(defun magit-git-rebase (target args) - (magit-run-git-sequencer "rebase" args target)) - -;;;###autoload (autoload 'magit-rebase-onto-pushremote "magit-sequence" nil t) -(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 -configured or unusable, then let the user first configure the -push-remote." - :if 'magit-get-current-branch - :description 'magit-pull--pushbranch-description - (interactive (list (magit-rebase-arguments))) - (pcase-let ((`(,branch ,remote) - (magit--select-push-remote "rebase onto that"))) - (magit-git-rebase (concat remote "/" branch) args))) - -;;;###autoload (autoload 'magit-rebase-onto-upstream "magit-sequence" nil t) -(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 -configured or unusable, then let the user first configure -the upstream." - :if 'magit-get-current-branch - :description 'magit-rebase--upstream-description - (interactive (list (magit-rebase-arguments))) - (let* ((branch (or (magit-get-current-branch) - (user-error "No branch is checked out"))) - (upstream (magit-get-upstream-branch branch))) - (when (or current-prefix-arg (not upstream)) - (setq upstream - (magit-read-upstream-branch - branch (format "Set upstream of %s and rebase onto that" branch))) - (magit-set-upstream-branch branch upstream)) - (magit-git-rebase upstream args))) - -(defun magit-rebase--upstream-description () - (when-let ((branch (magit-get-current-branch))) - (or (magit-get-upstream-branch branch) - (let ((remote (magit-get "branch" branch "remote")) - (merge (magit-get "branch" branch "merge")) - (u (magit--propertize-face "@{upstream}" 'bold))) - (cond - ((magit--unnamed-upstream-p remote merge) - (concat u ", replacing unnamed")) - ((magit--valid-upstream-p remote merge) - (concat u ", replacing non-existent")) - ((or remote merge) - (concat u ", replacing invalid")) - (t - (concat u ", setting that"))))))) - -;;;###autoload -(defun magit-rebase-branch (target args) - "Rebase the current branch onto a branch read in the minibuffer. -All commits that are reachable from `HEAD' but not from the -selected branch TARGET are being rebased." - (interactive (list (magit-read-other-branch-or-commit "Rebase onto") - (magit-rebase-arguments))) - (message "Rebasing...") - (magit-git-rebase target args) - (message "Rebasing...done")) - -;;;###autoload -(defun magit-rebase-subset (newbase start args) - "Rebase a subset of the current branch's history onto a new base. -Rebase commits from START to `HEAD' onto NEWBASE. -START has to be selected from a list of recent commits." - (interactive (list (magit-read-other-branch-or-commit - "Rebase subset onto" nil - (magit-get-upstream-branch)) - nil - (magit-rebase-arguments))) - (if start - (progn (message "Rebasing...") - (magit-run-git-sequencer "rebase" "--onto" newbase start args) - (message "Rebasing...done")) - (magit-log-select - `(lambda (commit) - (magit-rebase-subset ,newbase (concat commit "^") (list ,@args))) - (concat "Type %p on a commit to rebase it " - "and commits above it onto " newbase ",")))) - -(defvar magit-rebase-interactive-include-selected t) - -(defun magit-rebase-interactive-1 - (commit args message &optional editor delay-edit-confirm noassert confirm) - (declare (indent 2)) - (when commit - (if (eq commit :merge-base) - (setq commit (--if-let (magit-get-upstream-branch) - (magit-git-string "merge-base" it "HEAD") - nil)) - (unless (magit-rev-ancestor-p commit "HEAD") - (user-error "%s isn't an ancestor of HEAD" commit)) - (if (magit-commit-parents commit) - (when (or (not (eq this-command 'magit-rebase-interactive)) - magit-rebase-interactive-include-selected) - (setq commit (concat commit "^"))) - (setq args (cons "--root" args))))) - (when (and commit (not noassert)) - (setq commit (magit-rebase-interactive-assert - commit delay-edit-confirm - (--some (string-prefix-p "--rebase-merges" it) args)))) - (if (and commit (not confirm)) - (let ((process-environment process-environment)) - (when editor - (push (concat "GIT_SEQUENCE_EDITOR=" - (if (functionp editor) - (funcall editor commit) - editor)) - process-environment)) - (magit-run-git-sequencer "rebase" "-i" args - (unless (member "--root" args) commit))) - (magit-log-select - `(lambda (commit) - ;; 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) -(defvar magit--rebase-public-edit-confirmed nil) - -(defun magit-rebase-interactive-assert - (since &optional delay-edit-confirm rebase-merges) - (let* ((commit (magit-rebase--target-commit since)) - (branches (magit-list-publishing-branches commit))) - (setq magit--rebase-public-edit-confirmed - (delete (magit-toplevel) magit--rebase-public-edit-confirmed)) - (when (and branches - (or (not delay-edit-confirm) - ;; The user might have stopped at a published commit - ;; merely to add new commits *after* it. Try not to - ;; ask users whether they really want to edit public - ;; commits, when they don't actually intend to do so. - (not (--all-p (magit-rev-equal it commit) branches)))) - (let ((m1 "Some of these commits have already been published to ") - (m2 ".\nDo you really want to modify them")) - (magit-confirm (or magit--rebase-published-symbol 'rebase-published) - (concat m1 "%s" m2) - (concat m1 "%i public branches" m2) - nil branches)) - (push (magit-toplevel) magit--rebase-public-edit-confirmed))) - (if (and (magit-git-lines "rev-list" "--merges" (concat since "..HEAD")) - (not rebase-merges)) - (magit-read-char-case "Proceed despite merge in rebase range? " nil - (?c "[c]ontinue" since) - (?s "[s]elect other" nil) - (?a "[a]bort" (user-error "Quit"))) - since)) - -(defun magit-rebase--target-commit (since) - (if (string-suffix-p "^" since) - ;; If SINCE is "REV^", then the user selected - ;; "REV", which is the first commit that will - ;; be replaced. (from^..to] <=> [from..to] - (substring since 0 -1) - ;; The "--root" argument is being used. - since)) - -;;;###autoload -(defun magit-rebase-interactive (commit args) - "Start an interactive rebase sequence." - (interactive (list (magit-commit-at-point) - (magit-rebase-arguments))) - (magit-rebase-interactive-1 commit args - "Type %p on a commit to rebase it and all commits above it," - nil t)) - -;;;###autoload -(defun magit-rebase-autosquash (args) - "Combine squash and fixup commits with their intended targets." - (interactive (list (magit-rebase-arguments))) - (magit-rebase-interactive-1 :merge-base - (nconc (list "--autosquash" "--keep-empty") args) - "Type %p on a commit to squash into it and then rebase as necessary," - "true" nil t)) - -;;;###autoload -(defun magit-rebase-edit-commit (commit args) - "Edit 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 edit it," - (apply-partially #'magit-rebase--perl-editor 'edit) - t)) - -;;;###autoload -(defun magit-rebase-reword-commit (commit args) - "Reword 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 reword its message," - (apply-partially #'magit-rebase--perl-editor 'reword))) - -;;;###autoload -(defun magit-rebase-remove-commit (commit args) - "Remove a single older commit using rebase." - (interactive (list (magit-commit-at-point) - (magit-rebase-arguments))) - ;; 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)))) - (format "%s -i -p -e '++$x if not $x and s/^pick %s/%s %s/'" - magit-perl-executable - commit - (cl-case action - (edit "edit") - (remove "noop\n# pick") - (reword "reword") - (t (error "unknown action: %s" action))) - commit))) - -;;;###autoload -(defun magit-rebase-continue (&optional noedit) - "Restart the current rebasing operation. -In some cases this pops up a commit message buffer for you do -edit. With a prefix argument the old message is reused as-is." - (interactive "P") - (if (magit-rebase-in-progress-p) - (if (magit-anything-unstaged-p t) - (user-error "Cannot continue rebase with unstaged changes") - (when (and (magit-anything-staged-p) - (file-exists-p (magit-git-dir "rebase-merge")) - (not (member (magit-toplevel) - magit--rebase-public-edit-confirmed))) - (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) - (magit-run-git-async (magit--rebase-resume-command) "--continue") - (set-process-sentinel magit-this-process - #'magit-sequencer-process-sentinel) - magit-this-process) - (magit-run-git-sequencer (magit--rebase-resume-command) "--continue"))) - (user-error "No rebase in progress"))) - -;;;###autoload -(defun magit-rebase-skip () - "Skip the current commit and restart the current rebase operation." - (interactive) - (unless (magit-rebase-in-progress-p) - (user-error "No rebase in progress")) - (magit-run-git-sequencer (magit--rebase-resume-command) "--skip")) - -;;;###autoload -(defun magit-rebase-edit () - "Edit the todo list of the current rebase operation." - (interactive) - (unless (magit-rebase-in-progress-p) - (user-error "No rebase in progress")) - (magit-run-git-sequencer "rebase" "--edit-todo")) - -;;;###autoload -(defun magit-rebase-abort () - "Abort the current rebase operation, restoring the original branch." - (interactive) - (unless (magit-rebase-in-progress-p) - (user-error "No rebase in progress")) - (magit-confirm 'abort-rebase "Abort this rebase") - (magit-run-git (magit--rebase-resume-command) "--abort")) - -(defun magit-rebase-in-progress-p () - "Return t if a rebase is in progress." - (or (file-exists-p (magit-git-dir "rebase-merge")) - (file-exists-p (magit-git-dir "rebase-apply/onto")))) - -(defun magit--rebase-resume-command () - (if (file-exists-p (magit-git-dir "rebase-recursive")) "rbr" "rebase")) - -;;; Sections - -(defun magit-insert-sequencer-sequence () - "Insert section for the on-going cherry-pick or revert sequence. -If no such sequence is in progress, do nothing." - (let ((picking (magit-cherry-pick-in-progress-p))) - (when (or picking (magit-revert-in-progress-p)) - (magit-insert-section (sequence) - (magit-insert-heading (if picking "Cherry Picking" "Reverting")) - (when-let ((lines - (cdr (magit-file-lines (magit-git-dir "sequencer/todo"))))) - (dolist (line (nreverse lines)) - (when (string-match - "^\\(pick\\|revert\\) \\([^ ]+\\) \\(.*\\)$" line) - (magit-bind-match-strings (cmd hash msg) line - (magit-insert-section (commit hash) - (insert (propertize cmd 'font-lock-face 'magit-sequence-pick) - " " (propertize hash 'font-lock-face 'magit-hash) - " " msg "\n")))))) - (magit-sequence-insert-sequence - (magit-file-line (magit-git-dir (if picking - "CHERRY_PICK_HEAD" - "REVERT_HEAD"))) - (magit-file-line (magit-git-dir "sequencer/head"))) - (insert "\n"))))) - -(defun magit-insert-am-sequence () - "Insert section for the on-going patch applying sequence. -If no such sequence is in progress, do nothing." - (when (magit-am-in-progress-p) - (magit-insert-section (rebase-sequence) - (magit-insert-heading "Applying patches") - (let ((patches (nreverse (magit-rebase-patches))) - patch commit) - (while patches - (setq patch (pop patches)) - (setq commit (magit-commit-p - (cadr (split-string (magit-file-line patch))))) - (cond ((and commit patches) - (magit-sequence-insert-commit - "pick" commit 'magit-sequence-pick)) - (patches - (magit-sequence-insert-am-patch - "pick" patch 'magit-sequence-pick)) - (commit - (magit-sequence-insert-sequence commit "ORIG_HEAD")) - (t - (magit-sequence-insert-am-patch - "stop" patch 'magit-sequence-stop) - (magit-sequence-insert-sequence nil "ORIG_HEAD"))))) - (insert ?\n)))) - -(defun magit-sequence-insert-am-patch (type patch face) - (magit-insert-section (file patch) - (let ((title - (with-temp-buffer - (insert-file-contents patch nil nil 4096) - (unless (re-search-forward "^Subject: " nil t) - (goto-char (point-min))) - (buffer-substring (point) (line-end-position))))) - (insert (propertize type 'font-lock-face face) - ?\s (propertize (file-name-nondirectory patch) - 'font-lock-face 'magit-hash) - ?\s title - ?\n)))) - -(defun magit-insert-rebase-sequence () - "Insert section for the on-going rebase sequence. -If no such sequence is in progress, do nothing." - (when (magit-rebase-in-progress-p) - (let* ((interactive (file-directory-p (magit-git-dir "rebase-merge"))) - (dir (if interactive "rebase-merge/" "rebase-apply/")) - (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))) - (magit-insert-section (rebase-sequence) - (magit-insert-heading (format "Rebasing %s onto %s" name onto)) - (if interactive - (magit-rebase-insert-merge-sequence onto) - (magit-rebase-insert-apply-sequence onto)) - (insert ?\n))))) - -(defun magit-rebase--todo () - "Return `git-rebase-action' instances for remaining rebase actions. -These are ordered in that the same way they'll be sorted in the -status buffer (i.e. the reverse of how they will be applied)." - (let ((comment-start (or (magit-get "core.commentChar") "#")) - lines) - (with-temp-buffer - (insert-file-contents (magit-git-dir "rebase-merge/git-rebase-todo")) - (while (not (eobp)) - (let ((ln (git-rebase-current-line))) - (when (oref ln action-type) - (push ln lines))) - (forward-line))) - lines)) - -(defun magit-rebase-insert-merge-sequence (onto) - (dolist (line (magit-rebase--todo)) - (with-slots (action-type action action-options target) line - (pcase action-type - (`commit - (magit-sequence-insert-commit action target 'magit-sequence-pick)) - ((or (or `exec `label) - (and `merge (guard (not action-options)))) - (insert (propertize action 'font-lock-face 'magit-sequence-onto) "\s" - (propertize target 'font-lock-face 'git-rebase-label) "\n")) - (`merge - (if-let ((hash (and (string-match "-[cC] \\([^ ]+\\)" action-options) - (match-string 1 action-options)))) - (magit-insert-section (commit hash) - (magit-insert-heading - (propertize "merge" 'font-lock-face 'magit-sequence-pick) - "\s" - (magit-format-rev-summary hash) "\n")) - (error "failed to parse merge message hash")))))) - (magit-sequence-insert-sequence - (magit-file-line (magit-git-dir "rebase-merge/stopped-sha")) - onto - (--when-let (magit-file-lines (magit-git-dir "rebase-merge/done")) - (cadr (split-string (car (last it))))))) - -(defun magit-rebase-insert-apply-sequence (onto) - (let ((rewritten - (--map (car (split-string it)) - (magit-file-lines (magit-git-dir "rebase-apply/rewritten")))) - (stop (magit-file-line (magit-git-dir "rebase-apply/original-commit")))) - (dolist (patch (nreverse (cdr (magit-rebase-patches)))) - (let ((hash (cadr (split-string (magit-file-line patch))))) - (unless (or (member hash rewritten) - (equal hash stop)) - (magit-sequence-insert-commit "pick" hash 'magit-sequence-pick))))) - (magit-sequence-insert-sequence - (magit-file-line (magit-git-dir "rebase-apply/original-commit")) - onto)) - -(defun magit-rebase-patches () - (directory-files (magit-git-dir "rebase-apply") t "^[0-9]\\{4\\}$")) - -(defun magit-sequence-insert-sequence (stop onto &optional orig) - (let ((head (magit-rev-parse "HEAD")) done) - (setq onto (if onto (magit-rev-parse onto) head)) - (setq done (magit-git-lines "log" "--format=%H" (concat onto "..HEAD"))) - (when (and stop (not (member (magit-rev-parse stop) done))) - (let ((id (magit-patch-id stop))) - (--if-let (--first (equal (magit-patch-id it) id) done) - (setq stop it) - (cond - ((--first (magit-rev-equal it stop) done) - ;; The commit's testament has been executed. - (magit-sequence-insert-commit "void" stop 'magit-sequence-drop)) - ;; The faith of the commit is still undecided... - ((magit-anything-unmerged-p) - ;; ...and time travel isn't for the faint of heart. - (magit-sequence-insert-commit "join" stop 'magit-sequence-part)) - ((magit-anything-modified-p t) - ;; ...and the dust hasn't settled yet... - (magit-sequence-insert-commit - (let* ((magit--refresh-cache nil) - (staged (magit-commit-tree "oO" nil "HEAD")) - (unstaged (magit-commit-worktree "oO" "--reset"))) - (cond - ;; ...but we could end up at the same tree just by committing. - ((or (magit-rev-equal staged stop) - (magit-rev-equal unstaged stop)) "goal") - ;; ...but the changes are still there, untainted. - ((or (equal (magit-patch-id staged) id) - (equal (magit-patch-id unstaged) id)) "same") - ;; ...and some changes are gone and/or others were added. - (t "work"))) - stop 'magit-sequence-part)) - ;; The commit is definitely gone... - ((--first (magit-rev-equal it stop) done) - ;; ...but all of its changes are still in effect. - (magit-sequence-insert-commit "poof" stop 'magit-sequence-drop)) - (t - ;; ...and some changes are gone and/or other changes were added. - (magit-sequence-insert-commit "gone" stop 'magit-sequence-drop))) - (setq stop nil)))) - (dolist (rev done) - (apply 'magit-sequence-insert-commit - (cond ((equal rev stop) - ;; ...but its reincarnation lives on. - ;; Or it didn't die in the first place. - (list (if (and (equal rev head) - (equal (magit-patch-id rev) - (magit-patch-id orig))) - "stop" ; We haven't done anything yet. - "like") ; There are new commits. - rev (if (equal rev head) - 'magit-sequence-head - 'magit-sequence-stop))) - ((equal rev head) - (list "done" rev 'magit-sequence-head)) - (t - (list "done" rev 'magit-sequence-done))))) - (magit-sequence-insert-commit "onto" 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-heading - (propertize type 'font-lock-face face) "\s" - (magit-format-rev-summary hash) "\n"))) - -;;; _ -(provide 'magit-sequence) -;;; magit-sequence.el ends here diff --git a/elpa/magit-20210802.1524/magit-stash.el b/elpa/magit-20210802.1524/magit-stash.el deleted file mode 100644 index 3ff6858f..00000000 --- a/elpa/magit-20210802.1524/magit-stash.el +++ /dev/null @@ -1,544 +0,0 @@ -;;; magit-stash.el --- stash support for Magit -*- lexical-binding: t -*- - -;; 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) -;; 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. - -;;; Commentary: - -;; Support for Git stashes. - -;;; Code: - -(require 'magit) -(require 'magit-reflog) - -;; For `magit-stash-drop'. -(defvar helm-comp-read-use-marked) - -;;; Options - -(defgroup magit-stash nil - "List stashes and show stash diffs." - :group 'magit-modes) - -;;;; Diff options - -(defcustom magit-stash-sections-hook - '(magit-insert-stash-notes - magit-insert-stash-worktree - magit-insert-stash-index - magit-insert-stash-untracked) - "Hook run to insert sections into stash diff buffers." - :package-version '(magit . "2.1.0") - :group 'magit-stash - :type 'hook) - -;;;; Log options - -(defcustom magit-stashes-margin - (list (nth 0 magit-log-margin) - (nth 1 magit-log-margin) - 'magit-log-margin-width nil - (nth 4 magit-log-margin)) - "Format of the margin in `magit-stashes-mode' buffers. - -The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). - -If INIT is non-nil, then the margin is shown initially. -STYLE controls how to format the author or committer date. - It can be one of `age' (to show the age of the commit), - `age-abbreviated' (to abbreviate the time unit to a character), - or a string (suitable for `format-time-string') to show the - actual date. Option `magit-log-margin-show-committer-date' - controls which date is being displayed. -WIDTH controls the width of the margin. This exists for forward - compatibility and currently the value should not be changed. -AUTHOR controls whether the name of the author is also shown by - default. -AUTHOR-WIDTH has to be an integer. When the name of the author - is shown, then this specifies how much space is used to do so." - :package-version '(magit . "2.9.0") - :group 'magit-stash - :group 'magit-margin - :type magit-log-margin--custom-type - :initialize 'magit-custom-initialize-reset - :set-after '(magit-log-margin) - :set (apply-partially #'magit-margin-set-variable 'magit-stashes-mode)) - -;;; Commands - -;;;###autoload (autoload 'magit-stash "magit-stash" nil t) -(transient-define-prefix magit-stash () - "Stash uncommitted changes." - :man-page "git-stash" - ["Arguments" - ("-u" "Also save untracked files" ("-u" "--include-untracked")) - ("-a" "Also save untracked and ignored files" ("-a" "--all"))] - [["Stash" - ("z" "both" magit-stash-both) - ("i" "index" magit-stash-index) - ("w" "worktree" magit-stash-worktree) - ("x" "keeping index" magit-stash-keep-index)] - ["Snapshot" - ("Z" "both" magit-snapshot-both) - ("I" "index" magit-snapshot-index) - ("W" "worktree" magit-snapshot-worktree) - ("r" "to wip ref" magit-wip-commit)] - ["Use" - ("a" "Apply" magit-stash-apply) - ("p" "Pop" magit-stash-pop) - ("k" "Drop" magit-stash-drop)] - ["Inspect" - ("l" "List" magit-stash-list) - ("v" "Show" magit-stash-show)] - ["Transform" - ("b" "Branch" magit-stash-branch) - ("B" "Branch here" magit-stash-branch-here) - ("f" "Format patch" magit-stash-format-patch)]]) - -(defun magit-stash-arguments () - (transient-args 'magit-stash)) - -;;;###autoload -(defun magit-stash-both (message &optional include-untracked) - "Create a stash of the index and working tree. -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)) - (magit-stash-save message t t include-untracked t)) - -;;;###autoload -(defun magit-stash-index (message) - "Create a stash of the index only. -Unstaged and untracked changes are not stashed. The stashed -changes are applied in reverse to both the index and the -worktree. This command can fail when the worktree is not clean. -Applying the resulting stash has the inverse effect." - (interactive (list (magit-stash-read-message))) - (magit-stash-save message t nil nil t 'worktree)) - -;;;###autoload -(defun magit-stash-worktree (message &optional include-untracked) - "Create a stash of unstaged changes in the working tree. -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)) - (magit-stash-save message nil t include-untracked t 'index)) - -;;;###autoload -(defun magit-stash-keep-index (message &optional include-untracked) - "Create a stash of the index and working tree, keeping index intact. -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)) - (magit-stash-save message t t include-untracked t 'index)) - -(defun magit-stash-read-args () - (list (magit-stash-read-message) - (magit-stash-read-untracked))) - -(defun magit-stash-read-untracked () - (let ((prefix (prefix-numeric-value current-prefix-arg)) - (args (magit-stash-arguments))) - (cond ((or (= prefix 16) (member "--all" args)) 'all) - ((or (= prefix 4) (member "--include-untracked" args)) t)))) - -(defun magit-stash-read-message () - (let* ((default (format "On %s: " - (or (magit-get-current-branch) "(no branch)"))) - (input (magit-read-string "Stash message" default))) - (if (equal input default) - (concat default (magit-rev-format "%h %s")) - input))) - -;;;###autoload -(defun magit-snapshot-both (&optional include-untracked) - "Create a snapshot of the index and working tree. -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-snapshot-read-args)) - (magit-snapshot-save t t include-untracked t)) - -;;;###autoload -(defun magit-snapshot-index () - "Create a snapshot of the index only. -Unstaged and untracked changes are not stashed." - (interactive) - (magit-snapshot-save t nil nil t)) - -;;;###autoload -(defun magit-snapshot-worktree (&optional include-untracked) - "Create a snapshot of unstaged changes in the working tree. -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-snapshot-read-args)) - (magit-snapshot-save nil t include-untracked t)) - -(defun magit-snapshot-read-args () - (list (magit-stash-read-untracked))) - -(defun magit-snapshot-save (index worktree untracked &optional refresh) - (magit-stash-save (concat "WIP on " (magit-stash-summary)) - index worktree untracked refresh t)) - -;;;###autoload -(defun magit-stash-apply (stash) - "Apply a stash to the working tree. -Try to preserve the stash index. If that fails because there -are staged changes, apply without preserving the stash index." - (interactive (list (magit-read-stash "Apply stash"))) - (if (= (magit-call-git "stash" "apply" "--index" stash) 0) - (magit-refresh) - (magit-run-git "stash" "apply" stash))) - -(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 -are staged changes, apply without preserving the stash index -and forgo removing the stash." - (interactive (list (magit-read-stash "Pop stash"))) - (if (= (magit-call-git "stash" "apply" "--index" stash) 0) - (magit-stash-drop stash) - (magit-run-git "stash" "apply" stash))) - -;;;###autoload -(defun magit-stash-drop (stash) - "Remove a stash from the stash list. -When the region is active offer to drop all contained stashes." - (interactive - (list (--if-let (magit-region-values 'stash) - (magit-confirm 'drop-stashes nil "Drop %i stashes" nil it) - (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 "stash" "drop" stash)) - (magit-refresh)) - -;;;###autoload -(defun magit-stash-clear (ref) - "Remove all stashes saved in REF's reflog by deleting REF." - (interactive (let ((ref (or (magit-section-value-if 'stashes) "refs/stash"))) - (magit-confirm t (format "Drop all stashes in %s" ref)) - (list ref))) - (magit-run-git "update-ref" "-d" ref)) - -;;;###autoload -(defun magit-stash-branch (stash branch) - "Create and checkout a new BRANCH from STASH." - (interactive (list (magit-read-stash "Branch stash") - (magit-read-string-ns "Branch name"))) - (magit-run-git "stash" "branch" branch stash)) - -;;;###autoload -(defun magit-stash-branch-here (stash branch) - "Create and checkout a new BRANCH and apply STASH. -The branch is created using `magit-branch-and-checkout', using the -current branch or `HEAD' as the start-point." - (interactive (list (magit-read-stash "Branch stash") - (magit-read-string-ns "Branch name"))) - (let ((magit-inhibit-refresh t)) - (magit-branch-and-checkout branch (or (magit-get-current-branch) "HEAD"))) - (magit-stash-apply stash)) - -;;;###autoload -(defun magit-stash-format-patch (stash) - "Create a patch from STASH" - (interactive (list (magit-read-stash "Create patch from stash"))) - (with-temp-file (magit-rev-format "0001-%f.patch" stash) - (magit-git-insert "stash" "show" "-p" stash)) - (magit-refresh)) - -;;; Plumbing - -(defun magit-stash-save (message index worktree untracked - &optional refresh keep noerror ref) - (if (or (and index (magit-staged-files t)) - (and worktree (magit-unstaged-files t)) - (and untracked (magit-untracked-files (eq untracked 'all)))) - (magit-with-toplevel - (magit-stash-store message (or ref "refs/stash") - (magit-stash-create message index worktree untracked)) - (if (eq keep 'worktree) - (with-temp-buffer - (magit-git-insert "diff" "--cached") - (magit-run-git-with-input - "apply" "--reverse" "--cached" "--ignore-space-change" "-") - (magit-run-git-with-input - "apply" "--reverse" "--ignore-space-change" "-")) - (unless (eq keep t) - (if (eq keep 'index) - (magit-call-git "checkout" "--" ".") - (magit-call-git "reset" "--hard" "HEAD" "--")) - (when untracked - (magit-call-git "clean" "--force" "-d" - (and (eq untracked 'all) "-x"))))) - (when refresh - (magit-refresh))) - (unless noerror - (user-error "No %s changes to save" (cond ((not index) "unstaged") - ((not worktree) "staged") - (t "local")))))) - -(defun magit-stash-store (message ref commit) - (magit-update-ref ref message commit t)) - -(defun magit-stash-create (message index worktree untracked) - (unless (magit-rev-parse "--verify" "HEAD") - (error "You do not have the initial commit yet")) - (let ((magit-git-global-arguments (nconc (list "-c" "commit.gpgsign=false") - magit-git-global-arguments)) - (default-directory (magit-toplevel)) - (summary (magit-stash-summary)) - (head "HEAD")) - (when (and worktree (not index)) - (setq head (or (magit-commit-tree "pre-stash index" nil "HEAD") - (error "Cannot save the current index state")))) - (or (setq index (magit-commit-tree (concat "index on " summary) nil head)) - (error "Cannot save the current index state")) - (and untracked - (setq untracked (magit-untracked-files (eq untracked 'all))) - (setq untracked (magit-with-temp-index nil nil - (or (and (magit-update-files untracked) - (magit-commit-tree - (concat "untracked files on " summary))) - (error "Cannot save the untracked files"))))) - (magit-with-temp-index index "-m" - (when worktree - (or (magit-update-files (magit-git-items "diff" "-z" "--name-only" head)) - (error "Cannot save the current worktree state"))) - (or (magit-commit-tree message nil head index untracked) - (error "Cannot save the current worktree state"))))) - -(defun magit-stash-summary () - (concat (or (magit-get-current-branch) "(no branch)") - ": " (magit-rev-format "%h %s"))) - -;;; Sections - -(defvar magit-stashes-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-delete-thing] 'magit-stash-clear) - map) - "Keymap for `stashes' section.") - -(defvar magit-stash-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-visit-thing] 'magit-stash-show) - (define-key map [remap magit-delete-thing] 'magit-stash-drop) - (define-key map "a" 'magit-stash-apply) - (define-key map "A" 'magit-stash-pop) - map) - "Keymap for `stash' sections.") - -(magit-define-section-jumper magit-jump-to-stashes - "Stashes" stashes "refs/stash") - -(cl-defun magit-insert-stashes (&optional (ref "refs/stash") - (heading "Stashes:")) - "Insert `stashes' section showing reflog for \"refs/stash\". -If optional REF is non-nil, show reflog for that instead. -If optional HEADING is non-nil, use that as section heading -instead of \"Stashes:\"." - (let ((verified (magit-rev-verify ref)) - (autostash - (and (magit-rebase-in-progress-p) - (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) - (when autostash - (pcase-let ((`(,author ,date ,msg) - (split-string - (car (magit-git-lines - "show" "-q" "--format=%aN%x00%at%x00%s" - autostash)) - "\0"))) - (magit-insert-section (stash autostash) - (insert (propertize "AUTOSTASH" 'font-lock-face 'magit-hash)) - (insert " " msg "\n") - (save-excursion - (backward-char) - (magit-log-format-margin autostash author date))))) - (if verified - (magit-git-wash (apply-partially 'magit-log-wash-log 'stash) - "reflog" "--format=%gd%x00%aN%x00%at%x00%gs" ref) - (insert ?\n) - (save-excursion - (backward-char) - (magit-make-margin-overlay))))))) - -;;; List Stashes - -;;;###autoload -(defun magit-stash-list () - "List all stashes in a buffer." - (interactive) - (magit-stashes-setup-buffer)) - -(define-derived-mode magit-stashes-mode magit-reflog-mode "Magit Stashes" - "Mode for looking at lists of stashes." - :group 'magit-log - (hack-dir-local-variables-non-file-buffer)) - -(defun magit-stashes-setup-buffer () - (magit-setup-buffer #'magit-stashes-mode nil - (magit-buffer-refname "refs/stash"))) - -(defun magit-stashes-refresh-buffer () - (magit-insert-section (stashesbuf) - (magit-insert-heading (if (equal magit-buffer-refname "refs/stash") - "Stashes:" - (format "Stashes [%s]:" magit-buffer-refname))) - (magit-git-wash (apply-partially 'magit-log-wash-log 'stash) - "reflog" "--format=%gd%x00%aN%x00%at%x00%gs" magit-buffer-refname))) - -(cl-defmethod magit-buffer-value (&context (major-mode magit-stashes-mode)) - magit-buffer-refname) - -(defvar magit--update-stash-buffer nil) - -(defun magit-stashes-maybe-update-stash-buffer (&optional _) - "When moving in the stashes buffer, update the stash buffer. -If there is no stash buffer in the same frame, then do nothing." - (when (derived-mode-p 'magit-stashes-mode) - (magit--maybe-update-stash-buffer))) - -(defun magit--maybe-update-stash-buffer () - (when-let ((stash (magit-section-value-if 'stash)) - (buffer (magit-get-mode-buffer 'magit-stash-mode nil t))) - (if magit--update-stash-buffer - (setq magit--update-stash-buffer (list stash buffer)) - (setq magit--update-stash-buffer (list stash 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))))) - (lambda () - (pcase-let ((`(,stash ,buf) magit--update-stash-buffer)) - (setq magit--update-stash-buffer nil) - (when (buffer-live-p buf) - (let ((magit-display-buffer-noselect t)) - (apply #'magit-stash-show stash args)))) - (setq magit--update-stash-buffer nil))))))) - -;;; Show Stash - -;;;###autoload -(defun magit-stash-show (stash &optional args files) - "Show all diffs of a stash in a buffer." - (interactive (cons (or (and (not current-prefix-arg) - (magit-stash-at-point)) - (magit-read-stash "Show stash")) - (pcase-let ((`(,args ,files) - (magit-diff-arguments 'magit-stash-mode))) - (list (delete "--stat" args) files)))) - (magit-stash-setup-buffer stash args files)) - -(define-derived-mode magit-stash-mode magit-diff-mode "Magit Stash" - "Mode for looking at individual stashes." - :group 'magit-diff - (hack-dir-local-variables-non-file-buffer)) - -(defun magit-stash-setup-buffer (stash args files) - (magit-setup-buffer #'magit-stash-mode nil - (magit-buffer-revision stash) - (magit-buffer-range (format "%s^..%s" stash stash)) - (magit-buffer-diff-args args) - (magit-buffer-diff-files files))) - -(defun magit-stash-refresh-buffer () - (magit-set-header-line-format - (concat (capitalize magit-buffer-revision) " " - (propertize (magit-rev-format "%s" magit-buffer-revision) - 'font-lock-face - (list :weight 'normal :foreground - (face-attribute 'default :foreground))))) - (setq magit-buffer-revision-hash (magit-rev-parse magit-buffer-revision)) - (magit-insert-section (stash) - (magit-run-section-hook 'magit-stash-sections-hook))) - -(cl-defmethod magit-buffer-value (&context (major-mode magit-stash-mode)) - magit-buffer-revision) - -(defun magit-stash-insert-section (commit range message &optional files) - (magit-insert-section (commit commit) - (magit-insert-heading message) - (magit--insert-diff "diff" range "-p" "--no-prefix" magit-buffer-diff-args - "--" (or files magit-buffer-diff-files)))) - -(defun magit-insert-stash-notes () - "Insert section showing notes for a stash. -This shows the notes for stash@{N} but not for the other commits -that make up the stash." - (magit-insert-section section (note) - (magit-insert-heading "Notes") - (magit-git-insert "notes" "show" magit-buffer-revision) - (if (= (point) - (oref section content)) - (magit-cancel-section) - (insert "\n")))) - -(defun magit-insert-stash-index () - "Insert section showing staged changes of the stash." - (magit-stash-insert-section - (format "%s^2" magit-buffer-revision) - (format "%s^..%s^2" magit-buffer-revision magit-buffer-revision) - "Staged")) - -(defun magit-insert-stash-worktree () - "Insert section showing unstaged changes of the stash." - (magit-stash-insert-section - magit-buffer-revision - (format "%s^2..%s" magit-buffer-revision magit-buffer-revision) - "Unstaged")) - -(defun magit-insert-stash-untracked () - "Insert section showing the untracked files commit of the stash." - (let ((stash magit-buffer-revision) - (rev (concat magit-buffer-revision "^3"))) - (when (magit-rev-verify rev) - (magit-stash-insert-section (format "%s^3" stash) - (format "%s^..%s^3" stash stash) - "Untracked files" - (magit-git-items "ls-tree" "-z" "--name-only" - "-r" "--full-tree" rev))))) - -;;; _ -(provide 'magit-stash) -;;; magit-stash.el ends here diff --git a/elpa/magit-20210802.1524/magit-status.el b/elpa/magit-20210802.1524/magit-status.el deleted file mode 100644 index a7cad428..00000000 --- a/elpa/magit-20210802.1524/magit-status.el +++ /dev/null @@ -1,835 +0,0 @@ -;;; magit-status.el --- the grand overview -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements the status buffer. - -;;; Code: - -(require 'magit) - -;;; Options - -(defgroup magit-status nil - "Inspect and manipulate Git repositories." - :link '(info-link "(magit)Status Buffer") - :group 'magit-modes) - -(defcustom magit-status-mode-hook nil - "Hook run after entering Magit-Status mode." - :group 'magit-status - :type 'hook) - -(defcustom magit-status-headers-hook - '(magit-insert-error-header - magit-insert-diff-filter-header - magit-insert-head-branch-header - magit-insert-upstream-branch-header - magit-insert-push-branch-header - magit-insert-tags-header) - "Hook run to insert headers into the status buffer. - -This hook is run by `magit-insert-status-headers', which in turn -has to be a member of `magit-status-sections-hook' to be used at -all." - :package-version '(magit . "2.1.0") - :group 'magit-status - :type 'hook - :options '(magit-insert-error-header - magit-insert-diff-filter-header - magit-insert-repo-header - magit-insert-remote-header - magit-insert-head-branch-header - magit-insert-upstream-branch-header - magit-insert-push-branch-header - magit-insert-tags-header)) - -(defcustom magit-status-sections-hook - '(magit-insert-status-headers - magit-insert-merge-log - magit-insert-rebase-sequence - magit-insert-am-sequence - magit-insert-sequencer-sequence - magit-insert-bisect-output - magit-insert-bisect-rest - magit-insert-bisect-log - magit-insert-untracked-files - magit-insert-unstaged-changes - magit-insert-staged-changes - magit-insert-stashes - magit-insert-unpushed-to-pushremote - magit-insert-unpushed-to-upstream-or-recent - magit-insert-unpulled-from-pushremote - magit-insert-unpulled-from-upstream) - "Hook run to insert sections into a status buffer." - :package-version '(magit . "2.12.0") - :group 'magit-status - :type 'hook) - -(defcustom magit-status-initial-section '(1) - "The section point is placed on when a status buffer is created. - -When such a buffer is merely being refreshed or being shown again -after it was merely buried, then this option has no effect. - -If this is nil, then point remains on the very first section as -usual. Otherwise it has to be a list of integers and section -identity lists. The members of that list are tried in order -until a matching section is found. - -An integer means to jump to the nth section, 1 for example -jumps over the headings. To get a section's \"identity list\" -use \\[universal-argument] \\[magit-describe-section-briefly]. - -If, for example, you want to jump to the commits that haven't -been pulled from the upstream, or else the second section, then -use: (((unpulled . \"..@{upstream}\") (status)) 1). - -See option `magit-section-initial-visibility-alist' for how to -control the initial visibility of the jumped to section." - :package-version '(magit . "2.90.0") - :group 'magit-status - :type '(choice (const :tag "as usual" nil) - (repeat (choice (number :tag "nth top-level section") - (sexp :tag "section identity"))))) - -(defcustom magit-status-goto-file-position nil - "Whether to go to position corresponding to file position. - -If this is non-nil and the current buffer is visiting a file, -then `magit-status' tries to go to the position in the status -buffer that corresponds to the position in the file-visiting -buffer. This jumps into either the diff of unstaged changes -or the diff of staged changes. - -If the previously current buffer does not visit a file, or if -the file has neither unstaged nor staged changes then this has -no effect. - -The command `magit-status-here' tries to go to that position, -regardless of the value of this option." - :package-version '(magit . "3.0.0") - :group 'magit-status - :type 'boolean) - -(defcustom magit-status-show-hashes-in-headers nil - "Whether headers in the status buffer show hashes. -The functions which respect this option are -`magit-insert-head-branch-header', -`magit-insert-upstream-branch-header', and -`magit-insert-push-branch-header'." - :package-version '(magit . "2.4.0") - :group 'magit-status - :type 'boolean) - -(defcustom magit-status-margin - (list nil - (nth 1 magit-log-margin) - 'magit-log-margin-width nil - (nth 4 magit-log-margin)) - "Format of the margin in `magit-status-mode' buffers. - -The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). - -If INIT is non-nil, then the margin is shown initially. -STYLE controls how to format the author or committer date. - It can be one of `age' (to show the age of the commit), - `age-abbreviated' (to abbreviate the time unit to a character), - or a string (suitable for `format-time-string') to show the - actual date. Option `magit-log-margin-show-committer-date' - controls which date is being displayed. -WIDTH controls the width of the margin. This exists for forward - compatibility and currently the value should not be changed. -AUTHOR controls whether the name of the author is also shown by - default. -AUTHOR-WIDTH has to be an integer. When the name of the author - is shown, then this specifies how much space is used to do so." - :package-version '(magit . "2.9.0") - :group 'magit-status - :group 'magit-margin - :type magit-log-margin--custom-type - :initialize 'magit-custom-initialize-reset - :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 -(defun magit-init (directory) - "Initialize a Git repository, then show its status. - -If the directory is below an existing repository, then the user -has to confirm that a new one should be created inside. If the -directory is the root of the existing repository, then the user -has to confirm that it should be reinitialized. - -Non-interactively DIRECTORY is (re-)initialized unconditionally." - (interactive - (let ((directory (file-name-as-directory - (expand-file-name - (read-directory-name "Create repository in: "))))) - (when-let ((toplevel (magit-toplevel directory))) - (setq toplevel (expand-file-name toplevel)) - (unless (y-or-n-p (if (file-equal-p toplevel directory) - (format "Reinitialize existing repository %s? " - directory) - (format "%s is a repository. Create another in %s? " - toplevel directory))) - (user-error "Abort"))) - (list directory))) - ;; `git init' does not understand the meaning of "~"! - (magit-call-git "init" (magit-convert-filename-for-git - (expand-file-name directory))) - (magit-status-setup-buffer directory)) - -;;;###autoload -(defun magit-status (&optional directory cache) - "Show the status of the current Git repository in a buffer. - -If the current directory isn't located within a Git repository, -then prompt for an existing repository or an arbitrary directory, -depending on option `magit-repository-directories', and show the -status of the selected repository instead. - -* If that option specifies any existing repositories, then offer - those for completion and show the status buffer for the - selected one. - -* Otherwise read an arbitrary directory using regular file-name - completion. If the selected directory is the top-level of an - existing working tree, then show the status buffer for that. - -* Otherwise offer to initialize the selected directory as a new - repository. After creating the repository show its status - buffer. - -These fallback behaviors can also be forced using one or more -prefix arguments: - -* With two prefix arguments (or more precisely a numeric prefix - value of 16 or greater) read an arbitrary directory and act on - it as described above. The same could be accomplished using - the command `magit-init'. - -* With a single prefix argument read an existing repository, or - if none can be found based on `magit-repository-directories', - then fall back to the same behavior as with two prefix - arguments." - (interactive - (let ((magit--refresh-cache (list (cons 0 0)))) - (list (and (or current-prefix-arg (not (magit-toplevel))) - (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 - (let ((toplevel (magit-toplevel directory))) - (setq directory (file-name-as-directory - (expand-file-name directory))) - (if (and toplevel (file-equal-p directory toplevel)) - (magit-status-setup-buffer directory) - (when (y-or-n-p - (if toplevel - (format "%s is a repository. Create another in %s? " - toplevel directory) - (format "Create repository in %s? " directory))) - ;; Creating a new repository invalidates cached values. - (setq magit--refresh-cache nil) - (magit-init directory)))) - (magit-status-setup-buffer default-directory)))) - -(put 'magit-status 'interactive-only 'magit-status-setup-buffer) - -;;;###autoload -(defalias 'magit 'magit-status - "An alias for `magit-status' for better discoverability. - -Instead of invoking this alias for `magit-status' using -\"M-x magit RET\", you should bind a key to `magit-status' -and read the info node `(magit)Getting Started', which -also contains other useful hints.") - -;;;###autoload -(defun magit-status-here () - "Like `magit-status' but with non-nil `magit-status-goto-file-position'." - (interactive) - (let ((magit-status-goto-file-position t)) - (call-interactively #'magit-status))) - -(put 'magit-status-here 'interactive-only 'magit-status-setup-buffer) - -(defvar magit--remotes-using-recent-git nil) - -(defun magit--tramp-asserts (directory) - (when-let ((remote (file-remote-p directory))) - (unless (member remote magit--remotes-using-recent-git) - (if-let ((version (let ((default-directory directory)) - (magit-git-version)))) - (if (version<= magit--minimal-git version) - (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. - -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. - -Check the value of `magit-remote-git-executable' and consult -the info node `(tramp)Remote programs'." remote) :error))))) - -;;; Mode - -(defvar magit-status-mode-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map magit-mode-map) - (define-key map "j" 'magit-status-jump) - (define-key map [remap dired-jump] 'magit-dired-jump) - map) - "Keymap for `magit-status-mode'.") - -(transient-define-prefix magit-status-jump () - "In a Magit-Status buffer, jump to a section." - ["Jump to" - [("z " "Stashes" magit-jump-to-stashes - :if (lambda () (memq 'magit-insert-stashes magit-status-sections-hook))) - ("t " "Tracked" magit-jump-to-tracked - :if (lambda () (memq 'magit-insert-tracked-files magit-status-sections-hook))) - ("n " "Untracked" magit-jump-to-untracked - :if (lambda () (memq 'magit-insert-untracked-files magit-status-sections-hook))) - ("u " "Unstaged" magit-jump-to-unstaged - :if (lambda () (memq 'magit-insert-unstaged-changes magit-status-sections-hook))) - ("s " "Staged" magit-jump-to-staged - :if (lambda () (memq 'magit-insert-staged-changes magit-status-sections-hook)))] - [("fu" "Unpulled from upstream" magit-jump-to-unpulled-from-upstream - :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" 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))) - :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)))]]) - -(define-derived-mode magit-status-mode magit-mode "Magit" - "Mode for looking at Git status. - -This mode is documented in info node `(magit)Status Buffer'. - -\\\ -Type \\[magit-refresh] to refresh the current buffer. -Type \\[magit-section-toggle] to expand or hide the section at point. -Type \\[magit-visit-thing] to visit the change or commit at point. - -Type \\[magit-dispatch] to invoke major commands. - -Staging and applying changes is documented in info node -`(magit)Staging and Unstaging' and info node `(magit)Applying'. - -\\Type \ -\\[magit-apply] to apply the change at point, \ -\\[magit-stage] to stage, -\\[magit-unstage] to unstage, \ -\\[magit-discard] to discard, or \ -\\[magit-reverse] to reverse it. - -\\\ -Type \\[magit-commit] to create a commit. - -\\{magit-status-mode-map}" - :group 'magit-status - (hack-dir-local-variables-non-file-buffer) - (setq imenu-create-index-function - 'magit-imenu--status-create-index-function)) - -(put 'magit-status-mode 'magit-diff-default-arguments - '("--no-ext-diff")) -(put 'magit-status-mode 'magit-log-default-arguments - '("-n256" "--decorate")) - -;;;###autoload -(defun magit-status-setup-buffer (&optional directory) - (unless directory - (setq directory default-directory)) - (magit--tramp-asserts directory) - (let* ((default-directory directory) - (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))) - (col (and file (current-column))) - (buf (magit-setup-buffer #'magit-status-mode nil - (magit-buffer-diff-args (nth 0 d)) - (magit-buffer-diff-files (nth 1 d)) - (magit-buffer-log-args (nth 0 l)) - (magit-buffer-log-files (nth 1 l))))) - (when file - (with-current-buffer buf - (let ((staged (magit-get-section '((staged) (status))))) - (if (and staged - (cadr (magit-diff--locate-hunk file line staged))) - (magit-diff--goto-position file line col staged) - (let ((unstaged (magit-get-section '((unstaged) (status))))) - (unless (and unstaged - (magit-diff--goto-position file line col unstaged)) - (when staged - (magit-diff--goto-position file line col staged)))))))) - buf)) - -(defun magit-status-refresh-buffer () - (magit-git-exit-code "update-index" "--refresh") - (magit-insert-section (status) - (magit-run-section-hook 'magit-status-sections-hook))) - -(defun magit-status-goto-initial-section () - "In a `magit-status-mode' buffer, jump `magit-status-initial-section'. -Actually doing so is deferred until `magit-refresh-buffer-hook' -runs `magit-status-goto-initial-section-1'. That function then -removes itself from the hook, so that this only happens when the -status buffer is first created." - (when (and magit-status-initial-section - (derived-mode-p 'magit-status-mode)) - (add-hook 'magit-refresh-buffer-hook - 'magit-status-goto-initial-section-1 nil t))) - -(defun magit-status-goto-initial-section-1 () - "In a `magit-status-mode' buffer, jump `magit-status-initial-section'. -This function removes itself from `magit-refresh-buffer-hook'." - (when-let ((section - (--some (if (integerp it) - (nth (1- it) - (magit-section-siblings (magit-current-section) - 'next)) - (magit-get-section it)) - magit-status-initial-section))) - (goto-char (oref section start)) - (when-let ((vis (cdr (assq 'magit-status-initial-section - magit-section-initial-visibility-alist)))) - (if (eq vis 'hide) - (magit-section-hide section) - (magit-section-show section)))) - (remove-hook 'magit-refresh-buffer-hook - 'magit-status-goto-initial-section-1 t)) - -(defun magit-status-maybe-update-revision-buffer (&optional _) - "When moving in the status buffer, update the revision buffer. -If there is no revision buffer in the same frame, then do nothing." - (when (derived-mode-p 'magit-status-mode) - (magit--maybe-update-revision-buffer))) - -(defun magit-status-maybe-update-stash-buffer (&optional _) - "When moving in the status buffer, update the stash buffer. -If there is no stash buffer in the same frame, then do nothing." - (when (derived-mode-p 'magit-status-mode) - (magit--maybe-update-stash-buffer))) - -(defun magit-status-maybe-update-blob-buffer (&optional _) - "When moving in the status buffer, update the blob buffer. -If there is no blob buffer in the same frame, then do nothing." - (when (derived-mode-p 'magit-status-mode) - (magit--maybe-update-blob-buffer))) - -;;; Sections -;;;; Special Headers - -(defun magit-insert-status-headers () - "Insert header sections appropriate for `magit-status-mode' buffers. -The sections are inserted by running the functions on the hook -`magit-status-headers-hook'." - (if (magit-rev-verify "HEAD") - (magit-insert-headers 'magit-status-headers-hook) - (insert "In the beginning there was darkness\n\n"))) - -(defvar magit-error-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-visit-thing] 'magit-process-buffer) - map) - "Keymap for `error' sections.") - -(defun magit-insert-error-header () - "Insert the message about the Git error that just occurred. - -This function is only aware of the last error that occur when Git -was run for side-effects. If, for example, an error occurs while -generating a diff, then that error won't be inserted. Refreshing -the status buffer causes this section to disappear again." - (when magit-this-error - (magit-insert-section (error 'git) - (insert (propertize (format "%-10s" "GitError! ") - 'font-lock-face 'magit-section-heading)) - (insert (propertize magit-this-error - 'font-lock-face 'font-lock-warning-face)) - (when-let ((key (car (where-is-internal 'magit-process-buffer)))) - (insert (format " [Type `%s' for details]" (key-description key)))) - (insert ?\n)) - (setq magit-this-error nil))) - -(defun magit-insert-diff-filter-header () - "Insert a header line showing the effective diff filters." - (let ((ignore-modules (magit-ignore-submodules-p))) - (when (or ignore-modules - magit-buffer-diff-files) - (insert (propertize (format "%-10s" "Filter! ") - 'font-lock-face 'magit-section-heading)) - (when ignore-modules - (insert ignore-modules) - (when magit-buffer-diff-files - (insert " -- "))) - (when magit-buffer-diff-files - (insert (mapconcat #'identity magit-buffer-diff-files " "))) - (insert ?\n)))) - -;;;; Reference Headers - -(defun magit-insert-head-branch-header (&optional branch) - "Insert a header line about the current branch. -If `HEAD' is detached, then insert information about that commit -instead. The optional BRANCH argument is for internal use only." - (let ((branch (or branch (magit-get-current-branch))) - (output (magit-rev-format "%h %s" (or branch "HEAD")))) - (string-match "^\\([^ ]+\\) \\(.*\\)" output) - (magit-bind-match-strings (commit summary) output - (when (equal summary "") - (setq summary "(no commit message)")) - (if branch - (magit-insert-section (branch branch) - (insert (format "%-10s" "Head: ")) - (when magit-status-show-hashes-in-headers - (insert (propertize commit 'font-lock-face 'magit-hash) ?\s)) - (insert (propertize branch 'font-lock-face 'magit-branch-local)) - (insert ?\s) - (insert (funcall magit-log-format-message-function branch summary)) - (insert ?\n)) - (magit-insert-section (commit commit) - (insert (format "%-10s" "Head: ")) - (insert (propertize commit 'font-lock-face 'magit-hash)) - (insert ?\s) - (insert (funcall magit-log-format-message-function nil summary)) - (insert ?\n)))))) - -(defun magit-insert-upstream-branch-header (&optional branch upstream keyword) - "Insert a header line about the upstream of the current branch. -If no branch is checked out, then insert nothing. The optional -arguments are for internal use only." - (when-let ((branch (or branch (magit-get-current-branch)))) - (let ((remote (magit-get "branch" branch "remote")) - (merge (magit-get "branch" branch "merge")) - (rebase (magit-get "branch" branch "rebase"))) - (when (or remote merge) - (unless upstream - (setq upstream (magit-get-upstream-branch branch))) - (magit-insert-section (branch upstream) - (pcase rebase - ("true") - ("false" (setq rebase nil)) - (_ (setq rebase (magit-get-boolean "pull.rebase")))) - (insert (format "%-10s" (or keyword (if rebase "Rebase: " "Merge: ")))) - (insert - (if upstream - (concat (and magit-status-show-hashes-in-headers - (concat (propertize (magit-rev-format "%h" upstream) - 'font-lock-face 'magit-hash) - " ")) - upstream " " - (funcall magit-log-format-message-function upstream - (funcall magit-log-format-message-function nil - (or (magit-rev-format "%s" upstream) - "(no commit message)")))) - (cond - ((magit--unnamed-upstream-p remote merge) - (concat (propertize merge 'font-lock-face 'magit-branch-remote) - " from " - (propertize remote 'font-lock-face 'bold))) - ((magit--valid-upstream-p remote merge) - (if (equal remote ".") - (concat - (propertize merge 'font-lock-face 'magit-branch-local) - (propertize " does not exist" - 'font-lock-face 'font-lock-warning-face)) - (concat - (propertize merge 'font-lock-face 'magit-branch-remote) - (propertize " does not exist on " - 'font-lock-face 'font-lock-warning-face) - (propertize remote 'font-lock-face 'magit-branch-remote)))) - (t - (propertize "invalid upstream configuration" - 'font-lock-face 'font-lock-warning-face))))) - (insert ?\n)))))) - -(defun magit-insert-push-branch-header () - "Insert a header line about the branch the current branch is pushed to." - (when-let ((branch (magit-get-current-branch)) - (target (magit-get-push-branch branch))) - (magit-insert-section (branch target) - (insert (format "%-10s" "Push: ")) - (insert - (if (magit-rev-verify target) - (concat target " " - (and magit-status-show-hashes-in-headers - (concat (propertize (magit-rev-format "%h" target) - 'font-lock-face 'magit-hash) - " ")) - (funcall magit-log-format-message-function target - (funcall magit-log-format-message-function nil - (or (magit-rev-format "%s" target) - "(no commit message)")))) - (let ((remote (magit-get-push-remote branch))) - (if (magit-remote-p remote) - (concat target - (propertize " does not exist" - 'font-lock-face 'font-lock-warning-face)) - (concat remote - (propertize " remote does not exist" - 'font-lock-face 'font-lock-warning-face)))))) - (insert ?\n)))) - -(defun magit-insert-tags-header () - "Insert a header line about the current and/or next tag." - (let* ((this-tag (magit-get-current-tag nil t)) - (next-tag (magit-get-next-tag nil t)) - (this-cnt (cadr this-tag)) - (next-cnt (cadr next-tag)) - (this-tag (car this-tag)) - (next-tag (car next-tag)) - (both-tags (and this-tag next-tag t))) - (when (or this-tag next-tag) - (magit-insert-section (tag (or this-tag next-tag)) - (insert (format "%-10s" (if both-tags "Tags: " "Tag: "))) - (cl-flet ((insert-count - (tag count face) - (insert (concat (propertize tag 'font-lock-face 'magit-tag) - (and (> count 0) - (format " (%s)" - (propertize - (format "%s" count) - 'font-lock-face face))))))) - (when this-tag (insert-count this-tag this-cnt 'magit-branch-local)) - (when both-tags (insert ", ")) - (when next-tag (insert-count next-tag next-cnt 'magit-tag))) - (insert ?\n))))) - -;;;; Auxiliary Headers - -(defun magit-insert-user-header () - "Insert a header line about the current user." - (let ((name (magit-get "user.name")) - (email (magit-get "user.email"))) - (when (and name email) - (magit-insert-section (user name) - (insert (format "%-10s" "User: ")) - (insert (propertize name 'font-lock-face 'magit-log-author)) - (insert " <" email ">\n"))))) - -(defun magit-insert-repo-header () - "Insert a header line showing the path to the repository top-level." - (let ((topdir (magit-toplevel))) - (magit-insert-section (repo topdir) - (insert (format "%-10s%s\n" "Repo: " (abbreviate-file-name topdir)))))) - -(defun magit-insert-remote-header () - "Insert a header line about the remote of the current branch. - -If no remote is configured for the current branch, then fall back -showing the \"origin\" remote, or if that does not exist the first -remote in alphabetic order." - (when-let ((name (magit-get-some-remote)) - ;; Under certain configurations it's possible for url - ;; to be nil, when name is not, see #2858. - (url (magit-get "remote" name "url"))) - (magit-insert-section (remote name) - (insert (format "%-10s" "Remote: ")) - (insert (propertize name 'font-lock-face 'magit-branch-remote) ?\s) - (insert url ?\n)))) - -;;;; File Sections - -(defvar magit-untracked-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-delete-thing] 'magit-discard) - (define-key map "s" 'magit-stage) - map) - "Keymap for the `untracked' section.") - -(magit-define-section-jumper magit-jump-to-untracked "Untracked files" untracked) - -(defun magit-insert-untracked-files () - "Maybe insert a list or tree of untracked files. - -Do so depending on the value of `status.showUntrackedFiles'. -Note that even if the value is `all', Magit still initially -only shows directories. But the directory sections can then -be expanded using \"TAB\". - -If the first element of `magit-buffer-diff-files' is a -directory, then limit the list to files below that. The value -value of that variable can be set using \"D -- DIRECTORY RET g\"." - (let* ((show (or (magit-get "status.showUntrackedFiles") "normal")) - (base (car magit-buffer-diff-files)) - (base (and base (file-directory-p base) base))) - (unless (equal show "no") - (if (equal show "all") - (when-let ((files (magit-untracked-files nil base))) - (magit-insert-section (untracked) - (magit-insert-heading "Untracked files:") - (magit-insert-files files base) - (insert ?\n))) - (when-let ((files - (--mapcat (and (eq (aref it 0) ??) - (list (substring it 3))) - (magit-git-items "status" "-z" "--porcelain" - (magit-ignore-submodules-p t) - "--" base)))) - (magit-insert-section (untracked) - (magit-insert-heading "Untracked files:") - (dolist (file files) - (magit-insert-section (file file) - (insert (propertize file 'font-lock-face 'magit-filename) ?\n))) - (insert ?\n))))))) - -(magit-define-section-jumper magit-jump-to-tracked "Tracked files" tracked) - -(defun magit-insert-tracked-files () - "Insert a tree of tracked files. - -If the first element of `magit-buffer-diff-files' is a -directory, then limit the list to files below that. The value -value of that variable can be set using \"D -- DIRECTORY RET g\"." - (when-let ((files (magit-list-files))) - (let* ((base (car magit-buffer-diff-files)) - (base (and base (file-directory-p base) base))) - (magit-insert-section (tracked nil t) - (magit-insert-heading "Tracked files:") - (magit-insert-files files base) - (insert ?\n))))) - -(defun magit-insert-ignored-files () - "Insert a tree of ignored files. - -If the first element of `magit-buffer-diff-files' is a -directory, then limit the list to files below that. The value -of that variable can be set using \"D -- DIRECTORY RET g\"." - (when-let ((files (magit-ignored-files))) - (let* ((base (car magit-buffer-diff-files)) - (base (and base (file-directory-p base) base))) - (magit-insert-section (tracked nil t) - (magit-insert-heading "Ignored files:") - (magit-insert-files files base) - (insert ?\n))))) - -(magit-define-section-jumper magit-jump-to-skip-worktree "Skip-worktree files" skip-worktree) - -(defun magit-insert-skip-worktree-files () - "Insert a tree of skip-worktree files. - -If the first element of `magit-buffer-diff-files' is a -directory, then limit the list to files below that. The value -of that variable can be set using \"D -- DIRECTORY RET g\"." - (when-let ((files (magit-skip-worktree-files))) - (let* ((base (car magit-buffer-diff-files)) - (base (and base (file-directory-p base) base))) - (magit-insert-section (skip-worktree nil t) - (magit-insert-heading "Skip-worktree files:") - (magit-insert-files files base) - (insert ?\n))))) - -(magit-define-section-jumper magit-jump-to-assume-unchanged "Assume-unchanged files" assume-unchanged) - -(defun magit-insert-assume-unchanged-files () - "Insert a tree of files that are assumed to be unchanged. - -If the first element of `magit-buffer-diff-files' is a -directory, then limit the list to files below that. The value -of that variable can be set using \"D -- DIRECTORY RET g\"." - (when-let ((files (magit-assume-unchanged-files))) - (let* ((base (car magit-buffer-diff-files)) - (base (and base (file-directory-p base) base))) - (magit-insert-section (assume-unchanged nil t) - (magit-insert-heading "Assume-unchanged files:") - (magit-insert-files files base) - (insert ?\n))))) - -(defun magit-insert-files (files directory) - (while (and files (string-prefix-p (or directory "") (car files))) - (let ((dir (file-name-directory (car files)))) - (if (equal dir directory) - (let ((file (pop files))) - (magit-insert-section (file file) - (insert (propertize file 'font-lock-face 'magit-filename) ?\n))) - (magit-insert-section (file dir t) - (insert (propertize dir 'file 'magit-filename) ?\n) - (magit-insert-heading) - (setq files (magit-insert-files files dir)))))) - files) - -;;; _ -(provide 'magit-status) -;;; magit-status.el ends here diff --git a/elpa/magit-20210802.1524/magit-submodule.el b/elpa/magit-20210802.1524/magit-submodule.el deleted file mode 100644 index 9458f645..00000000 --- a/elpa/magit-20210802.1524/magit-submodule.el +++ /dev/null @@ -1,698 +0,0 @@ -;;; magit-submodule.el --- submodule 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) - -(defvar x-stretch-cursor) - -;;; Options - -(defcustom magit-module-sections-hook - '(magit-insert-modules-overview - magit-insert-modules-unpulled-from-upstream - magit-insert-modules-unpulled-from-pushremote - magit-insert-modules-unpushed-to-upstream - magit-insert-modules-unpushed-to-pushremote) - "Hook run by `magit-insert-modules'. - -That function isn't part of `magit-status-sections-hook's default -value, so you have to add it yourself for this hook to have any -effect." - :package-version '(magit . "2.11.0") - :group 'magit-status - :type 'hook) - -(defcustom magit-module-sections-nested t - "Whether `magit-insert-modules' wraps inserted sections. - -If this is non-nil, then only a single top-level section -is inserted. If it is nil, then all sections listed in -`magit-module-sections-hook' become top-level sections." - :package-version '(magit . "2.11.0") - :group 'magit-status - :type 'boolean) - -(defcustom magit-submodule-list-mode-hook '(hl-line-mode) - "Hook run after entering Magit-Submodule-List mode." - :package-version '(magit . "2.9.0") - :group 'magit-repolist - :type 'hook - :get 'magit-hook-custom-get - :options '(hl-line-mode)) - -(defcustom magit-submodule-list-columns - '(("Path" 25 magit-modulelist-column-path nil) - ("Version" 25 magit-repolist-column-version nil) - ("Branch" 20 magit-repolist-column-branch nil) - ("BU" 3 magit-repolist-column-unpushed-to-upstream ((:right-align t))) - ("BP" 3 magit-repolist-column-unpushed-to-pushremote ((:right-align t))) - ("B" 3 magit-repolist-column-branches ((:right-align t))) - ("S" 3 magit-repolist-column-stashes ((:right-align t)))) - "List of columns displayed by `magit-list-submodules'. - -Each element has the form (HEADER WIDTH FORMAT PROPS). - -HEADER is the string displayed in the header. WIDTH is the width -of the column. FORMAT is a function that is called with one -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'. - -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 - :type `(repeat (list :tag "Column" - (string :tag "Header Label") - (integer :tag "Column Width") - (function :tag "Inserter Function") - (repeat :tag "Properties" - (list (choice :tag "Property" - (const :right-align) - (const :pad-right) - (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. - -If this is nil, then that command does not offer to do so unless -a prefix argument is used. When this is t, then it does offer to -do so even without a prefix argument. - -In both cases the action still has to be confirmed unless that is -disabled using the option `magit-no-confirm'. Doing the latter -and also setting this variable to t will lead to tears." - :package-version '(magit . "2.90.0") - :group 'magit-commands - :type 'boolean) - -;;; Popup - -;;;###autoload (autoload 'magit-submodule "magit-submodule" nil t) -(transient-define-prefix magit-submodule () - "Act on a submodule." - :man-page "git-submodule" - ["Arguments" - ("-f" "Force" ("-f" "--force")) - ("-r" "Recursive" "--recursive") - ("-N" "Do not fetch" ("-N" "--no-fetch")) - ("-C" "Checkout tip" "--checkout") - ("-R" "Rebase onto tip" "--rebase") - ("-M" "Merge tip" "--merge") - ("-U" "Use upstream tip" "--remote")] - ["One module actions" - ("a" magit-submodule-add) - ("r" magit-submodule-register) - ("p" magit-submodule-populate) - ("u" magit-submodule-update) - ("s" magit-submodule-synchronize) - ("d" magit-submodule-unpopulate) - ("k" "Remove" magit-submodule-remove)] - ["All modules actions" - ("l" "List all modules" magit-list-submodules) - ("f" "Fetch all modules" magit-fetch-modules)]) - -(defun magit-submodule-arguments (&rest filters) - (--filter (and (member it filters) it) - (transient-args 'magit-submodule))) - -(defclass magit--git-submodule-suffix (transient-suffix) - ()) - -(cl-defmethod transient-format-description ((obj magit--git-submodule-suffix)) - (let ((value (delq nil (mapcar 'transient-infix-value transient--suffixes)))) - (replace-regexp-in-string - "\\[--[^]]+\\]" - (lambda (match) - (format (propertize "[%s]" 'face 'transient-inactive-argument) - (mapconcat (lambda (arg) - (propertize arg 'face - (if (member arg value) - 'transient-argument - 'transient-inactive-argument))) - (save-match-data - (split-string (substring match 1 -1) "|")) - (propertize "|" 'face 'transient-inactive-argument)))) - (cl-call-next-method obj)))) - -;;;###autoload (autoload 'magit-submodule-add "magit-submodule" nil t) -(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 -the superproject. If it is nil, then the path is determined -based on the URL. Optional NAME is the name of the module. If -it is nil, then PATH also becomes the name." - :class 'magit--git-submodule-suffix - :description "Add git submodule add [--force]" - (interactive - (magit-with-toplevel - (let* ((url (magit-read-string-ns "Add submodule (remote url)")) - (path (let ((read-file-name-function - (if (or (eq read-file-name-function 'ido-read-file-name) - (advice-function-member-p - 'ido-read-file-name - read-file-name-function)) - ;; The Ido variant doesn't work properly here. - #'read-file-name-default - read-file-name-function))) - (directory-file-name - (file-relative-name - (read-directory-name - "Add submodules at path: " nil nil nil - (and (string-match "\\([^./]+\\)\\(\\.git\\)?$" url) - (match-string 1 url)))))))) - (list url - (directory-file-name path) - (magit-submodule-read-name-for-path path) - (magit-submodule-arguments "--force"))))) - (magit-submodule-add-1 url path name args)) - -(defun magit-submodule-add-1 (url &optional path name args) - (magit-with-toplevel - (magit-submodule--maybe-reuse-gitdir name path) - (magit-run-git-async "submodule" "add" - (and name (list "--name" name)) - args "--" url path) - (set-process-sentinel - magit-this-process - (lambda (process event) - (when (memq (process-status process) '(exit signal)) - (if (> (process-exit-status process) 0) - (magit-process-sentinel process event) - (process-put process 'inhibit-refresh t) - (magit-process-sentinel process event) - (unless (version< (magit-git-version) "2.12.0") - (magit-call-git "submodule" "absorbgitdirs" path)) - (magit-refresh))))))) - -;;;###autoload -(defun magit-submodule-read-name-for-path (path &optional prefer-short) - (let* ((path (directory-file-name (file-relative-name path))) - (name (file-name-nondirectory path))) - (push (if prefer-short path name) minibuffer-history) - (magit-read-string-ns - "Submodule name" nil (cons 'minibuffer-history 2) - (or (--keep (pcase-let ((`(,var ,val) (split-string it "="))) - (and (equal val path) - (cadr (split-string var "\\.")))) - (magit-git-lines "config" "--list" "-f" ".gitmodules")) - (if prefer-short name path))))) - -;;;###autoload (autoload 'magit-submodule-register "magit-submodule" nil t) -(transient-define-suffix magit-submodule-register (modules) - "Register MODULES. - -With a prefix argument act on all suitable modules. Otherwise, -if the region selects modules, then act on those. Otherwise, if -there is a module at point, then act on that. Otherwise read a -single module from the user." - ;; This command and the underlying "git submodule init" do NOT - ;; "initialize" modules. They merely "register" modules in the - ;; super-projects $GIT_DIR/config file, the purpose of which is to - ;; allow users to change such values before actually initializing - ;; the modules. - :description "Register git submodule init" - (interactive - (list (magit-module-confirm "Register" 'magit-module-no-worktree-p))) - (magit-with-toplevel - (magit-run-git-async "submodule" "init" "--" modules))) - -;;;###autoload (autoload 'magit-submodule-populate "magit-submodule" nil t) -(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, -if the region selects modules, then act on those. Otherwise, if -there is a module at point, then act on that. Otherwise read a -single module from the user." - ;; This is the command that actually "initializes" modules. - ;; A module is initialized when it has a working directory, - ;; a gitlink, and a .gitmodules entry. - :description "Populate git submodule update --init" - (interactive - (list (magit-module-confirm "Populate" 'magit-module-no-worktree-p))) - (magit-with-toplevel - (magit-run-git-async "submodule" "update" "--init" "--" modules))) - -;;;###autoload (autoload 'magit-submodule-update "magit-submodule" nil t) -(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, -if the region selects modules, then act on those. Otherwise, if -there is a module at point, then act on that. Otherwise read a -single module from the user." - ;; Unlike `git-submodule's `update' command ours can only update - ;; "initialized" modules by checking out other commits but not - ;; "initialize" modules by creating the working directories. - ;; To do the latter we provide the "setup" command. - :class 'magit--git-submodule-suffix - :description "Update git submodule update [--force] [--no-fetch] - [--remote] [--recursive] [--checkout|--rebase|--merge]" - (interactive - (list (magit-module-confirm "Update" 'magit-module-worktree-p) - (magit-submodule-arguments - "--force" "--remote" "--recursive" "--checkout" "--rebase" "--merge" - "--no-fetch"))) - (magit-with-toplevel - (magit-run-git-async "submodule" "update" args "--" modules))) - -;;;###autoload (autoload 'magit-submodule-synchronize "magit-submodule" nil t) -(transient-define-suffix magit-submodule-synchronize (modules args) - "Synchronize url configuration of MODULES. - -With a prefix argument act on all suitable modules. Otherwise, -if the region selects modules, then act on those. Otherwise, if -there is a module at point, then act on that. Otherwise read a -single module from the user." - :class 'magit--git-submodule-suffix - :description "Synchronize git submodule sync [--recursive]" - (interactive - (list (magit-module-confirm "Synchronize" 'magit-module-worktree-p) - (magit-submodule-arguments "--recursive"))) - (magit-with-toplevel - (magit-run-git-async "submodule" "sync" args "--" modules))) - -;;;###autoload (autoload 'magit-submodule-unpopulate "magit-submodule" nil t) -(transient-define-suffix magit-submodule-unpopulate (modules args) - "Remove working directories of MODULES. - -With a prefix argument act on all suitable modules. Otherwise, -if the region selects modules, then act on those. Otherwise, if -there is a module at point, then act on that. Otherwise read a -single module from the user." - ;; Even though a package is "uninitialized" (it has no worktree) - ;; the super-projects $GIT_DIR/config may never-the-less set the - ;; module's url. This may happen if you `deinit' and then `init' - ;; to register (NOT initialize). Because the purpose of `deinit' - ;; is to remove the working directory AND to remove the url, this - ;; command does not limit itself to modules that have no working - ;; directory. - :class 'magit--git-submodule-suffix - :description "Unpopulate git submodule deinit [--force]" - (interactive - (list (magit-module-confirm "Unpopulate") - (magit-submodule-arguments "--force"))) - (magit-with-toplevel - (magit-run-git-async "submodule" "deinit" args "--" modules))) - -;;;###autoload -(defun magit-submodule-remove (modules args trash-gitdirs) - "Unregister MODULES and remove their working directories. - -For safety reasons, do not remove the gitdirs and if a module has -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. - -With the \"--force\" argument offer to remove dirty working -directories and with a prefix argument offer to delete gitdirs. -Both actions are very dangerous and have to be confirmed. There -are additional safety precautions in place, so you might be able -to recover from making a mistake here, but don't count on it." - (interactive - (list (if-let ((modules (magit-region-values 'magit-module-section t))) - (magit-confirm 'remove-modules nil "Remove %i modules" nil modules) - (list (magit-read-module-path "Remove module"))) - (magit-submodule-arguments "--force") - current-prefix-arg)) - (when (version< (magit-git-version) "2.12.0") - (error "This command requires Git v2.12.0")) - (when magit-submodule-remove-trash-gitdirs - (setq trash-gitdirs t)) - (magit-with-toplevel - (when-let - ((modified - (-filter (lambda (module) - (let ((default-directory (file-name-as-directory - (expand-file-name module)))) - (and (cddr (directory-files default-directory)) - (magit-anything-modified-p)))) - modules))) - (if (member "--force" args) - (if (magit-confirm 'remove-dirty-modules - "Remove dirty module %s" - "Remove %i dirty modules" - t modified) - (dolist (module modified) - (let ((default-directory (file-name-as-directory - (expand-file-name module)))) - (magit-git "stash" "push" - "-m" "backup before removal of this module"))) - (setq modules (cl-set-difference modules modified))) - (if (cdr modified) - (message "Omitting %s modules with uncommitted changes: %s" - (length modified) - (mapconcat #'identity modified ", ")) - (message "Omitting module %s, it has uncommitted changes" - (car modified))) - (setq modules (cl-set-difference modules modified)))) - (when modules - (let ((alist - (and trash-gitdirs - (--map (split-string it "\0") - (magit-git-lines "submodule" "foreach" "-q" - "printf \"$sm_path\\0$name\n\""))))) - (magit-git "submodule" "absorbgitdirs" "--" modules) - (magit-git "submodule" "deinit" args "--" modules) - (magit-git "rm" args "--" modules) - (when (and trash-gitdirs - (magit-confirm 'trash-module-gitdirs - "Trash gitdir of module %s" - "Trash gitdirs of %i modules" - t modules)) - (dolist (module modules) - (if-let ((name (cadr (assoc module alist)))) - ;; Disregard if `magit-delete-by-moving-to-trash' - ;; is nil. Not doing so would be too dangerous. - (delete-directory (magit-git-dir - (convert-standard-filename - (concat "modules/" name))) - t t) - (error "BUG: Weird module name and/or path for %s" module))))) - (magit-refresh)))) - -;;; Sections - -;;;###autoload -(defun magit-insert-modules () - "Insert submodule sections. -Hook `magit-module-sections-hook' controls which module sections -are inserted, and option `magit-module-sections-nested' controls -whether they are wrapped in an additional section." - (when-let ((modules (magit-list-module-paths))) - (if magit-module-sections-nested - (magit-insert-section (modules nil t) - (magit-insert-heading - (format "%s (%s)" - (propertize "Modules" - 'font-lock-face 'magit-section-heading) - (length modules))) - (magit-insert-section-body - (magit--insert-modules))) - (magit--insert-modules)))) - -(defun magit--insert-modules (&optional _section) - (magit-run-section-hook 'magit-module-sections-hook)) - -;;;###autoload -(defun magit-insert-modules-overview () - "Insert sections for all modules. -For each section insert the path and the output of `git describe --tags', -or, failing that, the abbreviated HEAD commit hash." - (when-let ((modules (magit-list-module-paths))) - (magit-insert-section (modules nil t) - (magit-insert-heading - (format "%s (%s)" - (propertize "Modules overview" - 'font-lock-face 'magit-section-heading) - (length modules))) - (magit-insert-section-body - (magit--insert-modules-overview))))) - -(defvar magit-modules-overview-align-numbers t) - -(defun magit--insert-modules-overview (&optional _section) - (magit-with-toplevel - (let* ((modules (magit-list-module-paths)) - (path-format (format "%%-%is " - (min (apply 'max (mapcar 'length modules)) - (/ (window-width) 2)))) - (branch-format (format "%%-%is " (min 25 (/ (window-width) 3))))) - (dolist (module modules) - (let ((default-directory - (expand-file-name (file-name-as-directory module)))) - (magit-insert-section (magit-module-section module t) - (insert (propertize (format path-format module) - 'font-lock-face 'magit-diff-file-heading)) - (if (not (file-exists-p ".git")) - (insert "(unpopulated)") - (insert (format - branch-format - (--if-let (magit-get-current-branch) - (propertize it 'font-lock-face 'magit-branch-local) - (propertize "(detached)" 'font-lock-face 'warning)))) - (--if-let (magit-git-string "describe" "--tags") - (progn (when (and magit-modules-overview-align-numbers - (string-match-p "\\`[0-9]" it)) - (insert ?\s)) - (insert (propertize it 'font-lock-face 'magit-tag))) - (--when-let (magit-rev-format "%h") - (insert (propertize it 'font-lock-face 'magit-hash))))) - (insert ?\n)))))) - (insert ?\n)) - -(defvar magit-modules-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-visit-thing] 'magit-list-submodules) - map) - "Keymap for `modules' sections.") - -(defvar magit-module-section-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map magit-file-section-map) - (define-key map (kbd "C-j") 'magit-submodule-visit) - (define-key map [C-return] 'magit-submodule-visit) - (define-key map [remap magit-visit-thing] 'magit-submodule-visit) - (define-key map [remap magit-delete-thing] 'magit-submodule-unpopulate) - (define-key map "K" 'magit-file-untrack) - (define-key map "R" 'magit-file-rename) - map) - "Keymap for `module' sections.") - -(defun magit-submodule-visit (module &optional other-window) - "Visit MODULE by calling `magit-status' on it. -Offer to initialize MODULE if it's not checked out yet. -With a prefix argument, visit in another window." - (interactive (list (or (magit-section-value-if 'module) - (magit-read-module-path "Visit module")) - current-prefix-arg)) - (magit-with-toplevel - (let ((path (expand-file-name module))) - (cond - ((file-exists-p (expand-file-name ".git" module)) - (magit-diff-visit-directory path other-window)) - ((y-or-n-p (format "Initialize submodule '%s' first?" module)) - (magit-run-git-async "submodule" "update" "--init" "--" module) - (set-process-sentinel - magit-this-process - (lambda (process event) - (let ((magit-process-raise-error t)) - (magit-process-sentinel process event)) - (when (and (eq (process-status process) 'exit) - (= (process-exit-status process) 0)) - (magit-diff-visit-directory path other-window))))) - ((file-exists-p path) - (dired-jump other-window (concat path "/."))))))) - -;;;###autoload -(defun magit-insert-modules-unpulled-from-upstream () - "Insert sections for modules that haven't been pulled from the upstream. -These sections can be expanded to show the respective commits." - (magit--insert-modules-logs "Modules unpulled from @{upstream}" - 'modules-unpulled-from-upstream - "HEAD..@{upstream}")) - -;;;###autoload -(defun magit-insert-modules-unpulled-from-pushremote () - "Insert sections for modules that haven't been pulled from the push-remote. -These sections can be expanded to show the respective commits." - (magit--insert-modules-logs "Modules unpulled from @{push}" - 'modules-unpulled-from-pushremote - "HEAD..@{push}")) - -;;;###autoload -(defun magit-insert-modules-unpushed-to-upstream () - "Insert sections for modules that haven't been pushed to the upstream. -These sections can be expanded to show the respective commits." - (magit--insert-modules-logs "Modules unmerged into @{upstream}" - 'modules-unpushed-to-upstream - "@{upstream}..HEAD")) - -;;;###autoload -(defun magit-insert-modules-unpushed-to-pushremote () - "Insert sections for modules that haven't been pushed to the push-remote. -These sections can be expanded to show the respective commits." - (magit--insert-modules-logs "Modules unpushed to @{push}" - 'modules-unpushed-to-pushremote - "@{push}..HEAD")) - -(defun magit--insert-modules-logs (heading type range) - "For internal use, don't add to a hook." - (unless (magit-ignore-submodules-p) - (when-let ((modules (magit-list-module-paths))) - (magit-insert-section section ((eval type) nil t) - (string-match "\\`\\(.+\\) \\([^ ]+\\)\\'" heading) - (magit-insert-heading - (propertize (match-string 1 heading) - 'font-lock-face 'magit-section-heading) - " " - (propertize (match-string 2 heading) - 'font-lock-face 'magit-branch-remote) - ":") - (magit-with-toplevel - (dolist (module modules) - (when (magit-module-worktree-p module) - (let ((default-directory - (expand-file-name (file-name-as-directory module)))) - (when (magit-file-accessible-directory-p default-directory) - (magit-insert-section sec (magit-module-section module t) - (magit-insert-heading - (propertize module - 'font-lock-face 'magit-diff-file-heading) - ":") - (magit-git-wash - (apply-partially 'magit-log-wash-log 'module) - "-c" "push.default=current" "log" "--oneline" range) - (when (> (point) - (oref sec content)) - (delete-char -1)))))))) - (if (> (point) - (oref section content)) - (insert ?\n) - (magit-cancel-section)))))) - -;;; List - -;;;###autoload -(defun magit-list-submodules () - "Display a list of the current repository's submodules." - (interactive) - (magit-submodule-list-setup magit-submodule-list-columns)) - -(defvar magit-submodule-list-mode-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map magit-repolist-mode-map) - map) - "Local keymap for Magit-Submodule-List mode buffers.") - -(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) - (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 - (expand-file-name (file-name-as-directory module)))) - (and (file-exists-p ".git") - (list module - (vconcat - (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 (spec) - "Insert the relative path of the submodule." - (cadr (assq :path spec))) - -;;; Utilities - -(defun magit-submodule--maybe-reuse-gitdir (name path) - (let ((gitdir - (magit-git-dir (convert-standard-filename (concat "modules/" name))))) - (when (and (file-exists-p gitdir) - (not (file-exists-p path))) - (pcase (read-char-choice - (concat - gitdir " already exists.\n" - "Type [u] to use the existing gitdir and create the working tree\n" - " [r] to rename the existing gitdir and clone again\n" - " [t] to trash the existing gitdir and clone again\n" - " [C-g] to abort ") - '(?u ?r ?t)) - (?u (magit-submodule--restore-worktree (expand-file-name path) gitdir)) - (?r (rename-file gitdir (concat gitdir "-" - (format-time-string "%F-%T")))) - (?t (delete-directory gitdir t t)))))) - -(defun magit-submodule--restore-worktree (worktree gitdir) - (make-directory worktree t) - (with-temp-file (expand-file-name ".git" worktree) - (insert "gitdir: " (file-relative-name gitdir worktree) "\n")) - (let ((default-directory worktree)) - (magit-call-git "reset" "--hard" "HEAD" "--"))) - -;;; _ -(provide 'magit-submodule) -;;; magit-submodule.el ends here diff --git a/elpa/magit-20210802.1524/magit-subtree.el b/elpa/magit-20210802.1524/magit-subtree.el deleted file mode 100644 index 34e9451e..00000000 --- a/elpa/magit-20210802.1524/magit-subtree.el +++ /dev/null @@ -1,184 +0,0 @@ -;;; magit-subtree.el --- subtree 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-subtree "magit-subtree" nil t) -(transient-define-prefix magit-subtree () - "Import or export subtrees." - :man-page "git-subtree" - ["Actions" - ("i" "Import" magit-subtree-import) - ("e" "Export" magit-subtree-export)]) - -;;;###autoload (autoload 'magit-subtree-import "magit-subtree" nil t) -(transient-define-prefix magit-subtree-import () - "Import subtrees." - :man-page "git-subtree" - ["Arguments" - (magit-subtree:--prefix) - (magit-subtree:--message) - ("-s" "Squash" "--squash")] - ["Actions" - [("a" "Add" magit-subtree-add) - ("c" "Add commit" magit-subtree-add-commit)] - [("m" "Merge" magit-subtree-merge) - ("f" "Pull" magit-subtree-pull)]]) - -;;;###autoload (autoload 'magit-subtree-export "magit-subtree" nil t) -(transient-define-prefix magit-subtree-export () - "Export subtrees." - :man-page "git-subtree" - ["Arguments" - (magit-subtree:--prefix) - (magit-subtree:--annotate) - (magit-subtree:--branch) - (magit-subtree:--onto) - ("-i" "Ignore joins" "--ignore-joins") - ("-j" "Rejoin" "--rejoin")] - ["Actions" - ("p" "Push" magit-subtree-push) - ("s" "Split" magit-subtree-split)]) - -(transient-define-argument magit-subtree:--prefix () - :description "Prefix" - :class 'transient-option - :shortarg "-P" - :argument "--prefix=" - :reader 'magit-subtree-read-prefix) - -(defun magit-subtree-read-prefix (prompt &optional default _history) - (let* ((insert-default-directory nil) - (topdir (magit-toplevel)) - (prefix (read-directory-name (concat prompt ": ") topdir default))) - (if (file-name-absolute-p prefix) - ;; At least `ido-mode's variant is not compatible. - (if (string-prefix-p topdir prefix) - (file-relative-name prefix topdir) - (user-error "%s isn't inside the repository at %s" prefix topdir)) - prefix))) - -(transient-define-argument magit-subtree:--message () - :description "Message" - :class 'transient-option - :shortarg "-m" - :argument "--message=") - -(transient-define-argument magit-subtree:--annotate () - :description "Annotate" - :class 'transient-option - :key "-a" - :argument "--annotate=") - -(transient-define-argument magit-subtree:--branch () - :description "Branch" - :class 'transient-option - :shortarg "-b" - :argument "--branch=") - -(transient-define-argument magit-subtree:--onto () - :description "Onto" - :class 'transient-option - :key "-o" - :argument "--onto=" - :reader 'magit-transient-read-revision) - -(defun magit-subtree-prefix (transient prompt) - (--if-let (--first (string-prefix-p "--prefix=" it) - (transient-args transient)) - (substring it 9) - (magit-subtree-read-prefix prompt))) - -(defun magit-subtree-arguments (transient) - (--remove (string-prefix-p "--prefix=" it) - (transient-args transient))) - -(defun magit-git-subtree (subcmd prefix &rest args) - (magit-run-git-async "subtree" subcmd (concat "--prefix=" prefix) args)) - -;;;###autoload -(defun magit-subtree-add (prefix repository ref args) - "Add REF from REPOSITORY as a new subtree at PREFIX." - (interactive - (cons (magit-subtree-prefix 'magit-subtree-import "Add subtree") - (let ((remote (magit-read-remote-or-url "From repository"))) - (list remote - (magit-read-refspec "Ref" remote) - (magit-subtree-arguments 'magit-subtree-import))))) - (magit-git-subtree "add" prefix args repository ref)) - -;;;###autoload -(defun magit-subtree-add-commit (prefix commit args) - "Add COMMIT as a new subtree at PREFIX." - (interactive - (list (magit-subtree-prefix 'magit-subtree-import "Add subtree") - (magit-read-string-ns "Commit") - (magit-subtree-arguments 'magit-subtree-import))) - (magit-git-subtree "add" prefix args commit)) - -;;;###autoload -(defun magit-subtree-merge (prefix commit args) - "Merge COMMIT into the PREFIX subtree." - (interactive - (list (magit-subtree-prefix 'magit-subtree-import "Merge into subtree") - (magit-read-string-ns "Commit") - (magit-subtree-arguments 'magit-subtree-import))) - (magit-git-subtree "merge" prefix args commit)) - -;;;###autoload -(defun magit-subtree-pull (prefix repository ref args) - "Pull REF from REPOSITORY into the PREFIX subtree." - (interactive - (cons (magit-subtree-prefix 'magit-subtree-import "Pull into subtree") - (let ((remote (magit-read-remote-or-url "From repository"))) - (list remote - (magit-read-refspec "Ref" remote) - (magit-subtree-arguments 'magit-subtree-import))))) - (magit-git-subtree "pull" prefix args repository ref)) - -;;;###autoload -(defun magit-subtree-push (prefix repository ref args) - "Extract the history of the subtree PREFIX and push it to REF on REPOSITORY." - (interactive (list (magit-subtree-prefix 'magit-subtree-export "Push subtree") - (magit-read-remote-or-url "To repository") - (magit-read-string-ns "To reference") - (magit-subtree-arguments 'magit-subtree-export))) - (magit-git-subtree "push" prefix args repository ref)) - -;;;###autoload -(defun magit-subtree-split (prefix commit args) - "Extract the history of the subtree PREFIX." - (interactive (list (magit-subtree-prefix 'magit-subtree-export "Split subtree") - (magit-read-string-ns "Commit") - (magit-subtree-arguments 'magit-subtree-export))) - (magit-git-subtree "split" prefix args commit)) - -;;; _ -(provide 'magit-subtree) -;;; magit-subtree.el ends here diff --git a/elpa/magit-20210802.1524/magit-tag.el b/elpa/magit-20210802.1524/magit-tag.el deleted file mode 100644 index d19abbe7..00000000 --- a/elpa/magit-20210802.1524/magit-tag.el +++ /dev/null @@ -1,219 +0,0 @@ -;;; magit-tag.el --- tag functionality -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements tag commands. - -;;; Code: - -(require 'magit) - -;; For `magit-tag-delete'. -(defvar helm-comp-read-use-marked) - -;;;###autoload (autoload 'magit-tag "magit" nil t) -(transient-define-prefix magit-tag () - "Create or delete a tag." - :man-page "git-tag" - ["Arguments" - ("-f" "Force" ("-f" "--force")) - ("-a" "Annotate" ("-a" "--annotate")) - ("-s" "Sign" ("-s" "--sign")) - (magit-tag:--local-user)] - [["Create" - ("t" "tag" magit-tag-create) - ("r" "release" magit-tag-release)] - ["Do" - ("k" "delete" magit-tag-delete) - ("p" "prune" magit-tag-prune)]]) - -(defun magit-tag-arguments () - (transient-args 'magit-tag)) - -(transient-define-argument magit-tag:--local-user () - :description "Sign as" - :class 'transient-option - :shortarg "-u" - :argument "--local-user=" - :reader 'magit-read-gpg-signing-key - :history-key 'magit:--gpg-sign) - -;;;###autoload -(defun magit-tag-create (name rev &optional args) - "Create a new tag with the given NAME at REV. -With a prefix argument annotate the tag. -\n(git tag [--annotate] NAME REV)" - (interactive (list (magit-read-tag "Tag name") - (magit-read-branch-or-commit "Place tag on") - (let ((args (magit-tag-arguments))) - (when current-prefix-arg - (cl-pushnew "--annotate" args)) - args))) - (magit-run-git-with-editor "tag" args name rev)) - -;;;###autoload -(defun magit-tag-delete (tags) - "Delete one or more tags. -If the region marks multiple tags (and nothing else), then offer -to delete those, otherwise prompt for a single tag to be deleted, -defaulting to the tag at point. -\n(git tag -d TAGS)" - (interactive (list (--if-let (magit-region-values 'tag) - (magit-confirm t nil "Delete %i tags" nil it) - (let ((helm-comp-read-use-marked t)) - (magit-read-tag "Delete tag" t))))) - (magit-run-git "tag" "-d" tags)) - -;;;###autoload -(defun magit-tag-prune (tags remote-tags remote) - "Offer to delete tags missing locally from REMOTE, and vice versa." - (interactive - (let* ((remote (magit-read-remote "Prune tags using remote")) - (tags (magit-list-tags)) - (rtags (prog2 (message "Determining remote tags...") - (magit-remote-list-tags remote) - (message "Determining remote tags...done"))) - (ltags (-difference tags rtags)) - (rtags (-difference rtags tags))) - (unless (or ltags rtags) - (message "Same tags exist locally and remotely")) - (unless (magit-confirm t - "Delete %s locally" - "Delete %i tags locally" - 'noabort ltags) - (setq ltags nil)) - (unless (magit-confirm t - "Delete %s from remote" - "Delete %i tags from remote" - 'noabort rtags) - (setq rtags nil)) - (list ltags rtags remote))) - (when tags - (magit-call-git "tag" "-d" tags)) - (when remote-tags - (magit-run-git-async "push" remote (--map (concat ":" it) remote-tags)))) - -(defvar magit-tag-version-regexp-alist - '(("^[-._+ ]?snapshot\\.?$" . -4) - ("^[-._+]$" . -4) - ("^[-._+ ]?\\(cvs\\|git\\|bzr\\|svn\\|hg\\|darcs\\)\\.?$" . -4) - ("^[-._+ ]?unknown\\.?$" . -4) - ("^[-._+ ]?alpha\\.?$" . -3) - ("^[-._+ ]?beta\\.?$" . -2) - ("^[-._+ ]?\\(pre\\|rc\\)\\.?$" . -1)) - "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 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 &optional args) - "Create a release tag. - -Assume that release tags match `magit-release-tag-regexp'. - -First prompt 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. - -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* - ((`(,pver ,ptag ,pmsg) (car (magit--list-releases))) - (tag (read-string "Create release tag: " ptag)) - (ver (and (string-match magit-release-tag-regexp tag) - (match-string 2 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) - (when (memq (process-status process) '(exit signal)) - (magit-process-sentinel process event) - (magit-refs-setup-buffer "HEAD" (magit-show-refs-arguments)))))) - -(defun magit--list-releases () - "Return a list of releases. -The list is ordered, beginning with the highest release. -Each release element has the form (VERSION TAG MESSAGE). -`magit-release-tag-regexp' is used to determine whether -a tag qualifies as a release tag." - (save-match-data - (mapcar - #'cdr - (nreverse - (cl-sort (cl-mapcan - (lambda (line) - (and (string-match " +" line) - (let ((tag (substring line 0 (match-beginning 0))) - (msg (substring line (match-end 0)))) - (and (string-match magit-release-tag-regexp tag) - (let ((ver (match-string 2 tag)) - (version-regexp-alist - magit-tag-version-regexp-alist)) - (list (list (version-to-list ver) - ver tag msg))))))) - ;; Cannot rely on "--sort=-version:refname" because - ;; that gets confused if the version prefix has changed. - (magit-git-lines "tag" "-n")) - ;; The inverse of this function does not exist. - #'version-list-< :key #'car))))) - -;;; _ -(provide 'magit-tag) -;;; magit-tag.el ends here diff --git a/elpa/magit-20210802.1524/magit-transient.el b/elpa/magit-20210802.1524/magit-transient.el deleted file mode 100644 index d03694b0..00000000 --- a/elpa/magit-20210802.1524/magit-transient.el +++ /dev/null @@ -1,200 +0,0 @@ -;;; magit-transient.el --- support for transients -*- lexical-binding: t -*- - -;; 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) -;; 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. - -;;; Commentary: - -;; This library implements Magit-specific prefix and suffix classes, -;; and their methods. - -;;; Code: - -(require 'magit-git) -(require 'magit-mode) -(require 'magit-process) - -(require 'transient) - -;;; Classes - -(defclass magit--git-variable (transient-variable) - ((scope :initarg :scope))) - -(defclass magit--git-variable:choices (magit--git-variable) - ((choices :initarg :choices) - (fallback :initarg :fallback :initform nil) - (default :initarg :default :initform nil))) - -(defclass magit--git-variable:urls (magit--git-variable) - ((seturl-arg :initarg :seturl-arg :initform nil))) - -;;; Methods -;;;; Init - -(cl-defmethod transient-init-scope ((obj magit--git-variable)) - (oset obj scope - (cond (transient--prefix - (oref transient--prefix scope)) - ((slot-boundp obj 'scope) - (funcall (oref obj scope) obj))))) - -(cl-defmethod transient-init-value ((obj magit--git-variable)) - (let ((variable (format (oref obj variable) - (oref obj scope)))) - (oset obj variable variable) - (oset obj value - (cond ((oref obj multi-value) - (magit-get-all variable)) - (t - (magit-git-string "config" "--local" variable)))))) - -;;;; Read - -(cl-defmethod transient-infix-read :around ((obj magit--git-variable:urls)) - (mapcar (lambda (url) - (if (string-prefix-p "~" url) - (expand-file-name url) - url)) - (cl-call-next-method obj))) - -(cl-defmethod transient-infix-read ((obj magit--git-variable:choices)) - (let ((choices (oref obj choices))) - (when (functionp choices) - (setq choices (funcall choices))) - (if-let ((value (oref obj value))) - (cadr (member value choices)) - (car choices)))) - -;;;; Readers - -(defun magit-transient-read-person (prompt initial-input history) - (magit-completing-read - prompt - (mapcar (lambda (line) - (save-excursion - (and (string-match "\\`[\s\t]+[0-9]+\t" line) - (list (substring line (match-end 0)))))) - (magit-git-lines "shortlog" "-n" "-s" "-e" "HEAD")) - nil nil initial-input history)) - -(defun magit-transient-read-revision (prompt initial-input history) - (or (magit-completing-read prompt (cons "HEAD" (magit-list-refnames)) - nil nil initial-input history - (or (magit-branch-or-commit-at-point) - (magit-get-current-branch))) - (user-error "Nothing selected"))) - -;;;; Set - -(cl-defmethod transient-infix-set ((obj magit--git-variable) value) - (let ((variable (oref obj variable))) - (oset obj value value) - (if (oref obj multi-value) - (magit-set-all value variable) - (magit-set value variable)) - (magit-refresh) - (unless (or value transient--prefix) - (message "Unset %s" variable)))) - -(cl-defmethod transient-infix-set ((obj magit--git-variable:urls) values) - (let ((previous (oref obj value)) - (seturl (oref obj seturl-arg)) - (remote (oref transient--prefix scope))) - (oset obj value values) - (dolist (v (-difference values previous)) - (magit-call-git "remote" "set-url" seturl "--add" remote v)) - (dolist (v (-difference previous values)) - (magit-call-git "remote" "set-url" seturl "--delete" remote - (concat "^" (regexp-quote v) "$"))) - (magit-refresh))) - -;;;; Draw - -(cl-defmethod transient-format-description ((obj magit--git-variable)) - (or (oref obj description) - (oref obj variable))) - -(cl-defmethod transient-format-value ((obj magit--git-variable)) - (if-let ((value (oref obj value))) - (if (oref obj multi-value) - (if (cdr value) - (mapconcat (lambda (v) - (concat "\n " - (propertize v 'face 'transient-value))) - value "") - (propertize (car value) 'face 'transient-value)) - (propertize (car (split-string value "\n")) - 'face 'transient-value)) - (propertize "unset" 'face 'transient-inactive-value))) - -(cl-defmethod transient-format-value ((obj magit--git-variable:choices)) - (let* ((variable (oref obj variable)) - (choices (oref obj choices)) - (local (magit-git-string "config" "--local" variable)) - (global (magit-git-string "config" "--global" variable)) - (default (oref obj default)) - (fallback (oref obj fallback)) - (fallback (and fallback - (when-let ((val (magit-get fallback))) - (concat fallback ":" val))))) - (when (functionp choices) - (setq choices (funcall choices))) - (concat - (propertize "[" 'face 'transient-inactive-value) - (mapconcat (lambda (choice) - (propertize choice 'face (if (equal choice local) - (if (member choice choices) - 'transient-value - 'font-lock-warning-face) - 'transient-inactive-value))) - (if (and local (not (member local choices))) - (cons local choices) - choices) - (propertize "|" 'face 'transient-inactive-value)) - (and (or global fallback default) - (concat - (propertize "|" 'face 'transient-inactive-value) - (cond (global - (propertize (concat "global:" global) - 'face (cond (local - 'transient-inactive-value) - ((member global choices) - 'transient-value) - (t - 'font-lock-warning-face)))) - (fallback - (propertize fallback - 'face (if local - 'transient-inactive-value - 'transient-value))) - (default - (propertize (concat "default:" default) - 'face (if local - 'transient-inactive-value - 'transient-value)))))) - (propertize "]" 'face 'transient-inactive-value)))) - -;;; _ -(provide 'magit-transient) -;;; magit-transient.el ends here diff --git a/elpa/magit-20210802.1524/magit-utils.el b/elpa/magit-20210802.1524/magit-utils.el deleted file mode 100644 index bfd2827d..00000000 --- a/elpa/magit-20210802.1524/magit-utils.el +++ /dev/null @@ -1,1231 +0,0 @@ -;;; magit-utils.el --- various utilities -*- lexical-binding: t; coding: utf-8 -*- - -;; 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. - -;; Author: Jonas Bernoulli -;; Maintainer: Jonas Bernoulli - -;; 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) -;; 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. - -;;; Commentary: - -;; This library defines several utility functions used by several -;; other libraries which cannot depend on one another (because -;; circular dependencies are not good). Luckily most (all) of these -;; functions have very little (nothing) to do with Git, so we not only -;; have to do this, it even makes sense. - -;; Unfortunately there are also some options which are used by several -;; libraries which cannot depend on one another, they are defined here -;; too. - -;;; Code: - -(require 'cl-lib) -(require 'dash) -(require 'eieio) -(require 'seq) -(require 'subr-x) - -(require 'crm) - -(eval-when-compile (require 'ido)) -(declare-function ido-completing-read+ "ido-completing-read+" - (prompt collection &optional predicate - require-match initial-input - hist def inherit-input-method)) -(declare-function Info-get-token "info" (pos start all &optional errorstring)) - -(eval-when-compile (require 'vc-git)) -(declare-function vc-git--run-command-string "vc-git" (file &rest args)) - -(eval-when-compile (require 'which-func)) -(declare-function which-function "which-func" ()) - -(defvar magit-wip-before-change-mode) - -;;; Options - -(defcustom magit-completing-read-function 'magit-builtin-completing-read - "Function to be called when requesting input from the user. - -If you have enabled `ivy-mode' or `helm-mode', then you don't -have to customize this option; `magit-builtin-completing-read' -will work just fine. However, if you use Ido completion, then -you do have to use `magit-ido-completing-read', because Ido is -less well behaved than the former, more modern alternatives. - -If you would like to use Ivy or Helm completion with Magit but -not enable the respective modes globally, then customize this -option to use `ivy-completing-read' or -`helm--completing-read-default'. If you choose to use -`ivy-completing-read', note that the items may always be shown in -alphabetical order, depending on your version of Ivy." - :group 'magit-essentials - :type '(radio (function-item magit-builtin-completing-read) - (function-item magit-ido-completing-read) - (function-item ivy-completing-read) - (function-item helm--completing-read-default) - (function :tag "Other function"))) - -(defcustom magit-dwim-selection - '((magit-stash-apply nil t) - (magit-stash-branch nil t) - (magit-stash-branch-here nil t) - (magit-stash-format-patch nil t) - (magit-stash-drop nil ask) - (magit-stash-pop nil ask) - (forge-browse-dwim nil t) - (forge-browse-commit nil t) - (forge-browse-branch nil t) - (forge-browse-remote nil t) - (forge-browse-issue nil t) - (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-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 -possible candidates. They do so even when there is a thing at -point that they can act on, which is then offered as the default. - -This option can be used to tell certain commands to use the thing -at point instead of asking the user to select a candidate to act -on, with or without confirmation. - -The value has the form ((COMMAND nil|PROMPT DEFAULT)...). - -- COMMAND is the command that should not prompt for a choice. - To have an effect, the command has to use the function - `magit-completing-read' or a utility function which in turn uses - that function. - -- If the command uses `magit-completing-read' multiple times, then - PROMPT can be used to only affect one of these uses. PROMPT, if - non-nil, is a regular expression that is used to match against - the PROMPT argument passed to `magit-completing-read'. - -- DEFAULT specifies how to use the default. If it is t, then - the DEFAULT argument passed to `magit-completing-read' is used - without confirmation. If it is `ask', then the user is given - a chance to abort. DEFAULT can also be nil, in which case the - entry has no effect." - :package-version '(magit . "2.12.0") - :group 'magit-commands - :type '(repeat - (list (symbol :tag "Command") ; It might not be fboundp yet. - (choice (const :tag "for all prompts" nil) - (regexp :tag "for prompts matching regexp")) - (choice (const :tag "offer other choices" nil) - (const :tag "require confirmation" ask) - (const :tag "use default without confirmation" t))))) - -(defconst magit--confirm-actions - '((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 '(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 -confirmation. Each of the below symbols stands for an action -which, when invoked unintentionally or without being fully aware -of the consequences, could lead to tears. In many cases there -are several commands that perform variations of a certain action, -so we don't use the command names but more generic symbols. - -Applying changes: - - `discard' Discarding one or more changes (i.e. hunks or the - complete diff for a file) loses that change, obviously. - - `reverse' Reverting one or more changes can usually be undone - by reverting the reversion. - - `stage-all-changes', `unstage-all-changes' When there are both - staged and unstaged changes, then un-/staging everything would - destroy that distinction. Of course that also applies when - un-/staging a single change, but then less is lost and one does - that so often that having to confirm every time would be - unacceptable. - -Files: - - `delete' When a file that isn't yet tracked by Git is deleted - then it is completely lost, not just the last changes. Very - dangerous. - - `trash' Instead of deleting a file it can also be move to the - system trash. Obviously much less dangerous than deleting it. - - Also see option `magit-delete-by-moving-to-trash'. - - `resurrect' A deleted file can easily be resurrected by - \"deleting\" the deletion, which is done using the same command - that was used to delete the same file in the first place. - - `untrack' Untracking a file can be undone by tracking it again. - - `rename' Renaming a file can easily be undone. - -Sequences: - - `reset-bisect' Aborting (known to Git as \"resetting\") a - bisect operation loses all information collected so far. - - `abort-rebase' Aborting a rebase throws away all already - modified commits, but it's possible to restore those from the - reflog. - - `abort-merge' Aborting a merge throws away all conflict - resolutions which has already been carried out by the user. - - `merge-dirty' Merging with a dirty worktree can make it hard to - go back to the state before the merge was initiated. - -References: - - `delete-unmerged-branch' Once a branch has been deleted it can - only be restored using low-level recovery tools provided by - Git. And even then the reflog is gone. The user always has - to confirm the deletion of a branch by accepting the default - 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 - 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. - - `drop-stashes' Dropping a stash is dangerous because Git stores - stashes in the reflog. Once a stash is removed, there is no - going back without using low-level recovery tools provided by - Git. When a single stash is dropped, then the user always has - to confirm by accepting the default (or selecting another). - 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'. - - `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 - and squash variants. - - `edit-published' Affects the commands `magit-edit-line-commit' - and `magit-diff-edit-hunk-commit'. These two commands make - it quite easy to accidentally edit a published commit, so you - should think twice before configuring them not to ask for - confirmation. - - To disable confirmation completely, add all three symbols here - or set `magit-published-branches' to nil. - -Removing modules: - - `remove-modules' When you remove the working directory of a - module that does not contain uncommitted changes, then that is - safer than doing so when there are uncommitted changes and/or - when you also remove the gitdir. Still, you don't want to do - that by accident. - - `remove-dirty-modules' When you remove the working directory of - a module that contains uncommitted changes, then those changes - are gone for good. It is better to go to the module, inspect - these changes and only if appropriate discard them manually. - - `trash-module-gitdirs' When you remove the gitdir of a module, - then all unpushed changes are gone for good. It is very easy - to forget that you have some unfinished work on an unpublished - feature branch or even in a stash. - - Actually there are some safety precautions in place, that might - help you out if you make an unwise choice here, but don't count - on it. In case of emergency, stay calm and check the stash and - the `trash-directory' for traces of lost work. - -Various: - - `kill-process' There seldom is a reason to kill a process. - -Global settings: - - Instead of adding all of the above symbols to the value of this - option you can also set it to the atom `t', which has the same - effect as adding all of the above symbols. Doing that most - certainly is a bad idea, especially because other symbols might - be added in the future. So even if you don't want to be asked - for confirmation for any of these actions, you are still better - of adding all of the respective symbols individually. - - When `magit-wip-before-change-mode' is enabled then these actions - can fairly easily be undone: `discard', `reverse', - `stage-all-changes', and `unstage-all-changes'. If and only if - this mode is enabled, then `safe-with-wip' has the same effect - as adding all of these symbols individually." - :package-version '(magit . "2.1.0") - :group 'magit-essentials - :group 'magit-commands - :type `(choice (const :tag "Always require confirmation" nil) - (const :tag "Never require confirmation" t) - (set :tag "Require confirmation except for" - ;; `remove-dirty-modules' and - ;; `trash-module-gitdirs' intentionally - ;; omitted. - ,@magit--confirm-actions))) - -(defcustom magit-slow-confirm '(drop-stashes) - "Whether to ask user \"y or n\" or \"yes or no\" questions. - -When this is nil, then `y-or-n-p' is used when the user has to -confirm a potentially destructive action. When this is t, then -`yes-or-no-p' is used instead. If this is a list of symbols -identifying actions, then `yes-or-no-p' is used for those, -`y-or-no-p' for all others. The list of actions is the same as -for `magit-no-confirm' (which see)." - :package-version '(magit . "2.9.0") - :group 'magit-miscellaneous - :type `(choice (const :tag "Always ask \"yes or no\" questions" t) - (const :tag "Always ask \"y or n\" questions" nil) - (set :tag "Ask \"yes or no\" questions only for" - ,@magit--confirm-actions))) - -(defcustom magit-no-message nil - "A list of messages Magit should not display. - -Magit displays most echo area messages using `message', but a few -are displayed using `magit-message' instead, which takes the same -arguments as the former, FORMAT-STRING and ARGS. `magit-message' -forgoes printing a message if any member of this list is a prefix -of the respective FORMAT-STRING. - -If Magit prints a message which causes you grief, then please -first investigate whether there is another option which can be -used to suppress it. If that is not the case, then ask the Magit -maintainers to start using `magit-message' instead of `message' -in that case. We are not proactively replacing all uses of -`message' with `magit-message', just in case someone *might* find -some of these messages useless. - -Messages which can currently be suppressed using this option are: -* \"Turning on magit-auto-revert-mode...\"" - :package-version '(magit . "2.8.0") - :group 'magit-miscellaneous - :type '(repeat string)) - -(defcustom magit-ellipsis (if (char-displayable-p ?…) "…" "...") - "String used to abbreviate text in process buffers. - -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 'string) - -(defcustom magit-update-other-window-delay 0.2 - "Delay before automatically updating the other window. - -When moving around in certain buffers, then certain other -buffers, which are being displayed in another window, may -optionally be updated to display information about the -section at point. - -When holding down a key to move by more than just one section, -then that would update that buffer for each section on the way. -To prevent that, updating the revision buffer is delayed, and -this option controls for how long. For optimal experience you -might have to adjust this delay and/or the keyboard repeat rate -and delay of your graphical environment or operating system." - :package-version '(magit . "2.3.0") - :group 'magit-miscellaneous - :type 'number) - -(defcustom magit-view-git-manual-method 'info - "How links to Git documentation are followed from Magit's Info manuals. - -`info' Follow the link to the node in the `gitman' Info manual - as usual. Unfortunately that manual is not installed by - default on some platforms, and when it is then the nodes - look worse than the actual manpages. - -`man' View the respective man-page using the `man' package. - -`woman' View the respective man-page using the `woman' package." - :package-version '(magit . "2.9.0") - :group 'magit-miscellaneous - :type '(choice (const :tag "view info manual" info) - (const :tag "view manpage using `man'" man) - (const :tag "view manpage using `woman'" woman))) - -;;; 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) - -(defun magit-completing-read (prompt collection &optional - predicate require-match initial-input - hist def fallback) - "Read a choice in the minibuffer, or use the default choice. - -This is the function that Magit commands use when they need the -user to select a single thing to act on. The arguments have the -same meaning as for `completing-read', except for FALLBACK, which -is unique to this function and is described below. - -Instead of asking the user to choose from a list of possible -candidates, this function may instead just return the default -specified by DEF, with or without requiring user confirmation. -Whether that is the case depends on PROMPT, `this-command' and -`magit-dwim-selection'. See the documentation of the latter for -more information. - -If it does use the default without the user even having to -confirm that, then `magit-completing-read--silent-default' is set -to t, otherwise nil. - -If it does read a value in the minibuffer, then this function -acts similarly to `completing-read', except for the following: - -- COLLECTION must be a list of choices. A function is not - supported. - -- If REQUIRE-MATCH is nil and the user exits without a choice, - then nil is returned instead of an empty string. - -- If REQUIRE-MATCH is non-nil and the user exits without a - choice, `user-error' is raised. - -- FALLBACK specifies a secondary default that is only used if - the primary default DEF is nil. The secondary default is not - subject to `magit-dwim-selection' — if DEF is nil but FALLBACK - is not, then this function always asks the user to choose a - candidate, just as if both defaults were nil. - -- \": \" is appended to PROMPT. - -- PROMPT is modified to end with \" (default DEF|FALLBACK): \" - provided that DEF or FALLBACK is non-nil, that neither - `ivy-mode' nor `helm-mode' is enabled, and that - `magit-completing-read-function' is set to its default value of - `magit-builtin-completing-read'." - (setq magit-completing-read--silent-default nil) - (if-let ((dwim (and def - (nth 2 (-first (pcase-lambda (`(,cmd ,re ,_)) - (and (eq this-command cmd) - (or (not re) - (string-match-p re prompt)))) - magit-dwim-selection))))) - (if (eq dwim 'ask) - (if (y-or-n-p (format "%s %s? " prompt def)) - def - (user-error "Abort")) - (setq magit-completing-read--silent-default t) - def) - (unless def - (setq def fallback)) - (let ((command this-command) - (reply (funcall magit-completing-read-function - (concat prompt ": ") - (if (and def (not (member def collection))) - (cons def collection) - collection) - predicate - require-match initial-input hist def))) - (setq this-command command) - ;; Note: Avoid `string=' to support `helm-comp-read-use-marked'. - (if (equal reply "") - (if require-match - (user-error "Nothing selected") - nil) - reply)))) - -(defun magit--completion-table (collection) - (lambda (string pred action) - (if (eq action 'metadata) - '(metadata (display-sort-function . identity)) - (complete-with-action action collection string pred)))) - -(defun magit-builtin-completing-read - (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 choices (magit--completion-table choices))) - (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) - "Read multiple items from CHOICES, separated by SEP. - -Set up the `crm' variables needed to read multiple values with -`read-from-minibuffer'. - -SEP is a regexp matching characters that can separate choices. -When SEP is nil, it defaults to `crm-default-separator'. -DEFAULT, HIST, and KEYMAP are passed to `read-from-minibuffer'. -When KEYMAP is nil, it defaults to `crm-local-completion-map'. - -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 - '(crm--choose-completion-string)) - (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))) - (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) - nil hist default)))) - (when (string-equal input "") - (or (setq input default) - (user-error "Nothing selected"))) - input)) - -(defun magit-completing-read-multiple* - (prompt table &optional predicate require-match initial-input - 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 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) - "Ido-based `completing-read' almost-replacement. - -Unfortunately `ido-completing-read' is not suitable as a -drop-in replacement for `completing-read', instead we use -`ido-completing-read+' from the third-party package by the -same name." - (if (require 'ido-completing-read+ nil t) - (ido-completing-read+ prompt choices predicate require-match - initial-input hist - (or def (and require-match (car choices)))) - (display-warning 'magit "ido-completing-read+ is not installed - -To use Ido completion with Magit you need to install the -third-party `ido-completing-read+' packages. Falling -back to built-in `completing-read' for now." :error) - (magit-builtin-completing-read prompt choices predicate require-match - initial-input hist def))) - -(defun magit-prompt-with-default (prompt def) - (if (and def (> (length prompt) 2) - (string-equal ": " (substring prompt -2))) - (format "%s (default %s): " (substring prompt 0 -2) def) - prompt)) - -(defvar magit-minibuffer-local-ns-map - (let ((map (make-sparse-keymap))) - (set-keymap-parent map minibuffer-local-map) - (define-key map "\s" 'magit-whitespace-disallowed) - (define-key map "\t" 'magit-whitespace-disallowed) - map)) - -(defun magit-whitespace-disallowed () - "Beep to tell the user that whitespace is not allowed." - (interactive) - (ding) - (message "Whitespace isn't allowed here") - (setq defining-kbd-macro nil) - (force-mode-line-update)) - -(defun magit-read-string (prompt &optional initial-input history default-value - inherit-input-method no-whitespace) - "Read a string from the minibuffer, prompting with string PROMPT. - -This is similar to `read-string', but -* empty input is only allowed if DEFAULT-VALUE is non-nil in - which case that is returned, -* whitespace is not allowed and leading and trailing whitespace is - removed automatically if NO-WHITESPACE is non-nil, -* \": \" is appended to PROMPT, and -* an invalid DEFAULT-VALUE is silently ignored." - (when default-value - (when (consp default-value) - (setq default-value (car default-value))) - (unless (stringp default-value) - (setq default-value nil))) - (let* ((minibuffer-completion-table nil) - (val (read-from-minibuffer - (magit-prompt-with-default (concat prompt ": ") default-value) - initial-input (and no-whitespace magit-minibuffer-local-ns-map) - nil history default-value inherit-input-method)) - (trim (lambda (regexp string) - (save-match-data - (if (string-match regexp string) - (replace-match "" t t string) - string))))) - (when (and (string= val "") default-value) - (setq val default-value)) - (when no-whitespace - (setq val (funcall trim "\\`\\(?:[ \t\n\r]+\\)" - (funcall trim "\\(?:[ \t\n\r]+\\)\\'" val)))) - (cond ((string= val "") - (user-error "Need non-empty input")) - ((and no-whitespace (string-match-p "[\s\t\n]" val)) - (user-error "Input contains whitespace")) - (t val)))) - -(defun magit-read-string-ns (prompt &optional initial-input history - default-value inherit-input-method) - "Call `magit-read-string' with non-nil NO-WHITESPACE." - (magit-read-string prompt initial-input history default-value - inherit-input-method t)) - -(defmacro magit-read-char-case (prompt verbose &rest clauses) - (declare (indent 2) - (debug (form form &rest (characterp form body)))) - `(prog1 (pcase (read-char-choice - (concat ,prompt - (mapconcat #'identity - (list ,@(mapcar #'cadr clauses)) - ", ") - ,(if verbose ", or [C-g] to abort " " ")) - ',(mapcar #'car clauses)) - ,@(--map `(,(car it) ,@(cddr it)) clauses)) - (message ""))) - -(defun magit-y-or-n-p (prompt &optional action) - "Ask user a \"y or n\" or a \"yes or no\" question using PROMPT. -Which kind of question is used depends on whether -ACTION is a member of option `magit-slow-confirm'." - (if (or (eq magit-slow-confirm t) - (and action (member action magit-slow-confirm))) - (yes-or-no-p prompt) - (y-or-n-p prompt))) - -(defvar magit--no-confirm-alist - '((safe-with-wip magit-wip-before-change-mode - discard reverse stage-all-changes unstage-all-changes))) - -(cl-defun magit-confirm (action &optional prompt prompt-n noabort - (items nil sitems)) - (declare (indent defun)) - (setq prompt-n (format (concat (or prompt-n prompt) "? ") (length items))) - (setq prompt (format (concat (or prompt (magit-confirm-make-prompt action)) - "? ") - (car items))) - (or (cond ((and (not (eq action t)) - (or (eq magit-no-confirm t) - (memq action magit-no-confirm) - (cl-member-if (pcase-lambda (`(,key ,var . ,sub)) - (and (memq key magit-no-confirm) - (memq action sub) - (or (not var) - (and (boundp var) - (symbol-value var))))) - magit--no-confirm-alist))) - (or (not sitems) items)) - ((not sitems) - (magit-y-or-n-p prompt action)) - ((= (length items) 1) - (and (magit-y-or-n-p prompt action) items)) - ((> (length items) 1) - (and (magit-y-or-n-p (concat (mapconcat #'identity items "\n") - "\n\n" prompt-n) - action) - items))) - (if noabort nil (user-error "Abort")))) - -(defun magit-confirm-files (action files &optional prompt) - (when files - (unless prompt - (setq prompt (magit-confirm-make-prompt action))) - (magit-confirm action - (concat prompt " %s") - (concat prompt " %i files") - nil files))) - -(defun magit-confirm-make-prompt (action) - (let ((prompt (symbol-name action))) - (replace-regexp-in-string - "-" " " (concat (upcase (substring prompt 0 1)) (substring prompt 1))))) - -(defun magit-read-number-string (prompt &optional default _history) - "Like `read-number' but return value is a string. -DEFAULT may be a number or a numeric string." - (number-to-string - (read-number prompt (if (stringp default) - (string-to-number default) - default)))) - -;;; Debug Utilities - -;;;###autoload -(defun magit-emacs-Q-command () - "Show a shell command that runs an uncustomized Emacs with only Magit loaded. -See info node `(magit)Debugging Tools' for more information." - (interactive) - (let ((cmd (mapconcat - #'shell-quote-argument - `(,(concat invocation-directory invocation-name) - "-Q" "--eval" "(setq debug-on-error t)" - ,@(cl-mapcan - (lambda (dir) (list "-L" dir)) - (delete-dups - (cl-mapcan - (lambda (lib) - (let ((path (locate-library lib))) - (cond - (path - (list (file-name-directory path))) - ((not (equal lib "libgit")) - (error "Cannot find mandatory dependency %s" lib))))) - '(;; Like `LOAD_PATH' in `default.mk'. - "dash" - "libgit" - "transient" - "with-editor" - ;; Obviously `magit' itself is needed too. - "magit" - ;; While these are part of the Magit repository, - ;; they are distributed as separate packages. - "magit-section" - "git-commit" - )))) - ;; Avoid Emacs bug#16406 by using full path. - "-l" ,(file-name-sans-extension (locate-library "magit"))) - " "))) - (message "Uncustomized Magit command saved to kill-ring, %s" - "please run it in a terminal.") - (kill-new cmd))) - -;;; Text Utilities - -(defmacro magit-bind-match-strings (varlist string &rest body) - "Bind variables to submatches according to VARLIST then evaluate BODY. -Bind the symbols in VARLIST to submatches of the current match -data, starting with 1 and incrementing by 1 for each symbol. If -the last match was against a string, then that has to be provided -as STRING." - (declare (indent 2) (debug (listp form body))) - (let ((s (cl-gensym "string")) - (i 0)) - `(let ((,s ,string)) - (let ,(save-match-data - (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 () - "Delete the rest of the current line." - (delete-region (point) (1+ (line-end-position)))) - -(defun magit-delete-match (&optional num) - "Delete text matched by last search. -If optional NUM is specified, only delete that subexpression." - (delete-region (match-beginning (or num 0)) - (match-end (or num 0)))) - -(defun magit-file-line (file) - "Return the first line of FILE as a string." - (when (file-regular-p file) - (with-temp-buffer - (insert-file-contents file) - (buffer-substring-no-properties (point-min) - (line-end-position))))) - -(defun magit-file-lines (file &optional keep-empty-lines) - "Return a list of strings containing one element per line in FILE. -Unless optional argument KEEP-EMPTY-LINES is t, trim all empty lines." - (when (file-regular-p file) - (with-temp-buffer - (insert-file-contents file) - (split-string (buffer-string) "\n" (not keep-empty-lines))))) - -(defun magit-set-header-line-format (string) - "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 side of STRING so that it aligns -with the text area." - (setq 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." - (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'." - (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)) - -(defun magit--put-face (beg end face string) - (put-text-property beg end 'face face string) - (put-text-property beg end 'font-lock-face face string)) - -(defun magit--format-spec (format specification) - "Like `format-spec' but preserve text properties in SPECIFICATION." - (with-temp-buffer - (insert format) - (goto-char (point-min)) - (while (search-forward "%" nil t) - (cond - ;; Quoted percent sign. - ((eq (char-after) ?%) - (delete-char 1)) - ;; Valid format spec. - ((looking-at "\\([-0-9.]*\\)\\([a-zA-Z]\\)") - (let* ((num (match-string 1)) - (spec (string-to-char (match-string 2))) - (val (assq spec specification))) - (unless val - (error "Invalid format character: `%%%c'" spec)) - (setq val (cdr val)) - ;; Pad result to desired length. - (let ((text (format (concat "%" num "s") val))) - ;; Insert first, to preserve text properties. - (if (next-property-change 0 (concat " " text)) - ;; If the inserted text has properties, then preserve those. - (insert text) - ;; Otherwise preserve FORMAT's properties, like `format-spec'. - (insert-and-inherit text)) - ;; Delete the specifier body. - (delete-region (+ (match-beginning 0) (length text)) - (+ (match-end 0) (length text))) - ;; Delete the percent sign. - (delete-region (1- (match-beginning 0)) (match-beginning 0))))) - ;; Signal an error on bogus format strings. - (t - (error "Invalid format string")))) - (buffer-string))) - -;;; Missing from Emacs - -(defun magit-kill-this-buffer () - "Kill the current buffer." - (interactive) - (kill-buffer (current-buffer))) - -(defun magit--buffer-string (&optional min max trim) - "Like `buffer-substring-no-properties' but the arguments are optional. - -This combines the benefits of `buffer-string', `buffer-substring' -and `buffer-substring-no-properties' into one function that is -not as painful to use as the latter. I.e. you can write - (magit--buffer-string) -instead of - (buffer-substring-no-properties (point-min) - (point-max)) - -Optional MIN defaults to the value of `point-min'. -Optional MAX defaults to the value of `point-max'. - -If optional TRIM is non-nil, then all leading and trailing -whitespace is remove. If it is the newline character, then -one trailing newline is added." - ;; Lets write that one last time and be done with it: - (let ((str (buffer-substring-no-properties (or min (point-min)) - (or max (point-max))))) - (if trim - (concat (string-trim str) - (and (eq trim ?\n) "\n")) - str))) - -;;; Kludges for Emacs Bugs - -(defun magit-file-accessible-directory-p (filename) - "Like `file-accessible-directory-p' but work around an Apple bug. -See http://debbugs.gnu.org/cgi/bugreport.cgi?bug=21573#17 -and https://github.com/magit/magit/issues/2295." - (and (file-directory-p filename) - (file-accessible-directory-p filename))) - -(when (version<= "25.1" emacs-version) - (with-eval-after-load 'vc-git - (defun vc-git-conflicted-files (directory) - "Return the list of files with conflicts in DIRECTORY." - (let* ((status - (vc-git--run-command-string directory "diff-files" - "--name-status")) - (lines (when status (split-string status "\n" 'omit-nulls))) - files) - (dolist (line lines files) - (when (string-match "\\([ MADRCU?!]\\)[ \t]+\\(.+\\)" line) - (let ((state (match-string 1 line)) - (file (match-string 2 line))) - (when (equal state "U") - (push (expand-file-name file directory) files))))))))) - -(when (< emacs-major-version 27) - (defun vc-git--call@bug21559 (fn buffer command &rest args) - "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559." - (let ((process-environment process-environment)) - (when revert-buffer-in-progress-p - (push "GIT_OPTIONAL_LOCKS=0" process-environment)) - (apply fn buffer command args))) - (advice-add 'vc-git--call :around 'vc-git--call@bug21559) - - (defun vc-git-command@bug21559 - (fn buffer okstatus file-or-list &rest flags) - "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559." - (let ((process-environment process-environment)) - (when revert-buffer-in-progress-p - (push "GIT_OPTIONAL_LOCKS=0" process-environment)) - (apply fn buffer okstatus file-or-list flags))) - (advice-add 'vc-git-command :around 'vc-git-command@bug21559) - - (defun auto-revert-handler@bug21559 (fn) - "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559." - (let ((revert-buffer-in-progress-p t)) - (funcall fn))) - (advice-add 'auto-revert-handler :around 'auto-revert-handler@bug21559) - ) - -(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. - -This is a simple wrapper around `which-function', that resets -Imenu's potentially outdated and therefore unreliable cache by -setting `imenu--index-alist' to nil before calling that function." - (setq imenu--index-alist nil) - (which-function)) - -;;; Kludges for Custom - -(defun magit-custom-initialize-reset (symbol exp) - "Initialize SYMBOL based on EXP. -Set the symbol, using `set-default' (unlike -`custom-initialize-reset' which uses the `:set' function if any.) -The value is either the symbol's current value - (as obtained using the `:get' function), if any, -or the value in the symbol's `saved-value' property if any, -or (last of all) the value of EXP." - (set-default-toplevel-value - symbol - (condition-case nil - (let ((def (default-toplevel-value symbol)) - (getter (get symbol 'custom-get))) - (if getter (funcall getter symbol) def)) - (error - (eval (let ((sv (get symbol 'saved-value))) - (if sv (car sv) exp))))))) - -(defun magit-hook-custom-get (symbol) - (if (symbol-file symbol 'defvar) - (default-toplevel-value symbol) - ;; - ;; Called by `custom-initialize-reset' on behalf of `symbol's - ;; `defcustom', which is being evaluated for the first time to - ;; set the initial value, but there's already a default value, - ;; which most likely was established by one or more `add-hook' - ;; calls. - ;; - ;; We combine the `standard-value' and the current value, while - ;; preserving the order established by `:options', and return - ;; the result of that to be used as the "initial" default value. - ;; - (let ((standard (eval (car (get symbol 'standard-value)))) - (current (default-toplevel-value symbol)) - (value nil)) - (dolist (fn (get symbol 'custom-options)) - (when (or (memq fn standard) - (memq fn current)) - (push fn value))) - (dolist (fn current) - (unless (memq fn value) - (push fn value))) - (nreverse value)))) - -;;; Kludges for Info Manuals - -;;;###autoload -(defun Info-follow-nearest-node--magit-gitman (fn &optional fork) - (let ((node (Info-get-token - (point) "\\*note[ \n\t]+" - "\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?"))) - (if (and node (string-match "^(gitman)\\(.+\\)" node)) - (pcase magit-view-git-manual-method - (`info (funcall fn fork)) - (`man (require 'man) - (man (match-string 1 node))) - (`woman (require 'woman) - (woman (match-string 1 node))) - (_ - (user-error "Invalid value for `magit-view-git-manual-method'"))) - (funcall fn fork)))) - -;;;###autoload -(advice-add 'Info-follow-nearest-node :around - 'Info-follow-nearest-node--magit-gitman) - -;;;###autoload -(defun org-man-export--magit-gitman (fn link description format) - (if (and (eq format 'texinfo) - (string-match-p "\\`git" link)) - (replace-regexp-in-string "%s" link " -@ifinfo -@ref{%s,,,gitman,}. -@end ifinfo -@ifhtml -@html -the %s(1) manpage. -@end html -@end ifhtml -@iftex -the %s(1) manpage. -@end iftex -") - (funcall fn link description format))) - -;;;###autoload -(advice-add 'org-man-export :around - 'org-man-export--magit-gitman) - -;;; Kludges for Package Managers - -(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 - -(defun magit-message (format-string &rest args) - "Display a message at the bottom of the screen, or not. -Like `message', except that if the users configured option -`magit-no-message' to prevent the message corresponding to -FORMAT-STRING to be displayed, then don't." - (unless (--first (string-prefix-p it format-string) magit-no-message) - (apply #'message format-string args))) - -(defun magit-msg (format-string &rest args) - "Display a message at the bottom of the screen, but don't log it. -Like `message', except that `message-log-max' is bound to nil." - (let ((message-log-max nil)) - (apply #'message format-string args))) - -(defmacro magit--with-temp-position (buf pos &rest body) - (declare (indent 2)) - `(with-current-buffer ,buf - (save-excursion - (save-restriction - (widen) - (goto-char (or ,pos 1)) - ,@body)))) - -;;; _ -(provide 'magit-utils) -;;; magit-utils.el ends here diff --git a/elpa/magit-20210802.1524/magit-wip.el b/elpa/magit-20210802.1524/magit-wip.el deleted file mode 100644 index 2820cab8..00000000 --- a/elpa/magit-20210802.1524/magit-wip.el +++ /dev/null @@ -1,456 +0,0 @@ -;;; magit-wip.el --- commit snapshots to work-in-progress refs -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library defines tree global modes which automatically commit -;; snapshots to branch-specific work-in-progress refs before and after -;; making changes, and two commands which can be used to do so on -;; demand. - -;;; Code: - -(require 'magit-core) -(require 'magit-log) - -;;; Options - -(defgroup magit-wip nil - "Automatically commit to work-in-progress refs." - :link '(info-link "(magit)Wip Modes") - :group 'magit-modes - :group 'magit-essentials) - -(defgroup magit-wip-legacy nil - "It is better to not use these modes individually." - :link '(info-link "(magit)Legacy Wip Modes") - :group 'magit-wip) - -(defcustom magit-wip-mode-lighter " Wip" - "Lighter for Magit-Wip mode." - :package-version '(magit . "2.90.0") - :group 'magit-wip - :type 'string) - -(defcustom magit-wip-after-save-local-mode-lighter "" - "Lighter for Magit-Wip-After-Save-Local mode." - :package-version '(magit . "2.1.0") - :group 'magit-wip-legacy - :type 'string) - -(defcustom magit-wip-after-apply-mode-lighter "" - "Lighter for Magit-Wip-After-Apply mode." - :package-version '(magit . "2.1.0") - :group 'magit-wip-legacy - :type 'string) - -(defcustom magit-wip-before-change-mode-lighter "" - "Lighter for Magit-Wip-Before-Change mode." - :package-version '(magit . "2.1.0") - :group 'magit-wip-legacy - :type 'string) - -(defcustom magit-wip-initial-backup-mode-lighter "" - "Lighter for Magit-Wip-Initial Backup mode." - :package-version '(magit . "2.1.0") - :group 'magit-wip-legacy - :type 'string) - -(defcustom magit-wip-merge-branch nil - "Whether to merge the current branch into its wip ref. - -If non-nil and the current branch has new commits, then it is -merged into the wip ref before creating a new wip commit. This -makes it easier to inspect wip history and the wip commits are -never garbage collected. - -If nil and the current branch has new commits, then the wip ref -is reset to the tip of the branch before creating a new wip -commit. With this setting wip commits are eventually garbage -collected. This is currently the default." - :package-version '(magit . "2.90.0") - :group 'magit-wip - :type 'boolean) - -(defcustom magit-wip-namespace "refs/wip/" - "Namespace used for work-in-progress refs. -The wip refs are named \"index/\" -and \"wtree/\". When snapshots -are created while the `HEAD' is detached then \"HEAD\" -is used as `branch-ref'." - :package-version '(magit . "2.1.0") - :group 'magit-wip - :type 'string) - -;;; Modes - -;;;###autoload -(define-minor-mode magit-wip-mode - "Save uncommitted changes to work-in-progress refs. - -Whenever appropriate (i.e. when dataloss would be a possibility -otherwise) this mode causes uncommitted changes to be committed -to dedicated work-in-progress refs. - -For historic reasons this mode is implemented on top of four -other `magit-wip-*' modes, which can also be used individually, -if you want finer control over when the wip refs are updated; -but that is discouraged." - :package-version '(magit . "2.90.0") - :lighter magit-wip-mode-lighter - :global t - (let ((arg (if magit-wip-mode 1 -1))) - (magit-wip-after-save-mode arg) - (magit-wip-after-apply-mode arg) - (magit-wip-before-change-mode arg) - (magit-wip-initial-backup-mode arg))) - -(define-minor-mode magit-wip-after-save-local-mode - "After saving, also commit to a worktree work-in-progress ref. - -After saving the current file-visiting buffer this mode also -commits the changes to the worktree work-in-progress ref for -the current branch. - -This mode should be enabled globally by turning on the globalized -variant `magit-wip-after-save-mode'." - :package-version '(magit . "2.1.0") - :lighter magit-wip-after-save-local-mode-lighter - (if magit-wip-after-save-local-mode - (if (and buffer-file-name (magit-inside-worktree-p t)) - (add-hook 'after-save-hook 'magit-wip-commit-buffer-file t t) - (setq magit-wip-after-save-local-mode nil) - (user-error "Need a worktree and a file")) - (remove-hook 'after-save-hook 'magit-wip-commit-buffer-file t))) - -(defun magit-wip-after-save-local-mode-turn-on () - (and buffer-file-name - (magit-inside-worktree-p t) - (magit-file-tracked-p buffer-file-name) - (magit-wip-after-save-local-mode))) - -;;;###autoload -(define-globalized-minor-mode magit-wip-after-save-mode - magit-wip-after-save-local-mode magit-wip-after-save-local-mode-turn-on - :package-version '(magit . "2.1.0") - :group 'magit-wip) - -(defun magit-wip-commit-buffer-file (&optional msg) - "Commit visited file to a worktree work-in-progress ref. - -Also see `magit-wip-after-save-mode' which calls this function -automatically whenever a buffer visiting a tracked file is saved." - (interactive) - (--when-let (magit-wip-get-ref) - (magit-with-toplevel - (let ((file (file-relative-name buffer-file-name))) - (magit-wip-commit-worktree - it (list file) - (format (cond (msg) - ((called-interactively-p 'any) - "wip-save %s after save") - (t - "autosave %s after save")) - file)))))) - -;;;###autoload -(define-minor-mode magit-wip-after-apply-mode - "Commit to work-in-progress refs. - -After applying a change using any \"apply variant\" -command (apply, stage, unstage, discard, and reverse) commit the -affected files to the current wip refs. For each branch there -may be two wip refs; one contains snapshots of the files as found -in the worktree and the other contains snapshots of the entries -in the index." - :package-version '(magit . "2.1.0") - :group 'magit-wip - :lighter magit-wip-after-apply-mode-lighter - :global t) - -(defun magit-wip-commit-after-apply (&optional files msg) - (when magit-wip-after-apply-mode - (magit-wip-commit files msg))) - -;;;###autoload -(define-minor-mode magit-wip-before-change-mode - "Commit to work-in-progress refs before certain destructive changes. - -Before invoking a revert command or an \"apply variant\" -command (apply, stage, unstage, discard, and reverse) commit the -affected tracked files to the current wip refs. For each branch -there may be two wip refs; one contains snapshots of the files -as found in the worktree and the other contains snapshots of the -entries in the index. - -Only changes to files which could potentially be affected by the -command which is about to be called are committed." - :package-version '(magit . "2.1.0") - :group 'magit-wip - :lighter magit-wip-before-change-mode-lighter - :global t) - -(defun magit-wip-commit-before-change (&optional files msg) - (when magit-wip-before-change-mode - (magit-with-toplevel - (magit-wip-commit files msg)))) - -(define-minor-mode magit-wip-initial-backup-mode - "Before saving a buffer for the first time, commit to a wip ref." - :package-version '(magit . "2.90.0") - :group 'magit-wip - :lighter magit-wip-initial-backup-mode-lighter - :global t - (if magit-wip-initial-backup-mode - (add-hook 'before-save-hook 'magit-wip-commit-initial-backup) - (remove-hook 'before-save-hook 'magit-wip-commit-initial-backup))) - -(defun magit--any-wip-mode-enabled-p () - "Return non-nil if any global wip mode is enabled." - (or magit-wip-mode - magit-wip-after-save-mode - magit-wip-after-apply-mode - magit-wip-before-change-mode - magit-wip-initial-backup-mode)) - -(defvar-local magit-wip-buffer-backed-up nil) -(put 'magit-wip-buffer-backed-up 'permanent-local t) - -;;;###autoload -(defun magit-wip-commit-initial-backup () - "Before saving, commit current file to a worktree wip ref. - -The user has to add this function to `before-save-hook'. - -Commit the current state of the visited file before saving the -current buffer to that file. This backs up the same version of -the file as `backup-buffer' would, but stores the backup in the -worktree wip ref, which is also used by the various Magit Wip -modes, instead of in a backup file as `backup-buffer' would. - -This function ignores the variables that affect `backup-buffer' -and can be used along-side that function, which is recommended -because this function only backs up files that are tracked in -a Git repository." - (when (and (not magit-wip-buffer-backed-up) - buffer-file-name - (magit-inside-worktree-p t) - (magit-file-tracked-p buffer-file-name)) - (let ((magit-save-repository-buffers nil)) - (magit-wip-commit-buffer-file "autosave %s before save")) - (setq magit-wip-buffer-backed-up t))) - -;;; Core - -(defun magit-wip-commit (&optional files msg) - "Commit all tracked files to the work-in-progress refs. - -Interactively, commit all changes to all tracked files using -a generic commit message. With a prefix-argument the commit -message is read in the minibuffer. - -Non-interactively, only commit changes to FILES using MSG as -commit message." - (interactive (list nil (if current-prefix-arg - (magit-read-string "Wip commit message") - "wip-save tracked files"))) - (--when-let (magit-wip-get-ref) - (magit-wip-commit-index it files msg) - (magit-wip-commit-worktree it files msg))) - -(defun magit-wip-commit-index (ref files msg) - (let* ((wipref (magit--wip-index-ref ref)) - (parent (magit-wip-get-parent ref wipref)) - (tree (magit-git-string "write-tree"))) - (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"))) - -(defun magit-wip-update-wipref (ref wipref tree parent files msg start-msg) - (cond - ((and (not (equal parent wipref)) - (or (not magit-wip-merge-branch) - (not (magit-rev-verify wipref)))) - (setq start-msg (concat "start autosaving " start-msg)) - (magit-update-ref wipref start-msg - (magit-git-string "commit-tree" "--no-gpg-sign" - "-p" parent "-m" start-msg - (concat parent "^{tree}"))) - (setq parent wipref)) - ((and magit-wip-merge-branch - (or (not (magit-rev-ancestor-p ref wipref)) - (not (magit-rev-ancestor-p - (concat (magit-git-string "log" "--format=%H" - "-1" "--merges" wipref) - "^2") - ref)))) - (setq start-msg (format "merge %s into %s" ref start-msg)) - (magit-update-ref wipref start-msg - (magit-git-string "commit-tree" "--no-gpg-sign" - "-p" wipref "-p" ref - "-m" start-msg - (concat ref "^{tree}"))) - (setq parent wipref))) - (when (magit-git-failure "diff-tree" "--quiet" parent tree "--" files) - (unless (and msg (not (= (aref msg 0) ?\s))) - (let ((len (length files))) - (setq msg (concat - (cond ((= len 0) "autosave tracked files") - ((> len 1) (format "autosave %s files" len)) - (t (concat "autosave " - (file-relative-name (car files) - (magit-toplevel))))) - msg)))) - (magit-update-ref wipref msg - (magit-git-string "commit-tree" "--no-gpg-sign" - "-p" parent "-m" msg tree)))) - -(defun magit-wip-get-ref () - (let ((ref (or (magit-git-string "symbolic-ref" "HEAD") "HEAD"))) - (and (magit-rev-verify ref) - ref))) - -(defun magit-wip-get-parent (ref wipref) - (if (and (magit-rev-verify wipref) - (equal (magit-git-string "merge-base" wipref ref) - (magit-rev-verify ref))) - wipref - ref)) - -(defun magit--wip-index-ref (&optional ref) - (magit--wip-ref "index/" ref)) - -(defun magit--wip-wtree-ref (&optional ref) - (magit--wip-ref "wtree/" ref)) - -(defun magit--wip-ref (namespace &optional ref) - (concat magit-wip-namespace namespace - (or (and ref (string-prefix-p "refs/" ref) ref) - (when-let ((branch (and (not (equal ref "HEAD")) - (or ref (magit-get-current-branch))))) - (concat "refs/heads/" branch)) - "HEAD"))) - -(defun magit-wip-maybe-add-commit-hook () - (when (and magit-wip-merge-branch - (magit-wip-any-enabled-p)) - (add-hook 'git-commit-post-finish-hook 'magit-wip-commit nil t))) - -(defun magit-wip-any-enabled-p () - (or magit-wip-mode - magit-wip-after-save-local-mode - magit-wip-after-save-mode - magit-wip-after-apply-mode - magit-wip-before-change-mode - magit-wip-initial-backup-mode)) - -;;; Log - -(defun magit-wip-log-index (args files) - "Show log for the index wip ref of the current branch." - (interactive (magit-log-arguments)) - (magit-log-setup-buffer (list (magit--wip-index-ref)) args files)) - -(defun magit-wip-log-worktree (args files) - "Show log for the worktree wip ref of the current branch." - (interactive (magit-log-arguments)) - (magit-log-setup-buffer (list (magit--wip-wtree-ref)) args files)) - -(defun magit-wip-log-current (branch args files count) - "Show log for the current branch and its wip refs. -With a negative prefix argument only show the worktree wip ref. -The absolute numeric value of the prefix argument controls how -many \"branches\" of each wip ref are shown." - (interactive - (nconc (list (or (magit-get-current-branch) "HEAD")) - (magit-log-arguments) - (list (prefix-numeric-value current-prefix-arg)))) - (magit-wip-log branch args files count)) - -(defun magit-wip-log (branch args files count) - "Show log for a branch and its wip refs. -With a negative prefix argument only show the worktree wip ref. -The absolute numeric value of the prefix argument controls how -many \"branches\" of each wip ref are shown." - (interactive - (nconc (list (magit-completing-read - "Log branch and its wip refs" - (-snoc (magit-list-local-branch-names) "HEAD") - nil t nil 'magit-revision-history - (or (magit-branch-at-point) - (magit-get-current-branch) - "HEAD"))) - (magit-log-arguments) - (list (prefix-numeric-value current-prefix-arg)))) - (magit-log-setup-buffer (nconc (list branch) - (magit-wip-log-get-tips - (magit--wip-wtree-ref branch) - (abs count)) - (and (>= count 0) - (magit-wip-log-get-tips - (magit--wip-index-ref branch) - (abs count)))) - args files)) - -(defun magit-wip-log-get-tips (wipref count) - (when-let ((reflog (magit-git-lines "reflog" wipref))) - (let (tips) - (while (and reflog (> count 1)) - (setq reflog (cl-member "^[^ ]+ [^:]+: restart autosaving" - reflog :test #'string-match-p)) - (when (and (cadr reflog) - (string-match "^[^ ]+ \\([^:]+\\)" (cadr reflog))) - (push (match-string 1 (cadr reflog)) tips)) - (setq reflog (cddr reflog)) - (cl-decf count)) - (cons wipref (nreverse tips))))) - -;;; _ -(provide 'magit-wip) -;;; magit-wip.el ends here diff --git a/elpa/magit-20210802.1524/magit-worktree.el b/elpa/magit-20210802.1524/magit-worktree.el deleted file mode 100644 index 47f71b6f..00000000 --- a/elpa/magit-20210802.1524/magit-worktree.el +++ /dev/null @@ -1,189 +0,0 @@ -;;; magit-worktree.el --- worktree support -*- lexical-binding: t -*- - -;; 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. - -;; 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. - -;;; Commentary: - -;; This library implements support for `git-worktree'. - -;;; Code: - -(require 'magit) - -;;; Options - -(defcustom magit-worktree-read-directory-name-function 'read-directory-name - "Function used to read a directory for worktree commands. -This is called with one argument, the prompt, and can be used -to e.g. use a base directory other than `default-directory'. -Used by `magit-worktree-checkout' and `magit-worktree-branch'." - :package-version '(magit . "3.0.0") - :group 'magit-commands - :type 'function) - -;;; Commands - -;;;###autoload (autoload 'magit-worktree "magit-worktree" nil t) -(transient-define-prefix magit-worktree () - "Act on a worktree." - :man-page "git-worktree" - [["Create new" - ("b" "worktree" magit-worktree-checkout) - ("c" "branch and worktree" magit-worktree-branch)] - ["Commands" - ("m" "Move worktree" magit-worktree-move) - ("k" "Delete worktree" magit-worktree-delete) - ("g" "Visit worktree" magit-worktree-status)]]) - -;;;###autoload -(defun magit-worktree-checkout (path branch) - "Checkout BRANCH in a new worktree at PATH." - (interactive - (let ((branch (magit-read-branch-or-commit "Checkout"))) - (list (funcall magit-worktree-read-directory-name-function - (format "Checkout %s in new worktree: " branch)) - branch))) - (magit-run-git "worktree" "add" (expand-file-name path) branch) - (magit-diff-visit-directory path)) - -;;;###autoload -(defun magit-worktree-branch (path branch start-point &optional force) - "Create a new BRANCH and check it out in a new worktree at PATH." - (interactive - `(,(funcall magit-worktree-read-directory-name-function - "Create worktree: ") - ,@(magit-branch-read-args "Create and checkout branch") - ,current-prefix-arg)) - (magit-run-git "worktree" "add" (if force "-B" "-b") - branch (expand-file-name path) start-point) - (magit-diff-visit-directory path)) - -;;;###autoload -(defun magit-worktree-move (worktree path) - "Move WORKTREE to PATH." - (interactive - (list (magit-completing-read "Move worktree" - (cdr (magit-list-worktrees)) - nil t nil nil - (magit-section-value-if 'worktree)) - (funcall magit-worktree-read-directory-name-function - "Move worktree to: "))) - (if (file-directory-p (expand-file-name ".git" worktree)) - (user-error "You may not move the main working tree") - (let ((preexisting-directory (file-directory-p path))) - (when (and (zerop (magit-call-git "worktree" "move" worktree - (expand-file-name path))) - (not (file-exists-p default-directory)) - (derived-mode-p 'magit-status-mode)) - (kill-buffer) - (magit-diff-visit-directory - (if preexisting-directory - (concat (file-name-as-directory path) - (file-name-nondirectory worktree)) - path))) - (magit-refresh)))) - -(defun magit-worktree-delete (worktree) - "Delete a worktree, defaulting to the worktree at point. -The primary worktree cannot be deleted." - (interactive - (list (magit-completing-read "Delete worktree" - (cdr (magit-list-worktrees)) - nil t nil nil - (magit-section-value-if 'worktree)))) - (if (file-directory-p (expand-file-name ".git" worktree)) - (user-error "Deleting %s would delete the shared .git directory" worktree) - (let ((primary (file-name-as-directory (caar (magit-list-worktrees))))) - (magit-confirm-files (if magit-delete-by-moving-to-trash 'trash 'delete) - (list "worktree")) - (when (file-exists-p worktree) - (let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash)) - (delete-directory worktree t magit-delete-by-moving-to-trash))) - (if (file-exists-p default-directory) - (magit-run-git "worktree" "prune") - (let ((default-directory primary)) - (magit-run-git "worktree" "prune")) - (when (derived-mode-p 'magit-status-mode) - (kill-buffer) - (magit-status-setup-buffer primary)))))) - -(defun magit-worktree-status (worktree) - "Show the status for the worktree at point. -If there is no worktree at point, then read one in the -minibuffer. If the worktree at point is the one whose -status is already being displayed in the current buffer, -then show it in Dired instead." - (interactive - (list (or (magit-section-value-if 'worktree) - (magit-completing-read - "Show status for worktree" - (cl-delete (directory-file-name (magit-toplevel)) - (magit-list-worktrees) - :test #'equal :key #'car))))) - (magit-diff-visit-directory worktree)) - -;;; Sections - -(defvar magit-worktree-section-map - (let ((map (make-sparse-keymap))) - (define-key map [remap magit-visit-thing] 'magit-worktree-status) - (define-key map [remap magit-delete-thing] 'magit-worktree-delete) - map) - "Keymap for `worktree' sections.") - -(defun magit-insert-worktrees () - "Insert sections for all worktrees. -If there is only one worktree, then insert nothing." - (let ((worktrees (magit-list-worktrees))) - (when (> (length worktrees) 1) - (magit-insert-section (worktrees) - (magit-insert-heading "Worktrees:") - (let* ((cols - (mapcar - (pcase-lambda (`(,path ,barep ,commit ,branch)) - (cons (cond - (branch (propertize - 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)")) - path)) - worktrees)) - (align (1+ (-max (--map (string-width (car it)) cols))))) - (pcase-dolist (`(,head . ,path) cols) - (magit-insert-section (worktree path) - (insert head) - (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))) - (insert ?\n)))) - (insert ?\n))))) - -;;; _ -(provide 'magit-worktree) -;;; magit-worktree.el ends here diff --git a/elpa/magit-20210802.1524/magit.el b/elpa/magit-20210802.1524/magit.el deleted file mode 100644 index c58e490f..00000000 --- a/elpa/magit-20210802.1524/magit.el +++ /dev/null @@ -1,684 +0,0 @@ -;;; magit.el --- A Git porcelain inside Emacs -*- lexical-binding: t; coding: utf-8 -*- - -;; 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 -;; Former-Maintainers: -;; Nicolas Dudebout -;; Peter J. Weisberg -;; Phil Jackson -;; Rémi Vanicat -;; Yann Hodique - -;; Keywords: git tools vc -;; Homepage: https://github.com/magit/magit -;; 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. - -;; Magit requires at least GNU Emacs 25.1 and Git 2.2.0. - -;;; Commentary: - -;; 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 '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") - -;;; Faces - -(defface magit-header-line - '((t :inherit magit-section-heading)) - "Face for the `header-line' in some Magit modes. -Note that some modes, such as `magit-log-select-mode', have their -own faces for the `header-line', or for parts of the -`header-line'." - :group 'magit-faces) - -(defface magit-header-line-key - '((t :inherit font-lock-builtin-face)) - "Face for keys in the `header-line'." - :group 'magit-faces) - -(defface magit-dimmed - '((((class color) (background light)) :foreground "grey50") - (((class color) (background dark)) :foreground "grey50")) - "Face for text that shouldn't stand out." - :group 'magit-faces) - -(defface magit-hash - '((((class color) (background light)) :foreground "grey60") - (((class color) (background dark)) :foreground "grey40")) - "Face for the sha1 part of the log output." - :group 'magit-faces) - -(defface magit-tag - '((((class color) (background light)) :foreground "Goldenrod4") - (((class color) (background dark)) :foreground "LightGoldenrod2")) - "Face for tag labels shown in log buffer." - :group 'magit-faces) - -(defface magit-branch-remote - '((((class color) (background light)) :foreground "DarkOliveGreen4") - (((class color) (background dark)) :foreground "DarkSeaGreen2")) - "Face for remote branch head labels shown in log buffer." - :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)) - "Face for current branch." - :group 'magit-faces) - -(defface magit-branch-local - '((((class color) (background light)) :foreground "SkyBlue4") - (((class color) (background dark)) :foreground "LightSkyBlue1")) - "Face for local branches." - :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)) - "Face for current branch." - :group 'magit-faces) - -(defface magit-branch-upstream - '((t :slant italic)) - "Face for upstream branch. -This face is only used in logs and it gets combined - with `magit-branch-local', `magit-branch-remote' -and/or `magit-branch-remote-head'." - :group 'magit-faces) - -(defface magit-head - '((((class color) (background light)) :inherit magit-branch-local) - (((class color) (background dark)) :inherit magit-branch-local)) - "Face for the symbolic ref `HEAD'." - :group 'magit-faces) - -(defface magit-refname - '((((class color) (background light)) :foreground "grey30") - (((class color) (background dark)) :foreground "grey80")) - "Face for refnames without a dedicated face." - :group 'magit-faces) - -(defface magit-refname-stash - '((t :inherit magit-refname)) - "Face for stash refnames." - :group 'magit-faces) - -(defface magit-refname-wip - '((t :inherit magit-refname)) - "Face for wip refnames." - :group 'magit-faces) - -(defface magit-refname-pullreq - '((t :inherit magit-refname)) - "Face for pullreq refnames." - :group 'magit-faces) - -(defface magit-keyword - '((t :inherit font-lock-string-face)) - "Face for parts of commit messages inside brackets." - :group 'magit-faces) - -(defface magit-keyword-squash - '((t :inherit font-lock-warning-face)) - "Face for squash! and fixup! keywords in commit messages." - :group 'magit-faces) - -(defface magit-signature-good - '((t :foreground "green")) - "Face for good signatures." - :group 'magit-faces) - -(defface magit-signature-bad - '((t :foreground "red" :weight bold)) - "Face for bad signatures." - :group 'magit-faces) - -(defface magit-signature-untrusted - '((t :foreground "medium aquamarine")) - "Face for good untrusted signatures." - :group 'magit-faces) - -(defface magit-signature-expired - '((t :foreground "orange")) - "Face for signatures that have expired." - :group 'magit-faces) - -(defface magit-signature-expired-key - '((t :inherit magit-signature-expired)) - "Face for signatures made by an expired key." - :group 'magit-faces) - -(defface magit-signature-revoked - '((t :foreground "violet red")) - "Face for signatures made by a revoked key." - :group 'magit-faces) - -(defface magit-signature-error - '((t :foreground "light blue")) - "Face for signatures that cannot be checked (e.g. missing key)." - :group 'magit-faces) - -(defface magit-cherry-unmatched - '((t :foreground "cyan")) - "Face for unmatched cherry commits." - :group 'magit-faces) - -(defface magit-cherry-equivalent - '((t :foreground "magenta")) - "Face for equivalent cherry commits." - :group 'magit-faces) - -(defface magit-filename - '((t :weight normal)) - "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) -(transient-define-prefix magit-dispatch () - "Invoke a Magit command from a list of available commands." - :info-manual "(magit)Top" - ["Transient and dwim commands" - [("A" "Apply" magit-cherry-pick) - ("b" "Branch" magit-branch) - ("B" "Bisect" magit-bisect) - ("c" "Commit" magit-commit) - ("C" "Clone" magit-clone) - ("d" "Diff" magit-diff) - ("D" "Diff (change)" magit-diff-refresh) - ("e" "Ediff (dwim)" magit-ediff-dwim) - ("E" "Ediff" magit-ediff)] - [("f" "Fetch" magit-fetch) - ("F" "Pull" magit-pull) - ("I" "Init" magit-init) - ("l" "Log" magit-log) - ("L" "Log (change)" magit-log-refresh) - ("m" "Merge" magit-merge) - ("M" "Remote" magit-remote) - ("o" "Submodule" magit-submodule) - ("O" "Subtree" magit-subtree)] - [("P" "Push" magit-push) - ("r" "Rebase" magit-rebase) - ("t" "Tag" magit-tag) - ("T" "Note" magit-notes) - ("V" "Revert" magit-revert) - ("w" "Apply patches" magit-am) - ("W" "Format patches" magit-patch) - ("X" "Reset" magit-reset)] - [("y" "Show Refs" magit-show-refs) - ("Y" "Cherries" magit-cherry) - ("z" "Stash" magit-stash) - ("!" "Run" magit-run) - ("%" "Worktree" magit-worktree)]] - ["Applying changes" - :if-derived magit-mode - [("a" "Apply" magit-apply) - ("v" "Reverse" magit-reverse) - ("k" "Discard" magit-discard)] - [("s" "Stage" magit-stage) - ("u" "Unstage" magit-unstage)] - [("S" "Stage all" magit-stage-modified) - ("U" "Unstage all" magit-unstage-all)]] - ["Essential commands" - :if-derived magit-mode - ("g" " refresh current buffer" magit-refresh) - ("" " toggle section at point" magit-section-toggle) - ("" "visit thing at point" magit-visit-thing) - ("C-h m" " show all key bindings" describe-mode)]) - -;;; Git Popup - -(defcustom magit-shell-command-verbose-prompt t - "Whether to show the working directory when reading a command. -This affects `magit-git-command', `magit-git-command-topdir', -`magit-shell-command', and `magit-shell-command-topdir'." - :package-version '(magit . "2.11.0") - :group 'magit-commands - :type 'boolean) - -(defvar magit-git-command-history nil) - -;;;###autoload (autoload 'magit-run "magit" nil t) -(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) - ("p" "in working directory" magit-git-command)] - ["Run shell command" - ("s" "in repository root" magit-shell-command-topdir) - ("S" "in working directory" magit-shell-command)] - ["Launch" - ("k" "gitk" magit-run-gitk) - ("a" "gitk --all" magit-run-gitk-all) - ("b" "gitk --branches" magit-run-gitk-branches) - ("g" "git gui" magit-run-git-gui)]]) - -;;;###autoload -(defun magit-git-command (command) - "Execute COMMAND asynchronously; display output. - -Interactively, prompt for COMMAND in the minibuffer. \"git \" is -used as initial input, but can be deleted to run another command. - -With a prefix argument COMMAND is run in the top-level directory -of the current working tree, otherwise in `default-directory'." - (interactive (list (magit-read-shell-command nil "git "))) - (magit--shell-command command)) - -;;;###autoload -(defun magit-git-command-topdir (command) - "Execute COMMAND asynchronously; display output. - -Interactively, prompt for COMMAND in the minibuffer. \"git \" is -used as initial input, but can be deleted to run another command. - -COMMAND is run in the top-level directory of the current -working tree." - (interactive (list (magit-read-shell-command t "git "))) - (magit--shell-command command (magit-toplevel))) - -;;;###autoload -(defun magit-shell-command (command) - "Execute COMMAND asynchronously; display output. - -Interactively, prompt for COMMAND in the minibuffer. With a -prefix argument COMMAND is run in the top-level directory of -the current working tree, otherwise in `default-directory'." - (interactive (list (magit-read-shell-command))) - (magit--shell-command command)) - -;;;###autoload -(defun magit-shell-command-topdir (command) - "Execute COMMAND asynchronously; display output. - -Interactively, prompt for COMMAND in the minibuffer. COMMAND -is run in the top-level directory of the current working tree." - (interactive (list (magit-read-shell-command t))) - (magit--shell-command command (magit-toplevel))) - -(defun magit--shell-command (command &optional directory) - (let ((default-directory (or directory default-directory)) - (process-environment process-environment)) - (push "GIT_PAGER=cat" process-environment) - (magit-start-process shell-file-name nil - shell-command-switch command)) - (magit-process-buffer)) - -(defun magit-read-shell-command (&optional toplevel initial-input) - (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: " - (abbreviate-file-name default-directory)) - "Async shell command: ") - initial-input 'magit-git-command-history))) - -;;; Font-Lock Keywords - -(defconst magit-font-lock-keywords - (eval-when-compile - `((,(concat "(\\(magit-define-section-jumper\\)\\_>" - "[ \t'\(]*" - "\\(\\(?:\\sw\\|\\s_\\)+\\)?") - (1 'font-lock-keyword-face) - (2 'font-lock-function-name-face nil t)) - (,(concat "(" (regexp-opt '("magit-insert-section" - "magit-section-case" - "magit-bind-match-strings" - "magit-with-temp-index" - "magit-with-blob" - "magit-with-toplevel") t) - "\\_>") - . 1)))) - -(font-lock-add-keywords 'emacs-lisp-mode magit-font-lock-keywords) - -;;; Version - -(defvar magit-version 'undefined - "The version of Magit that you're using. -Use the function by the same name instead of this variable.") - -;;;###autoload -(defun magit-version (&optional print-dest) - "Return the version of Magit currently in use. -If optional argument PRINT-DEST is non-nil, output -stream (interactively, the echo area, or the current buffer with -a prefix argument), also print the used versions of Magit, Git, -and Emacs to it." - (interactive (list (if current-prefix-arg (current-buffer) t))) - (let ((magit-git-global-arguments nil) - (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 (magit--straight-chase-links toplib))) - (push toplib debug) - (when toplib - (let* ((topdir (file-name-directory toplib)) - (gitdir (expand-file-name - ".git" (file-name-directory - (directory-file-name topdir)))) - (static (locate-library "magit-version.el" nil (list topdir))) - (static (and static (magit--straight-chase-links static)))) - (or (progn - (push 'repo debug) - (when (and (file-exists-p gitdir) - ;; It is a repo, but is it the Magit repo? - (file-exists-p - (expand-file-name "../lisp/magit.el" gitdir))) - (push t debug) - ;; Inside the repo the version file should only exist - ;; while running make. - (when (and static (not noninteractive)) - (ignore-errors (delete-file static))) - (setq magit-version - (let ((default-directory topdir)) - (magit-git-string "describe" - "--tags" "--dirty" "--always"))))) - (progn - (push 'static debug) - (when (and static (file-exists-p static)) - (push t debug) - (load-file static) - magit-version)) - (when (featurep 'package) - (push 'elpa debug) - (ignore-errors - (--when-let (assq 'magit package-alist) - (push t debug) - (setq magit-version - (and (fboundp 'package-desc-version) - (package-version-join - (package-desc-version (cadr it)))))))) - (progn - (push 'dirname debug) - (let ((dirname (file-name-nondirectory - (directory-file-name topdir)))) - (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" - (or magit-version "(unknown)") - (or (let ((magit-git-debug - (lambda (err) - (display-warning '(magit git) - err :error)))) - (magit-git-version t)) - "(unknown)") - emacs-version - system-type) - print-dest)) - (setq debug (reverse debug)) - (setq magit-version 'error) - (when magit-version - (push magit-version debug)) - (unless (equal (getenv "CI") "true") - ;; The repository is a sparse clone. - (message "Cannot determine Magit's version %S" debug))) - magit-version)) - -;;; Debugging Tools - -(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)) - (format " [%S]" (executable-find magit-git-executable))) - (format " (%s)\n" - (let* ((errmsg nil) - (magit-git-debug (lambda (err) (setq errmsg err)))) - (or (magit-git-version t) errmsg))))) - (insert (format "exec-path: %S\n" exec-path)) - (--when-let (cl-set-difference - (-filter #'file-exists-p (remq nil (parse-colon-path - (getenv "PATH")))) - (-filter #'file-exists-p (remq nil exec-path)) - :test #'file-equal-p) - (insert (format " entries in PATH, but not in exec-path: %S\n" it))) - (dolist (execdir exec-path) - (insert (format " %s (%s)\n" execdir (car (file-attributes execdir)))) - (when (file-directory-p execdir) - (dolist (exec (directory-files - execdir t (concat - "\\`git" (regexp-opt exec-suffixes) "\\'"))) - (insert (format " %s (%s)\n" exec - (let* ((magit-git-executable exec) - (errmsg nil) - (magit-git-debug (lambda (err) (setq errmsg err)))) - (or (magit-git-version t) errmsg))))))))) - -;;; Startup Asserts - -(defun magit-startup-asserts () - (when-let ((val (getenv "GIT_DIR"))) - (setenv "GIT_DIR") - (message "Magit unset $GIT_DIR (was %S). See \ -https://github.com/magit/magit/wiki/Don't-set-$GIT_DIR-and-alike" val)) - (when-let ((val (getenv "GIT_WORK_TREE"))) - (setenv "GIT_WORK_TREE") - (message "Magit unset $GIT_WORK_TREE (was %S). See \ -https://github.com/magit/magit/wiki/Don't-set-$GIT_DIR-and-alike" val)) - (let ((version (magit-git-version))) - (when (and version - (version< version magit--minimal-git) - (not (equal (getenv "CI") "true"))) - (display-warning 'magit (format "\ -Magit requires Git >= %s, you are using %s. - -If this comes as a surprise to you, because you do actually have -a newer version installed, then that probably means that the -older version happens to appear earlier on the `$PATH'. If you -always start Emacs from a shell, then that can be fixed in the -shell's init file. If you start Emacs by clicking on an icon, -or using some sort of application launcher, then you probably -have to adjust the environment as seen by graphical interface. -For X11 something like ~/.xinitrc should work. - -If you use Tramp to work inside remote Git repositories, then you -have to make sure a suitable Git is used on the remote machines -too.\n" magit--minimal-git version) :error))) - (when (version< emacs-version magit--minimal-emacs) - (display-warning 'magit (format "\ -Magit requires Emacs >= %s, you are using %s. - -If this comes as a surprise to you, because you do actually have -a newer version installed, then that probably means that the -older version happens to appear earlier on the `$PATH'. If you -always start Emacs from a shell, then that can be fixed in the -shell's init file. If you start Emacs by clicking on an icon, -or using some sort of application launcher, then you probably -have to adjust the environment as seen by graphical interface. -For X11 something like ~/.xinitrc should work.\n" - magit--minimal-emacs emacs-version) - :error))) - -;;; Loading Libraries - -(provide 'magit) - -(cl-eval-when (load eval) - (require 'magit-status) - (require 'magit-refs) - (require 'magit-files) - (require 'magit-reset) - (require 'magit-branch) - (require 'magit-merge) - (require 'magit-tag) - (require 'magit-worktree) - (require 'magit-notes) - (require 'magit-sequence) - (require 'magit-commit) - (require 'magit-remote) - (require 'magit-clone) - (require 'magit-fetch) - (require 'magit-pull) - (require 'magit-push) - (require 'magit-bisect) - (require 'magit-stash) - (require 'magit-blame) - (require 'magit-obsolete) - (require 'magit-submodule) - (unless (load "magit-autoloads" t t) - (require 'magit-patch) - (require 'magit-subtree) - (require 'magit-ediff) - (require 'magit-gitignore) - (require 'magit-extras) - (require 'git-rebase) - (require 'magit-imenu) - (require 'magit-bookmark))) - -(with-eval-after-load 'bookmark - (require 'magit-bookmark)) - -(if after-init-time - (progn (magit-startup-asserts) - (magit-version)) - (add-hook 'after-init-hook #'magit-startup-asserts t) - (add-hook 'after-init-hook #'magit-version t)) - -;;; magit.el ends here diff --git a/elpa/magit-20210802.1524/magit.info b/elpa/magit-20210802.1524/magit.info deleted file mode 100644 index 3e48d878..00000000 --- a/elpa/magit-20210802.1524/magit.info +++ /dev/null @@ -1,201 +0,0 @@ -This is magit.info, produced by makeinfo version 6.7 from magit.texi. - - 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 - Foundation, either version 3 of the License, or (at your option) - any later version. - - This document 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. - -INFO-DIR-SECTION Emacs -START-INFO-DIR-ENTRY -* Magit: (magit). Using Git from Emacs with Magit. -END-INFO-DIR-ENTRY - - -Indirect: -magit.info-1: 754 -magit.info-2: 302197 - -Tag Table: -(Indirect) -Node: Top754 -Node: Introduction6588 -Node: Installation11311 -Node: Installing from Melpa11641 -Node: Installing from the Git Repository12714 -Node: Post-Installation Tasks15446 -Node: Getting Started16731 -Node: Interface Concepts21971 -Node: Modes and Buffers22332 -Node: Switching Buffers24081 -Node: Naming Buffers28832 -Node: Quitting Windows32139 -Node: Automatic Refreshing of Magit Buffers33885 -Node: Automatic Saving of File-Visiting Buffers36779 -Node: Automatic Reverting of File-Visiting Buffers37964 -Node: Risk of Reverting Automatically42959 -Node: Sections45341 -Node: Section Movement46267 -Node: Section Visibility51177 -Node: Section Hooks57254 -Node: Section Types and Values59661 -Node: Section Options60964 -Node: Transient Commands61436 -Node: Transient Arguments and Buffer Variables62673 -Node: Completion Confirmation and the Selection69691 -Node: Action Confirmation70135 -Node: Completion and Confirmation77988 -Node: The Selection81174 -Node: The hunk-internal region84073 -Node: Support for Completion Frameworks85162 -Node: Additional Completion Options90069 -Node: Running Git90668 -Node: Viewing Git Output90941 -Node: Git Process Status92074 -Node: Running Git Manually93039 -Node: Git Executable95509 -Node: Global Git Arguments98511 -Node: Inspecting99317 -Node: Status Buffer100474 -Node: Status Sections104464 -Node: Status Header Sections110016 -Node: Status Module Sections112646 -Node: Status Options115151 -Node: Repository List116620 -Node: Logging119962 -Node: Refreshing Logs122523 -Node: Log Buffer123969 -Node: Log Margin128222 -Node: Select from Log131401 -Node: Reflog133626 -Node: Cherries135283 -Node: Diffing137131 -Node: Refreshing Diffs140210 -Node: Commands Available in Diffs143789 -Node: Diff Options146325 -Node: Revision Buffer151806 -Node: Ediffing155136 -Node: References Buffer158784 -Node: References Sections169304 -Node: Bisecting170165 -Node: Visiting Files and Blobs172517 -Node: General-Purpose Visit Commands172987 -Node: Visiting Files and Blobs from a Diff173943 -Node: Blaming177402 -Node: Manipulating183743 -Node: Creating Repository184085 -Node: Cloning Repository184640 -Node: Staging and Unstaging190045 -Node: Staging from File-Visiting Buffers194128 -Node: Applying195296 -Node: Committing197189 -Node: Initiating a Commit197772 -Node: Editing Commit Messages201707 -Node: Using the Revision Stack204510 -Node: Commit Pseudo Headers207561 -Node: Commit Mode and Hooks208897 -Node: Commit Message Conventions211835 -Node: Branching213963 -Node: The Two Remotes214189 -Node: Branch Commands216842 -Node: Branch Git Variables229553 -Node: Auxiliary Branch Commands234944 -Node: Merging236062 -Node: Resolving Conflicts240070 -Node: Rebasing245071 -Node: Editing Rebase Sequences249930 -Node: Information About In-Progress Rebase254258 -Ref: Information About In-Progress Rebase-Footnote-1263140 -Node: Cherry Picking263736 -Node: Reverting268067 -Node: Resetting269516 -Node: Stashing271382 -Node: Transferring276083 -Node: Remotes276305 -Node: Remote Commands276457 -Node: Remote Git Variables280538 -Node: Fetching281817 -Node: Pulling284304 -Node: Pushing285350 -Node: Plain Patches289688 -Node: Maildir Patches291179 -Node: Miscellaneous292693 -Node: Tagging293007 -Node: Notes294925 -Node: Submodules297297 -Node: Listing Submodules297515 -Node: Submodule Transient298921 -Node: Subtree302197 -Node: Worktree304173 -Node: Common Commands305278 -Node: Wip Modes307401 -Node: Wip Graph312332 -Node: Legacy Wip Modes314646 -Node: Commands for Buffers Visiting Files317541 -Node: Minor Mode for Buffers Visiting Blobs323163 -Node: Customizing323974 -Node: Per-Repository Configuration325570 -Node: Essential Settings327825 -Node: Safety328170 -Node: Performance329931 -Ref: Log Performance332960 -Ref: Diff Performance334270 -Ref: Refs Buffer Performance335611 -Ref: Committing Performance336186 -Node: Microsoft Windows Performance337099 -Node: MacOS Performance338290 -Ref: MacOS Performance-Footnote-1338995 -Node: Default Bindings339077 -Node: Plumbing341319 -Node: Calling Git342148 -Node: Getting a Value from Git343673 -Node: Calling Git for Effect347414 -Node: Section Plumbing353320 -Node: Creating Sections353548 -Node: Section Selection357448 -Node: Matching Sections359247 -Node: Refreshing Buffers365220 -Node: Conventions368368 -Node: Theming Faces368560 -Node: FAQ376675 -Node: FAQ - How to ...?377117 -Node: How to pronounce Magit?377530 -Node: How to show git's output?378332 -Node: How to install the gitman info manual?379118 -Node: How to show diffs for gpg-encrypted files?380088 -Node: How does branching and pushing work?380684 -Node: Can Magit be used as ediff-version-control-package?381047 -Node: Should I disable VC?383065 -Node: FAQ - Issues and Errors383683 -Node: Magit is slow384684 -Node: I changed several thousand files at once and now Magit is unusable384898 -Node: I am having problems committing385627 -Node: I am using MS Windows and cannot push with Magit386108 -Node: I am using OS X and SOMETHING works in shell but not in Magit386725 -Node: Expanding a file to show the diff causes it to disappear387556 -Node: Point is wrong in the COMMIT_EDITMSG buffer388137 -Node: The mode-line information isn't always up-to-date389183 -Node: A branch and tag sharing the same name breaks SOMETHING390246 -Node: My Git hooks work on the command-line but not inside Magit391132 -Node: git-commit-mode isn't used when committing from the command-line391978 -Node: Point ends up inside invisible text when jumping to a file-visiting buffer394249 -Node: I am unable to stage when using Tramp from MS Windows395109 -Node: I am no longer able to save popup defaults396016 -Node: Debugging Tools396976 -Node: Keystroke Index399155 -Node: Command Index433334 -Node: Function Index470546 -Node: Variable Index486959 - -End Tag Table - - -Local Variables: -coding: utf-8 -End: diff --git a/elpa/magit-20210802.1524/magit.info-1 b/elpa/magit-20210802.1524/magit.info-1 deleted file mode 100644 index 04089936..00000000 --- a/elpa/magit-20210802.1524/magit.info-1 +++ /dev/null @@ -1,7780 +0,0 @@ -This is magit.info, produced by makeinfo version 6.7 from magit.texi. - - 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 - Foundation, either version 3 of the License, or (at your option) - any later version. - - This document 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. - -INFO-DIR-SECTION Emacs -START-INFO-DIR-ENTRY -* Magit: (magit). Using Git from Emacs with Magit. -END-INFO-DIR-ENTRY - - -File: magit.info, Node: Top, Next: Introduction, Up: (dir) - -Magit User Manual -***************** - -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. - -This manual is for Magit version 3.2.0. - - 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 - Foundation, either version 3 of the License, or (at your option) - any later version. - - This document 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. - -* Menu: - -* Introduction:: -* Installation:: -* Getting Started:: -* Interface Concepts:: -* Inspecting:: -* Manipulating:: -* Transferring:: -* Miscellaneous:: -* Customizing:: -* Plumbing:: -* FAQ:: -* Debugging Tools:: -* Keystroke Index:: -* Command Index:: -* Function Index:: -* Variable Index:: - -— The Detailed Node Listing — - -Installation - -* Installing from Melpa:: -* Installing from the Git Repository:: -* Post-Installation Tasks:: - -Interface Concepts - -* Modes and Buffers:: -* Sections:: -* Transient Commands:: -* Transient Arguments and Buffer Variables:: -* Completion, Confirmation and the Selection: Completion Confirmation and the Selection. -* Running Git:: - -Modes and Buffers - -* Switching Buffers:: -* Naming Buffers:: -* Quitting Windows:: -* Automatic Refreshing of Magit Buffers:: -* Automatic Saving of File-Visiting Buffers:: -* Automatic Reverting of File-Visiting Buffers:: - - -Sections - -* Section Movement:: -* Section Visibility:: -* Section Hooks:: -* Section Types and Values:: -* Section Options:: - - -Completion, Confirmation and the Selection - -* Action Confirmation:: -* Completion and Confirmation:: -* The Selection:: -* The hunk-internal region:: -* Support for Completion Frameworks:: -* Additional Completion Options:: - - -Running Git - -* Viewing Git Output:: -* Git Process Status:: -* Running Git Manually:: -* Git Executable:: -* Global Git Arguments:: - - -Inspecting - -* Status Buffer:: -* Repository List:: -* Logging:: -* Diffing:: -* Ediffing:: -* References Buffer:: -* Bisecting:: -* Visiting Files and Blobs:: -* Blaming:: - -Status Buffer - -* Status Sections:: -* Status Header Sections:: -* Status Module Sections:: -* Status Options:: - - -Logging - -* Refreshing Logs:: -* Log Buffer:: -* Log Margin:: -* Select from Log:: -* Reflog:: -* Cherries:: - - -Diffing - -* Refreshing Diffs:: -* Commands Available in Diffs:: -* Diff Options:: -* Revision Buffer:: - - -References Buffer - -* References Sections:: - - -Visiting Files and Blobs - -* General-Purpose Visit Commands:: -* Visiting Files and Blobs from a Diff:: - - -Manipulating - -* Creating Repository:: -* Cloning Repository:: -* Staging and Unstaging:: -* Applying:: -* Committing:: -* Branching:: -* Merging:: -* Resolving Conflicts:: -* Rebasing:: -* Cherry Picking:: -* Resetting:: -* Stashing:: - -Staging and Unstaging - -* Staging from File-Visiting Buffers:: - - -Committing - -* Initiating a Commit:: -* Editing Commit Messages:: - - -Branching - -* The Two Remotes:: -* Branch Commands:: -* Branch Git Variables:: -* Auxiliary Branch Commands:: - - -Rebasing - -* Editing Rebase Sequences:: -* Information About In-Progress Rebase:: - - -Cherry Picking - -* Reverting:: - - -Transferring - -* Remotes:: -* Fetching:: -* Pulling:: -* Pushing:: -* Plain Patches:: -* Maildir Patches:: - -Remotes - -* Remote Commands:: -* Remote Git Variables:: - - -Miscellaneous - -* Tagging:: -* Notes:: -* Submodules:: -* Subtree:: -* Worktree:: -* Common Commands:: -* Wip Modes:: -* Commands for Buffers Visiting Files:: -* Minor Mode for Buffers Visiting Blobs:: - -Submodules - -* Listing Submodules:: -* Submodule Transient:: - - -Wip Modes - -* Wip Graph:: -* Legacy Wip Modes:: - - -Customizing - -* Per-Repository Configuration:: -* Essential Settings:: - -Essential Settings - -* Safety:: -* Performance:: -* Default Bindings:: - - -Plumbing - -* Calling Git:: -* Section Plumbing:: -* Refreshing Buffers:: -* Conventions:: - -Calling Git - -* Getting a Value from Git:: -* Calling Git for Effect:: - - -Section Plumbing - -* Creating Sections:: -* Section Selection:: -* Matching Sections:: - - -Conventions - -* Theming Faces:: - - -FAQ - -* FAQ - How to ...?:: -* FAQ - Issues and Errors:: - -FAQ - How to ...? - -* 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 ediff-version-control-package?:: -* Should I disable VC?:: - - -FAQ - Issues and Errors - -* Magit is slow:: -* I changed several thousand files at once and now Magit is unusable:: -* I am having problems committing:: -* I am using MS Windows and cannot push with Magit:: -* I am using OS X and SOMETHING works in shell, but not in Magit: I am using OS X and SOMETHING works in shell but not in Magit. -* Expanding a file to show the diff causes it to disappear:: -* Point is wrong in the COMMIT_EDITMSG buffer:: -* The mode-line information isn't always up-to-date:: -* A branch and tag sharing the same name breaks SOMETHING:: -* My Git hooks work on the command-line but not inside Magit:: -* 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:: - - - - -File: magit.info, Node: Introduction, Next: Installation, Prev: Top, Up: Top - -1 Introduction -************** - -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. - - Staging and otherwise applying changes is one of the most important -features in a Git porcelain and here Magit outshines anything else, -including Git itself. Git’s own staging interface (‘git add --patch’) -is so cumbersome that many users only use it in exceptional cases. In -Magit staging a hunk or even just part of a hunk is as trivial as -staging all changes made to a file. - - The most visible part of Magit’s interface is the status buffer, -which displays information about the current repository. Its content is -created by running several Git commands and making their output -actionable. Among other things, it displays information about the -current branch, lists unpulled and unpushed changes and contains -sections displaying the staged and unstaged changes. That might sound -noisy, but, since sections are collapsible, it’s not. - - To stage or unstage a change one places the cursor on the change and -then types ‘s’ or ‘u’. The change can be a file or a hunk, or when the -region is active (i.e. when there is a selection) several files or -hunks, or even just part of a hunk. The change or changes that these -commands - and many others - would act on are highlighted. - - Magit also implements several other "apply variants" in addition to -staging and unstaging. One can discard or reverse a change, or apply it -to the working tree. Git’s own porcelain only supports this for staging -and unstaging and you would have to do something like ‘git diff ... | -??? | git apply ...’ to discard, revert, or apply a single hunk on the -command line. In fact that’s exactly what Magit does internally (which -is what lead to the term "apply variants"). - - Magit isn’t just for Git experts, but it does assume some prior -experience with Git as well as Emacs. That being said, many users have -reported that using Magit was what finally taught them what Git is -capable of and how to use it to its fullest. Other users wished they -had switched to Emacs sooner so that they would have gotten their hands -on Magit earlier. - - While one has to know the basic features of Emacs to be able to make -full use of Magit, acquiring just enough Emacs skills doesn’t take long -and is worth it, even for users who prefer other editors. Vim users are -advised to give Evil (https://bitbucket.org/lyro/evil/wiki/Home), the -"Extensible VI Layer for Emacs", and Spacemacs -(https://github.com/syl20bnr/spacemacs), an "Emacs starter-kit focused -on Evil" a try. - - Magit provides a consistent and efficient Git porcelain. After a -short learning period, you will be able to perform most of your daily -version control tasks faster than you would on the command line. You -will likely also start using features that seemed too daunting in the -past. - - Magit fully embraces Git. It exposes many advanced features using a -simple but flexible interface instead of only wrapping the trivial ones -like many GUI clients do. Of course Magit supports logging, cloning, -pushing, and other commands that usually don’t fail in spectacular ways; -but it also supports tasks that often cannot be completed in a single -step. Magit fully supports tasks such as merging, rebasing, -cherry-picking, reverting, and blaming by not only providing a command -to initiate these tasks but also by displaying context sensitive -information along the way and providing commands that are useful for -resolving conflicts and resuming the sequence after doing so. - - Magit wraps and in many cases improves upon at least the following -Git porcelain commands: ‘add’, ‘am’, ‘bisect’, ‘blame’, ‘branch’, -‘checkout’, ‘cherry’, ‘cherry-pick’, ‘clean’, ‘clone’, ‘commit’, -‘config’, ‘describe’, ‘diff’, ‘fetch’, ‘format-patch’, ‘init’, ‘log’, -‘merge’, ‘merge-tree’, ‘mv’, ‘notes’, ‘pull’, ‘rebase’, ‘reflog’, -‘remote’, ‘request-pull’, ‘reset’, ‘revert’, ‘rm’, ‘show’, ‘stash’, -‘submodule’, ‘subtree’, ‘tag’, and ‘worktree.’ Many more Magit porcelain -commands are implemented on top of Git plumbing commands. - - -File: magit.info, Node: Installation, Next: Getting Started, Prev: Introduction, Up: Top - -2 Installation -************** - -Magit can be installed using Emacs’ package manager or manually from its -development repository. - -* Menu: - -* Installing from Melpa:: -* Installing from the Git Repository:: -* Post-Installation Tasks:: - - -File: magit.info, Node: Installing from Melpa, Next: Installing from the Git Repository, Up: Installation - -2.1 Installing from Melpa -========================= - -Magit is available from Melpa and Melpa-Stable. If you haven’t used -Emacs’ package manager before, then it is high time you familiarize -yourself with it by reading the documentation in the Emacs manual, see -*note (emacs)Packages::. Then add one of the archives to -‘package-archives’: - - • To use Melpa: - - (require 'package) - (add-to-list 'package-archives - '("melpa" . "http://melpa.org/packages/") t) - - • To use Melpa-Stable: - - (require 'package) - (add-to-list 'package-archives - '("melpa-stable" . "http://stable.melpa.org/packages/") t) - - Once you have added your preferred archive, you need to update the -local package list using: - - M-x package-refresh-contents RET - - Once you have done that, you can install Magit and its dependencies -using: - - M-x package-install RET magit RET - - Now see *note Post-Installation Tasks::. - - -File: magit.info, Node: Installing from the Git Repository, Next: Post-Installation Tasks, Prev: Installing from Melpa, Up: Installation - -2.2 Installing from the Git Repository -====================================== - -Magit depends on the ‘dash’, ‘transient’ and ‘with-editor’ libraries -which are available from Melpa and Melpa-Stable. Install them using -‘M-x package-install RET RET’. Of course you may also install -them manually from their repository. - - Then clone the Magit repository: - - $ git clone https://github.com/magit/magit.git ~/.emacs.d/site-lisp/magit - $ cd ~/.emacs.d/site-lisp/magit - - Then compile the libraries and generate the info manuals: - - $ make - - If you haven’t installed ‘dash’, ‘transient’ and ‘with-editor’ from -Melpa or at ‘/path/to/magit/../’, then you have to tell ‘make’ -where to find them. To do so create the file ‘/path/to/magit/config.mk’ -with the following content before running ‘make’: - - 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 - - Finally add this to your init file: - - (add-to-list 'load-path "~/.emacs.d/site-lisp/magit/lisp") - (require 'magit) - - (with-eval-after-load 'info - (info-initialize) - (add-to-list 'Info-directory-list - "~/.emacs.d/site-lisp/magit/Documentation/")) - - Of course if you installed the dependencies manually as well, then -you have to tell Emacs about them too, by prefixing the above with: - - (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") - - 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. - - Instead of requiring the feature ‘magit’, you could load just the -autoload definitions, by loading the file ‘magit-autoloads.el’. - - (load "/path/to/magit/lisp/magit-autoloads") - - Instead of running Magit directly from the repository by adding that -to the ‘load-path’, you might want to instead install it in some other -directory using ‘sudo make install’ and setting ‘load-path’ accordingly. - - To update Magit use: - - $ git pull - $ make - - At times it might be necessary to run ‘make clean all’ instead. - - To view all available targets use ‘make help’. - - Now see *note Post-Installation Tasks::. - - -File: magit.info, Node: Post-Installation Tasks, Prev: Installing from the Git Repository, Up: Installation - -2.3 Post-Installation Tasks -=========================== - -After installing Magit you should verify that you are indeed using the -Magit, Git, and Emacs releases you think you are using. It’s best to -restart Emacs before doing so, to make sure you are not using an -outdated value for ‘load-path’. - - M-x magit-version RET - - should display something like - - Magit 2.8.0, Git 2.10.2, Emacs 25.1.1, gnu/linux - - Then you might also want to read about options that many users likely -want to customize. See *note Essential Settings::. - - To be able to follow cross references to Git manpages found in this -manual, you might also have to manually install the ‘gitman’ info -manual, or advice ‘Info-follow-nearest-node’ to instead open the actual -manpage. See *note How to install the gitman info manual?::. - - If you are completely new to Magit then see *note Getting Started::. - - If you run into problems, then please see the *note FAQ::. Also see -the *note Debugging Tools::. - - And last but not least please consider making a donation, to ensure -that I can keep working on Magit. See . -for various donation options. - - -File: magit.info, Node: Getting Started, Next: Interface Concepts, Prev: Installation, Up: Top - -3 Getting Started -***************** - -This short tutorial describes the most essential features that many -Magitians use on a daily basis. It only scratches the surface but -should be enough to get you started. - - IMPORTANT: It is safest if you clone some repository just for this -tutorial. Alternatively you can use an existing local repository, but -if you do that, then you should commit all uncommitted changes before -proceeding. - - 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 -Magit. Many other Magit buffers may exist at a given time, but they are -often created from this buffer. - - Depending on what state your repository is in, this buffer may -contain sections titled "Staged changes", "Unstaged changes", "Unmerged -into origin/master", "Unpushed to origin/master", and many others. - - Since we are starting from a safe state, which you can easily return -to (by doing a ‘git reset --hard PRE-MAGIT-STATE’), there currently are -no staged or unstaged changes. Edit some files and save the changes. -Then go back to the status buffer, while at the same time refreshing it, -by typing ‘C-x g’. (When the status buffer, or any Magit buffer for -that matter, is the current buffer, then you can also use just ‘g’ to -refresh it). - - Move between sections using ‘p’ and ‘n’. Note that the bodies of -some sections are hidden. Type ‘TAB’ to expand or collapse the section -at point. You can also use ‘C-tab’ to cycle the visibility of the -current section and its children. Move to a file section inside the -section named "Unstaged changes" and type ‘s’ to stage the changes you -have made to that file. That file now appears under "Staged changes". - - Magit can stage and unstage individual hunks, not just complete -files. Move to the file you have just staged, expand it using ‘TAB’, -move to one of the hunks using ‘n’, and unstage just that by typing ‘u’. -Note how the staging (‘s’) and unstaging (‘u’) commands operate on the -change at point. Many other commands behave the same way. - - You can also un-/stage just part of a hunk. Inside the body of a -hunk section (move there using ‘C-n’), set the mark using ‘C-SPC’ and -move down until some added and/or removed lines fall inside the region -but not all of them. Again type ‘s’ to stage. - - It is also possible to un-/stage multiple files at once. Move to a -file section, type ‘C-SPC’, move to the next file using ‘n’, and then -‘s’ to stage both files. Note that both the mark and point have to be -on the headings of sibling sections for this to work. If the region -looks like it does in other buffers, then it doesn’t select Magit -sections that can be acted on as a unit. - - And then of course you want to commit your changes. Type ‘c’. This -shows the available commit commands and arguments in a buffer at the -bottom of the frame. Each command and argument is prefixed with the key -that invokes/sets it. Do not worry about this for now. We want to -create a "normal" commit, which is done by typing ‘c’ again. - - 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 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 -you just committed some random changes, but if that is not the case you -could push it by typing ‘P’ to show all the available push commands and -arguments and then ‘p’ to push to a branch with the same name as the -local branch onto the remote configured as the push-remote. (If the -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 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 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 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 *note 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. - - -File: magit.info, Node: Interface Concepts, Next: Inspecting, Prev: Getting Started, Up: Top - -4 Interface Concepts -******************** - -* Menu: - -* Modes and Buffers:: -* Sections:: -* Transient Commands:: -* Transient Arguments and Buffer Variables:: -* Completion, Confirmation and the Selection: Completion Confirmation and the Selection. -* Running Git:: - - -File: magit.info, Node: Modes and Buffers, Next: Sections, Up: Interface Concepts - -4.1 Modes and Buffers -===================== - -Magit provides several major-modes. For each of these modes there -usually exists only one buffer per repository. Separate modes and thus -buffers exist for commits, diffs, logs, and some other things. - - Besides these special purpose buffers, there also exists an overview -buffer, called the *status buffer*. It’s usually from this buffer that -the user invokes Git commands, or creates or visits other buffers. - - In this manual we often speak about "Magit buffers". By that we mean -buffers whose major-modes derive from ‘magit-mode’. - -‘M-x magit-toggle-buffer-lock’ (‘magit-toggle-buffer-lock’) - - This command locks the current buffer to its value or if the buffer - is already locked, then it unlocks it. - - Locking a buffer to its value prevents it from being reused to - display another value. The name of a locked buffer contains its - value, which allows telling it apart from other locked buffers and - the unlocked buffer. - - Not all Magit buffers can be locked to their values; for example, - it wouldn’t make sense to lock a status buffer. - - There can only be a single unlocked buffer using a certain - major-mode per repository. So when a buffer is being unlocked and - another unlocked buffer already exists for that mode and - repository, then the former buffer is instead deleted and the - latter is displayed in its place. - -* Menu: - -* Switching Buffers:: -* Naming Buffers:: -* Quitting Windows:: -* Automatic Refreshing of Magit Buffers:: -* Automatic Saving of File-Visiting Buffers:: -* Automatic Reverting of File-Visiting Buffers:: - - -File: magit.info, Node: Switching Buffers, Next: Naming Buffers, Up: Modes and Buffers - -4.1.1 Switching Buffers ------------------------ - - -- Function: magit-display-buffer buffer &optional display-function - - This function is a wrapper around ‘display-buffer’ and is used to - display any Magit buffer. It displays BUFFER in some window and, - unlike ‘display-buffer’, also selects that window, provided - ‘magit-display-buffer-noselect’ is ‘nil’. It also runs the hooks - mentioned below. - - If optional DISPLAY-FUNCTION is non-nil, then that is used to - display the buffer. Usually that is ‘nil’ and the function - specified by ‘magit-display-buffer-function’ is used. - - -- Variable: magit-display-buffer-noselect - - When this is non-nil, then ‘magit-display-buffer’ only displays the - buffer but forgoes also selecting the window. This variable should - not be set globally, it is only intended to be let-bound, by code - that automatically updates "the other window". This is used for - example when the revision buffer is updated when you move inside - the log buffer. - - -- User Option: magit-display-buffer-function - - The function specified here is called by ‘magit-display-buffer’ - with one argument, a buffer, to actually display that buffer. This - function should call ‘display-buffer’ with that buffer as first and - a list of display actions as second argument. - - Magit provides several functions, listed below, that are suitable - values for this option. If you want to use different rules, then a - good way of doing that is to start with a copy of one of these - functions and then adjust it to your needs. - - Instead of using a wrapper around ‘display-buffer’, that function - itself can be used here, in which case the display actions have to - be specified by adding them to ‘display-buffer-alist’ instead. - - To learn about display actions, see *note (elisp)Choosing Window::. - - -- Function: magit-display-buffer-traditional buffer - - This function is the current default value of the option - ‘magit-display-buffer-function’. Before that option and this - function were added, the behavior was hard-coded in many places all - over the code base but now all the rules are contained in this one - function (except for the "noselect" special case mentioned above). - - -- Function: magit-display-buffer-same-window-except-diff-v1 - - This function displays most buffers in the currently selected - window. If a buffer’s mode derives from ‘magit-diff-mode’ or - ‘magit-process-mode’, it is displayed in another window. - - -- Function: magit-display-buffer-fullframe-status-v1 - - This function fills the entire frame when displaying a status - buffer. Otherwise, it behaves like - ‘magit-display-buffer-traditional’. - - -- Function: magit-display-buffer-fullframe-status-topleft-v1 - - This function fills the entire frame when displaying a status - buffer. It behaves like ‘magit-display-buffer-fullframe-status-v1’ - except that it displays buffers that derive from ‘magit-diff-mode’ - or ‘magit-process-mode’ to the top or left of the current buffer - rather than to the bottom or right. As a result, Magit buffers - tend to pop up on the same side as they would if - ‘magit-display-buffer-traditional’ were in use. - - -- Function: magit-display-buffer-fullcolumn-most-v1 - - This function displays most buffers so that they fill the entire - height of the frame. However, the buffer is displayed in another - window if (1) the buffer’s mode derives from ‘magit-process-mode’, - or (2) the buffer’s mode derives from ‘magit-diff-mode’, provided - that the mode of the current buffer derives from ‘magit-log-mode’ - or ‘magit-cherry-mode’. - - -- User Option: magit-pre-display-buffer-hook - - This hook is run by ‘magit-display-buffer’ before displaying the - buffer. - - -- Function: magit-save-window-configuration - - This function saves the current window configuration. Later when - the buffer is buried, it may be restored by - ‘magit-restore-window-configuration’. - - -- User Option: magit-post-display-buffer-hook - - This hook is run by ‘magit-display-buffer’ after displaying the - buffer. - - -- Function: magit-maybe-set-dedicated - - This function remembers if a new window had to be created to - display the buffer, or whether an existing window was reused. This - information is later used by ‘magit-mode-quit-window’, to determine - whether the window should be deleted when its last Magit buffer is - buried. - - -File: magit.info, Node: Naming Buffers, Next: Quitting Windows, Prev: Switching Buffers, Up: Modes and Buffers - -4.1.2 Naming Buffers --------------------- - - -- User Option: magit-generate-buffer-name-function - - The function used to generate the names of Magit buffers. - - Such a function should take the options - ‘magit-uniquify-buffer-names’ as well as ‘magit-buffer-name-format’ - into account. If it doesn’t, then should be clearly stated in the - doc-string. And if it supports %-sequences beyond those mentioned - in the doc-string of the option ‘magit-buffer-name-format’, then - its own doc-string should describe the additions. - - -- Function: magit-generate-buffer-name-default-function mode - - This function returns a buffer name suitable for a buffer whose - major-mode is MODE and which shows information about the repository - in which ‘default-directory’ is located. - - This function uses ‘magit-buffer-name-format’ and supporting all of - the %-sequences mentioned the documentation of that option. It - also respects the option ‘magit-uniquify-buffer-names’. - - -- User Option: magit-buffer-name-format - - The format string used to name Magit buffers. - - At least the following %-sequences are supported: - - • ‘%m’ - - The name of the major-mode, but with the ‘-mode’ suffix - removed. - - • ‘%M’ - - Like ‘%m’ but abbreviate ‘magit-status-mode’ as ‘magit’. - - • ‘%v’ - - The value the buffer is locked to, in parentheses, or an empty - string if the buffer is not locked to a value. - - • ‘%V’ - - Like ‘%v’, but the string is prefixed with a space, unless it - is an empty string. - - • ‘%t’ - - The top-level directory of the working tree of the repository, - or if ‘magit-uniquify-buffer-names’ is non-nil an abbreviation - of that. - - • ‘%x’ - - If ‘magit-uniquify-buffer-names’ is nil "*", otherwise the - empty string. Due to limitations of the ‘uniquify’ package, - buffer names must end with the path. - - • ‘%T’ - - Obsolete, use "%t%x" instead. Like ‘%t’, but append an - asterisk if and only if ‘magit-uniquify-buffer-names’ is nil. - - The value should always contain ‘%m’ or ‘%M’, ‘%v’ or ‘%V’, and - ‘%t’ (or the obsolete ‘%T’). If ‘magit-uniquify-buffer-names’ is - non-nil, then the value must end with ‘%t’ or ‘%t%x’ (or the - obsolete ‘%T’). See issue #2841. - - -- User Option: magit-uniquify-buffer-names - - This option controls whether the names of Magit buffers are - uniquified. If the names are not being uniquified, then they - contain the full path of the top-level of the working tree of the - corresponding repository. If they are being uniquified, then they - end with the basename of the top-level, or if that would conflict - with the name used for other buffers, then the names of all these - buffers are adjusted until they no longer conflict. - - This is done using the ‘uniquify’ package; customize its options to - control how buffer names are uniquified. - - -File: magit.info, Node: Quitting Windows, Next: Automatic Refreshing of Magit Buffers, Prev: Naming Buffers, Up: Modes and Buffers - -4.1.3 Quitting Windows ----------------------- - -‘q’ (‘magit-mode-bury-buffer’) - - This command buries the current Magit buffer. - - With a prefix argument, it instead kills the buffer. With a double - prefix argument, also kills all other Magit buffers associated with - the current project. - - -- User Option: magit-bury-buffer-function - - The function used to actually bury or kill the current buffer. - - ‘magit-mode-bury-buffer’ calls this function with one argument. If - the argument is non-nil, then the function has to kill the current - buffer. Otherwise it has to bury it alive. The default value - currently is ‘magit-restore-window-configuration’. - - -- Function: magit-restore-window-configuration kill-buffer - - Bury or kill the current buffer using ‘quit-window’, which is - called with KILL-BUFFER as first and the selected window as second - argument. - - Then restore the window configuration that existed right before the - current buffer was displayed in the selected frame. Unfortunately - that also means that point gets adjusted in all the buffers, which - are being displayed in the selected frame. - - -- Function: magit-mode-quit-window kill-buffer - - Bury or kill the current buffer using ‘quit-window’, which is - called with KILL-BUFFER as first and the selected window as second - argument. - - Then, if the window was originally created to display a Magit - buffer and the buried buffer was the last remaining Magit buffer - that was ever displayed in the window, then that is deleted. - - -File: magit.info, Node: Automatic Refreshing of Magit Buffers, Next: Automatic Saving of File-Visiting Buffers, Prev: Quitting Windows, Up: Modes and Buffers - -4.1.4 Automatic Refreshing of Magit Buffers -------------------------------------------- - -After running a command which may change the state of the current -repository, the current Magit buffer and the corresponding status buffer -are refreshed. The status buffer can be automatically refreshed -whenever a buffer is saved to a file inside the respective repository by -adding a hook, like so: - - (with-eval-after-load 'magit-mode - (add-hook 'after-save-hook 'magit-after-save-refresh-status t)) - - Automatically refreshing Magit buffers ensures that the displayed -information is up-to-date most of the time but can lead to a noticeable -delay in big repositories. Other Magit buffers are not refreshed to -keep the delay to a minimum and also because doing so can sometimes be -undesirable. - - Buffers can also be refreshed explicitly, which is useful in buffers -that weren’t current during the last refresh and after changes were made -to the repository outside of Magit. - -‘g’ (‘magit-refresh’) - - This command refreshes the current buffer if its major mode derives - from ‘magit-mode’ as well as the corresponding status buffer. - - If the option ‘magit-revert-buffers’ calls for it, then it also - reverts all unmodified buffers that visit files being tracked in - the current repository. - -‘G’ (‘magit-refresh-all’) - - This command refreshes all Magit buffers belonging to the current - repository and also reverts all unmodified buffers that visit files - being tracked in the current repository. - - The file-visiting buffers are always reverted, even if - ‘magit-revert-buffers’ is nil. - - -- User Option: magit-refresh-buffer-hook - - This hook is run in each Magit buffer that was refreshed during the - current refresh - normally the current buffer and the status - buffer. - - -- User Option: magit-refresh-status-buffer - - When this option is non-nil, then the status buffer is - automatically refreshed after running git for side-effects, in - addition to the current Magit buffer, which is always refreshed - automatically. - - Only set this to nil after exhausting all other options to improve - performance. - - -- Function: magit-after-save-refresh-status - - This function is intended to be added to ‘after-save-hook’. After - doing that the corresponding status buffer is refreshed whenever a - buffer is saved to a file inside a repository. - - Note that refreshing a Magit buffer is done by re-creating its - contents from scratch, which can be slow in large repositories. If - you are not satisfied with Magit’s performance, then you should - obviously not add this function to that hook. - - -File: magit.info, Node: Automatic Saving of File-Visiting Buffers, Next: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Refreshing of Magit Buffers, Up: Modes and Buffers - -4.1.5 Automatic Saving of File-Visiting Buffers ------------------------------------------------ - -File-visiting buffers are by default saved at certain points in time. -This doesn’t guarantee that Magit buffers are always up-to-date, but, -provided one only edits files by editing them in Emacs and uses only -Magit to interact with Git, one can be fairly confident. When in doubt -or after outside changes, type ‘g’ (‘magit-refresh’) to save and refresh -explicitly. - - -- User Option: magit-save-repository-buffers - - This option controls whether file-visiting buffers are saved before - certain events. - - If this is non-nil then all modified file-visiting buffers - belonging to the current repository may be saved before running - commands, before creating new Magit buffers, and before explicitly - refreshing such buffers. If this is ‘dontask’ then this is done - without user intervention. If it is ‘t’ then the user has to - confirm each save. - - -File: magit.info, Node: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Saving of File-Visiting Buffers, Up: Modes and Buffers - -4.1.6 Automatic Reverting of File-Visiting Buffers --------------------------------------------------- - -By default Magit automatically reverts buffers that are visiting files -that are being tracked in a Git repository, after they have changed on -disk. When using Magit one often changes files on disk by running Git, -i.e. "outside Emacs", making this a rather important feature. - - For example, if you discard a change in the status buffer, then that -is done by running ‘git apply --reverse ...’, and Emacs considers the -file to have "changed on disk". If Magit did not automatically revert -the buffer, then you would have to type ‘M-x revert-buffer RET RET’ in -the visiting buffer before you could continue making changes. - - -- User Option: magit-auto-revert-mode - - When this mode is enabled, then buffers that visit tracked files - are automatically reverted after the visited files change on disk. - - -- User Option: global-auto-revert-mode - - When this mode is enabled, then any file-visiting buffer is - automatically reverted after the visited file changes on disk. - - If you like buffers that visit tracked files to be automatically - reverted, then you might also like any buffer to be reverted, not - just those visiting tracked files. If that is the case, then - enable this mode _instead of_ ‘magit-auto-revert-mode’. - - -- User Option: magit-auto-revert-immediately - - This option controls whether Magit reverts buffers immediately. - - If this is non-nil and either ‘global-auto-revert-mode’ or - ‘magit-auto-revert-mode’ is enabled, then Magit immediately reverts - buffers by explicitly calling ‘auto-revert-buffers’ after running - Git for side-effects. - - If ‘auto-revert-use-notify’ is non-nil (and file notifications are - actually supported), then ‘magit-auto-revert-immediately’ does not - have to be non-nil, because the reverts happen immediately anyway. - - If ‘magit-auto-revert-immediately’ and ‘auto-revert-use-notify’ are - both ‘nil’, then reverts happen after ‘auto-revert-interval’ - seconds of user inactivity. That is not desirable. - - -- User Option: auto-revert-use-notify - - This option controls whether file notification functions should be - used. Note that this variable unfortunately defaults to ‘t’ even - on systems on which file notifications cannot be used. - - -- User Option: magit-auto-revert-tracked-only - - This option controls whether ‘magit-auto-revert-mode’ only reverts - tracked files or all files that are located inside Git - repositories, including untracked files and files located inside - Git’s control directory. - - -- User Option: auto-revert-mode - - The global mode ‘magit-auto-revert-mode’ works by turning on this - local mode in the appropriate buffers (but - ‘global-auto-revert-mode’ is implemented differently). You can - also turn it on or off manually, which might be necessary if Magit - does not notice that a previously untracked file now is being - tracked or vice-versa. - - -- User Option: auto-revert-stop-on-user-input - - This option controls whether the arrival of user input suspends the - automatic reverts for ‘auto-revert-interval’ seconds. - - -- User Option: auto-revert-interval - - This option controls how many seconds Emacs waits for before - resuming suspended reverts. - - -- User Option: auto-revert-buffer-list-filter - - This option specifies an additional filter used by - ‘auto-revert-buffers’ to determine whether a buffer should be - reverted or not. - - This option is provided by Magit, which also advises - ‘auto-revert-buffers’ to respect it. Magit users who do not turn - on the local mode ‘auto-revert-mode’ themselves, are best served by - setting the value to ‘magit-auto-revert-repository-buffer-p’. - - However the default is nil, so as not to disturb users who do use - the local mode directly. If you experience delays when running - Magit commands, then you should consider using one of the - predicates provided by Magit - especially if you also use Tramp. - - Users who do turn on ‘auto-revert-mode’ in buffers in which Magit - doesn’t do that for them, should likely not use any filter. Users - who turn on ‘global-auto-revert-mode’, do not have to worry about - this option, because it is disregarded if the global mode is - enabled. - - -- User Option: auto-revert-verbose - - This option controls whether Emacs reports when a buffer has been - reverted. - - The options with the ‘auto-revert-’ prefix are located in the Custom -group named ‘auto-revert’. The other, Magit-specific, options are -located in the ‘magit’ group. - -* Menu: - -* Risk of Reverting Automatically:: - - -File: magit.info, Node: Risk of Reverting Automatically, Up: Automatic Reverting of File-Visiting Buffers - -Risk of Reverting Automatically -............................... - -For the vast majority of users, automatically reverting file-visiting -buffers after they have changed on disk is harmless. - - If a buffer is modified (i.e. it contains changes that haven’t been -saved yet), then Emacs will refuse to automatically revert it. If you -save a previously modified buffer, then that results in what is seen by -Git as an uncommitted change. Git will then refuse to carry out any -commands that would cause these changes to be lost. In other words, if -there is anything that could be lost, then either Git or Emacs will -refuse to discard the changes. - - However, if you use file-visiting buffers as a sort of ad hoc -"staging area", then the automatic reverts could potentially cause data -loss. So far I have heard from only one user who uses such a workflow. - - An example: You visit some file in a buffer, edit it, and save the -changes. Then, outside of Emacs (or at least not using Magit or by -saving the buffer) you change the file on disk again. At this point the -buffer is the only place where the intermediate version still exists. -You have saved the changes to disk, but that has since been overwritten. -Meanwhile Emacs considers the buffer to be unmodified (because you have -not made any changes to it since you last saved it to the visited file) -and therefore would not object to it being automatically reverted. At -this point an Auto-Revert mode would kick in. It would check whether -the buffer is modified and since that is not the case it would revert -it. The intermediate version would be lost. (Actually you could still -get it back using the ‘undo’ command.) - - If your workflow depends on Emacs preserving the intermediate version -in the buffer, then you have to disable all Auto-Revert modes. But -please consider that such a workflow would be dangerous even without -using an Auto-Revert mode, and should therefore be avoided. If Emacs -crashes or if you quit Emacs by mistake, then you would also lose the -buffer content. There would be no autosave file still containing the -intermediate version (because that was deleted when you saved the -buffer) and you would not be asked whether you want to save the buffer -(because it isn’t modified). - - -File: magit.info, Node: Sections, Next: Transient Commands, Prev: Modes and Buffers, Up: Interface Concepts - -4.2 Sections -============ - -Magit buffers are organized into nested sections, which can be collapsed -and expanded, similar to how sections are handled in Org mode. Each -section also has a type, and some sections also have a value. For each -section type there can also be a local keymap, shared by all sections of -that type. - - Taking advantage of the section value and type, many commands operate -on the current section, or when the region is active and selects -sections of the same type, all of the selected sections. Commands that -only make sense for a particular section type (as opposed to just -behaving differently depending on the type) are usually bound in section -type keymaps. - -* Menu: - -* Section Movement:: -* Section Visibility:: -* Section Hooks:: -* Section Types and Values:: -* Section Options:: - - -File: magit.info, Node: Section Movement, Next: Section Visibility, Up: Sections - -4.2.1 Section Movement ----------------------- - -To move within a section use the usual keys (‘C-p’, ‘C-n’, ‘C-b’, ‘C-f’ -etc), whose global bindings are not shadowed. To move to another -section use the following commands. - -‘p’ (‘magit-section-backward’) - - When not at the beginning of a section, then move to the beginning - of the current section. At the beginning of a section, instead - move to the beginning of the previous visible section. - -‘n’ (‘magit-section-forward’) - - Move to the beginning of the next visible section. - -‘M-p’ (‘magit-section-backward-siblings’) - - Move to the beginning of the previous sibling section. If there is - no previous sibling section, then move to the parent section - instead. - -‘M-n’ (‘magit-section-forward-siblings’) - - Move to the beginning of the next sibling section. If there is no - next sibling section, then move to the parent section instead. - -‘^’ (‘magit-section-up’) - - Move to the beginning of the parent of the current section. - - The above commands all call the hook ‘magit-section-movement-hook’. -Any of the functions listed below can be used as members of this hook. - - You might want to remove some of the functions that Magit adds using -‘add-hook’. In doing so you have to make sure you do not attempt to -remove function that haven’t even been added yet, for example: - - (with-eval-after-load 'magit-diff - (remove-hook 'magit-section-movement-hook - 'magit-hunk-set-window-start)) - - -- Variable: magit-section-movement-hook - - This hook is run by all of the above movement commands, after - arriving at the destination. - - -- Function: magit-hunk-set-window-start - - This hook function ensures that the beginning of the current - section is visible, provided it is a ‘hunk’ section. Otherwise, it - does nothing. - - Loading ‘magit-diff’ adds this function to the hook. - - -- Function: magit-section-set-window-start - - This hook function ensures that the beginning of the current - section is visible, regardless of the section’s type. If you add - this to ‘magit-section-movement-hook’, then you must remove the - hunk-only variant in turn. - - -- Function: magit-log-maybe-show-more-commits - - This hook function only has an effect in log buffers, and ‘point’ - is on the "show more" section. If that is the case, then it - doubles the number of commits that are being shown. - - Loading ‘magit-log’ adds this function to the hook. - - -- Function: magit-log-maybe-update-revision-buffer - - When moving inside a log buffer, then this function updates the - revision buffer, provided it is already being displayed in another - window of the same frame. - - Loading ‘magit-log’ adds this function to the hook. - - -- Function: magit-log-maybe-update-blob-buffer - - When moving inside a log buffer and another window of the same - frame displays a blob buffer, then this function instead displays - the blob buffer for the commit at point in that window. - - -- Function: magit-status-maybe-update-revision-buffer - - When moving inside a status buffer, then this function updates the - revision buffer, provided it is already being displayed in another - window of the same frame. - - -- Function: magit-status-maybe-update-stash-buffer - - When moving inside a status buffer, then this function updates the - stash buffer, provided it is already being displayed in another - window of the same frame. - - -- Function: magit-status-maybe-update-blob-buffer - - When moving inside a status buffer and another window of the same - frame displays a blob buffer, then this function instead displays - the blob buffer for the commit at point in that window. - - -- Function: magit-stashes-maybe-update-stash-buffer - - When moving inside a buffer listing stashes, then this function - updates the stash buffer, provided it is already being displayed in - another window of the same frame. - - -- User Option: magit-update-other-window-delay - - Delay before automatically updating the other window. - - When moving around in certain buffers, then certain other buffers, - which are being displayed in another window, may optionally be - updated to display information about the section at point. - - When holding down a key to move by more than just one section, then - that would update that buffer for each section on the way. To - prevent that, updating the revision buffer is delayed, and this - option controls for how long. For optimal experience you might - have to adjust this delay and/or the keyboard repeat rate and delay - of your graphical environment or operating system. - - -File: magit.info, Node: Section Visibility, Next: Section Hooks, Prev: Section Movement, Up: Sections - -4.2.2 Section Visibility ------------------------- - -Magit provides many commands for changing the visibility of sections, -but all you need to get started are the next two. - -‘TAB’ (‘magit-section-toggle’) - - Toggle the visibility of the body of the current section. - -‘C-’ (‘magit-section-cycle’) - - Cycle the visibility of current section and its children. - -‘M-’ (‘magit-section-cycle-diffs’) - - Cycle the visibility of diff-related sections in the current - buffer. - -‘S-’ (‘magit-section-cycle-global’) - - Cycle the visibility of all sections in the current buffer. - -‘1’ (‘magit-section-show-level-1’) -‘2’ (‘magit-section-show-level-2’) -‘3’ (‘magit-section-show-level-3’) -‘4’ (‘magit-section-show-level-4’) - - Show sections surrounding the current section up to level N. - -‘M-1’ (‘magit-section-show-level-1-all’) -‘M-2’ (‘magit-section-show-level-2-all’) -‘M-3’ (‘magit-section-show-level-3-all’) -‘M-4’ (‘magit-section-show-level-4-all’) - - Show all sections up to level N. - - Some functions, which are used to implement the above commands, are -also exposed as commands themselves. By default no keys are bound to -these commands, as they are generally perceived to be much less useful. -But your mileage may vary. - - -- Command: magit-section-show - - Show the body of the current section. - - -- Command: magit-section-hide - - Hide the body of the current section. - - -- Command: magit-section-show-headings - - Recursively show headings of children of the current section. Only - show the headings. Previously shown text-only bodies are hidden. - - -- Command: magit-section-show-children - - Recursively show the bodies of children of the current section. - With a prefix argument show children down to the level of the - current section, and hide deeper children. - - -- Command: magit-section-hide-children - - Recursively hide the bodies of children of the current section. - - -- Command: magit-section-toggle-children - - Toggle visibility of bodies of children of the current section. - - When a buffer is first created then some sections are shown expanded -while others are not. This is hard coded. When a buffer is refreshed -then the previous visibility is preserved. The initial visibility of -certain sections can also be overwritten using the hook -‘magit-section-set-visibility-hook’. - - -- User Option: magit-section-initial-visibility-alist - - This options can be used to override the initial visibility of - sections. In the future it will also be used to define the - defaults, but currently a section’s default is still hardcoded. - - The value is an alist. Each element maps a section type or lineage - to the initial visibility state for such sections. The state has - to be one of ‘show’ or ‘hide’, or a function that returns one of - these symbols. A function is called with the section as the only - argument. - - Use the command ‘magit-describe-section-briefly’ to determine a - section’s lineage or type. The vector in the output is the section - lineage and the type is the first element of that vector. - Wildcards can be used, see ‘magit-section-match’. - - -- User Option: magit-section-cache-visibility - - This option controls for which sections the previous visibility - state should be restored if a section disappears and later appears - again. The value is a boolean or a list of section types. If t, - then the visibility of all sections is cached. Otherwise this is - only done for sections whose type matches one of the listed types. - - This requires that the function ‘magit-section-cached-visibility’ - is a member of ‘magit-section-set-visibility-hook’. - - -- Variable: magit-section-set-visibility-hook - - This hook is run when first creating a buffer and also when - refreshing an existing buffer, and is used to determine the - visibility of the section currently being inserted. - - Each function is called with one argument, the section being - inserted. It should return ‘hide’ or ‘show’, or to leave the - visibility undefined ‘nil’. If no function decides on the - visibility and the buffer is being refreshed, then the visibility - is preserved; or if the buffer is being created, then the hard - coded default is used. - - Usually this should only be used to set the initial visibility but - not during refreshes. If ‘magit-insert-section--oldroot’ is - non-nil, then the buffer is being refreshed and these functions - should immediately return ‘nil’. - - -- User Option: magit-section-visibility-indicator - - This option controls whether and how to indicate that a section can - be expanded/collapsed. - - If nil, then no visibility indicators are shown. Otherwise the - value has to have one of these two forms: - - • ‘(EXPANDABLE-BITMAP . COLLAPSIBLE-BITMAP)’ - - Both values have to be variables whose values are fringe - bitmaps. In this case every section that can be expanded or - collapsed gets an indicator in the left fringe. - - To provide extra padding around the indicator, set - ‘left-fringe-width’ in ‘magit-mode-hook’, e.g.: - - (add-hook 'magit-mode-hook (lambda () - (setq left-fringe-width 20))) - - • ‘(STRING . BOOLEAN)’ - - In this case STRING (usually an ellipsis) is shown at the end - of the heading of every collapsed section. Expanded sections - get no indicator. The cdr controls whether the appearance of - these ellipsis take section highlighting into account. Doing - so might potentially have an impact on performance, while not - doing so is kinda ugly. - - -File: magit.info, Node: Section Hooks, Next: Section Types and Values, Prev: Section Visibility, Up: Sections - -4.2.3 Section Hooks -------------------- - -Which sections are inserted into certain buffers is controlled with -hooks. This includes the status and the refs buffers. For other -buffers, e.g. log and diff buffers, this is not possible. The command -‘magit-describe-section’ can be used to see which hook (if any) was -responsible for inserting the section at point. - - For buffers whose sections can be customized by the user, a hook -variable called ‘magit-TYPE-sections-hook’ exists. This hook should be -changed using ‘magit-add-section-hook’. Avoid using ‘add-hooks’ or the -Custom interface. - - The various available section hook variables are described later in -this manual along with the appropriate "section inserter functions". - - -- Function: magit-add-section-hook hook function &optional at append - local - - Add the function FUNCTION to the value of section hook HOOK. - - Add FUNCTION at the beginning of the hook list unless optional - APPEND is non-nil, in which case FUNCTION is added at the end. If - FUNCTION already is a member then move it to the new location. - - If optional AT is non-nil and a member of the hook list, then add - FUNCTION next to that instead. Add before or after AT, or replace - AT with FUNCTION depending on APPEND. If APPEND is the symbol - ‘replace’, then replace AT with FUNCTION. For any other non-nil - value place FUNCTION right after AT. If nil, then place FUNCTION - right before AT. If FUNCTION already is a member of the list but - AT is not, then leave FUNCTION where ever it already is. - - If optional LOCAL is non-nil, then modify the hook’s buffer-local - value rather than its global value. This makes the hook local by - copying the default value. That copy is then modified. - - HOOK should be a symbol. If HOOK is void, it is first set to nil. - HOOK’s value must not be a single hook function. FUNCTION should - be a function that takes no arguments and inserts one or multiple - sections at point, moving point forward. FUNCTION may choose not - to insert its section(s), when doing so would not make sense. It - should not be abused for other side-effects. - - To remove a function from a section hook, use ‘remove-hook’. - - -File: magit.info, Node: Section Types and Values, Next: Section Options, Prev: Section Hooks, Up: Sections - -4.2.4 Section Types and Values ------------------------------- - -Each section has a type, for example ‘hunk’, ‘file’, and ‘commit’. -Instances of certain section types also have a value. The value of a -section of type ‘file’, for example, is a file name. - - Users usually do not have to worry about a section’s type and value, -but knowing them can be handy at times. - -‘M-x magit-describe-section-briefly’ (‘magit-describe-section-briefly’) - - Show 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 is -only one of the reasons why the same key may do something different, -depending on what section is current. - - Additionally for each section type a keymap *might* be defined, named -‘magit-TYPE-section-map’. That keymap is used as text property keymap -of all text belonging to any section of the respective type. If such a -map does not exist for a certain type, then you can define it yourself, -and it will automatically be used. - - -File: magit.info, Node: Section Options, Prev: Section Types and Values, Up: Sections - -4.2.5 Section Options ---------------------- - -This section describes options that have an effect on more than just a -certain type of sections. As you can see there are not many of those. - - -- User Option: magit-section-show-child-count - - Whether to append the number of children to section headings. This - only affects sections that could benefit from this information. - - -File: magit.info, Node: Transient Commands, Next: Transient Arguments and Buffer Variables, Prev: Sections, Up: Interface Concepts - -4.3 Transient Commands -====================== - -Many Magit commands are implemented as *transient* commands. First the -user invokes a *prefix* command, which causes its *infix* arguments and -*suffix* commands to be displayed in the echo area. The user then -optionally sets some infix arguments and finally invokes one of the -suffix commands. - - This is implemented in the library ‘transient’. Earlier Magit -releases used the package ‘magit-popup’ and even earlier versions -library ‘magit-key-mode’. - - Transient is documented in *note (transient)Top::. - -‘C-c C-c’ (‘magit-dispatch’) - - This transient prefix command binds most of Magit’s other prefix - commands as suffix commands and displays them in a temporary buffer - until one of them is invoked. Invoking such a sub-prefix causes - the suffixes of that command to be bound and displayed instead of - those of ‘magit-dispatch’. - - This command is also, or especially, useful outside Magit buffers, so -you should setup a global binding: - - (global-set-key (kbd "C-x M-g") 'magit-dispatch) - - -File: magit.info, Node: Transient Arguments and Buffer Variables, Next: Completion Confirmation and the Selection, Prev: Transient Commands, Up: Interface Concepts - -4.4 Transient Arguments and Buffer Variables -============================================ - -The infix arguments of many of Magit’s transient prefix commands cease -to have an effect once the ‘git’ command that is called with those -arguments has returned. Commands that create a commit are a good -example for this. If the user changes the arguments, then that only -affects the next invocation of a suffix command. If the same transient -prefix command is later invoked again, then the arguments are initially -reset to the default value. This default value can be set for the -current Emacs session or saved permanently, see *note (transient)Saving -Values::. It is also possible to cycle through previously used sets of -arguments using ‘M-p’ and ‘M-n’, see *note (transient)Using History::. - - However the infix arguments of many other transient commands continue -to have an effect even after the ‘git’ command that was called with -those arguments has returned. The most important commands like this are -those that display a diff or log in a dedicated buffer. Their arguments -obviously continue to have an effect for as long as the respective diff -or log is being displayed. Furthermore the used arguments are stored in -buffer-local variables for future reference. - - For commands in the second group it isn’t always desirable to reset -their arguments to the global value when the transient prefix command is -invoked again. - - As mentioned above, it is possible to cycle through previously used -sets of arguments while a transient popup is visible. That means that -we could always reset the infix arguments to the default because the set -of arguments that is active in the existing buffer is only a few ‘M-p’ -away. Magit can be configured to behave like that, but because I expect -that most users would not find that very convenient, it is not the -default. - - Also note that it is possible to change the diff and log arguments -used in the current buffer (including the status buffer, which contains -both diff and log sections) using the respective "refresh" transient -prefix commands on ‘D’ and ‘L’. (‘d’ and ‘l’ on the other hand are -intended to change *what* diff or log is being displayed. It is -possible to also change *how* the diff or log is being displayed at the -same time, but if you only want to do the latter, then you should use -the refresh variants.) Because these secondary diff and log transient -prefixes are about *changing* the arguments used in the current buffer, -they *always* start out with the set of arguments that are currently in -effect in that buffer. - - Some commands are usually invoked directly even though they can also -be invoked as the suffix of a transient prefix command. Most -prominently ‘magit-show-commit’ is usually invoked by typing ‘RET’ while -point is on a commit in a log, but it can also be invoked from the -‘magit-diff’ transient prefix. - - When such a command is invoked directly, then it is important to -reuse the arguments as specified by the respective buffer-local values, -instead of using the default arguments. Imagine you press ‘RET’ in a -log to display the commit at point in a different buffer and then use -‘D’ to change how the diff is displayed in that buffer. And then you -press ‘RET’ on another commit to show that instead and the diff -arguments are reset to the default. Not cool; so Magit does not do that -by default. - - -- User Option: magit-prefix-use-buffer-arguments - - This option controls whether the infix arguments initially shown in - certain transient prefix commands are based on the arguments that - are currently in effect in the buffer that their suffixes update. - - The ‘magit-diff’ and ‘magit-log’ transient prefix commands are - affected by this option. - - -- User Option: magit-direct-use-buffer-arguments - - This option controls whether certain commands, when invoked - directly (i.e. not as the suffix of a transient prefix command), - use the arguments that are currently active in the buffer that they - are about to update. The alternative is to use the default value - for these arguments, which might change the arguments that are used - in the buffer. - -Valid values for both of the above options are: - - • ‘always’: Always use the set of arguments that is currently active - in the respective buffer, provided that buffer exists of course. - - • ‘selected’ or ‘t’: Use the set of arguments from the respective - buffer, but only if it is displayed in a window of the current - frame. This is the default for both variables. - - • ‘current’: Use the set of arguments from the respective buffer, but - only if it is the current buffer. - - • ‘never’: Never use the set of arguments from the respective buffer. - -I am afraid it gets more complicated still: - - • The global diff and log arguments are set for each support 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 mode does not change the value - for other modes. The history however is shared. - - • 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. - - • 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 commands, instead they use the dedicated - revision and stash buffers. - - At the time you invoke the diff prefix it is unknown to Magit which - of the suffix commands you are going to invoke. While not certain, - more often than not users invoke one of the commands that use the - diff buffer, so the initial infix arguments are those used in that - buffer. However if you invoke one of these commands directly, then - Magit knows that it should use the arguments from the revision - resp. stash buffer. - - • The log prefix also features reflog commands, but these commands do - not use the log arguments. - - • If ‘magit-show-refs’ is invoked from a ‘magit-refs-mode’ buffer, - then it acts as a refresh prefix and therefore unconditionally uses - the buffer’s arguments as initial arguments. If it is invoked - elsewhere with a prefix argument, then it acts as regular prefix - and therefore respects ‘magit-prefix-use-buffer-arguments’. If it - is invoked elsewhere without a prefix argument, then it acts as a - direct command and therefore respects - ‘magit-direct-use-buffer-arguments’. - - -File: magit.info, Node: Completion Confirmation and the Selection, Next: Running Git, Prev: Transient Arguments and Buffer Variables, Up: Interface Concepts - -4.5 Completion, Confirmation and the Selection -============================================== - -* Menu: - -* Action Confirmation:: -* Completion and Confirmation:: -* The Selection:: -* The hunk-internal region:: -* Support for Completion Frameworks:: -* Additional Completion Options:: - - -File: magit.info, Node: Action Confirmation, Next: Completion and Confirmation, Up: Completion Confirmation and the Selection - -4.5.1 Action Confirmation -------------------------- - -By default many actions that could potentially lead to data loss have to -be confirmed. This includes many very common actions, so this can -quickly become annoying. Many of these actions can be undone and if you -have thought about how to undo certain mistakes, then it should be safe -to disable confirmation for the respective actions. - - The option ‘magit-no-confirm’ can be used to tell Magit to perform -certain actions without the user having to confirm them. Note that -while this option can only be used to disable confirmation for a -specific set of actions, the next section explains another way of -telling Magit to ask fewer questions. - - -- User Option: magit-no-confirm - - The value of this option is a list of symbols, representing actions - that do not have to be confirmed by the user before being carried - out. - - By default many potentially dangerous commands ask the user for - confirmation. Each of the below symbols stands for an action - which, when invoked unintentionally or without being fully aware of - the consequences, could lead to tears. In many cases there are - several commands that perform variations of a certain action, so we - don’t use the command names but more generic symbols. - - • Applying changes: - - • ‘discard’ Discarding one or more changes (i.e. hunks or - the complete diff for a file) loses that change, - obviously. - - • ‘reverse’ Reverting one or more changes can usually be - undone by reverting the reversion. - - • ‘stage-all-changes’, ‘unstage-all-changes’ When there are - both staged and unstaged changes, then un-/staging - everything would destroy that distinction. Of course - that also applies when un-/staging a single change, but - then less is lost and one does that so often that having - to confirm every time would be unacceptable. - - • Files: - - • ‘delete’ When a file that isn’t yet tracked by Git is - deleted, then it is completely lost, not just the last - changes. Very dangerous. - - • ‘trash’ Instead of deleting a file it can also be move to - the system trash. Obviously much less dangerous than - deleting it. - - Also see option ‘magit-delete-by-moving-to-trash’. - - • ‘resurrect’ A deleted file can easily be resurrected by - "deleting" the deletion, which is done using the same - command that was used to delete the same file in the - first place. - - • ‘untrack’ Untracking a file can be undone by tracking it - again. - - • ‘rename’ Renaming a file can easily be undone. - - • Sequences: - - • ‘reset-bisect’ Aborting (known to Git as "resetting") a - bisect operation loses all information collected so far. - - • ‘abort-rebase’ Aborting a rebase throws away all already - modified commits, but it’s possible to restore those from - the reflog. - - • ‘abort-merge’ Aborting a merge throws away all conflict - resolutions which have already been carried out by the - user. - - • ‘merge-dirty’ Merging with a dirty worktree can make it - hard to go back to the state before the merge was - initiated. - - • References: - - • ‘delete-unmerged-branch’ Once a branch has been deleted, - it can only be restored using low-level recovery tools - provided by Git. And even then the reflog is gone. The - user always has to confirm the deletion of a branch by - accepting the default choice (or selecting another - branch), but when a branch has not been merged yet, also - make sure the user is aware of that. - - • ‘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 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. - - • ‘drop-stashes’ Dropping a stash is dangerous because Git - stores stashes in the reflog. Once a stash is removed, - there is no going back without using low-level recovery - tools provided by Git. When a single stash is dropped, - then the user always has to confirm by accepting the - default (or selecting another). 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". - - • ‘rebase-published’ Affects commands that perform - interactive rebases. This includes commands from the - commit transient that modify a commit other than "HEAD", - namely the various fixup and squash variants. - - • ‘edit-published’ Affects the commands - ‘magit-edit-line-commit’ and - ‘magit-diff-edit-hunk-commit’. These two commands make - it quite easy to accidentally edit a published commit, so - you should think twice before configuring them not to ask - for confirmation. - - To disable confirmation completely, add all three symbols here - or set ‘magit-published-branches’ to ‘nil’. - - • Various: - - • ‘kill-process’ There seldom is a reason to kill a - process. - - • Global settings: - - Instead of adding all of the above symbols to the value of - this option, you can also set it to the atom ‘t’, which has - the same effect as adding all of the above symbols. Doing - that most certainly is a bad idea, especially because other - symbols might be added in the future. So even if you don’t - want to be asked for confirmation for any of these actions, - you are still better of adding all of the respective symbols - individually. - - When ‘magit-wip-before-change-mode’ is enabled, then the - following actions can be undone fairly easily: ‘discard’, - ‘reverse’, ‘stage-all-changes’, and ‘unstage-all-changes’. If - and only if this mode is enabled, then ‘safe-with-wip’ has the - same effect as adding all of these symbols individually. - - -File: magit.info, Node: Completion and Confirmation, Next: The Selection, Prev: Action Confirmation, Up: Completion Confirmation and the Selection - -4.5.2 Completion and Confirmation ---------------------------------- - -Many Magit commands ask the user to select from a list of possible -things to act on, while offering the most likely choice as the default. -For many of these commands the default is the thing at point, provided -that it actually is a valid thing to act on. For many commands that act -on a branch, the current branch serves as the default if there is no -branch at point. - - These commands combine asking for confirmation and asking for a -target to act on into a single action. The user can confirm the default -target using ‘RET’ or abort using ‘C-g’. This is similar to a -‘y-or-n-p’ prompt, but the keys to confirm or abort differ. - - At the same time the user is also given the opportunity to select -another target, which is useful because for some commands and/or in some -situations you might want to select the action before selecting the -target by moving to it. - - However you might find that for some commands you always want to use -the default target, if any, or even that you want the command to act on -the default without requiring any confirmation at all. The option -‘magit-dwim-selection’ can be used to configure certain commands to that -effect. - - Note that when the region is active then many commands act on the -things that are selected using a mechanism based on the region, in many -cases after asking for confirmation. This region-based mechanism is -called the "selection" and is described in detail in the next section. -When a selection exists that is valid for the invoked command, then that -command never offers to act on something else, and whether it asks for -confirmation is not controlled by this option. - - Also note that Magit asks for confirmation of certain actions that -are not coupled with completion (or the selection). Such dialogs are -also not affected by this option and are described in the previous -section. - - -- User Option: magit-dwim-selection - - This option can be used to tell certain commands to use the thing at -point instead of asking the user to select a candidate to act on, with -or without confirmation. - - The value has the form ‘((COMMAND nil|PROMPT DEFAULT)...)’. - - • COMMAND is the command that should not prompt for a choice. To - have an effect, the command has to use the function - ‘magit-completing-read’ or a utility function which in turn uses - that function. - - • If the command uses ‘magit-completing-read’ multiple times, then - PROMPT can be used to only affect one of these uses. PROMPT, if - non-nil, is a regular expression that is used to match against the - PROMPT argument passed to ‘magit-completing-read’. - - • DEFAULT specifies how to use the default. If it is ‘t’, then the - DEFAULT argument passed to ‘magit-completing-read’ is used without - confirmation. If it is ‘ask’, then the user is given a chance to - abort. DEFAULT can also be ‘nil’, in which case the entry has no - effect. - - -File: magit.info, Node: The Selection, Next: The hunk-internal region, Prev: Completion and Confirmation, Up: Completion Confirmation and the Selection - -4.5.3 The Selection -------------------- - -If the region is active, then many Magit commands act on the things that -are selected using a mechanism based on the region instead of one single -thing. When the region is not active, then these commands act on the -thing at point or read a single thing to act on. This is described in -the previous section — this section only covers how multiple things are -selected, how that is visualized, and how certain commands behave when -that is the case. - - Magit’s mechanism for selecting multiple things, or rather sections -that represent these things, is based on the Emacs region, but the area -that Magit considers to be selected is typically larger than the region -and additional restrictions apply. - - Magit makes a distinction between a region that qualifies as forming -a valid Magit selection and a region that does not. If the region does -not qualify, then it is displayed as it is in other Emacs buffers. If -the region does qualify as a Magit selection, then the selection is -always visualized, while the region itself is only visualized if it -begins and ends on the same line. - - For a region to qualify as a Magit selection, it must begin in the -heading of one section and end in the heading of a sibling section. -Note that if the end of the region is at the very beginning of section -heading (i.e. at the very beginning of a line) then that section is -considered to be *inside* the selection. - - This is not consistent with how the region is normally treated in -Emacs — if the region ends at the beginning of a line, then that line is -outside the region. Due to how Magit visualizes the selection, it -should be obvious that this difference exists. - - Not every command acts on every valid selection. Some commands do -not even consider the location of point, others may act on the section -at point but not support acting on the selection, and even commands that -do support the selection of course only do so if it selects things that -they can act on. - - This is the main reason why the selection must include the section at -point. Even if a selection exists, the invoked command may disregard -it, in which case it may act on the current section only. It is much -safer to only act on the current section but not the other selected -sections than it is to act on the current section *instead* of the -selected sections. The latter would be much more surprising and if the -current section always is part of the selection, then that cannot -happen. - - -- Variable: magit-keep-region-overlay - - This variable controls whether the region is visualized as usual - even when a valid Magit selection or a hunk-internal region exists. - See the doc-string for more information. - - -File: magit.info, Node: The hunk-internal region, Next: Support for Completion Frameworks, Prev: The Selection, Up: Completion Confirmation and the Selection - -4.5.4 The hunk-internal region ------------------------------- - -Somewhat related to the Magit selection described in the previous -section is the hunk-internal region. - - Like the selection, the hunk-internal region is based on the Emacs -region but causes that region to not be visualized as it would in other -Emacs buffers, and includes the line on which the region ends even if it -ends at the very beginning of that line. - - Unlike the selection, which is based on a region that must begin in -the heading of one section and ends in the section of a sibling section, -the hunk-internal region must begin inside the *body* of a hunk section -and end in the body of the *same* section. - - The hunk-internal region is honored by "apply" commands, which can, -among other targets, act on a hunk. If the hunk-internal region is -active, then such commands act only on the marked part of the hunk -instead of on the complete hunk. - - -File: magit.info, Node: Support for Completion Frameworks, Next: Additional Completion Options, Prev: The hunk-internal region, Up: Completion Confirmation and the Selection - -4.5.5 Support for Completion Frameworks ---------------------------------------- - -The built-in option ‘completing-read-function’ specifies the low-level -function used by ‘completing-read’ to ask a user to select from a list -of choices. Its default value is ‘completing-read-default’. -Alternative completion frameworks typically activate themselves by -substituting their own implementation. - - Mostly for historic reasons Magit provides a similar option named -‘magit-completing-read-function’, which only controls the low-level -function used by ‘magit-completing-read’. This option also makes it -possible to use a different completing mechanism for Magit than for the -rest of Emacs, but doing that is not recommend. - - You most likely don’t have to customize the magit-specific option to -use an alternative completion framework. For example, if you enable -‘ivy-mode’, then Magit will respect that, and if you enable ‘helm-mode’, -then you are done too. - - However if you want to use Ido, then ‘ido-mode’ won’t do the trick. -You will also have to install the ‘ido-completing-read+’ package and use -‘magit-ido-completing-read’ as ‘magit-completing-read-function’. - - -- User Option: magit-completing-read-function - - The value of this variable is the low-level function used to - perform completion by code that uses ‘magit-completing-read’ (as - opposed to the built-in ‘completing-read’). - - The default value, ‘magit-builtin-completing-read’, is suitable for - the standard completion mechanism, ‘ivy-mode’, and ‘helm-mode’ at - least. - - The built-in ‘completing-read’ and ‘completing-read-default’ are - *not* suitable to be used here. ‘magit-builtin-completing-read’ - performs some additional work, and any function used in its place - has to do the same. - - -- Function: magit-builtin-completing-read prompt choices &optional - predicate require-match initial-input hist def - - This function performs completion using the built-in - ‘completing-read’ and does some additional magit-specific work. - - -- Function: magit-ido-completing-read prompt choices &optional - predicate require-match initial-input hist def - - This function performs completion using ‘ido-completing-read+’ from - the package by the same name (which you have to explicitly install) - and does some additional magit-specific work. - - We have to use ‘ido-completing-read+’ instead of the - ‘ido-completing-read’ that comes with Ido itself, because the - latter, while intended as a drop-in replacement, cannot serve that - purpose because it violates too many of the implicit conventions. - - -- Function: magit-completing-read prompt choices &optional predicate - require-match initial-input hist def fallback - - This is the function that Magit commands use when they need the - user to select a single thing to act on. The arguments have the - same meaning as for ‘completing-read’, except for FALLBACK, which - is unique to this function and is described below. - - Instead of asking the user to choose from a list of possible - candidates, this function may just return the default specified by - DEF, with or without requiring user confirmation. Whether that is - the case depends on PROMPT, ‘this-command’ and - ‘magit-dwim-selection’. See the documentation of the latter for - more information. - - If it does read a value in the minibuffer, then this function acts - similar to ‘completing-read’, except for the following: - - • COLLECTION must be a list of choices. A function is not - supported. - - • If REQUIRE-MATCH is ‘nil’ and the user exits without a choice, - then ‘nil’ is returned instead of an empty string. - - • If REQUIRE-MATCH is non-nil and the users exits without a - choice, an user-error is raised. - - • FALLBACK specifies a secondary default that is only used if - the primary default DEF is ‘nil’. The secondary default is - not subject to ‘magit-dwim-selection’ — if DEF is ‘nil’ but - FALLBACK is not, then this function always asks the user to - choose a candidate, just as if both defaults were ‘nil’. - - • ": " is appended to PROMPT. - - • PROMPT is modified to end with \" (default DEF|FALLBACK): \" - provided that DEF or FALLBACK is non-nil, that neither - ‘ivy-mode’ nor ‘helm-mode’ is enabled, and that - ‘magit-completing-read-function’ is set to its default value - of ‘magit-builtin-completing-read’. - - -File: magit.info, Node: Additional Completion Options, Prev: Support for Completion Frameworks, Up: Completion Confirmation and the Selection - -4.5.6 Additional Completion Options ------------------------------------ - - -- User Option: magit-list-refs-sortby - - For many commands that read a ref or refs from the user, the value - of this option can be used to control the order of the refs. Valid - values include any key accepted by the ‘--sort’ flag of ‘git - for-each-ref’. By default, refs are sorted alphabetically by their - full name (e.g., "refs/heads/master"). - - -File: magit.info, Node: Running Git, Prev: Completion Confirmation and the Selection, Up: Interface Concepts - -4.6 Running Git -=============== - -* Menu: - -* Viewing Git Output:: -* Git Process Status:: -* Running Git Manually:: -* Git Executable:: -* Global Git Arguments:: - - -File: magit.info, Node: Viewing Git Output, Next: Git Process Status, Up: Running Git - -4.6.1 Viewing Git Output ------------------------- - -Magit runs Git either for side-effects (e.g. when pushing) or to get -some value (e.g. the name of the current branch). - - When Git is run for side-effects, the process output is logged in a -per-repository log buffer, which can be consulted using the -‘magit-process’ command when things don’t go as expected. - - The output/errors for up to ‘magit-process-log-max’ Git commands are -retained. - -‘$’ (‘magit-process’) - - This commands displays the process buffer for the current - repository. - - Inside that buffer, the usual key bindings for navigating and showing -sections are available. There is one additional command. - -‘k’ (‘magit-process-kill’) - - This command kills the process represented by the section at point. - - -- User Option: 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. - - -File: magit.info, Node: Git Process Status, Next: Running Git Manually, Prev: Viewing Git Output, Up: Running Git - -4.6.2 Git Process Status ------------------------- - -When a Git process is running for side-effects, Magit displays an -indicator in the mode line, using the ‘magit-mode-line-process’ face. - - If the Git process exits successfully, the process indicator is -removed from the mode line immediately. - - In the case of a Git error, the process indicator is not removed, but -is instead highlighted with the ‘magit-mode-line-process-error’ face, -and the error details from the process buffer are provided as a tooltip -for mouse users. This error indicator persists in the mode line until -the next magit buffer refresh. - - If you do not wish process errors to be indicated in the mode line, -customize the ‘magit-process-display-mode-line-error’ user option. - - Process errors are additionally indicated at the top of the status -buffer. - - -File: magit.info, Node: Running Git Manually, Next: Git Executable, Prev: Git Process Status, Up: Running Git - -4.6.3 Running Git Manually --------------------------- - -While Magit provides many Emacs commands to interact with Git, it does -not cover everything. In those cases your existing Git knowledge will -come in handy. Magit provides some commands for running arbitrary Git -commands by typing them into the minibuffer, instead of having to switch -to a shell. - -‘!’ (‘magit-run’) - - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - -‘! !’ (‘magit-git-command-topdir’) - - This command reads a command from the user and executes it in the - top-level directory of the current working tree. - - The string "git " is used as initial input when prompting the user - for the command. It can be removed to run another command. - -‘! p’ (‘magit-git-command’) - - This command reads a command from the user and executes it in - ‘default-directory’. With a prefix argument the command is - executed in the top-level directory of the current working tree - instead. - - The string "git " is used as initial input when prompting the user - for the command. It can be removed to run another command. - -‘! s’ (‘magit-shell-command-topdir’) - - This command reads a command from the user and executes it in the - top-level directory of the current working tree. - -‘! S’ (‘magit-shell-command’) - - This command reads a command from the user and executes it in - ‘default-directory’. With a prefix argument the command is - executed in the top-level directory of the current working tree - instead. - - -- User Option: magit-shell-command-verbose-prompt - - Whether the prompt, used by the above commands when reading a shell - command, shows the directory in which it will be run. - - These suffix commands start external gui tools. - -‘! k’ (‘magit-run-gitk’) - - This command runs ‘gitk’ in the current repository. - -‘! a’ (‘magit-run-gitk-all’) - - This command runs ‘gitk --all’ in the current repository. - -‘! b’ (‘magit-run-gitk-branches’) - - This command runs ‘gitk --branches’ in the current repository. - -‘! g’ (‘magit-run-git-gui’) - - This command runs ‘git gui’ in the current repository. - - -File: magit.info, Node: Git Executable, Next: Global Git Arguments, Prev: Running Git Manually, Up: Running Git - -4.6.4 Git Executable --------------------- - -When Magit calls Git, then it may do so using the absolute path to the -‘git’ executable, or using just its name. - - 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 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". - - 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’. - -‘M-x magit-debug-git-executable’ (‘magit-debug-git-executable’) - - This command displays a buffer with information about - ‘magit-git-executable’ and ‘magit-remote-git-executable’. - -‘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. - - -File: magit.info, Node: Global Git Arguments, Prev: Git Executable, Up: Running Git - -4.6.5 Global Git Arguments --------------------------- - - -- User Option: magit-git-global-arguments - - The arguments set here are used every time the git executable is - run as a subprocess. They are placed right after the executable - itself and before the git command - as in ‘git HERE... COMMAND - REST’. For valid arguments see *note (gitman)git::. - - Be careful what you add here, especially if you are using Tramp to - connect to servers with ancient Git versions. Never remove - anything that is part of the default value, unless you really know - what you are doing. And think very hard before adding something; - it will be used every time Magit runs Git for any purpose. - - -File: magit.info, Node: Inspecting, Next: Manipulating, Prev: Interface Concepts, Up: Top - -5 Inspecting -************ - -The functionality provided by Magit can be roughly divided into three -groups: inspecting existing data, manipulating existing data or adding -new data, and transferring data. Of course that is a rather crude -distinction that often falls short, but it’s more useful than no -distinction at all. This section is concerned with inspecting data, the -next two with manipulating and transferring it. Then follows a section -about miscellaneous functionality, which cannot easily be fit into this -distinction. - - Of course other distinctions make sense too, e.g. Git’s distinction -between porcelain and plumbing commands, which for the most part is -equivalent to Emacs’ distinction between interactive commands and -non-interactive functions. All of the sections mentioned before are -mainly concerned with the porcelain – Magit’s plumbing layer is -described later. - -* Menu: - -* Status Buffer:: -* Repository List:: -* Logging:: -* Diffing:: -* Ediffing:: -* References Buffer:: -* Bisecting:: -* Visiting Files and Blobs:: -* Blaming:: - - -File: magit.info, Node: Status Buffer, Next: Repository List, Up: Inspecting - -5.1 Status Buffer -================= - -While other Magit buffers contain e.g. one particular diff or one -particular log, the status buffer contains the diffs for staged and -unstaged changes, logs for unpushed and unpulled commits, lists of -stashes and untracked files, and information related to the current -branch. - - During certain incomplete operations – for example when a merge -resulted in a conflict – additional information is displayed that helps -proceeding with or aborting the operation. - - The command ‘magit-status’ displays the status buffer belonging to -the current repository in another window. This command is used so often -that it should be bound globally. We recommend using ‘C-x g’: - - (global-set-key (kbd "C-x g") 'magit-status) - -‘C-x g’ (‘magit-status’) - - When invoked from within an existing Git repository, then this - command shows the status of that repository in a buffer. - - If the current directory isn’t located within a Git repository, - then this command prompts for an existing repository or an - arbitrary directory, depending on the option - ‘magit-repository-directories’, and the status for the selected - repository is shown instead. - - • If that option specifies any existing repositories, then the - user is asked to select one of them. - - • Otherwise the user is asked to select an arbitrary directory - using regular file-name completion. If the selected directory - is the top-level directory of an existing working tree, then - the status buffer for that is shown. - - • Otherwise the user is offered to initialize the selected - directory as a new repository. After creating the repository - its status buffer is shown. - - These fallback behaviors can also be forced using one or more - prefix arguments: - - • With two prefix arguments (or more precisely a numeric prefix - value of 16 or greater) an arbitrary directory is read, which - is then acted on as described above. The same could be - accomplished using the command ‘magit-init’. - - • With a single prefix argument an existing repository is read - from the user, or if no repository can be found based on the - value of ‘magit-repository-directories’, then the behavior is - the same as with two prefix arguments. - - -- User Option: magit-repository-directories - - List of directories that are Git repositories or contain Git - repositories. - - Each element has the form ‘(DIRECTORY . DEPTH)’. DIRECTORY has to - be a directory or a directory file-name, a string. DEPTH, an - integer, specifies the maximum depth to look for Git repositories. - If it is 0, then only add DIRECTORY itself. - - This option controls which repositories are being listed by - ‘magit-list-repositories’. It also affects ‘magit-status’ (which - see) in potentially surprising ways (see above). - - -- Command: ido-enter-magit-status - - From an Ido prompt used to open a file, instead drop into - ‘magit-status’. This is similar to ‘ido-magic-delete-char’, which, - despite its name, usually causes a Dired buffer to be created. - - To make this command available, use something like: - - (add-hook 'ido-setup-hook - (lambda () - (define-key ido-completion-map - (kbd \"C-x g\") 'ido-enter-magit-status))) - - Starting with Emacs 25.1 the Ido keymaps are defined just once - instead of every time Ido is invoked, so now you can modify it like - pretty much every other keymap: - - (define-key ido-common-completion-map - (kbd \"C-x g\") 'ido-enter-magit-status) - -* Menu: - -* Status Sections:: -* Status Header Sections:: -* Status Module Sections:: -* Status Options:: - - -File: magit.info, Node: Status Sections, Next: Status Header Sections, Up: Status Buffer - -5.1.1 Status Sections ---------------------- - -The contents of status buffers is controlled using the hook -‘magit-status-sections-hook’. See *note Section Hooks:: to learn about -such hooks and how to customize them. - - -- User Option: magit-status-sections-hook - - Hook run to insert sections into a status buffer. - - The first function on that hook by default is -‘magit-insert-status-headers’; it is described in the next section. By -default the following functions are also members of that hook: - - -- Function: magit-insert-merge-log - - Insert section for the on-going merge. Display the heads that are - being merged. If no merge is in progress, do nothing. - - -- Function: magit-insert-rebase-sequence - - Insert section for the on-going rebase sequence. If no such - sequence is in progress, do nothing. - - -- Function: magit-insert-am-sequence - - Insert section for the on-going patch applying sequence. If no - such sequence is in progress, do nothing. - - -- Function: magit-insert-sequencer-sequence - - Insert section for the on-going cherry-pick or revert sequence. If - no such sequence is in progress, do nothing. - - -- Function: magit-insert-bisect-output - - While bisecting, insert section with output from ‘git bisect’. - - -- Function: magit-insert-bisect-rest - - While bisecting, insert section visualizing the bisect state. - - -- Function: magit-insert-bisect-log - - While bisecting, insert section logging bisect progress. - - -- Function: magit-insert-untracked-files - - Maybe insert a list or tree of untracked files. - - Do so depending on the value of ‘status.showUntrackedFiles’. Note - that even if the value is ‘all’, Magit still initially only shows - directories. But the directory sections can then be expanded using - ‘TAB’. - - -- Function: magit-insert-unstaged-changes - - Insert section showing unstaged changes. - - -- Function: magit-insert-staged-changes - - Insert section showing staged changes. - - -- Function: magit-insert-stashes &optional ref heading - - Insert the ‘stashes’ section showing reflog for "refs/stash". If - optional REF is non-nil show reflog for that instead. If optional - HEADING is non-nil use that as section heading instead of - "Stashes:". - - -- Function: magit-insert-unpulled-from-upstream - - Insert section showing commits that haven’t been pulled from the - upstream branch yet. - - -- Function: magit-insert-unpulled-from-pushremote - - Insert section showing commits that haven’t been pulled from the - push-remote branch yet. - - -- Function: magit-insert-unpushed-to-upstream - - Insert section showing commits that haven’t been pushed to the - upstream yet. - - -- Function: magit-insert-unpushed-to-pushremote - - Insert section showing commits that haven’t been pushed to the - push-remote yet. - - The following functions can also be added to the above hook: - - -- Function: magit-insert-tracked-files - - Insert a tree of tracked files. - - -- Function: magit-insert-ignored-files - - Insert a tree of ignored files. Its possible to limit the logs in - the current buffer to a certain directory using ‘D = f - RET g’. If you do that, then that that also affects this command. - - The log filter can be used to limit to multiple files. In that - case this function only respects the first of the files and only if - it is a directory. - - -- Function: magit-insert-skip-worktree-files - - Insert a tree of skip-worktree files. If the first element of - ‘magit-buffer-diff-files’ is a directory, then limit the list to - files below that. The value of that variable can be set using ‘D - -- DIRECTORY RET g’. - - -- Function: magit-insert-assumed-unchanged-files - - Insert a tree of files that are assumed to be unchanged. If the - first element of ‘magit-buffer-diff-files’ is a directory, then - limit the list to files below that. The value of that variable can - be set using ‘D -- DIRECTORY RET g’. - - -- Function: magit-insert-unpulled-or-recent-commits - - Insert section showing unpulled or recent commits. If an upstream - is configured for the current branch and it is ahead of the current - branch, then show the missing commits. Otherwise, show the last - ‘magit-log-section-commit-count’ commits. - - -- Function: magit-insert-recent-commits - - Insert section showing the last ‘magit-log-section-commit-count’ - commits. - - -- User Option: magit-log-section-commit-count - - How many recent commits ‘magit-insert-recent-commits’ and - ‘magit-insert-unpulled-or-recent-commits’ (provided there are no - unpulled commits) show. - - -- Function: magit-insert-unpulled-cherries - - Insert section showing unpulled commits. Like - ‘magit-insert-unpulled-commits’ but prefix each commit that has not - been applied yet (i.e. a commit with a patch-id not shared with - any local commit) with "+", and all others with "-". - - -- Function: magit-insert-unpushed-cherries - - Insert section showing unpushed commits. Like - ‘magit-insert-unpushed-commits’ but prefix each commit which has - not been applied to upstream yet (i.e. a commit with a patch-id - not shared with any upstream commit) with "+" and all others with - "-". - - See *note References Buffer:: for some more section inserters, which -could be used here. - - -File: magit.info, Node: Status Header Sections, Next: Status Module Sections, Prev: Status Sections, Up: Status Buffer - -5.1.2 Status Header Sections ----------------------------- - -The contents of status buffers is controlled using the hook -‘magit-status-sections-hook’ (see *note Status Sections::). - - By default ‘magit-insert-status-headers’ is the first member of that -hook variable. - - -- Function: magit-insert-status-headers - - Insert headers sections appropriate for ‘magit-status-mode’ - buffers. The sections are inserted by running the functions on the - hook ‘magit-status-headers-hook’. - - -- User Option: magit-status-headers-hook - - Hook run to insert headers sections into the status buffer. - - This hook is run by ‘magit-insert-status-headers’, which in turn - has to be a member of ‘magit-status-sections-hook’ to be used at - all. - - By default the following functions are members of the above hook: - - -- Function: magit-insert-error-header - - Insert a header line showing the message about the Git error that - just occurred. - - This function is only aware of the last error that occur when Git - was run for side-effects. If, for example, an error occurs while - generating a diff, then that error won’t be inserted. Refreshing - the status buffer causes this section to disappear again. - - -- Function: magit-insert-diff-filter-header - - Insert a header line showing the effective diff filters. - - -- Function: magit-insert-head-branch-header - - Insert a header line about the current branch or detached ‘HEAD’. - - -- Function: magit-insert-upstream-branch-header - - Insert a header line about the branch that is usually pulled into - the current branch. - - -- Function: magit-insert-push-branch-header - - Insert a header line about the branch that the current branch is - usually pushed to. - - -- Function: magit-insert-tags-header - - Insert a header line about the current and/or next tag, along with - the number of commits between the tag and ‘HEAD’. - - The following functions can also be added to the above hook: - - -- Function: magit-insert-repo-header - - Insert a header line showing the path to the repository top-level. - - -- Function: magit-insert-remote-header - - Insert a header line about the remote of the current branch. - - If no remote is configured for the current branch, then fall back - showing the "origin" remote, or if that does not exist the first - remote in alphabetic order. - - -- Function: magit-insert-user-header - - Insert a header line about the current user. - - -File: magit.info, Node: Status Module Sections, Next: Status Options, Prev: Status Header Sections, Up: Status Buffer - -5.1.3 Status Module Sections ----------------------------- - -The contents of status buffers is controlled using the hook -‘magit-status-sections-hook’ (see *note Status Sections::). - - By default ‘magit-insert-modules’ is _not_ a member of that hook -variable. - - -- Function: magit-insert-modules - - Insert submodule sections. - - Hook ‘magit-module-sections-hook’ controls which module sections - are inserted, and option ‘magit-module-sections-nested’ controls - whether they are wrapped in an additional section. - - -- User Option: magit-module-sections-hook - - Hook run by ‘magit-insert-modules’. - - -- User Option: magit-module-sections-nested - - This option controls whether ‘magit-insert-modules’ wraps inserted - sections in an additional section. - - If this is non-nil, then only a single top-level section is - inserted. If it is nil, then all sections listed in - ‘magit-module-sections-hook’ become top-level sections. - - -- Function: magit-insert-modules-overview - - 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. - - -- Function: magit-insert-modules-unpulled-from-upstream - - Insert sections for modules that haven’t been pulled from the - upstream yet. These sections can be expanded to show the - respective commits. - - -- Function: magit-insert-modules-unpulled-from-pushremote - - Insert sections for modules that haven’t been pulled from the - push-remote yet. These sections can be expanded to show the - respective commits. - - -- Function: magit-insert-modules-unpushed-to-upstream - - Insert sections for modules that haven’t been pushed to the - upstream yet. These sections can be expanded to show the - respective commits. - - -- Function: magit-insert-modules-unpushed-to-pushremote - - Insert sections for modules that haven’t been pushed to the - push-remote yet. These sections can be expanded to show the - respective commits. - - -File: magit.info, Node: Status Options, Prev: Status Module Sections, Up: Status Buffer - -5.1.4 Status Options --------------------- - - -- User Option: magit-status-refresh-hook - - Hook run after a status buffer has been refreshed. - - -- User Option: magit-status-margin - - This option specifies whether the margin is initially shown in - Magit-Status mode buffers and how it is formatted. - - The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. - - • If INIT is non-nil, then the margin is shown initially. - - • STYLE controls how to format the author or committer date. It - can be one of ‘age’ (to show the age of the commit), - ‘age-abbreviated’ (to abbreviate the time unit to a - character), or a string (suitable for ‘format-time-string’) to - show the actual date. Option - ‘magit-log-margin-show-committer-date’ controls which date is - being displayed. - - • WIDTH controls the width of the margin. This exists for - forward compatibility and currently the value should not be - changed. - - • AUTHOR controls whether the name of the author is also shown - by default. - - • AUTHOR-WIDTH has to be an integer. When the name of the - author is shown, then this specifies how much space is used to - do so. - - Also see the proceeding section for more options concerning status -buffers. - - -File: magit.info, Node: Repository List, Next: Logging, Prev: Status Buffer, Up: Inspecting - -5.2 Repository List -=================== - - -- Command: magit-list-repositories - - This command displays a list of repositories in a separate buffer. - - The options ‘magit-repository-directories’ and - ‘magit-repository-directories-depth’ control which repositories are - displayed. - - -- User Option: magit-repolist-columns - - This option controls what columns are displayed by the command - ‘magit-list-repositories’ and how they are displayed. - - Each element has the form ‘(HEADER WIDTH FORMAT PROPS)’. - - HEADER is the string displayed in the header. WIDTH is the width - of the column. FORMAT is a function that is called with one - 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’. - - 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 - - This function inserts the identification of the repository. - Usually this is just its basename. - - -- Function: magit-repolist-column-path - - This function inserts the absolute path of the repository. - - -- Function: magit-repolist-column-version - - This function inserts a description of the repository’s ‘HEAD’ - revision. - - -- Function: magit-repolist-column-branch - - This function inserts the name of the current branch. - - -- Function: magit-repolist-column-upstream - - This function inserts the name of the upstream branch of the - current branch. - - -- Function: magit-repolist-column-branches - - This function inserts the number of branches. - - -- Function: magit-repolist-column-stashes - - This function inserts the number of stashes. - - -- Function: magit-repolist-column-flag - - This function inserts a flag as specified by - ‘magit-repolist-column-flag-alist’. - - By default this indicates whether there are uncommitted changes. - - • ‘N’ if there is at least one untracked file. - - • ‘U’ if there is at least one unstaged file. - - • ‘S’ if there is at least one staged file. - - Only the first one of these that applies is shown. - - -- Function: magit-repolist-column-unpulled-from-upstream - - This function inserts the number of upstream commits not in the - current branch. - - -- Function: magit-repolist-column-unpulled-from-pushremote - - This function inserts the number of commits in the push branch but - not the current branch. - - -- Function: magit-repolist-column-unpushed-to-upstream - - This function inserts the number of commits in the current branch - but not its upstream. - - -- Function: magit-repolist-column-unpushed-to-pushremote - - This function inserts the number of commits in the current branch - but not its push branch. - - -File: magit.info, Node: Logging, Next: Diffing, Prev: Repository List, Up: Inspecting - -5.3 Logging -=========== - -The status buffer contains logs for the unpushed and unpulled commits, -but that obviously isn’t enough. The transient prefix command -‘magit-log’, on ‘l’, features several suffix commands, which show a -specific log in a separate log buffer. - - Like other transient prefix commands, ‘magit-log’ also features -several infix arguments that can be changed before invoking one of the -suffix commands. However, in the case of the log transient, these -arguments may be taken from those currently in use in the current -repository’s log buffer, depending on the value of -‘magit-prefix-use-buffer-arguments’ (see *note Transient Arguments and -Buffer Variables::). - - For information about the various arguments, see *note -(gitman)git-log::. - - The switch ‘++order=VALUE’ is converted to one of -‘--author-date-order’, ‘--date-order’, or ‘--topo-order’ before being -passed to ‘git log’. - - The log transient also features several reflog commands. See *note -Reflog::. - -‘l’ (‘magit-log’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘l l’ (‘magit-log-current’) - - Show log for the current branch. When ‘HEAD’ is detached or with a - prefix argument, show log for one or more revs read from the - minibuffer. - -‘l o’ (‘magit-log-other’) - - Show log for one or more revs read from the minibuffer. The user - can input any revision or revisions separated by a space, or even - ranges, but only branches, tags, and a representation of the commit - at point are available as completion candidates. - -‘l h’ (‘magit-log-head’) - - Show log for ‘HEAD’. - -‘l L’ (‘magit-log-branches’) - - Show log for all local branches and ‘HEAD’. - -‘l b’ (‘magit-log-all-branches’) - - Show log for all local and remote branches and ‘HEAD’. - -‘l a’ (‘magit-log-all’) - - 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 *note Commands for -Buffers Visiting Files::. The command ‘magit-cherry’ also shows a log, -see *note Cherries::. - -* Menu: - -* Refreshing Logs:: -* Log Buffer:: -* Log Margin:: -* Select from Log:: -* Reflog:: -* Cherries:: - - -File: magit.info, Node: Refreshing Logs, Next: Log Buffer, Up: Logging - -5.3.1 Refreshing Logs ---------------------- - -The transient prefix command ‘magit-log-refresh’, on ‘L’, can be used to -change the log arguments used in the current buffer, without changing -which log is shown. This works in dedicated log buffers, but also in -the status buffer. - -‘L’ (‘magit-log-refresh’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘L g’ (‘magit-log-refresh’) - - This suffix command sets the local log arguments for the current - buffer. - -‘L s’ (‘magit-log-set-default-arguments’) - - This suffix command sets the default log arguments for buffers of - the same type as that of the current buffer. Other existing - buffers of the same type are not affected because their local - values have already been initialized. - -‘L w’ (‘magit-log-save-default-arguments’) - - This suffix command sets the default log arguments for buffers of - the same type as that of the current buffer, and saves the value - for future sessions. Other existing buffers of the same type are - not affected because their local values have already been - initialized. - -‘L t’ (‘magit-toggle-margin’) - - Show or hide the margin. - - -File: magit.info, Node: Log Buffer, Next: Log Margin, Prev: Refreshing Logs, Up: Logging - -5.3.2 Log Buffer ----------------- - -‘L’ (‘magit-log-refresh’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - See *note Refreshing Logs::. - -‘q’ (‘magit-log-bury-buffer’) - - Bury the current buffer or the revision buffer in the same frame. - Like ‘magit-mode-bury-buffer’ (which see) but with a negative - prefix argument instead bury the revision buffer, provided it is - displayed in the current frame. - -‘C-c C-b’ (‘magit-go-backward’) - - Move backward in current buffer’s history. - -‘C-c C-f’ (‘magit-go-forward’) - - Move forward in current buffer’s history. - -‘C-c C-n’ (‘magit-log-move-to-parent’) - - Move to a parent of the current commit. By default, this is the - first parent, but a numeric prefix can be used to specify another - parent. - -‘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. - -‘SPC’ (‘magit-diff-show-or-scroll-up’) - - Update the commit or diff buffer for the thing at point. - - Either show the commit or stash at point in the appropriate buffer, - or if that buffer is already being displayed in the current frame - and contains information about that commit or stash, then instead - scroll the buffer up. If there is no commit or stash at point, - then prompt for a commit. - -‘DEL’ (‘magit-diff-show-or-scroll-down’) - - Update the commit or diff buffer for the thing at point. - - Either show the commit or stash at point in the appropriate buffer, - or if that buffer is already being displayed in the current frame - and contains information about that commit or stash, then instead - scroll the buffer down. If there is no commit or stash at point, - then prompt for a commit. - -‘=’ (‘magit-log-toggle-commit-limit’) - - Toggle the number of commits the current log buffer is limited to. - If the number of commits is currently limited, then remove that - limit. Otherwise set it to 256. - -‘+’ (‘magit-log-double-commit-limit’) - - Double the number of commits the current log buffer is limited to. - -‘-’ (‘magit-log-half-commit-limit’) - - Half the number of commits the current log buffer is limited to. - - -- User Option: magit-log-auto-more - - Insert more log entries automatically when moving past the last - entry. Only considered when moving past the last entry with - ‘magit-goto-*-section’ commands. - - -- User Option: magit-log-show-refname-after-summary - - Whether to show the refnames after the commit summaries. This is - useful if you use really long branch names. - - Magit displays references in logs a bit differently from how Git does -it. - - Local branches are blue and remote branches are green. Of course -that depends on the used theme, as do the colors used for other types of -references. The current branch has a box around it, as do remote -branches that are their respective remote’s ‘HEAD’ branch. - - If a local branch and its push-target point at the same commit, then -their names are combined to preserve space and to make that relationship -visible. For example: - - origin/feature - [green][blue-] - - instead of - - feature origin/feature - [blue-] [green-------] - - Also note that while the transient features the ‘--show-signature’ -argument, that won’t actually be used when enabled, because Magit -defaults to use just one line per commit. Instead the commit colorized -to indicate the validity of the signed commit object, using the faces -named ‘magit-signature-*’ (which see). - - For a description of ‘magit-log-margin’ see *note Log Margin::. - - -File: magit.info, Node: Log Margin, Next: Select from Log, Prev: Log Buffer, Up: Logging - -5.3.3 Log Margin ----------------- - -In buffers which show one or more logs, it is possible to show -additional information about each commit in the margin. The options -used to configure the margin are named ‘magit-INFIX-margin’, where INFIX -is the same as in the respective major-mode ‘magit-INFIX-mode’. In -regular log buffers that would be ‘magit-log-margin’. - - -- User Option: magit-log-margin - - This option specifies whether the margin is initially shown in - Magit-Log mode buffers and how it is formatted. - - The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. - - • If INIT is non-nil, then the margin is shown initially. - - • STYLE controls how to format the author or committer date. It - can be one of ‘age’ (to show the age of the commit), - ‘age-abbreviated’ (to abbreviate the time unit to a - character), or a string (suitable for ‘format-time-string’) to - show the actual date. Option - ‘magit-log-margin-show-committer-date’ controls which date is - being displayed. - - • WIDTH controls the width of the margin. This exists for - forward compatibility and currently the value should not be - changed. - - • AUTHOR controls whether the name of the author is also shown - by default. - - • AUTHOR-WIDTH has to be an integer. When the name of the - author is shown, then this specifies how much space is used to - do so. - - You can change the STYLE and AUTHOR-WIDTH of all ‘magit-INFIX-margin’ -options to the same values by customizing ‘magit-log-margin’ *before* -‘magit’ is loaded. If you do that, then the respective values for the -other options will default to what you have set for that variable. -Likewise if you set INIT in ‘magit-log-margin’ to ‘nil’, then that is -used in the default of all other options. But setting it to ‘t’, i.e. -re-enforcing the default for that option, does not carry to other -options. - - -- User Option: magit-log-margin-show-committer-date - - This option specifies whether to show the committer date in the - margin. This option only controls whether the committer date is - displayed instead of the author date. Whether some date is - displayed in the margin and whether the margin is displayed at all - is controlled by other options. - -‘L’ (‘magit-margin-settings’) - - This transient prefix command binds the following suffix commands, - each of which changes the appearance of the margin in some way. - - In some buffers that support the margin, ‘L’ is instead bound to -‘magit-log-refresh’, but that transient features the same commands, and -then some other unrelated commands. - -‘L L’ (‘magit-toggle-margin’) - - This command shows or hides the margin. - -‘L l’ (‘magit-cycle-margin-style’) - - This command cycles the style used for the margin. - -‘L d’ (‘magit-toggle-margin-details’) - - This command shows or hides details in the margin. - - -File: magit.info, Node: Select from Log, Next: Reflog, Prev: Log Margin, Up: Logging - -5.3.4 Select from Log ---------------------- - -When the user has to select a recent commit that is reachable from -‘HEAD’, using regular completion would be inconvenient (because most -humans cannot remember hashes or "HEAD~5", at least not without double -checking). Instead a log buffer is used to select the commit, which has -the advantage that commits are presented in order and with the commit -message. - - Such selection logs are used when selecting the beginning of a rebase -and when selecting the commit to be squashed into. - - In addition to the key bindings available in all log buffers, the -following additional key bindings are available in selection log -buffers: - -‘C-c C-c’ (‘magit-log-select-pick’) - - Select the commit at point and act on it. Call - ‘magit-log-select-pick-function’ with the selected commit as - argument. - -‘C-c C-k’ (‘magit-log-select-quit’) - - Abort selecting a commit, don’t act on any commit. - - -- User Option: magit-log-select-margin - - This option specifies whether the margin is initially shown in - Magit-Log-Select mode buffers and how it is formatted. - - The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. - - • If INIT is non-nil, then the margin is shown initially. - - • STYLE controls how to format the author or committer date. It - can be one of ‘age’ (to show the age of the commit), - ‘age-abbreviated’ (to abbreviate the time unit to a - character), or a string (suitable for ‘format-time-string’) to - show the actual date. Option - ‘magit-log-margin-show-committer-date’ controls which date is - being displayed. - - • WIDTH controls the width of the margin. This exists for - forward compatibility and currently the value should not be - changed. - - • AUTHOR controls whether the name of the author is also shown - by default. - - • AUTHOR-WIDTH has to be an integer. When the name of the - author is shown, then this specifies how much space is used to - do so. - - -File: magit.info, Node: Reflog, Next: Cherries, Prev: Select from Log, Up: Logging - -5.3.5 Reflog ------------- - -Also see *note (gitman)git-reflog::. - - These reflog commands are available from the log transient. See -*note Logging::. - -‘l r’ (‘magit-reflog-current’) - - Display the reflog of the current branch. - -‘l O’ (‘magit-reflog-other’) - - Display the reflog of a branch or another ref. - -‘l H’ (‘magit-reflog-head’) - - Display the ‘HEAD’ reflog. - - -- User Option: magit-reflog-margin - - This option specifies whether the margin is initially shown in - Magit-Reflog mode buffers and how it is formatted. - - The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. - - • If INIT is non-nil, then the margin is shown initially. - - • STYLE controls how to format the author or committer date. It - can be one of ‘age’ (to show the age of the commit), - ‘age-abbreviated’ (to abbreviate the time unit to a - character), or a string (suitable for ‘format-time-string’) to - show the actual date. Option - ‘magit-log-margin-show-committer-date’ controls which date is - being displayed. - - • WIDTH controls the width of the margin. This exists for - forward compatibility and currently the value should not be - changed. - - • AUTHOR controls whether the name of the author is also shown - by default. - - • AUTHOR-WIDTH has to be an integer. When the name of the - author is shown, then this specifies how much space is used to - do so. - - -File: magit.info, Node: Cherries, Prev: Reflog, Up: Logging - -5.3.6 Cherries --------------- - -Cherries are commits that haven’t been applied upstream (yet), and are -usually visualized using a log. Each commit is prefixed with ‘-’ if it -has an equivalent in the upstream and ‘+’ if it does not, i.e. if it is -a cherry. - - The command ‘magit-cherry’ shows cherries for a single branch, but -the references buffer (see *note References Buffer::) can show cherries -for multiple "upstreams" at once. - - Also see *note (gitman)git-reflog::. - -‘Y’ (‘magit-cherry’) - - Show commits that are in a certain branch but that have not been - merged in the upstream branch. - - -- User Option: magit-cherry-margin - - This option specifies whether the margin is initially shown in - Magit-Cherry mode buffers and how it is formatted. - - The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. - - • If INIT is non-nil, then the margin is shown initially. - - • STYLE controls how to format the author or committer date. It - can be one of ‘age’ (to show the age of the commit), - ‘age-abbreviated’ (to abbreviate the time unit to a - character), or a string (suitable for ‘format-time-string’) to - show the actual date. Option - ‘magit-log-margin-show-committer-date’ controls which date is - being displayed. - - • WIDTH controls the width of the margin. This exists for - forward compatibility and currently the value should not be - changed. - - • AUTHOR controls whether the name of the author is also shown - by default. - - • AUTHOR-WIDTH has to be an integer. When the name of the - author is shown, then this specifies how much space is used to - do so. - - -File: magit.info, Node: Diffing, Next: Ediffing, Prev: Logging, Up: Inspecting - -5.4 Diffing -=========== - -The status buffer contains diffs for the staged and unstaged commits, -but that obviously isn’t enough. The transient prefix command -‘magit-diff’, on ‘d’, features several suffix commands, which show a -specific diff in a separate diff buffer. - - Like other transient prefix commands, ‘magit-diff’ also features -several infix arguments that can be changed before invoking one of the -suffix commands. However, in the case of the diff transient, these -arguments may be taken from those currently in use in the current -repository’s diff buffer, depending on the value of -‘magit-prefix-use-buffer-arguments’ (see *note Transient Arguments and -Buffer Variables::). - - Also see *note (gitman)git-diff::. - -‘d’ (‘magit-diff’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘d d’ (‘magit-diff-dwim’) - - Show changes for the thing at point. - -‘d r’ (‘magit-diff-range’) - - Show differences between two commits. - - RANGE should be a range (A..B or A...B) but can also be a single - commit. If one side of the range is omitted, then it defaults to - ‘HEAD’. If just a commit is given, then changes in the working - tree relative to that commit are shown. - - If the region is active, use the revisions on the first and last - line of the region. With a prefix argument, instead of diffing the - revisions, choose a revision to view changes along, starting at the - common ancestor of both revisions (i.e., use a "..." range). - -‘d w’ (‘magit-diff-working-tree’) - - Show changes between the current working tree and the ‘HEAD’ - commit. With a prefix argument show changes between the working - tree and a commit read from the minibuffer. - -‘d s’ (‘magit-diff-staged’) - - Show changes between the index and the ‘HEAD’ commit. With a - prefix argument show changes between the index and a commit read - from the minibuffer. - -‘d u’ (‘magit-diff-unstaged’) - - Show changes between the working tree and the index. - -‘d p’ (‘magit-diff-paths’) - - Show changes between any two files on disk. - - All of the above suffix commands update the repository’s diff buffer. -The diff transient also features two commands which show differences in -another buffer: - -‘d c’ (‘magit-show-commit’) - - Show the commit at point. If there is no commit at point or with a - prefix argument, prompt for a commit. - -‘d t’ (‘magit-stash-show’) - - 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 *note Commands for -Buffers Visiting Files::. - -* Menu: - -* Refreshing Diffs:: -* Commands Available in Diffs:: -* Diff Options:: -* Revision Buffer:: - - -File: magit.info, Node: Refreshing Diffs, Next: Commands Available in Diffs, Up: Diffing - -5.4.1 Refreshing Diffs ----------------------- - -The transient prefix command ‘magit-diff-refresh’, on ‘D’, can be used -to change the diff arguments used in the current buffer, without -changing which diff is shown. This works in dedicated diff buffers, but -also in the status buffer. - -‘D’ (‘magit-diff-refresh’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘D g’ (‘magit-diff-refresh’) - - This suffix command sets the local diff arguments for the current - buffer. - -‘D s’ (‘magit-diff-set-default-arguments’) - - This suffix command sets the default diff arguments for buffers of - the same type as that of the current buffer. Other existing - buffers of the same type are not affected because their local - values have already been initialized. - -‘D w’ (‘magit-diff-save-default-arguments’) - - This suffix command sets the default diff arguments for buffers of - the same type as that of the current buffer, and saves the value - for future sessions. Other existing buffers of the same type are - not affected because their local values have already been - initialized. - -‘D t’ (‘magit-diff-toggle-refine-hunk’) - - This command toggles hunk refinement on or off. - -‘D r’ (‘magit-diff-switch-range-type’) - - This command converts the diff range type from "revA..revB" to - "revB...revA", or vice versa. - -‘D f’ (‘magit-diff-flip-revs’) - - This command swaps revisions in the diff range from "revA..revB" to - "revB..revA", or vice versa. - -‘D F’ (‘magit-diff-toggle-file-filter’) - - This command toggles the file restriction of the diffs in the - current buffer, allowing you to quickly switch between viewing all - the changes in the commit and the restricted subset. As a special - case, when this command is called from a log buffer, it toggles the - file restriction in the repository’s revision buffer, which is - useful when you display a revision from a log buffer that is - restricted to a file or files. - - In addition to the above transient, which allows changing any of the -supported arguments, there also exist some commands that change only a -particular argument. - -‘-’ (‘magit-diff-less-context’) - - This command decreases the context for diff hunks by COUNT lines. - -‘+’ (‘magit-diff-more-context’) - - This command increases the context for diff hunks by COUNT lines. - -‘0’ (‘magit-diff-default-context’) - - This command resets the context for diff hunks to the default - height. - - The following commands quickly change what diff is being displayed -without having to using one of the diff transient. - -‘C-c C-d’ (‘magit-diff-while-committing’) - - While committing, this command shows the changes that are about to - be committed. While amending, invoking the command again toggles - between showing just the new changes or all the changes that will - be committed. - - This binding is available in the diff buffer as well as the commit - message buffer. - -‘C-c C-b’ (‘magit-go-backward’) - - This command moves backward in current buffer’s history. - -‘C-c C-f’ (‘magit-go-forward’) - - This command moves forward in current buffer’s history. - - -File: magit.info, Node: Commands Available in Diffs, Next: Diff Options, Prev: Refreshing Diffs, Up: Diffing - -5.4.2 Commands Available in Diffs ---------------------------------- - -Some commands are only available if point is inside a diff. - - ‘magit-diff-visit-file’ and related commands visit the appropriate -version of the file that the diff at point is about. Likewise -‘magit-diff-visit-worktree-file’ and related commands visit the worktree -version of the file that the diff at point is about. See *note Visiting -Files and Blobs from a Diff:: for more information and the key bindings. - -‘C-c C-t’ (‘magit-diff-trace-definition’) - - This command shows a log for the definition at point. - - -- User Option: magit-log-trace-definition-function - - The function specified by this option is used by - ‘magit-log-trace-definition’ to determine the function at point. - For major-modes that have special needs, you could set the local - value using the mode’s hook. - -‘C-c C-e’ (‘magit-diff-edit-hunk-commit’) - - From a hunk, this command edits the respective commit and visits - the file. - - First it visits the file being modified by the hunk at the correct - location using ‘magit-diff-visit-file’. This actually visits a - blob. When point is on a diff header, not within an individual - hunk, then this visits the blob the first hunk is about. - - Then it invokes ‘magit-edit-line-commit’, which uses an interactive - rebase to make the commit editable, or if that is not possible - because the commit is not reachable from ‘HEAD’ by checking out - that commit directly. This also causes the actual worktree file to - be visited. - - Neither the blob nor the file buffer are killed when finishing the - rebase. If that is undesirable, then it might be better to use - ‘magit-rebase-edit-command’ instead of this command. - -‘j’ (‘magit-jump-to-diffstat-or-diff’) - - This command jumps to the diffstat or diff. When point is on a - file inside the diffstat section, then jump to the respective diff - section. Otherwise, jump to the diffstat section or a child - thereof. - - The next two commands are not specific to Magit-Diff mode (or and -Magit buffer for that matter), but it might be worth pointing out that -they are available here too. - -‘SPC’ (‘scroll-up’) - - This command scrolls text upward. - -‘DEL’ (‘scroll-down’) - - This command scrolls text downward. - - -File: magit.info, Node: Diff Options, Next: Revision Buffer, Prev: Commands Available in Diffs, Up: Diffing - -5.4.3 Diff Options ------------------- - - -- User Option: magit-diff-refine-hunk - - Whether to show word-granularity differences within diff hunks. - - • ‘nil’ Never show fine differences. - - • ‘t’ Show fine differences for the current diff hunk only. - - • ‘all’ Show fine differences for all displayed diff hunks. - - -- User Option: magit-diff-refine-ignore-whitespace - - Whether to ignore whitespace changes in word-granularity - differences. - - -- User Option: magit-diff-adjust-tab-width - - Whether to adjust the width of tabs in diffs. - - Determining the correct width can be expensive if it requires - opening large and/or many files, so the widths are cached in the - variable ‘magit-diff--tab-width-cache’. Set that to nil to - invalidate the cache. - - • ‘nil’ Never adjust tab width. Use ‘tab-width’s value from the - Magit buffer itself instead. - - • ‘t’ If the corresponding file-visiting buffer exits, then use - ‘tab-width’’s value from that buffer. Doing this is cheap, so - this value is used even if a corresponding cache entry exists. - - • ‘always’ If there is no such buffer, then temporarily visit - the file to determine the value. - - • NUMBER Like ‘always’, but don’t visit files larger than NUMBER - bytes. - - -- User Option: magit-diff-paint-whitespace - - Specify where to highlight whitespace errors. - - See ‘magit-diff-highlight-trailing’, - ‘magit-diff-highlight-indentation’. The symbol ‘t’ means in all - diffs, ‘status’ means only in the status buffer, and nil means - nowhere. - - • ‘nil’ Never highlight whitespace errors. - - • ‘t’ Highlight whitespace errors everywhere. - - • ‘uncommitted’ Only highlight whitespace errors in diffs - showing uncommitted changes. For backward compatibility - ‘status’ is treated as a synonym. - - -- User Option: magit-diff-paint-whitespace-lines - - Specify in what kind of lines to highlight whitespace errors. - - • ‘t’ Highlight only in added lines. - - • ‘both’ Highlight in added and removed lines. - - • ‘all’ Highlight in added, removed and context lines. - - -- User Option: magit-diff-highlight-trailing - - Whether to highlight whitespace at the end of a line in diffs. - Used only when ‘magit-diff-paint-whitespace’ is non-nil. - - -- User Option: magit-diff-highlight-indentation - - This option controls whether to highlight the indentation in case - it used the "wrong" indentation style. Indentation is only - highlighted if ‘magit-diff-paint-whitespace’ is also non-nil. - - The value is an alist of the form ‘((REGEXP . INDENT)...)’. The - path to the current repository is matched against each element in - reverse order. Therefore if a REGEXP matches, then earlier - elements are not tried. - - If the used INDENT is ‘tabs’, highlight indentation with tabs. If - INDENT is an integer, highlight indentation with at least that many - spaces. Otherwise, highlight neither. - - -- User Option: magit-diff-hide-trailing-cr-characters - - Whether to hide ^M characters at the end of a line in diffs. - - -- User Option: magit-diff-highlight-hunk-region-functions - - This option specifies the functions used to highlight the - hunk-internal region. - - ‘magit-diff-highlight-hunk-region-dim-outside’ overlays the outside - of the hunk internal selection with a face that causes the added - and removed lines to have the same background color as context - lines. This function should not be removed from the value of this - option. - - ‘magit-diff-highlight-hunk-region-using-overlays’ and - ‘magit-diff-highlight-hunk-region-using-underline’ emphasize the - region by placing delimiting horizontal lines before and after it. - Both of these functions have glitches which cannot be fixed due to - limitations of Emacs’ display engine. For more information see - ff. - - Instead of, or in addition to, using delimiting horizontal lines, - to emphasize the boundaries, you may which to emphasize the text - itself, using ‘magit-diff-highlight-hunk-region-using-face’. - - In terminal frames it’s not possible to draw lines as the overlay - and underline variants normally do, so there they fall back to - calling the face function instead. - - -- User Option: magit-diff-unmarked-lines-keep-foreground - - This option controls whether added and removed lines outside the - hunk-internal region only lose their distinct background color or - 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 *note - (gitman)git-diff::. - - -File: magit.info, Node: Revision Buffer, Prev: Diff Options, Up: Diffing - -5.4.4 Revision Buffer ---------------------- - - -- User Option: magit-revision-insert-related-refs - - Whether to show related branches in revision buffers. - - • ‘nil’ Don’t show any related branches. - - • ‘t’ Show related local branches. - - • ‘all’ Show related local and remote branches. - - • ‘mixed’ Show all containing branches and local merged - branches. - - -- User Option: magit-revision-show-gravatars - - Whether to show gravatar images in revision buffers. - - If ‘nil’, then don’t insert any gravatar images. If ‘t’, then - insert both images. If ‘author’ or ‘committer’, then insert only - the respective image. - - If you have customized the option ‘magit-revision-headers-format’ - and want to insert the images then you might also have to specify - where to do so. In that case the value has to be a cons-cell of - two regular expressions. The car specifies where to insert the - author’s image. The top half of the image is inserted right after - the matched text, the bottom half on the next line in the same - column. The cdr specifies where to insert the committer’s image, - accordingly. Either the car or the cdr may be nil." - - -- User Option: magit-revision-use-hash-sections - - Whether to turn hashes inside the commit message into sections. - - If non-nil, then hashes inside the commit message are turned into - ‘commit’ sections. There is a trade off to be made between - performance and reliability: - - • ‘slow’ calls git for every word to be absolutely sure. - - • ‘quick’ skips words less than seven characters long. - - • ‘quicker’ additionally skips words that don’t contain a - number. - - • ‘quickest’ uses all words that are at least seven characters - long and which contain at least one number as well as at least - one letter. - - If nil, then no hashes are turned into sections, but you can still - visit the commit at point using "RET". - - The diffs shown in the revision buffer may be automatically -restricted to a subset of the changed files. If the revision buffer is -displayed from a log buffer, the revision buffer will share the same -file restriction as that log buffer (also see the command -‘magit-diff-toggle-file-filter’). - - -- User Option: magit-revision-filter-files-on-follow - - Whether showing a commit from a log buffer honors the log’s file - filter when the log arguments include ‘--follow’. - - When this option is nil, displaying a commit from a log ignores the - log’s file filter if the log arguments include ‘--follow’. Doing - so avoids showing an empty diff in revision buffers for commits - before a rename event. In such cases, the ‘--patch’ argument of - the log transient can be used to show the file-restricted diffs - inline. - - Set this option to non-nil to keep the log’s file restriction even - if ‘--follow’ is present in the log arguments. - - If the revision buffer is not displayed from a log buffer, the file -restriction is determined as usual (see *note Transient Arguments and -Buffer Variables::). - - -File: magit.info, Node: Ediffing, Next: References Buffer, Prev: Diffing, Up: Inspecting - -5.5 Ediffing -============ - -This section describes how to enter Ediff from Magit buffers. For -information on how to use Ediff itself, see *note (ediff)Top::. - -‘e’ (‘magit-ediff-dwim’) - - Compare, stage, or resolve using Ediff. - - This command tries to guess what file, and what commit or range the - user wants to compare, stage, or resolve using Ediff. It might - only be able to guess either the file, or range/commit, in which - case the user is asked about the other. It might not always guess - right, in which case the appropriate ‘magit-ediff-*’ command has to - be used explicitly. If it cannot read the user’s mind at all, then - it asks the user for a command to run. - -‘E’ (‘magit-ediff’) - - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - -‘E r’ (‘magit-ediff-compare’) - - Compare two revisions of a file using Ediff. - - If the region is active, use the revisions on the first and last - line of the region. With a prefix argument, instead of diffing the - revisions, choose a revision to view changes along, starting at the - common ancestor of both revisions (i.e., use a "..." range). - -‘E m’ (‘magit-ediff-resolve’) - - Resolve outstanding conflicts in a file using Ediff, defaulting to - the file at point. - - Provided that the value of ‘merge.conflictstyle’ is ‘diff3’, you - can view the file’s merge-base revision using ‘/’ in the Ediff - control buffer. - - In the rare event that you want to manually resolve all conflicts, - including those already resolved by Git, use - ‘ediff-merge-revisions-with-ancestor’. - -‘E s’ (‘magit-ediff-stage’) - - Stage and unstage changes to a file using Ediff, defaulting to the - file at point. - -‘E u’ (‘magit-ediff-show-unstaged’) - - Show unstaged changes to a file using Ediff. - -‘E i’ (‘magit-ediff-show-staged’) - - Show staged changes to a file using Ediff. - -‘E w’ (‘magit-ediff-show-working-tree’) - - Show changes in a file between ‘HEAD’ and working tree using Ediff. - -‘E c’ (‘magit-ediff-show-commit’) - - Show changes to a file introduced by a commit using Ediff. - -‘E z’ (‘magit-ediff-show-stash’) - - Show changes to a file introduced by a stash using Ediff. - - -- User Option: magit-ediff-dwim-show-on-hunks - - This option controls what command ‘magit-ediff-dwim’ calls when - point is on uncommitted hunks. When nil, always run - ‘magit-ediff-stage’. Otherwise, use ‘magit-ediff-show-staged’ and - ‘magit-ediff-show-unstaged’ to show staged and unstaged changes, - respectively. - - -- User Option: magit-ediff-show-stash-with-index - - This option controls whether ‘magit-ediff-show-stash’ includes a - buffer containing the file’s state in the index at the time the - stash was created. This makes it possible to tell which changes in - the stash were staged. - - -- User Option: magit-ediff-quit-hook - - This hook is run after quitting an Ediff session that was created - using a Magit command. The hook functions are run inside the Ediff - control buffer, and should not change the current buffer. - - This is similar to ‘ediff-quit-hook’ but takes the needs of Magit - into account. The regular ‘ediff-quit-hook’ is ignored by Ediff - sessions that were created using a Magit command. - - -File: magit.info, Node: References Buffer, Next: Bisecting, Prev: Ediffing, Up: Inspecting - -5.6 References Buffer -===================== - -‘y’ (‘magit-show-refs’) - - This command lists branches and tags in a dedicated buffer. - - However if this command is invoked again from this buffer or if it - is invoked with a prefix argument, then it acts as a transient - prefix command, which binds the following suffix commands and some - infix arguments. - - All of the following suffix commands list exactly the same branches -and tags. The only difference the optional feature that can be enabled -by changing the value of ‘magit-refs-show-commit-count’ (see below). -These commands specify a different branch or commit against which all -the other references are compared. - -‘y y’ (‘magit-show-refs-head’) - - This command lists branches and tags in a dedicated buffer. Each - reference is being compared with ‘HEAD’. - -‘y c’ (‘magit-show-refs-current’) - - This command lists branches and tags in a dedicated buffer. Each - reference is being compared with the current branch or ‘HEAD’ if it - is detached. - -‘y o’ (‘magit-show-refs-other’) - - This command lists branches and tags in a dedicated buffer. Each - reference is being compared with a branch read from the user. - - -- User Option: magit-refs-show-commit-count - - Whether to show commit counts in Magit-Refs mode buffers. - - • ‘all’ Show counts for branches and tags. - - • ‘branch’ Show counts for branches only. - - • ‘nil’ Never show counts. - - The default is ‘nil’ because anything else can be very expensive. - - -- User Option: magit-refs-pad-commit-counts - - Whether to pad all commit counts on all sides in Magit-Refs mode - buffers. - - If this is nil, then some commit counts are displayed right next to - one of the branches that appear next to the count, without any - space in between. This might look bad if the branch name faces - look too similar to ‘magit-dimmed’. - - If this is non-nil, then spaces are placed on both sides of all - commit counts. - - -- User Option: magit-refs-show-remote-prefix - - Whether to show the remote prefix in lists of remote branches. - - Showing the prefix is redundant because the name of the remote is - already shown in the heading preceding the list of its branches. - - -- User Option: magit-refs-primary-column-width - - Width of the primary column in ‘magit-refs-mode’ buffers. The - primary column is the column that contains the name of the branch - that the current row is about. - - If this is an integer, then the column is that many columns wide. - Otherwise it has to be a cons-cell of two integers. The first - specifies the minimal width, the second the maximal width. In that - case the actual width is determined using the length of the names - of the shown local branches. (Remote branches and tags are not - taken into account when calculating to optimal width.) - - -- User Option: magit-refs-focus-column-width - - Width of the focus column in ‘magit-refs-mode’ buffers. - - The focus column is the first column, which marks one branch - (usually the current branch) as the focused branch using ‘*’ or - ‘@’. For each other reference, this column optionally shows how - many commits it is ahead of the focused branch and ‘<’, or if it - isn’t ahead then the commits it is behind and ‘>’, or if it isn’t - behind either, then a ‘=’. - - This column may also display only ‘*’ or ‘@’ for the focused - branch, in which case this option is ignored. Use ‘L v’ to change - the verbosity of this column. - - -- User Option: magit-refs-margin - - This option specifies whether the margin is initially shown in - Magit-Refs mode buffers and how it is formatted. - - The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. - - • If INIT is non-nil, then the margin is shown initially. - - • STYLE controls how to format the author or committer date. It - can be one of ‘age’ (to show the age of the commit), - ‘age-abbreviated’ (to abbreviate the time unit to a - character), or a string (suitable for ‘format-time-string’) to - show the actual date. Option - ‘magit-log-margin-show-committer-date’ controls which date is - being displayed. - - • WIDTH controls the width of the margin. This exists for - forward compatibility and currently the value should not be - changed. - - • AUTHOR controls whether the name of the author is also shown - by default. - - • AUTHOR-WIDTH has to be an integer. When the name of the - author is shown, then this specifies how much space is used to - do so. - - -- User Option: magit-refs-margin-for-tags - - This option specifies whether to show information about tags in the - margin. This is disabled by default because it is slow if there - are many tags. - - The following variables control how individual refs are displayed. -If you change one of these variables (especially the "%c" part), then -you should also change the others to keep things aligned. The following -%-sequences are supported: - - • ‘%a’ Number of commits this ref has over the one we compare to. - - • ‘%b’ Number of commits the ref we compare to has over this one. - - • ‘%c’ Number of commits this ref has over the one we compare to. - For the ref which all other refs are compared this is instead "@", - if it is the current branch, or "#" otherwise. - - • ‘%C’ For the ref which all other refs are compared this is "@", if - it is the current branch, or "#" otherwise. For all other refs " - ". - - • ‘%h’ Hash of this ref’s tip. - - • ‘%m’ Commit summary of the tip of this ref. - - • ‘%n’ Name of this ref. - - • ‘%u’ Upstream of this local branch. - - • ‘%U’ Upstream of this local branch and additional local vs. - upstream information. - - -- User Option: magit-refs-filter-alist - - The purpose of this option is to forgo displaying certain refs - based on their name. If you want to not display any refs of a - certain type, then you should remove the appropriate function from - ‘magit-refs-sections-hook’ instead. - - This alist controls which tags and branches are omitted from being - displayed in ‘magit-refs-mode’ buffers. If it is ‘nil’, then all - refs are displayed (subject to ‘magit-refs-sections-hook’). - - All keys are tried in order until one matches. Then its value is - used and subsequent elements are ignored. If the value is non-nil, - then the reference is displayed, otherwise it is not. If no - element matches, then the reference is displayed. - - A key can either be a regular expression that the refname has to - match, or a function that takes the refname as only argument and - returns a boolean. A remote branch such as "origin/master" is - displayed as just "master", however for this comparison the former - is used. - -‘RET’ (‘magit-visit-ref’) - - This command visits the reference or revision at point in another - buffer. If there is no revision at point or with a prefix argument - then it prompts for a revision. - - This command behaves just like ‘magit-show-commit’ as described - above, except if point is on a reference in a ‘magit-refs-mode’ - buffer, in which case the behavior may be different, but only if - you have customized the option ‘magit-visit-ref-behavior’. - - -- User Option: magit-visit-ref-behavior - - This option controls how ‘magit-visit-ref’ behaves in - ‘magit-refs-mode’ buffers. - - By default ‘magit-visit-ref’ behaves like ‘magit-show-commit’, in - all buffers, including ‘magit-refs-mode’ buffers. When the type of - the section at point is ‘commit’ then "RET" is bound to - ‘magit-show-commit’, and when the type is either ‘branch’ or ‘tag’ - then it is bound to ‘magit-visit-ref’. - - "RET" is one of Magit’s most essential keys and at least by default - it should behave consistently across all of Magit, especially - because users quickly learn that it does something very harmless; - it shows more information about the thing at point in another - buffer. - - However "RET" used to behave differently in ‘magit-refs-mode’ - buffers, doing surprising things, some of which cannot really be - described as "visit this thing". If you’ve grown accustomed this - behavior, you can restore it by adding one or more of the below - symbols to the value of this option. But keep in mind that by - doing so you don’t only introduce inconsistencies, you also lose - some functionality and might have to resort to ‘M-x - magit-show-commit’ to get it back. - - ‘magit-visit-ref’ looks for these symbols in the order in which - they are described here. If the presence of a symbol applies to - the current situation, then the symbols that follow do not affect - the outcome. - - • ‘focus-on-ref’ - - With a prefix argument update the buffer to show commit counts - and lists of cherry commits relative to the reference at point - instead of relative to the current buffer or ‘HEAD’. - - Instead of adding this symbol, consider pressing "C-u y o - RET". - - • ‘create-branch’ - - If point is on a remote branch, then create a new local branch - with the same name, use the remote branch as its upstream, and - then check out the local branch. - - Instead of adding this symbol, consider pressing "b c RET - RET", like you would do in other buffers. - - • ‘checkout-any’ - - Check out the reference at point. If that reference is a tag - or a remote branch, then this results in a detached ‘HEAD’. - - Instead of adding this symbol, consider pressing "b b RET", - like you would do in other buffers. - - • ‘checkout-branch’ - - Check out the local branch at point. - - Instead of adding this symbol, consider pressing "b b RET", - like you would do in other buffers. - -* Menu: - -* References Sections:: - - -File: magit.info, Node: References Sections, Up: References Buffer - -5.6.1 References Sections -------------------------- - -The contents of references buffers is controlled using the hook -‘magit-refs-sections-hook’. See *note Section Hooks:: to learn about -such hooks and how to customize them. All of the below functions are -members of the default value. Note that it makes much less sense to -customize this hook than it does for the respective hook used for the -status buffer. - - -- User Option: magit-refs-sections-hook - - Hook run to insert sections into a references buffer. - - -- Function: magit-insert-local-branches - - Insert sections showing all local branches. - - -- Function: magit-insert-remote-branches - - Insert sections showing all remote-tracking branches. - - -- Function: magit-insert-tags - - Insert sections showing all tags. - - -File: magit.info, Node: Bisecting, Next: Visiting Files and Blobs, Prev: References Buffer, Up: Inspecting - -5.7 Bisecting -============= - -Also see *note (gitman)git-bisect::. - -‘B’ (‘magit-bisect’) - - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - - When bisecting is not in progress, then the transient features the -following suffix commands. - -‘B B’ (‘magit-bisect-start’) - - 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 known 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. - -‘B s’ (‘magit-bisect-run’) - - Bisect automatically by running commands after each step. - - When bisecting in progress, then the transient instead features the -following suffix commands. - -‘B b’ (‘magit-bisect-bad’) - - Mark the current commit as bad. Use this after you have asserted - that the commit does contain the bug in question. - -‘B g’ (‘magit-bisect-good’) - - Mark the current commit as good. Use this after you have asserted - that the commit does not contain the bug in question. - -‘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. - -‘B k’ (‘magit-bisect-skip’) - - Skip the current commit. Use this if for some reason the current - commit is not a good one to test. This command lets Git choose a - different one. - -‘B r’ (‘magit-bisect-reset’) - - After bisecting, cleanup bisection state and return to original - ‘HEAD’. - - By default the status buffer shows information about the ongoing -bisect session. - - -- User Option: magit-bisect-show-graph - - This option controls whether a graph is displayed for the log of - commits that still have to be bisected. - - -File: magit.info, Node: Visiting Files and Blobs, Next: Blaming, Prev: Bisecting, Up: Inspecting - -5.8 Visiting Files and Blobs -============================ - -Magit provides several commands that visit a file or blob (the version -of a file that is stored in a certain commit). Actually it provides -several *groups* of such commands and the several *variants* within each -group. - -* Menu: - -* General-Purpose Visit Commands:: -* Visiting Files and Blobs from a Diff:: - - -File: magit.info, Node: General-Purpose Visit Commands, Next: Visiting Files and Blobs from a Diff, Up: Visiting Files and Blobs - -5.8.1 General-Purpose Visit Commands ------------------------------------- - -These commands can be used anywhere to open any blob. Currently no keys -are bound to these commands by default, but that is likely to change. - - -- Command: magit-find-file - - This command reads a filename and revision from the user and visits - the respective blob in a buffer. The buffer is displayed in the - selected window. - - -- Command: magit-find-file-other-window - - This command reads a filename and revision from the user and visits - the respective blob in a buffer. The buffer is displayed in - another window. - - -- Command: magit-find-file-other-frame - - This command reads a filename and revision from the user and visits - the respective blob in a buffer. The buffer is displayed in - another frame. - - -File: magit.info, Node: Visiting Files and Blobs from a Diff, Prev: General-Purpose Visit Commands, Up: Visiting Files and Blobs - -5.8.2 Visiting Files and Blobs from a Diff ------------------------------------------- - -These commands can only be used when point is inside a diff. - -‘RET’ (‘magit-diff-visit-file’) - - This command visits the appropriate version of the file that the - diff at point is about. - - This commands visits the worktree version of the appropriate file. - The location of point inside the diff determines which file is - being visited. The visited version depends on what changes the - diff is about. - - • If the diff shows uncommitted changes (i.e. staged or - unstaged changes), then visit the file in the working tree - (i.e. the same "real" file that ‘find-file’ would visit. In - all other cases visit a "blob" (i.e. the version of a file as - stored in some commit). - - • If point is on a removed line, then visit the blob for the - first parent of the commit that removed that line, i.e. the - last commit where that line still exists. - - • If point is on an added or context line, then visit the blob - that adds that line, or if the diff shows from more than a - single commit, then visit the blob from the last of these - commits. - - In the file-visiting buffer this command goes to the line that - corresponds to the line that point is on in the diff. - - The buffer is displayed in the selected window. With a prefix - argument the buffer is displayed in another window instead. - - -- User Option: magit-diff-visit-previous-blob - - This option controls whether ‘magit-diff-visit-file’ may visit the - previous blob. When this is ‘t’ (the default) and point is on a - removed line in a diff for a committed change, then - ‘magit-diff-visit-file’ visits the blob from the last revision - which still had that line. - - Currently this is only supported for committed changes, for staged - and unstaged changes ‘magit-diff-visit-file’ always visits the file - in the working tree. - -‘C-’ (‘magit-diff-visit-file-worktree’) - - This command visits the worktree version of the appropriate file. - The location of point inside the diff determines which file is - being visited. Unlike ‘magit-diff-visit-file’ it always visits the - "real" file in the working tree, i.e the "current version" of the - file. - - In the file-visiting buffer this command goes to the line that - corresponds to the line that point is on in the diff. Lines that - were added or removed in the working tree, the index and other - commits in between are automatically accounted for. - - The buffer is displayed in the selected window. With a prefix - argument the buffer is displayed in another window instead. - - Variants of the above two commands exist that instead visit the file -in another window or in another frame. If you prefer such behavior, -then you may want to change the above key bindings, but note that the -above commands also use another window when invoked with a prefix -argument. - - -- Command: magit-diff-visit-file-other-window - -- Command: magit-diff-visit-file-other-frame - -- Command: magit-diff-visit-worktree-file-other-window - -- Command: magit-diff-visit-worktree-file-other-frame - - -File: magit.info, Node: Blaming, Prev: Visiting Files and Blobs, Up: Inspecting - -5.9 Blaming -=========== - -Also see *note (gitman)git-blame::. - - To start blaming invoke the ‘magit-file-dispatch’ transient prefix -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 have -to enter the blaming sub-transient first. - - The key bindings shown below assume that you enter the dispatch -transient using the default binding. - -‘C-c M-g B’ (‘magit-blame’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - Note that not all of the following suffixes are available at all -times. For example if ‘magit-blame-mode’ is not enabled, then the -command whose purpose is to turn off that mode would not be of any use -and therefore isn’t available. - -‘C-c M-g b’ (‘magit-blame-addition’) -‘C-c M-g B b’ (‘magit-blame-addition’) - - This command augments each line or chunk of lines in the current - file-visiting or blob-visiting buffer with information about what - commits last touched these lines. - - If the buffer visits a revision of that file, then history up to - that revision is considered. Otherwise, the file’s full history is - considered, including uncommitted changes. - - If Magit-Blame mode is already turned on in the current buffer then - blaming is done recursively, by visiting REVISION:FILE (using - ‘magit-find-file’), where REVISION is a parent of the revision that - added the current line or chunk of lines. - -‘C-c M-g r’ (‘magit-blame-removal’) -‘C-c M-g B r’ (‘magit-blame-removal’) - - This command augments each line or chunk of lines in the current - blob-visiting buffer with information about the revision that - removes it. It cannot be used in file-visiting buffers. - - Like ‘magit-blame-addition’, this command can be used recursively. - -‘C-c M-g f’ (‘magit-blame-reverse’) -‘C-c M-g B f’ (‘magit-blame-reverse’) - - This command augments each line or chunk of lines in the current - file-visiting or blob-visiting buffer with information about the - last revision in which a line still existed. - - Like ‘magit-blame-addition’, this command can be used recursively. - -‘C-c M-g e’ (‘magit-blame-echo’) -‘C-c M-g B e’ (‘magit-blame-echo’) - - This command is like ‘magit-blame-addition’ except that it doesn’t - turn on ‘read-only-mode’ and that it initially uses the - visualization style specified by option ‘magit-blame-echo-style’. - - The following key bindings are available when Magit-Blame mode is -enabled and Read-Only mode is not enabled. These commands are also -available in other buffers; here only the behavior is described that is -relevant in file-visiting buffers that are being blamed. - -‘RET’ (‘magit-show-commit’) - - This command shows the commit that last touched the line at point. - -‘SPC’ (‘magit-diff-show-or-scroll-up’) - - This command updates the commit buffer. - - This either shows the commit that last touched the line at point in - the appropriate buffer, or if that buffer is already being - displayed in the current frame and if that buffer contains - information about that commit, then the buffer is scrolled up - instead. - -‘DEL’ (‘magit-diff-show-or-scroll-down’) - - This command updates the commit buffer. - - This either shows the commit that last touched the line at point in - the appropriate buffer, or if that buffer is already being - displayed in the current frame and if that buffer contains - information about that commit, then the buffer is scrolled down - instead. - - The following key bindings are available when both Magit-Blame mode -and Read-Only mode are enabled. - -‘b’ (‘magit-blame’) - - See above. - -‘n’ (‘magit-blame-next-chunk’) - - This command moves to the next chunk. - -‘N’ (‘magit-blame-next-chunk-same-commit’) - - This command moves to the next chunk from the same commit. - -‘p’ (‘magit-blame-previous-chunk’) - - This command moves to the previous chunk. - -‘P’ (‘magit-blame-previous-chunk-same-commit’) - - This command moves to the previous chunk from the same commit. - -‘q’ (‘magit-blame-quit’) - - This command turns off Magit-Blame mode. If the buffer was created - during a recursive blame, then it also kills the buffer. - -‘M-w’ (‘magit-blame-copy-hash’) - - This command saves the hash of the current chunk’s commit to the - kill ring. - - When the region is active, the command saves the region’s content - instead of the hash, like ‘kill-ring-save’ would. - -‘c’ (‘magit-blame-cycle-style’) - - This command changes how blame information is visualized in the - current buffer by cycling through the styles specified using the - option ‘magit-blame-styles’. - - Blaming is also controlled using the following options. - - -- User Option: magit-blame-styles - - This option defines a list of styles used to visualize blame - information. For now see its doc-string to learn more. - - -- User Option: magit-blame-echo-style - - This option specifies the blame visualization style used by the - command ‘magit-blame-echo’. This must be a symbol that is used as - the identifier for one of the styles defined in - ‘magit-blame-styles’. - - -- User Option: magit-blame-time-format - - This option specifies the format string used to display times when - showing blame information. - - -- User Option: magit-blame-read-only - - This option controls whether blaming a buffer also makes - temporarily read-only. - - -- User Option: magit-blame-disable-modes - - This option lists incompatible minor-modes that should be disabled - temporarily when a buffer contains blame information. They are - enabled again when the buffer no longer shows blame information. - - -- User Option: magit-blame-goto-chunk-hook - - This hook is run when moving between chunks. - - -File: magit.info, Node: Manipulating, Next: Transferring, Prev: Inspecting, Up: Top - -6 Manipulating -************** - -* Menu: - -* Creating Repository:: -* Cloning Repository:: -* Staging and Unstaging:: -* Applying:: -* Committing:: -* Branching:: -* Merging:: -* Resolving Conflicts:: -* Rebasing:: -* Cherry Picking:: -* Resetting:: -* Stashing:: - - -File: magit.info, Node: Creating Repository, Next: Cloning Repository, Up: Manipulating - -6.1 Creating Repository -======================= - -‘M-x magit-init’ (‘magit-init’) - - This command initializes a repository and then shows the status - buffer for the new repository. - - If the directory is below an existing repository, then the user has - to confirm that a new one should be created inside. If the - directory is the root of the existing repository, then the user has - to confirm that it should be reinitialized. - - -File: magit.info, Node: Cloning Repository, Next: Staging and Unstaging, Prev: Creating Repository, Up: Manipulating - -6.2 Cloning Repository -====================== - -To clone a remote or local repository use ‘C’, which is bound to the -command ‘magit-clone’. This command either act as a transient prefix -command, which binds several infix arguments and suffix commands, or it -can invoke ‘git clone’ directly, depending on whether a prefix argument -is used and on the value of ‘magit-clone-always-transient’. - - -- User Option: magit-clone-always-transient - - This option controls whether the command ‘magit-clone’ always acts - as a transient prefix command, regardless of whether a prefix - argument is used or not. If ‘t’, then that command always acts as - a transient prefix. If ‘nil’, then a prefix argument has to be - used for it to act as a transient. - -‘C’ (‘magit-clone’) - - This command either acts as a transient prefix command as described - above or does the same thing as ‘transient-clone-regular’ as - described below. - - If it acts as a transient prefix, then it binds the following - suffix commands and several infix arguments. - -‘C C’ (‘magit-clone-regular’) - - This command creates a regular clone of an existing repository. - The repository and the target directory are read from the user. - -‘C s’ (‘magit-clone-shallow’) - - This command creates a shallow clone of an existing repository. - The repository and the target directory are read from the user. By - default the depth of the cloned history is a single commit, but - with a prefix argument the depth is read from the user. - -‘C b’ (‘magit-clone-bare’) - - This command creates a bare clone of an existing repository. The - repository and the target directory are read from the user. - -‘C m’ (‘magit-clone-mirror’) - - This command creates a mirror of an existing repository. The - repository and the target directory are read from the user. - - The following suffixes are disabled by default. See *note -(transient)Enabling and Disabling Suffixes:: for how to enable them. - -‘C d’ (‘magit-clone-shallow-since’) - - This command creates a shallow clone of an existing repository. - Only commits that were committed after a date are cloned, which is - read from the user. The repository and the target directory are - also read from the user. - -‘C e’ (‘magit-clone-shallow-exclude’) - - This command creates a shallow clone of an existing repository. - This reads a branch or tag from the user. Commits that are - reachable from that are not cloned. The repository and the target - directory are also read from the user. - - -- User Option: magit-clone-set-remote-head - - This option controls whether cloning causes the reference - ‘refs/remotes//HEAD’ to be created in the clone. The - default is to delete the reference after running ‘git clone’, which - insists on creating it. This is because the reference has not been - found to be particularly useful as it is not automatically updated - when the ‘HEAD’ of the remote changes. Setting this option to ‘t’ - preserves Git’s default behavior of creating the reference. - - -- User Option: magit-clone-set-remote.pushDefault - - This option controls whether the value of the Git variable - ‘remote.pushDefault’ is set after cloning. - - • If ‘t’, then it is always set without asking. - - • If ‘ask’, then the users are asked every time they clone a - repository. - - • If ‘nil’, then it is never set. - - -- User Option: magit-clone-default-directory - - This option control the default directory name used when reading - the destination for a cloning operation. - - • If ‘nil’ (the default), then the value of ‘default-directory’ - is used. - - • If a directory, then that is used. - - • If a function, then that is called with the remote url as the - only argument and the returned value is used. - - -- User Option: magit-clone-name-alist - - This option maps regular expressions, which match repository names, - to repository urls, making it possible for users to enter short - names instead of urls when cloning repositories. - - Each element has the form ‘(REGEXP HOSTNAME USER)’. When the user - enters a name when a cloning command asks for a name or url, then - that is looked up in this list. The first element whose REGEXP - matches is used. - - The format specified by option ‘magit-clone-url-format’ is used to - turn the name into an url, using HOSTNAME and the repository name. - If the provided name contains a slash, then that is used. - Otherwise if the name omits the owner of the repository, then the - default user specified in the matched entry is used. - - If USER contains a dot, then it is treated as a Git variable and - the value of that is used as the username. Otherwise it is used as - the username itself. - - -- User Option: magit-clone-url-format - - The format specified by this option is used when turning repository - names into urls. ‘%h’ is the hostname and ‘%n’ is the repository - name, including the name of the owner. - - -File: magit.info, Node: Staging and Unstaging, Next: Applying, Prev: Cloning Repository, Up: Manipulating - -6.3 Staging and Unstaging -========================= - -Like Git, Magit can of course stage and unstage complete files. Unlike -Git, it also allows users to gracefully un-/stage individual hunks and -even just part of a hunk. To stage individual hunks and parts of hunks -using Git directly, one has to use the very modal and rather clumsy -interface of a ‘git add --interactive’ session. - - With Magit, on the other hand, one can un-/stage individual hunks by -just moving point into the respective section inside a diff displayed in -the status buffer or a separate diff buffer and typing ‘s’ or ‘u’. To -operate on just parts of a hunk, mark the changes that should be -un-/staged using the region and then press the same key that would be -used to un-/stage. To stage multiple files or hunks at once use a -region that starts inside the heading of such a section and ends inside -the heading of a sibling section of the same type. - - Besides staging and unstaging, Magit also provides several other -"apply variants" that can also operate on a file, multiple files at -once, a hunk, multiple hunks at once, and on parts of a hunk. These -apply variants are described in the next section. - - You can also use Ediff to stage and unstage. See *note Ediffing::. - -‘s’ (‘magit-stage’) - - Add the change at point to the staging area. - - With a prefix argument and an untracked file (or files) at point, - stage the file but not its content. This makes it possible to - stage only a subset of the new file’s changes. - -‘S’ (‘magit-stage-modified’) - - Stage all changes to files modified in the worktree. Stage all new - content of tracked files and remove tracked files that no longer - exist in the working tree from the index also. With a prefix - argument also stage previously untracked (but not ignored) files. - -‘u’ (‘magit-unstage’) - - Remove the change at point from the staging area. - - Only staged changes can be unstaged. But by default this command - performs an action that is somewhat similar to unstaging, when it - is called on a committed change: it reverses the change in the - index but not in the working tree. - -‘U’ (‘magit-unstage-all’) - - Remove all changes from the staging area. - - -- User Option: magit-unstage-committed - - This option controls whether ‘magit-unstage’ "unstages" committed - changes by reversing them in the index but not the working tree. - The alternative is to raise an error. - -‘M-x magit-reverse-in-index’ (‘magit-reverse-in-index’) - - This command reverses the committed change at point in the index - but not the working tree. By default no key is bound directly to - this command, but it is indirectly called when ‘u’ - (‘magit-unstage’) is pressed on a committed change. - - This allows extracting a change from ‘HEAD’, while leaving it in - the working tree, so that it can later be committed using a - separate commit. A typical workflow would be: - - • Optionally make sure that there are no uncommitted changes. - - • Visit the ‘HEAD’ commit and navigate to the change that should - not have been included in that commit. - - • Type ‘u’ (‘magit-unstage’) to reverse it in the index. This - assumes that ‘magit-unstage-committed-changes’ is non-nil. - - • Type ‘c e’ to extend ‘HEAD’ with the staged changes, including - those that were already staged before. - - • Optionally stage the remaining changes using ‘s’ or ‘S’ and - then type ‘c c’ to create a new commit. - -‘M-x magit-reset-index’ (‘magit-reset-index’) - - Reset the index to some commit. The commit is read from the user - and defaults to the commit at point. If there is no commit at - point, then it defaults to ‘HEAD’. - -* Menu: - -* Staging from File-Visiting Buffers:: - - -File: magit.info, Node: Staging from File-Visiting Buffers, Up: Staging and Unstaging - -6.3.1 Staging from File-Visiting Buffers ----------------------------------------- - -Fine-grained un-/staging has to be done from the status or a diff -buffer, but it’s also possible to un-/stage all changes made to the file -visited in the current buffer right from inside that buffer. - -‘M-x magit-stage-file’ (‘magit-stage-file’) - - When invoked inside a file-visiting buffer, then stage all changes - to that file. In a Magit buffer, stage the file at point if any. - Otherwise prompt for a file to be staged. With a prefix argument - always prompt the user for a file, even in a file-visiting buffer - or when there is a file section at point. - -‘M-x magit-unstage-file’ (‘magit-unstage-file’) - - When invoked inside a file-visiting buffer, then unstage all - changes to that file. In a Magit buffer, unstage the file at point - if any. Otherwise prompt for a file to be unstaged. With a prefix - argument always prompt the user for a file, even in a file-visiting - buffer or when there is a file section at point. - - -File: magit.info, Node: Applying, Next: Committing, Prev: Staging and Unstaging, Up: Manipulating - -6.4 Applying -============ - -Magit provides several "apply variants": stage, unstage, discard, -reverse, and "regular apply". At least when operating on a hunk they -are all implemented using ‘git apply’, which is why they are called -"apply variants". - - • Stage. Apply a change from the working tree to the index. The - change also remains in the working tree. - - • Unstage. Remove a change from the index. The change remains in - the working tree. - - • Discard. On a staged change, remove it from the working tree and - the index. On an unstaged change, remove it from the working tree - only. - - • Reverse. Reverse a change in the working tree. Both committed and - staged changes can be reversed. Unstaged changes cannot be - reversed. Discard them instead. - - • Apply. Apply a change to the working tree. Both committed and - staged changes can be applied. Unstaged changes cannot be applied - - as they already have been applied. - - The previous section described the staging and unstaging commands. -What follows are the commands which implement the remaining apply -variants. - -‘a’ (‘magit-apply’) - - Apply the change at point to the working tree. - - With a prefix argument fallback to a 3-way merge. Doing so causes - the change to be applied to the index as well. - -‘k’ (‘magit-discard’) - - Remove the change at point from the working tree. - -‘v’ (‘magit-reverse’) - - Reverse the change at point in the working tree. - - With a prefix argument fallback to a 3-way merge. Doing so causes - the change to be applied to the index as well. - - With a prefix argument all apply variants attempt a 3-way merge when -appropriate (i.e. when ‘git apply’ is used internally). - - -File: magit.info, Node: Committing, Next: Branching, Prev: Applying, Up: Manipulating - -6.5 Committing -============== - -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 -‘.git/COMMIT_EDITMSG’ and then opens that file in an editor. Magit -arranges for that editor to be the Emacsclient. Once the user finishes -the editing session, the Emacsclient exits and Git creates the commit -using the file’s content as message. - -* Menu: - -* Initiating a Commit:: -* Editing Commit Messages:: - - -File: magit.info, Node: Initiating a Commit, Next: Editing Commit Messages, Up: Committing - -6.5.1 Initiating a Commit -------------------------- - -Also see *note (gitman)git-commit::. - -‘c’ (‘magit-commit’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘c c’ (‘magit-commit-create’) - - Create a new commit on ‘HEAD’. With a prefix argument amend to the - commit at ‘HEAD’ instead. - -‘c a’ (‘magit-commit-amend’) - - Amend the last commit. - -‘c e’ (‘magit-commit-extend’) - - Amend the last commit, without editing the message. With a prefix - argument keep the committer date, otherwise change it. The option - ‘magit-commit-extend-override-date’ can be used to inverse the - meaning of the prefix argument. - - Non-interactively respect the optional OVERRIDE-DATE argument and - ignore the option. - -‘c w’ (‘magit-commit-reword’) - - Reword the last commit, ignoring staged changes. With a prefix - argument keep the committer date, otherwise change it. The option - ‘magit-commit-reword-override-date’ can be used to inverse the - meaning of the prefix argument. - - Non-interactively respect the optional OVERRIDE-DATE argument and - ignore the option. - -‘c f’ (‘magit-commit-fixup’) - - Create a fixup commit. - - 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’. - -‘c F’ (‘magit-commit-instant-fixup’) - - Create a fixup commit and instantly rebase. - -‘c s’ (‘magit-commit-squash’) - - Create a squash commit, without editing the squash message. - - 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’. - -‘c S’ (‘magit-commit-instant-squash’) - - Create a squash commit and instantly rebase. - -‘c A’ (‘magit-commit-augment’) - - Create a squash commit, editing the squash message. - - 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’. - - -- User Option: magit-commit-ask-to-stage - - 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. - - -- User Option: magit-commit-reword-override-date - - Whether using ‘magit-commit-reword’ changes the committer date. - - -- User Option: magit-commit-squash-confirm - - Whether the commit targeted by squash and fixup has to be - confirmed. When non-nil then the commit at point (if any) is used - as default choice. Otherwise it has to be confirmed. This option - only affects ‘magit-commit-squash’ and ‘magit-commit-fixup’. The - "instant" variants 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’. - - -File: magit.info, Node: Editing Commit Messages, Prev: Initiating a Commit, Up: Committing - -6.5.2 Editing Commit Messages ------------------------------ - -After initiating a commit as described in the previous section, two new -buffers appear. One shows the changes that are about to be committed, -while the other is used to write the message. - - Commit messages are edited in an edit session - in the background -‘git’ is waiting for the editor, in our case ‘emacsclient’, to save the -commit message in a file (in most cases ‘.git/COMMIT_EDITMSG’) and then -return. If the editor returns with a non-zero exit status then ‘git’ -does not create the commit. So the most important commands are those -for finishing and aborting the commit. - -‘C-c C-c’ (‘with-editor-finish’) - - Finish the current editing session by returning with exit code 0. - Git then creates the commit using the message it finds in the file. - -‘C-c C-k’ (‘with-editor-cancel’) - - Cancel the current editing session by returning with exit code 1. - Git then cancels the commit, but leaves the file untouched. - - In addition to being used by ‘git commit’, messages may also be -stored in a ring that persists until Emacs is closed. By default the -message is stored at the beginning and the end of an edit session -(regardless of whether the session is finished successfully or was -canceled). It is sometimes useful to bring back messages from that -ring. - -‘C-c M-s’ (‘git-commit-save-message’) - - Save the current buffer content to the commit message ring. - -‘M-p’ (‘git-commit-prev-message’) - - Cycle backward through the commit message ring, after saving the - current message to the ring. With a numeric prefix ARG, go back - ARG comments. - -‘M-n’ (‘git-commit-next-message’) - - Cycle forward through the commit message ring, after saving the - current message to the ring. With a numeric prefix ARG, go back - ARG comments. - - By default the diff for the changes that are about to be committed -are automatically shown when invoking the commit. To prevent that, -remove ‘magit-commit-diff’ from ‘server-switch-hook’. - - When amending to an existing commit it may be useful to show either -the changes that are about to be added to that commit or to show those -changes alongside those that have already been committed. - -‘C-c C-d’ (‘magit-diff-while-committing’) - - While committing, show the changes that are about to be committed. - While amending, invoking the command again toggles between showing - just the new changes or all the changes that will be committed. - -* Menu: - -* Using the Revision Stack:: -* Commit Pseudo Headers:: -* Commit Mode and Hooks:: -* Commit Message Conventions:: - - -File: magit.info, Node: Using the Revision Stack, Next: Commit Pseudo Headers, Up: Editing Commit Messages - -Using the Revision Stack -........................ - -‘C-c C-w’ (‘magit-pop-revision-stack’) - - This command inserts a representation of a revision into the - current buffer. It can be used inside buffers used to write commit - messages but also in other buffers such as buffers used to edit - emails or ChangeLog files. - - By default this command pops the revision which was last added to - the ‘magit-revision-stack’ and inserts it into the current buffer - according to ‘magit-pop-revision-stack-format’. Revisions can be - put on the stack using ‘magit-copy-section-value’ and - ‘magit-copy-buffer-revision’. - - If the stack is empty or with a prefix argument it instead reads a - revision in the minibuffer. By using the minibuffer history this - allows selecting an item which was popped earlier or to insert an - arbitrary reference or revision without first pushing it onto the - stack. - - When reading the revision from the minibuffer, then it might not be - possible to guess the correct repository. When this command is - called inside a repository (e.g. while composing a commit - message), then that repository is used. Otherwise (e.g. while - composing an email) then the repository recorded for the top - element of the stack is used (even though we insert another - revision). If not called inside a repository and with an empty - stack, or with two prefix arguments, then read the repository in - the minibuffer too. - - -- User Option: magit-pop-revision-stack-format - - This option controls how the command ‘magit-pop-revision-stack’ - inserts a revision into the current buffer. - - The entries on the stack have the format ‘(HASH TOPLEVEL)’ and this - option has the format ‘(POINT-FORMAT EOB-FORMAT INDEX-REGEXP)’, all - of which may be nil or a string (though either one of EOB-FORMAT or - POINT-FORMAT should be a string, and if INDEX-REGEXP is non-nil, - then the two formats should be too). - - First INDEX-REGEXP is used to find the previously inserted entry, - by searching backward from point. The first submatch must match - the index number. That number is incremented by one, and becomes - the index number of the entry to be inserted. If you don’t want to - number the inserted revisions, then use nil for INDEX-REGEXP. - - If INDEX-REGEXP is non-nil then both POINT-FORMAT and EOB-FORMAT - should contain \"%N\", which is replaced with the number that was - determined in the previous step. - - Both formats, if non-nil and after removing %N, are then expanded - using ‘git show --format=FORMAT ...’ inside TOPLEVEL. - - The expansion of POINT-FORMAT is inserted at point, and the - 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). - - -File: magit.info, Node: Commit Pseudo Headers, Next: Commit Mode and Hooks, Prev: Using the Revision Stack, Up: Editing Commit Messages - -Commit Pseudo Headers -..................... - -Some projects use pseudo headers in commit messages. Magit colorizes -such headers and provides some commands to insert such headers. - - -- User Option: git-commit-known-pseudo-headers - - A list of Git pseudo headers to be highlighted. - -‘C-c C-i’ (‘git-commit-insert-pseudo-header’) - - Insert a commit message pseudo header. - -‘C-c C-a’ (‘git-commit-ack’) - - Insert a header acknowledging that you have looked at the commit. - -‘C-c C-r’ (‘git-commit-review’) - - Insert a header acknowledging that you have reviewed the commit. - -‘C-c C-s’ (‘git-commit-signoff’) - - Insert a header to sign off the commit. - -‘C-c C-t’ (‘git-commit-test’) - - Insert a header acknowledging that you have tested the commit. - -‘C-c C-o’ (‘git-commit-cc’) - - Insert a header mentioning someone who might be interested. - -‘C-c C-p’ (‘git-commit-reported’) - - Insert a header mentioning the person who reported the issue being - fixed by the commit. - -‘C-c M-i’ (‘git-commit-suggested’) - - Insert a header mentioning the person who suggested the change. - - -File: magit.info, Node: Commit Mode and Hooks, Next: Commit Message Conventions, Prev: Commit Pseudo Headers, Up: Editing Commit Messages - -Commit Mode and Hooks -..................... - -‘git-commit-mode’ is a minor mode that is only used to establish certain -key bindings. This makes it possible to use an arbitrary major mode in -buffers used to edit commit messages. It is even possible to use -different major modes in different repositories, which is useful when -different projects impose different commit message conventions. - - -- User Option: git-commit-major-mode - - The value of this option is the major mode used to edit Git commit - messages. - - Because ‘git-commit-mode’ is a minor mode, we don’t use its mode hook -to setup the buffer, except for the key bindings. All other setup -happens in the function ‘git-commit-setup’, which among other things -runs the hook ‘git-commit-setup-hook’. - - -- User Option: git-commit-setup-hook - - Hook run at the end of ‘git-commit-setup’. - -The following functions are suitable for this hook: - - -- Function: git-commit-save-message - - Save the current buffer content to the commit message ring. - - -- Function: git-commit-setup-changelog-support - - After this function is called, ChangeLog entries are treated as - paragraphs. - - -- Function: git-commit-turn-on-auto-fill - - Turn on ‘auto-fill-mode’ and set ‘fill-column’ to the value of - ‘git-commit-fill-column’. - - -- Function: git-commit-turn-on-flyspell - - Turn on Flyspell mode. Also prevent comments from being checked - and finally check current non-comment text. - - -- Function: git-commit-propertize-diff - - Propertize the diff shown inside the commit message buffer. Git - inserts such diffs into the commit message template when the - ‘--verbose’ argument is used. ‘magit-commit’ by default does not - offer that argument because the diff that is shown in a separate - buffer is more useful. But some users disagree, which is why this - function exists. - - -- Function: bug-reference-mode - - Hyperlink bug references in the buffer. - - -- Function: with-editor-usage-message - - Show usage information in the echo area. - - -- User Option: git-commit-setup-hook - - Hook run after the user finished writing a commit message. - - This hook is only run after pressing ‘C-c C-c’ in a buffer used to - edit a commit message. If a commit is created without the user - typing a message into a buffer, then this hook is not run. - - This hook is not run until the new commit has been created. If - doing so takes Git longer than one second, then this hook isn’t run - at all. For certain commands such as ‘magit-rebase-continue’ this - hook is never run because doing so would lead to a race condition. - - This hook is only run if ‘magit’ is available. - - Also see ‘magit-post-commit-hook’. - - -File: magit.info, Node: Commit Message Conventions, Prev: Commit Mode and Hooks, Up: Editing Commit Messages - -Commit Message Conventions -.......................... - -Git-Commit highlights certain violations of commonly accepted commit -message conventions. Certain violations even cause Git-Commit to ask -you to confirm that you really want to do that. This nagging can of -course be turned off, but the result of doing that usually is that -instead of some code it’s now the human who is reviewing your commits -who has to waste some time telling you to fix your commits. - - -- User Option: git-commit-summary-max-length - - The intended maximal length of the summary line of commit messages. - Characters beyond this column are colorized to indicate that this - preference has been violated. - - -- User Option: git-commit-fill-column - - Column beyond which automatic line-wrapping should happen in commit - message buffers. - - -- User Option: git-commit-finish-query-functions - - List of functions called to query before performing commit. - - The commit message buffer is current while the functions are - called. If any of them returns nil, then the commit is not - performed and the buffer is not killed. The user should then fix - the issue and try again. - - The functions are called with one argument. If it is non-nil then - that indicates that the user used a prefix argument to force - finishing the session despite issues. Functions should usually - honor this wish and return non-nil. - - By default the only member is ‘git-commit-check-style-conventions’. - - -- Function: git-commit-check-style-conventions - - This function checks for violations of certain basic style - conventions. For each violation it asks users if they want to - proceed anyway. - - -- User Option: git-commit-style-convention-checks - - This option controls what conventions the function by the same name - tries to enforce. The value is a list of self-explanatory symbols - identifying certain conventions; ‘non-empty-second-line’ and - ‘overlong-summary-line’. - - -File: magit.info, Node: Branching, Next: Merging, Prev: Committing, Up: Manipulating - -6.6 Branching -============= - -* Menu: - -* The Two Remotes:: -* Branch Commands:: -* Branch Git Variables:: -* Auxiliary Branch Commands:: - - -File: magit.info, Node: The Two Remotes, Next: Branch Commands, Up: Branching - -6.6.1 The Two Remotes ---------------------- - -The upstream branch of some local branch is the branch into which the -commits on that local branch should eventually be merged, usually -something like ‘origin/master’. For the ‘master’ branch itself the -upstream branch and the branch it is being pushed to, are usually the -same remote branch. But for a feature branch the upstream branch and -the branch it is being pushed to should differ. - - The commits on feature branches too should _eventually_ end up in a -remote branch such as ‘origin/master’ or ‘origin/maint’. Such a branch -should therefore be used as the upstream. But feature branches -shouldn’t be pushed directly to such branches. Instead a feature branch -‘my-feature’ is usually pushed to ‘my-fork/my-feature’ or if you are a -contributor ‘origin/my-feature’. After the new feature has been -reviewed, the maintainer merges the feature into ‘master’. And finally -‘master’ (not ‘my-feature’ itself) is pushed to ‘origin/master’. - - But new features seldom are perfect on the first try, and so feature -branches usually have to be reviewed, improved, and re-pushed several -times. Pushing should therefore be easy to do, and for that reason many -Git users have concluded that it is best to use the remote branch to -which the local feature branch is being pushed as its upstream. - - But luckily Git has long ago gained support for a push-remote which -can be configured separately from the upstream branch, using the -variables ‘branch..pushRemote’ and ‘remote.pushDefault’. So we no -longer have to choose which of the two remotes should be used as "the -remote". - - Each of the fetching, pulling, and pushing transient commands -features three suffix commands that act on the current branch and some -other branch. Of these, ‘p’ is bound to a command which acts on the -push-remote, ‘u’ is bound to a command which acts on the upstream, and -‘e’ is bound to a command which acts on any other branch. The status -buffer shows unpushed and unpulled commits for both the push-remote and -the upstream. - - It’s fairly simple to configure these two remotes. The values of all -the variables that are related to fetching, pulling, and pushing (as -well as some other branch-related variables) can be inspected and -changed using the command ‘magit-branch-configure’, which is available -from many transient prefix commands that deal with branches. It is also -possible to set the push-remote or upstream while pushing (see *note -Pushing::). - - -File: magit.info, Node: Branch Commands, Next: Branch Git Variables, Prev: The Two Remotes, Up: Branching - -6.6.2 Branch Commands ---------------------- - -The transient prefix command ‘magit-branch’ is used to create and -checkout branches, and to make changes to existing branches. It is not -used to fetch, pull, merge, rebase, or push branches, i.e. this command -deals with branches themselves, not with the commits reachable from -them. Those features are available from separate transient command. - -‘b’ (‘magit-branch’) - - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - - By default it also binds and displays the values of some - branch-related Git variables and allows changing their values. - - -- User Option: magit-branch-direct-configure - - This option controls whether the transient command ‘magit-branch’ - can 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. - -‘b C’ (‘magit-branch-configure’) -‘f C’ (‘magit-branch-configure’) -‘F C’ (‘magit-branch-configure’) -‘P C’ (‘magit-branch-configure’) - - This transient prefix command binds commands that set the value of - branch-related variables and displays them in a temporary buffer - until the transient is exited. - - With a prefix argument, this command always prompts for a branch. - - Without a prefix argument this depends on whether it was invoked as - a suffix of ‘magit-branch’ and on the - ‘magit-branch-direct-configure’ option. If ‘magit-branch’ already - displays the variables for the current branch, then it isn’t useful - to invoke another transient that displays them for the same branch. - In that case this command prompts for a branch. - - The variables are described in *note Branch Git Variables::. - -‘b b’ (‘magit-checkout’) - - Checkout a revision read in the minibuffer and defaulting to the - branch or arbitrary revision at point. If the 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. - -‘b n’ (‘magit-branch-create’) - - Create a new branch. The user is asked for a branch or arbitrary - revision to use as the starting point of the new branch. When a - branch name is provided, then that becomes the upstream branch of - the new branch. The name of the new branch is also read in the - minibuffer. - - Also see option ‘magit-branch-prefer-remote-upstream’. - -‘b c’ (‘magit-branch-and-checkout’) - - This command creates a new branch like ‘magit-branch-create’, but - then also checks it out. - - Also see option ‘magit-branch-prefer-remote-upstream’. - -‘b l’ (‘magit-branch-checkout’) - - This command checks out an existing or new local branch. It reads - a branch name from the user offering all local branches and a - subset of remote branches as candidates. Remote branches for which - a local branch by the same name exists are omitted from the list of - candidates. The user can also enter a completely new branch name. - - • If the user selects an existing local branch, then that is - checked out. - - • If the user selects a remote branch, then it creates and - checks out a new local branch with the same name, and - configures the selected remote branch as the push target. - - • If the user enters a new branch name, then it creates and - checks that out, after also reading the starting-point from - the user. - - In the latter two cases the upstream is also set. Whether it is - set to the chosen starting point or something else depends on the - value of ‘magit-branch-adjust-remote-upstream-alist’. - -‘b s’ (‘magit-branch-spinoff’) - - This command creates and checks out a new branch starting at and - tracking the current branch. That branch in turn is reset to the - last commit it shares with its upstream. If the current branch has - no upstream or no unpushed commits, then the new branch is created - anyway and the previously current branch is not touched. - - This is useful to create a feature branch after work has already - began on the old branch (likely but not necessarily "master"). - - If the current branch is a member of the value of option - ‘magit-branch-prefer-remote-upstream’ (which see), then the current - branch will be used as the starting point as usual, but the - upstream of the starting-point may be used as the upstream of the - new branch, instead of the starting-point itself. - - If optional FROM is non-nil, then the source branch is reset to - ‘FROM~’, instead of to the last commit it shares with its upstream. - Interactively, FROM is only ever non-nil, if the region selects - some commits, and among those commits, FROM is the commit that is - the fewest commits ahead of the source branch. - - The commit at the other end of the selection actually does not - matter, all commits between FROM and ‘HEAD’ are moved to the new - branch. If FROM is not reachable from ‘HEAD’ or is reachable from - the source branch’s upstream, then an error is raised. - -‘b S’ (‘magit-branch-spinout’) - - This command behaves like ‘magit-branch-spinoff’, except that it - does not change the current branch. If there are any uncommitted - changes, then it behaves exactly like ‘magit-branch-spinoff’. - -‘b x’ (‘magit-branch-reset’) - - This command resets a branch, defaulting to the branch at point, to - the tip of another branch or any other commit. - - When the branch being reset is the current branch, then a hard - reset is performed. If there are any uncommitted changes, then the - user has to confirm the reset because those changes would be lost. - - This is useful when you have started work on a feature branch but - realize it’s all crap and want to start over. - - When resetting to another branch and a prefix argument is used, - then the target branch is set as the upstream of the branch that is - being reset. - -‘b k’ (‘magit-branch-delete’) - - Delete one or multiple branches. If the region marks multiple - branches, then offer to delete those. Otherwise, prompt for a - single branch to be deleted, defaulting to the branch at point. - -‘b r’ (‘magit-branch-rename’) - - Rename a branch. The branch and the new name are read in the - minibuffer. With prefix argument the branch is renamed even if - that name conflicts with an existing branch. - - -- 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 ‘t’, - and I recommend you leave it at that. - - -- User Option: magit-branch-prefer-remote-upstream - - This option specifies whether remote upstreams are favored over - local upstreams when creating new branches. - - When a new branch is created, then the branch, commit, or stash at - point is suggested as the starting point of the new branch, or if - there is no such revision at point the current branch. In either - case the user may choose another starting point. - - If the chosen starting point is a branch, then it may also be set - as the upstream of the new branch, depending on the value of the - Git variable ‘branch.autoSetupMerge’. By default this is done for - remote branches, but not for local branches. - - You might prefer to always use some remote branch as upstream. If - the chosen starting point is (1) a local branch, (2) whose name - matches a member of the value of this option, (3) the upstream of - that local branch is a remote branch with the same name, and (4) - that remote branch can be fast-forwarded to the local branch, then - the chosen branch is used as starting point, but its own upstream - is used as the upstream of the new branch. - - Members of this option’s value are treated as branch names that - have to match exactly unless they contain a character that makes - them invalid as a branch name. Recommended characters to use to - trigger interpretation as a regexp are "*" and "^". Some other - characters which you might expect to be invalid, actually are not, - e.g. ".+$" are all perfectly valid. More precisely, if ‘git - check-ref-format --branch STRING’ exits with a non-zero status, - then treat STRING as a regexp. - - Assuming the chosen branch matches these conditions you would end - up with with e.g.: - - feature --upstream--> origin/master - - instead of - - feature --upstream--> master --upstream--> origin/master - - Which you prefer is a matter of personal preference. If you do - prefer the former, then you should add branches such as ‘master’, - ‘next’, and ‘maint’ to the value of this options. - - -- User Option: magit-branch-adjust-remote-upstream-alist - - The value of this option is an alist of branches to be used as the - upstream when branching a remote branch. - - When creating a local branch from an ephemeral branch located on a - remote, e.g. a feature or hotfix branch, then that remote branch - should usually not be used as the upstream branch, since the - push-remote already allows accessing it and having both the - upstream and the push-remote reference the same related branch - would be wasteful. Instead a branch like "maint" or "master" - should be used as the upstream. - - 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. - - UPSTREAM is the branch to be used as the upstream for branches - specified by RULE. It can be a local or a remote branch. - - RULE can either be a regular expression, matching branches whose - upstream should be the one specified by UPSTREAM. Or it can be a - list of the only branches that should *not* use UPSTREAM; all other - branches will. Matching is done after stripping the remote part of - the name of the branch that is being branched from. - - 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"))) - - Or if the names of all your ephemeral branches contain a slash, at - least in some repositories, then a good value could be: - - (("origin/master" . "/")) - - Of course you can also fine-tune: - - (("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"))) - - -- Command: magit-branch-orphan - - This command creates and checks out a new orphan branch with - contents from a given revision. - - -- Command: magit-branch-or-checkout - - This command is a hybrid between ‘magit-checkout’ and - ‘magit-branch-and-checkout’ and is intended as a replacement for - the former in ‘magit-branch’. - - It first asks the user for an existing branch or revision. If the - user input actually can be resolved as a branch or revision, then - it checks that out, just like ‘magit-checkout’ would. - - Otherwise it creates and checks out a new branch using the input as - its name. Before doing so it reads the starting-point for the new - branch. This is similar to what ‘magit-branch-and-checkout’ does. - - To use this command instead of ‘magit-checkout’ add this to your - init file: - - (transient-replace-suffix 'magit-branch 'magit-checkout - '("b" "dwim" magit-branch-or-checkout)) - - -File: magit.info, Node: Branch Git Variables, Next: Auxiliary Branch Commands, Prev: Branch Commands, Up: Branching - -6.6.3 Branch Git Variables --------------------------- - -These variables can be set from the transient prefix command -‘magit-branch-configure’. By default they can also be set from -‘magit-branch’. See *note Branch Commands::. - - -- Variable: branch.NAME.merge - - Together with ‘branch.NAME.remote’ this variable defines the - upstream branch of the local branch named NAME. The value of this - variable is the full reference of the upstream _branch_. - - -- Variable: branch.NAME.remote - - Together with ‘branch.NAME.merge’ this variable defines the - upstream branch of the local branch named NAME. The value of this - variable is the name of the upstream _remote_. - - -- Variable: branch.NAME.rebase - - This variable controls whether pulling into the branch named NAME - is done by rebasing or by merging the fetched branch. - - • When ‘true’ then pulling is done by rebasing. - - • When ‘false’ then pulling is done by merging. - - • When undefined then the value of ‘pull.rebase’ is used. The - default of that variable is ‘false’. - - -- Variable: branch.NAME.pushRemote - - This variable specifies the remote that the branch named NAME is - usually pushed to. The value has to be the name of an existing - remote. - - It is not possible to specify the name of _branch_ to push the - local branch to. The name of the remote branch is always the same - as the name of the local branch. - - If this variable is undefined but ‘remote.pushDefault’ is defined, - then the value of the latter is used. By default - ‘remote.pushDefault’ is undefined. - - -- Variable: branch.NAME.description - - This variable can be used to describe the branch named NAME. That - description is used e.g. when turning the branch into a series of - patches. - - The following variables specify defaults which are used if the above -branch-specific variables are not set. - - -- Variable: pull.rebase - - This variable specifies whether pulling is done by rebasing or by - merging. It can be overwritten using ‘branch.NAME.rebase’. - - • When ‘true’ then pulling is done by rebasing. - - • When ‘false’ (the default) then pulling is done by merging. - - Since it is never a good idea to merge the upstream branch into a - feature or hotfix branch and most branches are such branches, you - should consider setting this to ‘true’, and ‘branch.master.rebase’ - to ‘false’. - - -- Variable: remote.pushDefault - - This variable specifies what remote the local branches are usually - pushed to. This can be overwritten per branch using - ‘branch.NAME.pushRemote’. - - The following variables are used during the creation of a branch and -control whether the various branch-specific variables are automatically -set at this time. - - -- Variable: branch.autoSetupMerge - - This variable specifies under what circumstances creating a branch - NAME should result in the variables ‘branch.NAME.merge’ and - ‘branch.NAME.remote’ being set according to the starting point used - to create the branch. If the starting point isn’t a branch, then - these variables are never set. - - • When ‘always’ then the variables are set regardless of whether - the starting point is a local or a remote branch. - - • When ‘true’ (the default) then the variables are set when the - starting point is a remote branch, but not when it is a local - branch. - - • When ‘false’ then the variables are never set. - - -- Variable: branch.autoSetupRebase - - This variable specifies whether creating a branch NAME should - result in the variable ‘branch.NAME.rebase’ being set to ‘true’. - - • When ‘always’ then the variable is set regardless of whether - the starting point is a local or a remote branch. - - • When ‘local’ then the variable are set when the starting point - is a local branch, but not when it is a remote branch. - - • When ‘remote’ then the variable are set when the starting - point is a remote branch, but not when it is a local branch. - - • When ‘never’ (the default) then the variable is never set. - - Note that the respective commands always change the repository-local -values. If you want to change the global value, which is used when the -local value is undefined, then you have to do so on the command line, -e.g.: - - git config --global remote.autoSetupMerge always - - For more information about these variables you should also see - - *note (gitman)git-config::. Also see *note (gitman)git-branch::. , -*note (gitman)git-checkout::. and *note Pushing::. - - -- User Option: magit-prefer-remote-upstream - - This option controls whether commands that read a branch from the - user and then set it as the upstream branch, offer a local or a - remote branch as default completion candidate, when they have the - choice. - - This affects all commands that use ‘magit-read-upstream-branch’ or - ‘magit-read-starting-point’, which includes all commands that - change the upstream and many which create new branches. - - -File: magit.info, Node: Auxiliary Branch Commands, Prev: Branch Git Variables, Up: Branching - -6.6.4 Auxiliary Branch Commands -------------------------------- - -These commands are not available from the transient ‘magit-branch’ by -default. - - -- Command: magit-branch-shelve - - This command shelves a branch. This is done by deleting the - branch, and creating a new reference "refs/shelved/BRANCH-NAME" - pointing at the same commit as the branch pointed at. If the - deleted branch had a reflog, then that is preserved as the reflog - of the new reference. - - This is useful if you want to move a branch out of sight, but are - not ready to completely discard it yet. - - -- Command: magit-branch-unshelve - - This command unshelves a branch that was previously shelved using - ‘magit-branch-shelve’. This is done by deleting the reference - "refs/shelved/BRANCH-NAME" and creating a branch "BRANCH-NAME" - pointing at the same commit as the deleted reference pointed at. - If the deleted reference had a reflog, then that is restored as the - reflog of the branch. - - -File: magit.info, Node: Merging, Next: Resolving Conflicts, Prev: Branching, Up: Manipulating - -6.7 Merging -=========== - -Also see *note (gitman)git-merge::. For information on how to resolve -merge conflicts see the next section. - -‘m’ (‘magit-merge’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - When no merge is in progress, then the transient features the -following suffix commands. - -‘m m’ (‘magit-merge-plain’) - - This command merges another branch or an arbitrary revision into - the current branch. The branch or revision to be merged is read in - the minibuffer and defaults to the branch at point. - - Unless there are conflicts or a prefix argument is used, then the - resulting merge commit uses a generic commit message, and the user - does not get a chance to inspect or change it before the commit is - created. With a prefix argument this does not actually create the - merge commit, which makes it possible to inspect how conflicts were - resolved and to adjust the commit message. - -‘m e’ (‘magit-merge-editmsg’) - - This command merges another branch or an arbitrary revision into - the current branch and opens a commit message buffer, so that the - user can make adjustments. The commit is not actually created - until the user finishes with ‘C-c C-c’. - -‘m n’ (‘magit-merge-nocommit’) - - This command merges another branch or an arbitrary revision into - the current branch, but does not actually create the merge commit. - The user can then further adjust the merge, even when automatic - conflict resolution succeeded and/or adjust the commit message. - -‘m a’ (‘magit-merge-absorb’) - - This command merges another local branch into the current branch - and then removes the former. - - Before the source branch is merged, it is first force pushed to its - push-remote, provided the respective remote branch already exists. - This ensures that the respective pull-request (if any) won’t get - stuck on some obsolete version of the commits that are being - merged. Finally, if ‘magit-branch-pull-request’ was used to create - the merged branch, then the respective remote branch is also - removed. - -‘m i’ (‘magit-merge-into’) - - This command merges the current branch into another local branch - and then removes the former. The latter becomes the new current - branch. - - Before the source branch is merged, it is first force pushed to its - push-remote, provided the respective remote branch already exists. - This ensures that the respective pull-request (if any) won’t get - stuck on some obsolete version of the commits that are being - merged. Finally, if ‘magit-branch-pull-request’ was used to create - the merged branch, then the respective remote branch is also - removed. - -‘m s’ (‘magit-merge-squash’) - - This command squashes the changes introduced by another branch or - an arbitrary revision into the current branch. This only applies - the changes made by the squashed commits. No information is - preserved that would allow creating an actual merge commit. - Instead of this command you should probably use a command from the - apply transient. - -‘m p’ (‘magit-merge-preview’) - - This command shows a preview of merging another branch or an - arbitrary revision into the current branch. - - When a merge is in progress, then the transient instead features the -following suffix commands. - -‘m m’ (‘magit-merge’) - - After the user resolved conflicts, this command proceeds with the - merge. If some conflicts weren’t resolved, then this command - fails. - -‘m a’ (‘magit-merge-abort’) - - This command aborts the current merge operation. - - -File: magit.info, Node: Resolving Conflicts, Next: Rebasing, Prev: Merging, Up: Manipulating - -6.8 Resolving Conflicts -======================= - -When merging branches (or otherwise combining or changing history) -conflicts can occur. If you edited two completely different parts of -the same file in two branches and then merge one of these branches into -the other, then Git can resolve that on its own, but if you edit the -same area of a file, then a human is required to decide how the two -versions, or "sides of the conflict", are to be combined into one. - - Here we can only provide a brief introduction to the subject and -point you toward some tools that can help. If you are new to this, then -please also consult Git’s own documentation as well as other resources. - - If a file has conflicts and Git cannot resolve them by itself, then -it puts both versions into the affected file along with special markers -whose purpose is to denote the boundaries of the unresolved part of the -file and between the different versions. These boundary lines begin -with the strings consisting of six times the same character, one of ‘<’, -‘|’, ‘=’ and ‘>’ and are followed by information about the source of the -respective versions, e.g.: - - <<<<<<< HEAD - Take the blue pill. - ======= - Take the red pill. - >>>>>>> feature - - In this case you have chosen to take the red pill on one branch and -on another you picked the blue pill. Now that you are merging these two -diverging branches, Git cannot possibly know which pill you want to -take. - - To resolve that conflict you have to create a version of the affected -area of the file by keeping only one of the sides, possibly by editing -it in order to bring in the changes from the other side, remove the -other versions as well as the markers, and then stage the result. A -possible resolution might be: - - Take both pills. - - Often it is useful to see not only the two sides of the conflict but -also the "original" version from before the same area of the file was -modified twice on different branches. Instruct Git to insert that -version as well by running this command once: - - git config --global merge.conflictStyle diff3 - - The above conflict might then have looked like this: - - <<<<<<< HEAD - Take the blue pill. - ||||||| merged common ancestors - Take either the blue or the red pill, but not both. - ======= - Take the red pill. - >>>>>>> feature - - If that were the case, then the above conflict resolution would not -have been correct, which demonstrates why seeing the original version -alongside the conflicting versions can be useful. - - You can perform the conflict resolution completely by hand, but Emacs -also provides some packages that help in the process: Smerge, Ediff -(*note (ediff)Top::), and Emerge (*note (emacs)Emerge::). Magit does -not provide its own tools for conflict resolution, but it does make -using Smerge and Ediff more convenient. (Ediff supersedes Emerge, so -you probably don’t want to use the latter anyway.) - - In the Magit status buffer, files with unresolved conflicts are -listed in the "Unstaged changes" and/or "Staged changes" sections. They -are prefixed with the word "unmerged", which in this context essentially -is a synonym for "unresolved". - - Pressing ‘RET’ while point is on such a file section shows a buffer -visiting that file, turns on ‘smerge-mode’ in that buffer, and places -point inside the first area with conflicts. You should then resolve -that conflict using regular edit commands and/or Smerge commands. - - Unfortunately Smerge does not have a manual, but you can get a list -of commands and binding ‘C-c ^ C-h’ and press ‘RET’ while point is on a -command name to read its documentation. - - Normally you would edit one version and then tell Smerge to keep only -that version. Use ‘C-c ^ m’ (‘smerge-keep-mine’) to keep the ‘HEAD’ -version or ‘C-c ^ o’ (‘smerge-keep-other’) to keep the version that -follows "|||||||". Then use ‘C-c ^ n’ to move to the next conflicting -area in the same file. Once you are done resolving conflicts, return to -the Magit status buffer. The file should now be shown as "modified", no -longer as "unmerged", because Smerge automatically stages the file when -you save the buffer after resolving the last conflict. - - 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. - - Ediff can be used for other purposes as well. For more information -on how to enter Ediff from Magit, see *note Ediffing::. Explaining how -to use Ediff is beyond the scope of this manual, instead see *note -(ediff)Top::. - - If you are unsure whether you should Smerge or Ediff, then use the -former. It is much easier to understand and use, and except for truly -complex conflicts, the latter is usually overkill. - - -File: magit.info, Node: Rebasing, Next: Cherry Picking, Prev: Resolving Conflicts, Up: Manipulating - -6.9 Rebasing -============ - -Also see *note (gitman)git-rebase::. For information on how to resolve -conflicts that occur during rebases see the preceding section. - -‘r’ (‘magit-rebase’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - When no rebase is in progress, then the transient features the -following suffix commands. - - Using one of these commands _starts_ a rebase sequence. Git might -then stop somewhere along the way, either because you told it to do so, -or because applying a commit failed due to a conflict. When that -happens, then the status buffer shows information about the rebase -sequence which is in progress in a section similar to a log section. -See *note Information About In-Progress Rebase::. - - For information about the upstream and the push-remote, see *note The -Two Remotes::. - -‘r p’ (‘magit-rebase-onto-pushremote’) - - This command rebases the current branch onto its push-remote. - - With a prefix argument or when the push-remote is either not - configured or unusable, then let the user first configure the - push-remote. - -‘r u’ (‘magit-rebase-onto-upstream’) - - This command rebases the current branch onto its upstream branch. - - With a prefix argument or when the upstream is either not - configured or unusable, then let the user first configure the - upstream. - -‘r e’ (‘magit-rebase-branch’) - - This command rebases the current branch onto a branch read in the - minibuffer. All commits that are reachable from head but not from - the selected branch TARGET are being rebased. - -‘r s’ (‘magit-rebase-subset’) - - This command starts a non-interactive rebase sequence to transfer - commits from START to ‘HEAD’ onto NEWBASE. START has to be - selected from a list of recent commits. - - By default Magit uses the ‘--autostash’ argument, which causes -uncommitted changes to be stored in a stash before the rebase begins. -These changes are restored after the rebase completes and if possible -the stash is removed. If the stash does not apply cleanly, then the -stash is not removed. In case something goes wrong when resolving the -conflicts, this allows you to start over. - - Even though one of the actions is dedicated to interactive rebases, -the transient also features the infix argument ‘--interactive’. This -can be used to turn one of the other, non-interactive rebase variants -into an interactive rebase. - - For example if you want to clean up a feature branch and at the same -time rebase it onto ‘master’, then you could use ‘r-iu’. But we -recommend that you instead do that in two steps. First use ‘ri’ to -cleanup the feature branch, and then in a second step ‘ru’ to rebase it -onto ‘master’. That way if things turn out to be more complicated than -you thought and/or you make a mistake and have to start over, then you -only have to redo half the work. - - Explicitly enabling ‘--interactive’ won’t have an effect on the -following commands as they always use that argument anyway, even if it -is not enabled in the transient. - -‘r i’ (‘magit-rebase-interactive’) - - This command starts an interactive rebase sequence. - -‘r f’ (‘magit-rebase-autosquash’) - - This command combines squash and fixup commits with their intended - targets. - -‘r m’ (‘magit-rebase-edit-commit’) - - This command starts an interactive rebase sequence that lets the - user edit a single older commit. - -‘r w’ (‘magit-rebase-reword-commit’) - - This command starts an interactive rebase sequence that lets the - user reword a single older commit. - -‘r k’ (‘magit-rebase-remove-commit’) - - This command removes a single older commit using rebase. - - When a rebase is in progress, then the transient instead features the -following suffix commands. - -‘r r’ (‘magit-rebase-continue’) - - This command restart the current rebasing operation. - - In some cases this pops up a commit message buffer for you do edit. - With a prefix argument the old message is reused as-is. - -‘r s’ (‘magit-rebase-skip’) - - This command skips the current commit and restarts the current - rebase operation. - -‘r e’ (‘magit-rebase-edit’) - - This command lets the user edit the todo list of the current rebase - operation. - -‘r a’ (‘magit-rebase-abort’) - - This command aborts the current rebase operation, restoring the - original branch. - -* Menu: - -* Editing Rebase Sequences:: -* Information About In-Progress Rebase:: - - -File: magit.info, Node: Editing Rebase Sequences, Next: Information About In-Progress Rebase, Up: Rebasing - -6.9.1 Editing Rebase Sequences ------------------------------- - -‘C-c C-c’ (‘with-editor-finish’) - - Finish the current editing session by returning with exit code 0. - Git then uses the rebase instructions it finds in the file. - -‘C-c C-k’ (‘with-editor-cancel’) - - Cancel the current editing session by returning with exit code 1. - Git then forgoes starting the rebase sequence. - -‘RET’ (‘git-rebase-show-commit’) - - Show the commit on the current line in another buffer and select - that buffer. - -‘SPC’ (‘git-rebase-show-or-scroll-up’) - - Show the commit on the current line in another buffer without - selecting that buffer. If the revision buffer is already visible - in another window of the current frame, then instead scroll that - window up. - -‘DEL’ (‘git-rebase-show-or-scroll-down’) - - Show the commit on the current line in another buffer without - selecting that buffer. If the revision buffer is already visible - in another window of the current frame, then instead scroll that - window down. - -‘p’ (‘git-rebase-backward-line’) - - Move to previous line. - -‘n’ (‘forward-line’) - - Move to next line. - -‘M-p’ (‘git-rebase-move-line-up’) - - Move the current commit (or command) up. - -‘M-n’ (‘git-rebase-move-line-down’) - - Move the current commit (or command) down. - -‘r’ (‘git-rebase-reword’) - - Edit message of commit on current line. - -‘e’ (‘git-rebase-edit’) - - Stop at the commit on the current line. - -‘s’ (‘git-rebase-squash’) - - Meld commit on current line into previous commit, and edit message. - -‘f’ (‘git-rebase-fixup’) - - Meld commit on current line into previous commit, discarding the - current commit’s message. - -‘k’ (‘git-rebase-kill-line’) - - Kill the current action line. - -‘c’ (‘git-rebase-pick’) - - Use commit on current line. - -‘x’ (‘git-rebase-exec’) - - Insert a shell command to be run after the proceeding commit. - - If there already is such a command on the current line, then edit - that instead. With a prefix argument insert a new command even - when there already is one on the current line. With empty input - remove the command on the current line, if any. - -‘b’ (‘git-rebase-break’) - - Insert a break action before the current line, instructing Git to - return control to the user. - -‘y’ (‘git-rebase-insert’) - - Read an arbitrary commit and insert it below current line. - -‘C-x u’ (‘git-rebase-undo’) - - Undo some previous changes. Like ‘undo’ but works in read-only - buffers. - - -- User Option: git-rebase-auto-advance - - Whether to move to next line after changing a line. - - -- User Option: git-rebase-show-instructions - - Whether to show usage instructions inside the rebase buffer. - - -- User Option: git-rebase-confirm-cancel - - Whether confirmation is required to cancel. - - When a rebase is performed with the ‘--rebase-merges’ option, the -sequence will include a few other types of actions and the following -commands become relevant. - -‘l’ (‘git-rebase-label’) - - This commands inserts a label action or edits the one at point. - -‘t’ (‘git-rebase-reset’) - - This command inserts a reset action or edits the one at point. The - prompt will offer the labels that are currently present in the - buffer. - -‘MM’ (‘git-rebase-merge’) - - The command inserts a merge action or edits the one at point. The - prompt will offer the labels that are currently present in the - buffer. Specifying a message to reuse via ‘-c’ or ‘-C’ is not - supported; an editor will always be invoked for the merge. - -‘Mt’ (‘git-rebase-merge-toggle-editmsg’) - - This command toggles between the ‘-C’ and ‘-c’ options of the merge - action at point. These options both specify a commit whose message - should be reused. The lower-case variant instructs Git to invoke - the editor when creating the merge, allowing the user to edit the - message. - - -File: magit.info, Node: Information About In-Progress Rebase, Prev: Editing Rebase Sequences, Up: Rebasing - -6.9.2 Information About In-Progress Rebase ------------------------------------------- - -While a rebase sequence is in progress, the status buffer features a -section that lists the commits that have already been applied as well as -the commits that still have to be applied. - - The commits are split in two halves. When rebase stops at a commit, -either because the user has to deal with a conflict or because s/he -explicitly requested that rebase stops at that commit, then point is -placed on the commit that separates the two groups, i.e. on ‘HEAD’. -The commits above it have not been applied yet, while the ‘HEAD’ and the -commits below it have already been applied. In between these two groups -of applied and yet-to-be applied commits, there sometimes is a commit -which has been dropped. - - Each commit is prefixed with a word and these words are additionally -shown in different colors to indicate the status of the commits. - - The following colors are used: - - • Yellow commits have not been applied yet. - - • Gray commits have already been applied. - - • The blue commit is the ‘HEAD’ commit. - - • The green commit is the commit the rebase sequence stopped at. If - this is the same commit as ‘HEAD’ (e.g. because you haven’t done - anything yet after rebase stopped at the commit, then this commit - is shown in blue, not green). There can only be a green *and* a - blue commit at the same time, if you create one or more new commits - after rebase stops at a commit. - - • Red commits have been dropped. They are shown for reference only, - e.g. to make it easier to diff. - - Of course these colors are subject to the color-theme in use. - - The following words are used: - - • Commits prefixed with ‘pick’, ‘reword’, ‘edit’, ‘squash’, and - ‘fixup’ have not been applied yet. These words have the same - meaning here as they do in the buffer used to edit the rebase - sequence. See *note Editing Rebase Sequences::. When the - ‘--rebase-merges’ option was specified, ‘reset’, ‘label’, and - ‘merge’ lines may also be present. - - • Commits prefixed with ‘done’ and ‘onto’ have already been applied. - It is possible for such a commit to be the ‘HEAD’, in which case it - is blue. Otherwise it is grey. - - • The commit prefixed with ‘onto’ is the commit on top of which - all the other commits are being re-applied. This commit - itself did not have to be re-applied, it is the commit rebase - did rewind to before starting to re-apply other commits. - - • Commits prefixed with ‘done’ have already been re-applied. - This includes commits that have been re-applied but also new - commits that you have created during the rebase. - - • All other commits, those not prefixed with any of the above words, - are in some way related to the commit at which rebase stopped. - - To determine whether a commit is related to the stopped-at commit - their hashes, trees and patch-ids (1) are being compared. The - commit message is not used for this purpose. - - Generally speaking commits that are related to the stopped-at - commit can have any of the used colors, though not all color/word - combinations are possible. - - Words used for stopped-at commits are: - - • When a commit is prefixed with ‘void’, then that indicates - that Magit knows for sure that all the changes in that commit - have been applied using several new commits. This commit is - no longer reachable from ‘HEAD’, and it also isn’t one of the - commits that will be applied when resuming the session. - - • When a commit is prefixed with ‘join’, then that indicates - that the rebase sequence stopped at that commit due to a - conflict - you now have to join (merge) the changes with what - has already been applied. In a sense this is the commit - rebase stopped at, but while its effect is already in the - index and in the worktree (with conflict markers), the commit - itself has not actually been applied yet (it isn’t the - ‘HEAD’). So it is shown in yellow, like the other commits - that still have to be applied. - - • When a commit is prefixed with ‘stop’ or a _blue_ or _green_ - ‘same’, then that indicates that rebase stopped at this - commit, that it is still applied or has been applied again, - and that at least its patch-id is unchanged. - - • When a commit is prefixed with ‘stop’, then that - indicates that rebase stopped at that commit because you - requested that earlier, and its patch-id is unchanged. - It might even still be the exact same commit. - - • When a commit is prefixed with a _blue_ or _green_ - ‘same’, then that indicates that while its tree or hash - changed, its patch-id did not. If it is blue, then it is - the ‘HEAD’ commit (as always for blue). When it is - green, then it no longer is ‘HEAD’ because other commit - have been created since (but before continuing the - rebase). - - • When a commit is prefixed with ‘goal’, a _yellow_ ‘same,’ or - ‘work’, then that indicates that rebase applied that commit - but that you then reset ‘HEAD’ to an earlier commit (likely to - split it up into multiple commits), and that there are some - uncommitted changes remaining which likely (but not - necessarily) originate from that commit. - - • When a commit is prefixed with ‘goal’, then that - indicates that it is still possible to create a new - commit with the exact same tree (the "goal") without - manually editing any files, by committing the index, or - by staging all changes and then committing that. This is - the case when the original tree still exists in the index - or worktree in untainted form. - - • When a commit is prefixed with a yellow ‘same’, then that - indicates that it is no longer possible to create a - commit with the exact same tree, but that it is still - possible to create a commit with the same patch-id. This - would be the case if you created a new commit with other - changes, but the changes from the original commit still - exist in the index or working tree in untainted form. - - • When a commit is prefixed with ‘work’, then that - indicates that you reset ‘HEAD’ to an earlier commit, and - that there are some staged and/or unstaged changes - (likely, but not necessarily) originating from that - commit. However it is no longer possible to create a new - commit with the same tree or at least the same patch-id - because you have already made other changes. - - • When a commit is prefixed with ‘poof’ or ‘gone’, then that - indicates that rebase applied that commit but that you then - reset ‘HEAD’ to an earlier commit (likely to split it up into - multiple commits), and that there are no uncommitted changes. - - • When a commit is prefixed with ‘poof’, then that - indicates that it is no longer reachable from ‘HEAD’, but - that it has been replaced with one or more commits, which - together have the exact same effect. - - • When a commit is prefixed with ‘gone’, then that - indicates that it is no longer reachable from ‘HEAD’ and - that we also cannot determine whether its changes are - still in effect in one or more new commits. They might - be, but if so, then there must also be other changes - which makes it impossible to know for sure. - - Do not worry if you do not fully understand the above. That’s okay, -you will acquire a good enough understanding through practice. - - For other sequence operations such as cherry-picking, a similar -section is displayed, but they lack some of the features described -above, due to limitations in the git commands used to implement them. -Most importantly these sequences only support "picking" a commit but not -other actions such as "rewording", and they do not keep track of the -commits which have already been applied. - - ---------- Footnotes ---------- - - (1) The patch-id is a hash of the _changes_ introduced by a commit. -It differs from the hash of the commit itself, which is a hash of the -result of applying that change (i.e. the resulting trees and blobs) as -well as author and committer information, the commit message, and the -hashes of the parents of the commit. The patch-id hash on the other -hand is created only from the added and removed lines, even line numbers -and whitespace changes are ignored when calculating this hash. The -patch-ids of two commits can be used to answer the question "Do these -commits make the same change?". - - -File: magit.info, Node: Cherry Picking, Next: Resetting, Prev: Rebasing, Up: Manipulating - -6.10 Cherry Picking -=================== - -Also see *note (gitman)git-cherry-pick::. - -‘A’ (‘magit-cherry-pick’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - When no cherry-pick or revert is in progress, then the transient -features the following suffix commands. - -‘A A’ (‘magit-cherry-copy’) - - This command copies COMMITS from another branch onto the current - branch. If the region selects multiple commits, then those are - copied, without prompting. Otherwise the user is prompted for a - commit or range, defaulting to the commit at point. - -‘A a’ (‘magit-cherry-apply’) - - This command applies the changes in COMMITS from another branch - onto the current branch. If the region selects multiple commits, - then those are used, without prompting. Otherwise the user is - prompted for a commit or range, defaulting to the commit at point. - - This command also has a top-level binding, which can be invoked - without using the transient by typing ‘a’ at the top-level. - - The following commands not only apply some commits to some branch, -but also remove them from some other branch. The removal is performed -using either ‘git-update-ref’ or if necessary ‘git-rebase’. Both -applying commits as well as removing them using ‘git-rebase’ can lead to -conflicts. If that happens, then these commands abort and you not only -have to resolve the conflicts but also finish the process the same way -you would have to if these commands didn’t exist at all. - -‘A h’ (‘magit-cherry-harvest’) - - This command moves the selected COMMITS that must be located on - another BRANCH onto the current branch instead, removing them from - the former. When this command succeeds, then the same branch is - current as before. - - Applying the commits on the current branch or removing them from - the other branch can lead to conflicts. When that happens, then - this command stops and you have to resolve the conflicts and then - finish the process manually. - -‘A d’ (‘magit-cherry-donate’) - - This command moves the selected COMMITS from the current branch - onto another existing BRANCH, removing them from the former. When - this command succeeds, then the same branch is current as before. - - Applying the commits on the other branch or removing them from the - current branch can lead to conflicts. When that happens, then this - command stops and you have to resolve the conflicts and then finish - the process manually. - -‘A n’ (‘magit-cherry-spinout’) - - This command moves the selected COMMITS from the current branch - onto a new branch BRANCH, removing them from the former. When this - command succeeds, then the same branch is current as before. - - Applying the commits on the other branch or removing them from the - current branch can lead to conflicts. When that happens, then this - command stops and you have to resolve the conflicts and then finish - the process manually. - -‘A s’ (‘magit-cherry-spinoff’) - - This command moves the selected COMMITS from the current branch - onto a new branch BRANCH, removing them from the former. When this - command succeeds, then the new branch is checked out. - - Applying the commits on the other branch or removing them from the - current branch can lead to conflicts. When that happens, then this - command stops and you have to resolve the conflicts and then finish - the process manually. - - When a cherry-pick or revert is in progress, then the transient -instead features the following suffix commands. - -‘A A’ (‘magit-sequence-continue’) - - Resume the current cherry-pick or revert sequence. - -‘A s’ (‘magit-sequence-skip’) - - Skip the stopped at commit during a cherry-pick or revert sequence. - -‘A a’ (‘magit-sequence-abort’) - - Abort the current cherry-pick or revert sequence. This discards - all changes made since the sequence started. - -* Menu: - -* Reverting:: - - -File: magit.info, Node: Reverting, Up: Cherry Picking - -6.10.1 Reverting ----------------- - -‘V’ (‘magit-revert’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - When no cherry-pick or revert is in progress, then the transient -features the following suffix commands. - -‘V V’ (‘magit-revert-and-commit’) - - Revert a commit by creating a new commit. Prompt for a commit, - defaulting to the commit at point. If the region selects multiple - commits, then revert all of them, without prompting. - -‘V v’ (‘magit-revert-no-commit’) - - Revert a commit by applying it in reverse to the working tree. - Prompt for a commit, defaulting to the commit at point. If the - region selects multiple commits, then revert all of them, without - prompting. - - When a cherry-pick or revert is in progress, then the transient -instead features the following suffix commands. - -‘V A’ (‘magit-sequence-continue’) - - Resume the current cherry-pick or revert sequence. - -‘V s’ (‘magit-sequence-skip’) - - Skip the stopped at commit during a cherry-pick or revert sequence. - -‘V a’ (‘magit-sequence-abort’) - - Abort the current cherry-pick or revert sequence. This discards - all changes made since the sequence started. - - -File: magit.info, Node: Resetting, Next: Stashing, Prev: Cherry Picking, Up: Manipulating - -6.11 Resetting -============== - -Also see *note (gitman)git-reset::. - -‘x’ (‘magit-reset-quickly’) - - Reset the ‘HEAD’ and index to some commit read from the user and - defaulting to the commit at point, and possibly also reset the - working tree. With a prefix argument reset the working tree - otherwise don’t. - -‘X m’ (‘magit-reset-mixed’) - - Reset the ‘HEAD’ and index to some commit read from the user and - defaulting to the commit at point. The working tree is kept as-is. - -‘X s’ (‘magit-reset-soft’) - - Reset the ‘HEAD’ to some commit read from the user and defaulting - to the commit at point. The index and the working tree are kept - as-is. - -‘X h’ (‘magit-reset-hard’) - - Reset the ‘HEAD’, index, and working tree to some commit read from - the user and defaulting to the commit at point. - -‘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. - -‘X i’ (‘magit-reset-index’) - - Reset the index to some commit read from the user and defaulting to - the commit at point. Keep the ‘HEAD’ and working tree as-is, so if - the commit refers to the ‘HEAD’, then this effectively unstages all - changes. - -‘X w’ (‘magit-reset-worktree’) - - Reset the working tree to some commit read from the user and - defaulting to the commit at point. Keep the ‘HEAD’ and index - as-is. - -‘X f’ (‘magit-file-checkout’) - - Update file in the working tree and index to the contents from a - revision. Both the revision and file are read from the user. - - -File: magit.info, Node: Stashing, Prev: Resetting, Up: Manipulating - -6.12 Stashing -============= - -Also see *note (gitman)git-stash::. - -‘z’ (‘magit-stash’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘z z’ (‘magit-stash-both’) - - Create a stash of the index and working tree. Untracked files are - included according to infix arguments. One prefix argument is - equivalent to ‘--include-untracked’ while two prefix arguments are - equivalent to ‘--all’. - -‘z i’ (‘magit-stash-index’) - - Create a stash of the index only. Unstaged and untracked changes - are not stashed. - -‘z w’ (‘magit-stash-worktree’) - - Create a stash of unstaged changes in the working tree. Untracked - files are included according to infix arguments. One prefix - argument is equivalent to ‘--include-untracked’ while two prefix - arguments are equivalent to ‘--all’. - -‘z x’ (‘magit-stash-keep-index’) - - Create a stash of the index and working tree, keeping index intact. - Untracked files are included according to infix arguments. One - prefix argument is equivalent to ‘--include-untracked’ while two - prefix arguments are equivalent to ‘--all’. - -‘z Z’ (‘magit-snapshot-both’) - - Create a snapshot of the index and working tree. Untracked files - are included according to infix arguments. One prefix argument is - equivalent to ‘--include-untracked’ while two prefix arguments are - equivalent to ‘--all’. - -‘z I’ (‘magit-snapshot-index’) - - Create a snapshot of the index only. Unstaged and untracked - changes are not stashed. - -‘z W’ (‘magit-snapshot-worktree’) - - Create a snapshot of unstaged changes in the working tree. - Untracked files are included according to infix arguments. One - prefix argument is equivalent to ‘--include-untracked’ while two - prefix arguments are equivalent to ‘--all’-. - -‘z a’ (‘magit-stash-apply’) - - Apply a stash to the working tree. Try to preserve the stash - index. If that fails because there are staged changes, apply - without preserving the stash index. - -‘z p’ (‘magit-stash-pop’) - - Apply a stash to the working tree and remove it from stash list. - Try to preserve the stash index. If that fails because there are - staged changes, apply without preserving the stash index and forgo - removing the stash. - -‘z k’ (‘magit-stash-drop’) - - Remove a stash from the stash list. When the region is active, - offer to drop all contained stashes. - -‘z v’ (‘magit-stash-show’) - - Show all diffs of a stash in a buffer. - -‘z b’ (‘magit-stash-branch’) - - Create and checkout a new BRANCH from STASH. The branch starts at - the commit that was current when the stash was created. - -‘z B’ (‘magit-stash-branch-here’) - - Create and checkout a new BRANCH using ‘magit-branch’ with the - current branch or ‘HEAD’ as the starting-point. Then apply STASH, - dropping it if it applies cleanly. - -‘z f’ (‘magit-stash-format-patch’) - - Create a patch from STASH. - -‘k’ (‘magit-stash-clear’) - - Remove all stashes saved in REF’s reflog by deleting REF. - -‘z l’ (‘magit-stash-list’) - - List all stashes in a buffer. - - -- User Option: magit-stashes-margin - - This option specifies whether the margin is initially shown in - stashes buffers and how it is formatted. - - The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. - - • If INIT is non-nil, then the margin is shown initially. - - • STYLE controls how to format the author or committer date. It - can be one of ‘age’ (to show the age of the commit), - ‘age-abbreviated’ (to abbreviate the time unit to a - character), or a string (suitable for ‘format-time-string’) to - show the actual date. Option - ‘magit-log-margin-show-committer-date’ controls which date is - being displayed. - - • WIDTH controls the width of the margin. This exists for - forward compatibility and currently the value should not be - changed. - - • AUTHOR controls whether the name of the author is also shown - by default. - - • AUTHOR-WIDTH has to be an integer. When the name of the - author is shown, then this specifies how much space is used to - do so. - - -File: magit.info, Node: Transferring, Next: Miscellaneous, Prev: Manipulating, Up: Top - -7 Transferring -************** - -* Menu: - -* Remotes:: -* Fetching:: -* Pulling:: -* Pushing:: -* Plain Patches:: -* Maildir Patches:: - - -File: magit.info, Node: Remotes, Next: Fetching, Up: Transferring - -7.1 Remotes -=========== - -* Menu: - -* Remote Commands:: -* Remote Git Variables:: - - -File: magit.info, Node: Remote Commands, Next: Remote Git Variables, Up: Remotes - -7.1.1 Remote Commands ---------------------- - -The transient prefix command ‘magit-remote’ is used to add remotes and -to make changes to existing remotes. This command only deals with -remotes themselves, not with branches or the transfer of commits. Those -features are available from separate transient commands. - - Also see *note (gitman)git-remote::. - -‘M’ (‘magit-remote’) - - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - - By default it also binds and displays the values of some - remote-related Git variables and allows changing their values. - - -- User Option: magit-remote-direct-configure - - This option controls whether remote-related Git variables are - accessible directly from the transient ‘magit-remote’. - - If ‘t’ (the default) and a local branch is checked out, then - ‘magit-remote’ features the variables for the upstream remote of - that branch, or if ‘HEAD’ is detached, for ‘origin’, provided that - exists. - - If ‘nil’, then ‘magit-remote-configure’ has to be used to do so. - -‘M C’ (‘magit-remote-configure’) - - This transient prefix command binds commands that set the value of - remote-related variables and displays them in a temporary buffer - until the transient is exited. - - With a prefix argument, this command always prompts for a remote. - - Without a prefix argument this depends on whether it was invoked as - a suffix of ‘magit-remote’ and on the - ‘magit-remote-direct-configure’ option. If ‘magit-remote’ already - displays the variables for the upstream, then it does not make - sense to invoke another transient that displays them for the same - remote. In that case this command prompts for a remote. - - The variables are described in *note Remote Git Variables::. - -‘M a’ (‘magit-remote-add’) - - This command add a remote and fetches it. The remote name and url - are read in the minibuffer. - -‘M r’ (‘magit-remote-rename’) - - This command renames a remote. Both the old and the new names are - read in the minibuffer. - -‘M u’ (‘magit-remote-set-url’) - - This command changes the url of a remote. Both the remote and the - new url are read in the minibuffer. - -‘M k’ (‘magit-remote-remove’) - - This command deletes a remote, read in the minibuffer. - -‘M p’ (‘magit-remote-prune’) - - This command removes stale remote-tracking branches for a remote - read in the minibuffer. - -‘M P’ (‘magit-remote-prune-refspecs’) - - This command removes stale refspecs for a remote read in the - minibuffer. - - A refspec is stale if there no longer exists at least one branch on - the remote that would be fetched due to that refspec. A stale - refspec is problematic because its existence causes Git to refuse - to fetch according to the remaining non-stale refspecs. - - If only stale refspecs remain, then this command offers to either - delete the remote or to replace the stale refspecs with the default - refspec ("+refs/heads/*:refs/remotes/REMOTE/*"). - - This command also removes the remote-tracking branches that were - created due to the now stale refspecs. Other stale branches are - not removed. - - -- User Option: magit-remote-add-set-remote.pushDefault - - This option controls whether the user is asked whether they want to - set ‘remote.pushDefault’ after adding a remote. - - If ‘ask’, then users is always ask. If ‘ask-if-unset’, then the - user is only if the variable isn’t set already. If ‘nil’, then the - user isn’t asked and the variable isn’t set. If the value is a - string, then the variable is set without the user being asked, - provided that the name of the added remote is equal to that string - and the variable isn’t already set. - - -File: magit.info, Node: Remote Git Variables, Prev: Remote Commands, Up: Remotes - -7.1.2 Remote Git Variables --------------------------- - -These variables can be set from the transient prefix command -‘magit-remote-configure’. By default they can also be set from -‘magit-remote’. See *note Remote Commands::. - - -- Variable: remote.NAME.url - - This variable specifies the url of the remote named NAME. It can - have multiple values. - - -- Variable: remote.NAME.fetch - - The refspec used when fetching from the remote named NAME. It can - have multiple values. - - -- Variable: remote.NAME.pushurl - - This variable specifies the url used for fetching from the remote - named NAME. If it is not specified, then ‘remote.NAME.url’ is used - instead. It can have multiple values. - - -- Variable: remote.NAME.push - - The refspec used when pushing to the remote named NAME. It can - have multiple values. - - -- Variable: remote.NAME.tagOpts - - This variable specifies what tags are fetched by default. If the - value is ‘--no-tags’ then no tags are fetched. If the value is - ‘--tags’, then all tags are fetched. If this variable has no - value, then only tags are fetched that are reachable from fetched - branches. - - -File: magit.info, Node: Fetching, Next: Pulling, Prev: Remotes, Up: Transferring - -7.2 Fetching -============ - -Also see *note (gitman)git-fetch::. For information about the upstream -and the push-remote, see *note The Two Remotes::. - -‘f’ (‘magit-fetch’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘f p’ (‘magit-fetch-from-pushremote’) - - This command fetches from the current push-remote. - - With a prefix argument or when the push-remote is either not - configured or unusable, then let the user first configure the - push-remote. - -‘f u’ (‘magit-fetch-from-upstream’) - - This command fetch from the upstream of the current branch. - - If the upstream is configured for the current branch and names an - existing remote, then use that. Otherwise try to use another - remote: If only a single remote is configured, then use that. - Otherwise if a remote named "origin" exists, then use that. - - If no remote can be determined, then this command is not available - from the ‘magit-fetch’ transient prefix and invoking it directly - results in an error. - -‘f e’ (‘magit-fetch-other’) - - This command fetch from a repository read from the minibuffer. - -‘f o’ (‘magit-fetch-branch’) - - This command fetches a branch from a remote, both of which are read - from the minibuffer. - -‘f r’ (‘magit-fetch-refspec’) - - This command fetches from a remote using an explicit refspec, both - of which are read from the minibuffer. - -‘f a’ (‘magit-fetch-all’) - - This command fetches from all remotes. - -‘f m’ (‘magit-submodule-fetch’) - - This command fetches all submodules. With a prefix argument it - fetches all remotes of all submodules. - - -- User Option: magit-pull-or-fetch - - By default fetch and pull commands are available from separate - transient prefix command. Setting this to ‘t’ adds some (but not - all) of the above suffix commands to the ‘magit-pull’ transient. - - If you do that, then you might also want to change the key binding - for these prefix commands, e.g.: - - (setq magit-pull-or-fetch t) - (define-key magit-mode-map "f" 'magit-pull) ; was magit-fetch - (define-key magit-mode-map "F" nil) ; was magit-pull - - -File: magit.info, Node: Pulling, Next: Pushing, Prev: Fetching, Up: Transferring - -7.3 Pulling -=========== - -Also see *note (gitman)git-pull::. For information about the upstream -and the push-remote, see *note The Two Remotes::. - -‘F’ (‘magit-pull’) - - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - -‘F p’ (‘magit-pull-from-pushremote’) - - This command pulls from the push-remote of the current branch. - - With a prefix argument or when the push-remote is either not - configured or unusable, then let the user first configure the - push-remote. - -‘F u’ (‘magit-pull-from-upstream’) - - This command pulls from the upstream of the current branch. - - With a prefix argument or when the upstream is either not - configured or unusable, then let the user first configure the - upstream. - -‘F e’ (‘magit-pull-branch’) - - This command pulls from a branch read in the minibuffer. - - -File: magit.info, Node: Pushing, Next: Plain Patches, Prev: Pulling, Up: Transferring - -7.4 Pushing -=========== - -Also see *note (gitman)git-push::. For information about the upstream -and the push-remote, see *note The Two Remotes::. - -‘P’ (‘magit-push’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘P p’ (‘magit-push-current-to-pushremote’) - - This command pushes the current branch to its push-remote. - - With a prefix argument or when the push-remote is either not - configured or unusable, then let the user first configure the - push-remote. - -‘P u’ (‘magit-push-current-to-upstream’) - - This command pushes the current branch to its upstream branch. - - With a prefix argument or when the upstream is either not - configured or unusable, then let the user first configure the - upstream. - -‘P e’ (‘magit-push-current’) - - This command pushes the current branch to a branch read in the - minibuffer. - -‘P o’ (‘magit-push-other’) - - This command pushes an arbitrary branch or commit somewhere. Both - the source and the target are read in the minibuffer. - -‘P r’ (‘magit-push-refspecs’) - - This command pushes one or multiple refspecs to a remote, both of - which are read in the minibuffer. - - To use multiple refspecs, separate them with commas. Completion is - only available for the part before the colon, or when no colon is - used. - -‘P m’ (‘magit-push-matching’) - - This command pushes all matching branches to another repository. - - If only one remote exists, then push to that. Otherwise prompt for - a remote, offering the remote configured for the current branch as - default. - -‘P t’ (‘magit-push-tags’) - - This command pushes all tags to another repository. - - If only one remote exists, then push to that. Otherwise prompt for - a remote, offering the remote configured for the current branch as - default. - -‘P T’ (‘magit-push-tag’) - - 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. - - -- Command: magit-push-implicitly args - - This command pushes somewhere without using an explicit refspec. - - This command simply runs ‘git push -v [ARGS]’. ARGS are the infix - arguments. No explicit refspec arguments are used. Instead the - behavior depends on at least these Git variables: ‘push.default’, - ‘remote.pushDefault’, ‘branch..pushRemote’, - ‘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: - - (transient-insert-suffix 'magit-push \"p\" - '(\"i\" magit-push-implicitly))" - - -- Command: magit-push-to-remote remote args - - This command pushes to the remote REMOTE without using an explicit - refspec. The remote is read in the minibuffer. - - This command simply runs ‘git push -v [ARGS] REMOTE’. ARGS are the - infix arguments. No refspec arguments are used. Instead the - behavior depends on at least these Git variables: ‘push.default’, - ‘remote.pushDefault’, ‘branch..pushRemote’, - ‘branch..remote’, ‘branch..merge’, and - ‘remote..push’. - - -File: magit.info, Node: Plain Patches, Next: Maildir Patches, Prev: Pushing, Up: Transferring - -7.5 Plain Patches -================= - -‘W’ (‘magit-patch’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘W c’ (‘magit-patch-create’) - - This command creates patches for a set commits. If the region - marks several commits, then it creates patches for all of them. - Otherwise it functions as a transient prefix command, which - features several infix arguments and binds itself as a suffix - command. When this command is invoked as a suffix of itself, then - it creates a patch using the specified infix arguments. - -‘w a’ (‘magit-patch-apply’) - - This command applies a patch. This is a transient prefix command, - which features several infix arguments and binds itself as a suffix - command. When this command is invoked as a suffix of itself, then - it applies a patch using the specified infix arguments. - -‘W s’ (‘magit-patch-save’) - - This command creates a patch from the current diff. - - Inside ‘magit-diff-mode’ or ‘magit-revision-mode’ buffers, ‘C-x - C-w’ is also bound to this command. - - It is also possible to save a plain patch file by using ‘C-x C-w’ -inside a ‘magit-diff-mode’ or ‘magit-revision-mode’ buffer. - - -File: magit.info, Node: Maildir Patches, Prev: Plain Patches, Up: Transferring - -7.6 Maildir Patches -=================== - -Also see *note (gitman)git-am::. and *note (gitman)git-apply::. - -‘w’ (‘magit-am’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘w w’ (‘magit-am-apply-patches’) - - This command applies one or more patches. If the region marks - files, then those are applied as patches. Otherwise this command - reads a file-name in the minibuffer, defaulting to the file at - point. - -‘w m’ (‘magit-am-apply-maildir’) - - This command applies patches from a maildir. - -‘w a’ (‘magit-patch-apply’) - - This command applies a plain patch. For a longer description see - *note Plain Patches::. This command is only available from the - ‘magit-am’ transient for historic reasons. - - When an "am" operation is in progress, then the transient instead -features the following suffix commands. - -‘w w’ (‘magit-am-continue’) - - This command resumes the current patch applying sequence. - -‘w s’ (‘magit-am-skip’) - - This command skips the stopped at patch during a patch applying - sequence. - -‘w a’ (‘magit-am-abort’) - - This command aborts the current patch applying sequence. This - discards all changes made since the sequence started. - - -File: magit.info, Node: Miscellaneous, Next: Customizing, Prev: Transferring, Up: Top - -8 Miscellaneous -*************** - -* Menu: - -* Tagging:: -* Notes:: -* Submodules:: -* Subtree:: -* Worktree:: -* Common Commands:: -* Wip Modes:: -* Commands for Buffers Visiting Files:: -* Minor Mode for Buffers Visiting Blobs:: - - -File: magit.info, Node: Tagging, Next: Notes, Up: Miscellaneous - -8.1 Tagging -=========== - -Also see *note (gitman)git-tag::. - -‘t’ (‘magit-tag’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘t t’ (‘magit-tag-create’) - - This command creates a new tag with the given NAME at REV. With a - prefix argument it creates an annotated tag. - -‘t r’ (‘magit-tag-release’) - - 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 - increment the desired part of the version string. If you use - unconventional release tags or version numbers (e.g., - ‘v1.2.3-custom.1’), you can set the ‘magit-release-tag-regexp’ and - ‘magit-tag-version-regexp-alist’ variables. - - 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". - -‘t k’ (‘magit-tag-delete’) - - This command deletes one or more tags. If the region marks - multiple tags (and nothing else), then it offers to delete those. - Otherwise, it prompts for a single tag to be deleted, defaulting to - the tag at point. - -‘t p’ (‘magit-tag-prune’) - - This command offers to delete tags missing locally from REMOTE, and - vice versa. - - -File: magit.info, Node: Notes, Next: Submodules, Prev: Tagging, Up: Miscellaneous - -8.2 Notes -========= - -Also see *note (gitman)git-notes::. - -‘T’ (‘magit-notes’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - -‘T T’ (‘magit-notes-edit’) - - Edit the note attached to a commit, defaulting to the commit at - point. - - By default use the value of Git variable ‘core.notesRef’ or - "refs/notes/commits" if that is undefined. - -‘T r’ (‘magit-notes-remove’) - - Remove the note attached to a commit, defaulting to the commit at - point. - - By default use the value of Git variable ‘core.notesRef’ or - "refs/notes/commits" if that is undefined. - -‘T p’ (‘magit-notes-prune’) - - Remove notes about unreachable commits. - - It is possible to merge one note ref into another. That may result -in conflicts which have to resolved in the temporary worktree -".git/NOTES_MERGE_WORKTREE". - -‘T m’ (‘magit-notes-merge’) - - Merge the notes of a ref read from the user into the current notes - ref. The current notes ref is the value of Git variable - ‘core.notesRef’ or "refs/notes/commits" if that is undefined. - - When a notes merge is in progress then the transient features the -following suffix commands, instead of those listed above. - -‘T c’ (‘magit-notes-merge-commit’) - - Commit the current notes ref merge, after manually resolving - conflicts. - -‘T a’ (‘magit-notes-merge-abort’) - - Abort the current notes ref merge. - - The following variables control what notes reference ‘magit-notes-*’, -‘git notes’ and ‘git show’ act on and display. Both the local and -global values are displayed and can be modified. - - -- Variable: core.notesRef - - This variable specifies the notes ref that is displayed by default - and which commands act on by default. - - -- Variable: notes.displayRef - - This variable specifies additional notes ref to be displayed in - addition to the ref specified by ‘core.notesRef’. It can have - multiple values and may end with ‘*’ to display all refs in the - ‘refs/notes/’ namespace (or ‘**’ if some names contain slashes). - - -File: magit.info, Node: Submodules, Next: Subtree, Prev: Notes, Up: Miscellaneous - -8.3 Submodules -============== - -Also see *note (gitman)git-submodule::. - -* Menu: - -* Listing Submodules:: -* Submodule Transient:: - - -File: magit.info, Node: Listing Submodules, Next: Submodule Transient, Up: Submodules - -8.3.1 Listing Submodules ------------------------- - -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-modules’ to the hook -‘magit-status-sections-hook’ as described in *note Status Module -Sections::. - - -- Command: magit-list-submodules - - This command displays a list of the current repository’s submodules - in a separate buffer. - - It can be invoked by pressing ‘RET’ on the section titled - "Modules". - - -- User Option: magit-submodule-list-columns - - This option controls what columns are displayed by the command - ‘magit-list-submodules’ and how they are displayed. - - Each element has the form ‘(HEADER WIDTH FORMAT PROPS)’. - - HEADER is the string displayed in the header. WIDTH is the width - of the column. FORMAT is a function that is called with one - 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’. - - -File: magit.info, Node: Submodule Transient, Prev: Listing Submodules, Up: Submodules - -8.3.2 Submodule Transient -------------------------- - -‘o’ (‘magit-submodule’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - Some of the below commands default to act on the modules that are -selected using the region. For brevity their description talk about -"the selected modules", but if no modules are selected, then they act on -the current module instead, or if point isn’t on a module, then the read -a single module to act on. With a prefix argument these commands ignore -the selection and the current module and instead act on all suitable -modules. - -‘o a’ (‘magit-submodule-add’) - - This commands adds the repository at URL as a module. Optional - PATH is the path to the module relative to the root of the - super-project. If it is nil then the path is determined based on - URL. - -‘o r’ (‘magit-submodule-register’) - - This command registers the selected modules by copying their urls - from ".gitmodules" to "$GIT_DIR/config". These values can then be - edited before running ‘magit-submodule-populate’. If you don’t - need to edit any urls, then use the latter directly. - -‘o p’ (‘magit-submodule-populate’) - - This command creates the working directory or directories of the - selected modules, checking out the recorded commits. - -‘o u’ (‘magit-submodule-update’) - - This command updates the selected modules checking out the recorded - commits. - -‘o s’ (‘magit-submodule-synchronize’) - - This command synchronizes the urls of the selected modules, copying - the values from ".gitmodules" to the ".git/config" of the - super-project as well those of the modules. - -‘o d’ (‘magit-submodule-unpopulate’) - - This command removes the working directory of the selected modules. - -‘o l’ (‘magit-list-submodules’) - - This command displays a list of the current repository’s modules. - -‘o f’ (‘magit-fetch-modules’) - - This command fetches all modules. - - Option ‘magit-fetch-modules-jobs’ controls how many submodules are - being fetched in parallel. Also fetch the super-repository, - because ‘git fetch’ does not support not doing that. With a prefix - argument fetch all remotes. - diff --git a/elpa/magit-20210802.1524/magit.info-2 b/elpa/magit-20210802.1524/magit.info-2 deleted file mode 100644 index 6be0ba52..00000000 --- a/elpa/magit-20210802.1524/magit.info-2 +++ /dev/null @@ -1,3759 +0,0 @@ -This is magit.info, produced by makeinfo version 6.7 from magit.texi. - - 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 - Foundation, either version 3 of the License, or (at your option) - any later version. - - This document 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. - -INFO-DIR-SECTION Emacs -START-INFO-DIR-ENTRY -* Magit: (magit). Using Git from Emacs with Magit. -END-INFO-DIR-ENTRY - - -File: magit.info, Node: Subtree, Next: Worktree, Prev: Submodules, Up: Miscellaneous - -8.4 Subtree -=========== - -Also see *note (gitman)git-subtree::. - -‘O’ (‘magit-subtree’) - - This transient prefix command binds the two sub-transients; one for - importing a subtree and one for exporting a subtree. - -‘O i’ (‘magit-subtree-import’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - The suffixes of this command import subtrees. - - If the ‘--prefix’ argument is set, then the suffix commands use - that prefix without prompting the user. If it is unset, then they - read the prefix in the minibuffer. - -‘O i a’ (‘magit-subtree-add’) - - This command adds COMMIT from REPOSITORY as a new subtree at - PREFIX. - -‘O i c’ (‘magit-subtree-add-commit’) - - This command add COMMIT as a new subtree at PREFIX. - -‘O i m’ (‘magit-subtree-merge’) - - This command merges COMMIT into the PREFIX subtree. - -‘O i f’ (‘magit-subtree-pull’) - - This command pulls COMMIT from REPOSITORY into the PREFIX subtree. - -‘O e’ (‘magit-subtree-export’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - The suffixes of this command export subtrees. - - If the ‘--prefix’ argument is set, then the suffix commands use - that prefix without prompting the user. If it is unset, then they - read the prefix in the minibuffer. - -‘O e p’ (‘magit-subtree-push’) - - This command extract the history of the subtree PREFIX and pushes - it to REF on REPOSITORY. - -‘O e s’ (‘magit-subtree-split’) - - This command extracts the history of the subtree PREFIX. - - -File: magit.info, Node: Worktree, Next: Common Commands, Prev: Subtree, Up: Miscellaneous - -8.5 Worktree -============ - -Also see *note (gitman)git-worktree::. - -‘%’ (‘magit-worktree’) - - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - -‘% b’ (‘magit-worktree-checkout’) - - Checkout BRANCH in a new worktree at PATH. - -‘% c’ (‘magit-worktree-branch’) - - Create a new BRANCH and check it out in a new worktree at PATH. - -‘% m’ (‘magit-worktree-move’) - - Move an existing worktree to a new PATH. - -‘% k’ (‘magit-worktree-delete’) - - Delete a worktree, defaulting to the worktree at point. The - primary worktree cannot be deleted. - -‘% g’ (‘magit-worktree-status’) - - Show the status for the worktree at point. - - If there is no worktree at point, then read one in the minibuffer. - If the worktree at point is the one whose status is already being - displayed in the current buffer, then show it in Dired instead. - - -File: magit.info, Node: Common Commands, Next: Wip Modes, Prev: Worktree, Up: Miscellaneous - -8.6 Common Commands -=================== - -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. - -‘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, - branch, or tag section, it also pushes the (referenced) revision to - the ‘magit-revision-stack’. - - When the current section is a branch or a tag, and a prefix - argument is used, then it saves the revision at its tip to the - ‘kill-ring’ instead of the reference name. - - 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, then it strips the diff marker column and keeps only - either the added or removed lines, depending on the sign of the - prefix argument. - -‘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 is mainly intended for use in - ‘magit-revision-mode’ buffers, the only buffers where it is always - unambiguous exactly which revision should be saved. - - Most other Magit buffers usually show more than one revision, in - some way or another, so this command has to select one of them, and - that choice might not always be the one you think would have been - the best pick. - - Outside of Magit ‘M-w’ and ‘C-w’ are usually bound to -‘kill-ring-save’ and ‘kill-region’, and these commands would also be -useful in Magit buffers. Therefore when the region is active, then both -of these commands behave like ‘kill-ring-save’ instead of as described -above. - - -File: magit.info, Node: Wip Modes, Next: Commands for Buffers Visiting Files, Prev: Common Commands, Up: Miscellaneous - -8.7 Wip Modes -============= - -Git keeps *committed* changes around long enough for users to recover -changes they have accidentally deleted. It does so by not garbage -collecting any committed but no longer referenced objects for a certain -period of time, by default 30 days. - - But Git does *not* keep track of *uncommitted* changes in the working -tree and not even the index (the staging area). Because Magit makes it -so convenient to modify uncommitted changes, it also makes it easy to -shoot yourself in the foot in the process. - - For that reason Magit provides a global mode that saves *tracked* -files to work-in-progress references after or before certain actions. -(At present untracked files are never saved and for technical reasons -nothing is saved before the first commit has been created). - - Two separate work-in-progress references are used to track the state -of the index and of the working tree: ‘refs/wip/index/’ and -‘refs/wip/wtree/’, where ‘’ is the full ref of the -current branch, e.g. ‘refs/heads/master’. When the ‘HEAD’ is detached -then ‘HEAD’ is used in place of ‘’. - - Checking out another branch (or detaching ‘HEAD’) causes the use of -different wip refs for subsequent changes. - - -- User Option: magit-wip-mode - - When this mode is enabled, then uncommitted changes are committed - to dedicated work-in-progress refs whenever appropriate (i.e. when - dataloss would be a possibility otherwise). - - Setting this variable directly does not take effect; either use the - Custom interface to do so or call the respective mode function. - - For historic reasons this mode is implemented on top of four other - ‘magit-wip-*’ modes, which can also be used individually, if you - want finer control over when the wip refs are updated; but that is - discouraged. See *note Legacy Wip Modes::. - - To view the log for a branch and its wip refs use the commands -‘magit-wip-log’ and ‘magit-wip-log-current’. You should use ‘--graph’ -when using these commands. - - -- Command: magit-wip-log - - This command shows the log for a branch and its wip refs. With a - negative prefix argument only the worktree wip ref is shown. - - The absolute numeric value of the prefix argument controls how many - "branches" of each wip ref are shown. This is only relevant if the - value of ‘magit-wip-merge-branch’ is ‘nil’. - - -- Command: magit-wip-log-current - - This command shows the log for the current branch and its wip refs. - With a negative prefix argument only the worktree wip ref is shown. - - The absolute numeric value of the prefix argument controls how many - "branches" of each wip ref are shown. This is only relevant if the - value of ‘magit-wip-merge-branch’ is ‘nil’. - -‘X w’ (‘magit-reset-worktree’) - - This command resets the working tree to some commit read from the - user and defaulting to the commit at point, while keeping the - ‘HEAD’ and index as-is. - - This can be used to restore files to the state committed to a wip - ref. Note that this will discard any unstaged changes that might - have existed before invoking this command (but of course only after - committing that to the working tree wip ref). - - Note that even if you enable ‘magit-wip-mode’ this won’t give you -perfect protection. The most likely scenario for losing changes despite -the use of ‘magit-wip-mode’ is making a change outside Emacs and then -destroying it also outside Emacs. In some such a scenario, Magit, being -an Emacs package, didn’t get the opportunity to keep you from shooting -yourself in the foot. - - When you are unsure whether Magit did commit a change to the wip -refs, then you can explicitly request that all changes to all tracked -files are being committed. - -‘M-x magit-wip-commit’ (‘magit-wip-commit’) - - This command commits all changes to all tracked files to the index - and working tree work-in-progress refs. Like the modes described - above, it does not commit untracked files, but it does check all - tracked files for changes. Use this command when you suspect that - the modes might have overlooked a change made outside Emacs/Magit. - - -- User Option: magit-wip-namespace - - The namespace used for work-in-progress refs. It has to end with a - slash. The wip refs are named ‘index/’ and - ‘wtree/’. When snapshots are created while - the ‘HEAD’ is detached then ‘HEAD’ is used in place of - ‘’. - - -- User Option: magit-wip-mode-lighter - - Mode-line lighter for ‘magit-wip--mode’. - -* Menu: - -* Wip Graph:: -* Legacy Wip Modes:: - - -File: magit.info, Node: Wip Graph, Next: Legacy Wip Modes, Up: Wip Modes - -8.7.1 Wip Graph ---------------- - - -- User Option: magit-wip-merge-branch - - This option controls whether the current branch is merged into the - wip refs after a new commit was created on the branch. - - If non-nil and the current branch has new commits, then it is - merged into the wip ref before creating a new wip commit. This - makes it easier to inspect wip history and the wip commits are - never garbage collected. - - If nil and the current branch has new commits, then the wip ref is - reset to the tip of the branch before creating a new wip commit. - With this setting wip commits are eventually garbage collected. - - When ‘magit-wip-merge-branch’ is ‘t’, then the history looks like -this: - - *--*--*--*--*--* refs/wip/index/refs/heads/master - / / / - A-----B-----C refs/heads/master - - When ‘magit-wip-merge-branch’ is ‘nil’, then creating a commit on the -real branch and then making a change causes the wip refs to be recreated -to fork from the new commit. But the old commits on the wip refs are -not lost. They are still available from the reflog. To make it easier -to see when the fork point of a wip ref was changed, an additional -commit with the message "restart autosaving" is created on it (‘xxO’ -commits below are such boundary commits). - - Starting with - - BI0---BI1 refs/wip/index/refs/heads/master - / - A---B refs/heads/master - \ - BW0---BW1 refs/wip/wtree/refs/heads/master - - and committing the staged changes and editing and saving a file would -result in - - BI0---BI1 refs/wip/index/refs/heads/master - / - A---B---C refs/heads/master - \ \ - \ CW0---CW1 refs/wip/wtree/refs/heads/master - \ - BW0---BW1 refs/wip/wtree/refs/heads/master@{2} - - The fork-point of the index wip ref is not changed until some change -is being staged. Likewise just checking out a branch or creating a -commit does not change the fork-point of the working tree wip ref. The -fork-points are not adjusted until there actually is a change that -should be committed to the respective wip ref. - - -File: magit.info, Node: Legacy Wip Modes, Prev: Wip Graph, Up: Wip Modes - -8.7.2 Legacy Wip Modes ----------------------- - -It is recommended that you use the mode ‘magit-wip-mode’ (which see) and -ignore the existence of the following modes, which are preserved for -historic reasons. - - Setting the following variables directly does not take effect; either -use the Custom interface to do so or call the respective mode functions. - - -- User Option: magit-wip-after-save-mode - - When this mode is enabled, then saving a buffer that visits a file - tracked in a Git repository causes its current state to be - committed to the working tree wip ref for the current branch. - - -- User Option: magit-wip-after-apply-mode - - When this mode is enabled, then applying (i.e. staging, unstaging, - discarding, reversing, and regularly applying) a change to a file - tracked in a Git repository causes its current state to be - committed to the index and/or working tree wip refs for the current - branch. - - If you only ever edit files using Emacs and only ever interact with -Git using Magit, then the above two modes should be enough to protect -each and every change from accidental loss. In practice nobody does -that. Two additional modes exists that do commit to the wip refs before -making changes that could cause the loss of earlier changes. - - -- User Option: magit-wip-before-change-mode - - When this mode is enabled, then certain commands commit the - existing changes to the files they are about to make changes to. - - -- User Option: magit-wip-initial-backup-mode - - When this mode is enabled, then the current version of a file is - committed to the worktree wip ref before the buffer visiting that - file is saved for the first time since the buffer was created. - - This backs up the same version of the file that ‘backup-buffer’ - would save. While ‘backup-buffer’ uses a backup file, this mode - uses the same worktree wip ref as used by the other Magit Wip - modes. Like ‘backup-buffer’, it only does this once; unless you - kill the buffer and visit the file again only one backup will be - created per Emacs session. - - This mode ignores the variables that affect ‘backup-buffer’ and can - be used along-side that function, which is recommended because it - only backs up files that are tracked in a Git repository. - - -- User Option: magit-wip-after-save-local-mode-lighter - - Mode-line lighter for ‘magit-wip-after-save-local-mode’. - - -- User Option: magit-wip-after-apply-mode-lighter - - Mode-line lighter for ‘magit-wip-after-apply-mode’. - - -- User Option: magit-wip-before-change-mode-lighter - - Mode-line lighter for ‘magit-wip-before-change-mode’. - - -- User Option: magit-wip-initial-backup-mode-lighter - - Mode-line lighter for ‘magit-wip-initial-backup-mode’. - - -File: magit.info, Node: Commands for Buffers Visiting Files, Next: Minor Mode for Buffers Visiting Blobs, Prev: Wip Modes, Up: Miscellaneous - -8.8 Commands for Buffers Visiting Files -======================================= - -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 *note Default -Bindings:: and *note (elisp)Key Binding Conventions::. - - If you want a better binding, you have to add it yourself: - - (global-set-key (kbd "C-c g") 'magit-file-dispatch) - - The key bindings shown below assume that you have not improved the -binding for ‘magit-file-dispatch’. - -‘C-c M-g’ (‘magit-file-dispatch’) - - 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’. - -‘C-c M-g s’ (‘magit-stage-file’) - - Stage all changes to the file being visited in the current buffer. - -‘C-c M-g u’ (‘magit-unstage-file’) - - Unstage all changes to the file being visited in the current - buffer. - -‘C-c M-g c’ (‘magit-commit’) - - This transient prefix command binds the following suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. See *note Initiating a - Commit::. - -‘C-c M-g D’ (‘magit-diff’) - - This transient prefix command binds several diff suffix commands - and infix arguments and displays them in a temporary buffer until a - suffix is invoked. See *note Diffing::. - - This is the same command that ‘d’ is bound to in Magit buffers. If - this command is invoked from a file-visiting buffer, then the - initial value of the option (‘--’) that limits the diff to certain - file(s) is set to the visited file. - -‘C-c M-g d’ (‘magit-diff-buffer-file’) - - This command shows the diff for the file of blob that the current - buffer visits. - - -- User Option: magit-diff-buffer-file-locked - - This option controls whether ‘magit-diff-buffer-file’ uses a - dedicated buffer. See *note Modes and Buffers::. - -‘C-c M-g L’ (‘magit-log’) - - This transient prefix command binds several log suffix commands and - infix arguments and displays them in a temporary buffer until a - suffix is invoked. See *note Logging::. - - This is the same command that ‘l’ is bound to in Magit buffers. If - this command is invoked from a file-visiting buffer, then the - initial value of the option (‘--’) that limits the log to certain - file(s) is set to the visited file. - -‘C-c M-g l’ (‘magit-log-buffer-file’) - - This command shows the log for the file of blob that the current - buffer visits. Renames are followed when a prefix argument is used - or when ‘--follow’ is an active log argument. When the region is - active, the log is restricted to the selected line range. - -‘C-c M-g t’ (‘magit-log-trace-definition’) - - This command shows the log for the definition at point. - - -- User Option: magit-log-buffer-file-locked - - This option controls whether ‘magit-log-buffer-file’ uses a - dedicated buffer. See *note Modes and Buffers::. - -‘C-c M-g B’ (‘magit-blame’) - - This transient prefix command binds all blaming suffix commands - along with the appropriate infix arguments and displays them in a - temporary buffer until a suffix is invoked. - - For more information about this and the following commands also see - *note Blaming::. - - In addition to the ‘magit-blame’ sub-transient, the dispatch -transient also binds several blaming suffix commands directly. See -*note Blaming:: for information about those commands and bindings. - -‘C-c M-g e’ (‘magit-edit-line-commit’) - - This command makes the commit editable that added the current line. - - With a prefix argument it makes the commit editable that removes - the line, if any. The commit is determined using ‘git blame’ and - made editable using ‘git rebase --interactive’ if it is reachable - from ‘HEAD’, or by checking out the commit (or a branch that points - at it) otherwise. - -‘C-c M-g p’ (‘magit-blob-previous’) - - Visit the previous blob which modified the current file. - - There are a few additional commands that operate on a single file but -are not enabled in the file transient command by default: - - -- Command: magit-file-rename - - This command renames a file read from the user. - - -- Command: magit-file-delete - - This command deletes a file read from the user. - - -- Command: magit-file-untrack - - This command untracks a file read from the user. - - -- Command: magit-file-checkout - - This command updates a file in the working tree and index to the - contents from a revision. Both the revision and file are read from - the user. - - To enable them invoke the transient (‘C-c M-g’), enter "edit mode" -(‘C-x l’), set the "transient level" (‘C-x l’ again), enter ‘5’, and -leave edit mode (‘C-g’). Also see *note (transient)Enabling and -Disabling Suffixes::. - - -File: magit.info, Node: Minor Mode for Buffers Visiting Blobs, Prev: Commands for Buffers Visiting Files, Up: Miscellaneous - -8.9 Minor Mode for Buffers Visiting Blobs -========================================= - -The ‘magit-blob-mode’ enables certain Magit features in blob-visiting -buffers. Such buffers can be created using ‘magit-find-file’ and some -of the commands mentioned below, which also take care of turning on this -minor mode. Currently this mode only establishes a few key bindings, -but this might be extended. - -‘p’ (‘magit-blob-previous’) - - Visit the previous blob which modified the current file. - -‘n’ (‘magit-blob-next’) - - Visit the next blob which modified the current file. - -‘q’ (‘magit-kill-this-buffer’) - - Kill the current buffer. - - -File: magit.info, Node: Customizing, Next: Plumbing, Prev: Miscellaneous, Up: Top - -9 Customizing -************* - -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 it -using both Git variables as well as Emacs options. However this -flexibility doesn’t come without problems, including but not limited to -the following. - - • Some Git variables automatically have an effect in Magit without - requiring any explicit support. Sometimes that is desirable - in - other cases, it breaks Magit. - - When a certain Git setting breaks Magit but you want to keep using - that setting on the command line, then that can be accomplished by - overriding the value for Magit only by appending something like - ‘("-c" "some.variable=compatible-value")’ to - ‘magit-git-global-arguments’. - - • Certain settings like ‘fetch.prune=true’ are respected by Magit - commands (because they simply call the respective Git command) but - their value is not reflected in the respective transient buffers. - In this case the ‘--prune’ argument in ‘magit-fetch’ might be - active or inactive, but that doesn’t keep the Git variable from - being honored by the suffix commands anyway. So pruning might - happen despite the ‘--prune’ arguments being displayed in a way - that seems to indicate that no pruning will happen. - - I intend to address these and similar issues in a future release. - -* Menu: - -* Per-Repository Configuration:: -* Essential Settings:: - - -File: magit.info, Node: Per-Repository Configuration, Next: Essential Settings, Up: Customizing - -9.1 Per-Repository Configuration -================================ - -Magit can be configured on a per-repository level using both Git -variables as well as Emacs options. - - To set a Git variable for one repository only, simply set it in -‘/path/to/repo/.git/config’ instead of ‘$HOME/.gitconfig’ or -‘/etc/gitconfig’. See *note (gitman)git-config::. - - Similarly, Emacs options can be set for one repository only by -editing ‘/path/to/repo/.dir-locals.el’. See *note (emacs)Directory -Variables::. For example to disable automatic refreshes of -file-visiting buffers in just one huge repository use this: - - • ‘/path/to/huge/repo/.dir-locals.el’ - - ((nil . ((magit-refresh-buffers . nil)))) - - It might only be costly to insert certain information into Magit -buffers for repositories that are exceptionally large, in which case you -can disable the respective section inserters just for that repository: - - • ‘/path/to/tag/invested/repo/.dir-locals.el’ - - ((magit-status-mode - . ((eval . (magit-disable-section-inserter 'magit-insert-tags-header))))) - - -- Function: magit-disable-section-inserter fn - - This function disables the section inserter FN in the current - repository. It is only intended for use in ‘.dir-locals.el’ and - ‘.dir-locals-2.el’. - - If you want to apply the same settings to several, but not all, -repositories then keeping the repository-local config files in sync -would quickly become annoying. To avoid that you can create config -files for certain classes of repositories (e.g. "huge repositories") -and then include those files in the per-repository config files. For -example: - - • ‘/path/to/huge/repo/.git/config’ - - [include] - path = /path/to/huge-gitconfig - - • ‘/path/to/huge-gitconfig’ - - [status] - showUntrackedFiles = no - - • ‘$HOME/.emacs.d/init.el’ - - (dir-locals-set-class-variables 'huge-git-repository - '((nil . ((magit-refresh-buffers . nil))))) - - (dir-locals-set-directory-class - "/path/to/huge/repo/" 'huge-git-repository) - - -File: magit.info, Node: Essential Settings, Prev: Per-Repository Configuration, Up: Customizing - -9.2 Essential Settings -====================== - -The next two sections list and discuss several variables that many users -might want to customize, for safety and/or performance reasons. - -* Menu: - -* Safety:: -* Performance:: -* Default Bindings:: - - -File: magit.info, Node: Safety, Next: Performance, Up: Essential Settings - -9.2.1 Safety ------------- - -This section discusses various variables that you might want to change -(or *not* change) for safety reasons. - - Git keeps *committed* changes around long enough for users to recover -changes they have accidentally been deleted. It does not do the same -for *uncommitted* changes in the working tree and not even the index -(the staging area). Because Magit makes it so easy to modify -uncommitted changes, it also makes it easy to shoot yourself in the foot -in the process. For that reason Magit provides three global modes that -save *tracked* files to work-in-progress references after or before -certain actions. See *note Wip Modes::. - - These modes are not enabled by default because of performance -concerns. Instead a lot of potentially destructive commands require -confirmation every time they are used. In many cases this can be -disabled by adding a symbol to ‘magit-no-confirm’ (see *note Completion -and Confirmation::). If you enable the various wip modes then you -should add ‘safe-with-wip’ to this list. - - Similarly it isn’t necessary to require confirmation before moving a -file to the system trash - if you trashed a file by mistake then you can -recover it from there. Option ‘magit-delete-by-moving-to-trash’ -controls whether the system trash is used, which is the case by default. -Nevertheless, ‘trash’ isn’t a member of ‘magit-no-confirm’ - you might -want to change that. - - By default buffers visiting files are automatically reverted when the -visited file changes on disk. This isn’t as risky as it might seem, but -to make an informed decision you should see *note Risk of Reverting -Automatically::. - - -File: magit.info, Node: Performance, Next: Default Bindings, Prev: Safety, Up: Essential Settings - -9.2.2 Performance ------------------ - -After Magit has run ‘git’ for side-effects, it also refreshes the -current Magit buffer and the respective status buffer. This is -necessary because otherwise outdated information might be displayed -without the user noticing. Magit buffers are updated by recreating -their content from scratch, which makes updating simpler and less -error-prone, but also more costly. Keeping it simple and just -re-creating everything from scratch is an old design decision and -departing from that will require major refactoring. - - I plan to do that in time for the next major release. I also intend -to create logs and diffs asynchronously, which should also help a lot -but also requires major refactoring. - - Meanwhile you can tell Magit to only automatically refresh the -current Magit buffer, but not the status buffer. If you do that, then -the status buffer is only refreshed automatically if it is the current -buffer. - - (setq magit-refresh-status-buffer nil) - - You should also check whether any third-party packages have added -anything to ‘magit-refresh-buffer-hook’, ‘magit-status-refresh-hook’, -‘magit-pre-refresh-hook’, and ‘magit-post-refresh-hook’. If so, then -check whether those additions impact performance significantly. - - Magit can be told to refresh buffers verbosely using ‘M-x -magit-toggle-verbose-refresh’. Enabling this helps figuring out which -sections are bottlenecks. The additional output can be found in the -‘*Messages*’ buffer. - - Magit also reverts buffers for visited files located inside the -current repository when the visited file changes on disk. That is -implemented on top of ‘auto-revert-mode’ from the built-in library -‘autorevert’. To figure out whether that impacts performance, check -whether performance is significantly worse, when many buffers exist -and/or when some buffers visit files using TRAMP. If so, then this -should help. - - (setq auto-revert-buffer-list-filter - 'magit-auto-revert-repository-buffer-p) - - For alternative approaches see *note Automatic Reverting of -File-Visiting Buffers::. - - If you have enabled any features that are disabled by default, then -you should check whether they impact performance significantly. It’s -likely that they were not enabled by default because it is known that -they reduce performance at least in large repositories. - - If performance is only slow inside certain unusually large -repositories, then you might want to disable certain features on a -per-repository or per-repository-class basis only. See *note -Per-Repository Configuration::. For example it takes a long time to -determine the next and current tag in repository with exceptional -numbers of tags. It would therefore be a good idea to disable -‘magit-insert-tags-headers’, as explained at the mentioned node. - -* Menu: - -* Microsoft Windows Performance:: -* MacOS Performance:: - -Log Performance -............... - -When showing logs, Magit limits the number of commits initially shown in -the hope that this avoids unnecessary work. When using ‘--graph’ is -used, then this unfortunately does not have the desired effect for large -histories. Junio, Git’s maintainer, said on the git mailing list -(): "‘--graph’ wants to -compute the whole history and the max-count only affects the output -phase after ‘--graph’ does its computation". - - In other words, it’s not that Git is slow at outputting the -differences, or that Magit is slow at parsing the output - the problem -is that Git first goes outside and has a smoke. - - We actually work around this issue by limiting the number of commits -not only by using ‘-’ but by also using a range. But unfortunately -that’s not always possible. - - When more than a few thousand commits are shown, then the use of -‘--graph’ can slow things down. - - Using ‘--color --graph’ is even slower. Magit uses code that is part -of Emacs to turn control characters into faces. That code is pretty -slow and this is quite noticeable when showing a log with many branches -and merges. For that reason ‘--color’ is not enabled by default -anymore. Consider leaving it at that. - -Diff Performance -................ - -If diffs are slow, then consider turning off some optional diff features -by setting all or some of the following variables to ‘nil’: -‘magit-diff-highlight-indentation’, ‘magit-diff-highlight-trailing’, -‘magit-diff-paint-whitespace’, ‘magit-diff-highlight-hunk-body’, and -‘magit-diff-refine-hunk’. - - When showing a commit instead of some arbitrary diff, then some -additional information is displayed. Calculating this information can -be quite expensive given certain circumstances. If looking at a commit -using ‘magit-revision-mode’ takes considerably more time than looking at -the same commit in ‘magit-diff-mode’, then consider setting -‘magit-revision-insert-related-refs’ to ‘nil’. - - When you are often confronted with diffs that contain deleted files, -then you might want to enable the ‘--irreversible-delete’ argument. If -you do that then diffs still show that a file was deleted but without -also showing the complete deleted content of the file. This argument is -not available by default, see *note (transient)Enabling and Disabling -Suffixes::. Once you have done that you should enable it and save that -setting, see *note (transient)Saving Values::. You should do this in -both the diff (‘d’) and the diff refresh (‘D’) transient popups. - -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 -address that is to display fewer refs, obviously. - - If you are not, or only mildly, interested in seeing the list of -tags, then start by not displaying them: - - (remove-hook 'magit-refs-sections-hook 'magit-insert-tags) - - Then you should also make sure that the listed remote branches -actually all exist. You can do so by pruning branches which no longer -exist using ‘f-pa’. - -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 can -take a long time, which is especially distracting when you are -committing large amounts of generated data which you don’t actually -intend to inspect before committing. This behavior can be turned off -using: - - (remove-hook 'server-switch-hook 'magit-commit-diff) - - Then you can type ‘C-c C-d’ to show the diff when you actually want -to see it, but only then. Alternatively you can leave the hook alone -and just type ‘C-g’ in those cases when it takes too long to generate -the diff. If you do that, then you will end up with a broken diff -buffer, but doing it this way has the advantage that you usually get to -see the diff, which is useful because it increases the odds that you -spot potential issues. - - -File: magit.info, Node: Microsoft Windows Performance, Next: MacOS Performance, Up: Performance - -Microsoft Windows Performance -............................. - -In order to update the status buffer, ‘git’ has to be run a few dozen -times. That is problematic on Microsoft Windows, because that operating -system is exceptionally slow at starting processes. Sadly this is an -issue that can only be fixed by Microsoft itself, and they don’t appear -to be particularly interested in doing so. - - Beside the subprocess issue, there are also other Windows-specific -performance issues. Some of these have workarounds. The maintainers of -"Git for Windows" try to improve performance on Windows. Always use the -latest release in order to benefit from the latest performance tweaks. -Magit too tries to work around some Windows-specific issues. - - According to some sources, setting the following Git variables can -also help. - - git config --global core.preloadindex true # default since v2.1 - git config --global core.fscache true # default since v2.8 - git config --global gc.auto 256 - - You should also check whether an anti-virus program is affecting -performance. - - -File: magit.info, Node: MacOS Performance, Prev: Microsoft Windows Performance, Up: Performance - -MacOS Performance -................. - -Before Emacs 26.1 child processes were created using ‘fork’ on macOS. -That needlessly copied GUI resources, which is expensive. The result -was that forking took about 30 times as long on Darwin than on Linux, -and because Magit starts many ‘git’ processes that made quite a -difference. - - So make sure that you are using at least Emacs 26.1, in which case -the faster ‘vfork’ will be used. (The creation of child processes still -takes about twice as long on Darwin compared to Linux.) See (1) for -more information. - - ---------- Footnotes ---------- - - (1) - - - -File: magit.info, Node: Default Bindings, Prev: Performance, Up: Essential Settings - -9.2.3 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. - - (global-set-key (kbd "C-c g") 'magit-file-dispatch) - - Also see *note Commands for Buffers Visiting Files:: and *note - (elisp)Key Binding Conventions::. - - -File: magit.info, Node: Plumbing, Next: FAQ, Prev: Customizing, Up: Top - -10 Plumbing -*********** - -The following sections describe how to use several of Magit’s core -abstractions to extend Magit itself or implement a separate extension. - - A few of the low-level features used by Magit have been factored out -into separate libraries/packages, so that they can be used by other -packages, without having to depend on Magit. See *note -(with-editor)Top:: for information about ‘with-editor’. ‘transient’ -doesn’t have a manual yet. - - If you are trying to find an unused key that you can bind to a -command provided by your own Magit extension, then checkout -. - -* Menu: - -* Calling Git:: -* Section Plumbing:: -* Refreshing Buffers:: -* Conventions:: - - -File: magit.info, Node: Calling Git, Next: Section Plumbing, Up: Plumbing - -10.1 Calling Git -================ - -Magit provides many specialized functions for calling Git. All of these -functions are defined in either ‘magit-git.el’ or ‘magit-process.el’ and -have one of the prefixes ‘magit-run-’, ‘magit-call-’, ‘magit-start-’, or -‘magit-git-’ (which is also used for other things). - - All of these functions accept an indefinite number of arguments, -which are strings that specify command line arguments for Git (or in -some cases an arbitrary executable). These arguments are flattened -before being passed on to the executable; so instead of strings they can -also be lists of strings and arguments that are ‘nil’ are silently -dropped. Some of these functions also require a single mandatory -argument before these command line arguments. - - Roughly speaking, these functions run Git either to get some value or -for side-effects. The functions that return a value are useful to -collect the information necessary to populate a Magit buffer, while the -others are used to implement Magit commands. - - The functions in the value-only group always run synchronously, and -they never trigger a refresh. The function in the side-effect group can -be further divided into subgroups depending on whether they run Git -synchronously or asynchronously, and depending on whether they trigger a -refresh when the executable has finished. - -* Menu: - -* Getting a Value from Git:: -* Calling Git for Effect:: - - -File: magit.info, Node: Getting a Value from Git, Next: Calling Git for Effect, Up: Calling Git - -10.1.1 Getting a Value from Git -------------------------------- - -These functions run Git in order to get a value, an exit status, or -output. Of course you could also use them to run Git commands that have -side-effects, but that should be avoided. - - -- Function: magit-git-exit-code &rest args - - Executes git with ARGS and returns its exit code. - - -- Function: magit-git-success &rest args - - Executes git with ARGS and returns ‘t’ if the exit code is ‘0’, - ‘nil’ otherwise. - - -- Function: magit-git-failure &rest args - - Executes git with ARGS and returns ‘t’ if the exit code is ‘1’, - ‘nil’ otherwise. - - -- Function: magit-git-true &rest args - - Executes git with ARGS and returns ‘t’ if the first line printed by - git is the string "true", ‘nil’ otherwise. - - -- Function: magit-git-false &rest args - - Executes git with ARGS and returns ‘t’ if the first line printed by - git is the string "false", ‘nil’ otherwise. - - -- Function: magit-git-insert &rest args - - Executes git with ARGS and inserts its output at point. - - -- Function: magit-git-string &rest args - - Executes git with ARGS and returns the first line of its output. - If there is no output or if it begins with a newline character, - then this returns ‘nil’. - - -- Function: magit-git-lines &rest args - - Executes git with ARGS and returns its output as a list of lines. - Empty lines anywhere in the output are omitted. - - -- Function: magit-git-items &rest args - - Executes git with ARGS and returns its null-separated output as a - list. Empty items anywhere in the output are omitted. - - If the value of option ‘magit-git-debug’ is non-nil and git exits - with a non-zero exit status, then warn about that in the echo area - and 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 they occur we -need to be able to debug them. - - -- User Option: magit-git-debug - - Whether to report errors that occur when using ‘magit-git-insert’, - ‘magit-git-string’, ‘magit-git-lines’, or ‘magit-git-items’. This - does not actually raise an error. Instead a message is shown in - the echo area, and git’s standard error is insert into a new - section in the current repository’s process buffer. - - -- Function: magit-git-str &rest args - - This is a variant of ‘magit-git-string’ that ignores the option - ‘magit-git-debug’. It is mainly intended to be used while handling - errors in functions that do respect that option. Using such a - function while handing an error could cause yet another error and - therefore lead to an infinite recursion. You probably won’t ever - need to use this function. - - -File: magit.info, Node: Calling Git for Effect, Prev: Getting a Value from Git, Up: Calling Git - -10.1.2 Calling Git for Effect ------------------------------ - -These functions are used to run git to produce some effect. Most Magit -commands that actually run git do so by using such a function. - - Because we do not need to consume git’s output when using these -functions, their output is instead logged into a per-repository buffer, -which can be shown using ‘$’ from a Magit buffer or ‘M-x magit-process’ -elsewhere. - - These functions can have an effect in two distinct ways. Firstly, -running git may change something, i.e. create or push a new commit. -Secondly, that change may require that Magit buffers are refreshed to -reflect the changed state of the repository. But refreshing isn’t -always desirable, so only some of these functions do perform such a -refresh after git has returned. - - Sometimes it is useful to run git asynchronously. For example, when -the user has just initiated a push, then there is no reason to make her -wait until that has completed. In other cases it makes sense to wait -for git to complete before letting the user do something else. For -example after staging a change it is useful to wait until after the -refresh because that also automatically moves to the next change. - - -- Function: magit-call-git &rest args - - Calls git synchronously with ARGS. - - -- Function: magit-call-process program &rest args - - Calls PROGRAM synchronously with ARGS. - - -- Function: magit-run-git &rest args - - Calls git synchronously with ARGS and then refreshes. - - -- Function: magit-run-git-with-input &rest args - - Calls git synchronously with ARGS and sends it the content of the - current buffer on standard input. - - 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 - - Calls git synchronously with ARGS for side-effects only. This - function does not refresh the buffer. - - -- Function: magit-git-wash washer &rest args - - Execute Git with ARGS, inserting washed output at point. Actually - first insert the raw output at point. If there is no output call - ‘magit-cancel-section’. Otherwise temporarily narrow the buffer to - the inserted text, move to its beginning, and then call function - WASHER with ARGS as its sole argument. - - And now for the asynchronous variants. - - -- Function: magit-run-git-async &rest args - - Start Git, prepare for refresh, and return the process object. - ARGS is flattened and then used as arguments to Git. - - Display the command line arguments in the echo area. - - After Git returns some buffers are refreshed: the buffer that was - current when this function was called (if it is a Magit buffer and - still alive), as well as the respective Magit status buffer. - Unmodified buffers visiting files that are tracked in the current - repository are reverted if ‘magit-revert-buffers’ is non-nil. - - -- Function: magit-run-git-with-editor &rest args - - Export GIT_EDITOR and start Git. Also prepare for refresh and - return the process object. ARGS is flattened and then used as - arguments to Git. - - Display the command line arguments in the echo area. - - After Git returns some buffers are refreshed: the buffer that was - 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 input &rest args - - Start Git, prepare for refresh, and return the process object. - - If INPUT is non-nil, it has to be a buffer or the name of an - existing buffer. The buffer content becomes the processes standard - input. - - Option ‘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. - - After Git returns, some buffers are refreshed: the buffer that was - current when this function was called (if it is a Magit buffer and - still alive), as well as the respective Magit status buffer. - Unmodified buffers visiting files that are tracked in the current - repository are reverted if ‘magit-revert-buffers’ is non-nil. - - -- Function: magit-start-process &rest args - - Start PROGRAM, prepare for refresh, and return the process object. - - If optional argument INPUT is non-nil, it has to be a buffer or the - name of an existing buffer. The buffer content becomes the - processes standard input. - - The process is started using ‘start-file-process’ and then setup to - use the sentinel ‘magit-process-sentinel’ and the filter - ‘magit-process-filter’. Information required by these functions is - stored in the process object. When this function returns the - process has not started to run yet so it is possible to override - the sentinel and filter. - - After the process returns, ‘magit-process-sentinel’ refreshes the - buffer that was current when ‘magit-start-process’ was called (if - it is a Magit buffer and still alive), as well as the respective - Magit status buffer. Unmodified buffers visiting files that are - tracked in the current repository are reverted if - ‘magit-revert-buffers’ is non-nil. - - -- Variable: magit-this-process - - The child process which is about to start. This can be used to - change the filter and sentinel. - - -- Variable: magit-process-raise-error - - When this is non-nil, then ‘magit-process-sentinel’ raises an error - if git exits with a non-zero exit status. For debugging purposes. - - -File: magit.info, Node: Section Plumbing, Next: Refreshing Buffers, Prev: Calling Git, Up: Plumbing - -10.2 Section Plumbing -===================== - -* Menu: - -* Creating Sections:: -* Section Selection:: -* Matching Sections:: - - -File: magit.info, Node: Creating Sections, Next: Section Selection, Up: Section Plumbing - -10.2.1 Creating Sections ------------------------- - - -- Macro: magit-insert-section &rest args - - 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. Also if - a variable ‘magit-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. - - Optional VALUE is the value of the section, usually a string that - is required when acting on the section. - - When optional HIDE is non-nil collapse the section body by default, - i.e. when first creating the section, but not when refreshing the - buffer. Otherwise, expand it by default. This can be overwritten - using ‘magit-section-set-visibility-hook’. When a section is - recreated during a refresh, then the visibility of predecessor is - inherited and HIDE is ignored (but the hook is still honored). - - BODY is any number of forms that actually insert the section’s - heading and body. Optional NAME, if specified, has to be a symbol, - which is then bound to the struct of the section being inserted. - - Before BODY is evaluated the ‘start’ of the section object is set - to the value of ‘point’ and after BODY was evaluated its ‘end’ is - set to the new value of ‘point’; BODY is responsible for moving - ‘point’ forward. - - If it turns out inside BODY that the section is empty, then - ‘magit-cancel-section’ can be used to abort and remove all traces - 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. - - -- Function: magit-insert-heading &rest args - - Insert the heading for the section currently being inserted. - - This function should only be used inside ‘magit-insert-section’. - - When called without any arguments, then just set the ‘content’ slot - of the object representing the section being inserted to a marker - at ‘point’. The section should only contain a single line when - this function is used like this. - - When called with arguments ARGS, which have to be strings, then - insert those strings at point. The section should not contain any - text before this happens and afterwards it should again only - contain a single line. If the ‘face’ property is set anywhere - inside any of these strings, then insert all of them unchanged. - Otherwise use the ‘magit-section-heading’ face for all inserted - text. - - The ‘content’ property of the section struct is the end of the - heading (which lasts from ‘start’ to ‘content’) and the beginning - of the body (which lasts from ‘content’ to ‘end’). If the value of - ‘content’ is nil, then the section has no heading and its body - cannot be collapsed. If a section does have a heading then its - height must be exactly one line, including a trailing newline - character. This isn’t enforced; you are responsible for getting it - right. The only exception is that this function does insert a - newline character if necessary. - - -- Function: magit-cancel-section - - Cancel the section currently being inserted. This exits the - innermost call to ‘magit-insert-section’ and removes all traces of - what has already happened inside that call. - - -- Function: magit-define-section-jumper sym title &optional value - - Define an interactive function to go to section SYM. TITLE is the - displayed title of the section. - - -File: magit.info, Node: Section Selection, Next: Matching Sections, Prev: Creating Sections, Up: Section Plumbing - -10.2.2 Section Selection ------------------------- - - -- Function: magit-current-section - - Return the section at point. - - -- Function: magit-region-sections &optional condition multiple - - Return a list of the selected sections. - - When the region is active and constitutes a valid section - selection, then return a list of all selected sections. This is - the case when the region begins in the heading of a section and - ends in the heading of the same section or in that of a sibling - section. If optional MULTIPLE is non-nil, then the region cannot - begin and end in the same section. - - When the selection is not valid, then return nil. In this case, - most commands that can act on the selected sections will instead - act on the section at point. - - When the region looks like it would in any other buffer then the - selection is invalid. When the selection is valid then the region - uses the ‘magit-section-highlight’ face. This does not apply to - diffs where things get a bit more complicated, but even here if the - region looks like it usually does, then that’s not a valid - selection as far as this function is concerned. - - If optional CONDITION is non-nil, then the selection not only has - to be valid; all selected sections additionally have to match - CONDITION, or nil is returned. See ‘magit-section-match’ for the - forms CONDITION can take. - - -- Function: magit-region-values &optional condition multiple - - Return a list of the values of the selected sections. - - Return the values that themselves would be returned by - ‘magit-region-sections’ (which see). - - -File: magit.info, Node: Matching Sections, Prev: Section Selection, Up: Section Plumbing - -10.2.3 Matching Sections ------------------------- - -‘M-x magit-describe-section-briefly’ (‘magit-describe-section-briefly’) - - Show information about the section at point. This command is - intended for debugging purposes. - - -- Function: magit-section-ident section - - Return an unique identifier for SECTION. The return value has the - form ‘((TYPE . VALUE)...)’. - - -- Function: magit-get-section ident &optional root - - Return the section identified by IDENT. IDENT has to be a list as - returned by ‘magit-section-ident’. - - -- Function: magit-section-match condition &optional section - - Return ‘t’ if SECTION matches CONDITION. SECTION defaults to the - section at point. If SECTION is not specified and there also is no - section at point, then return ‘nil’. - - CONDITION can take the following forms: - • ‘(CONDITION...)’ - - matches if any of the CONDITIONs matches. - - • ‘[CLASS...]’ - - matches if the section’s class is the same as the first CLASS - or a subclass of that; the section’s parent class matches the - second CLASS; and so on. - - • ‘[* CLASS...]’ - - matches sections that match ‘[CLASS...]’ and also recursively - all their child sections. - - • ‘CLASS’ - - matches if the section’s class is the same as CLASS or a - subclass of that; regardless of the classes of the parent - sections. - - Each CLASS should be a class symbol, identifying a class that - derives from ‘magit-section’. For backward compatibility CLASS can - also be a "type symbol". A section matches such a symbol if the - value of its ‘type’ slot is ‘eq’. If a type symbol has an entry in - ‘magit--section-type-alist’, then a section also matches that type - if its class is a subclass of the class that corresponds to the - type as per that alist. - - Note that it is not necessary to specify the complete section - lineage as printed by ‘magit-describe-section-briefly’, unless of - course you want to be that precise. - - -- Function: magit-section-value-if condition &optional section - - If the section at point matches CONDITION, then return its value. - - If optional SECTION is non-nil then test whether that matches - instead. If there is no section at point and SECTION is nil, then - return nil. If the section does not match, then return nil. - - See ‘magit-section-match’ for the forms CONDITION can take. - - -- Function: magit-section-case &rest clauses - - Choose among clauses on the type of the section at point. - - Each clause looks like (CONDITION BODY...). The type of the - section is compared against each CONDITION; the BODY forms of the - first match are evaluated sequentially and the value of the last - form is returned. Inside BODY the symbol ‘it’ is bound to the - section at point. If no clause succeeds or if there is no section - at point return nil. - - See ‘magit-section-match’ for the forms CONDITION can take. - Additionally a CONDITION of t is allowed in the final clause and - matches if no other CONDITION match, even if there is no section at - point. - - -- Variable: magit-root-section - - The root section in the current buffer. All other sections are - descendants of this section. The value of this variable is set by - ‘magit-insert-section’ and you should never modify it. - - For diff related sections a few additional tools exist. - - -- Function: magit-diff-type &optional section - - Return the diff type of SECTION. - - The returned type is one of the symbols ‘staged’, ‘unstaged’, - ‘committed’, or ‘undefined’. This type serves a similar purpose as - the general type common to all sections (which is stored in the - ‘type’ slot of the corresponding ‘magit-section’ struct) but takes - additional information into account. When the SECTION isn’t - related to diffs and the buffer containing it also isn’t a - diff-only buffer, then return nil. - - Currently the type can also be one of ‘tracked’ and ‘untracked’, - but these values are not handled explicitly in every place they - should be. A possible fix could be to just return nil here. - - The section has to be a ‘diff’ or ‘hunk’ section, or a section - whose children are of type ‘diff’. If optional SECTION is nil, - return the diff type for the current section. In buffers whose - major mode is ‘magit-diff-mode’ SECTION is ignored and the type is - determined using other means. In ‘magit-revision-mode’ buffers the - type is always ‘committed’. - - -- Function: magit-diff-scope &optional section strict - - Return the diff scope of SECTION or the selected section(s). - - A diff’s "scope" describes what part of a diff is selected, it is a - symbol, one of ‘region’, ‘hunk’, ‘hunks’, ‘file’, ‘files’, or - ‘list’. Do not confuse this with the diff "type", as returned by - ‘magit-diff-type’. - - If optional SECTION is non-nil, then return the scope of that, - ignoring the sections selected by the region. Otherwise return the - scope of the current section, or if the region is active and - selects a valid group of diff related sections, the type of these - sections, i.e. ‘hunks’ or ‘files’. If SECTION (or if the current - section that is nil) is a ‘hunk’ section and the region starts and - ends inside the body of a that section, then the type is ‘region’. - - If optional STRICT is non-nil then return nil if the diff type of - the section at point is ‘untracked’ or the section at point is not - actually a ‘diff’ but a ‘diffstat’ section. - - -File: magit.info, Node: Refreshing Buffers, Next: Conventions, Prev: Section Plumbing, Up: Plumbing - -10.3 Refreshing Buffers -======================= - -All commands that create a new Magit buffer or change what is being -displayed in an existing buffer do so by calling ‘magit-mode-setup’. -Among other things, that function sets the buffer local values of -‘default-directory’ (to the top-level of the repository), -‘magit-refresh-function’, and ‘magit-refresh-args’. - - Buffers are refreshed by calling the function that is the local value -of ‘magit-refresh-function’ (a function named ‘magit-*-refresh-buffer’, -where ‘*’ may be something like ‘diff’) with the value of -‘magit-refresh-args’ as arguments. - - -- Macro: magit-mode-setup buffer switch-func mode refresh-func - &optional refresh-args - - This function displays and selects BUFFER, turns on MODE, and - refreshes a first time. - - This function displays and optionally selects BUFFER by calling - ‘magit-mode-display-buffer’ with BUFFER, MODE and SWITCH-FUNC as - arguments. Then it sets the local value of - ‘magit-refresh-function’ to REFRESH-FUNC and that of - ‘magit-refresh-args’ to REFRESH-ARGS. Finally it creates the - buffer content by calling REFRESH-FUNC with REFRESH-ARGS as - arguments. - - All arguments are evaluated before switching to BUFFER. - - -- Function: magit-mode-display-buffer buffer mode &optional - switch-function - - This function display BUFFER in some window and select it. BUFFER - may be a buffer or a string, the name of a buffer. The buffer is - returned. - - Unless BUFFER is already displayed in the selected frame, store the - previous window configuration as a buffer local value, so that it - can later be restored by ‘magit-mode-bury-buffer’. - - The buffer is displayed and selected using SWITCH-FUNCTION. If - that is ‘nil’ then ‘pop-to-buffer’ is used if the current buffer’s - major mode derives from ‘magit-mode’. Otherwise ‘switch-to-buffer’ - is used. - - -- Variable: magit-refresh-function - - The value of this buffer-local variable is the function used to - refresh the current buffer. It is called with ‘magit-refresh-args’ - as arguments. - - -- Variable: magit-refresh-args - - The list of arguments used by ‘magit-refresh-function’ to refresh - the current buffer. ‘magit-refresh-function’ is called with these - arguments. - - The value is usually set using ‘magit-mode-setup’, but in some - cases it’s also useful to provide commands that can change the - value. For example, the ‘magit-diff-refresh’ transient can be used - to change any of the arguments used to display the diff, without - having to specify again which differences should be shown, but - ‘magit-diff-more-context’, ‘magit-diff-less-context’ and - ‘magit-diff-default-context’ change just the ‘-U’ argument. In - both case this is done by changing the value of this variable and - then calling this ‘magit-refresh-function’. - - -File: magit.info, Node: Conventions, Prev: Refreshing Buffers, Up: Plumbing - -10.4 Conventions -================ - -Also see *note Completion and Confirmation::. - -* Menu: - -* Theming Faces:: - - -File: magit.info, Node: Theming Faces, Up: Conventions - -10.4.1 Theming Faces --------------------- - -The default theme uses blue for local branches, green for remote -branches, and goldenrod (brownish yellow) for tags. When creating a new -theme, you should probably follow that example. If your theme already -uses other colors, then stick to that. - - In older releases these reference faces used to have a background -color and a box around them. The basic default faces no longer do so, -to make Magit buffers much less noisy, and you should follow that -example at least with regards to boxes. (Boxes were used in the past to -work around a conflict between the highlighting overlay and text -property backgrounds. That’s no longer necessary because highlighting -no longer causes other background colors to disappear.) Alternatively -you can keep the background color and/or box, but then have to take -special care to adjust ‘magit-branch-current’ accordingly. By default -it looks mostly like ‘magit-branch-local’, but with a box (by default -the former is the only face that uses a box, exactly so that it sticks -out). If the former also uses a box, then you have to make sure that it -differs in some other way from the latter. - - The most difficult faces to theme are those related to diffs, -headings, highlighting, and the region. There are faces that fall into -all four groups - expect to spend some time getting this right. - - The ‘region’ face in the default theme, in both the light and dark -variants, as well as in many other themes, distributed with Emacs or by -third-parties, is very ugly. It is common to use a background color -that really sticks out, which is ugly but if that were the only problem -then it would be acceptable. Unfortunately many themes also set the -foreground color, which ensures that all text within the region is -readable. Without doing that there might be cases where some foreground -color is too close to the region background color to still be readable. -But it also means that text within the region loses all syntax -highlighting. - - I consider the work that went into getting the ‘region’ face right to -be a good indicator for the general quality of a theme. My -recommendation for the ‘region’ face is this: use a background color -slightly different from the background color of the ‘default’ face, and -do not set the foreground color at all. So for a light theme you might -use a light (possibly tinted) gray as the background color of ‘default’ -and a somewhat darker gray for the background of ‘region’. That should -usually be enough to not collide with the foreground color of any other -face. But if some other faces also set a light gray as background -color, then you should also make sure it doesn’t collide with those (in -some cases it might be acceptable though). - - Magit only uses the ‘region’ face when the region is "invalid" by its -own definition. In a Magit buffer the region is used to either select -multiple sibling sections, so that commands which support it act on all -of these sections instead of just the current section, or to select -lines within a single hunk section. In all other cases, the section is -considered invalid and Magit won’t act on it. But such invalid sections -happen, either because the user has not moved point enough yet to make -it valid or because she wants to use a non-magit command to act on the -region, e.g. ‘kill-region’. - - So using the regular ‘region’ face for invalid sections is a feature. -It tells the user that Magit won’t be able to act on it. It’s -acceptable if that face looks a bit odd and even (but less so) if it -collides with the background colors of section headings and other things -that have a background color. - - Magit highlights the current section. If a section has subsections, -then all of them are highlighted. This is done using faces that have -"highlight" in their names. For most sections, -‘magit-section-highlight’ is used for both the body and the heading. -Like the ‘region’ face, it should only set the background color to -something similar to that of ‘default’. The highlight background color -must be different from both the ‘region’ background color and the -‘default’ background color. - - For diff related sections Magit uses various faces to highlight -different parts of the selected section(s). Note that hunk headings, -unlike all other section headings, by default have a background color, -because it is useful to have very visible separators between hunks. -That face ‘magit-diff-hunk-heading’, should be different from both -‘magit-diff-hunk-heading-highlight’ and ‘magit-section-highlight’, as -well as from ‘magit-diff-context’ and ‘magit-diff-context-highlight’. -By default we do that by changing the foreground color. Changing the -background color would lead to complications, and there are already -enough we cannot get around. (Also note that it is generally a good -idea for section headings to always be bold, but only for sections that -have subsections). - - When there is a valid region selecting diff-related sibling sections, -i.e. multiple files or hunks, then the bodies of all these sections use -the respective highlight faces, but additionally the headings instead -use one of the faces ‘magit-diff-file-heading-selection’ or -‘magit-diff-hunk-heading-selection’. These faces have to be different -from the regular highlight variants to provide explicit visual -indication that the region is active. - - When theming diff related faces, start by setting the option -‘magit-diff-refine-hunk’ to ‘all’. You might personally prefer to only -refine the current hunk or not use hunk refinement at all, but some of -the users of your theme want all hunks to be refined, so you have to -cater to that. - - (Also turn on ‘magit-diff-highlight-indentation’, -‘magit-diff-highlight-trailing’, and ‘magit-diff-paint-whitespace’; and -insert some whitespace errors into the code you use for testing.) - - For e.g. "added lines" you have to adjust three faces: -‘magit-diff-added’, ‘magit-diff-added-highlight’, and -‘smerge-refined-added’. Make sure that the latter works well with both -of the former, as well as ‘smerge-other’ and ‘diff-added’. Then do the -same for the removed lines, context lines, lines added by us, and lines -added by them. Also make sure the respective added, removed, and -context faces use approximately the same saturation for both the -highlighted and unhighlighted variants. Also make sure the file and -diff headings work nicely with context lines (e.g. make them look -different). Line faces should set both the foreground and the -background color. For example, for added lines use two different -greens. - - It’s best if the foreground color of both the highlighted and the -unhighlighted variants are the same, so you will need to have to find a -color that works well on the highlight and unhighlighted background, the -refine background, and the highlight context background. When there is -an hunk internal region, then the added- and removed-lines background -color is used only within that region. Outside the region the -highlighted context background color is used. This makes it easier to -see what is being staged. With an hunk internal region the hunk heading -is shown using ‘magit-diff-hunk-heading-selection’, and so are the thin -lines that are added around the lines that fall within the region. The -background color of that has to be distinct enough from the various -other involved background colors. - - Nobody said this would be easy. If your theme restricts itself to a -certain set of colors, then you should make an exception here. -Otherwise it would be impossible to make the diffs look good in each and -every variation. Actually you might want to just stick to the default -definitions for these faces. You have been warned. Also please note -that if you do not get this right, this will in some cases look to users -like bugs in Magit - so please do it right or not at all. - - -File: magit.info, Node: FAQ, Next: Debugging Tools, Prev: Plumbing, Up: Top - -Appendix A FAQ -************** - -The next two nodes lists frequently asked questions. For a list of -frequently *and recently* asked questions, i.e. questions that haven’t -made it into the manual yet, see -. - - Please also use the *note Debugging Tools::. - -* Menu: - -* FAQ - How to ...?:: -* FAQ - Issues and Errors:: - - -File: magit.info, Node: FAQ - How to ...?, Next: FAQ - Issues and Errors, Up: FAQ - -A.1 FAQ - How to ...? -===================== - -* 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 ediff-version-control-package?:: -* Should I disable VC?:: - - -File: magit.info, Node: How to pronounce Magit?, Next: How to show git's output?, Up: FAQ - How to ...? - -A.1.1 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 . Also see -. - - -File: magit.info, Node: How to show git's output?, Next: How to install the gitman info manual?, Prev: How to pronounce Magit?, Up: FAQ - How to ...? - -A.1.2 How to show git’s output? -------------------------------- - -To show the output of recently run git commands, press ‘$’ (or, if that -isn’t available, ‘M-x magit-process-buffer’). This will show a buffer -containing a section per git invocation; as always press ‘TAB’ to expand -or collapse them. - - By default, git’s output is only inserted into the process buffer if -it is run for side-effects. When the output is consumed in some way, -also inserting it into the process buffer would be too expensive. For -debugging purposes, it’s possible to do so anyway by setting -‘magit-git-debug’ to ‘t’. - - -File: magit.info, Node: How to install the gitman info manual?, Next: How to show diffs for gpg-encrypted files?, Prev: How to show git's output?, Up: FAQ - How to ...? - -A.1.3 How to install the gitman info manual? --------------------------------------------- - -Git’s manpages can be exported as an info manual called ‘gitman’. -Magit’s own info manual links to nodes in that manual instead of the -actual manpages because Info doesn’t support linking to manpages. - - Unfortunately some distributions do not install the ‘gitman’ manual -by default and you will have to install a separate documentation package -to get it. - - Magit patches Info adding the ability to visit links to the ‘gitman’ -Info manual by instead viewing the respective manpage. If you prefer -that approach, then set the value of ‘magit-view-git-manual-method’ to -one of the supported packages ‘man’ or ‘woman’, e.g.: - - (setq magit-view-git-manual-method 'man) - - -File: magit.info, Node: How to show diffs for gpg-encrypted files?, Next: How does branching and pushing work?, Prev: How to install the gitman info manual?, Up: FAQ - How to ...? - -A.1.4 How to show diffs for gpg-encrypted files? ------------------------------------------------- - -Git supports showing diffs for encrypted files, but has to be told to do -so. Since Magit just uses Git to get the diffs, configuring Git also -affects the diffs displayed inside Magit. - - git config --global diff.gpg.textconv "gpg --no-tty --decrypt" - echo "*.gpg filter=gpg diff=gpg" > .gitattributes - - -File: magit.info, Node: How does branching and pushing work?, Next: Can Magit be used as ediff-version-control-package?, Prev: How to show diffs for gpg-encrypted files?, Up: FAQ - How to ...? - -A.1.5 How does branching and pushing work? ------------------------------------------- - -Please see *note Branching:: and - - - -File: magit.info, Node: Can Magit be used as ediff-version-control-package?, Next: Should I disable VC?, Prev: How does branching and pushing work?, Up: FAQ - How to ...? - -A.1.6 Can Magit be used as ‘ediff-version-control-package’? ------------------------------------------------------------ - -No, it cannot. For that to work the functions ‘ediff-magit-internal’ -and ‘ediff-magit-merge-internal’ would have to be implemented, and they -are not. These two functions are only used by the three commands -‘ediff-revision’, ‘ediff-merge-revisions-with-ancestor’, and -‘ediff-merge-revisions’. - - These commands only delegate the task of populating buffers with -certain revisions to the "internal" functions. The equally important -task of determining which revisions are to be compared/merged is not -delegated. Instead this is done without any support whatsoever from the -version control package/system - meaning that the user has to enter the -revisions explicitly. Instead of implementing ‘ediff-magit-internal’ we -provide ‘magit-ediff-compare’, which handles both tasks like it is 2005. - - The other commands ‘ediff-merge-revisions’ and -‘ediff-merge-revisions-with-ancestor’ are normally not what you want -when using a modern version control system like Git. Instead of letting -the user resolve only those conflicts which Git could not resolve on its -own, they throw away all work done by Git and then expect the user to -manually merge all conflicts, including those that had already been -resolved. That made sense back in the days when version control systems -couldn’t merge (or so I have been told), but not anymore. Once in a -blue moon you might actually want to see all conflicts, in which case -you *can* use these commands, which then use ‘ediff-vc-merge-internal’. -So we don’t actually have to implement ‘ediff-magit-merge-internal’. -Instead we provide the more useful command ‘magit-ediff-resolve’ which -only shows yet-to-be resolved conflicts. - - -File: magit.info, Node: Should I disable VC?, Prev: Can Magit be used as ediff-version-control-package?, Up: FAQ - How to ...? - -A.1.7 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’. - - -File: magit.info, Node: FAQ - Issues and Errors, Prev: FAQ - How to ...?, Up: FAQ - -A.2 FAQ - Issues and Errors -=========================== - -* Menu: - -* Magit is slow:: -* I changed several thousand files at once and now Magit is unusable:: -* I am having problems committing:: -* I am using MS Windows and cannot push with Magit:: -* I am using OS X and SOMETHING works in shell, but not in Magit: I am using OS X and SOMETHING works in shell but not in Magit. -* Expanding a file to show the diff causes it to disappear:: -* Point is wrong in the COMMIT_EDITMSG buffer:: -* The mode-line information isn't always up-to-date:: -* A branch and tag sharing the same name breaks SOMETHING:: -* My Git hooks work on the command-line but not inside Magit:: -* 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:: - - -File: magit.info, Node: Magit is slow, Next: I changed several thousand files at once and now Magit is unusable, Up: FAQ - Issues and Errors - -A.2.1 Magit is slow -------------------- - -See *note Performance::. - - -File: magit.info, Node: I changed several thousand files at once and now Magit is unusable, Next: I am having problems committing, Prev: Magit is slow, Up: FAQ - Issues and Errors - -A.2.2 I changed several thousand files at once and now Magit is unusable ------------------------------------------------------------------------- - -Magit is *currently* not expected to work under such conditions. It -sure would be nice if it did, and v2.5 will hopefully be a big step into -that direction. But it might take until v3.1 to accomplish fully -satisfactory performance, because that requires some heavy refactoring. - - But for now we recommend you use the command line to complete this -one commit. Also see *note Performance::. - - -File: magit.info, Node: I am having problems committing, Next: I am using MS Windows and cannot push with Magit, Prev: I changed several thousand files at once and now Magit is unusable, Up: FAQ - Issues and Errors - -A.2.3 I am having problems committing -------------------------------------- - -That likely means that Magit is having problems finding an appropriate -emacsclient executable. See *note (with-editor)Configuring -With-Editor:: and *note (with-editor)Debugging::. - - -File: magit.info, Node: I am using MS Windows and cannot push with Magit, Next: I am using OS X and SOMETHING works in shell but not in Magit, Prev: I am having problems committing, Up: FAQ - Issues and Errors - -A.2.4 I am using MS Windows and cannot push with Magit ------------------------------------------------------- - -It’s almost certain that Magit is only incidental to this issue. It is -much more likely that this is a configuration issue, even if you can -push on the command line. - - Detailed setup instructions can be found at -. - - -File: magit.info, Node: I am using OS X and SOMETHING works in shell but not in Magit, Next: Expanding a file to show the diff causes it to disappear, Prev: I am using MS Windows and cannot push with Magit, Up: FAQ - Issues and Errors - -A.2.5 I am using OS X and SOMETHING works in shell, but not in Magit --------------------------------------------------------------------- - -This usually occurs because Emacs doesn’t have the same environment -variables as your shell. Try installing and configuring -. By default it -synchronizes ‘$PATH’, which helps Magit find the same ‘git’ as the one -you are using on the shell. - - If SOMETHING is "passphrase caching with gpg-agent for commit and/or -tag signing", then you’ll also need to synchronize ‘$GPG_AGENT_INFO’. - - -File: magit.info, Node: Expanding a file to show the diff causes it to disappear, Next: Point is wrong in the COMMIT_EDITMSG buffer, Prev: I am using OS X and SOMETHING works in shell but not in Magit, Up: FAQ - Issues and Errors - -A.2.6 Expanding a file to show the diff causes it to disappear --------------------------------------------------------------- - -This is probably caused by a change of a ‘diff.*’ Git variable. You -probably set that variable for a reason, and should therefore only undo -that setting in Magit by customizing ‘magit-git-global-arguments’. - - -File: magit.info, Node: Point is wrong in the COMMIT_EDITMSG buffer, Next: The mode-line information isn't always up-to-date, Prev: Expanding a file to show the diff causes it to disappear, Up: FAQ - Issues and Errors - -A.2.7 Point is wrong in the ‘COMMIT_EDITMSG’ buffer ---------------------------------------------------- - -Neither Magit nor ‘git-commit‘ fiddle with point in the buffer used to -write commit messages, so something else must be doing it. - - You have probably globally enabled a mode which does restore point in -file-visiting buffers. It might be a bit surprising, but when you write -a commit message, then you are actually editing a file. - - So you have to figure out which package is doing. ‘saveplace’, -‘pointback’, and ‘session’ are likely candidates. These snippets might -help: - - (setq session-name-disable-regexp "\\(?:\\`'\\.git/[A-Z_]+\\'\\)") - - (with-eval-after-load 'pointback - (lambda () - (when (or git-commit-mode git-rebase-mode) - (pointback-mode -1)))) - - -File: magit.info, Node: The mode-line information isn't always up-to-date, Next: A branch and tag sharing the same name breaks SOMETHING, Prev: Point is wrong in the COMMIT_EDITMSG buffer, Up: FAQ - Issues and Errors - -A.2.8 The mode-line information isn’t always up-to-date -------------------------------------------------------- - -Magit is not responsible for the version control information that is -being displayed in the mode-line and looks something like ‘Git-master’. -The built-in "Version Control" package, also known as "VC", updates that -information, and can be told to do so more often: - - (setq auto-revert-check-vc-info t) - - But doing so isn’t good for performance. For more (overly -optimistic) information see *note (emacs)VC Mode Line::. - - 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: - - (setq-default mode-line-format - (delete '(vc-mode vc-mode) mode-line-format)) - - -File: magit.info, Node: A branch and tag sharing the same name breaks SOMETHING, Next: My Git hooks work on the command-line but not inside Magit, Prev: The mode-line information isn't always up-to-date, Up: FAQ - Issues and Errors - -A.2.9 A branch and tag sharing the same name breaks SOMETHING -------------------------------------------------------------- - -Or more generally, ambiguous refnames break SOMETHING. - - Magit assumes that refs are named non-ambiguously across the -"refs/heads/", "refs/tags/", and "refs/remotes/" namespaces (i.e., all -the names remain unique when those prefixes are stripped). We consider -ambiguous refnames unsupported and recommend that you use a -non-ambiguous naming scheme. However, if you do work with a repository -that has ambiguous refnames, please report any issues you encounter so -that we can investigate whether there is a simple fix. - - -File: magit.info, Node: My Git hooks work on the command-line but not inside Magit, Next: git-commit-mode isn't used when committing from the command-line, Prev: A branch and tag sharing the same name breaks SOMETHING, Up: FAQ - Issues and Errors - -A.2.10 My Git hooks work on the command-line but not inside Magit ------------------------------------------------------------------ - -When Magit calls ‘git’ it adds a few global arguments including -‘--literal-pathspecs’ and the ‘git’ process started by Magit then passes -that setting on to other ‘git’ process it starts itself. It does so by -setting the environment variable ‘GIT_LITERAL_PATHSPECS’, not by calling -subprocesses with the ‘--literal-pathspecs’ argument. You can therefore -override this setting in hook scripts using ‘unset -GIT_LITERAL_PATHSPECS’. - - -File: magit.info, Node: git-commit-mode isn't used when committing from the command-line, Next: Point ends up inside invisible text when jumping to a file-visiting buffer, Prev: My Git hooks work on the command-line but not inside Magit, Up: FAQ - Issues and Errors - -A.2.11 ‘git-commit-mode’ isn’t used when committing from the command-line -------------------------------------------------------------------------- - -The reason for this is that ‘git-commit.el’ has not been loaded yet -and/or that the server has not been started yet. These things have -always already been taken care of when you commit from Magit because in -order to do so, Magit has to be loaded and doing that involves loading -‘git-commit’ and starting the server. - - If you want to commit from the command-line, then you have to take -care of these things yourself. Your ‘init.el’ file should contain: - - (require 'git-commit) - (server-mode) - - Instead of ‘(require ’git-commit)‘ you may also use: - - (load "/path/to/magit-autoloads.el") - - You might want to do that because loading ‘git-commit’ causes large -parts of Magit to be loaded. - - There are also some variations of ‘(server-mode)’ that you might want -to try. Personally I use: - - (use-package server - :config (or (server-running-p) (server-mode))) - - Now you can use: - - $ emacs& - $ EDITOR=emacsclient git commit - - However you cannot use: - - $ killall emacs - $ EDITOR="emacsclient --alternate-editor emacs" git commit - - This will actually end up using ‘emacs’, not ‘emacsclient’. If you -do 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, then you cannot use ‘emacsclient’ directly. - - Instead you have to create a script that does something like this: - - Try to use ‘emacsclient’ (without using ‘--alternate-editor’). If -that succeeds, do nothing else. Otherwise start ‘emacs &’ (and -‘init.el’ must call ‘server-start’) and try to use ‘emacsclient’ again. - - -File: magit.info, Node: Point ends up inside invisible text when jumping to a file-visiting buffer, Next: I am unable to stage when using Tramp from MS Windows, Prev: git-commit-mode isn't used when committing from the command-line, Up: FAQ - Issues and Errors - -A.2.12 Point ends up inside invisible text when jumping to a file-visiting buffer ---------------------------------------------------------------------------------- - -This can happen when you type ‘RET’ on a hunk to visit the respective -file at the respective position. One solution to this problem is to use -‘global-reveal-mode’. It makes sure that text around point is always -visible. If that is too drastic for your taste, then you may instead -use ‘magit-diff-visit-file-hook’ to reveal the text, possibly using -‘reveal-post-command’ or for Org buffers ‘org-reveal’. - - -File: magit.info, Node: I am unable to stage when using Tramp from MS Windows, Next: I am no longer able to save popup defaults, Prev: Point ends up inside invisible text when jumping to a file-visiting buffer, Up: FAQ - Issues and Errors - -A.2.13 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 -. - - -File: magit.info, Node: I am no longer able to save popup defaults, Prev: I am unable to stage when using Tramp from MS Windows, Up: FAQ - Issues and Errors - -A.2.14 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 -for more details. - - -File: magit.info, Node: Debugging Tools, Next: Keystroke Index, Prev: FAQ, Up: Top - -B Debugging Tools -***************** - -Magit and its dependencies provide a few debugging tools, and we -appreciate it very much if you use those tools before reporting an -issue. Please include all relevant output when reporting an issue. - -‘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. - -‘M-x magit-emacs-Q-command’ (‘magit-emacs-Q-command’) - - This command shows a debugging shell command in the echo area and - adds it to the kill ring. Paste that command into a shell and run - it. - - This shell command starts ‘emacs’ with only ‘magit’ and its - dependencies loaded. Neither your configuration nor other - installed packages are loaded. This makes it easier to determine - whether some issue lays with Magit or something else. - - If you run Magit from its Git repository, then you should be able - to use ‘make emacs-Q’ instead of the output of this command. - -‘M-x magit-toggle-verbose-refresh’ (‘magit-toggle-verbose-refresh’) - - This command toggles whether Magit refreshes buffers verbosely. - Enabling this helps figuring out which sections are bottlenecks. - The additional output can be found in the ‘*Messages*’ buffer. - -‘M-x magit-debug-git-executable’ (‘magit-debug-git-executable’) - - This command displays a buffer containing information about the - available and used ‘git’ executable(s), and can be useful when - investigating ‘exec-path’ issues. - - Also see *note Git Executable::. - -‘M-x with-editor-debug’ (‘with-editor-debug’) - - This command displays a buffer containing information about the - available and used ‘emacsclient’ executable(s), and can be useful - when investigating why Magit (or rather ‘with-editor’) cannot find - an appropriate ‘emacsclient’ executable. - - Also see *note (with-editor)Debugging::. - - Please also see the *note FAQ::. - - -File: magit.info, Node: Keystroke Index, Next: Command Index, Prev: Debugging Tools, Up: Top - -Appendix C Keystroke Index -************************** - -[index] -* Menu: - -* !: Running Git Manually. - (line 12) -* ! !: Running Git Manually. - (line 17) -* ! a: Running Git Manually. - (line 58) -* ! b: Running Git Manually. - (line 62) -* ! g: Running Git Manually. - (line 66) -* ! k: Running Git Manually. - (line 54) -* ! p: Running Git Manually. - (line 25) -* ! s: Running Git Manually. - (line 35) -* ! S: Running Git Manually. - (line 40) -* $: Viewing Git Output. (line 16) -* %: Worktree. (line 8) -* % b: Worktree. (line 13) -* % c: Worktree. (line 17) -* % g: Worktree. (line 30) -* % k: Worktree. (line 25) -* % m: Worktree. (line 21) -* +: Log Buffer. (line 72) -* + <1>: Refreshing Diffs. (line 69) -* -: Log Buffer. (line 76) -* - <1>: Refreshing Diffs. (line 65) -* 0: Refreshing Diffs. (line 73) -* 1: Section Visibility. (line 26) -* 2: Section Visibility. (line 27) -* 3: Section Visibility. (line 28) -* 4: Section Visibility. (line 29) -* =: Log Buffer. (line 66) -* ^: Section Movement. (line 31) -* a: Applying. (line 33) -* A: Cherry Picking. (line 8) -* A A: Cherry Picking. (line 17) -* A a: Cherry Picking. (line 24) -* A A <1>: Cherry Picking. (line 90) -* A a <1>: Cherry Picking. (line 98) -* A d: Cherry Picking. (line 54) -* A h: Cherry Picking. (line 42) -* A n: Cherry Picking. (line 65) -* A s: Cherry Picking. (line 76) -* A s <1>: Cherry Picking. (line 94) -* B: Bisecting. (line 8) -* b: Blaming. (line 102) -* b <1>: Branch Commands. (line 12) -* b <2>: Editing Rebase Sequences. - (line 85) -* B B: Bisecting. (line 16) -* B b: Bisecting. (line 34) -* b b: Branch Commands. (line 49) -* b C: Branch Commands. (line 29) -* b c: Branch Commands. (line 67) -* B g: Bisecting. (line 39) -* B k: Bisecting. (line 51) -* b k: Branch Commands. (line 147) -* b l: Branch Commands. (line 74) -* B m: Bisecting. (line 44) -* b n: Branch Commands. (line 57) -* B r: Bisecting. (line 57) -* b r: Branch Commands. (line 153) -* B s: Bisecting. (line 27) -* b s: Branch Commands. (line 97) -* b S: Branch Commands. (line 125) -* b x: Branch Commands. (line 131) -* c: Blaming. (line 135) -* C: Cloning Repository. (line 20) -* c <1>: Initiating a Commit. (line 8) -* c <2>: Editing Rebase Sequences. - (line 72) -* c a: Initiating a Commit. (line 19) -* c A: Initiating a Commit. (line 67) -* C b: Cloning Repository. (line 41) -* C C: Cloning Repository. (line 29) -* c c: Initiating a Commit. (line 14) -* C d: Cloning Repository. (line 54) -* C e: Cloning Repository. (line 61) -* c e: Initiating a Commit. (line 23) -* c f: Initiating a Commit. (line 43) -* c F: Initiating a Commit. (line 51) -* C m: Cloning Repository. (line 46) -* C s: Cloning Repository. (line 34) -* c s: Initiating a Commit. (line 55) -* c S: Initiating a Commit. (line 63) -* c w: Initiating a Commit. (line 33) -* C-: Visiting Files and Blobs from a Diff. - (line 51) -* C-: Section Visibility. (line 13) -* C-c C-a: Commit Pseudo Headers. - (line 17) -* C-c C-b: Log Buffer. (line 21) -* C-c C-b <1>: Refreshing Diffs. (line 91) -* C-c C-c: Transient Commands. (line 18) -* C-c C-c <1>: Select from Log. (line 20) -* C-c C-c <2>: Editing Commit Messages. - (line 17) -* C-c C-c <3>: Editing Rebase Sequences. - (line 6) -* C-c C-d: Refreshing Diffs. (line 81) -* C-c C-d <1>: Editing Commit Messages. - (line 58) -* C-c C-e: Commands Available in Diffs. - (line 25) -* C-c C-f: Log Buffer. (line 25) -* C-c C-f <1>: Refreshing Diffs. (line 95) -* C-c C-i: Commit Pseudo Headers. - (line 13) -* C-c C-k: Select from Log. (line 26) -* C-c C-k <1>: Editing Commit Messages. - (line 22) -* C-c C-k <2>: Editing Rebase Sequences. - (line 11) -* C-c C-n: Log Buffer. (line 29) -* C-c C-o: Commit Pseudo Headers. - (line 33) -* C-c C-p: Commit Pseudo Headers. - (line 37) -* C-c C-r: Commit Pseudo Headers. - (line 21) -* C-c C-s: Commit Pseudo Headers. - (line 25) -* C-c C-t: Commands Available in Diffs. - (line 14) -* C-c C-t <1>: Commit Pseudo Headers. - (line 29) -* C-c C-w: Using the Revision Stack. - (line 6) -* C-c M-g: Commands for Buffers Visiting Files. - (line 21) -* C-c M-g B: Blaming. (line 18) -* C-c M-g b: Blaming. (line 29) -* C-c M-g B <1>: Commands for Buffers Visiting Files. - (line 93) -* C-c M-g B b: Blaming. (line 30) -* C-c M-g B e: Blaming. (line 64) -* C-c M-g B f: Blaming. (line 55) -* C-c M-g B r: Blaming. (line 46) -* C-c M-g c: Commands for Buffers Visiting Files. - (line 38) -* C-c M-g D: Commands for Buffers Visiting Files. - (line 45) -* C-c M-g d: Commands for Buffers Visiting Files. - (line 56) -* C-c M-g e: Blaming. (line 63) -* C-c M-g e <1>: Commands for Buffers Visiting Files. - (line 106) -* C-c M-g f: Blaming. (line 54) -* C-c M-g L: Commands for Buffers Visiting Files. - (line 66) -* C-c M-g l: Commands for Buffers Visiting Files. - (line 77) -* C-c M-g p: Commands for Buffers Visiting Files. - (line 116) -* C-c M-g r: Blaming. (line 45) -* C-c M-g s: Commands for Buffers Visiting Files. - (line 29) -* C-c M-g t: Commands for Buffers Visiting Files. - (line 84) -* C-c M-g u: Commands for Buffers Visiting Files. - (line 33) -* C-c M-i: Commit Pseudo Headers. - (line 42) -* C-c M-s: Editing Commit Messages. - (line 34) -* C-w: Common Commands. (line 10) -* C-x g: Status Buffer. (line 22) -* C-x u: Editing Rebase Sequences. - (line 94) -* d: Diffing. (line 21) -* D: Refreshing Diffs. (line 11) -* d c: Diffing. (line 69) -* d d: Diffing. (line 27) -* D f: Refreshing Diffs. (line 46) -* D F: Refreshing Diffs. (line 51) -* D g: Refreshing Diffs. (line 17) -* d p: Diffing. (line 61) -* d r: Diffing. (line 31) -* D r: Refreshing Diffs. (line 41) -* d s: Diffing. (line 51) -* D s: Refreshing Diffs. (line 22) -* d t: Diffing. (line 74) -* D t: Refreshing Diffs. (line 37) -* d u: Diffing. (line 57) -* d w: Diffing. (line 45) -* D w: Refreshing Diffs. (line 29) -* DEL: Log Buffer. (line 56) -* DEL <1>: Commands Available in Diffs. - (line 60) -* DEL <2>: Blaming. (line 89) -* DEL <3>: Editing Rebase Sequences. - (line 28) -* e: Ediffing. (line 9) -* E: Ediffing. (line 21) -* e <1>: Editing Rebase Sequences. - (line 55) -* E c: Ediffing. (line 65) -* E i: Ediffing. (line 57) -* E m: Ediffing. (line 35) -* E r: Ediffing. (line 26) -* E s: Ediffing. (line 48) -* E u: Ediffing. (line 53) -* E w: Ediffing. (line 61) -* E z: Ediffing. (line 69) -* f: Editing Rebase Sequences. - (line 63) -* f <1>: Fetching. (line 9) -* F: Pulling. (line 9) -* f a: Fetching. (line 50) -* f C: Branch Commands. (line 30) -* F C: Branch Commands. (line 31) -* f e: Fetching. (line 36) -* F e: Pulling. (line 30) -* f m: Fetching. (line 54) -* f o: Fetching. (line 40) -* f p: Fetching. (line 15) -* F p: Pulling. (line 14) -* f r: Fetching. (line 45) -* f u: Fetching. (line 23) -* F u: Pulling. (line 22) -* g: Automatic Refreshing of Magit Buffers. - (line 25) -* G: Automatic Refreshing of Magit Buffers. - (line 34) -* j: Log Buffer. (line 35) -* j <1>: Commands Available in Diffs. - (line 45) -* k: Viewing Git Output. (line 24) -* k <1>: Applying. (line 40) -* k <2>: Editing Rebase Sequences. - (line 68) -* k <3>: Stashing. (line 96) -* l: Logging. (line 29) -* L: Refreshing Logs. (line 11) -* L <1>: Log Buffer. (line 6) -* L <2>: Log Margin. (line 57) -* l <1>: Editing Rebase Sequences. - (line 115) -* l a: Logging. (line 60) -* l b: Logging. (line 56) -* L d: Log Margin. (line 74) -* L g: Refreshing Logs. (line 17) -* l h: Logging. (line 48) -* l H: Reflog. (line 19) -* l l: Logging. (line 35) -* l L: Logging. (line 52) -* L L: Log Margin. (line 66) -* L l: Log Margin. (line 70) -* l o: Logging. (line 41) -* l O: Reflog. (line 15) -* l r: Reflog. (line 11) -* L s: Refreshing Logs. (line 22) -* L t: Refreshing Logs. (line 37) -* L w: Refreshing Logs. (line 29) -* m: Merging. (line 9) -* M: Remote Commands. (line 13) -* m a: Merging. (line 45) -* m a <1>: Merging. (line 95) -* M a: Remote Commands. (line 50) -* M C: Remote Commands. (line 33) -* m e: Merging. (line 31) -* m i: Merging. (line 58) -* M k: Remote Commands. (line 65) -* m m: Merging. (line 18) -* m m <1>: Merging. (line 89) -* m n: Merging. (line 38) -* m p: Merging. (line 81) -* M p: Remote Commands. (line 69) -* M P: Remote Commands. (line 74) -* M r: Remote Commands. (line 55) -* m s: Merging. (line 72) -* M u: Remote Commands. (line 60) -* M-1: Section Visibility. (line 33) -* M-2: Section Visibility. (line 34) -* M-3: Section Visibility. (line 35) -* M-4: Section Visibility. (line 36) -* M-: Section Visibility. (line 17) -* M-n: Section Movement. (line 26) -* M-n <1>: Editing Commit Messages. - (line 44) -* M-n <2>: Editing Rebase Sequences. - (line 47) -* M-p: Section Movement. (line 20) -* M-p <1>: Editing Commit Messages. - (line 38) -* M-p <2>: Editing Rebase Sequences. - (line 43) -* M-w: Blaming. (line 127) -* M-w <1>: Common Commands. (line 28) -* M-x magit-debug-git-executable: Git Executable. (line 55) -* M-x magit-debug-git-executable <1>: Debugging Tools. (line 36) -* M-x magit-describe-section-briefly: Section Types and Values. - (line 13) -* M-x magit-describe-section-briefly <1>: Matching Sections. (line 6) -* M-x magit-emacs-Q-command: Debugging Tools. (line 16) -* M-x magit-init: Creating Repository. (line 6) -* M-x magit-reset-index: Staging and Unstaging. - (line 87) -* M-x magit-reverse-in-index: Staging and Unstaging. - (line 62) -* M-x magit-stage-file: Staging from File-Visiting Buffers. - (line 10) -* M-x magit-toggle-buffer-lock: Modes and Buffers. (line 17) -* M-x magit-toggle-verbose-refresh: Debugging Tools. (line 30) -* M-x magit-unstage-file: Staging from File-Visiting Buffers. - (line 18) -* M-x magit-version: Git Executable. (line 60) -* M-x magit-version <1>: Debugging Tools. (line 10) -* M-x magit-wip-commit: Wip Modes. (line 88) -* M-x with-editor-debug: Debugging Tools. (line 44) -* MM: Editing Rebase Sequences. - (line 125) -* Mt: Editing Rebase Sequences. - (line 132) -* n: Section Movement. (line 16) -* n <1>: Blaming. (line 106) -* N: Blaming. (line 110) -* n <2>: Editing Rebase Sequences. - (line 39) -* n <3>: Minor Mode for Buffers Visiting Blobs. - (line 16) -* o: Submodule Transient. (line 6) -* O: Subtree. (line 8) -* o a: Submodule Transient. (line 20) -* o d: Submodule Transient. (line 50) -* O e: Subtree. (line 42) -* O e p: Subtree. (line 54) -* O e s: Subtree. (line 59) -* o f: Submodule Transient. (line 58) -* O i: Subtree. (line 13) -* O i a: Subtree. (line 25) -* O i c: Subtree. (line 30) -* O i f: Subtree. (line 38) -* O i m: Subtree. (line 34) -* o l: Submodule Transient. (line 54) -* o p: Submodule Transient. (line 34) -* o r: Submodule Transient. (line 27) -* o s: Submodule Transient. (line 44) -* o u: Submodule Transient. (line 39) -* p: Section Movement. (line 10) -* p <1>: Blaming. (line 114) -* P: Blaming. (line 118) -* p <2>: Editing Rebase Sequences. - (line 35) -* P <1>: Pushing. (line 9) -* p <3>: Minor Mode for Buffers Visiting Blobs. - (line 12) -* P C: Branch Commands. (line 32) -* P e: Pushing. (line 31) -* P m: Pushing. (line 50) -* P o: Pushing. (line 36) -* P p: Pushing. (line 15) -* P r: Pushing. (line 41) -* P t: Pushing. (line 58) -* P T: Pushing. (line 66) -* P u: Pushing. (line 23) -* q: Quitting Windows. (line 6) -* q <1>: Log Buffer. (line 14) -* q <2>: Blaming. (line 122) -* q <3>: Minor Mode for Buffers Visiting Blobs. - (line 20) -* r: Rebasing. (line 9) -* r <1>: Editing Rebase Sequences. - (line 51) -* r a: Rebasing. (line 123) -* r e: Rebasing. (line 44) -* r e <1>: Rebasing. (line 118) -* r f: Rebasing. (line 84) -* r i: Rebasing. (line 80) -* r k: Rebasing. (line 99) -* r m: Rebasing. (line 89) -* r p: Rebasing. (line 28) -* r r: Rebasing. (line 106) -* r s: Rebasing. (line 50) -* r s <1>: Rebasing. (line 113) -* r u: Rebasing. (line 36) -* r w: Rebasing. (line 94) -* RET: References Buffer. (line 181) -* RET <1>: Visiting Files and Blobs from a Diff. - (line 8) -* RET <2>: Blaming. (line 75) -* RET <3>: Editing Rebase Sequences. - (line 16) -* s: Staging and Unstaging. - (line 28) -* S: Staging and Unstaging. - (line 36) -* s <1>: Editing Rebase Sequences. - (line 59) -* S-: Section Visibility. (line 22) -* SPC: Log Buffer. (line 46) -* SPC <1>: Commands Available in Diffs. - (line 56) -* SPC <2>: Blaming. (line 79) -* SPC <3>: Editing Rebase Sequences. - (line 21) -* t: Editing Rebase Sequences. - (line 119) -* t <1>: Tagging. (line 8) -* T: Notes. (line 8) -* T a: Notes. (line 52) -* T c: Notes. (line 47) -* t k: Tagging. (line 39) -* T m: Notes. (line 38) -* t p: Tagging. (line 46) -* T p: Notes. (line 30) -* t r: Tagging. (line 19) -* T r: Notes. (line 22) -* t t: Tagging. (line 14) -* T T: Notes. (line 14) -* TAB: Section Visibility. (line 9) -* u: Staging and Unstaging. - (line 43) -* U: Staging and Unstaging. - (line 52) -* v: Applying. (line 44) -* V: Reverting. (line 6) -* V A: Reverting. (line 31) -* V a: Reverting. (line 39) -* V s: Reverting. (line 35) -* V V: Reverting. (line 15) -* V v: Reverting. (line 21) -* W: Plain Patches. (line 6) -* w: Maildir Patches. (line 8) -* w a: Plain Patches. (line 21) -* w a <1>: Maildir Patches. (line 25) -* w a <2>: Maildir Patches. (line 43) -* W c: Plain Patches. (line 12) -* w m: Maildir Patches. (line 21) -* W s: Plain Patches. (line 28) -* w s: Maildir Patches. (line 38) -* w w: Maildir Patches. (line 14) -* w w <1>: Maildir Patches. (line 34) -* x: Editing Rebase Sequences. - (line 76) -* x <1>: Resetting. (line 8) -* X f: Resetting. (line 50) -* X h: Resetting. (line 26) -* X i: Resetting. (line 37) -* X k: Resetting. (line 31) -* X m: Resetting. (line 15) -* X s: Resetting. (line 20) -* X w: Resetting. (line 44) -* X w <1>: Wip Modes. (line 66) -* Y: Cherries. (line 17) -* y: References Buffer. (line 6) -* y <1>: Editing Rebase Sequences. - (line 90) -* y c: References Buffer. (line 26) -* y o: References Buffer. (line 32) -* y y: References Buffer. (line 21) -* z: Stashing. (line 8) -* z a: Stashing. (line 59) -* z b: Stashing. (line 81) -* z B: Stashing. (line 86) -* z f: Stashing. (line 92) -* z i: Stashing. (line 21) -* z I: Stashing. (line 47) -* z k: Stashing. (line 72) -* z l: Stashing. (line 100) -* z p: Stashing. (line 65) -* z v: Stashing. (line 77) -* z w: Stashing. (line 26) -* z W: Stashing. (line 52) -* z x: Stashing. (line 33) -* z z: Stashing. (line 14) -* z Z: Stashing. (line 40) - - -File: magit.info, Node: Command Index, Next: Function Index, Prev: Keystroke Index, Up: Top - -Appendix D Command Index -************************ - -[index] -* Menu: - -* forward-line: Editing Rebase Sequences. - (line 39) -* git-commit-ack: Commit Pseudo Headers. - (line 17) -* git-commit-cc: Commit Pseudo Headers. - (line 33) -* git-commit-insert-pseudo-header: Commit Pseudo Headers. - (line 13) -* git-commit-next-message: Editing Commit Messages. - (line 44) -* git-commit-prev-message: Editing Commit Messages. - (line 38) -* git-commit-reported: Commit Pseudo Headers. - (line 37) -* git-commit-review: Commit Pseudo Headers. - (line 21) -* git-commit-save-message: Editing Commit Messages. - (line 34) -* git-commit-signoff: Commit Pseudo Headers. - (line 25) -* git-commit-suggested: Commit Pseudo Headers. - (line 42) -* git-commit-test: Commit Pseudo Headers. - (line 29) -* git-rebase-backward-line: Editing Rebase Sequences. - (line 35) -* git-rebase-break: Editing Rebase Sequences. - (line 85) -* git-rebase-edit: Editing Rebase Sequences. - (line 55) -* git-rebase-exec: Editing Rebase Sequences. - (line 76) -* git-rebase-fixup: Editing Rebase Sequences. - (line 63) -* git-rebase-insert: Editing Rebase Sequences. - (line 90) -* git-rebase-kill-line: Editing Rebase Sequences. - (line 68) -* git-rebase-label: Editing Rebase Sequences. - (line 115) -* git-rebase-merge: Editing Rebase Sequences. - (line 125) -* git-rebase-merge-toggle-editmsg: Editing Rebase Sequences. - (line 132) -* git-rebase-move-line-down: Editing Rebase Sequences. - (line 47) -* git-rebase-move-line-up: Editing Rebase Sequences. - (line 43) -* git-rebase-pick: Editing Rebase Sequences. - (line 72) -* git-rebase-reset: Editing Rebase Sequences. - (line 119) -* git-rebase-reword: Editing Rebase Sequences. - (line 51) -* git-rebase-show-commit: Editing Rebase Sequences. - (line 16) -* git-rebase-show-or-scroll-down: Editing Rebase Sequences. - (line 28) -* git-rebase-show-or-scroll-up: Editing Rebase Sequences. - (line 21) -* git-rebase-squash: Editing Rebase Sequences. - (line 59) -* git-rebase-undo: Editing Rebase Sequences. - (line 94) -* ido-enter-magit-status: Status Buffer. (line 72) -* magit-am: Maildir Patches. (line 8) -* magit-am-abort: Maildir Patches. (line 43) -* magit-am-apply-maildir: Maildir Patches. (line 21) -* magit-am-apply-patches: Maildir Patches. (line 14) -* magit-am-continue: Maildir Patches. (line 34) -* magit-am-skip: Maildir Patches. (line 38) -* magit-apply: Applying. (line 33) -* magit-bisect: Bisecting. (line 8) -* magit-bisect-bad: Bisecting. (line 34) -* magit-bisect-good: Bisecting. (line 39) -* magit-bisect-mark: Bisecting. (line 44) -* magit-bisect-reset: Bisecting. (line 57) -* magit-bisect-run: Bisecting. (line 27) -* magit-bisect-skip: Bisecting. (line 51) -* magit-bisect-start: Bisecting. (line 16) -* magit-blame: Blaming. (line 18) -* magit-blame <1>: Blaming. (line 102) -* magit-blame <2>: Commands for Buffers Visiting Files. - (line 93) -* magit-blame-addition: Blaming. (line 29) -* magit-blame-addition <1>: Blaming. (line 30) -* magit-blame-copy-hash: Blaming. (line 127) -* magit-blame-cycle-style: Blaming. (line 135) -* magit-blame-echo: Blaming. (line 63) -* magit-blame-echo <1>: Blaming. (line 64) -* magit-blame-next-chunk: Blaming. (line 106) -* magit-blame-next-chunk-same-commit: Blaming. (line 110) -* magit-blame-previous-chunk: Blaming. (line 114) -* magit-blame-previous-chunk-same-commit: Blaming. (line 118) -* magit-blame-quit: Blaming. (line 122) -* magit-blame-removal: Blaming. (line 45) -* magit-blame-removal <1>: Blaming. (line 46) -* magit-blame-reverse: Blaming. (line 54) -* magit-blame-reverse <1>: Blaming. (line 55) -* magit-blob-next: Minor Mode for Buffers Visiting Blobs. - (line 16) -* magit-blob-previous: Commands for Buffers Visiting Files. - (line 116) -* magit-blob-previous <1>: Minor Mode for Buffers Visiting Blobs. - (line 12) -* magit-branch: Branch Commands. (line 12) -* magit-branch-and-checkout: Branch Commands. (line 67) -* magit-branch-checkout: Branch Commands. (line 74) -* magit-branch-configure: Branch Commands. (line 29) -* magit-branch-configure <1>: Branch Commands. (line 30) -* magit-branch-configure <2>: Branch Commands. (line 31) -* magit-branch-configure <3>: Branch Commands. (line 32) -* magit-branch-create: Branch Commands. (line 57) -* magit-branch-delete: Branch Commands. (line 147) -* magit-branch-or-checkout: Branch Commands. (line 267) -* magit-branch-orphan: Branch Commands. (line 262) -* magit-branch-rename: Branch Commands. (line 153) -* magit-branch-reset: Branch Commands. (line 131) -* magit-branch-shelve: Auxiliary Branch Commands. - (line 9) -* magit-branch-spinoff: Branch Commands. (line 97) -* magit-branch-spinout: Branch Commands. (line 125) -* magit-branch-unshelve: Auxiliary Branch Commands. - (line 20) -* magit-checkout: Branch Commands. (line 49) -* magit-cherry: Cherries. (line 17) -* magit-cherry-apply: Cherry Picking. (line 24) -* magit-cherry-copy: Cherry Picking. (line 17) -* magit-cherry-donate: Cherry Picking. (line 54) -* magit-cherry-harvest: Cherry Picking. (line 42) -* magit-cherry-pick: Cherry Picking. (line 8) -* magit-cherry-spinoff: Cherry Picking. (line 76) -* magit-cherry-spinout: Cherry Picking. (line 65) -* magit-clone: Cloning Repository. (line 20) -* magit-clone-bare: Cloning Repository. (line 41) -* magit-clone-mirror: Cloning Repository. (line 46) -* magit-clone-regular: Cloning Repository. (line 29) -* magit-clone-shallow: Cloning Repository. (line 34) -* magit-clone-shallow-exclude: Cloning Repository. (line 61) -* magit-clone-shallow-since: Cloning Repository. (line 54) -* magit-commit: Initiating a Commit. (line 8) -* magit-commit <1>: Commands for Buffers Visiting Files. - (line 38) -* magit-commit-amend: Initiating a Commit. (line 19) -* magit-commit-augment: Initiating a Commit. (line 67) -* magit-commit-create: Initiating a Commit. (line 14) -* magit-commit-extend: Initiating a Commit. (line 23) -* magit-commit-fixup: Initiating a Commit. (line 43) -* magit-commit-instant-fixup: Initiating a Commit. (line 51) -* magit-commit-instant-squash: Initiating a Commit. (line 63) -* magit-commit-reword: Initiating a Commit. (line 33) -* magit-commit-squash: Initiating a Commit. (line 55) -* magit-copy-buffer-revision: Common Commands. (line 28) -* magit-copy-section-value: Common Commands. (line 10) -* magit-cycle-margin-style: Log Margin. (line 70) -* magit-debug-git-executable: Git Executable. (line 55) -* magit-debug-git-executable <1>: Debugging Tools. (line 36) -* magit-describe-section-briefly: Section Types and Values. - (line 13) -* magit-describe-section-briefly <1>: Matching Sections. (line 6) -* magit-diff: Diffing. (line 21) -* magit-diff <1>: Commands for Buffers Visiting Files. - (line 45) -* magit-diff-buffer-file: Commands for Buffers Visiting Files. - (line 56) -* magit-diff-default-context: Refreshing Diffs. (line 73) -* magit-diff-dwim: Diffing. (line 27) -* magit-diff-edit-hunk-commit: Commands Available in Diffs. - (line 25) -* magit-diff-flip-revs: Refreshing Diffs. (line 46) -* magit-diff-less-context: Refreshing Diffs. (line 65) -* magit-diff-more-context: Refreshing Diffs. (line 69) -* magit-diff-paths: Diffing. (line 61) -* magit-diff-range: Diffing. (line 31) -* magit-diff-refresh: Refreshing Diffs. (line 11) -* magit-diff-refresh <1>: Refreshing Diffs. (line 17) -* magit-diff-save-default-arguments: Refreshing Diffs. (line 29) -* magit-diff-set-default-arguments: Refreshing Diffs. (line 22) -* magit-diff-show-or-scroll-down: Log Buffer. (line 56) -* magit-diff-show-or-scroll-down <1>: Blaming. (line 89) -* magit-diff-show-or-scroll-up: Log Buffer. (line 46) -* magit-diff-show-or-scroll-up <1>: Blaming. (line 79) -* magit-diff-staged: Diffing. (line 51) -* magit-diff-switch-range-type: Refreshing Diffs. (line 41) -* magit-diff-toggle-file-filter: Refreshing Diffs. (line 51) -* magit-diff-toggle-refine-hunk: Refreshing Diffs. (line 37) -* magit-diff-trace-definition: Commands Available in Diffs. - (line 14) -* magit-diff-unstaged: Diffing. (line 57) -* magit-diff-visit-file: Visiting Files and Blobs from a Diff. - (line 8) -* magit-diff-visit-file-other-frame: Visiting Files and Blobs from a Diff. - (line 74) -* magit-diff-visit-file-other-window: Visiting Files and Blobs from a Diff. - (line 73) -* magit-diff-visit-file-worktree: Visiting Files and Blobs from a Diff. - (line 51) -* magit-diff-visit-worktree-file-other-frame: Visiting Files and Blobs from a Diff. - (line 76) -* magit-diff-visit-worktree-file-other-window: Visiting Files and Blobs from a Diff. - (line 75) -* magit-diff-while-committing: Refreshing Diffs. (line 81) -* magit-diff-while-committing <1>: Editing Commit Messages. - (line 58) -* magit-diff-working-tree: Diffing. (line 45) -* magit-discard: Applying. (line 40) -* magit-dispatch: Transient Commands. (line 18) -* magit-ediff: Ediffing. (line 21) -* magit-ediff-compare: Ediffing. (line 26) -* magit-ediff-dwim: Ediffing. (line 9) -* magit-ediff-resolve: Ediffing. (line 35) -* magit-ediff-show-commit: Ediffing. (line 65) -* magit-ediff-show-staged: Ediffing. (line 57) -* magit-ediff-show-stash: Ediffing. (line 69) -* magit-ediff-show-unstaged: Ediffing. (line 53) -* magit-ediff-show-working-tree: Ediffing. (line 61) -* magit-ediff-stage: Ediffing. (line 48) -* magit-edit-line-commit: Commands for Buffers Visiting Files. - (line 106) -* magit-emacs-Q-command: Debugging Tools. (line 16) -* magit-fetch: Fetching. (line 9) -* magit-fetch-all: Fetching. (line 50) -* magit-fetch-branch: Fetching. (line 40) -* magit-fetch-from-pushremote: Fetching. (line 15) -* magit-fetch-from-upstream: Fetching. (line 23) -* magit-fetch-modules: Submodule Transient. (line 58) -* magit-fetch-other: Fetching. (line 36) -* magit-fetch-refspec: Fetching. (line 45) -* magit-file-checkout: Resetting. (line 50) -* magit-file-checkout <1>: Commands for Buffers Visiting Files. - (line 135) -* magit-file-delete: Commands for Buffers Visiting Files. - (line 127) -* magit-file-dispatch: Commands for Buffers Visiting Files. - (line 21) -* magit-file-rename: Commands for Buffers Visiting Files. - (line 123) -* magit-file-untrack: Commands for Buffers Visiting Files. - (line 131) -* magit-find-file: General-Purpose Visit Commands. - (line 9) -* magit-find-file-other-frame: General-Purpose Visit Commands. - (line 21) -* magit-find-file-other-window: General-Purpose Visit Commands. - (line 15) -* magit-git-command: Running Git Manually. - (line 25) -* magit-git-command-topdir: Running Git Manually. - (line 17) -* magit-go-backward: Log Buffer. (line 21) -* magit-go-backward <1>: Refreshing Diffs. (line 91) -* magit-go-forward: Log Buffer. (line 25) -* magit-go-forward <1>: Refreshing Diffs. (line 95) -* magit-init: Creating Repository. (line 6) -* magit-jump-to-diffstat-or-diff: Commands Available in Diffs. - (line 45) -* magit-kill-this-buffer: Minor Mode for Buffers Visiting Blobs. - (line 20) -* magit-list-repositories: Repository List. (line 6) -* magit-list-submodules: Listing Submodules. (line 13) -* magit-list-submodules <1>: Submodule Transient. (line 54) -* magit-log: Logging. (line 29) -* magit-log <1>: Commands for Buffers Visiting Files. - (line 66) -* magit-log-all: Logging. (line 60) -* magit-log-all-branches: Logging. (line 56) -* magit-log-branches: Logging. (line 52) -* magit-log-buffer-file: Commands for Buffers Visiting Files. - (line 77) -* magit-log-bury-buffer: Log Buffer. (line 14) -* magit-log-current: Logging. (line 35) -* magit-log-double-commit-limit: Log Buffer. (line 72) -* magit-log-half-commit-limit: Log Buffer. (line 76) -* magit-log-head: Logging. (line 48) -* magit-log-move-to-parent: Log Buffer. (line 29) -* magit-log-move-to-revision: Log Buffer. (line 35) -* magit-log-other: Logging. (line 41) -* magit-log-refresh: Refreshing Logs. (line 11) -* magit-log-refresh <1>: Refreshing Logs. (line 17) -* magit-log-refresh <2>: Log Buffer. (line 6) -* magit-log-save-default-arguments: Refreshing Logs. (line 29) -* magit-log-select-pick: Select from Log. (line 20) -* magit-log-select-quit: Select from Log. (line 26) -* magit-log-set-default-arguments: Refreshing Logs. (line 22) -* magit-log-toggle-commit-limit: Log Buffer. (line 66) -* magit-log-trace-definition: Commands for Buffers Visiting Files. - (line 84) -* magit-margin-settings: Log Margin. (line 57) -* magit-merge: Merging. (line 9) -* magit-merge <1>: Merging. (line 89) -* magit-merge-abort: Merging. (line 95) -* magit-merge-absorb: Merging. (line 45) -* magit-merge-editmsg: Merging. (line 31) -* magit-merge-into: Merging. (line 58) -* magit-merge-nocommit: Merging. (line 38) -* magit-merge-plain: Merging. (line 18) -* magit-merge-preview: Merging. (line 81) -* magit-merge-squash: Merging. (line 72) -* magit-mode-bury-buffer: Quitting Windows. (line 6) -* magit-notes: Notes. (line 8) -* magit-notes-edit: Notes. (line 14) -* magit-notes-merge: Notes. (line 38) -* magit-notes-merge-abort: Notes. (line 52) -* magit-notes-merge-commit: Notes. (line 47) -* magit-notes-prune: Notes. (line 30) -* magit-notes-remove: Notes. (line 22) -* magit-patch: Plain Patches. (line 6) -* magit-patch-apply: Plain Patches. (line 21) -* magit-patch-apply <1>: Maildir Patches. (line 25) -* magit-patch-create: Plain Patches. (line 12) -* magit-patch-save: Plain Patches. (line 28) -* magit-pop-revision-stack: Using the Revision Stack. - (line 6) -* magit-process: Viewing Git Output. (line 16) -* magit-process-kill: Viewing Git Output. (line 24) -* magit-pull: Pulling. (line 9) -* magit-pull-branch: Pulling. (line 30) -* magit-pull-from-pushremote: Pulling. (line 14) -* magit-pull-from-upstream: Pulling. (line 22) -* magit-push: Pushing. (line 9) -* magit-push-current: Pushing. (line 31) -* magit-push-current-to-pushremote: Pushing. (line 15) -* magit-push-current-to-upstream: Pushing. (line 23) -* magit-push-implicitly args: Pushing. (line 83) -* magit-push-matching: Pushing. (line 50) -* magit-push-other: Pushing. (line 36) -* magit-push-refspecs: Pushing. (line 41) -* magit-push-tag: Pushing. (line 66) -* magit-push-tags: Pushing. (line 58) -* magit-push-to-remote remote args: Pushing. (line 101) -* magit-rebase: Rebasing. (line 9) -* magit-rebase-abort: Rebasing. (line 123) -* magit-rebase-autosquash: Rebasing. (line 84) -* magit-rebase-branch: Rebasing. (line 44) -* magit-rebase-continue: Rebasing. (line 106) -* magit-rebase-edit: Rebasing. (line 118) -* magit-rebase-edit-commit: Rebasing. (line 89) -* magit-rebase-interactive: Rebasing. (line 80) -* magit-rebase-onto-pushremote: Rebasing. (line 28) -* magit-rebase-onto-upstream: Rebasing. (line 36) -* magit-rebase-remove-commit: Rebasing. (line 99) -* magit-rebase-reword-commit: Rebasing. (line 94) -* magit-rebase-skip: Rebasing. (line 113) -* magit-rebase-subset: Rebasing. (line 50) -* magit-reflog-current: Reflog. (line 11) -* magit-reflog-head: Reflog. (line 19) -* magit-reflog-other: Reflog. (line 15) -* magit-refresh: Automatic Refreshing of Magit Buffers. - (line 25) -* magit-refresh-all: Automatic Refreshing of Magit Buffers. - (line 34) -* magit-remote: Remote Commands. (line 13) -* magit-remote-add: Remote Commands. (line 50) -* magit-remote-configure: Remote Commands. (line 33) -* magit-remote-prune: Remote Commands. (line 69) -* magit-remote-prune-refspecs: Remote Commands. (line 74) -* magit-remote-remove: Remote Commands. (line 65) -* magit-remote-rename: Remote Commands. (line 55) -* magit-remote-set-url: Remote Commands. (line 60) -* magit-reset-hard: Resetting. (line 26) -* magit-reset-index: Staging and Unstaging. - (line 87) -* magit-reset-index <1>: Resetting. (line 37) -* magit-reset-keep: Resetting. (line 31) -* magit-reset-mixed: Resetting. (line 15) -* magit-reset-quickly: Resetting. (line 8) -* magit-reset-soft: Resetting. (line 20) -* magit-reset-worktree: Resetting. (line 44) -* magit-reset-worktree <1>: Wip Modes. (line 66) -* magit-reverse: Applying. (line 44) -* magit-reverse-in-index: Staging and Unstaging. - (line 62) -* magit-revert: Reverting. (line 6) -* magit-revert-and-commit: Reverting. (line 15) -* magit-revert-no-commit: Reverting. (line 21) -* magit-run: Running Git Manually. - (line 12) -* magit-run-git-gui: Running Git Manually. - (line 66) -* magit-run-gitk: Running Git Manually. - (line 54) -* magit-run-gitk-all: Running Git Manually. - (line 58) -* magit-run-gitk-branches: Running Git Manually. - (line 62) -* magit-section-backward: Section Movement. (line 10) -* magit-section-backward-siblings: Section Movement. (line 20) -* magit-section-cycle: Section Visibility. (line 13) -* magit-section-cycle-diffs: Section Visibility. (line 17) -* magit-section-cycle-global: Section Visibility. (line 22) -* magit-section-forward: Section Movement. (line 16) -* magit-section-forward-siblings: Section Movement. (line 26) -* magit-section-hide: Section Visibility. (line 49) -* magit-section-hide-children: Section Visibility. (line 64) -* magit-section-show: Section Visibility. (line 45) -* magit-section-show-children: Section Visibility. (line 58) -* magit-section-show-headings: Section Visibility. (line 53) -* magit-section-show-level-1: Section Visibility. (line 26) -* magit-section-show-level-1-all: Section Visibility. (line 33) -* magit-section-show-level-2: Section Visibility. (line 27) -* magit-section-show-level-2-all: Section Visibility. (line 34) -* magit-section-show-level-3: Section Visibility. (line 28) -* magit-section-show-level-3-all: Section Visibility. (line 35) -* magit-section-show-level-4: Section Visibility. (line 29) -* magit-section-show-level-4-all: Section Visibility. (line 36) -* magit-section-toggle: Section Visibility. (line 9) -* magit-section-toggle-children: Section Visibility. (line 68) -* magit-section-up: Section Movement. (line 31) -* magit-sequence-abort: Cherry Picking. (line 98) -* magit-sequence-abort <1>: Reverting. (line 39) -* magit-sequence-continue: Cherry Picking. (line 90) -* magit-sequence-continue <1>: Reverting. (line 31) -* magit-sequence-skip: Cherry Picking. (line 94) -* magit-sequence-skip <1>: Reverting. (line 35) -* magit-shell-command: Running Git Manually. - (line 40) -* magit-shell-command-topdir: Running Git Manually. - (line 35) -* magit-show-commit: Diffing. (line 69) -* magit-show-commit <1>: Blaming. (line 75) -* magit-show-refs: References Buffer. (line 6) -* magit-show-refs-current: References Buffer. (line 26) -* magit-show-refs-head: References Buffer. (line 21) -* magit-show-refs-other: References Buffer. (line 32) -* magit-snapshot-both: Stashing. (line 40) -* magit-snapshot-index: Stashing. (line 47) -* magit-snapshot-worktree: Stashing. (line 52) -* magit-stage: Staging and Unstaging. - (line 28) -* magit-stage-file: Staging from File-Visiting Buffers. - (line 10) -* magit-stage-file <1>: Commands for Buffers Visiting Files. - (line 29) -* magit-stage-modified: Staging and Unstaging. - (line 36) -* magit-stash: Stashing. (line 8) -* magit-stash-apply: Stashing. (line 59) -* magit-stash-both: Stashing. (line 14) -* magit-stash-branch: Stashing. (line 81) -* magit-stash-branch-here: Stashing. (line 86) -* magit-stash-clear: Stashing. (line 96) -* magit-stash-drop: Stashing. (line 72) -* magit-stash-format-patch: Stashing. (line 92) -* magit-stash-index: Stashing. (line 21) -* magit-stash-keep-index: Stashing. (line 33) -* magit-stash-list: Stashing. (line 100) -* magit-stash-pop: Stashing. (line 65) -* magit-stash-show: Diffing. (line 74) -* magit-stash-show <1>: Stashing. (line 77) -* magit-stash-worktree: Stashing. (line 26) -* magit-status: Status Buffer. (line 22) -* magit-submodule: Submodule Transient. (line 6) -* magit-submodule-add: Submodule Transient. (line 20) -* magit-submodule-fetch: Fetching. (line 54) -* magit-submodule-populate: Submodule Transient. (line 34) -* magit-submodule-register: Submodule Transient. (line 27) -* magit-submodule-synchronize: Submodule Transient. (line 44) -* magit-submodule-unpopulate: Submodule Transient. (line 50) -* magit-submodule-update: Submodule Transient. (line 39) -* magit-subtree: Subtree. (line 8) -* magit-subtree-add: Subtree. (line 25) -* magit-subtree-add-commit: Subtree. (line 30) -* magit-subtree-export: Subtree. (line 42) -* magit-subtree-import: Subtree. (line 13) -* magit-subtree-merge: Subtree. (line 34) -* magit-subtree-pull: Subtree. (line 38) -* magit-subtree-push: Subtree. (line 54) -* magit-subtree-split: Subtree. (line 59) -* magit-tag: Tagging. (line 8) -* magit-tag-create: Tagging. (line 14) -* magit-tag-delete: Tagging. (line 39) -* magit-tag-prune: Tagging. (line 46) -* magit-tag-release: Tagging. (line 19) -* magit-toggle-buffer-lock: Modes and Buffers. (line 17) -* magit-toggle-margin: Refreshing Logs. (line 37) -* magit-toggle-margin <1>: Log Margin. (line 66) -* magit-toggle-margin-details: Log Margin. (line 74) -* magit-toggle-verbose-refresh: Debugging Tools. (line 30) -* magit-unstage: Staging and Unstaging. - (line 43) -* magit-unstage-all: Staging and Unstaging. - (line 52) -* magit-unstage-file: Staging from File-Visiting Buffers. - (line 18) -* magit-unstage-file <1>: Commands for Buffers Visiting Files. - (line 33) -* magit-version: Git Executable. (line 60) -* magit-version <1>: Debugging Tools. (line 10) -* magit-visit-ref: References Buffer. (line 181) -* magit-wip-commit: Wip Modes. (line 88) -* magit-wip-log: Wip Modes. (line 48) -* magit-wip-log-current: Wip Modes. (line 57) -* magit-worktree: Worktree. (line 8) -* magit-worktree-branch: Worktree. (line 17) -* magit-worktree-checkout: Worktree. (line 13) -* magit-worktree-delete: Worktree. (line 25) -* magit-worktree-move: Worktree. (line 21) -* magit-worktree-status: Worktree. (line 30) -* scroll-down: Commands Available in Diffs. - (line 60) -* scroll-up: Commands Available in Diffs. - (line 56) -* with-editor-cancel: Editing Commit Messages. - (line 22) -* with-editor-cancel <1>: Editing Rebase Sequences. - (line 11) -* with-editor-debug: Debugging Tools. (line 44) -* with-editor-finish: Editing Commit Messages. - (line 17) -* with-editor-finish <1>: Editing Rebase Sequences. - (line 6) - - -File: magit.info, Node: Function Index, Next: Variable Index, Prev: Command Index, Up: Top - -Appendix E Function Index -************************* - -[index] -* Menu: - -* bug-reference-mode: Commit Mode and Hooks. - (line 56) -* git-commit-check-style-conventions: Commit Message Conventions. - (line 40) -* git-commit-propertize-diff: Commit Mode and Hooks. - (line 47) -* git-commit-save-message: Commit Mode and Hooks. - (line 28) -* git-commit-setup-changelog-support: Commit Mode and Hooks. - (line 32) -* git-commit-turn-on-auto-fill: Commit Mode and Hooks. - (line 37) -* git-commit-turn-on-flyspell: Commit Mode and Hooks. - (line 42) -* ido-enter-magit-status: Status Buffer. (line 72) -* magit-add-section-hook: Section Hooks. (line 20) -* magit-after-save-refresh-status: Automatic Refreshing of Magit Buffers. - (line 59) -* magit-branch-or-checkout: Branch Commands. (line 267) -* magit-branch-orphan: Branch Commands. (line 262) -* magit-branch-shelve: Auxiliary Branch Commands. - (line 9) -* magit-branch-unshelve: Auxiliary Branch Commands. - (line 20) -* magit-builtin-completing-read: Support for Completion Frameworks. - (line 42) -* magit-call-git: Calling Git for Effect. - (line 28) -* magit-call-process: Calling Git for Effect. - (line 32) -* magit-cancel-section: Creating Sections. (line 71) -* magit-completing-read: Support for Completion Frameworks. - (line 60) -* magit-current-section: Section Selection. (line 6) -* magit-define-section-jumper: Creating Sections. (line 77) -* magit-diff-scope: Matching Sections. (line 118) -* magit-diff-type: Matching Sections. (line 95) -* magit-diff-visit-file-other-frame: Visiting Files and Blobs from a Diff. - (line 74) -* magit-diff-visit-file-other-window: Visiting Files and Blobs from a Diff. - (line 73) -* magit-diff-visit-worktree-file-other-frame: Visiting Files and Blobs from a Diff. - (line 76) -* magit-diff-visit-worktree-file-other-window: Visiting Files and Blobs from a Diff. - (line 75) -* magit-disable-section-inserter: Per-Repository Configuration. - (line 31) -* magit-display-buffer: Switching Buffers. (line 6) -* magit-display-buffer-fullcolumn-most-v1: Switching Buffers. (line 75) -* magit-display-buffer-fullframe-status-topleft-v1: Switching Buffers. - (line 65) -* magit-display-buffer-fullframe-status-v1: Switching Buffers. - (line 59) -* magit-display-buffer-same-window-except-diff-v1: Switching Buffers. - (line 53) -* magit-display-buffer-traditional: Switching Buffers. (line 45) -* magit-file-checkout: Commands for Buffers Visiting Files. - (line 135) -* magit-file-delete: Commands for Buffers Visiting Files. - (line 127) -* magit-file-rename: Commands for Buffers Visiting Files. - (line 123) -* magit-file-untrack: Commands for Buffers Visiting Files. - (line 131) -* magit-find-file: General-Purpose Visit Commands. - (line 9) -* magit-find-file-other-frame: General-Purpose Visit Commands. - (line 21) -* magit-find-file-other-window: General-Purpose Visit Commands. - (line 15) -* magit-generate-buffer-name-default-function: Naming Buffers. - (line 17) -* magit-get-section: Matching Sections. (line 16) -* magit-git: Calling Git for Effect. - (line 50) -* magit-git-exit-code: Getting a Value from Git. - (line 10) -* magit-git-failure: Getting a Value from Git. - (line 19) -* magit-git-false: Getting a Value from Git. - (line 29) -* magit-git-insert: Getting a Value from Git. - (line 34) -* magit-git-items: Getting a Value from Git. - (line 49) -* magit-git-lines: Getting a Value from Git. - (line 44) -* magit-git-str: Getting a Value from Git. - (line 87) -* magit-git-string: Getting a Value from Git. - (line 38) -* magit-git-success: Getting a Value from Git. - (line 14) -* magit-git-true: Getting a Value from Git. - (line 24) -* magit-git-wash: Calling Git for Effect. - (line 55) -* magit-hunk-set-window-start: Section Movement. (line 51) -* magit-ido-completing-read: Support for Completion Frameworks. - (line 48) -* magit-insert-am-sequence: Status Sections. (line 28) -* magit-insert-assumed-unchanged-files: Status Sections. (line 117) -* magit-insert-bisect-log: Status Sections. (line 46) -* magit-insert-bisect-output: Status Sections. (line 38) -* magit-insert-bisect-rest: Status Sections. (line 42) -* magit-insert-diff-filter-header: Status Header Sections. - (line 38) -* magit-insert-error-header: Status Header Sections. - (line 28) -* magit-insert-head-branch-header: Status Header Sections. - (line 42) -* magit-insert-heading: Creating Sections. (line 42) -* magit-insert-ignored-files: Status Sections. (line 100) -* magit-insert-local-branches: References Sections. (line 17) -* magit-insert-merge-log: Status Sections. (line 18) -* magit-insert-modules: Status Module Sections. - (line 12) -* magit-insert-modules-overview: Status Module Sections. - (line 33) -* magit-insert-modules-unpulled-from-pushremote: Status Module Sections. - (line 50) -* magit-insert-modules-unpulled-from-upstream: Status Module Sections. - (line 44) -* magit-insert-modules-unpushed-to-pushremote: Status Module Sections. - (line 62) -* magit-insert-modules-unpushed-to-upstream: Status Module Sections. - (line 56) -* magit-insert-push-branch-header: Status Header Sections. - (line 51) -* magit-insert-rebase-sequence: Status Sections. (line 23) -* magit-insert-recent-commits: Status Sections. (line 131) -* magit-insert-remote-branches: References Sections. (line 21) -* magit-insert-remote-header: Status Header Sections. - (line 67) -* magit-insert-repo-header: Status Header Sections. - (line 63) -* magit-insert-section: Creating Sections. (line 6) -* magit-insert-sequencer-sequence: Status Sections. (line 33) -* magit-insert-skip-worktree-files: Status Sections. (line 110) -* magit-insert-staged-changes: Status Sections. (line 63) -* magit-insert-stashes: Status Sections. (line 67) -* magit-insert-status-headers: Status Header Sections. - (line 12) -* magit-insert-tags: References Sections. (line 25) -* magit-insert-tags-header: Status Header Sections. - (line 56) -* magit-insert-tracked-files: Status Sections. (line 96) -* magit-insert-unpulled-cherries: Status Sections. (line 142) -* magit-insert-unpulled-from-pushremote: Status Sections. (line 79) -* magit-insert-unpulled-from-upstream: Status Sections. (line 74) -* magit-insert-unpulled-or-recent-commits: Status Sections. (line 124) -* magit-insert-unpushed-cherries: Status Sections. (line 149) -* magit-insert-unpushed-to-pushremote: Status Sections. (line 89) -* magit-insert-unpushed-to-upstream: Status Sections. (line 84) -* magit-insert-unstaged-changes: Status Sections. (line 59) -* magit-insert-untracked-files: Status Sections. (line 50) -* magit-insert-upstream-branch-header: Status Header Sections. - (line 46) -* magit-insert-user-header: Status Header Sections. - (line 75) -* magit-list-repositories: Repository List. (line 6) -* magit-list-submodules: Listing Submodules. (line 13) -* magit-log-maybe-show-more-commits: Section Movement. (line 66) -* magit-log-maybe-update-blob-buffer: Section Movement. (line 82) -* magit-log-maybe-update-revision-buffer: Section Movement. (line 74) -* magit-maybe-set-dedicated: Switching Buffers. (line 100) -* magit-mode-display-buffer: Refreshing Buffers. (line 33) -* magit-mode-quit-window: Quitting Windows. (line 34) -* magit-mode-setup: Refreshing Buffers. (line 17) -* magit-process-file: Getting a Value from Git. - (line 67) -* magit-process-git: Getting a Value from Git. - (line 59) -* magit-push-implicitly: Pushing. (line 83) -* magit-push-to-remote: Pushing. (line 101) -* magit-region-sections: Section Selection. (line 10) -* magit-region-values: Section Selection. (line 37) -* magit-repolist-column-branch: Repository List. (line 50) -* magit-repolist-column-branches: Repository List. (line 59) -* magit-repolist-column-flag: Repository List. (line 67) -* magit-repolist-column-ident: Repository List. (line 36) -* magit-repolist-column-path: Repository List. (line 41) -* magit-repolist-column-stashes: Repository List. (line 63) -* magit-repolist-column-unpulled-from-pushremote: Repository List. - (line 87) -* magit-repolist-column-unpulled-from-upstream: Repository List. - (line 82) -* magit-repolist-column-unpushed-to-pushremote: Repository List. - (line 97) -* magit-repolist-column-unpushed-to-upstream: Repository List. - (line 92) -* magit-repolist-column-upstream: Repository List. (line 54) -* magit-repolist-column-version: Repository List. (line 45) -* magit-restore-window-configuration: Quitting Windows. (line 23) -* magit-run-git: Calling Git for Effect. - (line 36) -* magit-run-git-async: Calling Git for Effect. - (line 65) -* magit-run-git-with-editor: Calling Git for Effect. - (line 78) -* magit-run-git-with-input: Calling Git for Effect. - (line 40) -* magit-save-window-configuration: Switching Buffers. (line 89) -* magit-section-case: Matching Sections. (line 71) -* magit-section-hide: Section Visibility. (line 49) -* magit-section-hide-children: Section Visibility. (line 64) -* magit-section-ident: Matching Sections. (line 11) -* magit-section-match: Matching Sections. (line 21) -* magit-section-set-window-start: Section Movement. (line 59) -* magit-section-show: Section Visibility. (line 45) -* magit-section-show-children: Section Visibility. (line 58) -* magit-section-show-headings: Section Visibility. (line 53) -* magit-section-toggle-children: Section Visibility. (line 68) -* magit-section-value-if: Matching Sections. (line 61) -* magit-start-git: Calling Git for Effect. - (line 90) -* magit-start-process: Calling Git for Effect. - (line 109) -* magit-stashes-maybe-update-stash-buffer: Section Movement. (line 106) -* magit-status-maybe-update-blob-buffer: Section Movement. (line 100) -* magit-status-maybe-update-revision-buffer: Section Movement. - (line 88) -* magit-status-maybe-update-stash-buffer: Section Movement. (line 94) -* magit-wip-log: Wip Modes. (line 48) -* magit-wip-log-current: Wip Modes. (line 57) -* with-editor-usage-message: Commit Mode and Hooks. - (line 60) - - -File: magit.info, Node: Variable Index, Prev: Function Index, Up: Top - -Appendix F Variable Index -************************* - -[index] -* Menu: - -* auto-revert-buffer-list-filter: Automatic Reverting of File-Visiting Buffers. - (line 81) -* auto-revert-interval: Automatic Reverting of File-Visiting Buffers. - (line 76) -* auto-revert-mode: Automatic Reverting of File-Visiting Buffers. - (line 62) -* auto-revert-stop-on-user-input: Automatic Reverting of File-Visiting Buffers. - (line 71) -* auto-revert-use-notify: Automatic Reverting of File-Visiting Buffers. - (line 49) -* auto-revert-verbose: Automatic Reverting of File-Visiting Buffers. - (line 103) -* branch.autoSetupMerge: Branch Git Variables. - (line 81) -* branch.autoSetupRebase: Branch Git Variables. - (line 98) -* branch.NAME.description: Branch Git Variables. - (line 48) -* branch.NAME.merge: Branch Git Variables. - (line 10) -* branch.NAME.pushRemote: Branch Git Variables. - (line 34) -* branch.NAME.rebase: Branch Git Variables. - (line 22) -* branch.NAME.remote: Branch Git Variables. - (line 16) -* core.notesRef: Notes. (line 60) -* git-commit-fill-column: Commit Message Conventions. - (line 19) -* git-commit-finish-query-functions: Commit Message Conventions. - (line 24) -* git-commit-known-pseudo-headers: Commit Pseudo Headers. - (line 9) -* git-commit-major-mode: Commit Mode and Hooks. - (line 12) -* git-commit-setup-hook: Commit Mode and Hooks. - (line 22) -* git-commit-setup-hook <1>: Commit Mode and Hooks. - (line 64) -* git-commit-style-convention-checks: Commit Message Conventions. - (line 46) -* git-commit-summary-max-length: Commit Message Conventions. - (line 13) -* git-rebase-auto-advance: Editing Rebase Sequences. - (line 99) -* git-rebase-confirm-cancel: Editing Rebase Sequences. - (line 107) -* git-rebase-show-instructions: Editing Rebase Sequences. - (line 103) -* global-auto-revert-mode: Automatic Reverting of File-Visiting Buffers. - (line 22) -* magit-auto-revert-immediately: Automatic Reverting of File-Visiting Buffers. - (line 32) -* magit-auto-revert-mode: Automatic Reverting of File-Visiting Buffers. - (line 17) -* magit-auto-revert-tracked-only: Automatic Reverting of File-Visiting Buffers. - (line 55) -* magit-bisect-show-graph: Bisecting. (line 65) -* magit-blame-disable-modes: Blaming. (line 165) -* magit-blame-echo-style: Blaming. (line 148) -* magit-blame-goto-chunk-hook: Blaming. (line 171) -* magit-blame-read-only: Blaming. (line 160) -* magit-blame-styles: Blaming. (line 143) -* magit-blame-time-format: Blaming. (line 155) -* magit-branch-adjust-remote-upstream-alist: Branch Commands. (line 210) -* magit-branch-direct-configure: Branch Commands. (line 20) -* magit-branch-prefer-remote-upstream: Branch Commands. (line 165) -* magit-branch-read-upstream-first: Branch Commands. (line 159) -* magit-buffer-name-format: Naming Buffers. (line 27) -* magit-bury-buffer-function: Quitting Windows. (line 14) -* magit-cherry-margin: Cherries. (line 22) -* magit-clone-always-transient: Cloning Repository. (line 12) -* magit-clone-default-directory: Cloning Repository. (line 90) -* magit-clone-name-alist: Cloning Repository. (line 103) -* magit-clone-set-remote-head: Cloning Repository. (line 68) -* magit-clone-set-remote.pushDefault: Cloning Repository. (line 78) -* magit-clone-url-format: Cloning Repository. (line 124) -* magit-commit-ask-to-stage: Initiating a Commit. (line 75) -* magit-commit-extend-override-date: Initiating a Commit. (line 84) -* magit-commit-reword-override-date: Initiating a Commit. (line 88) -* magit-commit-show-diff: Initiating a Commit. (line 80) -* magit-commit-squash-confirm: Initiating a Commit. (line 92) -* magit-completing-read-function: Support for Completion Frameworks. - (line 27) -* magit-define-global-key-bindings: Default Bindings. (line 6) -* magit-diff-adjust-tab-width: Diff Options. (line 21) -* magit-diff-buffer-file-locked: Commands for Buffers Visiting Files. - (line 61) -* magit-diff-extra-stat-arguments: Diff Options. (line 128) -* magit-diff-hide-trailing-cr-characters: Diff Options. (line 90) -* magit-diff-highlight-hunk-region-functions: Diff Options. (line 94) -* magit-diff-highlight-indentation: Diff Options. (line 75) -* magit-diff-highlight-trailing: Diff Options. (line 70) -* magit-diff-paint-whitespace: Diff Options. (line 43) -* magit-diff-paint-whitespace-lines: Diff Options. (line 60) -* magit-diff-refine-hunk: Diff Options. (line 6) -* magit-diff-refine-ignore-whitespace: Diff Options. (line 16) -* magit-diff-unmarked-lines-keep-foreground: Diff Options. (line 120) -* magit-diff-visit-previous-blob: Visiting Files and Blobs from a Diff. - (line 39) -* magit-direct-use-buffer-arguments: Transient Arguments and Buffer Variables. - (line 73) -* magit-display-buffer-function: Switching Buffers. (line 27) -* magit-display-buffer-noselect: Switching Buffers. (line 18) -* magit-dwim-selection: Completion and Confirmation. - (line 42) -* magit-ediff-dwim-show-on-hunks: Ediffing. (line 73) -* magit-ediff-quit-hook: Ediffing. (line 88) -* magit-ediff-show-stash-with-index: Ediffing. (line 81) -* magit-generate-buffer-name-function: Naming Buffers. (line 6) -* magit-git-debug: Viewing Git Output. (line 28) -* magit-git-debug <1>: Getting a Value from Git. - (line 79) -* magit-git-executable: Git Executable. (line 26) -* magit-git-global-arguments: Global Git Arguments. - (line 6) -* magit-keep-region-overlay: The Selection. (line 52) -* magit-list-refs-sortby: Additional Completion Options. - (line 6) -* magit-log-auto-more: Log Buffer. (line 80) -* magit-log-buffer-file-locked: Commands for Buffers Visiting Files. - (line 88) -* magit-log-margin: Log Margin. (line 12) -* magit-log-margin-show-committer-date: Log Margin. (line 49) -* magit-log-section-commit-count: Status Sections. (line 136) -* magit-log-select-margin: Select from Log. (line 30) -* magit-log-show-refname-after-summary: Log Buffer. (line 86) -* magit-log-trace-definition-function: Commands Available in Diffs. - (line 18) -* magit-module-sections-hook: Status Module Sections. - (line 20) -* magit-module-sections-nested: Status Module Sections. - (line 24) -* magit-no-confirm: Action Confirmation. (line 18) -* magit-pop-revision-stack-format: Using the Revision Stack. - (line 35) -* magit-post-commit-hook: Initiating a Commit. (line 101) -* magit-post-display-buffer-hook: Switching Buffers. (line 95) -* magit-pre-display-buffer-hook: Switching Buffers. (line 84) -* magit-prefer-remote-upstream: Branch Git Variables. - (line 126) -* magit-prefix-use-buffer-arguments: Transient Arguments and Buffer Variables. - (line 64) -* magit-process-raise-error: Calling Git for Effect. - (line 136) -* magit-pull-or-fetch: Fetching. (line 59) -* magit-reflog-margin: Reflog. (line 23) -* magit-refresh-args: Refreshing Buffers. (line 55) -* magit-refresh-buffer-hook: Automatic Refreshing of Magit Buffers. - (line 43) -* magit-refresh-function: Refreshing Buffers. (line 49) -* magit-refresh-status-buffer: Automatic Refreshing of Magit Buffers. - (line 49) -* magit-refs-filter-alist: References Buffer. (line 159) -* magit-refs-focus-column-width: References Buffer. (line 82) -* magit-refs-margin: References Buffer. (line 97) -* magit-refs-margin-for-tags: References Buffer. (line 125) -* magit-refs-pad-commit-counts: References Buffer. (line 49) -* magit-refs-primary-column-width: References Buffer. (line 69) -* magit-refs-sections-hook: References Sections. (line 13) -* magit-refs-show-commit-count: References Buffer. (line 37) -* magit-refs-show-remote-prefix: References Buffer. (line 62) -* magit-remote-add-set-remote.pushDefault: Remote Commands. (line 92) -* magit-remote-direct-configure: Remote Commands. (line 21) -* magit-remote-git-executable: Git Executable. (line 33) -* magit-repolist-columns: Repository List. (line 14) -* magit-repository-directories: Status Buffer. (line 58) -* magit-revision-filter-files-on-follow: Revision Buffer. (line 64) -* magit-revision-insert-related-refs: Revision Buffer. (line 6) -* magit-revision-show-gravatars: Revision Buffer. (line 19) -* magit-revision-use-hash-sections: Revision Buffer. (line 36) -* magit-root-section: Matching Sections. (line 87) -* magit-save-repository-buffers: Automatic Saving of File-Visiting Buffers. - (line 13) -* magit-section-cache-visibility: Section Visibility. (line 95) -* magit-section-initial-visibility-alist: Section Visibility. (line 78) -* magit-section-movement-hook: Section Movement. (line 46) -* magit-section-set-visibility-hook: Section Visibility. (line 106) -* magit-section-show-child-count: Section Options. (line 9) -* magit-section-visibility-indicator: Section Visibility. (line 124) -* magit-shell-command-verbose-prompt: Running Git Manually. - (line 47) -* magit-stashes-margin: Stashing. (line 104) -* magit-status-headers-hook: Status Header Sections. - (line 18) -* magit-status-margin: Status Options. (line 10) -* magit-status-refresh-hook: Status Options. (line 6) -* magit-status-sections-hook: Status Sections. (line 10) -* magit-submodule-list-columns: Listing Submodules. (line 21) -* magit-this-process: Calling Git for Effect. - (line 131) -* magit-uniquify-buffer-names: Naming Buffers. (line 74) -* magit-unstage-committed: Staging and Unstaging. - (line 56) -* magit-update-other-window-delay: Section Movement. (line 112) -* magit-visit-ref-behavior: References Buffer. (line 192) -* magit-wip-after-apply-mode: Legacy Wip Modes. (line 19) -* magit-wip-after-apply-mode-lighter: Legacy Wip Modes. (line 59) -* magit-wip-after-save-local-mode-lighter: Legacy Wip Modes. (line 55) -* magit-wip-after-save-mode: Legacy Wip Modes. (line 13) -* magit-wip-before-change-mode: Legacy Wip Modes. (line 33) -* magit-wip-before-change-mode-lighter: Legacy Wip Modes. (line 63) -* magit-wip-initial-backup-mode: Legacy Wip Modes. (line 38) -* magit-wip-initial-backup-mode-lighter: Legacy Wip Modes. (line 67) -* magit-wip-merge-branch: Wip Graph. (line 6) -* magit-wip-mode: Wip Modes. (line 30) -* magit-wip-mode-lighter: Wip Modes. (line 104) -* magit-wip-namespace: Wip Modes. (line 96) -* notes.displayRef: Notes. (line 65) -* pull.rebase: Branch Git Variables. - (line 57) -* remote.NAME.fetch: Remote Git Variables. - (line 15) -* remote.NAME.push: Remote Git Variables. - (line 26) -* remote.NAME.pushurl: Remote Git Variables. - (line 20) -* remote.NAME.tagOpts: Remote Git Variables. - (line 31) -* remote.NAME.url: Remote Git Variables. - (line 10) -* remote.pushDefault: Branch Git Variables. - (line 71) - diff --git a/elpa/magit-20220116.1908/AUTHORS.md b/elpa/magit-20220116.1908/AUTHORS.md new file mode 100644 index 00000000..44343b63 --- /dev/null +++ b/elpa/magit-20220116.1908/AUTHORS.md @@ -0,0 +1,382 @@ +Authors +======= + +The following people have contributed to Magit, including the +libraries `git-commit.el`, `magit-popup.el`, and `with-editor.el` +which are distributed as separate Elpa packages. + +For statistics see https://magit.vc/stats/authors.html. + +Names below are sorted alphabetically. + +Author +------ + +- Marius Vollmer + +Maintainer +---------- + +- Jonas Bernoulli + +Developers +---------- + +- Kyle Meyer +- Noam Postavsky + +Retired Maintainers and Developers +---------------------------------- + +- Nicolas Dudebout +- Peter J. Weisberg +- Pieter Praet +- Phil Jackson +- Rémi Vanicat +- Yann Hodique + +Contributors +------------ + +- Aaron Culich +- Aaron Madlon-Kay +- Abdo Roig-Maranges +- Adam Benanti <0entropy@protonmail.com> +- Adam Kruszewski +- Adam Porter +- Adam Spiers +- Adeodato Simó +- Ævar Arnfjörð Bjarmason +- Alan Falloon +- Alban Gruin +- Aleksey Uimanov +- Alexander Gramiak +- Alexander Miller +- Alex Branham +- Alex Dunn +- Alexey Voinov +- Alex Kost +- Alex Ott +- Allen Li +- Andreas Fuchs +- Andreas Liljeqvist +- Andreas Rottmann +- Andrei Chițu +- Andrew Eggenberger +- Andrew Kirkpatrick +- Andrew Psaltis +- Andrew Schwartzmeyer +- Andrey Smirnov +- Andriy Kmit' +- Andy Sawyer +- Aria Edmonds +- Arialdo Martini +- Arnau Roig Ninerola +- Ashlynn Anderson +- Barak A. Pearlmutter +- Bar Magal +- Bart Bakker +- Basil L. Contovounesios +- Bastian Beischer +- Bastian Beranek +- Benjamin Motz +- Ben North +- Ben Walton +- Bob Uhl +- Boruch Baum +- Bradley Wright +- Brandon W Maister +- Brian Leung +- Brian Warner +- Bryan Shell +- Buster Copley +- Carl Lieberman +- Chillar Anand +- Chris Bernard +- Chris Done +- Chris LaRose +- Chris Moore +- Chris Ring +- Chris Shoemaker +- Christian Dietrich +- Christian Kluge +- Christophe Junke +- Christopher Monsanto +- Clément Pit-Claudel +- Cornelius Mika +- 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 Hull +- David L. Rager +- David Wallin +- Dean Kariniemi <8913263+d3k4r@users.noreply.github.com> +- Dennis Paskorz +- Divye Kapoor +- Dominique Quatravaux +- Duianto Vebotci +- Eli Barzilay +- Eric Davis +- Eric +- Eric Prud'hommeaux +- Eric Schulte +- Erik Anderson +- Evan Torrie +- Evgkeni Sampelnikof +- Eyal Lotem +- Fabian Wiget +- Felix Geller +- Felix Yan +- Feng Li +- Florian Ragwitz +- Franklin Delehelle +- Frédéric Giquel +- Fritz Grabo +- Fritz Stelzer +- Geoff Shannon +- George Kadianakis +- Graham Clark +- 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 +- Jan Tatarik +- Jasper St. Pierre +- Jeff Bellegarde +- Jeff Dairiki +- Jeremy Meng +- Jesse Alama +- Jim Blandy +- Joakim Jalap +- Johannes Altmanninger +- 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 +- Josh Elsasser +- Josiah Schwab +- Julien Danjou +- Justin Burkett +- Justin Caratzas +- Justin Guenther +- Justin Thomas +- Kan-Ru Chen +- Kenny Ballou +- Keshav Kini +- Kevin Brubeck Unhammer +- Kevin J. Foley +- Kévin Le Gouguec +- Kimberly Wolk +- Knut Olav Bøhmer +- Kyle Meyer +- Laurent Laffont +- Laverne Schrock +- Leandro Facchinetti +- Lele Gaifax +- Leo Liu +- Leonardo Etcheverry +- Leo Vivier +- Lingchao Xin +- Lin Sun +- Li-Yun Chang +- Lluís Vilanova +- Loic Dachary +- Louis Roché +- Luís Oliveira +- Luke Amdor +- Magnus Malm +- Mak Kolybabi +- Manuel Vázquez Acosta +- Marcel Wolf +- Marc Herbert +- Marcin Bachry +- Marco Craveiro +- Marco Wahl +- Marc Sherry +- Marian Schubert +- Mario Rodas +- Marius Vollmer +- 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 +- Michal Sojka +- Miciah Masters +- Miles Bader +- Miloš Mošić +- Mitchel Humpherys +- Moritz Bunkus +- Naoya Yamashita +- Natalie Weizenbaum +- Nguyễn Tuấn Anh +- Nic Ferier +- Nick Alcock +- Nick Alexander +- Nick Dimiduk +- Nicklas Lindgren +- Nicolas Dudebout +- Nicolas Petton +- Nicolas Richard +- 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 +- Peter Eisentraut +- Peter Jaros +- Peter J. Weisberg +- Peter Vasil +- Philippe Cavalaria +- Philippe Vaucher +- Philipp Fehre +- Philipp Haselwarter +- Philipp Stephani +- Philip Weaver +- Phil Jackson +- Phil Sainty +- Pierre Neidhardt +- Pieter Praet +- Prathamesh Sonpatki +- Pritam Baral +- rabio +- Radon Rosborough +- Rafael Laboissiere +- Raimon Grau +- Ramkumar Ramachandra +- Remco van 't Veer +- Rémi Vanicat +- René Stadler +- Richard Kim +- Robert Boone +- Robin Green +- Roey Darwish Dror +- Roger Crew +- Romain Francoise +- Ron Parker +- Roy Crihfield +- Rüdiger Sonderfeld +- Russell Black +- Ryan C. Thompson +- Sam Cedarbaum +- Samuel Bronson +- Samuel W. Flint +- Sanjoy Das +- Sean Allred +- Sean Bryant +- Sean Whitton +- Sebastian Wiesner +- Sébastien Gross +- Seong-Kook Shin +- Sergey Pashinin +- Sergey Vinokurov +- Servilio Afre Puentes +- Siavash Askari Nasr +- Silent Sphere +- Simon Pintarelli +- Štěpán Němec +- Steven Chow +- Steven E. Harris +- Steven Thomas +- Steven Vancoillie +- Steve Purcell +- Suhail Shergill +- Sylvain Rousseau +- Syohei Yoshida +- Szunti +- Takafumi Arakaki +- Tassilo Horn +- TEC +- Teemu Likonen +- Teruki Shigitani +- Thierry Volpiatto +- Thomas A Caswell +- Thomas Fini Hansen +- Thomas Frössman +- Thomas Jost +- Thomas Riccardi +- Tibor Simko +- Timo Juhani Lindfors +- Tim Perkins +- Tim Wraight +- Ting-Yu Lin +- Tom Feist +- Toon Claes +- Topi Miettinen +- Troy Hinckley +- Tsuyoshi Kitamoto +- Tunc Uzlu +- 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 +- Yuichi Higashi +- Yuri Khan +- Zach Latta +- zakora +- Zhu Zihao +- zilongshanren diff --git a/elpa/magit-20220116.1908/LICENSE b/elpa/magit-20220116.1908/LICENSE new file mode 100644 index 00000000..f288702d --- /dev/null +++ b/elpa/magit-20220116.1908/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + 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 + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "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. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +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 +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + 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 +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program 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 of the License, or + (at your option) any later version. + + This program 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 program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + 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 --git a/elpa/magit-20220116.1908/dir b/elpa/magit-20220116.1908/dir new file mode 100644 index 00000000..dfdbd715 --- /dev/null +++ b/elpa/magit-20220116.1908/dir @@ -0,0 +1,18 @@ +This is the file .../info/dir, which contains the +topmost node of the Info hierarchy, called (dir)Top. +The first time you invoke Info you start off looking at this node. + +File: dir, Node: Top This is the top of the INFO tree + + This (the Directory node) gives a menu of major topics. + Typing "q" exits, "H" lists all Info commands, "d" returns here, + "h" gives a primer for first-timers, + "mEmacs" visits the Emacs manual, etc. + + In Emacs, you can click mouse button 2 on a menu item or cross reference + to select it. + +* Menu: + +Emacs +* Magit: (magit). Using Git from Emacs with Magit. diff --git a/elpa/magit-20220116.1908/git-rebase.el b/elpa/magit-20220116.1908/git-rebase.el new file mode 100644 index 00000000..a893a64d --- /dev/null +++ b/elpa/magit-20220116.1908/git-rebase.el @@ -0,0 +1,833 @@ +;;; git-rebase.el --- Edit Git rebase files -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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: Phil Jackson +;; Maintainer: Jonas Bernoulli + +;; 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 . + +;;; Commentary: + +;; This package assists the user in editing the list of commits to be +;; rewritten during an interactive rebase. + +;; When the user initiates an interactive rebase, e.g. using "r e" in +;; a Magit buffer or on the command line using "git rebase -i REV", +;; Git invokes the `$GIT_SEQUENCE_EDITOR' (or if that is undefined +;; `$GIT_EDITOR' or even `$EDITOR') letting the user rearrange, drop, +;; reword, edit, and squash commits. + +;; This package provides the major-mode `git-rebase-mode' which makes +;; doing so much more fun, by making the buffer more colorful and +;; providing the following commands: +;; +;; C-c C-c Tell Git to make it happen. +;; C-c C-k Tell Git that you changed your mind, i.e. abort. +;; +;; p Move point to previous line. +;; n Move point to next line. +;; +;; M-p Move the commit at point up. +;; M-n Move the commit at point down. +;; +;; k Drop the commit at point. +;; c Don't drop the commit at point. +;; r Change the message of the commit at point. +;; e Edit the commit at point. +;; s Squash the commit at point, into the one above. +;; f Like "s" but don't also edit the commit message. +;; b Break for editing at this point in the sequence. +;; x Add a script to be run with the commit at point +;; being checked out. +;; z Add noop action at point. +;; +;; SPC Show the commit at point in another buffer. +;; RET Show the commit at point in another buffer and +;; select its window. +;; C-/ Undo last change. +;; +;; Commands for --rebase-merges: +;; l Associate label with current HEAD in sequence. +;; MM Merge specified revisions into HEAD. +;; Mt Toggle whether the merge will invoke an editor +;; before committing. +;; t Reset HEAD to the specified label. + +;; You should probably also read the `git-rebase' manpage. + +;;; Code: + +(require 'magit) + +(require 'easymenu) +(require 'server) +(require 'with-editor) + +(defvar recentf-exclude) + +;;; Options +;;;; Variables + +(defgroup git-rebase nil + "Edit Git rebase sequences." + :link '(info-link "(magit)Editing Rebase Sequences") + :group 'tools) + +(defcustom git-rebase-auto-advance t + "Whether to move to next line after changing a line." + :group 'git-rebase + :type 'boolean) + +(defcustom git-rebase-show-instructions t + "Whether to show usage instructions inside the rebase buffer." + :group 'git-rebase + :type 'boolean) + +(defcustom git-rebase-confirm-cancel t + "Whether confirmation is required to cancel." + :group 'git-rebase + :type 'boolean) + +;;;; Faces + +(defgroup git-rebase-faces nil + "Faces used by Git-Rebase mode." + :group 'faces + :group 'git-rebase) + +(defface git-rebase-hash '((t :inherit magit-hash)) + "Face for commit hashes." + :group 'git-rebase-faces) + +(defface git-rebase-label '((t :inherit magit-refname)) + "Face for labels in label, merge, and reset lines." + :group 'git-rebase-faces) + +(defface git-rebase-description '((t nil)) + "Face for commit descriptions." + :group 'git-rebase-faces) + +(defface git-rebase-action + '((t :inherit font-lock-keyword-face)) + "Face for action keywords." + :group 'git-rebase-faces) + +(defface git-rebase-killed-action + '((t :inherit font-lock-comment-face :strike-through t)) + "Face for commented commit action lines." + :group 'git-rebase-faces) + +(defface git-rebase-comment-hash + '((t :inherit git-rebase-hash :weight bold)) + "Face for commit hashes in commit message comments." + :group 'git-rebase-faces) + +(defface git-rebase-comment-heading + '((t :inherit font-lock-keyword-face)) + "Face for headings in rebase message comments." + :group 'git-rebase-faces) + +;;; Keymaps + +(defvar git-rebase-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map special-mode-map) + (define-key map (kbd "C-m") 'git-rebase-show-commit) + (define-key map (kbd "p") 'git-rebase-backward-line) + (define-key map (kbd "n") 'forward-line) + (define-key map (kbd "M-p") 'git-rebase-move-line-up) + (define-key map (kbd "M-n") 'git-rebase-move-line-down) + (define-key map (kbd "c") 'git-rebase-pick) + (define-key map (kbd "k") 'git-rebase-kill-line) + (define-key map (kbd "C-k") 'git-rebase-kill-line) + (define-key map (kbd "b") 'git-rebase-break) + (define-key map (kbd "e") 'git-rebase-edit) + (define-key map (kbd "l") 'git-rebase-label) + (define-key map (kbd "MM") 'git-rebase-merge) + (define-key map (kbd "Mt") 'git-rebase-merge-toggle-editmsg) + (define-key map (kbd "m") 'git-rebase-edit) + (define-key map (kbd "f") 'git-rebase-fixup) + (define-key map (kbd "q") 'undefined) + (define-key map (kbd "r") 'git-rebase-reword) + (define-key map (kbd "w") 'git-rebase-reword) + (define-key map (kbd "s") 'git-rebase-squash) + (define-key map (kbd "t") 'git-rebase-reset) + (define-key map (kbd "x") 'git-rebase-exec) + (define-key map (kbd "y") 'git-rebase-insert) + (define-key map (kbd "z") 'git-rebase-noop) + (define-key map (kbd "SPC") 'git-rebase-show-or-scroll-up) + (define-key map (kbd "DEL") 'git-rebase-show-or-scroll-down) + (define-key map (kbd "C-x C-t") 'git-rebase-move-line-up) + (define-key map [M-up] 'git-rebase-move-line-up) + (define-key map [M-down] 'git-rebase-move-line-down) + (define-key map [remap undo] 'git-rebase-undo) + map) + "Keymap for Git-Rebase mode.") + +(put 'git-rebase-reword :advertised-binding (kbd "r")) +(put 'git-rebase-move-line-up :advertised-binding (kbd "M-p")) +(put 'git-rebase-kill-line :advertised-binding (kbd "k")) + +(easy-menu-define git-rebase-mode-menu git-rebase-mode-map + "Git-Rebase mode menu" + '("Rebase" + ["Pick" git-rebase-pick t] + ["Reword" git-rebase-reword t] + ["Edit" git-rebase-edit t] + ["Squash" git-rebase-squash t] + ["Fixup" git-rebase-fixup t] + ["Kill" git-rebase-kill-line t] + ["Noop" git-rebase-noop t] + ["Execute" git-rebase-exec t] + ["Move Down" git-rebase-move-line-down t] + ["Move Up" git-rebase-move-line-up t] + "---" + ["Cancel" with-editor-cancel t] + ["Finish" with-editor-finish t])) + +(defvar git-rebase-command-descriptions + '((with-editor-finish . "tell Git to make it happen") + (with-editor-cancel . "tell Git that you changed your mind, i.e. abort") + (git-rebase-backward-line . "move point to previous line") + (forward-line . "move point to next line") + (git-rebase-move-line-up . "move the commit at point up") + (git-rebase-move-line-down . "move the commit at point down") + (git-rebase-show-or-scroll-up . "show the commit at point in another buffer") + (git-rebase-show-commit + . "show the commit at point in another buffer and select its window") + (undo . "undo last change") + (git-rebase-kill-line . "drop the commit at point") + (git-rebase-insert . "insert a line for an arbitrary commit") + (git-rebase-noop . "add noop action at point"))) + +;;; Commands + +(defun git-rebase-pick () + "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. +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. +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. +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. +If the region is active, act on all lines touched by the region." + (interactive) + (git-rebase-set-action "fixup")) + +(defvar-local git-rebase-comment-re nil) + +(defvar git-rebase-short-options + '((?b . "break") + (?e . "edit") + (?f . "fixup") + (?l . "label") + (?m . "merge") + (?p . "pick") + (?r . "reword") + (?s . "squash") + (?t . "reset") + (?x . "exec")) + "Alist mapping single key of an action to the full name.") + +(defclass git-rebase-action () + (;; action-type: commit, exec, bare, label, merge + (action-type :initarg :action-type :initform nil) + ;; Examples for each action type: + ;; | action | action options | target | trailer | + ;; |--------+----------------+---------+---------| + ;; | pick | | hash | subject | + ;; | exec | | command | | + ;; | noop | | | | + ;; | reset | | name | subject | + ;; | merge | -C hash | name | subject | + (action :initarg :action :initform nil) + (action-options :initarg :action-options :initform nil) + (target :initarg :target :initform nil) + (trailer :initarg :trailer :initform nil) + (comment-p :initarg :comment-p :initform nil))) + +(defvar git-rebase-line-regexps + `((commit . ,(concat + (regexp-opt '("e" "edit" + "f" "fixup" + "p" "pick" + "r" "reword" + "s" "squash") + "\\(?1:") + " \\(?3:[^ \n]+\\) ?\\(?4:.*\\)")) + (exec . "\\(?1:x\\|exec\\) \\(?3:.*\\)") + (bare . ,(concat (regexp-opt '("b" "break" "noop") "\\(?1:") + " *$")) + (label . ,(concat (regexp-opt '("l" "label" + "t" "reset") + "\\(?1:") + " \\(?3:[^ \n]+\\) ?\\(?4:.*\\)")) + (merge . ,(concat "\\(?1:m\\|merge\\) " + "\\(?:\\(?2:-[cC] [^ \n]+\\) \\)?" + "\\(?3:[^ \n]+\\)" + " ?\\(?4:.*\\)")))) + +;;;###autoload +(defun git-rebase-current-line () + "Parse current line into a `git-rebase-action' instance. +If the current line isn't recognized as a rebase line, an +instance with all nil values is returned." + (save-excursion + (goto-char (line-beginning-position)) + (if-let ((re-start (concat "^\\(?5:" (regexp-quote comment-start) + "\\)? *")) + (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))) + (or (cdr (assoc action git-rebase-short-options)) + action)) + :action-options (match-string-no-properties 2) + :target (match-string-no-properties 3) + :trailer (match-string-no-properties 4) + :comment-p (and (match-string 5) t)) + ;; Use default empty class rather than nil to ease handling. + (git-rebase-action)))) + +(defun git-rebase-set-action (action) + "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 + (when pos (goto-char pos)) + (and (oref (git-rebase-current-line) action-type) + t))) + +(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))))) + ((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. +If N is negative, move the commit up instead. With an active +region, move all the lines that the region touches, not just the +current line." + (interactive "p") + (pcase-let* ((`(,beg ,end) + (or (git-rebase-region-bounds) + (list (line-beginning-position) + (1+ (line-end-position))))) + (pt-offset (- (point) beg)) + (mark-offset (and mark-active (- (mark) beg)))) + (save-restriction + (narrow-to-region + (point-min) + (1- + (if git-rebase-show-instructions + (save-excursion + (goto-char (point-min)) + (while (or (git-rebase-line-p) + ;; The output for --rebase-merges has empty + ;; lines and "Branch" comments interspersed. + (looking-at-p "^$") + (looking-at-p (concat git-rebase-comment-re + " Branch"))) + (forward-line)) + (line-beginning-position)) + (point-max)))) + (if (or (and (< n 0) (= beg (point-min))) + (and (> n 0) (= end (point-max))) + (> end (point-max))) + (ding) + (goto-char (if (< n 0) beg end)) + (forward-line n) + (atomic-change-group + (let ((inhibit-read-only t)) + (insert (delete-and-extract-region beg end))) + (let ((new-beg (- (point) (- end beg)))) + (when (use-region-p) + (setq deactivate-mark nil) + (set-mark (+ new-beg mark-offset))) + (goto-char (+ new-beg pt-offset)))))))) + +(defun git-rebase-move-line-up (n) + "Move the current commit (or command) N lines up. +If N is negative, move the commit down instead. With an active +region, move all the lines that the region touches, not just the +current line." + (interactive "p") + (git-rebase-move-line-down (- n))) + +(defun git-rebase-highlight-region (start end window rol) + (let ((inhibit-read-only t) + (deactivate-mark nil) + (bounds (git-rebase-region-bounds))) + (mapc #'delete-overlay magit-section-highlight-overlays) + (when bounds + (magit-section-make-overlay (car bounds) (cadr bounds) + 'magit-section-heading-selection)) + (if (and bounds (not magit-section-keep-region-overlay)) + (funcall (default-value 'redisplay-unhighlight-region-function) rol) + (funcall (default-value 'redisplay-highlight-region-function) + start end window rol)))) + +(defun git-rebase-unhighlight-region (rol) + (mapc #'delete-overlay magit-section-highlight-overlays) + (funcall (default-value 'redisplay-unhighlight-region-function) rol)) + +(defun git-rebase-kill-line () + "Kill the current action line. +If the region is active, act on all lines touched by the region." + (interactive) + (git-rebase-set-action nil)) + +(defun git-rebase-insert (rev) + "Read an arbitrary commit and insert it below current line." + (interactive (list (magit-read-branch-or-commit "Insert revision"))) + (forward-line) + (--if-let (magit-rev-format "%h %s" rev) + (let ((inhibit-read-only t)) + (insert "pick " it ?\n)) + (user-error "Unknown revision"))) + +(defun git-rebase-set-noncommit-action (action value-fn arg) + (goto-char (line-beginning-position)) + (pcase-let* ((inhibit-read-only t) + (`(,initial ,trailer ,comment-p) + (and (not arg) + (with-slots ((ln-action action) + target trailer comment-p) + (git-rebase-current-line) + (and (equal ln-action action) + (list target trailer comment-p))))) + (value (funcall value-fn initial))) + (pcase (list value initial comment-p) + (`("" nil ,_) + (ding)) + (`("" ,_ ,_) + (magit-delete-line)) + (_ + (if initial + (magit-delete-line) + (forward-line)) + (insert (concat action " " value + (and (equal value initial) + trailer + (concat " " trailer)) + "\n")) + (unless git-rebase-auto-advance + (forward-line -1)))))) + +(defun git-rebase-exec (arg) + "Insert a shell command to be run after the current commit. + +If there already is such a command on the current line, then edit +that instead. With a prefix argument insert a new command even +when there already is one on the current line. With empty input +remove the command on the current line, if any." + (interactive "P") + (git-rebase-set-noncommit-action + "exec" + (lambda (initial) (read-shell-command "Execute: " initial)) + arg)) + +(defun git-rebase-label (arg) + "Add a label after the current commit. +If there already is a label on the current line, then edit that +instead. With a prefix argument, insert a new label even when +there is already a label on the current line. With empty input, +remove the label on the current line, if any." + (interactive "P") + (git-rebase-set-noncommit-action + "label" + (lambda (initial) + (read-from-minibuffer + "Label: " initial magit-minibuffer-local-ns-map)) + arg)) + +(defun git-rebase-buffer-labels () + (let (labels) + (save-excursion + (goto-char (point-min)) + (while (re-search-forward "^\\(?:l\\|label\\) \\([^ \n]+\\)" nil t) + (push (match-string-no-properties 1) labels))) + (nreverse labels))) + +(defun git-rebase-reset (arg) + "Reset the current HEAD to a label. +If there already is a reset command on the current line, then +edit that instead. With a prefix argument, insert a new reset +line even when point is already on a reset line. With empty +input, remove the reset command on the current line, if any." + (interactive "P") + (git-rebase-set-noncommit-action + "reset" + (lambda (initial) + (or (magit-completing-read "Label" (git-rebase-buffer-labels) + nil t initial) + "")) + arg)) + +(defun git-rebase-merge (arg) + "Add a merge command after the current commit. +If there is already a merge command on the current line, then +replace that command instead. With a prefix argument, insert a +new merge command even when there is already one on the current +line. With empty input, remove the merge command on the current +line, if any." + (interactive "P") + (git-rebase-set-noncommit-action + "merge" + (lambda (_) + (or (magit-completing-read "Merge" (git-rebase-buffer-labels)) + "")) + arg)) + +(defun git-rebase-merge-toggle-editmsg () + "Toggle whether an editor is invoked when performing the merge at point. +When a merge command uses a lower-case -c, the message for the +specified commit will be opened in an editor before creating the +commit. For an upper-case -C, the message will be used as is." + (interactive) + (with-slots (action-type target action-options trailer) + (git-rebase-current-line) + (if (eq action-type 'merge) + (let ((inhibit-read-only t)) + (magit-delete-line) + (insert + (format "merge %s %s %s\n" + (replace-regexp-in-string + "-[cC]" (lambda (c) + (if (equal c "-c") "-C" "-c")) + action-options t t) + target + trailer))) + (ding)))) + +(defun git-rebase-set-bare-action (action arg) + (goto-char (line-beginning-position)) + (with-slots ((ln-action action) comment-p) + (git-rebase-current-line) + (let ((same-action-p (equal action ln-action)) + (inhibit-read-only t)) + (when (or arg + (not ln-action) + (not same-action-p) + (and same-action-p comment-p)) + (unless (or arg (not same-action-p)) + (magit-delete-line)) + (insert action ?\n) + (unless git-rebase-auto-advance + (forward-line -1)))))) + +(defun git-rebase-noop (&optional arg) + "Add noop action at point. + +If the current line already contains a noop action, leave it +unchanged. If there is a commented noop action present, remove +the comment. Otherwise add a new noop action. With a prefix +argument insert a new noop action regardless of what is already +present on the current line. + +A noop action can be used to make git perform a rebase even if +no commits are selected. Without the noop action present, git +would see an empty file and therefore do nothing." + (interactive "P") + (git-rebase-set-bare-action "noop" arg)) + +(defun git-rebase-break (&optional arg) + "Add break action at point. + +If there is a commented break action present, remove the comment. +If the current line already contains a break action, add another +break action only if a prefix argument is given. + +A break action can be used to interrupt the rebase at the +specified point. It is particularly useful for pausing before +the first commit in the sequence. For other cases, the +equivalent behavior can be achieved with `git-rebase-edit'." + (interactive "P") + (git-rebase-set-bare-action "break" arg)) + +(defun git-rebase-undo (&optional arg) + "Undo some previous changes. +Like `undo' but works in read-only buffers." + (interactive "P") + (let ((inhibit-read-only t)) + (undo arg))) + +(defun git-rebase--show-commit (&optional scroll) + (let ((disable-magit-save-buffers t)) + (save-excursion + (goto-char (line-beginning-position)) + (--if-let (with-slots (action-type target) (git-rebase-current-line) + (and (eq action-type 'commit) + target)) + (pcase scroll + (`up (magit-diff-show-or-scroll-up)) + (`down (magit-diff-show-or-scroll-down)) + (_ (apply #'magit-show-commit it + (magit-diff-arguments 'magit-revision-mode)))) + (ding))))) + +(defun git-rebase-show-commit () + "Show the commit on the current line if any." + (interactive) + (git-rebase--show-commit)) + +(defun git-rebase-show-or-scroll-up () + "Update the commit buffer for commit on current line. + +Either show the commit at point in the appropriate buffer, or if +that buffer is already being displayed in the current frame and +contains information about that commit, then instead scroll the +buffer up." + (interactive) + (git-rebase--show-commit 'up)) + +(defun git-rebase-show-or-scroll-down () + "Update the commit buffer for commit on current line. + +Either show the commit at point in the appropriate buffer, or if +that buffer is already being displayed in the current frame and +contains information about that commit, then instead scroll the +buffer down." + (interactive) + (git-rebase--show-commit 'down)) + +(defun git-rebase-backward-line (&optional n) + "Move N lines backward (forward if N is negative). +Like `forward-line' but go into the opposite direction." + (interactive "p") + (forward-line (- (or n 1)))) + +;;; Mode + +;;;###autoload +(define-derived-mode git-rebase-mode special-mode "Git Rebase" + "Major mode for editing of a Git rebase file. + +Rebase files are generated when you run 'git rebase -i' or run +`magit-interactive-rebase'. They describe how Git should perform +the rebase. See the documentation for git-rebase (e.g., by +running 'man git-rebase' at the command line) for details." + :group 'git-rebase + (setq comment-start (or (magit-get "core.commentChar") "#")) + (setq git-rebase-comment-re (concat "^" (regexp-quote comment-start))) + (setq font-lock-defaults (list (git-rebase-mode-font-lock-keywords) t t)) + (unless git-rebase-show-instructions + (let ((inhibit-read-only t)) + (flush-lines git-rebase-comment-re))) + (unless with-editor-mode + ;; Maybe already enabled when using `shell-command' or an Emacs shell. + (with-editor-mode 1)) + (when git-rebase-confirm-cancel + (add-hook 'with-editor-cancel-query-functions + 'git-rebase-cancel-confirm nil t)) + (setq-local redisplay-highlight-region-function 'git-rebase-highlight-region) + (setq-local redisplay-unhighlight-region-function 'git-rebase-unhighlight-region) + (add-hook 'with-editor-pre-cancel-hook 'git-rebase-autostash-save nil t) + (add-hook 'with-editor-post-cancel-hook 'git-rebase-autostash-apply nil t) + (setq imenu-prev-index-position-function + #'magit-imenu--rebase-prev-index-position-function) + (setq imenu-extract-index-name-function + #'magit-imenu--rebase-extract-index-name-function) + (when (boundp 'save-place) + (setq save-place nil))) + +(defun git-rebase-cancel-confirm (force) + (or (not (buffer-modified-p)) + force + (magit-confirm 'abort-rebase "Abort this rebase" nil 'noabort))) + +(defun git-rebase-autostash-save () + (--when-let (magit-file-line (magit-git-dir "rebase-merge/autostash")) + (push (cons 'stash it) with-editor-cancel-alist))) + +(defun git-rebase-autostash-apply () + (--when-let (cdr (assq 'stash with-editor-cancel-alist)) + (magit-stash-apply it))) + +(defun git-rebase-match-comment-line (limit) + (re-search-forward (concat git-rebase-comment-re ".*") limit t)) + +(defun git-rebase-mode-font-lock-keywords () + "Font lock keywords for Git-Rebase mode." + `((,(concat "^" (cdr (assq 'commit git-rebase-line-regexps))) + (1 'git-rebase-action) + (3 'git-rebase-hash) + (4 'git-rebase-description)) + (,(concat "^" (cdr (assq 'exec git-rebase-line-regexps))) + (1 'git-rebase-action) + (3 'git-rebase-description)) + (,(concat "^" (cdr (assq 'bare git-rebase-line-regexps))) + (1 'git-rebase-action)) + (,(concat "^" (cdr (assq 'label git-rebase-line-regexps))) + (1 'git-rebase-action) + (3 'git-rebase-label) + (4 'font-lock-comment-face)) + ("^\\(m\\(?:erge\\)?\\) -[Cc] \\([^ \n]+\\) \\([^ \n]+\\)\\( #.*\\)?" + (1 'git-rebase-action) + (2 'git-rebase-hash) + (3 'git-rebase-label) + (4 'font-lock-comment-face)) + ("^\\(m\\(?:erge\\)?\\) \\([^ \n]+\\)" + (1 'git-rebase-action) + (2 'git-rebase-label)) + (,(concat git-rebase-comment-re " *" + (cdr (assq 'commit git-rebase-line-regexps))) + 0 'git-rebase-killed-action t) + (git-rebase-match-comment-line 0 'font-lock-comment-face) + ("\\[[^[]*\\]" + 0 'magit-keyword t) + ("\\(?:fixup!\\|squash!\\)" + 0 'magit-keyword-squash t) + (,(format "^%s Rebase \\([^ ]*\\) onto \\([^ ]*\\)" comment-start) + (1 'git-rebase-comment-hash t) + (2 'git-rebase-comment-hash t)) + (,(format "^%s \\(Commands:\\)" comment-start) + (1 'git-rebase-comment-heading t)) + (,(format "^%s Branch \\(.*\\)" comment-start) + (1 'git-rebase-label t)))) + +(defun git-rebase-mode-show-keybindings () + "Modify the \"Commands:\" section of the comment Git generates +at the bottom of the file so that in place of the one-letter +abbreviation for the command, it shows the command's keybinding. +By default, this is the same except for the \"pick\" command." + (let ((inhibit-read-only t)) + (save-excursion + (goto-char (point-min)) + (when (and git-rebase-show-instructions + (re-search-forward + (concat git-rebase-comment-re "\\s-+p, pick") + nil t)) + (goto-char (line-beginning-position)) + (pcase-dolist (`(,cmd . ,desc) git-rebase-command-descriptions) + (insert (format "%s %-8s %s\n" + comment-start + (substitute-command-keys (format "\\[%s]" cmd)) + desc))) + (while (re-search-forward (concat git-rebase-comment-re + "\\( ?\\)\\([^\n,],\\) " + "\\([^\n ]+\\) ") + nil t) + (let ((cmd (intern (concat "git-rebase-" (match-string 3))))) + (if (not (fboundp cmd)) + (delete-region (line-beginning-position) (1+ (line-end-position))) + (replace-match " " t t nil 1) + (replace-match + (format "%-8s" + (mapconcat #'key-description + (--remove (eq (elt it 0) 'menu-bar) + (reverse (where-is-internal + cmd git-rebase-mode-map))) + ", ")) + t t nil 2)))))))) + +(add-hook 'git-rebase-mode-hook 'git-rebase-mode-show-keybindings t) + +(defun git-rebase-mode-disable-before-save-hook () + (set (make-local-variable 'before-save-hook) nil)) + +(add-hook 'git-rebase-mode-hook 'git-rebase-mode-disable-before-save-hook) + +;;;###autoload +(defconst git-rebase-filename-regexp "/git-rebase-todo\\'") +;;;###autoload +(add-to-list 'auto-mode-alist + (cons git-rebase-filename-regexp 'git-rebase-mode)) + +(add-to-list 'with-editor-server-window-alist + (cons git-rebase-filename-regexp 'switch-to-buffer)) + +(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) + +;;; _ +(provide 'git-rebase) +;;; git-rebase.el ends here diff --git a/elpa/magit-20220116.1908/magit-apply.el b/elpa/magit-20220116.1908/magit-apply.el new file mode 100644 index 00000000..3edae33c --- /dev/null +++ b/elpa/magit-20220116.1908/magit-apply.el @@ -0,0 +1,808 @@ +;;; magit-apply.el --- apply Git diffs -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements commands for applying Git diffs or parts +;; of such a diff. The supported "apply variants" are apply, stage, +;; unstage, discard, and reverse - more than Git itself knows about, +;; at least at the porcelain level. + +;;; Code: + +(require 'magit-core) +(require 'magit-diff) +(require 'magit-wip) + +(require 'transient) ; See #3732. + +;; For `magit-apply' +(declare-function magit-am "magit-sequence" () t) +(declare-function magit-patch-apply "magit-patch" () t) +;; For `magit-discard-files' +(declare-function magit-checkout-stage "magit-merge" (file arg)) +(declare-function magit-checkout-read-stage "magit-merge" (file)) +(defvar auto-revert-verbose) +;; For `magit-stage-untracked' +(declare-function magit-submodule-add-1 "magit-submodule" + (url &optional path name args)) +(declare-function magit-submodule-read-name-for-path "magit-submodule" + (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) + +(cl-eval-when (compile load) + (when (< emacs-major-version 26) + (defalias 'smerge-keep-upper 'smerge-keep-mine) + (defalias 'smerge-keep-lower 'smerge-keep-other))) + +;;; Options + +(defcustom magit-delete-by-moving-to-trash t + "Whether Magit uses the system's trash can. + +You should absolutely not disable this and also remove `discard' +from `magit-no-confirm'. You shouldn't do that even if you have +all of the Magit-Wip modes enabled, because those modes do not +track any files that are not tracked in the proper branch." + :package-version '(magit . "2.1.0") + :group 'magit-essentials + :type 'boolean) + +(defcustom magit-unstage-committed t + "Whether unstaging a committed change reverts it instead. + +A committed change cannot be unstaged, because staging and +unstaging are actions that are concerned with the differences +between the index and the working tree, not with committed +changes. + +If this option is non-nil (the default), then typing \"u\" +\(`magit-unstage') on a committed change, causes it to be +reversed in the index but not the working tree. For more +information see command `magit-reverse-in-index'." + :package-version '(magit . "2.4.1") + :group 'magit-commands + :type 'boolean) + +(defcustom magit-reverse-atomically nil + "Whether to reverse changes atomically. + +If some changes can be reversed while others cannot, then nothing +is reversed if the value of this option is non-nil. But when it +is nil, then the changes that can be reversed are reversed and +for the other changes diff files are created that contain the +rejected reversals." + :package-version '(magit . "2.7.0") + :group 'magit-commands + :type 'boolean) + +(defcustom magit-post-stage-hook nil + "Hook run after staging changes. +This hook is run by `magit-refresh' if `this-command' +is a member of `magit-post-stage-hook-commands'." + :package-version '(magit . "2.90.0") + :group 'magit-commands + :type 'hook) + +(defvar magit-post-stage-hook-commands + '(magit-stage magit-stage-file magit-stage-modified)) + +(defcustom magit-post-unstage-hook nil + "Hook run after unstaging changes. +This hook is run by `magit-refresh' if `this-command' +is a member of `magit-post-unstage-hook-commands'." + :package-version '(magit . "2.90.0") + :group 'magit-commands + :type 'hook) + +(defvar magit-post-unstage-hook-commands + '(magit-unstage magit-unstage-file magit-unstage-all)) + +;;; Commands +;;;; Apply + +(defun magit-apply (&rest args) + "Apply the change at point to the working tree. +With a prefix argument fallback to a 3-way merge. Doing +so causes the change to be applied to the index as well." + (interactive (and current-prefix-arg (list "--3way"))) + (--when-let (magit-apply--get-selection) + (pcase (list (magit-diff-type) (magit-diff-scope)) + (`(,(or `unstaged `staged) ,_) + (user-error "Change is already in the working tree")) + (`(untracked ,(or `file `files)) + (call-interactively 'magit-am)) + (`(,_ region) (magit-apply-region it args)) + (`(,_ hunk) (magit-apply-hunk it args)) + (`(,_ hunks) (magit-apply-hunks it args)) + (`(rebase-sequence file) + (call-interactively 'magit-patch-apply)) + (`(,_ file) (magit-apply-diff it args)) + (`(,_ files) (magit-apply-diffs it args))))) + +(defun magit-apply--section-content (section) + (buffer-substring-no-properties (if (magit-hunk-section-p section) + (oref section start) + (oref section content)) + (oref section end))) + +(defun magit-apply-diffs (sections &rest args) + (setq sections (magit-apply--get-diffs sections)) + (magit-apply-patch sections args + (mapconcat + (lambda (s) + (concat (magit-diff-file-header s) + (magit-apply--section-content s))) + sections ""))) + +(defun magit-apply-diff (section &rest args) + (setq section (car (magit-apply--get-diffs (list section)))) + (magit-apply-patch section args + (concat (magit-diff-file-header section) + (magit-apply--section-content section)))) + +(defun magit-apply--adjust-hunk-new-starts (hunks) + "Adjust new line numbers in headers of HUNKS for partial application. +HUNKS should be a list of ordered, contiguous hunks to be applied +from a file. For example, if there is a sequence of hunks with +the headers + + @@ -2,6 +2,7 @@ + @@ -10,6 +11,7 @@ + @@ -18,6 +20,7 @@ + +and only the second and third are to be applied, they would be +adjusted as \"@@ -10,6 +10,7 @@\" and \"@@ -18,6 +19,7 @@\"." + (let* ((first-hunk (car hunks)) + (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 "Header hunks have to be applied individually")))) + (if (= offset 0) + hunks + (mapcar (lambda (hunk) + (if (string-match diff-hunk-header-re-unified hunk) + (replace-match (number-to-string + (- (string-to-number (match-string 3 hunk)) + offset)) + t t hunk 3) + (error "Hunk does not have expected header"))) + hunks)))) + +(defun magit-apply--adjust-hunk-new-start (hunk) + (car (magit-apply--adjust-hunk-new-starts (list hunk)))) + +(defun magit-apply-hunks (sections &rest args) + (let ((section (oref (car sections) parent))) + (when (string-match "^diff --cc" (oref section value)) + (user-error "Cannot un-/stage resolution hunks. Stage the whole file")) + (magit-apply-patch + section args + (concat (oref section header) + (mapconcat #'identity + (magit-apply--adjust-hunk-new-starts + (mapcar #'magit-apply--section-content sections)) + ""))))) + +(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")) + (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)) + (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-diff-hunk-region-patch section args))))) + +(defun magit-apply-patch (section:s args patch) + (let* ((files (if (atom section:s) + (list (oref section:s value)) + (--map (oref it value) section:s))) + (command (symbol-name this-command)) + (command (if (and command (string-match "^magit-\\([^-]+\\)" command)) + (match-string 1 command) + "apply")) + (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 magit-inhibit-refresh)) + (magit-wip-commit-before-change files (concat " before " command))) + (with-temp-buffer + (insert patch) + (magit-run-git-with-input + "apply" args "-p0" + (and ignore-context "-C0") + "--ignore-space-change" "-")) + (unless magit-inhibit-refresh + (when magit-wip-after-apply-mode + (magit-wip-commit-after-apply files (concat " after " command))) + (magit-refresh)))) + +(defun magit-apply--get-selection () + (or (magit-region-sections '(hunk file module) t) + (let ((section (magit-current-section))) + (pcase (oref section type) + ((or `hunk `file `module) section) + ((or `staged `unstaged `untracked + `stashed-index `stashed-worktree `stashed-untracked) + (oref section children)) + (_ (user-error "Cannot apply this, it's not a change")))))) + +(defun magit-apply--get-diffs (sections) + (magit-section-case + ([file diffstat] + (--map (or (magit-get-section + (append `((file . ,(oref it value))) + (magit-section-ident magit-root-section))) + (error "Cannot get required diff headers")) + sections)) + (t sections))) + +(defun magit-apply--diff-ignores-whitespace-p () + (and (cl-intersection magit-buffer-diff-args + '("--ignore-space-at-eol" + "--ignore-space-change" + "--ignore-all-space" + "--ignore-blank-lines") + :test #'equal) + t)) + +;;;; Stage + +(defun magit-stage (&optional intent) + "Add the change at point to the staging area. +With a prefix argument, INTENT, and an untracked file (or files) +at point, stage the file but not its content." + (interactive "P") + (--if-let (and (derived-mode-p 'magit-mode) (magit-apply--get-selection)) + (pcase (list (magit-diff-type) + (magit-diff-scope) + (magit-apply--diff-ignores-whitespace-p)) + (`(untracked ,_ ,_) (magit-stage-untracked intent)) + (`(unstaged region ,_) (magit-apply-region it "--cached")) + (`(unstaged hunk ,_) (magit-apply-hunk it "--cached")) + (`(unstaged hunks ,_) (magit-apply-hunks it "--cached")) + (`(unstaged file t) (magit-apply-diff it "--cached")) + (`(unstaged files t) (magit-apply-diffs it "--cached")) + (`(unstaged list t) (magit-apply-diffs it "--cached")) + (`(unstaged file nil) (magit-stage-1 "-u" (list (oref it value)))) + (`(unstaged files nil) (magit-stage-1 "-u" (magit-region-values nil t))) + (`(unstaged list nil) (magit-stage-modified)) + (`(staged ,_ ,_) (user-error "Already staged")) + (`(committed ,_ ,_) (user-error "Cannot stage committed changes")) + (`(undefined ,_ ,_) (user-error "Cannot stage this change"))) + (call-interactively 'magit-stage-file))) + +;;;###autoload +(defun magit-stage-file (file) + "Stage all changes to FILE. +With a prefix argument or when there is no file at point ask for +the file to be staged. Otherwise stage the file at point without +requiring confirmation." + (interactive + (let* ((atpoint (magit-section-value-if 'file)) + (current (magit-file-relative-name)) + (choices (nconc (magit-unstaged-files) + (magit-untracked-files))) + (default (car (member (or atpoint current) choices)))) + (list (if (or current-prefix-arg (not default)) + (magit-completing-read "Stage file" choices + nil t nil nil default) + default)))) + (magit-with-toplevel + (magit-stage-1 nil (list file)))) + +;;;###autoload +(defun magit-stage-modified (&optional all) + "Stage all changes to files modified in the worktree. +Stage all new content of tracked files and remove tracked files +that no longer exist in the working tree from the index also. +With a prefix argument also stage previously untracked (but not +ignored) files." + (interactive "P") + (when (magit-anything-staged-p) + (magit-confirm 'stage-all-changes)) + (magit-with-toplevel + (magit-stage-1 (if all "--all" "-u") magit-buffer-diff-files))) + +(defun magit-stage-1 (arg &optional files) + (magit-wip-commit-before-change files " before stage") + (magit-run-git "add" arg (if files (cons "--" files) ".")) + (when magit-auto-revert-mode + (mapc #'magit-turn-on-auto-revert-mode-if-desired files)) + (magit-wip-commit-after-apply files " after stage")) + +(defun magit-stage-untracked (&optional intent) + (let* ((section (magit-current-section)) + (files (pcase (magit-diff-scope) + (`file (list (oref section value))) + (`files (magit-region-values nil t)) + (`list (magit-untracked-files)))) + plain repos) + (dolist (file files) + (if (and (not (file-symlink-p file)) + (magit-git-repo-p file t)) + (push file repos) + (push file plain))) + (magit-wip-commit-before-change files " before stage") + (when plain + (magit-run-git "add" (and intent "--intent-to-add") + "--" plain) + (when magit-auto-revert-mode + (mapc #'magit-turn-on-auto-revert-mode-if-desired plain))) + (dolist (repo repos) + (save-excursion + (goto-char (oref (magit-get-section + `((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))))) + (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 + +(defun magit-unstage () + "Remove the change at point from the staging area." + (interactive) + (--when-let (magit-apply--get-selection) + (pcase (list (magit-diff-type) + (magit-diff-scope) + (magit-apply--diff-ignores-whitespace-p)) + (`(untracked ,_ ,_) (user-error "Cannot unstage untracked changes")) + (`(unstaged file ,_) (magit-unstage-intent (list (oref it value)))) + (`(unstaged files ,_) (magit-unstage-intent (magit-region-values nil t))) + (`(unstaged ,_ ,_) (user-error "Already unstaged")) + (`(staged region ,_) (magit-apply-region it "--reverse" "--cached")) + (`(staged hunk ,_) (magit-apply-hunk it "--reverse" "--cached")) + (`(staged hunks ,_) (magit-apply-hunks it "--reverse" "--cached")) + (`(staged file t) (magit-apply-diff it "--reverse" "--cached")) + (`(staged files t) (magit-apply-diffs it "--reverse" "--cached")) + (`(staged list t) (magit-apply-diffs it "--reverse" "--cached")) + (`(staged file nil) (magit-unstage-1 (list (oref it value)))) + (`(staged files nil) (magit-unstage-1 (magit-region-values nil t))) + (`(staged list nil) (magit-unstage-all)) + (`(committed ,_ ,_) (if magit-unstage-committed + (magit-reverse-in-index) + (user-error "Cannot unstage committed changes"))) + (`(undefined ,_ ,_) (user-error "Cannot unstage this change"))))) + +;;;###autoload +(defun magit-unstage-file (file) + "Unstage all changes to FILE. +With a prefix argument or when there is no file at point ask for +the file to be unstaged. Otherwise unstage the file at point +without requiring confirmation." + (interactive + (let* ((atpoint (magit-section-value-if 'file)) + (current (magit-file-relative-name)) + (choices (magit-staged-files)) + (default (car (member (or atpoint current) choices)))) + (list (if (or current-prefix-arg (not default)) + (magit-completing-read "Unstage file" choices + nil t nil nil default) + default)))) + (magit-with-toplevel + (magit-unstage-1 (list file)))) + +(defun magit-unstage-1 (files) + (magit-wip-commit-before-change files " before unstage") + (if (magit-no-commit-p) + (magit-run-git "rm" "--cached" "--" files) + (magit-run-git "reset" "HEAD" "--" files)) + (magit-wip-commit-after-apply files " after unstage")) + +(defun magit-unstage-intent (files) + (if-let ((staged (magit-staged-files)) + (intent (--filter (member it staged) files))) + (magit-unstage-1 intent) + (user-error "Already unstaged"))) + +;;;###autoload +(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)) + (magit-wip-commit-before-change nil " before unstage") + (magit-run-git "reset" "HEAD" "--" magit-buffer-diff-files) + (magit-wip-commit-after-apply nil " after unstage")) + +;;;; Discard + +(defun magit-discard () + "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)) + (`(committed ,_) (user-error "Cannot discard committed changes")) + (`(undefined ,_) (user-error "Cannot discard this change")) + (`(,_ region) (magit-discard-region it)) + (`(,_ hunk) (magit-discard-hunk it)) + (`(,_ hunks) (magit-discard-hunks it)) + (`(,_ file) (magit-discard-file it)) + (`(,_ files) (magit-discard-files it)) + (`(,_ list) (magit-discard-files it))))) + +(defun magit-discard-region (section) + (magit-confirm 'discard "Discard region") + (magit-discard-apply section 'magit-apply-region)) + +(defun magit-discard-hunk (section) + (magit-confirm 'discard "Discard 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) + (funcall apply section "--reverse") + (if (magit-anything-unstaged-p + nil (if (magit-file-section-p section) + (oref section value) + (magit-section-parent-value section))) + (progn (let ((magit-inhibit-refresh t)) + (funcall apply section "--reverse" "--cached") + (funcall apply section "--reverse" "--reject")) + (magit-refresh)) + (funcall apply section "--reverse" "--index")))) + +(defun magit-discard-hunks (sections) + (magit-confirm 'discard (format "Discard %s hunks from %s" + (length sections) + (magit-section-parent-value (car sections)))) + (magit-discard-apply-n sections 'magit-apply-hunks)) + +(defun magit-discard-apply-n (sections apply) + (let ((section (car sections))) + (if (eq (magit-diff-type section) 'unstaged) + (funcall apply sections "--reverse") + (if (magit-anything-unstaged-p + nil (if (magit-file-section-p section) + (oref section value) + (magit-section-parent-value section))) + (progn (let ((magit-inhibit-refresh t)) + (funcall apply sections "--reverse" "--cached") + (funcall apply sections "--reverse" "--reject")) + (magit-refresh)) + (funcall apply sections "--reverse" "--index"))))) + +(defun magit-discard-file (section) + (magit-discard-files (list section))) + +(defun magit-discard-files (sections) + (let ((auto-revert-verbose nil) + (type (magit-diff-type (car sections))) + (status (magit-file-status)) + files delete resurrect rename discard discard-new resolve) + (dolist (section sections) + (let ((file (oref section value))) + (push file files) + (pcase (cons (pcase type + (`staged ?X) + (`unstaged ?Y) + (`untracked ?Z)) + (cddr (assoc file status))) + (`(?Z) (dolist (f (magit-untracked-files nil file)) + (push f delete))) + ((or `(?Z ?? ??) `(?Z ?! ?!)) (push file delete)) + ((or `(?Z ?D ? ) `(,_ ?D ?D)) (push file delete)) + ((or `(,_ ?U ,_) `(,_ ,_ ?U)) (push file resolve)) + (`(,_ ?A ?A) (push file resolve)) + (`(?X ?M ,(or ? ?M ?D)) (push section discard)) + (`(?Y ,_ ?M ) (push section discard)) + (`(?X ?A ?M ) (push file discard-new)) + (`(?X ?C ?M ) (push file discard-new)) + (`(?X ?A ,(or ? ?D)) (push file delete)) + (`(?X ?C ,(or ? ?D)) (push file delete)) + (`(?X ?D ,(or ? ?M )) (push file resurrect)) + (`(?Y ,_ ?D ) (push file resurrect)) + (`(?X ?R ,(or ? ?M ?D)) (push file rename))))) + (unwind-protect + (let ((magit-inhibit-refresh t)) + (magit-wip-commit-before-change files " before discard") + (when resolve + (magit-discard-files--resolve (nreverse resolve))) + (when resurrect + (magit-discard-files--resurrect (nreverse resurrect))) + (when delete + (magit-discard-files--delete (nreverse delete) status)) + (when rename + (magit-discard-files--rename (nreverse rename) status)) + (when (or discard discard-new) + (magit-discard-files--discard (nreverse discard) + (nreverse discard-new))) + (magit-wip-commit-after-apply files " after discard")) + (magit-refresh)))) + +(defun magit-discard-files--resolve (files) + (if-let ((arg (and (cdr files) + (magit-read-char-case + (format "For these %i files\n%s\ncheckout:\n" + (length files) + (mapconcat (lambda (file) + (concat " " file)) + files "\n")) + t + (?o "[o]ur stage" "--ours") + (?t "[t]heir stage" "--theirs") + (?c "[c]onflict" "--merge") + (?i "decide [i]ndividually" nil))))) + (dolist (file files) + (magit-checkout-stage file arg)) + (dolist (file files) + (magit-checkout-stage file (magit-checkout-read-stage file))))) + +(defun magit-discard-files--resurrect (files) + (magit-confirm-files 'resurrect files) + (if (eq (magit-diff-type) 'staged) + (magit-call-git "reset" "--" files) + (magit-call-git "checkout" "--" files))) + +(defun magit-discard-files--delete (files status) + (magit-confirm-files (if magit-delete-by-moving-to-trash 'trash 'delete) + files) + (let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash)) + (dolist (file files) + (when (string-match-p "\\`\\\\?~" file) + (error "Refusing to delete %S, too dangerous" file)) + (pcase (nth 3 (assoc file status)) + ((guard (memq (magit-diff-type) '(unstaged untracked))) + (dired-delete-file file dired-recursive-deletes + magit-delete-by-moving-to-trash) + (dired-clean-up-after-deletion file)) + (?\s (delete-file file t) + (magit-call-git "rm" "--cached" "--" file)) + (?M (let ((temp (magit-git-string "checkout-index" "--temp" file))) + (string-match + (format "\\(.+?\\)\t%s" (regexp-quote file)) temp) + (rename-file (match-string 1 temp) + (setq temp (concat file ".~{index}~"))) + (delete-file temp t)) + (magit-call-git "rm" "--cached" "--force" "--" file)) + (?D (magit-call-git "checkout" "--" file) + (delete-file file t) + (magit-call-git "rm" "--cached" "--force" "--" file)))))) + +(defun magit-discard-files--rename (files status) + (magit-confirm 'rename "Undo rename %s" "Undo %i renames" nil + (mapcar (lambda (file) + (setq file (assoc file status)) + (format "%s -> %s" (cadr file) (car file))) + files)) + (dolist (file files) + (let ((orig (cadr (assoc file status)))) + (if (file-exists-p file) + (progn + (--when-let (file-name-directory orig) + (make-directory it t)) + (magit-call-git "mv" file orig)) + (magit-call-git "rm" "--cached" "--" file) + (magit-call-git "reset" "--" orig))))) + +(defun magit-discard-files--discard (sections new-files) + (let ((files (--map (oref it value) sections))) + (magit-confirm-files 'discard (append files new-files) + (format "Discard %s changes in" (magit-diff-type))) + (if (eq (magit-diff-type (car sections)) 'unstaged) + (magit-call-git "checkout" "--" files) + (when new-files + (magit-call-git "add" "--" new-files) + (magit-call-git "reset" "--" new-files)) + (let ((binaries (magit-binary-files "--cached"))) + (when binaries + (setq sections + (--remove (member (oref it value) binaries) + sections))) + (cond ((= (length sections) 1) + (magit-discard-apply (car sections) 'magit-apply-diff)) + (sections + (magit-discard-apply-n sections 'magit-apply-diffs))) + (when binaries + (let ((modified (magit-unstaged-files t))) + (setq binaries (--separate (member it modified) binaries))) + (when (cadr binaries) + (magit-call-git "reset" "--" (cadr binaries))) + (when (car binaries) + (user-error + (concat + "Cannot discard staged changes to binary files, " + "which also have unstaged changes. Unstage instead.")))))))) + +;;;; Reverse + +(defun magit-reverse (&rest args) + "Reverse the change at point in the working tree. +With a prefix argument fallback to a 3-way merge. Doing +so causes the change to be applied to the index as well." + (interactive (and current-prefix-arg (list "--3way"))) + (--when-let (magit-apply--get-selection) + (pcase (list (magit-diff-type) (magit-diff-scope)) + (`(untracked ,_) (user-error "Cannot reverse untracked changes")) + (`(unstaged ,_) (user-error "Cannot reverse unstaged changes")) + (`(,_ region) (magit-reverse-region it args)) + (`(,_ hunk) (magit-reverse-hunk it args)) + (`(,_ hunks) (magit-reverse-hunks it args)) + (`(,_ file) (magit-reverse-file it args)) + (`(,_ files) (magit-reverse-files it args)) + (`(,_ list) (magit-reverse-files it args))))) + +(defun magit-reverse-region (section args) + (magit-confirm 'reverse "Reverse region") + (magit-reverse-apply section 'magit-apply-region args)) + +(defun magit-reverse-hunk (section args) + (magit-confirm 'reverse "Reverse hunk") + (magit-reverse-apply section 'magit-apply-hunk args)) + +(defun magit-reverse-hunks (sections args) + (magit-confirm 'reverse + (format "Reverse %s hunks from %s" + (length sections) + (magit-section-parent-value (car sections)))) + (magit-reverse-apply sections 'magit-apply-hunks args)) + +(defun magit-reverse-file (section args) + (magit-reverse-files (list section) args)) + +(defun magit-reverse-files (sections args) + (pcase-let ((`(,binaries ,sections) + (let ((bs (magit-binary-files + (cond ((derived-mode-p 'magit-revision-mode) + magit-buffer-range) + ((derived-mode-p 'magit-diff-mode) + magit-buffer-range) + (t + "--cached"))))) + (--separate (member (oref it value) bs) + sections)))) + (magit-confirm-files 'reverse (--map (oref it value) sections)) + (cond ((= (length sections) 1) + (magit-reverse-apply (car sections) 'magit-apply-diff args)) + (sections + (magit-reverse-apply sections 'magit-apply-diffs args))) + (when binaries + (user-error "Cannot reverse binary files")))) + +(defun magit-reverse-apply (section:s apply args) + (funcall apply section:s "--reverse" args + (and (not magit-reverse-atomically) + (not (member "--3way" args)) + "--reject"))) + +(defun magit-reverse-in-index (&rest args) + "Reverse the change at point in the index but not the working tree. + +Use this command to extract a change from `HEAD', while leaving +it in the working tree, so that it can later be committed using +a separate commit. A typical workflow would be: + +0. Optionally make sure that there are no uncommitted changes. +1. Visit the `HEAD' commit and navigate to the change that should + not have been included in that commit. +2. Type \"u\" (`magit-unstage') to reverse it in the index. + This assumes that `magit-unstage-committed-changes' is non-nil. +3. Type \"c e\" to extend `HEAD' with the staged changes, + including those that were already staged before. +4. Optionally stage the remaining changes using \"s\" or \"S\" + and then type \"c c\" to create a new commit." + (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 --git a/elpa/magit-20220116.1908/magit-autoloads.el b/elpa/magit-20220116.1908/magit-autoloads.el new file mode 100644 index 00000000..89dad858 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-autoloads.el @@ -0,0 +1,2591 @@ +;;; magit-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "git-rebase" "git-rebase.el" (0 0 0 0)) +;;; Generated autoloads from git-rebase.el + +(autoload 'git-rebase-current-line "git-rebase" "\ +Parse current line into a `git-rebase-action' instance. +If the current line isn't recognized as a rebase line, an +instance with all nil values is returned." nil nil) + +(autoload 'git-rebase-mode "git-rebase" "\ +Major mode for editing of a Git rebase file. + +Rebase files are generated when you run 'git rebase -i' or run +`magit-interactive-rebase'. They describe how Git should perform +the rebase. See the documentation for git-rebase (e.g., by +running 'man git-rebase' at the command line) for details. + +\(fn)" t nil) + +(defconst git-rebase-filename-regexp "/git-rebase-todo\\'") + +(add-to-list 'auto-mode-alist (cons git-rebase-filename-regexp 'git-rebase-mode)) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "git-rebase" '("git-rebase-"))) + +;;;*** + +;;;### (autoloads nil "magit" "magit.el" (0 0 0 0)) +;;; Generated autoloads from magit.el + +(define-obsolete-variable-alias 'global-magit-file-mode 'magit-define-global-key-bindings "Magit 3.0.0") + +(defvar 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'.") + +(custom-autoload 'magit-define-global-key-bindings "magit" t) + +(defun magit-maybe-define-global-key-bindings nil (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)) + (autoload 'magit-dispatch "magit" nil t) + (autoload 'magit-run "magit" nil t) + +(autoload 'magit-git-command "magit" "\ +Execute COMMAND asynchronously; display output. + +Interactively, prompt for COMMAND in the minibuffer. \"git \" is +used as initial input, but can be deleted to run another command. + +With a prefix argument COMMAND is run in the top-level directory +of the current working tree, otherwise in `default-directory'. + +\(fn COMMAND)" t nil) + +(autoload 'magit-git-command-topdir "magit" "\ +Execute COMMAND asynchronously; display output. + +Interactively, prompt for COMMAND in the minibuffer. \"git \" is +used as initial input, but can be deleted to run another command. + +COMMAND is run in the top-level directory of the current +working tree. + +\(fn COMMAND)" t nil) + +(autoload 'magit-shell-command "magit" "\ +Execute COMMAND asynchronously; display output. + +Interactively, prompt for COMMAND in the minibuffer. With a +prefix argument COMMAND is run in the top-level directory of +the current working tree, otherwise in `default-directory'. + +\(fn COMMAND)" t nil) + +(autoload 'magit-shell-command-topdir "magit" "\ +Execute COMMAND asynchronously; display output. + +Interactively, prompt for COMMAND in the minibuffer. COMMAND +is run in the top-level directory of the current working tree. + +\(fn COMMAND)" t nil) + +(autoload 'magit-version "magit" "\ +Return the version of Magit currently in use. +If optional argument PRINT-DEST is non-nil, output +stream (interactively, the echo area, or the current buffer with +a prefix argument), also print the used versions of Magit, Git, +and Emacs to it. + +\(fn &optional PRINT-DEST)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-apply" "magit-apply.el" (0 0 0 0)) +;;; Generated autoloads from magit-apply.el + +(autoload 'magit-stage-file "magit-apply" "\ +Stage all changes to FILE. +With a prefix argument or when there is no file at point ask for +the file to be staged. Otherwise stage the file at point without +requiring confirmation. + +\(fn FILE)" t nil) + +(autoload 'magit-stage-modified "magit-apply" "\ +Stage all changes to files modified in the worktree. +Stage all new content of tracked files and remove tracked files +that no longer exist in the working tree from the index also. +With a prefix argument also stage previously untracked (but not +ignored) files. + +\(fn &optional ALL)" t nil) + +(autoload 'magit-unstage-file "magit-apply" "\ +Unstage all changes to FILE. +With a prefix argument or when there is no file at point ask for +the file to be unstaged. Otherwise unstage the file at point +without requiring confirmation. + +\(fn FILE)" t nil) + +(autoload 'magit-unstage-all "magit-apply" "\ +Remove all changes from the staging area." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-apply" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-autorevert" "magit-autorevert.el" (0 +;;;;;; 0 0 0)) +;;; Generated autoloads from magit-autorevert.el + +(put 'magit-auto-revert-mode 'globalized-minor-mode t) + +(defvar magit-auto-revert-mode (not (or global-auto-revert-mode noninteractive)) "\ +Non-nil if Magit-Auto-Revert mode is enabled. +See the `magit-auto-revert-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `magit-auto-revert-mode'.") + +(custom-autoload 'magit-auto-revert-mode "magit-autorevert" nil) + +(autoload 'magit-auto-revert-mode "magit-autorevert" "\ +Toggle Auto-Revert mode in all buffers. +With prefix ARG, enable Magit-Auto-Revert mode if ARG is positive; +otherwise, disable it. If called from Lisp, enable the mode if +ARG is omitted or nil. + +Auto-Revert mode is enabled in all buffers where +`magit-turn-on-auto-revert-mode-if-desired' would do it. +See `auto-revert-mode' for more information on Auto-Revert mode. + +\(fn &optional ARG)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-autorevert" '("auto-revert-buffer" "magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-bisect" "magit-bisect.el" (0 0 0 0)) +;;; Generated autoloads from magit-bisect.el + (autoload 'magit-bisect "magit-bisect" nil t) + +(autoload 'magit-bisect-start "magit-bisect" "\ +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 known +good and a known bad commit. To move the session forward use the +other actions from the bisect transient command (\\\\[magit-bisect]). + +\(fn BAD GOOD ARGS)" t nil) + +(autoload 'magit-bisect-reset "magit-bisect" "\ +After bisecting, cleanup bisection state and return to original `HEAD'." t nil) + +(autoload 'magit-bisect-good "magit-bisect" "\ +While bisecting, mark the current commit as good. +Use this after you have asserted that the commit does not contain +the bug in question." t nil) + +(autoload 'magit-bisect-bad "magit-bisect" "\ +While bisecting, mark the current commit as bad. +Use this after you have asserted that the commit does contain the +bug in question." t nil) + +(autoload 'magit-bisect-mark "magit-bisect" "\ +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." t nil) + +(autoload 'magit-bisect-skip "magit-bisect" "\ +While bisecting, skip the current commit. +Use this if for some reason the current commit is not a good one +to test. This command lets Git choose a different one." t nil) + +(autoload 'magit-bisect-run "magit-bisect" "\ +Bisect automatically by running commands after each step. + +Unlike `git bisect run' this can be used before bisecting has +begun. In that case it behaves like `git bisect start; git +bisect run'. + +\(fn CMDLINE &optional BAD GOOD ARGS)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-bisect" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-blame" "magit-blame.el" (0 0 0 0)) +;;; Generated autoloads from magit-blame.el + (autoload 'magit-blame-echo "magit-blame" nil t) + (autoload 'magit-blame-addition "magit-blame" nil t) + (autoload 'magit-blame-removal "magit-blame" nil t) + (autoload 'magit-blame-reverse "magit-blame" nil t) + (autoload 'magit-blame "magit-blame" nil t) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-blame" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-bookmark" "magit-bookmark.el" (0 0 0 +;;;;;; 0)) +;;; Generated autoloads from magit-bookmark.el + +(autoload 'magit--handle-bookmark "magit-bookmark" "\ +Open a bookmark created by `magit--make-bookmark'. +Call the `magit-*-setup-buffer' function of the the major-mode +with the variables' values as arguments, which were recorded by +`magit--make-bookmark'. Ignore `magit-display-buffer-function'. + +\(fn BOOKMARK)" nil nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-bookmark" '("magit--make-bookmark"))) + +;;;*** + +;;;### (autoloads nil "magit-branch" "magit-branch.el" (0 0 0 0)) +;;; Generated autoloads from magit-branch.el + (autoload 'magit-branch "magit" nil t) + +(autoload 'magit-checkout "magit-branch" "\ +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. + +\(git checkout REVISION). + +\(fn REVISION &optional ARGS)" t nil) + +(autoload 'magit-branch-create "magit-branch" "\ +Create BRANCH at branch or revision START-POINT. + +\(fn BRANCH START-POINT)" t nil) + +(autoload 'magit-branch-and-checkout "magit-branch" "\ +Create and checkout BRANCH at branch or revision START-POINT. + +\(fn BRANCH START-POINT &optional ARGS)" t nil) + +(autoload 'magit-branch-or-checkout "magit-branch" "\ +Hybrid between `magit-checkout' and `magit-branch-and-checkout'. + +Ask the user for an existing branch or revision. If the user +input actually can be resolved as a branch or revision, then +check that out, just like `magit-checkout' would. + +Otherwise create and checkout a new branch using the input as +its name. Before doing so read the starting-point for the new +branch. This is similar to what `magit-branch-and-checkout' +does. + +\(fn ARG &optional START-POINT)" t nil) + +(autoload 'magit-branch-checkout "magit-branch" "\ +Checkout an existing or new local branch. + +Read a branch name from the user offering all local branches and +a subset of remote branches as candidates. Omit remote branches +for which a local branch by the same name exists from the list +of candidates. The user can also enter a completely new branch +name. + +- If the user selects an existing local branch, then check that + out. + +- If the user selects a remote branch, then create and checkout + a new local branch with the same name. Configure the selected + remote branch as push target. + +- If the user enters a new branch name, then create and check + that out, after also reading the starting-point from the user. + +In the latter two cases the upstream is also set. Whether it is +set to the chosen START-POINT or something else depends on the +value of `magit-branch-adjust-remote-upstream-alist', just like +when using `magit-branch-and-checkout'. + +\(fn BRANCH &optional START-POINT)" t nil) + +(autoload 'magit-branch-orphan "magit-branch" "\ +Create and checkout an orphan BRANCH with contents from revision START-POINT. + +\(fn BRANCH START-POINT)" t nil) + +(autoload 'magit-branch-spinout "magit-branch" "\ +Create new branch from the unpushed commits. +Like `magit-branch-spinoff' but remain on the current branch. +If there are any uncommitted changes, then behave exactly like +`magit-branch-spinoff'. + +\(fn BRANCH &optional FROM)" t nil) + +(autoload 'magit-branch-spinoff "magit-branch" "\ +Create new branch from the unpushed commits. + +Create and checkout a new branch starting at and tracking the +current branch. That branch in turn is reset to the last commit +it shares with its upstream. If the current branch has no +upstream or no unpushed commits, then the new branch is created +anyway and the previously current branch is not touched. + +This is useful to create a feature branch after work has already +began on the old branch (likely but not necessarily \"master\"). + +If the current branch is a member of the value of option +`magit-branch-prefer-remote-upstream' (which see), then the +current branch will be used as the starting point as usual, but +the upstream of the starting-point may be used as the upstream +of the new branch, instead of the starting-point itself. + +If optional FROM is non-nil, then the source branch is reset +to `FROM~', instead of to the last commit it shares with its +upstream. Interactively, FROM is only ever non-nil, if the +region selects some commits, and among those commits, FROM is +the commit that is the fewest commits ahead of the source +branch. + +The commit at the other end of the selection actually does not +matter, all commits between FROM and `HEAD' are moved to the new +branch. If FROM is not reachable from `HEAD' or is reachable +from the source branch's upstream, then an error is raised. + +\(fn BRANCH &optional FROM)" t nil) + +(autoload 'magit-branch-reset "magit-branch" "\ +Reset a branch to the tip of another branch or any other commit. + +When the branch being reset is the current branch, then do a +hard reset. If there are any uncommitted changes, then the user +has to confirm the reset because those changes would be lost. + +This is useful when you have started work on a feature branch but +realize it's all crap and want to start over. + +When resetting to another branch and a prefix argument is used, +then also set the target branch as the upstream of the branch +that is being reset. + +\(fn BRANCH TO &optional SET-UPSTREAM)" t nil) + +(autoload 'magit-branch-delete "magit-branch" "\ +Delete one or multiple branches. +If the region marks multiple branches, then offer to delete +those, otherwise prompt for a single branch to be deleted, +defaulting to the branch at point. + +\(fn BRANCHES &optional FORCE)" t nil) + +(autoload 'magit-branch-rename "magit-branch" "\ +Rename the branch named OLD to NEW. + +With a prefix argument FORCE, rename even if a branch named NEW +already exists. + +If `branch.OLD.pushRemote' is set, then unset it. Depending on +the value of `magit-branch-rename-push-target' (which see) maybe +set `branch.NEW.pushRemote' and maybe rename the push-target on +the remote. + +\(fn OLD NEW &optional FORCE)" t nil) + +(autoload 'magit-branch-shelve "magit-branch" "\ +Shelve a BRANCH. +Rename \"refs/heads/BRANCH\" to \"refs/shelved/BRANCH\", +and also rename the respective reflog file. + +\(fn BRANCH)" t nil) + +(autoload 'magit-branch-unshelve "magit-branch" "\ +Unshelve a BRANCH +Rename \"refs/shelved/BRANCH\" to \"refs/heads/BRANCH\", +and also rename the respective reflog file. + +\(fn BRANCH)" t nil) + (autoload 'magit-branch-configure "magit-branch" nil t) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-branch" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-bundle" "magit-bundle.el" (0 0 0 0)) +;;; Generated autoloads from magit-bundle.el + (autoload 'magit-bundle "magit-bundle" nil t) + (autoload 'magit-bundle-import "magit-bundle" nil t) + +(autoload 'magit-bundle-create-tracked "magit-bundle" "\ +Create and track a new bundle. + +\(fn FILE TAG BRANCH REFS ARGS)" t nil) + +(autoload 'magit-bundle-update-tracked "magit-bundle" "\ +Update a bundle that is being tracked using TAG. + +\(fn TAG)" t nil) + +(autoload 'magit-bundle-verify "magit-bundle" "\ +Check whether FILE is valid and applies to the current repository. + +\(fn FILE)" t nil) + +(autoload 'magit-bundle-list-heads "magit-bundle" "\ +List the refs in FILE. + +\(fn FILE)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-bundle" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-clone" "magit-clone.el" (0 0 0 0)) +;;; Generated autoloads from magit-clone.el + (autoload 'magit-clone "magit-clone" nil t) + +(autoload 'magit-clone-regular "magit-clone" "\ +Create a clone of REPOSITORY in DIRECTORY. +Then show the status buffer for the new repository. + +\(fn REPOSITORY DIRECTORY ARGS)" t nil) + +(autoload 'magit-clone-shallow "magit-clone" "\ +Create a shallow clone of REPOSITORY in DIRECTORY. +Then show the status buffer for the new repository. +With a prefix argument read the DEPTH of the clone; +otherwise use 1. + +\(fn REPOSITORY DIRECTORY ARGS DEPTH)" t nil) + +(autoload 'magit-clone-shallow-since "magit-clone" "\ +Create a shallow clone of REPOSITORY in DIRECTORY. +Then show the status buffer for the new repository. +Exclude commits before DATE, which is read from the +user. + +\(fn REPOSITORY DIRECTORY ARGS DATE)" t nil) + +(autoload 'magit-clone-shallow-exclude "magit-clone" "\ +Create a shallow clone of REPOSITORY in DIRECTORY. +Then show the status buffer for the new repository. +Exclude commits reachable from EXCLUDE, which is a +branch or tag read from the user. + +\(fn REPOSITORY DIRECTORY ARGS EXCLUDE)" t nil) + +(autoload 'magit-clone-bare "magit-clone" "\ +Create a bare clone of REPOSITORY in DIRECTORY. +Then show the status buffer for the new repository. + +\(fn REPOSITORY DIRECTORY ARGS)" t nil) + +(autoload 'magit-clone-mirror "magit-clone" "\ +Create a mirror of REPOSITORY in DIRECTORY. +Then show the status buffer for the new repository. + +\(fn REPOSITORY DIRECTORY ARGS)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-clone" '("magit-clone-"))) + +;;;*** + +;;;### (autoloads nil "magit-commit" "magit-commit.el" (0 0 0 0)) +;;; Generated autoloads from magit-commit.el + (autoload 'magit-commit "magit-commit" nil t) + +(autoload 'magit-commit-create "magit-commit" "\ +Create a new commit on `HEAD'. +With a prefix argument, amend to the commit at `HEAD' instead. + +\(git commit [--amend] ARGS) + +\(fn &optional ARGS)" t nil) + +(autoload 'magit-commit-amend "magit-commit" "\ +Amend the last commit. + +\(git commit --amend ARGS) + +\(fn &optional ARGS)" t nil) + +(autoload 'magit-commit-extend "magit-commit" "\ +Amend the last commit, without editing the message. + +With a prefix argument keep the committer date, otherwise change +it. The option `magit-commit-extend-override-date' can be used +to inverse the meaning of the prefix argument. +\(git commit +--amend --no-edit) + +\(fn &optional ARGS OVERRIDE-DATE)" t nil) + +(autoload 'magit-commit-reword "magit-commit" "\ +Reword the last commit, ignoring staged changes. + +With a prefix argument keep the committer date, otherwise change +it. The option `magit-commit-reword-override-date' can be used +to inverse the meaning of the prefix argument. + +Non-interactively respect the optional OVERRIDE-DATE argument +and ignore the option. + +\(git commit --amend --only) + +\(fn &optional ARGS OVERRIDE-DATE)" t nil) + +(autoload 'magit-commit-fixup "magit-commit" "\ +Create a fixup commit. + +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'. + +\(fn &optional COMMIT ARGS)" t nil) + +(autoload 'magit-commit-squash "magit-commit" "\ +Create a squash commit, without editing the squash message. + +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'. + +If you want to immediately add a message to the squash commit, +then use `magit-commit-augment' instead of this command. + +\(fn &optional COMMIT ARGS)" t nil) + +(autoload 'magit-commit-augment "magit-commit" "\ +Create a squash commit, editing the squash message. + +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'. + +\(fn &optional COMMIT ARGS)" t nil) + +(autoload 'magit-commit-instant-fixup "magit-commit" "\ +Create a fixup commit targeting COMMIT and instantly rebase. + +\(fn &optional COMMIT ARGS)" t nil) + +(autoload 'magit-commit-instant-squash "magit-commit" "\ +Create a squash commit targeting COMMIT and instantly rebase. + +\(fn &optional COMMIT ARGS)" t nil) + +(autoload 'magit-commit-reshelve "magit-commit" "\ +Change the committer date and possibly the author date of `HEAD'. + +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. + +\(fn DATE UPDATE-AUTHOR &optional ARGS)" t nil) + +(autoload 'magit-commit-absorb-modules "magit-commit" "\ +Spread modified modules across recent commits. + +\(fn PHASE COMMIT)" t nil) + (autoload 'magit-commit-absorb "magit-commit" nil t) + (autoload 'magit-commit-autofixup "magit-commit" nil t) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-commit" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-diff" "magit-diff.el" (0 0 0 0)) +;;; Generated autoloads from magit-diff.el + (autoload 'magit-diff "magit-diff" nil t) + (autoload 'magit-diff-refresh "magit-diff" nil t) + +(autoload 'magit-diff-dwim "magit-diff" "\ +Show changes for the thing at point. + +\(fn &optional ARGS FILES)" t nil) + +(autoload 'magit-diff-range "magit-diff" "\ +Show differences between two commits. + +REV-OR-RANGE should be a range or a single revision. If it is a +revision, then show changes in the working tree relative to that +revision. If it is a range, but one side is omitted, then show +changes relative to `HEAD'. + +If the region is active, use the revisions on the first and last +line of the region as the two sides of the range. With a prefix +argument, instead of diffing the revisions, choose a revision to +view changes along, starting at the common ancestor of both +revisions (i.e., use a \"...\" range). + +\(fn REV-OR-RANGE &optional ARGS FILES)" t nil) + +(autoload 'magit-diff-working-tree "magit-diff" "\ +Show changes between the current working tree and the `HEAD' commit. +With a prefix argument show changes between the working tree and +a commit read from the minibuffer. + +\(fn &optional REV ARGS FILES)" t nil) + +(autoload 'magit-diff-staged "magit-diff" "\ +Show changes between the index and the `HEAD' commit. +With a prefix argument show changes between the index and +a commit read from the minibuffer. + +\(fn &optional REV ARGS FILES)" t nil) + +(autoload 'magit-diff-unstaged "magit-diff" "\ +Show changes between the working tree and the index. + +\(fn &optional ARGS FILES)" t nil) + +(autoload 'magit-diff-unmerged "magit-diff" "\ +Show changes that are being merged. + +\(fn &optional ARGS FILES)" t nil) + +(autoload 'magit-diff-while-committing "magit-diff" "\ +While committing, show the changes that are about to be committed. +While amending, invoking the command again toggles between +showing just the new changes or all the changes that will +be committed. + +\(fn &optional ARGS)" t nil) + +(autoload 'magit-diff-buffer-file "magit-diff" "\ +Show diff for the blob or file visited in the current buffer. + +When the buffer visits a blob, then show the respective commit. +When the buffer visits a file, then show the differenced between +`HEAD' and the working tree. In both cases limit the diff to +the file or blob." t nil) + +(autoload 'magit-diff-paths "magit-diff" "\ +Show changes between any two files on disk. + +\(fn A B)" t nil) + +(autoload 'magit-show-commit "magit-diff" "\ +Visit the revision at point in another buffer. +If there is no revision at point or with a prefix argument prompt +for a revision. + +\(fn REV &optional ARGS FILES MODULE)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-diff" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-ediff" "magit-ediff.el" (0 0 0 0)) +;;; Generated autoloads from magit-ediff.el + (autoload 'magit-ediff "magit-ediff" nil) + +(autoload 'magit-ediff-resolve "magit-ediff" "\ +Resolve outstanding conflicts in FILE using Ediff. +FILE has to be relative to the top directory of the repository. + +In the rare event that you want to manually resolve all +conflicts, including those already resolved by Git, use +`ediff-merge-revisions-with-ancestor'. + +\(fn FILE)" t nil) + +(autoload 'magit-ediff-stage "magit-ediff" "\ +Stage and unstage changes to FILE using Ediff. +FILE has to be relative to the top directory of the repository. + +\(fn FILE)" t nil) + +(autoload 'magit-ediff-compare "magit-ediff" "\ +Compare REVA:FILEA with REVB:FILEB using Ediff. + +FILEA and FILEB have to be relative to the top directory of the +repository. If REVA or REVB is nil, then this stands for the +working tree state. + +If the region is active, use the revisions on the first and last +line of the region. With a prefix argument, instead of diffing +the revisions, choose a revision to view changes along, starting +at the common ancestor of both revisions (i.e., use a \"...\" +range). + +\(fn REVA REVB FILEA FILEB)" t nil) + +(autoload 'magit-ediff-dwim "magit-ediff" "\ +Compare, stage, or resolve using Ediff. +This command tries to guess what file, and what commit or range +the user wants to compare, stage, or resolve using Ediff. It +might only be able to guess either the file, or range or commit, +in which case the user is asked about the other. It might not +always guess right, in which case the appropriate `magit-ediff-*' +command has to be used explicitly. If it cannot read the user's +mind at all, then it asks the user for a command to run." t nil) + +(autoload 'magit-ediff-show-staged "magit-ediff" "\ +Show staged changes using Ediff. + +This only allows looking at the changes; to stage, unstage, +and discard changes using Ediff, use `magit-ediff-stage'. + +FILE must be relative to the top directory of the repository. + +\(fn FILE)" t nil) + +(autoload 'magit-ediff-show-unstaged "magit-ediff" "\ +Show unstaged changes using Ediff. + +This only allows looking at the changes; to stage, unstage, +and discard changes using Ediff, use `magit-ediff-stage'. + +FILE must be relative to the top directory of the repository. + +\(fn FILE)" t nil) + +(autoload 'magit-ediff-show-working-tree "magit-ediff" "\ +Show changes between `HEAD' and working tree using Ediff. +FILE must be relative to the top directory of the repository. + +\(fn FILE)" t nil) + +(autoload 'magit-ediff-show-commit "magit-ediff" "\ +Show changes introduced by COMMIT using Ediff. + +\(fn COMMIT)" t nil) + +(autoload 'magit-ediff-show-stash "magit-ediff" "\ +Show changes introduced by STASH using Ediff. +`magit-ediff-show-stash-with-index' controls whether a +three-buffer Ediff is used in order to distinguish changes in the +stash that were staged. + +\(fn STASH)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-ediff" '("magit-ediff-"))) + +;;;*** + +;;;### (autoloads nil "magit-extras" "magit-extras.el" (0 0 0 0)) +;;; Generated autoloads from magit-extras.el + +(autoload 'magit-run-git-gui "magit-extras" "\ +Run `git gui' for the current git repository." t nil) + +(autoload 'magit-run-git-gui-blame "magit-extras" "\ +Run `git gui blame' on the given FILENAME and COMMIT. +Interactively run it for the current file and the `HEAD', with a +prefix or when the current file cannot be determined let the user +choose. When the current buffer is visiting FILENAME instruct +blame to center around the line point is on. + +\(fn COMMIT FILENAME &optional LINENUM)" t nil) + +(autoload 'magit-run-gitk "magit-extras" "\ +Run `gitk' in the current repository." t nil) + +(autoload 'magit-run-gitk-branches "magit-extras" "\ +Run `gitk --branches' in the current repository." t nil) + +(autoload 'magit-run-gitk-all "magit-extras" "\ +Run `gitk --all' in the current repository." t nil) + +(autoload 'ido-enter-magit-status "magit-extras" "\ +Drop into `magit-status' from file switching. + +This command does not work in Emacs 26.1. +See https://github.com/magit/magit/issues/3634 +and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31707. + +To make this command available use something like: + + (add-hook \\='ido-setup-hook + (lambda () + (define-key ido-completion-map + (kbd \"C-x g\") \\='ido-enter-magit-status))) + +Starting with Emacs 25.1 the Ido keymaps are defined just once +instead of every time Ido is invoked, so now you can modify it +like pretty much every other keymap: + + (define-key ido-common-completion-map + (kbd \"C-x g\") \\='ido-enter-magit-status)" t nil) + +(autoload 'magit-project-status "magit-extras" "\ +Run `magit-status' in the current project's root." t nil) + +(autoload 'magit-dired-jump "magit-extras" "\ +Visit file at point using Dired. +With a prefix argument, visit in another window. If there +is no file at point, then instead visit `default-directory'. + +\(fn &optional OTHER-WINDOW)" t nil) + +(autoload 'magit-dired-log "magit-extras" "\ +Show log for all marked files, or the current file. + +\(fn &optional FOLLOW)" t nil) + +(autoload 'magit-dired-am-apply-patches "magit-extras" "\ +In Dired, apply the marked (or next ARG) files as patches. +If inside a repository, then apply in that. Otherwise prompt +for a repository. + +\(fn REPO &optional ARG)" t nil) + +(autoload 'magit-do-async-shell-command "magit-extras" "\ +Open FILE with `dired-do-async-shell-command'. +Interactively, open the file at point. + +\(fn FILE)" t nil) + +(autoload 'magit-previous-line "magit-extras" "\ +Like `previous-line' but with Magit-specific shift-selection. + +Magit's selection mechanism is based on the region but selects an +area that is larger than the region. This causes `previous-line' +when invoked while holding the shift key to move up one line and +thereby select two lines. When invoked inside a hunk body this +command does not move point on the first invocation and thereby +it only selects a single line. Which inconsistency you prefer +is a matter of preference. + +\(fn &optional ARG TRY-VSCROLL)" t nil) + +(function-put 'magit-previous-line 'interactive-only '"use `forward-line' with negative argument instead.") + +(autoload 'magit-next-line "magit-extras" "\ +Like `next-line' but with Magit-specific shift-selection. + +Magit's selection mechanism is based on the region but selects +an area that is larger than the region. This causes `next-line' +when invoked while holding the shift key to move down one line +and thereby select two lines. When invoked inside a hunk body +this command does not move point on the first invocation and +thereby it only selects a single line. Which inconsistency you +prefer is a matter of preference. + +\(fn &optional ARG TRY-VSCROLL)" t nil) + +(function-put 'magit-next-line 'interactive-only 'forward-line) + +(autoload 'magit-clean "magit-extras" "\ +Remove untracked files from the working tree. +With a prefix argument also remove ignored files, +with two prefix arguments remove ignored files only. + +\(git clean -f -d [-x|-X]) + +\(fn &optional ARG)" t nil) + +(autoload 'magit-generate-changelog "magit-extras" "\ +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. + +\(fn &optional AMENDING)" t nil) + +(autoload 'magit-add-change-log-entry "magit-extras" "\ +Find change log file and add date entry and item for current change. +This differs from `add-change-log-entry' (which see) in that +it acts on the current hunk in a Magit buffer instead of on +a position in a file-visiting buffer. + +\(fn &optional WHOAMI FILE-NAME OTHER-WINDOW)" t nil) + +(autoload 'magit-add-change-log-entry-other-window "magit-extras" "\ +Find change log file in other window and add entry and item. +This differs from `add-change-log-entry-other-window' (which see) +in that it acts on the current hunk in a Magit buffer instead of +on a position in a file-visiting buffer. + +\(fn &optional WHOAMI FILE-NAME)" t nil) + +(autoload 'magit-edit-line-commit "magit-extras" "\ +Edit the commit that added the current line. + +With a prefix argument edit the commit that removes the line, +if any. The commit is determined using `git blame' and made +editable using `git rebase --interactive' if it is reachable +from `HEAD', or by checking out the commit (or a branch that +points at it) otherwise. + +\(fn &optional TYPE)" t nil) + +(autoload 'magit-diff-edit-hunk-commit "magit-extras" "\ +From a hunk, edit the respective commit and visit the file. + +First visit the file being modified by the hunk at the correct +location using `magit-diff-visit-file'. This actually visits a +blob. When point is on a diff header, not within an individual +hunk, then this visits the blob the first hunk is about. + +Then invoke `magit-edit-line-commit', which uses an interactive +rebase to make the commit editable, or if that is not possible +because the commit is not reachable from `HEAD' by checking out +that commit directly. This also causes the actual worktree file +to be visited. + +Neither the blob nor the file buffer are killed when finishing +the rebase. If that is undesirable, then it might be better to +use `magit-rebase-edit-command' instead of this command. + +\(fn FILE)" t nil) + +(autoload 'magit-reshelve-since "magit-extras" "\ +Change the author and committer dates of the commits since REV. + +Ask the user for the first reachable commit whose dates should +be changed. Then read the new date for that commit. The initial +minibuffer input and the previous history element offer good +values. The next commit will be created one minute later and so +on. + +This command is only intended for interactive use and should only +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'. + +\(fn REV KEYID)" t nil) + +(autoload 'magit-pop-revision-stack "magit-extras" "\ +Insert a representation of a revision into the current buffer. + +Pop a revision from the `magit-revision-stack' and insert it into +the current buffer according to `magit-pop-revision-stack-format'. +Revisions can be put on the stack using `magit-copy-section-value' +and `magit-copy-buffer-revision'. + +If the stack is empty or with a prefix argument, instead read a +revision in the minibuffer. By using the minibuffer history this +allows selecting an item which was popped earlier or to insert an +arbitrary reference or revision without first pushing it onto the +stack. + +When reading the revision from the minibuffer, then it might not +be possible to guess the correct repository. When this command +is called inside a repository (e.g. while composing a commit +message), then that repository is used. Otherwise (e.g. while +composing an email) then the repository recorded for the top +element of the stack is used (even though we insert another +revision). If not called inside a repository and with an empty +stack, or with two prefix arguments, then read the repository in +the minibuffer too. + +\(fn REV TOPLEVEL)" t nil) + +(autoload 'magit-copy-section-value "magit-extras" "\ +Save the value of the current section for later use. + +Save the section value to the `kill-ring', and, provided that +the current section is a commit, branch, or tag section, push +the (referenced) revision to the `magit-revision-stack' for use +with `magit-pop-revision-stack'. + +When `magit-copy-revision-abbreviated' is non-nil, save the +abbreviated revision to the `kill-ring' and the +`magit-revision-stack'. + +When the current section is a branch or a tag, and a prefix +argument is used, then save the revision at its tip to the +`kill-ring' instead of the reference name. + +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, then strip the diff marker column and keep only either +the added or removed lines, depending on the sign of the prefix +argument. + +\(fn ARG)" t nil) + +(autoload 'magit-copy-buffer-revision "magit-extras" "\ +Save the revision of the current buffer for later use. + +Save the revision shown in the current buffer to the `kill-ring' +and push it to the `magit-revision-stack'. + +This command is mainly intended for use in `magit-revision-mode' +buffers, the only buffers where it is always unambiguous exactly +which revision should be saved. + +Most other Magit buffers usually show more than one revision, in +some way or another, so this command has to select one of them, +and that choice might not always be the one you think would have +been the best pick. + +In such buffers it is often more useful to save the value of +the current section instead, using `magit-copy-section-value'. + +When the region is active, then save that to the `kill-ring', +like `kill-ring-save' would, instead of behaving as described +above. + +When `magit-copy-revision-abbreviated' is non-nil, save the +abbreviated revision to the `kill-ring' and the +`magit-revision-stack'." t nil) + +(autoload 'magit-display-repository-buffer "magit-extras" "\ +Display a Magit buffer belonging to the current Git repository. +The buffer is displayed using `magit-display-buffer', which see. + +\(fn BUFFER)" t nil) + +(autoload 'magit-switch-to-repository-buffer "magit-extras" "\ +Switch to a Magit buffer belonging to the current Git repository. + +\(fn BUFFER)" t nil) + +(autoload 'magit-switch-to-repository-buffer-other-window "magit-extras" "\ +Switch to a Magit buffer belonging to the current Git repository. + +\(fn BUFFER)" t nil) + +(autoload 'magit-switch-to-repository-buffer-other-frame "magit-extras" "\ +Switch to a Magit buffer belonging to the current Git repository. + +\(fn BUFFER)" t nil) + +(autoload 'magit-abort-dwim "magit-extras" "\ +Abort current operation. +Depending on the context, this will abort a merge, a rebase, a +patch application, a cherry-pick, a revert, or a bisect." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-extras" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-fetch" "magit-fetch.el" (0 0 0 0)) +;;; Generated autoloads from magit-fetch.el + (autoload 'magit-fetch "magit-fetch" nil t) + (autoload 'magit-fetch-from-pushremote "magit-fetch" nil t) + (autoload 'magit-fetch-from-upstream "magit-fetch" nil t) + +(autoload 'magit-fetch-other "magit-fetch" "\ +Fetch from another repository. + +\(fn REMOTE ARGS)" t nil) + +(autoload 'magit-fetch-branch "magit-fetch" "\ +Fetch a BRANCH from a REMOTE. + +\(fn REMOTE BRANCH ARGS)" t nil) + +(autoload 'magit-fetch-refspec "magit-fetch" "\ +Fetch a REFSPEC from a REMOTE. + +\(fn REMOTE REFSPEC ARGS)" t nil) + +(autoload 'magit-fetch-all "magit-fetch" "\ +Fetch from all remotes. + +\(fn ARGS)" t nil) + +(autoload 'magit-fetch-all-prune "magit-fetch" "\ +Fetch from all remotes, and prune. +Prune remote tracking branches for branches that have been +removed on the respective remote." t nil) + +(autoload 'magit-fetch-all-no-prune "magit-fetch" "\ +Fetch from all remotes." t nil) + (autoload 'magit-fetch-modules "magit-fetch" nil t) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-fetch" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-files" "magit-files.el" (0 0 0 0)) +;;; Generated autoloads from magit-files.el + +(autoload 'magit-find-file "magit-files" "\ +View FILE from REV. +Switch to a buffer visiting blob REV:FILE, creating one if none +already exists. If prior to calling this command the current +buffer and/or cursor position is about the same file, then go +to the line and column corresponding to that location. + +\(fn REV FILE)" t nil) + +(autoload 'magit-find-file-other-window "magit-files" "\ +View FILE from REV, in another window. +Switch to a buffer visiting blob REV:FILE, creating one if none +already exists. If prior to calling this command the current +buffer and/or cursor position is about the same file, then go to +the line and column corresponding to that location. + +\(fn REV FILE)" t nil) + +(autoload 'magit-find-file-other-frame "magit-files" "\ +View FILE from REV, in another frame. +Switch to a buffer visiting blob REV:FILE, creating one if none +already exists. If prior to calling this command the current +buffer and/or cursor position is about the same file, then go to +the line and column corresponding to that location. + +\(fn REV FILE)" t nil) + (autoload 'magit-file-dispatch "magit" nil t) + +(autoload 'magit-blob-visit-file "magit-files" "\ +View the file from the worktree corresponding to the current blob. +When visiting a blob or the version from the index, then go to +the same location in the respective file in the working tree." t nil) + +(autoload 'magit-file-checkout "magit-files" "\ +Checkout FILE from REV. + +\(fn REV FILE)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-files" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-git" "magit-git.el" (0 0 0 0)) +;;; Generated autoloads from magit-git.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-git" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-gitignore" "magit-gitignore.el" (0 0 +;;;;;; 0 0)) +;;; Generated autoloads from magit-gitignore.el + (autoload 'magit-gitignore "magit-gitignore" nil t) + +(autoload 'magit-gitignore-in-topdir "magit-gitignore" "\ +Add the Git ignore RULE to the top-level \".gitignore\" file. +Since this file is tracked, it is shared with other clones of the +repository. Also stage the file. + +\(fn RULE)" t nil) + +(autoload 'magit-gitignore-in-subdir "magit-gitignore" "\ +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. + +\(fn RULE DIRECTORY)" t nil) + +(autoload 'magit-gitignore-in-gitdir "magit-gitignore" "\ +Add the Git ignore RULE to \"$GIT_DIR/info/exclude\". +Rules in that file only affects this clone of the repository. + +\(fn RULE)" t nil) + +(autoload 'magit-gitignore-on-system "magit-gitignore" "\ +Add the Git ignore RULE to the file specified by `core.excludesFile'. +Rules that are defined in that file affect all local repositories. + +\(fn RULE)" t nil) + +(autoload 'magit-skip-worktree "magit-gitignore" "\ +Call \"git update-index --skip-worktree -- FILE\". + +\(fn FILE)" t nil) + +(autoload 'magit-no-skip-worktree "magit-gitignore" "\ +Call \"git update-index --no-skip-worktree -- FILE\". + +\(fn FILE)" t nil) + +(autoload 'magit-assume-unchanged "magit-gitignore" "\ +Call \"git update-index --assume-unchanged -- FILE\". + +\(fn FILE)" t nil) + +(autoload 'magit-no-assume-unchanged "magit-gitignore" "\ +Call \"git update-index --no-assume-unchanged -- FILE\". + +\(fn FILE)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-gitignore" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-imenu" "magit-imenu.el" (0 0 0 0)) +;;; Generated autoloads from magit-imenu.el + +(autoload 'magit-imenu--log-prev-index-position-function "magit-imenu" "\ +Move point to previous line in current buffer. +This function is used as a value for +`imenu-prev-index-position-function'." nil nil) + +(autoload 'magit-imenu--log-extract-index-name-function "magit-imenu" "\ +Return imenu name for line at point. +This function is used as a value for +`imenu-extract-index-name-function'. Point should be at the +beginning of the line." nil nil) + +(autoload 'magit-imenu--diff-prev-index-position-function "magit-imenu" "\ +Move point to previous file line in current buffer. +This function is used as a value for +`imenu-prev-index-position-function'." nil nil) + +(autoload 'magit-imenu--diff-extract-index-name-function "magit-imenu" "\ +Return imenu name for line at point. +This function is used as a value for +`imenu-extract-index-name-function'. Point should be at the +beginning of the line." nil nil) + +(autoload 'magit-imenu--status-create-index-function "magit-imenu" "\ +Return an alist of all imenu entries in current buffer. +This function is used as a value for +`imenu-create-index-function'." nil nil) + +(autoload 'magit-imenu--refs-create-index-function "magit-imenu" "\ +Return an alist of all imenu entries in current buffer. +This function is used as a value for +`imenu-create-index-function'." nil nil) + +(autoload 'magit-imenu--cherry-create-index-function "magit-imenu" "\ +Return an alist of all imenu entries in current buffer. +This function is used as a value for +`imenu-create-index-function'." nil nil) + +(autoload 'magit-imenu--submodule-prev-index-position-function "magit-imenu" "\ +Move point to previous line in magit-submodule-list buffer. +This function is used as a value for +`imenu-prev-index-position-function'." nil nil) + +(autoload 'magit-imenu--submodule-extract-index-name-function "magit-imenu" "\ +Return imenu name for line at point. +This function is used as a value for +`imenu-extract-index-name-function'. Point should be at the +beginning of the line." nil nil) + +(autoload 'magit-imenu--repolist-prev-index-position-function "magit-imenu" "\ +Move point to previous line in magit-repolist buffer. +This function is used as a value for +`imenu-prev-index-position-function'." nil nil) + +(autoload 'magit-imenu--repolist-extract-index-name-function "magit-imenu" "\ +Return imenu name for line at point. +This function is used as a value for +`imenu-extract-index-name-function'. Point should be at the +beginning of the line." nil nil) + +(autoload 'magit-imenu--process-prev-index-position-function "magit-imenu" "\ +Move point to previous process in magit-process buffer. +This function is used as a value for +`imenu-prev-index-position-function'." nil nil) + +(autoload 'magit-imenu--process-extract-index-name-function "magit-imenu" "\ +Return imenu name for line at point. +This function is used as a value for +`imenu-extract-index-name-function'. Point should be at the +beginning of the line." nil nil) + +(autoload 'magit-imenu--rebase-prev-index-position-function "magit-imenu" "\ +Move point to previous commit in git-rebase buffer. +This function is used as a value for +`imenu-prev-index-position-function'." nil nil) + +(autoload 'magit-imenu--rebase-extract-index-name-function "magit-imenu" "\ +Return imenu name for line at point. +This function is used as a value for +`imenu-extract-index-name-function'. Point should be at the +beginning of the line." nil nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-imenu" '("magit-imenu--index-function"))) + +;;;*** + +;;;### (autoloads nil "magit-log" "magit-log.el" (0 0 0 0)) +;;; Generated autoloads from magit-log.el + (autoload 'magit-log "magit-log" nil t) + (autoload 'magit-log-refresh "magit-log" nil t) + +(autoload 'magit-log-current "magit-log" "\ +Show log for the current branch. +When `HEAD' is detached or with a prefix argument show log for +one or more revs read from the minibuffer. + +\(fn REVS &optional ARGS FILES)" t nil) + +(autoload 'magit-log-other "magit-log" "\ +Show log for one or more revs read from the minibuffer. +The user can input any revision or revisions separated by a +space, or even ranges, but only branches and tags, and a +representation of the commit at point, are available as +completion candidates. + +\(fn REVS &optional ARGS FILES)" t nil) + +(autoload 'magit-log-head "magit-log" "\ +Show log for `HEAD'. + +\(fn &optional ARGS FILES)" t nil) + +(autoload 'magit-log-branches "magit-log" "\ +Show log for all local branches and `HEAD'. + +\(fn &optional ARGS FILES)" t nil) + +(autoload 'magit-log-matching-branches "magit-log" "\ +Show log for all branches matching PATTERN and `HEAD'. + +\(fn PATTERN &optional ARGS FILES)" t nil) + +(autoload 'magit-log-matching-tags "magit-log" "\ +Show log for all tags matching PATTERN and `HEAD'. + +\(fn PATTERN &optional ARGS FILES)" t nil) + +(autoload 'magit-log-all-branches "magit-log" "\ +Show log for all local and remote branches and `HEAD'. + +\(fn &optional ARGS FILES)" t nil) + +(autoload 'magit-log-all "magit-log" "\ +Show log for all references and `HEAD'. + +\(fn &optional ARGS FILES)" t nil) + +(autoload 'magit-log-buffer-file "magit-log" "\ +Show log for the blob or file visited in the current buffer. +With a prefix argument or when `--follow' is an active log +argument, then follow renames. When the region is active, +restrict the log to the lines that the region touches. + +\(fn &optional FOLLOW BEG END)" t nil) + +(autoload 'magit-log-trace-definition "magit-log" "\ +Show log for the definition at point. + +\(fn FILE FN REV)" t nil) + +(autoload 'magit-log-merged "magit-log" "\ +Show log for the merge of COMMIT into BRANCH. + +More precisely, find merge commit M that brought COMMIT into +BRANCH, and show the log of the range \"M^1..M\". If COMMIT is +directly on BRANCH, then show approximately twenty surrounding +commits instead. + +This command requires git-when-merged, which is available from +https://github.com/mhagger/git-when-merged. + +\(fn COMMIT BRANCH &optional ARGS FILES)" t nil) + +(autoload 'magit-log-move-to-parent "magit-log" "\ +Move to the Nth parent of the current commit. + +\(fn &optional N)" t nil) + (autoload 'magit-shortlog "magit-log" nil t) + +(autoload 'magit-shortlog-since "magit-log" "\ +Show a history summary for commits since REV. + +\(fn REV ARGS)" t nil) + +(autoload 'magit-shortlog-range "magit-log" "\ +Show a history summary for commit or range REV-OR-RANGE. + +\(fn REV-OR-RANGE ARGS)" t nil) + +(autoload 'magit-cherry "magit-log" "\ +Show commits in a branch that are not merged in the upstream branch. + +\(fn HEAD UPSTREAM)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-log" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-margin" "magit-margin.el" (0 0 0 0)) +;;; Generated autoloads from magit-margin.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-margin" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-merge" "magit-merge.el" (0 0 0 0)) +;;; Generated autoloads from magit-merge.el + (autoload 'magit-merge "magit" nil t) + +(autoload 'magit-merge-plain "magit-merge" "\ +Merge commit REV into the current branch; using default message. + +Unless there are conflicts or a prefix argument is used create a +merge commit using a generic commit message and without letting +the user inspect the result. With a prefix argument pretend the +merge failed to give the user the opportunity to inspect the +merge. + +\(git merge --no-edit|--no-commit [ARGS] REV) + +\(fn REV &optional ARGS NOCOMMIT)" t nil) + +(autoload 'magit-merge-editmsg "magit-merge" "\ +Merge commit REV into the current branch; and edit message. +Perform the merge and prepare a commit message but let the user +edit it. + +\(git merge --edit --no-ff [ARGS] REV) + +\(fn REV &optional ARGS)" t nil) + +(autoload 'magit-merge-nocommit "magit-merge" "\ +Merge commit REV into the current branch; pretending it failed. +Pretend the merge failed to give the user the opportunity to +inspect the merge and change the commit message. + +\(git merge --no-commit --no-ff [ARGS] REV) + +\(fn REV &optional ARGS)" t nil) + +(autoload 'magit-merge-into "magit-merge" "\ +Merge the current branch into BRANCH and remove the former. + +Before merging, force push the source branch to its push-remote, +provided the respective remote branch already exists, ensuring +that the respective pull-request (if any) won't get stuck on some +obsolete version of the commits that are being merged. Finally +if `forge-branch-pullreq' was used to create the merged branch, +then also remove the respective remote branch. + +\(fn BRANCH &optional ARGS)" t nil) + +(autoload 'magit-merge-absorb "magit-merge" "\ +Merge BRANCH into the current branch and remove the former. + +Before merging, force push the source branch to its push-remote, +provided the respective remote branch already exists, ensuring +that the respective pull-request (if any) won't get stuck on some +obsolete version of the commits that are being merged. Finally +if `forge-branch-pullreq' was used to create the merged branch, +then also remove the respective remote branch. + +\(fn BRANCH &optional ARGS)" t nil) + +(autoload 'magit-merge-squash "magit-merge" "\ +Squash commit REV into the current branch; don't create a commit. + +\(git merge --squash REV) + +\(fn REV)" t nil) + +(autoload 'magit-merge-preview "magit-merge" "\ +Preview result of merging REV into the current branch. + +\(fn REV)" t nil) + +(autoload 'magit-merge-abort "magit-merge" "\ +Abort the current merge operation. + +\(git merge --abort)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-merge" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-mode" "magit-mode.el" (0 0 0 0)) +;;; Generated autoloads from magit-mode.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-mode" '("disable-magit-save-buffers" "magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-notes" "magit-notes.el" (0 0 0 0)) +;;; Generated autoloads from magit-notes.el + (autoload 'magit-notes "magit" nil t) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-notes" '("magit-notes-"))) + +;;;*** + +;;;### (autoloads nil "magit-obsolete" "magit-obsolete.el" (0 0 0 +;;;;;; 0)) +;;; Generated autoloads from magit-obsolete.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-obsolete" '("magit--magit-popup-warning"))) + +;;;*** + +;;;### (autoloads nil "magit-patch" "magit-patch.el" (0 0 0 0)) +;;; Generated autoloads from magit-patch.el + (autoload 'magit-patch "magit-patch" nil t) + (autoload 'magit-patch-create "magit-patch" nil t) + (autoload 'magit-patch-apply "magit-patch" nil t) + +(autoload 'magit-patch-save "magit-patch" "\ +Write current diff into patch FILE. + +What arguments are used to create the patch depends on the value +of `magit-patch-save-arguments' and whether a prefix argument is +used. + +If the value is the symbol `buffer', then use the same arguments +as the buffer. With a prefix argument use no arguments. + +If the value is a list beginning with the symbol `exclude', then +use the same arguments as the buffer except for those matched by +entries in the cdr of the list. The comparison is done using +`string-prefix-p'. With a prefix argument use the same arguments +as the buffer. + +If the value is a list of strings (including the empty list), +then use those arguments. With a prefix argument use the same +arguments as the buffer. + +Of course the arguments that are required to actually show the +same differences as those shown in the buffer are always used. + +\(fn FILE &optional ARG)" t nil) + +(autoload 'magit-request-pull "magit-patch" "\ +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. +END is the last commit, usually a branch name, which upstream +is asked to pull. START has to be reachable from that commit. + +\(fn URL START END)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-patch" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-process" "magit-process.el" (0 0 0 0)) +;;; Generated autoloads from magit-process.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-process" '("magit-" "tramp-sh-handle-"))) + +;;;*** + +;;;### (autoloads nil "magit-pull" "magit-pull.el" (0 0 0 0)) +;;; Generated autoloads from magit-pull.el + (autoload 'magit-pull "magit-pull" nil t) + (autoload 'magit-pull-from-pushremote "magit-pull" nil t) + (autoload 'magit-pull-from-upstream "magit-pull" nil t) + +(autoload 'magit-pull-branch "magit-pull" "\ +Pull from a branch read in the minibuffer. + +\(fn SOURCE ARGS)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-pull" '("magit-pull-"))) + +;;;*** + +;;;### (autoloads nil "magit-push" "magit-push.el" (0 0 0 0)) +;;; Generated autoloads from magit-push.el + (autoload 'magit-push "magit-push" nil t) + (autoload 'magit-push-current-to-pushremote "magit-push" nil t) + (autoload 'magit-push-current-to-upstream "magit-push" nil t) + +(autoload 'magit-push-current "magit-push" "\ +Push the current branch to a branch read in the minibuffer. + +\(fn TARGET ARGS)" t nil) + +(autoload 'magit-push-other "magit-push" "\ +Push an arbitrary branch or commit somewhere. +Both the source and the target are read in the minibuffer. + +\(fn SOURCE TARGET ARGS)" t nil) + +(autoload 'magit-push-refspecs "magit-push" "\ +Push one or multiple REFSPECS to a REMOTE. +Both the REMOTE and the REFSPECS are read in the minibuffer. To +use multiple REFSPECS, separate them with commas. Completion is +only available for the part before the colon, or when no colon +is used. + +\(fn REMOTE REFSPECS ARGS)" t nil) + +(autoload 'magit-push-matching "magit-push" "\ +Push all matching branches to another repository. +If multiple remotes exist, then read one from the user. +If just one exists, use that without requiring confirmation. + +\(fn REMOTE &optional ARGS)" t nil) + +(autoload 'magit-push-tags "magit-push" "\ +Push all tags to another repository. +If only one remote exists, then push to that. Otherwise prompt +for a remote, offering the remote configured for the current +branch as default. + +\(fn REMOTE &optional ARGS)" t nil) + +(autoload 'magit-push-tag "magit-push" "\ +Push a tag to another repository. + +\(fn TAG REMOTE &optional ARGS)" t nil) + +(autoload 'magit-push-notes-ref "magit-push" "\ +Push a notes ref to another repository. + +\(fn REF REMOTE &optional ARGS)" t nil) + (autoload 'magit-push-implicitly "magit-push" nil t) + +(autoload 'magit-push-to-remote "magit-push" "\ +Push to REMOTE without using an explicit refspec. +The REMOTE is read in the minibuffer. + +This command simply runs \"git push -v [ARGS] REMOTE\". ARGS +are the arguments specified in the popup buffer. No refspec +arguments are used. Instead the behavior depends on at least +these Git variables: `push.default', `remote.pushDefault', +`branch..pushRemote', `branch..remote', +`branch..merge', and `remote..push'. + +\(fn REMOTE ARGS)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-push" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-reflog" "magit-reflog.el" (0 0 0 0)) +;;; Generated autoloads from magit-reflog.el + +(autoload 'magit-reflog-current "magit-reflog" "\ +Display the reflog of the current branch. +If `HEAD' is detached, then show the reflog for that instead." t nil) + +(autoload 'magit-reflog-other "magit-reflog" "\ +Display the reflog of a branch or another ref. + +\(fn REF)" t nil) + +(autoload 'magit-reflog-head "magit-reflog" "\ +Display the `HEAD' reflog." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-reflog" '("magit-reflog-"))) + +;;;*** + +;;;### (autoloads nil "magit-refs" "magit-refs.el" (0 0 0 0)) +;;; Generated autoloads from magit-refs.el + (autoload 'magit-show-refs "magit-refs" nil t) + +(autoload 'magit-show-refs-head "magit-refs" "\ +List and compare references in a dedicated buffer. +Compared with `HEAD'. + +\(fn &optional ARGS)" t nil) + +(autoload 'magit-show-refs-current "magit-refs" "\ +List and compare references in a dedicated buffer. +Compare with the current branch or `HEAD' if it is detached. + +\(fn &optional ARGS)" t nil) + +(autoload 'magit-show-refs-other "magit-refs" "\ +List and compare references in a dedicated buffer. +Compared with a branch read from the user. + +\(fn &optional REF ARGS)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-refs" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-remote" "magit-remote.el" (0 0 0 0)) +;;; Generated autoloads from magit-remote.el + (autoload 'magit-remote "magit-remote" nil t) + +(autoload 'magit-remote-add "magit-remote" "\ +Add a remote named REMOTE and fetch it. + +\(fn REMOTE URL &optional ARGS)" t nil) + +(autoload 'magit-remote-rename "magit-remote" "\ +Rename the remote named OLD to NEW. + +\(fn OLD NEW)" t nil) + +(autoload 'magit-remote-remove "magit-remote" "\ +Delete the remote named REMOTE. + +\(fn REMOTE)" t nil) + +(autoload 'magit-remote-prune "magit-remote" "\ +Remove stale remote-tracking branches for REMOTE. + +\(fn REMOTE)" t nil) + +(autoload 'magit-remote-prune-refspecs "magit-remote" "\ +Remove stale refspecs for REMOTE. + +A refspec is stale if there no longer exists at least one branch +on the remote that would be fetched due to that refspec. A stale +refspec is problematic because its existence causes Git to refuse +to fetch according to the remaining non-stale refspecs. + +If only stale refspecs remain, then offer to either delete the +remote or to replace the stale refspecs with the default refspec. + +Also remove the remote-tracking branches that were created due to +the now stale refspecs. Other stale branches are not removed. + +\(fn REMOTE)" t nil) + +(autoload 'magit-remote-set-head "magit-remote" "\ +Set the local representation of REMOTE's default branch. +Query REMOTE and set the symbolic-ref refs/remotes//HEAD +accordingly. With a prefix argument query for the branch to be +used, which allows you to select an incorrect value if you fancy +doing that. + +\(fn REMOTE &optional BRANCH)" t nil) + +(autoload 'magit-remote-unset-head "magit-remote" "\ +Unset the local representation of REMOTE's default branch. +Delete the symbolic-ref \"refs/remotes//HEAD\". + +\(fn REMOTE)" t nil) + +(autoload 'magit-remote-unshallow "magit-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. + +\(fn REMOTE)" t nil) + (autoload 'magit-remote-configure "magit-remote" nil t) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-remote" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-repos" "magit-repos.el" (0 0 0 0)) +;;; Generated autoloads from magit-repos.el + +(autoload 'magit-list-repositories "magit-repos" "\ +Display a list of repositories. + +Use the options `magit-repository-directories' to control which +repositories are displayed." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-repos" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-reset" "magit-reset.el" (0 0 0 0)) +;;; Generated autoloads from magit-reset.el + (autoload 'magit-reset "magit" nil t) + +(autoload 'magit-reset-mixed "magit-reset" "\ +Reset the `HEAD' and index to COMMIT, but not the working tree. + +\(git reset --mixed COMMIT) + +\(fn COMMIT)" t nil) + +(autoload 'magit-reset-soft "magit-reset" "\ +Reset the `HEAD' to COMMIT, but not the index and working tree. + +\(git reset --soft REVISION) + +\(fn COMMIT)" t nil) + +(autoload 'magit-reset-hard "magit-reset" "\ +Reset the `HEAD', index, and working tree to COMMIT. + +\(git reset --hard REVISION) + +\(fn COMMIT)" t nil) + +(autoload 'magit-reset-keep "magit-reset" "\ +Reset the `HEAD' and index to COMMIT, while keeping uncommitted changes. + +\(git reset --keep REVISION) + +\(fn COMMIT)" t nil) + +(autoload 'magit-reset-index "magit-reset" "\ +Reset the index to COMMIT. +Keep the `HEAD' and working tree as-is, so if COMMIT refers to the +head this effectively unstages all changes. + +\(git reset COMMIT .) + +\(fn COMMIT)" t nil) + +(autoload 'magit-reset-worktree "magit-reset" "\ +Reset the worktree to COMMIT. +Keep the `HEAD' and index as-is. + +\(fn COMMIT)" t nil) + +(autoload 'magit-reset-quickly "magit-reset" "\ +Reset the `HEAD' and index to COMMIT, and possibly the working tree. +With a prefix argument reset the working tree otherwise don't. + +\(git reset --mixed|--hard COMMIT) + +\(fn COMMIT &optional HARD)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-reset" '("magit-reset-"))) + +;;;*** + +;;;### (autoloads nil "magit-sequence" "magit-sequence.el" (0 0 0 +;;;;;; 0)) +;;; Generated autoloads from magit-sequence.el + +(autoload 'magit-sequencer-continue "magit-sequence" "\ +Resume the current cherry-pick or revert sequence." t nil) + +(autoload 'magit-sequencer-skip "magit-sequence" "\ +Skip the stopped at commit during a cherry-pick or revert sequence." t nil) + +(autoload 'magit-sequencer-abort "magit-sequence" "\ +Abort the current cherry-pick or revert sequence. +This discards all changes made since the sequence started." t nil) + (autoload 'magit-cherry-pick "magit-sequence" nil t) + +(autoload 'magit-cherry-copy "magit-sequence" "\ +Copy COMMITS from another branch onto the current branch. +Prompt for a commit, defaulting to the commit at point. If +the region selects multiple commits, then pick all of them, +without prompting. + +\(fn COMMITS &optional ARGS)" t nil) + +(autoload 'magit-cherry-apply "magit-sequence" "\ +Apply the changes in COMMITS but do not commit them. +Prompt for a commit, defaulting to the commit at point. If +the region selects multiple commits, then apply all of them, +without prompting. + +\(fn COMMITS &optional ARGS)" t nil) + +(autoload 'magit-cherry-harvest "magit-sequence" "\ +Move COMMITS from another BRANCH onto the current branch. +Remove the COMMITS from BRANCH and stay on the current branch. +If a conflict occurs, then you have to fix that and finish the +process manually. + +\(fn COMMITS BRANCH &optional ARGS)" t nil) + +(autoload 'magit-cherry-donate "magit-sequence" "\ +Move COMMITS from the current branch onto another existing BRANCH. +Remove COMMITS from the current branch and stay on that branch. +If a conflict occurs, then you have to fix that and finish the +process manually. `HEAD' is allowed to be detached initially. + +\(fn COMMITS BRANCH &optional ARGS)" t nil) + +(autoload 'magit-cherry-spinout "magit-sequence" "\ +Move COMMITS from the current branch onto a new BRANCH. +Remove COMMITS from the current branch and stay on that branch. +If a conflict occurs, then you have to fix that and finish the +process manually. + +\(fn COMMITS BRANCH START-POINT &optional ARGS)" t nil) + +(autoload 'magit-cherry-spinoff "magit-sequence" "\ +Move COMMITS from the current branch onto a new BRANCH. +Remove COMMITS from the current branch and checkout BRANCH. +If a conflict occurs, then you have to fix that and finish +the process manually. + +\(fn COMMITS BRANCH START-POINT &optional ARGS)" t nil) + (autoload 'magit-revert "magit-sequence" nil t) + +(autoload 'magit-revert-and-commit "magit-sequence" "\ +Revert COMMIT by creating a new commit. +Prompt for a commit, defaulting to the commit at point. If +the region selects multiple commits, then revert all of them, +without prompting. + +\(fn COMMIT &optional ARGS)" t nil) + +(autoload 'magit-revert-no-commit "magit-sequence" "\ +Revert COMMIT by applying it in reverse to the worktree. +Prompt for a commit, defaulting to the commit at point. If +the region selects multiple commits, then revert all of them, +without prompting. + +\(fn COMMIT &optional ARGS)" t nil) + (autoload 'magit-am "magit-sequence" nil t) + +(autoload 'magit-am-apply-patches "magit-sequence" "\ +Apply the patches FILES. + +\(fn &optional FILES ARGS)" t nil) + +(autoload 'magit-am-apply-maildir "magit-sequence" "\ +Apply the patches from MAILDIR. + +\(fn &optional MAILDIR ARGS)" t nil) + +(autoload 'magit-am-continue "magit-sequence" "\ +Resume the current patch applying sequence." t nil) + +(autoload 'magit-am-skip "magit-sequence" "\ +Skip the stopped at patch during a patch applying sequence." t nil) + +(autoload 'magit-am-abort "magit-sequence" "\ +Abort the current patch applying sequence. +This discards all changes made since the sequence started." t nil) + (autoload 'magit-rebase "magit-sequence" nil t) + (autoload 'magit-rebase-onto-pushremote "magit-sequence" nil t) + (autoload 'magit-rebase-onto-upstream "magit-sequence" nil t) + +(autoload 'magit-rebase-branch "magit-sequence" "\ +Rebase the current branch onto a branch read in the minibuffer. +All commits that are reachable from `HEAD' but not from the +selected branch TARGET are being rebased. + +\(fn TARGET ARGS)" t nil) + +(autoload 'magit-rebase-subset "magit-sequence" "\ +Rebase a subset of the current branch's history onto a new base. +Rebase commits from START to `HEAD' onto NEWBASE. +START has to be selected from a list of recent commits. + +\(fn NEWBASE START ARGS)" t nil) + +(autoload 'magit-rebase-interactive "magit-sequence" "\ +Start an interactive rebase sequence. + +\(fn COMMIT ARGS)" t nil) + +(autoload 'magit-rebase-autosquash "magit-sequence" "\ +Combine squash and fixup commits with their intended targets. + +\(fn ARGS)" t nil) + +(autoload 'magit-rebase-edit-commit "magit-sequence" "\ +Edit a single older commit using rebase. + +\(fn COMMIT ARGS)" t nil) + +(autoload 'magit-rebase-reword-commit "magit-sequence" "\ +Reword a single older commit using rebase. + +\(fn COMMIT ARGS)" t nil) + +(autoload 'magit-rebase-remove-commit "magit-sequence" "\ +Remove a single older commit using rebase. + +\(fn COMMIT ARGS)" t nil) + +(autoload 'magit-rebase-continue "magit-sequence" "\ +Restart the current rebasing operation. +In some cases this pops up a commit message buffer for you do +edit. With a prefix argument the old message is reused as-is. + +\(fn &optional NOEDIT)" t nil) + +(autoload 'magit-rebase-skip "magit-sequence" "\ +Skip the current commit and restart the current rebase operation." t nil) + +(autoload 'magit-rebase-edit "magit-sequence" "\ +Edit the todo list of the current rebase operation." t nil) + +(autoload 'magit-rebase-abort "magit-sequence" "\ +Abort the current rebase operation, restoring the original branch." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-sequence" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-stash" "magit-stash.el" (0 0 0 0)) +;;; Generated autoloads from magit-stash.el + (autoload 'magit-stash "magit-stash" nil t) + +(autoload 'magit-stash-both "magit-stash" "\ +Create a stash of the index and working tree. +Untracked files are included according to infix arguments. +One prefix argument is equivalent to `--include-untracked' +while two prefix arguments are equivalent to `--all'. + +\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil) + +(autoload 'magit-stash-index "magit-stash" "\ +Create a stash of the index only. +Unstaged and untracked changes are not stashed. The stashed +changes are applied in reverse to both the index and the +worktree. This command can fail when the worktree is not clean. +Applying the resulting stash has the inverse effect. + +\(fn MESSAGE)" t nil) + +(autoload 'magit-stash-worktree "magit-stash" "\ +Create a stash of unstaged changes in the working tree. +Untracked files are included according to infix arguments. +One prefix argument is equivalent to `--include-untracked' +while two prefix arguments are equivalent to `--all'. + +\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil) + +(autoload 'magit-stash-keep-index "magit-stash" "\ +Create a stash of the index and working tree, keeping index intact. +Untracked files are included according to infix arguments. +One prefix argument is equivalent to `--include-untracked' +while two prefix arguments are equivalent to `--all'. + +\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil) + +(autoload 'magit-snapshot-both "magit-stash" "\ +Create a snapshot of the index and working tree. +Untracked files are included according to infix arguments. +One prefix argument is equivalent to `--include-untracked' +while two prefix arguments are equivalent to `--all'. + +\(fn &optional INCLUDE-UNTRACKED)" t nil) + +(autoload 'magit-snapshot-index "magit-stash" "\ +Create a snapshot of the index only. +Unstaged and untracked changes are not stashed." t nil) + +(autoload 'magit-snapshot-worktree "magit-stash" "\ +Create a snapshot of unstaged changes in the working tree. +Untracked files are included according to infix arguments. +One prefix argument is equivalent to `--include-untracked' +while two prefix arguments are equivalent to `--all'. + +\(fn &optional INCLUDE-UNTRACKED)" t nil) + +(autoload 'magit-stash-apply "magit-stash" "\ +Apply a stash to the working tree. +Try to preserve the stash index. If that fails because there +are staged changes, apply without preserving the stash index. + +\(fn STASH)" t nil) + +(autoload 'magit-stash-pop "magit-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 +are staged changes, apply without preserving the stash index +and forgo removing the stash. + +\(fn STASH)" t nil) + +(autoload 'magit-stash-drop "magit-stash" "\ +Remove a stash from the stash list. +When the region is active offer to drop all contained stashes. + +\(fn STASH)" t nil) + +(autoload 'magit-stash-clear "magit-stash" "\ +Remove all stashes saved in REF's reflog by deleting REF. + +\(fn REF)" t nil) + +(autoload 'magit-stash-branch "magit-stash" "\ +Create and checkout a new BRANCH from STASH. + +\(fn STASH BRANCH)" t nil) + +(autoload 'magit-stash-branch-here "magit-stash" "\ +Create and checkout a new BRANCH and apply STASH. +The branch is created using `magit-branch-and-checkout', using the +current branch or `HEAD' as the start-point. + +\(fn STASH BRANCH)" t nil) + +(autoload 'magit-stash-format-patch "magit-stash" "\ +Create a patch from STASH + +\(fn STASH)" t nil) + +(autoload 'magit-stash-list "magit-stash" "\ +List all stashes in a buffer." t nil) + +(autoload 'magit-stash-show "magit-stash" "\ +Show all diffs of a stash in a buffer. + +\(fn STASH &optional ARGS FILES)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-stash" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-status" "magit-status.el" (0 0 0 0)) +;;; Generated autoloads from magit-status.el + +(autoload 'magit-init "magit-status" "\ +Initialize a Git repository, then show its status. + +If the directory is below an existing repository, then the user +has to confirm that a new one should be created inside. If the +directory is the root of the existing repository, then the user +has to confirm that it should be reinitialized. + +Non-interactively DIRECTORY is (re-)initialized unconditionally. + +\(fn DIRECTORY)" t nil) + +(autoload 'magit-status "magit-status" "\ +Show the status of the current Git repository in a buffer. + +If the current directory isn't located within a Git repository, +then prompt for an existing repository or an arbitrary directory, +depending on option `magit-repository-directories', and show the +status of the selected repository instead. + +* If that option specifies any existing repositories, then offer + those for completion and show the status buffer for the + selected one. + +* Otherwise read an arbitrary directory using regular file-name + completion. If the selected directory is the top-level of an + existing working tree, then show the status buffer for that. + +* Otherwise offer to initialize the selected directory as a new + repository. After creating the repository show its status + buffer. + +These fallback behaviors can also be forced using one or more +prefix arguments: + +* With two prefix arguments (or more precisely a numeric prefix + value of 16 or greater) read an arbitrary directory and act on + it as described above. The same could be accomplished using + the command `magit-init'. + +* With a single prefix argument read an existing repository, or + if none can be found based on `magit-repository-directories', + then fall back to the same behavior as with two prefix + arguments. + +\(fn &optional DIRECTORY CACHE)" t nil) + +(defalias 'magit 'magit-status "\ +An alias for `magit-status' for better discoverability. + +Instead of invoking this alias for `magit-status' using +\"M-x magit RET\", you should bind a key to `magit-status' +and read the info node `(magit)Getting Started', which +also contains other useful hints.") + +(autoload 'magit-status-here "magit-status" "\ +Like `magit-status' but with non-nil `magit-status-goto-file-position'." t nil) + +(autoload 'magit-status-quick "magit-status" "\ +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)." t nil) + +(autoload 'magit-status-setup-buffer "magit-status" "\ + + +\(fn &optional DIRECTORY)" nil nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-status" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-submodule" "magit-submodule.el" (0 0 +;;;;;; 0 0)) +;;; Generated autoloads from magit-submodule.el + (autoload 'magit-submodule "magit-submodule" nil t) + (autoload 'magit-submodule-add "magit-submodule" nil t) + +(autoload 'magit-submodule-read-name-for-path "magit-submodule" "\ + + +\(fn PATH &optional PREFER-SHORT)" nil nil) + (autoload 'magit-submodule-register "magit-submodule" nil t) + (autoload 'magit-submodule-populate "magit-submodule" nil t) + (autoload 'magit-submodule-update "magit-submodule" nil t) + (autoload 'magit-submodule-synchronize "magit-submodule" nil t) + (autoload 'magit-submodule-unpopulate "magit-submodule" nil t) + +(autoload 'magit-submodule-remove "magit-submodule" "\ +Unregister MODULES and remove their working directories. + +For safety reasons, do not remove the gitdirs and if a module has +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. + +With the \"--force\" argument offer to remove dirty working +directories and with a prefix argument offer to delete gitdirs. +Both actions are very dangerous and have to be confirmed. There +are additional safety precautions in place, so you might be able +to recover from making a mistake here, but don't count on it. + +\(fn MODULES ARGS TRASH-GITDIRS)" t nil) + +(autoload 'magit-insert-modules "magit-submodule" "\ +Insert submodule sections. +Hook `magit-module-sections-hook' controls which module sections +are inserted, and option `magit-module-sections-nested' controls +whether they are wrapped in an additional section." nil nil) + +(autoload 'magit-insert-modules-overview "magit-submodule" "\ +Insert sections for all modules. +For each section insert the path and the output of `git describe --tags', +or, failing that, the abbreviated HEAD commit hash." nil nil) + +(autoload 'magit-insert-modules-unpulled-from-upstream "magit-submodule" "\ +Insert sections for modules that haven't been pulled from the upstream. +These sections can be expanded to show the respective commits." nil nil) + +(autoload 'magit-insert-modules-unpulled-from-pushremote "magit-submodule" "\ +Insert sections for modules that haven't been pulled from the push-remote. +These sections can be expanded to show the respective commits." nil nil) + +(autoload 'magit-insert-modules-unpushed-to-upstream "magit-submodule" "\ +Insert sections for modules that haven't been pushed to the upstream. +These sections can be expanded to show the respective commits." nil nil) + +(autoload 'magit-insert-modules-unpushed-to-pushremote "magit-submodule" "\ +Insert sections for modules that haven't been pushed to the push-remote. +These sections can be expanded to show the respective commits." nil nil) + +(autoload 'magit-list-submodules "magit-submodule" "\ +Display a list of the current repository's submodules." t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-submodule" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-subtree" "magit-subtree.el" (0 0 0 0)) +;;; Generated autoloads from magit-subtree.el + (autoload 'magit-subtree "magit-subtree" nil t) + (autoload 'magit-subtree-import "magit-subtree" nil t) + (autoload 'magit-subtree-export "magit-subtree" nil t) + +(autoload 'magit-subtree-add "magit-subtree" "\ +Add REF from REPOSITORY as a new subtree at PREFIX. + +\(fn PREFIX REPOSITORY REF ARGS)" t nil) + +(autoload 'magit-subtree-add-commit "magit-subtree" "\ +Add COMMIT as a new subtree at PREFIX. + +\(fn PREFIX COMMIT ARGS)" t nil) + +(autoload 'magit-subtree-merge "magit-subtree" "\ +Merge COMMIT into the PREFIX subtree. + +\(fn PREFIX COMMIT ARGS)" t nil) + +(autoload 'magit-subtree-pull "magit-subtree" "\ +Pull REF from REPOSITORY into the PREFIX subtree. + +\(fn PREFIX REPOSITORY REF ARGS)" t nil) + +(autoload 'magit-subtree-push "magit-subtree" "\ +Extract the history of the subtree PREFIX and push it to REF on REPOSITORY. + +\(fn PREFIX REPOSITORY REF ARGS)" t nil) + +(autoload 'magit-subtree-split "magit-subtree" "\ +Extract the history of the subtree PREFIX. + +\(fn PREFIX COMMIT ARGS)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-subtree" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-tag" "magit-tag.el" (0 0 0 0)) +;;; Generated autoloads from magit-tag.el + (autoload 'magit-tag "magit" nil t) + +(autoload 'magit-tag-create "magit-tag" "\ +Create a new tag with the given NAME at REV. +With a prefix argument annotate the tag. + +\(git tag [--annotate] NAME REV) + +\(fn NAME REV &optional ARGS)" t nil) + +(autoload 'magit-tag-delete "magit-tag" "\ +Delete one or more tags. +If the region marks multiple tags (and nothing else), then offer +to delete those, otherwise prompt for a single tag to be deleted, +defaulting to the tag at point. + +\(git tag -d TAGS) + +\(fn TAGS)" t nil) + +(autoload 'magit-tag-prune "magit-tag" "\ +Offer to delete tags missing locally from REMOTE, and vice versa. + +\(fn TAGS REMOTE-TAGS REMOTE)" t nil) + +(autoload 'magit-tag-release "magit-tag" "\ +Create a release tag. + +Assume that release tags match `magit-release-tag-regexp'. + +First prompt 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. + +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\". + +\(fn TAG MSG &optional ARGS)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-tag" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-transient" "magit-transient.el" (0 0 +;;;;;; 0 0)) +;;; Generated autoloads from magit-transient.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-transient" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-utils" "magit-utils.el" (0 0 0 0)) +;;; Generated autoloads from magit-utils.el + +(autoload 'magit-emacs-Q-command "magit-utils" "\ +Show a shell command that runs an uncustomized Emacs with only Magit loaded. +See info node `(magit)Debugging Tools' for more information." t nil) + +(autoload 'Info-follow-nearest-node--magit-gitman "magit-utils" "\ + + +\(fn FN &optional FORK)" nil nil) + +(advice-add 'Info-follow-nearest-node :around 'Info-follow-nearest-node--magit-gitman) + +(autoload 'org-man-export--magit-gitman "magit-utils" "\ + + +\(fn FN LINK DESCRIPTION FORMAT)" nil nil) + +(advice-add 'org-man-export :around 'org-man-export--magit-gitman) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-utils" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-wip" "magit-wip.el" (0 0 0 0)) +;;; Generated autoloads from magit-wip.el + +(defvar magit-wip-mode nil "\ +Non-nil if Magit-Wip mode is enabled. +See the `magit-wip-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `magit-wip-mode'.") + +(custom-autoload 'magit-wip-mode "magit-wip" nil) + +(autoload 'magit-wip-mode "magit-wip" "\ +Save uncommitted changes to work-in-progress refs. + +If called interactively, enable Magit-Wip mode if ARG is +positive, and disable it if ARG is zero or negative. If called +from Lisp, also enable the mode if ARG is omitted or nil, and +toggle it if ARG is `toggle'; disable the mode otherwise. + +Whenever appropriate (i.e. when dataloss would be a possibility +otherwise) this mode causes uncommitted changes to be committed +to dedicated work-in-progress refs. + +For historic reasons this mode is implemented on top of four +other `magit-wip-*' modes, which can also be used individually, +if you want finer control over when the wip refs are updated; +but that is discouraged. + +\(fn &optional ARG)" t nil) + +(put 'magit-wip-after-save-mode 'globalized-minor-mode t) + +(defvar magit-wip-after-save-mode nil "\ +Non-nil if Magit-Wip-After-Save mode is enabled. +See the `magit-wip-after-save-mode' command +for a description of this minor mode. +Setting this variable directly does not take effect; +either customize it (see the info node `Easy Customization') +or call the function `magit-wip-after-save-mode'.") + +(custom-autoload 'magit-wip-after-save-mode "magit-wip" nil) + +(autoload 'magit-wip-after-save-mode "magit-wip" "\ +Toggle Magit-Wip-After-Save-Local mode in all buffers. +With prefix ARG, enable Magit-Wip-After-Save mode if ARG is positive; +otherwise, disable it. If called from Lisp, enable the mode if +ARG is omitted or nil. + +Magit-Wip-After-Save-Local mode is enabled in all buffers where +`magit-wip-after-save-local-mode-turn-on' would do it. +See `magit-wip-after-save-local-mode' for more information on Magit-Wip-After-Save-Local mode. + +\(fn &optional ARG)" t nil) + +(defvar magit-wip-after-apply-mode nil "\ +Non-nil if Magit-Wip-After-Apply mode is enabled. +See the `magit-wip-after-apply-mode' command +for a description of this minor mode.") + +(custom-autoload 'magit-wip-after-apply-mode "magit-wip" nil) + +(autoload 'magit-wip-after-apply-mode "magit-wip" "\ +Commit to work-in-progress refs. + +If called interactively, enable Magit-Wip-After-Apply mode if ARG +is positive, and disable it if ARG is zero or negative. If +called from Lisp, also enable the mode if ARG is omitted or nil, +and toggle it if ARG is `toggle'; disable the mode otherwise. + +After applying a change using any \"apply variant\" +command (apply, stage, unstage, discard, and reverse) commit the +affected files to the current wip refs. For each branch there +may be two wip refs; one contains snapshots of the files as found +in the worktree and the other contains snapshots of the entries +in the index. + +\(fn &optional ARG)" t nil) + +(defvar magit-wip-before-change-mode nil "\ +Non-nil if Magit-Wip-Before-Change mode is enabled. +See the `magit-wip-before-change-mode' command +for a description of this minor mode.") + +(custom-autoload 'magit-wip-before-change-mode "magit-wip" nil) + +(autoload 'magit-wip-before-change-mode "magit-wip" "\ +Commit to work-in-progress refs before certain destructive changes. + +If called interactively, enable Magit-Wip-Before-Change mode if +ARG is positive, and disable it if ARG is zero or negative. If +called from Lisp, also enable the mode if ARG is omitted or nil, +and toggle it if ARG is `toggle'; disable the mode otherwise. + +Before invoking a revert command or an \"apply variant\" +command (apply, stage, unstage, discard, and reverse) commit the +affected tracked files to the current wip refs. For each branch +there may be two wip refs; one contains snapshots of the files +as found in the worktree and the other contains snapshots of the +entries in the index. + +Only changes to files which could potentially be affected by the +command which is about to be called are committed. + +\(fn &optional ARG)" t nil) + +(autoload 'magit-wip-commit-initial-backup "magit-wip" "\ +Before saving, commit current file to a worktree wip ref. + +The user has to add this function to `before-save-hook'. + +Commit the current state of the visited file before saving the +current buffer to that file. This backs up the same version of +the file as `backup-buffer' would, but stores the backup in the +worktree wip ref, which is also used by the various Magit Wip +modes, instead of in a backup file as `backup-buffer' would. + +This function ignores the variables that affect `backup-buffer' +and can be used along-side that function, which is recommended +because this function only backs up files that are tracked in +a Git repository." nil nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-wip" '("magit-"))) + +;;;*** + +;;;### (autoloads nil "magit-worktree" "magit-worktree.el" (0 0 0 +;;;;;; 0)) +;;; Generated autoloads from magit-worktree.el + (autoload 'magit-worktree "magit-worktree" nil t) + +(autoload 'magit-worktree-checkout "magit-worktree" "\ +Checkout BRANCH in a new worktree at PATH. + +\(fn PATH BRANCH)" t nil) + +(autoload 'magit-worktree-branch "magit-worktree" "\ +Create a new BRANCH and check it out in a new worktree at PATH. + +\(fn PATH BRANCH START-POINT &optional FORCE)" t nil) + +(autoload 'magit-worktree-move "magit-worktree" "\ +Move WORKTREE to PATH. + +\(fn WORKTREE PATH)" t nil) + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-worktree" '("magit-"))) + +;;;*** + +;;;### (autoloads nil nil ("magit-core.el" "magit-pkg.el") (0 0 0 +;;;;;; 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; magit-autoloads.el ends here diff --git a/elpa/magit-20220116.1908/magit-autorevert.el b/elpa/magit-20220116.1908/magit-autorevert.el new file mode 100644 index 00000000..c998d7a6 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-autorevert.el @@ -0,0 +1,268 @@ +;;; magit-autorevert.el --- revert buffers when files in repository change -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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-git) + +(require 'autorevert) + +;;; Options + +(defgroup magit-auto-revert nil + "Revert buffers when files in repository change." + :link '(custom-group-link auto-revert) + :link '(info-link "(magit)Automatic Reverting of File-Visiting Buffers") + :group 'auto-revert + :group 'magit-essentials + :group 'magit-modes) + +(defcustom auto-revert-buffer-list-filter nil + "Filter that determines which buffers `auto-revert-buffers' reverts. + +This option is provided by Magit, which also advises +`auto-revert-buffers' to respect it. Magit users who do not turn +on the local mode `auto-revert-mode' themselves, are best served +by setting the value to `magit-auto-revert-repository-buffer-p'. + +However the default is nil, so as not to disturb users who do use +the local mode directly. If you experience delays when running +Magit commands, then you should consider using one of the +predicates provided by Magit - especially if you also use Tramp. + +Users who do turn on `auto-revert-mode' in buffers in which Magit +doesn't do that for them, should likely not use any filter. +Users who turn on `global-auto-revert-mode', do not have to worry +about this option, because it is disregarded if the global mode +is enabled." + :package-version '(magit . "2.4.2") + :group 'auto-revert + :group 'magit-auto-revert + :group 'magit-related + :type '(radio (const :tag "No filter" nil) + (function-item magit-auto-revert-buffer-p) + (function-item magit-auto-revert-repository-buffer-p) + function)) + +(defcustom magit-auto-revert-tracked-only t + "Whether `magit-auto-revert-mode' only reverts tracked files." + :package-version '(magit . "2.4.0") + :group 'magit-auto-revert + :type 'boolean + :set (lambda (var val) + (set var val) + (when (and (bound-and-true-p magit-auto-revert-mode) + (featurep 'magit-autorevert)) + (magit-auto-revert-mode -1) + (magit-auto-revert-mode)))) + +(defcustom magit-auto-revert-immediately t + "Whether Magit reverts buffers immediately. + +If this is non-nil and either `global-auto-revert-mode' or +`magit-auto-revert-mode' is enabled, then Magit immediately +reverts buffers by explicitly calling `auto-revert-buffers' +after running Git for side-effects. + +If `auto-revert-use-notify' is non-nil (and file notifications +are actually supported), then `magit-auto-revert-immediately' +does not have to be non-nil, because the reverts happen +immediately anyway. + +If `magit-auto-revert-immediately' and `auto-revert-use-notify' +are both nil, then reverts happen after `auto-revert-interval' +seconds of user inactivity. That is not desirable." + :package-version '(magit . "2.4.0") + :group 'magit-auto-revert + :type 'boolean) + +;;; Mode + +(defun magit-turn-on-auto-revert-mode-if-desired (&optional file) + (if file + (--when-let (find-buffer-visiting file) + (with-current-buffer it + (magit-turn-on-auto-revert-mode-if-desired))) + (when (and buffer-file-name + (file-readable-p buffer-file-name) + (or (< emacs-major-version 27) + (with-no-warnings + (condition-case nil + (executable-find magit-git-executable t) ; see #3684 + (wrong-number-of-arguments t)))) ; very old 27 built + (magit-toplevel) + (or (not magit-auto-revert-tracked-only) + (magit-file-tracked-p buffer-file-name)) + (not auto-revert-mode) ; see #3014 + (not global-auto-revert-mode)) ; see #3460 + (auto-revert-mode 1)))) + +;;;###autoload +(define-globalized-minor-mode magit-auto-revert-mode auto-revert-mode + magit-turn-on-auto-revert-mode-if-desired + :package-version '(magit . "2.4.0") + :link '(info-link "(magit)Automatic Reverting of File-Visiting Buffers") + :group 'magit-auto-revert + :group 'magit-essentials + ;; - When `global-auto-revert-mode' is enabled, then this mode is + ;; redundant. + ;; - In all other cases enable the mode because if buffers are not + ;; automatically reverted that would make many very common tasks + ;; much more cumbersome. + :init-value (not (or global-auto-revert-mode + noninteractive))) +;; - Unfortunately `:init-value t' only sets the value of the mode +;; variable but does not cause the mode function to be called. +;; - I don't think it works like this on purpose, but since one usually +;; should not enable global modes by default, it is understandable. +;; - If the user has set the variable `magit-auto-revert-mode' to nil +;; after loading magit (instead of doing so before loading magit or +;; by using the function), then we should still respect that setting. +;; - If the user sets one of these variables after loading magit and +;; after `after-init-hook' has run, then that won't have an effect +;; and there is nothing we can do about it. +(defun magit-auto-revert-mode--init-kludge () + "This is an internal kludge to be used on `after-init-hook'. +Do not use this function elsewhere, and don't remove it from +the `after-init-hook'. For more information see the comments +and code surrounding the definition of this function." + (if magit-auto-revert-mode + (let ((start (current-time))) + (magit-message "Turning on magit-auto-revert-mode...") + (magit-auto-revert-mode 1) + (magit-message + "Turning on magit-auto-revert-mode...done%s" + (let ((elapsed (float-time (time-subtract nil start)))) + (if (> elapsed 0.2) + (format " (%.3fs, %s buffers checked)" elapsed + (length (buffer-list))) + "")))) + (magit-auto-revert-mode -1))) +(if after-init-time + ;; Since `after-init-hook' has already been + ;; run, turn the mode on or off right now. + (magit-auto-revert-mode--init-kludge) + ;; By the time the init file has been fully loaded the + ;; values of the relevant variables might have changed. + (add-hook 'after-init-hook #'magit-auto-revert-mode--init-kludge t)) + +(put 'magit-auto-revert-mode 'function-documentation + "Toggle Magit Auto Revert mode. +If called interactively, enable Magit Auto Revert mode if ARG is +positive, and disable it if ARG is zero or negative. If called +from Lisp, also enable the mode if ARG is omitted or nil, and +toggle it if ARG is `toggle'; disable the mode otherwise. + +Magit Auto Revert mode is a global minor mode that reverts +buffers associated with a file that is located inside a Git +repository when the file changes on disk. Use `auto-revert-mode' +to revert a particular buffer. Or use `global-auto-revert-mode' +to revert all file-visiting buffers, not just those that visit +a file located inside a Git repository. + +This global mode works by turning on the buffer-local mode +`auto-revert-mode' at the time a buffer is first created. The +local mode is turned on if the visited file is being tracked in +a Git repository at the time when the buffer is created. + +If `magit-auto-revert-tracked-only' is non-nil (the default), +then only tracked files are reverted. But if you stage a +previously untracked file using `magit-stage', then this mode +notices that. + +Unlike `global-auto-revert-mode', this mode never reverts any +buffers that are not visiting files. + +The behavior of this mode can be customized using the options +in the `autorevert' and `magit-autorevert' groups. + +This function calls the hook `magit-auto-revert-mode-hook'. + +Like nearly every mode, this mode should be enabled or disabled +by calling the respective mode function, the reason being that +changing the state of a mode involves more than merely toggling +a single switch, so setting the mode variable is not enough. +Also, you should not use `after-init-hook' to disable this mode.") + +(defun magit-auto-revert-buffers () + (when (and magit-auto-revert-immediately + (or global-auto-revert-mode + (and magit-auto-revert-mode auto-revert-buffer-list))) + (let ((auto-revert-buffer-list-filter + (or auto-revert-buffer-list-filter + #'magit-auto-revert-repository-buffer-p))) + (auto-revert-buffers)))) + +(defvar magit-auto-revert-toplevel nil) + +(defvar magit-auto-revert-counter 1 + "Incremented each time `auto-revert-buffers' is called.") + +(defun magit-auto-revert-buffer-p (buffer) + "Return non-nil if BUFFER visits a file inside the current repository. +The current repository is the one containing `default-directory'. +If there is no current repository, then return t for any BUFFER." + (magit-auto-revert-repository-buffer-p buffer t)) + +(defun magit-auto-revert-repository-buffer-p (buffer &optional fallback) + "Return non-nil if BUFFER visits a file inside the current repository. +The current repository is the one containing `default-directory'. +If there is no current repository, then return FALLBACK (which +defaults to nil) for any BUFFER." + ;; Call `magit-toplevel' just once per cycle. + (unless (and magit-auto-revert-toplevel + (= (cdr magit-auto-revert-toplevel) + magit-auto-revert-counter)) + (setq magit-auto-revert-toplevel + (cons (or (magit-toplevel) 'no-repo) + magit-auto-revert-counter))) + (let ((top (car magit-auto-revert-toplevel))) + (if (eq top 'no-repo) + fallback + (let ((dir (buffer-local-value 'default-directory buffer))) + (and (equal (file-remote-p dir) + (file-remote-p top)) + ;; ^ `tramp-handle-file-in-directory-p' lacks this optimization. + (file-in-directory-p dir top)))))) + +(defun auto-revert-buffers--buffer-list-filter (fn) + (cl-incf magit-auto-revert-counter) + (if (or global-auto-revert-mode + (not auto-revert-buffer-list) + (not auto-revert-buffer-list-filter)) + (funcall fn) + (let ((auto-revert-buffer-list + (-filter auto-revert-buffer-list-filter + auto-revert-buffer-list))) + (funcall fn)) + (unless auto-revert-timer + (auto-revert-set-timer)))) + +(advice-add 'auto-revert-buffers :around + 'auto-revert-buffers--buffer-list-filter) + +;;; _ +(provide 'magit-autorevert) +;;; magit-autorevert.el ends here diff --git a/elpa/magit-20220116.1908/magit-bisect.el b/elpa/magit-20220116.1908/magit-bisect.el new file mode 100644 index 00000000..ff2a53b5 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-bisect.el @@ -0,0 +1,310 @@ +;;; magit-bisect.el --- bisect support for Magit -*- lexical-binding: t -*- + +;; Copyright (C) 2011-2022 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. + +;;; Commentary: + +;; Use a binary search to find the commit that introduced a bug. + +;;; Code: + +(require 'magit) + +;;; Options + +(defcustom magit-bisect-show-graph t + "Whether to use `--graph' in the log showing commits yet to be bisected." + :package-version '(magit . "2.8.0") + :group 'magit-status + :type 'boolean) + +(defface magit-bisect-good + '((t :foreground "DarkOliveGreen")) + "Face for good bisect revisions." + :group 'magit-faces) + +(defface magit-bisect-skip + '((t :foreground "DarkGoldenrod")) + "Face for skipped bisect revisions." + :group 'magit-faces) + +(defface magit-bisect-bad + '((t :foreground "IndianRed4")) + "Face for bad bisect revisions." + :group 'magit-faces) + +;;; Commands + +;;;###autoload (autoload 'magit-bisect "magit-bisect" nil t) +(transient-define-prefix magit-bisect () + "Narrow in on the commit that introduced a bug." + :man-page "git-bisect" + [:class transient-subgroups + :if-not magit-bisect-in-progress-p + ["Arguments" + ("-n" "Don't checkout commits" "--no-checkout") + ("-p" "Follow only first parent of a merge" "--first-parent" + :if (lambda () (magit-git-version>= "2.29"))) + (6 magit-bisect:--term-old + :if (lambda () (magit-git-version>= "2.7"))) + (6 magit-bisect:--term-new + :if (lambda () (magit-git-version>= "2.7")))] + ["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 () (magit-git-version>= "2.7"))) + ("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 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 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) + (user-error "Already bisecting") + (magit-bisect-start-read-args))) + (unless (magit-rev-ancestor-p good bad) + (user-error + "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 args bad good) t)) + +(defun magit-bisect-start-read-args () + (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 () + "After bisecting, cleanup bisection state and return to original `HEAD'." + (interactive) + (magit-confirm 'reset-bisect) + (magit-run-git "bisect" "reset") + (ignore-errors (delete-file (magit-git-dir "BISECT_CMD_OUTPUT")))) + +;;;###autoload +(defun magit-bisect-good () + "While bisecting, mark the current commit as good. +Use this after you have asserted that the commit does not contain +the bug in question." + (interactive) + (magit-git-bisect (or (cadr (magit-bisect-terms)) + (user-error "Not bisecting")))) + +;;;###autoload +(defun magit-bisect-bad () + "While bisecting, mark the current commit as bad. +Use this after you have asserted that the commit does contain the +bug in question." + (interactive) + (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 () + "While bisecting, skip the current commit. +Use this if for some reason the current commit is not a good one +to test. This command lets Git choose a different one." + (interactive) + (magit-git-bisect "skip")) + +;;;###autoload +(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 +begun. In that case it behaves like `git bisect start; git +bisect run'." + (interactive (let ((args (and (not (magit-bisect-in-progress-p)) + (magit-bisect-start-read-args)))) + (cons (read-shell-command "Bisect shell command: ") args))) + (when (and 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--with-connection-local-variables + (magit-git-bisect "run" (list shell-file-name + shell-command-switch cmdline)))) + +(defun magit-git-bisect (subcommand &optional args no-assert) + (unless (or no-assert (magit-bisect-in-progress-p)) + (user-error "Not bisecting")) + (message "Bisecting...") + (magit-with-toplevel + (magit-run-git-async "bisect" subcommand args)) + (set-process-sentinel + magit-this-process + (lambda (process event) + (when (memq (process-status process) '(exit signal)) + (if (> (process-exit-status process) 0) + (magit-process-sentinel process event) + (process-put process 'inhibit-refresh t) + (magit-process-sentinel process event) + (when (buffer-live-p (process-buffer process)) + (with-current-buffer (process-buffer process) + (when-let ((section (get-text-property (point) 'magit-section)) + (output (buffer-substring-no-properties + (oref section content) + (oref section end)))) + (with-temp-file (magit-git-dir "BISECT_CMD_OUTPUT") + (insert output))))) + (magit-refresh)) + (message "Bisecting...done"))))) + +;;; Sections + +(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) + (let* ((lines + (or (magit-file-lines (magit-git-dir "BISECT_CMD_OUTPUT")) + (list "Bisecting: (no saved bisect output)" + "It appears you have invoked `git bisect' from a shell." + "There is nothing wrong with that, we just cannot display" + "anything useful here. Consult the shell output instead."))) + (done-re "^\\([a-z0-9]\\{40\\}\\) is the first bad commit$") + (bad-line (or (and (string-match done-re (car lines)) + (pop lines)) + (--first (string-match done-re it) lines)))) + (magit-insert-section ((eval (if bad-line 'commit 'bisect-output)) + (and bad-line (match-string 1 bad-line))) + (magit-insert-heading + (propertize (or bad-line (pop lines)) + 'font-lock-face 'magit-section-heading)) + (dolist (line lines) + (insert line "\n")))) + (insert "\n"))) + +(defun magit-insert-bisect-rest () + "While bisecting, insert section visualizing the bisect state." + (when (magit-bisect-in-progress-p) + (magit-insert-section (bisect-view) + (magit-insert-heading "Bisect Rest:") + (magit-git-wash (apply-partially 'magit-log-wash-log 'bisect-vis) + "bisect" "visualize" "git" "log" + "--format=%h%x00%D%x00%s" "--decorate=full" + (and magit-bisect-show-graph "--graph"))))) + +(defun magit-insert-bisect-log () + "While bisecting, insert section logging bisect progress." + (when (magit-bisect-in-progress-p) + (magit-insert-section (bisect-log) + (magit-insert-heading "Bisect Log:") + (magit-git-wash #'magit-wash-bisect-log "bisect" "log") + (insert ?\n)))) + +(defun magit-wash-bisect-log (_args) + (let (beg) + (while (progn (setq beg (point-marker)) + (re-search-forward "^\\(git bisect [^\n]+\n\\)" nil t)) + (magit-bind-match-strings (heading) nil + (magit-delete-match) + (save-restriction + (narrow-to-region beg (point)) + (goto-char (point-min)) + (magit-insert-section (bisect-item heading t) + (insert (propertize heading 'font-lock-face + 'magit-section-secondary-heading)) + (magit-insert-heading) + (magit-wash-sequence + (apply-partially 'magit-log-wash-rev 'bisect-log + (magit-abbrev-length))) + (insert ?\n))))) + (when (re-search-forward + "# first bad commit: \\[\\([a-z0-9]\\{40\\}\\)\\] [^\n]+\n" nil t) + (magit-bind-match-strings (hash) nil + (magit-delete-match) + (magit-insert-section (bisect-item) + (insert hash " is the first bad commit\n")))))) + +;;; _ +(provide 'magit-bisect) +;;; magit-bisect.el ends here diff --git a/elpa/magit-20220116.1908/magit-blame.el b/elpa/magit-20220116.1908/magit-blame.el new file mode 100644 index 00000000..81c6219e --- /dev/null +++ b/elpa/magit-20220116.1908/magit-blame.el @@ -0,0 +1,951 @@ +;;; magit-blame.el --- blame support for Magit -*- lexical-binding: t -*- + +;; Copyright (C) 2012-2022 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. + +;;; Commentary: + +;; Annotates each line in file-visiting buffer with information from +;; the revision which last modified the line. + +;;; Code: + +(require 'magit) + +;;; Options + +(defgroup magit-blame nil + "Blame support for Magit." + :link '(info-link "(magit)Blaming") + :group 'magit-modes) + +(defcustom magit-blame-styles + '((headings + (heading-format . "%-20a %C %s\n")) + (margin + (margin-format . (" %s%f" " %C %a" " %H")) + (margin-width . 42) + (margin-face . magit-blame-margin) + (margin-body-face . (magit-blame-dimmed))) + (highlight + (highlight-face . magit-blame-highlight)) + (lines + (show-lines . t) + (show-message . t))) + "List of styles used to visualize blame information. + +Each entry has the form (IDENT (KEY . VALUE)...). IDENT has +to be a symbol uniquely identifying the style. The following +KEYs are recognized: + + `show-lines' + Whether to prefix each chunk of lines with a thin line. + This has no effect if `heading-format' is non-nil. + `show-message' + Whether to display a commit's summary line in the echo area + when crossing chunks. + `highlight-face' + Face used to highlight the first line of each chunk. + If this is nil, then those lines are not highlighted. + `heading-format' + String specifying the information to be shown above each + chunk of lines. It must end with a newline character. + `margin-format' + String specifying the information to be shown in the left + buffer margin. It must NOT end with a newline character. + This can also be a list of formats used for the lines at + the same positions within the chunk. If the chunk has + more lines than formats are specified, then the last is + repeated. + `margin-width' + Width of the margin, provided `margin-format' is non-nil. + `margin-face' + Face used in the margin, provided `margin-format' is + non-nil. This face is used in combination with the faces + that are specific to the used %-specs. If this is nil, + then `magit-blame-margin' is used. + `margin-body-face' + Face used in the margin for all but first line of a chunk. + This face is used in combination with the faces that are + specific to the used %-specs. This can also be a list of + faces (usually one face), in which case only these faces + are used and the %-spec faces are ignored. A good value + might be `(magit-blame-dimmed)'. If this is nil, then + the same face as for the first line is used. + +The following %-specs can be used in `heading-format' and +`margin-format': + + %H hash using face `magit-blame-hash' + %s summary using face `magit-blame-summary' + %a author using face `magit-blame-name' + %A author time using face `magit-blame-date' + %c committer using face `magit-blame-name' + %C committer time using face `magit-blame-date' + +Additionally if `margin-format' ends with %f, then the string +that is displayed in the margin is made at least `margin-width' +characters wide, which may be desirable if the used face sets +the background color. + +The style used in the current buffer can be cycled from the blame +popup. Blame commands (except `magit-blame-echo') use the first +style as the initial style when beginning to blame in a buffer." + :package-version '(magit . "2.13.0") + :group 'magit-blame + :type 'string) + +(defcustom magit-blame-echo-style 'lines + "The blame visualization style used by `magit-blame-echo'. +A symbol that has to be used as the identifier for one of the +styles defined in `magit-blame-styles'." + :package-version '(magit . "2.13.0") + :group 'magit-blame + :type 'symbol) + +(defcustom magit-blame-time-format "%F %H:%M" + "Format for time strings in blame headings." + :group 'magit-blame + :type 'string) + +(defcustom magit-blame-read-only t + "Whether to initially make the blamed buffer read-only." + :package-version '(magit . "2.13.0") + :group 'magit-blame + :type 'boolean) + +(defcustom magit-blame-disable-modes '(fci-mode yascroll-bar-mode) + "List of modes not compatible with Magit-Blame mode. +This modes are turned off when Magit-Blame mode is turned on, +and then turned on again when turning off the latter." + :group 'magit-blame + :type '(repeat (symbol :tag "Mode"))) + +(defcustom magit-blame-mode-lighter " Blame" + "The mode-line lighter of the Magit-Blame mode." + :group 'magit-blame + :type '(choice (const :tag "No lighter" "") string)) + +(defcustom magit-blame-goto-chunk-hook + '(magit-blame-maybe-update-revision-buffer + magit-blame-maybe-show-message) + "Hook run after point entered another chunk." + :package-version '(magit . "2.13.0") + :group 'magit-blame + :type 'hook + :get 'magit-hook-custom-get + :options '(magit-blame-maybe-update-revision-buffer + magit-blame-maybe-show-message)) + +;;; Faces + +(defface magit-blame-highlight + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "grey80" + :foreground "black") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "grey25" + :foreground "white")) + "Face used for highlighting when blaming. +Also see option `magit-blame-styles'." + :group 'magit-faces) + +(defface magit-blame-margin + '((t :inherit magit-blame-highlight + :weight normal + :slant normal)) + "Face used for the blame margin by default when blaming. +Also see option `magit-blame-styles'." + :group 'magit-faces) + +(defface magit-blame-dimmed + '((t :inherit magit-dimmed + :weight normal + :slant normal)) + "Face used for the blame margin in some cases when blaming. +Also see option `magit-blame-styles'." + :group 'magit-faces) + +(defface magit-blame-heading + `((t ,@(and (>= emacs-major-version 27) '(:extend t)) + :inherit magit-blame-highlight + :weight normal + :slant normal)) + "Face used for blame headings by default when blaming. +Also see option `magit-blame-styles'." + :group 'magit-faces) + +(defface magit-blame-summary '((t nil)) + "Face used for commit summaries when blaming." + :group 'magit-faces) + +(defface magit-blame-hash '((t nil)) + "Face used for commit hashes when blaming." + :group 'magit-faces) + +(defface magit-blame-name '((t nil)) + "Face used for author and committer names when blaming." + :group 'magit-faces) + +(defface magit-blame-date '((t nil)) + "Face used for dates when blaming." + :group 'magit-faces) + +;;; Chunks + +(defclass magit-blame-chunk () + (;; + (orig-rev :initarg :orig-rev) + (orig-line :initarg :orig-line) + (final-line :initarg :final-line) + (num-lines :initarg :num-lines) + ;; previous + (prev-rev :initform nil) + (prev-file :initform nil) + ;; filename + (orig-file))) + +(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 (and (not (derived-mode-p 'dired-mode)) + (magit-file-relative-name + nil (not magit-buffer-file-name)))) + (line (format "%i,+1" (line-number-at-pos)))) + (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) + (overlays-at pos))) + +(defun magit-blame--overlay-at (&optional pos key) + (unless pos + (setq pos (point))) + (--first (overlay-get it (or key 'magit-blame-chunk)) + (nconc (overlays-at pos) + (overlays-in pos pos)))) + +;;; Keymaps + +(defvar magit-blame-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-c C-q") 'magit-blame-quit) + map) + "Keymap for `magit-blame-mode'. +Note that most blaming key bindings are defined +in `magit-blame-read-only-mode-map' instead.") + +(defvar magit-blame-read-only-mode-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-m") 'magit-show-commit) + (define-key map (kbd "p") 'magit-blame-previous-chunk) + (define-key map (kbd "P") 'magit-blame-previous-chunk-same-commit) + (define-key map (kbd "n") 'magit-blame-next-chunk) + (define-key map (kbd "N") 'magit-blame-next-chunk-same-commit) + (define-key map (kbd "b") 'magit-blame-addition) + (define-key map (kbd "r") 'magit-blame-removal) + (define-key map (kbd "f") 'magit-blame-reverse) + (define-key map (kbd "B") 'magit-blame) + (define-key map (kbd "c") 'magit-blame-cycle-style) + (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'.") + +;;; Modes +;;;; Variables + +(defvar-local magit-blame-buffer-read-only nil) +(defvar-local magit-blame-cache nil) +(defvar-local magit-blame-disabled-modes nil) +(defvar-local magit-blame-process nil) +(defvar-local magit-blame-recursive-p nil) +(defvar-local magit-blame-type nil) +(defvar-local magit-blame-separator nil) +(defvar-local magit-blame-previous-chunk nil) + +(defvar-local magit-blame--style nil) + +(defsubst magit-blame--style-get (key) + (cdr (assoc key (cdr magit-blame--style)))) + +;;;; Base Mode + +(define-minor-mode magit-blame-mode + "Display blame information inline." + :lighter magit-blame-mode-lighter + (cond (magit-blame-mode + (when (called-interactively-p 'any) + (setq magit-blame-mode nil) + (user-error + (concat "Don't call `magit-blame-mode' directly; " + "instead use `magit-blame'"))) + (add-hook 'after-save-hook 'magit-blame--refresh t t) + (add-hook 'post-command-hook 'magit-blame-goto-chunk-hook t t) + (add-hook 'before-revert-hook 'magit-blame--remove-overlays t t) + (add-hook 'after-revert-hook 'magit-blame--refresh t t) + (add-hook 'read-only-mode-hook 'magit-blame-toggle-read-only t t) + (setq magit-blame-buffer-read-only buffer-read-only) + (when (or magit-blame-read-only magit-buffer-file-name) + (read-only-mode 1)) + (dolist (mode magit-blame-disable-modes) + (when (and (boundp mode) (symbol-value mode)) + (funcall mode -1) + (push mode magit-blame-disabled-modes))) + (setq magit-blame-separator (magit-blame--format-separator)) + (unless magit-blame--style + (setq magit-blame--style (car magit-blame-styles))) + (magit-blame--update-margin)) + (t + (when (process-live-p magit-blame-process) + (kill-process magit-blame-process) + (while magit-blame-process + (sit-for 0.01))) ; avoid racing the sentinel + (remove-hook 'after-save-hook 'magit-blame--refresh t) + (remove-hook 'post-command-hook 'magit-blame-goto-chunk-hook t) + (remove-hook 'before-revert-hook 'magit-blame--remove-overlays t) + (remove-hook 'after-revert-hook 'magit-blame--refresh t) + (remove-hook 'read-only-mode-hook 'magit-blame-toggle-read-only t) + (unless magit-blame-buffer-read-only + (read-only-mode -1)) + (magit-blame-read-only-mode -1) + (dolist (mode magit-blame-disabled-modes) + (funcall mode 1)) + (kill-local-variable 'magit-blame-disabled-modes) + (kill-local-variable 'magit-blame-type) + (kill-local-variable 'magit-blame--style) + (magit-blame--update-margin) + (magit-blame--remove-overlays)))) + +(defun magit-blame--refresh () + (magit-blame--run (magit-blame-arguments))) + +(defun magit-blame-goto-chunk-hook () + (let ((chunk (magit-blame-chunk-at (point)))) + (when (cl-typep chunk 'magit-blame-chunk) + (unless (eq chunk magit-blame-previous-chunk) + (run-hooks 'magit-blame-goto-chunk-hook)) + (setq magit-blame-previous-chunk chunk)))) + +(defun magit-blame-toggle-read-only () + (magit-blame-read-only-mode (if buffer-read-only 1 -1))) + +;;;; Read-Only Mode + +(define-minor-mode magit-blame-read-only-mode + "Provide keybindings for Magit-Blame mode. + +This minor-mode provides the key bindings for Magit-Blame mode, +but only when Read-Only mode is also enabled because these key +bindings would otherwise conflict badly with regular bindings. + +When both Magit-Blame mode and Read-Only mode are enabled, then +this mode gets automatically enabled too and when one of these +modes is toggled, then this mode also gets toggled automatically. + +\\{magit-blame-read-only-mode-map}") + +;;;; Kludges + +(defun magit-blame-put-keymap-before-view-mode () + "Put `magit-blame-read-only-mode' ahead of `view-mode' in `minor-mode-map-alist'." + (--when-let (assq 'magit-blame-read-only-mode + (cl-member 'view-mode minor-mode-map-alist :key #'car)) + (setq minor-mode-map-alist + (cons it (delq it minor-mode-map-alist)))) + (remove-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode)) + +(add-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode) + +;;; Process + +(defun magit-blame--run (args) + (magit-with-toplevel + (unless magit-blame-mode + (magit-blame-mode 1)) + (message "Blaming...") + (magit-blame-run-process + (or magit-buffer-refname magit-buffer-revision) + (magit-file-relative-name nil (not magit-buffer-file-name)) + (if (memq magit-blame-type '(final removal)) + (cons "--reverse" args) + args) + (list (line-number-at-pos (window-start)) + (line-number-at-pos (1- (window-end nil t))))) + (set-process-sentinel magit-this-process + 'magit-blame-process-quickstart-sentinel))) + +(defun magit-blame-run-process (revision file args &optional lines) + (let ((process (magit-parse-git-async + "blame" "--incremental" args + (and lines (list "-L" (apply #'format "%s,%s" lines))) + revision "--" file))) + (set-process-filter process 'magit-blame-process-filter) + (set-process-sentinel process 'magit-blame-process-sentinel) + (process-put process 'arguments (list revision file args)) + (setq magit-blame-cache (make-hash-table :test 'equal)) + (setq magit-blame-process process))) + +(defun magit-blame-process-quickstart-sentinel (process event) + (when (memq (process-status process) '(exit signal)) + (magit-blame-process-sentinel process event t) + (magit-blame-assert-buffer process) + (with-current-buffer (process-get process 'command-buf) + (when magit-blame-mode + (let ((default-directory (magit-toplevel))) + (apply #'magit-blame-run-process + (process-get process 'arguments))))))) + +(defun magit-blame-process-sentinel (process _event &optional quiet) + (let ((status (process-status process))) + (when (memq status '(exit signal)) + (kill-buffer (process-buffer process)) + (if (and (eq status 'exit) + (zerop (process-exit-status process))) + (unless quiet + (message "Blaming...done")) + (magit-blame-assert-buffer process) + (with-current-buffer (process-get process 'command-buf) + (if magit-blame-mode + (progn (magit-blame-mode -1) + (message "Blaming...failed")) + (message "Blaming...aborted")))) + (kill-local-variable 'magit-blame-process)))) + +(defun magit-blame-process-filter (process string) + (internal-default-process-filter process string) + (let ((buf (process-get process 'command-buf)) + (pos (process-get process 'parsed)) + (mark (process-mark process)) + type cache) + (with-current-buffer buf + (setq type magit-blame-type) + (setq cache magit-blame-cache)) + (with-current-buffer (process-buffer process) + (goto-char pos) + (while (and (< (point) mark) + (save-excursion (re-search-forward "^filename .+\n" nil t))) + (pcase-let* ((`(,chunk ,revinfo) + (magit-blame--parse-chunk type)) + (rev (oref chunk orig-rev))) + (if revinfo + (puthash rev revinfo cache) + (setq revinfo + (or (gethash rev cache) + (puthash rev (magit-blame--commit-alist rev) cache)))) + (magit-blame--make-overlays buf chunk revinfo)) + (process-put process 'parsed (point)))))) + +(defun magit-blame--parse-chunk (type) + (let (chunk revinfo) + (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) + :orig-line (string-to-number (match-string 2)) + :final-line (string-to-number (match-string 3)) + :num-lines (string-to-number (match-string 4)))) + (forward-line) + (let (done) + (while (not done) + (cond ((looking-at "^filename \\(.+\\)") + (setq done t) + (setf orig-file (magit-decode-git-path (match-string 1)))) + ((looking-at "^previous \\(.\\{40\\}\\) \\(.+\\)") + (setf prev-rev (match-string 1)) + (setf prev-file (magit-decode-git-path (match-string 2)))) + ((looking-at "^\\([^ ]+\\) \\(.+\\)") + (push (cons (match-string 1) + (match-string 2)) revinfo))) + (forward-line))) + (when (and (eq type 'removal) prev-rev) + (cl-rotatef orig-rev prev-rev) + (cl-rotatef orig-file prev-file) + (setq revinfo nil))) + (list chunk revinfo))) + +(defun magit-blame--commit-alist (rev) + (cl-mapcar 'cons + '("summary" + "author" "author-time" "author-tz" + "committer" "committer-time" "committer-tz") + (split-string (magit-rev-format "%s\v%an\v%ad\v%cn\v%cd" rev + "--date=format:%s\v%z") + "\v"))) + +(defun magit-blame-assert-buffer (process) + (unless (buffer-live-p (process-get process 'command-buf)) + (kill-process process) + (user-error "Buffer being blamed has been killed"))) + +;;; Display + +(defun magit-blame--make-overlays (buf chunk revinfo) + (with-current-buffer buf + (save-excursion + (save-restriction + (widen) + (goto-char (point-min)) + (forward-line (1- (oref chunk final-line))) + (let ((beg (point)) + (end (save-excursion + (forward-line (oref chunk num-lines)) + (point)))) + (magit-blame--remove-overlays beg end) + (magit-blame--make-margin-overlays chunk revinfo beg end) + (magit-blame--make-heading-overlay chunk revinfo beg end) + (magit-blame--make-highlight-overlay chunk beg)))))) + +(defun magit-blame--make-margin-overlays (chunk revinfo _beg end) + (save-excursion + (let ((line 0)) + (while (< (point) end) + (magit-blame--make-margin-overlay chunk revinfo line) + (forward-line) + (cl-incf line))))) + +(defun magit-blame--make-margin-overlay (chunk revinfo line) + (let* ((end (line-end-position)) + ;; If possible avoid putting this on the first character + ;; of the line to avoid a conflict with the line overlay. + (beg (min (1+ (line-beginning-position)) end)) + (ov (make-overlay beg end))) + (overlay-put ov 'magit-blame-chunk chunk) + (overlay-put ov 'magit-blame-revinfo revinfo) + (overlay-put ov 'magit-blame-margin line) + (magit-blame--update-margin-overlay ov))) + +(defun magit-blame--make-heading-overlay (chunk revinfo beg end) + (let ((ov (make-overlay beg end))) + (overlay-put ov 'magit-blame-chunk chunk) + (overlay-put ov 'magit-blame-revinfo revinfo) + (overlay-put ov 'magit-blame-heading t) + (magit-blame--update-heading-overlay ov))) + +(defun magit-blame--make-highlight-overlay (chunk beg) + (let ((ov (make-overlay beg (1+ (line-end-position))))) + (overlay-put ov 'magit-blame-chunk chunk) + (overlay-put ov 'magit-blame-highlight t) + (magit-blame--update-highlight-overlay ov))) + +(defun magit-blame--update-margin () + (setq left-margin-width (or (magit-blame--style-get 'margin-width) 0)) + (set-window-buffer (selected-window) (current-buffer))) + +(defun magit-blame--update-overlays () + (save-restriction + (widen) + (dolist (ov (overlays-in (point-min) (point-max))) + (cond ((overlay-get ov 'magit-blame-heading) + (magit-blame--update-heading-overlay ov)) + ((overlay-get ov 'magit-blame-margin) + (magit-blame--update-margin-overlay ov)) + ((overlay-get ov 'magit-blame-highlight) + (magit-blame--update-highlight-overlay ov)))))) + +(defun magit-blame--update-margin-overlay (ov) + (overlay-put + ov 'before-string + (and (magit-blame--style-get 'margin-width) + (propertize + "o" 'display + (list (list 'margin 'left-margin) + (let ((line (overlay-get ov 'magit-blame-margin)) + (format (magit-blame--style-get 'margin-format)) + (face (magit-blame--style-get 'margin-face))) + (magit-blame--format-string + ov + (or (and (atom format) + format) + (nth line format) + (car (last format))) + (or (and (not (zerop line)) + (magit-blame--style-get 'margin-body-face)) + face + 'magit-blame-margin)))))))) + +(defun magit-blame--update-heading-overlay (ov) + (overlay-put + ov 'before-string + (--if-let (magit-blame--style-get 'heading-format) + (magit-blame--format-string ov it 'magit-blame-heading) + (and (magit-blame--style-get 'show-lines) + (or (not (magit-blame--style-get 'margin-format)) + (save-excursion + (goto-char (overlay-start ov)) + ;; Special case of the special case described in + ;; `magit-blame--make-margin-overlay'. For empty + ;; lines it is not possible to show both overlays + ;; without the line being to high. + (not (= (point) (line-end-position))))) + magit-blame-separator)))) + +(defun magit-blame--update-highlight-overlay (ov) + (overlay-put ov 'font-lock-face (magit-blame--style-get 'highlight-face))) + +(defun magit-blame--format-string (ov format face) + (let* ((chunk (overlay-get ov 'magit-blame-chunk)) + (revinfo (overlay-get ov 'magit-blame-revinfo)) + (key (list format face)) + (string (cdr (assoc key revinfo)))) + (unless string + (setq string + (and format + (magit-blame--format-string-1 (oref chunk orig-rev) + revinfo format face))) + (nconc revinfo (list (cons key string)))) + string)) + +(defun magit-blame--format-string-1 (rev revinfo format face) + (let ((str + (if (equal rev "0000000000000000000000000000000000000000") + (propertize (concat (if (string-prefix-p "\s" format) "\s" "") + "Not Yet Committed" + (if (string-suffix-p "\n" format) "\n" "")) + 'font-lock-face face) + (magit--format-spec + (propertize format 'font-lock-face face) + (cl-flet* ((p0 (s f) + (propertize s 'font-lock-face + (if face + (if (listp face) + face + (list f face)) + f))) + (p1 (k f) + (p0 (cdr (assoc k revinfo)) f)) + (p2 (k1 k2 f) + (p0 (magit-blame--format-time-string + (cdr (assoc k1 revinfo)) + (cdr (assoc k2 revinfo))) + f))) + `((?H . ,(p0 rev 'magit-blame-hash)) + (?s . ,(p1 "summary" 'magit-blame-summary)) + (?a . ,(p1 "author" 'magit-blame-name)) + (?c . ,(p1 "committer" 'magit-blame-name)) + (?A . ,(p2 "author-time" "author-tz" 'magit-blame-date)) + (?C . ,(p2 "committer-time" "committer-tz" 'magit-blame-date)) + (?f . ""))))))) + (if-let ((width (and (string-suffix-p "%f" format) + (magit-blame--style-get 'margin-width)))) + (concat str + (propertize (make-string (max 0 (- width (length str))) ?\s) + 'font-lock-face face)) + str))) + +(defun magit-blame--format-separator () + (propertize + (concat (propertize "\s" 'display '(space :height (2))) + (propertize "\n" 'line-height 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) + magit-blame-time-format)) + (tz-in-second (and (string-match "%z" time-format) + (car (last (parse-time-string tz)))))) + (format-time-string time-format + (seconds-to-time (string-to-number time)) + tz-in-second))) + +(defun magit-blame--remove-overlays (&optional beg end) + (save-restriction + (widen) + (dolist (ov (overlays-in (or beg (point-min)) + (or end (point-max)))) + (when (overlay-get ov 'magit-blame-chunk) + (delete-overlay ov))))) + +(defun magit-blame-maybe-show-message () + (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))))) + (progn (set-text-properties 0 (length msg) nil msg) + (message msg)) + (message "Commit data not available yet. Still blaming."))))) + +;;; Commands + +;;;###autoload (autoload 'magit-blame-echo "magit-blame" nil t) +(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 +not turn on `read-only-mode'." + :if (lambda () + (and buffer-file-name + (or (not magit-blame-mode) + buffer-read-only))) + (interactive (list (magit-blame-arguments))) + (when magit-buffer-file-name + (user-error "Blob buffers aren't supported")) + (setq-local magit-blame--style + (assq magit-blame-echo-style magit-blame-styles)) + (setq-local magit-blame-disable-modes + (cons 'eldoc-mode magit-blame-disable-modes)) + (if (not magit-blame-mode) + (let ((magit-blame-read-only nil)) + (magit-blame--pre-blame-assert 'addition) + (magit-blame--pre-blame-setup 'addition) + (magit-blame--run args)) + (read-only-mode -1) + (magit-blame--update-overlays))) + +;;;###autoload (autoload 'magit-blame-addition "magit-blame" nil t) +(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) + (magit-blame--pre-blame-setup 'addition) + (magit-blame--run args)) + +;;;###autoload (autoload 'magit-blame-removal "magit-blame" nil t) +(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))) + (unless magit-buffer-file-name + (user-error "Only blob buffers can be blamed in reverse")) + (magit-blame--pre-blame-assert 'removal) + (magit-blame--pre-blame-setup 'removal) + (magit-blame--run args)) + +;;;###autoload (autoload 'magit-blame-reverse "magit-blame" nil t) +(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))) + (unless magit-buffer-file-name + (user-error "Only blob buffers can be blamed in reverse")) + (magit-blame--pre-blame-assert 'final) + (magit-blame--pre-blame-setup 'final) + (magit-blame--run args)) + +(defun magit-blame--pre-blame-assert (type) + (unless (magit-toplevel) + (magit--not-inside-repository-error)) + (if (and magit-blame-mode + (eq type magit-blame-type)) + (if-let ((chunk (magit-current-blame-chunk))) + (unless (oref chunk prev-rev) + (user-error "Chunk has no further history")) + (user-error "Commit data not available yet. Still blaming.")) + (unless (magit-file-relative-name nil (not magit-buffer-file-name)) + (if buffer-file-name + (user-error "Buffer isn't visiting a tracked file") + (user-error "Buffer isn't visiting a file"))))) + +(defun magit-blame--pre-blame-setup (type) + (when magit-blame-mode + (if (eq type magit-blame-type) + (let ((style magit-blame--style)) + (magit-blame-visit-other-file) + (setq-local magit-blame--style style) + (setq-local magit-blame-recursive-p t) + ;; Set window-start for the benefit of quickstart. + (redisplay)) + (magit-blame--remove-overlays))) + (setq magit-blame-type type)) + +(defun magit-blame-visit-other-file () + "Visit another blob related to the current chunk." + (interactive) + (with-slots (prev-rev prev-file orig-line) + (magit-current-blame-chunk) + (unless prev-rev + (user-error "Chunk has no further history")) + (magit-with-toplevel + (magit-find-file prev-rev prev-file)) + ;; TODO Adjust line like magit-diff-visit-file. + (goto-char (point-min)) + (forward-line (1- orig-line)))) + +(defun magit-blame-visit-file () + "Visit the blob related to the current chunk." + (interactive) + (with-slots (orig-rev orig-file orig-line) + (magit-current-blame-chunk) + (magit-with-toplevel + (magit-find-file orig-rev orig-file)) + (goto-char (point-min)) + (forward-line (1- orig-line)))) + +(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." + :if-non-nil 'magit-blame-mode + (interactive) + (magit-blame-mode -1) + (when magit-blame-recursive-p + (kill-buffer))) + +(defun magit-blame-next-chunk () + "Move to the next chunk." + (interactive) + (--if-let (next-single-char-property-change (point) 'magit-blame-chunk) + (goto-char it) + (user-error "No more chunks"))) + +(defun magit-blame-previous-chunk () + "Move to the previous chunk." + (interactive) + (--if-let (previous-single-char-property-change (point) 'magit-blame-chunk) + (goto-char it) + (user-error "No more chunks"))) + +(defun magit-blame-next-chunk-same-commit (&optional previous) + "Move to the next chunk from the same commit.\n\n(fn)" + (interactive) + (if-let ((rev (oref (magit-current-blame-chunk) orig-rev))) + (let ((pos (point)) ov) + (save-excursion + (while (and (not ov) + (not (= pos (if previous (point-min) (point-max)))) + (setq pos (funcall + (if previous + 'previous-single-char-property-change + 'next-single-char-property-change) + pos 'magit-blame-chunk))) + (--when-let (magit-blame--overlay-at pos) + (when (equal (oref (magit-blame-chunk-at pos) orig-rev) rev) + (setq ov it))))) + (if ov + (goto-char (overlay-start ov)) + (user-error "No more chunks from same commit"))) + (user-error "This chunk hasn't been blamed yet"))) + +(defun magit-blame-previous-chunk-same-commit () + "Move to the previous chunk from the same commit." + (interactive) + (magit-blame-next-chunk-same-commit 'previous-single-char-property-change)) + +(defun magit-blame-cycle-style () + "Change how blame information is visualized. +Cycle through the elements of option `magit-blame-styles'." + (interactive) + (setq magit-blame--style + (or (cadr (cl-member (car magit-blame--style) + magit-blame-styles :key #'car)) + (car magit-blame-styles))) + (magit-blame--update-margin) + (magit-blame--update-overlays)) + +(defun magit-blame-copy-hash () + "Save hash of the current chunk's commit to the kill ring. + +When the region is active, then save the region's content +instead of the hash, like `kill-ring-save' would." + (interactive) + (if (use-region-p) + (call-interactively #'copy-region-as-kill) + (kill-new (message "%s" (oref (magit-current-blame-chunk) orig-rev))))) + +;;; Popup + +;;;###autoload (autoload 'magit-blame "magit-blame" nil t) +(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" + ("b" "Show commits adding lines" magit-blame-addition) + ("r" "Show commits removing lines" magit-blame-removal) + ("f" "Show last commits that still have lines" magit-blame-reverse) + ("m" "Blame echo" magit-blame-echo) + ("q" "Quit blaming" magit-blame-quit)] + ["Refresh" + :if-non-nil magit-blame-mode + ("c" "Cycle style" magit-blame-cycle-style :transient t)]) + +(defun magit-blame-arguments () + (transient-args 'magit-blame)) + +(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+) + +(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 + +(defun magit-blame-maybe-update-revision-buffer () + (when-let ((chunk (magit-current-blame-chunk)) + (commit (oref chunk orig-rev)) + (buffer (magit-get-mode-buffer 'magit-revision-mode nil t))) + (if magit--update-revision-buffer + (setq magit--update-revision-buffer (list commit buffer)) + (setq magit--update-revision-buffer (list commit buffer)) + (run-with-idle-timer + magit-update-other-window-delay nil + (lambda () + (pcase-let ((`(,rev ,buf) magit--update-revision-buffer)) + (setq magit--update-revision-buffer nil) + (when (buffer-live-p buf) + (let ((magit-display-buffer-noselect t)) + (apply #'magit-show-commit rev + (magit-diff-arguments 'magit-revision-mode)))))))))) + +;;; _ +(provide 'magit-blame) +;;; magit-blame.el ends here diff --git a/elpa/magit-20220116.1908/magit-bookmark.el b/elpa/magit-20220116.1908/magit-bookmark.el new file mode 100644 index 00000000..b65b3ace --- /dev/null +++ b/elpa/magit-20220116.1908/magit-bookmark.el @@ -0,0 +1,209 @@ +;;; magit-bookmark.el --- bookmark support for Magit -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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 + +;; 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) +;; 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. + +;;; Commentary: + +;; Support for bookmarks for most Magit buffers. + +;;; Code: + +(require 'magit) +(require 'bookmark) + +;;; Core + +(defun magit--make-bookmark () + "Create a bookmark for the current Magit buffer. +Input values are the major-mode's `magit-bookmark-name' method, +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) + ;; `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)) + (bookmark-prop-set bookmark 'defaults (list (magit-bookmark-name))) + (dolist (var (get major-mode 'magit-bookmark-variables)) + (bookmark-prop-set bookmark var (symbol-value var))) + (bookmark-prop-set + bookmark 'magit-hidden-sections + (--keep (and (oref it hidden) + (cons (oref it type) + (if (derived-mode-p 'magit-stash-mode) + (replace-regexp-in-string + (regexp-quote magit-buffer-revision) + magit-buffer-revision-hash + (oref it value)) + (oref it value)))) + (oref magit-root-section children))) + bookmark) + (user-error "Bookmarking is not implemented for %s buffers" major-mode))) + +;;;###autoload +(defun magit--handle-bookmark (bookmark) + "Open a bookmark created by `magit--make-bookmark'. +Call the `magit-*-setup-buffer' function of the the major-mode +with the variables' values as arguments, which were recorded by +`magit--make-bookmark'. Ignore `magit-display-buffer-function'." + (let ((buffer (let ((default-directory (bookmark-get-filename bookmark)) + (mode (bookmark-prop-get bookmark 'mode)) + (magit-display-buffer-function #'identity) + (magit-display-buffer-noselect t)) + (apply (intern (format "%s-setup-buffer" + (substring (symbol-name mode) 0 -5))) + (--map (bookmark-prop-get bookmark it) + (get mode 'magit-bookmark-variables)))))) + (set-buffer buffer) ; That is the interface we have to adhere to. + (when-let ((hidden (bookmark-prop-get bookmark 'magit-hidden-sections))) + (with-current-buffer buffer + (dolist (child (oref magit-root-section children)) + (if (member (cons (oref child type) + (oref child value)) + 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 () + "Return name for bookmark to current buffer." + (format "%s%s" + (substring (symbol-name major-mode) 0 -5) + (if-let ((vars (get major-mode 'magit-bookmark-variables))) + (cl-mapcan (lambda (var) + (let ((val (symbol-value var))) + (if (and val (atom val)) + (list val) + val))) + vars) + ""))) + +;;; Diff +;;;; Diff + +(put 'magit-diff-mode 'magit-bookmark-variables + '(magit-buffer-range-hashed + magit-buffer-typearg + magit-buffer-diff-args + magit-buffer-diff-files)) + +(cl-defmethod magit-bookmark-name (&context (major-mode magit-diff-mode)) + (format "magit-diff(%s%s)" + (pcase (magit-diff-type) + (`staged "staged") + (`unstaged "unstaged") + (`committed magit-buffer-range) + (`undefined + (delq nil (list magit-buffer-typearg magit-buffer-range-hashed)))) + (if magit-buffer-diff-files + (concat " -- " (mapconcat #'identity magit-buffer-diff-files " ")) + ""))) + +;;;; Revision + +(put 'magit-revision-mode 'magit-bookmark-variables + '(magit-buffer-revision-hash + magit-buffer-diff-args + magit-buffer-diff-files)) + +(cl-defmethod magit-bookmark-name (&context (major-mode magit-revision-mode)) + (format "magit-revision(%s %s)" + (magit-rev-abbrev magit-buffer-revision) + (if magit-buffer-diff-files + (mapconcat #'identity magit-buffer-diff-files " ") + (magit-rev-format "%s" magit-buffer-revision)))) + +;;;; Stash + +(put 'magit-stash-mode 'magit-bookmark-variables + '(magit-buffer-revision-hash + magit-buffer-diff-args + magit-buffer-diff-files)) + +(cl-defmethod magit-bookmark-name (&context (major-mode magit-stash-mode)) + (format "magit-stash(%s %s)" + (magit-rev-abbrev magit-buffer-revision) + (if magit-buffer-diff-files + (mapconcat #'identity magit-buffer-diff-files " ") + (magit-rev-format "%s" magit-buffer-revision)))) + +;;; Log +;;;; Log + +(put 'magit-log-mode 'magit-bookmark-variables + '(magit-buffer-revisions + magit-buffer-log-args + magit-buffer-log-files)) + +(cl-defmethod magit-bookmark-name (&context (major-mode magit-log-mode)) + (format "magit-log(%s%s)" + (mapconcat #'identity magit-buffer-revisions " ") + (if magit-buffer-log-files + (concat " -- " (mapconcat #'identity magit-buffer-log-files " ")) + ""))) + +;;;; Cherry + +(put 'magit-cherry-mode 'magit-bookmark-variables + '(magit-buffer-refname + magit-buffer-upstream)) + +(cl-defmethod magit-bookmark-name (&context (major-mode magit-cherry-mode)) + (format "magit-cherry(%s > %s)" + magit-buffer-refname + magit-buffer-upstream)) + +;;;; Reflog + +(put 'magit-reflog-mode 'magit-bookmark-variables + '(magit-buffer-refname)) + +(cl-defmethod magit-bookmark-name (&context (major-mode magit-reflog-mode)) + (format "magit-reflog(%s)" magit-buffer-refname)) + +;;; Misc + +(put 'magit-status-mode 'magit-bookmark-variables nil) + +(put 'magit-refs-mode 'magit-bookmark-variables + '(magit-buffer-upstream + magit-buffer-arguments)) + +(put 'magit-stashes-mode 'magit-bookmark-variables nil) + +(cl-defmethod magit-bookmark-name (&context (major-mode magit-stashes-mode)) + (format "magit-states(%s)" magit-buffer-refname)) + +;;; _ +(provide 'magit-bookmark) +;;; magit-bookmark.el ends here diff --git a/elpa/magit-20220116.1908/magit-branch.el b/elpa/magit-20220116.1908/magit-branch.el new file mode 100644 index 00000000..c663eb14 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-branch.el @@ -0,0 +1,937 @@ +;;; magit-branch.el --- branch support -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements support for branches. It defines commands +;; for creating, checking out, manipulating, and configuring branches. +;; Commands defined here are mainly concerned with branches as +;; pointers, commands that deal with what a branch points at, are +;; defined elsewhere. + +;;; Code: + +(require 'magit) +(require 'magit-reset) + +;;; Options + +(defcustom magit-branch-read-upstream-first t + "Whether to read upstream before name of new branch when creating a branch. + +`nil' Read the branch name first. +`t' Read the upstream first. +`fallback' Read the upstream first, but if it turns out that the chosen + value is not a valid upstream (because it cannot be resolved + as an existing revision), then treat it as the name of the + new branch and continue by reading the upstream next." + :package-version '(magit . "2.2.0") + :group 'magit-commands + :type '(choice (const :tag "read branch name first" nil) + (const :tag "read upstream first" t) + (const :tag "read upstream first, with fallback" fallback))) + +(defcustom magit-branch-prefer-remote-upstream nil + "Whether to favor remote upstreams when creating new branches. + +When a new branch is created, then the branch, commit, or stash +at point is suggested as the default starting point of the new +branch, or if there is no such revision at point the current +branch. In either case the user may choose another starting +point. + +If the chosen starting point is a branch, then it may also be set +as the upstream of the new branch, depending on the value of the +Git variable `branch.autoSetupMerge'. By default this is done +for remote branches, but not for local branches. + +You might prefer to always use some remote branch as upstream. +If the chosen starting point is (1) a local branch, (2) whose +name matches a member of the value of this option, (3) the +upstream of that local branch is a remote branch with the same +name, and (4) that remote branch can be fast-forwarded to the +local branch, then the chosen branch is used as starting point, +but its own upstream is used as the upstream of the new branch. + +Members of this option's value are treated as branch names that +have to match exactly unless they contain a character that makes +them invalid as a branch name. Recommended characters to use +to trigger interpretation as a regexp are \"*\" and \"^\". Some +other characters which you might expect to be invalid, actually +are not, e.g. \".+$\" are all perfectly valid. More precisely, +if `git check-ref-format --branch STRING' exits with a non-zero +status, then treat STRING as a regexp. + +Assuming the chosen branch matches these conditions you would end +up with with e.g.: + + feature --upstream--> origin/master + +instead of + + feature --upstream--> master --upstream--> origin/master + +Which you prefer is a matter of personal preference. If you do +prefer the former, then you should add branches such as \"master\", +\"next\", and \"maint\" to the value of this options." + :package-version '(magit . "2.4.0") + :group 'magit-commands + :type '(repeat string)) + +(defcustom magit-branch-adjust-remote-upstream-alist nil + "Alist of upstreams to be used when branching from remote branches. + +When creating a local branch from an ephemeral branch located +on a remote, e.g. a feature or hotfix branch, then that remote +branch should usually not be used as the upstream branch, since +the push-remote already allows accessing it and having both the +upstream and the push-remote reference the same related branch +would be wasteful. Instead a branch like \"maint\" or \"master\" +should be used as the upstream. + +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 +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. + +RULE can either be a regular expression, matching branches whose +upstream should be the one specified by UPSTREAM. Or it can be +a list of the only branches that should *not* use UPSTREAM; all +other branches will. Matching is done after stripping the remote +part of the name of the branch that is being branched from. + +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\"))) + +Or if the names of all your ephemeral branches contain a slash, +at least in some repositories, then a good value could be: + + ((\"origin/master\" . \"/\")) + +Of course you can also fine-tune: + + ((\"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." + :package-version '(magit . "2.9.0") + :group 'magit-commands + :type '(repeat (cons (string :tag "Use upstream") + (choice :tag "for branches" + (regexp :tag "matching") + (repeat :tag "except" + (string :tag "branch")))))) + +(defcustom magit-branch-rename-push-target t + "Whether the push-remote setup is preserved when renaming a branch. + +The command `magit-branch-rename' renames a branch named OLD to +NEW. This option controls how much of the push-remote setup is +preserved when doing so. + +When nil, then preserve nothing and unset `branch.OLD.pushRemote'. + +When `local-only', then first set `branch.NEW.pushRemote' to the + same value as `branch.OLD.pushRemote', provided the latter is + actually set and unless the former already has another value. + +When t, then rename the branch named OLD on the remote specified + by `branch.OLD.pushRemote' to NEW, provided OLD exists on that + remote and unless NEW already exists on the remote. + +When `forge-only' and the `forge' package is available, then + behave like `t' if the remote points to a repository on a forge + (currently Github or Gitlab), otherwise like `local-only'. + +Another supported but obsolete value is `github-only'. It is a + misnomer because it now treated as an alias for `forge-only'." + :package-version '(magit . "2.90.0") + :group 'magit-commands + :type '(choice + (const :tag "Don't preserve push-remote setup" nil) + (const :tag "Preserve push-remote setup" local-only) + (const :tag "... and rename corresponding branch on remote" t) + (const :tag "... but only if remote is on a forge" forge-only))) + +(defcustom magit-branch-direct-configure t + "Whether the command `magit-branch' shows Git variables. +When set to nil, no variables are displayed by this transient +command, instead the sub-transient `magit-branch-configure' +has to be used to view and change branch related variables." + :package-version '(magit . "2.7.0") + :group 'magit-commands + :type 'boolean) + +(defcustom magit-published-branches '("origin/master") + "List of branches that are considered to be published." + :package-version '(magit . "2.13.0") + :group 'magit-commands + :type '(repeat string)) + +;;; Commands + +;;;###autoload (autoload 'magit-branch "magit" nil t) +(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 () (magit-git-version>= "2.13")))] + ["Variables" + :if (lambda () + (and magit-branch-direct-configure + (oref transient--prefix scope))) + ("d" magit-branch..description) + ("u" magit-branch..merge/remote) + ("r" magit-branch..rebase) + ("p" magit-branch..pushRemote)] + [["Checkout" + ("b" "branch/revision" magit-checkout) + ("l" "local branch" magit-branch-checkout) + (6 "o" "new orphan" magit-branch-orphan)] + ["" + ("c" "new branch" magit-branch-and-checkout) + ("s" "new spin-off" magit-branch-spinoff) + (5 "w" "new worktree" magit-worktree-checkout)] + ["Create" + ("n" "new branch" magit-branch-create) + ("S" "new spin-out" magit-branch-spinout) + (5 "W" "new worktree" magit-worktree-branch)] + ["Do" + ("C" "configure..." magit-branch-configure) + ("m" "rename" magit-branch-rename) + ("x" "reset" magit-branch-reset) + ("k" "delete" magit-branch-delete)] + ["" + (7 "h" "shelve" magit-branch-shelve) + (7 "H" "unshelve" magit-branch-unshelve)]] + (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 &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") + (magit-branch-arguments))) + (when (string-match "\\`heads/\\(.+\\)" revision) + (setq revision (match-string 1 revision))) + (magit-run-git "checkout" args revision)) + +;;;###autoload +(defun magit-branch-create (branch start-point) + "Create BRANCH at branch or revision START-POINT." + (interactive (magit-branch-read-args "Create branch")) + (magit-call-git "branch" branch start-point) + (magit-branch-maybe-adjust-upstream branch start-point) + (magit-refresh)) + +;;;###autoload +(defun magit-branch-and-checkout (branch start-point &optional args) + "Create and checkout BRANCH at branch or revision START-POINT." + (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" args "-b" branch start-point) + (magit-branch-maybe-adjust-upstream branch start-point) + (magit-refresh))) + +;;;###autoload +(defun magit-branch-or-checkout (arg &optional start-point) + "Hybrid between `magit-checkout' and `magit-branch-and-checkout'. + +Ask the user for an existing branch or revision. If the user +input actually can be resolved as a branch or revision, then +check that out, just like `magit-checkout' would. + +Otherwise create and checkout a new branch using the input as +its name. Before doing so read the starting-point for the new +branch. This is similar to what `magit-branch-and-checkout' +does." + (interactive + (let ((arg (magit-read-other-branch-or-commit "Checkout"))) + (list arg + (and (not (magit-commit-p arg)) + (magit-read-starting-point "Create and checkout branch" arg))))) + (when (string-match "\\`heads/\\(.+\\)" arg) + (setq arg (match-string 1 arg))) + (if start-point + (magit-branch-and-checkout arg start-point) + (magit-checkout arg))) + +;;;###autoload +(defun magit-branch-checkout (branch &optional start-point) + "Checkout an existing or new local branch. + +Read a branch name from the user offering all local branches and +a subset of remote branches as candidates. Omit remote branches +for which a local branch by the same name exists from the list +of candidates. The user can also enter a completely new branch +name. + +- If the user selects an existing local branch, then check that + out. + +- If the user selects a remote branch, then create and checkout + a new local branch with the same name. Configure the selected + remote branch as push target. + +- If the user enters a new branch name, then create and check + that out, after also reading the starting-point from the user. + +In the latter two cases the upstream is also set. Whether it is +set to the chosen START-POINT or something else depends on the +value of `magit-branch-adjust-remote-upstream-alist', just like +when using `magit-branch-and-checkout'." + (interactive + (let* ((current (magit-get-current-branch)) + (local (magit-list-local-branch-names)) + (remote (--filter (and (string-match "[^/]+/" it) + (not (member (substring it (match-end 0)) + (cons "HEAD" local)))) + (magit-list-remote-branch-names))) + (choices (nconc (delete current local) remote)) + (atpoint (magit-branch-at-point)) + (choice (magit-completing-read + "Checkout branch" choices + nil nil nil 'magit-revision-history + (or (car (member atpoint choices)) + (and atpoint + (car (member (and (string-match "[^/]+/" atpoint) + (substring atpoint (match-end 0))) + choices))))))) + (cond ((member choice remote) + (list (and (string-match "[^/]+/" choice) + (substring choice (match-end 0))) + choice)) + ((member choice local) + (list choice)) + (t + (list choice (magit-read-starting-point "Create" choice)))))) + (if (not start-point) + (magit-checkout branch (magit-branch-arguments)) + (when (magit-anything-modified-p t) + (user-error "Cannot checkout when there are uncommitted changes")) + (let ((magit-inhibit-refresh t)) + (magit-branch-and-checkout branch start-point)) + (when (magit-remote-branch-p start-point) + (pcase-let ((`(,remote . ,remote-branch) + (magit-split-branch-name start-point))) + (when (and (equal branch remote-branch) + (not (equal remote (magit-get "remote.pushDefault")))) + (magit-set remote "branch" branch "pushRemote")))) + (magit-refresh))) + +(defun magit-branch-maybe-adjust-upstream (branch start-point) + (--when-let + (or (and (magit-get-upstream-branch branch) + (magit-get-indirect-upstream-branch start-point)) + (and (magit-remote-branch-p start-point) + (let ((name (cdr (magit-split-branch-name start-point)))) + (-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 +(defun magit-branch-orphan (branch start-point) + "Create and checkout an orphan BRANCH with contents from revision START-POINT." + (interactive (magit-branch-read-args "Create and checkout orphan branch")) + (magit-run-git "checkout" "--orphan" branch start-point)) + +(defun magit-branch-read-args (prompt &optional default-start) + (if magit-branch-read-upstream-first + (let ((choice (magit-read-starting-point prompt nil default-start))) + (if (magit-rev-verify choice) + (list (magit-read-string-ns + (if magit-completing-read--silent-default + (format "%s (starting at `%s')" prompt choice) + "Name for new branch") + (let ((def (mapconcat #'identity + (cdr (split-string choice "/")) + "/"))) + (and (member choice (magit-list-remote-branch-names)) + (not (member def (magit-list-local-branch-names))) + def))) + choice) + (if (eq magit-branch-read-upstream-first 'fallback) + (list choice + (magit-read-starting-point prompt choice default-start)) + (user-error "Not a valid starting-point: %s" choice)))) + (let ((branch (magit-read-string-ns (concat prompt " named")))) + (list branch (magit-read-starting-point prompt branch default-start))))) + +;;;###autoload +(defun magit-branch-spinout (branch &optional from) + "Create new branch from the unpushed commits. +Like `magit-branch-spinoff' but remain on the current branch. +If there are any uncommitted changes, then behave exactly like +`magit-branch-spinoff'." + (interactive (list (magit-read-string-ns "Spin out branch") + (car (last (magit-region-values 'commit))))) + (magit--branch-spinoff branch from nil)) + +;;;###autoload +(defun magit-branch-spinoff (branch &optional from) + "Create new branch from the unpushed commits. + +Create and checkout a new branch starting at and tracking the +current branch. That branch in turn is reset to the last commit +it shares with its upstream. If the current branch has no +upstream or no unpushed commits, then the new branch is created +anyway and the previously current branch is not touched. + +This is useful to create a feature branch after work has already +began on the old branch (likely but not necessarily \"master\"). + +If the current branch is a member of the value of option +`magit-branch-prefer-remote-upstream' (which see), then the +current branch will be used as the starting point as usual, but +the upstream of the starting-point may be used as the upstream +of the new branch, instead of the starting-point itself. + +If optional FROM is non-nil, then the source branch is reset +to `FROM~', instead of to the last commit it shares with its +upstream. Interactively, FROM is only ever non-nil, if the +region selects some commits, and among those commits, FROM is +the commit that is the fewest commits ahead of the source +branch. + +The commit at the other end of the selection actually does not +matter, all commits between FROM and `HEAD' are moved to the new +branch. If FROM is not reachable from `HEAD' or is reachable +from the source branch's upstream, then an error is raised." + (interactive (list (magit-read-string-ns "Spin off branch") + (car (last (magit-region-values 'commit))))) + (magit--branch-spinoff branch from t)) + +(defun magit--branch-spinoff (branch from checkout) + (when (magit-branch-p branch) + (user-error "Cannot spin off %s. It already exists" branch)) + (when (and (not checkout) + (magit-anything-modified-p)) + (message "Staying on HEAD due to uncommitted changes") + (setq checkout t)) + (if-let ((current (magit-get-current-branch))) + (let ((tracked (magit-get-upstream-branch current)) + base) + (when from + (unless (magit-rev-ancestor-p from current) + (user-error "Cannot spin off %s. %s is not reachable from %s" + branch from current)) + (when (and tracked + (magit-rev-ancestor-p from tracked)) + (user-error "Cannot spin off %s. %s is ancestor of upstream %s" + branch from tracked))) + (let ((magit-process-raise-error t)) + (if checkout + (magit-call-git "checkout" "-b" branch current) + (magit-call-git "branch" branch current))) + (--when-let (magit-get-indirect-upstream-branch current) + (magit-call-git "branch" "--set-upstream-to" it branch)) + (when (and tracked + (setq base + (if from + (concat from "^") + (magit-git-string "merge-base" current tracked))) + (not (magit-rev-eq base current))) + (if checkout + (magit-call-git "update-ref" "-m" + (format "reset: moving to %s" base) + (concat "refs/heads/" current) base) + (magit-call-git "reset" "--hard" base)))) + (if checkout + (magit-call-git "checkout" "-b" branch) + (magit-call-git "branch" branch))) + (magit-refresh)) + +;;;###autoload +(defun magit-branch-reset (branch to &optional set-upstream) + "Reset a branch to the tip of another branch or any other commit. + +When the branch being reset is the current branch, then do a +hard reset. If there are any uncommitted changes, then the user +has to confirm the reset because those changes would be lost. + +This is useful when you have started work on a feature branch but +realize it's all crap and want to start over. + +When resetting to another branch and a prefix argument is used, +then also set the target branch as the upstream of the branch +that is being reset." + (interactive + (let* ((atpoint (magit-local-branch-at-point)) + (branch (magit-read-local-branch "Reset branch" atpoint))) + (list branch + (magit-completing-read (format "Reset %s to" branch) + (delete branch (magit-list-branch-names)) + nil nil nil 'magit-revision-history + (or (and (not (equal branch atpoint)) atpoint) + (magit-get-upstream-branch branch))) + current-prefix-arg))) + (let ((magit-inhibit-refresh t)) + (if (equal branch (magit-get-current-branch)) + (if (and (magit-anything-modified-p) + (not (yes-or-no-p + "Uncommitted changes will be lost. Proceed? "))) + (user-error "Abort") + (magit-reset-hard to)) + (magit-call-git "update-ref" + "-m" (format "reset: moving to %s" to) + (magit-git-string "rev-parse" "--symbolic-full-name" + branch) + to)) + (when (and set-upstream (magit-branch-p to)) + (magit-set-upstream-branch branch to) + (magit-branch-maybe-adjust-upstream branch to))) + (magit-refresh)) + +(defvar magit-branch-delete-never-verify nil + "Whether `magit-branch-delete' always pushes with \"--no-verify\".") + +;;;###autoload +(defun magit-branch-delete (branches &optional force) + "Delete one or multiple branches. +If the region marks multiple branches, then offer to delete +those, otherwise prompt for a single branch to be deleted, +defaulting to the branch at point." + ;; One would expect this to be a command as simple as, for example, + ;; `magit-branch-rename'; but it turns out everyone wants to squeeze + ;; a bit of extra functionality into this one, including myself. + (interactive + (let ((branches (magit-region-values 'branch t)) + (force current-prefix-arg)) + (if (> (length branches) 1) + (magit-confirm t nil "Delete %i branches" nil branches) + (setq branches + (list (magit-read-branch-prefer-other + (if force "Force delete branch" "Delete branch"))))) + (unless force + (when-let ((unmerged (-remove #'magit-branch-merged-p branches))) + (if (magit-confirm 'delete-unmerged-branch + "Delete unmerged branch %s" + "Delete %i unmerged branches" + 'noabort unmerged) + (setq force branches) + (or (setq branches (-difference branches unmerged)) + (user-error "Abort"))))) + (list branches force))) + (let* ((refs (mapcar #'magit-ref-fullname branches)) + (ambiguous (--remove it refs))) + (when ambiguous + (user-error + "%s ambiguous. Please cleanup using git directly." + (let ((len (length ambiguous))) + (cond + ((= len 1) + (format "%s is" (-first #'magit-ref-ambiguous-p branches))) + ((= len (length refs)) + (format "These %s names are" len)) + (t + (format "%s of these names are" len)))))) + (cond + ((string-match "^refs/remotes/\\([^/]+\\)" (car refs)) + (let* ((remote (match-string 1 (car refs))) + (offset (1+ (length remote)))) + (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) + (mapc 'magit-branch-unset-pushRemote branches) + (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)) + (target (magit-get-upstream-branch))) + (when (equal branch (magit-get-current-branch)) + (when (or (equal branch target) + (not target)) + (setq target (magit-main-branch))) + (pcase (if (or (equal branch target) + (not target)) + (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 (format "[c]heckout %s & delete" target) 'target) + (?a "[a]bort" 'abort))) + (`detach (unless (or (equal force '(4)) + (member branch force) + (magit-branch-merged-p branch t)) + (magit-confirm 'delete-unmerged-branch + "Delete unmerged branch %s" "" + nil (list branch))) + (magit-call-git "checkout" "--detach")) + (`target (unless (or (equal force '(4)) + (member branch force) + (magit-branch-merged-p branch target)) + (magit-confirm 'delete-unmerged-branch + "Delete unmerged branch %s" "" + nil (list branch))) + (magit-call-git "checkout" target)) + (`abort (user-error "Abort"))) + (setq force t)) + (magit-branch-maybe-delete-pr-remote branch) + (magit-branch-unset-pushRemote branch) + (magit-run-git "branch" (if force "-D" "-d") branch)))))) + +(put 'magit-branch-delete 'interactive-only t) + +(defun magit-branch-maybe-delete-pr-remote (branch) + (when-let ((remote (magit-get "branch" branch "pullRequestRemote"))) + (let* ((variable (format "remote.%s.fetch" remote)) + (refspecs (magit-get-all variable))) + (unless (member (format "+refs/heads/*:refs/remotes/%s/*" remote) + refspecs) + (let ((refspec + (if (equal (magit-get "branch" branch "pushRemote") remote) + (format "+refs/heads/%s:refs/remotes/%s/%s" + branch remote branch) + (let ((merge (magit-get "branch" branch "merge"))) + (and merge + (string-prefix-p "refs/heads/" merge) + (setq merge (substring merge 11)) + (format "+refs/heads/%s:refs/remotes/%s/%s" + merge remote merge)))))) + (when (member refspec refspecs) + (if (and (= (length refspecs) 1) + (magit-confirm 'delete-pr-remote + (format "Also delete remote %s (%s)" remote + "no pull-request branch remains") + nil t)) + (magit-call-git "remote" "rm" remote) + (magit-call-git "config" "--unset-all" variable + (format "^%s$" (regexp-quote refspec)))))))))) + +(defun magit-branch-unset-pushRemote (branch) + (magit-set nil "branch" branch "pushRemote")) + +(defun magit-delete-remote-branch-sentinel (remote refs process event) + (when (memq (process-status process) '(exit signal)) + (if (= (process-exit-status process) 1) + (if-let ((on-remote (--map (concat "refs/remotes/" remote "/" it) + (magit-remote-list-branches remote))) + (rest (--filter (and (not (member it on-remote)) + (magit-ref-exists-p it)) + refs))) + (progn + (process-put process 'inhibit-refresh t) + (magit-process-sentinel process event) + (setq magit-this-error nil) + (message "Some remote branches no longer exist. %s" + "Deleting just the local tracking refs instead...") + (dolist (ref rest) + (magit-call-git "update-ref" "-d" ref)) + (magit-refresh) + (message "Deleting local remote-tracking refs...done")) + (magit-process-sentinel process event)) + (magit-process-sentinel process event)))) + +;;;###autoload +(defun magit-branch-rename (old new &optional force) + "Rename the branch named OLD to NEW. + +With a prefix argument FORCE, rename even if a branch named NEW +already exists. + +If `branch.OLD.pushRemote' is set, then unset it. Depending on +the value of `magit-branch-rename-push-target' (which see) maybe +set `branch.NEW.pushRemote' and maybe rename the push-target on +the remote." + (interactive + (let ((branch (magit-read-local-branch "Rename branch"))) + (list branch + (magit-read-string-ns (format "Rename branch '%s' to" branch) + nil 'magit-revision-history) + current-prefix-arg))) + (when (string-match "\\`heads/\\(.+\\)" old) + (setq old (match-string 1 old))) + (when (equal old new) + (user-error "Old and new branch names are the same")) + (magit-call-git "branch" (if force "-M" "-m") old new) + (when magit-branch-rename-push-target + (let ((remote (magit-get-push-remote old)) + (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-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)) + (or (not (memq magit-branch-rename-push-target + '(forge-only github-only))) + (and (require (quote forge) nil t) + (fboundp 'forge--forge-remote-p) + (forge--forge-remote-p remote)))) + (let ((old-target (magit-get-push-branch old t)) + (new-target (magit-get-push-branch new t)) + (remote (magit-get-push-remote new))) + (when (and old-target + (not new-target) + (magit-y-or-n-p (format "Also rename %S to %S on \"%s\"" + old new remote))) + ;; Rename on (i.e. within) the remote, but only if the + ;; destination ref doesn't exist yet. If that ref already + ;; exists, then it probably is of some value and we better + ;; not touch it. Ignore what the local ref points at, + ;; i.e. if the local and the remote ref didn't point at + ;; the same commit before the rename then keep it that way. + (magit-call-git "push" "-v" remote + (format "%s:refs/heads/%s" old-target new) + (format ":refs/heads/%s" old))))))) + (magit-branch-unset-pushRemote old) + (magit-refresh)) + +;;;###autoload +(defun magit-branch-shelve (branch) + "Shelve a BRANCH. +Rename \"refs/heads/BRANCH\" to \"refs/shelved/BRANCH\", +and also rename the respective reflog file." + (interactive (list (magit-read-other-local-branch "Shelve branch"))) + (let ((old (concat "refs/heads/" branch)) + (new (concat "refs/shelved/" branch))) + (magit-git "update-ref" new old "") + (magit--rename-reflog-file old new) + (magit-branch-unset-pushRemote branch) + (magit-run-git "branch" "-D" branch))) + +;;;###autoload +(defun magit-branch-unshelve (branch) + "Unshelve a BRANCH +Rename \"refs/shelved/BRANCH\" to \"refs/heads/BRANCH\", +and also rename the respective reflog file." + (interactive + (list (magit-completing-read + "Unshelve branch" + (--map (substring it 8) + (magit-list-refnames "refs/shelved")) + nil t))) + (let ((old (concat "refs/shelved/" branch)) + (new (concat "refs/heads/" branch))) + (magit-git "update-ref" new old "") + (magit--rename-reflog-file old new) + (magit-run-git "update-ref" "-d" old))) + +(defun magit--rename-reflog-file (old new) + (let ((old (magit-git-dir (concat "logs/" old))) + (new (magit-git-dir (concat "logs/" new)))) + (when (file-exists-p old) + (make-directory (file-name-directory new) t) + (rename-file old new t)))) + +;;; Configure + +;;;###autoload (autoload 'magit-branch-configure "magit-branch" nil t) +(transient-define-prefix magit-branch-configure (branch) + "Configure a branch." + :man-page "git-branch" + [:description + (lambda () + (concat + (propertize "Configure " 'face 'transient-heading) + (propertize (oref transient--prefix scope) 'face 'magit-branch-local))) + ("d" magit-branch..description) + ("u" magit-branch..merge/remote) + ("r" magit-branch..rebase) + ("p" magit-branch..pushRemote)] + ["Configure repository defaults" + ("R" magit-pull.rebase) + ("P" magit-remote.pushDefault)] + ["Configure branch creation" + ("a m" magit-branch.autoSetupMerge) + ("a r" magit-branch.autoSetupRebase)] + (interactive + (list (or (and (not current-prefix-arg) + (not (and magit-branch-direct-configure + (eq transient-current-command 'magit-branch))) + (magit-get-current-branch)) + (magit--read-branch-scope)))) + (transient-setup 'magit-branch-configure nil nil :scope branch)) + +(defun magit--read-branch-scope (&optional obj) + (magit-read-local-branch + (if obj + (format "Set %s for branch" + (format (oref obj variable) "")) + "Configure 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 transient-current-prefix scope))) + (magit-run-git-with-editor "branch" "--edit-description" branch)) + +(add-hook 'find-file-hook 'magit-branch-description-check-buffers) + +(defun magit-branch-description-check-buffers () + (and buffer-file-name + (string-match-p "/\\(BRANCH\\|EDIT\\)_DESCRIPTION\\'" buffer-file-name))) + +(defclass magit--git-branch:upstream (magit--git-variable) + ((format :initform " %k %m %M\n %r %R"))) + +(transient-define-infix magit-branch..merge/remote () + :class 'magit--git-branch:upstream) + +(cl-defmethod transient-init-value ((obj magit--git-branch:upstream)) + (when-let ((branch (oref transient--prefix scope)) + (remote (magit-get "branch" branch "remote")) + (merge (magit-get "branch" branch "merge"))) + (oset obj value (list remote merge)))) + +(cl-defmethod transient-infix-read ((obj magit--git-branch:upstream)) + (if (oref obj value) + (oset obj value nil) + (magit-read-upstream-branch (oref transient--prefix scope) "Upstream"))) + +(cl-defmethod transient-infix-set ((obj magit--git-branch:upstream) refname) + (magit-set-upstream-branch (oref transient--prefix scope) refname) + (oset obj value + (let ((branch (oref transient--prefix scope))) + (when-let ((r (magit-get "branch" branch "remote")) + (m (magit-get "branch" branch "merge"))) + (list r m)))) + (magit-refresh)) + +(cl-defmethod transient-format ((obj magit--git-branch:upstream)) + (let ((branch (oref transient--prefix scope))) + (format-spec + (oref obj format) + `((?k . ,(transient-format-key obj)) + (?r . ,(format "branch.%s.remote" branch)) + (?m . ,(format "branch.%s.merge" branch)) + (?R . ,(transient-format-value obj #'car)) + (?M . ,(transient-format-value obj #'cadr)))))) + +(cl-defmethod transient-format-value ((obj magit--git-branch:upstream) key) + (if-let ((value (funcall key (oref obj value)))) + (propertize value 'face 'transient-argument) + (propertize "unset" 'face 'transient-inactive-argument))) + +(transient-define-infix magit-branch..rebase () + :class 'magit--git-variable:choices + :scope 'magit--read-branch-scope + :variable "branch.%s.rebase" + :fallback "pull.rebase" + :choices '("true" "false") + :default "false") + +(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) + +(transient-define-infix magit-pull.rebase () + :class 'magit--git-variable:choices + :variable "pull.rebase" + :choices '("true" "false") + :default "false") + +(transient-define-infix magit-remote.pushDefault () + :class 'magit--git-variable:choices + :variable "remote.pushDefault" + :choices 'magit-list-remotes) + +(transient-define-infix magit-branch.autoSetupMerge () + :class 'magit--git-variable:choices + :variable "branch.autoSetupMerge" + :choices '("always" "true" "false") + :default "true") + +(transient-define-infix magit-branch.autoSetupRebase () + :class 'magit--git-variable:choices + :variable "branch.autoSetupRebase" + :choices '("always" "local" "remote" "never") + :default "never") + +;;; _ +(provide 'magit-branch) +;;; magit-branch.el ends here diff --git a/elpa/magit-20220116.1908/magit-bundle.el b/elpa/magit-20220116.1908/magit-bundle.el new file mode 100644 index 00000000..8afa7ffc --- /dev/null +++ b/elpa/magit-20220116.1908/magit-bundle.el @@ -0,0 +1,135 @@ +;;; magit-bundle.el --- bundle support for Magit -*- lexical-binding: t -*- + +;; Copyright (C) 2011-2022 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 --git a/elpa/magit-20220116.1908/magit-clone.el b/elpa/magit-20220116.1908/magit-clone.el new file mode 100644 index 00000000..f2813cb8 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-clone.el @@ -0,0 +1,298 @@ +;;; magit-clone.el --- clone a repository -*- lexical-binding: t -*- + +;; Copyright (C) 2008-2022 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. + +;;; Commentary: + +;; This library implements clone commands. + +;;; Code: + +(require 'magit) + +;;; Options + +(defcustom magit-clone-set-remote-head nil + "Whether cloning creates the symbolic-ref `/HEAD'." + :package-version '(magit . "2.4.2") + :group 'magit-commands + :type 'boolean) + +(defcustom magit-clone-set-remote.pushDefault 'ask + "Whether to set the value of `remote.pushDefault' after cloning. + +If t, then set without asking. If nil, then don't set. If +`ask', then ask." + :package-version '(magit . "2.4.0") + :group 'magit-commands + :type '(choice (const :tag "set" t) + (const :tag "ask" ask) + (const :tag "don't set" nil))) + +(defcustom magit-clone-default-directory nil + "Default directory to use when `magit-clone' reads destination. +If nil (the default), then use the value of `default-directory'. +If a directory, then use that. If a function, then call that +with the remote url as only argument and use the returned value." + :package-version '(magit . "2.90.0") + :group 'magit-commands + :type '(choice (const :tag "value of default-directory") + (directory :tag "constant directory") + (function :tag "function's value"))) + +(defcustom magit-clone-always-transient nil + "Whether `magit-clone' always acts as a transient prefix command. +If nil, then a prefix argument has to be used to show the transient +popup instead of invoking the default suffix `magit-clone-regular' +directly." + :package-version '(magit . "3.0.0") + :group 'magit-commands + :type 'boolean) + +(defcustom magit-clone-name-alist + '(("\\`\\(?:github:\\|gh:\\)?\\([^:]+\\)\\'" "github.com" "github.user") + ("\\`\\(?:gitlab:\\|gl:\\)\\([^:]+\\)\\'" "gitlab.com" "gitlab.user")) + "Alist mapping repository names to repository urls. + +Each element has the form (REGEXP HOSTNAME USER). When the user +enters a name when a cloning command asks for a name or url, then +that is looked up in this list. The first element whose REGEXP +matches is used. + +The format specified by option `magit-clone-url-format' is used +to turn the name into an url, using HOSTNAME and the repository +name. If the provided name contains a slash, then that is used. +Otherwise if the name omits the owner of the repository, then the +default user specified in the matched entry is used. + +If USER contains a dot, then it is treated as a Git variable and +the value of that is used as the username. Otherwise it is used +as the username itself." + :package-version '(magit . "3.0.0") + :group 'magit-commands + :type '(repeat (list regexp + (string :tag "hostname") + (string :tag "user name or git variable")))) + +(defcustom magit-clone-url-format "git@%h:%n.git" + "Format used when turning repository names into urls. +%h is the hostname and %n is the repository name, including +the name of the owner. Also see `magit-clone-name-alist'." + :package-version '(magit . "3.0.0") + :group 'magit-commands + :type 'regexp) + +;;; Commands + +;;;###autoload (autoload 'magit-clone "magit-clone" nil t) +(transient-define-prefix magit-clone (&optional transient) + "Clone a repository." + :man-page "git-clone" + ["Fetch arguments" + ("-B" "Clone a single branch" "--single-branch") + ("-n" "Do not clone tags" "--no-tags") + ("-S" "Clones submodules" "--recurse-submodules" :level 6) + ("-l" "Do not optimize" "--no-local" :level 7)] + ["Setup arguments" + ("-o" "Set name of remote" ("-o" "--origin=")) + ("-b" "Set HEAD branch" ("-b" "--branch=")) + ("-g" "Separate git directory" "--separate-git-dir=" + transient-read-directory :level 7) + ("-t" "Use template directory" "--template=" + transient-read-existing-directory :level 6)] + ["Local sharing arguments" + ("-s" "Share objects" ("-s" "--shared" :level 7)) + ("-h" "Do not use hardlinks" "--no-hardlinks")] + ["Clone" + ("C" "regular" magit-clone-regular) + ("s" "shallow" magit-clone-shallow) + ("d" "shallow since date" magit-clone-shallow-since :level 7) + ("e" "shallow excluding" magit-clone-shallow-exclude :level 7) + ("b" "bare" magit-clone-bare) + ("m" "mirror" magit-clone-mirror)] + (interactive (list (or magit-clone-always-transient current-prefix-arg))) + (if transient + (transient-setup #'magit-clone) + (call-interactively #'magit-clone-regular))) + +;;;###autoload +(defun magit-clone-regular (repository directory args) + "Create a clone of REPOSITORY in DIRECTORY. +Then show the status buffer for the new repository." + (interactive (magit-clone-read-args)) + (magit-clone-internal repository directory args)) + +;;;###autoload +(defun magit-clone-shallow (repository directory args depth) + "Create a shallow clone of REPOSITORY in DIRECTORY. +Then show the status buffer for the new repository. +With a prefix argument read the DEPTH of the clone; +otherwise use 1." + (interactive (append (magit-clone-read-args) + (list (if current-prefix-arg + (read-number "Depth: " 1) + 1)))) + (magit-clone-internal repository directory + (cons (format "--depth=%s" depth) args))) + +;;;###autoload +(defun magit-clone-shallow-since (repository directory args date) + "Create a shallow clone of REPOSITORY in DIRECTORY. +Then show the status buffer for the new repository. +Exclude commits before DATE, which is read from the +user." + (interactive (append (magit-clone-read-args) + (list (transient-read-date "Exclude commits before: " + nil nil)))) + (magit-clone-internal repository directory + (cons (format "--shallow-since=%s" date) args))) + +;;;###autoload +(defun magit-clone-shallow-exclude (repository directory args exclude) + "Create a shallow clone of REPOSITORY in DIRECTORY. +Then show the status buffer for the new repository. +Exclude commits reachable from EXCLUDE, which is a +branch or tag read from the user." + (interactive (append (magit-clone-read-args) + (list (read-string "Exclude commits reachable from: ")))) + (magit-clone-internal repository directory + (cons (format "--shallow-exclude=%s" exclude) args))) + +;;;###autoload +(defun magit-clone-bare (repository directory args) + "Create a bare clone of REPOSITORY in DIRECTORY. +Then show the status buffer for the new repository." + (interactive (magit-clone-read-args)) + (magit-clone-internal repository directory (cons "--bare" args))) + +;;;###autoload +(defun magit-clone-mirror (repository directory args) + "Create a mirror of REPOSITORY in DIRECTORY. +Then show the status buffer for the new repository." + (interactive (magit-clone-read-args)) + (magit-clone-internal repository directory (cons "--mirror" args))) + +(defun magit-clone-internal (repository directory args) + (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))) + (list repo + (read-directory-name + "Clone to: " + (if (functionp magit-clone-default-directory) + (funcall magit-clone-default-directory repo) + magit-clone-default-directory) + nil nil + (magit-clone--url-to-name repo)) + (transient-args 'magit-clone)))) + +(defun magit-clone-read-repository () + (magit-read-char-case "Clone from " nil + (?u "[u]rl or name" + (let ((str (magit-read-string-ns "Clone from url or name"))) + (if (string-match-p "\\(://\\|@\\)" str) + str + (magit-clone--name-to-url str)))) + (?p "[p]ath" + (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 (seq-some + (pcase-lambda (`(,re ,host ,user)) + (and (string-match re name) + (let ((repo (match-string 1 name))) + (magit-clone--format-url host user repo)))) + magit-clone-name-alist) + (user-error "Not an url and no matching entry in `%s'" + 'magit-clone-name-alist))) + +(defun magit-clone--format-url (host user repo) + (format-spec + magit-clone-url-format + `((?h . ,host) + (?n . ,(if (string-match-p "/" repo) + repo + (if (string-match-p "\\." user) + (if-let ((user (magit-get user))) + (concat user "/" repo) + (user-error "Set %S or specify owner explicitly" user)) + (concat user "/" repo))))))) + +;;; _ +(provide 'magit-clone) +;;; magit-clone.el ends here diff --git a/elpa/magit-20220116.1908/magit-commit.el b/elpa/magit-20220116.1908/magit-commit.el new file mode 100644 index 00000000..c2b5a429 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-commit.el @@ -0,0 +1,705 @@ +;;; magit-commit.el --- create Git commits -*- lexical-binding: t -*- + +;; Copyright (C) 2008-2022 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. + +;;; Commentary: + +;; This library implements commands for creating Git commits. These +;; commands just initiate the commit, support for writing the commit +;; messages is implemented in `git-commit.el'. + +;;; Code: + +(require 'magit) +(require 'magit-sequence) + +(eval-when-compile (require 'epa)) ; for `epa-protocol' +(eval-when-compile (require 'epg)) + +;;; Options + +(defcustom magit-commit-ask-to-stage 'verbose + "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) + (const :tag "Ask showing diff" verbose) + (const :tag "Stage without confirmation" stage) + (const :tag "Don't ask" nil))) + +(defcustom magit-commit-show-diff t + "Whether the relevant diff is automatically shown when committing." + :package-version '(magit . "2.3.0") + :group 'magit-commands + :type 'boolean) + +(defcustom magit-commit-extend-override-date t + "Whether using `magit-commit-extend' changes the committer date." + :package-version '(magit . "2.3.0") + :group 'magit-commands + :type 'boolean) + +(defcustom magit-commit-reword-override-date t + "Whether using `magit-commit-reword' changes the committer date." + :package-version '(magit . "2.3.0") + :group 'magit-commands + :type 'boolean) + +(defcustom magit-commit-squash-confirm t + "Whether the commit targeted by squash and fixup has to be confirmed. +When non-nil then the commit at point (if any) is used as default +choice, otherwise it has to be confirmed. This option only +affects `magit-commit-squash' and `magit-commit-fixup'. The +\"instant\" variants always require confirmation because making +an error while using those is harder to recover from." + :package-version '(magit . "2.1.0") + :group 'magit-commands + :type 'boolean) + +(defcustom magit-post-commit-hook nil + "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 and then finishes by pressing +\\\\[with-editor-finish]. + +Also see `git-commit-post-finish-hook'." + :package-version '(magit . "2.90.0") + :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 + magit-commit-augment + magit-commit-instant-fixup + magit-commit-instant-squash)) + +;;; Popup + +;;;###autoload (autoload 'magit-commit "magit-commit" nil t) +(transient-define-prefix magit-commit () + "Create a new commit or replace an existing commit." + :info-manual "(magit)Initiating a Commit" + :man-page "git-commit" + ["Arguments" + ("-a" "Stage all modified and deleted files" ("-a" "--all")) + ("-e" "Allow empty commit" "--allow-empty") + ("-v" "Show diff of changes to be committed" ("-v" "--verbose")) + ("-n" "Disable hooks" ("-n" "--no-verify")) + ("-R" "Claim authorship and reset author date" "--reset-author") + (magit:--author :description "Override the author") + (7 "-D" "Override the author date" "--date=" transient-read-date) + ("-s" "Add Signed-off-by line" ("-s" "--signoff")) + (5 magit:--gpg-sign) + (magit-commit:--reuse-message)] + [["Create" + ("c" "Commit" magit-commit-create)] + ["Edit HEAD" + ("e" "Extend" magit-commit-extend) + ("w" "Reword" magit-commit-reword) + ("a" "Amend" magit-commit-amend) + (6 "n" "Reshelve" magit-commit-reshelve)] + ["Edit" + ("f" "Fixup" magit-commit-fixup) + ("s" "Squash" magit-commit-squash) + ("A" "Augment" magit-commit-augment) + (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)]] + (interactive) + (if-let ((buffer (magit-commit-message-buffer))) + (switch-to-buffer buffer) + (transient-setup 'magit-commit))) + +(defun magit-commit-arguments nil + (transient-args 'magit-commit)) + +(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-signing-key) + +(defvar magit-gpg-secret-key-hist nil) + +(defun magit-read-gpg-secret-key + (prompt &optional initial-input history predicate) + (require 'epa) + (let* ((keys (cl-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)) + +(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" + :argument "--reuse-message=" + :reader 'magit-read-reuse-message + :history-key 'magit-revision-history) + +(defun magit-read-reuse-message (prompt &optional default history) + (magit-completing-read prompt (magit-list-refnames) + nil nil nil history + (or default + (and (magit-rev-verify "ORIG_HEAD") + "ORIG_HEAD")))) + +;;; Commands + +;;;###autoload +(defun magit-commit-create (&optional args) + "Create a new commit on `HEAD'. +With a prefix argument, amend to the commit at `HEAD' instead. +\n(git commit [--amend] ARGS)" + (interactive (if current-prefix-arg + (list (cons "--amend" (magit-commit-arguments))) + (list (magit-commit-arguments)))) + (when (member "--all" args) + (setq this-command 'magit-commit-all)) + (when (setq args (magit-commit-assert args)) + (let ((default-directory (magit-toplevel))) + (magit-run-git-with-editor "commit" args)))) + +;;;###autoload +(defun magit-commit-amend (&optional args) + "Amend the last commit. +\n(git commit --amend ARGS)" + (interactive (list (magit-commit-arguments))) + (magit-commit-amend-assert) + (magit-run-git-with-editor "commit" "--amend" args)) + +;;;###autoload +(defun magit-commit-extend (&optional args override-date) + "Amend the last commit, without editing the message. + +With a prefix argument keep the committer date, otherwise change +it. The option `magit-commit-extend-override-date' can be used +to inverse the meaning of the prefix argument. \n(git commit +--amend --no-edit)" + (interactive (list (magit-commit-arguments) + (if current-prefix-arg + (not magit-commit-extend-override-date) + magit-commit-extend-override-date))) + (when (setq args (magit-commit-assert args)) + (magit-commit-amend-assert) + (let ((process-environment process-environment)) + (unless override-date + (push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment)) + (magit-run-git-with-editor "commit" "--amend" "--no-edit" args)))) + +;;;###autoload +(defun magit-commit-reword (&optional args override-date) + "Reword the last commit, ignoring staged changes. + +With a prefix argument keep the committer date, otherwise change +it. The option `magit-commit-reword-override-date' can be used +to inverse the meaning of the prefix argument. + +Non-interactively respect the optional OVERRIDE-DATE argument +and ignore the option. +\n(git commit --amend --only)" + (interactive (list (magit-commit-arguments) + (if current-prefix-arg + (not magit-commit-reword-override-date) + magit-commit-reword-override-date))) + (magit-commit-amend-assert) + (let ((process-environment process-environment)) + (unless override-date + (push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment)) + (cl-pushnew "--allow-empty" args :test #'equal) + (magit-run-git-with-editor "commit" "--amend" "--only" args))) + +;;;###autoload +(defun magit-commit-fixup (&optional commit args) + "Create a fixup commit. + +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'." + (interactive (list (magit-commit-at-point) + (magit-commit-arguments))) + (magit-commit-squash-internal "--fixup" commit args)) + +;;;###autoload +(defun magit-commit-squash (&optional commit args) + "Create a squash commit, without editing the squash message. + +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'. + +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)) + +;;;###autoload +(defun magit-commit-augment (&optional commit args) + "Create a squash commit, editing the squash message. + +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'." + (interactive (list (magit-commit-at-point) + (magit-commit-arguments))) + (magit-commit-squash-internal "--squash" commit args nil t)) + +;;;###autoload +(defun magit-commit-instant-fixup (&optional commit args) + "Create a fixup commit targeting COMMIT and instantly rebase." + (interactive (list (magit-commit-at-point) + (magit-commit-arguments))) + (magit-commit-squash-internal "--fixup" commit args t)) + +;;;###autoload +(defun magit-commit-instant-squash (&optional commit args) + "Create a squash commit targeting COMMIT and instantly rebase." + (interactive (list (magit-commit-at-point) + (magit-commit-arguments))) + (magit-commit-squash-internal "--squash" commit args t)) + +(defun magit-commit-squash-internal + (option commit &optional args rebase edit confirmed) + (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 + (format "%s isn't an ancestor of HEAD. " commit) nil + (?c "[c]reate without rebasing" (setq rebase nil)) + (?s "[s]elect other" (setq commit nil)) + (?a "[a]bort" (user-error "Quit"))))) + (when commit + (setq commit (magit-rebase-interactive-assert commit t))) + (if (and commit + (or confirmed + (not (or rebase + current-prefix-arg + magit-commit-squash-confirm)))) + (let ((magit-commit-show-diff nil)) + (push (concat option "=" commit) args) + (unless edit + (push "--no-edit" args)) + (if rebase + (magit-with-editor + (magit-call-git + "commit" "--no-gpg-sign" + (-remove-first + (apply-partially #'string-match-p "\\`--gpg-sign=") + args))) + (magit-run-git-with-editor "commit" args)) + t) ; The commit was created; used by below lambda. + (magit-log-select + (lambda (commit) + (when (and (magit-commit-squash-internal option commit args + rebase edit t) + rebase) + (magit-commit-amend-assert commit) + (magit-rebase-interactive-1 commit + (list "--autosquash" "--autostash" "--keep-empty") + "" "true" nil t))) + (format "Type %%p on a commit to %s into it," + (substring option 2)) + nil nil nil commit) + (when magit-commit-show-diff + (let ((magit-display-buffer-noselect t)) + (apply #'magit-diff-staged nil (magit-diff-arguments))))))) + +(defun magit-commit-amend-assert (&optional commit) + (--when-let (magit-list-publishing-branches commit) + (let ((m1 "This commit has already been published to ") + (m2 ".\nDo you really want to modify it")) + (magit-confirm 'amend-published + (concat m1 "%s" m2) + (concat m1 "%i public branches" m2) + nil it)))) + +(defun magit-commit-assert (args &optional strict) + (cond + ((or (magit-anything-staged-p) + (and (magit-anything-unstaged-p) + ;; ^ Everything of nothing is still nothing. + (member "--all" args)) + (and (not strict) + ;; ^ For amend variants that don't make sense otherwise. + (or (member "--amend" 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)) + (y-or-n-p "Nothing staged. Continue in-progress rebase? ")) + (setq this-command 'magit-rebase-continue) + (magit-run-git-sequencer "rebase" "--continue") + nil) + ((and (file-exists-p (magit-git-dir "MERGE_MSG")) + (not (magit-anything-unstaged-p))) + (or args (list "--"))) + ((not (magit-anything-unstaged-p)) + (user-error "Nothing staged (or unstaged)")) + (magit-commit-ask-to-stage + (when (eq magit-commit-ask-to-stage 'verbose) + (magit-diff-unstaged)) + (prog1 (when (or (eq magit-commit-ask-to-stage 'stage) + (y-or-n-p "Nothing staged. Stage and commit all unstaged changes? ")) + (magit-run-git "add" "-u" ".") + (or args (list "--"))) + (when (and (eq magit-commit-ask-to-stage 'verbose) + (derived-mode-p 'magit-diff-mode)) + (magit-mode-bury-buffer)))) + (t + (user-error "Nothing staged")))) + +(defvar magit--reshelve-history nil) + +;;;###autoload +(defun magit-commit-reshelve (date update-author &optional args) + "Change the committer date and possibly the author date of `HEAD'. + +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 ((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 update-author + "Change author and committer dates to: " + "Change committer date to: ") + (cons (format-time-string "%F %T %z") 17) + '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 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) +(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 git-absorb executable, which +is available from https://github.com/tummychow/git-absorb. +See `magit-commit-autofixup' for an alternative implementation." + ["Arguments" + ("-f" "Skip safety checks" ("-f" "--force")) + ("-v" "Display more output" ("-v" "--verbose"))] + ["Actions" + ("x" "Absorb" magit-commit-absorb)] + (interactive (if current-prefix-arg + (list 'transient nil nil) + (list 'select + (magit-get-upstream-branch) + (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")) + (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)) + (progn (magit-run-git-async "autofixup" "-vv" args commit) t) + (magit-log-select + (lambda (commit) + (with-no-warnings ; about non-interactive use + (magit-commit-autofixup 'run commit args))) + nil nil nil nil commit)))) + +(transient-define-argument magit-autofixup:--context () + :description "Diff context lines" + :class 'transient-option + :shortarg "-c" + :argument "--context=" + :reader 'transient-read-number-N0) + +(transient-define-argument magit-autofixup:--strict () + :description "Strictness" + :class 'transient-option + :shortarg "-s" + :argument "--strict=" + :reader 'transient-read-number-N0) + +;;; Pending Diff + +(defun magit-commit-diff () + (when (and git-commit-mode magit-commit-show-diff) + (when-let ((diff-buffer (magit-get-mode-buffer 'magit-diff-mode))) + ;; This window just started displaying the commit message + ;; buffer. Without this that buffer would immediately be + ;; replaced with the diff buffer. See #2632. + (unrecord-window-buffer nil diff-buffer)) + (condition-case nil + (let ((args (car (magit-diff-arguments))) + (magit-inhibit-save-previous-winconf 'unset) + (magit-display-buffer-noselect t) + (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 + (magit-diff-staged nil args)) + (magit-commit-all + (magit-diff-working-tree nil args)) + ((magit-commit-amend + magit-commit-reword + magit-rebase-reword-commit) + (magit-diff-while-amending args)) + (t (if (magit-anything-staged-p) + (magit-diff-staged nil args) + (magit-diff-while-amending args))))) + (quit)))) + +;; 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)) + +;;; Message Utilities + +(defun magit-commit-message-buffer () + (let* ((find-file-visit-truename t) ; git uses truename of COMMIT_EDITMSG + (topdir (magit-toplevel))) + (--first (equal topdir (with-current-buffer it + (and git-commit-mode (magit-toplevel)))) + (append (buffer-list (selected-frame)) + (buffer-list))))) + +(defvar magit-commit-add-log-insert-function 'magit-commit-add-log-insert + "Used by `magit-commit-add-log' to insert a single entry.") + +(defun magit-commit-add-log () + "Add a stub for the current change into the commit message buffer. +If no commit is in progress, then initiate it. Use the function +specified by variable `magit-commit-add-log-insert-function' to +actually insert the entry." + (interactive) + (pcase-let* ((hunk (and (magit-section-match 'hunk) + (magit-current-section))) + (log (magit-commit-message-buffer)) + (`(,buf ,pos) (magit-diff-visit-file--noselect))) + (unless log + (unless (magit-commit-assert nil) + (user-error "Abort")) + (magit-commit-create) + (while (not (setq log (magit-commit-message-buffer))) + (sit-for 0.01))) + (magit--with-temp-position buf pos + (funcall magit-commit-add-log-insert-function log + (magit-file-relative-name) + (and hunk (add-log-current-defun)))))) + +(defun magit-commit-add-log-insert (buffer file defun) + (with-current-buffer buffer + (undo-boundary) + (goto-char (point-max)) + (while (re-search-backward (concat "^" comment-start) nil t)) + (save-restriction + (narrow-to-region (point-min) (point)) + (cond ((re-search-backward (format "* %s\\(?: (\\([^)]+\\))\\)?: " file) + nil t) + (when (equal (match-string 1) defun) + (setq defun nil)) + (re-search-forward ": ")) + (t + (when (re-search-backward "^[\\*(].+\n" nil t) + (goto-char (match-end 0))) + (while (re-search-forward "^[^\\*\n].*\n" nil t)) + (if defun + (progn (insert (format "* %s (%s): \n" file defun)) + (setq defun nil)) + (insert (format "* %s: \n" file))) + (backward-char) + (unless (looking-at "\n[\n\\']") + (insert ?\n) + (backward-char)))) + (when defun + (forward-line) + (let ((limit (save-excursion + (and (re-search-forward "^\\*" nil t) + (point))))) + (unless (or (looking-back (format "(%s): " defun) + (line-beginning-position)) + (re-search-forward (format "^(%s): " defun) limit t)) + (while (re-search-forward "^[^\\*\n].*\n" limit t)) + (insert (format "(%s): \n" defun)) + (backward-char))))))) + +;;; _ +(provide 'magit-commit) +;;; magit-commit.el ends here diff --git a/elpa/magit-20220116.1908/magit-core.el b/elpa/magit-20220116.1908/magit-core.el new file mode 100644 index 00000000..c0873a98 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-core.el @@ -0,0 +1,133 @@ +;;; magit-core.el --- core functionality -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library requires several other libraries, so that yet other +;; libraries can just require this one, instead of having to require +;; all the other ones. In other words this separates the low-level +;; stuff from the rest. It also defines some Custom groups. + +;;; Code: + +(require 'magit-utils) +(require 'magit-section) +(require 'magit-git) +(require 'magit-mode) +(require 'magit-margin) +(require 'magit-process) +(require 'magit-transient) +(require 'magit-autorevert) + +(when (magit--libgit-available-p) + (condition-case err + (require 'magit-libgit) + (error + (setq magit-inhibit-libgit 'error) + (message "Error while loading `magit-libgit': %S" err) + (message "That is not fatal. The `libegit2' module just won't be used.")))) + +(defgroup magit nil + "Controlling Git from Emacs." + :link '(url-link "https://magit.vc") + :link '(info-link "(magit)FAQ") + :link '(info-link "(magit)") + :group 'tools) + +(defgroup magit-essentials nil + "Options that every Magit user should briefly think about. + +Each of these options falls into one or more of these categories: + +* Options that affect Magit's behavior in fundamental ways. +* Options that affect safety. +* Options that affect performance. +* Options that are of a personal nature." + :link '(info-link "(magit)Essential Settings") + :group 'magit) + +(defgroup magit-miscellaneous nil + "Miscellaneous Magit options." + :group 'magit) + +(defgroup magit-commands nil + "Options controlling behavior of certain commands." + :group 'magit) + +(defgroup magit-modes nil + "Modes used or provided by Magit." + :group 'magit) + +(defgroup magit-buffers nil + "Options concerning Magit buffers." + :link '(info-link "(magit)Modes and Buffers") + :group 'magit) + +(defgroup magit-refresh nil + "Options controlling how Magit buffers are refreshed." + :link '(info-link "(magit)Automatic Refreshing of Magit Buffers") + :group 'magit + :group 'magit-buffers) + +(defgroup magit-faces nil + "Faces used by Magit." + :group 'magit + :group 'faces) + +(custom-add-to-group 'magit-faces 'diff-refine-added 'custom-face) +(custom-add-to-group 'magit-faces 'diff-refine-removed 'custom-face) + +(defgroup magit-extensions nil + "Extensions to Magit." + :group 'magit) + +(custom-add-to-group 'magit-modes 'git-commit 'custom-group) +(custom-add-to-group 'magit-faces 'git-commit-faces 'custom-group) +(custom-add-to-group 'magit-modes 'git-rebase 'custom-group) +(custom-add-to-group 'magit-faces 'git-rebase-faces 'custom-group) +(custom-add-to-group 'magit 'magit-section 'custom-group) +(custom-add-to-group 'magit-faces 'magit-section-faces 'custom-group) +(custom-add-to-group 'magit-process 'with-editor 'custom-group) + +(defgroup magit-related nil + "Options that are relevant to Magit but that are defined elsewhere." + :link '(custom-group-link vc) + :link '(custom-group-link smerge) + :link '(custom-group-link ediff) + :link '(custom-group-link auto-revert) + :group 'magit + :group 'magit-extensions + :group 'magit-essentials) + +(custom-add-to-group 'magit-related 'auto-revert-check-vc-info 'custom-variable) +(custom-add-to-group 'magit-auto-revert 'auto-revert-check-vc-info 'custom-variable) + +(custom-add-to-group 'magit-related 'ediff-window-setup-function 'custom-variable) +(custom-add-to-group 'magit-related 'smerge-refine-ignore-whitespace 'custom-variable) +(custom-add-to-group 'magit-related 'vc-follow-symlinks 'custom-variable) + +;;; _ +(provide 'magit-core) +;;; magit-core.el ends here diff --git a/elpa/magit-20220116.1908/magit-diff.el b/elpa/magit-20220116.1908/magit-diff.el new file mode 100644 index 00000000..b38c17ad --- /dev/null +++ b/elpa/magit-20220116.1908/magit-diff.el @@ -0,0 +1,3400 @@ +;;; magit-diff.el --- inspect Git diffs -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements support for looking at Git diffs and +;; commits. + +;;; Code: + +(require 'magit-core) +(require 'git-commit) + +(eval-when-compile (require 'ansi-color)) +(require 'diff-mode) +(require 'image) +(require 'smerge-mode) + +;; For `magit-diff-popup' +(declare-function magit-stash-show "magit-stash" (stash &optional args files)) +;; For `magit-diff-visit-file' +(declare-function dired-jump "dired" ; dired-x before 27.1 + (&optional other-window file-name)) +(declare-function magit-find-file-noselect "magit-files" (rev file)) +(declare-function magit-status-setup-buffer "magit-status" (&optional directory)) +;; For `magit-diff-while-committing' +(declare-function magit-commit-message-buffer "magit-commit" ()) +;; For `magit-insert-revision-gravatar' +(defvar gravatar-size) +;; For `magit-show-commit' and `magit-diff-show-or-scroll' +(declare-function magit-current-blame-chunk "magit-blame" (&optional type noerror)) +(declare-function magit-blame-mode "magit-blame" (&optional arg)) +(defvar magit-blame-mode) +;; For `magit-diff-show-or-scroll' +(declare-function git-rebase-current-line "git-rebase" ()) +;; For `magit-diff-unmerged' +(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") + +(eval-when-compile + (cl-pushnew 'orig-rev eieio--known-slot-names) + (cl-pushnew 'action-type eieio--known-slot-names) + (cl-pushnew 'target eieio--known-slot-names)) + +;;; 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 + "Hook run after entering Magit-Diff mode." + :group 'magit-diff + :type 'hook) + +(defcustom magit-diff-sections-hook + '(magit-insert-diff + magit-insert-xref-buttons) + "Hook run to insert sections into a `magit-diff-mode' buffer." + :package-version '(magit . "2.3.0") + :group 'magit-diff + :type 'hook) + +(defcustom magit-diff-expansion-threshold 60 + "After how many seconds not to expand anymore diffs. + +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. + +The hook function `magit-diff-expansion-threshold' has to be a +member of `magit-section-set-visibility-hook' for this option +to have any effect." + :package-version '(magit . "2.9.0") + :group 'magit-diff + :type 'float) + +(defcustom magit-diff-highlight-hunk-body t + "Whether to highlight bodies of selected hunk sections. +This only has an effect if `magit-diff-highlight' is a +member of `magit-section-highlight-hook', which see." + :package-version '(magit . "2.1.0") + :group 'magit-diff + :type 'boolean) + +(defcustom magit-diff-highlight-hunk-region-functions + '(magit-diff-highlight-hunk-region-dim-outside + magit-diff-highlight-hunk-region-using-overlays) + "The functions used to highlight the hunk-internal region. + +`magit-diff-highlight-hunk-region-dim-outside' overlays the outside +of the hunk internal selection with a face that causes the added and +removed lines to have the same background color as context lines. +This function should not be removed from the value of this option. + +`magit-diff-highlight-hunk-region-using-overlays' and +`magit-diff-highlight-hunk-region-using-underline' emphasize the +region by placing delimiting horizontal lines before and after it. +The underline variant was implemented because Eli said that is +how we should do it. However the overlay variant actually works +better. Also see https://github.com/magit/magit/issues/2758. + +Instead of, or in addition to, using delimiting horizontal lines, +to emphasize the boundaries, you may which to emphasize the text +itself, using `magit-diff-highlight-hunk-region-using-face'. + +In terminal frames it's not possible to draw lines as the overlay +and underline variants normally do, so there they fall back to +calling the face function instead." + :package-version '(magit . "2.9.0") + :set-after '(magit-diff-show-lines-boundaries) + :group 'magit-diff + :type 'hook + :options '(magit-diff-highlight-hunk-region-dim-outside + magit-diff-highlight-hunk-region-using-underline + magit-diff-highlight-hunk-region-using-overlays + magit-diff-highlight-hunk-region-using-face)) + +(defcustom magit-diff-unmarked-lines-keep-foreground t + "Whether `magit-diff-highlight-hunk-region-dim-outside' preserves foreground. +When this is set to nil, then that function only adjusts the +foreground color but added and removed lines outside the region +keep their distinct foreground colors." + :package-version '(magit . "2.9.0") + :group 'magit-diff + :type 'boolean) + +(defcustom magit-diff-refine-hunk nil + "Whether to show word-granularity differences within diff hunks. + +nil Never show fine differences. +t Show fine differences for the current diff hunk only. +`all' Show fine differences for all displayed diff hunks." + :group 'magit-diff + :safe (lambda (val) (memq val '(nil t all))) + :type '(choice (const :tag "Never" nil) + (const :tag "Current" t) + (const :tag "All" all))) + +(defcustom magit-diff-refine-ignore-whitespace smerge-refine-ignore-whitespace + "Whether to ignore whitespace changes in word-granularity differences." + :package-version '(magit . "3.0.0") + :set-after '(smerge-refine-ignore-whitespace) + :group 'magit-diff + :safe 'booleanp + :type 'boolean) + +(put 'magit-diff-refine-hunk 'permanent-local t) + +(defcustom magit-diff-adjust-tab-width nil + "Whether to adjust the width of tabs in diffs. + +Determining the correct width can be expensive if it requires +opening large and/or many files, so the widths are cached in +the variable `magit-diff--tab-width-cache'. Set that to nil +to invalidate the cache. + +nil Never adjust tab width. Use `tab-width's value from + the Magit buffer itself instead. + +t If the corresponding file-visiting buffer exits, then + use `tab-width's value from that buffer. Doing this is + cheap, so this value is used even if a corresponding + cache entry exists. + +`always' If there is no such buffer, then temporarily visit the + file to determine the value. + +NUMBER Like `always', but don't visit files larger than NUMBER + bytes." + :package-version '(magit . "2.12.0") + :group 'magit-diff + :type '(choice (const :tag "Never" nil) + (const :tag "If file-visiting buffer exists" t) + (integer :tag "If file isn't larger than N bytes") + (const :tag "Always" always))) + +(defcustom magit-diff-paint-whitespace t + "Specify where to highlight whitespace errors. + +nil Never highlight whitespace errors. +t Highlight whitespace errors everywhere. +`uncommitted' Only highlight whitespace errors in diffs + showing uncommitted changes. + +For backward compatibility `status' is treated as a synonym +for `uncommitted'. + +The option `magit-diff-paint-whitespace-lines' controls for +what lines (added/remove/context) errors are highlighted. + +The options `magit-diff-highlight-trailing' and +`magit-diff-highlight-indentation' control what kind of +whitespace errors are highlighted." + :group 'magit-diff + :safe (lambda (val) (memq val '(t nil uncommitted status))) + :type '(choice (const :tag "In all diffs" t) + (const :tag "Only in uncommitted changes" uncommitted) + (const :tag "Never" nil))) + +(defcustom magit-diff-paint-whitespace-lines t + "Specify in what kind of lines to highlight whitespace errors. + +t Highlight only in added lines. +`both' Highlight in added and removed lines. +`all' Highlight in added, removed and context lines." + :package-version '(magit . "3.0.0") + :group 'magit-diff + :safe (lambda (val) (memq val '(t both all))) + :type '(choice (const :tag "in added lines" t) + (const :tag "in added and removed lines" both) + (const :tag "in added, removed and context lines" all))) + +(defcustom magit-diff-highlight-trailing t + "Whether to highlight whitespace at the end of a line in diffs. +Used only when `magit-diff-paint-whitespace' is non-nil." + :group 'magit-diff + :safe 'booleanp + :type 'boolean) + +(defcustom magit-diff-highlight-indentation nil + "Highlight the \"wrong\" indentation style. +Used only when `magit-diff-paint-whitespace' is non-nil. + +The value is an alist of the form ((REGEXP . INDENT)...). The +path to the current repository is matched against each element +in reverse order. Therefore if a REGEXP matches, then earlier +elements are not tried. + +If the used INDENT is `tabs', highlight indentation with tabs. +If INDENT is an integer, highlight indentation with at least +that many spaces. Otherwise, highlight neither." + :group 'magit-diff + :type `(repeat (cons (string :tag "Directory regexp") + (choice (const :tag "Tabs" tabs) + (integer :tag "Spaces" :value ,tab-width) + (const :tag "Neither" nil))))) + +(defcustom magit-diff-hide-trailing-cr-characters + (and (memq system-type '(ms-dos windows-nt)) t) + "Whether to hide ^M characters at the end of a line in diffs." + :package-version '(magit . "2.6.0") + :group 'magit-diff + :type 'boolean) + +(defcustom magit-diff-highlight-keywords t + "Whether to highlight bracketed keywords in commit messages." + :package-version '(magit . "2.12.0") + :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 + "Whether `magit-diff-buffer-file' uses a dedicated buffer." + :package-version '(magit . "2.7.0") + :group 'magit-commands + :group 'magit-diff + :type 'boolean) + +;;;; Revision Mode + +(defgroup magit-revision nil + "Inspect and manipulate Git commits." + :link '(info-link "(magit)Revision Buffer") + :group 'magit-modes) + +(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 + goto-address-mode)) + +(defcustom magit-revision-sections-hook + '(magit-insert-revision-tag + magit-insert-revision-headers + magit-insert-revision-message + magit-insert-revision-notes + magit-insert-revision-diff + magit-insert-xref-buttons) + "Hook run to insert sections into a `magit-revision-mode' buffer." + :package-version '(magit . "2.3.0") + :group 'magit-revision + :type 'hook) + +(defcustom magit-revision-headers-format "\ +Author: %aN <%aE> +AuthorDate: %ad +Commit: %cN <%cE> +CommitDate: %cd +" + "Format string used to insert headers in revision buffers. + +All headers in revision buffers are inserted by the section +inserter `magit-insert-revision-headers'. Some of the headers +are created by calling `git show --format=FORMAT' where FORMAT +is the format specified here. Other headers are hard coded or +subject to option `magit-revision-insert-related-refs'." + :package-version '(magit . "2.3.0") + :group 'magit-revision + :type 'string) + +(defcustom magit-revision-insert-related-refs t + "Whether to show related branches in revision buffers + +`nil' Don't show any related branches. +`t' Show related local branches. +`all' Show related local and remote branches. +`mixed' Show all containing branches and local merged branches." + :package-version '(magit . "2.1.0") + :group 'magit-revision + :type '(choice (const :tag "don't" nil) + (const :tag "local only" t) + (const :tag "all related" all) + (const :tag "all containing, local merged" mixed))) + +(defcustom magit-revision-use-hash-sections 'quicker + "Whether to turn hashes inside the commit message into sections. + +If non-nil, then hashes inside the commit message are turned into +`commit' sections. There is a trade off to be made between +performance and reliability: + +- `slow' calls git for every word to be absolutely sure. +- `quick' skips words less than seven characters long. +- `quicker' additionally skips words that don't contain a number. +- `quickest' uses all words that are at least seven characters + long and which contain at least one number as well as at least + one letter. + +If nil, then no hashes are turned into sections, but you can +still visit the commit at point using \"RET\"." + :package-version '(magit . "2.12.0") + :group 'magit-revision + :type '(choice (const :tag "Use sections, quickest" quickest) + (const :tag "Use sections, quicker" quicker) + (const :tag "Use sections, quick" quick) + (const :tag "Use sections, slow" slow) + (const :tag "Don't use sections" nil))) + +(defcustom magit-revision-show-gravatars nil + "Whether to show gravatar images in revision buffers. + +If nil, then don't insert any gravatar images. If t, then insert +both images. If `author' or `committer', then insert only the +respective image. + +If you have customized the option `magit-revision-header-format' +and want to insert the images then you might also have to specify +where to do so. In that case the value has to be a cons-cell of +two regular expressions. The car specifies where to insert the +author's image. The top half of the image is inserted right +after the matched text, the bottom half on the next line in the +same column. The cdr specifies where to insert the committer's +image, accordingly. Either the car or the cdr may be nil." + :package-version '(magit . "2.3.0") + :group 'magit-revision + :type '(choice (const :tag "Don't show gravatars" nil) + (const :tag "Show gravatars" t) + (const :tag "Show author gravatar" author) + (const :tag "Show committer gravatar" committer) + (cons :tag "Show gravatars using custom pattern." + (regexp :tag "Author regexp" "^Author: ") + (regexp :tag "Committer regexp" "^Commit: ")))) + +(defcustom magit-revision-use-gravatar-kludge nil + "Whether to work around a bug which affects display of gravatars. + +Gravatar images are spliced into two halves which are then +displayed on separate lines. On OS X the splicing has a bug in +some Emacs builds, which causes the top and bottom halves to be +interchanged. Enabling this option works around this issue by +interchanging the halves once more, which cancels out the effect +of the bug. + +See https://github.com/magit/magit/issues/2265 +and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=7847. + +Starting with Emacs 26.1 this kludge should not be required for +any build." + :package-version '(magit . "2.3.0") + :group 'magit-revision + :type 'boolean) + +(defcustom magit-revision-fill-summary-line nil + "Whether to fill excessively long summary lines. + +If this is an integer, then the summary line is filled if it is +longer than either the limit specified here or `window-width'. + +You may want to only set this locally in \".dir-locals-2.el\" for +repositories known to contain bad commit messages. + +The body of the message is left alone because (a) most people who +write excessively long summary lines usually don't add a body and +(b) even people who have the decency to wrap their lines may have +a good reason to include a long line in the body sometimes." + :package-version '(magit . "2.90.0") + :group 'magit-revision + :type '(choice (const :tag "Don't fill" nil) + (integer :tag "Fill if longer than"))) + +(defcustom magit-revision-filter-files-on-follow nil + "Whether to honor file filter if log arguments include --follow. + +When a commit is displayed from a log buffer, the resulting +revision buffer usually shares the log's file arguments, +restricting the diff to those files. However, there's a +complication when the log arguments include --follow: if the log +follows a file across a rename event, keeping the file +restriction would mean showing an empty diff in revision buffers +for commits before the rename event. + +When this option is nil, the revision buffer ignores the log's +filter if the log arguments include --follow. If non-nil, the +log's file filter is always honored." + :package-version '(magit . "3.0.0") + :group 'magit-revision + :type 'boolean) + +;;;; Visit Commands + +(defcustom magit-diff-visit-previous-blob t + "Whether `magit-diff-visit-file' may visit the previous blob. + +When this is t and point is on a removed line in a diff for a +committed change, then `magit-diff-visit-file' visits the blob +from the last revision which still had that line. + +Currently this is only supported for committed changes, for +staged and unstaged changes `magit-diff-visit-file' always +visits the file in the working tree." + :package-version '(magit . "2.9.0") + :group 'magit-diff + :type 'boolean) + +(defcustom magit-diff-visit-avoid-head-blob nil + "Whether `magit-diff-visit-file' avoids visiting a blob from `HEAD'. + +By default `magit-diff-visit-file' always visits the blob that +added the current line, while `magit-diff-visit-worktree-file' +visits the respective file in the working tree. For the `HEAD' +commit, the former command used to visit the worktree file too, +but that made it impossible to visit a blob from `HEAD'. + +When point is on a removed line and that change has not been +committed yet, then `magit-diff-visit-file' now visits the last +blob that still had that line, which is a blob from `HEAD'. +Previously this function used to visit the worktree file not +only for added lines but also for such removed lines. + +If you prefer the old behaviors, then set this to t." + :package-version '(magit . "3.0.0") + :group 'magit-diff + :type 'boolean) + +;;; Faces + +(defface magit-diff-file-heading + `((t ,@(and (>= emacs-major-version 27) '(:extend t)) + :weight bold)) + "Face for diff file headings." + :group 'magit-faces) + +(defface magit-diff-file-heading-highlight + `((t ,@(and (>= emacs-major-version 27) '(:extend t)) + :inherit magit-section-highlight)) + "Face for current diff file headings." + :group 'magit-faces) + +(defface magit-diff-file-heading-selection + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :inherit magit-diff-file-heading-highlight + :foreground "salmon4") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :inherit magit-diff-file-heading-highlight + :foreground "LightSalmon3")) + "Face for selected diff file headings." + :group 'magit-faces) + +(defface magit-diff-hunk-heading + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "grey80" + :foreground "grey30") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "grey25" + :foreground "grey70")) + "Face for diff hunk headings." + :group 'magit-faces) + +(defface magit-diff-hunk-heading-highlight + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "grey75" + :foreground "grey30") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "grey35" + :foreground "grey70")) + "Face for current diff hunk headings." + :group 'magit-faces) + +(defface magit-diff-hunk-heading-selection + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :inherit magit-diff-hunk-heading-highlight + :foreground "salmon4") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :inherit magit-diff-hunk-heading-highlight + :foreground "LightSalmon3")) + "Face for selected diff hunk headings." + :group 'magit-faces) + +(defface magit-diff-hunk-region + `((t :inherit bold + ,@(and (>= emacs-major-version 27) + (list :extend (ignore-errors (face-attribute 'region :extend)))))) + "Face used by `magit-diff-highlight-hunk-region-using-face'. + +This face is overlaid over text that uses other hunk faces, +and those normally set the foreground and background colors. +The `:foreground' and especially the `:background' properties +should be avoided here. Setting the latter would cause the +loss of information. Good properties to set here are `:weight' +and `:slant'." + :group 'magit-faces) + +(defface magit-diff-revision-summary + '((t :inherit magit-diff-hunk-heading)) + "Face for commit message summaries." + :group 'magit-faces) + +(defface magit-diff-revision-summary-highlight + '((t :inherit magit-diff-hunk-heading-highlight)) + "Face for highlighted commit message summaries." + :group 'magit-faces) + +(defface magit-diff-lines-heading + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :inherit magit-diff-hunk-heading-highlight + :background "LightSalmon3") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :inherit magit-diff-hunk-heading-highlight + :foreground "grey80" + :background "salmon4")) + "Face for diff hunk heading when lines are marked." + :group 'magit-faces) + +(defface magit-diff-lines-boundary + `((t ,@(and (>= emacs-major-version 27) '(:extend t)) ; !important + :inherit magit-diff-lines-heading)) + "Face for boundary of marked lines in diff hunk." + :group 'magit-faces) + +(defface magit-diff-conflict-heading + '((t :inherit magit-diff-hunk-heading)) + "Face for conflict markers." + :group 'magit-faces) + +(defface magit-diff-added + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "#ddffdd" + :foreground "#22aa22") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "#335533" + :foreground "#ddffdd")) + "Face for lines in a diff that have been added." + :group 'magit-faces) + +(defface magit-diff-removed + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "#ffdddd" + :foreground "#aa2222") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "#553333" + :foreground "#ffdddd")) + "Face for lines in a diff that have been removed." + :group 'magit-faces) + +(defface magit-diff-our + '((t :inherit magit-diff-removed)) + "Face for lines in a diff for our side in a conflict." + :group 'magit-faces) + +(defface magit-diff-base + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "#ffffcc" + :foreground "#aaaa11") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "#555522" + :foreground "#ffffcc")) + "Face for lines in a diff for the base side in a conflict." + :group 'magit-faces) + +(defface magit-diff-their + '((t :inherit magit-diff-added)) + "Face for lines in a diff for their side in a conflict." + :group 'magit-faces) + +(defface magit-diff-context + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :foreground "grey50") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :foreground "grey70")) + "Face for lines in a diff that are unchanged." + :group 'magit-faces) + +(defface magit-diff-added-highlight + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "#cceecc" + :foreground "#22aa22") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "#336633" + :foreground "#cceecc")) + "Face for lines in a diff that have been added." + :group 'magit-faces) + +(defface magit-diff-removed-highlight + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "#eecccc" + :foreground "#aa2222") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "#663333" + :foreground "#eecccc")) + "Face for lines in a diff that have been removed." + :group 'magit-faces) + +(defface magit-diff-our-highlight + '((t :inherit magit-diff-removed-highlight)) + "Face for lines in a diff for our side in a conflict." + :group 'magit-faces) + +(defface magit-diff-base-highlight + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "#eeeebb" + :foreground "#aaaa11") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "#666622" + :foreground "#eeeebb")) + "Face for lines in a diff for the base side in a conflict." + :group 'magit-faces) + +(defface magit-diff-their-highlight + '((t :inherit magit-diff-added-highlight)) + "Face for lines in a diff for their side in a conflict." + :group 'magit-faces) + +(defface magit-diff-context-highlight + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "grey95" + :foreground "grey50") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "grey20" + :foreground "grey70")) + "Face for lines in the current context in a diff." + :group 'magit-faces) + +(defface magit-diff-whitespace-warning + '((t :inherit trailing-whitespace)) + "Face for highlighting whitespace errors added lines." + :group 'magit-faces) + +(defface magit-diffstat-added + '((((class color) (background light)) :foreground "#22aa22") + (((class color) (background dark)) :foreground "#448844")) + "Face for plus sign in diffstat." + :group 'magit-faces) + +(defface magit-diffstat-removed + '((((class color) (background light)) :foreground "#aa2222") + (((class color) (background dark)) :foreground "#aa4444")) + "Face for minus sign in diffstat." + :group 'magit-faces) + +;;; Arguments +;;;; Prefix Classes + +(defclass magit-diff-prefix (transient-prefix) + ((history-key :initform 'magit-diff) + (major-mode :initform 'magit-diff-mode))) + +(defclass magit-diff-refresh-prefix (magit-diff-prefix) + ((history-key :initform 'magit-diff) + (major-mode :initform nil))) + +;;;; Prefix Methods + +(cl-defmethod transient-init-value ((obj magit-diff-prefix)) + (pcase-let ((`(,args ,files) + (magit-diff--get-value 'magit-diff-mode + magit-prefix-use-buffer-arguments))) + (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)))) + +(cl-defmethod transient-init-value ((obj magit-diff-refresh-prefix)) + (oset obj value (if magit-buffer-diff-files + `(("--" ,@magit-buffer-diff-files) + ,magit-buffer-diff-args) + magit-buffer-diff-args))) + +(cl-defmethod transient-set-value ((obj magit-diff-prefix)) + (magit-diff--set-value obj)) + +(cl-defmethod transient-save-value ((obj magit-diff-prefix)) + (magit-diff--set-value obj 'save)) + +;;;; Argument Access + +(defun magit-diff-arguments (&optional mode) + "Return the current diff arguments." + (if (memq transient-current-command '(magit-diff magit-diff-refresh)) + (pcase-let ((`(,args ,alist) + (-separate #'atom (transient-get-value)))) + (list args (cdr (assoc "--" alist)))) + (magit-diff--get-value (or mode 'magit-diff-mode)))) + +(defun magit-diff--get-value (mode &optional use-buffer-args) + (unless use-buffer-args + (setq use-buffer-args magit-direct-use-buffer-arguments)) + (let (args files) + (cond + ((and (memq use-buffer-args '(always selected current)) + (eq major-mode mode)) + (setq args magit-buffer-diff-args) + (setq files magit-buffer-diff-files)) + ((and (memq use-buffer-args '(always selected)) + (when-let ((buffer (magit-get-mode-buffer + mode nil + (eq use-buffer-args 'selected)))) + (setq args (buffer-local-value 'magit-buffer-diff-args buffer)) + (setq files (buffer-local-value 'magit-buffer-diff-files buffer)) + t))) + ((plist-member (symbol-plist mode) 'magit-diff-current-arguments) + (setq args (get mode 'magit-diff-current-arguments))) + ((when-let ((elt (assq (intern (format "magit-diff:%s" mode)) + transient-values))) + (setq args (cdr elt)) + t)) + (t + (setq args (get mode 'magit-diff-default-arguments)))) + (list args files))) + +(defun magit-diff--set-value (obj &optional save) + (pcase-let* ((obj (oref obj prototype)) + (mode (or (oref obj major-mode) major-mode)) + (key (intern (format "magit-diff:%s" mode))) + (`(,args ,alist) + (-separate #'atom (transient-get-value))) + (files (cdr (assoc "--" alist)))) + (put mode 'magit-diff-current-arguments args) + (when save + (setf (alist-get key transient-values) args) + (transient-save-values)) + (transient--history-push obj) + (setq magit-buffer-diff-args args) + (setq magit-buffer-diff-files files) + (magit-refresh))) + +;;; Section Classes + +(defclass magit-file-section (magit-section) + ((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) + ((keymap :initform 'magit-hunk-section-map) + (refined :initform nil) + (combined :initform nil) + (from-range :initform nil) + (from-ranges :initform nil) + (to-range :initform nil) + (about :initform nil))) + +(setf (alist-get 'hunk magit--section-type-alist) 'magit-hunk-section) +(setf (alist-get 'module magit--section-type-alist) 'magit-module-section) +(setf (alist-get 'file magit--section-type-alist) 'magit-file-section) + +;;; Commands +;;;; Prefix Commands + +;;;###autoload (autoload 'magit-diff "magit-diff" nil t) +(transient-define-prefix magit-diff () + "Show changes between different versions." + :man-page "git-diff" + :class 'magit-diff-prefix + ["Limit arguments" + (magit:--) + (magit-diff:--ignore-submodules) + ("-b" "Ignore whitespace changes" ("-b" "--ignore-space-change")) + ("-w" "Ignore all whitespace" ("-w" "--ignore-all-space")) + (5 "-D" "Omit preimage for deletes" ("-D" "--irreversible-delete"))] + ["Context arguments" + (magit-diff:-U) + ("-W" "Show surrounding functions" ("-W" "--function-context"))] + ["Tune arguments" + (magit-diff:--diff-algorithm) + (magit-diff:-M) + (magit-diff:-C) + ("-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" + [("d" "Dwim" magit-diff-dwim) + ("r" "Diff range" magit-diff-range) + ("p" "Diff paths" magit-diff-paths)] + [("u" "Diff unstaged" magit-diff-unstaged) + ("s" "Diff staged" magit-diff-staged) + ("w" "Diff worktree" magit-diff-working-tree)] + [("c" "Show commit" magit-show-commit) + ("t" "Show stash" magit-stash-show)]]) + +;;;###autoload (autoload 'magit-diff-refresh "magit-diff" nil t) +(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 + ["Limit arguments" + (magit:--) + (magit-diff:--ignore-submodules) + ("-b" "Ignore whitespace changes" ("-b" "--ignore-space-change")) + ("-w" "Ignore all whitespace" ("-w" "--ignore-all-space")) + (5 "-D" "Omit preimage for deletes" ("-D" "--irreversible-delete"))] + ["Context arguments" + (magit-diff:-U) + ("-W" "Show surrounding functions" ("-W" "--function-context"))] + ["Tune arguments" + (magit-diff:--diff-algorithm) + (magit-diff:-M) + (magit-diff:-C) + ("-x" "Disallow external diff drivers" "--no-ext-diff") + ("-s" "Show stats" "--stat" + :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" + ("g" "buffer" magit-diff-refresh) + ("s" "buffer and set defaults" transient-set :transient nil) + ("w" "buffer and save defaults" transient-save :transient nil)] + ["Toggle" + ("t" "hunk refinement" magit-diff-toggle-refine-hunk) + ("F" "file filter" magit-diff-toggle-file-filter) + ("b" "buffer lock" magit-toggle-buffer-lock + :if-mode (magit-diff-mode magit-revision-mode magit-stash-mode))] + [:if-mode magit-diff-mode + :description "Do" + ("r" "switch range type" magit-diff-switch-range-type) + ("f" "flip revisions" magit-diff-flip-revs)]] + (interactive) + (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) + (setq magit-buffer-diff-files files)) + (magit-refresh))) + +;;;; Infix Commands + +(transient-define-argument magit:-- () + :description "Limit to files" + :class 'transient-files + :key "--" + :argument "--" + :prompt "Limit to file(s): " + :reader 'magit-read-files + :multi-value t) + +(defun magit-read-files (prompt initial-input history) + (magit-completing-read-multiple* prompt + (magit-list-files) + nil nil + (or initial-input (magit-file-at-point)) + history)) + +(transient-define-argument magit-diff:-U () + :description "Context lines" + :class 'transient-option + :argument "-U" + :reader 'transient-read-number-N0) + +(transient-define-argument magit-diff:-M () + :description "Detect renames" + :class 'transient-option + :argument "-M" + :allow-empty t + :reader 'transient-read-number-N+) + +(transient-define-argument magit-diff:-C () + :description "Detect copies" + :class 'transient-option + :argument "-C" + :allow-empty t + :reader 'transient-read-number-N+) + +(transient-define-argument magit-diff:--diff-algorithm () + :description "Diff algorithm" + :class 'transient-option + :key "-A" + :argument "--diff-algorithm=" + :reader 'magit-diff-select-algorithm) + +(defun magit-diff-select-algorithm (&rest _ignore) + (magit-read-char-case nil t + (?d "[d]efault" "default") + (?m "[m]inimal" "minimal") + (?p "[p]atience" "patience") + (?h "[h]istogram" "histogram"))) + +(transient-define-argument magit-diff:--ignore-submodules () + :description "Ignore submodules" + :class 'transient-option + :key "-i" + :argument "--ignore-submodules=" + :reader 'magit-diff-select-ignore-submodules) + +(defun magit-diff-select-ignore-submodules (&rest _ignored) + (magit-read-char-case "Ignore submodules " t + (?u "[u]ntracked" "untracked") + (?d "[d]irty" "dirty") + (?a "[a]ll" "all"))) + +(transient-define-argument magit-diff:--color-moved () + :description "Color moved lines" + :class 'transient-option + :key "-m" + :argument "--color-moved=" + :reader 'magit-diff-select-color-moved-mode) + +(defun magit-diff-select-color-moved-mode (&rest _ignore) + (magit-read-char-case "Color moved " t + (?d "[d]efault" "default") + (?p "[p]lain" "plain") + (?b "[b]locks" "blocks") + (?z "[z]ebra" "zebra") + (?Z "[Z] dimmed-zebra" "dimmed-zebra"))) + +(transient-define-argument magit-diff:--color-moved-ws () + :description "Whitespace treatment for --color-moved" + :class 'transient-option + :key "=w" + :argument "--color-moved-ws=" + :reader 'magit-diff-select-color-moved-ws-mode) + +(defun magit-diff-select-color-moved-ws-mode (&rest _ignore) + (magit-read-char-case "Ignore whitespace " t + (?i "[i]ndentation" "allow-indentation-change") + (?e "[e]nd of line" "ignore-space-at-eol") + (?s "[s]pace change" "ignore-space-change") + (?a "[a]ll space" "ignore-all-space") + (?n "[n]o" "no"))) + +;;;; Setup Commands + +;;;###autoload +(defun magit-diff-dwim (&optional args files) + "Show changes for the thing at point." + (interactive (magit-diff-arguments)) + (pcase (magit-diff--dwim) + (`unmerged (magit-diff-unmerged args files)) + (`unstaged (magit-diff-unstaged args files)) + (`staged + (let ((file (magit-file-at-point))) + (if (and file (equal (cddr (car (magit-file-status file))) '(?D ?U))) + ;; File was deleted by us and modified by them. Show the latter. + (magit-diff-unmerged args (list file)) + (magit-diff-staged nil args files)))) + (`(commit . ,value) + (magit-diff-range (format "%s^..%s" value value) args files)) + (`(stash . ,value) (magit-stash-show value args)) + ((and range (pred stringp)) + (magit-diff-range range args files)) + (_ + (call-interactively #'magit-diff-range)))) + +(defun magit-diff--dwim () + "Return information for performing DWIM diff. + +The information can be in three forms: +1. TYPE + A symbol describing a type of diff where no additional information + is needed to generate the diff. Currently, this includes `staged', + `unstaged' and `unmerged'. +2. (TYPE . VALUE) + Like #1 but the diff requires additional information, which is + given by VALUE. Currently, this includes `commit' and `stash', + where VALUE is the given commit or stash, respectively. +3. RANGE + A string indicating a diff range. + +If no DWIM context is found, nil is returned." + (cond + ((--when-let (magit-region-values '(commit branch) t) + (deactivate-mark) + (concat (car (last it)) ".." (car it)))) + (magit-buffer-refname + (cons 'commit magit-buffer-refname)) + ((derived-mode-p 'magit-stash-mode) + (cons 'commit + (magit-section-case + (commit (oref it 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) + magit-buffer-range) + (t + (magit-section-case + ([* unstaged] 'unstaged) + ([* staged] 'staged) + (unmerged 'unmerged) + (unpushed (magit-diff--range-to-endpoints (oref it value))) + (unpulled (magit-diff--range-to-endpoints (oref it value))) + (branch (let ((current (magit-get-current-branch)) + (atpoint (oref it value))) + (if (equal atpoint current) + (--if-let (magit-get-upstream-branch) + (format "%s...%s" it current) + (if (magit-anything-modified-p) + current + (cons 'commit current))) + (format "%s...%s" + (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 (forge--pullreq-range (oref it value) t)))))) + +(defun magit-diff--range-to-endpoints (range) + (cond ((string-match "\\.\\.\\." range) (replace-match ".." nil nil range)) + ((string-match "\\.\\." range) (replace-match "..." nil nil range)) + (t range))) + +(defun magit-diff-read-range-or-commit (prompt &optional secondary-default mbase) + "Read range or revision with special diff range treatment. +If MBASE is non-nil, prompt for which rev to place at the end of +a \"revA...revB\" range. Otherwise, always construct +\"revA..revB\" range." + (--if-let (magit-region-values '(commit branch) t) + (let ((revA (car (last it))) + (revB (car it))) + (deactivate-mark) + (if mbase + (let ((base (magit-git-string "merge-base" revA revB))) + (cond + ((string= (magit-rev-parse revA) base) + (format "%s..%s" revA revB)) + ((string= (magit-rev-parse revB) base) + (format "%s..%s" revB revA)) + (t + (let ((main (magit-completing-read "View changes along" + (list revA revB) + nil t nil nil revB))) + (format "%s...%s" + (if (string= main revB) revA revB) main))))) + (format "%s..%s" revA revB))) + (magit-read-range prompt + (or (pcase (magit-diff--dwim) + (`(commit . ,value) + (format "%s^..%s" value value)) + ((and range (pred stringp)) + range)) + secondary-default + (magit-get-current-branch))))) + +;;;###autoload +(defun magit-diff-range (rev-or-range &optional args files) + "Show differences between two commits. + +REV-OR-RANGE should be a range or a single revision. If it is a +revision, then show changes in the working tree relative to that +revision. If it is a range, but one side is omitted, then show +changes relative to `HEAD'. + +If the region is active, use the revisions on the first and last +line of the region as the two sides of the range. With a prefix +argument, instead of diffing the revisions, choose a revision to +view changes along, starting at the common ancestor of both +revisions (i.e., use a \"...\" range)." + (interactive (cons (magit-diff-read-range-or-commit "Diff for range" + nil current-prefix-arg) + (magit-diff-arguments))) + (magit-diff-setup-buffer rev-or-range nil args files)) + +;;;###autoload +(defun magit-diff-working-tree (&optional rev args files) + "Show changes between the current working tree and the `HEAD' commit. +With a prefix argument show changes between the working tree and +a commit read from the minibuffer." + (interactive + (cons (and current-prefix-arg + (magit-read-branch-or-commit "Diff working tree and commit")) + (magit-diff-arguments))) + (magit-diff-setup-buffer (or rev "HEAD") nil args files)) + +;;;###autoload +(defun magit-diff-staged (&optional rev args files) + "Show changes between the index and the `HEAD' commit. +With a prefix argument show changes between the index and +a commit read from the minibuffer." + (interactive + (cons (and current-prefix-arg + (magit-read-branch-or-commit "Diff index and commit")) + (magit-diff-arguments))) + (magit-diff-setup-buffer rev "--cached" args files)) + +;;;###autoload +(defun magit-diff-unstaged (&optional args files) + "Show changes between the working tree and the index." + (interactive (magit-diff-arguments)) + (magit-diff-setup-buffer nil nil args files)) + +;;;###autoload +(defun magit-diff-unmerged (&optional args files) + "Show changes that are being merged." + (interactive (magit-diff-arguments)) + (unless (magit-merge-in-progress-p) + (user-error "No merge is in progress")) + (magit-diff-setup-buffer (magit--merge-range) nil args files)) + +;;;###autoload +(defun magit-diff-while-committing (&optional args) + "While committing, show the changes that are about to be committed. +While amending, invoking the command again toggles between +showing just the new changes or all the changes that will +be committed." + (interactive (list (car (magit-diff-arguments)))) + (unless (magit-commit-message-buffer) + (user-error "No commit in progress")) + (let ((magit-display-buffer-noselect t)) + (if-let ((diff-buf (magit-get-mode-buffer 'magit-diff-mode 'selected))) + (with-current-buffer diff-buf + (cond ((and (equal magit-buffer-range "HEAD^") + (equal magit-buffer-typearg "--cached")) + (magit-diff-staged nil args)) + ((and (equal magit-buffer-range nil) + (equal magit-buffer-typearg "--cached")) + (magit-diff-while-amending args)) + ((magit-anything-staged-p) + (magit-diff-staged nil args)) + (t + (magit-diff-while-amending args)))) + (if (magit-anything-staged-p) + (magit-diff-staged nil args) + (magit-diff-while-amending args))))) + +(define-key git-commit-mode-map + (kbd "C-c C-d") 'magit-diff-while-committing) + +(defun magit-diff-while-amending (&optional args) + (magit-diff-setup-buffer "HEAD^" "--cached" args nil)) + +;;;###autoload +(defun magit-diff-buffer-file () + "Show diff for the blob or file visited in the current buffer. + +When the buffer visits a blob, then show the respective commit. +When the buffer visits a file, then show the differenced between +`HEAD' and the working tree. In both cases limit the diff to +the file or blob." + (interactive) + (require 'magit) + (if-let ((file (magit-file-relative-name))) + (if magit-buffer-refname + (magit-show-commit magit-buffer-refname + (car (magit-show-commit--arguments)) + (list file)) + (save-buffer) + (let ((line (line-number-at-pos)) + (col (current-column))) + (with-current-buffer + (magit-diff-setup-buffer (or (magit-get-current-branch) "HEAD") + nil + (car (magit-diff-arguments)) + (list file) + magit-diff-buffer-file-locked) + (magit-diff--goto-position file line col)))) + (user-error "Buffer isn't visiting a file"))) + +;;;###autoload +(defun magit-diff-paths (a b) + "Show changes between any two files on disk." + (interactive (list (read-file-name "First file: " nil nil t) + (read-file-name "Second file: " nil nil t))) + (magit-diff-setup-buffer nil "--no-index" + nil (list (magit-convert-filename-for-git + (expand-file-name a)) + (magit-convert-filename-for-git + (expand-file-name b))))) + +(defun magit-show-commit--arguments () + (pcase-let ((`(,args ,diff-files) + (magit-diff-arguments 'magit-revision-mode))) + (list args (if (derived-mode-p 'magit-log-mode) + (and (or magit-revision-filter-files-on-follow + (not (member "--follow" magit-buffer-log-args))) + magit-buffer-log-files) + diff-files)))) + +;;;###autoload +(defun magit-show-commit (rev &optional args files module) + "Visit the revision at point in another buffer. +If there is no revision at point or with a prefix argument prompt +for a revision." + (interactive + (pcase-let* ((mcommit (magit-section-value-if 'module-commit)) + (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) + (magit-read-branch-or-commit "Show commit" atpoint)) + args + files + (and mcommit + (magit-section-parent-value (magit-current-section)))))) + (require 'magit) + (let ((file (magit-file-relative-name))) + (magit-with-toplevel + (when module + (setq default-directory + (expand-file-name (file-name-as-directory module)))) + (unless (magit-commit-p rev) + (user-error "%s is not a commit" rev)) + (let ((buf (magit-revision-setup-buffer rev args files))) + (when file + (save-buffer) + (let ((line (magit-diff-visit--offset file (list "-R" rev) + (line-number-at-pos))) + (col (current-column))) + (with-current-buffer buf + (magit-diff--goto-position file line col)))))))) + +(defun magit-diff--locate-hunk (file line &optional parent) + (when-let ((diff (cl-find-if (lambda (section) + (and (cl-typep section 'magit-file-section) + (equal (oref section value) file))) + (oref (or parent magit-root-section) children)))) + (let (hunk (hunks (oref diff children))) + (cl-block nil + (while (setq hunk (pop hunks)) + (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))) + (pcase-let ((`(,section ,exact) pos)) + (cond ((cl-typep section 'magit-file-section) + (goto-char (oref section start))) + (exact + (goto-char (oref section content)) + (let ((pos (car (oref section to-range)))) + (while (or (< pos line) + (= (char-after) ?-)) + (unless (= (char-after) ?-) + (cl-incf pos)) + (forward-line))) + (forward-char (1+ column))) + (t + (goto-char (oref section start)) + (setq section (oref section parent)))) + (while section + (when (oref section hidden) + (magit-section-show section)) + (setq section (oref section parent)))) + (magit-section-update-highlight) + t)) + +;;;; Setting Commands + +(defun magit-diff-switch-range-type () + "Convert diff range type. +Change \"revA..revB\" to \"revA...revB\", or vice versa." + (interactive) + (if (and magit-buffer-range + (derived-mode-p 'magit-diff-mode) + (string-match magit-range-re magit-buffer-range)) + (setq magit-buffer-range + (replace-match (if (string= (match-string 2 magit-buffer-range) "..") + "..." + "..") + t t magit-buffer-range 2)) + (user-error "No range to change")) + (magit-refresh)) + +(defun magit-diff-flip-revs () + "Swap revisions in diff range. +Change \"revA..revB\" to \"revB..revA\"." + (interactive) + (if (and magit-buffer-range + (derived-mode-p 'magit-diff-mode) + (string-match magit-range-re magit-buffer-range)) + (progn + (setq magit-buffer-range + (concat (match-string 3 magit-buffer-range) + (match-string 2 magit-buffer-range) + (match-string 1 magit-buffer-range))) + (magit-refresh)) + (user-error "No range to swap"))) + +(defun magit-diff-toggle-file-filter () + "Toggle the file restriction of the current buffer's diffs. +If the current buffer's mode is derived from `magit-log-mode', +toggle the file restriction in the repository's revision buffer +instead." + (interactive) + (cl-flet ((toggle () + (if (or magit-buffer-diff-files + magit-buffer-diff-files-suspended) + (cl-rotatef magit-buffer-diff-files + magit-buffer-diff-files-suspended) + (setq magit-buffer-diff-files + (transient-infix-read 'magit:--))) + (magit-refresh))) + (cond + ((derived-mode-p 'magit-log-mode + 'magit-cherry-mode + 'magit-reflog-mode) + (if-let ((buffer (magit-get-mode-buffer 'magit-revision-mode))) + (with-current-buffer buffer (toggle)) + (message "No revision buffer"))) + ((local-variable-p 'magit-buffer-diff-files) + (toggle)) + (t + (user-error "Cannot toggle file filter in this buffer"))))) + +(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))))) + +(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)))) + +(defun magit-diff-default-context () + "Reset context for diff hunks to the default height." + (interactive) + (magit-diff-set-context #'ignore)) + +(defun magit-diff-set-context (fn) + (let* ((def (--if-let (magit-get "diff.context") (string-to-number it) 3)) + (val magit-buffer-diff-args) + (arg (--first (string-match "^-U\\([0-9]+\\)?$" it) val)) + (num (--if-let (and arg (match-string 1 arg)) (string-to-number it) def)) + (val (delete arg val)) + (num (funcall fn num)) + (arg (and num (not (= num def)) (format "-U%i" num))) + (val (if arg (cons arg val) val))) + (setq magit-buffer-diff-args val)) + (magit-refresh)) + +(defun magit-diff-context-p () + (if-let ((arg (--first (string-match "^-U\\([0-9]+\\)$" it) + magit-buffer-diff-args))) + (not (equal arg "-U0")) + t)) + +(defun magit-diff-ignore-any-space-p () + (--any-p (member it magit-buffer-diff-args) + '("--ignore-cr-at-eol" + "--ignore-space-at-eol" + "--ignore-space-change" "-b" + "--ignore-all-space" "-w" + "--ignore-blank-space"))) + +(defun magit-diff-toggle-refine-hunk (&optional style) + "Turn diff-hunk refining on or off. + +If hunk refining is currently on, then hunk refining is turned off. +If hunk refining is off, then hunk refining is turned on, in +`selected' mode (only the currently selected hunk is refined). + +With a prefix argument, the \"third choice\" is used instead: +If hunk refining is currently on, then refining is kept on, but +the refining mode (`selected' or `all') is switched. +If hunk refining is off, then hunk refining is turned on, in +`all' mode (all hunks refined). + +Customize variable `magit-diff-refine-hunk' to change the default mode." + (interactive "P") + (setq-local magit-diff-refine-hunk + (if style + (if (eq magit-diff-refine-hunk 'all) t 'all) + (not magit-diff-refine-hunk))) + (magit-diff-update-hunk-refinement)) + +;;;; Visit Commands +;;;;; Dwim Variants + +(defun magit-diff-visit-file (file &optional other-window) + "From a diff visit the appropriate version of FILE. + +Display the buffer in the selected window. With a prefix +argument OTHER-WINDOW display the buffer in another window +instead. + +Visit the worktree version of the appropriate file. The location +of point inside the diff determines which file is being visited. +The visited version depends on what changes the diff is about. + +1. If the diff shows uncommitted changes (i.e. stage or unstaged + changes), then visit the file in the working tree (i.e. the + same \"real\" file that `find-file' would visit. In all other + cases visit a \"blob\" (i.e. the version of a file as stored + in some commit). + +2. If point is on a removed line, then visit the blob for the + first parent of the commit that removed that line, i.e. the + last commit where that line still exists. + +3. If point is on an added or context line, then visit the blob + that adds that line, or if the diff shows from more than a + single commit, then visit the blob from the last of these + commits. + +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) 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 + #'switch-to-buffer-other-window + #'pop-to-buffer-same-window))) + +(defun magit-diff-visit-file-other-window (file) + "From a diff visit the appropriate version of FILE in another window. +Like `magit-diff-visit-file' but use +`switch-to-buffer-other-window'." + (interactive (list (magit-file-at-point t t))) + (magit-diff-visit-file--internal file nil #'switch-to-buffer-other-window)) + +(defun magit-diff-visit-file-other-frame (file) + "From a diff visit the appropriate version of FILE in another frame. +Like `magit-diff-visit-file' but use +`switch-to-buffer-other-frame'." + (interactive (list (magit-file-at-point t t))) + (magit-diff-visit-file--internal file nil #'switch-to-buffer-other-frame)) + +;;;;; Worktree Variants + +(defun magit-diff-visit-worktree-file (file &optional other-window) + "From a diff visit the worktree version of FILE. + +Display the buffer in the selected window. With a prefix +argument OTHER-WINDOW display the buffer in another window +instead. + +Visit the worktree version of the appropriate file. The location +of point inside the diff determines which file is being visited. + +Unlike `magit-diff-visit-file' always visits the \"real\" file in +the working tree, i.e the \"current version\" of the file. + +In the file-visiting buffer also go to the line that corresponds +to the line that point is on in the diff. Lines that were added +or removed in the working tree, the index and other commits in +between are automatically accounted for." + (interactive (list (magit-file-at-point t t) current-prefix-arg)) + (magit-diff-visit-file--internal file t + (if other-window + #'switch-to-buffer-other-window + #'pop-to-buffer-same-window))) + +(defun magit-diff-visit-worktree-file-other-window (file) + "From a diff visit the worktree version of FILE in another window. +Like `magit-diff-visit-worktree-file' but use +`switch-to-buffer-other-window'." + (interactive (list (magit-file-at-point t t))) + (magit-diff-visit-file--internal file t #'switch-to-buffer-other-window)) + +(defun magit-diff-visit-worktree-file-other-frame (file) + "From a diff visit the worktree version of FILE in another frame. +Like `magit-diff-visit-worktree-file' but use +`switch-to-buffer-other-frame'." + (interactive (list (magit-file-at-point t t))) + (magit-diff-visit-file--internal file t #'switch-to-buffer-other-frame)) + +;;;;; Internal + +(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 +to display the buffer in some window." + (if (magit-file-accessible-directory-p file) + (magit-diff-visit-directory file force-worktree) + (pcase-let ((`(,buf ,pos) + (magit-diff-visit-file--noselect file force-worktree))) + (funcall fn buf) + (magit-diff-visit-file--setup buf pos) + buf))) + +(defun magit-diff-visit-directory (directory &optional other-window) + "Visit DIRECTORY in some window. +Display the buffer in the selected window unless OTHER-WINDOW is +non-nil. If DIRECTORY is the top-level directory of the current +repository, then visit the containing directory using Dired and +in the Dired buffer put point on DIRECTORY. Otherwise display +the Magit-Status buffer for DIRECTORY." + (if (equal (magit-toplevel directory) + (magit-toplevel)) + (dired-jump other-window (concat directory "/.")) + (let ((display-buffer-overriding-action + (if other-window + '(nil (inhibit-same-window t)) + '(display-buffer-same-window)))) + (magit-status-setup-buffer directory)))) + +(defun magit-diff-visit-file--setup (buf pos) + (if-let ((win (get-buffer-window buf 'visible))) + (with-selected-window win + (when pos + (unless (<= (point-min) pos (point-max)) + (widen)) + (goto-char pos)) + (when (and buffer-file-name + (magit-anything-unmerged-p buffer-file-name)) + (smerge-start-session)) + (run-hooks 'magit-diff-visit-file-hook)) + (error "File buffer is not visible"))) + +(defun magit-diff-visit-file--noselect (&optional file goto-worktree) + (unless file + (setq file (magit-file-at-point t t))) + (let* ((hunk (magit-diff-visit--hunk)) + (goto-from (and hunk + (magit-diff-visit--goto-from-p hunk goto-worktree))) + (line (and hunk (magit-diff-hunk-line hunk goto-from))) + (col (and hunk (magit-diff-hunk-column hunk goto-from))) + (spec (magit-diff--dwim)) + (rev (if goto-from + (magit-diff-visit--range-from spec) + (magit-diff-visit--range-to spec))) + (buf (if (or goto-worktree + (and (not (stringp rev)) + (or magit-diff-visit-avoid-head-blob + (not goto-from)))) + (or (get-file-buffer file) + (find-file-noselect file)) + (magit-find-file-noselect (if (stringp rev) rev "HEAD") + file)))) + (if line + (with-current-buffer buf + (cond ((eq rev 'staged) + (setq line (magit-diff-visit--offset file nil line))) + ((and goto-worktree + (stringp rev)) + (setq line (magit-diff-visit--offset file rev line)))) + (list buf (save-restriction + (widen) + (goto-char (point-min)) + (forward-line (1- line)) + (move-to-column col) + (point)))) + (list buf nil)))) + +(defun magit-diff-visit--hunk () + (when-let ((scope (magit-diff-scope))) + (let ((section (magit-current-section))) + (cl-case scope + ((file files) + (setq section (car (oref section children)))) + (list + (setq section (car (oref section children))) + (when section + (setq section (car (oref section children)))))) + (and + ;; Unmerged files appear in the list of staged changes + ;; but unlike in the list of unstaged changes no diffs + ;; are shown here. In that case `section' is nil. + section + ;; Currently the `hunk' type is also abused for file + ;; mode changes, which we are not interested in here. + ;; Such sections have no value. + (oref section value) + section)))) + +(defun magit-diff-visit--goto-from-p (section in-worktree) + (and magit-diff-visit-previous-blob + (not in-worktree) + (not (oref section combined)) + (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 (and magit-diff-visit-jump-to-change (< (point) content)) + (goto-char content) + (re-search-forward "^[-+]")) + (+ (car (if goto-from from-range to-range)) + (let ((prefix (if combined (length from-ranges) 1)) + (target (point)) + (offset 0)) + (goto-char content) + (while (< (point) target) + (unless (string-match-p + (if goto-from "\\+" "-") + (buffer-substring (point) (+ (point) prefix))) + (cl-incf offset)) + (forward-line)) + offset))))) + +(defun magit-diff-hunk-column (section goto-from) + (if (or (< (point) + (oref section content)) + (and (not goto-from) + (= (char-after (line-beginning-position)) ?-))) + 0 + (max 0 (- (+ (current-column) 2) + (length (oref section value)))))) + +(defun magit-diff-visit--range-from (spec) + (cond ((consp spec) + (concat (cdr spec) "^")) + ((stringp spec) + (car (magit-split-range spec))) + (t + spec))) + +(defun magit-diff-visit--range-to (spec) + (if (symbolp spec) + spec + (let ((rev (if (consp spec) + (cdr spec) + (cdr (magit-split-range spec))))) + (if (and magit-diff-visit-avoid-head-blob + (magit-rev-head-p rev)) + 'unstaged + rev)))) + +(defun magit-diff-visit--offset (file rev line) + (let ((offset 0)) + (with-temp-buffer + (save-excursion + (magit-with-toplevel + (magit-git-insert "diff" rev "--" file))) + (catch 'found + (while (re-search-forward + "^@@ -\\([0-9]+\\),\\([0-9]+\\) \\+\\([0-9]+\\),\\([0-9]+\\) @@.*\n" + nil t) + (let ((from-beg (string-to-number (match-string 1))) + (from-len (string-to-number (match-string 2))) + ( to-len (string-to-number (match-string 4)))) + (if (<= from-beg line) + (if (< (+ from-beg from-len) line) + (cl-incf offset (- to-len from-len)) + (let ((rest (- line from-beg))) + (while (> rest 0) + (pcase (char-after) + (?\s (cl-decf rest)) + (?- (cl-decf offset) (cl-decf rest)) + (?+ (cl-incf offset))) + (forward-line)))) + (throw 'found nil)))))) + (+ line offset))) + +;;;; Scroll Commands + +(defun magit-diff-show-or-scroll-up () + "Update the commit or diff buffer for the thing at point. + +Either show the commit or stash at point in the appropriate +buffer, or if that buffer is already being displayed in the +current frame and contains information about that commit or +stash, then instead scroll the buffer up. If there is no +commit or stash at point, then prompt for a commit." + (interactive) + (magit-diff-show-or-scroll 'scroll-up)) + +(defun magit-diff-show-or-scroll-down () + "Update the commit or diff buffer for the thing at point. + +Either show the commit or stash at point in the appropriate +buffer, or if that buffer is already being displayed in the +current frame and contains information about that commit or +stash, then instead scroll the buffer down. If there is no +commit or stash at point, then prompt for a commit." + (interactive) + (magit-diff-show-or-scroll 'scroll-down)) + +(defun magit-diff-show-or-scroll (fn) + (let (rev cmd buf win) + (cond + (magit-blame-mode + (setq rev (oref (magit-current-blame-chunk) orig-rev)) + (setq cmd 'magit-show-commit) + (setq buf (magit-get-mode-buffer 'magit-revision-mode))) + ((derived-mode-p 'git-rebase-mode) + (with-slots (action-type target) + (git-rebase-current-line) + (if (not (eq action-type 'commit)) + (user-error "No commit on this line") + (setq rev target) + (setq cmd 'magit-show-commit) + (setq buf (magit-get-mode-buffer 'magit-revision-mode))))) + (t + (magit-section-case + (branch + (setq rev (magit-ref-maybe-qualify (oref it value))) + (setq cmd 'magit-show-commit) + (setq buf (magit-get-mode-buffer 'magit-revision-mode))) + (commit + (setq rev (oref it value)) + (setq cmd 'magit-show-commit) + (setq buf (magit-get-mode-buffer 'magit-revision-mode))) + (stash + (setq rev (oref it value)) + (setq cmd 'magit-stash-show) + (setq buf (magit-get-mode-buffer 'magit-stash-mode)))))) + (if rev + (if (and buf + (setq win (get-buffer-window buf)) + (with-current-buffer buf + (and (equal rev magit-buffer-revision) + (equal (magit-rev-parse rev) + magit-buffer-revision-hash)))) + (with-selected-window win + (condition-case nil + (funcall fn) + (error + (goto-char (pcase fn + (`scroll-up (point-min)) + (`scroll-down (point-max))))))) + (let ((magit-display-buffer-noselect t)) + (if (eq cmd 'magit-show-commit) + (apply #'magit-show-commit rev (magit-show-commit--arguments)) + (funcall cmd rev)))) + (call-interactively #'magit-show-commit)))) + +;;;; Section Commands + +(defun magit-section-cycle-diffs () + "Cycle visibility of diff-related sections in the current buffer." + (interactive) + (when-let ((sections + (cond ((derived-mode-p 'magit-status-mode) + (--mapcat + (when it + (when (oref it hidden) + (magit-section-show it)) + (oref it children)) + (list (magit-get-section '((staged) (status))) + (magit-get-section '((unstaged) (status)))))) + ((derived-mode-p 'magit-diff-mode) + (-filter #'magit-file-section-p + (oref magit-root-section children)))))) + (if (--any-p (oref it hidden) sections) + (dolist (s sections) + (magit-section-show s) + (magit-section-hide-children s)) + (let ((children (--mapcat (oref it children) sections))) + (cond ((and (--any-p (oref it hidden) children) + (--any-p (oref it children) children)) + (mapc 'magit-section-show-headings sections)) + ((seq-some 'magit-section-hidden-body children) + (mapc 'magit-section-show-children sections)) + (t + (mapc 'magit-section-hide sections))))))) + +;;; Diff Mode + +(defvar magit-diff-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-mode-map) + (define-key map (kbd "C-c C-d") 'magit-diff-while-committing) + (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 "SPC") 'scroll-up) + (define-key map (kbd "DEL") 'scroll-down) + (define-key map (kbd "j") 'magit-jump-to-diffstat-or-diff) + (define-key map [remap write-file] 'magit-patch-save) + map) + "Keymap for `magit-diff-mode'.") + +(define-derived-mode magit-diff-mode magit-mode "Magit Diff" + "Mode for looking at a Git diff. + +This mode is documented in info node `(magit)Diff Buffer'. + +\\\ +Type \\[magit-refresh] to refresh the current buffer. +Type \\[magit-section-toggle] to expand or hide the section at point. +Type \\[magit-visit-thing] to visit the hunk or file at point. + +Staging and applying changes is documented in info node +`(magit)Staging and Unstaging' and info node `(magit)Applying'. + +\\Type \ +\\[magit-apply] to apply the change at point, \ +\\[magit-stage] to stage, +\\[magit-unstage] to unstage, \ +\\[magit-discard] to discard, or \ +\\[magit-reverse] to reverse it. + +\\{magit-diff-mode-map}" + :group 'magit-diff + (hack-dir-local-variables-non-file-buffer) + (setq imenu-prev-index-position-function + 'magit-imenu--diff-prev-index-position-function) + (setq imenu-extract-index-name-function + 'magit-imenu--diff-extract-index-name-function)) + +(put 'magit-diff-mode 'magit-diff-default-arguments + '("--stat" "--no-ext-diff")) + +(defun magit-diff-setup-buffer (range typearg args files &optional locked) + (require 'magit) + (magit-setup-buffer #'magit-diff-mode locked + (magit-buffer-range range) + (magit-buffer-typearg typearg) + (magit-buffer-diff-args args) + (magit-buffer-diff-files files) + (magit-buffer-diff-files-suspended nil))) + +(defun magit-diff-refresh-buffer () + "Refresh the current `magit-diff-mode' buffer." + (magit-set-header-line-format + (if (equal magit-buffer-typearg "--no-index") + (apply #'format "Differences between %s and %s" magit-buffer-diff-files) + (concat (if 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")) + (pcase (length magit-buffer-diff-files) + (0) + (1 (concat " in file " (car magit-buffer-diff-files))) + (_ (concat " in files " + (mapconcat #'identity magit-buffer-diff-files ", "))))))) + (setq magit-buffer-range-hashed + (and magit-buffer-range (magit-hash-range magit-buffer-range))) + (magit-insert-section (diffbuf) + (magit-run-section-hook 'magit-diff-sections-hook))) + +(cl-defmethod magit-buffer-value (&context (major-mode magit-diff-mode)) + (nconc (cond (magit-buffer-range + (delq nil (list magit-buffer-range magit-buffer-typearg))) + ((equal magit-buffer-typearg "--cached") + (list 'staged)) + (t + (list 'unstaged magit-buffer-typearg))) + (and magit-buffer-diff-files (cons "--" magit-buffer-diff-files)))) + +(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 (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 "s" 'magit-stage) + (define-key map "u" 'magit-unstage) + (define-key map "&" 'magit-do-async-shell-command) + (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))) + (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\\|" + (substring magit-diff-conflict-headline-re 1) + "\\)")) + +(defconst magit-diff-statline-re + (concat "^ ?" + "\\(.*\\)" ; file + "\\( +| +\\)" ; separator + "\\([0-9]+\\|Bin\\(?: +[0-9]+ -> [0-9]+ bytes\\)?$\\) ?" + "\\(\\+*\\)" ; add + "\\(-*\\)$")) ; del + +(defvar magit-diff--reset-non-color-moved + (list + "-c" "color.diff.context=normal" + "-c" "color.diff.plain=normal" ; historical synonym for context + "-c" "color.diff.meta=normal" + "-c" "color.diff.frag=normal" + "-c" "color.diff.func=normal" + "-c" "color.diff.old=normal" + "-c" "color.diff.new=normal" + "-c" "color.diff.commit=normal" + "-c" "color.diff.whitespace=normal" + ;; "git-range-diff" does not support "--color-moved", so we don't + ;; need to reset contextDimmed, oldDimmed, newDimmed, contextBold, + ;; oldBold, and newBold. + )) + +(defun magit-insert-diff () + "Insert the diff into this `magit-diff-mode' buffer." + (magit--insert-diff + "diff" magit-buffer-range "-p" "--no-prefix" + (and (member "--stat" magit-buffer-diff-args) "--numstat") + magit-buffer-typearg + magit-buffer-diff-args "--" + magit-buffer-diff-files)) + +(defun magit--insert-diff (&rest args) + (declare (indent 0)) + (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 (and (not (equal cmd "merge-tree")) + (pcase (magit-repository-local-get 'diff-ita-kludge-p 'unset) + (`unset + (let ((val (magit-git-version>= "2.19.0"))) + (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" args) + (setq magit-git-global-arguments + (append magit-diff--reset-non-color-moved + magit-git-global-arguments))) + (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) + (magit-diff-wash-diffstat)) + (when (re-search-forward magit-diff-headline-re limit t) + (goto-char (line-beginning-position)) + (magit-wash-sequence (apply-partially 'magit-diff-wash-diff args)) + (insert ?\n))) + +(defun magit-jump-to-diffstat-or-diff () + "Jump to the diffstat or diff. +When point is on a file inside the diffstat section, then jump +to the respective diff section, otherwise jump to the diffstat +section or a child thereof." + (interactive) + (--if-let (magit-get-section + (append (magit-section-case + ([file diffstat] `((file . ,(oref it value)))) + (file `((file . ,(oref it value)) (diffstat))) + (t '((diffstat)))) + (magit-section-ident magit-root-section))) + (magit-section-goto it) + (user-error "No diffstat in this buffer"))) + +(defun magit-diff-wash-signature () + (when (looking-at "^gpg: ") + (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))) + (when (re-search-forward "^ ?\\([0-9]+ +files? change[^\n]*\n\\)" nil t) + (setq heading (match-string 1)) + (magit-delete-match) + (goto-char beg) + (magit-insert-section (diffstat) + (insert (propertize heading 'font-lock-face 'magit-diff-file-heading)) + (magit-insert-heading) + (let (files) + (while (looking-at "^[-0-9]+\t[-0-9]+\t\\(.+\\)$") + (push (magit-decode-git-path + (let ((f (match-string 1))) + (cond + ((string-match "\\`\\([^{]+\\){\\(.+\\) => \\(.+\\)}\\'" f) + (concat (match-string 1 f) + (match-string 3 f))) + ((string-match " => " f) + (substring f (match-end 0))) + (t f)))) + files) + (magit-delete-line)) + (setq files (nreverse files)) + (while (looking-at magit-diff-statline-re) + (magit-bind-match-strings (file sep cnt add del) nil + (magit-delete-line) + (when (string-match " +$" file) + (setq sep (concat (match-string 0 file) sep)) + (setq file (substring file 0 (match-beginning 0)))) + (let ((le (length file)) ld) + (setq file (magit-decode-git-path file)) + (setq ld (length file)) + (when (> le ld) + (setq sep (concat (make-string (- le ld) ?\s) sep)))) + (magit-insert-section (file (pop files)) + (insert (propertize file 'font-lock-face 'magit-filename) + sep cnt " ") + (when add + (insert (propertize add 'font-lock-face + 'magit-diffstat-added))) + (when del + (insert (propertize del 'font-lock-face + 'magit-diffstat-removed))) + (insert "\n"))))) + (if (looking-at "^$") (forward-line) (insert "\n")))))) + +(defun magit-diff-wash-diff (args) + (when (cl-member-if (lambda (arg) (string-prefix-p "--color-moved" arg)) args) + (require 'ansi-color) + (ansi-color-apply-on-region (point-min) (point-max))) + (cond + ((looking-at "^Submodule") + (magit-diff-wash-submodule)) + ((looking-at "^\\* Unmerged path \\(.*\\)") + (let ((file (magit-decode-git-path (match-string 1)))) + (magit-delete-line) + (unless (and (derived-mode-p 'magit-status-mode) + (not (member "--cached" args))) + (magit-insert-section (file file) + (insert (propertize + (format "unmerged %s%s" file + (pcase (cddr (car (magit-file-status file))) + (`(?D ?D) " (both deleted)") + (`(?D ?U) " (deleted by us)") + (`(?U ?D) " (deleted by them)") + (`(?A ?A) " (both added)") + (`(?A ?U) " (added by us)") + (`(?U ?A) " (added by them)") + (`(?U ?U) ""))) + 'font-lock-face 'magit-diff-file-heading)) + (insert ?\n)))) + t) + ((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\\}\\) \\(.+\\)$") + (magit-bind-match-strings (side _blob name) nil + (pcase side + ("result" (setq file name)) + ("our" (setq orig name)) + ("their" (setq file name)) + ("base" (setq base name)))) + (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 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"))) + (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))) + (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")) + ((looking-at "Binary files 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-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 rename 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" 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 '(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 () + ;; See `show_submodule_summary' in submodule.c and "this" commit. + (when (looking-at "^Submodule \\([^ ]+\\)") + (let ((module (match-string 1)) + untracked modified) + (when (looking-at "^Submodule [^ ]+ contains untracked content$") + (magit-delete-line) + (setq untracked t)) + (when (looking-at "^Submodule [^ ]+ contains modified content$") + (magit-delete-line) + (setq modified t)) + (cond + ((and (looking-at "^Submodule \\([^ ]+\\) \\([^ :]+\\)\\( (rewind)\\)?:$") + (equal (match-string 1) module)) + (magit-bind-match-strings (_module range rewind) nil + (magit-delete-line) + (while (looking-at "^ \\([<>]\\) \\(.*\\)$") + (magit-delete-line)) + (when rewind + (setq range (replace-regexp-in-string "[^.]\\(\\.\\.\\)[^.]" + "..." range t t 1))) + (magit-insert-section (magit-module-section module t) + (magit-insert-heading + (propertize (concat "modified " module) + 'font-lock-face 'magit-diff-file-heading) + " (" + (cond (rewind "rewind") + ((string-match-p "\\.\\.\\." range) "non-ff") + (t "new commits")) + (and (or modified untracked) + (concat ", " + (and modified "modified") + (and modified untracked " and ") + (and untracked "untracked") + " content")) + ")") + (let ((default-directory + (file-name-as-directory + (expand-file-name module (magit-toplevel))))) + (magit-git-wash (apply-partially 'magit-log-wash-log 'module) + "log" "--oneline" "--left-right" range) + (delete-char -1))))) + ((and (looking-at "^Submodule \\([^ ]+\\) \\([^ ]+\\) (\\([^)]+\\))$") + (equal (match-string 1) module)) + (magit-bind-match-strings (_module _range msg) nil + (magit-delete-line) + (magit-insert-section (magit-module-section module) + (magit-insert-heading + (propertize (concat "submodule " module) + 'font-lock-face 'magit-diff-file-heading) + " (" msg ")")))) + (t + (magit-insert-section (magit-module-section module) + (magit-insert-heading + (propertize (concat "modified " module) + 'font-lock-face 'magit-diff-file-heading) + " (" + (and modified "modified") + (and modified untracked " and ") + (and untracked "untracked") + " content)"))))))) + +(defun magit-diff-wash-hunk () + (when (looking-at "^@\\{2,\\} \\(.+?\\) @\\{2,\\}\\(?: \\(.*\\)\\)?") + (let* ((heading (match-string 0)) + (ranges (mapcar (lambda (str) + (mapcar #'string-to-number + (split-string (substring str 1) ","))) + (split-string (match-string 1)))) + (about (match-string 2)) + (combined (= (length ranges) 3)) + (value (cons about ranges))) + (magit-delete-line) + (magit-insert-section section (hunk value) + (insert (propertize (concat heading "\n") + 'font-lock-face 'magit-diff-hunk-heading)) + (magit-insert-heading) + (while (not (or (eobp) (looking-at "^[^-+\s\\]"))) + (forward-line)) + (oset section end (point)) + (oset section washer 'magit-diff-paint-hunk) + (oset section combined combined) + (if combined + (oset section from-ranges (butlast ranges)) + (oset section from-range (car ranges))) + (oset section to-range (car (last ranges))) + (oset section about about))) + t)) + +(defun magit-diff-expansion-threshold (section) + "Keep new diff sections collapsed if washing takes too long." + (and (magit-file-section-p section) + (> (float-time (time-subtract (current-time) magit-refresh-start-time)) + magit-diff-expansion-threshold) + 'hide)) + +(add-hook 'magit-section-set-visibility-hook #'magit-diff-expansion-threshold) + +;;; Revision Mode + +(define-derived-mode magit-revision-mode magit-diff-mode "Magit Rev" + "Mode for looking at a Git commit. + +This mode is documented in info node `(magit)Revision Buffer'. + +\\\ +Type \\[magit-refresh] to refresh the current buffer. +Type \\[magit-section-toggle] to expand or hide the section at point. +Type \\[magit-visit-thing] to visit the hunk or file at point. + +Staging and applying changes is documented in info node +`(magit)Staging and Unstaging' and info node `(magit)Applying'. + +\\Type \ +\\[magit-apply] to apply the change at point, \ +\\[magit-stage] to stage, +\\[magit-unstage] to unstage, \ +\\[magit-discard] to discard, or \ +\\[magit-reverse] to reverse it. + +\\{magit-revision-mode-map}" + :group 'magit-revision + (hack-dir-local-variables-non-file-buffer)) + +(put 'magit-revision-mode 'magit-diff-default-arguments + '("--stat" "--no-ext-diff")) + +(defun magit-revision-setup-buffer (rev args files) + (magit-setup-buffer #'magit-revision-mode nil + (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-suspended nil))) + +(defun magit-revision-refresh-buffer () + (setq magit-buffer-revision-hash (magit-rev-parse magit-buffer-revision)) + (magit-set-header-line-format + (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 ", ")))))) + (magit-insert-section (commitbuf) + (magit-run-section-hook 'magit-revision-sections-hook))) + +(cl-defmethod magit-buffer-value (&context (major-mode magit-revision-mode)) + (cons magit-buffer-revision magit-buffer-diff-files)) + +(defun magit-insert-revision-diff () + "Insert the diff into this `magit-revision-mode' buffer." + (magit--insert-diff + "show" "-p" "--cc" "--format=" "--no-prefix" + (and (member "--stat" magit-buffer-diff-args) "--numstat") + magit-buffer-diff-args + (concat magit-buffer-revision "^{commit}") + "--" magit-buffer-diff-files)) + +(defun magit-insert-revision-tag () + "Insert tag message and headers into a revision buffer. +This function only inserts anything when `magit-show-commit' is +called with a tag as argument, when that is called with a commit +or a ref which is not a branch, then it inserts nothing." + (when (equal (magit-object-type magit-buffer-revision) "tag") + (magit-insert-section (taginfo) + (let ((beg (point))) + ;; "git verify-tag -v" would output what we need, but the gpg + ;; output is send to stderr and we have no control over the + ;; order in which stdout and stderr are inserted, which would + ;; make parsing hard. We are forced to use "git cat-file tag" + ;; instead, which inserts the signature instead of verifying + ;; it. We remove that later and then insert the verification + ;; output using "git verify-tag" (without the "-v"). + (magit-git-insert "cat-file" "tag" magit-buffer-revision) + (goto-char beg) + (forward-line 3) + (delete-region beg (point))) + (looking-at "^tagger \\([^<]+\\) <\\([^>]+\\)") + (let ((heading (format "Tagger: %s <%s>" + (match-string 1) + (match-string 2)))) + (magit-delete-line) + (insert (propertize heading 'font-lock-face + 'magit-section-secondary-heading))) + (magit-insert-heading) + (if (re-search-forward "-----BEGIN PGP SIGNATURE-----" nil t) + (progn + (let ((beg (match-beginning 0))) + (re-search-forward "-----END PGP SIGNATURE-----") + (delete-region beg (point))) + (insert ?\n) + (magit-process-git t "verify-tag" magit-buffer-revision)) + (goto-char (point-max))) + (insert ?\n)))) + +(defvar magit-commit-message-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] 'magit-show-commit) + map) + "Keymap for `commit-message' sections.") + +(defun magit-insert-revision-message () + "Insert the commit message into a revision buffer." + (magit-insert-section section (commit-message) + (oset section heading-highlight-face 'magit-diff-revision-summary-highlight) + (let ((beg (point)) + (rev magit-buffer-revision)) + (insert (with-temp-buffer + (magit-rev-insert-format "%B" rev) + (magit-revision--wash-message))) + (if (= (point) (+ beg 2)) + (progn (backward-delete-char 2) + (insert "(no message)\n")) + (goto-char beg) + (save-excursion + (while (search-forward "\r\n" nil t) ; Remove trailing CRs. + (delete-region (match-beginning 0) (1+ (match-beginning 0))))) + (when magit-revision-fill-summary-line + (let ((fill-column (min magit-revision-fill-summary-line + (window-width)))) + (fill-region (point) (line-end-position)))) + (when magit-revision-use-hash-sections + (save-excursion + (while (not (eobp)) + (re-search-forward "\\_<" nil 'move) + (let ((beg (point))) + (re-search-forward "\\_>" nil t) + (when (> (point) beg) + (let ((text (buffer-substring-no-properties beg (point)))) + (when (pcase magit-revision-use-hash-sections + (`quickest ; false negatives and positives + (and (>= (length text) 7) + (string-match-p "[0-9]" text) + (string-match-p "[a-z]" text))) + (`quicker ; false negatives (number-less hashes) + (and (>= (length text) 7) + (string-match-p "[0-9]" text) + (magit-commit-p text))) + (`quick ; false negatives (short hashes) + (and (>= (length text) 7) + (magit-commit-p text))) + (`slow + (magit-commit-p text))) + (put-text-property beg (point) + 'font-lock-face 'magit-hash) + (let ((end (point))) + (goto-char beg) + (magit-insert-section (commit text) + (goto-char end)))))))))) + (save-excursion + (forward-line) + (magit--add-face-text-property + beg (point) 'magit-diff-revision-summary) + (magit-insert-heading)) + (when magit-diff-highlight-keywords + (save-excursion + (while (re-search-forward "\\[[^[]*\\]" nil t) + (let ((beg (match-beginning 0)) + (end (match-end 0))) + (put-text-property + beg end 'font-lock-face + (if-let ((face (get-text-property beg 'font-lock-face))) + (list face 'magit-keyword) + 'magit-keyword)))))) + (goto-char (point-max)))))) + +(defun magit-insert-revision-notes () + "Insert commit notes into a revision buffer." + (let* ((var "core.notesRef") + (def (or (magit-get var) "refs/notes/commits"))) + (dolist (ref (or (magit-list-active-notes-refs))) + (magit-insert-section section (notes ref (not (equal ref def))) + (oset section heading-highlight-face 'magit-diff-hunk-heading-highlight) + (let ((beg (point)) + (rev magit-buffer-revision)) + (insert (with-temp-buffer + (magit-git-insert "-c" (concat "core.notesRef=" ref) + "notes" "show" rev) + (magit-revision--wash-message))) + (if (= (point) beg) + (magit-cancel-section) + (goto-char beg) + (end-of-line) + (insert (format " (%s)" + (propertize (if (string-prefix-p "refs/notes/" ref) + (substring ref 11) + ref) + 'font-lock-face 'magit-refname))) + (forward-char) + (magit--add-face-text-property beg (point) 'magit-diff-hunk-heading) + (magit-insert-heading) + (goto-char (point-max)) + (insert ?\n))))))) + +(defun magit-revision--wash-message () + (let ((major-mode 'git-commit-mode)) + (hack-dir-local-variables) + (hack-local-variables-apply)) + (unless (memq git-commit-major-mode '(nil text-mode)) + (funcall git-commit-major-mode) + (font-lock-ensure)) + (buffer-string)) + +(defun magit-insert-revision-headers () + "Insert headers about the commit into a revision buffer." + (magit-insert-section (headers) + (--when-let (magit-rev-format "%D" magit-buffer-revision "--decorate=full") + (insert (magit-format-ref-labels it) ?\s)) + (insert (propertize + (magit-rev-parse (concat magit-buffer-revision "^{commit}")) + 'font-lock-face 'magit-hash)) + (magit-insert-heading) + (let ((beg (point))) + (magit-rev-insert-format magit-revision-headers-format + magit-buffer-revision) + (magit-insert-revision-gravatars magit-buffer-revision beg)) + (when magit-revision-insert-related-refs + (dolist (parent (magit-commit-parents magit-buffer-revision)) + (magit-insert-section (commit parent) + (let ((line (magit-rev-format "%h %s" parent))) + (string-match "^\\([^ ]+\\) \\(.*\\)" line) + (magit-bind-match-strings (hash msg) line + (insert "Parent: ") + (insert (propertize hash 'font-lock-face 'magit-hash)) + (insert " " msg "\n"))))) + (magit--insert-related-refs + magit-buffer-revision "--merged" "Merged" + (eq magit-revision-insert-related-refs 'all)) + (magit--insert-related-refs + magit-buffer-revision "--contains" "Contained" + (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))) + (magit-insert-section (tag tag) + (insert + (format "Follows: %s (%s)\n" + (propertize tag 'font-lock-face 'magit-tag) + (propertize (number-to-string cnt) + 'font-lock-face 'magit-branch-local)))))) + (when-let ((precedes (magit-get-next-tag magit-buffer-revision t))) + (let ((tag (car precedes)) + (cnt (cadr precedes))) + (magit-insert-section (tag tag) + (insert (format "Precedes: %s (%s)\n" + (propertize tag 'font-lock-face 'magit-tag) + (propertize (number-to-string cnt) + 'font-lock-face 'magit-tag)))))) + (insert ?\n)))) + +(defun magit--insert-related-refs (rev arg title remote) + (when-let ((refs (magit-list-related-branches arg rev (and remote "-a")))) + (insert title ":" (make-string (- 10 (length title)) ?\s)) + (dolist (branch refs) + (if (<= (+ (current-column) 1 (length branch)) + (window-width)) + (insert ?\s) + (insert ?\n (make-string 12 ?\s))) + (magit-insert-section (branch branch) + (insert (propertize branch 'font-lock-face + (if (string-prefix-p "remotes/" branch) + 'magit-branch-remote + 'magit-branch-local))))) + (insert ?\n))) + +(defun magit-insert-revision-gravatars (rev beg) + (when (and magit-revision-show-gravatars + (window-system)) + (require 'gravatar) + (pcase-let ((`(,author . ,committer) + (pcase magit-revision-show-gravatars + (`t '("^Author: " . "^Commit: ")) + (`author '("^Author: " . nil)) + (`committer '(nil . "^Commit: ")) + (_ magit-revision-show-gravatars)))) + (--when-let (and author (magit-rev-format "%aE" rev)) + (magit-insert-revision-gravatar beg rev it author)) + (--when-let (and committer (magit-rev-format "%cE" rev)) + (magit-insert-revision-gravatar beg rev it committer))))) + +(defun magit-insert-revision-gravatar (beg rev email regexp) + (save-excursion + (goto-char beg) + (when (re-search-forward regexp nil t) + (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)))) + (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 gravatar-size rev + (point-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 + (save-excursion + (goto-char marker) + ;; The buffer might display another revision by now or + ;; it might have been refreshed, in which case another + ;; process might already have inserted the image. + (when (and (equal rev magit-buffer-revision) + (not (eq (car-safe + (car-safe + (get-text-property (point) 'display))) + 'image))) + ;; `image-property' wasn't added until 26.1. + (setcdr image (plist-put (cdr image) :ascent 'center)) + (setcdr image (plist-put (cdr image) :relief 1)) + (setcdr image (plist-put (cdr image) :scale 1)) + (setcdr image (plist-put (cdr image) :height size)) + (let ((top (list image '(slice 0.0 0.0 1.0 0.5))) + (bot (list image '(slice 0.0 0.5 1.0 1.0))) + (align `((space :align-to ,align-to)))) + (when magit-revision-use-gravatar-kludge + (cl-rotatef top bot)) + (let ((inhibit-read-only t)) + (insert (propertize " " 'display top)) + (insert (propertize " " 'display align)) + (forward-line) + (forward-char column) + (insert (propertize " " 'display bot)) + (insert (propertize " " 'display align)))))))))) + +;;; Merge-Preview Mode + +(define-derived-mode magit-merge-preview-mode magit-diff-mode "Magit Merge" + "Mode for previewing a merge." + :group 'magit-diff + (hack-dir-local-variables-non-file-buffer)) + +(put 'magit-merge-preview-mode 'magit-diff-default-arguments + '("--no-ext-diff")) + +(defun magit-merge-preview-setup-buffer (rev) + (magit-setup-buffer #'magit-merge-preview-mode nil + (magit-buffer-revision rev) + (magit-buffer-range (format "%s^..%s" rev rev)))) + +(defun magit-merge-preview-refresh-buffer () + (let* ((branch (magit-get-current-branch)) + (head (or branch (magit-rev-verify "HEAD")))) + (magit-set-header-line-format (format "Preview merge of %s into %s" + magit-buffer-revision + (or branch "HEAD"))) + (magit-insert-section (diffbuf) + (magit--insert-diff + "merge-tree" (magit-git-string "merge-base" head magit-buffer-revision) + head magit-buffer-revision)))) + +(cl-defmethod magit-buffer-value (&context (major-mode magit-merge-preview-mode)) + magit-buffer-revision) + +;;; Diff Sections + +(defun magit-hunk-set-window-start (section) + "When SECTION is a `hunk', ensure that its beginning is visible. +It the SECTION has a different type, then do nothing." + (when (magit-hunk-section-p section) + (magit-section-set-window-start section))) + +(add-hook 'magit-section-movement-hook #'magit-hunk-set-window-start) + +(defun magit-hunk-goto-successor (section arg) + (and (magit-hunk-section-p section) + (when-let ((parent (magit-get-section + (magit-section-ident + (oref section parent))))) + (let* ((children (oref parent children)) + (siblings (magit-section-siblings section 'prev)) + (previous (nth (length siblings) children))) + (if (not arg) + (--when-let (or previous (car (last children))) + (magit-section-goto it) + t) + (when previous + (magit-section-goto previous)) + (if (and (stringp arg) + (re-search-forward arg (oref parent end) t)) + (goto-char (match-beginning 0)) + (goto-char (oref (car (last children)) end)) + (forward-line -1) + (while (looking-at "^ ") (forward-line -1)) + (while (looking-at "^[-+]") (forward-line -1)) + (forward-line))))))) + +(add-hook 'magit-section-goto-successor-hook #'magit-hunk-goto-successor) + +(defvar magit-unstaged-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] 'magit-diff-unstaged) + (define-key map [remap magit-delete-thing] 'magit-discard) + (define-key map "s" 'magit-stage) + (define-key map "u" 'magit-unstage) + map) + "Keymap for the `unstaged' section.") + +(magit-define-section-jumper magit-jump-to-unstaged "Unstaged changes" unstaged) + +(defun magit-insert-unstaged-changes () + "Insert section showing unstaged changes." + (magit-insert-section (unstaged) + (magit-insert-heading "Unstaged changes:") + (magit--insert-diff + "diff" magit-buffer-diff-args "--no-prefix" + "--" magit-buffer-diff-files))) + +(defvar magit-staged-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] 'magit-diff-staged) + (define-key map [remap magit-delete-thing] 'magit-discard) + (define-key map [remap magit-revert-no-commit] 'magit-reverse) + (define-key map "s" 'magit-stage) + (define-key map "u" 'magit-unstage) + map) + "Keymap for the `staged' section.") + +(magit-define-section-jumper magit-jump-to-staged "Staged changes" staged) + +(defun magit-insert-staged-changes () + "Insert section showing staged changes." + ;; Avoid listing all files as deleted when visiting a bare repo. + (unless (magit-bare-repo-p) + (magit-insert-section (staged) + (magit-insert-heading "Staged changes:") + (magit--insert-diff + "diff" "--cached" magit-buffer-diff-args "--no-prefix" + "--" magit-buffer-diff-files)))) + +;;; Diff Type + +(defun magit-diff-type (&optional section) + "Return the diff type of SECTION. + +The returned type is one of the symbols `staged', `unstaged', +`committed', or `undefined'. This type serves a similar purpose +as the general type common to all sections (which is stored in +the `type' slot of the corresponding `magit-section' struct) but +takes additional information into account. When the SECTION +isn't related to diffs and the buffer containing it also isn't +a diff-only buffer, then return nil. + +Currently the type can also be one of `tracked' and `untracked' +but these values are not handled explicitly everywhere they +should be and a possible fix could be to just return nil here. + +The section has to be a `diff' or `hunk' section, or a section +whose children are of type `diff'. If optional SECTION is nil, +return the diff type for the current section. In buffers whose +major mode is `magit-diff-mode' SECTION is ignored and the type +is determined using other means. In `magit-revision-mode' +buffers the type is always `committed'. + +Do not confuse this with `magit-diff-scope' (which see)." + (--when-let (or section (magit-current-section)) + (cond ((derived-mode-p 'magit-revision-mode 'magit-stash-mode) 'committed) + ((derived-mode-p 'magit-diff-mode) + (let ((range magit-buffer-range) + (const magit-buffer-typearg)) + (cond ((equal const "--no-index") 'undefined) + ((or (not range) + (magit-rev-eq range "HEAD")) + (if (equal const "--cached") + 'staged + 'unstaged)) + ((equal const "--cached") + (if (magit-rev-head-p range) + 'staged + 'undefined)) ; i.e. committed and staged + (t 'committed)))) + ((derived-mode-p 'magit-status-mode) + (let ((stype (oref it type))) + (if (memq stype '(staged unstaged tracked untracked)) + stype + (pcase stype + ((or `file `module) + (let* ((parent (oref it parent)) + (type (oref parent type))) + (if (memq type '(file module)) + (magit-diff-type parent) + 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)) + (t 'undefined)))) + +(cl-defun magit-diff-scope (&optional (section nil ssection) strict) + "Return the diff scope of SECTION or the selected section(s). + +A diff's \"scope\" describes what part of a diff is selected, it is +a symbol, one of `region', `hunk', `hunks', `file', `files', or +`list'. Do not confuse this with the diff \"type\", as returned by +`magit-diff-type'. + +If optional SECTION is non-nil, then return the scope of that, +ignoring the sections selected by the region. Otherwise return +the scope of the current section, or if the region is active and +selects a valid group of diff related sections, the type of these +sections, i.e. `hunks' or `files'. If SECTION, or if that is nil +the current section, is a `hunk' section; and the region region +starts and ends inside the body of a that section, then the type +is `region'. If the region is empty after a mouse click, then +`hunk' is returned instead of `region'. + +If optional STRICT is non-nil, then return nil if the diff type of +the section at point is `untracked' or the section at point is not +actually a `diff' but a `diffstat' section." + (let ((siblings (and (not ssection) (magit-region-sections nil t)))) + (setq section (or section (car siblings) (magit-current-section))) + (when (and section + (or (not strict) + (and (not (eq (magit-diff-type section) 'untracked)) + (not (eq (--when-let (oref section parent) + (oref it type)) + 'diffstat))))) + (pcase (list (oref section type) + (and siblings t) + (magit-diff-use-hunk-region-p) + ssection) + (`(hunk nil t ,_) + (if (magit-section-internal-region-p section) 'region 'hunk)) + (`(hunk t t nil) 'hunks) + (`(hunk ,_ ,_ ,_) 'hunk) + (`(file t t nil) 'files) + (`(file ,_ ,_ ,_) 'file) + (`(module t t nil) 'files) + (`(module ,_ ,_ ,_) 'file) + (`(,(or `staged `unstaged `untracked) nil ,_ ,_) 'list))))) + +(defun magit-diff-use-hunk-region-p () + (and (region-active-p) + ;; TODO implement this from first principals + ;; currently it's trial-and-error + (not (and (or (eq this-command 'mouse-drag-region) + (eq last-command 'mouse-drag-region) + ;; When another window was previously + ;; selected then the last-command is + ;; some byte-code function. + (byte-code-function-p last-command)) + (eq (region-end) (region-beginning)))))) + +;;; Diff Highlight + +(add-hook 'magit-section-unhighlight-hook #'magit-diff-unhighlight) +(add-hook 'magit-section-highlight-hook #'magit-diff-highlight) + +(defun magit-diff-unhighlight (section selection) + "Remove the highlighting of the diff-related SECTION." + (when (magit-hunk-section-p section) + (magit-diff-paint-hunk section selection nil) + t)) + +(defun magit-diff-highlight (section selection) + "Highlight the diff-related SECTION. +If SECTION is not a diff-related section, then do nothing and +return nil. If SELECTION is non-nil, then it is a list of sections +selected by the region, including SECTION. All of these sections +are highlighted." + (if (and (magit-section-match 'commit section) + (oref section children)) + (progn (if selection + (dolist (section selection) + (magit-diff-highlight-list section selection)) + (magit-diff-highlight-list section)) + t) + (when-let ((scope (magit-diff-scope section t))) + (cond ((eq scope 'region) + (magit-diff-paint-hunk section selection t)) + (selection + (dolist (section selection) + (magit-diff-highlight-recursive section selection))) + (t + (magit-diff-highlight-recursive section))) + t))) + +(defun magit-diff-highlight-recursive (section &optional selection) + (pcase (magit-diff-scope section) + (`list (magit-diff-highlight-list section selection)) + (`file (magit-diff-highlight-file section selection)) + (`hunk (magit-diff-highlight-heading section selection) + (magit-diff-paint-hunk section selection t)) + (_ (magit-section-highlight section nil)))) + +(defun magit-diff-highlight-list (section &optional selection) + (let ((beg (oref section start)) + (cnt (oref section content)) + (end (oref section end))) + (when (or (eq this-command 'mouse-drag-region) + (not selection)) + (unless (and (region-active-p) + (<= (region-beginning) beg)) + (magit-section-make-overlay beg cnt 'magit-section-highlight)) + (unless (oref section hidden) + (dolist (child (oref section children)) + (when (or (eq this-command 'mouse-drag-region) + (not (and (region-active-p) + (<= (region-beginning) + (oref child start))))) + (magit-diff-highlight-recursive child selection))))) + (when magit-diff-highlight-hunk-body + (magit-section-make-overlay (1- end) end 'magit-section-highlight)))) + +(defun magit-diff-highlight-file (section &optional selection) + (magit-diff-highlight-heading section selection) + (unless (oref section hidden) + (dolist (child (oref section children)) + (magit-diff-highlight-recursive child selection)))) + +(defun magit-diff-highlight-heading (section &optional selection) + (magit-section-make-overlay + (oref section start) + (or (oref section content) + (oref section end)) + (pcase (list (oref section type) + (and (member section selection) + (not (eq this-command 'mouse-drag-region)))) + (`(file t) 'magit-diff-file-heading-selection) + (`(file nil) 'magit-diff-file-heading-highlight) + (`(module t) 'magit-diff-file-heading-selection) + (`(module nil) 'magit-diff-file-heading-highlight) + (`(hunk t) 'magit-diff-hunk-heading-selection) + (`(hunk nil) 'magit-diff-hunk-heading-highlight)))) + +;;; Hunk Paint + +(cl-defun magit-diff-paint-hunk + (section &optional selection + (highlight (magit-section-selected-p section selection))) + (let (paint) + (unless magit-diff-highlight-hunk-body + (setq highlight nil)) + (cond (highlight + (unless (oref section hidden) + (add-to-list 'magit-section-highlighted-sections section) + (cond ((memq section magit-section-unhighlight-sections) + (setq magit-section-unhighlight-sections + (delq section magit-section-unhighlight-sections))) + (magit-diff-highlight-hunk-body + (setq paint t))))) + (t + (cond ((and (oref section hidden) + (memq section magit-section-unhighlight-sections)) + (add-to-list 'magit-section-highlighted-sections section) + (setq magit-section-unhighlight-sections + (delq section magit-section-unhighlight-sections))) + (t + (setq paint t))))) + (when paint + (save-excursion + (goto-char (oref section start)) + (let ((end (oref section end)) + (merging (looking-at "@@@")) + (diff-type (magit-diff-type)) + (stage nil) + (tab-width (magit-diff-tab-width + (magit-section-parent-value section)))) + (forward-line) + (while (< (point) end) + (when (and magit-diff-hide-trailing-cr-characters + (char-equal ?\r (char-before (line-end-position)))) + (put-text-property (1- (line-end-position)) (line-end-position) + 'invisible t)) + (put-text-property + (point) (1+ (line-end-position)) 'font-lock-face + (cond + ((looking-at "^\\+\\+?\\([<=|>]\\)\\{7\\}") + (setq stage (pcase (list (match-string 1) highlight) + (`("<" nil) 'magit-diff-our) + (`("<" t) 'magit-diff-our-highlight) + (`("|" nil) 'magit-diff-base) + (`("|" t) 'magit-diff-base-highlight) + (`("=" nil) 'magit-diff-their) + (`("=" t) 'magit-diff-their-highlight) + (`(">" nil) nil))) + 'magit-diff-conflict-heading) + ((looking-at (if merging "^\\(\\+\\| \\+\\)" "^\\+")) + (magit-diff-paint-tab merging tab-width) + (magit-diff-paint-whitespace merging 'added diff-type) + (or stage + (if highlight 'magit-diff-added-highlight 'magit-diff-added))) + ((looking-at (if merging "^\\(-\\| -\\)" "^-")) + (magit-diff-paint-tab merging tab-width) + (magit-diff-paint-whitespace merging 'removed diff-type) + (if highlight 'magit-diff-removed-highlight 'magit-diff-removed)) + (t + (magit-diff-paint-tab merging tab-width) + (magit-diff-paint-whitespace merging 'context diff-type) + (if highlight 'magit-diff-context-highlight 'magit-diff-context)))) + (forward-line)))))) + (magit-diff-update-hunk-refinement section)) + +(defvar magit-diff--tab-width-cache nil) + +(defun magit-diff-tab-width (file) + (setq file (expand-file-name file)) + (cl-flet ((cache (value) + (let ((elt (assoc file magit-diff--tab-width-cache))) + (if elt + (setcdr elt value) + (setq magit-diff--tab-width-cache + (cons (cons file value) + magit-diff--tab-width-cache)))) + value)) + (cond + ((not magit-diff-adjust-tab-width) + tab-width) + ((--when-let (find-buffer-visiting file) + (cache (buffer-local-value 'tab-width it)))) + ((--when-let (assoc file magit-diff--tab-width-cache) + (or (cdr it) + tab-width))) + ((or (eq magit-diff-adjust-tab-width 'always) + (and (numberp magit-diff-adjust-tab-width) + (>= magit-diff-adjust-tab-width + (nth 7 (file-attributes file))))) + (cache (buffer-local-value 'tab-width (find-file-noselect file)))) + (t + (cache nil) + tab-width)))) + +(defun magit-diff-paint-tab (merging width) + (save-excursion + (forward-char (if merging 2 1)) + (while (= (char-after) ?\t) + (put-text-property (point) (1+ (point)) + 'display (list (list 'space :width width))) + (forward-char)))) + +(defun magit-diff-paint-whitespace (merging line-type diff-type) + (when (and magit-diff-paint-whitespace + (or (not (memq magit-diff-paint-whitespace '(uncommitted status))) + (memq diff-type '(staged unstaged))) + (cl-case line-type + (added t) + (removed (memq magit-diff-paint-whitespace-lines '(all both))) + (context (memq magit-diff-paint-whitespace-lines '(all))))) + (let ((prefix (if merging "^[-\\+\s]\\{2\\}" "^[-\\+\s]")) + (indent + (if (local-variable-p 'magit-diff-highlight-indentation) + magit-diff-highlight-indentation + (setq-local + magit-diff-highlight-indentation + (cdr (--first (string-match-p (car it) default-directory) + (nreverse + (default-value + 'magit-diff-highlight-indentation)))))))) + (when (and magit-diff-highlight-trailing + (looking-at (concat prefix ".*?\\([ \t]+\\)$"))) + (let ((ov (make-overlay (match-beginning 1) (match-end 1) nil t))) + (overlay-put ov 'font-lock-face 'magit-diff-whitespace-warning) + (overlay-put ov 'priority 2) + (overlay-put ov 'evaporate t))) + (when (or (and (eq indent 'tabs) + (looking-at (concat prefix "\\( *\t[ \t]*\\)"))) + (and (integerp indent) + (looking-at (format "%s\\([ \t]* \\{%s,\\}[ \t]*\\)" + prefix indent)))) + (let ((ov (make-overlay (match-beginning 1) (match-end 1) nil t))) + (overlay-put ov 'font-lock-face 'magit-diff-whitespace-warning) + (overlay-put ov 'priority 2) + (overlay-put ov 'evaporate t)))))) + +(defun magit-diff-update-hunk-refinement (&optional section) + (if section + (unless (oref section hidden) + (pcase (list magit-diff-refine-hunk + (oref section refined) + (eq section (magit-current-section))) + ((or `(all nil ,_) `(t nil t)) + (oset section refined t) + (save-excursion + (goto-char (oref section start)) + ;; `diff-refine-hunk' does not handle combined diffs. + (unless (looking-at "@@@") + (let ((smerge-refine-ignore-whitespace + magit-diff-refine-ignore-whitespace) + ;; Avoid fsyncing many small temp files + (write-region-inhibit-fsync t)) + (diff-refine-hunk))))) + ((or `(nil t ,_) `(t t nil)) + (oset section refined nil) + (remove-overlays (oref section start) + (oref section end) + 'diff-mode 'fine)))) + (cl-labels ((recurse (section) + (if (magit-section-match 'hunk section) + (magit-diff-update-hunk-refinement section) + (dolist (child (oref section children)) + (recurse child))))) + (recurse magit-root-section)))) + + +;;; Hunk Region + +(defun magit-diff-hunk-region-beginning () + (save-excursion (goto-char (region-beginning)) + (line-beginning-position))) + +(defun magit-diff-hunk-region-end () + (save-excursion (goto-char (region-end)) + (line-end-position))) + +(defun magit-diff-update-hunk-region (section) + "Highlight the hunk-internal region if any." + (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)) + 'font-lock-face 'magit-diff-lines-heading + 'display (magit-diff-hunk-region-header section) + 'after-string (magit-diff--hunk-after-string 'magit-diff-lines-heading)) + (run-hook-with-args 'magit-diff-highlight-hunk-region-functions section) + t)) + +(defun magit-diff-highlight-hunk-region-dim-outside (section) + "Dim the parts of the hunk that are outside the hunk-internal region. +This is done by using the same foreground and background color +for added and removed lines as for context lines." + (let ((face (if magit-diff-highlight-hunk-body + 'magit-diff-context-highlight + 'magit-diff-context))) + (when magit-diff-unmarked-lines-keep-foreground + (setq face `(,@(and (>= emacs-major-version 27) '(:extend t)) + :background ,(face-attribute face :background)))) + (magit-diff--make-hunk-overlay (oref section content) + (magit-diff-hunk-region-beginning) + 'font-lock-face face + 'priority 2) + (magit-diff--make-hunk-overlay (1+ (magit-diff-hunk-region-end)) + (oref section end) + 'font-lock-face face + 'priority 2))) + +(defun magit-diff-highlight-hunk-region-using-face (_section) + "Highlight the hunk-internal region by making it bold. +Or rather highlight using the face `magit-diff-hunk-region', though +changing only the `:weight' and/or `:slant' is recommended for that +face." + (magit-diff--make-hunk-overlay (magit-diff-hunk-region-beginning) + (1+ (magit-diff-hunk-region-end)) + 'font-lock-face 'magit-diff-hunk-region)) + +(defun magit-diff-highlight-hunk-region-using-overlays (section) + "Emphasize the hunk-internal region using delimiting horizontal lines. +This is implemented as single-pixel newlines places inside overlays." + (if (window-system) + (let ((beg (magit-diff-hunk-region-beginning)) + (end (magit-diff-hunk-region-end)) + (str (propertize + (concat (propertize "\s" 'display '(space :height (1))) + (propertize "\n" 'line-height t)) + 'font-lock-face 'magit-diff-lines-boundary))) + (magit-diff--make-hunk-overlay beg (1+ beg) 'before-string str) + (magit-diff--make-hunk-overlay end (1+ end) 'after-string str)) + (magit-diff-highlight-hunk-region-using-face section))) + +(defun magit-diff-highlight-hunk-region-using-underline (section) + "Emphasize the hunk-internal region using delimiting horizontal lines. +This is implemented by overlining and underlining the first and +last (visual) lines of the region." + (if (window-system) + (let* ((beg (magit-diff-hunk-region-beginning)) + (end (magit-diff-hunk-region-end)) + (beg-eol (save-excursion (goto-char beg) + (end-of-visual-line) + (point))) + (end-bol (save-excursion (goto-char end) + (beginning-of-visual-line) + (point))) + (color (face-background 'magit-diff-lines-boundary nil t))) + (cl-flet ((ln (b e &rest face) + (magit-diff--make-hunk-overlay + b e 'font-lock-face face 'after-string + (magit-diff--hunk-after-string face)))) + (if (= beg end-bol) + (ln beg beg-eol :overline color :underline color) + (ln beg beg-eol :overline color) + (ln end-bol end :underline color)))) + (magit-diff-highlight-hunk-region-using-face section))) + +(defun magit-diff--make-hunk-overlay (start end &rest args) + (let ((ov (make-overlay start end nil t))) + (overlay-put ov 'evaporate t) + (while args (overlay-put ov (pop args) (pop args))) + (push ov magit-section--region-overlays) + ov)) + +(defun magit-diff--hunk-after-string (face) + (propertize "\s" + 'font-lock-face face + 'display (list 'space :align-to + `(+ (0 . right) + ,(min (window-hscroll) + (- (line-end-position) + (line-beginning-position))))) + ;; This prevents the cursor from being rendered at the + ;; edge of the window. + 'cursor t)) + +;;; Hunk Utilities + +(defun magit-diff-inside-hunk-body-p () + "Return non-nil if point is inside the body of a hunk." + (and (magit-section-match 'hunk) + (when-let ((content (oref (magit-current-section) content))) + (> (point) content)))) + +;;; Diff Extract + +(defun magit-diff-file-header (section &optional no-rename) + (when (magit-hunk-section-p section) + (setq section (oref section parent))) + (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))) + (string-match "\n" patch) + (substring patch 0 (1- (match-end 0))))) + +(defun magit-diff-hunk-region-patch (section &optional args) + (let ((op (if (member "--reverse" args) "+" "-")) + (sbeg (oref section start)) + (rbeg (magit-diff-hunk-region-beginning)) + (rend (region-end)) + (send (oref section end)) + (patch nil)) + (save-excursion + (goto-char sbeg) + (while (< (point) send) + (looking-at "\\(.\\)\\([^\n]*\n\\)") + (cond ((or (string-match-p "[@ ]" (match-string-no-properties 1)) + (and (>= (point) rbeg) + (<= (point) rend))) + (push (match-string-no-properties 0) patch)) + ((equal op (match-string-no-properties 1)) + (push (concat " " (match-string-no-properties 2)) patch))) + (forward-line))) + (let ((buffer-list-update-hook nil)) ; #3759 + (with-temp-buffer + (insert (mapconcat #'identity (reverse patch) "")) + (diff-fixup-modifs (point-min) (point-max)) + (setq patch (buffer-string)))) + patch)) + +;;; _ +(provide 'magit-diff) +;;; magit-diff.el ends here diff --git a/elpa/magit-20220116.1908/magit-ediff.el b/elpa/magit-20220116.1908/magit-ediff.el new file mode 100644 index 00000000..97b49cc8 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-ediff.el @@ -0,0 +1,482 @@ +;;; magit-ediff.el --- Ediff extension for Magit -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library provides basic support for Ediff. + +;;; Code: + +(require 'magit) + +(require 'ediff) +(require 'smerge-mode) + +(defvar smerge-ediff-buf) +(defvar smerge-ediff-windows) + +;;; Options + +(defgroup magit-ediff nil + "Ediff support for Magit." + :link '(info-link "(magit)Ediffing") + :group 'magit-extensions) + +(defcustom magit-ediff-quit-hook + '(magit-ediff-cleanup-auxiliary-buffers + magit-ediff-restore-previous-winconf) + "Hooks to run after finishing Ediff, when that was invoked using Magit. +The hooks are run in the Ediff control buffer. This is similar +to `ediff-quit-hook' but takes the needs of Magit into account. +The `ediff-quit-hook' is ignored by Ediff sessions which were +invoked using Magit." + :package-version '(magit . "2.2.0") + :group 'magit-ediff + :type 'hook + :get 'magit-hook-custom-get + :options '(magit-ediff-cleanup-auxiliary-buffers + magit-ediff-restore-previous-winconf)) + +(defcustom magit-ediff-dwim-show-on-hunks nil + "Whether `magit-ediff-dwim' runs show variants on hunks. +If non-nil, `magit-ediff-show-staged' or +`magit-ediff-show-unstaged' are called based on what section the +hunk is in. Otherwise, `magit-ediff-dwim' runs +`magit-ediff-stage' when point is on an uncommitted hunk." + :package-version '(magit . "2.2.0") + :group 'magit-ediff + :type 'boolean) + +(defcustom magit-ediff-show-stash-with-index t + "Whether `magit-ediff-show-stash' shows the state of the index. + +If non-nil, use a third Ediff buffer to distinguish which changes +in the stash were staged. In cases where the stash contains no +staged changes, fall back to a two-buffer Ediff. + +More specifically, a stash is a merge commit, stash@{N}, with +potentially three parents. + +* stash@{N}^1 represents the `HEAD' commit at the time the stash + was created. + +* stash@{N}^2 records any changes that were staged when the stash + was made. + +* stash@{N}^3, if it exists, contains files that were untracked + when stashing. + +If this option is non-nil, `magit-ediff-show-stash' will run +Ediff on a file using three buffers: one for stash@{N}, another +for stash@{N}^1, and a third for stash@{N}^2. + +Otherwise, Ediff uses two buffers, comparing +stash@{N}^1..stash@{N}. Along with any unstaged changes, changes +in the index commit, stash@{N}^2, will be shown in this +comparison unless they conflicted with changes in the working +tree at the time of stashing." + :package-version '(magit . "2.6.0") + :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) +(transient-define-prefix magit-ediff () + "Show differences using the Ediff package." + :info-manual "(ediff)" + ["Ediff" + [("E" "Dwim" magit-ediff-dwim) + ("s" "Stage" magit-ediff-stage) + ("m" "Resolve" magit-ediff-resolve)] + [("u" "Show unstaged" magit-ediff-show-unstaged) + ("i" "Show staged" magit-ediff-show-staged) + ("w" "Show worktree" magit-ediff-show-working-tree)] + [("c" "Show commit" magit-ediff-show-commit) + ("r" "Show range" magit-ediff-compare) + ("z" "Show stash" magit-ediff-show-stash)]]) + +;;;###autoload +(defun magit-ediff-resolve (file) + "Resolve outstanding conflicts in FILE using Ediff. +FILE has to be relative to the top directory of the repository. + +In the rare event that you want to manually resolve all +conflicts, including those already resolved by Git, use +`ediff-merge-revisions-with-ancestor'." + (interactive + (let ((current (magit-current-file)) + (unmerged (magit-unmerged-files))) + (unless unmerged + (user-error "There are no unresolved conflicts")) + (list (magit-completing-read "Resolve file" unmerged nil t nil nil + (car (member current unmerged)))))) + (magit-with-toplevel + (with-current-buffer (find-file-noselect file) + (smerge-ediff) + (setq-local + ediff-quit-hook + (lambda () + (let ((bufC ediff-buffer-C) + (bufS smerge-ediff-buf)) + (with-current-buffer bufS + (when (yes-or-no-p (format "Conflict resolution finished; save %s? " + buffer-file-name)) + (erase-buffer) + (insert-buffer-substring bufC) + (save-buffer)))) + (when (buffer-live-p ediff-buffer-A) (kill-buffer ediff-buffer-A)) + (when (buffer-live-p ediff-buffer-B) (kill-buffer ediff-buffer-B)) + (when (buffer-live-p ediff-buffer-C) (kill-buffer ediff-buffer-C)) + (when (buffer-live-p ediff-ancestor-buffer) + (kill-buffer ediff-ancestor-buffer)) + (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. +FILE has to be relative to the top directory of the repository." + (interactive + (let ((files (magit-tracked-files))) + (list (magit-completing-read "Selectively stage file" files nil t nil nil + (car (member (magit-current-file) files)))))) + (magit-with-toplevel + (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 + (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) + "Compare REVA:FILEA with REVB:FILEB using Ediff. + +FILEA and FILEB have to be relative to the top directory of the +repository. If REVA or REVB is nil, then this stands for the +working tree state. + +If the region is active, use the revisions on the first and last +line of the region. With a prefix argument, instead of diffing +the revisions, choose a revision to view changes along, starting +at the common ancestor of both revisions (i.e., use a \"...\" +range)." + (interactive + (pcase-let ((`(,revA ,revB) (magit-ediff-compare--read-revisions + nil current-prefix-arg))) + (nconc (list revA revB) + (magit-ediff-read-files revA revB)))) + (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 + "Compare range or commit" + nil mbase)))) + (--if-let (magit-split-range input) + (-cons-to-list it) + (list input nil)))) + +(defun magit-ediff-read-files (revA revB &optional fileB) + "Read file in REVB, return it and the corresponding file in REVA. +When FILEB is non-nil, use this as REVB's file instead of +prompting for it." + (unless fileB + (setq fileB (magit-read-file-choice + (format "File to compare between %s and %s" + revA (or revB "the working tree")) + (magit-changed-files revA revB) + (format "No changed files between %s and %s" + revA (or revB "the working tree"))))) + (list (or (car (member fileB (magit-revision-files revA))) + (cdr (assoc fileB (magit-renamed-files revB revA))) + (magit-read-file-choice + (format "File in %s to compare with %s in %s" + revA fileB (or revB "the working tree")) + (magit-changed-files revB revA) + (format "No files have changed between %s and %s" + revA revB))) + fileB)) + +;;;###autoload +(defun magit-ediff-dwim () + "Compare, stage, or resolve using Ediff. +This command tries to guess what file, and what commit or range +the user wants to compare, stage, or resolve using Ediff. It +might only be able to guess either the file, or range or commit, +in which case the user is asked about the other. It might not +always guess right, in which case the appropriate `magit-ediff-*' +command has to be used explicitly. If it cannot read the user's +mind at all, then it asks the user for a command to run." + (interactive) + (magit-section-case + (hunk (save-excursion + (goto-char (oref (oref it parent) start)) + (magit-ediff-dwim))) + (t + (let ((range (magit-diff--dwim)) + (file (magit-current-file)) + command revA revB) + (pcase range + ((and (guard (not magit-ediff-dwim-show-on-hunks)) + (or `unstaged `staged)) + (setq command (if (magit-anything-unmerged-p) + #'magit-ediff-resolve + #'magit-ediff-stage))) + (`unstaged (setq command #'magit-ediff-show-unstaged)) + (`staged (setq command #'magit-ediff-show-staged)) + (`(commit . ,value) + (setq command #'magit-ediff-show-commit) + (setq revB value)) + (`(stash . ,value) + (setq command #'magit-ediff-show-stash) + (setq revB value)) + ((pred stringp) + (pcase-let ((`(,a ,b) (magit-ediff-compare--read-revisions range))) + (setq command #'magit-ediff-compare) + (setq revA a) + (setq revB b))) + (_ + (when (derived-mode-p 'magit-diff-mode) + (pcase (magit-diff-type) + (`committed (pcase-let ((`(,a ,b) + (magit-ediff-compare--read-revisions + magit-buffer-range))) + (setq revA a) + (setq revB b))) + ((guard (not magit-ediff-dwim-show-on-hunks)) + (setq command #'magit-ediff-stage)) + (`unstaged (setq command #'magit-ediff-show-unstaged)) + (`staged (setq command #'magit-ediff-show-staged)) + (`undefined (setq command nil)) + (_ (setq command nil)))))) + (cond ((not command) + (call-interactively + (magit-read-char-case + "Failed to read your mind; do you want to " t + (?c "[c]ommit" 'magit-ediff-show-commit) + (?r "[r]ange" 'magit-ediff-compare) + (?s "[s]tage" 'magit-ediff-stage) + (?v "resol[v]e" 'magit-ediff-resolve)))) + ((eq command 'magit-ediff-compare) + (apply 'magit-ediff-compare revA revB + (magit-ediff-read-files revA revB file))) + ((eq command 'magit-ediff-show-commit) + (magit-ediff-show-commit revB)) + ((eq command 'magit-ediff-show-stash) + (magit-ediff-show-stash revB)) + (file + (funcall command file)) + (t + (call-interactively command))))))) + +;;;###autoload +(defun magit-ediff-show-staged (file) + "Show staged changes using Ediff. + +This only allows looking at the changes; to stage, unstage, +and discard changes using Ediff, use `magit-ediff-stage'. + +FILE must be relative to the top directory of the repository." + (interactive + (list (magit-read-file-choice "Show staged changes for file" + (magit-staged-files) + "No staged files"))) + (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) + "Show unstaged changes using Ediff. + +This only allows looking at the changes; to stage, unstage, +and discard changes using Ediff, use `magit-ediff-stage'. + +FILE must be relative to the top directory of the repository." + (interactive + (list (magit-read-file-choice "Show unstaged changes for file" + (magit-unstaged-files) + "No unstaged files"))) + (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) + "Show changes between `HEAD' and working tree using Ediff. +FILE must be relative to the top directory of the repository." + (interactive + (list (magit-read-file-choice "Show changes in file" + (magit-changed-files "HEAD") + "No changed files"))) + (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) + "Show changes introduced by COMMIT using Ediff." + (interactive (list (magit-read-branch-or-commit "Revision"))) + (let ((revA (concat commit "^")) + (revB commit)) + (apply #'magit-ediff-compare + revA revB + (magit-ediff-read-files revA revB (magit-current-file))))) + +;;;###autoload +(defun magit-ediff-show-stash (stash) + "Show changes introduced by STASH using Ediff. +`magit-ediff-show-stash-with-index' controls whether a +three-buffer Ediff is used in order to distinguish changes in the +stash that were staged." + (interactive (list (magit-read-stash "Stash"))) + (pcase-let* ((revA (concat stash "^1")) + (revB (concat stash "^2")) + (revC stash) + (`(,fileA ,fileC) (magit-ediff-read-files revA revC)) + (fileB fileC)) + (if (and magit-ediff-show-stash-with-index + (member fileA (magit-changed-files revB revA))) + (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 () + (let* ((ctl-buf ediff-control-buffer) + (ctl-win (ediff-get-visible-buffer-window ctl-buf)) + (ctl-frm ediff-control-frame) + (main-frame (cond ((window-live-p ediff-window-A) + (window-frame ediff-window-A)) + ((window-live-p ediff-window-B) + (window-frame ediff-window-B))))) + (ediff-kill-buffer-carefully ediff-diff-buffer) + (ediff-kill-buffer-carefully ediff-custom-diff-buffer) + (ediff-kill-buffer-carefully ediff-fine-diff-buffer) + (ediff-kill-buffer-carefully ediff-tmp-buffer) + (ediff-kill-buffer-carefully ediff-error-buffer) + (ediff-kill-buffer-carefully ediff-msg-buffer) + (ediff-kill-buffer-carefully ediff-debug-buffer) + (when (boundp 'ediff-patch-diagnostics) + (ediff-kill-buffer-carefully ediff-patch-diagnostics)) + (cond ((and (ediff-window-display-p) + (frame-live-p ctl-frm)) + (delete-frame ctl-frm)) + ((window-live-p ctl-win) + (delete-window ctl-win))) + (ediff-kill-buffer-carefully ctl-buf) + (when (frame-live-p main-frame) + (select-frame main-frame)))) + +(defun magit-ediff-restore-previous-winconf () + (set-window-configuration magit-ediff-previous-winconf)) + +;;; _ +(provide 'magit-ediff) +;;; magit-ediff.el ends here diff --git a/elpa/magit-20220116.1908/magit-extras.el b/elpa/magit-20220116.1908/magit-extras.el new file mode 100644 index 00000000..a7966d1a --- /dev/null +++ b/elpa/magit-20220116.1908/magit-extras.el @@ -0,0 +1,837 @@ +;;; magit-extras.el --- additional functionality for Magit -*- lexical-binding: t -*- + +;; Copyright (C) 2008-2022 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. + +;;; Commentary: + +;; Additional functionality for Magit. + +;;; Code: + +(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." + :group 'magit-extensions) + +;;; External Tools + +(defcustom magit-gitk-executable + (or (and (eq system-type 'windows-nt) + (let ((exe (magit-git-string + "-c" "alias.X=!x() { which \"$1\" | cygpath -mf -; }; x" + "X" "gitk.exe"))) + (and exe (file-executable-p exe) exe))) + (executable-find "gitk") "gitk") + "The Gitk executable." + :group 'magit-extras + :set-after '(magit-git-executable) + :type 'string) + +;;;###autoload +(defun magit-run-git-gui () + "Run `git gui' for the current git repository." + (interactive) + (magit-with-toplevel (magit-process-git 0 "gui"))) + +;;;###autoload +(defun magit-run-git-gui-blame (commit filename &optional linenum) + "Run `git gui blame' on the given FILENAME and COMMIT. +Interactively run it for the current file and the `HEAD', with a +prefix or when the current file cannot be determined let the user +choose. When the current buffer is visiting FILENAME instruct +blame to center around the line point is on." + (interactive + (let (revision filename) + (when (or current-prefix-arg + (not (setq revision "HEAD" + filename (magit-file-relative-name nil 'tracked)))) + (setq revision (magit-read-branch-or-commit "Blame from revision")) + (setq filename (magit-read-file-from-rev revision "Blame file"))) + (list revision filename + (and (equal filename + (ignore-errors + (magit-file-relative-name buffer-file-name))) + (line-number-at-pos))))) + (magit-with-toplevel + (magit-process-git 0 "gui" "blame" + (and linenum (list (format "--line=%d" linenum))) + commit + filename))) + +;;;###autoload +(defun magit-run-gitk () + "Run `gitk' in the current repository." + (interactive) + (magit-process-file magit-gitk-executable nil 0)) + +;;;###autoload +(defun magit-run-gitk-branches () + "Run `gitk --branches' in the current repository." + (interactive) + (magit-process-file magit-gitk-executable nil 0 nil "--branches")) + +;;;###autoload +(defun magit-run-gitk-all () + "Run `gitk --all' in the current repository." + (interactive) + (magit-process-file magit-gitk-executable nil 0 nil "--all")) + +;;; Emacs Tools + +;;;###autoload +(defun ido-enter-magit-status () + "Drop into `magit-status' from file switching. + +This command does not work in Emacs 26.1. +See https://github.com/magit/magit/issues/3634 +and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31707. + +To make this command available use something like: + + (add-hook \\='ido-setup-hook + (lambda () + (define-key ido-completion-map + (kbd \"C-x g\") \\='ido-enter-magit-status))) + +Starting with Emacs 25.1 the Ido keymaps are defined just once +instead of every time Ido is invoked, so now you can modify it +like pretty much every other keymap: + + (define-key ido-common-completion-map + (kbd \"C-x g\") \\='ido-enter-magit-status)" + (interactive) + (setq ido-exit 'fallback) + (setq ido-fallback 'magit-status) ; for Emacs >= 26.2 + (with-no-warnings (setq fallback 'magit-status)) ; for Emacs 25 + (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 +is no file at point, then instead visit `default-directory'." + (interactive "P") + (dired-jump other-window + (when-let ((file (magit-file-at-point))) + (expand-file-name (if (file-directory-p file) + (file-name-as-directory file) + file))))) + +;;;###autoload +(defun magit-dired-log (&optional follow) + "Show log for all marked files, or the current file." + (interactive "P") + (if-let ((topdir (magit-toplevel default-directory))) + (let ((args (car (magit-log-arguments))) + (files (dired-get-marked-files nil nil #'magit-file-tracked-p))) + (unless files + (user-error "No marked file is being tracked by Git")) + (when (and follow + (not (member "--follow" args)) + (not (cdr files))) + (push "--follow" args)) + (magit-log-setup-buffer + (list (or (magit-get-current-branch) "HEAD")) + args + (let ((default-directory topdir)) + (mapcar #'file-relative-name files)) + magit-log-buffer-file-locked)) + (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." + (interactive (list (or (magit-file-at-point) + (completing-read "Act on file: " + (magit-list-files))))) + (require 'dired-aux) + (dired-do-async-shell-command + (dired-read-shell-command "& on %s: " current-prefix-arg (list file)) + nil (list file))) + +;;; Shift Selection + +(defun magit--turn-on-shift-select-mode-p () + (and shift-select-mode + this-command-keys-shift-translated + (not mark-active) + (not (eq (car-safe transient-mark-mode) 'only)))) + +;;;###autoload +(defun magit-previous-line (&optional arg try-vscroll) + "Like `previous-line' but with Magit-specific shift-selection. + +Magit's selection mechanism is based on the region but selects an +area that is larger than the region. This causes `previous-line' +when invoked while holding the shift key to move up one line and +thereby select two lines. When invoked inside a hunk body this +command does not move point on the first invocation and thereby +it only selects a single line. Which inconsistency you prefer +is a matter of preference." + (declare (interactive-only + "use `forward-line' with negative argument instead.")) + (interactive "p\np") + (unless arg (setq arg 1)) + (let ((stay (or (magit-diff-inside-hunk-body-p) + (magit-section-position-in-heading-p)))) + (if (and stay (= arg 1) (magit--turn-on-shift-select-mode-p)) + (push-mark nil nil t) + (with-no-warnings + (handle-shift-selection) + (previous-line (if stay (max (1- arg) 1) arg) try-vscroll))))) + +;;;###autoload +(defun magit-next-line (&optional arg try-vscroll) + "Like `next-line' but with Magit-specific shift-selection. + +Magit's selection mechanism is based on the region but selects +an area that is larger than the region. This causes `next-line' +when invoked while holding the shift key to move down one line +and thereby select two lines. When invoked inside a hunk body +this command does not move point on the first invocation and +thereby it only selects a single line. Which inconsistency you +prefer is a matter of preference." + (declare (interactive-only forward-line)) + (interactive "p\np") + (unless arg (setq arg 1)) + (let ((stay (or (magit-diff-inside-hunk-body-p) + (magit-section-position-in-heading-p)))) + (if (and stay (= arg 1) (magit--turn-on-shift-select-mode-p)) + (push-mark nil nil t) + (with-no-warnings + (handle-shift-selection) + (next-line (if stay (max (1- arg) 1) arg) try-vscroll))))) + +;;; Clean + +;;;###autoload +(defun magit-clean (&optional arg) + "Remove untracked files from the working tree. +With a prefix argument also remove ignored files, +with two prefix arguments remove ignored files only. +\n(git clean -f -d [-x|-X])" + (interactive "p") + (when (yes-or-no-p (format "Remove %s files? " + (pcase arg + (1 "untracked") + (4 "untracked and ignored") + (_ "ignored")))) + (magit-wip-commit-before-change) + (magit-run-git "clean" "-f" "-d" (pcase arg (4 "-x") (16 "-X"))))) + +(put 'magit-clean 'disabled t) + +;;; ChangeLog + +;;;###autoload +(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. +This differs from `add-change-log-entry' (which see) in that +it acts on the current hunk in a Magit buffer instead of on +a position in a file-visiting buffer." + (interactive (list current-prefix-arg + (prompt-for-change-log-name))) + (pcase-let ((`(,buf ,pos) (magit-diff-visit-file--noselect))) + (magit--with-temp-position buf pos + (let ((add-log-buffer-file-name-function + (lambda () + (or magit-buffer-file-name + (buffer-file-name))))) + (add-change-log-entry whoami file-name other-window))))) + +;;;###autoload +(defun magit-add-change-log-entry-other-window (&optional whoami file-name) + "Find change log file in other window and add entry and item. +This differs from `add-change-log-entry-other-window' (which see) +in that it acts on the current hunk in a Magit buffer instead of +on a position in a file-visiting buffer." + (interactive (and current-prefix-arg + (list current-prefix-arg + (prompt-for-change-log-name)))) + (magit-add-change-log-entry whoami file-name t)) + +;;; Edit Line Commit + +;;;###autoload +(defun magit-edit-line-commit (&optional type) + "Edit the commit that added the current line. + +With a prefix argument edit the commit that removes the line, +if any. The commit is determined using `git blame' and made +editable using `git rebase --interactive' if it is reachable +from `HEAD', or by checking out the commit (or a branch that +points at it) otherwise." + (interactive (list (and current-prefix-arg 'removal))) + (let* ((chunk (magit-current-blame-chunk (or type 'addition))) + (rev (oref chunk orig-rev))) + (if (equal rev "0000000000000000000000000000000000000000") + (message "This line has not been committed yet") + (let ((rebase (magit-rev-ancestor-p rev "HEAD")) + (file (expand-file-name (oref chunk orig-file) + (magit-toplevel)))) + (if rebase + (let ((magit--rebase-published-symbol 'edit-published)) + (magit-rebase-edit-commit rev (magit-rebase-arguments))) + (magit-checkout (or (magit-rev-branch rev) rev))) + (unless (and buffer-file-name + (file-equal-p file buffer-file-name)) + (let ((blame-type (and magit-blame-mode magit-blame-type))) + (if rebase + (set-process-sentinel + magit-this-process + (lambda (process event) + (magit-sequencer-process-sentinel process event) + (when (eq (process-status process) 'exit) + (find-file file) + (when blame-type + (magit-blame--pre-blame-setup blame-type) + (magit-blame--run (magit-blame-arguments)))))) + (find-file file) + (when blame-type + (magit-blame--pre-blame-setup blame-type) + (magit-blame--run (magit-blame-arguments)))))))))) + +(put 'magit-edit-line-commit 'disabled t) + +;;;###autoload +(defun magit-diff-edit-hunk-commit (file) + "From a hunk, edit the respective commit and visit the file. + +First visit the file being modified by the hunk at the correct +location using `magit-diff-visit-file'. This actually visits a +blob. When point is on a diff header, not within an individual +hunk, then this visits the blob the first hunk is about. + +Then invoke `magit-edit-line-commit', which uses an interactive +rebase to make the commit editable, or if that is not possible +because the commit is not reachable from `HEAD' by checking out +that commit directly. This also causes the actual worktree file +to be visited. + +Neither the blob nor the file buffer are killed when finishing +the rebase. If that is undesirable, then it might be better to +use `magit-rebase-edit-command' instead of this command." + (interactive (list (magit-file-at-point t t))) + (let ((magit-diff-visit-previous-blob nil)) + (with-current-buffer + (magit-diff-visit-file--internal file nil #'pop-to-buffer-same-window) + (magit-edit-line-commit)))) + +(put 'magit-diff-edit-hunk-commit 'disabled t) + +;;; 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 keyid) + "Change the author and committer dates of the commits since REV. + +Ask the user for the first reachable commit whose dates should +be changed. Then read the new date for that commit. The initial +minibuffer input and the previous history element offer good +values. The next commit will be created one minute later and so +on. + +This command is only intended for interactive use and should only +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 + (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) + (when (memq (process-status process) '(exit signal)) + (if (> (process-exit-status process) 0) + (magit-process-sentinel process event) + (process-put process 'inhibit-refresh t) + (magit-process-sentinel process event) + (magit-run-git "update-ref" "-d" backup)))))))))))) + +;;; Revision Stack + +(defvar magit-revision-stack nil) + +(defcustom magit-pop-revision-stack-format + '("[%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 +of the revision last pushed to the `magit-revision-stack' into +the current buffer. It inserts text at point and/or near the end +of the buffer, and removes the consumed revision from the stack. + +The entries on the stack have the format (HASH TOPLEVEL) and this +option has the format (POINT-FORMAT EOB-FORMAT INDEX-REGEXP), all +of which may be nil or a string (though either one of EOB-FORMAT +or POINT-FORMAT should be a string, and if INDEX-REGEXP is +non-nil, then the two formats should be too). + +First INDEX-REGEXP is used to find the previously inserted entry, +by searching backward from point. The first submatch must match +the index number. That number is incremented by one, and becomes +the index number of the entry to be inserted. If you don't want +to number the inserted revisions, then use nil for INDEX-REGEXP. + +If INDEX-REGEXP is non-nil, then both POINT-FORMAT and EOB-FORMAT +should contain \"%N\", which is replaced with the number that was +determined in the previous step. + +Both formats, if non-nil and after removing %N, are then expanded +using `git show --format=FORMAT ...' inside TOPLEVEL. + +The expansion of POINT-FORMAT is inserted at point, and the +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 . "3.2.0") + :group 'magit-commands + :type '(list (choice (string :tag "Insert at point format") + (cons (string :tag "Insert at point format") + (repeat (string :tag "Argument to git show"))) + (const :tag "Don't insert at point" nil)) + (choice (string :tag "Insert at eob format") + (cons (string :tag "Insert at eob format") + (repeat (string :tag "Argument to git show"))) + (const :tag "Don't insert at eob" nil)) + (choice (regexp :tag "Find index regexp") + (const :tag "Don't number entries" nil)))) + +(defcustom magit-copy-revision-abbreviated nil + "Whether to save abbreviated revision to `kill-ring' and `magit-revision-stack'." + :package-version '(magit . "3.0.0") + :group 'magit-miscellaneous + :type 'boolean) + +;;;###autoload +(defun magit-pop-revision-stack (rev toplevel) + "Insert a representation of a revision into the current buffer. + +Pop a revision from the `magit-revision-stack' and insert it into +the current buffer according to `magit-pop-revision-stack-format'. +Revisions can be put on the stack using `magit-copy-section-value' +and `magit-copy-buffer-revision'. + +If the stack is empty or with a prefix argument, instead read a +revision in the minibuffer. By using the minibuffer history this +allows selecting an item which was popped earlier or to insert an +arbitrary reference or revision without first pushing it onto the +stack. + +When reading the revision from the minibuffer, then it might not +be possible to guess the correct repository. When this command +is called inside a repository (e.g. while composing a commit +message), then that repository is used. Otherwise (e.g. while +composing an email) then the repository recorded for the top +element of the stack is used (even though we insert another +revision). If not called inside a repository and with an empty +stack, or with two prefix arguments, then read the repository in +the minibuffer too." + (interactive + (if (or current-prefix-arg (not magit-revision-stack)) + (let ((default-directory + (or (and (not (= (prefix-numeric-value current-prefix-arg) 16)) + (or (magit-toplevel) + (cadr (car magit-revision-stack)))) + (magit-read-repository)))) + (list (magit-read-branch-or-commit "Insert revision") + default-directory)) + (push (caar magit-revision-stack) magit-revision-history) + (pop magit-revision-stack))) + (if rev + (pcase-let ((`(,pnt-format ,eob-format ,idx-format) + magit-pop-revision-stack-format)) + (let ((default-directory toplevel) + (idx (and idx-format + (save-excursion + (if (re-search-backward idx-format nil t) + (number-to-string + (1+ (string-to-number (match-string 1)))) + "1")))) + pnt-args eob-args) + (when (listp pnt-format) + (setq pnt-args (cdr pnt-format)) + (setq pnt-format (car pnt-format))) + (when (listp eob-format) + (setq eob-args (cdr eob-format)) + (setq eob-format (car eob-format))) + (when pnt-format + (when idx-format + (setq pnt-format + (replace-regexp-in-string "%N" idx pnt-format t t))) + (magit-rev-insert-format pnt-format rev pnt-args) + (backward-delete-char 1)) + (when eob-format + (when idx-format + (setq eob-format + (replace-regexp-in-string "%N" idx eob-format t t))) + (save-excursion + (goto-char (point-max)) + (skip-syntax-backward ">s-") + (beginning-of-line) + (if (and comment-start (looking-at comment-start)) + (while (looking-at comment-start) + (forward-line -1)) + (forward-line) + (unless (= (current-column) 0) + (insert ?\n))) + (insert ?\n) + (magit-rev-insert-format eob-format rev eob-args) + (backward-delete-char 1))))) + (user-error "Revision stack is empty"))) + +(define-key git-commit-mode-map + (kbd "C-c C-w") 'magit-pop-revision-stack) + +;;;###autoload +(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 +the current section is a commit, branch, or tag section, push +the (referenced) revision to the `magit-revision-stack' for use +with `magit-pop-revision-stack'. + +When `magit-copy-revision-abbreviated' is non-nil, save the +abbreviated revision to the `kill-ring' and the +`magit-revision-stack'. + +When the current section is a branch or a tag, and a prefix +argument is used, then save the revision at its tip to the +`kill-ring' instead of the reference name. + +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, 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 arg + (magit-section-internal-region-p) + (magit-section-match 'hunk)) + (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 + (when-let ((section (magit-current-section)) + (value (oref section value))) + (magit-section-case + ((branch commit module-commit tag) + (let ((default-directory default-directory) ref) + (magit-section-case + ((branch tag) + (setq ref value)) + (module-commit + (setq default-directory + (file-name-as-directory + (expand-file-name (magit-section-parent-value section) + (magit-toplevel)))))) + (setq value (magit-rev-parse + (and magit-copy-revision-abbreviated "--short") + value)) + (push (list value default-directory) magit-revision-stack) + (kill-new (message "%s" (or (and current-prefix-arg ref) + value))))) + (t (kill-new (message "%s" value)))))))) + +;;;###autoload +(defun magit-copy-buffer-revision () + "Save the revision of the current buffer for later use. + +Save the revision shown in the current buffer to the `kill-ring' +and push it to the `magit-revision-stack'. + +This command is mainly intended for use in `magit-revision-mode' +buffers, the only buffers where it is always unambiguous exactly +which revision should be saved. + +Most other Magit buffers usually show more than one revision, in +some way or another, so this command has to select one of them, +and that choice might not always be the one you think would have +been the best pick. + +In such buffers it is often more useful to save the value of +the current section instead, using `magit-copy-section-value'. + +When the region is active, then save that to the `kill-ring', +like `kill-ring-save' would, instead of behaving as described +above. + +When `magit-copy-revision-abbreviated' is non-nil, save the +abbreviated revision to the `kill-ring' and the +`magit-revision-stack'." + (interactive) + (if (use-region-p) + (call-interactively #'copy-region-as-kill) + (when-let ((rev (or magit-buffer-revision + (cl-case major-mode + (magit-diff-mode + (if (string-match "\\.\\.\\.?\\(.+\\)" + magit-buffer-range) + (match-string 1 magit-buffer-range) + magit-buffer-range)) + (magit-status-mode "HEAD"))))) + (when (magit-commit-p rev) + (setq rev (magit-rev-parse + (and magit-copy-revision-abbreviated "--short") + rev)) + (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 +(defun magit-abort-dwim () + "Abort current operation. +Depending on the context, this will abort a merge, a rebase, a +patch application, a cherry-pick, a revert, or a bisect." + (interactive) + (cond ((magit-merge-in-progress-p) (magit-merge-abort)) + ((magit-rebase-in-progress-p) (magit-rebase-abort)) + ((magit-am-in-progress-p) (magit-am-abort)) + ((magit-sequencer-in-progress-p) (magit-sequencer-abort)) + ((magit-bisect-in-progress-p) (magit-bisect-reset)))) + +;;; _ +(provide 'magit-extras) +;;; magit-extras.el ends here diff --git a/elpa/magit-20220116.1908/magit-fetch.el b/elpa/magit-20220116.1908/magit-fetch.el new file mode 100644 index 00000000..3cbd008d --- /dev/null +++ b/elpa/magit-20220116.1908/magit-fetch.el @@ -0,0 +1,203 @@ +;;; magit-fetch.el --- download objects and refs -*- lexical-binding: t -*- + +;; Copyright (C) 2008-2022 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. + +;;; Commentary: + +;; This library implements fetch commands. + +;;; Code: + +(require 'magit) + +(defvar magit-fetch-modules-jobs nil) +(make-obsolete-variable + 'magit-fetch-modules-jobs + "invoke `magit-fetch-modules' with a prefix argument instead." + "Magit 3.0.0") + +;;; Commands + +;;;###autoload (autoload 'magit-fetch "magit-fetch" nil t) +(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")) + (7 "-u" "Fetch full history" "--unshallow")] + ["Fetch from" + ("p" magit-fetch-from-pushremote) + ("u" magit-fetch-from-upstream) + ("e" "elsewhere" magit-fetch-other) + ("a" "all remotes" magit-fetch-all)] + ["Fetch" + ("o" "another branch" magit-fetch-branch) + ("r" "explicit refspec" magit-fetch-refspec) + ("m" "submodules" magit-fetch-modules)] + ["Configure" + ("C" "variables..." magit-branch-configure)]) + +(defun magit-fetch-arguments () + (transient-args 'magit-fetch)) + +(defun magit-git-fetch (remote args) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "fetch" remote args)) + +;;;###autoload (autoload 'magit-fetch-from-pushremote "magit-fetch" nil t) +(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 +configured or unusable, then let the user first configure the +push-remote." + :description 'magit-fetch--pushremote-description + (interactive (list (magit-fetch-arguments))) + (let ((remote (magit-get-push-remote))) + (when (or current-prefix-arg + (not (member remote (magit-list-remotes)))) + (let ((var (magit--push-remote-variable))) + (setq remote + (magit-read-remote (format "Set %s and fetch from there" var))) + (magit-set remote var))) + (magit-git-fetch remote args))) + +(defun magit-fetch--pushremote-description () + (let* ((branch (magit-get-current-branch)) + (remote (magit-get-push-remote branch)) + (v (magit--push-remote-variable branch t))) + (cond + ((member remote (magit-list-remotes)) remote) + (remote + (format "%s, replacing invalid" v)) + (t + (format "%s, setting that" v))))) + +;;;###autoload (autoload 'magit-fetch-from-upstream "magit-fetch" nil t) +(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 +an existing remote, then use that. Otherwise try to use another +remote: If only a single remote is configured, then use that. +Otherwise if a remote named \"origin\" exists, then use that. + +If no remote can be determined, then this command is not available +from the `magit-fetch' transient prefix and invoking it directly +results in an error." + :if (lambda () (magit-get-current-remote t)) + :description (lambda () (magit-get-current-remote t)) + (interactive (list (magit-get-current-remote t) + (magit-fetch-arguments))) + (unless remote + (error "The \"current\" remote could not be determined")) + (magit-git-fetch remote args)) + +;;;###autoload +(defun magit-fetch-other (remote args) + "Fetch from another repository." + (interactive (list (magit-read-remote "Fetch remote") + (magit-fetch-arguments))) + (magit-git-fetch remote args)) + +;;;###autoload +(defun magit-fetch-branch (remote branch args) + "Fetch a BRANCH from a REMOTE." + (interactive + (let ((remote (magit-read-remote-or-url "Fetch from remote or url"))) + (list remote + (magit-read-remote-branch "Fetch branch" remote) + (magit-fetch-arguments)))) + (magit-git-fetch remote (cons branch args))) + +;;;###autoload +(defun magit-fetch-refspec (remote refspec args) + "Fetch a REFSPEC from a REMOTE." + (interactive + (let ((remote (magit-read-remote-or-url "Fetch from remote or url"))) + (list remote + (magit-read-refspec "Fetch using refspec" remote) + (magit-fetch-arguments)))) + (magit-git-fetch remote (cons refspec args))) + +;;;###autoload +(defun magit-fetch-all (args) + "Fetch from all remotes." + (interactive (list (magit-fetch-arguments))) + (magit-git-fetch nil (cons "--all" args))) + +;;;###autoload +(defun magit-fetch-all-prune () + "Fetch from all remotes, and prune. +Prune remote tracking branches for branches that have been +removed on the respective remote." + (interactive) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "remote" "update" "--prune")) + +;;;###autoload +(defun magit-fetch-all-no-prune () + "Fetch from all remotes." + (interactive) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "remote" "update")) + +;;;###autoload (autoload 'magit-fetch-modules "magit-fetch" nil t) +(transient-define-prefix magit-fetch-modules (&optional transient args) + "Fetch all submodules. + +Fetching is done using \"git fetch --recurse-submodules\", which +means that the super-repository and recursively all submodules +are also fetched. + +To set and potentially save other arguments invoke this command +with a prefix argument." + :man-page "git-fetch" + :value (list "--verbose" + (cond (magit-fetch-modules-jobs + (format "--jobs=%s" magit-fetch-modules-jobs)) + (t "--jobs=4"))) + ["Arguments" + ("-v" "verbose" "--verbose") + ("-a" "all remotes" "--all") + ("-j" "number of jobs" "--jobs=" :reader transient-read-number-N+)] + ["Action" + ("m" "fetch modules" magit-fetch-modules)] + (interactive (if current-prefix-arg + (list t) + (list nil (transient-args 'magit-fetch-modules)))) + (if transient + (transient-setup 'magit-fetch-modules) + (when (magit-git-version< "2.8.0") + (when-let ((value (transient-arg-value "--jobs=" args))) + (message "Dropping --jobs; not supported by Git v%s" + (magit-git-version)) + (setq args (remove (format "--jobs=%s" value) args)))) + (magit-with-toplevel + (magit-run-git-async "fetch" "--recurse-submodules" args)))) + +;;; _ +(provide 'magit-fetch) +;;; magit-fetch.el ends here diff --git a/elpa/magit-20220116.1908/magit-files.el b/elpa/magit-20220116.1908/magit-files.el new file mode 100644 index 00000000..2b91c8ef --- /dev/null +++ b/elpa/magit-20220116.1908/magit-files.el @@ -0,0 +1,529 @@ +;;; magit-files.el --- finding files -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements support for finding blobs, staged files, +;; and Git configuration files. It also implements modes useful in +;; buffers visiting files and blobs, and the commands used by those +;; modes. + +;;; Code: + +(require 'magit) + +;;; Find Blob + +(defvar magit-find-file-hook nil) +(add-hook 'magit-find-file-hook #'magit-blob-mode) + +;;;###autoload +(defun magit-find-file (rev file) + "View FILE from REV. +Switch to a buffer visiting blob REV:FILE, creating one if none +already exists. If prior to calling this command the current +buffer and/or cursor position is about the same file, then go +to the line and column corresponding to that location." + (interactive (magit-find-file-read-args "Find file")) + (magit-find-file--internal rev file #'pop-to-buffer-same-window)) + +;;;###autoload +(defun magit-find-file-other-window (rev file) + "View FILE from REV, in another window. +Switch to a buffer visiting blob REV:FILE, creating one if none +already exists. If prior to calling this command the current +buffer and/or cursor position is about the same file, then go to +the line and column corresponding to that location." + (interactive (magit-find-file-read-args "Find file in other window")) + (magit-find-file--internal rev file #'switch-to-buffer-other-window)) + +;;;###autoload +(defun magit-find-file-other-frame (rev file) + "View FILE from REV, in another frame. +Switch to a buffer visiting blob REV:FILE, creating one if none +already exists. If prior to calling this command the current +buffer and/or cursor position is about the same file, then go to +the line and column corresponding to that location." + (interactive (magit-find-file-read-args "Find file in other frame")) + (magit-find-file--internal rev file #'switch-to-buffer-other-frame)) + +(defun magit-find-file-read-args (prompt) + (let ((pseudo-revs '("{worktree}" "{index}"))) + (if-let ((rev (magit-completing-read "Find file from revision" + (append pseudo-revs + (magit-list-refnames nil t)) + nil nil nil 'magit-revision-history + (or (magit-branch-or-commit-at-point) + (magit-get-current-branch))))) + (list rev (magit-read-file-from-rev (if (member rev pseudo-revs) + "HEAD" + rev) + prompt)) + (user-error "Nothing selected")))) + +(defun magit-find-file--internal (rev file fn) + (let ((buf (magit-find-file-noselect rev file)) + line col) + (when-let ((visited-file (magit-file-relative-name))) + (setq line (line-number-at-pos)) + (setq col (current-column)) + (cond + ((not (equal visited-file file))) + ((equal magit-buffer-revision rev)) + ((equal rev "{worktree}") + (setq line (magit-diff-visit--offset file magit-buffer-revision line))) + ((equal rev "{index}") + (setq line (magit-diff-visit--offset file nil line))) + (magit-buffer-revision + (setq line (magit-diff-visit--offset + file (concat magit-buffer-revision ".." rev) line))) + (t + (setq line (magit-diff-visit--offset file (list "-R" rev) line))))) + (funcall fn buf) + (when line + (with-current-buffer buf + (widen) + (goto-char (point-min)) + (forward-line (1- line)) + (move-to-column col))) + buf)) + +(defun magit-find-file-noselect (rev file) + "Read FILE from REV into a buffer and return the buffer. +REV is a revision or one of \"{worktree}\" or \"{index}\". +FILE must be relative to the top directory of the repository." + (magit-find-file-noselect-1 rev file)) + +(defun magit-find-file-noselect-1 (rev file &optional revert) + "Read FILE from REV into a buffer and return the buffer. +REV is a revision or one of \"{worktree}\" or \"{index}\". +FILE must be relative to the top directory of the repository. +Non-nil REVERT means to revert the buffer. If `ask-revert', +then only after asking. A non-nil value for REVERT is ignored if REV is +\"{worktree}\"." + (if (equal rev "{worktree}") + (find-file-noselect (expand-file-name file (magit-toplevel))) + (let ((topdir (magit-toplevel))) + (when (file-name-absolute-p file) + (setq file (file-relative-name file topdir))) + (with-current-buffer (magit-get-revision-buffer-create rev file) + (when (or (not magit-buffer-file-name) + (if (eq revert 'ask-revert) + (y-or-n-p (format "%s already exists; revert it? " + (buffer-name)))) + revert) + (setq magit-buffer-revision + (if (equal rev "{index}") + "{index}" + (magit-rev-format "%H" rev))) + (setq magit-buffer-refname rev) + (setq magit-buffer-file-name (expand-file-name file topdir)) + (setq default-directory + (let ((dir (file-name-directory magit-buffer-file-name))) + (if (file-exists-p dir) dir topdir))) + (setq-local revert-buffer-function #'magit-revert-rev-file-buffer) + (revert-buffer t t) + (run-hooks (if (equal rev "{index}") + 'magit-find-index-hook + 'magit-find-file-hook))) + (current-buffer))))) + +(defun magit-get-revision-buffer-create (rev file) + (magit-get-revision-buffer rev file t)) + +(defun magit-get-revision-buffer (rev file &optional create) + (funcall (if create 'get-buffer-create 'get-buffer) + (format "%s.~%s~" file (subst-char-in-string ?/ ?_ rev)))) + +(defun magit-revert-rev-file-buffer (_ignore-auto noconfirm) + (when (or noconfirm + (and (not (buffer-modified-p)) + (catch 'found + (dolist (regexp revert-without-query) + (when (string-match regexp magit-buffer-file-name) + (throw 'found t))))) + (yes-or-no-p (format "Revert buffer from Git %s? " + (if (equal magit-buffer-refname "{index}") + "index" + (concat "revision " magit-buffer-refname))))) + (let* ((inhibit-read-only t) + (default-directory (magit-toplevel)) + (file (file-relative-name magit-buffer-file-name)) + (coding-system-for-read (or coding-system-for-read 'undecided))) + (erase-buffer) + (magit-git-insert "cat-file" "-p" + (if (equal magit-buffer-refname "{index}") + (concat ":" file) + (concat magit-buffer-refname ":" file))) + (setq buffer-file-coding-system last-coding-system-used)) + (let ((buffer-file-name magit-buffer-file-name) + (after-change-major-mode-hook + (remq 'global-diff-hl-mode-enable-in-buffers + after-change-major-mode-hook))) + (normal-mode t)) + (setq buffer-read-only t) + (set-buffer-modified-p nil) + (goto-char (point-min)))) + +;;; Find Index + +(defvar magit-find-index-hook nil) + +(defun magit-find-file-index-noselect (file &optional revert) + "Read FILE from the index into a buffer and return the buffer. +FILE must to be relative to the top directory of the repository." + (magit-find-file-noselect-1 "{index}" file (or revert 'ask-revert))) + +(defun magit-update-index () + "Update the index with the contents of the current buffer. +The current buffer has to be visiting a file in the index, which +is done using `magit-find-index-noselect'." + (interactive) + (let ((file (magit-file-relative-name))) + (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-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")) + (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"))) + (message "Abort"))) + (--when-let (magit-get-mode-buffer 'magit-status-mode) + (with-current-buffer it (magit-refresh))) + t) + +;;; Find Config File + +(defun magit-find-git-config-file (filename &optional wildcards) + "Edit a file located in the current repository's git directory. + +When \".git\", located at the root of the working tree, is a +regular file, then that makes it cumbersome to open a file +located in the actual git directory. + +This command is like `find-file', except that it temporarily +binds `default-directory' to the actual git directory, while +reading the FILENAME." + (interactive + (let ((default-directory (magit-git-dir))) + (find-file-read-args "Find file: " + (confirm-nonexistent-file-or-buffer)))) + (find-file filename wildcards)) + +(defun magit-find-git-config-file-other-window (filename &optional wildcards) + "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 +located in the actual git directory. + +This command is like `find-file-other-window', except that it +temporarily binds `default-directory' to the actual git +directory, while reading the FILENAME." + (interactive + (let ((default-directory (magit-git-dir))) + (find-file-read-args "Find file in other window: " + (confirm-nonexistent-file-or-buffer)))) + (find-file-other-window filename wildcards)) + +(defun magit-find-git-config-file-other-frame (filename &optional wildcards) + "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 +located in the actual git directory. + +This command is like `find-file-other-frame', except that it +temporarily binds `default-directory' to the actual git +directory, while reading the FILENAME." + (interactive + (let ((default-directory (magit-git-dir))) + (find-file-read-args "Find file in other frame: " + (confirm-nonexistent-file-or-buffer)))) + (find-file-other-frame filename wildcards)) + +;;; File Dispatch + +;;;###autoload (autoload 'magit-file-dispatch "magit" nil t) +(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) + ("u" "Unstage" magit-unstage-file) + ("c" "Commit" magit-commit) + ("e" "Edit line" magit-edit-line-commit)] + [("D" "Diff..." magit-diff) + ("d" "Diff" magit-diff-buffer-file) + ("g" "Status" magit-status-here)] + [("L" "Log..." magit-log) + ("l" "Log" magit-log-buffer-file) + ("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) + ("f" "...reverse" magit-blame-reverse) + ("m" "Blame echo" magit-blame-echo) + ("q" "Quit blame" magit-blame-quit)] + [("p" "Prev blob" magit-blob-previous) + ("n" "Next blob" magit-blob-next) + ("v" "Goto blob" magit-find-file) + ("V" "Goto file" magit-blob-visit-file)] + [(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)]] + (interactive) + (transient-setup + (if (magit-file-relative-name) + 'magit-file-dispatch + 'magit-dispatch))) + +;;; Blob Mode + +(defvar magit-blob-mode-map + (let ((map (make-sparse-keymap))) + (define-key map "p" 'magit-blob-previous) + (define-key map "n" 'magit-blob-next) + (define-key map "b" 'magit-blame-addition) + (define-key map "r" 'magit-blame-removal) + (define-key map "f" 'magit-blame-reverse) + (define-key map "q" 'magit-kill-this-buffer) + map) + "Keymap for `magit-blob-mode'.") + +(define-minor-mode magit-blob-mode + "Enable some Magit features in blob-visiting buffers. + +Currently this only adds the following key bindings. +\n\\{magit-blob-mode-map}" + :package-version '(magit . "2.3.0")) + +(defun magit-blob-next () + "Visit the next blob which modified the current file." + (interactive) + (if magit-buffer-file-name + (magit-blob-visit (or (magit-blob-successor magit-buffer-revision + magit-buffer-file-name) + magit-buffer-file-name)) + (if (buffer-file-name (buffer-base-buffer)) + (user-error "You have reached the end of time") + (user-error "Buffer isn't visiting a file or blob")))) + +(defun magit-blob-previous () + "Visit the previous blob which modified the current file." + (interactive) + (if-let ((file (or magit-buffer-file-name + (buffer-file-name (buffer-base-buffer))))) + (--if-let (magit-blob-ancestor magit-buffer-revision file) + (magit-blob-visit it) + (user-error "You have reached the beginning of time")) + (user-error "Buffer isn't visiting a file or blob"))) + +;;;###autoload +(defun magit-blob-visit-file () + "View the file from the worktree corresponding to the current blob. +When visiting a blob or the version from the index, then go to +the same location in the respective file in the working tree." + (interactive) + (if-let ((file (magit-file-relative-name))) + (magit-find-file--internal "{worktree}" file #'pop-to-buffer-same-window) + (user-error "Not visiting a blob"))) + +(defun magit-blob-visit (blob-or-file) + (if (stringp blob-or-file) + (find-file blob-or-file) + (pcase-let ((`(,rev ,file) blob-or-file)) + (magit-find-file rev file) + (apply #'message "%s (%s %s ago)" + (magit-rev-format "%s" rev) + (magit--age (magit-rev-format "%ct" rev)))))) + +(defun magit-blob-ancestor (rev file) + (let ((lines (magit-with-toplevel + (magit-git-lines "log" "-2" "--format=%H" "--name-only" + "--follow" (or rev "HEAD") "--" file)))) + (if rev (cddr lines) (butlast lines 2)))) + +(defun magit-blob-successor (rev file) + (let ((lines (magit-with-toplevel + (magit-git-lines "log" "--format=%H" "--name-only" "--follow" + "HEAD" "--" file)))) + (catch 'found + (while lines + (if (equal (nth 2 lines) rev) + (throw 'found (list (nth 0 lines) (nth 1 lines))) + (setq lines (nthcdr 2 lines))))))) + +;;; File Commands + +(defun magit-file-rename (file newname) + "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 "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)) + (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 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) + (magit-convert-filename-for-git newname)) + (rename-file file newname current-prefix-arg)) + (when oldbuf + (with-current-buffer oldbuf + (let ((buffer-read-only buffer-read-only)) + (set-visited-file-name dstfile nil t)) + (if (fboundp 'vc-refresh-state) + (vc-refresh-state) + (with-no-warnings + (vc-find-file-hook)))))) + (magit-refresh)) + +(defun magit-file-untrack (files &optional force) + "Untrack the selected FILES or one file read in the minibuffer. + +With a prefix argument FORCE do so even when the files have +staged as well as unstaged changes." + (interactive (list (or (--if-let (magit-region-values 'file t) + (progn + (unless (magit-file-tracked-p (car it)) + (user-error "Already untracked")) + (magit-confirm-files 'untrack it "Untrack")) + (list (magit-read-tracked-file "Untrack file")))) + current-prefix-arg)) + (magit-with-toplevel + (magit-run-git "rm" "--cached" (and force "--force") "--" files))) + +(defun magit-file-delete (files &optional force) + "Delete the selected FILES or one file read in the minibuffer. + +With a prefix argument FORCE do so even when the files have +uncommitted changes. When the files aren't being tracked in +Git, then fallback to using `delete-file'." + (interactive (list (--if-let (magit-region-values 'file t) + (magit-confirm-files 'delete it "Delete") + (list (magit-read-file "Delete file"))) + current-prefix-arg)) + (if (magit-file-tracked-p (car files)) + (magit-call-git "rm" (and force "--force") "--" files) + (let ((topdir (magit-toplevel))) + (dolist (file files) + (delete-file (expand-file-name file topdir) t)))) + (magit-refresh)) + +;;;###autoload +(defun magit-file-checkout (rev file) + "Checkout FILE from REV." + (interactive + (let ((rev (magit-read-branch-or-commit + "Checkout from revision" magit-buffer-revision))) + (list rev (magit-read-file-from-rev rev "Checkout file")))) + (magit-with-toplevel + (magit-run-git "checkout" rev "--" file))) + +;;; Read File + +(defvar magit-read-file-hist nil) + +(defun magit-read-file-from-rev (rev prompt &optional default) + (let ((files (magit-revision-files rev))) + (magit-completing-read + prompt files nil t nil 'magit-read-file-hist + (car (member (or default (magit-current-file)) files))))) + +(defun magit-read-file (prompt &optional tracked-only) + (let ((choices (nconc (magit-list-files) + (unless tracked-only (magit-untracked-files))))) + (magit-completing-read + prompt choices nil t nil nil + (car (member (or (magit-section-value-if '(file submodule)) + (magit-file-relative-name nil tracked-only)) + choices))))) + +(defun magit-read-tracked-file (prompt) + (magit-read-file prompt t)) + +(defun magit-read-file-choice (prompt files &optional error default) + "Read file from FILES. + +If FILES has only one member, return that instead of prompting. +If FILES has no members, give a user error. ERROR can be given +to provide a more informative error. + +If DEFAULT is non-nil, use this as the default value instead of +`magit-current-file'." + (pcase (length files) + (0 (user-error (or error "No file choices"))) + (1 (car files)) + (_ (magit-completing-read + prompt files nil t nil 'magit-read-file-hist + (car (member (or default (magit-current-file)) files)))))) + +(defun magit-read-changed-file (rev-or-range prompt &optional default) + (magit-read-file-choice + prompt + (magit-changed-files rev-or-range) + default + (concat "No file changed in " rev-or-range))) + +;;; _ +(provide 'magit-files) +;;; magit-files.el ends here diff --git a/elpa/magit-20220116.1908/magit-git.el b/elpa/magit-20220116.1908/magit-git.el new file mode 100644 index 00000000..80e2e30f --- /dev/null +++ b/elpa/magit-20220116.1908/magit-git.el @@ -0,0 +1,2501 @@ +;;; magit-git.el --- Git functionality -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements wrappers for various Git plumbing commands. + +;;; Code: + +(require 'magit-utils) +(require 'magit-section) + +;; From `magit-branch'. +(defvar magit-branch-prefer-remote-upstream) +(defvar magit-published-branches) + +;; From `magit-margin'. +(declare-function magit-maybe-make-margin-overlay "magit-margin" ()) + +;; From `magit-mode'. +(declare-function magit-get-mode-buffer "magit-mode" + (mode &optional value frame)) +(declare-function magit-refresh "magit-mode" ()) +(defvar magit-buffer-diff-args) +(defvar magit-buffer-file-name) +(defvar magit-buffer-log-args) +(defvar magit-buffer-log-files) +(defvar magit-buffer-refname) +(defvar magit-buffer-revision) + +;; From `magit-process'. +(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" + (process &optional infile buffer display &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) +(defvar magit-process-error-message-regexps) + +;; 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 + +(defvar magit-inhibit-libgit nil + "Whether to inhibit the use of libgit.") + +(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 'unknown) + (setq magit--libgit-available-p + (and module-file-suffix + (let ((libgit (locate-library "libgit"))) + (and libgit + (or (locate-library "libegit2") + (let ((load-path + (cons (expand-file-name + (convert-standard-filename "build") + (file-name-directory libgit)) + load-path))) + (locate-library "libegit2"))))))) + magit--libgit-available-p)) + +(defun magit-gitimpl () + "Return the Git implementation used in this repository." + (if (and (not magit-inhibit-libgit) + (not (file-remote-p default-directory)) + (magit--libgit-available-p)) + 'libgit + 'git)) + +;;; Options + +;; For now this is shared between `magit-process' and `magit-git'. +(defgroup magit-process nil + "Git and other external processes used by Magit." + :group 'magit) + +(defvar magit-git-environment + (list (format "INSIDE_EMACS=%s,magit" emacs-version)) + "Prepended to `process-environment' while running git.") + +(defcustom magit-git-output-coding-system + (and (eq system-type 'windows-nt) 'utf-8) + "Coding system for receiving output from Git. + +If non-nil, the Git config value `i18n.logOutputEncoding' should +be set via `magit-git-global-arguments' to value consistent with +this." + :package-version '(magit . "2.9.0") + :group 'magit-process + :type '(choice (coding-system :tag "Coding system to decode Git output") + (const :tag "Use system default" nil))) + +(defvar magit-git-w32-path-hack nil + "Alist of (EXE . (PATHENTRY)). +This specifies what additional PATH setting needs to be added to +the environment in order to run the non-wrapper git executables +successfully.") + +(defcustom magit-git-executable + (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 + ;; ask it for native paths. + (let* ((core-exe + (car + (process-lines + it "-c" + "alias.X=!x() { which \"$1\" | cygpath -mf -; }; x" + "X" "git"))) + (hack-entry (assoc core-exe magit-git-w32-path-hack)) + ;; Running the libexec/git-core executable + ;; requires some extra PATH entries. + (path-hack + (list (concat "PATH=" + (car (process-lines + it "-c" + "alias.P=!cygpath -wp \"$PATH\"" + "P")))))) + ;; The defcustom STANDARD expression can be + ;; evaluated many times, so make sure it is + ;; idempotent. + (if hack-entry + (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 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) + +(defcustom magit-git-global-arguments + `("--no-pager" "--literal-pathspecs" + "-c" "core.preloadindex=true" + "-c" "log.showSignature=false" + "-c" "color.ui=false" + "-c" "color.diff=false" + ,@(and (eq system-type 'windows-nt) + (list "-c" "i18n.logOutputEncoding=UTF-8"))) + "Global Git arguments. + +The arguments set here are used every time the git executable is +run as a subprocess. They are placed right after the executable +itself and before the git command - as in `git HERE... COMMAND +REST'. See the manpage `git(1)' for valid arguments. + +Be careful what you add here, especially if you are using Tramp +to connect to servers with ancient Git versions. Never remove +anything that is part of the default value, unless you really +know what you are doing. And think very hard before adding +something; it will be used every time Magit runs Git for any +purpose." + :package-version '(magit . "2.9.0") + :group 'magit-commands + :group 'magit-process + :type '(repeat string)) + +(defvar magit-git-debug nil + "Whether to enable additional reporting of git errors. + +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 \ +\\\\[magit-process]. + +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. + +Also see `magit-process-extreme-logging'.") + +(defcustom magit-prefer-remote-upstream nil + "Whether to favor remote branches when reading the upstream branch. + +This controls whether commands that read a branch from the user +and then set it as the upstream branch, offer a local or a remote +branch as default completion candidate, when they have the choice. + +This affects all commands that use `magit-read-upstream-branch' +or `magit-read-starting-point', which includes most commands +that change the upstream and many that create new branches." + :package-version '(magit . "2.4.2") + :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. + +This affects commands that read a ref. More specifically, it +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. By default, refs are sorted according to +their full refname (i.e., 'refs/...'). + +Any value accepted by the `--sort' flag of `git for-each-ref' can +be used. For example, \"-creatordate\" places refs with more +recent committer or tagger dates earlier in the list. A list of +strings can also be given in order to pass multiple sort keys to +`git for-each-ref'. + +Note that, depending on the completion framework you use, this +may not be sufficient to change the order in which the refs are +displayed. It only controls the order of the collection passed +to `magit-completing-read' or, for commands that support reading +multiple strings, `read-from-minibuffer'. The completion +framework ultimately determines how the collection is displayed." + :package-version '(magit . "2.11.0") + :group 'magit-miscellaneous + :type '(choice string (repeat string))) + +;;; Git + +(defvar magit--refresh-cache nil) + +(defmacro magit--with-refresh-cache (key &rest body) + (declare (indent 1) (debug (form body))) + (let ((k (cl-gensym))) + `(if magit--refresh-cache + (let ((,k ,key)) + (--if-let (assoc ,k (cdr magit--refresh-cache)) + (progn (cl-incf (caar magit--refresh-cache)) + (cdr it)) + (cl-incf (cdar magit--refresh-cache)) + (let ((value ,(macroexp-progn body))) + (push (cons ,k value) + (cdr magit--refresh-cache)) + value))) + ,@body))) + +(defvar magit-with-editor-envvar "GIT_EDITOR" + "The environment variable exported by `magit-with-editor'. +Set this to \"GIT_SEQUENCE_EDITOR\" if you do not want to use +Emacs to edit commit messages but would like to do so to edit +rebase sequences.") + +(defmacro magit-with-editor (&rest body) + "Like `with-editor' but let-bind some more variables. +Also respect the value of `magit-with-editor-envvar'." + (declare (indent 0) (debug (body))) + `(let ((magit-process-popup-time -1) + ;; The user may have customized `shell-file-name' to + ;; something which results in `w32-shell-dos-semantics' nil + ;; (which changes the quoting style used by + ;; `shell-quote-argument'), but Git for Windows expects shell + ;; quoting in the dos style. + (shell-file-name (if (and (eq system-type 'windows-nt) + ;; If we have Cygwin mount points, + ;; the git flavor is cygwin, so dos + ;; shell quoting is probably wrong. + (not magit-cygwin-mount-points)) + "cmdproxy" + shell-file-name))) + (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. + +Magit has many specialized functions for running Git; they all +pass arguments through this function before handing them to Git, +to do the following. + +* Flatten ARGS, removing nil arguments. +* Prepend `magit-git-global-arguments' to ARGS. +* On w32 systems, encode to `w32-ansi-code-page'." + (setq args (append magit-git-global-arguments (-flatten args))) + (if (and (eq system-type 'windows-nt) (boundp 'w32-ansi-code-page)) + ;; On w32, the process arguments *must* be encoded in the + ;; current code-page (see #3250). + (mapcar (lambda (arg) + (encode-coding-string + arg (intern (format "cp%d" w32-ansi-code-page)))) + args) + args)) + +(defun magit-git-exit-code (&rest args) + "Execute Git with ARGS, returning its exit code." + (magit-process-git nil args)) + +(defun magit-git-success (&rest args) + "Execute Git with ARGS, returning t if its exit code is 0." + (= (magit-git-exit-code args) 0)) + +(defun magit-git-failure (&rest args) + "Execute Git with ARGS, returning t if its exit code is 1." + (= (magit-git-exit-code args) 1)) + +(defun magit-git-string-p (&rest args) + "Execute Git with ARGS, returning the first line of its output. +If the exit code isn't zero or if there is no output, then return +nil. Neither of these results is considered an error; if that is +what you want, then use `magit-git-string-ng' instead. + +This is an experimental replacement for `magit-git-string', and +still subject to major changes." + (magit--with-refresh-cache (cons default-directory args) + (magit--with-temp-process-buffer + (and (zerop (magit-process-git t args)) + (not (bobp)) + (progn + (goto-char (point-min)) + (buffer-substring-no-properties (point) (line-end-position))))))) + +(defun magit-git-string-ng (&rest args) + "Execute Git with ARGS, returning the first line of its output. +If the exit code isn't zero or if there is no output, then that +is considered an error, but instead of actually signaling an +error, return nil. Additionally the output is put in the process +buffer (creating it if necessary) and the error message is shown +in the status buffer (provided it exists). + +This is an experimental replacement for `magit-git-string', and +still subject to major changes. Also see `magit-git-string-p'." + (magit--with-refresh-cache + (list default-directory 'magit-git-string-ng args) + (magit--with-temp-process-buffer + (let* ((args (magit-process-git-arguments args)) + (status (magit-process-git t args))) + (if (zerop status) + (and (not (bobp)) + (progn + (goto-char (point-min)) + (buffer-substring-no-properties + (point) (line-end-position)))) + (let ((buf (current-buffer))) + (with-current-buffer (magit-process-buffer t) + (magit-process-insert-section default-directory + magit-git-executable args + status buf))) + (when-let ((status-buf (magit-get-mode-buffer 'magit-status-mode))) + (let ((msg (magit--locate-error-message))) + (with-current-buffer status-buf + (setq magit-this-error msg)))) + nil))))) + +(defun magit-git-str (&rest args) + "Execute Git with ARGS, returning the first line of its output. +If there is no output, return nil. If the output begins with a +newline, return an empty string. Like `magit-git-string' but +ignore `magit-git-debug'." + (setq args (-flatten args)) + (magit--with-refresh-cache (cons default-directory 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)))))) + +(defun magit-git-output (&rest args) + "Execute Git with ARGS, returning its output." + (setq args (-flatten args)) + (magit--with-refresh-cache (cons default-directory 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") + +(defun magit-git-true (&rest args) + "Execute Git with ARGS, returning t if it prints \"true\". +If it prints \"false\", then return nil. For any other output +signal `magit-invalid-git-boolean'." + (pcase (magit-git-output args) + ((or "true" "true\n") t) + ((or "false" "false\n") nil) + (output (signal 'magit-invalid-git-boolean (list output))))) + +(defun magit-git-false (&rest args) + "Execute Git with ARGS, returning t if it prints \"false\". +If it prints \"true\", then return nil. For any other output +signal `magit-invalid-git-boolean'." + (pcase (magit-git-output args) + ((or "true" "true\n") nil) + ((or "false" "false\n") t) + (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. +If Git exits with a non-zero exit status, then show a message and +add a section in the respective process buffer." + (setq args (magit-process-git-arguments args)) + (if magit-git-debug + (let (log) + (unwind-protect + (progn + (setq log (make-temp-file "magit-stderr")) + (delete-file log) + (let ((exit (magit-process-git (list t log) args))) + (when (> exit 0) + (let ((msg "Git failed")) + (when (file-exists-p log) + (setq msg (with-temp-buffer + (insert-file-contents log) + (goto-char (point-max)) + (if (functionp magit-git-debug) + (funcall magit-git-debug (buffer-string)) + (magit--locate-error-message)))) + (let ((magit-git-debug nil)) + (with-current-buffer (magit-process-buffer t) + (magit-process-insert-section default-directory + magit-git-executable + args exit log)))) + (message "%s" msg))) + exit)) + (ignore-errors (delete-file log)))) + (magit-process-git (list t nil) args))) + +(defun magit--locate-error-message () + (goto-char (point-max)) + (and (run-hook-wrapped 'magit-process-error-message-regexps + (lambda (re) (re-search-backward re nil t))) + (match-string-no-properties 1))) + +(defun magit-git-string (&rest args) + "Execute Git with ARGS, returning the first line of its output. +If there is no output, return nil. If the output begins with a +newline, return an empty string." + (setq args (-flatten args)) + (magit--with-refresh-cache (cons default-directory args) + (magit--with-temp-process-buffer + (apply #'magit-git-insert args) + (unless (bobp) + (goto-char (point-min)) + (buffer-substring-no-properties (point) (line-end-position)))))) + +(defun magit-git-lines (&rest args) + "Execute Git with ARGS, returning its output as a list of lines. +Empty lines anywhere in the output are omitted. + +If Git exits with a non-zero exit status, then report show a +message and add a section in the respective process buffer." + (magit--with-temp-process-buffer + (apply #'magit-git-insert args) + (split-string (buffer-string) "\n" t))) + +(defun magit-git-items (&rest args) + "Execute Git with ARGS, returning its null-separated output as a list. +Empty items anywhere in the output are omitted. + +If Git exits with a non-zero exit status, then report show a +message and add a section in the respective process buffer." + (magit--with-temp-process-buffer + (apply #'magit-git-insert args) + (split-string (buffer-string) "\0" t))) + +(defun magit-git-wash (washer &rest args) + "Execute Git with ARGS, inserting washed output at point. +Actually first insert the raw output at point. If there is no +output, call `magit-cancel-section'. Otherwise temporarily narrow +the buffer to the inserted text, move to its beginning, and then +call function WASHER with ARGS as its sole argument." + (declare (indent 1)) + (let ((beg (point))) + (setq args (-flatten args)) + (magit-git-insert args) + (if (= (point) beg) + (magit-cancel-section) + (unless (bolp) + (insert "\n")) + (save-restriction + (narrow-to-region beg (point)) + (goto-char beg) + (funcall washer args)) + (when (or (= (point) beg) + (= (point) (1+ beg))) + (magit-cancel-section)) + (magit-maybe-make-margin-overlay)))) + +(defun magit-git-version (&optional raw) + "Return the installed Git version." + (--when-let (let (magit-git-global-arguments) + (ignore-errors (substring (magit-git-string "version") 12))) + (if raw it (and (string-match "\\`\\([0-9]+\\(\\.[0-9]+\\)\\{1,2\\}\\)" it) + (match-string 1 it))))) + +(defun magit-git-version>= (n) + "Return t if `magit-git-version's value is greater than or equal to N." + (magit--version>= (magit-git-version) n)) + +(defun magit-git-version< (n) + "Return t if `magit-git-version's value is smaller than N." + (version< (magit-git-version) n)) + +;;; Variables + +(defun magit-config-get-from-cached-list (key) + (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)) + (magit--with-refresh-cache (cons (magit-toplevel) 'config) + (let ((configs (make-hash-table :test 'equal))) + (dolist (conf (magit-git-items "config" "--list" "-z")) + (let* ((nl-pos (cl-position ?\n conf)) + (key (substring conf 0 nl-pos)) + (val (if nl-pos (substring conf (1+ nl-pos)) ""))) + (puthash key (nconc (gethash key configs) (list val)) configs))) + configs)))) + +(defun magit-get (&rest keys) + "Return the value of the Git variable specified by KEYS." + (car (last (apply 'magit-get-all keys)))) + +(defun magit-get-all (&rest keys) + "Return all values of the Git variable specified by KEYS." + (let ((magit-git-debug nil) + (arg (and (or (null (car keys)) + (string-prefix-p "--" (car keys))) + (pop keys))) + (key (mapconcat 'identity keys "."))) + (if (and magit--refresh-cache (not arg)) + (magit-config-get-from-cached-list key) + (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. +Also see `magit-git-config-p'." + (let ((key (mapconcat 'identity keys "."))) + (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." + (let ((arg (and (or (null (car keys)) + (string-prefix-p "--" (car keys))) + (pop keys))) + (key (mapconcat 'identity keys "."))) + (if value + (magit-git-success "config" arg key value) + (magit-git-success "config" arg "--unset" key)) + value)) + +(gv-define-setter magit-get (val &rest keys) + `(magit-set ,val ,@keys)) + +(defun magit-set-all (values &rest keys) + "Set all values of the Git variable specified by KEYS to VALUES." + (let ((arg (and (or (null (car keys)) + (string-prefix-p "--" (car keys))) + (pop keys))) + (var (mapconcat 'identity keys "."))) + (when (magit-get var) + (magit-call-git "config" arg "--unset-all" var)) + (dolist (v values) + (magit-call-git "config" arg "--add" var v)))) + +;;; Files + +(defun magit--safe-default-directory (&optional file) + (catch 'unsafe-default-dir + (let ((dir (file-name-as-directory + (expand-file-name (or file default-directory)))) + (previous nil)) + (while (not (magit-file-accessible-directory-p dir)) + (setq dir (file-name-directory (directory-file-name dir))) + (when (equal dir previous) + (throw 'unsafe-default-dir nil)) + (setq previous dir)) + dir))) + +(defmacro magit--with-safe-default-directory (file &rest body) + (declare (indent 1) (debug (form body))) + `(when-let ((default-directory (magit--safe-default-directory ,file))) + ,@body)) + +(defun magit-gitdir (&optional directory) + "Return the absolute and resolved path of the .git directory. + +If the `GIT_DIR' environment variable is define then return that. +Otherwise return the .git directory for DIRECTORY, or if that is +nil, then for `default-directory' instead. If the directory is +not located inside a Git repository, then return nil." + (let ((default-directory (or directory default-directory))) + (magit-git-dir))) + +(defun magit-git-dir (&optional path) + "Return the absolute and resolved path of the .git directory. + +If the `GIT_DIR' environment variable is define then return that. +Otherwise return the .git directory for `default-directory'. If +the directory is not located inside a Git repository, then return +nil." + (magit--with-refresh-cache (list default-directory 'magit-git-dir path) + (magit--with-safe-default-directory nil + (when-let ((dir (magit-rev-parse-safe "--git-dir"))) + (setq dir (file-name-as-directory (magit-expand-git-file-name dir))) + (unless (file-remote-p dir) + (setq dir (concat (file-remote-p default-directory) dir))) + (if path (expand-file-name (convert-standard-filename path) dir) dir))))) + +(defvar magit--separated-gitdirs nil) + +(defun magit--record-separated-gitdir () + (let ((topdir (magit-toplevel)) + (gitdir (magit-git-dir))) + ;; Kludge: git-annex converts submodule gitdirs to symlinks. See #3599. + (when (file-symlink-p (directory-file-name gitdir)) + (setq gitdir (file-truename gitdir))) + ;; We want to delete the entry for `topdir' here, rather than within + ;; (unless ...), in case a `--separate-git-dir' repository was switched to + ;; the standard structure (i.e., "topdir/.git/"). + (setq magit--separated-gitdirs (cl-delete topdir + magit--separated-gitdirs + :key #'car :test #'equal)) + (unless (equal (file-name-as-directory (expand-file-name ".git" topdir)) + gitdir) + (push (cons topdir gitdir) magit--separated-gitdirs)))) + +(defun magit-toplevel (&optional directory) + "Return the absolute path to the toplevel of the current repository. + +From within the working tree or control directory of a repository +return the absolute path to the toplevel directory of the working +tree. As a special case, from within a bare repository return +the control directory instead. When called outside a repository +then return nil. + +When optional DIRECTORY is non-nil then return the toplevel for +that directory instead of the one for `default-directory'. + +Try to respect the option `find-file-visit-truename', i.e. when +the value of that option is nil, then avoid needlessly returning +the truename. When a symlink to a sub-directory of the working +tree is involved, or when called from within a sub-directory of +the gitdir or from the toplevel of a gitdir, which itself is not +located within the working tree, then it is not possible to avoid +returning the truename." + (magit--with-refresh-cache + (cons (or directory default-directory) 'magit-toplevel) + (magit--with-safe-default-directory directory + (if-let ((topdir (magit-rev-parse-safe "--show-toplevel"))) + (let (updir) + (setq topdir (magit-expand-git-file-name topdir)) + (if (and + ;; Always honor these settings. + (not find-file-visit-truename) + (not (getenv "GIT_WORK_TREE")) + ;; `--show-cdup' is the relative path to the toplevel + ;; from `(file-truename default-directory)'. Here we + ;; pretend it is relative to `default-directory', and + ;; go to that directory. Then we check whether + ;; `--show-toplevel' still returns the same value and + ;; whether `--show-cdup' now is the empty string. If + ;; both is the case, then we are at the toplevel of + ;; the same working tree, but also avoided needlessly + ;; following any symlinks. + (progn + (setq updir (file-name-as-directory + (magit-rev-parse-safe "--show-cdup"))) + (setq updir (if (file-name-absolute-p updir) + (concat (file-remote-p default-directory) updir) + (expand-file-name updir))) + (let ((default-directory updir)) + (and (string-equal (magit-rev-parse-safe "--show-cdup") "") + (--when-let (magit-rev-parse-safe "--show-toplevel") + (string-equal (magit-expand-git-file-name it) + topdir)))))) + updir + (concat (file-remote-p default-directory) + (file-name-as-directory topdir)))) + (when-let ((gitdir (magit-rev-parse-safe "--git-dir"))) + (setq gitdir (file-name-as-directory + (if (file-name-absolute-p gitdir) + ;; We might have followed a symlink. + (concat (file-remote-p default-directory) + (magit-expand-git-file-name gitdir)) + (expand-file-name gitdir)))) + (if (magit-bare-repo-p) + gitdir + (let* ((link (expand-file-name "gitdir" gitdir)) + (wtree (and (file-exists-p link) + (magit-file-line link)))) + (cond + ((and wtree + ;; Ignore .git/gitdir files that result from a + ;; Git bug. See #2364. + (not (equal wtree ".git"))) + ;; Return the linked working tree. + (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. + ((car (rassoc gitdir magit--separated-gitdirs))) + (t + ;; Step outside the control directory to enter the working tree. + (file-name-directory (directory-file-name gitdir))))))))))) + +(defmacro magit-with-toplevel (&rest body) + (declare (indent defun) (debug (body))) + (let ((toplevel (cl-gensym "toplevel"))) + `(let ((,toplevel (magit-toplevel))) + (if ,toplevel + (let ((default-directory ,toplevel)) + ,@body) + (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 () + (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. +If it is below the working directory, then return nil. +If it isn't below either, then signal an error unless NOERROR +is non-nil, in which case return nil." + (and (magit--assert-default-directory noerror) + ;; Below a repository directory that is not located below the + ;; working directory "git rev-parse --is-inside-git-dir" prints + ;; "false", which is wrong. + (let ((gitdir (magit-git-dir))) + (cond (gitdir (file-in-directory-p default-directory gitdir)) + (noerror nil) + (t (signal 'magit-outside-git-repo default-directory)))))) + +(defun magit-inside-worktree-p (&optional noerror) + "Return t if `default-directory' is below the working directory. +If it is below the repository directory, then return nil. +If it isn't below either, then signal an error unless NOERROR +is non-nil, in which case return nil." + (and (magit--assert-default-directory noerror) + (condition-case nil + (magit-rev-parse-true "--is-inside-work-tree") + (magit-invalid-git-boolean + (and (not noerror) + (signal 'magit-outside-git-repo default-directory)))))) + +(cl-defgeneric magit-bare-repo-p (&optional noerror) + "Return t if the current repository is bare. +If it is non-bare, then return nil. If `default-directory' +isn't below a Git repository, then signal an error unless +NOERROR is non-nil, in which case return nil." + (and (magit--assert-default-directory noerror) + (condition-case nil + (magit-rev-parse-true "--is-bare-repository") + (magit-invalid-git-boolean + (and (not noerror) + (signal 'magit-outside-git-repo default-directory)))))) + +(defun magit--assert-default-directory (&optional noerror) + (or (file-directory-p default-directory) + (and (not noerror) + (let ((exists (file-exists-p default-directory))) + (signal (if exists 'file-error 'file-missing) + (list "Running git in directory" + (if exists + "Not a directory" + "No such file or directory") + default-directory)))))) + +(defun magit-git-repo-p (directory &optional non-bare) + "Return t if DIRECTORY is a Git repository. +When optional NON-BARE is non-nil also return nil if DIRECTORY is +a bare repository." + (and (file-directory-p directory) ; Avoid archives, see #3397. + (or (file-regular-p (expand-file-name ".git" directory)) + (file-directory-p (expand-file-name ".git" directory)) + (and (not non-bare) + (file-regular-p (expand-file-name "HEAD" directory)) + (file-directory-p (expand-file-name "refs" directory)) + (file-directory-p (expand-file-name "objects" directory)))))) + +(defun magit-file-relative-name (&optional file tracked) + "Return the path of FILE relative to the repository root. + +If optional FILE is nil or omitted, return the relative path of +the file being visited in the current buffer, if any, else nil. +If the file is not inside a Git repository, then return nil. + +If TRACKED is non-nil, return the path only if it matches a +tracked file." + (unless file + (with-current-buffer (or (buffer-base-buffer) + (current-buffer)) + (setq file (or magit-buffer-file-name buffer-file-name + (and (derived-mode-p 'dired-mode) default-directory))))) + (when (and file (or (not tracked) + (magit-file-tracked-p (file-relative-name file)))) + (--when-let (magit-toplevel + (magit--safe-default-directory + (directory-file-name (file-name-directory file)))) + (file-relative-name file it)))) + +(defun magit-file-tracked-p (file) + (magit-git-success "ls-files" "--error-unmatch" file)) + +(defun magit-list-files (&rest args) + (apply #'magit-git-items "ls-files" "-z" "--full-name" args)) + +(defun magit-tracked-files () + (magit-list-files "--cached")) + +(defun magit-untracked-files (&optional all files) + (magit-list-files "--other" (unless all "--exclude-standard") "--" files)) + +(defun magit-unstaged-files (&optional nomodules files) + (magit-git-items "diff-files" "-z" "--name-only" + (and nomodules "--ignore-submodules") + "--" files)) + +(defun magit-staged-files (&optional nomodules files) + (magit-git-items "diff-index" "-z" "--name-only" "--cached" + (and nomodules "--ignore-submodules") + (magit-headish) "--" files)) + +(defun magit-binary-files (&rest args) + (--mapcat (and (string-match "^-\t-\t\\(.+\\)" it) + (list (match-string 1 it))) + (apply #'magit-git-items + "diff" "-z" "--numstat" "--ignore-submodules" + args))) + +(defun magit-unmerged-files () + (magit-git-items "diff-files" "-z" "--name-only" "--diff-filter=U")) + +(defun magit-ignored-files () + (magit-git-items "ls-files" "-z" "--others" "--ignored" + "--exclude-standard" "--directory")) + +(defun magit-skip-worktree-files () + (--keep (and (and (= (aref it 0) ?S) + (substring it 2))) + (magit-list-files "-t"))) + +(defun magit-assume-unchanged-files () + (--keep (and (and (memq (aref it 0) '(?h ?s ?m ?r ?c ?k)) + (substring it 2))) + (magit-list-files "-v"))) + +(defun magit-revision-files (rev) + (magit-with-toplevel + (magit-git-items "ls-tree" "-z" "-r" "--name-only" rev))) + +(defun magit-changed-files (rev-or-range &optional other-rev) + "Return list of files the have changed between two revisions. +If OTHER-REV is non-nil, REV-OR-RANGE should be a revision, not a +range. Otherwise, it can be any revision or range accepted by +\"git diff\" (i.e., , .., or ...)." + (magit-with-toplevel + (magit-git-items "diff" "-z" "--name-only" rev-or-range other-rev))) + +(defun magit-renamed-files (revA revB) + (--map (cons (nth 1 it) (nth 2 it)) + (-partition 3 (magit-git-items + "diff-tree" "-r" "--diff-filter=R" "-z" "-M" + revA revB)))) + +(defun magit-file-status (&rest args) + (magit--with-temp-process-buffer + (save-excursion (magit-git-insert "status" "-z" args)) + (let ((pos (point)) status) + (while (> (skip-chars-forward "[:print:]") 0) + (let ((x (char-after pos)) + (y (char-after (1+ pos))) + (file (buffer-substring (+ pos 3) (point)))) + (forward-char) + (if (memq x '(?R ?C)) + (progn + (setq pos (point)) + (skip-chars-forward "[:print:]") + (push (list file (buffer-substring pos (point)) x y) status) + (forward-char)) + (push (list file nil x y) status))) + (setq pos (point))) + status))) + +(defcustom magit-cygwin-mount-points + (when (eq system-type 'windows-nt) + (cl-sort (--map (if (string-match "^\\(.*\\) on \\(.*\\) type" it) + (cons (file-name-as-directory (match-string 2 it)) + (file-name-as-directory (match-string 1 it))) + (lwarn '(magit) :error + "Failed to parse Cygwin mount: %S" it)) + ;; If --exec-path is not a native Windows path, + ;; then we probably have a cygwin git. + (let ((process-environment + (append magit-git-environment process-environment))) + (and (not (string-match-p + "\\`[a-zA-Z]:" + (car (process-lines + magit-git-executable "--exec-path")))) + (ignore-errors (process-lines "mount"))))) + #'> :key (pcase-lambda (`(,cyg . ,_win)) (length cyg)))) + "Alist of (CYGWIN . WIN32) directory names. +Sorted from longest to shortest CYGWIN name." + :package-version '(magit . "2.3.0") + :group 'magit-process + :type '(alist :key-type string :value-type directory)) + +(defun magit-expand-git-file-name (filename) + (unless (file-name-absolute-p filename) + (setq filename (expand-file-name filename))) + (-if-let ((cyg . win) + (cl-assoc filename magit-cygwin-mount-points + :test (lambda (f cyg) (string-prefix-p cyg f)))) + (concat win (substring filename (length cyg))) + filename)) + +(defun magit-convert-filename-for-git (filename) + "Convert FILENAME so that it can be passed to git. +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))) + (let ((expanded (expand-file-name filename))) + (or (file-remote-p expanded 'localname) + expanded))) + filename)) + +(defun magit-decode-git-path (path) + (if (eq (aref path 0) ?\") + (decode-coding-string (read path) + (or magit-git-output-coding-system + (car default-process-coding-system)) + t) + path)) + +(defun magit-file-at-point (&optional expand assert) + (if-let ((file (magit-section-case + (file (oref it value)) + (hunk (magit-section-parent-value it))))) + (if expand + (expand-file-name file (magit-toplevel)) + file) + (when assert + (user-error "No file at point")))) + +(defun magit-current-file () + (or (magit-file-relative-name) + (magit-file-at-point) + (and (derived-mode-p 'magit-log-mode) + (car magit-buffer-log-files)))) + +;;; Predicates + +(defun magit-no-commit-p () + "Return t if there is no commit in the current Git repository." + (not (magit-rev-verify "HEAD"))) + +(defun magit-merge-commit-p (commit) + "Return t if COMMIT is a merge commit." + (> (length (magit-commit-parents commit)) 1)) + +(defun magit-anything-staged-p (&optional ignore-submodules &rest files) + "Return t if there are any staged changes. +If optional FILES is non-nil, then only changes to those files +are considered." + (magit-git-failure "diff" "--quiet" "--cached" + (and ignore-submodules "--ignore-submodules") + "--" files)) + +(defun magit-anything-unstaged-p (&optional ignore-submodules &rest files) + "Return t if there are any unstaged changes. +If optional FILES is non-nil, then only changes to those files +are considered." + (magit-git-failure "diff" "--quiet" + (and ignore-submodules "--ignore-submodules") + "--" files)) + +(defun magit-anything-modified-p (&optional ignore-submodules &rest files) + "Return t if there are any staged or unstaged changes. +If optional FILES is non-nil, then only changes to those files +are considered." + (or (apply 'magit-anything-staged-p ignore-submodules files) + (apply 'magit-anything-unstaged-p ignore-submodules files))) + +(defun magit-anything-unmerged-p (&rest files) + "Return t if there are any merge conflicts. +If optional FILES is non-nil, then only conflicts in those files +are considered." + (and (magit-git-string "ls-files" "--unmerged" files) t)) + +(defun magit-module-worktree-p (module) + (magit-with-toplevel + (file-exists-p (expand-file-name (expand-file-name ".git" module))))) + +(defun magit-module-no-worktree-p (module) + (not (magit-module-worktree-p module))) + +(defun magit-ignore-submodules-p (&optional return-argument) + (or (cl-find-if (lambda (arg) + (string-prefix-p "--ignore-submodules" arg)) + magit-buffer-diff-args) + (when-let ((value (magit-get "diff.ignoreSubmodules"))) + (if return-argument + (concat "--ignore-submodules=" value) + (concat "diff.ignoreSubmodules=" value))))) + +;;; Revisions and References + +(defun magit-rev-parse (&rest args) + "Execute `git rev-parse ARGS', returning first line of output. +If there is no output, return nil." + (apply #'magit-git-string "rev-parse" args)) + +(defun magit-rev-parse-safe (&rest args) + "Execute `git rev-parse ARGS', returning first line of output. +If there is no output, return nil. Like `magit-rev-parse' but +ignore `magit-git-debug'." + (apply #'magit-git-str "rev-parse" args)) + +(defun magit-rev-parse-true (&rest args) + "Execute `git rev-parse ARGS', returning t if it prints \"true\". +If it prints \"false\", then return nil. For any other output +signal an error." + (magit-git-true "rev-parse" args)) + +(defun magit-rev-parse-false (&rest args) + "Execute `git rev-parse ARGS', returning t if it prints \"false\". +If it prints \"true\", then return nil. For any other output +signal an error." + (magit-git-false "rev-parse" args)) + +(defun magit-rev-parse-p (&rest args) + "Execute `git rev-parse ARGS', returning t if it prints \"true\". +Return t if the first (and usually only) output line is the +string \"true\", otherwise return nil." + (equal (magit-git-str "rev-parse" args) "true")) + +(defun magit-rev-verify (rev) + (magit-git-string-p "rev-parse" "--verify" rev)) + +(defun magit-commit-p (rev) + "Return full hash for REV if it names an existing commit." + (magit-rev-verify (concat rev "^{commit}"))) + +(defalias 'magit-rev-verify-commit 'magit-commit-p) + +(defalias 'magit-rev-hash 'magit-commit-p) + +(defun magit-rev-equal (a b) + "Return t if there are no differences between the commits A and B." + (magit-git-success "diff" "--quiet" a b)) + +(defun magit-rev-eq (a b) + "Return t if A and B refer to the same commit." + (let ((a (magit-commit-p a)) + (b (magit-commit-p b))) + (and a b (equal a b)))) + +(defun magit-rev-ancestor-p (a b) + "Return non-nil if commit A is an ancestor of commit B." + (magit-git-success "merge-base" "--is-ancestor" a b)) + +(defun magit-rev-head-p (rev) + (or (equal rev "HEAD") + (and rev + (not (string-match-p "\\.\\." rev)) + (equal (magit-rev-parse rev) + (magit-rev-parse "HEAD"))))) + +(defun magit-rev-author-p (rev) + "Return t if the user is the author of REV. +More precisely return t if `user.name' is equal to the author +name of REV and/or `user.email' is equal to the author email +of REV." + (or (equal (magit-get "user.name") (magit-rev-format "%an" rev)) + (equal (magit-get "user.email") (magit-rev-format "%ae" rev)))) + +(defun magit-rev-name (rev &optional pattern not-anchored) + "Return a symbolic name for REV using `git-name-rev'. + +PATTERN can be used to limit the result to a matching ref. +Unless NOT-ANCHORED is non-nil, the beginning of the ref must +match PATTERN. + +An anchored lookup is done using the arguments +\"--exclude=*/ --exclude=*/HEAD\" in addition to +\"--refs=\", provided at least version v2.13 of Git is +used. Older versions did not support the \"--exclude\" argument. +When \"--exclude\" cannot be used and `git-name-rev' returns a +ref that should have been excluded, then that is discarded and +this function returns nil instead. This is unfortunate because +there might be other refs that do match. To fix that, update +Git." + (if (magit-git-version< "2.13") + (when-let + ((ref (magit-git-string "name-rev" "--name-only" "--no-undefined" + (and pattern (concat "--refs=" pattern)) + rev))) + (if (and pattern + (string-match-p "\\`refs/[^/]+/\\*\\'" pattern)) + (let ((namespace (substring pattern 0 -1))) + (and (not (or (string-suffix-p "HEAD" ref) + (and (string-match-p namespace ref) + (not (magit-rev-verify + (concat namespace ref)))))) + ref)) + ref)) + (magit-git-string "name-rev" "--name-only" "--no-undefined" + (and pattern (concat "--refs=" pattern)) + (and pattern + (not not-anchored) + (list "--exclude=*/HEAD" + (concat "--exclude=*/" pattern))) + rev))) + +(defun magit-rev-branch (rev) + (--when-let (magit-rev-name rev "refs/heads/*") + (unless (string-match-p "[~^]" it) it))) + +(defun magit-get-shortname (rev) + (let* ((fn (apply-partially 'magit-rev-name rev)) + (name (or (funcall fn "refs/tags/*") + (funcall fn "refs/heads/*") + (funcall fn "refs/remotes/*")))) + (cond ((not name) + (magit-rev-parse "--short" rev)) + ((string-match "^\\(?:tags\\|remotes\\)/\\(.+\\)" name) + (if (magit-ref-ambiguous-p (match-string 1 name)) + name + (match-string 1 name))) + (t (magit-ref-maybe-qualify name))))) + +(defun magit-name-branch (rev &optional lax) + (or (magit-name-local-branch rev) + (magit-name-remote-branch rev) + (and lax (or (magit-name-local-branch rev t) + (magit-name-remote-branch rev t))))) + +(defun magit-name-local-branch (rev &optional lax) + (--when-let (magit-rev-name rev "refs/heads/*") + (and (or lax (not (string-match-p "[~^]" it))) it))) + +(defun magit-name-remote-branch (rev &optional lax) + (--when-let (magit-rev-name rev "refs/remotes/*") + (and (or lax (not (string-match-p "[~^]" it))) + (substring it 8)))) + +(defun magit-name-tag (rev &optional lax) + (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." + (magit-rev-parse "--verify" "--abbrev-ref" refname)) + +(defun magit-ref-fullname (refname) + "Return fully qualified refname for REFNAME. +If REFNAME is ambiguous, return nil." + (magit-rev-parse "--verify" "--symbolic-full-name" refname)) + +(defun magit-ref-ambiguous-p (refname) + (save-match-data + (if (string-match "\\`\\([^^~]+\\)\\(.*\\)" refname) + (not (magit-ref-fullname (match-string 1 refname))) + (error "%S has an unrecognized format" refname)))) + +(defun magit-ref-maybe-qualify (refname &optional prefix) + "If REFNAME is ambiguous, try to disambiguate it by prepend PREFIX to it. +Return an unambiguous refname, either REFNAME or that prefixed +with PREFIX, nil otherwise. If REFNAME has an offset suffix +such as \"~1\", then that is preserved. If optional PREFIX is +nil, then use \"heads/\". " + (if (magit-ref-ambiguous-p refname) + (let ((refname (concat (or prefix "heads/") refname))) + (and (not (magit-ref-ambiguous-p refname)) refname)) + refname)) + +(defun magit-ref-exists-p (ref) + (magit-git-success "show-ref" "--verify" ref)) + +(defun magit-ref-equal (a b) + "Return t if the refnames A and B are `equal'. +A symbolic-ref pointing to some ref, is `equal' to that ref, +as are two symbolic-refs pointing to the same ref. Refnames +may be abbreviated." + (let ((a (magit-ref-fullname a)) + (b (magit-ref-fullname b))) + (and a b (equal a b)))) + +(defun magit-ref-eq (a b) + "Return t if the refnames A and B are `eq'. +A symbolic-ref is `eq' to itself, but not to the ref it points +to, or to some other symbolic-ref that points to the same ref." + (let ((symbolic-a (magit-symbolic-ref-p a)) + (symbolic-b (magit-symbolic-ref-p b))) + (or (and symbolic-a + symbolic-b + (equal a b)) + (and (not symbolic-a) + (not symbolic-b) + (magit-ref-equal a b))))) + +(defun magit-headish () + "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")) + +(defun magit-branch-at-point () + (magit-section-case + (branch (oref it value)) + (commit (or (magit--painted-branch-at-point) + (magit-name-branch (oref it value)))))) + +(defun magit--painted-branch-at-point (&optional type) + (or (and (not (eq type 'remote)) + (memq (get-text-property (point) 'font-lock-face) + (list 'magit-branch-local + 'magit-branch-current)) + (when-let ((branch (thing-at-point 'git-revision t))) + (cdr (magit-split-branch-name branch)))) + (and (not (eq type 'local)) + (memq (get-text-property (point) 'font-lock-face) + (list 'magit-branch-remote + 'magit-branch-remote-head)) + (thing-at-point 'git-revision t)))) + +(defun magit-local-branch-at-point () + (magit-section-case + (branch (let ((branch (magit-ref-maybe-qualify (oref it value)))) + (when (member branch (magit-list-local-branch-names)) + branch))) + (commit (or (magit--painted-branch-at-point 'local) + (magit-name-local-branch (oref it value)))))) + +(defun magit-remote-branch-at-point () + (magit-section-case + (branch (let ((branch (oref it value))) + (when (member branch (magit-list-remote-branch-names)) + branch))) + (commit (or (magit--painted-branch-at-point 'remote) + (magit-name-remote-branch (oref it value)))))) + +(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 (magit-section-case + (branch (magit-ref-maybe-qualify (oref it value))) + (commit (or (magit--painted-branch-at-point) + (let ((rev (oref it value))) + (or (magit-name-branch rev) rev)))) + (tag (magit-ref-maybe-qualify (oref it value) "tags/")) + (pullreq (or (and (fboundp 'forge--pullreq-branch) + (magit-branch-p + (forge--pullreq-branch (oref it value)))) + (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) + magit-buffer-revision))) + +(defun magit-tag-at-point () + (magit-section-case + (tag (oref it value)) + (commit (magit-name-tag (oref it value))))) + +(defun magit-stash-at-point () + (magit-section-value-if 'stash)) + +(defun magit-remote-at-point () + (magit-section-case + (remote (oref it value)) + ([branch remote] (magit-section-parent-value it)))) + +(defun magit-module-at-point (&optional predicate) + (when (magit-section-match 'magit-module-section) + (let ((module (oref (magit-current-section) value))) + (and (or (not predicate) + (funcall predicate module)) + module)))) + +(defun magit-get-current-branch () + "Return the refname of the currently checked out branch. +Return nil if no branch is currently checked out." + (magit-git-string "symbolic-ref" "--short" "HEAD")) + +(defvar magit-get-previous-branch-timeout 0.5 + "Maximum time to spend in `magit-get-previous-branch'. +Given as a number of seconds.") + +(defun magit-get-previous-branch () + "Return the refname of the previously checked out branch. +Return nil if no branch can be found in the `HEAD' reflog +which is different from the current branch and still exists. +The amount of time spent searching is limited by +`magit-get-previous-branch-timeout'." + (let ((t0 (float-time)) + (current (magit-get-current-branch)) + (i 1) prev) + (while (if (> (- (float-time) t0) magit-get-previous-branch-timeout) + (setq prev nil) ;; Timed out. + (and (setq prev (magit-rev-verify (format "@{-%i}" i))) + (or (not (setq prev (magit-rev-branch prev))) + (equal prev current)))) + (cl-incf i)) + prev)) + +(defun magit-set-upstream-branch (branch upstream) + "Set UPSTREAM as the upstream of BRANCH. +If UPSTREAM is nil, then unset BRANCH's upstream. +Otherwise UPSTREAM has to be an existing branch." + (if upstream + (magit-call-git "branch" "--set-upstream-to" upstream branch) + (magit-call-git "branch" "--unset-upstream" branch))) + +(defun magit-get-upstream-ref (&optional branch) + "Return the upstream branch of BRANCH as a fully qualified ref. +It BRANCH is nil, then return the upstream of the current branch, +if any, nil otherwise. If the upstream is not configured, the +configured remote is an url, or the named branch does not exist, +then return nil. I.e. return an existing local or +remote-tracking branch ref." + (when-let ((branch (or branch (magit-get-current-branch)))) + (magit-ref-fullname (concat branch "@{upstream}")))) + +(defun magit-get-upstream-branch (&optional branch) + "Return the name of the upstream branch of BRANCH. +It BRANCH is nil, then return the upstream of the current branch +if any, nil otherwise. If the upstream is not configured, the +configured remote is an url, or the named branch does not exist, +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." + (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"))) + (and remote (not (equal remote ".")) + ;; The user has opted in... + (or force + (--some (if (magit-git-success "check-ref-format" "--branch" it) + (equal it branch) + (string-match-p it branch)) + magit-branch-prefer-remote-upstream)) + ;; and local BRANCH tracks a remote branch... + (let ((upstream (magit-get-upstream-branch branch))) + ;; whose upstream... + (and upstream + ;; has the same name as BRANCH... + (equal (substring upstream (1+ (length remote))) branch) + ;; and can be fast-forwarded to BRANCH. + (magit-rev-ancestor-p upstream branch) + upstream))))) + +(defun magit-get-upstream-remote (&optional branch allow-unnamed) + (when-let ((branch (or branch (magit-get-current-branch))) + (remote (magit-get "branch" branch "remote"))) + (and (not (equal remote ".")) + (cond ((member remote (magit-list-remotes)) + (magit--propertize-face remote 'magit-branch-remote)) + ((and allow-unnamed + (string-match-p "\\(\\`.\\{0,2\\}/\\|[:@]\\)" remote)) + (magit--propertize-face remote 'bold)))))) + +(defun magit-get-unnamed-upstream (&optional branch) + (when-let ((branch (or branch (magit-get-current-branch))) + (remote (magit-get "branch" branch "remote")) + (merge (magit-get "branch" branch "merge"))) + (and (magit--unnamed-upstream-p remote merge) + (list (magit--propertize-face remote 'bold) + (magit--propertize-face merge 'magit-branch-remote))))) + +(defun magit--unnamed-upstream-p (remote merge) + (and remote (string-match-p "\\(\\`\\.\\{0,2\\}/\\|[:@]\\)" remote) + merge (string-prefix-p "refs/" merge))) + +(defun magit--valid-upstream-p (remote merge) + (and (or (equal remote ".") + (member remote (magit-list-remotes))) + (string-prefix-p "refs/" merge))) + +(defun magit-get-current-remote (&optional allow-unnamed) + (or (magit-get-upstream-remote nil allow-unnamed) + (when-let ((remotes (magit-list-remotes)) + (remote (if (= (length remotes) 1) + (car remotes) + (magit-primary-remote)))) + (magit--propertize-face remote 'magit-branch-remote)))) + +(defun magit-get-push-remote (&optional branch) + (when-let ((remote + (or (and (or branch (setq branch (magit-get-current-branch))) + (magit-get "branch" branch "pushRemote")) + (magit-get "remote.pushDefault")))) + (magit--propertize-face remote 'magit-branch-remote))) + +(defun magit-get-push-branch (&optional branch verify) + (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" + (concat branch "@{push}")))) + (when (and ref (string-prefix-p "refs/remotes/" ref)) + (substring ref 13)))) + +(defun magit-get-remote (&optional branch) + (when (or branch (setq branch (magit-get-current-branch))) + (let ((remote (magit-get "branch" branch "remote"))) + (unless (equal remote ".") + remote)))) + +(defun magit-get-some-remote (&optional branch) + (or (magit-get-remote branch) + (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. + +TARGET defaults to the current branch. If `HEAD' is detached and +TARGET is nil, then always return nil. As a special case, if +TARGET is t, then return non-nil if BRANCH is merged into any one +of the other local branches. + +If, and only if, BRANCH has an upstream, then only return non-nil +if BRANCH is merged into both TARGET (as described above) as well +as into its upstream." + (and (--if-let (and (magit-branch-p branch) + (magit-get-upstream-branch branch)) + (magit-git-success "merge-base" "--is-ancestor" branch it) + t) + (if (eq target t) + (delete (magit-name-local-branch branch) + (magit-list-containing-branches branch)) + (--when-let (or target (magit-get-current-branch)) + (magit-git-success "merge-base" "--is-ancestor" branch it))))) + +(defun magit-get-tracked (refname) + "Return the remote branch tracked by the remote-tracking branch REFNAME. +The returned value has the form (REMOTE . REF), where REMOTE is +the name of a remote and REF is the ref local to the remote." + (when-let ((ref (magit-ref-fullname refname))) + (save-match-data + (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"))))) + +(defun magit-split-branch-name (branch) + (cond ((member branch (magit-list-local-branch-names)) + (cons "." branch)) + ((string-match "/" branch) + (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) + "Return the closest tag reachable from REV. + +If optional REV is nil, then default to `HEAD'. +If optional WITH-DISTANCE is non-nil then return (TAG COMMITS), +if it is `dirty' return (TAG COMMIT DIRTY). COMMITS is the number +of commits in `HEAD' but not in TAG and DIRTY is t if there are +uncommitted changes, nil otherwise." + (--when-let (magit-git-str "describe" "--long" "--tags" + (and (eq with-distance 'dirty) "--dirty") rev) + (save-match-data + (string-match + "\\(.+\\)-\\(?:0[0-9]*\\|\\([0-9]+\\)\\)-g[0-9a-z]+\\(-dirty\\)?$" it) + (if with-distance + `(,(match-string 1 it) + ,(string-to-number (or (match-string 2 it) "0")) + ,@(and (match-string 3 it) (list t))) + (match-string 1 it))))) + +(defun magit-get-next-tag (&optional rev with-distance) + "Return the closest tag from which REV is reachable. + +If optional REV is nil, then default to `HEAD'. +If no such tag can be found or if the distance is 0 (in which +case it is the current tag, not the next), return nil instead. +If optional WITH-DISTANCE is non-nil, then return (TAG COMMITS) +where COMMITS is the number of commits in TAG but not in REV." + (--when-let (magit-git-str "describe" "--contains" (or rev "HEAD")) + (save-match-data + (when (string-match "^[^^~]+" it) + (setq it (match-string 0 it)) + (unless (equal it (magit-get-current-tag rev)) + (if with-distance + (list it (car (magit-rev-diff-count it rev))) + it)))))) + +(defun magit-list-refs (&optional namespaces format sortby) + "Return list of references. + +When NAMESPACES is non-nil, list refs from these namespaces +rather than those from `magit-list-refs-namespaces'. + +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'. + +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'" + (unless format + (setq format "%(refname)")) + (let ((refs (magit-git-lines "for-each-ref" + (concat "--format=" format) + (--map (concat "--sort=" it) + (pcase (or sortby magit-list-refs-sortby) + ((and val (pred stringp)) (list val)) + ((and val (pred listp)) val))) + (or namespaces magit-list-refs-namespaces)))) + (if (member format '("%(refname)" "%(refname:short)")) + (let ((case-fold-search nil)) + (--remove (string-match-p "\\(\\`\\|/\\)HEAD\\'" it) + refs)) + refs))) + +(defun magit-list-branches () + (magit-list-refs (list "refs/heads" "refs/remotes"))) + +(defun magit-list-local-branches () + (magit-list-refs "refs/heads")) + +(defun magit-list-remote-branches (&optional remote) + (magit-list-refs (concat "refs/remotes/" remote))) + +(defun magit-list-related-branches (relation &optional commit &rest args) + (--remove (string-match-p "\\(\\`(HEAD\\|HEAD -> \\)" it) + (--map (substring it 2) + (magit-git-lines "branch" args relation commit)))) + +(defun magit-list-containing-branches (&optional commit &rest args) + (magit-list-related-branches "--contains" commit args)) + +(defun magit-list-publishing-branches (&optional commit) + (--filter (magit-rev-ancestor-p (or commit "HEAD") it) + magit-published-branches)) + +(defun magit-list-merged-branches (&optional commit &rest args) + (magit-list-related-branches "--merged" commit args)) + +(defun magit-list-unmerged-branches (&optional commit &rest args) + (magit-list-related-branches "--no-merged" commit args)) + +(defun magit-list-unmerged-to-upstream-branches () + (--filter (when-let ((upstream (magit-get-upstream-branch it))) + (member it (magit-list-unmerged-branches upstream))) + (magit-list-local-branch-names))) + +(defun magit-list-branches-pointing-at (commit) + (let ((re (format "\\`%s refs/\\(heads\\|remotes\\)/\\(.*\\)\\'" + (magit-rev-verify commit)))) + (--keep (and (string-match re it) + (let ((name (match-string 2 it))) + (and (not (string-suffix-p "HEAD" name)) + name))) + (magit-git-lines "show-ref")))) + +(defun magit-list-refnames (&optional namespaces include-special) + (nconc (magit-list-refs namespaces "%(refname:short)") + (and include-special + (magit-list-special-refnames)))) + +(defvar magit-special-refnames + '("HEAD" "ORIG_HEAD" "FETCH_HEAD" "MERGE_HEAD" "CHERRY_PICK_HEAD")) + +(defun magit-list-special-refnames () + (let ((gitdir (magit-gitdir))) + (cl-mapcan (lambda (name) + (and (file-exists-p (expand-file-name name gitdir)) + (list name))) + magit-special-refnames))) + +(defun magit-list-branch-names () + (magit-list-refnames (list "refs/heads" "refs/remotes"))) + +(defun magit-list-local-branch-names () + (magit-list-refnames "refs/heads")) + +(defun magit-list-remote-branch-names (&optional remote relative) + (if (and remote relative) + (let ((regexp (format "^refs/remotes/%s/\\(.+\\)" remote))) + (--mapcat (when (string-match regexp it) + (list (match-string 1 it))) + (magit-list-remote-branches remote))) + (magit-list-refnames (concat "refs/remotes/" remote)))) + +(defun magit-format-refs (format &rest args) + (let ((lines (magit-git-lines + "for-each-ref" (concat "--format=" format) + (or args (list "refs/heads" "refs/remotes" "refs/tags"))))) + (if (string-match-p "\f" format) + (--map (split-string it "\f") lines) + lines))) + +(defun magit-list-remotes () + (magit-git-lines "remote")) + +(defun magit-list-tags () + (magit-git-lines "tag")) + +(defun magit-list-stashes (&optional format) + (magit-git-lines "stash" "list" (concat "--format=" (or format "%gd")))) + +(defun magit-list-active-notes-refs () + "Return notes refs according to `core.notesRef' and `notes.displayRef'." + (magit-git-lines "for-each-ref" "--format=%(refname)" + (or (magit-get "core.notesRef") "refs/notes/commits") + (magit-get-all "notes.displayRef"))) + +(defun magit-list-notes-refnames () + (--map (substring it 6) (magit-list-refnames "refs/notes"))) + +(defun magit-remote-list-tags (remote) + (--keep (and (not (string-match-p "\\^{}$" it)) + (substring it 51)) + (magit-git-lines "ls-remote" "--tags" remote))) + +(defun magit-remote-list-branches (remote) + (--keep (and (not (string-match-p "\\^{}$" it)) + (substring it 52)) + (magit-git-lines "ls-remote" "--heads" remote))) + +(defun magit-remote-list-refs (remote) + (--keep (and (not (string-match-p "\\^{}$" it)) + (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." + (magit-git-string "submodule--helper" "name" path)) + +(defun magit-list-worktrees () + (let ((remote (file-remote-p default-directory)) + worktrees worktree) + (dolist (line (let ((magit-git-global-arguments + ;; KLUDGE At least in v2.8.3 this triggers a segfault. + (remove "--no-pager" magit-git-global-arguments))) + (magit-git-lines "worktree" "list" "--porcelain"))) + (cond ((string-prefix-p "worktree" line) + (let ((path (substring line 9))) + (when remote + (setq path (concat remote path))) + ;; If the git directory is separate from the main + ;; worktree, then "git worktree" returns the git + ;; directory instead of the worktree, which isn't + ;; what it is supposed to do and not what we want. + (setq path (magit-toplevel path)) + (setq worktree (list path nil nil nil)) + (push worktree worktrees))) + ((string-equal line "bare") + (let* ((default-directory (car worktree)) + (wt (and (not (magit-get-boolean "core.bare")) + (magit-get "core.worktree")))) + (if (and wt (file-exists-p (expand-file-name wt))) + (progn (setf (nth 0 worktree) (expand-file-name wt)) + (setf (nth 2 worktree) (magit-rev-parse "HEAD")) + (setf (nth 3 worktree) (magit-get-current-branch))) + (setf (nth 1 worktree) t)))) + ((string-prefix-p "HEAD" line) + (setf (nth 2 worktree) (substring line 5))) + ((string-prefix-p "branch" line) + (setf (nth 3 worktree) (substring line 18))) + ((string-equal line "detached")))) + (nreverse worktrees))) + +(defun magit-symbolic-ref-p (name) + (magit-git-success "symbolic-ref" "--quiet" name)) + +(defun magit-ref-p (rev) + (or (car (member rev (magit-list-refs "refs/"))) + (car (member rev (magit-list-refnames "refs/"))))) + +(defun magit-branch-p (rev) + (or (car (member rev (magit-list-branches))) + (car (member rev (magit-list-branch-names))))) + +(defun magit-local-branch-p (rev) + (or (car (member rev (magit-list-local-branches))) + (car (member rev (magit-list-local-branch-names))))) + +(defun magit-remote-branch-p (rev) + (or (car (member rev (magit-list-remote-branches))) + (car (member rev (magit-list-remote-branch-names))))) + +(defun magit-branch-set-face (branch) + (magit--propertize-face branch (if (magit-local-branch-p branch) + 'magit-branch-local + 'magit-branch-remote))) + +(defun magit-tag-p (rev) + (car (member rev (magit-list-tags)))) + +(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)." + (mapcar 'string-to-number + (split-string (magit-git-string "rev-list" + "--count" "--left-right" + (concat a "..." b)) + "\t"))) + +(defun magit-abbrev-length () + (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))) + +(defun magit-rev-abbrev (rev) + (magit-rev-parse (magit-abbrev-arg "short") rev)) + +(defun magit-commit-children (commit &optional args) + (mapcar #'car + (--filter (member commit (cdr it)) + (--map (split-string it " ") + (magit-git-lines + "log" "--format=%H %P" + (or args (list "--branches" "--tags" "--remotes")) + "--not" commit))))) + +(defun magit-commit-parents (commit) + (--when-let (magit-git-string "rev-list" "-1" "--parents" commit) + (cdr (split-string it)))) + +(defun magit-patch-id (rev) + (magit--with-connection-local-variables + (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)))) + (format "%s diff-tree -u %s | %s patch-id" exec rev exec))) + (car (split-string (buffer-string)))))) + +(defun magit-rev-format (format &optional rev args) + (let ((str (magit-git-string "show" "--no-patch" + (concat "--format=" format) args + (if rev (concat rev "^{commit}") "HEAD") "--"))) + (unless (string-equal str "") + str))) + +(defun magit-rev-insert-format (format &optional rev args) + (magit-git-insert "show" "--no-patch" + (concat "--format=" format) args + (if rev (concat rev "^{commit}") "HEAD") "--")) + +(defun magit-format-rev-summary (rev) + (--when-let (magit-rev-format "%h %s" rev) + (string-match " " it) + (magit--put-face 0 (match-beginning 0) 'magit-hash it) + it)) + +(defvar magit-ref-namespaces + '(("\\`HEAD\\'" . magit-head) + ("\\`refs/tags/\\(.+\\)" . magit-tag) + ("\\`refs/heads/\\(.+\\)" . magit-branch-local) + ("\\`refs/remotes/\\(.+\\)" . magit-branch-remote) + ("\\`refs/bisect/\\(bad\\)" . magit-bisect-bad) + ("\\`refs/bisect/\\(skip.*\\)" . magit-bisect-skip) + ("\\`refs/bisect/\\(good.*\\)" . magit-bisect-good) + ("\\`refs/stash$" . magit-refname-stash) + ("\\`refs/wip/\\(.+\\)" . magit-refname-wip) + ("\\`refs/pullreqs/\\(.+\\)" . magit-refname-pullreq) + ("\\`\\(bad\\):" . magit-bisect-bad) + ("\\`\\(skip\\):" . magit-bisect-skip) + ("\\`\\(good\\):" . magit-bisect-good) + ("\\`\\(.+\\)" . magit-refname)) + "How refs are formatted for display. + +Each entry controls how a certain type of ref is displayed, and +has the form (REGEXP . FACE). REGEXP is a regular expression +used to match full refs. The first entry whose REGEXP matches +the reference is used. + +In log and revision buffers the first regexp submatch becomes the +\"label\" that represents the ref and is propertized with FONT. +In refs buffers the displayed text is controlled by other means +and this option only controls what face is used.") + +(defun magit-format-ref-labels (string) + (save-match-data + (let ((regexp "\\(, \\|tag: \\|HEAD -> \\)") + names) + (if (and (derived-mode-p 'magit-log-mode) + (member "--simplify-by-decoration" magit-buffer-log-args)) + (let ((branches (magit-list-local-branch-names)) + (re (format "^%s/.+" (regexp-opt (magit-list-remotes))))) + (setq names + (--map (cond ((string-equal it "HEAD") it) + ((string-prefix-p "refs/" it) it) + ((member it branches) (concat "refs/heads/" it)) + ((string-match re it) (concat "refs/remotes/" it)) + (t (concat "refs/" it))) + (split-string + (replace-regexp-in-string "tag: " "refs/tags/" string) + regexp t)))) + (setq names (split-string string regexp t))) + (let (state head upstream tags branches remotes other combined) + (dolist (ref names) + (let* ((face (cdr (--first (string-match (car it) ref) + magit-ref-namespaces))) + (name (magit--propertize-face + (or (match-string 1 ref) ref) face))) + (cl-case face + ((magit-bisect-bad magit-bisect-skip magit-bisect-good) + (setq state name)) + (magit-head + (setq head (magit--propertize-face "@" 'magit-head))) + (magit-tag (push name tags)) + (magit-branch-local (push name branches)) + (magit-branch-remote (push name remotes)) + (t (push name other))))) + (setq remotes + (-keep + (lambda (name) + (if (string-match "\\`\\([^/]*\\)/\\(.*\\)\\'" name) + (let ((r (match-string 1 name)) + (b (match-string 2 name))) + (and (not (equal b "HEAD")) + (if (equal (concat "refs/remotes/" name) + (magit-git-string + "symbolic-ref" + (format "refs/remotes/%s/HEAD" r))) + (magit--propertize-face + name 'magit-branch-remote-head) + name))) + name)) + remotes)) + (let* ((current (magit-get-current-branch)) + (target (magit-get-upstream-branch current))) + (dolist (name branches) + (let ((push (car (member (magit-get-push-branch name) remotes)))) + (when push + (setq remotes (delete push remotes)) + (string-match "^[^/]*/" push) + (setq push (substring push 0 (match-end 0)))) + (cond + ((equal name current) + (setq head + (concat push + (magit--propertize-face + name 'magit-branch-current)))) + ((equal name target) + (setq upstream + (concat push + (magit--propertize-face + name '(magit-branch-upstream + magit-branch-local))))) + (t + (push (concat push name) combined))))) + (when (and target (not upstream)) + (if (member target remotes) + (progn + (magit--add-face-text-property + 0 (length target) 'magit-branch-upstream nil target) + (setq upstream target) + (setq remotes (delete target remotes))) + (when-let ((target (car (member target combined)))) + (magit--add-face-text-property + 0 (length target) 'magit-branch-upstream nil target) + (setq upstream target) + (setq combined (delete target combined)))))) + (mapconcat #'identity + (-flatten `(,state + ,head + ,upstream + ,@(nreverse tags) + ,@(nreverse combined) + ,@(nreverse remotes) + ,@other)) + " "))))) + +(defun magit-object-type (object) + (magit-git-string "cat-file" "-t" object)) + +(defmacro magit-with-blob (commit file &rest body) + (declare (indent 2) + (debug (form form body))) + `(magit--with-temp-process-buffer + (let ((buffer-file-name ,file)) + (save-excursion + (magit-git-insert "cat-file" "-p" + (concat ,commit ":" buffer-file-name))) + (decode-coding-inserted-region + (point-min) (point-max) buffer-file-name t nil nil t) + ,@body))) + +(defmacro magit-with-temp-index (tree arg &rest body) + (declare (indent 2) (debug (form form body))) + (let ((file (cl-gensym "file"))) + `(let ((magit--refresh-cache nil) + (,file (magit-convert-filename-for-git + (make-temp-name (magit-git-dir "index.magit."))))) + (unwind-protect + (magit-with-toplevel + (--when-let ,tree + (or (magit-git-success "read-tree" ,arg it + (concat "--index-output=" ,file)) + (error "Cannot read tree %s" it))) + (if (file-remote-p default-directory) + (let ((magit-tramp-process-environment + (cons (concat "GIT_INDEX_FILE=" ,file) + magit-tramp-process-environment))) + ,@body) + (let ((process-environment + (cons (concat "GIT_INDEX_FILE=" ,file) + process-environment))) + ,@body))) + (ignore-errors + (delete-file (concat (file-remote-p default-directory) ,file))))))) + +(defun magit-commit-tree (message &optional tree &rest parents) + (magit-git-string "commit-tree" "--no-gpg-sign" "-m" message + (--mapcat (list "-p" it) (delq nil parents)) + (or tree + (magit-git-string "write-tree") + (error "Cannot write tree")))) + +(defun magit-commit-worktree (message &optional arg &rest other-parents) + (magit-with-temp-index "HEAD" arg + (and (magit-update-files (magit-unstaged-files)) + (apply #'magit-commit-tree message nil "HEAD" other-parents)))) + +(defun magit-update-files (files) + (magit-git-success "update-index" "--add" "--remove" "--" files)) + +(defun magit-update-ref (ref message rev &optional stashish) + (let ((magit--refresh-cache nil)) + (or (if (magit-git-version>= "2.6.0") + (zerop (magit-call-git "update-ref" "--create-reflog" + "-m" message ref rev + (or (magit-rev-verify ref) ""))) + ;; `--create-reflog' didn't exist before v2.6.0 + (let ((oldrev (magit-rev-verify ref)) + (logfile (magit-git-dir (concat "logs/" ref)))) + (unless (file-exists-p logfile) + (when oldrev + (magit-git-success "update-ref" "-d" ref oldrev)) + (make-directory (file-name-directory logfile) t) + (with-temp-file logfile) + (when (and oldrev (not stashish)) + (magit-git-success "update-ref" "-m" "enable reflog" + ref oldrev "")))) + (magit-git-success "update-ref" "-m" message ref rev + (or (magit-rev-verify ref) ""))) + (error "Cannot update %s with %s" ref rev)))) + +(defconst magit-range-re + (concat "\\`\\([^ \t]*[^.]\\)?" ; revA + "\\(\\.\\.\\.?\\)" ; range marker + "\\([^.][^ \t]*\\)?\\'")) ; revB + +(defun magit-split-range (range) + (and (string-match magit-range-re range) + (let ((beg (or (match-string 1 range) "HEAD")) + (end (or (match-string 3 range) "HEAD"))) + (cons (if (string-equal (match-string 2 range) "...") + (magit-git-string "merge-base" beg end) + beg) + end)))) + +(defun magit-hash-range (range) + (if (string-match magit-range-re range) + (concat (magit-rev-hash (match-string 1 range)) + (match-string 2 range) + (magit-rev-hash (match-string 3 range))) + (magit-rev-hash range))) + +(put 'git-revision 'thing-at-point 'magit-thingatpt--git-revision) +(defun magit-thingatpt--git-revision () + (--when-let + (let ((c "\s\n\t~^:?*[\\")) + (cl-letf (((get 'git-revision 'beginning-op) + (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 (>= (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 + (or (magit-branch-at-point) + secondary-default + (magit-get-current-branch)))) + +(defun magit-read-branch-or-commit (prompt &optional secondary-default) + (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 + prompt + (or (--when-let (magit-region-values '(commit branch) t) + (deactivate-mark) + (concat (car (last it)) ".." (car it))) + (magit-branch-or-commit-at-point) + secondary-default + (magit-get-current-branch)))) + +(defun magit-read-range (prompt &optional default) + (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) + (let ((choice (magit-completing-read + prompt + (-union (and local-branch + (if remote + (concat remote "/" local-branch) + (--map (concat it "/" local-branch) + (magit-list-remotes)))) + (magit-list-remote-branch-names remote t)) + nil require-match nil 'magit-revision-history default))) + (if (or remote (string-match "\\`\\([^/]+\\)/\\(.+\\)" choice)) + choice + (user-error "`%s' doesn't have the form REMOTE/BRANCH" choice)))) + +(defun magit-read-refspec (prompt remote) + (magit-completing-read prompt + (prog2 (message "Determining available refs...") + (magit-remote-list-refs remote) + (message "Determining available refs...done")))) + +(defun magit-read-local-branch (prompt &optional secondary-default) + (magit-completing-read prompt (magit-list-local-branch-names) + nil t nil 'magit-revision-history + (or (magit-local-branch-at-point) + secondary-default + (magit-get-current-branch)))) + +(defun magit-read-local-branch-or-commit (prompt) + (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 + (push commit choices)) + (or (magit-completing-read prompt choices + nil nil nil 'magit-revision-history + (or (magit-local-branch-at-point) commit)) + (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) + (magit-list-refs "refs/")) + nil t nil 'magit-revision-history + (or (magit-local-branch-at-point) + secondary-default + (magit-get-current-branch)))) + +(defun magit-read-other-branch + (prompt &optional exclude secondary-default no-require-match) + (let* ((current (magit-get-current-branch)) + (atpoint (magit-branch-at-point)) + (exclude (or exclude current)) + (default (or (and (not (equal atpoint exclude)) atpoint) + (and (not (equal current exclude)) current) + secondary-default + (magit-get-previous-branch)))) + (magit-completing-read prompt (delete exclude (magit-list-branch-names)) + nil (not no-require-match) + nil 'magit-revision-history default))) + +(defun magit-read-other-branch-or-commit + (prompt &optional exclude secondary-default) + (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)) + (not (and (not current) + (magit-rev-equal atpoint "HEAD"))) + atpoint) + (and (not (equal current exclude)) current) + secondary-default + (magit-get-previous-branch)))) + (or (magit-completing-read prompt (delete exclude (magit-list-refnames)) + nil nil nil 'magit-revision-history default) + (user-error "Nothing selected")))) + +(defun magit-read-other-local-branch + (prompt &optional exclude secondary-default no-require-match) + (let* ((current (magit-get-current-branch)) + (atpoint (magit-local-branch-at-point)) + (exclude (or exclude current)) + (default (or (and (not (equal atpoint exclude)) atpoint) + (and (not (equal current exclude)) current) + secondary-default + (magit-get-previous-branch)))) + (magit-completing-read prompt + (delete exclude (magit-list-local-branch-names)) + nil (not no-require-match) + nil 'magit-revision-history default))) + +(defun magit-read-branch-prefer-other (prompt) + (let* ((current (magit-get-current-branch)) + (commit (magit-commit-at-point)) + (atrev (and commit (magit-list-branches-pointing-at commit))) + (atpoint (magit--painted-branch-at-point))) + (magit-completing-read prompt (magit-list-branch-names) + nil t nil 'magit-revision-history + (or (magit-section-value-if 'branch) + atpoint + (and (not (cdr atrev)) (car atrev)) + (--first (not (equal it current)) atrev) + (magit-get-previous-branch) + (car atrev))))) + +(defun magit-read-upstream-branch (&optional branch prompt) + "Read the upstream for BRANCH using PROMPT. +If optional BRANCH is nil, then read the upstream for the +current branch, or raise an error if no branch is checked +out. Only existing branches can be selected." + (unless branch + (setq branch (or (magit-get-current-branch) + (error "Need a branch to set its upstream")))) + (let ((branches (delete branch (magit-list-branch-names)))) + (magit-completing-read + (or prompt (format "Change upstream of %s to" branch)) + branches nil t nil 'magit-revision-history + (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))) + (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) + (or (magit-completing-read + (concat prompt + (and branch + (if (bound-and-true-p ivy-mode) + ;; Ivy-mode strips faces from prompt. + (format " `%s'" branch) + (concat " " (magit--propertize-face + branch 'magit-branch-local)))) + " starting at") + (nconc (list "HEAD") + (magit-list-refnames) + (directory-files (magit-git-dir) nil "_HEAD\\'")) + nil nil nil 'magit-revision-history + (or default (magit--default-starting-point))) + (user-error "Nothing selected"))) + +(defun magit--default-starting-point () + (or (let ((r (magit-remote-branch-at-point)) + (l (magit-local-branch-at-point))) + (if magit-prefer-remote-upstream (or r l) (or l r))) + (magit-commit-at-point) + (magit-stash-at-point) + (magit-get-current-branch))) + +(defun magit-read-tag (prompt &optional require-match) + (magit-completing-read prompt (magit-list-tags) nil + require-match nil 'magit-revision-history + (magit-tag-at-point))) + +(defun magit-read-stash (prompt) + (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))) + (if (and use-only (= (length remotes) 1)) + (car remotes) + (magit-completing-read prompt remotes + nil t nil nil + (or default + (magit-remote-at-point) + (magit-get-remote)))))) + +(defun magit-read-remote-or-url (prompt &optional default) + (magit-completing-read prompt + (nconc (magit-list-remotes) + (list "https://" "git://" "git@")) + nil nil nil nil + (or default + (magit-remote-at-point) + (magit-get-remote)))) + +(defun magit-read-module-path (prompt &optional predicate) + (magit-completing-read prompt (magit-list-module-paths) + predicate t nil nil + (magit-module-at-point predicate))) + +(defun magit-module-confirm (verb &optional predicate) + (let (modules) + (if current-prefix-arg + (progn + (setq modules (magit-list-module-paths)) + (when predicate + (setq modules (-filter predicate modules))) + (unless modules + (if predicate + (user-error "No modules satisfying %s available" predicate) + (user-error "No modules available")))) + (setq modules (magit-region-values 'magit-module-section)) + (when modules + (when predicate + (setq modules (-filter predicate modules))) + (unless modules + (user-error "No modules satisfying %s selected" predicate)))) + (if (> (length modules) 1) + (magit-confirm t nil (format "%s %%i modules" verb) nil modules) + (list (magit-read-module-path (format "%s module" verb) predicate))))) + +;;; _ +(provide 'magit-git) +;;; magit-git.el ends here diff --git a/elpa/magit-20220116.1908/magit-gitignore.el b/elpa/magit-20220116.1908/magit-gitignore.el new file mode 100644 index 00000000..7ff64695 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-gitignore.el @@ -0,0 +1,198 @@ +;;; magit-gitignore.el --- intentionally untracked files -*- lexical-binding: t -*- + +;; Copyright (C) 2008-2022 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. + +;;; Commentary: + +;; This library implements gitignore commands. + +;;; Code: + +(require 'magit) + +;;; Transient + +;;;###autoload (autoload 'magit-gitignore "magit-gitignore" nil t) +(transient-define-prefix magit-gitignore () + "Instruct Git to ignore a file or pattern." + :man-page "gitignore" + ["Gitignore" + ("t" "shared at toplevel (.gitignore)" + magit-gitignore-in-topdir) + ("s" "shared in subdirectory (path/to/.gitignore)" + magit-gitignore-in-subdir) + ("p" "privately (.git/info/exclude)" + magit-gitignore-in-gitdir) + ("g" magit-gitignore-on-system + :if (lambda () (magit-get "core.excludesfile")) + :description (lambda () + (format "privately for all repositories (%s)" + (magit-get "core.excludesfile"))))] + ["Skip worktree" + (7 "w" "do skip worktree" magit-skip-worktree) + (7 "W" "do not skip worktree" magit-no-skip-worktree)] + ["Assume unchanged" + (7 "u" "do assume unchanged" magit-assume-unchanged) + (7 "U" "do not assume unchanged" magit-no-assume-unchanged)]) + +;;; Gitignore Commands + +;;;###autoload +(defun magit-gitignore-in-topdir (rule) + "Add the Git ignore RULE to the top-level \".gitignore\" file. +Since this file is tracked, it is shared with other clones of the +repository. Also stage the file." + (interactive (list (magit-gitignore-read-pattern))) + (magit-with-toplevel + (magit--gitignore rule ".gitignore") + (magit-run-git "add" ".gitignore"))) + +;;;###autoload +(defun magit-gitignore-in-subdir (rule directory) + "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." + (interactive (list (magit-gitignore-read-pattern) + (read-directory-name "Limit rule to files in: "))) + (magit-with-toplevel + (let ((file (expand-file-name ".gitignore" directory))) + (magit--gitignore rule file) + (magit-run-git "add" (magit-convert-filename-for-git file))))) + +;;;###autoload +(defun magit-gitignore-in-gitdir (rule) + "Add the Git ignore RULE to \"$GIT_DIR/info/exclude\". +Rules in that file only affects this clone of the repository." + (interactive (list (magit-gitignore-read-pattern))) + (magit--gitignore rule (magit-git-dir "info/exclude")) + (magit-refresh)) + +;;;###autoload +(defun magit-gitignore-on-system (rule) + "Add the Git ignore RULE to the file specified by `core.excludesFile'. +Rules that are defined in that file affect all local repositories." + (interactive (list (magit-gitignore-read-pattern))) + (magit--gitignore rule + (or (magit-get "core.excludesFile") + (error "Variable `core.excludesFile' isn't set"))) + (magit-refresh)) + +(defun magit--gitignore (rule file) + (when-let ((directory (file-name-directory file))) + (make-directory directory t)) + (with-temp-buffer + (when (file-exists-p file) + (insert-file-contents file)) + (goto-char (point-max)) + (unless (bolp) + (insert "\n")) + (insert (replace-regexp-in-string "\\(\\\\*\\)" "\\1\\1" rule)) + (insert "\n") + (write-region nil nil file))) + +(defun magit-gitignore-read-pattern () + (let* ((default (magit-current-file)) + (base (car magit-buffer-diff-files)) + (base (and base (file-directory-p base) base)) + (choices + (delete-dups + (--mapcat + (cons (concat "/" it) + (when-let ((ext (file-name-extension it))) + (list (concat "/" (file-name-directory it) "*." ext) + (concat "*." ext)))) + (sort (nconc + (magit-untracked-files nil base) + ;; The untracked section of the status buffer lists + ;; directories containing only untracked files. + ;; Add those as candidates. + (-filter #'directory-name-p + (magit-list-files + "--other" "--exclude-standard" "--directory" + "--no-empty-directory" "--" base))) + #'string-lessp))))) + (when default + (setq default (concat "/" default)) + (unless (member default choices) + (setq default (concat "*." (file-name-extension default))) + (unless (member default choices) + (setq default nil)))) + (magit-completing-read "File or pattern to ignore" + choices nil nil nil nil default))) + +;;; Skip Worktree Commands + +;;;###autoload +(defun magit-skip-worktree (file) + "Call \"git update-index --skip-worktree -- FILE\"." + (interactive + (list (magit-read-file-choice "Skip worktree for" + (magit-with-toplevel + (cl-set-difference + (magit-list-files) + (magit-skip-worktree-files) + :test #'equal))))) + (magit-with-toplevel + (magit-run-git "update-index" "--skip-worktree" "--" file))) + +;;;###autoload +(defun magit-no-skip-worktree (file) + "Call \"git update-index --no-skip-worktree -- FILE\"." + (interactive + (list (magit-read-file-choice "Do not skip worktree for" + (magit-with-toplevel + (magit-skip-worktree-files))))) + (magit-with-toplevel + (magit-run-git "update-index" "--no-skip-worktree" "--" file))) + +;;; Assume Unchanged Commands + +;;;###autoload +(defun magit-assume-unchanged (file) + "Call \"git update-index --assume-unchanged -- FILE\"." + (interactive + (list (magit-read-file-choice "Assume file to be unchanged" + (magit-with-toplevel + (cl-set-difference + (magit-list-files) + (magit-assume-unchanged-files) + :test #'equal))))) + (magit-with-toplevel + (magit-run-git "update-index" "--assume-unchanged" "--" file))) + +;;;###autoload +(defun magit-no-assume-unchanged (file) + "Call \"git update-index --no-assume-unchanged -- FILE\"." + (interactive + (list (magit-read-file-choice "Do not assume file to be unchanged" + (magit-with-toplevel + (magit-assume-unchanged-files))))) + (magit-with-toplevel + (magit-run-git "update-index" "--no-assume-unchanged" "--" file))) + +;;; _ +(provide 'magit-gitignore) +;;; magit-gitignore.el ends here diff --git a/elpa/magit-20220116.1908/magit-imenu.el b/elpa/magit-20220116.1908/magit-imenu.el new file mode 100644 index 00000000..fad04dec --- /dev/null +++ b/elpa/magit-20220116.1908/magit-imenu.el @@ -0,0 +1,253 @@ +;;; magit-imenu.el --- Integrate Imenu in magit major modes -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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: 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) +;; 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. + +;;; Commentary: + +;; Emacs' major modes can facilitate navigation in their buffers by +;; supporting Imenu. In such major modes, launching Imenu (M-x imenu) +;; makes Emacs display a list of items (e.g., function definitions in +;; a programming major mode). Selecting an item from this list moves +;; point to this item. + +;; magit-imenu.el adds Imenu support to every major mode in Magit. + +;;; Code: + +(require 'magit) +(require 'git-rebase) + +;;; Core + +(defun magit-imenu--index-function (entry-types menu-types) + "Return an alist of imenu entries in current buffer. + +ENTRY-TYPES is a list of section types to be selected through +`imenu'. + +MENU-TYPES is a list of section types containing elements of +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'." + ;; 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 (memq type entry-types) + (memq parent-type menu-types))))) + (let* ((section (magit-current-section)) + (name (buffer-substring-no-properties + (line-beginning-position) + (line-end-position))) + (parent (oref section parent)) + (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))) + entries))) + (mapcar (lambda (menu-title) + (cons menu-title (gethash menu-title entries))) + (hash-table-keys entries)))) + +;;; Log mode + +;;;###autoload +(defun magit-imenu--log-prev-index-position-function () + "Move point to previous line in current buffer. +This function is used as a value for +`imenu-prev-index-position-function'." + (magit-section--backward-find + (lambda () + (-contains-p '(commit stash) + (oref (magit-current-section) type))))) + +;;;###autoload +(defun magit-imenu--log-extract-index-name-function () + "Return imenu name for line at point. +This function is used as a value for +`imenu-extract-index-name-function'. Point should be at the +beginning of the line." + (save-match-data + (looking-at "\\([^ ]+\\)[ *|]+\\(.+\\)$") + (format "%s: %s" + (match-string-no-properties 1) + (match-string-no-properties 2)))) + +;;; Diff mode + +;;;###autoload +(defun magit-imenu--diff-prev-index-position-function () + "Move point to previous file line in current buffer. +This function is used as a value for +`imenu-prev-index-position-function'." + (magit-section--backward-find + (lambda () + (let ((section (magit-current-section))) + (and (magit-file-section-p section) + (not (equal (oref (oref section parent) type) + 'diffstat))))))) + +;;;###autoload +(defun magit-imenu--diff-extract-index-name-function () + "Return imenu name for line at point. +This function is used as a value for +`imenu-extract-index-name-function'. Point should be at the +beginning of the line." + (buffer-substring-no-properties (line-beginning-position) + (line-end-position))) + +;;; Status mode + +;;;###autoload +(defun magit-imenu--status-create-index-function () + "Return an alist of all imenu entries in current buffer. +This function is used as a value for +`imenu-create-index-function'." + (magit-imenu--index-function + '(file commit stash pullreq issue) + '(unpushed unstaged unpulled untracked staged stashes pullreqs issues))) + +;;; Refs mode + +;;;###autoload +(defun magit-imenu--refs-create-index-function () + "Return an alist of all imenu entries in current buffer. +This function is used as a value for +`imenu-create-index-function'." + (magit-imenu--index-function + '(branch commit tag) + '(local remote tags))) + +;;; Cherry mode + +;;;###autoload +(defun magit-imenu--cherry-create-index-function () + "Return an alist of all imenu entries in current buffer. +This function is used as a value for +`imenu-create-index-function'." + (magit-imenu--index-function + '(commit) + '(cherries))) + +;;; Submodule list mode + +;;;###autoload +(defun magit-imenu--submodule-prev-index-position-function () + "Move point to previous line in magit-submodule-list buffer. +This function is used as a value for +`imenu-prev-index-position-function'." + (unless (bobp) + (forward-line -1))) + +;;;###autoload +(defun magit-imenu--submodule-extract-index-name-function () + "Return imenu name for line at point. +This function is used as a value for +`imenu-extract-index-name-function'. Point should be at the +beginning of the line." + (elt (tabulated-list-get-entry) 0)) + +;;; Repolist mode + +;;;###autoload +(defun magit-imenu--repolist-prev-index-position-function () + "Move point to previous line in magit-repolist buffer. +This function is used as a value for +`imenu-prev-index-position-function'." + (unless (bobp) + (forward-line -1))) + +;;;###autoload +(defun magit-imenu--repolist-extract-index-name-function () + "Return imenu name for line at point. +This function is used as a value for +`imenu-extract-index-name-function'. Point should be at the +beginning of the line." + (let ((entry (tabulated-list-get-entry))) + (format "%s (%s)" + (elt entry 0) + (elt entry (1- (length entry)))))) + +;;; Process mode + +;;;###autoload +(defun magit-imenu--process-prev-index-position-function () + "Move point to previous process in magit-process buffer. +This function is used as a value for +`imenu-prev-index-position-function'." + (magit-section--backward-find + (lambda () + (eq (oref (magit-current-section) type) 'process)))) + +;;;###autoload +(defun magit-imenu--process-extract-index-name-function () + "Return imenu name for line at point. +This function is used as a value for +`imenu-extract-index-name-function'. Point should be at the +beginning of the line." + (buffer-substring-no-properties (line-beginning-position) + (line-end-position))) + +;;; Rebase mode + +;;;###autoload +(defun magit-imenu--rebase-prev-index-position-function () + "Move point to previous commit in git-rebase buffer. +This function is used as a value for +`imenu-prev-index-position-function'." + (catch 'found + (while (not (bobp)) + (git-rebase-backward-line) + (when (git-rebase-line-p) + (throw 'found t))))) + +;;;###autoload +(defun magit-imenu--rebase-extract-index-name-function () + "Return imenu name for line at point. +This function is used as a value for +`imenu-extract-index-name-function'. Point should be at the +beginning of the line." + (buffer-substring-no-properties (line-beginning-position) + (line-end-position))) + +;;; _ +(provide 'magit-imenu) +;;; magit-imenu.el ends here diff --git a/elpa/magit-20220116.1908/magit-log.el b/elpa/magit-20220116.1908/magit-log.el new file mode 100644 index 00000000..3c9a12c1 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-log.el @@ -0,0 +1,1870 @@ +;;; magit-log.el --- inspect Git history -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements support for looking at Git logs, including +;; special logs like cherry-logs, as well as for selecting a commit +;; from a log. + +;;; Code: + +(require 'magit-core) +(require 'magit-diff) + +(declare-function magit-blob-visit "magit-files" (blob-or-file)) +(declare-function magit-insert-head-branch-header "magit-status" + (&optional branch)) +(declare-function magit-insert-upstream-branch-header "magit-status" + (&optional branch pull keyword)) +(declare-function magit-read-file-from-rev "magit-files" + (rev prompt &optional default)) +(declare-function magit-show-commit "magit-diff" + (arg1 &optional arg2 arg3 arg4)) +(declare-function magit-reflog-format-subject "magit-reflog" (subject)) +(defvar magit-refs-focus-column-width) +(defvar magit-refs-margin) +(defvar magit-refs-show-commit-count) +(defvar magit-buffer-margin) +(defvar magit-status-margin) +(defvar magit-status-sections-hook) + +(require 'ansi-color) +(require 'crm) +(require 'which-func) + +;;; 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 + "Hook run after entering Magit-Log mode." + :group 'magit-log + :type 'hook) + +(defcustom magit-log-remove-graph-args '("--follow" "--grep" "-G" "-S" "-L") + "The log arguments that cause the `--graph' argument to be dropped." + :package-version '(magit . "2.3.0") + :group 'magit-log + :type '(repeat (string :tag "Argument")) + :options '("--follow" "--grep" "-G" "-S" "-L")) + +(defcustom magit-log-revision-headers-format "\ +%+b%+N +Author: %aN <%aE> +Committer: %cN <%cE>" + "Additional format string used with the `++header' argument." + :package-version '(magit . "3.2.0") + :group 'magit-log + :type 'string) + +(defcustom magit-log-auto-more nil + "Insert more log entries automatically when moving past the last entry. +Only considered when moving past the last entry with +`magit-goto-*-section' commands." + :group 'magit-log + :type 'boolean) + +(defcustom magit-log-margin '(t age magit-log-margin-width t 18) + "Format of the margin in `magit-log-mode' buffers. + +The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). + +If INIT is non-nil, then the margin is shown initially. +STYLE controls how to format the author or committer date. + It can be one of `age' (to show the age of the commit), + `age-abbreviated' (to abbreviate the time unit to a character), + or a string (suitable for `format-time-string') to show the + actual date. Option `magit-log-margin-show-committer-date' + controls which date is being displayed. +WIDTH controls the width of the margin. This exists for forward + compatibility and currently the value should not be changed. +AUTHOR controls whether the name of the author is also shown by + default. +AUTHOR-WIDTH has to be an integer. When the name of the author + is shown, then this specifies how much space is used to do so." + :package-version '(magit . "2.9.0") + :group 'magit-log + :group 'magit-margin + :type magit-log-margin--custom-type + :initialize 'magit-custom-initialize-reset + :set (apply-partially #'magit-margin-set-variable 'magit-log-mode)) + +(defcustom magit-log-margin-show-committer-date nil + "Whether to show the committer date in the margin. + +This option only controls whether the committer date is displayed +instead of the author date. Whether some date is displayed in +the margin and whether the margin is displayed at all is +controlled by other options." + :package-version '(magit . "3.0.0") + :group 'magit-log + :group 'magit-margin + :type 'boolean) + +(defcustom magit-log-show-refname-after-summary nil + "Whether to show refnames after commit summaries. +This is useful if you use really long branch names." + :package-version '(magit . "2.2.0") + :group 'magit-log + :type 'boolean) + +(defcustom magit-log-highlight-keywords t + "Whether to highlight bracketed keywords in commit summaries." + :package-version '(magit . "2.12.0") + :group 'magit-log + :type 'boolean) + +(defcustom magit-log-header-line-function 'magit-log-header-line-sentence + "Function used to generate text shown in header line of log buffers." + :package-version '(magit . "2.12.0") + :group 'magit-log + :type '(choice (function-item magit-log-header-line-arguments) + (function-item magit-log-header-line-sentence) + function)) + +(defcustom magit-log-trace-definition-function 'magit-which-function + "Function used to determine the function at point. +This is used by the command `magit-log-trace-definition'. +You should prefer `magit-which-function' over `which-function' +because the latter may make use of Imenu's outdated cache." + :package-version '(magit . "3.0.0") + :group 'magit-log + :type '(choice (function-item magit-which-function) + (function-item which-function) + (function-item add-log-current-defun) + function)) + +(defface magit-log-graph + '((((class color) (background light)) :foreground "grey30") + (((class color) (background dark)) :foreground "grey80")) + "Face for the graph part of the log output." + :group 'magit-faces) + +(defface magit-log-author + '((((class color) (background light)) + :foreground "firebrick" + :slant normal + :weight normal) + (((class color) (background dark)) + :foreground "tomato" + :slant normal + :weight normal)) + "Face for the author part of the log output." + :group 'magit-faces) + +(defface magit-log-date + '((((class color) (background light)) + :foreground "grey30" + :slant normal + :weight normal) + (((class color) (background dark)) + :foreground "grey80" + :slant normal + :weight normal)) + "Face for the date part of the log output." + :group 'magit-faces) + +(defface magit-header-line-log-select + '((t :inherit bold)) + "Face for the `header-line' in `magit-log-select-mode'." + :group 'magit-faces) + +;;;; File Log + +(defcustom magit-log-buffer-file-locked t + "Whether `magit-log-buffer-file-quick' uses a dedicated buffer." + :package-version '(magit . "2.7.0") + :group 'magit-commands + :group 'magit-log + :type 'boolean) + +;;;; Select Mode + +(defcustom magit-log-select-show-usage 'both + "Whether to show usage information when selecting a commit from a log. +The message can be shown in the `echo-area' or the `header-line', or in +`both' places. If the value isn't one of these symbols, then it should +be nil, in which case no usage information is shown." + :package-version '(magit . "2.1.0") + :group 'magit-log + :type '(choice (const :tag "in echo-area" echo-area) + (const :tag "in header-line" header-line) + (const :tag "in both places" both) + (const :tag "nowhere"))) + +(defcustom magit-log-select-margin + (list (nth 0 magit-log-margin) + (nth 1 magit-log-margin) + 'magit-log-margin-width t + (nth 4 magit-log-margin)) + "Format of the margin in `magit-log-select-mode' buffers. + +The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). + +If INIT is non-nil, then the margin is shown initially. +STYLE controls how to format the author or committer date. + It can be one of `age' (to show the age of the commit), + `age-abbreviated' (to abbreviate the time unit to a character), + or a string (suitable for `format-time-string') to show the + actual date. Option `magit-log-margin-show-committer-date' + controls which date is being displayed. +WIDTH controls the width of the margin. This exists for forward + compatibility and currently the value should not be changed. +AUTHOR controls whether the name of the author is also shown by + default. +AUTHOR-WIDTH has to be an integer. When the name of the author + is shown, then this specifies how much space is used to do so." + :package-version '(magit . "2.9.0") + :group 'magit-log + :group 'magit-margin + :type magit-log-margin--custom-type + :initialize 'magit-custom-initialize-reset + :set-after '(magit-log-margin) + :set (apply-partially #'magit-margin-set-variable 'magit-log-select-mode)) + +;;;; Cherry Mode + +(defcustom magit-cherry-sections-hook + '(magit-insert-cherry-headers + magit-insert-cherry-commits) + "Hook run to insert sections into the cherry buffer." + :package-version '(magit . "2.1.0") + :group 'magit-log + :type 'hook) + +(defcustom magit-cherry-margin + (list (nth 0 magit-log-margin) + (nth 1 magit-log-margin) + 'magit-log-margin-width t + (nth 4 magit-log-margin)) + "Format of the margin in `magit-cherry-mode' buffers. + +The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). + +If INIT is non-nil, then the margin is shown initially. +STYLE controls how to format the author or committer date. + It can be one of `age' (to show the age of the commit), + `age-abbreviated' (to abbreviate the time unit to a character), + or a string (suitable for `format-time-string') to show the + actual date. Option `magit-log-margin-show-committer-date' + controls which date is being displayed. +WIDTH controls the width of the margin. This exists for forward + compatibility and currently the value should not be changed. +AUTHOR controls whether the name of the author is also shown by + default. +AUTHOR-WIDTH has to be an integer. When the name of the author + is shown, then this specifies how much space is used to do so." + :package-version '(magit . "2.9.0") + :group 'magit-log + :group 'magit-margin + :type magit-log-margin--custom-type + :initialize 'magit-custom-initialize-reset + :set-after '(magit-log-margin) + :set (apply-partially #'magit-margin-set-variable 'magit-cherry-mode)) + +;;;; Log Sections + +(defcustom magit-log-section-commit-count 10 + "How many recent commits to show in certain log sections. +How many recent commits `magit-insert-recent-commits' and +`magit-insert-unpulled-from-upstream-or-recent' (provided +the upstream isn't ahead of the current branch) show." + :package-version '(magit . "2.1.0") + :group 'magit-status + :type 'number) + +;;; Arguments +;;;; Prefix Classes + +(defclass magit-log-prefix (transient-prefix) + ((history-key :initform 'magit-log) + (major-mode :initform 'magit-log-mode))) + +(defclass magit-log-refresh-prefix (magit-log-prefix) + ((history-key :initform 'magit-log) + (major-mode :initform nil))) + +;;;; Prefix Methods + +(cl-defmethod transient-init-value ((obj magit-log-prefix)) + (pcase-let ((`(,args ,files) + (magit-log--get-value 'magit-log-mode + magit-prefix-use-buffer-arguments))) + (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)))) + +(cl-defmethod transient-init-value ((obj magit-log-refresh-prefix)) + (oset obj value (if magit-buffer-log-files + `(("--" ,@magit-buffer-log-files) + ,magit-buffer-log-args) + magit-buffer-log-args))) + +(cl-defmethod transient-set-value ((obj magit-log-prefix)) + (magit-log--set-value obj)) + +(cl-defmethod transient-save-value ((obj magit-log-prefix)) + (magit-log--set-value obj 'save)) + +;;;; Argument Access + +(defun magit-log-arguments (&optional mode) + "Return the current log arguments." + (if (memq transient-current-command '(magit-log magit-log-refresh)) + (pcase-let ((`(,args ,alist) + (-separate #'atom (transient-get-value)))) + (list args (cdr (assoc "--" alist)))) + (magit-log--get-value (or mode 'magit-log-mode)))) + +(defun magit-log--get-value (mode &optional use-buffer-args) + (unless use-buffer-args + (setq use-buffer-args magit-direct-use-buffer-arguments)) + (let (args files) + (cond + ((and (memq use-buffer-args '(always selected current)) + (eq major-mode mode)) + (setq args magit-buffer-log-args) + (setq files magit-buffer-log-files)) + ((and (memq use-buffer-args '(always selected)) + (when-let ((buffer (magit-get-mode-buffer + mode nil + (eq use-buffer-args 'selected)))) + (setq args (buffer-local-value 'magit-buffer-log-args buffer)) + (setq files (buffer-local-value 'magit-buffer-log-files buffer)) + t))) + ((plist-member (symbol-plist mode) 'magit-log-current-arguments) + (setq args (get mode 'magit-log-current-arguments))) + ((when-let ((elt (assq (intern (format "magit-log:%s" mode)) + transient-values))) + (setq args (cdr elt)) + t)) + (t + (setq args (get mode 'magit-log-default-arguments)))) + (list args files))) + +(defun magit-log--set-value (obj &optional save) + (pcase-let* ((obj (oref obj prototype)) + (mode (or (oref obj major-mode) major-mode)) + (key (intern (format "magit-log:%s" mode))) + (`(,args ,alist) + (-separate #'atom (transient-get-value))) + (files (cdr (assoc "--" alist)))) + (put mode 'magit-log-current-arguments args) + (when save + (setf (alist-get key transient-values) args) + (transient-save-values)) + (transient--history-push obj) + (setq magit-buffer-log-args args) + (unless (derived-mode-p 'magit-log-select-mode) + (setq magit-buffer-log-files files)) + (magit-refresh))) + +;;; Commands +;;;; Prefix Commands + +;;;###autoload (autoload 'magit-log "magit-log" nil t) +(transient-define-prefix magit-log () + "Show a commit or reference log." + :man-page "git-log" + :class 'magit-log-prefix + ;; The grouping in git-log(1) appears to be guided by implementation + ;; details, so our logical grouping only follows it to an extend. + ;; Arguments that are "misplaced" here: + ;; 1. From "Commit Formatting". + ;; 2. From "Common Diff Options". + ;; 3. From unnamed first group. + ;; 4. Implemented by Magit. + ["Commit limiting" + (magit-log:-n) + (magit:--author) + (7 magit-log:--since) + (7 magit-log:--until) + (magit-log:--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 + (7 "=m" "Omit merges" "--no-merges") + (7 "=p" "First parent" "--first-parent")] + ["History simplification" + ( "-D" "Simplify by decoration" "--simplify-by-decoration") + (magit:--) + ( "-f" "Follow renames when showing single-file log" "--follow") ;3 + (6 "/s" "Only commits changing given paths" "--sparse") + (7 "/d" "Only selected commits plus meaningful history" "--dense") + (7 "/a" "Only commits existing directly on ancestry path" "--ancestry-path") + (6 "/f" "Do not prune history" "--full-history") + (7 "/m" "Prune some history" "--simplify-merges")] + ["Commit ordering" + (magit-log:--*-order) + ("-r" "Reverse order" "--reverse")] + ["Formatting" + ("-g" "Show graph" "--graph") ;1 + ("-c" "Show graph in color" "--color") ;2 + ("-d" "Show refnames" "--decorate") ;3 + ("=S" "Show signatures" "--show-signature") ;1 + ("-h" "Show header" "++header") ;4 + ("-p" "Show diffs" ("-p" "--patch")) ;2 + ("-s" "Show diffstats" "--stat")] ;2 + [["Log" + ("l" "current" magit-log-current) + ("o" "other" magit-log-other) + ("h" "HEAD" magit-log-head)] + ["" + ("L" "local branches" magit-log-branches) + (7 "B" "matching branches" magit-log-matching-branches) + (7 "T" "matching tags" magit-log-matching-tags) + ("b" "all branches" magit-log-all-branches) + ("a" "all references" magit-log-all) + (7 "m" "merged" magit-log-merged)] + ["Reflog" + ("r" "current" magit-reflog-current) + ("O" "other" magit-reflog-other) + ("H" "HEAD" magit-reflog-head)] + [: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)] + ["Other" + (5 "s" "shortlog" magit-shortlog)]]) + +;;;###autoload (autoload 'magit-log-refresh "magit-log" nil t) +(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 + [:if-mode magit-log-mode + :class transient-subgroups + ["Commit limiting" + (magit-log:-n) + (magit:--author) + (magit-log:--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)] + ["History simplification" + ( "-D" "Simplify by decoration" "--simplify-by-decoration") + (magit:--) + ( "-f" "Follow renames when showing single-file log" "--follow") ;3 + (6 "/s" "Only commits changing given paths" "--sparse") + (7 "/d" "Only selected commits plus meaningful history" "--dense") + (7 "/a" "Only commits existing directly on ancestry path" "--ancestry-path") + (6 "/f" "Do not prune history" "--full-history") + (7 "/m" "Prune some history" "--simplify-merges")] + ["Commit ordering" + (magit-log:--*-order) + ("-r" "Reverse order" "--reverse")] + ["Formatting" + ("-g" "Show graph" "--graph") + ("-c" "Show graph in color" "--color") + ("-d" "Show refnames" "--decorate") + ("=S" "Show signatures" "--show-signature") + ("-h" "Show header" "++header") + ("-p" "Show diffs" ("-p" "--patch")) + ("-s" "Show diffstats" "--stat")]] + [:if-not-mode magit-log-mode + :description "Arguments" + (magit-log:-n) + (magit-log:--*-order) + ("-g" "Show graph" "--graph") + ("-c" "Show graph in color" "--color") + ("-d" "Show refnames" "--decorate")] + [["Refresh" + ("g" "buffer" magit-log-refresh) + ("s" "buffer and set defaults" transient-set :transient nil) + ("w" "buffer and save defaults" transient-save :transient nil)] + ["Margin" + ("L" "toggle visibility" magit-toggle-margin) + ("l" "cycle style" magit-cycle-margin-style) + ("d" "toggle details" magit-toggle-margin-details) + ("x" "toggle shortstat" magit-toggle-log-margin-style)] + [:if-mode magit-log-mode + :description "Toggle" + ("b" "buffer lock" magit-toggle-buffer-lock)]] + (interactive) + (cond + ((not (eq transient-current-command 'magit-log-refresh)) + (pcase major-mode + (`magit-reflog-mode + (user-error "Cannot change log arguments in reflog buffers")) + (`magit-cherry-mode + (user-error "Cannot change log arguments in cherry buffers"))) + (transient-setup 'magit-log-refresh)) + (t + (pcase-let ((`(,args ,files) (magit-log-arguments))) + (setq magit-buffer-log-args args) + (unless (derived-mode-p 'magit-log-select-mode) + (setq magit-buffer-log-files files))) + (magit-refresh)))) + +;;;; Infix Commands + +(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" + ;; stands for) this is the only argument where we do not use the + ;; long argument ("--max-count"). + :shortarg "-n" + :argument "-n" + :reader 'transient-read-number-N+) + +(transient-define-argument magit:--author () + :description "Limit to author" + :class 'transient-option + :key "-A" + :argument "--author=" + :reader 'magit-transient-read-person) + +(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" + :argument-format "--%s-order" + :argument-regexp "\\(--\\(topo\\|author-date\\|date\\)-order\\)" + :choices '("topo" "author-date" "date")) + +(transient-define-argument magit-log:--grep () + :description "Search messages" + :class 'transient-option + :key "-F" + :argument "--grep=") + +(transient-define-argument magit-log:-G () + :description "Search changes" + :class 'transient-option + :argument "-G") + +(transient-define-argument magit-log:-S () + :description "Search occurrences" + :class 'transient-option + :argument "-S") + +(transient-define-argument magit-log:-L () + :description "Trace line evolution" + :class 'transient-option + :argument "-L" + :reader 'magit-read-file-trace) + +(defun magit-read-file-trace (&rest _ignored) + (let ((file (magit-read-file-from-rev "HEAD" "File")) + (trace (magit-read-string "Trace"))) + (concat trace ":" file))) + +;;;; Setup Commands + +(defvar magit-log-read-revs-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map crm-local-completion-map) + (define-key map "\s" 'self-insert-command) + map)) + +(defun magit-log-read-revs (&optional use-current) + (or (and use-current (--when-let (magit-get-current-branch) (list it))) + (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." + (magit-read-string (format "Type a pattern to pass to %s" option))) + +;;;###autoload +(defun magit-log-current (revs &optional args files) + "Show log for the current branch. +When `HEAD' is detached or with a prefix argument show log for +one or more revs read from the minibuffer." + (interactive (cons (magit-log-read-revs t) + (magit-log-arguments))) + (magit-log-setup-buffer revs args files)) + +;;;###autoload +(defun magit-log-other (revs &optional args files) + "Show log for one or more revs read from the minibuffer. +The user can input any revision or revisions separated by a +space, or even ranges, but only branches and tags, and a +representation of the commit at point, are available as +completion candidates." + (interactive (cons (magit-log-read-revs) + (magit-log-arguments))) + (magit-log-setup-buffer revs args files)) + +;;;###autoload +(defun magit-log-head (&optional args files) + "Show log for `HEAD'." + (interactive (magit-log-arguments)) + (magit-log-setup-buffer (list "HEAD") args files)) + +;;;###autoload +(defun magit-log-branches (&optional args files) + "Show log for all local branches and `HEAD'." + (interactive (magit-log-arguments)) + (magit-log-setup-buffer (if (magit-get-current-branch) + (list "--branches") + (list "HEAD" "--branches")) + args files)) + +;;;###autoload +(defun magit-log-matching-branches (pattern &optional args files) + "Show log for all branches matching PATTERN and `HEAD'." + (interactive (cons (magit-log-read-pattern "--branches") (magit-log-arguments))) + (magit-log-setup-buffer + (list "HEAD" (format "--branches=%s" pattern)) + args files)) + +;;;###autoload +(defun magit-log-matching-tags (pattern &optional args files) + "Show log for all tags matching PATTERN and `HEAD'." + (interactive (cons (magit-log-read-pattern "--tags") (magit-log-arguments))) + (magit-log-setup-buffer + (list "HEAD" (format "--tags=%s" pattern)) + args files)) + +;;;###autoload +(defun magit-log-all-branches (&optional args files) + "Show log for all local and remote branches and `HEAD'." + (interactive (magit-log-arguments)) + (magit-log-setup-buffer (if (magit-get-current-branch) + (list "--branches" "--remotes") + (list "HEAD" "--branches" "--remotes")) + args files)) + +;;;###autoload +(defun magit-log-all (&optional args files) + "Show log for all references and `HEAD'." + (interactive (magit-log-arguments)) + (magit-log-setup-buffer (if (magit-get-current-branch) + (list "--all") + (list "HEAD" "--all")) + args files)) + +;;;###autoload +(defun magit-log-buffer-file (&optional follow beg end) + "Show log for the blob or file visited in the current buffer. +With a prefix argument or when `--follow' is an active log +argument, then follow renames. When the region is active, +restrict the log to the lines that the region touches." + (interactive + (cons current-prefix-arg + (and (region-active-p) + (magit-file-relative-name) + (save-restriction + (widen) + (list (line-number-at-pos (region-beginning)) + (line-number-at-pos + (let ((end (region-end))) + (if (char-after end) + end + ;; Ensure that we don't get the line number + ;; of a trailing newline. + (1- end))))))))) + (require 'magit) + (if-let ((file (magit-file-relative-name))) + (magit-log-setup-buffer + (list (or magit-buffer-refname + (magit-get-current-branch) + "HEAD")) + (let ((args (car (magit-log-arguments)))) + (when (and follow (not (member "--follow" args))) + (push "--follow" args)) + (when (and (file-regular-p + (expand-file-name file (magit-toplevel))) + beg end) + (setq args (cons (format "-L%s,%s:%s" beg end file) + (cl-delete "-L" args :test + 'string-prefix-p))) + (setq file nil)) + args) + (and file (list file)) + magit-log-buffer-file-locked) + (user-error "Buffer isn't visiting a file"))) + +;;;###autoload +(defun magit-log-trace-definition (file fn rev) + "Show log for the definition at point." + (interactive (list (or (magit-file-relative-name) + (user-error "Buffer isn't visiting a file")) + (or (funcall magit-log-trace-definition-function) + (user-error "No function at point found")) + (or magit-buffer-refname + (magit-get-current-branch) + "HEAD"))) + (require 'magit) + (magit-log-setup-buffer + (list rev) + (cons (format "-L:%s%s:%s" + (replace-regexp-in-string ":" "\\:" (regexp-quote fn) nil t) + (if (derived-mode-p 'lisp-mode 'emacs-lisp-mode) + ;; Git doesn't treat "-" the same way as + ;; "_", leading to false-positives such as + ;; "foo-suffix" being considered a match + ;; for "foo". Wing it. + "\\( \\|$\\)" + ;; We could use "\\b" here, but since Git + ;; already does something equivalent, that + ;; isn't necessary. + "") + file) + (cl-delete "-L" (car (magit-log-arguments)) + :test 'string-prefix-p)) + nil magit-log-buffer-file-locked)) + +(defun magit-diff-trace-definition () + "Show log for the definition at point in a diff." + (interactive) + (pcase-let ((`(,buf ,pos) (magit-diff-visit-file--noselect))) + (magit--with-temp-position buf pos + (call-interactively #'magit-log-trace-definition)))) + +;;;###autoload +(defun magit-log-merged (commit branch &optional args files) + "Show log for the merge of COMMIT into BRANCH. + +More precisely, find merge commit M that brought COMMIT into +BRANCH, and show the log of the range \"M^1..M\". If COMMIT is +directly on BRANCH, then show approximately twenty surrounding +commits instead. + +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 "Log merge of commit"))) + (list commit + (magit-read-other-branch "Merged into" commit))) + (magit-log-arguments))) + (unless (executable-find "git-when-merged") + (user-error "This command requires git-when-merged (%s)" + "https://github.com/mhagger/git-when-merged")) + (let (exit m) + (with-temp-buffer + (save-excursion + (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)) + args files nil commit) + (setq m (string-trim-left (substring m (string-match " " m)))) + (if (equal m "Commit is directly on this branch.") + (let* ((from (concat commit "~10")) + (to (- (car (magit-rev-diff-count branch commit)) 10)) + (to (if (<= to 0) + branch + (format "%s~%s" branch to)))) + (unless (magit-rev-verify-commit from) + (setq from (magit-git-string "rev-list" "--max-parents=0" + commit))) + (magit-log-setup-buffer (list (concat from ".." to)) + (cons "--first-parent" args) + files nil commit)) + (user-error "Could not find when %s was merged into %s: %s" + commit branch m))))) + +;;;; Limit Commands + +(defun magit-log-toggle-commit-limit () + "Toggle the number of commits the current log buffer is limited to. +If the number of commits is currently limited, then remove that +limit. Otherwise set it to 256." + (interactive) + (magit-log-set-commit-limit (lambda (&rest _) nil))) + +(defun magit-log-double-commit-limit () + "Double the number of commits the current log buffer is limited to." + (interactive) + (magit-log-set-commit-limit '*)) + +(defun magit-log-half-commit-limit () + "Half the number of commits the current log buffer is limited to." + (interactive) + (magit-log-set-commit-limit '/)) + +(defun magit-log-set-commit-limit (fn) + (let* ((val magit-buffer-log-args) + (arg (--first (string-match "^-n\\([0-9]+\\)?$" it) val)) + (num (and arg (string-to-number (match-string 1 arg)))) + (num (if num (funcall fn num 2) 256))) + (setq val (delete arg val)) + (setq magit-buffer-log-args + (if (and num (> num 0)) + (cons (format "-n%i" num) val) + val))) + (magit-refresh)) + +(defun magit-log-get-commit-limit () + (--when-let (--first (string-match "^-n\\([0-9]+\\)?$" it) + magit-buffer-log-args) + (string-to-number (match-string 1 it)))) + +;;;; Mode Commands + +(defun magit-log-bury-buffer (&optional arg) + "Bury the current buffer or the revision buffer in the same frame. +Like `magit-mode-bury-buffer' (which see) but with a negative +prefix argument instead bury the revision buffer, provided it +is displayed in the current frame." + (interactive "p") + (if (< arg 0) + (let* ((buf (magit-get-mode-buffer 'magit-revision-mode)) + (win (and buf (get-buffer-window buf (selected-frame))))) + (if win + (with-selected-window win + (with-current-buffer buf + (magit-mode-bury-buffer (> (abs arg) 1)))) + (user-error "No revision buffer in this frame"))) + (magit-mode-bury-buffer (> arg 1)))) + +;;;###autoload +(defun magit-log-move-to-parent (&optional n) + "Move to the Nth parent of the current commit." + (interactive "p") + (when (derived-mode-p 'magit-log-mode) + (when (magit-section-match 'commit) + (let* ((section (magit-current-section)) + (parent-rev (format "%s^%s" (oref section value) (or n 1)))) + (if-let ((parent-hash (magit-rev-parse "--short" parent-rev))) + (if-let ((parent (--first (equal (oref it value) + parent-hash) + (magit-section-siblings section 'next)))) + (magit-section-goto parent) + (user-error + (substitute-command-keys + (concat "Parent " parent-hash " not found. Try typing " + "\\[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 + '("-G" "--grep" "--author") + "Arguments which disable the graph speedup hack.") + +(defvar magit-log-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-mode-map) + (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) + (define-key map "q" 'magit-log-bury-buffer) + map) + "Keymap for `magit-log-mode'.") + +(define-derived-mode magit-log-mode magit-mode "Magit Log" + "Mode for looking at Git log. + +This mode is documented in info node `(magit)Log Buffer'. + +\\\ +Type \\[magit-refresh] to refresh the current buffer. +Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \ +to visit the commit at point. + +Type \\[magit-branch] to see available branch commands. +Type \\[magit-merge] to merge the branch or commit at point. +Type \\[magit-cherry-pick] to apply the commit at point. +Type \\[magit-reset] to reset `HEAD' to the commit at point. + +\\{magit-log-mode-map}" + :group 'magit-log + (hack-dir-local-variables-non-file-buffer) + (setq imenu-prev-index-position-function + 'magit-imenu--log-prev-index-position-function) + (setq imenu-extract-index-name-function + 'magit-imenu--log-extract-index-name-function)) + +(put 'magit-log-mode 'magit-log-default-arguments + '("--graph" "-n256" "--decorate")) + +(defun magit-log-setup-buffer (revs args files &optional locked focus) + (require 'magit) + (with-current-buffer + (magit-setup-buffer #'magit-log-mode locked + (magit-buffer-revisions revs) + (magit-buffer-log-args args) + (magit-buffer-log-files files)) + (when (if focus + (magit-log-goto-commit-section focus) + (magit-log-goto-same-commit)) + (magit-section-update-highlight)) + (current-buffer))) + +(defun magit-log-refresh-buffer () + (let ((revs magit-buffer-revisions) + (args magit-buffer-log-args) + (files magit-buffer-log-files)) + (magit-set-header-line-format + (funcall magit-log-header-line-function revs args files)) + (unless (= (length files) 1) + (setq args (remove "--follow" args))) + (when (and (car magit-log-remove-graph-args) + (--any-p (string-match-p + (concat "^" (regexp-opt magit-log-remove-graph-args)) it) + args)) + (setq args (remove "--graph" args))) + (unless (member "--graph" args) + (setq args (remove "--color" args))) + (when-let ((limit (magit-log-get-commit-limit)) + (limit (* 2 limit)) ; increase odds for complete graph + (count (and (= (length revs) 1) + (> limit 1024) ; otherwise it's fast enough + (setq revs (car revs)) + (not (string-match-p "\\.\\." revs)) + (not (member revs '("--all" "--branches"))) + (-none-p (lambda (arg) + (--any-p (string-prefix-p it arg) + magit-log-disable-graph-hack-args)) + args) + (magit-git-string "rev-list" "--count" + "--first-parent" args revs)))) + (setq revs (if (< (string-to-number count) limit) + revs + (format "%s~%s..%s" revs limit revs)))) + (magit-insert-section (logbuf) + (magit-insert-log revs args files)))) + +(cl-defmethod magit-buffer-value (&context (major-mode magit-log-mode)) + (append magit-buffer-revisions + (if (and magit-buffer-revisions magit-buffer-log-files) + (cons "--" magit-buffer-log-files) + magit-buffer-log-files))) + +(defun magit-log-header-line-arguments (revs args files) + "Return string describing some of the used arguments." + (mapconcat (lambda (arg) + (if (string-match-p " " arg) + (prin1 arg) + arg)) + `("git" "log" ,@args ,@revs "--" ,@files) + " ")) + +(defun magit-log-header-line-sentence (revs args files) + "Return string containing all arguments." + (concat "Commits in " + (mapconcat #'identity revs " ") + (and (member "--reverse" args) + " in reverse") + (and files (concat " touching " + (mapconcat 'identity files " "))) + (--some (and (string-prefix-p "-L" it) + (concat " " it)) + args))) + +(defun magit-insert-log (revs &optional args files) + "Insert a log section. +Do not add this to a hook variable." + (let ((magit-git-global-arguments + (remove "--literal-pathspecs" magit-git-global-arguments))) + (magit-git-wash (apply-partially #'magit-log-wash-log 'log) + "log" + (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 " + "") + (if (member "--decorate" args) "%D" "") + (if (member "--show-signature" args) + (progn (setq args (remove "--show-signature" args)) "%G?") + "") + (if magit-log-margin-show-committer-date "%ct" "%at") + (if (member "++header" args) + (if (member "--graph" (setq args (remove "++header" args))) + (concat "\n" magit-log-revision-headers-format "\n") + (concat "\n" magit-log-revision-headers-format "\n")) + "")) + (progn + (--when-let (--first (string-match "^\\+\\+order=\\(.+\\)$" it) args) + (setq args (cons (format "--%s-order" (match-string 1 it)) + (remove it args)))) + (when (member "--decorate" args) + (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))) + +(defvar magit-commit-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] 'magit-show-commit) + (define-key map "a" 'magit-cherry-apply) + map) + "Keymap for `commit' sections.") + +(defvar magit-module-commit-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] 'magit-show-commit) + map) + "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]+\\)? " ; 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:[^ \n]*\\) " ; date + "\\(?2:.*\\)$")) ; msg + +(defconst magit-log-cherry-re + (concat "^" + "\\(?8:[-+]\\) " ; cherry + "\\(?1:[0-9a-fA-F]+\\) " ; sha1 + "\\(?2:.*\\)$")) ; msg + +(defconst magit-log-module-re + (concat "^" + "\\(?:\\(?11:[<>]\\) \\)?" ; side + "\\(?1:[0-9a-fA-F]+\\) " ; sha1 + "\\(?2:.*\\)$")) ; msg + +(defconst magit-log-bisect-vis-re + (concat "^" + "\\(?4:[-_/|\\*o<>. ]*\\)" ; graph + "\\(?1:[0-9a-fA-F]+\\)?\0" ; sha1 + "\\(?3:[^\0\n]+\\)?\0" ; refs + "\\(?2:.*\\)$")) ; msg + +(defconst magit-log-bisect-log-re + (concat "^# " + "\\(?3:[^: \n]+:\\) " ; "refs" + "\\[\\(?1:[^]\n]+\\)\\] " ; sha1 + "\\(?2:.*\\)$")) ; msg + +(defconst magit-log-reflog-re + (concat "^" + "\\(?1:[^\0\n]+\\)\0" ; sha1 + "\\(?5:[^\0\n]*\\)\0" ; author + "\\(?:\\(?:[^@\n]+@{\\(?6:[^}\n]+\\)}\0" ; date + "\\(?10:merge \\|autosave \\|restart \\|[^:\n]+: \\)?" ; refsub + "\\(?2:.*\\)?\\)\\|\0\\)$")) ; msg + +(defconst magit-reflog-subject-re + (concat "\\(?1:[^ ]+\\) ?" ; command + "\\(?2:\\(?: ?-[^ ]+\\)+\\)?" ; option + "\\(?: ?(\\(?3:[^)]+\\))\\)?")) ; type + +(defconst magit-log-stash-re + (concat "^" + "\\(?1:[^\0\n]+\\)\0" ; "sha1" + "\\(?5:[^\0\n]*\\)\0" ; author + "\\(?6:[^\0\n]+\\)\0" ; date + "\\(?2:.*\\)$")) ; msg + +(defvar magit-log-count nil) + +(defvar magit-log-format-message-function 'magit-log-propertize-keywords) + +(defun magit-log-wash-log (style args) + (setq args (-flatten args)) + (when (and (member "--graph" args) + (member "--color" args)) + (let ((ansi-color-apply-face-function + (lambda (beg end face) + (put-text-property beg end 'font-lock-face + (or face 'magit-log-graph))))) + (ansi-color-apply-on-region (point-min) (point-max)))) + (when (eq style 'cherry) + (reverse-region (point-min) (point-max))) + (let ((magit-log-count 0)) + (when (looking-at "^\\.\\.\\.") + (magit-delete-line)) + (magit-wash-sequence (apply-partially 'magit-log-wash-rev style + (magit-abbrev-length))) + (if (derived-mode-p 'magit-log-mode 'magit-reflog-mode) + (when (eq magit-log-count (magit-log-get-commit-limit)) + (magit-insert-section (longer) + (insert-text-button + (substitute-command-keys + (format "Type \\<%s>\\[%s] to show more history" + 'magit-log-mode-map + 'magit-log-double-commit-limit)) + 'action (lambda (_button) + (magit-log-double-commit-limit)) + 'follow-link t + 'mouse-face 'magit-section-highlight))) + (insert ?\n)))) + +(cl-defun magit-log-wash-rev (style abbrev) + (when (derived-mode-p 'magit-log-mode 'magit-reflog-mode) + (cl-incf magit-log-count)) + (looking-at (pcase style + (`log magit-log-heading-re) + (`cherry magit-log-cherry-re) + (`module magit-log-module-re) + (`reflog magit-log-reflog-re) + (`stash magit-log-stash-re) + (`bisect-vis magit-log-bisect-vis-re) + (`bisect-log magit-log-bisect-log-re))) + (magit-bind-match-strings + (hash msg refs graph author date gpg cherry _ refsub side) nil + (setq msg (substring-no-properties msg)) + (when refs + (setq refs (substring-no-properties refs))) + (let ((align (or (eq style 'cherry) + (not (member "--stat" magit-buffer-log-args)))) + (non-graph-re (if (eq style 'bisect-vis) + magit-log-bisect-vis-re + magit-log-heading-re))) + (magit-delete-line) + ;; If the reflog entries have been pruned, the output of `git + ;; reflog show' includes a partial line that refers to the hash + ;; of the youngest expired reflog entry. + (when (and (eq style 'reflog) (not date)) + (cl-return-from magit-log-wash-rev t)) + (magit-insert-section section (commit hash) + (pcase style + (`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) + (insert (make-string (1- magit-refs-focus-column-width) ?\s))) + (insert (propertize cherry 'font-lock-face + (if (string= cherry "-") + 'magit-cherry-equivalent + 'magit-cherry-unmatched))) + (insert ?\s)) + (when side + (insert (propertize side 'font-lock-face + (if (string= side "<") + 'magit-cherry-equivalent + 'magit-cherry-unmatched))) + (insert ?\s)) + (when align + (insert hash ?\s)) + (when graph + (insert graph)) + (unless align + (insert hash ?\s)) + (when (and refs (not magit-log-show-refname-after-summary)) + (insert (magit-format-ref-labels refs) ?\s)) + (when (eq style 'reflog) + (insert (format "%-2s " (1- magit-log-count))) + (when refsub + (insert (magit-reflog-format-subject + (substring refsub 0 (if (string-match-p ":" refsub) -2 -1)))))) + (when msg + (insert (funcall magit-log-format-message-function hash msg))) + (when (and refs magit-log-show-refname-after-summary) + (insert ?\s) + (insert (magit-format-ref-labels refs))) + (insert ?\n) + (when (memq style '(log reflog stash)) + (goto-char (line-beginning-position)) + (when (and refsub + (string-match "\\`\\([^ ]\\) \\+\\(..\\)\\(..\\)" date)) + (setq date (+ (string-to-number (match-string 1 date)) + (* (string-to-number (match-string 2 date)) 60 60) + (* (string-to-number (match-string 3 date)) 60)))) + (save-excursion + (backward-char) + (magit-log-format-margin hash author date))) + (when (and (eq style 'cherry) + (magit-buffer-margin-p)) + (save-excursion + (backward-char) + (apply #'magit-log-format-margin hash + (split-string (magit-rev-format "%aN%x00%ct" hash) "\0")))) + (when (and graph + (not (eobp)) + (not (looking-at non-graph-re))) + (when (looking-at "") + (magit-insert-heading) + (delete-char 1) + (magit-insert-section (commit-header) + (forward-line) + (magit-insert-heading) + (re-search-forward "") + (backward-delete-char 1) + (forward-char) + (insert ?\n)) + (delete-char 1)) + (if (looking-at "^\\(---\\|\n\s\\|\ndiff\\)") + (let ((limit (save-excursion + (and (re-search-forward non-graph-re nil t) + (match-beginning 0))))) + (unless (oref magit-insert-section--current content) + (magit-insert-heading)) + (delete-char (if (looking-at "\n") 1 4)) + (magit-diff-wash-diffs (list "--stat") limit)) + (when align + (setq align (make-string (1+ abbrev) ? ))) + (when (and (not (eobp)) (not (looking-at non-graph-re))) + (when align + (setq align (make-string (1+ abbrev) ? ))) + (while (and (not (eobp)) (not (looking-at non-graph-re))) + (when align + (save-excursion (insert align))) + (magit-make-margin-overlay) + (forward-line)) + ;; When `--format' is used and its value isn't one of the + ;; predefined formats, then `git-log' does not insert a + ;; separator line. + (save-excursion + (forward-line -1) + (looking-at "[-_/|\\*o<>. ]*")) + (setq graph (match-string 0)) + (unless (string-match-p "[/\\.]" graph) + (insert graph ?\n)))))))) + t) + +(defun magit-log-propertize-keywords (_rev msg) + (let ((boundary 0)) + (when (string-match "^\\(?:squash\\|fixup\\)! " msg boundary) + (setq boundary (match-end 0)) + (magit--put-face (match-beginning 0) (1- boundary) + 'magit-keyword-squash msg)) + (when magit-log-highlight-keywords + (while (string-match "\\[[^[]*?]" msg boundary) + (setq boundary (match-end 0)) + (magit--put-face (match-beginning 0) boundary + 'magit-keyword msg)))) + msg) + +(defun magit-log-maybe-show-more-commits (section) + "When point is at the end of a log buffer, insert more commits. + +Log buffers end with a button \"Type + to show more history\". +When the use of a section movement command puts point on that +button, then automatically show more commits, without the user +having to press \"+\". + +This function is called by `magit-section-movement-hook' and +exists mostly for backward compatibility reasons." + (when (and (eq (oref section type) 'longer) + magit-log-auto-more) + (magit-log-double-commit-limit) + (forward-line -1) + (magit-section-forward))) + +(add-hook 'magit-section-movement-hook #'magit-log-maybe-show-more-commits) + +(defvar magit--update-revision-buffer nil) + +(defun magit-log-maybe-update-revision-buffer (&optional _) + "When moving in a log or cherry buffer, update the revision buffer. +If there is no revision buffer in the same frame, then do nothing." + (when (derived-mode-p 'magit-log-mode 'magit-cherry-mode 'magit-reflog-mode) + (magit--maybe-update-revision-buffer))) + +(add-hook 'magit-section-movement-hook #'magit-log-maybe-update-revision-buffer) + +(defun magit--maybe-update-revision-buffer () + (when-let ((commit (magit-section-value-if 'commit)) + (buffer (magit-get-mode-buffer 'magit-revision-mode nil t))) + (if magit--update-revision-buffer + (setq magit--update-revision-buffer (list commit buffer)) + (setq magit--update-revision-buffer (list commit buffer)) + (run-with-idle-timer + magit-update-other-window-delay nil + (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) + (when (buffer-live-p buf) + (let ((magit-display-buffer-noselect t)) + (apply #'magit-show-commit rev args)))) + (setq magit--update-revision-buffer nil))))))) + +(defvar magit--update-blob-buffer nil) + +(defun magit-log-maybe-update-blob-buffer (&optional _) + "When moving in a log or cherry buffer, update the blob buffer. +If there is no blob buffer in the same frame, then do nothing." + (when (derived-mode-p 'magit-log-mode 'magit-cherry-mode 'magit-reflog-mode) + (magit--maybe-update-blob-buffer))) + +(defun magit--maybe-update-blob-buffer () + (when-let ((commit (magit-section-value-if 'commit)) + (buffer (--first (with-current-buffer it + (eq revert-buffer-function + 'magit-revert-rev-file-buffer)) + (mapcar #'window-buffer (window-list))))) + (if magit--update-blob-buffer + (setq magit--update-blob-buffer (list commit buffer)) + (setq magit--update-blob-buffer (list commit buffer)) + (run-with-idle-timer + magit-update-other-window-delay nil + (lambda () + (pcase-let ((`(,rev ,buf) magit--update-blob-buffer)) + (setq magit--update-blob-buffer nil) + (when (buffer-live-p buf) + (with-selected-window (get-buffer-window buf) + (with-current-buffer buf + (save-excursion + (magit-blob-visit (list (magit-rev-parse rev) + (magit-file-relative-name + magit-buffer-file-name))))))))))))) + +(defun magit-log-goto-commit-section (rev) + (let ((abbrev (magit-rev-format "%h" rev))) + (when-let ((section (--first (equal (oref it value) abbrev) + (oref magit-root-section children)))) + (goto-char (oref section start))))) + +(defun magit-log-goto-same-commit () + (when (and magit-previous-section + (magit-section-match '(commit branch) + magit-previous-section)) + (magit-log-goto-commit-section (oref magit-previous-section value)))) + +;;; Log Margin + +(defvar-local magit-log-margin-show-shortstat nil) + +(defun magit-toggle-log-margin-style () + "Toggle between the regular and the shortstat margin style. +The shortstat style is experimental and rather slow." + (interactive) + (setq magit-log-margin-show-shortstat + (not magit-log-margin-show-shortstat)) + (magit-set-buffer-margin nil t)) + +(defun magit-log-format-margin (rev author date) + (when (magit-margin-option) + (if magit-log-margin-show-shortstat + (magit-log-format-shortstat-margin rev) + (magit-log-format-author-margin author date)))) + +(defun magit-log-format-author-margin (author date &optional previous-line) + (pcase-let ((`(,_ ,style ,width ,details ,details-width) + (or magit-buffer-margin + (symbol-value (magit-margin-option))))) + (magit-make-margin-overlay + (concat (and details + (concat (magit--propertize-face + (truncate-string-to-width + (or author "") + details-width + nil ?\s + (if (char-displayable-p ?…) "…" ">")) + 'magit-log-author) + " ")) + (magit--propertize-face + (if (stringp style) + (format-time-string + style + (seconds-to-time (string-to-number date))) + (pcase-let* ((abbr (eq style 'age-abbreviated)) + (`(,cnt ,unit) (magit--age date abbr))) + (format (format (if abbr "%%2i%%-%ic" "%%2i %%-%is") + (- width (if details (1+ details-width) 0))) + cnt unit))) + 'magit-log-date)) + previous-line))) + +(defun magit-log-format-shortstat-margin (rev) + (magit-make-margin-overlay + (if-let ((line (and rev (magit-git-string + "show" "--format=" "--shortstat" rev)))) + (if (string-match "\ +\\([0-9]+\\) files? changed, \ +\\(?:\\([0-9]+\\) insertions?(\\+)\\)?\ +\\(?:\\(?:, \\)?\\([0-9]+\\) deletions?(-)\\)?\\'" line) + (magit-bind-match-strings (files add del) line + (format + "%5s %5s%4s" + (if add + (magit--propertize-face (format "%s+" add) + 'magit-diffstat-added) + "") + (if del + (magit--propertize-face (format "%s-" del) + 'magit-diffstat-removed) + "") + files)) + "") + ""))) + +(defun magit-log-margin-width (style details details-width) + (if magit-log-margin-show-shortstat + 16 + (+ (if details (1+ details-width) 0) + (if (stringp style) + (length (format-time-string style)) + (+ 2 ; two digits + 1 ; trailing space + (if (eq style 'age-abbreviated) + 1 ; single character + (+ 1 ; gap after digits + (apply #'max (--map (max (length (nth 1 it)) + (length (nth 2 it))) + magit--age-spec))))))))) + +;;; Select Mode + +(defvar magit-log-select-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-log-mode-map) + (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'.") + +(put 'magit-log-select-pick :advertised-binding [?\C-c ?\C-c]) +(put 'magit-log-select-quit :advertised-binding [?\C-c ?\C-k]) + +(define-derived-mode magit-log-select-mode magit-log-mode "Magit Select" + "Mode for selecting a commit from history. + +This mode is documented in info node `(magit)Select from Log'. + +\\\ +Type \\[magit-refresh] to refresh the current buffer. +Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \ +to visit the commit at point. + +\\\ +Type \\[magit-log-select-pick] to select the commit at point. +Type \\[magit-log-select-quit] to abort without selecting a commit." + :group 'magit-log + (hack-dir-local-variables-non-file-buffer)) + +(put 'magit-log-select-mode 'magit-log-default-arguments + '("--graph" "-n256" "--decorate")) + +(defun magit-log-select-setup-buffer (revs args) + (magit-setup-buffer #'magit-log-select-mode nil + (magit-buffer-revisions revs) + (magit-buffer-log-args args))) + +(defun magit-log-select-refresh-buffer () + (magit-insert-section (logbuf) + (magit-insert-log magit-buffer-revisions + magit-buffer-log-args))) + +(cl-defmethod magit-buffer-value (&context (major-mode magit-log-select-mode)) + magit-buffer-revisions) + +(defvar-local magit-log-select-pick-function nil) +(defvar-local magit-log-select-quit-function nil) + +(defun magit-log-select (pick &optional msg quit branch args initial) + (declare (indent defun)) + (unless initial + (setq initial (magit-commit-at-point))) + (magit-log-select-setup-buffer + (or branch (magit-get-current-branch) "HEAD") + (append args + (car (magit-log--get-value 'magit-log-select-mode + magit-direct-use-buffer-arguments)))) + (when initial + (magit-log-goto-commit-section initial)) + (setq magit-log-select-pick-function pick) + (setq magit-log-select-quit-function quit) + (when magit-log-select-show-usage + (let ((pick (propertize (substitute-command-keys + "\\[magit-log-select-pick]") + 'font-lock-face + 'magit-header-line-key)) + (quit (propertize (substitute-command-keys + "\\[magit-log-select-quit]") + 'font-lock-face + 'magit-header-line-key))) + (setq msg (format-spec + (if msg + (if (string-suffix-p "," msg) + (concat msg " or %q to abort") + msg) + "Type %p to select commit at point, or %q to abort") + `((?p . ,pick) + (?q . ,quit))))) + (magit--add-face-text-property + 0 (length msg) 'magit-header-line-log-select t msg) + (when (memq magit-log-select-show-usage '(both header-line)) + (magit-set-header-line-format msg)) + (when (memq magit-log-select-show-usage '(both echo-area)) + (message "%s" (substring-no-properties msg))))) + +(defun magit-log-select-pick () + "Select the commit at point and act on it. +Call `magit-log-select-pick-function' with the selected +commit as argument." + (interactive) + (let ((fun magit-log-select-pick-function) + (rev (magit-commit-at-point))) + (magit-mode-bury-buffer 'kill) + (funcall fun rev))) + +(defun magit-log-select-quit () + "Abort selecting a commit, don't act on any commit. +Call `magit-log-select-quit-function' if set." + (interactive) + (let ((fun magit-log-select-quit-function)) + (magit-mode-bury-buffer 'kill) + (when fun (funcall fun)))) + +;;; Cherry Mode + +(defvar magit-cherry-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-mode-map) + (define-key map "q" 'magit-log-bury-buffer) + (define-key map "L" 'magit-margin-settings) + map) + "Keymap for `magit-cherry-mode'.") + +(define-derived-mode magit-cherry-mode magit-mode "Magit Cherry" + "Mode for looking at commits not merged upstream. + +\\\ +Type \\[magit-refresh] to refresh the current buffer. +Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \ +to visit the commit at point. + +Type \\[magit-cherry-pick] to apply the commit at point. + +\\{magit-cherry-mode-map}" + :group 'magit-log + (hack-dir-local-variables-non-file-buffer) + (setq imenu-create-index-function + 'magit-imenu--cherry-create-index-function)) + +(defun magit-cherry-setup-buffer (head upstream) + (magit-setup-buffer #'magit-cherry-mode nil + (magit-buffer-refname head) + (magit-buffer-upstream upstream) + (magit-buffer-range (concat upstream ".." head)))) + +(defun magit-cherry-refresh-buffer () + (magit-insert-section (cherry) + (magit-run-section-hook 'magit-cherry-sections-hook))) + +(cl-defmethod magit-buffer-value (&context (major-mode magit-cherry-mode)) + magit-buffer-range) + +;;;###autoload +(defun magit-cherry (head upstream) + "Show commits in a branch that are not merged in the upstream branch." + (interactive + (let ((head (magit-read-branch "Cherry head"))) + (list head (magit-read-other-branch "Cherry upstream" head + (magit-get-upstream-branch head))))) + (require 'magit) + (magit-cherry-setup-buffer head upstream)) + +(defun magit-insert-cherry-headers () + "Insert headers appropriate for `magit-cherry-mode' buffers." + (let ((branch (propertize magit-buffer-refname + 'font-lock-face 'magit-branch-local)) + (upstream (propertize magit-buffer-upstream 'font-lock-face + (if (magit-local-branch-p magit-buffer-upstream) + 'magit-branch-local + 'magit-branch-remote)))) + (magit-insert-head-branch-header branch) + (magit-insert-upstream-branch-header branch upstream "Upstream: ") + (insert ?\n))) + +(defun magit-insert-cherry-commits () + "Insert commit sections into a `magit-cherry-mode' buffer." + (magit-insert-section (cherries) + (magit-insert-heading "Cherry commits:") + (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry) + "cherry" "-v" "--abbrev" + magit-buffer-upstream + magit-buffer-refname))) + +;;; Log Sections +;;;; Standard Log Sections + +(defvar magit-unpulled-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] 'magit-diff-dwim) + map) + "Keymap for `unpulled' sections.") + +(magit-define-section-jumper magit-jump-to-unpulled-from-upstream + "Unpulled from @{upstream}" unpulled "..@{upstream}") + +(defun magit-insert-unpulled-from-upstream () + "Insert commits that haven't been pulled from the upstream yet." + (when-let ((upstream (magit-get-upstream-branch))) + (magit-insert-section (unpulled "..@{upstream}" t) + (magit-insert-heading + (format (propertize "Unpulled from %s." + 'font-lock-face 'magit-section-heading) + upstream)) + (magit-insert-log "..@{upstream}" magit-buffer-log-args) + (magit-log-insert-child-count)))) + +(magit-define-section-jumper magit-jump-to-unpulled-from-pushremote + "Unpulled from " unpulled + (concat ".." (magit-get-push-branch))) + +(defun magit-insert-unpulled-from-pushremote () + "Insert commits that haven't been pulled from the push-remote yet." + (--when-let (magit-get-push-branch) + (when (magit--insert-pushremote-log-p) + (magit-insert-section (unpulled (concat ".." it) t) + (magit-insert-heading + (format (propertize "Unpulled from %s." + 'font-lock-face 'magit-section-heading) + (propertize it 'font-lock-face 'magit-branch-remote))) + (magit-insert-log (concat ".." it) magit-buffer-log-args) + (magit-log-insert-child-count))))) + +(defvar magit-unpushed-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] 'magit-diff-dwim) + map) + "Keymap for `unpushed' sections.") + +(magit-define-section-jumper magit-jump-to-unpushed-to-upstream + "Unpushed to @{upstream}" unpushed "@{upstream}..") + +(defun magit-insert-unpushed-to-upstream-or-recent () + "Insert section showing unpushed or other recent commits. +If an upstream is configured for the current branch and it is +behind of the current branch, then show the commits that have +not yet been pushed into the upstream branch. If no upstream is +configured or if the upstream is not behind of the current branch, +then show the last `magit-log-section-commit-count' commits." + (let ((upstream (magit-get-upstream-branch))) + (if (or (not upstream) + (magit-rev-ancestor-p "HEAD" upstream)) + (magit-insert-recent-commits 'unpushed "@{upstream}..") + (magit-insert-unpushed-to-upstream)))) + +(defun magit-insert-unpushed-to-upstream () + "Insert commits that haven't been pushed to the upstream yet." + (when (magit-git-success "rev-parse" "@{upstream}") + (magit-insert-section (unpushed "@{upstream}..") + (magit-insert-heading + (format (propertize "Unmerged into %s." + 'font-lock-face 'magit-section-heading) + (magit-get-upstream-branch))) + (magit-insert-log "@{upstream}.." magit-buffer-log-args) + (magit-log-insert-child-count)))) + +(defun magit-insert-recent-commits (&optional type value) + "Insert section showing recent commits. +Show the last `magit-log-section-commit-count' commits." + (let* ((start (format "HEAD~%s" magit-log-section-commit-count)) + (range (and (magit-rev-verify start) + (concat start "..HEAD")))) + (magit-insert-section ((eval (or type 'recent)) + (or value range) + t) + (magit-insert-heading "Recent commits") + (magit-insert-log range + (cons (format "-n%d" magit-log-section-commit-count) + (--remove (string-prefix-p "-n" it) + magit-buffer-log-args)))))) + +(magit-define-section-jumper magit-jump-to-unpushed-to-pushremote + "Unpushed to " unpushed + (concat (magit-get-push-branch) "..")) + +(defun magit-insert-unpushed-to-pushremote () + "Insert commits that haven't been pushed to the push-remote yet." + (--when-let (magit-get-push-branch) + (when (magit--insert-pushremote-log-p) + (magit-insert-section (unpushed (concat it "..") t) + (magit-insert-heading + (format (propertize "Unpushed to %s." + 'font-lock-face 'magit-section-heading) + (propertize it 'font-lock-face 'magit-branch-remote))) + (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)))) + (when (> count 0) + (when (= count (magit-log-get-commit-limit)) + (setq count (format "%s+" count))) + (save-excursion + (goto-char (- (oref magit-insert-section--current content) 2)) + (insert (format " (%s)" count)) + (delete-char 1)))))) + +;;;; Auxiliary Log Sections + +(defun magit-insert-unpulled-cherries () + "Insert section showing unpulled commits. +Like `magit-insert-unpulled-from-upstream' but prefix each commit +which has not been applied yet (i.e. a commit with a patch-id +not shared with any local commit) with \"+\", and all others with +\"-\"." + (when (magit-git-success "rev-parse" "@{upstream}") + (magit-insert-section (unpulled "..@{upstream}") + (magit-insert-heading "Unpulled commits:") + (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry) + "cherry" "-v" (magit-abbrev-arg) + (magit-get-current-branch) "@{upstream}")))) + +(defun magit-insert-unpushed-cherries () + "Insert section showing unpushed commits. +Like `magit-insert-unpushed-to-upstream' but prefix each commit +which has not been applied to upstream yet (i.e. a commit with +a patch-id not shared with any upstream commit) with \"+\", and +all others with \"-\"." + (when (magit-git-success "rev-parse" "@{upstream}") + (magit-insert-section (unpushed "@{upstream}..") + (magit-insert-heading "Unpushed commits:") + (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry) + "cherry" "-v" (magit-abbrev-arg) "@{upstream}")))) + +;;; _ +(provide 'magit-log) +;;; magit-log.el ends here diff --git a/elpa/magit-20220116.1908/magit-margin.el b/elpa/magit-20220116.1908/magit-margin.el new file mode 100644 index 00000000..4cd8074f --- /dev/null +++ b/elpa/magit-20220116.1908/magit-margin.el @@ -0,0 +1,238 @@ +;;; magit-margin.el --- margins in Magit buffers -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements support for showing additional information +;; in the margins of Magit buffers. Currently this is only used for +;; commits, for which the committer date or age, and optionally the +;; author name are shown. + +;;; Code: + +(require 'magit-section) +(require 'magit-transient) +(require 'magit-mode) + +(defgroup magit-margin nil + "Information Magit displays in the margin. + +You can change the STYLE and AUTHOR-WIDTH of all `magit-*-margin' +options to the same values by customizing `magit-log-margin' +*before* `magit' is loaded. If you do that, then the respective +values for the other options will default to what you have set +for that variable. Likewise if you set `magit-log-margin's INIT +to nil, then that is used in the default of all other options. But +setting it to t, i.e. re-enforcing the default for that option, +does not carry to other options." + :link '(info-link "(magit)Log Margin") + :group 'magit-log) + +(defvar-local magit-buffer-margin nil) +(put 'magit-buffer-margin 'permanent-local t) + +(defvar-local magit-set-buffer-margin-refresh nil) + +(defvar magit--age-spec) + +;;; Commands + +(transient-define-prefix magit-margin-settings () + "Change what information is displayed in the margin." + :info-manual "(magit) Log Margin" + ["Margin" + ("L" "Toggle visibility" magit-toggle-margin) + ("l" "Cycle style" magit-cycle-margin-style) + ("d" "Toggle details" magit-toggle-margin-details) + ("v" "Change verbosity" magit-refs-set-show-commit-count + :if-derived magit-refs-mode)]) + +(defun magit-toggle-margin () + "Show or hide the Magit margin." + (interactive) + (unless (magit-margin-option) + (user-error "Magit margin isn't supported in this buffer")) + (setcar magit-buffer-margin (not (magit-buffer-margin-p))) + (magit-set-buffer-margin)) + +(defun magit-cycle-margin-style () + "Cycle style used for the Magit margin." + (interactive) + (unless (magit-margin-option) + (user-error "Magit margin isn't supported in this buffer")) + ;; This is only suitable for commit margins (there are not others). + (setf (cadr magit-buffer-margin) + (pcase (cadr magit-buffer-margin) + (`age 'age-abbreviated) + (`age-abbreviated + (let ((default (cadr (symbol-value (magit-margin-option))))) + (if (stringp default) default "%Y-%m-%d %H:%M "))) + (_ 'age))) + (magit-set-buffer-margin nil t)) + +(defun magit-toggle-margin-details () + "Show or hide details in the Magit margin." + (interactive) + (unless (magit-margin-option) + (user-error "Magit margin isn't supported in this buffer")) + (setf (nth 3 magit-buffer-margin) + (not (nth 3 magit-buffer-margin))) + (magit-set-buffer-margin nil t)) + +;;; Core + +(defun magit-buffer-margin-p () + (car magit-buffer-margin)) + +(defun magit-margin-option () + (pcase major-mode + (`magit-cherry-mode 'magit-cherry-margin) + (`magit-log-mode 'magit-log-margin) + (`magit-log-select-mode 'magit-log-select-margin) + (`magit-reflog-mode 'magit-reflog-margin) + (`magit-refs-mode 'magit-refs-margin) + (`magit-stashes-mode 'magit-stashes-margin) + (`magit-status-mode 'magit-status-margin) + (`forge-notifications-mode 'magit-status-margin))) + +(defun magit-set-buffer-margin (&optional reset refresh) + (when-let ((option (magit-margin-option))) + (let* ((default (symbol-value option)) + (default-width (nth 2 default))) + (when (or reset (not magit-buffer-margin)) + (setq magit-buffer-margin (copy-sequence default))) + (pcase-let ((`(,enable ,style ,_width ,details ,details-width) + magit-buffer-margin)) + (when (functionp default-width) + (setf (nth 2 magit-buffer-margin) + (funcall default-width style details details-width))) + (dolist (window (get-buffer-window-list nil nil 0)) + (with-selected-window window + (magit-set-window-margin window) + (if enable + (add-hook 'window-configuration-change-hook + 'magit-set-window-margin nil t) + (remove-hook 'window-configuration-change-hook + 'magit-set-window-margin t)))) + (when (and enable (or refresh magit-set-buffer-margin-refresh)) + (magit-refresh-buffer)))))) + +(defun magit-set-window-margin (&optional window) + (when (or window (setq window (get-buffer-window))) + (with-selected-window window + (set-window-margins + nil (car (window-margins)) + (and (magit-buffer-margin-p) + (nth 2 magit-buffer-margin)))))) + +(defun magit-make-margin-overlay (&optional string previous-line) + (if previous-line + (save-excursion + (forward-line -1) + (magit-make-margin-overlay string)) + ;; Don't put the overlay on the complete line to work around #1880. + (let ((o (make-overlay (1+ (line-beginning-position)) + (line-end-position) + nil t))) + (overlay-put o 'evaporate t) + (overlay-put o 'before-string + (propertize "o" 'display + (list (list 'margin 'right-margin) + (or string " "))))))) + +(defun magit-maybe-make-margin-overlay () + (when (or (magit-section-match + '(unpulled unpushed recent stashes local cherries) + magit-insert-section--current) + (and (eq major-mode 'magit-refs-mode) + (magit-section-match + '(remote commit tags) + magit-insert-section--current))) + (magit-make-margin-overlay nil t))) + +;;; Custom Support + +(defun magit-margin-set-variable (mode symbol value) + (set-default symbol value) + (message "Updating margins in %s buffers..." mode) + (dolist (buffer (buffer-list)) + (with-current-buffer buffer + (when (eq major-mode mode) + (magit-set-buffer-margin t) + (magit-refresh)))) + (message "Updating margins in %s buffers...done" mode)) + +(defconst magit-log-margin--custom-type + '(list (boolean :tag "Show margin initially") + (choice :tag "Show committer" + (string :tag "date using time-format" "%Y-%m-%d %H:%M ") + (const :tag "date's age" age) + (const :tag "date's age (abbreviated)" age-abbreviated)) + (const :tag "Calculate width using magit-log-margin-width" + magit-log-margin-width) + (boolean :tag "Show author name by default") + (integer :tag "Show author name using width"))) + +;;; Time Utilities + +(defvar magit--age-spec + `((?Y "year" "years" ,(round (* 60 60 24 365.2425))) + (?M "month" "months" ,(round (* 60 60 24 30.436875))) + (?w "week" "weeks" ,(* 60 60 24 7)) + (?d "day" "days" ,(* 60 60 24)) + (?h "hour" "hours" ,(* 60 60)) + (?m "minute" "minutes" 60) + (?s "second" "seconds" 1)) + "Time units used when formatting relative commit ages. + +The value is a list of time units, beginning with the longest. +Each element has the form (CHAR UNIT UNITS SECONDS). UNIT is the +time unit, UNITS is the plural of that unit. CHAR is a character +abbreviation. And SECONDS is the number of seconds in one UNIT. + +This is defined as a variable to make it possible to use time +units for a language other than English. It is not defined +as an option, because most other parts of Magit are always in +English.") + +(defun magit--age (date &optional abbreviate) + (cl-labels ((fn (age spec) + (pcase-let ((`(,char ,unit ,units ,weight) (car spec))) + (let ((cnt (round (/ age weight 1.0)))) + (if (or (not (cdr spec)) + (>= (/ age weight) 1)) + (list cnt (cond (abbreviate char) + ((= cnt 1) unit) + (t units))) + (fn age (cdr spec))))))) + (fn (abs (- (float-time) + (if (stringp date) + (string-to-number date) + date))) + magit--age-spec))) + +;;; _ +(provide 'magit-margin) +;;; magit-margin.el ends here diff --git a/elpa/magit-20220116.1908/magit-merge.el b/elpa/magit-20220116.1908/magit-merge.el new file mode 100644 index 00000000..470cac96 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-merge.el @@ -0,0 +1,319 @@ +;;; magit-merge.el --- merge functionality -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements merge commands. + +;;; Code: + +(require 'magit) +(require 'magit-diff) + +(declare-function magit-git-push "magit-push" (branch target args)) + +;;; Commands + +;;;###autoload (autoload 'magit-merge "magit" nil t) +(transient-define-prefix magit-merge () + "Merge branches." + :man-page "git-merge" + :incompatible '(("--ff-only" "--no-ff")) + ["Arguments" + :if-not magit-merge-in-progress-p + ("-f" "Fast-forward only" "--ff-only") + ("-n" "No fast-forward" "--no-ff") + (magit-merge:--strategy) + (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 + [("m" "Merge" magit-merge-plain) + ("e" "Merge and edit message" magit-merge-editmsg) + ("n" "Merge but don't commit" magit-merge-nocommit) + ("a" "Absorb" magit-merge-absorb)] + [("p" "Preview merge" magit-merge-preview) + "" + ("s" "Squash merge" magit-merge-squash) + ("i" "Dissolve" magit-merge-into)]] + ["Actions" + :if magit-merge-in-progress-p + ("m" "Commit merge" magit-commit-create) + ("a" "Abort merge" magit-merge-abort)]) + +(defun magit-merge-arguments () + (transient-args 'magit-merge)) + +(transient-define-argument magit-merge:--strategy () + :description "Strategy" + :class 'transient-option + ;; key for merge and rebase: "-s" + ;; key for cherry-pick and revert: "=s" + ;; shortarg for merge and rebase: "-s" + ;; shortarg for cherry-pick and revert: none + :key "-s" + :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. + +Unless there are conflicts or a prefix argument is used create a +merge commit using a generic commit message and without letting +the user inspect the result. With a prefix argument pretend the +merge failed to give the user the opportunity to inspect the +merge. + +\(git merge --no-edit|--no-commit [ARGS] REV)" + (interactive (list (magit-read-other-branch-or-commit "Merge") + (magit-merge-arguments) + current-prefix-arg)) + (magit-merge-assert) + (magit-run-git-async "merge" (if nocommit "--no-commit" "--no-edit") args rev)) + +;;;###autoload +(defun magit-merge-editmsg (rev &optional args) + "Merge commit REV into the current branch; and edit message. +Perform the merge and prepare a commit message but let the user +edit it. +\n(git merge --edit --no-ff [ARGS] REV)" + (interactive (list (magit-read-other-branch-or-commit "Merge") + (magit-merge-arguments))) + (magit-merge-assert) + (cl-pushnew "--no-ff" args :test #'equal) + (apply #'magit-run-git-with-editor "merge" "--edit" + (append (delete "--ff-only" args) + (list rev)))) + +;;;###autoload +(defun magit-merge-nocommit (rev &optional args) + "Merge commit REV into the current branch; pretending it failed. +Pretend the merge failed to give the user the opportunity to +inspect the merge and change the commit message. +\n(git merge --no-commit --no-ff [ARGS] REV)" + (interactive (list (magit-read-other-branch-or-commit "Merge") + (magit-merge-arguments))) + (magit-merge-assert) + (cl-pushnew "--no-ff" args :test #'equal) + (magit-run-git-async "merge" "--no-commit" args rev)) + +;;;###autoload +(defun magit-merge-into (branch &optional args) + "Merge the current branch into BRANCH and remove the former. + +Before merging, force push the source branch to its push-remote, +provided the respective remote branch already exists, ensuring +that the respective pull-request (if any) won't get stuck on some +obsolete version of the commits that are being merged. Finally +if `forge-branch-pullreq' was used to create the merged branch, +then also remove the respective remote branch." + (interactive + (list (magit-read-other-local-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)) + (head (magit-rev-parse "HEAD"))) + (when (zerop (magit-call-git "checkout" branch)) + (if current + (magit--merge-absorb current args) + (magit-run-git-with-editor "merge" args head))))) + +;;;###autoload +(defun magit-merge-absorb (branch &optional args) + "Merge BRANCH into the current branch and remove the former. + +Before merging, force push the source branch to its push-remote, +provided the respective remote branch already exists, ensuring +that the respective pull-request (if any) won't get stuck on some +obsolete version of the commits that are being merged. Finally +if `forge-branch-pullreq' was used to create the merged branch, +then also remove the respective remote branch." + (interactive (list (magit-read-other-local-branch "Absorb branch") + (magit-merge-arguments))) + (magit--merge-absorb branch args)) + +(defun magit--merge-absorb (branch args) + (when (equal branch (magit-main-branch)) + (unless (yes-or-no-p + (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 + (magit-git-push branch target (list "--force-with-lease")) + (set-process-sentinel + magit-this-process + (lambda (process event) + (when (memq (process-status process) '(exit signal)) + (if (not (zerop (process-exit-status process))) + (magit-process-sentinel process event) + (process-put process 'inhibit-refresh t) + (magit-process-sentinel process event) + (magit--merge-absorb-1 branch args)))))) + (magit--merge-absorb-1 branch args))) + +(defun magit--merge-absorb-1 (branch args) + (if-let ((pr (magit-get "branch" branch "pullRequest"))) + (magit-run-git-async + "merge" args "-m" + (format "Merge branch '%s'%s [#%s]" + branch + (let ((current (magit-get-current-branch))) + (if (equal current (magit-main-branch)) + "" + (format " into %s" current))) + pr) + branch) + (magit-run-git-async "merge" args "--no-edit" branch)) + (set-process-sentinel + magit-this-process + (lambda (process event) + (when (memq (process-status process) '(exit signal)) + (if (> (process-exit-status process) 0) + (magit-process-sentinel process event) + (process-put process 'inhibit-refresh t) + (magit-process-sentinel process event) + (magit-branch-maybe-delete-pr-remote branch) + (magit-branch-unset-pushRemote branch) + (magit-run-git "branch" "-D" branch)))))) + +;;;###autoload +(defun magit-merge-squash (rev) + "Squash commit REV into the current branch; don't create a commit. +\n(git merge --squash REV)" + (interactive (list (magit-read-other-branch-or-commit "Squash"))) + (magit-merge-assert) + (magit-run-git-async "merge" "--squash" rev)) + +;;;###autoload +(defun magit-merge-preview (rev) + "Preview result of merging REV into the current branch." + (interactive (list (magit-read-other-branch-or-commit "Preview merge"))) + (magit-merge-preview-setup-buffer rev)) + +;;;###autoload +(defun magit-merge-abort () + "Abort the current merge operation. +\n(git merge --abort)" + (interactive) + (unless (file-exists-p (magit-git-dir "MERGE_HEAD")) + (user-error "No merge in progress")) + (magit-confirm 'abort-merge) + (magit-run-git-async "merge" "--abort")) + +(defun magit-checkout-stage (file arg) + "During a conflict checkout and stage side, or restore conflict." + (interactive + (let ((file (magit-completing-read "Checkout file" + (magit-tracked-files) nil nil nil + 'magit-read-file-hist + (magit-current-file)))) + (cond ((member file (magit-unmerged-files)) + (list file (magit-checkout-read-stage file))) + ((yes-or-no-p (format "Restore conflicts in %s? " file)) + (list file "--merge")) + (t + (user-error "Quit"))))) + (pcase (cons arg (cddr (car (magit-file-status file)))) + ((or `("--ours" ?D ,_) + `("--theirs" ,_ ?D)) + (magit-run-git "rm" "--" file)) + (_ (if (equal arg "--merge") + ;; This fails if the file was deleted on one + ;; side. And we cannot do anything about it. + (magit-run-git "checkout" "--merge" "--" file) + (magit-call-git "checkout" arg "--" file) + (magit-run-git "add" "-u" "--" file))))) + +;;; Utilities + +(defun magit-merge-in-progress-p () + (file-exists-p (magit-git-dir "MERGE_HEAD"))) + +(defun magit--merge-range (&optional head) + (unless head + (setq head (magit-get-shortname + (car (magit-file-lines (magit-git-dir "MERGE_HEAD")))))) + (and head + (concat (magit-git-string "merge-base" "--octopus" "HEAD" head) + ".." head))) + +(defun magit-merge-assert () + (or (not (magit-anything-modified-p t)) + (magit-confirm 'merge-dirty + "Merging with dirty worktree is risky. Continue"))) + +(defun magit-checkout-read-stage (file) + (magit-read-char-case (format "For %s checkout: " file) t + (?o "[o]ur stage" "--ours") + (?t "[t]heir stage" "--theirs") + (?c "[c]onflict" "--merge"))) + +;;; Sections + +(defvar magit-unmerged-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] 'magit-diff-dwim) + map) + "Keymap for `unmerged' sections.") + +(defun magit-insert-merge-log () + "Insert section for the on-going merge. +Display the heads that are being merged. +If no merge is in progress, do nothing." + (when (magit-merge-in-progress-p) + (let* ((heads (mapcar #'magit-get-shortname + (magit-file-lines (magit-git-dir "MERGE_HEAD")))) + (range (magit--merge-range (car heads)))) + (magit-insert-section (unmerged range) + (magit-insert-heading + (format "Merging %s:" (mapconcat #'identity heads ", "))) + (magit-insert-log + range + (let ((args magit-buffer-log-args)) + (unless (member "--decorate=full" magit-buffer-log-args) + (push "--decorate=full" args)) + args)))))) + +;;; _ +(provide 'magit-merge) +;;; magit-merge.el ends here diff --git a/elpa/magit-20220116.1908/magit-mode.el b/elpa/magit-20220116.1908/magit-mode.el new file mode 100644 index 00000000..f32bf0d7 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-mode.el @@ -0,0 +1,1462 @@ +;;; magit-mode.el --- create and refresh Magit buffers -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements the abstract major-mode `magit-mode' from +;; which almost all other Magit major-modes derive. The code in here +;; is mostly concerned with creating and refreshing Magit buffers. + +;;; Code: + +(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' +(defvar magit-post-commit-hook-commands) +(defvar magit-post-stage-hook-commands) +(defvar magit-post-unstage-hook-commands) +;; For `magit-refresh' and `magit-refresh-all' +(declare-function magit-auto-revert-buffers "magit-autorevert" ()) +;; For `magit-refresh-buffer' +(declare-function magit-process-unset-mode-line-error-status "magit-process" ()) +;; For `magit-refresh-get-relative-position' +(declare-function magit-hunk-section-p "magit-diff" (section) t) +;; For `magit-mode-setup-internal' +(declare-function magit-status-goto-initial-section "magit-status" ()) +;; For `magit-mode' from `bookmark' +(defvar bookmark-make-record-function) + +;;; Options + +(defcustom magit-mode-hook + '(magit-load-config-extensions) + "Hook run when entering a mode derived from Magit mode." + :package-version '(magit . "3.0.0") + :group 'magit-modes + :type 'hook + :options '(magit-load-config-extensions + bug-reference-mode)) + +(defcustom magit-setup-buffer-hook + '(magit-maybe-save-repository-buffers + magit-set-buffer-margin) + "Hook run by `magit-setup-buffer'. + +This is run right after displaying the buffer and right before +generating or updating its content. `magit-mode-hook' and other, +more specific, `magit-mode-*-hook's on the other hand are run +right before displaying the buffer. Usually one of these hooks +should be used instead of this one." + :package-version '(magit . "2.3.0") + :group 'magit-modes + :type 'hook + :options '(magit-maybe-save-repository-buffers + magit-set-buffer-margin)) + +(defcustom magit-pre-refresh-hook '(magit-maybe-save-repository-buffers) + "Hook run before refreshing in `magit-refresh'. + +This hook, or `magit-post-refresh-hook', should be used +for functions that are not tied to a particular buffer. + +To run a function with a particular buffer current, use +`magit-refresh-buffer-hook' and use `derived-mode-p' +inside your function." + :package-version '(magit . "2.4.0") + :group 'magit-refresh + :type 'hook + :options '(magit-maybe-save-repository-buffers)) + +(defcustom magit-post-refresh-hook nil + "Hook run after refreshing in `magit-refresh'. + +This hook, or `magit-pre-refresh-hook', should be used +for functions that are not tied to a particular buffer. + +To run a function with a particular buffer current, use +`magit-refresh-buffer-hook' and use `derived-mode-p' +inside your function." + :package-version '(magit . "2.4.0") + :group 'magit-refresh + :type 'hook) + +(defcustom magit-display-buffer-function 'magit-display-buffer-traditional + "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', +which in turn uses the function specified here." + :package-version '(magit . "2.3.0") + :group 'magit-buffers + :type '(radio (function-item magit-display-buffer-traditional) + (function-item magit-display-buffer-same-window-except-diff-v1) + (function-item magit-display-buffer-fullframe-status-v1) + (function-item magit-display-buffer-fullframe-status-topleft-v1) + (function-item magit-display-buffer-fullcolumn-most-v1) + (function-item display-buffer) + (function :tag "Function"))) + +(defcustom magit-pre-display-buffer-hook '(magit-save-window-configuration) + "Hook run by `magit-display-buffer' before displaying the buffer." + :package-version '(magit . "2.3.0") + :group 'magit-buffers + :type 'hook + :get 'magit-hook-custom-get + :options '(magit-save-window-configuration)) + +(defcustom magit-post-display-buffer-hook '(magit-maybe-set-dedicated) + "Hook run by `magit-display-buffer' after displaying the buffer." + :package-version '(magit . "2.3.0") + :group 'magit-buffers + :type 'hook + :get 'magit-hook-custom-get + :options '(magit-maybe-set-dedicated)) + +(defcustom magit-generate-buffer-name-function + 'magit-generate-buffer-name-default-function + "The function used to generate the name for a Magit buffer." + :package-version '(magit . "2.3.0") + :group 'magit-buffers + :type '(radio (function-item magit-generate-buffer-name-default-function) + (function :tag "Function"))) + +(defcustom magit-buffer-name-format "%x%M%v: %t%x" + "The format string used to name Magit buffers. + +The following %-sequences are supported: + +`%m' The name of the major-mode, but with the `-mode' suffix + removed. + +`%M' Like \"%m\" but abbreviate `magit-status-mode' as `magit'. + +`%v' The value the buffer is locked to, in parentheses, or an + empty string if the buffer is not locked to a value. + +`%V' Like \"%v\", but the string is prefixed with a space, unless + it is an empty string. + +`%t' The top-level directory of the working tree of the + repository, or if `magit-uniquify-buffer-names' is non-nil + an abbreviation of that. + +`%x' If `magit-uniquify-buffer-names' is nil \"*\", otherwise the + empty string. Due to limitations of the `uniquify' package, + buffer names must end with the path. + +`%T' Obsolete, use \"%t%x\" instead. Like \"%t\", but append an + asterisk if and only if `magit-uniquify-buffer-names' is nil. + +The value should always contain \"%m\" or \"%M\", \"%v\" or +\"%V\", and \"%t\" (or the obsolete \"%T\"). + +If `magit-uniquify-buffer-names' is non-nil, then the value must +end with \"%t\" or \"%t%x\" (or the obsolete \"%T\"). See issue +#2841. + +This is used by `magit-generate-buffer-name-default-function'. +If another `magit-generate-buffer-name-function' is used, then +it may not respect this option, or on the contrary it may +support additional %-sequences." + :package-version '(magit . "2.12.0") + :group 'magit-buffers + :type 'string) + +(defcustom magit-uniquify-buffer-names t + "Whether to uniquify the names of Magit buffers." + :package-version '(magit . "2.3.0") + :group 'magit-buffers + :type 'boolean) + +(defcustom magit-bury-buffer-function 'magit-mode-quit-window + "The function used to bury or kill the current Magit buffer." + :package-version '(magit . "3.2.0") + :group 'magit-buffers + :type '(radio (function-item quit-window) + (function-item magit-mode-quit-window) + (function-item magit-restore-window-configuration) + (function :tag "Function"))) + +(defcustom magit-prefix-use-buffer-arguments 'selected + "Whether certain prefix commands reuse arguments active in relevant buffer. + +This affects the transient prefix commands `magit-diff', +`magit-log' and `magit-show-refs'. + +Valid values are: + +`always': Always use the set of arguments that is currently + active in the respective buffer, provided that buffer exists + of course. +`selected': Use the set of arguments from the respective + 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 respective buffer, + but only if it is the current buffer. +`never': Never use the set of arguments from the respective + buffer. + +For more information see info node `(magit)Transient 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) + (const :tag "use args from buffer if it is current" current) + (const :tag "never use args from buffer" never))) + +(defcustom magit-direct-use-buffer-arguments 'selected + "Whether certain commands reuse arguments active in relevant buffer. + +This affects certain commands such as `magit-show-commit' that +are suffixes of the diff or log transient prefix commands, but +only if they are invoked directly, i.e. *not* as a suffix. + +Valid values are: + +`always': Always use the set of arguments that is currently + active in the respective buffer, provided that buffer exists + of course. +`selected': Use the set of arguments from the respective + 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 respective buffer, + but only if it is the current buffer. +`never': Never use the set of arguments from the respective + buffer. + +For more information see info node `(magit)Transient 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) + (const :tag "use args from buffer if it is current" current) + (const :tag "never use args from buffer" never))) + +(defcustom magit-region-highlight-hook '(magit-diff-update-hunk-region) + "Functions used to highlight the region. + +Each function is run with the current section as only argument +until one of them returns non-nil. If all functions return nil, +then fall back to regular region highlighting." + :package-version '(magit . "2.1.0") + :group 'magit-refresh + :type 'hook + :options '(magit-diff-update-hunk-region)) + +(defcustom magit-create-buffer-hook nil + "Normal hook run after creating a new `magit-mode' buffer." + :package-version '(magit . "2.90.0") + :group 'magit-refresh + :type 'hook) + +(defcustom magit-refresh-buffer-hook nil + "Normal hook for `magit-refresh-buffer' to run after refreshing." + :package-version '(magit . "2.1.0") + :group 'magit-refresh + :type 'hook) + +(defcustom magit-refresh-status-buffer t + "Whether the status buffer is refreshed after running git. + +When this is non-nil, then the status buffer is automatically +refreshed after running git for side-effects, in addition to the +current Magit buffer, which is always refreshed automatically. + +Only set this to nil after exhausting all other options to +improve performance." + :package-version '(magit . "2.4.0") + :group 'magit-refresh + :group 'magit-status + :type 'boolean) + +(defcustom magit-refresh-verbose nil + "Whether to revert Magit buffers verbosely." + :package-version '(magit . "2.1.0") + :group 'magit-refresh + :type 'boolean) + +(defcustom magit-save-repository-buffers t + "Whether to save file-visiting buffers when appropriate. + +If non-nil, then all modified file-visiting buffers belonging +to the current repository may be saved before running Magit +commands and before creating or refreshing Magit buffers. +If `dontask', then this is done without user intervention, for +any other non-nil value the user has to confirm each save. + +The default is t to avoid surprises, but `dontask' is the +recommended value." + :group 'magit-essentials + :group 'magit-buffers + :type '(choice (const :tag "Never" nil) + (const :tag "Ask" t) + (const :tag "Save without asking" dontask))) + +;;; Key Bindings + +(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 "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) + (define-key map "B" 'magit-bisect) + (define-key map "c" 'magit-commit) + (define-key map "C" 'magit-clone) + (define-key map "d" 'magit-diff) + (define-key map "D" 'magit-diff-refresh) + (define-key map "e" 'magit-ediff-dwim) + (define-key map "E" 'magit-ediff) + (define-key map "f" 'magit-fetch) + (define-key map "F" 'magit-pull) + (define-key map "g" 'magit-refresh) + (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) + (define-key map "S" 'magit-stage-modified) + (define-key map "t" 'magit-tag) + (define-key map "T" 'magit-notes) + (define-key map "u" 'magit-unstage-file) + (define-key map "U" 'magit-unstage-all) + (define-key map "v" 'magit-revert-no-commit) + (define-key map "V" 'magit-revert) + (define-key map "w" 'magit-am) + (define-key map "W" 'magit-patch) + (define-key map "x" 'magit-reset-quickly) + (define-key map "X" 'magit-reset) + (define-key map "y" 'magit-show-refs) + (define-key map "Y" 'magit-cherry) + (define-key map "z" 'magit-stash) + (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-w") 'magit-copy-section-value) + (define-key map (kbd "M-w") 'magit-copy-buffer-revision) + (define-key map [remap previous-line] 'magit-previous-line) + (define-key map [remap next-line] 'magit-next-line) + (define-key map [remap evil-previous-line] 'evil-previous-visual-line) + (define-key map [remap evil-next-line] 'evil-next-visual-line) + map) + "Parent keymap for all keymaps of modes derived from `magit-mode'.") + +(defun magit-delete-thing () + "This is a placeholder command. +Where applicable, section-specific keymaps bind another command +which deletes the thing at point." + (interactive) + (user-error "There is no thing at point that could be deleted")) + +(defun magit-visit-thing () + "This is a placeholder command. +Where applicable, section-specific keymaps bind another command +which visits the thing at point." + (interactive) + (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"))) + +(defun magit-edit-thing () + "This is a placeholder command. +Where applicable, section-specific keymaps bind another command +which lets you edit the thing at point, likely in another buffer." + (interactive) + (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"))) + +(defun magit-browse-thing () + "This is a placeholder command. +Where applicable, section-specific keymaps bind another command +which visits the thing at point using `browse-url'." + (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] + 'bug-reference-push-button)) + +(easy-menu-define magit-mode-menu magit-mode-map + "Magit menu" + '("Magit" + ["Refresh" magit-refresh t] + ["Refresh all" magit-refresh-all t] + "---" + ["Stage" magit-stage t] + ["Stage modified" magit-stage-modified t] + ["Unstage" magit-unstage t] + ["Reset index" magit-reset-index t] + ["Commit" magit-commit t] + ["Add log entry" magit-commit-add-log t] + ["Tag" magit-tag-create t] + "---" + ["Diff working tree" magit-diff-working-tree t] + ["Diff" magit-diff t] + ("Log" + ["Log" magit-log-other t] + ["Reflog" magit-reflog-other t] + ["Extended..." magit-log t]) + "---" + ["Cherry pick" magit-cherry-pick t] + ["Revert commit" magit-revert 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] + ["Snapshot" magit-snapshot-both t] + "---" + ["Branch..." magit-checkout t] + ["Merge" magit-merge t] + ["Ediff resolve" magit-ediff-resolve t] + ["Rebase..." magit-rebase t] + "---" + ["Push" magit-push t] + ["Pull" magit-pull-branch t] + ["Remote update" magit-fetch-all t] + ("Submodule" + ["Submodule update" magit-submodule-update t] + ["Submodule update and init" magit-submodule-setup t] + ["Submodule init" magit-submodule-init t] + ["Submodule sync" magit-submodule-sync t]) + "---" + ("Extensions") + "---" + ["Display Git output" magit-process-buffer t] + ["Quit Magit" magit-mode-bury-buffer t])) + +;;; Mode + +(defun magit-load-config-extensions () + "Load Magit extensions that are defined at the Git config layer." + (dolist (ext (magit-get-all "magit.extension")) + (let ((sym (intern (format "magit-%s-mode" ext)))) + (when (fboundp sym) + (funcall sym 1))))) + +(define-derived-mode magit-mode magit-section-mode "Magit" + "Parent major mode from which Magit major modes inherit. + +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 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 + +(defvar-local magit-buffer-arguments nil) +(defvar-local magit-buffer-diff-args nil) +(defvar-local magit-buffer-diff-files nil) +(defvar-local magit-buffer-diff-files-suspended nil) +(defvar-local magit-buffer-file-name nil) +(defvar-local magit-buffer-files nil) +(defvar-local magit-buffer-log-args nil) +(defvar-local magit-buffer-log-files nil) +(defvar-local magit-buffer-range nil) +(defvar-local magit-buffer-range-hashed nil) +(defvar-local magit-buffer-refname nil) +(defvar-local magit-buffer-revision nil) +(defvar-local magit-buffer-revision-hash nil) +(defvar-local magit-buffer-revisions nil) +(defvar-local magit-buffer-typearg nil) +(defvar-local magit-buffer-upstream nil) + +;; These variables are also used in file-visiting buffers. +;; Because the user may change the major-mode, they have +;; to be permanent buffer-local. +(put 'magit-buffer-file-name 'permanent-local t) +(put 'magit-buffer-refname 'permanent-local t) +(put 'magit-buffer-revision 'permanent-local t) +(put 'magit-buffer-revision-hash 'permanent-local t) + +;; `magit-status' re-enables mode function but its refresher +;; function does not reinstate this. +(put 'magit-buffer-diff-files-suspended 'permanent-local t) + +(defvar-local magit-refresh-args nil + "Obsolete. Possibly the arguments used to refresh the current buffer. +Some third-party packages might still use this, but Magit does not.") +(put 'magit-refresh-args 'permanent-local t) +(make-obsolete-variable 'magit-refresh-args nil "Magit 3.0.0") + +(defvar magit-buffer-lock-functions nil + "Obsolete buffer-locking support for third-party modes. +Implement the generic function `magit-buffer-value' for +your mode instead of adding an entry to this variable.") +(make-obsolete-variable 'magit-buffer-lock-functions nil "Magit 3.0.0") + +(cl-defgeneric magit-buffer-value () + (when-let ((fn (cdr (assq major-mode magit-buffer-lock-functions)))) + (funcall fn (with-no-warnings magit-refresh-args)))) + +(defvar-local magit-previous-section nil) +(put 'magit-previous-section 'permanent-local t) + +;;; Setup Buffer + +(defmacro magit-setup-buffer (mode &optional locked &rest bindings) + (declare (indent 2)) + `(magit-setup-buffer-internal + ,mode ,locked + ,(cons 'list (mapcar (pcase-lambda (`(,var ,form)) + `(list ',var ,form)) + bindings)))) + +(defun magit-setup-buffer-internal (mode locked bindings) + (let* ((value (and locked + (with-temp-buffer + (pcase-dolist (`(,var ,val) bindings) + (set (make-local-variable var) val)) + (let ((major-mode mode)) + (magit-buffer-value))))) + (buffer (magit-get-mode-buffer mode value)) + (section (and buffer (magit-current-section))) + (created (not buffer))) + (unless buffer + (setq buffer (magit-with-toplevel + (magit-generate-new-buffer mode value)))) + (with-current-buffer buffer + (setq magit-previous-section section) + (funcall mode) + (magit-xref-setup 'magit-setup-buffer-internal bindings) + (pcase-dolist (`(,var ,val) bindings) + (set (make-local-variable var) val)) + (when created + (magit-status-goto-initial-section) + (run-hooks 'magit-create-buffer-hook))) + (magit-display-buffer buffer) + (with-current-buffer buffer + (run-hooks 'magit-setup-buffer-hook) + (magit-refresh-buffer)) + buffer)) + +(defun magit-mode-setup (mode &rest args) + "Setup up a MODE buffer using ARGS to generate its content." + (declare (obsolete magit-setup-buffer "Magit 3.0.0")) + (with-no-warnings + (magit-mode-setup-internal mode args))) + +(defun magit-mode-setup-internal (mode args &optional locked) + "Setup up a MODE buffer using ARGS to generate its content. +When optional LOCKED is non-nil, then create a buffer that is +locked to its value, which is derived from MODE and ARGS." + (declare (obsolete magit-setup-buffer "Magit 3.0.0")) + (let* ((value (and locked + (with-temp-buffer + (with-no-warnings + (setq magit-refresh-args args)) + (let ((major-mode mode)) + (magit-buffer-value))))) + (buffer (magit-get-mode-buffer mode value)) + (section (and buffer (magit-current-section))) + (created (not buffer))) + (unless buffer + (setq buffer (magit-with-toplevel + (magit-generate-new-buffer mode value)))) + (with-current-buffer buffer + (setq magit-previous-section section) + (with-no-warnings + (setq magit-refresh-args args)) + (funcall mode) + (magit-xref-setup 'magit-mode-setup-internal args) + (when created + (magit-status-goto-initial-section) + (run-hooks 'magit-create-buffer-hook))) + (magit-display-buffer buffer) + (with-current-buffer buffer + (run-hooks 'magit-mode-setup-hook) + (magit-refresh-buffer)))) + +;;; Display Buffer + +(defvar magit-display-buffer-noselect nil + "If non-nil, then `magit-display-buffer' doesn't call `select-window'.") + +(defun magit-display-buffer (buffer &optional display-function) + "Display BUFFER in some window and maybe select it. + +If optional DISPLAY-FUNCTION is non-nil, then use that to display +the buffer. Otherwise use `magit-display-buffer-function', which +is the normal case. + +Then, unless `magit-display-buffer-noselect' is non-nil, select +the window which was used to display the buffer. + +Also run the hooks `magit-pre-display-buffer-hook' +and `magit-post-display-buffer-hook'." + (with-current-buffer buffer + (run-hooks 'magit-pre-display-buffer-hook)) + (let ((window (funcall (or display-function magit-display-buffer-function) + buffer))) + (unless magit-display-buffer-noselect + (let* ((old-frame (selected-frame)) + (new-frame (window-frame window))) + (select-window window) + (unless (eq old-frame new-frame) + (select-frame-set-input-focus new-frame))))) + (with-current-buffer buffer + (run-hooks 'magit-post-display-buffer-hook))) + +(defun magit-display-buffer-traditional (buffer) + "Display BUFFER the way this has traditionally been done." + (display-buffer + buffer (if (and (derived-mode-p 'magit-mode) + (not (memq (with-current-buffer buffer major-mode) + '(magit-process-mode + magit-revision-mode + magit-diff-mode + magit-stash-mode + magit-status-mode)))) + '(display-buffer-same-window) + nil))) ; display in another window + +(defun magit-display-buffer-same-window-except-diff-v1 (buffer) + "Display BUFFER in the selected window except for some modes. +If a buffer's `major-mode' derives from `magit-diff-mode' or +`magit-process-mode', display it in another window. Display all +other buffers in the selected window." + (display-buffer + buffer (if (with-current-buffer buffer + (derived-mode-p 'magit-diff-mode 'magit-process-mode)) + '(nil (inhibit-same-window . t)) + '(display-buffer-same-window)))) + +(defun magit--display-buffer-fullframe (buffer alist) + (when-let ((window (or (display-buffer-reuse-window buffer alist) + (display-buffer-same-window buffer alist) + (display-buffer-pop-up-window buffer alist) + (display-buffer-use-some-window buffer alist)))) + (delete-other-windows window) + window)) + +(defun magit-display-buffer-fullframe-status-v1 (buffer) + "Display BUFFER, filling entire frame if BUFFER is a status buffer. +Otherwise, behave like `magit-display-buffer-traditional'." + (if (eq (with-current-buffer buffer major-mode) + 'magit-status-mode) + (display-buffer buffer '(magit--display-buffer-fullframe)) + (magit-display-buffer-traditional buffer))) + +(defun magit--display-buffer-topleft (buffer alist) + (or (display-buffer-reuse-window buffer alist) + (when-let ((window2 (display-buffer-pop-up-window buffer alist))) + (let ((window1 (get-buffer-window)) + (buffer1 (current-buffer)) + (buffer2 (window-buffer window2)) + (w2-quit-restore (window-parameter window2 'quit-restore))) + (set-window-buffer window1 buffer2) + (set-window-buffer window2 buffer1) + (select-window window2) + ;; Swap some window state that `magit-mode-quit-window' and + ;; `quit-restore-window' inspect. + (set-window-prev-buffers window2 (cdr (window-prev-buffers window1))) + (set-window-prev-buffers window1 nil) + (set-window-parameter window2 'magit-dedicated + (window-parameter window1 'magit-dedicated)) + (set-window-parameter window1 'magit-dedicated t) + (set-window-parameter window1 'quit-restore + (list 'window 'window + (nth 2 w2-quit-restore) + (nth 3 w2-quit-restore))) + (set-window-parameter window2 'quit-restore nil) + window1)))) + +(defun magit-display-buffer-fullframe-status-topleft-v1 (buffer) + "Display BUFFER, filling entire frame if BUFFER is a status buffer. +When BUFFER derives from `magit-diff-mode' or +`magit-process-mode', try to display BUFFER to the top or left of +the current buffer rather than to the bottom or right, as +`magit-display-buffer-fullframe-status-v1' would. Whether the +split is made vertically or horizontally is determined by +`split-window-preferred-function'." + (display-buffer + buffer + (cond ((eq (with-current-buffer buffer major-mode) + 'magit-status-mode) + '(magit--display-buffer-fullframe)) + ((with-current-buffer buffer + (derived-mode-p 'magit-diff-mode 'magit-process-mode)) + '(magit--display-buffer-topleft)) + (t + '(display-buffer-same-window))))) + +(defun magit--display-buffer-fullcolumn (buffer alist) + (when-let ((window (or (display-buffer-reuse-window buffer alist) + (display-buffer-same-window buffer alist) + (display-buffer-below-selected buffer alist)))) + (delete-other-windows-vertically window) + window)) + +(defun magit-display-buffer-fullcolumn-most-v1 (buffer) + "Display BUFFER using the full column except in some cases. +For most cases where BUFFER's `major-mode' derives from +`magit-mode', display it in the selected window and grow that +window to the full height of the frame, deleting other windows in +that column as necessary. However, display BUFFER in another +window if 1) BUFFER's mode derives from `magit-process-mode', or +2) BUFFER's mode derives from `magit-diff-mode', provided that +the mode of the current buffer derives from `magit-log-mode' or +`magit-cherry-mode'." + (display-buffer + buffer + (cond ((and (or git-commit-mode + (derived-mode-p 'magit-log-mode + 'magit-cherry-mode + 'magit-reflog-mode)) + (with-current-buffer buffer + (derived-mode-p 'magit-diff-mode))) + nil) + ((with-current-buffer buffer + (derived-mode-p 'magit-process-mode)) + nil) + (t + '(magit--display-buffer-fullcolumn))))) + +(defun magit-maybe-set-dedicated () + "Mark the selected window as dedicated if appropriate. + +If a new window was created to display the buffer, then remember +that fact. That information is used by `magit-mode-quit-window', +to determine whether the window should be deleted when its last +Magit buffer is buried." + (let ((window (get-buffer-window (current-buffer)))) + (when (and (window-live-p window) + (not (window-prev-buffers window))) + (set-window-parameter window 'magit-dedicated t)))) + +;;; Get Buffer + +(defvar-local magit--default-directory nil + "Value of `default-directory' when buffer is generated. +This exists to prevent a let-bound `default-directory' from +tricking `magit-get-mode-buffer' or `magit-mode-get-buffers' +into thinking a buffer belongs to a repo that it doesn't.") +(put 'magit--default-directory 'permanent-local t) + +(defun magit-mode-get-buffers () + (let ((topdir (magit-toplevel))) + (--filter (with-current-buffer it + (and (derived-mode-p 'magit-mode) + (equal magit--default-directory topdir))) + (buffer-list)))) + +(defvar-local magit-buffer-locked-p nil) +(put 'magit-buffer-locked-p 'permanent-local t) + +(defun magit-get-mode-buffer (mode &optional value frame) + "Return buffer belonging to the current repository whose major-mode is MODE. + +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 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 locked to that value. + +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. +If `visible', then only consider buffers on all visible frames. +If `selected' or t, then only consider buffers on the selected + frame. +If a frame, then only consider buffers on that frame." + (if-let ((topdir (magit-toplevel))) + (cl-flet* ((b (buffer) + (with-current-buffer buffer + (and (eq major-mode mode) + (equal magit--default-directory topdir) + (if value + (and magit-buffer-locked-p + (equal (magit-buffer-value) value)) + (not magit-buffer-locked-p)) + buffer))) + (w (window) + (b (window-buffer window))) + (f (frame) + (seq-some #'w (window-list frame 'no-minibuf)))) + (pcase-exhaustive 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) + (declare (obsolete magit-get-mode-buffer "Magit 3.0.0")) + (when create + (error "`magit-mode-get-buffer's CREATE argument is obsolete")) + (if-let ((topdir (magit-toplevel))) + (--first (with-current-buffer it + (and (eq major-mode mode) + (equal magit--default-directory topdir) + (if value + (and magit-buffer-locked-p + (equal (magit-buffer-value) value)) + (not magit-buffer-locked-p)))) + (if frame + (mapcar #'window-buffer + (window-list (unless (eq frame t) frame))) + (buffer-list))) + (magit--not-inside-repository-error))) + +(defun magit-generate-new-buffer (mode &optional value) + (let* ((name (funcall magit-generate-buffer-name-function mode value)) + (buffer (generate-new-buffer name))) + (with-current-buffer buffer + (setq magit--default-directory default-directory) + (setq magit-buffer-locked-p (and value t)) + (magit-restore-section-visibility-cache mode)) + (when magit-uniquify-buffer-names + (add-to-list 'uniquify-list-buffers-directory-modes mode) + (with-current-buffer buffer + (setq list-buffers-directory (abbreviate-file-name default-directory))) + (let ((uniquify-buffer-name-style + (if (memq uniquify-buffer-name-style '(nil forward)) + 'post-forward-angle-brackets + uniquify-buffer-name-style))) + (uniquify-rationalize-file-buffer-names + name (file-name-directory (directory-file-name default-directory)) + buffer))) + buffer)) + +(defun magit-generate-buffer-name-default-function (mode &optional value) + "Generate buffer name for a MODE buffer in the current repository. +The returned name is based on `magit-buffer-name-format' and +takes `magit-uniquify-buffer-names' and VALUE, if non-nil, into +account." + (let ((m (substring (symbol-name mode) 0 -5)) + (v (and value (format "%s" (if (listp value) value (list value))))) + (n (if magit-uniquify-buffer-names + (file-name-nondirectory + (directory-file-name default-directory)) + (abbreviate-file-name default-directory)))) + (format-spec + magit-buffer-name-format + `((?m . ,m) + (?M . ,(if (eq mode 'magit-status-mode) "magit" m)) + (?v . ,(or v "")) + (?V . ,(if v (concat " " v) "")) + (?t . ,n) + (?x . ,(if magit-uniquify-buffer-names "" "*")) + (?T . ,(if magit-uniquify-buffer-names n (concat n "*"))))))) + +;;; Buffer Lock + +(defun magit-toggle-buffer-lock () + "Lock the current buffer to its value or unlock it. + +Locking a buffer to its value prevents it from being reused to +display another value. The name of a locked buffer contains its +value, which allows telling it apart from other locked buffers +and the unlocked buffer. + +Not all Magit buffers can be locked to their values, for example +it wouldn't make sense to lock a status buffer. + +There can only be a single unlocked buffer using a certain +major-mode per repository. So when a buffer is being unlocked +and another unlocked buffer already exists for that mode and +repository, then the former buffer is instead deleted and the +latter is displayed in its place." + (interactive) + (if magit-buffer-locked-p + (if-let ((unlocked (magit-get-mode-buffer major-mode))) + (let ((locked (current-buffer))) + (switch-to-buffer unlocked nil t) + (kill-buffer locked)) + (setq magit-buffer-locked-p nil) + (rename-buffer (funcall magit-generate-buffer-name-function + major-mode))) + (if-let ((value (magit-buffer-value))) + (if-let ((locked (magit-get-mode-buffer major-mode value))) + (let ((unlocked (current-buffer))) + (switch-to-buffer locked nil t) + (kill-buffer unlocked)) + (setq magit-buffer-locked-p t) + (rename-buffer (funcall magit-generate-buffer-name-function + major-mode value))) + (user-error "Buffer has no value it could be locked to")))) + +;;; Bury Buffer + +(defun magit-mode-bury-buffer (&optional kill-buffer) + "Bury the current buffer. +With a prefix argument, kill the buffer instead. +With two prefix arguments, also kill all Magit buffers associated +with this repository. +This is done using `magit-bury-buffer-function'." + (interactive "P") + ;; Kill all associated Magit buffers when a double prefix arg is given. + (when (>= (prefix-numeric-value kill-buffer) 16) + (let ((current (current-buffer))) + (dolist (buf (magit-mode-get-buffers)) + (unless (eq buf current) + (kill-buffer buf))))) + (funcall magit-bury-buffer-function kill-buffer)) + +(defun magit-mode-quit-window (kill-buffer) + "Quit the selected window and bury its buffer. + +This behaves similar to `quit-window', but when the window +was originally created to display a Magit buffer and the +current buffer is the last remaining Magit buffer that was +ever displayed in the selected window, then delete that +window." + (if (or (one-window-p) + (--first (let ((buffer (car it))) + (and (not (eq buffer (current-buffer))) + (buffer-live-p buffer) + (or (not (window-parameter nil 'magit-dedicated)) + (with-current-buffer buffer + (derived-mode-p 'magit-mode + 'magit-process-mode))))) + (window-prev-buffers))) + (quit-window kill-buffer) + (let ((window (selected-window))) + (quit-window kill-buffer) + (when (window-live-p window) + (delete-window window))))) + +;;; Refresh Buffers + +(defvar magit-inhibit-refresh nil) + +(defun magit-refresh () + "Refresh some buffers belonging to the current repository. + +Refresh the current buffer if its major mode derives from +`magit-mode', and refresh the corresponding status buffer. + +Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'." + (interactive) + (unless magit-inhibit-refresh + (unwind-protect + (let ((start (current-time)) + (magit--refresh-cache (or magit--refresh-cache + (list (cons 0 0))))) + (when magit-refresh-verbose + (message "Refreshing magit...")) + (magit-run-hook-with-benchmark 'magit-pre-refresh-hook) + (cond ((derived-mode-p 'magit-mode) + (magit-refresh-buffer)) + ((derived-mode-p 'tabulated-list-mode) + (revert-buffer))) + (--when-let (and magit-refresh-status-buffer + (not (derived-mode-p 'magit-status-mode)) + (magit-get-mode-buffer 'magit-status-mode)) + (with-current-buffer it + (magit-refresh-buffer))) + (magit-auto-revert-buffers) + (cond + ((and (not this-command) + (memq last-command magit-post-commit-hook-commands)) + (magit-run-hook-with-benchmark 'magit-post-commit-hook)) + ((memq this-command magit-post-stage-hook-commands) + (magit-run-hook-with-benchmark 'magit-post-stage-hook)) + ((memq this-command magit-post-unstage-hook-commands) + (magit-run-hook-with-benchmark 'magit-post-unstage-hook))) + (magit-run-hook-with-benchmark 'magit-post-refresh-hook) + (when magit-refresh-verbose + (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 () + "Refresh all buffers belonging to the current repository. + +Refresh all Magit buffers belonging to the current repository, +and revert buffers that visit files located inside the current +repository. + +Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'." + (interactive) + (magit-run-hook-with-benchmark 'magit-pre-refresh-hook) + (dolist (buffer (magit-mode-get-buffers)) + (with-current-buffer buffer (magit-refresh-buffer))) + (magit-auto-revert-buffers) + (magit-run-hook-with-benchmark 'magit-post-refresh-hook)) + +(defvar-local magit-refresh-start-time nil) + +(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" + (substring (symbol-name major-mode) 0 -5)))) + (magit--refresh-cache (or magit--refresh-cache (list (cons 0 0))))) + (when (functionp refresh) + (when magit-refresh-verbose + (message "Refreshing buffer `%s'..." (buffer-name))) + (let* ((buffer (current-buffer)) + (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-sections nil) + (setq magit-section-unhighlight-sections nil) + (magit-process-unset-mode-line-error-status) + (let ((inhibit-read-only t)) + (erase-buffer) + (save-excursion + (apply refresh (with-no-warnings magit-refresh-args)))) + (pcase-dolist (`(,window . ,args) windows) + (if (eq buffer (window-buffer window)) + (with-selected-window window + (apply #'magit-section-goto-successor args)) + (with-current-buffer buffer + (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)) + (when magit-refresh-verbose + (message "Refreshing buffer `%s'...done (%.3fs)" (buffer-name) + (float-time (time-subtract (current-time) + magit-refresh-start-time))))))) + +(defun magit-refresh-get-relative-position () + (when-let ((section (magit-current-section))) + (let ((start (oref section start))) + (list (- (line-number-at-pos (point)) + (line-number-at-pos start)) + (- (point) (line-beginning-position)) + (and (magit-hunk-section-p section) + (region-active-p) + (progn (goto-char (line-beginning-position)) + (when (looking-at "^[-+]") (forward-line)) + (while (looking-at "^[ @]") (forward-line)) + (let ((beg (point))) + (cond ((looking-at "^[-+]") + (forward-line) + (while (looking-at "^[-+]") (forward-line)) + (while (looking-at "^ ") (forward-line)) + (forward-line -1) + (regexp-quote (buffer-substring-no-properties + beg (line-end-position)))) + (t t))))))))) + +;;; Save File-Visiting Buffers + +(defvar disable-magit-save-buffers nil) + +(defun magit-pre-command-hook () + (setq disable-magit-save-buffers nil)) +(add-hook 'pre-command-hook #'magit-pre-command-hook) + +(defvar magit-after-save-refresh-buffers nil) + +(defun magit-after-save-refresh-buffers () + (dolist (buffer magit-after-save-refresh-buffers) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (magit-refresh-buffer)))) + (setq magit-after-save-refresh-buffers nil) + (remove-hook 'post-command-hook 'magit-after-save-refresh-buffers)) + +(defun magit-after-save-refresh-status () + "Refresh the status buffer of the current repository. + +This function is intended to be added to `after-save-hook'. + +If the status buffer does not exist or the file being visited in +the current buffer isn't inside the working tree of a repository, +then do nothing. + +Note that refreshing a Magit buffer is done by re-creating its +contents from scratch, which can be slow in large repositories. +If you are not satisfied with Magit's performance, then you +should obviously not add this function to that hook." + (when (and (not disable-magit-save-buffers) + (magit-inside-worktree-p t)) + (--when-let (ignore-errors (magit-get-mode-buffer 'magit-status-mode)) + (add-to-list 'magit-after-save-refresh-buffers it) + (add-hook 'post-command-hook 'magit-after-save-refresh-buffers)))) + +(defun magit-maybe-save-repository-buffers () + "Maybe save file-visiting buffers belonging to the current repository. +Do so if `magit-save-repository-buffers' is non-nil. You should +not remove this from any hooks, instead set that variable to nil +if you so desire." + (when (and magit-save-repository-buffers + (not disable-magit-save-buffers)) + (setq disable-magit-save-buffers t) + (let ((msg (current-message))) + (magit-save-repository-buffers + (eq magit-save-repository-buffers 'dontask)) + (when (and msg + (current-message) + (not (equal msg (current-message)))) + (message "%s" msg))))) + +(add-hook 'magit-pre-refresh-hook #'magit-maybe-save-repository-buffers) +(add-hook 'magit-pre-call-git-hook #'magit-maybe-save-repository-buffers) +(add-hook 'magit-pre-start-git-hook #'magit-maybe-save-repository-buffers) + +(defvar-local magit-inhibit-refresh-save nil) + +(defun magit-save-repository-buffers (&optional arg) + "Save file-visiting buffers belonging to the current repository. +After any buffer where `buffer-save-without-query' is non-nil +is saved without asking, the user is asked about each modified +buffer which visits a file in the current repository. Optional +argument (the prefix) non-nil means save all with no questions." + (interactive "P") + (when-let ((topdir (magit-rev-parse-safe "--show-toplevel"))) + (let ((remote (file-remote-p default-directory)) + (save-some-buffers-action-alist + `((?Y (lambda (buffer) + (with-current-buffer buffer + (setq buffer-save-without-query t) + (save-buffer))) + "to save the current buffer and remember choice") + (?N (lambda (buffer) + (with-current-buffer buffer + (setq magit-inhibit-refresh-save t))) + "to skip the current buffer and remember choice") + ,@save-some-buffers-action-alist))) + (save-some-buffers + arg (lambda () + (and buffer-file-name + ;; - Check whether refreshing is disabled. + (not magit-inhibit-refresh-save) + ;; - Check whether the visited file is either on the + ;; same remote as the repository, or both are on + ;; the local system. + (equal (file-remote-p buffer-file-name) remote) + ;; Delayed checks that are more expensive for remote + ;; repositories, due to the required network access. + ;; - Check whether the file is inside the repository. + (equal (magit-rev-parse-safe "--show-toplevel") topdir) + ;; - Check whether the file is actually writable. + (file-writable-p buffer-file-name))))))) + +;;; Restore Window Configuration + +(defvar magit-inhibit-save-previous-winconf nil) + +(defvar-local magit-previous-window-configuration nil) +(put 'magit-previous-window-configuration 'permanent-local t) + +(defun magit-save-window-configuration () + "Save the current window configuration. + +Later, when the buffer is buried, it may be restored by +`magit-restore-window-configuration'." + (if magit-inhibit-save-previous-winconf + (when (eq magit-inhibit-save-previous-winconf 'unset) + (setq magit-previous-window-configuration nil)) + (unless (get-buffer-window (current-buffer) (selected-frame)) + (setq magit-previous-window-configuration + (current-window-configuration))))) + +(defun magit-restore-window-configuration (&optional kill-buffer) + "Bury or kill the current buffer and restore previous window configuration." + (let ((winconf magit-previous-window-configuration) + (buffer (current-buffer)) + (frame (selected-frame))) + (quit-window kill-buffer (selected-window)) + (when (and winconf (equal frame (window-configuration-frame winconf))) + (set-window-configuration winconf) + (when (buffer-live-p buffer) + (with-current-buffer buffer + (setq magit-previous-window-configuration nil)))))) + +;;; Buffer History + +(defun magit-go-backward () + "Move backward in current buffer's history." + (interactive) + (if help-xref-stack + (help-xref-go-back (current-buffer)) + (user-error "No previous entry in buffer's history"))) + +(defun magit-go-forward () + "Move forward in current buffer's history." + (interactive) + (if help-xref-forward-stack + (help-xref-go-forward (current-buffer)) + (user-error "No next entry in buffer's history"))) + +(defun magit-insert-xref-buttons () + "Insert xref buttons." + (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 + (when help-xref-stack + (insert " ")) + (magit-xref-insert-button help-forward-label 'magit-xref-forward)))) + +(defun magit-xref-insert-button (label type) + (magit-insert-section (button label) + (insert-text-button label 'type type + 'help-args (list (current-buffer))))) + +(define-button-type 'magit-xref-backward + :supertype 'help-back + 'mouse-face 'magit-section-highlight + 'help-echo (purecopy "mouse-2, RET: go back to previous history entry")) + +(define-button-type 'magit-xref-forward + :supertype 'help-forward + 'mouse-face 'magit-section-highlight + 'help-echo (purecopy "mouse-2, RET: go back to next history entry")) + +(defvar magit-xref-modes + '(magit-log-mode + magit-reflog-mode + magit-diff-mode + magit-revision-mode) + "List of modes for which to insert navigation buttons.") + +(defun magit-xref-setup (fn args) + (when (memq major-mode magit-xref-modes) + (when help-xref-stack-item + (push (cons (point) help-xref-stack-item) help-xref-stack) + (setq help-xref-forward-stack nil)) + (when (called-interactively-p 'interactive) + (--when-let (nthcdr 10 help-xref-stack) + (setcdr it nil))) + (setq help-xref-stack-item + (list 'magit-xref-restore fn default-directory args)))) + +(defun magit-xref-restore (fn dir args) + (setq default-directory dir) + (funcall fn major-mode nil args) + (magit-refresh-buffer)) + +;;; Repository-Local Cache + +(defvar magit-repository-local-cache nil + "Alist mapping `magit-toplevel' paths to alists of key/value pairs.") + +(defun magit-repository-local-repository () + "Return the key for the current repository." + (or (bound-and-true-p magit--default-directory) + (magit-toplevel))) + +(defun magit-repository-local-set (key value &optional repository) + "Set the repository-local VALUE for KEY. + +Unless specified, REPOSITORY is the current buffer's repository. + +If REPOSITORY is nil (meaning there is no current repository), +then the value is not cached, and we return nil." + (let* ((repokey (or repository (magit-repository-local-repository))) + (cache (assoc repokey magit-repository-local-cache))) + ;; Don't cache values for a nil REPOSITORY, as the 'set' and 'get' + ;; calls for some KEY may happen in unrelated contexts. + (when repokey + (if cache + (let ((keyvalue (assoc key (cdr cache)))) + (if keyvalue + ;; Update pre-existing value for key. + (setcdr keyvalue value) + ;; No such key in repository-local cache. + (push (cons key value) (cdr cache)))) + ;; No cache for this repository. + (push (cons repokey (list (cons key value))) + magit-repository-local-cache))))) + +(defun magit-repository-local-exists-p (key &optional repository) + "Non-nil when a repository-local value exists for KEY. + +Return a (KEY . VALUE) cons cell. + +The KEY is matched using `equal'. + +Unless specified, REPOSITORY is the current buffer's repository." + (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. + +Return DEFAULT if no value for KEY exists. + +The KEY is matched using `equal'. + +Unless specified, REPOSITORY is the current buffer's repository." + (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." + (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) + (magit-repository-local-set + (cons major-mode 'magit-section-visibility-cache) + magit-section-visibility-cache))) + +(defun magit-restore-section-visibility-cache (mode) + (setq magit-section-visibility-cache + (magit-repository-local-get + (cons mode 'magit-section-visibility-cache)))) + +(defun magit-zap-caches () + "Zap caches for the current repository. +Remove the repository's entry from `magit-repository-local-cache' +and set `magit-section-visibility-cache' to nil in all of the +repository's Magit buffers." + (interactive) + (magit-with-toplevel + (setq magit-repository-local-cache + (cl-delete default-directory + magit-repository-local-cache + :key #'car :test #'equal))) + (dolist (buffer (magit-mode-get-buffers)) + (with-current-buffer buffer + (setq magit-section-visibility-cache nil))) + (setq magit--libgit-available-p 'unknown)) + +;;; Utilities + +(defun magit-toggle-verbose-refresh () + "Toggle whether Magit refreshes buffers verbosely. +Enabling this helps figuring out which sections are bottlenecks. +The additional output can be found in the *Messages* buffer." + (interactive) + (setq magit-refresh-verbose (not magit-refresh-verbose)) + (message "%s verbose refreshing" + (if magit-refresh-verbose "Enabled" "Disabled"))) + +(defun magit-run-hook-with-benchmark (hook) + (when hook + (if magit-refresh-verbose + (let ((start (current-time))) + (message "Running %s..." hook) + (run-hooks hook) + (message "Running %s...done (%.3fs)" hook + (float-time (time-subtract (current-time) start)))) + (run-hooks hook)))) + +;;; _ +(provide 'magit-mode) +;;; magit-mode.el ends here diff --git a/elpa/magit-20220116.1908/magit-notes.el b/elpa/magit-20220116.1908/magit-notes.el new file mode 100644 index 00000000..30bbc5f9 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-notes.el @@ -0,0 +1,202 @@ +;;; magit-notes.el --- notes support -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements support for `git-notes'. + +;;; Code: + +(require 'magit) + +;;; Commands + +;;;###autoload (autoload 'magit-notes "magit" nil t) +(transient-define-prefix magit-notes () + "Edit notes attached to commits." + :man-page "git-notes" + ["Configure local settings" + ("c" magit-core.notesRef) + ("d" magit-notes.displayRef)] + ["Configure global settings" + ("C" magit-global-core.notesRef) + ("D" magit-global-notes.displayRef)] + ["Arguments for prune" + :if-not magit-notes-merging-p + ("-n" "Dry run" ("-n" "--dry-run"))] + ["Arguments for edit and remove" + :if-not magit-notes-merging-p + (magit-notes:--ref)] + ["Arguments for merge" + :if-not magit-notes-merging-p + (magit-notes:--strategy)] + ["Actions" + :if-not magit-notes-merging-p + ("T" "Edit" magit-notes-edit) + ("r" "Remove" magit-notes-remove) + ("m" "Merge" magit-notes-merge) + ("p" "Prune" magit-notes-prune)] + ["Actions" + :if magit-notes-merging-p + ("c" "Commit merge" magit-notes-merge-commit) + ("a" "Abort merge" magit-notes-merge-abort)]) + +(defun magit-notes-merging-p () + (let ((dir (magit-git-dir "NOTES_MERGE_WORKTREE"))) + (and (file-directory-p dir) + (directory-files dir nil "^[^.]")))) + +(transient-define-infix magit-core.notesRef () + :class 'magit--git-variable + :variable "core.notesRef" + :reader 'magit-notes-read-ref + :prompt "Set local core.notesRef") + +(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") + +(transient-define-infix magit-global-core.notesRef () + :class 'magit--git-variable + :variable "core.notesRef" + :reader 'magit-notes-read-ref + :prompt "Set global core.notesRef") + +(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") + +(transient-define-argument magit-notes:--ref () + :description "Manipulate ref" + :class 'transient-option + :key "-r" + :argument "--ref=" + :reader 'magit-notes-read-ref) + +(transient-define-argument magit-notes:--strategy () + :description "Merge strategy" + :class 'transient-option + :shortarg "-s" + :argument "--strategy=" + :choices '("manual" "ours" "theirs" "union" "cat_sort_uniq")) + +(defun magit-notes-edit (commit &optional ref) + "Edit the note attached to COMMIT. +REF is the notes ref used to store the notes. + +Interactively or when optional REF is nil use the value of Git +variable `core.notesRef' or \"refs/notes/commits\" if that is +undefined." + (interactive (magit-notes-read-args "Edit notes")) + (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref)) + "edit" commit)) + +(defun magit-notes-remove (commit &optional ref) + "Remove the note attached to COMMIT. +REF is the notes ref from which the note is removed. + +Interactively or when optional REF is nil use the value of Git +variable `core.notesRef' or \"refs/notes/commits\" if that is +undefined." + (interactive (magit-notes-read-args "Remove notes")) + (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref)) + "remove" commit)) + +(defun magit-notes-merge (ref) + "Merge the notes ref REF into the current notes ref. + +The current notes ref is the value of Git variable +`core.notesRef' or \"refs/notes/commits\" if that is undefined. + +When there are conflicts, then they have to be resolved in the +temporary worktree \".git/NOTES_MERGE_WORKTREE\". When +done use `magit-notes-merge-commit' to finish. To abort +use `magit-notes-merge-abort'." + (interactive (list (magit-read-string-ns "Merge reference"))) + (magit-run-git-with-editor "notes" "merge" ref)) + +(defun magit-notes-merge-commit () + "Commit the current notes ref merge. +Also see `magit-notes-merge'." + (interactive) + (magit-run-git-with-editor "notes" "merge" "--commit")) + +(defun magit-notes-merge-abort () + "Abort the current notes ref merge. +Also see `magit-notes-merge'." + (interactive) + (magit-run-git-with-editor "notes" "merge" "--abort")) + +(defun magit-notes-prune (&optional dry-run) + "Remove notes about unreachable commits." + (interactive (list (and (member "--dry-run" (transient-args 'magit-notes)) t))) + (when dry-run + (magit-process-buffer)) + (magit-run-git-with-editor "notes" "prune" (and dry-run "--dry-run"))) + +;;; Readers + +(defun magit-notes-read-ref (prompt _initial-input history) + (--when-let (magit-completing-read + prompt (magit-list-notes-refnames) nil nil + (--when-let (magit-get "core.notesRef") + (if (string-prefix-p "refs/notes/" it) + (substring it 11) + it)) + history) + (if (string-prefix-p "refs/" it) + it + (concat "refs/notes/" it)))) + +(defun magit-notes-read-refs (prompt &optional _initial-input _history) + (mapcar (lambda (ref) + (if (string-prefix-p "refs/" ref) + ref + (concat "refs/notes/" ref))) + (completing-read-multiple + (concat prompt ": ") + (magit-list-notes-refnames) nil nil + (mapconcat (lambda (ref) + (if (string-prefix-p "refs/notes/" ref) + (substring ref 11) + ref)) + (magit-get-all "notes.displayRef") + ",")))) + +(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)))) + +;;; _ +(provide 'magit-notes) +;;; magit-notes.el ends here diff --git a/elpa/magit-20220116.1908/magit-obsolete.el b/elpa/magit-20220116.1908/magit-obsolete.el new file mode 100644 index 00000000..e6605f34 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-obsolete.el @@ -0,0 +1,114 @@ +;;; magit-obsolete.el --- obsolete definitions -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library defines aliases for obsolete variables and functions. + +;;; Code: + +(require 'magit) + +;;; Obsolete since v3.0.0 + +(define-obsolete-function-alias 'magit-diff-visit-file-worktree + 'magit-diff-visit-worktree-file "Magit 3.0.0") + +(define-obsolete-function-alias 'magit-status-internal + 'magit-status-setup-buffer "Magit 3.0.0") + +(define-obsolete-variable-alias 'magit-mode-setup-hook + 'magit-setup-buffer-hook "Magit 3.0.0") + +(define-obsolete-variable-alias 'magit-branch-popup-show-variables + 'magit-branch-direct-configure "Magit 3.0.0") + +(define-obsolete-function-alias 'magit-dispatch-popup + 'magit-dispatch "Magit 3.0.0") + +(define-obsolete-function-alias 'magit-repolist-column-dirty + 'magit-repolist-column-flag "Magit 3.0.0") + +(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. +It now uses Transient. +See https://emacsair.me/2019/02/14/transient-0.1. + +However your configuration and/or some third-party package that +you use still depends on the `magit-popup' package. But because +`magit' no longer depends on that, `package' has removed it from +your system. + +If some package that you use still depends on `magit-popup' but +does not declare it as a dependency, then please contact its +maintainer about that and install `magit-popup' explicitly. + +If you yourself use functions that are defined in `magit-popup' +in your configuration, then the next step depends on what you use +that for. + +* If you use `magit-popup' to define your own popups but do not + modify any of Magit's old popups, then you have to install + `magit-popup' explicitly. (You can also migrate to Transient, + but there is no need to rush that.) + +* If you add additional arguments and/or actions to Magit's popups, + then you have to port that to modify the new \"transients\" instead. + See https://github.com/magit/magit/wiki/\ +Converting-popup-modifications-to-transient-modifications + +To find installed packages that still use `magit-popup' you can +use e.g. \"M-x rgrep RET magit-popup RET RET ~/.emacs.d/ RET\".")) +(cl-eval-when (eval load) + (unless (require (quote magit-popup) nil t) + (defun magit-define-popup-switch (&rest _) + (magit--magit-popup-warning)) + (defun magit-define-popup-option (&rest _) + (magit--magit-popup-warning)) + (defun magit-define-popup-variable (&rest _) + (magit--magit-popup-warning)) + (defun magit-define-popup-action (&rest _) + (magit--magit-popup-warning)) + (defun magit-define-popup-sequence-action (&rest _) + (magit--magit-popup-warning)) + (defun magit-define-popup-key (&rest _) + (magit--magit-popup-warning)) + (defun magit-define-popup-keys-deferred (&rest _) + (magit--magit-popup-warning)) + (defun magit-change-popup-key (&rest _) + (magit--magit-popup-warning)) + (defun magit-remove-popup-key (&rest _) + (magit--magit-popup-warning)))) + +;;; _ +(provide 'magit-obsolete) +;;; magit-obsolete.el ends here diff --git a/elpa/magit-20220116.1908/magit-patch.el b/elpa/magit-20220116.1908/magit-patch.el new file mode 100644 index 00000000..e526bead --- /dev/null +++ b/elpa/magit-20220116.1908/magit-patch.el @@ -0,0 +1,329 @@ +;;; magit-patch.el --- creating and applying patches -*- lexical-binding: t -*- + +;; Copyright (C) 2008-2022 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. + +;;; Commentary: + +;; This library implements patch commands. + +;;; Code: + +(require 'magit) + +;;; Options + +(defcustom magit-patch-save-arguments '(exclude "--stat") + "Control arguments used by the command `magit-patch-save'. + +`magit-patch-save' (which see) saves a diff for the changes +shown in the current buffer in a patch file. It may use the +same arguments as used in the buffer or a subset thereof, or +a constant list of arguments, depending on this option and +the prefix argument." + :package-version '(magit . "2.12.0") + :group 'magit-diff + :type '(choice (const :tag "use buffer arguments" buffer) + (cons :tag "use buffer arguments except" + (const :format "" exclude) + (repeat :format "%v%i\n" + (string :tag "Argument"))) + (repeat :tag "use constant arguments" + (string :tag "Argument")))) + +;;; Commands + +;;;###autoload (autoload 'magit-patch "magit-patch" nil t) +(transient-define-prefix magit-patch () + "Create or apply patches." + ["Actions" + [("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) +(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' +which creates patches for all commits that are reachable from +`HEAD' but not from the specified commit)." + :man-page "git-format-patch" + :incompatible '(("--subject-prefix=" "--rfc")) + ["Mail arguments" + (6 magit-format-patch:--in-reply-to) + (6 magit-format-patch:--thread) + (6 magit-format-patch:--from) + (6 magit-format-patch:--to) + (6 magit-format-patch:--cc)] + ["Patch arguments" + (magit-format-patch:--base) + (magit-format-patch:--reroll-count) + (5 magit-format-patch:--interdiff) + (magit-format-patch:--range-diff) + (magit-format-patch:--subject-prefix) + ("C-m r " "RFC subject prefix" "--rfc") + ("C-m l " "Add cover letter" "--cover-letter") + (5 magit-format-patch:--cover-from-description) + (5 magit-format-patch:--notes) + (magit-format-patch:--output-directory)] + ["Diff arguments" + (magit-diff:-U) + (magit-diff:-M) + (magit-diff:-C) + (magit-diff:--diff-algorithm) + (magit:--) + (7 "-b" "Ignore whitespace changes" ("-b" "--ignore-space-change")) + (7 "-w" "Ignore all whitespace" ("-w" "--ignore-all-space"))] + ["Actions" + ("c" "Create patches" magit-patch-create)] + (interactive + (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)) + (let ((range (magit-read-range-or-commit + "Format range or commit"))) + (if (string-match-p "\\.\\." range) + range + (format "%s~..%s" range range)))) + (let ((args (transient-args 'magit-patch-create))) + (list (-filter #'stringp args) + (cdr (assoc "--" args))))))) + (if (not range) + (transient-setup 'magit-patch-create) + (magit-run-git "format-patch" range args "--" files) + (when (member "--cover-letter" args) + (save-match-data + (find-file + (expand-file-name + (concat (when-let ((v (transient-arg-value "--reroll-count=" args))) + (format "v%s-" v)) + "0000-cover-letter.patch") + (let ((topdir (magit-toplevel))) + (if-let ((dir (transient-arg-value "--output-directory=" args))) + (expand-file-name dir topdir) + topdir)))))))) + +(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=") + +(transient-define-argument magit-format-patch:--thread () + :description "Thread style" + :class 'transient-option + :key "C-m s " + :argument "--thread=" + :reader #'magit-format-patch-select-thread-style) + +(defun magit-format-patch-select-thread-style (&rest _ignore) + (magit-read-char-case "Thread style " t + (?d "[d]eep" "deep") + (?s "[s]hallow" "shallow"))) + +(transient-define-argument magit-format-patch:--base () + :description "Insert base commit" + :class 'transient-option + :key "C-m b " + :argument "--base=" + :reader #'magit-format-patch-select-base) + +(defun magit-format-patch-select-base (prompt initial-input history) + (or (magit-completing-read prompt (cons "auto" (magit-list-refnames)) + nil nil initial-input history "auto") + (user-error "Nothing selected"))) + +(transient-define-argument magit-format-patch:--reroll-count () + :description "Reroll count" + :class 'transient-option + :key "C-m v " + :shortarg "-v" + :argument "--reroll-count=" + :reader 'transient-read-number-N+) + +(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) + +(transient-define-argument magit-format-patch:--range-diff () + :description "Insert range-diff" + :class 'transient-option + :key "C-m d r" + :argument "--range-diff=" + :reader #'magit-format-patch-select-range-diff) + +(defun magit-format-patch-select-range-diff (prompt _initial-input _history) + (magit-read-range-or-commit prompt)) + +(transient-define-argument magit-format-patch:--subject-prefix () + :description "Subject Prefix" + :class 'transient-option + :key "C-m p " + :argument "--subject-prefix=") + +(transient-define-argument magit-format-patch:--cover-from-description () + :description "Use branch description" + :class 'transient-option + :key "C-m D " + :argument "--cover-from-description=" + :reader #'magit-format-patch-select-description-mode) + +(defun magit-format-patch-select-description-mode (&rest _ignore) + (magit-read-char-case "Use description as " t + (?m "[m]essage" "message") + (?s "[s]ubject" "subject") + (?a "[a]uto" "auto") + (?n "[n]othing" "none"))) + +(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) + +(transient-define-argument magit-format-patch:--from () + :description "From" + :class 'transient-option + :key "C-m C-f" + :argument "--from=" + :reader 'magit-transient-read-person) + +(transient-define-argument magit-format-patch:--to () + :description "To" + :class 'transient-option + :key "C-m C-t" + :argument "--to=" + :reader 'magit-transient-read-person) + +(transient-define-argument magit-format-patch:--cc () + :description "CC" + :class 'transient-option + :key "C-m C-c" + :argument "--cc=" + :reader 'magit-transient-read-person) + +(transient-define-argument magit-format-patch:--output-directory () + :description "Output directory" + :class 'transient-option + :key "C-m o " + :shortarg "-o" + :argument "--output-directory=" + :reader 'transient-read-existing-directory) + +;;;###autoload (autoload 'magit-patch-apply "magit-patch" nil t) +(transient-define-prefix magit-patch-apply (file &rest args) + "Apply the patch file FILE." + :man-page "git-apply" + ["Arguments" + ("-i" "Also apply to index" "--index") + ("-c" "Only apply to index" "--cached") + ("-3" "Fall back on 3way merge" ("-3" "--3way"))] + ["Actions" + ("a" "Apply patch" magit-patch-apply)] + (interactive + (if (not (eq transient-current-command 'magit-patch-apply)) + (list nil) + (list (expand-file-name + (read-file-name "Apply patch: " + default-directory nil nil + (when-let ((file (magit-file-at-point))) + (file-relative-name file)))) + (transient-args 'magit-patch-apply)))) + (if (not file) + (transient-setup 'magit-patch-apply) + (magit-run-git "apply" args "--" (magit-convert-filename-for-git file)))) + +;;;###autoload +(defun magit-patch-save (file &optional arg) + "Write current diff into patch FILE. + +What arguments are used to create the patch depends on the value +of `magit-patch-save-arguments' and whether a prefix argument is +used. + +If the value is the symbol `buffer', then use the same arguments +as the buffer. With a prefix argument use no arguments. + +If the value is a list beginning with the symbol `exclude', then +use the same arguments as the buffer except for those matched by +entries in the cdr of the list. The comparison is done using +`string-prefix-p'. With a prefix argument use the same arguments +as the buffer. + +If the value is a list of strings (including the empty list), +then use those arguments. With a prefix argument use the same +arguments as the buffer. + +Of course the arguments that are required to actually show the +same differences as those shown in the buffer are always used." + (interactive (list (read-file-name "Write patch file: " default-directory) + current-prefix-arg)) + (unless (derived-mode-p 'magit-diff-mode) + (user-error "Only diff buffers can be saved as patches")) + (let ((rev magit-buffer-range) + (typearg magit-buffer-typearg) + (args magit-buffer-diff-args) + (files magit-buffer-diff-files)) + (cond ((eq magit-patch-save-arguments 'buffer) + (when arg + (setq args nil))) + ((eq (car-safe magit-patch-save-arguments) 'exclude) + (unless arg + (setq args (-difference args (cdr magit-patch-save-arguments))))) + ((not arg) + (setq args magit-patch-save-arguments))) + (with-temp-file file + (magit-git-insert "diff" rev "-p" typearg args "--" files))) + (magit-refresh)) + +;;;###autoload +(defun magit-request-pull (url start end) + "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. +END is the last commit, usually a branch name, which upstream +is asked to pull. START has to be reachable from that commit." + (interactive + (list (magit-get "remote" (magit-read-remote "Remote") "url") + (magit-read-branch-or-commit "Start" (magit-get-upstream-branch)) + (magit-read-branch-or-commit "End"))) + (let ((dir default-directory)) + ;; mu4e changes default-directory + (compose-mail) + (setq default-directory dir)) + (message-goto-body) + (magit-git-insert "request-pull" start url end) + (set-buffer-modified-p nil)) + +;;; _ +(provide 'magit-patch) +;;; magit-patch.el ends here diff --git a/elpa/magit-20220116.1908/magit-pkg.el b/elpa/magit-20220116.1908/magit-pkg.el new file mode 100644 index 00000000..e7653c99 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-pkg.el @@ -0,0 +1,18 @@ +(define-package "magit" "20220116.1908" "A Git porcelain inside Emacs." + '((emacs "25.1") + (dash "20210826") + (git-commit "20211004") + (magit-section "20211004") + (transient "20210920") + (with-editor "20211001")) + :commit "2a7812705f5cf4b864bb162576415863f4116285" :authors + '(("Marius Vollmer" . "marius.vollmer@gmail.com") + ("Jonas Bernoulli" . "jonas@bernoul.li")) + :maintainer + '("Jonas Bernoulli" . "jonas@bernoul.li") + :keywords + '("git" "tools" "vc") + :url "https://github.com/magit/magit") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/magit-20220116.1908/magit-process.el b/elpa/magit-20220116.1908/magit-process.el new file mode 100644 index 00000000..165bd162 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-process.el @@ -0,0 +1,1229 @@ +;;; magit-process.el --- process functionality -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements the tools used to run Git for side-effects. + +;; Note that the functions used to run Git and then consume its +;; output, are defined in `magit-git.el'. There's a bit of overlap +;; though. + +;;; Code: + +(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)) + +;;; Options + +(defcustom magit-process-connection-type (not (eq system-type 'cygwin)) + "Connection type used for the Git process. + +If nil, use pipes: this is usually more efficient, and works on Cygwin. +If t, use ptys: this enables Magit to prompt for passphrases when needed." + :group 'magit-process + :type '(choice (const :tag "pipe" nil) + (const :tag "pty" t))) + +(defcustom magit-need-cygwin-noglob + (and (eq system-type 'windows-nt) + (with-temp-buffer + (let ((process-environment + (append magit-git-environment process-environment))) + (condition-case e + (process-file magit-git-executable + nil (current-buffer) nil + "-c" "alias.echo=!echo" "echo" "x{0}") + (file-error + (lwarn 'magit-process :warning + "Could not run Git: %S" e)))) + (equal "x0\n" (buffer-string)))) + "Whether to use a workaround for Cygwin's globbing behavior. + +If non-nil, add environment variables to `process-environment' to +prevent the git.exe distributed by Cygwin and MSYS2 from +attempting to perform glob expansion when called from a native +Windows build of Emacs. See #2246." + :package-version '(magit . "2.3.0") + :group 'magit-process + :type '(choice (const :tag "Yes" t) + (const :tag "No" nil))) + +(defcustom magit-process-popup-time -1 + "Popup the process buffer if a command takes longer than this many seconds." + :group 'magit-process + :type '(choice (const :tag "Never" -1) + (const :tag "Immediately" 0) + (integer :tag "After this many seconds"))) + +(defcustom magit-process-log-max 32 + "Maximum number of sections to keep in a process log buffer. +When adding a new section would go beyond the limit set here, +then the older half of the sections are remove. Sections that +belong to processes that are still running are never removed. +When this is nil, no sections are ever removed." + :package-version '(magit . "2.1.0") + :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. + +These are displayed in a tooltip for `mode-line-process' errors. + +If `magit-process-error-tooltip-max-lines' is nil, the tooltip +displays the text of `magit-process-error-summary' instead." + :package-version '(magit . "2.12.0") + :group 'magit-process + :type '(choice (const :tag "Use summary line" nil) + integer)) + +(defcustom magit-credential-cache-daemon-socket + (--some (pcase-let ((`(,prog . ,args) (split-string it))) + (if (and prog + (string-match-p + "\\`\\(?:\\(?:/.*/\\)?git-credential-\\)?cache\\'" prog)) + (or (cl-loop for (opt val) on args + if (string= opt "--socket") + return val) + (expand-file-name "~/.git-credential-cache/socket")))) + ;; Note: `magit-process-file' is not yet defined when + ;; evaluating this form, so we use `process-lines'. + (ignore-errors + (let ((process-environment + (append magit-git-environment process-environment))) + (process-lines magit-git-executable + "config" "--get-all" "credential.helper")))) + "If non-nil, start a credential cache daemon using this socket. + +When using Git's cache credential helper in the normal way, Emacs +sends a SIGHUP to the credential daemon after the git subprocess +has exited, causing the daemon to also quit. This can be avoided +by starting the `git-credential-cache--daemon' process directly +from Emacs. + +The function `magit-maybe-start-credential-cache-daemon' takes +care of starting the daemon if necessary, using the value of this +option as the socket. If this option is nil, then it does not +start any daemon. Likewise if another daemon is already running, +then it starts no new daemon. This function has to be a member +of the hook variable `magit-credential-hook' for this to work. +If an error occurs while starting the daemon, most likely because +the necessary executable is missing, then the function removes +itself from the hook, to avoid further futile attempts." + :package-version '(magit . "2.3.0") + :group 'magit-process + :type '(choice (file :tag "Socket") + (const :tag "Don't start a cache daemon" nil))) + +(defcustom magit-process-yes-or-no-prompt-regexp + (concat " [\[(]" + "\\([Yy]\\(?:es\\)?\\)" + "[/|]" + "\\([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 + :type 'regexp) + +(defcustom magit-process-password-prompt-regexps + '("^\\(Enter \\)?[Pp]assphrase\\( for \\(RSA \\)?key '.*'\\)?: ?$" + ;; Match-group 99 is used to identify the "user@host" part. + "^\\(Enter \\)?[Pp]assword\\( for '?\\(https?://\\)?\\(?99:[^']*\\)'?\\)?: ?$" + "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 . "3.0.0") + :group 'magit-process + :type '(repeat (regexp))) + +(defcustom magit-process-find-password-functions nil + "List of functions to try in sequence to get a password. + +These functions may be called when git asks for a password, which +is detected using `magit-process-password-prompt-regexps'. They +are called if and only if matching the prompt resulted in the +value of the 99th submatch to be non-nil. Therefore users can +control for which prompts these functions should be called by +putting the host name in the 99th submatch, or not. + +If the functions are called, then they are called in the order +given, with the host name as only argument, until one of them +returns non-nil. If they are not called or none of them returns +non-nil, then the password is read from the user instead." + :package-version '(magit . "2.3.0") + :group 'magit-process + :type 'hook + :options '(magit-process-password-auth-source)) + +(defcustom magit-process-username-prompt-regexps + '("^Username for '.*': ?$") + "List of regexps matching username prompts of Git and its subprocesses." + :package-version '(magit . "2.1.0") + :group 'magit-process + :type '(repeat (regexp))) + +(defcustom magit-process-prompt-functions nil + "List of functions used to forward arbitrary questions to the user. + +Magit has dedicated support for forwarding username and password +prompts and Yes-or-No questions asked by Git and its subprocesses +to the user. This can be customized using other options in the +`magit-process' customization group. + +If you encounter a new question that isn't handled by default, +then those options should be used instead of this hook. + +However subprocesses may also ask questions that differ too much +from what the code related to the above options assume, and this +hook allows users to deal with such questions explicitly. + +Each function is called with the process and the output string +as arguments until one of the functions returns non-nil. The +function is responsible for asking the user the appropriate +question using e.g. `read-char-choice' and then forwarding the +answer to the process using `process-send-string'. + +While functions such as `magit-process-yes-or-no-prompt' may not +be sufficient to handle some prompt, it may still be of benefit +to look at the implementations to gain some insights on how to +implement such functions." + :package-version '(magit . "3.0.0") + :group 'magit-process + :type 'hook) + +(defcustom magit-process-ensure-unix-line-ending t + "Whether Magit should ensure a unix coding system when talking to Git." + :package-version '(magit . "2.6.0") + :group 'magit-process + :type 'boolean) + +(defcustom magit-process-display-mode-line-error t + "Whether Magit should retain and highlight process errors in the mode line." + :package-version '(magit . "2.12.0") + :group 'magit-process + :type 'boolean) + +(defface magit-process-ok + '((t :inherit magit-section-heading :foreground "green")) + "Face for zero exit-status." + :group 'magit-faces) + +(defface magit-process-ng + '((t :inherit magit-section-heading :foreground "red")) + "Face for non-zero exit-status." + :group 'magit-faces) + +(defface magit-mode-line-process + '((t :inherit mode-line-emphasis)) + "Face for `mode-line-process' status when Git is running for side-effects." + :group 'magit-faces) + +(defface magit-mode-line-process-error + '((t :inherit error)) + "Face for `mode-line-process' error status. + +Used when `magit-process-display-mode-line-error' is non-nil." + :group 'magit-faces) + +;;; Process Mode + +(defvar magit-process-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-mode-map) + map) + "Keymap for `magit-process-mode'.") + +(define-derived-mode magit-process-mode magit-mode "Magit Process" + "Mode for looking at Git process output." + :group 'magit-process + (hack-dir-local-variables-non-file-buffer) + (setq imenu-prev-index-position-function + 'magit-imenu--process-prev-index-position-function) + (setq imenu-extract-index-name-function + 'magit-imenu--process-extract-index-name-function)) + +(defun magit-process-buffer (&optional nodisplay) + "Display the current repository's process buffer. + +If that buffer doesn't exist yet, then create it. +Non-interactively return the buffer and unless +optional NODISPLAY is non-nil also display it." + (interactive) + (let ((topdir (magit-toplevel))) + (unless topdir + (magit--with-safe-default-directory nil + (setq topdir default-directory) + (let (prev) + (while (not (equal topdir prev)) + (setq prev topdir) + (setq topdir (file-name-directory (directory-file-name topdir))))))) + (let ((buffer (or (--first (with-current-buffer it + (and (eq major-mode 'magit-process-mode) + (equal default-directory topdir))) + (buffer-list)) + (let ((default-directory topdir)) + (magit-generate-new-buffer 'magit-process-mode))))) + (with-current-buffer buffer + (if magit-root-section + (when magit-process-log-max + (magit-process-truncate-log)) + (magit-process-mode) + (let ((inhibit-read-only t) + (magit-insert-section--parent nil) + (magit-insert-section--oldroot nil)) + (make-local-variable 'text-property-default-nonsticky) + (magit-insert-section (processbuf) + (insert "\n"))))) + (unless nodisplay + (magit-display-buffer buffer)) + buffer))) + +(defun magit-process-kill () + "Kill the process at point." + (interactive) + (when-let ((process (magit-section-value-if 'process))) + (unless (eq (process-status process) 'run) + (user-error "Process isn't running")) + (magit-confirm 'kill-process) + (kill-process process))) + +;;; Synchronous Processes + +(defvar magit-process-raise-error nil) + +(defun magit-git (&rest args) + "Call Git synchronously in a separate process, for side-effects. + +Option `magit-git-executable' specifies the Git executable. +The arguments ARGS specify arguments to Git, they are flattened +before use. + +Process output goes into a new section in the buffer returned by +`magit-process-buffer'. If Git exits with a non-zero status, +then raise an error." + (let ((magit-process-raise-error t)) + (magit-call-git args))) + +(defun magit-run-git (&rest args) + "Call Git synchronously in a separate process, and refresh. + +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. + +After Git returns, the current buffer (if it is a Magit buffer) +as well as the current repository's status buffer are refreshed. + +Process output goes into a new section in the buffer returned by +`magit-process-buffer'." + (let ((magit--refresh-cache (list (cons 0 0)))) + (magit-call-git args) + (when (member (car args) '("init" "clone")) + ;; Creating a new repository invalidates the cache. + (setq magit--refresh-cache nil)) + (magit-refresh))) + +(defvar magit-pre-call-git-hook nil) + +(defun magit-call-git (&rest args) + "Call Git synchronously in a separate process. + +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. + +Process output goes into a new section in the buffer returned by +`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) + (magit-process-git-arguments args)))) + +(defun magit-call-process (program &rest args) + "Call PROGRAM synchronously in a separate process. +Process output goes into a new section in the buffer returned by +`magit-process-buffer'." + (pcase-let ((`(,process-buf . ,section) + (magit-process-setup program args))) + (magit-process-finish + (let ((inhibit-read-only t)) + (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))) + +(defun magit-process-environment () + ;; The various w32 hacks are only applicable when running on the + ;; local machine. As of Emacs 25.1, a local binding of + ;; process-environment different from the top-level value affects + ;; the environment used in + ;; tramp-sh-handle-{start-file-process,process-file}. + (let ((local (not (file-remote-p default-directory)))) + (append magit-git-environment + (and local + (cdr (assoc magit-git-executable magit-git-w32-path-hack))) + (and local magit-need-cygwin-noglob + (mapcar (lambda (var) + (concat var "=" (--if-let (getenv var) + (concat it " noglob") + "noglob"))) + '("CYGWIN" "MSYS"))) + process-environment))) + +(defvar magit-this-process nil) + +(defun magit-run-git-with-input (&rest args) + "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's standard +input. The buffer is assumed to be temporary and thus OK to +modify. + +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." + (when (eq system-type 'windows-nt) + ;; On w32, git expects UTF-8 encoded input, ignore any user + ;; configuration telling us otherwise (see #3250). + (encode-coding-region (point-min) (point-max) 'utf-8-unix)) + (if (file-remote-p default-directory) + ;; We lack `process-file-region', so fall back to asynch + + ;; waiting in remote case. + (progn + (magit-start-git (current-buffer) args) + (while (and magit-this-process + (eq (process-status magit-this-process) 'run)) + (sleep-for 0.005))) + (run-hooks 'magit-pre-call-git-hook) + (pcase-let* ((process-environment (magit-process-environment)) + (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)) + (inhibit-read-only t)) + (magit-process-finish + (apply #'call-process-region (point-min) (point-max) + (magit-git-executable) nil process-buf nil flat-args) + process-buf nil default-directory section)))) + +;;; Asynchronous Processes + +(defun magit-run-git-async (&rest args) + "Start Git, prepare for refresh, and return the process object. +ARGS is flattened and then used as arguments to Git. + +Display the command line arguments in the echo area. + +After Git returns some buffers are refreshed: the buffer that was +current when this function was called (if it is a Magit buffer +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) + (let ((m (mapconcat #'identity (-flatten args) " "))) + (remove-list-of-text-properties 0 (length m) '(face) m) + m)) + (magit-start-git nil args)) + +(defun magit-run-git-with-editor (&rest args) + "Export GIT_EDITOR and start Git. +Also prepare for refresh and return the process object. +ARGS is flattened and then used as arguments to Git. + +Display the command line arguments in the echo area. + +After Git returns some buffers are refreshed: the buffer that was +current when this function was called (if it is a Magit buffer +and still alive), as well as the respective Magit status buffer. + +See `magit-start-process' and `with-editor' for more information." + (magit--record-separated-gitdir) + (magit-with-editor (magit-run-git-async args))) + +(defun magit-run-git-sequencer (&rest args) + "Export GIT_EDITOR and start Git. +Also prepare for refresh and return the process object. +ARGS is flattened and then used as arguments to Git. + +Display the command line arguments in the echo area. + +After Git returns some buffers are refreshed: the buffer that was +current when this function was called (if it is a Magit buffer +and still alive), as well as the respective Magit status buffer. +If the sequence stops at a commit, make the section representing +that commit the current section by moving `point' there. + +See `magit-start-process' and `with-editor' for more information." + (apply #'magit-run-git-with-editor args) + (set-process-sentinel magit-this-process #'magit-sequencer-process-sentinel) + magit-this-process) + +(defvar magit-pre-start-git-hook nil) + +(defun magit-start-git (input &rest args) + "Start Git, prepare for refresh, and return the process object. + +If INPUT is non-nil, it has to be a buffer or the name of an +existing buffer. The buffer content becomes the processes +standard input. + +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. + +After Git returns some buffers are refreshed: the buffer that was +current when this function was called (if it is a Magit buffer +and still alive), as well as the respective Magit status buffer. + +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 + (magit-process-git-arguments args)))) + +(defun magit-start-process (program &optional input &rest args) + "Start PROGRAM, prepare for refresh, and return the process object. + +If optional argument INPUT is non-nil, it has to be a buffer or +the name of an existing buffer. The buffer content becomes the +processes standard input. + +The process is started using `start-file-process' and then setup +to use the sentinel `magit-process-sentinel' and the filter +`magit-process-filter'. Information required by these functions +is stored in the process object. When this function returns the +process has not started to run yet so it is possible to override +the sentinel and filter. + +After the process returns, `magit-process-sentinel' refreshes the +buffer that was current when `magit-start-process' was called (if +it is a Magit buffer and still alive), as well as the respective +Magit status buffer." + (pcase-let* + ((`(,process-buf . ,section) + (magit-process-setup program args)) + (process + (let ((process-connection-type + ;; Don't use a pty, because it would set icrnl + ;; which would modify the input (issue #20). + (and (not input) magit-process-connection-type)) + (process-environment (magit-process-environment)) + (default-process-coding-system (magit--process-coding-system))) + (apply #'start-file-process + (file-name-nondirectory program) + process-buf program args)))) + (with-editor-set-process-filter process #'magit-process-filter) + (set-process-sentinel process #'magit-process-sentinel) + (set-process-buffer process process-buf) + (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 nil 'utf-8-unix)) + (process-put process 'section section) + (process-put process 'command-buf (current-buffer)) + (process-put process 'default-dir default-directory) + (when magit-inhibit-refresh + (process-put process 'inhibit-refresh t)) + (oset section process process) + (with-current-buffer process-buf + (set-marker (process-mark process) (point))) + (when input + (with-current-buffer input + (process-send-region process (point-min) (point-max)) + (process-send-eof process))) + (setq magit-this-process process) + (oset section value process) + (magit-process-display-buffer process) + process)) + +(defun magit-parse-git-async (&rest args) + (setq args (magit-process-git-arguments args)) + (let ((command-buf (current-buffer)) + (process-buf (generate-new-buffer " *temp*")) + (toplevel (magit-toplevel))) + (with-current-buffer process-buf + (setq default-directory toplevel) + (let ((process + (let ((process-connection-type nil) + (process-environment (magit-process-environment)) + (default-process-coding-system + (magit--process-coding-system))) + (apply #'start-file-process "git" process-buf + (magit-git-executable) args)))) + (process-put process 'command-buf command-buf) + (process-put process 'parsed (point)) + (setq magit-this-process process) + process)))) + +;;; Process Internals + +(defun magit-process-setup (program args) + (magit-process-set-mode-line program args) + (let ((pwd default-directory) + (buf (magit-process-buffer t))) + (cons buf (with-current-buffer buf + (prog1 (magit-process-insert-section pwd program args nil nil) + (backward-char 1)))))) + +(defun magit-process-insert-section (pwd program args &optional errcode errlog) + (let ((inhibit-read-only t) + (magit-insert-section--parent magit-root-section) + (magit-insert-section--oldroot nil)) + (goto-char (1- (point-max))) + (magit-insert-section (process) + (insert (if errcode + (format "%3s " (propertize (number-to-string errcode) + 'font-lock-face 'magit-process-ng)) + "run ")) + (unless (equal (expand-file-name pwd) + (expand-file-name default-directory)) + (insert (file-relative-name pwd default-directory) ?\s)) + (insert (magit-process--format-arguments program args)) + (magit-insert-heading) + (when errlog + (if (bufferp errlog) + (insert (with-current-buffer errlog + (buffer-substring-no-properties (point-min) (point-max)))) + (insert-file-contents errlog) + (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)) + (count (length tail))) + (when (> (1+ count) magit-process-log-max) + (while (and (cdr tail) + (> count (/ magit-process-log-max 2))) + (let* ((inhibit-read-only t) + (section (car tail)) + (process (oref section process))) + (cond ((not process)) + ((memq (process-status process) '(exit signal)) + (delete-region (oref section start) + (1+ (oref section end))) + (cl-decf count)) + (t + (push section head)))) + (pop tail)) + (oset magit-root-section children + (nconc (reverse head) tail))))) + +(defun magit-process-sentinel (process event) + "Default sentinel used by `magit-start-process'." + (when (memq (process-status process) '(exit signal)) + (setq event (substring event 0 -1)) + (when (string-match "^finished" event) + (message (concat (capitalize (process-name process)) " finished"))) + (magit-process-finish process) + (when (eq process magit-this-process) + (setq magit-this-process nil)) + (unless (process-get process 'inhibit-refresh) + (let ((command-buf (process-get process 'command-buf))) + (if (buffer-live-p command-buf) + (with-current-buffer command-buf + (magit-refresh)) + (with-temp-buffer + (setq default-directory (process-get process 'default-dir)) + (magit-refresh))))))) + +(defun magit-sequencer-process-sentinel (process event) + "Special sentinel used by `magit-run-git-sequencer'." + (when (memq (process-status process) '(exit signal)) + (magit-process-sentinel process event) + (when-let ((process-buf (process-buffer process))) + (when (buffer-live-p process-buf) + (when-let ((status-buf (with-current-buffer process-buf + (magit-get-mode-buffer 'magit-status-mode)))) + (with-current-buffer status-buf + (--when-let + (magit-get-section + `((commit . ,(magit-rev-parse "HEAD")) + (,(pcase (car (cadr (-split-at + (1+ (length magit-git-global-arguments)) + (process-command process)))) + ((or "rebase" "am") 'rebase-sequence) + ((or "cherry-pick" "revert") 'sequence))) + (status))) + (goto-char (oref it start)) + (magit-section-update-highlight)))))))) + +(defun magit-process-filter (proc string) + "Default filter used by `magit-start-process'." + (with-current-buffer (process-buffer proc) + (let ((inhibit-read-only t)) + (goto-char (process-mark proc)) + ;; Find last ^M in string. If one was found, ignore + ;; everything before it and delete the current line. + (when-let ((ret-pos (cl-position ?\r string :from-end t))) + (cl-callf substring string (1+ ret-pos)) + (delete-region (line-beginning-position) (point))) + (insert (propertize string 'magit-section + (process-get proc 'section))) + (set-marker (process-mark proc) (point)) + ;; Make sure prompts are matched after removing ^M. + (magit-process-yes-or-no-prompt proc string) + (magit-process-username-prompt proc string) + (magit-process-password-prompt proc string) + (run-hook-with-args-until-success 'magit-process-prompt-functions + proc string)))) + +(defmacro magit-process-kill-on-abort (proc &rest body) + (declare (indent 1) (debug (form body))) + (let ((map (cl-gensym))) + `(let ((,map (make-sparse-keymap))) + (set-keymap-parent ,map minibuffer-local-map) + ;; 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)) + (abort-recursive-edit))) + (let ((minibuffer-local-map ,map)) + ,@body)))) + +(defun magit-process-yes-or-no-prompt (process string) + "Forward Yes-or-No prompts to the user." + (when-let ((beg (string-match magit-process-yes-or-no-prompt-regexp string))) + (let ((max-mini-window-height 30)) + (process-send-string + process + (downcase + (concat + (match-string + (if (save-match-data + (magit-process-kill-on-abort process + (yes-or-no-p (substring string 0 beg)))) 1 2) + string) + "\n")))))) + +(defun magit-process-password-auth-source (key) + "Use `auth-source-search' to get a password. +If found, return the password. Otherwise, return nil. + +To use this function add it to the appropriate hook + (add-hook 'magit-process-find-password-functions + 'magit-process-password-auth-source) + +KEY typically derives from a prompt such as: + Password for 'https://yourname@github.com' +in which case it would be the string + yourname@github.com +which matches the ~/.authinfo.gpg entry + machine github.com login yourname password 12345 +or iff that is undefined, for backward compatibility + 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)) + (host (match-string 2 key)) + (secret + (plist-get + (car (or (auth-source-search :max 1 :host host :user user) + (auth-source-search :max 1 :host key))) + :secret))) + (if (functionp secret) + (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 functions return nil, then read the password +from the user." + (when-let ((prompt (magit-process-match-prompt + magit-process-password-prompt-regexps string))) + (process-send-string + process (magit-process-kill-on-abort process + (concat (or (when-let ((key (match-string 99 string))) + (run-hook-with-args-until-success + 'magit-process-find-password-functions key)) + (read-passwd prompt)) + "\n"))))) + +(defun magit-process-username-prompt (process string) + "Forward username prompts to the user." + (--when-let (magit-process-match-prompt + magit-process-username-prompt-regexps string) + (process-send-string + process (magit-process-kill-on-abort process + (concat (read-string it nil nil (user-login-name)) "\n"))))) + +(defun magit-process-match-prompt (prompts string) + "Match STRING against PROMPTS and set match data. +Return the matched string suffixed with \": \", if needed." + (when (--any-p (string-match it string) prompts) + (let ((prompt (match-string 0 string))) + (cond ((string-suffix-p ": " prompt) prompt) + ((string-suffix-p ":" prompt) (concat prompt " ")) + (t (concat prompt ": ")))))) + +(defun magit--process-coding-system () + (let ((fro (or magit-git-output-coding-system + (car default-process-coding-system))) + (to (cdr default-process-coding-system))) + (if magit-process-ensure-unix-line-ending + (cons (coding-system-change-eol-conversion fro 'unix) + (coding-system-change-eol-conversion to 'unix)) + (cons fro to)))) + +(defvar magit-credential-hook nil + "Hook run before Git needs credentials.") + +(defvar magit-credential-cache-daemon-process nil) + +(defun magit-maybe-start-credential-cache-daemon () + "Maybe start a `git-credential-cache--daemon' process. + +If such a process is already running or if the value of option +`magit-credential-cache-daemon-socket' is nil, then do nothing. +Otherwise start the process passing the value of that options +as argument." + (unless (or (not magit-credential-cache-daemon-socket) + (process-live-p magit-credential-cache-daemon-process) + (memq magit-credential-cache-daemon-process + (list-system-processes))) + (setq magit-credential-cache-daemon-process + (or (--first (let* ((attr (process-attributes it)) + (comm (cdr (assq 'comm attr))) + (user (cdr (assq 'user attr)))) + (and (string= comm "git-credential-cache--daemon") + (string= user user-login-name))) + (list-system-processes)) + (condition-case nil + (start-process "git-credential-cache--daemon" + " *git-credential-cache--daemon*" + (magit-git-executable) + "credential-cache--daemon" + magit-credential-cache-daemon-socket) + ;; Some Git implementations (e.g. Windows) won't have + ;; this program; if we fail the first time, stop trying. + ((debug error) + (remove-hook 'magit-credential-hook + #'magit-maybe-start-credential-cache-daemon))))))) + +(add-hook 'magit-credential-hook #'magit-maybe-start-credential-cache-daemon) + +(defun tramp-sh-handle-start-file-process--magit-tramp-process-environment + (fn name buffer program &rest args) + (if magit-tramp-process-environment + (apply fn name buffer + (car magit-tramp-process-environment) + (append (cdr magit-tramp-process-environment) + (cons program args))) + (apply fn name buffer program args))) + +(advice-add 'tramp-sh-handle-start-file-process :around + 'tramp-sh-handle-start-file-process--magit-tramp-process-environment) + +(defun tramp-sh-handle-process-file--magit-tramp-process-environment + (fn program &optional infile destination display &rest args) + (if magit-tramp-process-environment + (apply fn "env" infile destination display + (append magit-tramp-process-environment + (cons program args))) + (apply fn program infile destination display args))) + +(advice-add 'tramp-sh-handle-process-file :around + 'tramp-sh-handle-process-file--magit-tramp-process-environment) + +(defvar magit-mode-line-process-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd " ") + 'magit-process-buffer) + map) + "Keymap for `mode-line-process'.") + +(defun magit-process-set-mode-line (program args) + "Display the git command (sans arguments) in the mode line." + (when (equal program (magit-git-executable)) + (setq args (nthcdr (length magit-git-global-arguments) args))) + (let ((str (concat " " (propertize + (concat (file-name-nondirectory program) + (and args (concat " " (car args)))) + 'mouse-face 'highlight + 'keymap magit-mode-line-process-map + 'help-echo "mouse-1: Show process buffer" + 'font-lock-face 'magit-mode-line-process)))) + (magit-repository-local-set 'mode-line-process str) + (dolist (buf (magit-mode-get-buffers)) + (with-current-buffer buf + (setq mode-line-process str))) + (force-mode-line-update t))) + +(defun magit-process-set-mode-line-error-status (&optional error str) + "Apply an error face to the string set by `magit-process-set-mode-line'. + +If ERROR is supplied, include it in the `mode-line-process' tooltip. + +If STR is supplied, it replaces the `mode-line-process' text." + (setq str (or str (magit-repository-local-get 'mode-line-process))) + (when str + (setq error (format "%smouse-1: Show process buffer" + (if (stringp error) + (concat error "\n\n") + ""))) + (setq str (concat " " (propertize + (substring-no-properties str 1) + 'mouse-face 'highlight + 'keymap magit-mode-line-process-map + 'help-echo error + 'font-lock-face 'magit-mode-line-process-error))) + (magit-repository-local-set 'mode-line-process str) + (dolist (buf (magit-mode-get-buffers)) + (with-current-buffer buf + (setq mode-line-process str))) + (force-mode-line-update t) + ;; We remove any error status from the mode line when a magit + ;; buffer is refreshed (see `magit-refresh-buffer'), but we must + ;; ensure that we ignore any refreshes during the remainder of the + ;; current command -- otherwise a newly-set error status would be + ;; removed before it was seen. We set a flag which prevents the + ;; status from being removed prior to the next command, so that + ;; the error status is guaranteed to remain visible until then. + (let ((repokey (magit-repository-local-repository))) + ;; 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-hook 'pre-command-hook + #'enable-magit-process-unset-mode-line) + ;; Clear the inhibit flag for the repository in + ;; which we set it. + (magit-repository-local-set + 'inhibit-magit-process-unset-mode-line nil repokey))) + ;; Set the inhibit flag until the next command is invoked. + (magit-repository-local-set + 'inhibit-magit-process-unset-mode-line t repokey) + (add-hook 'pre-command-hook + #'enable-magit-process-unset-mode-line))))) + +(defun magit-process-unset-mode-line-error-status () + "Remove any current error status from the mode line." + (let ((status (or mode-line-process + (magit-repository-local-get 'mode-line-process)))) + (when (and status + (eq (get-text-property 1 'font-lock-face status) + 'magit-mode-line-process-error)) + (magit-process-unset-mode-line)))) + +(defun magit-process-unset-mode-line (&optional directory) + "Remove the git command from the mode line." + (let ((default-directory (or directory default-directory))) + (unless (magit-repository-local-get 'inhibit-magit-process-unset-mode-line) + (magit-repository-local-set 'mode-line-process nil) + (dolist (buf (magit-mode-get-buffers)) + (with-current-buffer buf (setq mode-line-process nil))) + (force-mode-line-update t)))) + +(defvar magit-process-error-message-regexps + (list "^\\*ERROR\\*: Canceled by user$" + "^\\(?:error\\|fatal\\|git\\): \\(.*\\)$" + "^\\(Cannot rebase:.*\\)$")) + +(define-error 'magit-git-error "Git error") + +(defun magit-process-error-summary (process-buf section) + "A one-line error summary from the given SECTION." + (or (and (buffer-live-p process-buf) + (with-current-buffer process-buf + (and (oref section content) + (save-excursion + (goto-char (oref section end)) + (run-hook-wrapped + 'magit-process-error-message-regexps + (lambda (re) + (save-excursion + (and (re-search-backward + re (oref section start) t) + (or (match-string-no-properties 1) + (and (not magit-process-raise-error) + 'suppressed)))))))))) + "Git failed")) + +(defun magit-process-error-tooltip (process-buf section) + "Returns the text from SECTION of the PROCESS-BUF buffer. + +Limited by `magit-process-error-tooltip-max-lines'." + (and (integerp magit-process-error-tooltip-max-lines) + (> magit-process-error-tooltip-max-lines 0) + (buffer-live-p process-buf) + (with-current-buffer process-buf + (save-excursion + (goto-char (or (oref section content) + (oref section start))) + (buffer-substring-no-properties + (point) + (save-excursion + (forward-line magit-process-error-tooltip-max-lines) + (goto-char + (if (> (point) (oref section end)) + (oref section end) + (point))) + ;; Remove any trailing whitespace. + (when (re-search-backward "[^[:space:]\n]" + (oref section start) t) + (forward-char 1)) + (point))))))) + +(defvar-local magit-this-error nil) + +(defvar magit-process-finish-apply-ansi-colors nil) + +(defun magit-process-finish (arg &optional process-buf command-buf + default-dir section) + (unless (integerp arg) + (setq process-buf (process-buffer arg)) + (setq command-buf (process-get arg 'command-buf)) + (setq default-dir (process-get arg 'default-dir)) + (setq section (process-get arg 'section)) + (setq arg (process-exit-status arg))) + (when (fboundp 'dired-uncache) + (dired-uncache default-dir)) + (when (buffer-live-p process-buf) + (with-current-buffer process-buf + (let ((inhibit-read-only t) + (marker (oref section start))) + (goto-char marker) + (save-excursion + (delete-char 3) + (set-marker-insertion-type marker nil) + (insert (propertize (format "%3s" arg) + 'magit-section section + 'font-lock-face (if (= arg 0) + 'magit-process-ok + 'magit-process-ng))) + (set-marker-insertion-type marker t)) + (when magit-process-finish-apply-ansi-colors + (ansi-color-apply-on-region (oref section content) + (oref section end))) + (if (= (oref section end) + (+ (line-end-position) 2)) + (save-excursion + (goto-char (1+ (line-end-position))) + (delete-char -1) + (oset section content nil)) + (let ((buf (magit-process-buffer t))) + (when (and (= arg 0) + (not (--any-p (eq (window-buffer it) buf) + (window-list)))) + (magit-section-hide section))))))) + (if (= arg 0) + ;; Unset the `mode-line-process' value upon success. + (magit-process-unset-mode-line default-dir) + ;; Otherwise process the error. + (let ((msg (magit-process-error-summary process-buf section))) + ;; Change `mode-line-process' to an error face upon failure. + (if magit-process-display-mode-line-error + (magit-process-set-mode-line-error-status + (or (magit-process-error-tooltip process-buf section) + msg)) + (magit-process-unset-mode-line default-dir)) + ;; Either signal the error, or else display the error summary in + ;; the status buffer and with a message in the echo area. + (cond + (magit-process-raise-error + (signal 'magit-git-error (list (format "%s (in %s)" msg default-dir)))) + ((not (eq msg 'suppressed)) + (when (buffer-live-p process-buf) + (with-current-buffer process-buf + (when-let ((status-buf (magit-get-mode-buffer 'magit-status-mode))) + (with-current-buffer status-buf + (setq magit-this-error msg))))) + (message "%s ... [%s buffer %s for details]" msg + (if-let ((key (and (buffer-live-p command-buf) + (with-current-buffer command-buf + (car (where-is-internal + 'magit-process-buffer)))))) + (format "Hit %s to see" (key-description key)) + "See") + (buffer-name process-buf)))))) + arg) + +(defun magit-process-display-buffer (process) + (when (process-live-p process) + (let ((buf (process-buffer process))) + (cond ((not (buffer-live-p buf))) + ((= magit-process-popup-time 0) + (if (minibufferp) + (switch-to-buffer-other-window buf) + (pop-to-buffer buf))) + ((> magit-process-popup-time 0) + (run-with-timer magit-process-popup-time nil + (lambda (p) + (when (eq (process-status p) 'run) + (let ((buf (process-buffer p))) + (when (buffer-live-p buf) + (if (minibufferp) + (switch-to-buffer-other-window buf) + (pop-to-buffer buf)))))) + process)))))) + +(defun magit--log-action (summary line list) + (let (heading lines) + (if (cdr list) + (progn (setq heading (funcall summary list)) + (setq lines (mapcar line list))) + (setq heading (funcall line (car list)))) + (with-current-buffer (magit-process-buffer t) + (goto-char (1- (point-max))) + (let ((inhibit-read-only t)) + (magit-insert-section (message) + (magit-insert-heading (concat " * " heading)) + (when lines + (dolist (line lines) + (insert line "\n")) + (insert "\n")))) + (let ((inhibit-message t)) + (when heading + (setq lines (cons heading lines))) + (message (mapconcat #'identity lines "\n")))))) + +;;; _ +(provide 'magit-process) +;;; magit-process.el ends here diff --git a/elpa/magit-20220116.1908/magit-pull.el b/elpa/magit-20220116.1908/magit-pull.el new file mode 100644 index 00000000..db8783f3 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-pull.el @@ -0,0 +1,168 @@ +;;; magit-pull.el --- update local objects and refs -*- lexical-binding: t -*- + +;; Copyright (C) 2008-2022 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. + +;;; Commentary: + +;; This library implements pull commands. + +;;; Code: + +(require 'magit) + +;;; Options + +(defcustom magit-pull-or-fetch nil + "Whether `magit-pull' also offers some fetch suffixes." + :package-version '(magit . "3.0.0") + :group 'magit-commands + :type 'boolean) + +;;; Commands + +;;;###autoload (autoload 'magit-pull "magit-pull" nil t) +(transient-define-prefix magit-pull () + "Pull from another repository." + :man-page "git-pull" + :incompatible '(("--ff-only" "--rebase")) + [:description + (lambda () (if magit-pull-or-fetch "Pull arguments" "Arguments")) + ("-f" "Fast-forward only" "--ff-only") + ("-r" "Rebase local commits" ("-r" "--rebase")) + ("-A" "Autostash" "--autostash" :level 7)] + [:description + (lambda () + (if-let ((branch (magit-get-current-branch))) + (concat + (propertize "Pull into " 'face 'transient-heading) + (propertize branch 'face 'magit-branch-local) + (propertize " from" 'face 'transient-heading)) + (propertize "Pull from" 'face 'transient-heading))) + ("p" magit-pull-from-pushremote) + ("u" magit-pull-from-upstream) + ("e" "elsewhere" magit-pull-branch)] + ["Fetch from" + :if-non-nil magit-pull-or-fetch + ("f" "remotes" magit-fetch-all-no-prune) + ("F" "remotes and prune" magit-fetch-all-prune)] + ["Fetch" + :if-non-nil magit-pull-or-fetch + ("o" "another branch" magit-fetch-branch) + ("s" "explicit refspec" magit-fetch-refspec) + ("m" "submodules" magit-fetch-modules)] + ["Configure" + ("r" magit-branch..rebase :if magit-get-current-branch) + ("C" "variables..." magit-branch-configure)] + (interactive) + (transient-setup 'magit-pull nil nil :scope (magit-get-current-branch))) + +(defun magit-pull-arguments () + (transient-args 'magit-pull)) + +;;;###autoload (autoload 'magit-pull-from-pushremote "magit-pull" nil t) +(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 +configured or unusable, then let the user first configure the +push-remote." + :if 'magit-get-current-branch + :description 'magit-pull--pushbranch-description + (interactive (list (magit-pull-arguments))) + (pcase-let ((`(,branch ,remote) + (magit--select-push-remote "pull from there"))) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "pull" args remote branch))) + +(defun magit-pull--pushbranch-description () + ;; Also used by `magit-rebase-onto-pushremote'. + (let* ((branch (magit-get-current-branch)) + (target (magit-get-push-branch branch t)) + (remote (magit-get-push-remote branch)) + (v (magit--push-remote-variable branch t))) + (cond + (target) + ((member remote (magit-list-remotes)) + (format "%s, replacing non-existent" v)) + (remote + (format "%s, replacing invalid" v)) + (t + (format "%s, setting that" v))))) + +;;;###autoload (autoload 'magit-pull-from-upstream "magit-pull" nil t) +(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 +configured or unusable, then let the user first configure +the upstream." + :if 'magit-get-current-branch + :description 'magit-pull--upstream-description + (interactive (list (magit-pull-arguments))) + (let* ((branch (or (magit-get-current-branch) + (user-error "No branch is checked out"))) + (remote (magit-get "branch" branch "remote")) + (merge (magit-get "branch" branch "merge"))) + (when (or current-prefix-arg + (not (or (magit-get-upstream-branch branch) + (magit--unnamed-upstream-p remote merge)))) + (magit-set-upstream-branch + branch (magit-read-upstream-branch + branch (format "Set upstream of %s and pull from there" branch))) + (setq remote (magit-get "branch" branch "remote")) + (setq merge (magit-get "branch" branch "merge"))) + (run-hooks 'magit-credential-hook) + (magit-run-git-with-editor "pull" args remote merge))) + +(defun magit-pull--upstream-description () + (when-let ((branch (magit-get-current-branch))) + (or (magit-get-upstream-branch branch) + (let ((remote (magit-get "branch" branch "remote")) + (merge (magit-get "branch" branch "merge")) + (u (magit--propertize-face "@{upstream}" 'bold))) + (cond + ((magit--unnamed-upstream-p remote merge) + (format "%s of %s" + (magit--propertize-face merge 'magit-branch-remote) + (magit--propertize-face remote 'bold))) + ((magit--valid-upstream-p remote merge) + (concat u ", replacing non-existent")) + ((or remote merge) + (concat u ", replacing invalid")) + (t + (concat u ", setting that"))))))) + +;;;###autoload +(defun magit-pull-branch (source args) + "Pull from a branch read in the minibuffer." + (interactive (list (magit-read-remote-branch "Pull" nil nil nil t) + (magit-pull-arguments))) + (run-hooks 'magit-credential-hook) + (pcase-let ((`(,remote . ,branch) + (magit-get-tracked source))) + (magit-run-git-with-editor "pull" args remote branch))) + +;;; _ +(provide 'magit-pull) +;;; magit-pull.el ends here diff --git a/elpa/magit-20220116.1908/magit-push.el b/elpa/magit-20220116.1908/magit-push.el new file mode 100644 index 00000000..918053ba --- /dev/null +++ b/elpa/magit-20220116.1908/magit-push.el @@ -0,0 +1,344 @@ +;;; magit-push.el --- update remote objects and refs -*- lexical-binding: t -*- + +;; Copyright (C) 2008-2022 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. + +;;; Commentary: + +;; This library implements push commands. + +;;; Code: + +(require 'magit) + +;;; Commands + +;;;###autoload (autoload 'magit-push "magit-push" nil t) +(transient-define-prefix magit-push () + "Push to another repository." + :man-page "git-push" + ["Arguments" + ("-f" "Force with lease" (nil "--force-with-lease")) + ("-F" "Force" ("-f" "--force")) + ("-h" "Disable hooks" "--no-verify") + ("-n" "Dry run" ("-n" "--dry-run")) + (5 "-u" "Set upstream" "--set-upstream") + (7 "-t" "Follow tags" "--follow-tags")] + [:if magit-get-current-branch + :description (lambda () + (format (propertize "Push %s to" 'face 'transient-heading) + (propertize (magit-get-current-branch) + 'face 'magit-branch-local))) + ("p" magit-push-current-to-pushremote) + ("u" magit-push-current-to-upstream) + ("e" "elsewhere" magit-push-current)] + ["Push" + [("o" "another branch" magit-push-other) + ("r" "explicit refspecs" magit-push-refspecs) + ("m" "matching branches" magit-push-matching)] + [("T" "a tag" magit-push-tag) + ("t" "all tags" magit-push-tags) + (6 "n" "a note ref" magit-push-notes-ref)]] + ["Configure" + ("C" "Set variables..." magit-branch-configure)]) + +(defun magit-push-arguments () + (transient-args 'magit-push)) + +(defun magit-git-push (branch target args) + (run-hooks 'magit-credential-hook) + ;; If the remote branch already exists, then we do not have to + ;; qualify the target, which we prefer to avoid doing because + ;; using the default namespace is wrong in obscure cases. + (pcase-let ((namespace (if (magit-get-tracked target) "" "refs/heads/")) + (`(,remote . ,target) + (magit-split-branch-name target))) + (magit-run-git-async "push" "-v" args remote + (format "%s:%s%s" branch namespace target)))) + +;;;###autoload (autoload 'magit-push-current-to-pushremote "magit-push" nil t) +(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 +from the user, set it, and then push to it. With a prefix +argument the push-remote can be changed before pushed to it." + :if 'magit-get-current-branch + :description 'magit-push--pushbranch-description + (interactive (list (magit-push-arguments))) + (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" + branch branch)))) ; see #3847 and #3872 + +(defun magit-push--pushbranch-description () + (let* ((branch (magit-get-current-branch)) + (target (magit-get-push-branch branch t)) + (remote (magit-get-push-remote branch)) + (v (magit--push-remote-variable branch t))) + (cond + (target) + ((member remote (magit-list-remotes)) + (format "%s, creating it" + (magit--propertize-face (concat remote "/" branch) + 'magit-branch-remote))) + (remote + (format "%s, replacing invalid" v)) + (t + (format "%s, setting that" v))))) + +;;;###autoload (autoload 'magit-push-current-to-upstream "magit-push" nil t) +(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 +configured or unusable, then let the user first configure +the upstream." + :if 'magit-get-current-branch + :description 'magit-push--upstream-description + (interactive (list (magit-push-arguments))) + (let* ((branch (or (magit-get-current-branch) + (user-error "No branch is checked out"))) + (remote (magit-get "branch" branch "remote")) + (merge (magit-get "branch" branch "merge"))) + (when (or current-prefix-arg + (not (or (magit-get-upstream-branch branch) + (magit--unnamed-upstream-p remote merge) + (magit--valid-upstream-p remote merge)))) + (let* ((branches (-union (--map (concat it "/" branch) + (magit-list-remotes)) + (magit-list-remote-branch-names))) + (upstream (magit-completing-read + (format "Set upstream of %s and push there" branch) + 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*)) + (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))) + (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)))) + +(defun magit-push--upstream-description () + (when-let ((branch (magit-get-current-branch))) + (or (magit-get-upstream-branch branch) + (let ((remote (magit-get "branch" branch "remote")) + (merge (magit-get "branch" branch "merge")) + (u (magit--propertize-face "@{upstream}" 'bold))) + (cond + ((magit--unnamed-upstream-p remote merge) + (format "%s as %s" + (magit--propertize-face remote 'bold) + (magit--propertize-face merge 'magit-branch-remote))) + ((magit--valid-upstream-p remote merge) + (format "%s creating %s" + (magit--propertize-face remote 'magit-branch-remote) + (magit--propertize-face merge 'magit-branch-remote))) + ((or remote merge) + (concat u ", creating it and replacing invalid")) + (t + (concat u ", creating it"))))))) + +;;;###autoload +(defun magit-push-current (target args) + "Push the current branch to a branch read in the minibuffer." + (interactive + (--if-let (magit-get-current-branch) + (list (magit-read-remote-branch (format "Push %s to" it) + nil nil it 'confirm) + (magit-push-arguments)) + (user-error "No branch is checked out"))) + (magit-git-push (magit-get-current-branch) target args)) + +;;;###autoload +(defun magit-push-other (source target args) + "Push an arbitrary branch or commit somewhere. +Both the source and the target are read in the minibuffer." + (interactive + (let ((source (magit-read-local-branch-or-commit "Push"))) + (list source + (magit-read-remote-branch + (format "Push %s to" source) nil + (if (magit-local-branch-p source) + (or (magit-get-push-branch source) + (magit-get-upstream-branch source)) + (and (magit-rev-ancestor-p source "HEAD") + (or (magit-get-push-branch) + (magit-get-upstream-branch)))) + source 'confirm) + (magit-push-arguments)))) + (magit-git-push source target args)) + +(defvar magit-push-refspecs-history nil) + +;;;###autoload +(defun magit-push-refspecs (remote refspecs args) + "Push one or multiple REFSPECS to a REMOTE. +Both the REMOTE and the REFSPECS are read in the minibuffer. To +use multiple REFSPECS, separate them with commas. Completion is +only available for the part before the colon, or when no colon +is used." + (interactive + (list (magit-read-remote "Push to remote") + (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)) + +;;;###autoload +(defun magit-push-matching (remote &optional args) + "Push all matching branches to another repository. +If multiple remotes exist, then read one from the user. +If just one exists, use that without requiring confirmation." + (interactive (list (magit-read-remote "Push matching branches to" nil t) + (magit-push-arguments))) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "push" "-v" args remote ":")) + +;;;###autoload +(defun magit-push-tags (remote &optional args) + "Push all tags to another repository. +If only one remote exists, then push to that. Otherwise prompt +for a remote, offering the remote configured for the current +branch as default." + (interactive (list (magit-read-remote "Push tags to remote" nil t) + (magit-push-arguments))) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "push" remote "--tags" args)) + +;;;###autoload +(defun magit-push-tag (tag remote &optional args) + "Push a tag to another repository." + (interactive + (let ((tag (magit-read-tag "Push tag"))) + (list tag (magit-read-remote (format "Push %s to remote" tag) nil t) + (magit-push-arguments)))) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "push" remote tag args)) + +;;;###autoload +(defun magit-push-notes-ref (ref remote &optional args) + "Push a notes ref to another repository." + (interactive + (let ((note (magit-notes-read-ref "Push notes" nil nil))) + (list note + (magit-read-remote (format "Push %s to remote" note) nil t) + (magit-push-arguments)))) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "push" remote ref 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 +arguments specified in the popup buffer. No explicit refspec +arguments are used. Instead the behavior depends on at least +these Git variables: `push.default', `remote.pushDefault', +`branch..pushRemote', `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: + + (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)) + +(defun magit-push-implicitly--desc () + (let ((default (magit-get "push.default"))) + (unless (equal default "nothing") + (or (when-let ((remote (or (magit-get-remote) + (magit-primary-remote))) + (refspec (magit-get "remote" remote "push"))) + (format "%s using %s" + (magit--propertize-face remote 'magit-branch-remote) + (magit--propertize-face refspec 'bold))) + (--when-let (and (not (magit-get-push-branch)) + (magit-get-upstream-branch)) + (format "%s aka %s\n" + (magit-branch-set-face it) + (magit--propertize-face "@{upstream}" 'bold))) + (--when-let (magit-get-push-branch) + (format "%s aka %s\n" + (magit-branch-set-face it) + (magit--propertize-face "pushRemote" 'bold))) + (--when-let (magit-get-@{push}-branch) + (format "%s aka %s\n" + (magit-branch-set-face it) + (magit--propertize-face "@{push}" 'bold))) + (format "using %s (%s is %s)\n" + (magit--propertize-face "git push" 'bold) + (magit--propertize-face "push.default" 'bold) + (magit--propertize-face default 'bold)))))) + +;;;###autoload +(defun magit-push-to-remote (remote args) + "Push to REMOTE without using an explicit refspec. +The REMOTE is read in the minibuffer. + +This command simply runs \"git push -v [ARGS] REMOTE\". ARGS +are the arguments specified in the popup buffer. No refspec +arguments are used. Instead the behavior depends on at least +these Git variables: `push.default', `remote.pushDefault', +`branch..pushRemote', `branch..remote', +`branch..merge', and `remote..push'." + (interactive (list (magit-read-remote "Push to remote") + (magit-push-arguments))) + (run-hooks 'magit-credential-hook) + (magit-run-git-async "push" "-v" args remote)) + +(defun magit-push-to-remote--desc () + (format "using %s\n" (magit--propertize-face "git push " 'bold))) + +;;; _ +(provide 'magit-push) +;;; magit-push.el ends here diff --git a/elpa/magit-20220116.1908/magit-reflog.el b/elpa/magit-20220116.1908/magit-reflog.el new file mode 100644 index 00000000..fb79d8ef --- /dev/null +++ b/elpa/magit-20220116.1908/magit-reflog.el @@ -0,0 +1,212 @@ +;;; magit-reflog.el --- inspect ref history -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements support for looking at Git reflogs. + +;;; Code: + +(require 'magit-core) +(require 'magit-log) + +;;; Options + +(defcustom magit-reflog-limit 256 + "Maximal number of entries initially shown in reflog buffers. +The limit in the current buffer can be changed using \"+\" +and \"-\"." + :package-version '(magit . "3.0.0") + :group 'magit-commands + :type 'number) + +(defcustom magit-reflog-margin + (list (nth 0 magit-log-margin) + (nth 1 magit-log-margin) + 'magit-log-margin-width nil + (nth 4 magit-log-margin)) + "Format of the margin in `magit-reflog-mode' buffers. + +The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). + +If INIT is non-nil, then the margin is shown initially. +STYLE controls how to format the author or committer date. + It can be one of `age' (to show the age of the commit), + `age-abbreviated' (to abbreviate the time unit to a character), + or a string (suitable for `format-time-string') to show the + actual date. Option `magit-log-margin-show-committer-date' + controls which date is being displayed. +WIDTH controls the width of the margin. This exists for forward + compatibility and currently the value should not be changed. +AUTHOR controls whether the name of the author is also shown by + default. +AUTHOR-WIDTH has to be an integer. When the name of the author + is shown, then this specifies how much space is used to do so." + :package-version '(magit . "2.9.0") + :group 'magit-log + :group 'magit-margin + :type magit-log-margin--custom-type + :initialize 'magit-custom-initialize-reset + :set-after '(magit-log-margin) + :set (apply-partially #'magit-margin-set-variable 'magit-reflog-mode)) + +;;; Faces + +(defface magit-reflog-commit '((t :foreground "green")) + "Face for commit commands in reflogs." + :group 'magit-faces) + +(defface magit-reflog-amend '((t :foreground "magenta")) + "Face for amend commands in reflogs." + :group 'magit-faces) + +(defface magit-reflog-merge '((t :foreground "green")) + "Face for merge, checkout and branch commands in reflogs." + :group 'magit-faces) + +(defface magit-reflog-checkout '((t :foreground "blue")) + "Face for checkout commands in reflogs." + :group 'magit-faces) + +(defface magit-reflog-reset '((t :foreground "red")) + "Face for reset commands in reflogs." + :group 'magit-faces) + +(defface magit-reflog-rebase '((t :foreground "magenta")) + "Face for rebase commands in reflogs." + :group 'magit-faces) + +(defface magit-reflog-cherry-pick '((t :foreground "green")) + "Face for cherry-pick commands in reflogs." + :group 'magit-faces) + +(defface magit-reflog-remote '((t :foreground "cyan")) + "Face for pull and clone commands in reflogs." + :group 'magit-faces) + +(defface magit-reflog-other '((t :foreground "cyan")) + "Face for other commands in reflogs." + :group 'magit-faces) + +;;; Commands + +;;;###autoload +(defun magit-reflog-current () + "Display the reflog of the current branch. +If `HEAD' is detached, then show the reflog for that instead." + (interactive) + (magit-reflog-setup-buffer (or (magit-get-current-branch) "HEAD"))) + +;;;###autoload +(defun magit-reflog-other (ref) + "Display the reflog of a branch or another ref." + (interactive (list (magit-read-local-branch-or-ref "Show reflog for"))) + (magit-reflog-setup-buffer ref)) + +;;;###autoload +(defun magit-reflog-head () + "Display the `HEAD' reflog." + (interactive) + (magit-reflog-setup-buffer "HEAD")) + +;;; Mode + +(defvar magit-reflog-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-log-mode-map) + (define-key map (kbd "C-c C-n") 'undefined) + (define-key map (kbd "L") 'magit-margin-settings) + map) + "Keymap for `magit-reflog-mode'.") + +(define-derived-mode magit-reflog-mode magit-mode "Magit Reflog" + "Mode for looking at Git reflog. + +This mode is documented in info node `(magit)Reflog'. + +\\\ +Type \\[magit-refresh] to refresh the current buffer. +Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \ +to visit the commit at point. + +Type \\[magit-cherry-pick] to apply the commit at point. +Type \\[magit-reset] to reset `HEAD' to the commit at point. + +\\{magit-reflog-mode-map}" + :group 'magit-log + (hack-dir-local-variables-non-file-buffer)) + +(defun magit-reflog-setup-buffer (ref) + (require 'magit) + (magit-setup-buffer #'magit-reflog-mode nil + (magit-buffer-refname ref) + (magit-buffer-log-args (list (format "-n%s" magit-reflog-limit))))) + +(defun magit-reflog-refresh-buffer () + (magit-set-header-line-format (concat "Reflog for " magit-buffer-refname)) + (magit-insert-section (reflogbuf) + (magit-git-wash (apply-partially 'magit-log-wash-log 'reflog) + "reflog" "show" "--format=%h%x00%aN%x00%gd%x00%gs" "--date=raw" + magit-buffer-log-args magit-buffer-refname "--"))) + +(cl-defmethod magit-buffer-value (&context (major-mode magit-reflog-mode)) + magit-buffer-refname) + +(defvar magit-reflog-labels + '(("commit" . magit-reflog-commit) + ("amend" . magit-reflog-amend) + ("merge" . magit-reflog-merge) + ("checkout" . magit-reflog-checkout) + ("branch" . magit-reflog-checkout) + ("reset" . magit-reflog-reset) + ("rebase" . magit-reflog-rebase) + ("cherry-pick" . magit-reflog-cherry-pick) + ("initial" . magit-reflog-commit) + ("pull" . magit-reflog-remote) + ("clone" . magit-reflog-remote) + ("autosave" . magit-reflog-commit) + ("restart" . magit-reflog-reset))) + +(defun magit-reflog-format-subject (subject) + (let* ((match (string-match magit-reflog-subject-re subject)) + (command (and match (match-string 1 subject))) + (option (and match (match-string 2 subject))) + (type (and match (match-string 3 subject))) + (label (if (string= command "commit") + (or type command) + command)) + (text (if (string= command "commit") + label + (mapconcat #'identity + (delq nil (list command option type)) + " ")))) + (format "%-16s " + (magit--propertize-face + text (or (cdr (assoc label magit-reflog-labels)) + 'magit-reflog-other))))) + +;;; _ +(provide 'magit-reflog) +;;; magit-reflog.el ends here diff --git a/elpa/magit-20220116.1908/magit-refs.el b/elpa/magit-20220116.1908/magit-refs.el new file mode 100644 index 00000000..0117e083 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-refs.el @@ -0,0 +1,762 @@ +;;; magit-refs.el --- listing references -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements support for listing references in a buffer. + +;;; Code: + +(require 'magit) + +;;; Options + +(defgroup magit-refs nil + "Inspect and manipulate Git branches and tags." + :link '(info-link "(magit)References Buffer") + :group 'magit-modes) + +(defcustom magit-refs-mode-hook nil + "Hook run after entering Magit-Refs mode." + :package-version '(magit . "2.1.0") + :group 'magit-refs + :type 'hook) + +(defcustom magit-refs-sections-hook + '(magit-insert-error-header + magit-insert-branch-description + magit-insert-local-branches + magit-insert-remote-branches + magit-insert-tags) + "Hook run to insert sections into a references buffer." + :package-version '(magit . "2.1.0") + :group 'magit-refs + :type 'hook) + +(defcustom magit-refs-show-commit-count nil + "Whether to show commit counts in Magit-Refs mode buffers. + +all Show counts for branches and tags. +branch Show counts for branches only. +nil Never show counts. + +To change the value in an existing buffer use the command +`magit-refs-set-show-commit-count'." + :package-version '(magit . "2.1.0") + :group 'magit-refs + :safe (lambda (val) (memq val '(all branch nil))) + :type '(choice (const all :tag "For branches and tags") + (const branch :tag "For branches only") + (const nil :tag "Never"))) +(put 'magit-refs-show-commit-count 'safe-local-variable 'symbolp) +(put 'magit-refs-show-commit-count 'permanent-local t) + +(defcustom magit-refs-pad-commit-counts nil + "Whether to pad all counts on all sides in `magit-refs-mode' buffers. + +If this is nil, then some commit counts are displayed right next +to one of the branches that appear next to the count, without any +space in between. This might look bad if the branch name faces +look too similar to `magit-dimmed'. + +If this is non-nil, then spaces are placed on both sides of all +commit counts." + :package-version '(magit . "2.12.0") + :group 'magit-refs + :type 'boolean) + +(defvar magit-refs-show-push-remote nil + "Whether to show the push-remotes of local branches. +Also show the commits that the local branch is ahead and behind +the push-target. Unfortunately there is a bug in Git that makes +this useless (the commits ahead and behind the upstream are +shown), so this isn't enabled yet.") + +(defcustom magit-refs-show-remote-prefix nil + "Whether to show the remote prefix in lists of remote branches. + +This is redundant because the name of the remote is already shown +in the heading preceding the list of its branches." + :package-version '(magit . "2.12.0") + :group 'magit-refs + :type 'boolean) + +(defcustom magit-refs-margin + (list nil + (nth 1 magit-log-margin) + 'magit-log-margin-width nil + (nth 4 magit-log-margin)) + "Format of the margin in `magit-refs-mode' buffers. + +The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). + +If INIT is non-nil, then the margin is shown initially. +STYLE controls how to format the author or committer date. + It can be one of `age' (to show the age of the commit), + `age-abbreviated' (to abbreviate the time unit to a character), + or a string (suitable for `format-time-string') to show the + actual date. Option `magit-log-margin-show-committer-date' + controls which date is being displayed. +WIDTH controls the width of the margin. This exists for forward + compatibility and currently the value should not be changed. +AUTHOR controls whether the name of the author is also shown by + default. +AUTHOR-WIDTH has to be an integer. When the name of the author + is shown, then this specifies how much space is used to do so." + :package-version '(magit . "2.9.0") + :group 'magit-refs + :group 'magit-margin + :safe (lambda (val) (memq val '(all branch nil))) + :type magit-log-margin--custom-type + :initialize 'magit-custom-initialize-reset + :set-after '(magit-log-margin) + :set (apply-partially #'magit-margin-set-variable 'magit-refs-mode)) + +(defcustom magit-refs-margin-for-tags nil + "Whether to show information about tags in the margin. + +This is disabled by default because it is slow if there are many +tags." + :package-version '(magit . "2.9.0") + :group 'magit-refs + :group 'magit-margin + :type 'boolean) + +(defcustom magit-refs-primary-column-width (cons 16 32) + "Width of the focus column in `magit-refs-mode' buffers. + +The primary column is the column that contains the name of the +branch that the current row is about. + +If this is an integer, then the column is that many columns wide. +Otherwise it has to be a cons-cell of two integers. The first +specifies the minimal width, the second the maximal width. In that +case the actual width is determined using the length of the names +of the shown local branches. (Remote branches and tags are not +taken into account when calculating to optimal width.)" + :package-version '(magit . "2.12.0") + :group 'magit-refs + :type '(choice (integer :tag "Constant wide") + (cons :tag "Wide constrains" + (integer :tag "Minimum") + (integer :tag "Maximum")))) + +(defcustom magit-refs-focus-column-width 5 + "Width of the focus column in `magit-refs-mode' buffers. + +The focus column is the first column, which marks one +branch (usually the current branch) as the focused branch using +\"*\" or \"@\". For each other reference, this column optionally +shows how many commits it is ahead of the focused branch and \"<\", or +if it isn't ahead then the commits it is behind and \">\", or if it +isn't behind either, then a \"=\". + +This column may also display only \"*\" or \"@\" for the focused +branch, in which case this option is ignored. Use \"L v\" to +change the verbosity of this column." + :package-version '(magit . "2.12.0") + :group 'magit-refs + :type 'integer) + +(defcustom magit-refs-filter-alist nil + "Alist controlling which refs are omitted from `magit-refs-mode' buffers. + +The purpose of this option is to forgo displaying certain refs +based on their name. If you want to not display any refs of a +certain type, then you should remove the appropriate function +from `magit-refs-sections-hook' instead. + +All keys are tried in order until one matches. Then its value +is used and subsequent elements are ignored. If the value is +non-nil, then the reference is displayed, otherwise it is not. +If no element matches, then the reference is displayed. + +A key can either be a regular expression that the refname has to +match, or a function that takes the refname as only argument and +returns a boolean. A remote branch such as \"origin/master\" is +displayed as just \"master\", however for this comparison the +former is used." + :package-version '(magit . "2.12.0") + :group 'magit-refs + :type '(alist :key-type (choice :tag "Key" regexp function) + :value-type (boolean :tag "Value" + :on "show (non-nil)" + :off "omit (nil)"))) + +(defcustom magit-visit-ref-behavior nil + "Control how `magit-visit-ref' behaves in `magit-refs-mode' buffers. + +By default `magit-visit-ref' behaves like `magit-show-commit', +in all buffers, including `magit-refs-mode' buffers. When the +type of the section at point is `commit' then \"RET\" is bound to +`magit-show-commit', and when the type is either `branch' or +`tag' then it is bound to `magit-visit-ref'. + +\"RET\" is one of Magit's most essential keys and at least by +default it should behave consistently across all of Magit, +especially because users quickly learn that it does something +very harmless; it shows more information about the thing at point +in another buffer. + +However \"RET\" used to behave differently in `magit-refs-mode' +buffers, doing surprising things, some of which cannot really be +described as \"visit this thing\". If you have grown accustomed +to such inconsistent, but to you useful, behavior, then you can +restore that by adding one or more of the below symbols to the +value of this option. But keep in mind that by doing so you +don't only introduce inconsistencies, you also lose some +functionality and might have to resort to `M-x magit-show-commit' +to get it back. + +`magit-visit-ref' looks for these symbols in the order in which +they are described here. If the presence of a symbol applies to +the current situation, then the symbols that follow do not affect +the outcome. + +`focus-on-ref' + + With a prefix argument update the buffer to show commit counts + and lists of cherry commits relative to the reference at point + instead of relative to the current buffer or `HEAD'. + + Instead of adding this symbol, consider pressing \"C-u y o RET\". + +`create-branch' + + If point is on a remote branch, then create a new local branch + with the same name, use the remote branch as its upstream, and + then check out the local branch. + + Instead of adding this symbol, consider pressing \"b c RET RET\", + like you would do in other buffers. + +`checkout-any' + + Check out the reference at point. If that reference is a tag + or a remote branch, then this results in a detached `HEAD'. + + Instead of adding this symbol, consider pressing \"b b RET\", + like you would do in other buffers. + +`checkout-branch' + + Check out the local branch at point. + + Instead of adding this symbol, consider pressing \"b b RET\", + like you would do in other buffers." + :package-version '(magit . "2.9.0") + :group 'magit-refs + :group 'magit-commands + :options '(focus-on-ref create-branch checkout-any checkout-branch) + :type '(list :convert-widget custom-hook-convert-widget)) + +;;; Mode + +(defvar magit-refs-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-mode-map) + (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'.") + +(define-derived-mode magit-refs-mode magit-mode "Magit Refs" + "Mode which lists and compares references. + +This mode is documented in info node `(magit)References Buffer'. + +\\\ +Type \\[magit-refresh] to refresh the current buffer. +Type \\[magit-section-toggle] to expand or hide the section at point. +Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \ +to visit the commit or branch at point. + +Type \\[magit-branch] to see available branch commands. +Type \\[magit-merge] to merge the branch or commit at point. +Type \\[magit-cherry-pick] to apply the commit at point. +Type \\[magit-reset] to reset `HEAD' to the commit at point. + +\\{magit-refs-mode-map}" + :group 'magit-refs + (hack-dir-local-variables-non-file-buffer) + (setq imenu-create-index-function + #'magit-imenu--refs-create-index-function)) + +(defun magit-refs-setup-buffer (ref args) + (magit-setup-buffer #'magit-refs-mode nil + (magit-buffer-upstream ref) + (magit-buffer-arguments args))) + +(defun magit-refs-refresh-buffer () + (setq magit-set-buffer-margin-refresh (not (magit-buffer-margin-p))) + (unless (magit-rev-verify magit-buffer-upstream) + (setq magit-refs-show-commit-count nil)) + (magit-set-header-line-format + (format "%s %s" magit-buffer-upstream + (mapconcat #'identity magit-buffer-arguments " "))) + (magit-insert-section (branchbuf) + (magit-run-section-hook 'magit-refs-sections-hook)) + (add-hook 'kill-buffer-hook 'magit-preserve-section-visibility-cache)) + +(cl-defmethod magit-buffer-value (&context (major-mode magit-refs-mode)) + (cons magit-buffer-upstream magit-buffer-arguments)) + +;;; Commands + +;;;###autoload (autoload 'magit-show-refs "magit-refs" nil t) +(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 to HEAD" "--merged") + ("-N" "Not merged" "--no-merged=" magit-transient-read-revision) + ("-n" "Not merged to HEAD" "--no-merged") + (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) + ("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 + (transient-setup 'magit-show-refs) + (magit-refs-setup-buffer "HEAD" (magit-show-refs-arguments)))) + +(defun magit-show-refs-arguments (&optional use-buffer-args) + (unless use-buffer-args + (setq use-buffer-args magit-direct-use-buffer-arguments)) + (let (args) + (cond + ((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)) + ((and (memq use-buffer-args '(always selected)) + (when-let ((buffer (magit-get-mode-buffer + 'magit-refs-mode nil + (eq use-buffer-args 'selected)))) + (setq args (buffer-local-value 'magit-buffer-arguments buffer)) + t))) + (t + (setq args (alist-get 'magit-show-refs transient-values)))) + args)) + +(transient-define-argument magit-for-each-ref:--contains () + :description "Contains" + :class 'transient-option + :key "-c" + :argument "--contains=" + :reader 'magit-transient-read-revision) + +(transient-define-argument magit-for-each-ref:--sort () + :description "Sort" + :class 'transient-option + :key "-s" + :argument "--sort=" + :reader 'magit-read-ref-sort) + +(defun magit-read-ref-sort (prompt initial-input _history) + (magit-completing-read prompt + '("-committerdate" "-authordate" + "committerdate" "authordate") + nil nil initial-input)) + +;;;###autoload +(defun magit-show-refs-head (&optional args) + "List and compare references in a dedicated buffer. +Compared with `HEAD'." + (interactive (list (magit-show-refs-arguments))) + (magit-refs-setup-buffer "HEAD" args)) + +;;;###autoload +(defun magit-show-refs-current (&optional args) + "List and compare references in a dedicated buffer. +Compare with the current branch or `HEAD' if it is detached." + (interactive (list (magit-show-refs-arguments))) + (magit-refs-setup-buffer (magit-get-current-branch) args)) + +;;;###autoload +(defun magit-show-refs-other (&optional ref args) + "List and compare references in a dedicated buffer. +Compared with a branch read from the user." + (interactive (list (magit-read-other-branch "Compare with") + (magit-show-refs-arguments))) + (magit-refs-setup-buffer ref args)) + +(defun magit-refs-set-show-commit-count () + "Change for which refs the commit count is shown." + (interactive) + (setq-local magit-refs-show-commit-count + (magit-read-char-case "Show commit counts for " nil + (?a "[a]ll refs" 'all) + (?b "[b]ranches only" t) + (?n "[n]othing" nil))) + (magit-refresh)) + +(defun magit-visit-ref () + "Visit the reference or revision at point in another buffer. +If there is no revision at point or with a prefix argument prompt +for a revision. + +This command behaves just like `magit-show-commit', except if +point is on a reference in a `magit-refs-mode' buffer (a buffer +listing branches and tags), in which case the behavior may be +different, but only if you have customized the option +`magit-visit-ref-behavior' (which see)." + (interactive) + (if (and (derived-mode-p 'magit-refs-mode) + (magit-section-match '(branch tag))) + (let ((ref (oref (magit-current-section) value))) + (cond (current-prefix-arg + (cond ((memq 'focus-on-ref magit-visit-ref-behavior) + (magit-refs-setup-buffer ref (magit-show-refs-arguments))) + (magit-visit-ref-behavior + ;; Don't prompt for commit to visit. + (let ((current-prefix-arg nil)) + (call-interactively #'magit-show-commit))))) + ((and (memq 'create-branch magit-visit-ref-behavior) + (magit-section-match [branch remote])) + (let ((branch (cdr (magit-split-branch-name ref)))) + (if (magit-branch-p branch) + (if (magit-rev-eq branch ref) + (magit-call-git "checkout" branch) + (setq branch (propertize branch 'face 'magit-branch-local)) + (setq ref (propertize ref 'face 'magit-branch-remote)) + (pcase (prog1 (read-char-choice (format (propertize "\ +Branch %s already exists. + [c]heckout %s as-is + [r]reset %s to %s and checkout %s + [a]bort " 'face 'minibuffer-prompt) branch branch branch ref branch) + '(?c ?r ?a)) + (message "")) ; otherwise prompt sticks + (?c (magit-call-git "checkout" branch)) + (?r (magit-call-git "checkout" "-B" branch ref)) + (?a (user-error "Abort")))) + (magit-call-git "checkout" "-b" branch ref)) + (setq magit-buffer-upstream branch) + (magit-refresh))) + ((or (memq 'checkout-any magit-visit-ref-behavior) + (and (memq 'checkout-branch magit-visit-ref-behavior) + (magit-section-match [branch local]))) + (magit-call-git "checkout" ref) + (setq magit-buffer-upstream ref) + (magit-refresh)) + (t + (call-interactively #'magit-show-commit)))) + (call-interactively #'magit-show-commit))) + +;;; Sections + +(defvar magit-remote-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-delete-thing] 'magit-remote-remove) + (define-key map "R" 'magit-remote-rename) + map) + "Keymap for `remote' sections.") + +(defvar magit-branch-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] 'magit-visit-ref) + (define-key map [remap magit-delete-thing] 'magit-branch-delete) + (define-key map "R" 'magit-branch-rename) + map) + "Keymap for `branch' sections.") + +(defvar magit-tag-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] 'magit-visit-ref) + (define-key map [remap magit-delete-thing] 'magit-tag-delete) + map) + "Keymap for `tag' sections.") + +(defun magit-insert-branch-description () + "Insert header containing the description of the current branch. +Insert a header line with the name and description of the +current branch. The description is taken from the Git variable +`branch..description'; if that is undefined then no header +line is inserted at all." + (when-let ((branch (magit-get-current-branch)) + (desc (magit-get "branch" branch "description")) + (desc (split-string desc "\n"))) + (when (equal (car (last desc)) "") + (setq desc (butlast desc))) + (magit-insert-section (branchdesc branch t) + (magit-insert-heading branch ": " (car desc)) + (when (cdr desc) + (insert (mapconcat 'identity (cdr desc) "\n")) + (insert "\n\n"))))) + +(defun magit-insert-tags () + "Insert sections showing all tags." + (when-let ((tags (magit-git-lines "tag" "--list" "-n" magit-buffer-arguments))) + (let ((_head (magit-rev-parse "HEAD"))) + (magit-insert-section (tags) + (magit-insert-heading "Tags:") + (dolist (tag tags) + (string-match "^\\([^ \t]+\\)[ \t]+\\([^ \t\n].*\\)?" tag) + (let ((tag (match-string 1 tag)) + (msg (match-string 2 tag))) + (when (magit-refs--insert-refname-p tag) + (magit-insert-section (tag tag t) + (magit-insert-heading + (magit-refs--format-focus-column tag 'tag) + (propertize tag 'font-lock-face 'magit-tag) + (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)) + (magit-refs--insert-cherry-commits tag))))) + (insert ?\n) + (magit-make-margin-overlay nil t))))) + +(defun magit-insert-remote-branches () + "Insert sections showing all remote-tracking branches." + (dolist (remote (magit-list-remotes)) + (magit-insert-section (remote remote) + (magit-insert-heading + (let ((pull (magit-get "remote" remote "url")) + (push (magit-get "remote" remote "pushurl"))) + (format (propertize "Remote %s (%s):" + 'font-lock-face 'magit-section-heading) + (propertize remote 'font-lock-face 'magit-branch-remote) + (concat pull (and pull push ", ") push)))) + (let (head) + (dolist (line (magit-git-lines "for-each-ref" "--format=\ +%(symref:short)%00%(refname:short)%00%(refname)%00%(subject)" + (concat "refs/remotes/" remote) + magit-buffer-arguments)) + (pcase-let ((`(,head-branch ,branch ,ref ,msg) + (-replace "" nil (split-string line "\0")))) + (if head-branch + (progn (cl-assert (equal branch (concat remote "/HEAD"))) + (setq head head-branch)) + (when (magit-refs--insert-refname-p branch) + (magit-insert-section (branch branch t) + (let ((headp (equal branch head)) + (abbrev (if magit-refs-show-remote-prefix + branch + (substring branch (1+ (length remote)))))) + (magit-insert-heading + (magit-refs--format-focus-column branch) + (magit-refs--propertize-branch + abbrev ref (and headp 'magit-branch-remote-head)) + (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)) + (magit-refs--insert-cherry-commits branch))))))) + (insert ?\n) + (magit-make-margin-overlay nil t)))) + +(defun magit-insert-local-branches () + "Insert sections showing all local branches." + (magit-insert-section (local nil) + (magit-insert-heading "Branches:") + (dolist (line (magit-refs--format-local-branches)) + (pcase-let ((`(,branch . ,strings) line)) + (magit-insert-section + ((eval (if branch 'branch 'commit)) + (or branch (magit-rev-parse "HEAD")) + t) + (apply #'magit-insert-heading strings) + (when (magit-buffer-margin-p) + (magit-refs--format-margin branch)) + (magit-refs--insert-cherry-commits branch)))) + (insert ?\n) + (magit-make-margin-overlay nil t))) + +(defun magit-refs--format-local-branches () + (let ((lines (-keep 'magit-refs--format-local-branch + (magit-git-lines + "for-each-ref" + (concat "--format=\ +%(HEAD)%00%(refname:short)%00%(refname)%00\ +%(upstream:short)%00%(upstream)%00%(upstream:track)%00" + (if magit-refs-show-push-remote "\ +%(push:remotename)%00%(push)%00%(push:track)%00%(subject)" + "%00%00%00%(subject)")) + "refs/heads" + magit-buffer-arguments)))) + (unless (magit-get-current-branch) + (push (magit-refs--format-local-branch + (concat "*\0\0\0\0\0\0\0\0" (magit-rev-format "%s"))) + lines)) + (setq-local magit-refs-primary-column-width + (let ((def (default-value 'magit-refs-primary-column-width))) + (if (atom def) + def + (pcase-let ((`(,min . ,max) def)) + (min max (apply #'max min (mapcar #'car lines))))))) + (mapcar (pcase-lambda (`(,_ ,branch ,focus ,branch-desc ,u:ahead ,p:ahead + ,u:behind ,upstream ,p:behind ,push ,msg)) + (list branch focus branch-desc u:ahead p:ahead + (make-string (max 1 (- magit-refs-primary-column-width + (length (concat branch-desc + u:ahead + p:ahead + u:behind)))) + ?\s) + u:behind upstream p:behind push + msg)) + lines))) + +(defun magit-refs--format-local-branch (line) + (pcase-let ((`(,head ,branch ,ref ,upstream ,u:ref ,u:track + ,push ,p:ref ,p:track ,msg) + (-replace "" nil (split-string line "\0")))) + (when (or (not branch) + (magit-refs--insert-refname-p branch)) + (let* ((headp (equal head "*")) + (pushp (and push + magit-refs-show-push-remote + (magit-rev-verify p:ref) + (not (equal p:ref u:ref)))) + (branch-desc + (if branch + (magit-refs--propertize-branch + branch ref (and headp 'magit-branch-current)) + (magit--propertize-face "(detached)" 'magit-branch-warning))) + (u:ahead (and u:track + (string-match "ahead \\([0-9]+\\)" u:track) + (magit--propertize-face + (concat (and magit-refs-pad-commit-counts " ") + (match-string 1 u:track) + ">") + 'magit-dimmed))) + (u:behind (and u:track + (string-match "behind \\([0-9]+\\)" u:track) + (magit--propertize-face + (concat "<" + (match-string 1 u:track) + (and magit-refs-pad-commit-counts " ")) + 'magit-dimmed))) + (p:ahead (and pushp p:track + (string-match "ahead \\([0-9]+\\)" p:track) + (magit--propertize-face + (concat (match-string 1 p:track) + ">" + (and magit-refs-pad-commit-counts " ")) + 'magit-branch-remote))) + (p:behind (and pushp p:track + (string-match "behind \\([0-9]+\\)" p:track) + (magit--propertize-face + (concat "<" + (match-string 1 p:track) + (and magit-refs-pad-commit-counts " ")) + 'magit-dimmed)))) + (list (1+ (length (concat branch-desc u:ahead p:ahead u:behind))) + branch + (magit-refs--format-focus-column branch headp) + branch-desc u:ahead p:ahead u:behind + (and upstream + (concat (if (equal u:track "[gone]") + (magit--propertize-face upstream 'error) + (magit-refs--propertize-branch upstream u:ref)) + " ")) + (and pushp + (concat p:behind + (magit--propertize-face + push 'magit-branch-remote) + " ")) + (and msg (magit-log-propertize-keywords nil msg))))))) + +(defun magit-refs--format-focus-column (ref &optional type) + (let ((focus magit-buffer-upstream) + (width (if magit-refs-show-commit-count + magit-refs-focus-column-width + 1))) + (format + (format "%%%ss " width) + (cond ((or (equal ref focus) + (and (eq type t) + (equal focus "HEAD"))) + (magit--propertize-face (concat (if (equal focus "HEAD") "@" "*") + (make-string (1- width) ?\s)) + 'magit-section-heading)) + ((if (eq type 'tag) + (eq magit-refs-show-commit-count 'all) + magit-refs-show-commit-count) + (pcase-let ((`(,behind ,ahead) + (magit-rev-diff-count magit-buffer-upstream ref))) + (magit--propertize-face + (cond ((> ahead 0) (concat "<" (number-to-string ahead))) + ((> behind 0) (concat (number-to-string behind) ">")) + (t "=")) + 'magit-dimmed))) + (t ""))))) + +(defun magit-refs--propertize-branch (branch ref &optional head-face) + (let ((face (cdr (cl-find-if (pcase-lambda (`(,re . ,_)) + (string-match-p re ref)) + magit-ref-namespaces)))) + (magit--propertize-face + branch (if head-face (list face head-face) face)))) + +(defun magit-refs--insert-refname-p (refname) + (--if-let (-first (pcase-lambda (`(,key . ,_)) + (if (functionp key) + (funcall key refname) + (string-match-p key refname))) + magit-refs-filter-alist) + (cdr it) + t)) + +(defun magit-refs--insert-cherry-commits (ref) + (magit-insert-section-body + (let ((start (point)) + (magit-insert-section--current nil)) + (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry) + "cherry" "-v" (magit-abbrev-arg) magit-buffer-upstream ref) + (if (= (point) start) + (message "No cherries for %s" ref) + (magit-make-margin-overlay nil t))))) + +(defun magit-refs--format-margin (commit) + (save-excursion + (goto-char (line-beginning-position 0)) + (let ((line (magit-rev-format "%ct%cN" commit))) + (magit-log-format-margin commit + (substring line 10) + (substring line 0 10))))) + +;;; _ +(provide 'magit-refs) +;;; magit-refs.el ends here diff --git a/elpa/magit-20220116.1908/magit-remote.el b/elpa/magit-20220116.1908/magit-remote.el new file mode 100644 index 00000000..4be41fcf --- /dev/null +++ b/elpa/magit-20220116.1908/magit-remote.el @@ -0,0 +1,371 @@ +;;; magit-remote.el --- transfer Git commits -*- lexical-binding: t -*- + +;; Copyright (C) 2008-2022 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. + +;;; Commentary: + +;; This library implements remote commands. + +;;; Code: + +(require 'magit) + +;;; Options + +(defcustom magit-remote-add-set-remote.pushDefault 'ask-if-unset + "Whether to set the value of `remote.pushDefault' after adding a remote. + +If `ask', then always ask. If `ask-if-unset', then ask, but only +if the variable isn't set already. If nil, then don't ever set. +If the value is a string, then set without asking, provided that +the name of the added remote is equal to that string and the +variable isn't already set." + :package-version '(magit . "2.4.0") + :group 'magit-commands + :type '(choice (const :tag "ask if unset" ask-if-unset) + (const :tag "always ask" ask) + (string :tag "set if named") + (const :tag "don't set"))) + +(defcustom magit-remote-direct-configure t + "Whether the command `magit-remote' shows Git variables. +When set to nil, no variables are displayed by this transient +command, instead the sub-transient `magit-remote-configure' +has to be used to view and change remote related variables." + :package-version '(magit . "2.12.0") + :group 'magit-commands + :type 'boolean) + +(defcustom magit-prefer-push-default nil + "Whether to prefer `remote.pushDefault' over per-branch variables." + :package-version '(magit . "3.0.0") + :group 'magit-commands + :type 'boolean) + +;;; Commands + +;;;###autoload (autoload 'magit-remote "magit-remote" nil t) +(transient-define-prefix magit-remote (remote) + "Add, configure or remove a remote." + :man-page "git-remote" + :value '("-f") + ["Variables" + :if (lambda () + (and magit-remote-direct-configure + (oref transient--prefix scope))) + ("u" magit-remote..url) + ("U" magit-remote..fetch) + ("s" magit-remote..pushurl) + ("S" magit-remote..push) + ("O" magit-remote..tagopt)] + ["Arguments for add" + ("-f" "Fetch after add" "-f")] + ["Actions" + [("a" "Add" magit-remote-add) + ("r" "Rename" magit-remote-rename) + ("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) + (7 "z" "Unshallow remote" magit-remote-unshallow)]] + (interactive (list (magit-get-current-remote))) + (transient-setup 'magit-remote nil nil :scope remote)) + +(defun magit-read-url (prompt &optional initial-input) + (let ((url (magit-read-string-ns prompt initial-input))) + (if (string-prefix-p "~" url) + (expand-file-name url) + url))) + +;;;###autoload +(defun magit-remote-add (remote url &optional args) + "Add a remote named REMOTE and fetch it." + (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) + ((or `(ask ,_) `(ask-if-unset nil)) + (y-or-n-p (format "Set `remote.pushDefault' to \"%s\"? " remote)))) + (progn (magit-call-git "remote" "add" args remote url) + (setf (magit-get "remote.pushDefault") remote) + (magit-refresh)) + (magit-run-git-async "remote" "add" args remote url))) + +;;;###autoload +(defun magit-remote-rename (old new) + "Rename the remote named OLD to NEW." + (interactive + (let ((remote (magit-read-remote "Rename remote"))) + (list remote (magit-read-string-ns (format "Rename %s to" remote))))) + (unless (string= old new) + (magit-call-git "remote" "rename" old new) + (magit-remote--cleanup-push-variables old new) + (magit-refresh))) + +;;;###autoload +(defun magit-remote-remove (remote) + "Delete the remote named REMOTE." + (interactive (list (magit-read-remote "Delete remote"))) + (magit-call-git "remote" "rm" remote) + (magit-remote--cleanup-push-variables remote) + (magit-refresh)) + +(defun magit-remote--cleanup-push-variables (remote &optional new-name) + (magit-with-toplevel + (when (equal (magit-get "remote.pushDefault") remote) + (magit-set new-name "remote.pushDefault")) + (dolist (var (magit-git-lines "config" "--name-only" + "--get-regexp" "^branch\.[^.]*\.pushRemote" + (format "^%s$" remote))) + (magit-call-git "config" (and (not new-name) "--unset") var new-name)))) + +(defconst magit--refspec-re "\\`\\(\\+\\)?\\([^:]+\\):\\(.*\\)\\'") + +;;;###autoload +(defun magit-remote-prune (remote) + "Remove stale remote-tracking branches for REMOTE." + (interactive (list (magit-read-remote "Prune stale branches of remote"))) + (magit-run-git-async "remote" "prune" remote)) + +;;;###autoload +(defun magit-remote-prune-refspecs (remote) + "Remove stale refspecs for REMOTE. + +A refspec is stale if there no longer exists at least one branch +on the remote that would be fetched due to that refspec. A stale +refspec is problematic because its existence causes Git to refuse +to fetch according to the remaining non-stale refspecs. + +If only stale refspecs remain, then offer to either delete the +remote or to replace the stale refspecs with the default refspec. + +Also remove the remote-tracking branches that were created due to +the now stale refspecs. Other stale branches are not removed." + (interactive (list (magit-read-remote "Prune refspecs of remote"))) + (let* ((tracking-refs (magit-list-remote-branches remote)) + (remote-refs (magit-remote-list-refs remote)) + (variable (format "remote.%s.fetch" remote)) + (refspecs (magit-get-all variable)) + stale) + (dolist (refspec refspecs) + (when (string-match magit--refspec-re refspec) + (let ((theirs (match-string 2 refspec)) + (ours (match-string 3 refspec))) + (unless (if (string-match "\\*" theirs) + (let ((re (replace-match ".*" t t theirs))) + (--some (string-match-p re it) remote-refs)) + (member theirs remote-refs)) + (push (cons refspec + (if (string-match "\\*" ours) + (let ((re (replace-match ".*" t t ours))) + (--filter (string-match-p re it) tracking-refs)) + (list (car (member ours tracking-refs))))) + stale))))) + (if (not stale) + (message "No stale refspecs for remote %S" remote) + (if (= (length stale) + (length refspecs)) + (magit-read-char-case + (format "All of %s's refspecs are stale. " remote) nil + (?s "replace with [d]efault refspec" + (magit-set-all + (list (format "+refs/heads/*:refs/remotes/%s/*" remote)) + variable)) + (?r "[r]emove remote" + (magit-call-git "remote" "rm" remote)) + (?a "or [a]abort" + (user-error "Abort"))) + (if (if (= (length stale) 1) + (pcase-let ((`(,refspec . ,refs) (car stale))) + (magit-confirm 'prune-stale-refspecs + (format "Prune stale refspec %s and branch %%s" refspec) + (format "Prune stale refspec %s and %%i branches" refspec) + nil refs)) + (magit-confirm 'prune-stale-refspecs nil + (format "Prune %%i stale refspecs and %i branches" + (length (cl-mapcan (lambda (s) (copy-sequence (cdr s))) + stale))) + nil + (mapcar (pcase-lambda (`(,refspec . ,refs)) + (concat refspec "\n" + (mapconcat (lambda (b) (concat " " b)) + refs "\n"))) + stale))) + (pcase-dolist (`(,refspec . ,refs) stale) + (magit-call-git "config" "--unset" variable + (regexp-quote refspec)) + (magit--log-action + (lambda (refs) + (format "Deleting %i branches" (length refs))) + (lambda (ref) + (format "Deleting branch %s (was %s)" ref + (magit-rev-parse "--short" ref))) + refs) + (dolist (ref refs) + (magit-call-git "update-ref" "-d" ref))) + (user-error "Abort"))) + (magit-refresh)))) + +;;;###autoload +(defun magit-remote-set-head (remote &optional branch) + "Set the local representation of REMOTE's default branch. +Query REMOTE and set the symbolic-ref refs/remotes//HEAD +accordingly. With a prefix argument query for the branch to be +used, which allows you to select an incorrect value if you fancy +doing that." + (interactive + (let ((remote (magit-read-remote "Set HEAD for remote"))) + (list remote + (and current-prefix-arg + (magit-read-remote-branch (format "Set %s/HEAD to" remote) + remote nil nil t))))) + (magit-run-git "remote" "set-head" remote (or branch "--auto"))) + +;;;###autoload +(defun magit-remote-unset-head (remote) + "Unset the local representation of REMOTE's default branch. +Delete the symbolic-ref \"refs/remotes//HEAD\"." + (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) +(transient-define-prefix magit-remote-configure (remote) + "Configure a remote." + :man-page "git-remote" + [:description + (lambda () + (concat + (propertize "Configure " 'face 'transient-heading) + (propertize (oref transient--prefix scope) 'face 'magit-branch-remote))) + ("u" magit-remote..url) + ("U" magit-remote..fetch) + ("s" magit-remote..pushurl) + ("S" magit-remote..push) + ("O" magit-remote..tagopt)] + (interactive + (list (or (and (not current-prefix-arg) + (not (and magit-remote-direct-configure + (eq transient-current-command 'magit-remote))) + (magit-get-current-remote)) + (magit--read-remote-scope)))) + (transient-setup 'magit-remote-configure nil nil :scope remote)) + +(defun magit--read-remote-scope (&optional obj) + (magit-read-remote + (if obj + (format "Set %s for remote" + (format (oref obj variable) "")) + "Configure remote"))) + +(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) + +(transient-define-infix magit-remote..fetch () + :class 'magit--git-variable + :scope 'magit--read-remote-scope + :variable "remote.%s.fetch" + :multi-value t) + +(transient-define-infix magit-remote..pushurl () + :class 'magit--git-variable:urls + :scope 'magit--read-remote-scope + :variable "remote.%s.pushurl" + :multi-value t + :history-key 'magit-remote..*url + :seturl-arg "--push") + +(transient-define-infix magit-remote..push () + :class 'magit--git-variable + :scope 'magit--read-remote-scope + :variable "remote.%s.push") + +(transient-define-infix magit-remote..tagopt () + :class 'magit--git-variable:choices + :scope 'magit--read-remote-scope + :variable "remote.%s.tagOpt" + :choices '("--no-tags" "--tags")) + +;;; Transfer Utilities + +(defun magit--push-remote-variable (&optional branch short) + (unless branch + (setq branch (magit-get-current-branch))) + (magit--propertize-face + (if (or (not branch) magit-prefer-push-default) + (if short "pushDefault" "remote.pushDefault") + (if short "pushRemote" (format "branch.%s.pushRemote" branch))) + 'bold)) + +(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)) + (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 changed))) + +;;; _ +(provide 'magit-remote) +;;; magit-remote.el ends here diff --git a/elpa/magit-20220116.1908/magit-repos.el b/elpa/magit-20220116.1908/magit-repos.el new file mode 100644 index 00000000..123c2edb --- /dev/null +++ b/elpa/magit-20220116.1908/magit-repos.el @@ -0,0 +1,389 @@ +;;; magit-repos.el --- listing repositories -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements support for listing repositories. This +;; includes getting a Lisp list of known repositories as well as a +;; mode for listing repositories in a buffer. + +;;; Code: + +(require 'magit-core) + +(declare-function magit-status-setup-buffer "magit-status" (&optional directory)) + +(defvar x-stretch-cursor) + +;;; Options + +(defcustom magit-repository-directories nil + "List of directories that are or contain Git repositories. + +Each element has the form (DIRECTORY . DEPTH). DIRECTORY has +to be a directory or a directory file-name, a string. DEPTH, +an integer, specifies the maximum depth to look for Git +repositories. If it is 0, then only add DIRECTORY itself. + +This option controls which repositories are being listed by +`magit-list-repositories'. It also affects `magit-status' +\(which see) in potentially surprising ways." + :package-version '(magit . "3.0.0") + :group 'magit-essentials + :type '(repeat (cons directory (integer :tag "Depth")))) + +(defgroup magit-repolist nil + "List repositories in a buffer." + :link '(info-link "(magit)Repository List") + :group 'magit-modes) + +(defcustom magit-repolist-mode-hook '(hl-line-mode) + "Hook run after entering Magit-Repolist mode." + :package-version '(magit . "2.9.0") + :group 'magit-repolist + :type 'hook + :get 'magit-hook-custom-get + :options '(hl-line-mode)) + +(defcustom magit-repolist-columns + '(("Name" 25 magit-repolist-column-ident nil) + ("Version" 25 magit-repolist-column-version nil) + ("BU" 3 magit-repolist-column-unpushed-to-upstream + ((:right-align t) + (:help-echo "Local changes not in upstream"))) + ("Path" 99 magit-repolist-column-path nil)) + "List of columns displayed by `magit-list-repositories'. + +Each element has the form (HEADER WIDTH FORMAT PROPS). + +HEADER is the string displayed in the header. WIDTH is the width +of the column. FORMAT is a function that is called with one +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'. +Some entries also use `:help-echo', but `tabulated-list' does not +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" + (string :tag "Header Label") + (integer :tag "Column Width") + (function :tag "Inserter Function") + (repeat :tag "Properties" + (list (choice :tag "Property" + (const :right-align) + (const :pad-right) + (symbol)) + (sexp :tag "Value")))))) + +(defcustom magit-repolist-column-flag-alist + '((magit-untracked-files . "N") + (magit-unstaged-files . "U") + (magit-staged-files . "S")) + "Association list of predicates and flags for `magit-repolist-column-flag'. + +Each element is of the form (FUNCTION . FLAG). Each FUNCTION is +called with no arguments, with `default-directory' bound to the +top level of a repository working tree, until one of them returns +a non-nil value. FLAG corresponding to that function is returned +as the value of `magit-repolist-column-flag'." + :package-version '(magit . "3.0.0") + :group 'magit-repolist + :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 +(defun magit-list-repositories () + "Display a list of repositories. + +Use the options `magit-repository-directories' to control which +repositories are displayed." + (interactive) + (magit-repolist-setup (default-value 'magit-repolist-columns))) + +;;;; Mode + +(defvar magit-repolist-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map tabulated-list-mode-map) + (define-key map (kbd "C-m") 'magit-repolist-status) + map) + "Local keymap for Magit-Repolist mode buffers.") + +(defun magit-repolist-status (&optional _button) + "Show the status for the repository at point." + (interactive) + (--if-let (tabulated-list-get-id) + (magit-status-setup-buffer (expand-file-name it)) + (user-error "There is no repository at point"))) + +(define-derived-mode magit-repolist-mode tabulated-list-mode "Repos" + "Major mode for browsing a list of Git repositories." + (setq-local x-stretch-cursor nil) + (setq tabulated-list-padding 0) + (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 + (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))))) + (message "Listing repositories...") + (tabulated-list-init-header) + (tabulated-list-print t) + (message "Listing repositories...done")) + +;;;; Columns + +(defun magit-repolist-column-ident (spec) + "Insert the identification of the repository. +Usually this is just its basename." + (cadr (assq :id spec))) + +(defun magit-repolist-column-path (_) + "Insert the absolute path of the repository." + (abbreviate-file-name default-directory)) + +(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. + (magit-git-string "show" "--no-patch" "--format=%cd-g%h" + "--date=format:%Y%m%d.%H%M")))) + (save-match-data + (when (string-match + "\\(?:-\\([0-9]*\\)-g[a-z0-9]*\\)?\\(?:-\\(dirty\\)\\)?\\'" v) + (magit--put-face (match-beginning 0) (match-end 0) 'shadow v) + (when (match-end 1) + (magit--put-face (match-beginning 1) (match-end 1) 'bold v)) + (when (match-end 2) + (magit--put-face (match-beginning 2) (match-end 2) 'error v))) + (if (and v (string-match "\\`[0-9]" v)) + (concat " " v) + (when (and v (string-match "\\`[^0-9]+" v)) + (magit--put-face 0 (match-end 0) 'shadow v)) + v)))) + +(defun magit-repolist-column-branch (_) + "Insert the current branch." + (let ((branch (magit-get-current-branch))) + (if (member branch magit-main-branch-names) + (magit--propertize-face branch 'shadow) + branch))) + +(defun magit-repolist-column-upstream (_) + "Insert the upstream branch of the current branch." + (magit-get-upstream-branch)) + +(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. +- N if there is at least one untracked file. +- 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." + (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 (spec) + "Insert number of upstream commits not in the current branch." + (--when-let (magit-get-upstream-branch) + (magit-repolist-insert-count (cadr (magit-rev-diff-count "HEAD" it)) spec))) + +(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) + (magit-repolist-insert-count (cadr (magit-rev-diff-count "HEAD" it)) spec))) + +(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) + (magit-repolist-insert-count (car (magit-rev-diff-count "HEAD" it)) spec))) + +(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) + (magit-repolist-insert-count (car (magit-rev-diff-count "HEAD" it)) spec))) + +(defun magit-repolist-column-branches (spec) + "Insert number of branches." + (magit-repolist-insert-count (length (magit-list-local-branches)) + `((:normal-count 1) ,@spec))) + +(defun magit-repolist-column-stashes (spec) + "Insert number of stashes." + (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 + +(defun magit-read-repository (&optional read-directory-name) + "Read a Git repository in the minibuffer, with completion. + +The completion choices are the basenames of top-levels of +repositories found in the directories specified by option +`magit-repository-directories'. In case of name conflicts +the basenames are prefixed with the name of the respective +parent directories. The returned value is the actual path +to the selected repository. + +If READ-DIRECTORY-NAME is non-nil or no repositories can be +found based on the value of `magit-repository-directories', +then read an arbitrary directory using `read-directory-name' +instead." + (if-let ((repos (and (not read-directory-name) + magit-repository-directories + (magit-repos-alist)))) + (let ((reply (magit-completing-read "Git repository" repos))) + (file-name-as-directory + (or (cdr (assoc reply repos)) + (if (file-directory-p reply) + (expand-file-name reply) + (user-error "Not a repository or a directory: %s" reply))))) + (file-name-as-directory + (read-directory-name "Git repository: " + (or (magit-toplevel) default-directory))))) + +(defun magit-list-repos () + (cl-mapcan (pcase-lambda (`(,dir . ,depth)) + (magit-list-repos-1 dir depth)) + magit-repository-directories)) + +(defun magit-list-repos-1 (directory depth) + (cond ((file-readable-p (expand-file-name ".git" directory)) + (list (file-name-as-directory directory))) + ((and (> depth 0) (magit-file-accessible-directory-p directory)) + (--mapcat (and (file-directory-p it) + (magit-list-repos-1 it (1- depth))) + (directory-files directory t + directory-files-no-dot-files-regexp t))))) + +(defun magit-list-repos-uniquify (alist) + (let (result (dict (make-hash-table :test 'equal))) + (dolist (a (delete-dups alist)) + (puthash (car a) (cons (cdr a) (gethash (car a) dict)) dict)) + (maphash + (lambda (key value) + (if (= (length value) 1) + (push (cons key (car value)) result) + (setq result + (append result + (magit-list-repos-uniquify + (--map (cons (concat + key "\\" + (file-name-nondirectory + (directory-file-name + (substring it 0 (- (1+ (length key))))))) + it) + value)))))) + dict) + result)) + +(defun magit-repos-alist () + (magit-list-repos-uniquify + (--map (cons (file-name-nondirectory (directory-file-name it)) it) + (magit-list-repos)))) + +;;; _ +(provide 'magit-repos) +;;; magit-repos.el ends here diff --git a/elpa/magit-20220116.1908/magit-reset.el b/elpa/magit-20220116.1908/magit-reset.el new file mode 100644 index 00000000..6203a69e --- /dev/null +++ b/elpa/magit-20220116.1908/magit-reset.el @@ -0,0 +1,137 @@ +;;; magit-reset.el --- reset fuctionality -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements reset commands. + +;;; Code: + +(require 'magit) + +;;;###autoload (autoload 'magit-reset "magit" nil t) +(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) + "" + ("f" "a file" magit-file-checkout)]) + +;;;###autoload +(defun magit-reset-mixed (commit) + "Reset the `HEAD' and index to COMMIT, but not the working tree. +\n(git reset --mixed COMMIT)" + (interactive (list (magit-reset-read-branch-or-commit "Reset %s to"))) + (magit-reset-internal "--mixed" commit)) + +;;;###autoload +(defun magit-reset-soft (commit) + "Reset the `HEAD' to COMMIT, but not the index and working tree. +\n(git reset --soft REVISION)" + (interactive (list (magit-reset-read-branch-or-commit "Soft reset %s to"))) + (magit-reset-internal "--soft" commit)) + +;;;###autoload +(defun magit-reset-hard (commit) + "Reset the `HEAD', index, and working tree to COMMIT. +\n(git reset --hard REVISION)" + (interactive (list (magit-reset-read-branch-or-commit + (concat (magit--propertize-face "Hard" 'bold) + " reset %s to")))) + (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 +head this effectively unstages all changes. +\n(git reset COMMIT .)" + (interactive (list (magit-read-branch-or-commit "Reset index to"))) + (magit-reset-internal nil commit ".")) + +;;;###autoload +(defun magit-reset-worktree (commit) + "Reset the worktree to COMMIT. +Keep the `HEAD' and index as-is." + (interactive (list (magit-read-branch-or-commit "Reset worktree to"))) + (magit-wip-commit-before-change nil " before reset") + (magit-with-temp-index commit nil + (magit-call-git "checkout-index" "--all" "--force")) + (magit-wip-commit-after-apply nil " after reset") + (magit-refresh)) + +;;;###autoload +(defun magit-reset-quickly (commit &optional hard) + "Reset the `HEAD' and index to COMMIT, and possibly the working tree. +With a prefix argument reset the working tree otherwise don't. +\n(git reset --mixed|--hard COMMIT)" + (interactive (list (magit-reset-read-branch-or-commit + (if current-prefix-arg + (concat (magit--propertize-face "Hard" 'bold) + " reset %s to") + "Reset %s to")) + current-prefix-arg)) + (magit-reset-internal (if hard "--hard" "--mixed") commit)) + +(defun magit-reset-read-branch-or-commit (prompt) + "Prompt for and return a ref to reset HEAD to. + +PROMPT is a format string, where either the current branch name +or \"detached head\" will be substituted for %s." + (magit-read-branch-or-commit + (format prompt (or (magit-get-current-branch) "detached head")))) + +(defun magit-reset-internal (arg commit &optional path) + (when (and (not (member arg '("--hard" nil))) + (equal (magit-rev-parse commit) + (magit-rev-parse "HEAD~"))) + (with-temp-buffer + (magit-git-insert "show" "-s" "--format=%B" "HEAD") + (when git-commit-major-mode + (funcall git-commit-major-mode)) + (git-commit-setup-font-lock) + (git-commit-save-message))) + (let ((cmd (if (and (equal commit "HEAD") (not arg)) "unstage" "reset"))) + (magit-wip-commit-before-change nil (concat " before " cmd)) + (magit-run-git "reset" arg commit "--" path) + (when (equal cmd "unstage") + (magit-wip-commit-after-apply nil " after unstage")))) + +;;; _ +(provide 'magit-reset) +;;; magit-reset.el ends here diff --git a/elpa/magit-20220116.1908/magit-sequence.el b/elpa/magit-20220116.1908/magit-sequence.el new file mode 100644 index 00000000..ab6c4b17 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-sequence.el @@ -0,0 +1,1074 @@ +;;; magit-sequence.el --- history manipulation in Magit -*- lexical-binding: t -*- + +;; Copyright (C) 2011-2022 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. + +;;; Commentary: + +;; Support for Git commands that replay commits and help the user make +;; changes along the way. Supports `cherry-pick', `revert', `rebase', +;; `rebase--interactive' and `am'. + +;;; Code: + +(require 'magit) + +;; For `magit-rebase--todo'. +(declare-function git-rebase-current-line "git-rebase" ()) +(eval-when-compile + (cl-pushnew 'action-type eieio--known-slot-names) + (cl-pushnew 'action eieio--known-slot-names) + (cl-pushnew 'action-options eieio--known-slot-names) + (cl-pushnew 'target eieio--known-slot-names)) + +;;; Options +;;;; Faces + +(defface magit-sequence-pick + '((t :inherit default)) + "Face used in sequence sections." + :group 'magit-faces) + +(defface magit-sequence-stop + '((((class color) (background light)) :foreground "DarkOliveGreen4") + (((class color) (background dark)) :foreground "DarkSeaGreen2")) + "Face used in sequence sections." + :group 'magit-faces) + +(defface magit-sequence-part + '((((class color) (background light)) :foreground "Goldenrod4") + (((class color) (background dark)) :foreground "LightGoldenrod2")) + "Face used in sequence sections." + :group 'magit-faces) + +(defface magit-sequence-head + '((((class color) (background light)) :foreground "SkyBlue4") + (((class color) (background dark)) :foreground "LightSkyBlue1")) + "Face used in sequence sections." + :group 'magit-faces) + +(defface magit-sequence-drop + '((((class color) (background light)) :foreground "IndianRed") + (((class color) (background dark)) :foreground "IndianRed")) + "Face used in sequence sections." + :group 'magit-faces) + +(defface magit-sequence-done + '((t :inherit magit-hash)) + "Face used in sequence sections." + :group 'magit-faces) + +(defface magit-sequence-onto + '((t :inherit magit-sequence-done)) + "Face used in sequence sections." + :group 'magit-faces) + +(defface magit-sequence-exec + '((t :inherit magit-hash)) + "Face used in sequence sections." + :group 'magit-faces) + +;;; Common + +;;;###autoload +(defun magit-sequencer-continue () + "Resume the current cherry-pick or revert sequence." + (interactive) + (if (magit-sequencer-in-progress-p) + (if (magit-anything-unstaged-p t) + (user-error "Cannot continue due to unstaged changes") + (magit-run-git-sequencer + (if (magit-revert-in-progress-p) "revert" "cherry-pick") "--continue")) + (user-error "No cherry-pick or revert in progress"))) + +;;;###autoload +(defun magit-sequencer-skip () + "Skip the stopped at commit during a cherry-pick or revert sequence." + (interactive) + (if (magit-sequencer-in-progress-p) + (progn (magit-call-git "reset" "--hard") + (magit-sequencer-continue)) + (user-error "No cherry-pick or revert in progress"))) + +;;;###autoload +(defun magit-sequencer-abort () + "Abort the current cherry-pick or revert sequence. +This discards all changes made since the sequence started." + (interactive) + (if (magit-sequencer-in-progress-p) + (magit-run-git-sequencer + (if (magit-revert-in-progress-p) "revert" "cherry-pick") "--abort") + (user-error "No cherry-pick or revert in progress"))) + +(defun magit-sequencer-in-progress-p () + (or (magit-cherry-pick-in-progress-p) + (magit-revert-in-progress-p))) + +;;; Cherry-Pick + +(defvar magit-perl-executable "perl" + "The Perl executable.") + +;;;###autoload (autoload 'magit-cherry-pick "magit-sequence" nil t) +(transient-define-prefix magit-cherry-pick () + "Apply or transplant commits." + :man-page "git-cherry-pick" + :value '("--ff") + :incompatible '(("--ff" "-x")) + ["Arguments" + :if-not magit-sequencer-in-progress-p + (magit-cherry-pick:--mainline) + ("=s" magit-merge:--strategy) + ("-F" "Attempt fast-forward" "--ff") + ("-x" "Reference cherry in commit message" "-x") + ("-e" "Edit commit messages" ("-e" "--edit")) + ("-s" "Add Signed-off-by lines" ("-s" "--signoff")) + (5 magit:--gpg-sign)] + [:if-not magit-sequencer-in-progress-p + ["Apply here" + ("A" "Pick" magit-cherry-copy) + ("a" "Apply" magit-cherry-apply) + ("h" "Harvest" magit-cherry-harvest) + ("m" "Squash" magit-merge-squash)] + ["Apply elsewhere" + ("d" "Donate" magit-cherry-donate) + ("n" "Spinout" magit-cherry-spinout) + ("s" "Spinoff" magit-cherry-spinoff)]] + ["Actions" + :if magit-sequencer-in-progress-p + ("A" "Continue" magit-sequencer-continue) + ("s" "Skip" magit-sequencer-skip) + ("a" "Abort" magit-sequencer-abort)]) + +(transient-define-argument magit-cherry-pick:--mainline () + :description "Replay merge relative to parent" + :class 'transient-option + :shortarg "-m" + :argument "--mainline=" + :reader 'transient-read-number-N+) + +(defun magit-cherry-pick-read-args (prompt) + (list (or (nreverse (magit-region-values 'commit)) + (magit-read-other-branch-or-commit prompt)) + (transient-args 'magit-cherry-pick))) + +(defun magit--cherry-move-read-args (verb away fn &optional allow-detached) + (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 (or (magit-get-current-branch) + (and allow-detached (magit-rev-parse "HEAD"))))) + (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 + (lambda (commits) + (magit-branch-read-args + (format "Create branch from %s cherries" (length commits)) + (magit-get-upstream-branch))))) + +;;;###autoload +(defun magit-cherry-copy (commits &optional args) + "Copy COMMITS from another branch onto the current branch. +Prompt for a commit, defaulting to the commit at point. If +the region selects multiple commits, then pick all of them, +without prompting." + (interactive (magit-cherry-pick-read-args "Cherry-pick")) + (magit--cherry-pick commits args)) + +;;;###autoload +(defun magit-cherry-apply (commits &optional args) + "Apply the changes in COMMITS but do not commit them. +Prompt for a commit, defaulting to the commit at point. If +the region selects multiple commits, then apply all of them, +without prompting." + (interactive (magit-cherry-pick-read-args "Apply changes from commit")) + (magit--cherry-pick commits (cons "--no-commit" (remove "--ff" args)))) + +;;;###autoload +(defun magit-cherry-harvest (commits branch &optional args) + "Move COMMITS from another BRANCH onto the current branch. +Remove the COMMITS from BRANCH and stay on the current branch. +If a conflict occurs, then you have to fix that and finish the +process manually." + (interactive + (magit--cherry-move-read-args "harvest" nil + (lambda (commits) + (list (let ((branches (magit-list-containing-branches (car commits)))) + (pcase (length branches) + (0 nil) + (1 (car branches)) + (_ (magit-completing-read + (let ((len (length commits))) + (if (= len 1) + "Remove 1 cherry from branch" + (format "Remove %s cherries from branch" len))) + branches nil t)))))))) + (magit--cherry-move commits branch (magit-get-current-branch) args nil t)) + +;;;###autoload +(defun magit-cherry-donate (commits branch &optional args) + "Move COMMITS from the current branch onto another existing BRANCH. +Remove COMMITS from the current branch and stay on that branch. +If a conflict occurs, then you have to fix that and finish the +process manually. `HEAD' is allowed to be detached initially." + (interactive + (magit--cherry-move-read-args "donate" t + (lambda (commits) + (list (magit-read-other-branch + (let ((len (length commits))) + (if (= len 1) + "Move 1 cherry to branch" + (format "Move %s cherries to branch" len)))))) + 'allow-detached)) + (magit--cherry-move commits + (or (magit-get-current-branch) + (magit-rev-parse "HEAD")) + branch args)) + +;;;###autoload +(defun magit-cherry-spinout (commits branch start-point &optional args) + "Move COMMITS from the current branch onto a new BRANCH. +Remove COMMITS from the current branch and stay on that branch. +If a conflict occurs, then you have to fix that and finish the +process manually." + (interactive (magit--cherry-spinoff-read-args "spinout")) + (magit--cherry-move commits (magit-get-current-branch) branch args + start-point)) + +;;;###autoload +(defun magit-cherry-spinoff (commits branch start-point &optional args) + "Move COMMITS from the current branch onto a new BRANCH. +Remove COMMITS from the current branch and checkout BRANCH. +If a conflict occurs, then you have to fix that and finish +the process manually." + (interactive (magit--cherry-spinoff-read-args "spinoff")) + (magit--cherry-move commits (magit-get-current-branch) branch args + start-point t)) + +(defun magit--cherry-move (commits src dst args + &optional start-point checkout-dst) + (let ((current (magit-get-current-branch))) + (unless (magit-branch-p dst) + (let ((magit-process-raise-error t)) + (magit-call-git "branch" dst start-point)) + (--when-let (magit-get-indirect-upstream-branch start-point) + (magit-call-git "branch" "--set-upstream-to" it dst))) + (unless (equal dst current) + (let ((magit-process-raise-error t)) + (magit-call-git "checkout" dst))) + (if (not src) ; harvest only + (magit--cherry-pick commits args) + (let ((tip (car (last commits))) + (keep (concat (car commits) "^"))) + (magit--cherry-pick commits args) + (set-process-sentinel + magit-this-process + (lambda (process event) + (when (memq (process-status process) '(exit signal)) + (if (> (process-exit-status process) 0) + (magit-process-sentinel process event) + (process-put process 'inhibit-refresh t) + (magit-process-sentinel process event) + (cond + ((magit-rev-equal tip src) + (magit-call-git "update-ref" + "-m" (format "reset: moving to %s" keep) + (magit-ref-fullname src) + keep tip) + (if (not checkout-dst) + (magit-run-git "checkout" src) + (magit-refresh))) + (t + (magit-git "checkout" src) + (let ((process-environment process-environment)) + (push (format "%s=%s -i -ne '/^pick (%s)/ or print'" + "GIT_SEQUENCE_EDITOR" + magit-perl-executable + (mapconcat #'magit-rev-abbrev commits "|")) + process-environment) + (magit-run-git-sequencer "rebase" "-i" keep)) + (when checkout-dst + (set-process-sentinel + magit-this-process + (lambda (process event) + (when (memq (process-status process) '(exit signal)) + (if (> (process-exit-status process) 0) + (magit-process-sentinel process event) + (process-put process 'inhibit-refresh t) + (magit-process-sentinel process event) + (magit-run-git "checkout" dst)))))))))))))))) + +(defun magit--cherry-pick (commits args &optional revert) + (let ((command (if revert "revert" "cherry-pick"))) + (when (stringp commits) + (setq commits (if (string-match-p "\\.\\." commits) + (split-string commits "\\.\\.") + (list commits)))) + (magit-run-git-sequencer + (if revert "revert" "cherry-pick") + (pcase-let ((`(,merge ,non-merge) + (-separate 'magit-merge-commit-p commits))) + (cond + ((not merge) + (--remove (string-prefix-p "--mainline=" it) args)) + (non-merge + (user-error "Cannot %s merge and non-merge commits at once" + command)) + ((--first (string-prefix-p "--mainline=" it) args) + args) + (t + (cons (format "--mainline=%s" + (read-number "Replay merges relative to parent: ")) + args)))) + commits))) + +(defun magit-cherry-pick-in-progress-p () + ;; .git/sequencer/todo does not exist when there is only one commit left. + (file-exists-p (magit-git-dir "CHERRY_PICK_HEAD"))) + +;;; Revert + +;;;###autoload (autoload 'magit-revert "magit-sequence" nil t) +(transient-define-prefix magit-revert () + "Revert existing commits, with or without creating new commits." + :man-page "git-revert" + :value '("--edit") + ["Arguments" + :if-not magit-sequencer-in-progress-p + (magit-cherry-pick:--mainline) + ("-e" "Edit commit message" ("-e" "--edit")) + ("-E" "Don't edit commit message" "--no-edit") + ("=s" magit-merge:--strategy) + ("-s" "Add Signed-off-by lines" ("-s" "--signoff")) + (5 magit:--gpg-sign)] + ["Actions" + :if-not magit-sequencer-in-progress-p + ("V" "Revert commit(s)" magit-revert-and-commit) + ("v" "Revert changes" magit-revert-no-commit)] + ["Actions" + :if magit-sequencer-in-progress-p + ("V" "Continue" magit-sequencer-continue) + ("s" "Skip" magit-sequencer-skip) + ("a" "Abort" magit-sequencer-abort)]) + +(defun magit-revert-read-args (prompt) + (list (or (magit-region-values 'commit) + (magit-read-branch-or-commit prompt)) + (transient-args 'magit-revert))) + +;;;###autoload +(defun magit-revert-and-commit (commit &optional args) + "Revert COMMIT by creating a new commit. +Prompt for a commit, defaulting to the commit at point. If +the region selects multiple commits, then revert all of them, +without prompting." + (interactive (magit-revert-read-args "Revert commit")) + (magit--cherry-pick commit args t)) + +;;;###autoload +(defun magit-revert-no-commit (commit &optional args) + "Revert COMMIT by applying it in reverse to the worktree. +Prompt for a commit, defaulting to the commit at point. If +the region selects multiple commits, then revert all of them, +without prompting." + (interactive (magit-revert-read-args "Revert changes")) + (magit--cherry-pick commit (cons "--no-commit" args) t)) + +(defun magit-revert-in-progress-p () + ;; .git/sequencer/todo does not exist when there is only one commit left. + (file-exists-p (magit-git-dir "REVERT_HEAD"))) + +;;; Patch + +;;;###autoload (autoload 'magit-am "magit-sequence" nil t) +(transient-define-prefix magit-am () + "Apply patches received by email." + :man-page "git-am" + :value '("--3way") + ["Arguments" + :if-not magit-am-in-progress-p + ("-3" "Fall back on 3way merge" ("-3" "--3way")) + (magit-apply:-p) + ("-c" "Remove text before scissors line" ("-c" "--scissors")) + ("-k" "Inhibit removal of email cruft" ("-k" "--keep")) + ("-b" "Limit removal of email cruft" "--keep-non-patch") + ("-d" "Use author date as committer date" "--committer-date-is-author-date") + ("-t" "Use current time as author date" "--ignore-date") + ("-s" "Add Signed-off-by lines" ("-s" "--signoff")) + (5 magit:--gpg-sign)] + ["Apply" + :if-not magit-am-in-progress-p + ("m" "maildir" magit-am-apply-maildir) + ("w" "patches" magit-am-apply-patches) + ("a" "plain patch" magit-patch-apply)] + ["Actions" + :if magit-am-in-progress-p + ("w" "Continue" magit-am-continue) + ("s" "Skip" magit-am-skip) + ("a" "Abort" magit-am-abort)]) + +(defun magit-am-arguments () + (transient-args 'magit-am)) + +(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 +(defun magit-am-apply-patches (&optional files args) + "Apply the patches FILES." + (interactive (list (or (magit-region-values 'file) + (list (let ((default (magit-file-at-point))) + (read-file-name + (if default + (format "Apply patch (%s): " default) + "Apply patch: ") + nil default)))) + (magit-am-arguments))) + (magit-run-git-sequencer "am" args "--" + (--map (magit-convert-filename-for-git + (expand-file-name it)) + files))) + +;;;###autoload +(defun magit-am-apply-maildir (&optional maildir args) + "Apply the patches from MAILDIR." + (interactive (list (read-file-name "Apply mbox or Maildir: ") + (magit-am-arguments))) + (magit-run-git-sequencer "am" args (magit-convert-filename-for-git + (expand-file-name maildir)))) + +;;;###autoload +(defun magit-am-continue () + "Resume the current patch applying sequence." + (interactive) + (if (magit-am-in-progress-p) + (if (magit-anything-unstaged-p t) + (error "Cannot continue due to unstaged changes") + (magit-run-git-sequencer "am" "--continue")) + (user-error "Not applying any patches"))) + +;;;###autoload +(defun magit-am-skip () + "Skip the stopped at patch during a patch applying sequence." + (interactive) + (if (magit-am-in-progress-p) + (magit-run-git-sequencer "am" "--skip") + (user-error "Not applying any patches"))) + +;;;###autoload +(defun magit-am-abort () + "Abort the current patch applying sequence. +This discards all changes made since the sequence started." + (interactive) + (if (magit-am-in-progress-p) + (magit-run-git "am" "--abort") + (user-error "Not applying any patches"))) + +(defun magit-am-in-progress-p () + (file-exists-p (magit-git-dir "rebase-apply/applying"))) + +;;; Rebase + +;;;###autoload (autoload 'magit-rebase "magit-sequence" nil t) +(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") + :if (lambda () (magit-git-version< "2.33.0"))) + ("-r" "Rebase merges" ("-r" "--rebase-merges=") + magit-rebase-merges-select-mode + :if (lambda () (magit-git-version>= "2.18.0"))) + (7 magit-merge:--strategy) + (7 magit-merge:--strategy-option) + (7 "=X" magit-diff:--diff-algorithm :argument "-Xdiff-algorithm=") + ("-d" "Use author date as committer date" "--committer-date-is-author-date") + ("-t" "Use current time as author date" "--ignore-date") + ("-a" "Autosquash" "--autosquash") + ("-A" "Autostash" "--autostash") + ("-i" "Interactive" ("-i" "--interactive")) + ("-h" "Disable hooks" "--no-verify") + (7 magit-rebase:--exec) + (5 magit:--gpg-sign)] + [:if-not magit-rebase-in-progress-p + :description (lambda () + (format (propertize "Rebase %s onto" 'face 'transient-heading) + (propertize (or (magit-get-current-branch) "HEAD") + 'face 'magit-branch-local))) + ("p" magit-rebase-onto-pushremote) + ("u" magit-rebase-onto-upstream) + ("e" "elsewhere" magit-rebase-branch)] + ["Rebase" + :if-not magit-rebase-in-progress-p + [("i" "interactively" magit-rebase-interactive) + ("s" "a subset" magit-rebase-subset)] + [("m" "to modify a commit" magit-rebase-edit-commit) + ("w" "to reword a commit" magit-rebase-reword-commit) + ("k" "to remove a commit" magit-rebase-remove-commit) + ("f" "to autosquash" magit-rebase-autosquash) + (6 "t" "to change dates" magit-reshelve-since)]] + ["Actions" + :if magit-rebase-in-progress-p + ("r" "Continue" magit-rebase-continue) + ("s" "Skip" magit-rebase-skip) + ("e" "Edit" magit-rebase-edit) + ("a" "Abort" magit-rebase-abort)]) + +(transient-define-argument magit-rebase:--exec () + :description "Run command after commits" + :class 'transient-option + :shortarg "-x" + :argument "--exec=" + :reader #'read-shell-command) + +(defun magit-rebase-merges-select-mode (&rest _ignore) + (magit-read-char-case nil t + (?n "[n]o-rebase-cousins" "no-rebase-cousins") + (?r "[r]ebase-cousins" "rebase-cousins"))) + +(defun magit-rebase-arguments () + (transient-args 'magit-rebase)) + +(defun magit-git-rebase (target args) + (magit-run-git-sequencer "rebase" args target)) + +;;;###autoload (autoload 'magit-rebase-onto-pushremote "magit-sequence" nil t) +(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 +configured or unusable, then let the user first configure the +push-remote." + :if 'magit-get-current-branch + :description 'magit-pull--pushbranch-description + (interactive (list (magit-rebase-arguments))) + (pcase-let ((`(,branch ,remote) + (magit--select-push-remote "rebase onto that"))) + (magit-git-rebase (concat remote "/" branch) args))) + +;;;###autoload (autoload 'magit-rebase-onto-upstream "magit-sequence" nil t) +(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 +configured or unusable, then let the user first configure +the upstream." + :if 'magit-get-current-branch + :description 'magit-rebase--upstream-description + (interactive (list (magit-rebase-arguments))) + (let* ((branch (or (magit-get-current-branch) + (user-error "No branch is checked out"))) + (upstream (magit-get-upstream-branch branch))) + (when (or current-prefix-arg (not upstream)) + (setq upstream + (magit-read-upstream-branch + branch (format "Set upstream of %s and rebase onto that" branch))) + (magit-set-upstream-branch branch upstream)) + (magit-git-rebase upstream args))) + +(defun magit-rebase--upstream-description () + (when-let ((branch (magit-get-current-branch))) + (or (magit-get-upstream-branch branch) + (let ((remote (magit-get "branch" branch "remote")) + (merge (magit-get "branch" branch "merge")) + (u (magit--propertize-face "@{upstream}" 'bold))) + (cond + ((magit--unnamed-upstream-p remote merge) + (concat u ", replacing unnamed")) + ((magit--valid-upstream-p remote merge) + (concat u ", replacing non-existent")) + ((or remote merge) + (concat u ", replacing invalid")) + (t + (concat u ", setting that"))))))) + +;;;###autoload +(defun magit-rebase-branch (target args) + "Rebase the current branch onto a branch read in the minibuffer. +All commits that are reachable from `HEAD' but not from the +selected branch TARGET are being rebased." + (interactive (list (magit-read-other-branch-or-commit "Rebase onto") + (magit-rebase-arguments))) + (message "Rebasing...") + (magit-git-rebase target args) + (message "Rebasing...done")) + +;;;###autoload +(defun magit-rebase-subset (newbase start args) + "Rebase a subset of the current branch's history onto a new base. +Rebase commits from START to `HEAD' onto NEWBASE. +START has to be selected from a list of recent commits." + (interactive (list (magit-read-other-branch-or-commit + "Rebase subset onto" nil + (magit-get-upstream-branch)) + nil + (magit-rebase-arguments))) + (if start + (progn (message "Rebasing...") + (magit-run-git-sequencer "rebase" "--onto" newbase start args) + (message "Rebasing...done")) + (magit-log-select + `(lambda (commit) + (magit-rebase-subset ,newbase (concat commit "^") (list ,@args))) + (concat "Type %p on a commit to rebase it " + "and commits above it onto " newbase ",")))) + +(defvar magit-rebase-interactive-include-selected t) + +(defun magit-rebase-interactive-1 + (commit args message &optional editor delay-edit-confirm noassert confirm) + (declare (indent 2)) + (when commit + (if (eq commit :merge-base) + (setq commit (--if-let (magit-get-upstream-branch) + (magit-git-string "merge-base" it "HEAD") + nil)) + (unless (magit-rev-ancestor-p commit "HEAD") + (user-error "%s isn't an ancestor of HEAD" commit)) + (if (magit-commit-parents commit) + (when (or (not (eq this-command 'magit-rebase-interactive)) + magit-rebase-interactive-include-selected) + (setq commit (concat commit "^"))) + (setq args (cons "--root" args))))) + (when (and commit (not noassert)) + (setq commit (magit-rebase-interactive-assert + commit delay-edit-confirm + (--some (string-prefix-p "--rebase-merges" it) args)))) + (if (and commit (not confirm)) + (let ((process-environment process-environment)) + (when editor + (push (concat "GIT_SEQUENCE_EDITOR=" + (if (functionp editor) + (funcall editor commit) + editor)) + process-environment)) + (magit-run-git-sequencer "rebase" "-i" args + (unless (member "--root" args) commit))) + (magit-log-select + `(lambda (commit) + ;; 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) +(defvar magit--rebase-public-edit-confirmed nil) + +(defun magit-rebase-interactive-assert + (since &optional delay-edit-confirm rebase-merges) + (let* ((commit (magit-rebase--target-commit since)) + (branches (magit-list-publishing-branches commit))) + (setq magit--rebase-public-edit-confirmed + (delete (magit-toplevel) magit--rebase-public-edit-confirmed)) + (when (and branches + (or (not delay-edit-confirm) + ;; The user might have stopped at a published commit + ;; merely to add new commits *after* it. Try not to + ;; ask users whether they really want to edit public + ;; commits, when they don't actually intend to do so. + (not (--all-p (magit-rev-equal it commit) branches)))) + (let ((m1 "Some of these commits have already been published to ") + (m2 ".\nDo you really want to modify them")) + (magit-confirm (or magit--rebase-published-symbol 'rebase-published) + (concat m1 "%s" m2) + (concat m1 "%i public branches" m2) + nil branches)) + (push (magit-toplevel) magit--rebase-public-edit-confirmed))) + (if (and (magit-git-lines "rev-list" "--merges" (concat since "..HEAD")) + (not rebase-merges)) + (magit-read-char-case "Proceed despite merge in rebase range? " nil + (?c "[c]ontinue" since) + (?s "[s]elect other" nil) + (?a "[a]bort" (user-error "Quit"))) + since)) + +(defun magit-rebase--target-commit (since) + (if (string-suffix-p "^" since) + ;; If SINCE is "REV^", then the user selected + ;; "REV", which is the first commit that will + ;; be replaced. (from^..to] <=> [from..to] + (substring since 0 -1) + ;; The "--root" argument is being used. + since)) + +;;;###autoload +(defun magit-rebase-interactive (commit args) + "Start an interactive rebase sequence." + (interactive (list (magit-commit-at-point) + (magit-rebase-arguments))) + (magit-rebase-interactive-1 commit args + "Type %p on a commit to rebase it and all commits above it," + nil t)) + +;;;###autoload +(defun magit-rebase-autosquash (args) + "Combine squash and fixup commits with their intended targets." + (interactive (list (magit-rebase-arguments))) + (magit-rebase-interactive-1 :merge-base + (nconc (list "--autosquash" "--keep-empty") args) + "Type %p on a commit to squash into it and then rebase as necessary," + "true" nil t)) + +;;;###autoload +(defun magit-rebase-edit-commit (commit args) + "Edit 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 edit it," + (apply-partially #'magit-rebase--perl-editor 'edit) + t)) + +;;;###autoload +(defun magit-rebase-reword-commit (commit args) + "Reword 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 reword its message," + (apply-partially #'magit-rebase--perl-editor 'reword))) + +;;;###autoload +(defun magit-rebase-remove-commit (commit args) + "Remove a single older commit using rebase." + (interactive (list (magit-commit-at-point) + (magit-rebase-arguments))) + ;; 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)))) + (format "%s -i -p -e '++$x if not $x and s/^pick %s/%s %s/'" + magit-perl-executable + commit + (cl-case action + (edit "edit") + (remove "noop\n# pick") + (reword "reword") + (t (error "unknown action: %s" action))) + commit))) + +;;;###autoload +(defun magit-rebase-continue (&optional noedit) + "Restart the current rebasing operation. +In some cases this pops up a commit message buffer for you do +edit. With a prefix argument the old message is reused as-is." + (interactive "P") + (if (magit-rebase-in-progress-p) + (if (magit-anything-unstaged-p t) + (user-error "Cannot continue rebase with unstaged changes") + (when (and (magit-anything-staged-p) + (file-exists-p (magit-git-dir "rebase-merge")) + (not (member (magit-toplevel) + magit--rebase-public-edit-confirmed))) + (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) + (magit-run-git-async (magit--rebase-resume-command) "--continue") + (set-process-sentinel magit-this-process + #'magit-sequencer-process-sentinel) + magit-this-process) + (magit-run-git-sequencer (magit--rebase-resume-command) "--continue"))) + (user-error "No rebase in progress"))) + +;;;###autoload +(defun magit-rebase-skip () + "Skip the current commit and restart the current rebase operation." + (interactive) + (unless (magit-rebase-in-progress-p) + (user-error "No rebase in progress")) + (magit-run-git-sequencer (magit--rebase-resume-command) "--skip")) + +;;;###autoload +(defun magit-rebase-edit () + "Edit the todo list of the current rebase operation." + (interactive) + (unless (magit-rebase-in-progress-p) + (user-error "No rebase in progress")) + (magit-run-git-sequencer "rebase" "--edit-todo")) + +;;;###autoload +(defun magit-rebase-abort () + "Abort the current rebase operation, restoring the original branch." + (interactive) + (unless (magit-rebase-in-progress-p) + (user-error "No rebase in progress")) + (magit-confirm 'abort-rebase "Abort this rebase") + (magit-run-git (magit--rebase-resume-command) "--abort")) + +(defun magit-rebase-in-progress-p () + "Return t if a rebase is in progress." + (or (file-exists-p (magit-git-dir "rebase-merge")) + (file-exists-p (magit-git-dir "rebase-apply/onto")))) + +(defun magit--rebase-resume-command () + (if (file-exists-p (magit-git-dir "rebase-recursive")) "rbr" "rebase")) + +;;; Sections + +(defun magit-insert-sequencer-sequence () + "Insert section for the on-going cherry-pick or revert sequence. +If no such sequence is in progress, do nothing." + (let ((picking (magit-cherry-pick-in-progress-p))) + (when (or picking (magit-revert-in-progress-p)) + (magit-insert-section (sequence) + (magit-insert-heading (if picking "Cherry Picking" "Reverting")) + (when-let ((lines + (cdr (magit-file-lines (magit-git-dir "sequencer/todo"))))) + (dolist (line (nreverse lines)) + (when (string-match + "^\\(pick\\|revert\\) \\([^ ]+\\) \\(.*\\)$" line) + (magit-bind-match-strings (cmd hash msg) line + (magit-insert-section (commit hash) + (insert (propertize cmd 'font-lock-face 'magit-sequence-pick) + " " (propertize hash 'font-lock-face 'magit-hash) + " " msg "\n")))))) + (magit-sequence-insert-sequence + (magit-file-line (magit-git-dir (if picking + "CHERRY_PICK_HEAD" + "REVERT_HEAD"))) + (magit-file-line (magit-git-dir "sequencer/head"))) + (insert "\n"))))) + +(defun magit-insert-am-sequence () + "Insert section for the on-going patch applying sequence. +If no such sequence is in progress, do nothing." + (when (magit-am-in-progress-p) + (magit-insert-section (rebase-sequence) + (magit-insert-heading "Applying patches") + (let ((patches (nreverse (magit-rebase-patches))) + patch commit) + (while patches + (setq patch (pop patches)) + (setq commit (magit-commit-p + (cadr (split-string (magit-file-line patch))))) + (cond ((and commit patches) + (magit-sequence-insert-commit + "pick" commit 'magit-sequence-pick)) + (patches + (magit-sequence-insert-am-patch + "pick" patch 'magit-sequence-pick)) + (commit + (magit-sequence-insert-sequence commit "ORIG_HEAD")) + (t + (magit-sequence-insert-am-patch + "stop" patch 'magit-sequence-stop) + (magit-sequence-insert-sequence nil "ORIG_HEAD"))))) + (insert ?\n)))) + +(defun magit-sequence-insert-am-patch (type patch face) + (magit-insert-section (file patch) + (let ((title + (with-temp-buffer + (insert-file-contents patch nil nil 4096) + (unless (re-search-forward "^Subject: " nil t) + (goto-char (point-min))) + (buffer-substring (point) (line-end-position))))) + (insert (propertize type 'font-lock-face face) + ?\s (propertize (file-name-nondirectory patch) + 'font-lock-face 'magit-hash) + ?\s title + ?\n)))) + +(defun magit-insert-rebase-sequence () + "Insert section for the on-going rebase sequence. +If no such sequence is in progress, do nothing." + (when (magit-rebase-in-progress-p) + (let* ((interactive (file-directory-p (magit-git-dir "rebase-merge"))) + (dir (if interactive "rebase-merge/" "rebase-apply/")) + (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))) + (magit-insert-section (rebase-sequence) + (magit-insert-heading (format "Rebasing %s onto %s" name onto)) + (if interactive + (magit-rebase-insert-merge-sequence onto) + (magit-rebase-insert-apply-sequence onto)) + (insert ?\n))))) + +(defun magit-rebase--todo () + "Return `git-rebase-action' instances for remaining rebase actions. +These are ordered in that the same way they'll be sorted in the +status buffer (i.e. the reverse of how they will be applied)." + (let ((comment-start (or (magit-get "core.commentChar") "#")) + lines) + (with-temp-buffer + (insert-file-contents (magit-git-dir "rebase-merge/git-rebase-todo")) + (while (not (eobp)) + (let ((ln (git-rebase-current-line))) + (when (oref ln action-type) + (push ln lines))) + (forward-line))) + lines)) + +(defun magit-rebase-insert-merge-sequence (onto) + (dolist (line (magit-rebase--todo)) + (with-slots (action-type action action-options target) line + (pcase action-type + (`commit + (magit-sequence-insert-commit action target 'magit-sequence-pick)) + ((or (or `exec `label) + (and `merge (guard (not action-options)))) + (insert (propertize action 'font-lock-face 'magit-sequence-onto) "\s" + (propertize target 'font-lock-face 'git-rebase-label) "\n")) + (`merge + (if-let ((hash (and (string-match "-[cC] \\([^ ]+\\)" action-options) + (match-string 1 action-options)))) + (magit-insert-section (commit hash) + (magit-insert-heading + (propertize "merge" 'font-lock-face 'magit-sequence-pick) + "\s" + (magit-format-rev-summary hash) "\n")) + (error "failed to parse merge message hash")))))) + (magit-sequence-insert-sequence + (magit-file-line (magit-git-dir "rebase-merge/stopped-sha")) + onto + (--when-let (magit-file-lines (magit-git-dir "rebase-merge/done")) + (cadr (split-string (car (last it))))))) + +(defun magit-rebase-insert-apply-sequence (onto) + (let ((rewritten + (--map (car (split-string it)) + (magit-file-lines (magit-git-dir "rebase-apply/rewritten")))) + (stop (magit-file-line (magit-git-dir "rebase-apply/original-commit")))) + (dolist (patch (nreverse (cdr (magit-rebase-patches)))) + (let ((hash (cadr (split-string (magit-file-line patch))))) + (unless (or (member hash rewritten) + (equal hash stop)) + (magit-sequence-insert-commit "pick" hash 'magit-sequence-pick))))) + (magit-sequence-insert-sequence + (magit-file-line (magit-git-dir "rebase-apply/original-commit")) + onto)) + +(defun magit-rebase-patches () + (directory-files (magit-git-dir "rebase-apply") t "^[0-9]\\{4\\}$")) + +(defun magit-sequence-insert-sequence (stop onto &optional orig) + (let ((head (magit-rev-parse "HEAD")) done) + (setq onto (if onto (magit-rev-parse onto) head)) + (setq done (magit-git-lines "log" "--format=%H" (concat onto "..HEAD"))) + (when (and stop (not (member (magit-rev-parse stop) done))) + (let ((id (magit-patch-id stop))) + (--if-let (--first (equal (magit-patch-id it) id) done) + (setq stop it) + (cond + ((--first (magit-rev-equal it stop) done) + ;; The commit's testament has been executed. + (magit-sequence-insert-commit "void" stop 'magit-sequence-drop)) + ;; The faith of the commit is still undecided... + ((magit-anything-unmerged-p) + ;; ...and time travel isn't for the faint of heart. + (magit-sequence-insert-commit "join" stop 'magit-sequence-part)) + ((magit-anything-modified-p t) + ;; ...and the dust hasn't settled yet... + (magit-sequence-insert-commit + (let* ((magit--refresh-cache nil) + (staged (magit-commit-tree "oO" nil "HEAD")) + (unstaged (magit-commit-worktree "oO" "--reset"))) + (cond + ;; ...but we could end up at the same tree just by committing. + ((or (magit-rev-equal staged stop) + (magit-rev-equal unstaged stop)) "goal") + ;; ...but the changes are still there, untainted. + ((or (equal (magit-patch-id staged) id) + (equal (magit-patch-id unstaged) id)) "same") + ;; ...and some changes are gone and/or others were added. + (t "work"))) + stop 'magit-sequence-part)) + ;; The commit is definitely gone... + ((--first (magit-rev-equal it stop) done) + ;; ...but all of its changes are still in effect. + (magit-sequence-insert-commit "poof" stop 'magit-sequence-drop)) + (t + ;; ...and some changes are gone and/or other changes were added. + (magit-sequence-insert-commit "gone" stop 'magit-sequence-drop))) + (setq stop nil)))) + (dolist (rev done) + (apply 'magit-sequence-insert-commit + (cond ((equal rev stop) + ;; ...but its reincarnation lives on. + ;; Or it didn't die in the first place. + (list (if (and (equal rev head) + (equal (magit-patch-id rev) + (magit-patch-id orig))) + "stop" ; We haven't done anything yet. + "like") ; There are new commits. + rev (if (equal rev head) + 'magit-sequence-head + 'magit-sequence-stop))) + ((equal rev head) + (list "done" rev 'magit-sequence-head)) + (t + (list "done" rev 'magit-sequence-done))))) + (magit-sequence-insert-commit "onto" 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-heading + (propertize type 'font-lock-face face) "\s" + (magit-format-rev-summary hash) "\n"))) + +;;; _ +(provide 'magit-sequence) +;;; magit-sequence.el ends here diff --git a/elpa/magit-20220116.1908/magit-stash.el b/elpa/magit-20220116.1908/magit-stash.el new file mode 100644 index 00000000..2b80fc87 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-stash.el @@ -0,0 +1,548 @@ +;;; magit-stash.el --- stash support for Magit -*- lexical-binding: t -*- + +;; Copyright (C) 2008-2022 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. + +;;; Commentary: + +;; Support for Git stashes. + +;;; Code: + +(require 'magit) +(require 'magit-reflog) + +;;; Options + +(defgroup magit-stash nil + "List stashes and show stash diffs." + :group 'magit-modes) + +;;;; Diff options + +(defcustom magit-stash-sections-hook + '(magit-insert-stash-notes + magit-insert-stash-worktree + magit-insert-stash-index + magit-insert-stash-untracked) + "Hook run to insert sections into stash diff buffers." + :package-version '(magit . "2.1.0") + :group 'magit-stash + :type 'hook) + +;;;; Log options + +(defcustom magit-stashes-margin + (list (nth 0 magit-log-margin) + (nth 1 magit-log-margin) + 'magit-log-margin-width nil + (nth 4 magit-log-margin)) + "Format of the margin in `magit-stashes-mode' buffers. + +The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). + +If INIT is non-nil, then the margin is shown initially. +STYLE controls how to format the author or committer date. + It can be one of `age' (to show the age of the commit), + `age-abbreviated' (to abbreviate the time unit to a character), + or a string (suitable for `format-time-string') to show the + actual date. Option `magit-log-margin-show-committer-date' + controls which date is being displayed. +WIDTH controls the width of the margin. This exists for forward + compatibility and currently the value should not be changed. +AUTHOR controls whether the name of the author is also shown by + default. +AUTHOR-WIDTH has to be an integer. When the name of the author + is shown, then this specifies how much space is used to do so." + :package-version '(magit . "2.9.0") + :group 'magit-stash + :group 'magit-margin + :type magit-log-margin--custom-type + :initialize 'magit-custom-initialize-reset + :set-after '(magit-log-margin) + :set (apply-partially #'magit-margin-set-variable 'magit-stashes-mode)) + +;;; Commands + +;;;###autoload (autoload 'magit-stash "magit-stash" nil t) +(transient-define-prefix magit-stash () + "Stash uncommitted changes." + :man-page "git-stash" + ["Arguments" + ("-u" "Also save untracked files" ("-u" "--include-untracked")) + ("-a" "Also save untracked and ignored files" ("-a" "--all"))] + [["Stash" + ("z" "both" magit-stash-both) + ("i" "index" magit-stash-index) + ("w" "worktree" magit-stash-worktree) + ("x" "keeping index" magit-stash-keep-index)] + ["Snapshot" + ("Z" "both" magit-snapshot-both) + ("I" "index" magit-snapshot-index) + ("W" "worktree" magit-snapshot-worktree) + ("r" "to wip ref" magit-wip-commit)] + ["Use" + ("a" "Apply" magit-stash-apply) + ("p" "Pop" magit-stash-pop) + ("k" "Drop" magit-stash-drop)] + ["Inspect" + ("l" "List" magit-stash-list) + ("v" "Show" magit-stash-show)] + ["Transform" + ("b" "Branch" magit-stash-branch) + ("B" "Branch here" magit-stash-branch-here) + ("f" "Format patch" magit-stash-format-patch)]]) + +(defun magit-stash-arguments () + (transient-args 'magit-stash)) + +;;;###autoload +(defun magit-stash-both (message &optional include-untracked) + "Create a stash of the index and working tree. +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 + (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 +(defun magit-stash-index (message) + "Create a stash of the index only. +Unstaged and untracked changes are not stashed. The stashed +changes are applied in reverse to both the index and the +worktree. This command can fail when the worktree is not clean. +Applying the resulting stash has the inverse effect." + (interactive (list (magit-stash-read-message))) + (magit-stash-save message t nil nil t 'worktree)) + +;;;###autoload +(defun magit-stash-worktree (message &optional include-untracked) + "Create a stash of unstaged changes in the working tree. +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)) + (magit-stash-save message nil t include-untracked t 'index)) + +;;;###autoload +(defun magit-stash-keep-index (message &optional include-untracked) + "Create a stash of the index and working tree, keeping index intact. +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)) + (magit-stash-save message t t include-untracked t 'index)) + +(defun magit-stash-read-args () + (list (magit-stash-read-message) + (magit-stash-read-untracked))) + +(defun magit-stash-read-untracked () + (let ((prefix (prefix-numeric-value current-prefix-arg)) + (args (magit-stash-arguments))) + (cond ((or (= prefix 16) (member "--all" args)) 'all) + ((or (= prefix 4) (member "--include-untracked" args)) t)))) + +(defun magit-stash-read-message () + (let* ((default (format "On %s: " + (or (magit-get-current-branch) "(no branch)"))) + (input (magit-read-string "Stash message" default))) + (if (equal input default) + (concat default (magit-rev-format "%h %s")) + input))) + +;;;###autoload +(defun magit-snapshot-both (&optional include-untracked) + "Create a snapshot of the index and working tree. +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-snapshot-read-args)) + (magit-snapshot-save t t include-untracked t)) + +;;;###autoload +(defun magit-snapshot-index () + "Create a snapshot of the index only. +Unstaged and untracked changes are not stashed." + (interactive) + (magit-snapshot-save t nil nil t)) + +;;;###autoload +(defun magit-snapshot-worktree (&optional include-untracked) + "Create a snapshot of unstaged changes in the working tree. +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-snapshot-read-args)) + (magit-snapshot-save nil t include-untracked t)) + +(defun magit-snapshot-read-args () + (list (magit-stash-read-untracked))) + +(defun magit-snapshot-save (index worktree untracked &optional refresh) + (magit-stash-save (concat "WIP on " (magit-stash-summary)) + index worktree untracked refresh t)) + +;;;###autoload +(defun magit-stash-apply (stash) + "Apply a stash to the working tree. +Try to preserve the stash index. If that fails because there +are staged changes, apply without preserving the stash index." + (interactive (list (magit-read-stash "Apply stash"))) + (if (= (magit-call-git "stash" "apply" "--index" stash) 0) + (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 +are staged changes, apply without preserving the stash index +and forgo removing the stash." + (interactive (list (magit-read-stash "Pop stash"))) + (if (= (magit-call-git "stash" "apply" "--index" stash) 0) + (magit-stash-drop stash) + (magit-run-git "stash" "apply" stash))) + +;;;###autoload +(defun magit-stash-drop (stash) + "Remove a stash from the stash list. +When the region is active offer to drop all contained stashes." + (interactive + (list (--if-let (magit-region-values 'stash) + (magit-confirm 'drop-stashes nil "Drop %i stashes" nil it) + (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 "stash" "drop" stash)) + (magit-refresh)) + +;;;###autoload +(defun magit-stash-clear (ref) + "Remove all stashes saved in REF's reflog by deleting REF." + (interactive (let ((ref (or (magit-section-value-if 'stashes) "refs/stash"))) + (magit-confirm t (format "Drop all stashes in %s" ref)) + (list ref))) + (magit-run-git "update-ref" "-d" ref)) + +;;;###autoload +(defun magit-stash-branch (stash branch) + "Create and checkout a new BRANCH from STASH." + (interactive (list (magit-read-stash "Branch stash") + (magit-read-string-ns "Branch name"))) + (magit-run-git "stash" "branch" branch stash)) + +;;;###autoload +(defun magit-stash-branch-here (stash branch) + "Create and checkout a new BRANCH and apply STASH. +The branch is created using `magit-branch-and-checkout', using the +current branch or `HEAD' as the start-point." + (interactive (list (magit-read-stash "Branch stash") + (magit-read-string-ns "Branch name"))) + (let ((magit-inhibit-refresh t)) + (magit-branch-and-checkout branch (or (magit-get-current-branch) "HEAD"))) + (magit-stash-apply stash)) + +;;;###autoload +(defun magit-stash-format-patch (stash) + "Create a patch from STASH" + (interactive (list (magit-read-stash "Create patch from stash"))) + (with-temp-file (magit-rev-format "0001-%f.patch" stash) + (magit-git-insert "stash" "show" "-p" stash)) + (magit-refresh)) + +;;; Plumbing + +(defun magit-stash-save (message index worktree untracked + &optional refresh keep noerror ref) + (if (or (and index (magit-staged-files t)) + (and worktree (magit-unstaged-files t)) + (and untracked (magit-untracked-files (eq untracked 'all)))) + (magit-with-toplevel + (magit-stash-store message (or ref "refs/stash") + (magit-stash-create message index worktree untracked)) + (if (eq keep 'worktree) + (with-temp-buffer + (magit-git-insert "diff" "--cached") + (magit-run-git-with-input + "apply" "--reverse" "--cached" "--ignore-space-change" "-") + (magit-run-git-with-input + "apply" "--reverse" "--ignore-space-change" "-")) + (unless (eq keep t) + (if (eq keep 'index) + (magit-call-git "checkout" "--" ".") + (magit-call-git "reset" "--hard" "HEAD" "--")) + (when untracked + (magit-call-git "clean" "--force" "-d" + (and (eq untracked 'all) "-x"))))) + (when refresh + (magit-refresh))) + (unless noerror + (user-error "No %s changes to save" (cond ((not index) "unstaged") + ((not worktree) "staged") + (t "local")))))) + +(defun magit-stash-store (message ref commit) + (magit-update-ref ref message commit t)) + +(defun magit-stash-create (message index worktree untracked) + (unless (magit-rev-parse "--verify" "HEAD") + (error "You do not have the initial commit yet")) + (let ((magit-git-global-arguments (nconc (list "-c" "commit.gpgsign=false") + magit-git-global-arguments)) + (default-directory (magit-toplevel)) + (summary (magit-stash-summary)) + (head "HEAD")) + (when (and worktree (not index)) + (setq head (or (magit-commit-tree "pre-stash index" nil "HEAD") + (error "Cannot save the current index state")))) + (or (setq index (magit-commit-tree (concat "index on " summary) nil head)) + (error "Cannot save the current index state")) + (and untracked + (setq untracked (magit-untracked-files (eq untracked 'all))) + (setq untracked (magit-with-temp-index nil nil + (or (and (magit-update-files untracked) + (magit-commit-tree + (concat "untracked files on " summary))) + (error "Cannot save the untracked files"))))) + (magit-with-temp-index index "-m" + (when worktree + (or (magit-update-files (magit-git-items "diff" "-z" "--name-only" head)) + (error "Cannot save the current worktree state"))) + (or (magit-commit-tree message nil head index untracked) + (error "Cannot save the current worktree state"))))) + +(defun magit-stash-summary () + (concat (or (magit-get-current-branch) "(no branch)") + ": " (magit-rev-format "%h %s"))) + +;;; Sections + +(defvar magit-stashes-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-delete-thing] 'magit-stash-clear) + map) + "Keymap for `stashes' section.") + +(defvar magit-stash-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] 'magit-stash-show) + (define-key map [remap magit-delete-thing] 'magit-stash-drop) + (define-key map "a" 'magit-stash-apply) + (define-key map "A" 'magit-stash-pop) + map) + "Keymap for `stash' sections.") + +(magit-define-section-jumper magit-jump-to-stashes + "Stashes" stashes "refs/stash") + +(cl-defun magit-insert-stashes (&optional (ref "refs/stash") + (heading "Stashes:")) + "Insert `stashes' section showing reflog for \"refs/stash\". +If optional REF is non-nil, show reflog for that instead. +If optional HEADING is non-nil, use that as section heading +instead of \"Stashes:\"." + (let ((verified (magit-rev-verify ref)) + (autostash + (and (magit-rebase-in-progress-p) + (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) + (when autostash + (pcase-let ((`(,author ,date ,msg) + (split-string + (car (magit-git-lines + "show" "-q" "--format=%aN%x00%at%x00%s" + autostash)) + "\0"))) + (magit-insert-section (stash autostash) + (insert (propertize "AUTOSTASH" 'font-lock-face 'magit-hash)) + (insert " " msg "\n") + (save-excursion + (backward-char) + (magit-log-format-margin autostash author date))))) + (if verified + (magit-git-wash (apply-partially 'magit-log-wash-log 'stash) + "reflog" "--format=%gd%x00%aN%x00%at%x00%gs" ref) + (insert ?\n) + (save-excursion + (backward-char) + (magit-make-margin-overlay))))))) + +;;; List Stashes + +;;;###autoload +(defun magit-stash-list () + "List all stashes in a buffer." + (interactive) + (magit-stashes-setup-buffer)) + +(define-derived-mode magit-stashes-mode magit-reflog-mode "Magit Stashes" + "Mode for looking at lists of stashes." + :group 'magit-log + (hack-dir-local-variables-non-file-buffer)) + +(defun magit-stashes-setup-buffer () + (magit-setup-buffer #'magit-stashes-mode nil + (magit-buffer-refname "refs/stash"))) + +(defun magit-stashes-refresh-buffer () + (magit-insert-section (stashesbuf) + (magit-insert-heading (if (equal magit-buffer-refname "refs/stash") + "Stashes:" + (format "Stashes [%s]:" magit-buffer-refname))) + (magit-git-wash (apply-partially 'magit-log-wash-log 'stash) + "reflog" "--format=%gd%x00%aN%x00%at%x00%gs" magit-buffer-refname))) + +(cl-defmethod magit-buffer-value (&context (major-mode magit-stashes-mode)) + magit-buffer-refname) + +(defvar magit--update-stash-buffer nil) + +(defun magit-stashes-maybe-update-stash-buffer (&optional _) + "When moving in the stashes buffer, update the stash buffer. +If there is no stash buffer in the same frame, then do nothing." + (when (derived-mode-p 'magit-stashes-mode) + (magit--maybe-update-stash-buffer))) + +(defun magit--maybe-update-stash-buffer () + (when-let ((stash (magit-section-value-if 'stash)) + (buffer (magit-get-mode-buffer 'magit-stash-mode nil t))) + (if magit--update-stash-buffer + (setq magit--update-stash-buffer (list stash buffer)) + (setq magit--update-stash-buffer (list stash 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))))) + (lambda () + (pcase-let ((`(,stash ,buf) magit--update-stash-buffer)) + (setq magit--update-stash-buffer nil) + (when (buffer-live-p buf) + (let ((magit-display-buffer-noselect t)) + (apply #'magit-stash-show stash args)))) + (setq magit--update-stash-buffer nil))))))) + +;;; Show Stash + +;;;###autoload +(defun magit-stash-show (stash &optional args files) + "Show all diffs of a stash in a buffer." + (interactive (cons (or (and (not current-prefix-arg) + (magit-stash-at-point)) + (magit-read-stash "Show stash")) + (pcase-let ((`(,args ,files) + (magit-diff-arguments 'magit-stash-mode))) + (list (delete "--stat" args) files)))) + (magit-stash-setup-buffer stash args files)) + +(define-derived-mode magit-stash-mode magit-diff-mode "Magit Stash" + "Mode for looking at individual stashes." + :group 'magit-diff + (hack-dir-local-variables-non-file-buffer)) + +(defun magit-stash-setup-buffer (stash args files) + (magit-setup-buffer #'magit-stash-mode nil + (magit-buffer-revision stash) + (magit-buffer-range (format "%s^..%s" stash stash)) + (magit-buffer-diff-args args) + (magit-buffer-diff-files files))) + +(defun magit-stash-refresh-buffer () + (magit-set-header-line-format + (concat (capitalize magit-buffer-revision) " " + (propertize (magit-rev-format "%s" magit-buffer-revision) + 'font-lock-face + (list :weight 'normal :foreground + (face-attribute 'default :foreground))))) + (setq magit-buffer-revision-hash (magit-rev-parse magit-buffer-revision)) + (magit-insert-section (stash) + (magit-run-section-hook 'magit-stash-sections-hook))) + +(cl-defmethod magit-buffer-value (&context (major-mode magit-stash-mode)) + magit-buffer-revision) + +(defun magit-stash-insert-section (commit range message &optional files) + (magit-insert-section (commit commit) + (magit-insert-heading message) + (magit--insert-diff "diff" range "-p" "--no-prefix" magit-buffer-diff-args + "--" (or files magit-buffer-diff-files)))) + +(defun magit-insert-stash-notes () + "Insert section showing notes for a stash. +This shows the notes for stash@{N} but not for the other commits +that make up the stash." + (magit-insert-section section (note) + (magit-insert-heading "Notes") + (magit-git-insert "notes" "show" magit-buffer-revision) + (if (= (point) + (oref section content)) + (magit-cancel-section) + (insert "\n")))) + +(defun magit-insert-stash-index () + "Insert section showing staged changes of the stash." + (magit-stash-insert-section + (format "%s^2" magit-buffer-revision) + (format "%s^..%s^2" magit-buffer-revision magit-buffer-revision) + "Staged")) + +(defun magit-insert-stash-worktree () + "Insert section showing unstaged changes of the stash." + (magit-stash-insert-section + magit-buffer-revision + (format "%s^2..%s" magit-buffer-revision magit-buffer-revision) + "Unstaged")) + +(defun magit-insert-stash-untracked () + "Insert section showing the untracked files commit of the stash." + (let ((stash magit-buffer-revision) + (rev (concat magit-buffer-revision "^3"))) + (when (magit-rev-verify rev) + (magit-stash-insert-section (format "%s^3" stash) + (format "%s^..%s^3" stash stash) + "Untracked files" + (magit-git-items "ls-tree" "-z" "--name-only" + "-r" "--full-tree" rev))))) + +;;; _ +(provide 'magit-stash) +;;; magit-stash.el ends here diff --git a/elpa/magit-20220116.1908/magit-status.el b/elpa/magit-20220116.1908/magit-status.el new file mode 100644 index 00000000..eed0dcd2 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-status.el @@ -0,0 +1,860 @@ +;;; magit-status.el --- the grand overview -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements the status buffer. + +;;; Code: + +(require 'magit) + +;;; Options + +(defgroup magit-status nil + "Inspect and manipulate Git repositories." + :link '(info-link "(magit)Status Buffer") + :group 'magit-modes) + +(defcustom magit-status-mode-hook nil + "Hook run after entering Magit-Status mode." + :group 'magit-status + :type 'hook) + +(defcustom magit-status-headers-hook + '(magit-insert-error-header + magit-insert-diff-filter-header + magit-insert-head-branch-header + magit-insert-upstream-branch-header + magit-insert-push-branch-header + magit-insert-tags-header) + "Hook run to insert headers into the status buffer. + +This hook is run by `magit-insert-status-headers', which in turn +has to be a member of `magit-status-sections-hook' to be used at +all." + :package-version '(magit . "2.1.0") + :group 'magit-status + :type 'hook + :options '(magit-insert-error-header + magit-insert-diff-filter-header + magit-insert-repo-header + magit-insert-remote-header + magit-insert-head-branch-header + magit-insert-upstream-branch-header + magit-insert-push-branch-header + magit-insert-tags-header)) + +(defcustom magit-status-sections-hook + '(magit-insert-status-headers + magit-insert-merge-log + magit-insert-rebase-sequence + magit-insert-am-sequence + magit-insert-sequencer-sequence + magit-insert-bisect-output + magit-insert-bisect-rest + magit-insert-bisect-log + magit-insert-untracked-files + magit-insert-unstaged-changes + magit-insert-staged-changes + magit-insert-stashes + magit-insert-unpushed-to-pushremote + magit-insert-unpushed-to-upstream-or-recent + magit-insert-unpulled-from-pushremote + magit-insert-unpulled-from-upstream) + "Hook run to insert sections into a status buffer." + :package-version '(magit . "2.12.0") + :group 'magit-status + :type 'hook) + +(defcustom magit-status-initial-section '(1) + "The section point is placed on when a status buffer is created. + +When such a buffer is merely being refreshed or being shown again +after it was merely buried, then this option has no effect. + +If this is nil, then point remains on the very first section as +usual. Otherwise it has to be a list of integers and section +identity lists. The members of that list are tried in order +until a matching section is found. + +An integer means to jump to the nth section, 1 for example +jumps over the headings. To get a section's \"identity list\" +use \\[universal-argument] \\[magit-describe-section-briefly]. + +If, for example, you want to jump to the commits that haven't +been pulled from the upstream, or else the second section, then +use: (((unpulled . \"..@{upstream}\") (status)) 1). + +See option `magit-section-initial-visibility-alist' for how to +control the initial visibility of the jumped to section." + :package-version '(magit . "2.90.0") + :group 'magit-status + :type '(choice (const :tag "as usual" nil) + (repeat (choice (number :tag "nth top-level section") + (sexp :tag "section identity"))))) + +(defcustom magit-status-goto-file-position nil + "Whether to go to position corresponding to file position. + +If this is non-nil and the current buffer is visiting a file, +then `magit-status' tries to go to the position in the status +buffer that corresponds to the position in the file-visiting +buffer. This jumps into either the diff of unstaged changes +or the diff of staged changes. + +If the previously current buffer does not visit a file, or if +the file has neither unstaged nor staged changes then this has +no effect. + +The command `magit-status-here' tries to go to that position, +regardless of the value of this option." + :package-version '(magit . "3.0.0") + :group 'magit-status + :type 'boolean) + +(defcustom magit-status-show-hashes-in-headers nil + "Whether headers in the status buffer show hashes. +The functions which respect this option are +`magit-insert-head-branch-header', +`magit-insert-upstream-branch-header', and +`magit-insert-push-branch-header'." + :package-version '(magit . "2.4.0") + :group 'magit-status + :type 'boolean) + +(defcustom magit-status-margin + (list nil + (nth 1 magit-log-margin) + 'magit-log-margin-width nil + (nth 4 magit-log-margin)) + "Format of the margin in `magit-status-mode' buffers. + +The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH). + +If INIT is non-nil, then the margin is shown initially. +STYLE controls how to format the author or committer date. + It can be one of `age' (to show the age of the commit), + `age-abbreviated' (to abbreviate the time unit to a character), + or a string (suitable for `format-time-string') to show the + actual date. Option `magit-log-margin-show-committer-date' + controls which date is being displayed. +WIDTH controls the width of the margin. This exists for forward + compatibility and currently the value should not be changed. +AUTHOR controls whether the name of the author is also shown by + default. +AUTHOR-WIDTH has to be an integer. When the name of the author + is shown, then this specifies how much space is used to do so." + :package-version '(magit . "2.9.0") + :group 'magit-status + :group 'magit-margin + :type magit-log-margin--custom-type + :initialize 'magit-custom-initialize-reset + :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 +(defun magit-init (directory) + "Initialize a Git repository, then show its status. + +If the directory is below an existing repository, then the user +has to confirm that a new one should be created inside. If the +directory is the root of the existing repository, then the user +has to confirm that it should be reinitialized. + +Non-interactively DIRECTORY is (re-)initialized unconditionally." + (interactive + (let ((directory (file-name-as-directory + (expand-file-name + (read-directory-name "Create repository in: "))))) + (when-let ((toplevel (magit-toplevel directory))) + (setq toplevel (expand-file-name toplevel)) + (unless (y-or-n-p (if (file-equal-p toplevel directory) + (format "Reinitialize existing repository %s? " + directory) + (format "%s is a repository. Create another in %s? " + toplevel directory))) + (user-error "Abort"))) + (list directory))) + ;; `git init' does not understand the meaning of "~"! + (magit-call-git "init" (magit-convert-filename-for-git + (expand-file-name directory))) + (magit-status-setup-buffer directory)) + +;;;###autoload +(defun magit-status (&optional directory cache) + "Show the status of the current Git repository in a buffer. + +If the current directory isn't located within a Git repository, +then prompt for an existing repository or an arbitrary directory, +depending on option `magit-repository-directories', and show the +status of the selected repository instead. + +* If that option specifies any existing repositories, then offer + those for completion and show the status buffer for the + selected one. + +* Otherwise read an arbitrary directory using regular file-name + completion. If the selected directory is the top-level of an + existing working tree, then show the status buffer for that. + +* Otherwise offer to initialize the selected directory as a new + repository. After creating the repository show its status + buffer. + +These fallback behaviors can also be forced using one or more +prefix arguments: + +* With two prefix arguments (or more precisely a numeric prefix + value of 16 or greater) read an arbitrary directory and act on + it as described above. The same could be accomplished using + the command `magit-init'. + +* With a single prefix argument read an existing repository, or + if none can be found based on `magit-repository-directories', + then fall back to the same behavior as with two prefix + arguments." + (interactive + (let ((magit--refresh-cache (list (cons 0 0)))) + (list (and (or current-prefix-arg (not (magit-toplevel))) + (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 + (let ((toplevel (magit-toplevel directory))) + (setq directory (file-name-as-directory + (expand-file-name directory))) + (if (and toplevel (file-equal-p directory toplevel)) + (magit-status-setup-buffer directory) + (when (y-or-n-p + (if toplevel + (format "%s is a repository. Create another in %s? " + toplevel directory) + (format "Create repository in %s? " directory))) + ;; Creating a new repository invalidates cached values. + (setq magit--refresh-cache nil) + (magit-init directory)))) + (magit-status-setup-buffer default-directory)))) + +(put 'magit-status 'interactive-only 'magit-status-setup-buffer) + +;;;###autoload +(defalias 'magit 'magit-status + "An alias for `magit-status' for better discoverability. + +Instead of invoking this alias for `magit-status' using +\"M-x magit RET\", you should bind a key to `magit-status' +and read the info node `(magit)Getting Started', which +also contains other useful hints.") + +;;;###autoload +(defun magit-status-here () + "Like `magit-status' but with non-nil `magit-status-goto-file-position'." + (interactive) + (let ((magit-status-goto-file-position t)) + (call-interactively #'magit-status))) + +(put 'magit-status-here 'interactive-only 'magit-status-setup-buffer) + +;;;###autoload +(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) + (when-let ((remote (file-remote-p directory))) + (unless (member remote magit--remotes-using-recent-git) + (if-let ((version (let ((default-directory directory)) + (magit-git-version)))) + (if (magit--version>= version magit--minimal-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. + +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. + +Check the value of `magit-remote-git-executable' and consult +the info node `(tramp)Remote programs'." remote) :error))))) + +;;; Mode + +(defvar magit-status-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-mode-map) + (define-key map "j" 'magit-status-jump) + (define-key map [remap dired-jump] 'magit-dired-jump) + map) + "Keymap for `magit-status-mode'.") + +(transient-define-prefix magit-status-jump () + "In a Magit-Status buffer, jump to a section." + ["Jump to" + [("z " "Stashes" magit-jump-to-stashes + :if (lambda () (memq 'magit-insert-stashes magit-status-sections-hook))) + ("t " "Tracked" magit-jump-to-tracked + :if (lambda () (memq 'magit-insert-tracked-files magit-status-sections-hook))) + ("n " "Untracked" magit-jump-to-untracked + :if (lambda () (memq 'magit-insert-untracked-files magit-status-sections-hook))) + ("u " "Unstaged" magit-jump-to-unstaged + :if (lambda () (memq 'magit-insert-unstaged-changes magit-status-sections-hook))) + ("s " "Staged" magit-jump-to-staged + :if (lambda () (memq 'magit-insert-staged-changes magit-status-sections-hook)))] + [("fu" "Unpulled from upstream" magit-jump-to-unpulled-from-upstream + :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" 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))) + :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)))] + [("i" "Using Imenu" imenu)]]) + +(define-derived-mode magit-status-mode magit-mode "Magit" + "Mode for looking at Git status. + +This mode is documented in info node `(magit)Status Buffer'. + +\\\ +Type \\[magit-refresh] to refresh the current buffer. +Type \\[magit-section-toggle] to expand or hide the section at point. +Type \\[magit-visit-thing] to visit the change or commit at point. + +Type \\[magit-dispatch] to invoke major commands. + +Staging and applying changes is documented in info node +`(magit)Staging and Unstaging' and info node `(magit)Applying'. + +\\Type \ +\\[magit-apply] to apply the change at point, \ +\\[magit-stage] to stage, +\\[magit-unstage] to unstage, \ +\\[magit-discard] to discard, or \ +\\[magit-reverse] to reverse it. + +\\\ +Type \\[magit-commit] to create a commit. + +\\{magit-status-mode-map}" + :group 'magit-status + (hack-dir-local-variables-non-file-buffer) + (setq imenu-create-index-function + 'magit-imenu--status-create-index-function)) + +(put 'magit-status-mode 'magit-diff-default-arguments + '("--no-ext-diff")) +(put 'magit-status-mode 'magit-log-default-arguments + '("-n256" "--decorate")) + +;;;###autoload +(defun magit-status-setup-buffer (&optional directory) + (unless directory + (setq directory default-directory)) + (magit--tramp-asserts directory) + (let* ((default-directory directory) + (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))) + (col (and file (current-column))) + (buf (magit-setup-buffer #'magit-status-mode nil + (magit-buffer-diff-args (nth 0 d)) + (magit-buffer-diff-files (nth 1 d)) + (magit-buffer-log-args (nth 0 l)) + (magit-buffer-log-files (nth 1 l))))) + (when file + (with-current-buffer buf + (let ((staged (magit-get-section '((staged) (status))))) + (if (and staged + (cadr (magit-diff--locate-hunk file line staged))) + (magit-diff--goto-position file line col staged) + (let ((unstaged (magit-get-section '((unstaged) (status))))) + (unless (and unstaged + (magit-diff--goto-position file line col unstaged)) + (when staged + (magit-diff--goto-position file line col staged)))))))) + buf)) + +(defun magit-status-refresh-buffer () + (magit-git-exit-code "update-index" "--refresh") + (magit-insert-section (status) + (magit-run-section-hook 'magit-status-sections-hook))) + +(defun magit-status-goto-initial-section () + "In a `magit-status-mode' buffer, jump `magit-status-initial-section'. +Actually doing so is deferred until `magit-refresh-buffer-hook' +runs `magit-status-goto-initial-section-1'. That function then +removes itself from the hook, so that this only happens when the +status buffer is first created." + (when (and magit-status-initial-section + (derived-mode-p 'magit-status-mode)) + (add-hook 'magit-refresh-buffer-hook + 'magit-status-goto-initial-section-1 nil t))) + +(defun magit-status-goto-initial-section-1 () + "In a `magit-status-mode' buffer, jump `magit-status-initial-section'. +This function removes itself from `magit-refresh-buffer-hook'." + (when-let ((section + (--some (if (integerp it) + (nth (1- it) + (magit-section-siblings (magit-current-section) + 'next)) + (magit-get-section it)) + magit-status-initial-section))) + (goto-char (oref section start)) + (when-let ((vis (cdr (assq 'magit-status-initial-section + magit-section-initial-visibility-alist)))) + (if (eq vis 'hide) + (magit-section-hide section) + (magit-section-show section)))) + (remove-hook 'magit-refresh-buffer-hook + 'magit-status-goto-initial-section-1 t)) + +(defun magit-status-maybe-update-revision-buffer (&optional _) + "When moving in the status buffer, update the revision buffer. +If there is no revision buffer in the same frame, then do nothing." + (when (derived-mode-p 'magit-status-mode) + (magit--maybe-update-revision-buffer))) + +(defun magit-status-maybe-update-stash-buffer (&optional _) + "When moving in the status buffer, update the stash buffer. +If there is no stash buffer in the same frame, then do nothing." + (when (derived-mode-p 'magit-status-mode) + (magit--maybe-update-stash-buffer))) + +(defun magit-status-maybe-update-blob-buffer (&optional _) + "When moving in the status buffer, update the blob buffer. +If there is no blob buffer in the same frame, then do nothing." + (when (derived-mode-p 'magit-status-mode) + (magit--maybe-update-blob-buffer))) + +;;; Sections +;;;; Special Headers + +(defun magit-insert-status-headers () + "Insert header sections appropriate for `magit-status-mode' buffers. +The sections are inserted by running the functions on the hook +`magit-status-headers-hook'." + (if (magit-rev-verify "HEAD") + (magit-insert-headers 'magit-status-headers-hook) + (insert "In the beginning there was darkness\n\n"))) + +(defvar magit-error-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] 'magit-process-buffer) + map) + "Keymap for `error' sections.") + +(defun magit-insert-error-header () + "Insert the message about the Git error that just occurred. + +This function is only aware of the last error that occur when Git +was run for side-effects. If, for example, an error occurs while +generating a diff, then that error won't be inserted. Refreshing +the status buffer causes this section to disappear again." + (when magit-this-error + (magit-insert-section (error 'git) + (insert (propertize (format "%-10s" "GitError! ") + 'font-lock-face 'magit-section-heading)) + (insert (propertize magit-this-error 'font-lock-face 'error)) + (when-let ((key (car (where-is-internal 'magit-process-buffer)))) + (insert (format " [Type `%s' for details]" (key-description key)))) + (insert ?\n)) + (setq magit-this-error nil))) + +(defun magit-insert-diff-filter-header () + "Insert a header line showing the effective diff filters." + (let ((ignore-modules (magit-ignore-submodules-p))) + (when (or ignore-modules + magit-buffer-diff-files) + (insert (propertize (format "%-10s" "Filter! ") + 'font-lock-face 'magit-section-heading)) + (when ignore-modules + (insert ignore-modules) + (when magit-buffer-diff-files + (insert " -- "))) + (when magit-buffer-diff-files + (insert (mapconcat #'identity magit-buffer-diff-files " "))) + (insert ?\n)))) + +;;;; Reference Headers + +(defun magit-insert-head-branch-header (&optional branch) + "Insert a header line about the current branch. +If `HEAD' is detached, then insert information about that commit +instead. The optional BRANCH argument is for internal use only." + (let ((branch (or branch (magit-get-current-branch))) + (output (magit-rev-format "%h %s" (or branch "HEAD")))) + (string-match "^\\([^ ]+\\) \\(.*\\)" output) + (magit-bind-match-strings (commit summary) output + (when (equal summary "") + (setq summary "(no commit message)")) + (if branch + (magit-insert-section (branch branch) + (insert (format "%-10s" "Head: ")) + (when magit-status-show-hashes-in-headers + (insert (propertize commit 'font-lock-face 'magit-hash) ?\s)) + (insert (propertize branch 'font-lock-face 'magit-branch-local)) + (insert ?\s) + (insert (funcall magit-log-format-message-function branch summary)) + (insert ?\n)) + (magit-insert-section (commit commit) + (insert (format "%-10s" "Head: ")) + (insert (propertize commit 'font-lock-face 'magit-hash)) + (insert ?\s) + (insert (funcall magit-log-format-message-function nil summary)) + (insert ?\n)))))) + +(defun magit-insert-upstream-branch-header (&optional branch upstream keyword) + "Insert a header line about the upstream of the current branch. +If no branch is checked out, then insert nothing. The optional +arguments are for internal use only." + (when-let ((branch (or branch (magit-get-current-branch)))) + (let ((remote (magit-get "branch" branch "remote")) + (merge (magit-get "branch" branch "merge")) + (rebase (magit-get "branch" branch "rebase"))) + (when (or remote merge) + (unless upstream + (setq upstream (magit-get-upstream-branch branch))) + (magit-insert-section (branch upstream) + (pcase rebase + ("true") + ("false" (setq rebase nil)) + (_ (setq rebase (magit-get-boolean "pull.rebase")))) + (insert (format "%-10s" (or keyword (if rebase "Rebase: " "Merge: ")))) + (insert + (if upstream + (concat (and magit-status-show-hashes-in-headers + (concat (propertize (magit-rev-format "%h" upstream) + 'font-lock-face 'magit-hash) + " ")) + upstream " " + (funcall magit-log-format-message-function upstream + (funcall magit-log-format-message-function nil + (or (magit-rev-format "%s" upstream) + "(no commit message)")))) + (cond + ((magit--unnamed-upstream-p remote merge) + (concat (propertize merge 'font-lock-face 'magit-branch-remote) + " from " + (propertize remote 'font-lock-face 'bold))) + ((magit--valid-upstream-p remote merge) + (if (equal remote ".") + (concat + (propertize merge 'font-lock-face 'magit-branch-local) " " + (propertize "does not exist" + 'font-lock-face 'magit-branch-warning)) + (format + "%s %s %s" + (propertize merge 'font-lock-face 'magit-branch-remote) + (propertize "does not exist on" + 'font-lock-face 'magit-branch-warning) + (propertize remote 'font-lock-face 'magit-branch-remote)))) + (t + (propertize "invalid upstream configuration" + 'font-lock-face 'magit-branch-warning))))) + (insert ?\n)))))) + +(defun magit-insert-push-branch-header () + "Insert a header line about the branch the current branch is pushed to." + (when-let ((branch (magit-get-current-branch)) + (target (magit-get-push-branch branch))) + (magit-insert-section (branch target) + (insert (format "%-10s" "Push: ")) + (insert + (if (magit-rev-verify target) + (concat target " " + (and magit-status-show-hashes-in-headers + (concat (propertize (magit-rev-format "%h" target) + 'font-lock-face 'magit-hash) + " ")) + (funcall magit-log-format-message-function target + (funcall magit-log-format-message-function nil + (or (magit-rev-format "%s" target) + "(no commit message)")))) + (let ((remote (magit-get-push-remote branch))) + (if (magit-remote-p remote) + (concat target " " + (propertize "does not exist" + 'font-lock-face 'magit-branch-warning)) + (concat remote " " + (propertize "remote does not exist" + 'font-lock-face 'magit-branch-warning)))))) + (insert ?\n)))) + +(defun magit-insert-tags-header () + "Insert a header line about the current and/or next tag." + (let* ((this-tag (magit-get-current-tag nil t)) + (next-tag (magit-get-next-tag nil t)) + (this-cnt (cadr this-tag)) + (next-cnt (cadr next-tag)) + (this-tag (car this-tag)) + (next-tag (car next-tag)) + (both-tags (and this-tag next-tag t))) + (when (or this-tag next-tag) + (magit-insert-section (tag (or this-tag next-tag)) + (insert (format "%-10s" (if both-tags "Tags: " "Tag: "))) + (cl-flet ((insert-count + (tag count face) + (insert (concat (propertize tag 'font-lock-face 'magit-tag) + (and (> count 0) + (format " (%s)" + (propertize + (format "%s" count) + 'font-lock-face face))))))) + (when this-tag (insert-count this-tag this-cnt 'magit-branch-local)) + (when both-tags (insert ", ")) + (when next-tag (insert-count next-tag next-cnt 'magit-tag))) + (insert ?\n))))) + +;;;; Auxiliary Headers + +(defun magit-insert-user-header () + "Insert a header line about the current user." + (let ((name (magit-get "user.name")) + (email (magit-get "user.email"))) + (when (and name email) + (magit-insert-section (user name) + (insert (format "%-10s" "User: ")) + (insert (propertize name 'font-lock-face 'magit-log-author)) + (insert " <" email ">\n"))))) + +(defun magit-insert-repo-header () + "Insert a header line showing the path to the repository top-level." + (let ((topdir (magit-toplevel))) + (magit-insert-section (repo topdir) + (insert (format "%-10s%s\n" "Repo: " (abbreviate-file-name topdir)))))) + +(defun magit-insert-remote-header () + "Insert a header line about the remote of the current branch. + +If no remote is configured for the current branch, then fall back +showing the \"origin\" remote, or if that does not exist the first +remote in alphabetic order." + (when-let ((name (magit-get-some-remote)) + ;; Under certain configurations it's possible for url + ;; to be nil, when name is not, see #2858. + (url (magit-get "remote" name "url"))) + (magit-insert-section (remote name) + (insert (format "%-10s" "Remote: ")) + (insert (propertize name 'font-lock-face 'magit-branch-remote) ?\s) + (insert url ?\n)))) + +;;;; File Sections + +(defvar magit-untracked-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-delete-thing] 'magit-discard) + (define-key map "s" 'magit-stage) + map) + "Keymap for the `untracked' section.") + +(magit-define-section-jumper magit-jump-to-untracked "Untracked files" untracked) + +(defun magit-insert-untracked-files () + "Maybe insert a list or tree of untracked files. + +Do so depending on the value of `status.showUntrackedFiles'. +Note that even if the value is `all', Magit still initially +only shows directories. But the directory sections can then +be expanded using \"TAB\". + +If the first element of `magit-buffer-diff-files' is a +directory, then limit the list to files below that. The value +value of that variable can be set using \"D -- DIRECTORY RET g\"." + (let* ((show (or (magit-get "status.showUntrackedFiles") "normal")) + (base (car magit-buffer-diff-files)) + (base (and base (file-directory-p base) base))) + (unless (equal show "no") + (if (equal show "all") + (when-let ((files (magit-untracked-files nil base))) + (magit-insert-section (untracked) + (magit-insert-heading "Untracked files:") + (magit-insert-files files base) + (insert ?\n))) + (when-let ((files + (--mapcat (and (eq (aref it 0) ??) + (list (substring it 3))) + (magit-git-items "status" "-z" "--porcelain" + (magit-ignore-submodules-p t) + "--" base)))) + (magit-insert-section (untracked) + (magit-insert-heading "Untracked files:") + (dolist (file files) + (magit-insert-section (file file) + (insert (propertize file 'font-lock-face 'magit-filename) ?\n))) + (insert ?\n))))))) + +(magit-define-section-jumper magit-jump-to-tracked "Tracked files" tracked) + +(defun magit-insert-tracked-files () + "Insert a tree of tracked files. + +If the first element of `magit-buffer-diff-files' is a +directory, then limit the list to files below that. The value +value of that variable can be set using \"D -- DIRECTORY RET g\"." + (when-let ((files (magit-list-files))) + (let* ((base (car magit-buffer-diff-files)) + (base (and base (file-directory-p base) base))) + (magit-insert-section (tracked nil t) + (magit-insert-heading "Tracked files:") + (magit-insert-files files base) + (insert ?\n))))) + +(defun magit-insert-ignored-files () + "Insert a tree of ignored files. + +If the first element of `magit-buffer-diff-files' is a +directory, then limit the list to files below that. The value +of that variable can be set using \"D -- DIRECTORY RET g\"." + (when-let ((files (magit-ignored-files))) + (let* ((base (car magit-buffer-diff-files)) + (base (and base (file-directory-p base) base))) + (magit-insert-section (tracked nil t) + (magit-insert-heading "Ignored files:") + (magit-insert-files files base) + (insert ?\n))))) + +(magit-define-section-jumper magit-jump-to-skip-worktree "Skip-worktree files" skip-worktree) + +(defun magit-insert-skip-worktree-files () + "Insert a tree of skip-worktree files. + +If the first element of `magit-buffer-diff-files' is a +directory, then limit the list to files below that. The value +of that variable can be set using \"D -- DIRECTORY RET g\"." + (when-let ((files (magit-skip-worktree-files))) + (let* ((base (car magit-buffer-diff-files)) + (base (and base (file-directory-p base) base))) + (magit-insert-section (skip-worktree nil t) + (magit-insert-heading "Skip-worktree files:") + (magit-insert-files files base) + (insert ?\n))))) + +(magit-define-section-jumper magit-jump-to-assume-unchanged "Assume-unchanged files" assume-unchanged) + +(defun magit-insert-assume-unchanged-files () + "Insert a tree of files that are assumed to be unchanged. + +If the first element of `magit-buffer-diff-files' is a +directory, then limit the list to files below that. The value +of that variable can be set using \"D -- DIRECTORY RET g\"." + (when-let ((files (magit-assume-unchanged-files))) + (let* ((base (car magit-buffer-diff-files)) + (base (and base (file-directory-p base) base))) + (magit-insert-section (assume-unchanged nil t) + (magit-insert-heading "Assume-unchanged files:") + (magit-insert-files files base) + (insert ?\n))))) + +(defun magit-insert-files (files directory) + (while (and files (string-prefix-p (or directory "") (car files))) + (let ((dir (file-name-directory (car files)))) + (if (equal dir directory) + (let ((file (pop files))) + (magit-insert-section (file file) + (insert (propertize file 'font-lock-face 'magit-filename) ?\n))) + (magit-insert-section (file dir t) + (insert (propertize dir 'file 'magit-filename) ?\n) + (magit-insert-heading) + (setq files (magit-insert-files files dir)))))) + files) + +;;; _ +(provide 'magit-status) +;;; magit-status.el ends here diff --git a/elpa/magit-20220116.1908/magit-submodule.el b/elpa/magit-20220116.1908/magit-submodule.el new file mode 100644 index 00000000..a6d98231 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-submodule.el @@ -0,0 +1,703 @@ +;;; magit-submodule.el --- submodule support for Magit -*- lexical-binding: t -*- + +;; Copyright (C) 2011-2022 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) + +(defvar x-stretch-cursor) + +;;; Options + +(defcustom magit-module-sections-hook + '(magit-insert-modules-overview + magit-insert-modules-unpulled-from-upstream + magit-insert-modules-unpulled-from-pushremote + magit-insert-modules-unpushed-to-upstream + magit-insert-modules-unpushed-to-pushremote) + "Hook run by `magit-insert-modules'. + +That function isn't part of `magit-status-sections-hook's default +value, so you have to add it yourself for this hook to have any +effect." + :package-version '(magit . "2.11.0") + :group 'magit-status + :type 'hook) + +(defcustom magit-module-sections-nested t + "Whether `magit-insert-modules' wraps inserted sections. + +If this is non-nil, then only a single top-level section +is inserted. If it is nil, then all sections listed in +`magit-module-sections-hook' become top-level sections." + :package-version '(magit . "2.11.0") + :group 'magit-status + :type 'boolean) + +(defcustom magit-submodule-list-mode-hook '(hl-line-mode) + "Hook run after entering Magit-Submodule-List mode." + :package-version '(magit . "2.9.0") + :group 'magit-repolist + :type 'hook + :get 'magit-hook-custom-get + :options '(hl-line-mode)) + +(defcustom magit-submodule-list-columns + '(("Path" 25 magit-modulelist-column-path nil) + ("Version" 25 magit-repolist-column-version nil) + ("Branch" 20 magit-repolist-column-branch nil) + ("BU" 3 magit-repolist-column-unpushed-to-upstream ((:right-align t))) + ("BP" 3 magit-repolist-column-unpushed-to-pushremote ((:right-align t))) + ("B" 3 magit-repolist-column-branches ((:right-align t))) + ("S" 3 magit-repolist-column-stashes ((:right-align t)))) + "List of columns displayed by `magit-list-submodules'. + +Each element has the form (HEADER WIDTH FORMAT PROPS). + +HEADER is the string displayed in the header. WIDTH is the width +of the column. FORMAT is a function that is called with one +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'. + +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 + :type `(repeat (list :tag "Column" + (string :tag "Header Label") + (integer :tag "Column Width") + (function :tag "Inserter Function") + (repeat :tag "Properties" + (list (choice :tag "Property" + (const :right-align) + (const :pad-right) + (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. + +If this is nil, then that command does not offer to do so unless +a prefix argument is used. When this is t, then it does offer to +do so even without a prefix argument. + +In both cases the action still has to be confirmed unless that is +disabled using the option `magit-no-confirm'. Doing the latter +and also setting this variable to t will lead to tears." + :package-version '(magit . "2.90.0") + :group 'magit-commands + :type 'boolean) + +;;; Popup + +;;;###autoload (autoload 'magit-submodule "magit-submodule" nil t) +(transient-define-prefix magit-submodule () + "Act on a submodule." + :man-page "git-submodule" + ["Arguments" + ("-f" "Force" ("-f" "--force")) + ("-r" "Recursive" "--recursive") + ("-N" "Do not fetch" ("-N" "--no-fetch")) + ("-C" "Checkout tip" "--checkout") + ("-R" "Rebase onto tip" "--rebase") + ("-M" "Merge tip" "--merge") + ("-U" "Use upstream tip" "--remote")] + ["One module actions" + ("a" magit-submodule-add) + ("r" magit-submodule-register) + ("p" magit-submodule-populate) + ("u" magit-submodule-update) + ("s" magit-submodule-synchronize) + ("d" magit-submodule-unpopulate) + ("k" "Remove" magit-submodule-remove)] + ["All modules actions" + ("l" "List all modules" magit-list-submodules) + ("f" "Fetch all modules" magit-fetch-modules)]) + +(defun magit-submodule-arguments (&rest filters) + (--filter (and (member it filters) it) + (transient-args 'magit-submodule))) + +(defclass magit--git-submodule-suffix (transient-suffix) + ()) + +(cl-defmethod transient-format-description ((obj magit--git-submodule-suffix)) + (let ((value (delq nil (mapcar 'transient-infix-value transient--suffixes)))) + (replace-regexp-in-string + "\\[--[^]]+\\]" + (lambda (match) + (format (propertize "[%s]" 'face 'transient-inactive-argument) + (mapconcat (lambda (arg) + (propertize arg 'face + (if (member arg value) + 'transient-argument + 'transient-inactive-argument))) + (save-match-data + (split-string (substring match 1 -1) "|")) + (propertize "|" 'face 'transient-inactive-argument)))) + (cl-call-next-method obj)))) + +;;;###autoload (autoload 'magit-submodule-add "magit-submodule" nil t) +(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 +the superproject. If it is nil, then the path is determined +based on the URL. Optional NAME is the name of the module. If +it is nil, then PATH also becomes the name." + :class 'magit--git-submodule-suffix + :description "Add git submodule add [--force]" + (interactive + (magit-with-toplevel + (let* ((url (magit-read-string-ns "Add submodule (remote url)")) + (path (let ((read-file-name-function + (if (or (eq read-file-name-function 'ido-read-file-name) + (advice-function-member-p + 'ido-read-file-name + read-file-name-function)) + ;; The Ido variant doesn't work properly here. + #'read-file-name-default + read-file-name-function))) + (directory-file-name + (file-relative-name + (read-directory-name + "Add submodules at path: " nil nil nil + (and (string-match "\\([^./]+\\)\\(\\.git\\)?$" url) + (match-string 1 url)))))))) + (list url + (directory-file-name path) + (magit-submodule-read-name-for-path path) + (magit-submodule-arguments "--force"))))) + (magit-submodule-add-1 url path name args)) + +(defun magit-submodule-add-1 (url &optional path name args) + (magit-with-toplevel + (magit-submodule--maybe-reuse-gitdir name path) + (magit-run-git-async "submodule" "add" + (and name (list "--name" name)) + args "--" url path) + (set-process-sentinel + magit-this-process + (lambda (process event) + (when (memq (process-status process) '(exit signal)) + (if (> (process-exit-status process) 0) + (magit-process-sentinel process event) + (process-put process 'inhibit-refresh t) + (magit-process-sentinel process event) + (when (magit-git-version>= "2.12.0") + (magit-call-git "submodule" "absorbgitdirs" path)) + (magit-refresh))))))) + +;;;###autoload +(defun magit-submodule-read-name-for-path (path &optional prefer-short) + (let* ((path (directory-file-name (file-relative-name path))) + (name (file-name-nondirectory path))) + (push (if prefer-short path name) minibuffer-history) + (magit-read-string-ns + "Submodule name" nil (cons 'minibuffer-history 2) + (or (--keep (pcase-let ((`(,var ,val) (split-string it "="))) + (and (equal val path) + (cadr (split-string var "\\.")))) + (magit-git-lines "config" "--list" "-f" ".gitmodules")) + (if prefer-short name path))))) + +;;;###autoload (autoload 'magit-submodule-register "magit-submodule" nil t) +(transient-define-suffix magit-submodule-register (modules) + "Register MODULES. + +With a prefix argument act on all suitable modules. Otherwise, +if the region selects modules, then act on those. Otherwise, if +there is a module at point, then act on that. Otherwise read a +single module from the user." + ;; This command and the underlying "git submodule init" do NOT + ;; "initialize" modules. They merely "register" modules in the + ;; super-projects $GIT_DIR/config file, the purpose of which is to + ;; allow users to change such values before actually initializing + ;; the modules. + :description "Register git submodule init" + (interactive + (list (magit-module-confirm "Register" 'magit-module-no-worktree-p))) + (magit-with-toplevel + (magit-run-git-async "submodule" "init" "--" modules))) + +;;;###autoload (autoload 'magit-submodule-populate "magit-submodule" nil t) +(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, +if the region selects modules, then act on those. Otherwise, if +there is a module at point, then act on that. Otherwise read a +single module from the user." + ;; This is the command that actually "initializes" modules. + ;; A module is initialized when it has a working directory, + ;; a gitlink, and a .gitmodules entry. + :description "Populate git submodule update --init" + (interactive + (list (magit-module-confirm "Populate" 'magit-module-no-worktree-p))) + (magit-with-toplevel + (magit-run-git-async "submodule" "update" "--init" "--" modules))) + +;;;###autoload (autoload 'magit-submodule-update "magit-submodule" nil t) +(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, +if the region selects modules, then act on those. Otherwise, if +there is a module at point, then act on that. Otherwise read a +single module from the user." + ;; Unlike `git-submodule's `update' command ours can only update + ;; "initialized" modules by checking out other commits but not + ;; "initialize" modules by creating the working directories. + ;; To do the latter we provide the "setup" command. + :class 'magit--git-submodule-suffix + :description "Update git submodule update [--force] [--no-fetch] + [--remote] [--recursive] [--checkout|--rebase|--merge]" + (interactive + (list (magit-module-confirm "Update" 'magit-module-worktree-p) + (magit-submodule-arguments + "--force" "--remote" "--recursive" "--checkout" "--rebase" "--merge" + "--no-fetch"))) + (magit-with-toplevel + (magit-run-git-async "submodule" "update" args "--" modules))) + +;;;###autoload (autoload 'magit-submodule-synchronize "magit-submodule" nil t) +(transient-define-suffix magit-submodule-synchronize (modules args) + "Synchronize url configuration of MODULES. + +With a prefix argument act on all suitable modules. Otherwise, +if the region selects modules, then act on those. Otherwise, if +there is a module at point, then act on that. Otherwise read a +single module from the user." + :class 'magit--git-submodule-suffix + :description "Synchronize git submodule sync [--recursive]" + (interactive + (list (magit-module-confirm "Synchronize" 'magit-module-worktree-p) + (magit-submodule-arguments "--recursive"))) + (magit-with-toplevel + (magit-run-git-async "submodule" "sync" args "--" modules))) + +;;;###autoload (autoload 'magit-submodule-unpopulate "magit-submodule" nil t) +(transient-define-suffix magit-submodule-unpopulate (modules args) + "Remove working directories of MODULES. + +With a prefix argument act on all suitable modules. Otherwise, +if the region selects modules, then act on those. Otherwise, if +there is a module at point, then act on that. Otherwise read a +single module from the user." + ;; Even though a package is "uninitialized" (it has no worktree) + ;; the super-projects $GIT_DIR/config may never-the-less set the + ;; module's url. This may happen if you `deinit' and then `init' + ;; to register (NOT initialize). Because the purpose of `deinit' + ;; is to remove the working directory AND to remove the url, this + ;; command does not limit itself to modules that have no working + ;; directory. + :class 'magit--git-submodule-suffix + :description "Unpopulate git submodule deinit [--force]" + (interactive + (list (magit-module-confirm "Unpopulate") + (magit-submodule-arguments "--force"))) + (magit-with-toplevel + (magit-run-git-async "submodule" "deinit" args "--" modules))) + +;;;###autoload +(defun magit-submodule-remove (modules args trash-gitdirs) + "Unregister MODULES and remove their working directories. + +For safety reasons, do not remove the gitdirs and if a module has +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. + +With the \"--force\" argument offer to remove dirty working +directories and with a prefix argument offer to delete gitdirs. +Both actions are very dangerous and have to be confirmed. There +are additional safety precautions in place, so you might be able +to recover from making a mistake here, but don't count on it." + (interactive + (list (if-let ((modules (magit-region-values 'magit-module-section t))) + (magit-confirm 'remove-modules nil "Remove %i modules" nil modules) + (list (magit-read-module-path "Remove module"))) + (magit-submodule-arguments "--force") + current-prefix-arg)) + (when (magit-git-version< "2.12.0") + (error "This command requires Git v2.12.0")) + (when magit-submodule-remove-trash-gitdirs + (setq trash-gitdirs t)) + (magit-with-toplevel + (when-let + ((modified + (-filter (lambda (module) + (let ((default-directory (file-name-as-directory + (expand-file-name module)))) + (and (cddr (directory-files default-directory)) + (magit-anything-modified-p)))) + modules))) + (if (member "--force" args) + (if (magit-confirm 'remove-dirty-modules + "Remove dirty module %s" + "Remove %i dirty modules" + t modified) + (dolist (module modified) + (let ((default-directory (file-name-as-directory + (expand-file-name module)))) + (magit-git "stash" "push" + "-m" "backup before removal of this module"))) + (setq modules (cl-set-difference modules modified :test #'equal))) + (if (cdr modified) + (message "Omitting %s modules with uncommitted changes: %s" + (length modified) + (mapconcat #'identity modified ", ")) + (message "Omitting module %s, it has uncommitted changes" + (car modified))) + (setq modules (cl-set-difference modules modified :test #'equal)))) + (when modules + (let ((alist + (and trash-gitdirs + (--map (split-string it "\0") + (magit-git-lines "submodule" "foreach" "-q" + "printf \"$sm_path\\0$name\n\""))))) + (magit-git "submodule" "absorbgitdirs" "--" modules) + (magit-git "submodule" "deinit" args "--" modules) + (magit-git "rm" args "--" modules) + (when (and trash-gitdirs + (magit-confirm 'trash-module-gitdirs + "Trash gitdir of module %s" + "Trash gitdirs of %i modules" + t modules)) + (dolist (module modules) + (if-let ((name (cadr (assoc module alist)))) + ;; Disregard if `magit-delete-by-moving-to-trash' + ;; is nil. Not doing so would be too dangerous. + (delete-directory (magit-git-dir + (convert-standard-filename + (concat "modules/" name))) + t t) + (error "BUG: Weird module name and/or path for %s" module))))) + (magit-refresh)))) + +;;; Sections + +;;;###autoload +(defun magit-insert-modules () + "Insert submodule sections. +Hook `magit-module-sections-hook' controls which module sections +are inserted, and option `magit-module-sections-nested' controls +whether they are wrapped in an additional section." + (when-let ((modules (magit-list-module-paths))) + (if magit-module-sections-nested + (magit-insert-section (modules nil t) + (magit-insert-heading + (format "%s (%s)" + (propertize "Modules" + 'font-lock-face 'magit-section-heading) + (length modules))) + (magit-insert-section-body + (magit--insert-modules))) + (magit--insert-modules)))) + +(defun magit--insert-modules (&optional _section) + (magit-run-section-hook 'magit-module-sections-hook)) + +;;;###autoload +(defun magit-insert-modules-overview () + "Insert sections for all modules. +For each section insert the path and the output of `git describe --tags', +or, failing that, the abbreviated HEAD commit hash." + (when-let ((modules (magit-list-module-paths))) + (magit-insert-section (modules nil t) + (magit-insert-heading + (format "%s (%s)" + (propertize "Modules overview" + 'font-lock-face 'magit-section-heading) + (length modules))) + (magit-insert-section-body + (magit--insert-modules-overview))))) + +(defvar magit-modules-overview-align-numbers t) + +(defun magit--insert-modules-overview (&optional _section) + (magit-with-toplevel + (let* ((modules (magit-list-module-paths)) + (path-format (format "%%-%is " + (min (apply 'max (mapcar 'length modules)) + (/ (window-width) 2)))) + (branch-format (format "%%-%is " (min 25 (/ (window-width) 3))))) + (dolist (module modules) + (let ((default-directory + (expand-file-name (file-name-as-directory module)))) + (magit-insert-section (magit-module-section module t) + (insert (propertize (format path-format module) + 'font-lock-face 'magit-diff-file-heading)) + (if (not (file-exists-p ".git")) + (insert "(unpopulated)") + (insert (format + branch-format + (--if-let (magit-get-current-branch) + (propertize it 'font-lock-face 'magit-branch-local) + (propertize "(detached)" 'font-lock-face 'warning)))) + (--if-let (magit-git-string "describe" "--tags") + (progn (when (and magit-modules-overview-align-numbers + (string-match-p "\\`[0-9]" it)) + (insert ?\s)) + (insert (propertize it 'font-lock-face 'magit-tag))) + (--when-let (magit-rev-format "%h") + (insert (propertize it 'font-lock-face 'magit-hash))))) + (insert ?\n)))))) + (insert ?\n)) + +(defvar magit-modules-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] 'magit-list-submodules) + map) + "Keymap for `modules' sections.") + +(defvar magit-module-section-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-file-section-map) + (define-key map (kbd "C-j") 'magit-submodule-visit) + (define-key map [C-return] 'magit-submodule-visit) + (define-key map [remap magit-visit-thing] 'magit-submodule-visit) + (define-key map [remap magit-delete-thing] 'magit-submodule-unpopulate) + (define-key map "K" 'magit-file-untrack) + (define-key map "R" 'magit-file-rename) + map) + "Keymap for `module' sections.") + +(defun magit-submodule-visit (module &optional other-window) + "Visit MODULE by calling `magit-status' on it. +Offer to initialize MODULE if it's not checked out yet. +With a prefix argument, visit in another window." + (interactive (list (or (magit-section-value-if 'module) + (magit-read-module-path "Visit module")) + current-prefix-arg)) + (magit-with-toplevel + (let ((path (expand-file-name module))) + (cond + ((file-exists-p (expand-file-name ".git" module)) + (magit-diff-visit-directory path other-window)) + ((y-or-n-p (format "Initialize submodule '%s' first?" module)) + (magit-run-git-async "submodule" "update" "--init" "--" module) + (set-process-sentinel + magit-this-process + (lambda (process event) + (let ((magit-process-raise-error t)) + (magit-process-sentinel process event)) + (when (and (eq (process-status process) 'exit) + (= (process-exit-status process) 0)) + (magit-diff-visit-directory path other-window))))) + ((file-exists-p path) + (dired-jump other-window (concat path "/."))))))) + +;;;###autoload +(defun magit-insert-modules-unpulled-from-upstream () + "Insert sections for modules that haven't been pulled from the upstream. +These sections can be expanded to show the respective commits." + (magit--insert-modules-logs "Modules unpulled from @{upstream}" + 'modules-unpulled-from-upstream + "HEAD..@{upstream}")) + +;;;###autoload +(defun magit-insert-modules-unpulled-from-pushremote () + "Insert sections for modules that haven't been pulled from the push-remote. +These sections can be expanded to show the respective commits." + (magit--insert-modules-logs "Modules unpulled from @{push}" + 'modules-unpulled-from-pushremote + "HEAD..@{push}")) + +;;;###autoload +(defun magit-insert-modules-unpushed-to-upstream () + "Insert sections for modules that haven't been pushed to the upstream. +These sections can be expanded to show the respective commits." + (magit--insert-modules-logs "Modules unmerged into @{upstream}" + 'modules-unpushed-to-upstream + "@{upstream}..HEAD")) + +;;;###autoload +(defun magit-insert-modules-unpushed-to-pushremote () + "Insert sections for modules that haven't been pushed to the push-remote. +These sections can be expanded to show the respective commits." + (magit--insert-modules-logs "Modules unpushed to @{push}" + 'modules-unpushed-to-pushremote + "@{push}..HEAD")) + +(defun magit--insert-modules-logs (heading type range) + "For internal use, don't add to a hook." + (unless (magit-ignore-submodules-p) + (when-let ((modules (magit-list-module-paths))) + (magit-insert-section section ((eval type) nil t) + (string-match "\\`\\(.+\\) \\([^ ]+\\)\\'" heading) + (magit-insert-heading + (propertize (match-string 1 heading) + 'font-lock-face 'magit-section-heading) + " " + (propertize (match-string 2 heading) + 'font-lock-face 'magit-branch-remote) + ":") + (magit-with-toplevel + (dolist (module modules) + (when (magit-module-worktree-p module) + (let ((default-directory + (expand-file-name (file-name-as-directory module)))) + (when (magit-file-accessible-directory-p default-directory) + (magit-insert-section sec (magit-module-section module t) + (magit-insert-heading + (propertize module + 'font-lock-face 'magit-diff-file-heading) + ":") + (magit-git-wash + (apply-partially 'magit-log-wash-log 'module) + "-c" "push.default=current" "log" "--oneline" range) + (when (> (point) + (oref sec content)) + (delete-char -1)))))))) + (if (> (point) + (oref section content)) + (insert ?\n) + (magit-cancel-section)))))) + +;;; List + +;;;###autoload +(defun magit-list-submodules () + "Display a list of the current repository's submodules." + (interactive) + (magit-submodule-list-setup magit-submodule-list-columns)) + +(defvar magit-submodule-list-mode-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map magit-repolist-mode-map) + map) + "Local keymap for Magit-Submodule-List mode buffers.") + +(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) + (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)) + +(defvar-local magit-submodule-list-predicate nil) + +(defun magit-submodule-list-setup (columns &optional predicate) + (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) + (setq-local magit-submodule-list-predicate predicate) + (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 + (expand-file-name (file-name-as-directory module)))) + (and (file-exists-p ".git") + (or (not magit-submodule-list-predicate) + (funcall magit-submodule-list-predicate module)) + (list module + (vconcat + (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 t) + (message "Listing submodules...done")) + +(defun magit-modulelist-column-path (spec) + "Insert the relative path of the submodule." + (cadr (assq :path spec))) + +;;; Utilities + +(defun magit-submodule--maybe-reuse-gitdir (name path) + (let ((gitdir + (magit-git-dir (convert-standard-filename (concat "modules/" name))))) + (when (and (file-exists-p gitdir) + (not (file-exists-p path))) + (pcase (read-char-choice + (concat + gitdir " already exists.\n" + "Type [u] to use the existing gitdir and create the working tree\n" + " [r] to rename the existing gitdir and clone again\n" + " [t] to trash the existing gitdir and clone again\n" + " [C-g] to abort ") + '(?u ?r ?t)) + (?u (magit-submodule--restore-worktree (expand-file-name path) gitdir)) + (?r (rename-file gitdir (concat gitdir "-" + (format-time-string "%F-%T")))) + (?t (delete-directory gitdir t t)))))) + +(defun magit-submodule--restore-worktree (worktree gitdir) + (make-directory worktree t) + (with-temp-file (expand-file-name ".git" worktree) + (insert "gitdir: " (file-relative-name gitdir worktree) "\n")) + (let ((default-directory worktree)) + (magit-call-git "reset" "--hard" "HEAD" "--"))) + +;;; _ +(provide 'magit-submodule) +;;; magit-submodule.el ends here diff --git a/elpa/magit-20220116.1908/magit-subtree.el b/elpa/magit-20220116.1908/magit-subtree.el new file mode 100644 index 00000000..3d0514ed --- /dev/null +++ b/elpa/magit-20220116.1908/magit-subtree.el @@ -0,0 +1,184 @@ +;;; magit-subtree.el --- subtree support for Magit -*- lexical-binding: t -*- + +;; Copyright (C) 2011-2022 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-subtree "magit-subtree" nil t) +(transient-define-prefix magit-subtree () + "Import or export subtrees." + :man-page "git-subtree" + ["Actions" + ("i" "Import" magit-subtree-import) + ("e" "Export" magit-subtree-export)]) + +;;;###autoload (autoload 'magit-subtree-import "magit-subtree" nil t) +(transient-define-prefix magit-subtree-import () + "Import subtrees." + :man-page "git-subtree" + ["Arguments" + (magit-subtree:--prefix) + (magit-subtree:--message) + ("-s" "Squash" "--squash")] + ["Actions" + [("a" "Add" magit-subtree-add) + ("c" "Add commit" magit-subtree-add-commit)] + [("m" "Merge" magit-subtree-merge) + ("f" "Pull" magit-subtree-pull)]]) + +;;;###autoload (autoload 'magit-subtree-export "magit-subtree" nil t) +(transient-define-prefix magit-subtree-export () + "Export subtrees." + :man-page "git-subtree" + ["Arguments" + (magit-subtree:--prefix) + (magit-subtree:--annotate) + (magit-subtree:--branch) + (magit-subtree:--onto) + ("-i" "Ignore joins" "--ignore-joins") + ("-j" "Rejoin" "--rejoin")] + ["Actions" + ("p" "Push" magit-subtree-push) + ("s" "Split" magit-subtree-split)]) + +(transient-define-argument magit-subtree:--prefix () + :description "Prefix" + :class 'transient-option + :shortarg "-P" + :argument "--prefix=" + :reader 'magit-subtree-read-prefix) + +(defun magit-subtree-read-prefix (prompt &optional default _history) + (let* ((insert-default-directory nil) + (topdir (magit-toplevel)) + (prefix (read-directory-name (concat prompt ": ") topdir default))) + (if (file-name-absolute-p prefix) + ;; At least `ido-mode's variant is not compatible. + (if (string-prefix-p topdir prefix) + (file-relative-name prefix topdir) + (user-error "%s isn't inside the repository at %s" prefix topdir)) + prefix))) + +(transient-define-argument magit-subtree:--message () + :description "Message" + :class 'transient-option + :shortarg "-m" + :argument "--message=") + +(transient-define-argument magit-subtree:--annotate () + :description "Annotate" + :class 'transient-option + :key "-a" + :argument "--annotate=") + +(transient-define-argument magit-subtree:--branch () + :description "Branch" + :class 'transient-option + :shortarg "-b" + :argument "--branch=") + +(transient-define-argument magit-subtree:--onto () + :description "Onto" + :class 'transient-option + :key "-o" + :argument "--onto=" + :reader 'magit-transient-read-revision) + +(defun magit-subtree-prefix (transient prompt) + (--if-let (--first (string-prefix-p "--prefix=" it) + (transient-args transient)) + (substring it 9) + (magit-subtree-read-prefix prompt))) + +(defun magit-subtree-arguments (transient) + (--remove (string-prefix-p "--prefix=" it) + (transient-args transient))) + +(defun magit-git-subtree (subcmd prefix &rest args) + (magit-run-git-async "subtree" subcmd (concat "--prefix=" prefix) args)) + +;;;###autoload +(defun magit-subtree-add (prefix repository ref args) + "Add REF from REPOSITORY as a new subtree at PREFIX." + (interactive + (cons (magit-subtree-prefix 'magit-subtree-import "Add subtree") + (let ((remote (magit-read-remote-or-url "From repository"))) + (list remote + (magit-read-refspec "Ref" remote) + (magit-subtree-arguments 'magit-subtree-import))))) + (magit-git-subtree "add" prefix args repository ref)) + +;;;###autoload +(defun magit-subtree-add-commit (prefix commit args) + "Add COMMIT as a new subtree at PREFIX." + (interactive + (list (magit-subtree-prefix 'magit-subtree-import "Add subtree") + (magit-read-string-ns "Commit") + (magit-subtree-arguments 'magit-subtree-import))) + (magit-git-subtree "add" prefix args commit)) + +;;;###autoload +(defun magit-subtree-merge (prefix commit args) + "Merge COMMIT into the PREFIX subtree." + (interactive + (list (magit-subtree-prefix 'magit-subtree-import "Merge into subtree") + (magit-read-string-ns "Commit") + (magit-subtree-arguments 'magit-subtree-import))) + (magit-git-subtree "merge" prefix args commit)) + +;;;###autoload +(defun magit-subtree-pull (prefix repository ref args) + "Pull REF from REPOSITORY into the PREFIX subtree." + (interactive + (cons (magit-subtree-prefix 'magit-subtree-import "Pull into subtree") + (let ((remote (magit-read-remote-or-url "From repository"))) + (list remote + (magit-read-refspec "Ref" remote) + (magit-subtree-arguments 'magit-subtree-import))))) + (magit-git-subtree "pull" prefix args repository ref)) + +;;;###autoload +(defun magit-subtree-push (prefix repository ref args) + "Extract the history of the subtree PREFIX and push it to REF on REPOSITORY." + (interactive (list (magit-subtree-prefix 'magit-subtree-export "Push subtree") + (magit-read-remote-or-url "To repository") + (magit-read-string-ns "To reference") + (magit-subtree-arguments 'magit-subtree-export))) + (magit-git-subtree "push" prefix args repository ref)) + +;;;###autoload +(defun magit-subtree-split (prefix commit args) + "Extract the history of the subtree PREFIX." + (interactive (list (magit-subtree-prefix 'magit-subtree-export "Split subtree") + (magit-read-string-ns "Commit") + (magit-subtree-arguments 'magit-subtree-export))) + (magit-git-subtree "split" prefix args commit)) + +;;; _ +(provide 'magit-subtree) +;;; magit-subtree.el ends here diff --git a/elpa/magit-20220116.1908/magit-tag.el b/elpa/magit-20220116.1908/magit-tag.el new file mode 100644 index 00000000..c10a46c8 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-tag.el @@ -0,0 +1,219 @@ +;;; magit-tag.el --- tag functionality -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements tag commands. + +;;; Code: + +(require 'magit) + +;; For `magit-tag-delete'. +(defvar helm-comp-read-use-marked) + +;;;###autoload (autoload 'magit-tag "magit" nil t) +(transient-define-prefix magit-tag () + "Create or delete a tag." + :man-page "git-tag" + ["Arguments" + ("-f" "Force" ("-f" "--force")) + ("-a" "Annotate" ("-a" "--annotate")) + ("-s" "Sign" ("-s" "--sign")) + (magit-tag:--local-user)] + [["Create" + ("t" "tag" magit-tag-create) + ("r" "release" magit-tag-release)] + ["Do" + ("k" "delete" magit-tag-delete) + ("p" "prune" magit-tag-prune)]]) + +(defun magit-tag-arguments () + (transient-args 'magit-tag)) + +(transient-define-argument magit-tag:--local-user () + :description "Sign as" + :class 'transient-option + :shortarg "-u" + :argument "--local-user=" + :reader 'magit-read-gpg-signing-key + :history-key 'magit:--gpg-sign) + +;;;###autoload +(defun magit-tag-create (name rev &optional args) + "Create a new tag with the given NAME at REV. +With a prefix argument annotate the tag. +\n(git tag [--annotate] NAME REV)" + (interactive (list (magit-read-tag "Tag name") + (magit-read-branch-or-commit "Place tag on") + (let ((args (magit-tag-arguments))) + (when current-prefix-arg + (cl-pushnew "--annotate" args)) + args))) + (magit-run-git-with-editor "tag" args name rev)) + +;;;###autoload +(defun magit-tag-delete (tags) + "Delete one or more tags. +If the region marks multiple tags (and nothing else), then offer +to delete those, otherwise prompt for a single tag to be deleted, +defaulting to the tag at point. +\n(git tag -d TAGS)" + (interactive (list (--if-let (magit-region-values 'tag) + (magit-confirm t nil "Delete %i tags" nil it) + (let ((helm-comp-read-use-marked t)) + (magit-read-tag "Delete tag" t))))) + (magit-run-git "tag" "-d" tags)) + +;;;###autoload +(defun magit-tag-prune (tags remote-tags remote) + "Offer to delete tags missing locally from REMOTE, and vice versa." + (interactive + (let* ((remote (magit-read-remote "Prune tags using remote")) + (tags (magit-list-tags)) + (rtags (prog2 (message "Determining remote tags...") + (magit-remote-list-tags remote) + (message "Determining remote tags...done"))) + (ltags (-difference tags rtags)) + (rtags (-difference rtags tags))) + (unless (or ltags rtags) + (message "Same tags exist locally and remotely")) + (unless (magit-confirm t + "Delete %s locally" + "Delete %i tags locally" + 'noabort ltags) + (setq ltags nil)) + (unless (magit-confirm t + "Delete %s from remote" + "Delete %i tags from remote" + 'noabort rtags) + (setq rtags nil)) + (list ltags rtags remote))) + (when tags + (magit-call-git "tag" "-d" tags)) + (when remote-tags + (magit-run-git-async "push" remote (--map (concat ":" it) remote-tags)))) + +(defvar magit-tag-version-regexp-alist + '(("^[-._+ ]?snapshot\\.?$" . -4) + ("^[-._+]$" . -4) + ("^[-._+ ]?\\(cvs\\|git\\|bzr\\|svn\\|hg\\|darcs\\)\\.?$" . -4) + ("^[-._+ ]?unknown\\.?$" . -4) + ("^[-._+ ]?alpha\\.?$" . -3) + ("^[-._+ ]?beta\\.?$" . -2) + ("^[-._+ ]?\\(pre\\|rc\\)\\.?$" . -1)) + "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 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 &optional args) + "Create a release tag. + +Assume that release tags match `magit-release-tag-regexp'. + +First prompt 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. + +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* + ((`(,pver ,ptag ,pmsg) (car (magit--list-releases))) + (tag (read-string "Create release tag: " ptag)) + (ver (and (string-match magit-release-tag-regexp tag) + (match-string 2 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) + (when (memq (process-status process) '(exit signal)) + (magit-process-sentinel process event) + (magit-refs-setup-buffer "HEAD" (magit-show-refs-arguments)))))) + +(defun magit--list-releases () + "Return a list of releases. +The list is ordered, beginning with the highest release. +Each release element has the form (VERSION TAG MESSAGE). +`magit-release-tag-regexp' is used to determine whether +a tag qualifies as a release tag." + (save-match-data + (mapcar + #'cdr + (nreverse + (cl-sort (cl-mapcan + (lambda (line) + (and (string-match " +" line) + (let ((tag (substring line 0 (match-beginning 0))) + (msg (substring line (match-end 0)))) + (and (string-match magit-release-tag-regexp tag) + (let ((ver (match-string 2 tag)) + (version-regexp-alist + magit-tag-version-regexp-alist)) + (list (list (version-to-list ver) + ver tag msg))))))) + ;; Cannot rely on "--sort=-version:refname" because + ;; that gets confused if the version prefix has changed. + (magit-git-lines "tag" "-n")) + ;; The inverse of this function does not exist. + #'version-list-< :key #'car))))) + +;;; _ +(provide 'magit-tag) +;;; magit-tag.el ends here diff --git a/elpa/magit-20220116.1908/magit-transient.el b/elpa/magit-20220116.1908/magit-transient.el new file mode 100644 index 00000000..8d6d582f --- /dev/null +++ b/elpa/magit-20220116.1908/magit-transient.el @@ -0,0 +1,200 @@ +;;; magit-transient.el --- support for transients -*- lexical-binding: t -*- + +;; Copyright (C) 2008-2022 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. + +;;; Commentary: + +;; This library implements Magit-specific prefix and suffix classes, +;; and their methods. + +;;; Code: + +(require 'magit-git) +(require 'magit-mode) +(require 'magit-process) + +(require 'transient) + +;;; Classes + +(defclass magit--git-variable (transient-variable) + ((scope :initarg :scope))) + +(defclass magit--git-variable:choices (magit--git-variable) + ((choices :initarg :choices) + (fallback :initarg :fallback :initform nil) + (default :initarg :default :initform nil))) + +(defclass magit--git-variable:urls (magit--git-variable) + ((seturl-arg :initarg :seturl-arg :initform nil))) + +;;; Methods +;;;; Init + +(cl-defmethod transient-init-scope ((obj magit--git-variable)) + (oset obj scope + (cond (transient--prefix + (oref transient--prefix scope)) + ((slot-boundp obj 'scope) + (funcall (oref obj scope) obj))))) + +(cl-defmethod transient-init-value ((obj magit--git-variable)) + (let ((variable (format (oref obj variable) + (oref obj scope)))) + (oset obj variable variable) + (oset obj value + (cond ((oref obj multi-value) + (magit-get-all variable)) + (t + (magit-git-string "config" "--local" variable)))))) + +;;;; Read + +(cl-defmethod transient-infix-read :around ((obj magit--git-variable:urls)) + (mapcar (lambda (url) + (if (string-prefix-p "~" url) + (expand-file-name url) + url)) + (cl-call-next-method obj))) + +(cl-defmethod transient-infix-read ((obj magit--git-variable:choices)) + (let ((choices (oref obj choices))) + (when (functionp choices) + (setq choices (funcall choices))) + (if-let ((value (oref obj value))) + (cadr (member value choices)) + (car choices)))) + +;;;; Readers + +(defun magit-transient-read-person (prompt initial-input history) + (magit-completing-read + prompt + (mapcar (lambda (line) + (save-excursion + (and (string-match "\\`[\s\t]+[0-9]+\t" line) + (list (substring line (match-end 0)))))) + (magit-git-lines "shortlog" "-n" "-s" "-e" "HEAD")) + nil nil initial-input history)) + +(defun magit-transient-read-revision (prompt initial-input history) + (or (magit-completing-read prompt (cons "HEAD" (magit-list-refnames)) + nil nil initial-input history + (or (magit-branch-or-commit-at-point) + (magit-get-current-branch))) + (user-error "Nothing selected"))) + +;;;; Set + +(cl-defmethod transient-infix-set ((obj magit--git-variable) value) + (let ((variable (oref obj variable))) + (oset obj value value) + (if (oref obj multi-value) + (magit-set-all value variable) + (magit-set value variable)) + (magit-refresh) + (unless (or value transient--prefix) + (message "Unset %s" variable)))) + +(cl-defmethod transient-infix-set ((obj magit--git-variable:urls) values) + (let ((previous (oref obj value)) + (seturl (oref obj seturl-arg)) + (remote (oref transient--prefix scope))) + (oset obj value values) + (dolist (v (-difference values previous)) + (magit-call-git "remote" "set-url" seturl "--add" remote v)) + (dolist (v (-difference previous values)) + (magit-call-git "remote" "set-url" seturl "--delete" remote + (concat "^" (regexp-quote v) "$"))) + (magit-refresh))) + +;;;; Draw + +(cl-defmethod transient-format-description ((obj magit--git-variable)) + (or (oref obj description) + (oref obj variable))) + +(cl-defmethod transient-format-value ((obj magit--git-variable)) + (if-let ((value (oref obj value))) + (if (oref obj multi-value) + (if (cdr value) + (mapconcat (lambda (v) + (concat "\n " + (propertize v 'face 'transient-value))) + value "") + (propertize (car value) 'face 'transient-value)) + (propertize (car (split-string value "\n")) + 'face 'transient-value)) + (propertize "unset" 'face 'transient-inactive-value))) + +(cl-defmethod transient-format-value ((obj magit--git-variable:choices)) + (let* ((variable (oref obj variable)) + (choices (oref obj choices)) + (local (magit-git-string "config" "--local" variable)) + (global (magit-git-string "config" "--global" variable)) + (default (oref obj default)) + (fallback (oref obj fallback)) + (fallback (and fallback + (when-let ((val (magit-get fallback))) + (concat fallback ":" val))))) + (when (functionp choices) + (setq choices (funcall choices))) + (concat + (propertize "[" 'face 'transient-inactive-value) + (mapconcat (lambda (choice) + (propertize choice 'face (if (equal choice local) + (if (member choice choices) + 'transient-value + 'font-lock-warning-face) + 'transient-inactive-value))) + (if (and local (not (member local choices))) + (cons local choices) + choices) + (propertize "|" 'face 'transient-inactive-value)) + (and (or global fallback default) + (concat + (propertize "|" 'face 'transient-inactive-value) + (cond (global + (propertize (concat "global:" global) + 'face (cond (local + 'transient-inactive-value) + ((member global choices) + 'transient-value) + (t + 'font-lock-warning-face)))) + (fallback + (propertize fallback + 'face (if local + 'transient-inactive-value + 'transient-value))) + (default + (propertize (concat "default:" default) + 'face (if local + 'transient-inactive-value + 'transient-value)))))) + (propertize "]" 'face 'transient-inactive-value)))) + +;;; _ +(provide 'magit-transient) +;;; magit-transient.el ends here diff --git a/elpa/magit-20220116.1908/magit-utils.el b/elpa/magit-20220116.1908/magit-utils.el new file mode 100644 index 00000000..473b7041 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-utils.el @@ -0,0 +1,1263 @@ +;;; magit-utils.el --- various utilities -*- lexical-binding: t; coding: utf-8 -*- + +;; Copyright (C) 2010-2022 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 + +;; 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) +;; 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. + +;;; Commentary: + +;; This library defines several utility functions used by several +;; other libraries which cannot depend on one another (because +;; circular dependencies are not good). Luckily most (all) of these +;; functions have very little (nothing) to do with Git, so we not only +;; have to do this, it even makes sense. + +;; Unfortunately there are also some options which are used by several +;; libraries which cannot depend on one another, they are defined here +;; too. + +;;; Code: + +(require 'cl-lib) +(require 'dash) +(require 'eieio) +(require 'seq) +(require 'subr-x) + +(require 'crm) + +(eval-when-compile (require 'ido)) +(declare-function Info-get-token "info" (pos start all &optional errorstring)) + +(eval-when-compile (require 'vc-git)) +(declare-function vc-git--run-command-string "vc-git" (file &rest args)) + +(eval-when-compile (require 'which-func)) +(declare-function which-function "which-func" ()) + +(defvar magit-wip-before-change-mode) + +;;; Options + +(defcustom magit-completing-read-function 'magit-builtin-completing-read + "Function to be called when requesting input from the user. + +If you have enabled `ivy-mode' or `helm-mode', then you don't +have to customize this option; `magit-builtin-completing-read' +will work just fine. However, if you use Ido completion, then +you do have to use `magit-ido-completing-read', because Ido is +less well behaved than the former, more modern alternatives. + +If you would like to use Ivy or Helm completion with Magit but +not enable the respective modes globally, then customize this +option to use `ivy-completing-read' or +`helm--completing-read-default'. If you choose to use +`ivy-completing-read', note that the items may always be shown in +alphabetical order, depending on your version of Ivy." + :group 'magit-essentials + :type '(radio (function-item magit-builtin-completing-read) + (function-item magit-ido-completing-read) + (function-item ivy-completing-read) + (function-item helm--completing-read-default) + (function :tag "Other function"))) + +(defcustom magit-dwim-selection + '((magit-stash-apply nil t) + (magit-stash-branch nil t) + (magit-stash-branch-here nil t) + (magit-stash-format-patch nil t) + (magit-stash-drop nil ask) + (magit-stash-pop nil ask) + (forge-browse-dwim nil t) + (forge-browse-commit nil t) + (forge-browse-branch nil t) + (forge-browse-remote nil t) + (forge-browse-issue nil t) + (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-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 +possible candidates. They do so even when there is a thing at +point that they can act on, which is then offered as the default. + +This option can be used to tell certain commands to use the thing +at point instead of asking the user to select a candidate to act +on, with or without confirmation. + +The value has the form ((COMMAND nil|PROMPT DEFAULT)...). + +- COMMAND is the command that should not prompt for a choice. + To have an effect, the command has to use the function + `magit-completing-read' or a utility function which in turn uses + that function. + +- If the command uses `magit-completing-read' multiple times, then + PROMPT can be used to only affect one of these uses. PROMPT, if + non-nil, is a regular expression that is used to match against + the PROMPT argument passed to `magit-completing-read'. + +- DEFAULT specifies how to use the default. If it is t, then + the DEFAULT argument passed to `magit-completing-read' is used + without confirmation. If it is `ask', then the user is given + a chance to abort. DEFAULT can also be nil, in which case the + entry has no effect." + :package-version '(magit . "2.12.0") + :group 'magit-commands + :type '(repeat + (list (symbol :tag "Command") ; It might not be fboundp yet. + (choice (const :tag "for all prompts" nil) + (regexp :tag "for prompts matching regexp")) + (choice (const :tag "offer other choices" nil) + (const :tag "require confirmation" ask) + (const :tag "use default without confirmation" t))))) + +(defconst magit--confirm-actions + '((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 '(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 +confirmation. Each of the below symbols stands for an action +which, when invoked unintentionally or without being fully aware +of the consequences, could lead to tears. In many cases there +are several commands that perform variations of a certain action, +so we don't use the command names but more generic symbols. + +Applying changes: + + `discard' Discarding one or more changes (i.e. hunks or the + complete diff for a file) loses that change, obviously. + + `reverse' Reverting one or more changes can usually be undone + by reverting the reversion. + + `stage-all-changes', `unstage-all-changes' When there are both + staged and unstaged changes, then un-/staging everything would + destroy that distinction. Of course that also applies when + un-/staging a single change, but then less is lost and one does + that so often that having to confirm every time would be + unacceptable. + +Files: + + `delete' When a file that isn't yet tracked by Git is deleted + then it is completely lost, not just the last changes. Very + dangerous. + + `trash' Instead of deleting a file it can also be move to the + system trash. Obviously much less dangerous than deleting it. + + Also see option `magit-delete-by-moving-to-trash'. + + `resurrect' A deleted file can easily be resurrected by + \"deleting\" the deletion, which is done using the same command + that was used to delete the same file in the first place. + + `untrack' Untracking a file can be undone by tracking it again. + + `rename' Renaming a file can easily be undone. + +Sequences: + + `reset-bisect' Aborting (known to Git as \"resetting\") a + bisect operation loses all information collected so far. + + `abort-rebase' Aborting a rebase throws away all already + modified commits, but it's possible to restore those from the + reflog. + + `abort-merge' Aborting a merge throws away all conflict + resolutions which has already been carried out by the user. + + `merge-dirty' Merging with a dirty worktree can make it hard to + go back to the state before the merge was initiated. + +References: + + `delete-unmerged-branch' Once a branch has been deleted it can + only be restored using low-level recovery tools provided by + Git. And even then the reflog is gone. The user always has + to confirm the deletion of a branch by accepting the default + 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 + 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. + + `drop-stashes' Dropping a stash is dangerous because Git stores + stashes in the reflog. Once a stash is removed, there is no + going back without using low-level recovery tools provided by + Git. When a single stash is dropped, then the user always has + to confirm by accepting the default (or selecting another). + 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'. + + `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 + and squash variants. + + `edit-published' Affects the commands `magit-edit-line-commit' + and `magit-diff-edit-hunk-commit'. These two commands make + it quite easy to accidentally edit a published commit, so you + should think twice before configuring them not to ask for + confirmation. + + To disable confirmation completely, add all three symbols here + or set `magit-published-branches' to nil. + +Removing modules: + + `remove-modules' When you remove the working directory of a + module that does not contain uncommitted changes, then that is + safer than doing so when there are uncommitted changes and/or + when you also remove the gitdir. Still, you don't want to do + that by accident. + + `remove-dirty-modules' When you remove the working directory of + a module that contains uncommitted changes, then those changes + are gone for good. It is better to go to the module, inspect + these changes and only if appropriate discard them manually. + + `trash-module-gitdirs' When you remove the gitdir of a module, + then all unpushed changes are gone for good. It is very easy + to forget that you have some unfinished work on an unpublished + feature branch or even in a stash. + + Actually there are some safety precautions in place, that might + help you out if you make an unwise choice here, but don't count + on it. In case of emergency, stay calm and check the stash and + the `trash-directory' for traces of lost work. + +Various: + + `kill-process' There seldom is a reason to kill a process. + +Global settings: + + Instead of adding all of the above symbols to the value of this + option you can also set it to the atom `t', which has the same + effect as adding all of the above symbols. Doing that most + certainly is a bad idea, especially because other symbols might + be added in the future. So even if you don't want to be asked + for confirmation for any of these actions, you are still better + of adding all of the respective symbols individually. + + When `magit-wip-before-change-mode' is enabled then these actions + can fairly easily be undone: `discard', `reverse', + `stage-all-changes', and `unstage-all-changes'. If and only if + this mode is enabled, then `safe-with-wip' has the same effect + as adding all of these symbols individually." + :package-version '(magit . "2.1.0") + :group 'magit-essentials + :group 'magit-commands + :type `(choice (const :tag "Always require confirmation" nil) + (const :tag "Never require confirmation" t) + (set :tag "Require confirmation except for" + ;; `remove-dirty-modules' and + ;; `trash-module-gitdirs' intentionally + ;; omitted. + ,@magit--confirm-actions))) + +(defcustom magit-slow-confirm '(drop-stashes) + "Whether to ask user \"y or n\" or \"yes or no\" questions. + +When this is nil, then `y-or-n-p' is used when the user has to +confirm a potentially destructive action. When this is t, then +`yes-or-no-p' is used instead. If this is a list of symbols +identifying actions, then `yes-or-no-p' is used for those, +`y-or-no-p' for all others. The list of actions is the same as +for `magit-no-confirm' (which see)." + :package-version '(magit . "2.9.0") + :group 'magit-miscellaneous + :type `(choice (const :tag "Always ask \"yes or no\" questions" t) + (const :tag "Always ask \"y or n\" questions" nil) + (set :tag "Ask \"yes or no\" questions only for" + ,@magit--confirm-actions))) + +(defcustom magit-no-message nil + "A list of messages Magit should not display. + +Magit displays most echo area messages using `message', but a few +are displayed using `magit-message' instead, which takes the same +arguments as the former, FORMAT-STRING and ARGS. `magit-message' +forgoes printing a message if any member of this list is a prefix +of the respective FORMAT-STRING. + +If Magit prints a message which causes you grief, then please +first investigate whether there is another option which can be +used to suppress it. If that is not the case, then ask the Magit +maintainers to start using `magit-message' instead of `message' +in that case. We are not proactively replacing all uses of +`message' with `magit-message', just in case someone *might* find +some of these messages useless. + +Messages which can currently be suppressed using this option are: +* \"Turning on magit-auto-revert-mode...\"" + :package-version '(magit . "2.8.0") + :group 'magit-miscellaneous + :type '(repeat string)) + +(defcustom magit-ellipsis (if (char-displayable-p ?…) "…" "...") + "String used to abbreviate text in process buffers. + +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 'string) + +(defcustom magit-update-other-window-delay 0.2 + "Delay before automatically updating the other window. + +When moving around in certain buffers, then certain other +buffers, which are being displayed in another window, may +optionally be updated to display information about the +section at point. + +When holding down a key to move by more than just one section, +then that would update that buffer for each section on the way. +To prevent that, updating the revision buffer is delayed, and +this option controls for how long. For optimal experience you +might have to adjust this delay and/or the keyboard repeat rate +and delay of your graphical environment or operating system." + :package-version '(magit . "2.3.0") + :group 'magit-miscellaneous + :type 'number) + +(defcustom magit-view-git-manual-method 'info + "How links to Git documentation are followed from Magit's Info manuals. + +`info' Follow the link to the node in the `gitman' Info manual + as usual. Unfortunately that manual is not installed by + default on some platforms, and when it is then the nodes + look worse than the actual manpages. + +`man' View the respective man-page using the `man' package. + +`woman' View the respective man-page using the `woman' package." + :package-version '(magit . "2.9.0") + :group 'magit-miscellaneous + :type '(choice (const :tag "view info manual" info) + (const :tag "view manpage using `man'" man) + (const :tag "view manpage using `woman'" woman))) + +;;; 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) + +(defun magit-completing-read (prompt collection &optional + predicate require-match initial-input + hist def fallback) + "Read a choice in the minibuffer, or use the default choice. + +This is the function that Magit commands use when they need the +user to select a single thing to act on. The arguments have the +same meaning as for `completing-read', except for FALLBACK, which +is unique to this function and is described below. + +Instead of asking the user to choose from a list of possible +candidates, this function may instead just return the default +specified by DEF, with or without requiring user confirmation. +Whether that is the case depends on PROMPT, `this-command' and +`magit-dwim-selection'. See the documentation of the latter for +more information. + +If it does use the default without the user even having to +confirm that, then `magit-completing-read--silent-default' is set +to t, otherwise nil. + +If it does read a value in the minibuffer, then this function +acts similarly to `completing-read', except for the following: + +- COLLECTION must be a list of choices. A function is not + supported. + +- If REQUIRE-MATCH is nil and the user exits without a choice, + then nil is returned instead of an empty string. + +- If REQUIRE-MATCH is non-nil and the user exits without a + choice, `user-error' is raised. + +- FALLBACK specifies a secondary default that is only used if + the primary default DEF is nil. The secondary default is not + subject to `magit-dwim-selection' — if DEF is nil but FALLBACK + is not, then this function always asks the user to choose a + candidate, just as if both defaults were nil. + +- \": \" is appended to PROMPT. + +- PROMPT is modified to end with \" (default DEF|FALLBACK): \" + provided that DEF or FALLBACK is non-nil, that neither + `ivy-mode' nor `helm-mode' is enabled, and that + `magit-completing-read-function' is set to its default value of + `magit-builtin-completing-read'." + (setq magit-completing-read--silent-default nil) + (if-let ((dwim (and def + (nth 2 (-first (pcase-lambda (`(,cmd ,re ,_)) + (and (eq this-command cmd) + (or (not re) + (string-match-p re prompt)))) + magit-dwim-selection))))) + (if (eq dwim 'ask) + (if (y-or-n-p (format "%s %s? " prompt def)) + def + (user-error "Abort")) + (setq magit-completing-read--silent-default t) + def) + (unless def + (setq def fallback)) + (let ((command this-command) + (reply (funcall magit-completing-read-function + (concat prompt ": ") + (if (and def (not (member def collection))) + (cons def collection) + collection) + predicate + require-match initial-input hist def))) + (setq this-command command) + ;; Note: Avoid `string=' to support `helm-comp-read-use-marked'. + (if (equal reply "") + (if require-match + (user-error "Nothing selected") + nil) + reply)))) + +(defun magit--completion-table (collection) + (lambda (string pred action) + (if (eq action 'metadata) + '(metadata (display-sort-function . identity)) + (complete-with-action action collection string pred)))) + +(defun magit-builtin-completing-read + (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 choices (magit--completion-table choices))) + (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) + "Read multiple items from CHOICES, separated by SEP. + +Set up the `crm' variables needed to read multiple values with +`read-from-minibuffer'. + +SEP is a regexp matching characters that can separate choices. +When SEP is nil, it defaults to `crm-default-separator'. +DEFAULT, HIST, and KEYMAP are passed to `read-from-minibuffer'. +When KEYMAP is nil, it defaults to `crm-local-completion-map'. + +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 + '(crm--choose-completion-string)) + (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))) + (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) + nil hist default)))) + (when (string-equal input "") + (or (setq input default) + (user-error "Nothing selected"))) + input)) + +(defun magit-completing-read-multiple* + (prompt table &optional predicate require-match initial-input + 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 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) + "Ido-based `completing-read' almost-replacement. + +Unfortunately `ido-completing-read' is not suitable as a +drop-in replacement for `completing-read', instead we use +`ido-completing-read+' from the third-party package by the +same name." + (if (and (require 'ido-completing-read+ nil t) + (fboundp 'ido-completing-read+)) + (ido-completing-read+ prompt choices predicate require-match + initial-input hist + (or def (and require-match (car choices)))) + (display-warning 'magit "ido-completing-read+ is not installed + +To use Ido completion with Magit you need to install the +third-party `ido-completing-read+' packages. Falling +back to built-in `completing-read' for now." :error) + (magit-builtin-completing-read prompt choices predicate require-match + initial-input hist def))) + +(defun magit-prompt-with-default (prompt def) + (if (and def (> (length prompt) 2) + (string-equal ": " (substring prompt -2))) + (format "%s (default %s): " (substring prompt 0 -2) def) + prompt)) + +(defvar magit-minibuffer-local-ns-map + (let ((map (make-sparse-keymap))) + (set-keymap-parent map minibuffer-local-map) + (define-key map "\s" 'magit-whitespace-disallowed) + (define-key map "\t" 'magit-whitespace-disallowed) + map)) + +(defun magit-whitespace-disallowed () + "Beep to tell the user that whitespace is not allowed." + (interactive) + (ding) + (message "Whitespace isn't allowed here") + (setq defining-kbd-macro nil) + (force-mode-line-update)) + +(defun magit-read-string (prompt &optional initial-input history default-value + inherit-input-method no-whitespace) + "Read a string from the minibuffer, prompting with string PROMPT. + +This is similar to `read-string', but +* empty input is only allowed if DEFAULT-VALUE is non-nil in + which case that is returned, +* whitespace is not allowed and leading and trailing whitespace is + removed automatically if NO-WHITESPACE is non-nil, +* \": \" is appended to PROMPT, and +* an invalid DEFAULT-VALUE is silently ignored." + (when default-value + (when (consp default-value) + (setq default-value (car default-value))) + (unless (stringp default-value) + (setq default-value nil))) + (let* ((minibuffer-completion-table nil) + (val (read-from-minibuffer + (magit-prompt-with-default (concat prompt ": ") default-value) + initial-input (and no-whitespace magit-minibuffer-local-ns-map) + nil history default-value inherit-input-method)) + (trim (lambda (regexp string) + (save-match-data + (if (string-match regexp string) + (replace-match "" t t string) + string))))) + (when (and (string= val "") default-value) + (setq val default-value)) + (when no-whitespace + (setq val (funcall trim "\\`\\(?:[ \t\n\r]+\\)" + (funcall trim "\\(?:[ \t\n\r]+\\)\\'" val)))) + (cond ((string= val "") + (user-error "Need non-empty input")) + ((and no-whitespace (string-match-p "[\s\t\n]" val)) + (user-error "Input contains whitespace")) + (t val)))) + +(defun magit-read-string-ns (prompt &optional initial-input history + default-value inherit-input-method) + "Call `magit-read-string' with non-nil NO-WHITESPACE." + (magit-read-string prompt initial-input history default-value + inherit-input-method t)) + +(defmacro magit-read-char-case (prompt verbose &rest clauses) + (declare (indent 2) + (debug (form form &rest (characterp form body)))) + `(prog1 (pcase (read-char-choice + (concat ,prompt + (mapconcat #'identity + (list ,@(mapcar #'cadr clauses)) + ", ") + ,(if verbose ", or [C-g] to abort " " ")) + ',(mapcar #'car clauses)) + ,@(--map `(,(car it) ,@(cddr it)) clauses)) + (message ""))) + +(defun magit-y-or-n-p (prompt &optional action) + "Ask user a \"y or n\" or a \"yes or no\" question using PROMPT. +Which kind of question is used depends on whether +ACTION is a member of option `magit-slow-confirm'." + (if (or (eq magit-slow-confirm t) + (and action (member action magit-slow-confirm))) + (yes-or-no-p prompt) + (y-or-n-p prompt))) + +(defvar magit--no-confirm-alist + '((safe-with-wip magit-wip-before-change-mode + discard reverse stage-all-changes unstage-all-changes))) + +(cl-defun magit-confirm (action &optional prompt prompt-n noabort + (items nil sitems)) + (declare (indent defun)) + (setq prompt-n (format (concat (or prompt-n prompt) "? ") (length items))) + (setq prompt (format (concat (or prompt (magit-confirm-make-prompt action)) + "? ") + (car items))) + (or (cond ((and (not (eq action t)) + (or (eq magit-no-confirm t) + (memq action magit-no-confirm) + (cl-member-if (pcase-lambda (`(,key ,var . ,sub)) + (and (memq key magit-no-confirm) + (memq action sub) + (or (not var) + (and (boundp var) + (symbol-value var))))) + magit--no-confirm-alist))) + (or (not sitems) items)) + ((not sitems) + (magit-y-or-n-p prompt action)) + ((= (length items) 1) + (and (magit-y-or-n-p prompt action) items)) + ((> (length items) 1) + (and (magit-y-or-n-p (concat (mapconcat #'identity items "\n") + "\n\n" prompt-n) + action) + items))) + (if noabort nil (user-error "Abort")))) + +(defun magit-confirm-files (action files &optional prompt) + (when files + (unless prompt + (setq prompt (magit-confirm-make-prompt action))) + (magit-confirm action + (concat prompt " %s") + (concat prompt " %i files") + nil files))) + +(defun magit-confirm-make-prompt (action) + (let ((prompt (symbol-name action))) + (replace-regexp-in-string + "-" " " (concat (upcase (substring prompt 0 1)) (substring prompt 1))))) + +(defun magit-read-number-string (prompt &optional default _history) + "Like `read-number' but return value is a string. +DEFAULT may be a number or a numeric string." + (number-to-string + (read-number prompt (if (stringp default) + (string-to-number default) + default)))) + +;;; Debug Utilities + +;;;###autoload +(defun magit-emacs-Q-command () + "Show a shell command that runs an uncustomized Emacs with only Magit loaded. +See info node `(magit)Debugging Tools' for more information." + (interactive) + (let ((cmd (mapconcat + #'shell-quote-argument + `(,(concat invocation-directory invocation-name) + "-Q" "--eval" "(setq debug-on-error t)" + ,@(cl-mapcan + (lambda (dir) (list "-L" dir)) + (delete-dups + (cl-mapcan + (lambda (lib) + (let ((path (locate-library lib))) + (cond + (path + (list (file-name-directory path))) + ((not (equal lib "libgit")) + (error "Cannot find mandatory dependency %s" lib))))) + '(;; Like `LOAD_PATH' in `default.mk'. + "dash" + "libgit" + "transient" + "with-editor" + ;; Obviously `magit' itself is needed too. + "magit" + ;; While these are part of the Magit repository, + ;; they are distributed as separate packages. + "magit-section" + "git-commit" + )))) + ;; Avoid Emacs bug#16406 by using full path. + "-l" ,(file-name-sans-extension (locate-library "magit"))) + " "))) + (message "Uncustomized Magit command saved to kill-ring, %s" + "please run it in a terminal.") + (kill-new cmd))) + +;;; Text Utilities + +(defmacro magit-bind-match-strings (varlist string &rest body) + "Bind variables to submatches according to VARLIST then evaluate BODY. +Bind the symbols in VARLIST to submatches of the current match +data, starting with 1 and incrementing by 1 for each symbol. If +the last match was against a string, then that has to be provided +as STRING." + (declare (indent 2) (debug (listp form body))) + (let ((s (cl-gensym "string")) + (i 0)) + `(let ((,s ,string)) + (let ,(save-match-data + (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 () + "Delete the rest of the current line." + (delete-region (point) (1+ (line-end-position)))) + +(defun magit-delete-match (&optional num) + "Delete text matched by last search. +If optional NUM is specified, only delete that subexpression." + (delete-region (match-beginning (or num 0)) + (match-end (or num 0)))) + +(defun magit-file-line (file) + "Return the first line of FILE as a string." + (when (file-regular-p file) + (with-temp-buffer + (insert-file-contents file) + (buffer-substring-no-properties (point-min) + (line-end-position))))) + +(defun magit-file-lines (file &optional keep-empty-lines) + "Return a list of strings containing one element per line in FILE. +Unless optional argument KEEP-EMPTY-LINES is t, trim all empty lines." + (when (file-regular-p file) + (with-temp-buffer + (insert-file-contents file) + (split-string (buffer-string) "\n" (not keep-empty-lines))))) + +(defun magit-set-header-line-format (string) + "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 side of STRING so that it aligns +with the text area." + (setq 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." + (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'." + (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)) + +(defun magit--put-face (beg end face string) + (put-text-property beg end 'face face string) + (put-text-property beg end 'font-lock-face face string)) + +(defun magit--format-spec (format specification) + "Like `format-spec' but preserve text properties in SPECIFICATION." + (with-temp-buffer + (insert format) + (goto-char (point-min)) + (while (search-forward "%" nil t) + (cond + ;; Quoted percent sign. + ((eq (char-after) ?%) + (delete-char 1)) + ;; Valid format spec. + ((looking-at "\\([-0-9.]*\\)\\([a-zA-Z]\\)") + (let* ((num (match-string 1)) + (spec (string-to-char (match-string 2))) + (val (assq spec specification))) + (unless val + (error "Invalid format character: `%%%c'" spec)) + (setq val (cdr val)) + ;; Pad result to desired length. + (let ((text (format (concat "%" num "s") val))) + ;; Insert first, to preserve text properties. + (if (next-property-change 0 (concat " " text)) + ;; If the inserted text has properties, then preserve those. + (insert text) + ;; Otherwise preserve FORMAT's properties, like `format-spec'. + (insert-and-inherit text)) + ;; Delete the specifier body. + (delete-region (+ (match-beginning 0) (length text)) + (+ (match-end 0) (length text))) + ;; Delete the percent sign. + (delete-region (1- (match-beginning 0)) (match-beginning 0))))) + ;; Signal an error on bogus format strings. + (t + (error "Invalid format string")))) + (buffer-string))) + +;;; Missing from Emacs + +(defun magit-kill-this-buffer () + "Kill the current buffer." + (interactive) + (kill-buffer (current-buffer))) + +(defun magit--buffer-string (&optional min max trim) + "Like `buffer-substring-no-properties' but the arguments are optional. + +This combines the benefits of `buffer-string', `buffer-substring' +and `buffer-substring-no-properties' into one function that is +not as painful to use as the latter. I.e. you can write + (magit--buffer-string) +instead of + (buffer-substring-no-properties (point-min) + (point-max)) + +Optional MIN defaults to the value of `point-min'. +Optional MAX defaults to the value of `point-max'. + +If optional TRIM is non-nil, then all leading and trailing +whitespace is remove. If it is the newline character, then +one trailing newline is added." + ;; Lets write that one last time and be done with it: + (let ((str (buffer-substring-no-properties (or min (point-min)) + (or max (point-max))))) + (if trim + (concat (string-trim str) + (and (eq trim ?\n) "\n")) + str))) + +(defun magit--version> (v1 v2) + "Return t if version V1 is higher (younger) than V2. +This function should be named `version>' and be part of Emacs." + (version-list-< (version-to-list v2) (version-to-list v1))) + +(defun magit--version>= (v1 v2) + "Return t if version V1 is higher (younger) than or equal to V2. +This function should be named `version>=' and be part of Emacs." + (version-list-<= (version-to-list v2) (version-to-list v1))) + +;;; Kludges for Emacs Bugs + +(defun magit-file-accessible-directory-p (filename) + "Like `file-accessible-directory-p' but work around an Apple bug. +See http://debbugs.gnu.org/cgi/bugreport.cgi?bug=21573#17 +and https://github.com/magit/magit/issues/2295." + (and (file-directory-p filename) + (file-accessible-directory-p filename))) + +(when (magit--version>= emacs-version "25.1") + (with-eval-after-load 'vc-git + (defun vc-git-conflicted-files (directory) + "Return the list of files with conflicts in DIRECTORY." + (let* ((status + (vc-git--run-command-string directory "diff-files" + "--name-status")) + (lines (when status (split-string status "\n" 'omit-nulls))) + files) + (dolist (line lines files) + (when (string-match "\\([ MADRCU?!]\\)[ \t]+\\(.+\\)" line) + (let ((state (match-string 1 line)) + (file (match-string 2 line))) + (when (equal state "U") + (push (expand-file-name file directory) files))))))))) + +(when (< emacs-major-version 27) + (defun vc-git--call@bug21559 (fn buffer command &rest args) + "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559." + (let ((process-environment process-environment)) + (when revert-buffer-in-progress-p + (push "GIT_OPTIONAL_LOCKS=0" process-environment)) + (apply fn buffer command args))) + (advice-add 'vc-git--call :around 'vc-git--call@bug21559) + + (defun vc-git-command@bug21559 + (fn buffer okstatus file-or-list &rest flags) + "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559." + (let ((process-environment process-environment)) + (when revert-buffer-in-progress-p + (push "GIT_OPTIONAL_LOCKS=0" process-environment)) + (apply fn buffer okstatus file-or-list flags))) + (advice-add 'vc-git-command :around 'vc-git-command@bug21559) + + (defun auto-revert-handler@bug21559 (fn) + "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559." + (let ((revert-buffer-in-progress-p t)) + (funcall fn))) + (advice-add 'auto-revert-handler :around 'auto-revert-handler@bug21559) + ) + +(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. + +This is a simple wrapper around `which-function', that resets +Imenu's potentially outdated and therefore unreliable cache by +setting `imenu--index-alist' to nil before calling that function." + (setq imenu--index-alist nil) + (which-function)) + +;;; Kludges for Custom + +(defun magit-custom-initialize-reset (symbol exp) + "Initialize SYMBOL based on EXP. +Set the symbol, using `set-default' (unlike +`custom-initialize-reset' which uses the `:set' function if any.) +The value is either the symbol's current value + (as obtained using the `:get' function), if any, +or the value in the symbol's `saved-value' property if any, +or (last of all) the value of EXP." + (set-default-toplevel-value + symbol + (condition-case nil + (let ((def (default-toplevel-value symbol)) + (getter (get symbol 'custom-get))) + (if getter (funcall getter symbol) def)) + (error + (eval (let ((sv (get symbol 'saved-value))) + (if sv (car sv) exp))))))) + +(defun magit-hook-custom-get (symbol) + (if (symbol-file symbol 'defvar) + (default-toplevel-value symbol) + ;; + ;; Called by `custom-initialize-reset' on behalf of `symbol's + ;; `defcustom', which is being evaluated for the first time to + ;; set the initial value, but there's already a default value, + ;; which most likely was established by one or more `add-hook' + ;; calls. + ;; + ;; We combine the `standard-value' and the current value, while + ;; preserving the order established by `:options', and return + ;; the result of that to be used as the "initial" default value. + ;; + (let ((standard (eval (car (get symbol 'standard-value)))) + (current (default-toplevel-value symbol)) + (value nil)) + (dolist (fn (get symbol 'custom-options)) + (when (or (memq fn standard) + (memq fn current)) + (push fn value))) + (dolist (fn current) + (unless (memq fn value) + (push fn value))) + (nreverse value)))) + +;;; Kludges for Info Manuals + +;;;###autoload +(defun Info-follow-nearest-node--magit-gitman (fn &optional fork) + (let ((node (Info-get-token + (point) "\\*note[ \n\t]+" + "\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?"))) + (if (and node (string-match "^(gitman)\\(.+\\)" node)) + (pcase magit-view-git-manual-method + (`info (funcall fn fork)) + (`man (require 'man) + (man (match-string 1 node))) + (`woman (require 'woman) + (woman (match-string 1 node))) + (_ + (user-error "Invalid value for `magit-view-git-manual-method'"))) + (funcall fn fork)))) + +;;;###autoload +(advice-add 'Info-follow-nearest-node :around + 'Info-follow-nearest-node--magit-gitman) + +;;;###autoload +(defun org-man-export--magit-gitman (fn link description format) + (if (and (eq format 'texinfo) + (string-match-p "\\`git" link)) + (replace-regexp-in-string "%s" link " +@ifinfo +@ref{%s,,,gitman,}. +@end ifinfo +@ifhtml +@html +the %s(1) manpage. +@end html +@end ifhtml +@iftex +the %s(1) manpage. +@end iftex +") + (funcall fn link description format))) + +;;;###autoload +(advice-add 'org-man-export :around + 'org-man-export--magit-gitman) + +;;; Kludges for Package Managers + +(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)) + +;;; Kludges for older Emacs versions + +(if (fboundp 'with-connection-local-variables) + (defalias 'magit--with-connection-local-variables + 'with-connection-local-variables) + (defmacro magit--with-connection-local-variables (&rest body) + "Abridged `with-connection-local-variables' for pre Emacs 27 compatibility. +Bind shell file name and switch for remote execution. +`with-connection-local-variables' isn't available until Emacs 27. +This kludge provides the minimal functionality required by +Magit." + `(if (file-remote-p default-directory) + (let* ((vec (tramp-dissect-file-name default-directory)) + (shell-file-name (tramp-get-method-parameter + vec + 'tramp-remote-shell)) + (shell-command-switch (mapconcat + #'identity + (tramp-get-method-parameter + vec + 'tramp-remote-shell-args) + " "))) + (progn ,@body)) + ,@body))) + +;;; Miscellaneous + +(defun magit-message (format-string &rest args) + "Display a message at the bottom of the screen, or not. +Like `message', except that if the users configured option +`magit-no-message' to prevent the message corresponding to +FORMAT-STRING to be displayed, then don't." + (unless (--first (string-prefix-p it format-string) magit-no-message) + (apply #'message format-string args))) + +(defun magit-msg (format-string &rest args) + "Display a message at the bottom of the screen, but don't log it. +Like `message', except that `message-log-max' is bound to nil." + (let ((message-log-max nil)) + (apply #'message format-string args))) + +(defmacro magit--with-temp-position (buf pos &rest body) + (declare (indent 2)) + `(with-current-buffer ,buf + (save-excursion + (save-restriction + (widen) + (goto-char (or ,pos 1)) + ,@body)))) + +;;; _ +(provide 'magit-utils) +;;; magit-utils.el ends here diff --git a/elpa/magit-20220116.1908/magit-wip.el b/elpa/magit-20220116.1908/magit-wip.el new file mode 100644 index 00000000..7f42b573 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-wip.el @@ -0,0 +1,463 @@ +;;; magit-wip.el --- commit snapshots to work-in-progress refs -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library defines tree global modes which automatically commit +;; snapshots to branch-specific work-in-progress refs before and after +;; making changes, and two commands which can be used to do so on +;; demand. + +;;; Code: + +(require 'magit-core) +(require 'magit-log) + +;;; Options + +(defgroup magit-wip nil + "Automatically commit to work-in-progress refs." + :link '(info-link "(magit)Wip Modes") + :group 'magit-modes + :group 'magit-essentials) + +(defgroup magit-wip-legacy nil + "It is better to not use these modes individually." + :link '(info-link "(magit)Legacy Wip Modes") + :group 'magit-wip) + +(defcustom magit-wip-mode-lighter " Wip" + "Lighter for Magit-Wip mode." + :package-version '(magit . "2.90.0") + :group 'magit-wip + :type 'string) + +(defcustom magit-wip-after-save-local-mode-lighter "" + "Lighter for Magit-Wip-After-Save-Local mode." + :package-version '(magit . "2.1.0") + :group 'magit-wip-legacy + :type 'string) + +(defcustom magit-wip-after-apply-mode-lighter "" + "Lighter for Magit-Wip-After-Apply mode." + :package-version '(magit . "2.1.0") + :group 'magit-wip-legacy + :type 'string) + +(defcustom magit-wip-before-change-mode-lighter "" + "Lighter for Magit-Wip-Before-Change mode." + :package-version '(magit . "2.1.0") + :group 'magit-wip-legacy + :type 'string) + +(defcustom magit-wip-initial-backup-mode-lighter "" + "Lighter for Magit-Wip-Initial Backup mode." + :package-version '(magit . "2.1.0") + :group 'magit-wip-legacy + :type 'string) + +(defcustom magit-wip-merge-branch nil + "Whether to merge the current branch into its wip ref. + +If non-nil and the current branch has new commits, then it is +merged into the wip ref before creating a new wip commit. This +makes it easier to inspect wip history and the wip commits are +never garbage collected. + +If nil and the current branch has new commits, then the wip ref +is reset to the tip of the branch before creating a new wip +commit. With this setting wip commits are eventually garbage +collected. This is currently the default." + :package-version '(magit . "2.90.0") + :group 'magit-wip + :type 'boolean) + +(defcustom magit-wip-namespace "refs/wip/" + "Namespace used for work-in-progress refs. +The wip refs are named \"index/\" +and \"wtree/\". When snapshots +are created while the `HEAD' is detached then \"HEAD\" +is used as `branch-ref'." + :package-version '(magit . "2.1.0") + :group 'magit-wip + :type 'string) + +;;; Modes + +;;;###autoload +(define-minor-mode magit-wip-mode + "Save uncommitted changes to work-in-progress refs. + +Whenever appropriate (i.e. when dataloss would be a possibility +otherwise) this mode causes uncommitted changes to be committed +to dedicated work-in-progress refs. + +For historic reasons this mode is implemented on top of four +other `magit-wip-*' modes, which can also be used individually, +if you want finer control over when the wip refs are updated; +but that is discouraged." + :package-version '(magit . "2.90.0") + :lighter magit-wip-mode-lighter + :global t + (let ((arg (if magit-wip-mode 1 -1))) + (magit-wip-after-save-mode arg) + (magit-wip-after-apply-mode arg) + (magit-wip-before-change-mode arg) + (magit-wip-initial-backup-mode arg))) + +(define-minor-mode magit-wip-after-save-local-mode + "After saving, also commit to a worktree work-in-progress ref. + +After saving the current file-visiting buffer this mode also +commits the changes to the worktree work-in-progress ref for +the current branch. + +This mode should be enabled globally by turning on the globalized +variant `magit-wip-after-save-mode'." + :package-version '(magit . "2.1.0") + :lighter magit-wip-after-save-local-mode-lighter + (if magit-wip-after-save-local-mode + (if (and buffer-file-name (magit-inside-worktree-p t)) + (add-hook 'after-save-hook 'magit-wip-commit-buffer-file t t) + (setq magit-wip-after-save-local-mode nil) + (user-error "Need a worktree and a file")) + (remove-hook 'after-save-hook 'magit-wip-commit-buffer-file t))) + +(defun magit-wip-after-save-local-mode-turn-on () + (and buffer-file-name + (magit-inside-worktree-p t) + (magit-file-tracked-p buffer-file-name) + (magit-wip-after-save-local-mode))) + +;;;###autoload +(define-globalized-minor-mode magit-wip-after-save-mode + magit-wip-after-save-local-mode magit-wip-after-save-local-mode-turn-on + :package-version '(magit . "2.1.0") + :group 'magit-wip) + +(defun magit-wip-commit-buffer-file (&optional msg) + "Commit visited file to a worktree work-in-progress ref. + +Also see `magit-wip-after-save-mode' which calls this function +automatically whenever a buffer visiting a tracked file is saved." + (interactive) + (--when-let (magit-wip-get-ref) + (magit-with-toplevel + (let ((file (file-relative-name buffer-file-name))) + (magit-wip-commit-worktree + it (list file) + (format (cond (msg) + ((called-interactively-p 'any) + "wip-save %s after save") + (t + "autosave %s after save")) + file)))))) + +;;;###autoload +(define-minor-mode magit-wip-after-apply-mode + "Commit to work-in-progress refs. + +After applying a change using any \"apply variant\" +command (apply, stage, unstage, discard, and reverse) commit the +affected files to the current wip refs. For each branch there +may be two wip refs; one contains snapshots of the files as found +in the worktree and the other contains snapshots of the entries +in the index." + :package-version '(magit . "2.1.0") + :group 'magit-wip + :lighter magit-wip-after-apply-mode-lighter + :global t) + +(defun magit-wip-commit-after-apply (&optional files msg) + (when magit-wip-after-apply-mode + (magit-wip-commit files msg))) + +;;;###autoload +(define-minor-mode magit-wip-before-change-mode + "Commit to work-in-progress refs before certain destructive changes. + +Before invoking a revert command or an \"apply variant\" +command (apply, stage, unstage, discard, and reverse) commit the +affected tracked files to the current wip refs. For each branch +there may be two wip refs; one contains snapshots of the files +as found in the worktree and the other contains snapshots of the +entries in the index. + +Only changes to files which could potentially be affected by the +command which is about to be called are committed." + :package-version '(magit . "2.1.0") + :group 'magit-wip + :lighter magit-wip-before-change-mode-lighter + :global t) + +(defun magit-wip-commit-before-change (&optional files msg) + (when magit-wip-before-change-mode + (magit-with-toplevel + (magit-wip-commit files msg)))) + +(define-minor-mode magit-wip-initial-backup-mode + "Before saving a buffer for the first time, commit to a wip ref." + :package-version '(magit . "2.90.0") + :group 'magit-wip + :lighter magit-wip-initial-backup-mode-lighter + :global t + (if magit-wip-initial-backup-mode + (add-hook 'before-save-hook 'magit-wip-commit-initial-backup) + (remove-hook 'before-save-hook 'magit-wip-commit-initial-backup))) + +(defun magit--any-wip-mode-enabled-p () + "Return non-nil if any global wip mode is enabled." + (or magit-wip-mode + magit-wip-after-save-mode + magit-wip-after-apply-mode + magit-wip-before-change-mode + magit-wip-initial-backup-mode)) + +(defvar-local magit-wip-buffer-backed-up nil) +(put 'magit-wip-buffer-backed-up 'permanent-local t) + +;;;###autoload +(defun magit-wip-commit-initial-backup () + "Before saving, commit current file to a worktree wip ref. + +The user has to add this function to `before-save-hook'. + +Commit the current state of the visited file before saving the +current buffer to that file. This backs up the same version of +the file as `backup-buffer' would, but stores the backup in the +worktree wip ref, which is also used by the various Magit Wip +modes, instead of in a backup file as `backup-buffer' would. + +This function ignores the variables that affect `backup-buffer' +and can be used along-side that function, which is recommended +because this function only backs up files that are tracked in +a Git repository." + (when (and (not magit-wip-buffer-backed-up) + buffer-file-name + (magit-inside-worktree-p t) + (magit-file-tracked-p buffer-file-name)) + (let ((magit-save-repository-buffers nil)) + (magit-wip-commit-buffer-file "autosave %s before save")) + (setq magit-wip-buffer-backed-up t))) + +;;; Core + +(defun magit-wip-commit (&optional files msg) + "Commit all tracked files to the work-in-progress refs. + +Interactively, commit all changes to all tracked files using +a generic commit message. With a prefix-argument the commit +message is read in the minibuffer. + +Non-interactively, only commit changes to FILES using MSG as +commit message." + (interactive (list nil (if current-prefix-arg + (magit-read-string "Wip commit message") + "wip-save tracked files"))) + (--when-let (magit-wip-get-ref) + (magit-wip-commit-index it files msg) + (magit-wip-commit-worktree it files msg))) + +(defun magit-wip-commit-index (ref files msg) + (let* ((wipref (magit--wip-index-ref ref)) + (parent (magit-wip-get-parent ref wipref)) + (tree (magit-git-string "write-tree"))) + (magit-wip-update-wipref ref wipref tree parent files msg "index"))) + +(defun magit-wip-commit-worktree (ref files msg) + (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 (magit-git-version>= "2.25.0"))) + (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 + ((and (not (equal parent wipref)) + (or (not magit-wip-merge-branch) + (not (magit-rev-verify wipref)))) + (setq start-msg (concat "start autosaving " start-msg)) + (magit-update-ref wipref start-msg + (magit-git-string "commit-tree" "--no-gpg-sign" + "-p" parent "-m" start-msg + (concat parent "^{tree}"))) + (setq parent wipref)) + ((and magit-wip-merge-branch + (or (not (magit-rev-ancestor-p ref wipref)) + (not (magit-rev-ancestor-p + (concat (magit-git-string "log" "--format=%H" + "-1" "--merges" wipref) + "^2") + ref)))) + (setq start-msg (format "merge %s into %s" ref start-msg)) + (magit-update-ref wipref start-msg + (magit-git-string "commit-tree" "--no-gpg-sign" + "-p" wipref "-p" ref + "-m" start-msg + (concat ref "^{tree}"))) + (setq parent wipref))) + (when (magit-git-failure "diff-tree" "--quiet" parent tree "--" files) + (unless (and msg (not (= (aref msg 0) ?\s))) + (let ((len (length files))) + (setq msg (concat + (cond ((= len 0) "autosave tracked files") + ((> len 1) (format "autosave %s files" len)) + (t (concat "autosave " + (file-relative-name (car files) + (magit-toplevel))))) + msg)))) + (magit-update-ref wipref msg + (magit-git-string "commit-tree" "--no-gpg-sign" + "-p" parent "-m" msg tree)))) + +(defun magit-wip-get-ref () + (let ((ref (or (magit-git-string "symbolic-ref" "HEAD") "HEAD"))) + (and (magit-rev-verify ref) + ref))) + +(defun magit-wip-get-parent (ref wipref) + (if (and (magit-rev-verify wipref) + (equal (magit-git-string "merge-base" wipref ref) + (magit-rev-verify ref))) + wipref + ref)) + +(defun magit--wip-index-ref (&optional ref) + (magit--wip-ref "index/" ref)) + +(defun magit--wip-wtree-ref (&optional ref) + (magit--wip-ref "wtree/" ref)) + +(defun magit--wip-ref (namespace &optional ref) + (concat magit-wip-namespace namespace + (or (and ref (string-prefix-p "refs/" ref) ref) + (when-let ((branch (and (not (equal ref "HEAD")) + (or ref (magit-get-current-branch))))) + (concat "refs/heads/" branch)) + "HEAD"))) + +(defun magit-wip-maybe-add-commit-hook () + (when (and magit-wip-merge-branch + (magit-wip-any-enabled-p)) + (add-hook 'git-commit-post-finish-hook 'magit-wip-commit nil t))) + +(defun magit-wip-any-enabled-p () + (or magit-wip-mode + magit-wip-after-save-local-mode + magit-wip-after-save-mode + magit-wip-after-apply-mode + magit-wip-before-change-mode + magit-wip-initial-backup-mode)) + +;;; Log + +(defun magit-wip-log-index (args files) + "Show log for the index wip ref of the current branch." + (interactive (magit-log-arguments)) + (magit-log-setup-buffer (list (magit--wip-index-ref)) args files)) + +(defun magit-wip-log-worktree (args files) + "Show log for the worktree wip ref of the current branch." + (interactive (magit-log-arguments)) + (magit-log-setup-buffer (list (magit--wip-wtree-ref)) args files)) + +(defun magit-wip-log-current (branch args files count) + "Show log for the current branch and its wip refs. +With a negative prefix argument only show the worktree wip ref. +The absolute numeric value of the prefix argument controls how +many \"branches\" of each wip ref are shown." + (interactive + (nconc (list (or (magit-get-current-branch) "HEAD")) + (magit-log-arguments) + (list (prefix-numeric-value current-prefix-arg)))) + (magit-wip-log branch args files count)) + +(defun magit-wip-log (branch args files count) + "Show log for a branch and its wip refs. +With a negative prefix argument only show the worktree wip ref. +The absolute numeric value of the prefix argument controls how +many \"branches\" of each wip ref are shown." + (interactive + (nconc (list (magit-completing-read + "Log branch and its wip refs" + (-snoc (magit-list-local-branch-names) "HEAD") + nil t nil 'magit-revision-history + (or (magit-branch-at-point) + (magit-get-current-branch) + "HEAD"))) + (magit-log-arguments) + (list (prefix-numeric-value current-prefix-arg)))) + (magit-log-setup-buffer (nconc (list branch) + (magit-wip-log-get-tips + (magit--wip-wtree-ref branch) + (abs count)) + (and (>= count 0) + (magit-wip-log-get-tips + (magit--wip-index-ref branch) + (abs count)))) + args files)) + +(defun magit-wip-log-get-tips (wipref count) + (when-let ((reflog (magit-git-lines "reflog" wipref))) + (let (tips) + (while (and reflog (> count 1)) + ;; "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))) + (push (match-string 1 (cadr reflog)) tips)) + (setq reflog (cddr reflog)) + (cl-decf count)) + (cons wipref (nreverse tips))))) + +;;; _ +(provide 'magit-wip) +;;; magit-wip.el ends here diff --git a/elpa/magit-20220116.1908/magit-worktree.el b/elpa/magit-20220116.1908/magit-worktree.el new file mode 100644 index 00000000..3e176e35 --- /dev/null +++ b/elpa/magit-20220116.1908/magit-worktree.el @@ -0,0 +1,192 @@ +;;; magit-worktree.el --- worktree support -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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. + +;;; Commentary: + +;; This library implements support for `git-worktree'. + +;;; Code: + +(require 'magit) + +;;; Options + +(defcustom magit-worktree-read-directory-name-function 'read-directory-name + "Function used to read a directory for worktree commands. +This is called with one argument, the prompt, and can be used +to e.g. use a base directory other than `default-directory'. +Used by `magit-worktree-checkout' and `magit-worktree-branch'." + :package-version '(magit . "3.0.0") + :group 'magit-commands + :type 'function) + +;;; Commands + +;;;###autoload (autoload 'magit-worktree "magit-worktree" nil t) +(transient-define-prefix magit-worktree () + "Act on a worktree." + :man-page "git-worktree" + [["Create new" + ("b" "worktree" magit-worktree-checkout) + ("c" "branch and worktree" magit-worktree-branch)] + ["Commands" + ("m" "Move worktree" magit-worktree-move) + ("k" "Delete worktree" magit-worktree-delete) + ("g" "Visit worktree" magit-worktree-status)]]) + +;;;###autoload +(defun magit-worktree-checkout (path branch) + "Checkout BRANCH in a new worktree at PATH." + (interactive + (let ((branch (magit-read-branch-or-commit "Checkout"))) + (list (funcall magit-worktree-read-directory-name-function + (format "Checkout %s in new worktree: " branch)) + branch))) + (magit-run-git "worktree" "add" (magit--expand-worktree path) branch) + (magit-diff-visit-directory path)) + +;;;###autoload +(defun magit-worktree-branch (path branch start-point &optional force) + "Create a new BRANCH and check it out in a new worktree at PATH." + (interactive + `(,(funcall magit-worktree-read-directory-name-function + "Create worktree: ") + ,@(magit-branch-read-args "Create and checkout branch") + ,current-prefix-arg)) + (magit-run-git "worktree" "add" (if force "-B" "-b") + branch (magit--expand-worktree path) start-point) + (magit-diff-visit-directory path)) + +;;;###autoload +(defun magit-worktree-move (worktree path) + "Move WORKTREE to PATH." + (interactive + (list (magit-completing-read "Move worktree" + (cdr (magit-list-worktrees)) + nil t nil nil + (magit-section-value-if 'worktree)) + (funcall magit-worktree-read-directory-name-function + "Move worktree to: "))) + (if (file-directory-p (expand-file-name ".git" worktree)) + (user-error "You may not move the main working tree") + (let ((preexisting-directory (file-directory-p path))) + (when (and (zerop (magit-call-git "worktree" "move" worktree + (magit--expand-worktree path))) + (not (file-exists-p default-directory)) + (derived-mode-p 'magit-status-mode)) + (kill-buffer) + (magit-diff-visit-directory + (if preexisting-directory + (concat (file-name-as-directory path) + (file-name-nondirectory worktree)) + path))) + (magit-refresh)))) + +(defun magit-worktree-delete (worktree) + "Delete a worktree, defaulting to the worktree at point. +The primary worktree cannot be deleted." + (interactive + (list (magit-completing-read "Delete worktree" + (cdr (magit-list-worktrees)) + nil t nil nil + (magit-section-value-if 'worktree)))) + (if (file-directory-p (expand-file-name ".git" worktree)) + (user-error "Deleting %s would delete the shared .git directory" worktree) + (let ((primary (file-name-as-directory (caar (magit-list-worktrees))))) + (magit-confirm-files (if magit-delete-by-moving-to-trash 'trash 'delete) + (list "worktree")) + (when (file-exists-p worktree) + (let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash)) + (delete-directory worktree t magit-delete-by-moving-to-trash))) + (if (file-exists-p default-directory) + (magit-run-git "worktree" "prune") + (let ((default-directory primary)) + (magit-run-git "worktree" "prune")) + (when (derived-mode-p 'magit-status-mode) + (kill-buffer) + (magit-status-setup-buffer primary)))))) + +(defun magit-worktree-status (worktree) + "Show the status for the worktree at point. +If there is no worktree at point, then read one in the +minibuffer. If the worktree at point is the one whose +status is already being displayed in the current buffer, +then show it in Dired instead." + (interactive + (list (or (magit-section-value-if 'worktree) + (magit-completing-read + "Show status for worktree" + (cl-delete (directory-file-name (magit-toplevel)) + (magit-list-worktrees) + :test #'equal :key #'car))))) + (magit-diff-visit-directory worktree)) + +(defun magit--expand-worktree (path) + (magit-convert-filename-for-git (expand-file-name path))) + +;;; Sections + +(defvar magit-worktree-section-map + (let ((map (make-sparse-keymap))) + (define-key map [remap magit-visit-thing] 'magit-worktree-status) + (define-key map [remap magit-delete-thing] 'magit-worktree-delete) + map) + "Keymap for `worktree' sections.") + +(defun magit-insert-worktrees () + "Insert sections for all worktrees. +If there is only one worktree, then insert nothing." + (let ((worktrees (magit-list-worktrees))) + (when (> (length worktrees) 1) + (magit-insert-section (worktrees) + (magit-insert-heading "Worktrees:") + (let* ((cols + (mapcar + (pcase-lambda (`(,path ,barep ,commit ,branch)) + (cons (cond + (branch (propertize + 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)")) + path)) + worktrees)) + (align (1+ (-max (--map (string-width (car it)) cols))))) + (pcase-dolist (`(,head . ,path) cols) + (magit-insert-section (worktree path) + (insert head) + (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))) + (insert ?\n)))) + (insert ?\n))))) + +;;; _ +(provide 'magit-worktree) +;;; magit-worktree.el ends here diff --git a/elpa/magit-20220116.1908/magit.el b/elpa/magit-20220116.1908/magit.el new file mode 100644 index 00000000..83cba084 --- /dev/null +++ b/elpa/magit-20220116.1908/magit.el @@ -0,0 +1,729 @@ +;;; magit.el --- A Git porcelain inside Emacs -*- lexical-binding: t; coding: utf-8 -*- + +;; Copyright (C) 2008-2022 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 +;; Former-Maintainers: +;; Nicolas Dudebout +;; Peter J. Weisberg +;; Phil Jackson +;; Rémi Vanicat +;; Yann Hodique + +;; Keywords: git tools vc +;; Homepage: https://github.com/magit/magit +;; 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 +;; 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. + +;; Magit requires at least GNU Emacs 25.1 and Git 2.2.0. + +;;; Commentary: + +;; 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 '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") + +;;; Faces + +(defface magit-header-line + '((t :inherit magit-section-heading)) + "Face for the `header-line' in some Magit modes. +Note that some modes, such as `magit-log-select-mode', have their +own faces for the `header-line', or for parts of the +`header-line'." + :group 'magit-faces) + +(defface magit-header-line-key + '((t :inherit font-lock-builtin-face)) + "Face for keys in the `header-line'." + :group 'magit-faces) + +(defface magit-dimmed + '((((class color) (background light)) :foreground "grey50") + (((class color) (background dark)) :foreground "grey50")) + "Face for text that shouldn't stand out." + :group 'magit-faces) + +(defface magit-hash + '((((class color) (background light)) :foreground "grey60") + (((class color) (background dark)) :foreground "grey40")) + "Face for the sha1 part of the log output." + :group 'magit-faces) + +(defface magit-tag + '((((class color) (background light)) :foreground "Goldenrod4") + (((class color) (background dark)) :foreground "LightGoldenrod2")) + "Face for tag labels shown in log buffer." + :group 'magit-faces) + +(defface magit-branch-remote + '((((class color) (background light)) :foreground "DarkOliveGreen4") + (((class color) (background dark)) :foreground "DarkSeaGreen2")) + "Face for remote branch head labels shown in log buffer." + :group 'magit-faces) + +(defface magit-branch-remote-head + '((((supports (:box t))) :inherit magit-branch-remote :box t) + (t :inherit magit-branch-remote :inverse-video t)) + "Face for current branch." + :group 'magit-faces) + +(defface magit-branch-local + '((((class color) (background light)) :foreground "SkyBlue4") + (((class color) (background dark)) :foreground "LightSkyBlue1")) + "Face for local branches." + :group 'magit-faces) + +(defface magit-branch-current + '((((supports (:box t))) :inherit magit-branch-local :box t) + (t :inherit magit-branch-local :inverse-video t)) + "Face for current branch." + :group 'magit-faces) + +(defface magit-branch-upstream + '((t :slant italic)) + "Face for upstream branch. +This face is only used in logs and it gets combined + with `magit-branch-local', `magit-branch-remote' +and/or `magit-branch-remote-head'." + :group 'magit-faces) + +(defface magit-branch-warning + '((t :inherit warning)) + "Face for warning about (missing) branch." + :group 'magit-faces) + +(defface magit-head + '((((class color) (background light)) :inherit magit-branch-local) + (((class color) (background dark)) :inherit magit-branch-local)) + "Face for the symbolic ref `HEAD'." + :group 'magit-faces) + +(defface magit-refname + '((((class color) (background light)) :foreground "grey30") + (((class color) (background dark)) :foreground "grey80")) + "Face for refnames without a dedicated face." + :group 'magit-faces) + +(defface magit-refname-stash + '((t :inherit magit-refname)) + "Face for stash refnames." + :group 'magit-faces) + +(defface magit-refname-wip + '((t :inherit magit-refname)) + "Face for wip refnames." + :group 'magit-faces) + +(defface magit-refname-pullreq + '((t :inherit magit-refname)) + "Face for pullreq refnames." + :group 'magit-faces) + +(defface magit-keyword + '((t :inherit font-lock-string-face)) + "Face for parts of commit messages inside brackets." + :group 'magit-faces) + +(defface magit-keyword-squash + '((t :inherit font-lock-warning-face)) + "Face for squash! and fixup! keywords in commit messages." + :group 'magit-faces) + +(defface magit-signature-good + '((t :foreground "green")) + "Face for good signatures." + :group 'magit-faces) + +(defface magit-signature-bad + '((t :foreground "red" :weight bold)) + "Face for bad signatures." + :group 'magit-faces) + +(defface magit-signature-untrusted + '((t :foreground "medium aquamarine")) + "Face for good untrusted signatures." + :group 'magit-faces) + +(defface magit-signature-expired + '((t :foreground "orange")) + "Face for signatures that have expired." + :group 'magit-faces) + +(defface magit-signature-expired-key + '((t :inherit magit-signature-expired)) + "Face for signatures made by an expired key." + :group 'magit-faces) + +(defface magit-signature-revoked + '((t :foreground "violet red")) + "Face for signatures made by a revoked key." + :group 'magit-faces) + +(defface magit-signature-error + '((t :foreground "light blue")) + "Face for signatures that cannot be checked (e.g. missing key)." + :group 'magit-faces) + +(defface magit-cherry-unmatched + '((t :foreground "cyan")) + "Face for unmatched cherry commits." + :group 'magit-faces) + +(defface magit-cherry-equivalent + '((t :foreground "magenta")) + "Face for equivalent cherry commits." + :group 'magit-faces) + +(defface magit-filename + '((t :weight normal)) + "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) +(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) + ("C" "Clone" magit-clone) + ("d" "Diff" magit-diff) + ("D" "Diff (change)" magit-diff-refresh) + ("e" "Ediff (dwim)" magit-ediff-dwim) + ("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 → 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 → magit-reset-quickly + ("X" "Reset" magit-reset) + ("y" "Show Refs" magit-show-refs) + ("Y" "Cherries" magit-cherry) + ("z" "Stash" magit-stash) + ("Z" "Worktree" magit-worktree) + ("!" "Run" magit-run)]] + ["Applying changes" + :if-derived magit-mode + [("a" "Apply" magit-apply) + ("v" "Reverse" magit-reverse) + ("k" "Discard" magit-discard)] + [("s" "Stage" magit-stage) + ("u" "Unstage" magit-unstage)] + [("S" "Stage all" magit-stage-modified) + ("U" "Unstage all" magit-unstage-all)]] + ["Essential commands" + :if-derived magit-mode + ("g" " refresh current buffer" magit-refresh) + ("" " toggle section at point" magit-section-toggle) + ("" "visit thing at point" magit-visit-thing) + ("C-x m" " show all key bindings" describe-mode)]) + +;;; Git Popup + +(defcustom magit-shell-command-verbose-prompt t + "Whether to show the working directory when reading a command. +This affects `magit-git-command', `magit-git-command-topdir', +`magit-shell-command', and `magit-shell-command-topdir'." + :package-version '(magit . "2.11.0") + :group 'magit-commands + :type 'boolean) + +(defvar magit-git-command-history nil) + +;;;###autoload (autoload 'magit-run "magit" nil t) +(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) + ("p" "in working directory" magit-git-command)] + ["Run shell command" + ("s" "in repository root" magit-shell-command-topdir) + ("S" "in working directory" magit-shell-command)] + ["Launch" + ("k" "gitk" magit-run-gitk) + ("a" "gitk --all" magit-run-gitk-all) + ("b" "gitk --branches" magit-run-gitk-branches) + ("g" "git gui" magit-run-git-gui)]]) + +;;;###autoload +(defun magit-git-command (command) + "Execute COMMAND asynchronously; display output. + +Interactively, prompt for COMMAND in the minibuffer. \"git \" is +used as initial input, but can be deleted to run another command. + +With a prefix argument COMMAND is run in the top-level directory +of the current working tree, otherwise in `default-directory'." + (interactive (list (magit-read-shell-command nil "git "))) + (magit--shell-command command)) + +;;;###autoload +(defun magit-git-command-topdir (command) + "Execute COMMAND asynchronously; display output. + +Interactively, prompt for COMMAND in the minibuffer. \"git \" is +used as initial input, but can be deleted to run another command. + +COMMAND is run in the top-level directory of the current +working tree." + (interactive (list (magit-read-shell-command t "git "))) + (magit--shell-command command (magit-toplevel))) + +;;;###autoload +(defun magit-shell-command (command) + "Execute COMMAND asynchronously; display output. + +Interactively, prompt for COMMAND in the minibuffer. With a +prefix argument COMMAND is run in the top-level directory of +the current working tree, otherwise in `default-directory'." + (interactive (list (magit-read-shell-command))) + (magit--shell-command command)) + +;;;###autoload +(defun magit-shell-command-topdir (command) + "Execute COMMAND asynchronously; display output. + +Interactively, prompt for COMMAND in the minibuffer. COMMAND +is run in the top-level directory of the current working tree." + (interactive (list (magit-read-shell-command t))) + (magit--shell-command command (magit-toplevel))) + +(defun magit--shell-command (command &optional directory) + (let ((default-directory (or directory default-directory)) + (process-environment process-environment)) + (push "GIT_PAGER=cat" process-environment) + (magit--with-connection-local-variables + (magit-start-process shell-file-name nil + shell-command-switch command))) + (magit-process-buffer)) + +(defun magit-read-shell-command (&optional toplevel initial-input) + (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: " + (abbreviate-file-name default-directory)) + "Async shell command: ") + initial-input 'magit-git-command-history))) + +;;; Font-Lock Keywords + +(defconst magit-font-lock-keywords + (eval-when-compile + `((,(concat "(\\(magit-define-section-jumper\\)\\_>" + "[ \t'\(]*" + "\\(\\(?:\\sw\\|\\s_\\)+\\)?") + (1 'font-lock-keyword-face) + (2 'font-lock-function-name-face nil t)) + (,(concat "(" (regexp-opt '("magit-insert-section" + "magit-section-case" + "magit-bind-match-strings" + "magit-with-temp-index" + "magit-with-blob" + "magit-with-toplevel") t) + "\\_>") + . 1)))) + +(font-lock-add-keywords 'emacs-lisp-mode magit-font-lock-keywords) + +;;; Version + +(defvar magit-version 'undefined + "The version of Magit that you're using. +Use the function by the same name instead of this variable.") + +;;;###autoload +(defun magit-version (&optional print-dest) + "Return the version of Magit currently in use. +If optional argument PRINT-DEST is non-nil, output +stream (interactively, the echo area, or the current buffer with +a prefix argument), also print the used versions of Magit, Git, +and Emacs to it." + (interactive (list (if current-prefix-arg (current-buffer) t))) + (let ((magit-git-global-arguments nil) + (toplib (or load-file-name buffer-file-name)) + debug) + (unless (and toplib + (member (file-name-nondirectory toplib) + '("magit.el" "magit.el.gz"))) + (let ((load-suffixes (reverse load-suffixes))) ; prefer .el than .elc + (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)) + (gitdir (expand-file-name + ".git" (file-name-directory + (directory-file-name topdir)))) + (static (locate-library "magit-version.el" nil (list topdir))) + (static (and static (magit--straight-chase-links static)))) + (or (progn + (push 'repo debug) + (when (and (file-exists-p gitdir) + ;; It is a repo, but is it the Magit repo? + (file-exists-p + (expand-file-name "../lisp/magit.el" gitdir))) + (push t debug) + ;; Inside the repo the version file should only exist + ;; while running make. + (when (and static (not noninteractive)) + (ignore-errors (delete-file static))) + (setq magit-version + (let ((default-directory topdir)) + (magit-git-string "describe" + "--tags" "--dirty" "--always"))))) + (progn + (push 'static debug) + (when (and static (file-exists-p static)) + (push t debug) + (load-file static) + magit-version)) + (when (featurep 'package) + (push 'elpa debug) + (ignore-errors + (--when-let (assq 'magit package-alist) + (push t debug) + (setq magit-version + (and (fboundp 'package-desc-version) + (package-version-join + (package-desc-version (cadr it)))))))) + (progn + (push 'dirname debug) + (let ((dirname (file-name-nondirectory + (directory-file-name topdir)))) + (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%s, Git %s, Emacs %s, %s" + (or magit-version "(unknown)") + (or (and (ignore-errors + (magit--version>= magit-version "2008")) + (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) + err :error)))) + (magit-git-version t)) + "(unknown)") + emacs-version + system-type) + print-dest)) + (setq debug (reverse debug)) + (setq magit-version 'error) + (when magit-version + (push magit-version debug)) + (unless (equal (getenv "CI") "true") + ;; The repository is a sparse clone. + (message "Cannot determine Magit's version %S" debug))) + magit-version)) + +;;; Debugging Tools + +(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)) + (format " [%S]" (executable-find magit-git-executable))) + (format " (%s)\n" + (let* ((errmsg nil) + (magit-git-debug (lambda (err) (setq errmsg err)))) + (or (magit-git-version t) errmsg))))) + (insert (format "exec-path: %S\n" exec-path)) + (--when-let (cl-set-difference + (-filter #'file-exists-p (remq nil (parse-colon-path + (getenv "PATH")))) + (-filter #'file-exists-p (remq nil exec-path)) + :test #'file-equal-p) + (insert (format " entries in PATH, but not in exec-path: %S\n" it))) + (dolist (execdir exec-path) + (insert (format " %s (%s)\n" execdir (car (file-attributes execdir)))) + (when (file-directory-p execdir) + (dolist (exec (directory-files + execdir t (concat + "\\`git" (regexp-opt exec-suffixes) "\\'"))) + (insert (format " %s (%s)\n" exec + (let* ((magit-git-executable exec) + (errmsg nil) + (magit-git-debug (lambda (err) (setq errmsg err)))) + (or (magit-git-version t) errmsg))))))))) + +;;; Startup Asserts + +(defun magit-startup-asserts () + (when-let ((val (getenv "GIT_DIR"))) + (setenv "GIT_DIR") + (message "Magit unset $GIT_DIR (was %S). See \ +https://github.com/magit/magit/wiki/Don't-set-$GIT_DIR-and-alike" val)) + (when-let ((val (getenv "GIT_WORK_TREE"))) + (setenv "GIT_WORK_TREE") + (message "Magit unset $GIT_WORK_TREE (was %S). See \ +https://github.com/magit/magit/wiki/Don't-set-$GIT_DIR-and-alike" val)) + (let ((version (magit-git-version))) + (when (and version + (version< version magit--minimal-git) + (not (equal (getenv "CI") "true"))) + (display-warning 'magit (format "\ +Magit requires Git >= %s, you are using %s. + +If this comes as a surprise to you, because you do actually have +a newer version installed, then that probably means that the +older version happens to appear earlier on the `$PATH'. If you +always start Emacs from a shell, then that can be fixed in the +shell's init file. If you start Emacs by clicking on an icon, +or using some sort of application launcher, then you probably +have to adjust the environment as seen by graphical interface. +For X11 something like ~/.xinitrc should work. + +If you use Tramp to work inside remote Git repositories, then you +have to make sure a suitable Git is used on the remote machines +too.\n" magit--minimal-git version) :error))) + (when (version< emacs-version magit--minimal-emacs) + (display-warning 'magit (format "\ +Magit requires Emacs >= %s, you are using %s. + +If this comes as a surprise to you, because you do actually have +a newer version installed, then that probably means that the +older version happens to appear earlier on the `$PATH'. If you +always start Emacs from a shell, then that can be fixed in the +shell's init file. If you start Emacs by clicking on an icon, +or using some sort of application launcher, then you probably +have to adjust the environment as seen by graphical interface. +For X11 something like ~/.xinitrc should work.\n" + magit--minimal-emacs emacs-version) + :error))) + +;;; Loading Libraries + +(provide 'magit) + +(cl-eval-when (load eval) + (require 'magit-status) + (require 'magit-refs) + (require 'magit-files) + (require 'magit-reset) + (require 'magit-branch) + (require 'magit-merge) + (require 'magit-tag) + (require 'magit-worktree) + (require 'magit-notes) + (require 'magit-sequence) + (require 'magit-commit) + (require 'magit-remote) + (require 'magit-clone) + (require 'magit-fetch) + (require 'magit-pull) + (require 'magit-push) + (require 'magit-bisect) + (require 'magit-stash) + (require 'magit-blame) + (require 'magit-obsolete) + (require 'magit-submodule) + (unless (load "magit-autoloads" t t) + (require 'magit-patch) + (require 'magit-subtree) + (require 'magit-ediff) + (require 'magit-gitignore) + (require 'magit-extras) + (require 'git-rebase) + (require 'magit-imenu) + (require 'magit-bookmark))) + +(with-eval-after-load 'bookmark + (require 'magit-bookmark)) + +(if after-init-time + (progn (magit-startup-asserts) + (magit-version)) + (add-hook 'after-init-hook #'magit-startup-asserts t) + (add-hook 'after-init-hook #'magit-version t)) + +;;; magit.el ends here diff --git a/elpa/magit-20220116.1908/magit.info b/elpa/magit-20220116.1908/magit.info new file mode 100644 index 00000000..1dac8896 --- /dev/null +++ b/elpa/magit-20220116.1908/magit.info @@ -0,0 +1,10995 @@ +This is magit.info, produced by makeinfo version 6.7 from magit.texi. + + Copyright (C) 2015-2022 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 + Foundation, either version 3 of the License, or (at your option) + any later version. + + This document 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. + +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* Magit: (magit). Using Git from Emacs with Magit. +END-INFO-DIR-ENTRY + + +File: magit.info, Node: Top, Next: Introduction, Up: (dir) + +Magit User Manual +***************** + +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. + +This manual is for Magit version v3.3.0-79-g2e73b66c2+1. + + Copyright (C) 2015-2022 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 + Foundation, either version 3 of the License, or (at your option) + any later version. + + This document 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. + +* Menu: + +* Introduction:: +* Installation:: +* Getting Started:: +* Interface Concepts:: +* Inspecting:: +* Manipulating:: +* Transferring:: +* Miscellaneous:: +* Customizing:: +* Plumbing:: +* FAQ:: +* Debugging Tools:: +* Keystroke Index:: +* Function and Command Index:: +* Variable Index:: + +— The Detailed Node Listing — + +Installation + +* Installing from Melpa:: +* Installing from the Git Repository:: +* Post-Installation Tasks:: + +Interface Concepts + +* Modes and Buffers:: +* Sections:: +* Transient Commands:: +* Transient Arguments and Buffer Variables:: +* Completion, Confirmation and the Selection: Completion Confirmation and the Selection. +* Running Git:: + +Modes and Buffers + +* Switching Buffers:: +* Naming Buffers:: +* Quitting Windows:: +* Automatic Refreshing of Magit Buffers:: +* Automatic Saving of File-Visiting Buffers:: +* Automatic Reverting of File-Visiting Buffers:: + + +Sections + +* Section Movement:: +* Section Visibility:: +* Section Hooks:: +* Section Types and Values:: +* Section Options:: + + +Completion, Confirmation and the Selection + +* Action Confirmation:: +* Completion and Confirmation:: +* The Selection:: +* The hunk-internal region:: +* Support for Completion Frameworks:: +* Additional Completion Options:: + + +Running Git + +* Viewing Git Output:: +* Git Process Status:: +* Running Git Manually:: +* Git Executable:: +* Global Git Arguments:: + + +Inspecting + +* Status Buffer:: +* Repository List:: +* Logging:: +* Diffing:: +* Ediffing:: +* References Buffer:: +* Bisecting:: +* Visiting Files and Blobs:: +* Blaming:: + +Status Buffer + +* Status Sections:: +* Status Header Sections:: +* Status Module Sections:: +* Status Options:: + + +Logging + +* Refreshing Logs:: +* Log Buffer:: +* Log Margin:: +* Select from Log:: +* Reflog:: +* Cherries:: + + +Diffing + +* Refreshing Diffs:: +* Commands Available in Diffs:: +* Diff Options:: +* Revision Buffer:: + + +References Buffer + +* References Sections:: + + +Visiting Files and Blobs + +* General-Purpose Visit Commands:: +* Visiting Files and Blobs from a Diff:: + + +Manipulating + +* Creating Repository:: +* Cloning Repository:: +* Staging and Unstaging:: +* Applying:: +* Committing:: +* Branching:: +* Merging:: +* Resolving Conflicts:: +* Rebasing:: +* Cherry Picking:: +* Resetting:: +* Stashing:: + +Staging and Unstaging + +* Staging from File-Visiting Buffers:: + + +Committing + +* Initiating a Commit:: +* Editing Commit Messages:: + + +Branching + +* The Two Remotes:: +* Branch Commands:: +* Branch Git Variables:: +* Auxiliary Branch Commands:: + + +Rebasing + +* Editing Rebase Sequences:: +* Information About In-Progress Rebase:: + + +Cherry Picking + +* Reverting:: + + +Transferring + +* Remotes:: +* Fetching:: +* Pulling:: +* Pushing:: +* Plain Patches:: +* Maildir Patches:: + +Remotes + +* Remote Commands:: +* Remote Git Variables:: + + +Miscellaneous + +* Tagging:: +* Notes:: +* Submodules:: +* Subtree:: +* Worktree:: +* Bundle:: +* Common Commands:: +* Wip Modes:: +* Commands for Buffers Visiting Files:: +* Minor Mode for Buffers Visiting Blobs:: + +Submodules + +* Listing Submodules:: +* Submodule Transient:: + + +Wip Modes + +* Wip Graph:: +* Legacy Wip Modes:: + + +Customizing + +* Per-Repository Configuration:: +* Essential Settings:: + +Essential Settings + +* Safety:: +* Performance:: +* Default Bindings:: + + +Plumbing + +* Calling Git:: +* Section Plumbing:: +* Refreshing Buffers:: +* Conventions:: + +Calling Git + +* Getting a Value from Git:: +* Calling Git for Effect:: + + +Section Plumbing + +* Creating Sections:: +* Section Selection:: +* Matching Sections:: + + +Conventions + +* Theming Faces:: + + +FAQ + +* FAQ - How to ...?:: +* FAQ - Issues and Errors:: + +FAQ - How to ...? + +* 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 ediff-version-control-package?:: +* Should I disable VC?:: + + +FAQ - Issues and Errors + +* Magit is slow:: +* I changed several thousand files at once and now Magit is unusable:: +* I am having problems committing:: +* I am using MS Windows and cannot push with Magit:: +* I am using OS X and SOMETHING works in shell, but not in Magit: I am using OS X and SOMETHING works in shell but not in Magit. +* Expanding a file to show the diff causes it to disappear:: +* Point is wrong in the COMMIT_EDITMSG buffer:: +* The mode-line information isn't always up-to-date:: +* A branch and tag sharing the same name breaks SOMETHING:: +* My Git hooks work on the command-line but not inside Magit:: +* 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:: + + + + +File: magit.info, Node: Introduction, Next: Installation, Prev: Top, Up: Top + +1 Introduction +************** + +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. + + Staging and otherwise applying changes is one of the most important +features in a Git porcelain and here Magit outshines anything else, +including Git itself. Git’s own staging interface (‘git add --patch’) +is so cumbersome that many users only use it in exceptional cases. In +Magit staging a hunk or even just part of a hunk is as trivial as +staging all changes made to a file. + + The most visible part of Magit’s interface is the status buffer, +which displays information about the current repository. Its content is +created by running several Git commands and making their output +actionable. Among other things, it displays information about the +current branch, lists unpulled and unpushed changes and contains +sections displaying the staged and unstaged changes. That might sound +noisy, but, since sections are collapsible, it’s not. + + To stage or unstage a change one places the cursor on the change and +then types ‘s’ or ‘u’. The change can be a file or a hunk, or when the +region is active (i.e. when there is a selection) several files or +hunks, or even just part of a hunk. The change or changes that these +commands - and many others - would act on are highlighted. + + Magit also implements several other "apply variants" in addition to +staging and unstaging. One can discard or reverse a change, or apply it +to the working tree. Git’s own porcelain only supports this for staging +and unstaging and you would have to do something like ‘git diff ... | +??? | git apply ...’ to discard, revert, or apply a single hunk on the +command line. In fact that’s exactly what Magit does internally (which +is what lead to the term "apply variants"). + + Magit isn’t just for Git experts, but it does assume some prior +experience with Git as well as Emacs. That being said, many users have +reported that using Magit was what finally taught them what Git is +capable of and how to use it to its fullest. Other users wished they +had switched to Emacs sooner so that they would have gotten their hands +on Magit earlier. + + While one has to know the basic features of Emacs to be able to make +full use of Magit, acquiring just enough Emacs skills doesn’t take long +and is worth it, even for users who prefer other editors. Vim users are +advised to give Evil (https://github.com/emacs-evil/evil), the +"Extensible VI Layer for Emacs", and Spacemacs +(https://github.com/syl20bnr/spacemacs), an "Emacs starter-kit focused +on Evil" a try. + + Magit provides a consistent and efficient Git porcelain. After a +short learning period, you will be able to perform most of your daily +version control tasks faster than you would on the command line. You +will likely also start using features that seemed too daunting in the +past. + + Magit fully embraces Git. It exposes many advanced features using a +simple but flexible interface instead of only wrapping the trivial ones +like many GUI clients do. Of course Magit supports logging, cloning, +pushing, and other commands that usually don’t fail in spectacular ways; +but it also supports tasks that often cannot be completed in a single +step. Magit fully supports tasks such as merging, rebasing, +cherry-picking, reverting, and blaming by not only providing a command +to initiate these tasks but also by displaying context sensitive +information along the way and providing commands that are useful for +resolving conflicts and resuming the sequence after doing so. + + Magit wraps and in many cases improves upon at least the following +Git porcelain commands: ‘add’, ‘am’, ‘bisect’, ‘blame’, ‘branch’, +‘checkout’, ‘cherry’, ‘cherry-pick’, ‘clean’, ‘clone’, ‘commit’, +‘config’, ‘describe’, ‘diff’, ‘fetch’, ‘format-patch’, ‘init’, ‘log’, +‘merge’, ‘merge-tree’, ‘mv’, ‘notes’, ‘pull’, ‘rebase’, ‘reflog’, +‘remote’, ‘request-pull’, ‘reset’, ‘revert’, ‘rm’, ‘show’, ‘stash’, +‘submodule’, ‘subtree’, ‘tag’, and ‘worktree.’ Many more Magit porcelain +commands are implemented on top of Git plumbing commands. + + +File: magit.info, Node: Installation, Next: Getting Started, Prev: Introduction, Up: Top + +2 Installation +************** + +Magit can be installed using Emacs’ package manager or manually from its +development repository. + +* Menu: + +* Installing from Melpa:: +* Installing from the Git Repository:: +* Post-Installation Tasks:: + + +File: magit.info, Node: Installing from Melpa, Next: Installing from the Git Repository, Up: Installation + +2.1 Installing from Melpa +========================= + +Magit is available from Melpa and Melpa-Stable. If you haven’t used +Emacs’ package manager before, then it is high time you familiarize +yourself with it by reading the documentation in the Emacs manual, see +*note (emacs)Packages::. Then add one of the archives to +‘package-archives’: + + • To use Melpa: + + (require 'package) + (add-to-list 'package-archives + '("melpa" . "http://melpa.org/packages/") t) + + • To use Melpa-Stable: + + (require 'package) + (add-to-list 'package-archives + '("melpa-stable" . "http://stable.melpa.org/packages/") t) + + Once you have added your preferred archive, you need to update the +local package list using: + + M-x package-refresh-contents RET + + Once you have done that, you can install Magit and its dependencies +using: + + M-x package-install RET magit RET + + Now see *note Post-Installation Tasks::. + + +File: magit.info, Node: Installing from the Git Repository, Next: Post-Installation Tasks, Prev: Installing from Melpa, Up: Installation + +2.2 Installing from the Git Repository +====================================== + +Magit depends on the ‘dash’, ‘transient’ and ‘with-editor’ libraries +which are available from Melpa and Melpa-Stable. Install them using +‘M-x package-install RET RET’. Of course you may also install +them manually from their repository. + + Then clone the Magit repository: + + $ git clone https://github.com/magit/magit.git ~/.emacs.d/site-lisp/magit + $ cd ~/.emacs.d/site-lisp/magit + + Then compile the libraries and generate the info manuals: + + $ make + + If you haven’t installed ‘dash’, ‘transient’ and ‘with-editor’ from +Melpa or at ‘/path/to/magit/../’, then you have to tell ‘make’ +where to find them. To do so create the file ‘/path/to/magit/config.mk’ +with the following content before running ‘make’: + + 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 + + Finally add this to your init file: + + (add-to-list 'load-path "~/.emacs.d/site-lisp/magit/lisp") + (require 'magit) + + (with-eval-after-load 'info + (info-initialize) + (add-to-list 'Info-directory-list + "~/.emacs.d/site-lisp/magit/Documentation/")) + + Of course if you installed the dependencies manually as well, then +you have to tell Emacs about them too, by prefixing the above with: + + (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") + + 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. + + Instead of requiring the feature ‘magit’, you could load just the +autoload definitions, by loading the file ‘magit-autoloads.el’. + + (load "/path/to/magit/lisp/magit-autoloads") + + Instead of running Magit directly from the repository by adding that +to the ‘load-path’, you might want to instead install it in some other +directory using ‘sudo make install’ and setting ‘load-path’ accordingly. + + To update Magit use: + + $ git pull + $ make + + At times it might be necessary to run ‘make clean all’ instead. + + To view all available targets use ‘make help’. + + Now see *note Post-Installation Tasks::. + + +File: magit.info, Node: Post-Installation Tasks, Prev: Installing from the Git Repository, Up: Installation + +2.3 Post-Installation Tasks +=========================== + +After installing Magit you should verify that you are indeed using the +Magit, Git, and Emacs releases you think you are using. It’s best to +restart Emacs before doing so, to make sure you are not using an +outdated value for ‘load-path’. + + M-x magit-version RET + + should display something like + + Magit 2.8.0, Git 2.10.2, Emacs 25.1.1, gnu/linux + + Then you might also want to read about options that many users likely +want to customize. See *note Essential Settings::. + + To be able to follow cross references to Git manpages found in this +manual, you might also have to manually install the ‘gitman’ info +manual, or advice ‘Info-follow-nearest-node’ to instead open the actual +manpage. See *note How to install the gitman info manual?::. + + If you are completely new to Magit then see *note Getting Started::. + + If you run into problems, then please see the *note FAQ::. Also see +the *note Debugging Tools::. + + And last but not least please consider making a donation, to ensure +that I can keep working on Magit. See . +for various donation options. + + +File: magit.info, Node: Getting Started, Next: Interface Concepts, Prev: Installation, Up: Top + +3 Getting Started +***************** + +This short tutorial describes the most essential features that many +Magitians use on a daily basis. It only scratches the surface but +should be enough to get you started. + + IMPORTANT: It is safest if you clone some repository just for this +tutorial. Alternatively you can use an existing local repository, but +if you do that, then you should commit all uncommitted changes before +proceeding. + + 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 +Magit. Many other Magit buffers may exist at a given time, but they are +often created from this buffer. + + Depending on what state your repository is in, this buffer may +contain sections titled "Staged changes", "Unstaged changes", "Unmerged +into origin/master", "Unpushed to origin/master", and many others. + + Since we are starting from a safe state, which you can easily return +to (by doing a ‘git reset --hard PRE-MAGIT-STATE’), there currently are +no staged or unstaged changes. Edit some files and save the changes. +Then go back to the status buffer, while at the same time refreshing it, +by typing ‘C-x g’. (When the status buffer, or any Magit buffer for +that matter, is the current buffer, then you can also use just ‘g’ to +refresh it). + + Move between sections using ‘p’ and ‘n’. Note that the bodies of +some sections are hidden. Type ‘TAB’ to expand or collapse the section +at point. You can also use ‘C-tab’ to cycle the visibility of the +current section and its children. Move to a file section inside the +section named "Unstaged changes" and type ‘s’ to stage the changes you +have made to that file. That file now appears under "Staged changes". + + Magit can stage and unstage individual hunks, not just complete +files. Move to the file you have just staged, expand it using ‘TAB’, +move to one of the hunks using ‘n’, and unstage just that by typing ‘u’. +Note how the staging (‘s’) and unstaging (‘u’) commands operate on the +change at point. Many other commands behave the same way. + + You can also un-/stage just part of a hunk. Inside the body of a +hunk section (move there using ‘C-n’), set the mark using ‘C-SPC’ and +move down until some added and/or removed lines fall inside the region +but not all of them. Again type ‘s’ to stage. + + It is also possible to un-/stage multiple files at once. Move to a +file section, type ‘C-SPC’, move to the next file using ‘n’, and then +‘s’ to stage both files. Note that both the mark and point have to be +on the headings of sibling sections for this to work. If the region +looks like it does in other buffers, then it doesn’t select Magit +sections that can be acted on as a unit. + + And then of course you want to commit your changes. Type ‘c’. This +shows the available commit commands and arguments in a buffer at the +bottom of the frame. Each command and argument is prefixed with the key +that invokes/sets it. Do not worry about this for now. We want to +create a "normal" commit, which is done by typing ‘c’ again. + + 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 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 +you just committed some random changes, but if that is not the case you +could push it by typing ‘P’ to show all the available push commands and +arguments and then ‘p’ to push to a branch with the same name as the +local branch onto the remote configured as the push-remote. (If the +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 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 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 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 *note 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. + + +File: magit.info, Node: Interface Concepts, Next: Inspecting, Prev: Getting Started, Up: Top + +4 Interface Concepts +******************** + +* Menu: + +* Modes and Buffers:: +* Sections:: +* Transient Commands:: +* Transient Arguments and Buffer Variables:: +* Completion, Confirmation and the Selection: Completion Confirmation and the Selection. +* Running Git:: + + +File: magit.info, Node: Modes and Buffers, Next: Sections, Up: Interface Concepts + +4.1 Modes and Buffers +===================== + +Magit provides several major-modes. For each of these modes there +usually exists only one buffer per repository. Separate modes and thus +buffers exist for commits, diffs, logs, and some other things. + + Besides these special purpose buffers, there also exists an overview +buffer, called the *status buffer*. It’s usually from this buffer that +the user invokes Git commands, or creates or visits other buffers. + + In this manual we often speak about "Magit buffers". By that we mean +buffers whose major-modes derive from ‘magit-mode’. + +‘M-x magit-toggle-buffer-lock’ + This command locks the current buffer to its value or if the buffer + is already locked, then it unlocks it. + + Locking a buffer to its value prevents it from being reused to + display another value. The name of a locked buffer contains its + value, which allows telling it apart from other locked buffers and + the unlocked buffer. + + Not all Magit buffers can be locked to their values; for example, + it wouldn’t make sense to lock a status buffer. + + There can only be a single unlocked buffer using a certain + major-mode per repository. So when a buffer is being unlocked and + another unlocked buffer already exists for that mode and + repository, then the former buffer is instead deleted and the + latter is displayed in its place. + +* Menu: + +* Switching Buffers:: +* Naming Buffers:: +* Quitting Windows:: +* Automatic Refreshing of Magit Buffers:: +* Automatic Saving of File-Visiting Buffers:: +* Automatic Reverting of File-Visiting Buffers:: + + +File: magit.info, Node: Switching Buffers, Next: Naming Buffers, Up: Modes and Buffers + +4.1.1 Switching Buffers +----------------------- + + -- Function: magit-display-buffer buffer &optional display-function + This function is a wrapper around ‘display-buffer’ and is used to + display any Magit buffer. It displays BUFFER in some window and, + unlike ‘display-buffer’, also selects that window, provided + ‘magit-display-buffer-noselect’ is ‘nil’. It also runs the hooks + mentioned below. + + If optional DISPLAY-FUNCTION is non-nil, then that is used to + display the buffer. Usually that is ‘nil’ and the function + specified by ‘magit-display-buffer-function’ is used. + + -- Variable: magit-display-buffer-noselect + When this is non-nil, then ‘magit-display-buffer’ only displays the + buffer but forgoes also selecting the window. This variable should + not be set globally, it is only intended to be let-bound, by code + that automatically updates "the other window". This is used for + example when the revision buffer is updated when you move inside + the log buffer. + + -- User Option: magit-display-buffer-function + The function specified here is called by ‘magit-display-buffer’ + with one argument, a buffer, to actually display that buffer. This + function should call ‘display-buffer’ with that buffer as first and + a list of display actions as second argument. + + Magit provides several functions, listed below, that are suitable + values for this option. If you want to use different rules, then a + good way of doing that is to start with a copy of one of these + functions and then adjust it to your needs. + + Instead of using a wrapper around ‘display-buffer’, that function + itself can be used here, in which case the display actions have to + be specified by adding them to ‘display-buffer-alist’ instead. + + To learn about display actions, see *note (elisp)Choosing Window::. + + -- Function: magit-display-buffer-traditional buffer + This function is the current default value of the option + ‘magit-display-buffer-function’. Before that option and this + function were added, the behavior was hard-coded in many places all + over the code base but now all the rules are contained in this one + function (except for the "noselect" special case mentioned above). + + -- Function: magit-display-buffer-same-window-except-diff-v1 + This function displays most buffers in the currently selected + window. If a buffer’s mode derives from ‘magit-diff-mode’ or + ‘magit-process-mode’, it is displayed in another window. + + -- Function: magit-display-buffer-fullframe-status-v1 + This function fills the entire frame when displaying a status + buffer. Otherwise, it behaves like + ‘magit-display-buffer-traditional’. + + -- Function: magit-display-buffer-fullframe-status-topleft-v1 + This function fills the entire frame when displaying a status + buffer. It behaves like ‘magit-display-buffer-fullframe-status-v1’ + except that it displays buffers that derive from ‘magit-diff-mode’ + or ‘magit-process-mode’ to the top or left of the current buffer + rather than to the bottom or right. As a result, Magit buffers + tend to pop up on the same side as they would if + ‘magit-display-buffer-traditional’ were in use. + + -- Function: magit-display-buffer-fullcolumn-most-v1 + This function displays most buffers so that they fill the entire + height of the frame. However, the buffer is displayed in another + window if (1) the buffer’s mode derives from ‘magit-process-mode’, + or (2) the buffer’s mode derives from ‘magit-diff-mode’, provided + that the mode of the current buffer derives from ‘magit-log-mode’ + or ‘magit-cherry-mode’. + + -- User Option: magit-pre-display-buffer-hook + This hook is run by ‘magit-display-buffer’ before displaying the + buffer. + + -- Function: magit-save-window-configuration + This function saves the current window configuration. Later when + the buffer is buried, it may be restored by + ‘magit-restore-window-configuration’. + + -- User Option: magit-post-display-buffer-hook + This hook is run by ‘magit-display-buffer’ after displaying the + buffer. + + -- Function: magit-maybe-set-dedicated + This function remembers if a new window had to be created to + display the buffer, or whether an existing window was reused. This + information is later used by ‘magit-mode-quit-window’, to determine + whether the window should be deleted when its last Magit buffer is + buried. + + +File: magit.info, Node: Naming Buffers, Next: Quitting Windows, Prev: Switching Buffers, Up: Modes and Buffers + +4.1.2 Naming Buffers +-------------------- + + -- User Option: magit-generate-buffer-name-function + The function used to generate the names of Magit buffers. + + Such a function should take the options + ‘magit-uniquify-buffer-names’ as well as ‘magit-buffer-name-format’ + into account. If it doesn’t, then should be clearly stated in the + doc-string. And if it supports %-sequences beyond those mentioned + in the doc-string of the option ‘magit-buffer-name-format’, then + its own doc-string should describe the additions. + + -- Function: magit-generate-buffer-name-default-function mode + This function returns a buffer name suitable for a buffer whose + major-mode is MODE and which shows information about the repository + in which ‘default-directory’ is located. + + This function uses ‘magit-buffer-name-format’ and supporting all of + the %-sequences mentioned the documentation of that option. It + also respects the option ‘magit-uniquify-buffer-names’. + + -- User Option: magit-buffer-name-format + The format string used to name Magit buffers. + + At least the following %-sequences are supported: + + • ‘%m’ + + The name of the major-mode, but with the ‘-mode’ suffix + removed. + + • ‘%M’ + + Like ‘%m’ but abbreviate ‘magit-status-mode’ as ‘magit’. + + • ‘%v’ + + The value the buffer is locked to, in parentheses, or an empty + string if the buffer is not locked to a value. + + • ‘%V’ + + Like ‘%v’, but the string is prefixed with a space, unless it + is an empty string. + + • ‘%t’ + + The top-level directory of the working tree of the repository, + or if ‘magit-uniquify-buffer-names’ is non-nil an abbreviation + of that. + + • ‘%x’ + + If ‘magit-uniquify-buffer-names’ is nil "*", otherwise the + empty string. Due to limitations of the ‘uniquify’ package, + buffer names must end with the path. + + • ‘%T’ + + Obsolete, use "%t%x" instead. Like ‘%t’, but append an + asterisk if and only if ‘magit-uniquify-buffer-names’ is nil. + + The value should always contain ‘%m’ or ‘%M’, ‘%v’ or ‘%V’, and + ‘%t’ (or the obsolete ‘%T’). If ‘magit-uniquify-buffer-names’ is + non-nil, then the value must end with ‘%t’ or ‘%t%x’ (or the + obsolete ‘%T’). See issue #2841. + + -- User Option: magit-uniquify-buffer-names + This option controls whether the names of Magit buffers are + uniquified. If the names are not being uniquified, then they + contain the full path of the top-level of the working tree of the + corresponding repository. If they are being uniquified, then they + end with the basename of the top-level, or if that would conflict + with the name used for other buffers, then the names of all these + buffers are adjusted until they no longer conflict. + + This is done using the ‘uniquify’ package; customize its options to + control how buffer names are uniquified. + + +File: magit.info, Node: Quitting Windows, Next: Automatic Refreshing of Magit Buffers, Prev: Naming Buffers, Up: Modes and Buffers + +4.1.3 Quitting Windows +---------------------- + +‘q’ (‘magit-mode-bury-buffer’) + This command buries the current Magit buffer. + + With a prefix argument, it instead kills the buffer. With a double + prefix argument, also kills all other Magit buffers associated with + the current project. + + -- User Option: magit-bury-buffer-function + The function used to actually bury or kill the current buffer. + + ‘magit-mode-bury-buffer’ calls this function with one argument. If + the argument is non-nil, then the function has to kill the current + buffer. Otherwise it has to bury it alive. The default value + currently is ‘magit-restore-window-configuration’. + + -- Function: magit-restore-window-configuration kill-buffer + Bury or kill the current buffer using ‘quit-window’, which is + called with KILL-BUFFER as first and the selected window as second + argument. + + Then restore the window configuration that existed right before the + current buffer was displayed in the selected frame. Unfortunately + that also means that point gets adjusted in all the buffers, which + are being displayed in the selected frame. + + -- Function: magit-mode-quit-window kill-buffer + Bury or kill the current buffer using ‘quit-window’, which is + called with KILL-BUFFER as first and the selected window as second + argument. + + Then, if the window was originally created to display a Magit + buffer and the buried buffer was the last remaining Magit buffer + that was ever displayed in the window, then that is deleted. + + +File: magit.info, Node: Automatic Refreshing of Magit Buffers, Next: Automatic Saving of File-Visiting Buffers, Prev: Quitting Windows, Up: Modes and Buffers + +4.1.4 Automatic Refreshing of Magit Buffers +------------------------------------------- + +After running a command which may change the state of the current +repository, the current Magit buffer and the corresponding status buffer +are refreshed. The status buffer can be automatically refreshed +whenever a buffer is saved to a file inside the respective repository by +adding a hook, like so: + + (with-eval-after-load 'magit-mode + (add-hook 'after-save-hook 'magit-after-save-refresh-status t)) + + Automatically refreshing Magit buffers ensures that the displayed +information is up-to-date most of the time but can lead to a noticeable +delay in big repositories. Other Magit buffers are not refreshed to +keep the delay to a minimum and also because doing so can sometimes be +undesirable. + + Buffers can also be refreshed explicitly, which is useful in buffers +that weren’t current during the last refresh and after changes were made +to the repository outside of Magit. + +‘g’ (‘magit-refresh’) + This command refreshes the current buffer if its major mode derives + from ‘magit-mode’ as well as the corresponding status buffer. + + If the option ‘magit-revert-buffers’ calls for it, then it also + reverts all unmodified buffers that visit files being tracked in + the current repository. + +‘G’ (‘magit-refresh-all’) + This command refreshes all Magit buffers belonging to the current + repository and also reverts all unmodified buffers that visit files + being tracked in the current repository. + + The file-visiting buffers are always reverted, even if + ‘magit-revert-buffers’ is nil. + + -- User Option: magit-refresh-buffer-hook + This hook is run in each Magit buffer that was refreshed during the + current refresh - normally the current buffer and the status + buffer. + + -- User Option: magit-refresh-status-buffer + When this option is non-nil, then the status buffer is + automatically refreshed after running git for side-effects, in + addition to the current Magit buffer, which is always refreshed + automatically. + + Only set this to nil after exhausting all other options to improve + performance. + + -- Function: magit-after-save-refresh-status + This function is intended to be added to ‘after-save-hook’. After + doing that the corresponding status buffer is refreshed whenever a + buffer is saved to a file inside a repository. + + Note that refreshing a Magit buffer is done by re-creating its + contents from scratch, which can be slow in large repositories. If + you are not satisfied with Magit’s performance, then you should + obviously not add this function to that hook. + + +File: magit.info, Node: Automatic Saving of File-Visiting Buffers, Next: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Refreshing of Magit Buffers, Up: Modes and Buffers + +4.1.5 Automatic Saving of File-Visiting Buffers +----------------------------------------------- + +File-visiting buffers are by default saved at certain points in time. +This doesn’t guarantee that Magit buffers are always up-to-date, but, +provided one only edits files by editing them in Emacs and uses only +Magit to interact with Git, one can be fairly confident. When in doubt +or after outside changes, type ‘g’ (‘magit-refresh’) to save and refresh +explicitly. + + -- User Option: magit-save-repository-buffers + This option controls whether file-visiting buffers are saved before + certain events. + + If this is non-nil then all modified file-visiting buffers + belonging to the current repository may be saved before running + commands, before creating new Magit buffers, and before explicitly + refreshing such buffers. If this is ‘dontask’ then this is done + without user intervention. If it is ‘t’ then the user has to + confirm each save. + + +File: magit.info, Node: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Saving of File-Visiting Buffers, Up: Modes and Buffers + +4.1.6 Automatic Reverting of File-Visiting Buffers +-------------------------------------------------- + +By default Magit automatically reverts buffers that are visiting files +that are being tracked in a Git repository, after they have changed on +disk. When using Magit one often changes files on disk by running Git, +i.e. "outside Emacs", making this a rather important feature. + + For example, if you discard a change in the status buffer, then that +is done by running ‘git apply --reverse ...’, and Emacs considers the +file to have "changed on disk". If Magit did not automatically revert +the buffer, then you would have to type ‘M-x revert-buffer RET RET’ in +the visiting buffer before you could continue making changes. + + -- User Option: magit-auto-revert-mode + When this mode is enabled, then buffers that visit tracked files + are automatically reverted after the visited files change on disk. + + -- User Option: global-auto-revert-mode + When this mode is enabled, then any file-visiting buffer is + automatically reverted after the visited file changes on disk. + + If you like buffers that visit tracked files to be automatically + reverted, then you might also like any buffer to be reverted, not + just those visiting tracked files. If that is the case, then + enable this mode _instead of_ ‘magit-auto-revert-mode’. + + -- User Option: magit-auto-revert-immediately + This option controls whether Magit reverts buffers immediately. + + If this is non-nil and either ‘global-auto-revert-mode’ or + ‘magit-auto-revert-mode’ is enabled, then Magit immediately reverts + buffers by explicitly calling ‘auto-revert-buffers’ after running + Git for side-effects. + + If ‘auto-revert-use-notify’ is non-nil (and file notifications are + actually supported), then ‘magit-auto-revert-immediately’ does not + have to be non-nil, because the reverts happen immediately anyway. + + If ‘magit-auto-revert-immediately’ and ‘auto-revert-use-notify’ are + both ‘nil’, then reverts happen after ‘auto-revert-interval’ + seconds of user inactivity. That is not desirable. + + -- User Option: auto-revert-use-notify + This option controls whether file notification functions should be + used. Note that this variable unfortunately defaults to ‘t’ even + on systems on which file notifications cannot be used. + + -- User Option: magit-auto-revert-tracked-only + This option controls whether ‘magit-auto-revert-mode’ only reverts + tracked files or all files that are located inside Git + repositories, including untracked files and files located inside + Git’s control directory. + + -- User Option: auto-revert-mode + The global mode ‘magit-auto-revert-mode’ works by turning on this + local mode in the appropriate buffers (but + ‘global-auto-revert-mode’ is implemented differently). You can + also turn it on or off manually, which might be necessary if Magit + does not notice that a previously untracked file now is being + tracked or vice-versa. + + -- User Option: auto-revert-stop-on-user-input + This option controls whether the arrival of user input suspends the + automatic reverts for ‘auto-revert-interval’ seconds. + + -- User Option: auto-revert-interval + This option controls how many seconds Emacs waits for before + resuming suspended reverts. + + -- User Option: auto-revert-buffer-list-filter + This option specifies an additional filter used by + ‘auto-revert-buffers’ to determine whether a buffer should be + reverted or not. + + This option is provided by Magit, which also advises + ‘auto-revert-buffers’ to respect it. Magit users who do not turn + on the local mode ‘auto-revert-mode’ themselves, are best served by + setting the value to ‘magit-auto-revert-repository-buffer-p’. + + However the default is nil, so as not to disturb users who do use + the local mode directly. If you experience delays when running + Magit commands, then you should consider using one of the + predicates provided by Magit - especially if you also use Tramp. + + Users who do turn on ‘auto-revert-mode’ in buffers in which Magit + doesn’t do that for them, should likely not use any filter. Users + who turn on ‘global-auto-revert-mode’, do not have to worry about + this option, because it is disregarded if the global mode is + enabled. + + -- User Option: auto-revert-verbose + This option controls whether Emacs reports when a buffer has been + reverted. + + The options with the ‘auto-revert-’ prefix are located in the Custom +group named ‘auto-revert’. The other, Magit-specific, options are +located in the ‘magit’ group. + +* Menu: + +* Risk of Reverting Automatically:: + + +File: magit.info, Node: Risk of Reverting Automatically, Up: Automatic Reverting of File-Visiting Buffers + +Risk of Reverting Automatically +............................... + +For the vast majority of users, automatically reverting file-visiting +buffers after they have changed on disk is harmless. + + If a buffer is modified (i.e. it contains changes that haven’t been +saved yet), then Emacs will refuse to automatically revert it. If you +save a previously modified buffer, then that results in what is seen by +Git as an uncommitted change. Git will then refuse to carry out any +commands that would cause these changes to be lost. In other words, if +there is anything that could be lost, then either Git or Emacs will +refuse to discard the changes. + + However, if you use file-visiting buffers as a sort of ad hoc +"staging area", then the automatic reverts could potentially cause data +loss. So far I have heard from only one user who uses such a workflow. + + An example: You visit some file in a buffer, edit it, and save the +changes. Then, outside of Emacs (or at least not using Magit or by +saving the buffer) you change the file on disk again. At this point the +buffer is the only place where the intermediate version still exists. +You have saved the changes to disk, but that has since been overwritten. +Meanwhile Emacs considers the buffer to be unmodified (because you have +not made any changes to it since you last saved it to the visited file) +and therefore would not object to it being automatically reverted. At +this point an Auto-Revert mode would kick in. It would check whether +the buffer is modified and since that is not the case it would revert +it. The intermediate version would be lost. (Actually you could still +get it back using the ‘undo’ command.) + + If your workflow depends on Emacs preserving the intermediate version +in the buffer, then you have to disable all Auto-Revert modes. But +please consider that such a workflow would be dangerous even without +using an Auto-Revert mode, and should therefore be avoided. If Emacs +crashes or if you quit Emacs by mistake, then you would also lose the +buffer content. There would be no autosave file still containing the +intermediate version (because that was deleted when you saved the +buffer) and you would not be asked whether you want to save the buffer +(because it isn’t modified). + + +File: magit.info, Node: Sections, Next: Transient Commands, Prev: Modes and Buffers, Up: Interface Concepts + +4.2 Sections +============ + +Magit buffers are organized into nested sections, which can be collapsed +and expanded, similar to how sections are handled in Org mode. Each +section also has a type, and some sections also have a value. For each +section type there can also be a local keymap, shared by all sections of +that type. + + Taking advantage of the section value and type, many commands operate +on the current section, or when the region is active and selects +sections of the same type, all of the selected sections. Commands that +only make sense for a particular section type (as opposed to just +behaving differently depending on the type) are usually bound in section +type keymaps. + +* Menu: + +* Section Movement:: +* Section Visibility:: +* Section Hooks:: +* Section Types and Values:: +* Section Options:: + + +File: magit.info, Node: Section Movement, Next: Section Visibility, Up: Sections + +4.2.1 Section Movement +---------------------- + +To move within a section use the usual keys (‘C-p’, ‘C-n’, ‘C-b’, ‘C-f’ +etc), whose global bindings are not shadowed. To move to another +section use the following commands. + +‘p’ (‘magit-section-backward’) + When not at the beginning of a section, then move to the beginning + of the current section. At the beginning of a section, instead + move to the beginning of the previous visible section. + +‘n’ (‘magit-section-forward’) + Move to the beginning of the next visible section. + +‘M-p’ (‘magit-section-backward-siblings’) + Move to the beginning of the previous sibling section. If there is + no previous sibling section, then move to the parent section + instead. + +‘M-n’ (‘magit-section-forward-siblings’) + Move to the beginning of the next sibling section. If there is no + next sibling section, then move to the parent section instead. + +‘^’ (‘magit-section-up’) + Move to the beginning of the parent of the current section. + + The above commands all call the hook ‘magit-section-movement-hook’. +Any of the functions listed below can be used as members of this hook. + + You might want to remove some of the functions that Magit adds using +‘add-hook’. In doing so you have to make sure you do not attempt to +remove function that haven’t even been added yet, for example: + + (with-eval-after-load 'magit-diff + (remove-hook 'magit-section-movement-hook + 'magit-hunk-set-window-start)) + + -- Variable: magit-section-movement-hook + This hook is run by all of the above movement commands, after + arriving at the destination. + + -- Function: magit-hunk-set-window-start + This hook function ensures that the beginning of the current + section is visible, provided it is a ‘hunk’ section. Otherwise, it + does nothing. + + Loading ‘magit-diff’ adds this function to the hook. + + -- Function: magit-section-set-window-start + This hook function ensures that the beginning of the current + section is visible, regardless of the section’s type. If you add + this to ‘magit-section-movement-hook’, then you must remove the + hunk-only variant in turn. + + -- Function: magit-log-maybe-show-more-commits + This hook function only has an effect in log buffers, and ‘point’ + is on the "show more" section. If that is the case, then it + doubles the number of commits that are being shown. + + Loading ‘magit-log’ adds this function to the hook. + + -- Function: magit-log-maybe-update-revision-buffer + When moving inside a log buffer, then this function updates the + revision buffer, provided it is already being displayed in another + window of the same frame. + + Loading ‘magit-log’ adds this function to the hook. + + -- Function: magit-log-maybe-update-blob-buffer + When moving inside a log buffer and another window of the same + frame displays a blob buffer, then this function instead displays + the blob buffer for the commit at point in that window. + + -- Function: magit-status-maybe-update-revision-buffer + When moving inside a status buffer, then this function updates the + revision buffer, provided it is already being displayed in another + window of the same frame. + + -- Function: magit-status-maybe-update-stash-buffer + When moving inside a status buffer, then this function updates the + stash buffer, provided it is already being displayed in another + window of the same frame. + + -- Function: magit-status-maybe-update-blob-buffer + When moving inside a status buffer and another window of the same + frame displays a blob buffer, then this function instead displays + the blob buffer for the commit at point in that window. + + -- Function: magit-stashes-maybe-update-stash-buffer + When moving inside a buffer listing stashes, then this function + updates the stash buffer, provided it is already being displayed in + another window of the same frame. + + -- User Option: magit-update-other-window-delay + Delay before automatically updating the other window. + + When moving around in certain buffers, then certain other buffers, + which are being displayed in another window, may optionally be + updated to display information about the section at point. + + When holding down a key to move by more than just one section, then + that would update that buffer for each section on the way. To + prevent that, updating the revision buffer is delayed, and this + option controls for how long. For optimal experience you might + have to adjust this delay and/or the keyboard repeat rate and delay + of your graphical environment or operating system. + + +File: magit.info, Node: Section Visibility, Next: Section Hooks, Prev: Section Movement, Up: Sections + +4.2.2 Section Visibility +------------------------ + +Magit provides many commands for changing the visibility of sections, +but all you need to get started are the next two. + +‘’ (‘magit-section-toggle’) + Toggle the visibility of the body of the current section. + +‘C-’ (‘magit-section-cycle’) + Cycle the visibility of current section and its children. + +‘M-’ (‘magit-section-cycle-diffs’) + Cycle the visibility of diff-related sections in the current + buffer. + +‘S-’ (‘magit-section-cycle-global’) + Cycle the visibility of all sections in the current buffer. + +‘1’ (‘magit-section-show-level-1’) +‘2’ (‘magit-section-show-level-2’) +‘3’ (‘magit-section-show-level-3’) +‘4’ (‘magit-section-show-level-4’) + Show sections surrounding the current section up to level N. + +‘M-1’ (‘magit-section-show-level-1-all’) +‘M-2’ (‘magit-section-show-level-2-all’) +‘M-3’ (‘magit-section-show-level-3-all’) +‘M-4’ (‘magit-section-show-level-4-all’) + Show all sections up to level N. + + Some functions, which are used to implement the above commands, are +also exposed as commands themselves. By default no keys are bound to +these commands, as they are generally perceived to be much less useful. +But your mileage may vary. + + -- Command: magit-section-show + Show the body of the current section. + + -- Command: magit-section-hide + Hide the body of the current section. + + -- Command: magit-section-show-headings + Recursively show headings of children of the current section. Only + show the headings. Previously shown text-only bodies are hidden. + + -- Command: magit-section-show-children + Recursively show the bodies of children of the current section. + With a prefix argument show children down to the level of the + current section, and hide deeper children. + + -- Command: magit-section-hide-children + Recursively hide the bodies of children of the current section. + + -- Command: magit-section-toggle-children + Toggle visibility of bodies of children of the current section. + + When a buffer is first created then some sections are shown expanded +while others are not. This is hard coded. When a buffer is refreshed +then the previous visibility is preserved. The initial visibility of +certain sections can also be overwritten using the hook +‘magit-section-set-visibility-hook’. + + -- User Option: magit-section-initial-visibility-alist + This options can be used to override the initial visibility of + sections. In the future it will also be used to define the + defaults, but currently a section’s default is still hardcoded. + + The value is an alist. Each element maps a section type or lineage + to the initial visibility state for such sections. The state has + to be one of ‘show’ or ‘hide’, or a function that returns one of + these symbols. A function is called with the section as the only + argument. + + Use the command ‘magit-describe-section-briefly’ to determine a + section’s lineage or type. The vector in the output is the section + lineage and the type is the first element of that vector. + Wildcards can be used, see ‘magit-section-match’. + + -- User Option: magit-section-cache-visibility + This option controls for which sections the previous visibility + state should be restored if a section disappears and later appears + again. The value is a boolean or a list of section types. If t, + then the visibility of all sections is cached. Otherwise this is + only done for sections whose type matches one of the listed types. + + This requires that the function ‘magit-section-cached-visibility’ + is a member of ‘magit-section-set-visibility-hook’. + + -- Variable: magit-section-set-visibility-hook + This hook is run when first creating a buffer and also when + refreshing an existing buffer, and is used to determine the + visibility of the section currently being inserted. + + Each function is called with one argument, the section being + inserted. It should return ‘hide’ or ‘show’, or to leave the + visibility undefined ‘nil’. If no function decides on the + visibility and the buffer is being refreshed, then the visibility + is preserved; or if the buffer is being created, then the hard + coded default is used. + + Usually this should only be used to set the initial visibility but + not during refreshes. If ‘magit-insert-section--oldroot’ is + non-nil, then the buffer is being refreshed and these functions + should immediately return ‘nil’. + + -- User Option: magit-section-visibility-indicator + This option controls whether and how to indicate that a section can + be expanded/collapsed. + + If nil, then no visibility indicators are shown. Otherwise the + value has to have one of these two forms: + + • ‘(EXPANDABLE-BITMAP . COLLAPSIBLE-BITMAP)’ + + Both values have to be variables whose values are fringe + bitmaps. In this case every section that can be expanded or + collapsed gets an indicator in the left fringe. + + To provide extra padding around the indicator, set + ‘left-fringe-width’ in ‘magit-mode-hook’, e.g.: + + (add-hook 'magit-mode-hook (lambda () + (setq left-fringe-width 20))) + + • ‘(STRING . BOOLEAN)’ + + In this case STRING (usually an ellipsis) is shown at the end + of the heading of every collapsed section. Expanded sections + get no indicator. The cdr controls whether the appearance of + these ellipsis take section highlighting into account. Doing + so might potentially have an impact on performance, while not + doing so is kinda ugly. + + +File: magit.info, Node: Section Hooks, Next: Section Types and Values, Prev: Section Visibility, Up: Sections + +4.2.3 Section Hooks +------------------- + +Which sections are inserted into certain buffers is controlled with +hooks. This includes the status and the refs buffers. For other +buffers, e.g. log and diff buffers, this is not possible. The command +‘magit-describe-section’ can be used to see which hook (if any) was +responsible for inserting the section at point. + + For buffers whose sections can be customized by the user, a hook +variable called ‘magit-TYPE-sections-hook’ exists. This hook should be +changed using ‘magit-add-section-hook’. Avoid using ‘add-hooks’ or the +Custom interface. + + The various available section hook variables are described later in +this manual along with the appropriate "section inserter functions". + + -- Function: magit-add-section-hook hook function &optional at append + local + Add the function FUNCTION to the value of section hook HOOK. + + Add FUNCTION at the beginning of the hook list unless optional + APPEND is non-nil, in which case FUNCTION is added at the end. If + FUNCTION already is a member then move it to the new location. + + If optional AT is non-nil and a member of the hook list, then add + FUNCTION next to that instead. Add before or after AT, or replace + AT with FUNCTION depending on APPEND. If APPEND is the symbol + ‘replace’, then replace AT with FUNCTION. For any other non-nil + value place FUNCTION right after AT. If nil, then place FUNCTION + right before AT. If FUNCTION already is a member of the list but + AT is not, then leave FUNCTION where ever it already is. + + If optional LOCAL is non-nil, then modify the hook’s buffer-local + value rather than its global value. This makes the hook local by + copying the default value. That copy is then modified. + + HOOK should be a symbol. If HOOK is void, it is first set to nil. + HOOK’s value must not be a single hook function. FUNCTION should + be a function that takes no arguments and inserts one or multiple + sections at point, moving point forward. FUNCTION may choose not + to insert its section(s), when doing so would not make sense. It + should not be abused for other side-effects. + + To remove a function from a section hook, use ‘remove-hook’. + + +File: magit.info, Node: Section Types and Values, Next: Section Options, Prev: Section Hooks, Up: Sections + +4.2.4 Section Types and Values +------------------------------ + +Each section has a type, for example ‘hunk’, ‘file’, and ‘commit’. +Instances of certain section types also have a value. The value of a +section of type ‘file’, for example, is a file name. + + Users usually do not have to worry about a section’s type and value, +but knowing them can be handy at times. + +‘H’ (‘magit-describe-section’) + This command shows information about the section at point in a + separate buffer. + + -- 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 is +only one of the reasons why the same key may do something different, +depending on what section is current. + + Additionally for each section type a keymap *might* be defined, named +‘magit-TYPE-section-map’. That keymap is used as text property keymap +of all text belonging to any section of the respective type. If such a +map does not exist for a certain type, then you can define it yourself, +and it will automatically be used. + + +File: magit.info, Node: Section Options, Prev: Section Types and Values, Up: Sections + +4.2.5 Section Options +--------------------- + +This section describes options that have an effect on more than just a +certain type of sections. As you can see there are not many of those. + + -- User Option: magit-section-show-child-count + Whether to append the number of children to section headings. This + only affects sections that could benefit from this information. + + +File: magit.info, Node: Transient Commands, Next: Transient Arguments and Buffer Variables, Prev: Sections, Up: Interface Concepts + +4.3 Transient Commands +====================== + +Many Magit commands are implemented as *transient* commands. First the +user invokes a *prefix* command, which causes its *infix* arguments and +*suffix* commands to be displayed in the echo area. The user then +optionally sets some infix arguments and finally invokes one of the +suffix commands. + + This is implemented in the library ‘transient’. Earlier Magit +releases used the package ‘magit-popup’ and even earlier versions +library ‘magit-key-mode’. + + Transient is documented in *note (transient)Top::. + +‘C-c C-c’ (‘magit-dispatch’) + This transient prefix command binds most of Magit’s other prefix + commands as suffix commands and displays them in a temporary buffer + until one of them is invoked. Invoking such a sub-prefix causes + the suffixes of that command to be bound and displayed instead of + those of ‘magit-dispatch’. + + This command is also, or especially, useful outside Magit buffers, so +you should setup a global binding: + + (global-set-key (kbd "C-x M-g") 'magit-dispatch) + + +File: magit.info, Node: Transient Arguments and Buffer Variables, Next: Completion Confirmation and the Selection, Prev: Transient Commands, Up: Interface Concepts + +4.4 Transient Arguments and Buffer Variables +============================================ + +The infix arguments of many of Magit’s transient prefix commands cease +to have an effect once the ‘git’ command that is called with those +arguments has returned. Commands that create a commit are a good +example for this. If the user changes the arguments, then that only +affects the next invocation of a suffix command. If the same transient +prefix command is later invoked again, then the arguments are initially +reset to the default value. This default value can be set for the +current Emacs session or saved permanently, see *note (transient)Saving +Values::. It is also possible to cycle through previously used sets of +arguments using ‘M-p’ and ‘M-n’, see *note (transient)Using History::. + + However the infix arguments of many other transient commands continue +to have an effect even after the ‘git’ command that was called with +those arguments has returned. The most important commands like this are +those that display a diff or log in a dedicated buffer. Their arguments +obviously continue to have an effect for as long as the respective diff +or log is being displayed. Furthermore the used arguments are stored in +buffer-local variables for future reference. + + For commands in the second group it isn’t always desirable to reset +their arguments to the global value when the transient prefix command is +invoked again. + + As mentioned above, it is possible to cycle through previously used +sets of arguments while a transient popup is visible. That means that +we could always reset the infix arguments to the default because the set +of arguments that is active in the existing buffer is only a few ‘M-p’ +away. Magit can be configured to behave like that, but because I expect +that most users would not find that very convenient, it is not the +default. + + Also note that it is possible to change the diff and log arguments +used in the current buffer (including the status buffer, which contains +both diff and log sections) using the respective "refresh" transient +prefix commands on ‘D’ and ‘L’. (‘d’ and ‘l’ on the other hand are +intended to change *what* diff or log is being displayed. It is +possible to also change *how* the diff or log is being displayed at the +same time, but if you only want to do the latter, then you should use +the refresh variants.) Because these secondary diff and log transient +prefixes are about *changing* the arguments used in the current buffer, +they *always* start out with the set of arguments that are currently in +effect in that buffer. + + Some commands are usually invoked directly even though they can also +be invoked as the suffix of a transient prefix command. Most +prominently ‘magit-show-commit’ is usually invoked by typing ‘RET’ while +point is on a commit in a log, but it can also be invoked from the +‘magit-diff’ transient prefix. + + When such a command is invoked directly, then it is important to +reuse the arguments as specified by the respective buffer-local values, +instead of using the default arguments. Imagine you press ‘RET’ in a +log to display the commit at point in a different buffer and then use +‘D’ to change how the diff is displayed in that buffer. And then you +press ‘RET’ on another commit to show that instead and the diff +arguments are reset to the default. Not cool; so Magit does not do that +by default. + + -- User Option: magit-prefix-use-buffer-arguments + This option controls whether the infix arguments initially shown in + certain transient prefix commands are based on the arguments that + are currently in effect in the buffer that their suffixes update. + + The ‘magit-diff’ and ‘magit-log’ transient prefix commands are + affected by this option. + + -- User Option: magit-direct-use-buffer-arguments + This option controls whether certain commands, when invoked + directly (i.e. not as the suffix of a transient prefix command), + use the arguments that are currently active in the buffer that they + are about to update. The alternative is to use the default value + for these arguments, which might change the arguments that are used + in the buffer. + +Valid values for both of the above options are: + + • ‘always’: Always use the set of arguments that is currently active + in the respective buffer, provided that buffer exists of course. + • ‘selected’ or ‘t’: Use the set of arguments from the respective + buffer, but only if it is displayed in a window of the current + frame. This is the default for both variables. + • ‘current’: Use the set of arguments from the respective buffer, but + only if it is the current buffer. + • ‘never’: Never use the set of arguments from the respective buffer. + +I am afraid it gets more complicated still: + + • 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 mode does not change the value + for other modes. The history however is shared. + + • 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 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 commands, instead they use the dedicated + revision and stash buffers. + + At the time you invoke the diff prefix it is unknown to Magit which + of the suffix commands you are going to invoke. While not certain, + more often than not users invoke one of the commands that use the + diff buffer, so the initial infix arguments are those used in that + buffer. However if you invoke one of these commands directly, then + Magit knows that it should use the arguments from the revision + resp. stash buffer. + + • The log prefix also features reflog commands, but these commands do + not use the log arguments. + + • If ‘magit-show-refs’ is invoked from a ‘magit-refs-mode’ buffer, + then it acts as a refresh prefix and therefore unconditionally uses + the buffer’s arguments as initial arguments. If it is invoked + elsewhere with a prefix argument, then it acts as regular prefix + and therefore respects ‘magit-prefix-use-buffer-arguments’. If it + is invoked elsewhere without a prefix argument, then it acts as a + direct command and therefore respects + ‘magit-direct-use-buffer-arguments’. + + +File: magit.info, Node: Completion Confirmation and the Selection, Next: Running Git, Prev: Transient Arguments and Buffer Variables, Up: Interface Concepts + +4.5 Completion, Confirmation and the Selection +============================================== + +* Menu: + +* Action Confirmation:: +* Completion and Confirmation:: +* The Selection:: +* The hunk-internal region:: +* Support for Completion Frameworks:: +* Additional Completion Options:: + + +File: magit.info, Node: Action Confirmation, Next: Completion and Confirmation, Up: Completion Confirmation and the Selection + +4.5.1 Action Confirmation +------------------------- + +By default many actions that could potentially lead to data loss have to +be confirmed. This includes many very common actions, so this can +quickly become annoying. Many of these actions can be undone and if you +have thought about how to undo certain mistakes, then it should be safe +to disable confirmation for the respective actions. + + The option ‘magit-no-confirm’ can be used to tell Magit to perform +certain actions without the user having to confirm them. Note that +while this option can only be used to disable confirmation for a +specific set of actions, the next section explains another way of +telling Magit to ask fewer questions. + + -- User Option: magit-no-confirm + The value of this option is a list of symbols, representing actions + that do not have to be confirmed by the user before being carried + out. + + By default many potentially dangerous commands ask the user for + confirmation. Each of the below symbols stands for an action + which, when invoked unintentionally or without being fully aware of + the consequences, could lead to tears. In many cases there are + several commands that perform variations of a certain action, so we + don’t use the command names but more generic symbols. + + • Applying changes: + + • ‘discard’ Discarding one or more changes (i.e. hunks or + the complete diff for a file) loses that change, + obviously. + + • ‘reverse’ Reverting one or more changes can usually be + undone by reverting the reversion. + + • ‘stage-all-changes’, ‘unstage-all-changes’ When there are + both staged and unstaged changes, then un-/staging + everything would destroy that distinction. Of course + that also applies when un-/staging a single change, but + then less is lost and one does that so often that having + to confirm every time would be unacceptable. + + • Files: + + • ‘delete’ When a file that isn’t yet tracked by Git is + deleted, then it is completely lost, not just the last + changes. Very dangerous. + + • ‘trash’ Instead of deleting a file it can also be move to + the system trash. Obviously much less dangerous than + deleting it. + + Also see option ‘magit-delete-by-moving-to-trash’. + + • ‘resurrect’ A deleted file can easily be resurrected by + "deleting" the deletion, which is done using the same + command that was used to delete the same file in the + first place. + + • ‘untrack’ Untracking a file can be undone by tracking it + again. + + • ‘rename’ Renaming a file can easily be undone. + + • Sequences: + + • ‘reset-bisect’ Aborting (known to Git as "resetting") a + bisect operation loses all information collected so far. + + • ‘abort-rebase’ Aborting a rebase throws away all already + modified commits, but it’s possible to restore those from + the reflog. + + • ‘abort-merge’ Aborting a merge throws away all conflict + resolutions which have already been carried out by the + user. + + • ‘merge-dirty’ Merging with a dirty worktree can make it + hard to go back to the state before the merge was + initiated. + + • References: + + • ‘delete-unmerged-branch’ Once a branch has been deleted, + it can only be restored using low-level recovery tools + provided by Git. And even then the reflog is gone. The + user always has to confirm the deletion of a branch by + accepting the default choice (or selecting another + branch), but when a branch has not been merged yet, also + make sure the user is aware of that. + + • ‘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 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. + + • ‘drop-stashes’ Dropping a stash is dangerous because Git + stores stashes in the reflog. Once a stash is removed, + there is no going back without using low-level recovery + tools provided by Git. When a single stash is dropped, + then the user always has to confirm by accepting the + default (or selecting another). 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". + + • ‘rebase-published’ Affects commands that perform + interactive rebases. This includes commands from the + commit transient that modify a commit other than "HEAD", + namely the various fixup and squash variants. + + • ‘edit-published’ Affects the commands + ‘magit-edit-line-commit’ and + ‘magit-diff-edit-hunk-commit’. These two commands make + it quite easy to accidentally edit a published commit, so + you should think twice before configuring them not to ask + for confirmation. + + To disable confirmation completely, add all three symbols here + or set ‘magit-published-branches’ to ‘nil’. + + • Various: + + • ‘kill-process’ There seldom is a reason to kill a + process. + + • Global settings: + + Instead of adding all of the above symbols to the value of + this option, you can also set it to the atom ‘t’, which has + the same effect as adding all of the above symbols. Doing + that most certainly is a bad idea, especially because other + symbols might be added in the future. So even if you don’t + want to be asked for confirmation for any of these actions, + you are still better of adding all of the respective symbols + individually. + + When ‘magit-wip-before-change-mode’ is enabled, then the + following actions can be undone fairly easily: ‘discard’, + ‘reverse’, ‘stage-all-changes’, and ‘unstage-all-changes’. If + and only if this mode is enabled, then ‘safe-with-wip’ has the + same effect as adding all of these symbols individually. + + +File: magit.info, Node: Completion and Confirmation, Next: The Selection, Prev: Action Confirmation, Up: Completion Confirmation and the Selection + +4.5.2 Completion and Confirmation +--------------------------------- + +Many Magit commands ask the user to select from a list of possible +things to act on, while offering the most likely choice as the default. +For many of these commands the default is the thing at point, provided +that it actually is a valid thing to act on. For many commands that act +on a branch, the current branch serves as the default if there is no +branch at point. + + These commands combine asking for confirmation and asking for a +target to act on into a single action. The user can confirm the default +target using ‘RET’ or abort using ‘C-g’. This is similar to a +‘y-or-n-p’ prompt, but the keys to confirm or abort differ. + + At the same time the user is also given the opportunity to select +another target, which is useful because for some commands and/or in some +situations you might want to select the action before selecting the +target by moving to it. + + However you might find that for some commands you always want to use +the default target, if any, or even that you want the command to act on +the default without requiring any confirmation at all. The option +‘magit-dwim-selection’ can be used to configure certain commands to that +effect. + + Note that when the region is active then many commands act on the +things that are selected using a mechanism based on the region, in many +cases after asking for confirmation. This region-based mechanism is +called the "selection" and is described in detail in the next section. +When a selection exists that is valid for the invoked command, then that +command never offers to act on something else, and whether it asks for +confirmation is not controlled by this option. + + Also note that Magit asks for confirmation of certain actions that +are not coupled with completion (or the selection). Such dialogs are +also not affected by this option and are described in the previous +section. + + -- User Option: magit-dwim-selection + This option can be used to tell certain commands to use the thing at +point instead of asking the user to select a candidate to act on, with +or without confirmation. + + The value has the form ‘((COMMAND nil|PROMPT DEFAULT)...)’. + + • COMMAND is the command that should not prompt for a choice. To + have an effect, the command has to use the function + ‘magit-completing-read’ or a utility function which in turn uses + that function. + + • If the command uses ‘magit-completing-read’ multiple times, then + PROMPT can be used to only affect one of these uses. PROMPT, if + non-nil, is a regular expression that is used to match against the + PROMPT argument passed to ‘magit-completing-read’. + + • DEFAULT specifies how to use the default. If it is ‘t’, then the + DEFAULT argument passed to ‘magit-completing-read’ is used without + confirmation. If it is ‘ask’, then the user is given a chance to + abort. DEFAULT can also be ‘nil’, in which case the entry has no + effect. + + +File: magit.info, Node: The Selection, Next: The hunk-internal region, Prev: Completion and Confirmation, Up: Completion Confirmation and the Selection + +4.5.3 The Selection +------------------- + +If the region is active, then many Magit commands act on the things that +are selected using a mechanism based on the region instead of one single +thing. When the region is not active, then these commands act on the +thing at point or read a single thing to act on. This is described in +the previous section — this section only covers how multiple things are +selected, how that is visualized, and how certain commands behave when +that is the case. + + Magit’s mechanism for selecting multiple things, or rather sections +that represent these things, is based on the Emacs region, but the area +that Magit considers to be selected is typically larger than the region +and additional restrictions apply. + + Magit makes a distinction between a region that qualifies as forming +a valid Magit selection and a region that does not. If the region does +not qualify, then it is displayed as it is in other Emacs buffers. If +the region does qualify as a Magit selection, then the selection is +always visualized, while the region itself is only visualized if it +begins and ends on the same line. + + For a region to qualify as a Magit selection, it must begin in the +heading of one section and end in the heading of a sibling section. +Note that if the end of the region is at the very beginning of section +heading (i.e. at the very beginning of a line) then that section is +considered to be *inside* the selection. + + This is not consistent with how the region is normally treated in +Emacs — if the region ends at the beginning of a line, then that line is +outside the region. Due to how Magit visualizes the selection, it +should be obvious that this difference exists. + + Not every command acts on every valid selection. Some commands do +not even consider the location of point, others may act on the section +at point but not support acting on the selection, and even commands that +do support the selection of course only do so if it selects things that +they can act on. + + This is the main reason why the selection must include the section at +point. Even if a selection exists, the invoked command may disregard +it, in which case it may act on the current section only. It is much +safer to only act on the current section but not the other selected +sections than it is to act on the current section *instead* of the +selected sections. The latter would be much more surprising and if the +current section always is part of the selection, then that cannot +happen. + + -- Variable: magit-keep-region-overlay + This variable controls whether the region is visualized as usual + even when a valid Magit selection or a hunk-internal region exists. + See the doc-string for more information. + + +File: magit.info, Node: The hunk-internal region, Next: Support for Completion Frameworks, Prev: The Selection, Up: Completion Confirmation and the Selection + +4.5.4 The hunk-internal region +------------------------------ + +Somewhat related to the Magit selection described in the previous +section is the hunk-internal region. + + Like the selection, the hunk-internal region is based on the Emacs +region but causes that region to not be visualized as it would in other +Emacs buffers, and includes the line on which the region ends even if it +ends at the very beginning of that line. + + Unlike the selection, which is based on a region that must begin in +the heading of one section and ends in the section of a sibling section, +the hunk-internal region must begin inside the *body* of a hunk section +and end in the body of the *same* section. + + The hunk-internal region is honored by "apply" commands, which can, +among other targets, act on a hunk. If the hunk-internal region is +active, then such commands act only on the marked part of the hunk +instead of on the complete hunk. + + +File: magit.info, Node: Support for Completion Frameworks, Next: Additional Completion Options, Prev: The hunk-internal region, Up: Completion Confirmation and the Selection + +4.5.5 Support for Completion Frameworks +--------------------------------------- + +The built-in option ‘completing-read-function’ specifies the low-level +function used by ‘completing-read’ to ask a user to select from a list +of choices. Its default value is ‘completing-read-default’. +Alternative completion frameworks typically activate themselves by +substituting their own implementation. + + Mostly for historic reasons Magit provides a similar option named +‘magit-completing-read-function’, which only controls the low-level +function used by ‘magit-completing-read’. This option also makes it +possible to use a different completing mechanism for Magit than for the +rest of Emacs, but doing that is not recommend. + + You most likely don’t have to customize the magit-specific option to +use an alternative completion framework. For example, if you enable +‘ivy-mode’, then Magit will respect that, and if you enable ‘helm-mode’, +then you are done too. + + However if you want to use Ido, then ‘ido-mode’ won’t do the trick. +You will also have to install the ‘ido-completing-read+’ package and use +‘magit-ido-completing-read’ as ‘magit-completing-read-function’. + + -- User Option: magit-completing-read-function + The value of this variable is the low-level function used to + perform completion by code that uses ‘magit-completing-read’ (as + opposed to the built-in ‘completing-read’). + + The default value, ‘magit-builtin-completing-read’, is suitable for + the standard completion mechanism, ‘ivy-mode’, and ‘helm-mode’ at + least. + + The built-in ‘completing-read’ and ‘completing-read-default’ are + *not* suitable to be used here. ‘magit-builtin-completing-read’ + performs some additional work, and any function used in its place + has to do the same. + + -- Function: magit-builtin-completing-read prompt choices &optional + predicate require-match initial-input hist def + This function performs completion using the built-in + ‘completing-read’ and does some additional magit-specific work. + + -- Function: magit-ido-completing-read prompt choices &optional + predicate require-match initial-input hist def + This function performs completion using ‘ido-completing-read+’ from + the package by the same name (which you have to explicitly install) + and does some additional magit-specific work. + + We have to use ‘ido-completing-read+’ instead of the + ‘ido-completing-read’ that comes with Ido itself, because the + latter, while intended as a drop-in replacement, cannot serve that + purpose because it violates too many of the implicit conventions. + + -- Function: magit-completing-read prompt choices &optional predicate + require-match initial-input hist def fallback + This is the function that Magit commands use when they need the + user to select a single thing to act on. The arguments have the + same meaning as for ‘completing-read’, except for FALLBACK, which + is unique to this function and is described below. + + Instead of asking the user to choose from a list of possible + candidates, this function may just return the default specified by + DEF, with or without requiring user confirmation. Whether that is + the case depends on PROMPT, ‘this-command’ and + ‘magit-dwim-selection’. See the documentation of the latter for + more information. + + If it does read a value in the minibuffer, then this function acts + similar to ‘completing-read’, except for the following: + + • COLLECTION must be a list of choices. A function is not + supported. + + • If REQUIRE-MATCH is ‘nil’ and the user exits without a choice, + then ‘nil’ is returned instead of an empty string. + + • If REQUIRE-MATCH is non-nil and the users exits without a + choice, an user-error is raised. + + • FALLBACK specifies a secondary default that is only used if + the primary default DEF is ‘nil’. The secondary default is + not subject to ‘magit-dwim-selection’ — if DEF is ‘nil’ but + FALLBACK is not, then this function always asks the user to + choose a candidate, just as if both defaults were ‘nil’. + + • ": " is appended to PROMPT. + + • PROMPT is modified to end with \" (default DEF|FALLBACK): \" + provided that DEF or FALLBACK is non-nil, that neither + ‘ivy-mode’ nor ‘helm-mode’ is enabled, and that + ‘magit-completing-read-function’ is set to its default value + of ‘magit-builtin-completing-read’. + + +File: magit.info, Node: Additional Completion Options, Prev: Support for Completion Frameworks, Up: Completion Confirmation and the Selection + +4.5.6 Additional Completion Options +----------------------------------- + + -- User Option: magit-list-refs-sortby + For many commands that read a ref or refs from the user, the value + of this option can be used to control the order of the refs. Valid + values include any key accepted by the ‘--sort’ flag of ‘git + for-each-ref’. By default, refs are sorted alphabetically by their + full name (e.g., "refs/heads/master"). + + +File: magit.info, Node: Running Git, Prev: Completion Confirmation and the Selection, Up: Interface Concepts + +4.6 Running Git +=============== + +* Menu: + +* Viewing Git Output:: +* Git Process Status:: +* Running Git Manually:: +* Git Executable:: +* Global Git Arguments:: + + +File: magit.info, Node: Viewing Git Output, Next: Git Process Status, Up: Running Git + +4.6.1 Viewing Git Output +------------------------ + +Magit runs Git either for side-effects (e.g. when pushing) or to get +some value (e.g. the name of the current branch). + + When Git is run for side-effects, the process output is logged in a +per-repository log buffer, which can be consulted using the +‘magit-process’ command when things don’t go as expected. + + The output/errors for up to ‘magit-process-log-max’ Git commands are +retained. + +‘$’ (‘magit-process’) + This commands displays the process buffer for the current + repository. + + Inside that buffer, the usual key bindings for navigating and showing +sections are available. There is one additional command. + +‘k’ (‘magit-process-kill’) + This command kills the process represented by the section at point. + + -- Variable: magit-git-debug + 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. + + +File: magit.info, Node: Git Process Status, Next: Running Git Manually, Prev: Viewing Git Output, Up: Running Git + +4.6.2 Git Process Status +------------------------ + +When a Git process is running for side-effects, Magit displays an +indicator in the mode line, using the ‘magit-mode-line-process’ face. + + If the Git process exits successfully, the process indicator is +removed from the mode line immediately. + + In the case of a Git error, the process indicator is not removed, but +is instead highlighted with the ‘magit-mode-line-process-error’ face, +and the error details from the process buffer are provided as a tooltip +for mouse users. This error indicator persists in the mode line until +the next magit buffer refresh. + + If you do not wish process errors to be indicated in the mode line, +customize the ‘magit-process-display-mode-line-error’ user option. + + Process errors are additionally indicated at the top of the status +buffer. + + +File: magit.info, Node: Running Git Manually, Next: Git Executable, Prev: Git Process Status, Up: Running Git + +4.6.3 Running Git Manually +-------------------------- + +While Magit provides many Emacs commands to interact with Git, it does +not cover everything. In those cases your existing Git knowledge will +come in handy. Magit provides some commands for running arbitrary Git +commands by typing them into the minibuffer, instead of having to switch +to a shell. + +‘!’ (‘magit-run’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + +‘! !’ (‘magit-git-command-topdir’) + This command reads a command from the user and executes it in the + top-level directory of the current working tree. + + The string "git " is used as initial input when prompting the user + for the command. It can be removed to run another command. + +‘:’ (‘magit-git-command’) +‘! p’ + This command reads a command from the user and executes it in + ‘default-directory’. With a prefix argument the command is + executed in the top-level directory of the current working tree + instead. + + The string "git " is used as initial input when prompting the user + for the command. It can be removed to run another command. + +‘! s’ (‘magit-shell-command-topdir’) + This command reads a command from the user and executes it in the + top-level directory of the current working tree. + +‘! S’ (‘magit-shell-command’) + This command reads a command from the user and executes it in + ‘default-directory’. With a prefix argument the command is + executed in the top-level directory of the current working tree + instead. + + -- User Option: magit-shell-command-verbose-prompt + Whether the prompt, used by the above commands when reading a shell + command, shows the directory in which it will be run. + + These suffix commands start external gui tools. + +‘! k’ (‘magit-run-gitk’) + This command runs ‘gitk’ in the current repository. + +‘! a’ (‘magit-run-gitk-all’) + This command runs ‘gitk --all’ in the current repository. + +‘! b’ (‘magit-run-gitk-branches’) + This command runs ‘gitk --branches’ in the current repository. + +‘! g’ (‘magit-run-git-gui’) + This command runs ‘git gui’ in the current repository. + + +File: magit.info, Node: Git Executable, Next: Global Git Arguments, Prev: Running Git Manually, Up: Running Git + +4.6.4 Git Executable +-------------------- + +When Magit calls Git, then it may do so using the absolute path to the +‘git’ executable, or using just its name. + + 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 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’. + +‘M-x magit-debug-git-executable’ + This command displays a buffer with information about + ‘magit-git-executable’ and ‘magit-remote-git-executable’. + +‘M-x 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. + + +File: magit.info, Node: Global Git Arguments, Prev: Git Executable, Up: Running Git + +4.6.5 Global Git Arguments +-------------------------- + + -- User Option: magit-git-global-arguments + The arguments set here are used every time the git executable is + run as a subprocess. They are placed right after the executable + itself and before the git command - as in ‘git HERE... COMMAND + REST’. For valid arguments see *note (gitman)git::. + + Be careful what you add here, especially if you are using Tramp to + connect to servers with ancient Git versions. Never remove + anything that is part of the default value, unless you really know + what you are doing. And think very hard before adding something; + it will be used every time Magit runs Git for any purpose. + + +File: magit.info, Node: Inspecting, Next: Manipulating, Prev: Interface Concepts, Up: Top + +5 Inspecting +************ + +The functionality provided by Magit can be roughly divided into three +groups: inspecting existing data, manipulating existing data or adding +new data, and transferring data. Of course that is a rather crude +distinction that often falls short, but it’s more useful than no +distinction at all. This section is concerned with inspecting data, the +next two with manipulating and transferring it. Then follows a section +about miscellaneous functionality, which cannot easily be fit into this +distinction. + + Of course other distinctions make sense too, e.g. Git’s distinction +between porcelain and plumbing commands, which for the most part is +equivalent to Emacs’ distinction between interactive commands and +non-interactive functions. All of the sections mentioned before are +mainly concerned with the porcelain – Magit’s plumbing layer is +described later. + +* Menu: + +* Status Buffer:: +* Repository List:: +* Logging:: +* Diffing:: +* Ediffing:: +* References Buffer:: +* Bisecting:: +* Visiting Files and Blobs:: +* Blaming:: + + +File: magit.info, Node: Status Buffer, Next: Repository List, Up: Inspecting + +5.1 Status Buffer +================= + +While other Magit buffers contain e.g. one particular diff or one +particular log, the status buffer contains the diffs for staged and +unstaged changes, logs for unpushed and unpulled commits, lists of +stashes and untracked files, and information related to the current +branch. + + During certain incomplete operations – for example when a merge +resulted in a conflict – additional information is displayed that helps +proceeding with or aborting the operation. + + The command ‘magit-status’ displays the status buffer belonging to +the current repository in another window. This command is used so often +that it should be bound globally. We recommend using ‘C-x g’: + + (global-set-key (kbd "C-x g") 'magit-status) + +‘C-x g’ (‘magit-status’) + When invoked from within an existing Git repository, then this + command shows the status of that repository in a buffer. + + If the current directory isn’t located within a Git repository, + then this command prompts for an existing repository or an + arbitrary directory, depending on the option + ‘magit-repository-directories’, and the status for the selected + repository is shown instead. + + • If that option specifies any existing repositories, then the + user is asked to select one of them. + + • Otherwise the user is asked to select an arbitrary directory + using regular file-name completion. If the selected directory + is the top-level directory of an existing working tree, then + the status buffer for that is shown. + + • Otherwise the user is offered to initialize the selected + directory as a new repository. After creating the repository + its status buffer is shown. + + These fallback behaviors can also be forced using one or more + prefix arguments: + + • With two prefix arguments (or more precisely a numeric prefix + value of 16 or greater) an arbitrary directory is read, which + is then acted on as described above. The same could be + accomplished using the command ‘magit-init’. + + • With a single prefix argument an existing repository is read + from the user, or if no repository can be found based on the + value of ‘magit-repository-directories’, then the behavior is + the same as with two prefix arguments. + + -- User Option: magit-repository-directories + List of directories that are Git repositories or contain Git + repositories. + + Each element has the form ‘(DIRECTORY . DEPTH)’. DIRECTORY has to + be a directory or a directory file-name, a string. DEPTH, an + integer, specifies the maximum depth to look for Git repositories. + If it is 0, then only add DIRECTORY itself. + + This option controls which repositories are being listed by + ‘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: + + (global-set-key (kbd "C-x g") 'magit-status-quick). + + 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 + ‘magit-status’. This is similar to ‘ido-magic-delete-char’, which, + despite its name, usually causes a Dired buffer to be created. + + To make this command available, use something like: + + (add-hook 'ido-setup-hook + (lambda () + (define-key ido-completion-map + (kbd \"C-x g\") 'ido-enter-magit-status))) + + Starting with Emacs 25.1 the Ido keymaps are defined just once + instead of every time Ido is invoked, so now you can modify it like + pretty much every other keymap: + + (define-key ido-common-completion-map + (kbd \"C-x g\") 'ido-enter-magit-status) + +* Menu: + +* Status Sections:: +* Status Header Sections:: +* Status Module Sections:: +* Status Options:: + + +File: magit.info, Node: Status Sections, Next: Status Header Sections, Up: Status Buffer + +5.1.1 Status Sections +--------------------- + +The contents of status buffers is controlled using the hook +‘magit-status-sections-hook’. See *note Section Hooks:: to learn about +such hooks and how to customize them. + + -- User Option: magit-status-sections-hook + Hook run to insert sections into a status buffer. + + The first function on that hook by default is +‘magit-insert-status-headers’; it is described in the next section. By +default the following functions are also members of that hook: + + -- Function: magit-insert-merge-log + Insert section for the on-going merge. Display the heads that are + being merged. If no merge is in progress, do nothing. + + -- Function: magit-insert-rebase-sequence + Insert section for the on-going rebase sequence. If no such + sequence is in progress, do nothing. + + -- Function: magit-insert-am-sequence + Insert section for the on-going patch applying sequence. If no + such sequence is in progress, do nothing. + + -- Function: magit-insert-sequencer-sequence + Insert section for the on-going cherry-pick or revert sequence. If + no such sequence is in progress, do nothing. + + -- Function: magit-insert-bisect-output + While bisecting, insert section with output from ‘git bisect’. + + -- Function: magit-insert-bisect-rest + While bisecting, insert section visualizing the bisect state. + + -- Function: magit-insert-bisect-log + While bisecting, insert section logging bisect progress. + + -- Function: magit-insert-untracked-files + Maybe insert a list or tree of untracked files. + + Do so depending on the value of ‘status.showUntrackedFiles’. Note + that even if the value is ‘all’, Magit still initially only shows + directories. But the directory sections can then be expanded using + ‘TAB’. + + -- Function: magit-insert-unstaged-changes + Insert section showing unstaged changes. + + -- Function: magit-insert-staged-changes + Insert section showing staged changes. + + -- Function: magit-insert-stashes &optional ref heading + Insert the ‘stashes’ section showing reflog for "refs/stash". If + optional REF is non-nil show reflog for that instead. If optional + HEADING is non-nil use that as section heading instead of + "Stashes:". + + -- Function: magit-insert-unpulled-from-upstream + Insert section showing commits that haven’t been pulled from the + upstream branch yet. + + -- Function: magit-insert-unpulled-from-pushremote + Insert section showing commits that haven’t been pulled from the + push-remote branch yet. + + -- Function: magit-insert-unpushed-to-upstream + Insert section showing commits that haven’t been pushed to the + upstream yet. + + -- Function: magit-insert-unpushed-to-pushremote + Insert section showing commits that haven’t been pushed to the + push-remote yet. + + The following functions can also be added to the above hook: + + -- Function: magit-insert-tracked-files + Insert a tree of tracked files. + + -- Function: magit-insert-ignored-files + Insert a tree of ignored files. Its possible to limit the logs in + the current buffer to a certain directory using ‘D = f + RET g’. If you do that, then that that also affects this command. + + The log filter can be used to limit to multiple files. In that + case this function only respects the first of the files and only if + it is a directory. + + -- Function: magit-insert-skip-worktree-files + Insert a tree of skip-worktree files. If the first element of + ‘magit-buffer-diff-files’ is a directory, then limit the list to + files below that. The value of that variable can be set using ‘D + -- DIRECTORY RET g’. + + -- Function: magit-insert-assumed-unchanged-files + Insert a tree of files that are assumed to be unchanged. If the + first element of ‘magit-buffer-diff-files’ is a directory, then + limit the list to files below that. The value of that variable can + be set using ‘D -- DIRECTORY RET g’. + + -- Function: magit-insert-unpulled-or-recent-commits + Insert section showing unpulled or recent commits. If an upstream + is configured for the current branch and it is ahead of the current + branch, then show the missing commits. Otherwise, show the last + ‘magit-log-section-commit-count’ commits. + + -- Function: magit-insert-recent-commits + Insert section showing the last ‘magit-log-section-commit-count’ + commits. + + -- User Option: magit-log-section-commit-count + How many recent commits ‘magit-insert-recent-commits’ and + ‘magit-insert-unpulled-or-recent-commits’ (provided there are no + unpulled commits) show. + + -- Function: magit-insert-unpulled-cherries + Insert section showing unpulled commits. Like + ‘magit-insert-unpulled-commits’ but prefix each commit that has not + been applied yet (i.e. a commit with a patch-id not shared with + any local commit) with "+", and all others with "-". + + -- Function: magit-insert-unpushed-cherries + Insert section showing unpushed commits. Like + ‘magit-insert-unpushed-commits’ but prefix each commit which has + not been applied to upstream yet (i.e. a commit with a patch-id + not shared with any upstream commit) with "+" and all others with + "-". + + See *note References Buffer:: for some more section inserters, which +could be used here. + + +File: magit.info, Node: Status Header Sections, Next: Status Module Sections, Prev: Status Sections, Up: Status Buffer + +5.1.2 Status Header Sections +---------------------------- + +The contents of status buffers is controlled using the hook +‘magit-status-sections-hook’ (see *note Status Sections::). + + By default ‘magit-insert-status-headers’ is the first member of that +hook variable. + + -- Function: magit-insert-status-headers + Insert headers sections appropriate for ‘magit-status-mode’ + buffers. The sections are inserted by running the functions on the + hook ‘magit-status-headers-hook’. + + -- User Option: magit-status-headers-hook + Hook run to insert headers sections into the status buffer. + + This hook is run by ‘magit-insert-status-headers’, which in turn + has to be a member of ‘magit-status-sections-hook’ to be used at + all. + + By default the following functions are members of the above hook: + + -- Function: magit-insert-error-header + Insert a header line showing the message about the Git error that + just occurred. + + This function is only aware of the last error that occur when Git + was run for side-effects. If, for example, an error occurs while + generating a diff, then that error won’t be inserted. Refreshing + the status buffer causes this section to disappear again. + + -- Function: magit-insert-diff-filter-header + Insert a header line showing the effective diff filters. + + -- Function: magit-insert-head-branch-header + Insert a header line about the current branch or detached ‘HEAD’. + + -- Function: magit-insert-upstream-branch-header + Insert a header line about the branch that is usually pulled into + the current branch. + + -- Function: magit-insert-push-branch-header + Insert a header line about the branch that the current branch is + usually pushed to. + + -- Function: magit-insert-tags-header + Insert a header line about the current and/or next tag, along with + the number of commits between the tag and ‘HEAD’. + + The following functions can also be added to the above hook: + + -- Function: magit-insert-repo-header + Insert a header line showing the path to the repository top-level. + + -- Function: magit-insert-remote-header + Insert a header line about the remote of the current branch. + + If no remote is configured for the current branch, then fall back + showing the "origin" remote, or if that does not exist the first + remote in alphabetic order. + + -- Function: magit-insert-user-header + Insert a header line about the current user. + + +File: magit.info, Node: Status Module Sections, Next: Status Options, Prev: Status Header Sections, Up: Status Buffer + +5.1.3 Status Module Sections +---------------------------- + +The contents of status buffers is controlled using the hook +‘magit-status-sections-hook’ (see *note Status Sections::). + + By default ‘magit-insert-modules’ is _not_ a member of that hook +variable. + + -- Function: magit-insert-modules + Insert submodule sections. + + Hook ‘magit-module-sections-hook’ controls which module sections + are inserted, and option ‘magit-module-sections-nested’ controls + whether they are wrapped in an additional section. + + -- User Option: magit-module-sections-hook + Hook run by ‘magit-insert-modules’. + + -- User Option: magit-module-sections-nested + This option controls whether ‘magit-insert-modules’ wraps inserted + sections in an additional section. + + If this is non-nil, then only a single top-level section is + inserted. If it is nil, then all sections listed in + ‘magit-module-sections-hook’ become top-level sections. + + -- Function: magit-insert-modules-overview + 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. + + -- Function: magit-insert-modules-unpulled-from-upstream + Insert sections for modules that haven’t been pulled from the + upstream yet. These sections can be expanded to show the + respective commits. + + -- Function: magit-insert-modules-unpulled-from-pushremote + Insert sections for modules that haven’t been pulled from the + push-remote yet. These sections can be expanded to show the + respective commits. + + -- Function: magit-insert-modules-unpushed-to-upstream + Insert sections for modules that haven’t been pushed to the + upstream yet. These sections can be expanded to show the + respective commits. + + -- Function: magit-insert-modules-unpushed-to-pushremote + Insert sections for modules that haven’t been pushed to the + push-remote yet. These sections can be expanded to show the + respective commits. + + +File: magit.info, Node: Status Options, Prev: Status Module Sections, Up: Status Buffer + +5.1.4 Status Options +-------------------- + + -- User Option: magit-status-refresh-hook + Hook run after a status buffer has been refreshed. + + -- User Option: magit-status-margin + This option specifies whether the margin is initially shown in + Magit-Status mode buffers and how it is formatted. + + The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. + + • If INIT is non-nil, then the margin is shown initially. + • STYLE controls how to format the author or committer date. It + can be one of ‘age’ (to show the age of the commit), + ‘age-abbreviated’ (to abbreviate the time unit to a + character), or a string (suitable for ‘format-time-string’) to + show the actual date. Option + ‘magit-log-margin-show-committer-date’ controls which date is + being displayed. + • WIDTH controls the width of the margin. This exists for + forward compatibility and currently the value should not be + changed. + • AUTHOR controls whether the name of the author is also shown + by default. + • AUTHOR-WIDTH has to be an integer. When the name of the + author is shown, then this specifies how much space is used to + do so. + + Also see the proceeding section for more options concerning status +buffers. + + +File: magit.info, Node: Repository List, Next: Logging, Prev: Status Buffer, Up: Inspecting + +5.2 Repository List +=================== + + -- Command: magit-list-repositories + This command displays a list of repositories in a separate buffer. + + The options ‘magit-repository-directories’ and + ‘magit-repository-directories-depth’ control which repositories are + displayed. + + -- User Option: magit-repolist-columns + This option controls what columns are displayed by the command + ‘magit-list-repositories’ and how they are displayed. + + Each element has the form ‘(HEADER WIDTH FORMAT PROPS)’. + + HEADER is the string displayed in the header. WIDTH is the width + of the column. FORMAT is a function that is called with one + 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’. + + 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 + This function inserts the identification of the repository. + Usually this is just its basename. + + -- Function: magit-repolist-column-path + This function inserts the absolute path of the repository. + + -- Function: magit-repolist-column-version + This function inserts a description of the repository’s ‘HEAD’ + revision. + + -- Function: magit-repolist-column-branch + This function inserts the name of the current branch. + + -- Function: magit-repolist-column-upstream + This function inserts the name of the upstream branch of the + current branch. + + -- Function: magit-repolist-column-branches + This function inserts the number of branches. + + -- Function: magit-repolist-column-stashes + This function inserts the number of stashes. + + -- Function: magit-repolist-column-flag + This function inserts a flag as specified by + ‘magit-repolist-column-flag-alist’. + + By default this indicates whether there are uncommitted changes. + + • ‘N’ if there is at least one untracked file. + • ‘U’ if there is at least one unstaged file. + • ‘S’ if there is at least one staged file. + + Only the first one of these that applies is shown. + + -- Function: magit-repolist-column-unpulled-from-upstream + This function inserts the number of upstream commits not in the + current branch. + + -- Function: magit-repolist-column-unpulled-from-pushremote + This function inserts the number of commits in the push branch but + not the current branch. + + -- Function: magit-repolist-column-unpushed-to-upstream + This function inserts the number of commits in the current branch + but not its upstream. + + -- Function: magit-repolist-column-unpushed-to-pushremote + This function inserts the number of commits in the current branch + but not its push branch. + + +File: magit.info, Node: Logging, Next: Diffing, Prev: Repository List, Up: Inspecting + +5.3 Logging +=========== + +The status buffer contains logs for the unpushed and unpulled commits, +but that obviously isn’t enough. The transient prefix command +‘magit-log’, on ‘l’, features several suffix commands, which show a +specific log in a separate log buffer. + + Like other transient prefix commands, ‘magit-log’ also features +several infix arguments that can be changed before invoking one of the +suffix commands. However, in the case of the log transient, these +arguments may be taken from those currently in use in the current +repository’s log buffer, depending on the value of +‘magit-prefix-use-buffer-arguments’ (see *note Transient Arguments and +Buffer Variables::). + + For information about the various arguments, see *note +(gitman)git-log::. + + The switch ‘++order=VALUE’ is converted to one of +‘--author-date-order’, ‘--date-order’, or ‘--topo-order’ before being +passed to ‘git log’. + + The log transient also features several reflog commands. See *note +Reflog::. + +‘l’ (‘magit-log’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘l l’ (‘magit-log-current’) + Show log for the current branch. When ‘HEAD’ is detached or with a + prefix argument, show log for one or more revs read from the + minibuffer. + +‘l o’ (‘magit-log-other’) + Show log for one or more revs read from the minibuffer. The user + can input any revision or revisions separated by a space, or even + ranges, but only branches, tags, and a representation of the commit + at point are available as completion candidates. + +‘l h’ (‘magit-log-head’) + Show log for ‘HEAD’. + +‘l L’ (‘magit-log-branches’) + Show log for all local branches and ‘HEAD’. + +‘l b’ (‘magit-log-all-branches’) + Show log for all local and remote branches and ‘HEAD’. + +‘l a’ (‘magit-log-all’) + 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 *note Commands for +Buffers Visiting Files::. The command ‘magit-cherry’ also shows a log, +see *note Cherries::. + +* Menu: + +* Refreshing Logs:: +* Log Buffer:: +* Log Margin:: +* Select from Log:: +* Reflog:: +* Cherries:: + + +File: magit.info, Node: Refreshing Logs, Next: Log Buffer, Up: Logging + +5.3.1 Refreshing Logs +--------------------- + +The transient prefix command ‘magit-log-refresh’, on ‘L’, can be used to +change the log arguments used in the current buffer, without changing +which log is shown. This works in dedicated log buffers, but also in +the status buffer. + +‘L’ (‘magit-log-refresh’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘L g’ (‘magit-log-refresh’) + This suffix command sets the local log arguments for the current + buffer. + +‘L s’ (‘magit-log-set-default-arguments’) + This suffix command sets the default log arguments for buffers of + the same type as that of the current buffer. Other existing + buffers of the same type are not affected because their local + values have already been initialized. + +‘L w’ (‘magit-log-save-default-arguments’) + This suffix command sets the default log arguments for buffers of + the same type as that of the current buffer, and saves the value + for future sessions. Other existing buffers of the same type are + not affected because their local values have already been + initialized. + +‘L t’ (‘magit-toggle-margin’) + Show or hide the margin. + + +File: magit.info, Node: Log Buffer, Next: Log Margin, Prev: Refreshing Logs, Up: Logging + +5.3.2 Log Buffer +---------------- + +‘L’ (‘magit-log-refresh’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + See *note Refreshing Logs::. + +‘q’ (‘magit-log-bury-buffer’) + Bury the current buffer or the revision buffer in the same frame. + Like ‘magit-mode-bury-buffer’ (which see) but with a negative + prefix argument instead bury the revision buffer, provided it is + displayed in the current frame. + +‘C-c C-b’ (‘magit-go-backward’) + Move backward in current buffer’s history. + +‘C-c C-f’ (‘magit-go-forward’) + Move forward in current buffer’s history. + +‘C-c C-n’ (‘magit-log-move-to-parent’) + Move to a parent of the current commit. By default, this is the + first parent, but a numeric prefix can be used to specify another + parent. + +‘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. + +‘’ (‘magit-diff-show-or-scroll-up’) + Update the commit or diff buffer for the thing at point. + + Either show the commit or stash at point in the appropriate buffer, + or if that buffer is already being displayed in the current frame + and contains information about that commit or stash, then instead + scroll the buffer up. If there is no commit or stash at point, + then prompt for a commit. + +‘’ (‘magit-diff-show-or-scroll-down’) + Update the commit or diff buffer for the thing at point. + + Either show the commit or stash at point in the appropriate buffer, + or if that buffer is already being displayed in the current frame + and contains information about that commit or stash, then instead + scroll the buffer down. If there is no commit or stash at point, + then prompt for a commit. + +‘=’ (‘magit-log-toggle-commit-limit’) + Toggle the number of commits the current log buffer is limited to. + If the number of commits is currently limited, then remove that + limit. Otherwise set it to 256. + +‘+’ (‘magit-log-double-commit-limit’) + Double the number of commits the current log buffer is limited to. + +‘-’ (‘magit-log-half-commit-limit’) + Half the number of commits the current log buffer is limited to. + + -- User Option: magit-log-auto-more + Insert more log entries automatically when moving past the last + entry. Only considered when moving past the last entry with + ‘magit-goto-*-section’ commands. + + -- User Option: magit-log-show-refname-after-summary + Whether to show the refnames after the commit summaries. This is + useful if you use really long branch names. + + Magit displays references in logs a bit differently from how Git does +it. + + Local branches are blue and remote branches are green. Of course +that depends on the used theme, as do the colors used for other types of +references. The current branch has a box around it, as do remote +branches that are their respective remote’s ‘HEAD’ branch. + + If a local branch and its push-target point at the same commit, then +their names are combined to preserve space and to make that relationship +visible. For example: + + origin/feature + [green][blue-] + + instead of + + feature origin/feature + [blue-] [green-------] + + Also note that while the transient features the ‘--show-signature’ +argument, that won’t actually be used when enabled, because Magit +defaults to use just one line per commit. Instead the commit colorized +to indicate the validity of the signed commit object, using the faces +named ‘magit-signature-*’ (which see). + + For a description of ‘magit-log-margin’ see *note Log Margin::. + + +File: magit.info, Node: Log Margin, Next: Select from Log, Prev: Log Buffer, Up: Logging + +5.3.3 Log Margin +---------------- + +In buffers which show one or more logs, it is possible to show +additional information about each commit in the margin. The options +used to configure the margin are named ‘magit-INFIX-margin’, where INFIX +is the same as in the respective major-mode ‘magit-INFIX-mode’. In +regular log buffers that would be ‘magit-log-margin’. + + -- User Option: magit-log-margin + This option specifies whether the margin is initially shown in + Magit-Log mode buffers and how it is formatted. + + The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. + + • If INIT is non-nil, then the margin is shown initially. + • STYLE controls how to format the author or committer date. It + can be one of ‘age’ (to show the age of the commit), + ‘age-abbreviated’ (to abbreviate the time unit to a + character), or a string (suitable for ‘format-time-string’) to + show the actual date. Option + ‘magit-log-margin-show-committer-date’ controls which date is + being displayed. + • WIDTH controls the width of the margin. This exists for + forward compatibility and currently the value should not be + changed. + • AUTHOR controls whether the name of the author is also shown + by default. + • AUTHOR-WIDTH has to be an integer. When the name of the + author is shown, then this specifies how much space is used to + do so. + + You can change the STYLE and AUTHOR-WIDTH of all ‘magit-INFIX-margin’ +options to the same values by customizing ‘magit-log-margin’ *before* +‘magit’ is loaded. If you do that, then the respective values for the +other options will default to what you have set for that variable. +Likewise if you set INIT in ‘magit-log-margin’ to ‘nil’, then that is +used in the default of all other options. But setting it to ‘t’, i.e. +re-enforcing the default for that option, does not carry to other +options. + + -- User Option: magit-log-margin-show-committer-date + This option specifies whether to show the committer date in the + margin. This option only controls whether the committer date is + displayed instead of the author date. Whether some date is + displayed in the margin and whether the margin is displayed at all + is controlled by other options. + +‘L’ (‘magit-margin-settings’) + This transient prefix command binds the following suffix commands, + each of which changes the appearance of the margin in some way. + + In some buffers that support the margin, ‘L’ is instead bound to +‘magit-log-refresh’, but that transient features the same commands, and +then some other unrelated commands. + +‘L L’ (‘magit-toggle-margin’) + This command shows or hides the margin. + +‘L l’ (‘magit-cycle-margin-style’) + This command cycles the style used for the margin. + +‘L d’ (‘magit-toggle-margin-details’) + This command shows or hides details in the margin. + + +File: magit.info, Node: Select from Log, Next: Reflog, Prev: Log Margin, Up: Logging + +5.3.4 Select from Log +--------------------- + +When the user has to select a recent commit that is reachable from +‘HEAD’, using regular completion would be inconvenient (because most +humans cannot remember hashes or "HEAD~5", at least not without double +checking). Instead a log buffer is used to select the commit, which has +the advantage that commits are presented in order and with the commit +message. + + Such selection logs are used when selecting the beginning of a rebase +and when selecting the commit to be squashed into. + + In addition to the key bindings available in all log buffers, the +following additional key bindings are available in selection log +buffers: + +‘C-c C-c’ (‘magit-log-select-pick’) + Select the commit at point and act on it. Call + ‘magit-log-select-pick-function’ with the selected commit as + argument. + +‘C-c C-k’ (‘magit-log-select-quit’) + Abort selecting a commit, don’t act on any commit. + + -- User Option: magit-log-select-margin + This option specifies whether the margin is initially shown in + Magit-Log-Select mode buffers and how it is formatted. + + The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. + + • If INIT is non-nil, then the margin is shown initially. + • STYLE controls how to format the author or committer date. It + can be one of ‘age’ (to show the age of the commit), + ‘age-abbreviated’ (to abbreviate the time unit to a + character), or a string (suitable for ‘format-time-string’) to + show the actual date. Option + ‘magit-log-margin-show-committer-date’ controls which date is + being displayed. + • WIDTH controls the width of the margin. This exists for + forward compatibility and currently the value should not be + changed. + • AUTHOR controls whether the name of the author is also shown + by default. + • AUTHOR-WIDTH has to be an integer. When the name of the + author is shown, then this specifies how much space is used to + do so. + + +File: magit.info, Node: Reflog, Next: Cherries, Prev: Select from Log, Up: Logging + +5.3.5 Reflog +------------ + +Also see *note (gitman)git-reflog::. + + These reflog commands are available from the log transient. See +*note Logging::. + +‘l r’ (‘magit-reflog-current’) + Display the reflog of the current branch. + +‘l O’ (‘magit-reflog-other’) + Display the reflog of a branch or another ref. + +‘l H’ (‘magit-reflog-head’) + Display the ‘HEAD’ reflog. + + -- User Option: magit-reflog-margin + This option specifies whether the margin is initially shown in + Magit-Reflog mode buffers and how it is formatted. + + The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. + + • If INIT is non-nil, then the margin is shown initially. + • STYLE controls how to format the author or committer date. It + can be one of ‘age’ (to show the age of the commit), + ‘age-abbreviated’ (to abbreviate the time unit to a + character), or a string (suitable for ‘format-time-string’) to + show the actual date. Option + ‘magit-log-margin-show-committer-date’ controls which date is + being displayed. + • WIDTH controls the width of the margin. This exists for + forward compatibility and currently the value should not be + changed. + • AUTHOR controls whether the name of the author is also shown + by default. + • AUTHOR-WIDTH has to be an integer. When the name of the + author is shown, then this specifies how much space is used to + do so. + + +File: magit.info, Node: Cherries, Prev: Reflog, Up: Logging + +5.3.6 Cherries +-------------- + +Cherries are commits that haven’t been applied upstream (yet), and are +usually visualized using a log. Each commit is prefixed with ‘-’ if it +has an equivalent in the upstream and ‘+’ if it does not, i.e. if it is +a cherry. + + The command ‘magit-cherry’ shows cherries for a single branch, but +the references buffer (see *note References Buffer::) can show cherries +for multiple "upstreams" at once. + + Also see *note (gitman)git-reflog::. + +‘Y’ (‘magit-cherry’) + Show commits that are in a certain branch but that have not been + merged in the upstream branch. + + -- User Option: magit-cherry-margin + This option specifies whether the margin is initially shown in + Magit-Cherry mode buffers and how it is formatted. + + The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. + + • If INIT is non-nil, then the margin is shown initially. + • STYLE controls how to format the author or committer date. It + can be one of ‘age’ (to show the age of the commit), + ‘age-abbreviated’ (to abbreviate the time unit to a + character), or a string (suitable for ‘format-time-string’) to + show the actual date. Option + ‘magit-log-margin-show-committer-date’ controls which date is + being displayed. + • WIDTH controls the width of the margin. This exists for + forward compatibility and currently the value should not be + changed. + • AUTHOR controls whether the name of the author is also shown + by default. + • AUTHOR-WIDTH has to be an integer. When the name of the + author is shown, then this specifies how much space is used to + do so. + + +File: magit.info, Node: Diffing, Next: Ediffing, Prev: Logging, Up: Inspecting + +5.4 Diffing +=========== + +The status buffer contains diffs for the staged and unstaged commits, +but that obviously isn’t enough. The transient prefix command +‘magit-diff’, on ‘d’, features several suffix commands, which show a +specific diff in a separate diff buffer. + + Like other transient prefix commands, ‘magit-diff’ also features +several infix arguments that can be changed before invoking one of the +suffix commands. However, in the case of the diff transient, these +arguments may be taken from those currently in use in the current +repository’s diff buffer, depending on the value of +‘magit-prefix-use-buffer-arguments’ (see *note Transient Arguments and +Buffer Variables::). + + Also see *note (gitman)git-diff::. + +‘d’ (‘magit-diff’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘d d’ (‘magit-diff-dwim’) + Show changes for the thing at point. + +‘d r’ (‘magit-diff-range’) + Show differences between two commits. + + RANGE should be a range (A..B or A...B) but can also be a single + commit. If one side of the range is omitted, then it defaults to + ‘HEAD’. If just a commit is given, then changes in the working + tree relative to that commit are shown. + + If the region is active, use the revisions on the first and last + line of the region. With a prefix argument, instead of diffing the + revisions, choose a revision to view changes along, starting at the + common ancestor of both revisions (i.e., use a "..." range). + +‘d w’ (‘magit-diff-working-tree’) + Show changes between the current working tree and the ‘HEAD’ + commit. With a prefix argument show changes between the working + tree and a commit read from the minibuffer. + +‘d s’ (‘magit-diff-staged’) + Show changes between the index and the ‘HEAD’ commit. With a + prefix argument show changes between the index and a commit read + from the minibuffer. + +‘d u’ (‘magit-diff-unstaged’) + Show changes between the working tree and the index. + +‘d p’ (‘magit-diff-paths’) + Show changes between any two files on disk. + + All of the above suffix commands update the repository’s diff buffer. +The diff transient also features two commands which show differences in +another buffer: + +‘d c’ (‘magit-show-commit’) + Show the commit at point. If there is no commit at point or with a + prefix argument, prompt for a commit. + +‘d t’ (‘magit-stash-show’) + 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 *note Commands for +Buffers Visiting Files::. + +* Menu: + +* Refreshing Diffs:: +* Commands Available in Diffs:: +* Diff Options:: +* Revision Buffer:: + + +File: magit.info, Node: Refreshing Diffs, Next: Commands Available in Diffs, Up: Diffing + +5.4.1 Refreshing Diffs +---------------------- + +The transient prefix command ‘magit-diff-refresh’, on ‘D’, can be used +to change the diff arguments used in the current buffer, without +changing which diff is shown. This works in dedicated diff buffers, but +also in the status buffer. + +‘D’ (‘magit-diff-refresh’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘D g’ (‘magit-diff-refresh’) + This suffix command sets the local diff arguments for the current + buffer. + +‘D s’ (‘magit-diff-set-default-arguments’) + This suffix command sets the default diff arguments for buffers of + the same type as that of the current buffer. Other existing + buffers of the same type are not affected because their local + values have already been initialized. + +‘D w’ (‘magit-diff-save-default-arguments’) + This suffix command sets the default diff arguments for buffers of + the same type as that of the current buffer, and saves the value + for future sessions. Other existing buffers of the same type are + not affected because their local values have already been + initialized. + +‘D t’ (‘magit-diff-toggle-refine-hunk’) + This command toggles hunk refinement on or off. + +‘D r’ (‘magit-diff-switch-range-type’) + This command converts the diff range type from "revA..revB" to + "revB...revA", or vice versa. + +‘D f’ (‘magit-diff-flip-revs’) + This command swaps revisions in the diff range from "revA..revB" to + "revB..revA", or vice versa. + +‘D F’ (‘magit-diff-toggle-file-filter’) + This command toggles the file restriction of the diffs in the + current buffer, allowing you to quickly switch between viewing all + the changes in the commit and the restricted subset. As a special + case, when this command is called from a log buffer, it toggles the + file restriction in the repository’s revision buffer, which is + useful when you display a revision from a log buffer that is + restricted to a file or files. + + In addition to the above transient, which allows changing any of the +supported arguments, there also exist some commands that change only a +particular argument. + +‘-’ (‘magit-diff-less-context’) + This command decreases the context for diff hunks by COUNT lines. + +‘+’ (‘magit-diff-more-context’) + This command increases the context for diff hunks by COUNT lines. + +‘0’ (‘magit-diff-default-context’) + This command resets the context for diff hunks to the default + height. + + The following commands quickly change what diff is being displayed +without having to using one of the diff transient. + +‘C-c C-d’ (‘magit-diff-while-committing’) + While committing, this command shows the changes that are about to + be committed. While amending, invoking the command again toggles + between showing just the new changes or all the changes that will + be committed. + + This binding is available in the diff buffer as well as the commit + message buffer. + +‘C-c C-b’ (‘magit-go-backward’) + This command moves backward in current buffer’s history. + +‘C-c C-f’ (‘magit-go-forward’) + This command moves forward in current buffer’s history. + + +File: magit.info, Node: Commands Available in Diffs, Next: Diff Options, Prev: Refreshing Diffs, Up: Diffing + +5.4.2 Commands Available in Diffs +--------------------------------- + +Some commands are only available if point is inside a diff. + + ‘magit-diff-visit-file’ and related commands visit the appropriate +version of the file that the diff at point is about. Likewise +‘magit-diff-visit-worktree-file’ and related commands visit the worktree +version of the file that the diff at point is about. See *note Visiting +Files and Blobs from a Diff:: for more information and the key bindings. + +‘C-c C-t’ (‘magit-diff-trace-definition’) + This command shows a log for the definition at point. + + -- User Option: magit-log-trace-definition-function + The function specified by this option is used by + ‘magit-log-trace-definition’ to determine the function at point. + For major-modes that have special needs, you could set the local + value using the mode’s hook. + +‘C-c C-e’ (‘magit-diff-edit-hunk-commit’) + From a hunk, this command edits the respective commit and visits + the file. + + First it visits the file being modified by the hunk at the correct + location using ‘magit-diff-visit-file’. This actually visits a + blob. When point is on a diff header, not within an individual + hunk, then this visits the blob the first hunk is about. + + Then it invokes ‘magit-edit-line-commit’, which uses an interactive + rebase to make the commit editable, or if that is not possible + because the commit is not reachable from ‘HEAD’ by checking out + that commit directly. This also causes the actual worktree file to + be visited. + + Neither the blob nor the file buffer are killed when finishing the + rebase. If that is undesirable, then it might be better to use + ‘magit-rebase-edit-command’ instead of this command. + +‘j’ (‘magit-jump-to-diffstat-or-diff’) + This command jumps to the diffstat or diff. When point is on a + file inside the diffstat section, then jump to the respective diff + section. Otherwise, jump to the diffstat section or a child + thereof. + + The next two commands are not specific to Magit-Diff mode (or and +Magit buffer for that matter), but it might be worth pointing out that +they are available here too. + +‘’ (‘scroll-up’) + This command scrolls text upward. + +‘’ (‘scroll-down’) + This command scrolls text downward. + + +File: magit.info, Node: Diff Options, Next: Revision Buffer, Prev: Commands Available in Diffs, Up: Diffing + +5.4.3 Diff Options +------------------ + + -- User Option: magit-diff-refine-hunk + Whether to show word-granularity differences within diff hunks. + + • ‘nil’ Never show fine differences. + • ‘t’ Show fine differences for the current diff hunk only. + • ‘all’ Show fine differences for all displayed diff hunks. + + -- User Option: magit-diff-refine-ignore-whitespace + Whether to ignore whitespace changes in word-granularity + differences. + + -- User Option: magit-diff-adjust-tab-width + Whether to adjust the width of tabs in diffs. + + Determining the correct width can be expensive if it requires + opening large and/or many files, so the widths are cached in the + variable ‘magit-diff--tab-width-cache’. Set that to nil to + invalidate the cache. + + • ‘nil’ Never adjust tab width. Use ‘tab-width’s value from the + Magit buffer itself instead. + + • ‘t’ If the corresponding file-visiting buffer exits, then use + ‘tab-width’’s value from that buffer. Doing this is cheap, so + this value is used even if a corresponding cache entry exists. + + • ‘always’ If there is no such buffer, then temporarily visit + the file to determine the value. + + • NUMBER Like ‘always’, but don’t visit files larger than NUMBER + bytes. + + -- User Option: magit-diff-paint-whitespace + Specify where to highlight whitespace errors. + + See ‘magit-diff-highlight-trailing’, + ‘magit-diff-highlight-indentation’. The symbol ‘t’ means in all + diffs, ‘status’ means only in the status buffer, and nil means + nowhere. + + • ‘nil’ Never highlight whitespace errors. + • ‘t’ Highlight whitespace errors everywhere. + • ‘uncommitted’ Only highlight whitespace errors in diffs + showing uncommitted changes. For backward compatibility + ‘status’ is treated as a synonym. + + -- User Option: magit-diff-paint-whitespace-lines + Specify in what kind of lines to highlight whitespace errors. + + • ‘t’ Highlight only in added lines. + • ‘both’ Highlight in added and removed lines. + • ‘all’ Highlight in added, removed and context lines. + + -- User Option: magit-diff-highlight-trailing + Whether to highlight whitespace at the end of a line in diffs. + Used only when ‘magit-diff-paint-whitespace’ is non-nil. + + -- User Option: magit-diff-highlight-indentation + This option controls whether to highlight the indentation in case + it used the "wrong" indentation style. Indentation is only + highlighted if ‘magit-diff-paint-whitespace’ is also non-nil. + + The value is an alist of the form ‘((REGEXP . INDENT)...)’. The + path to the current repository is matched against each element in + reverse order. Therefore if a REGEXP matches, then earlier + elements are not tried. + + If the used INDENT is ‘tabs’, highlight indentation with tabs. If + INDENT is an integer, highlight indentation with at least that many + spaces. Otherwise, highlight neither. + + -- User Option: magit-diff-hide-trailing-cr-characters + Whether to hide ^M characters at the end of a line in diffs. + + -- User Option: magit-diff-highlight-hunk-region-functions + This option specifies the functions used to highlight the + hunk-internal region. + + ‘magit-diff-highlight-hunk-region-dim-outside’ overlays the outside + of the hunk internal selection with a face that causes the added + and removed lines to have the same background color as context + lines. This function should not be removed from the value of this + option. + + ‘magit-diff-highlight-hunk-region-using-overlays’ and + ‘magit-diff-highlight-hunk-region-using-underline’ emphasize the + region by placing delimiting horizontal lines before and after it. + Both of these functions have glitches which cannot be fixed due to + limitations of Emacs’ display engine. For more information see + ff. + + Instead of, or in addition to, using delimiting horizontal lines, + to emphasize the boundaries, you may which to emphasize the text + itself, using ‘magit-diff-highlight-hunk-region-using-face’. + + In terminal frames it’s not possible to draw lines as the overlay + and underline variants normally do, so there they fall back to + calling the face function instead. + + -- User Option: magit-diff-unmarked-lines-keep-foreground + This option controls whether added and removed lines outside the + hunk-internal region only lose their distinct background color or + 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 *note + (gitman)git-diff::. + + +File: magit.info, Node: Revision Buffer, Prev: Diff Options, Up: Diffing + +5.4.4 Revision Buffer +--------------------- + + -- User Option: magit-revision-insert-related-refs + Whether to show related branches in revision buffers. + + • ‘nil’ Don’t show any related branches. + • ‘t’ Show related local branches. + • ‘all’ Show related local and remote branches. + • ‘mixed’ Show all containing branches and local merged + branches. + + -- User Option: magit-revision-show-gravatars + Whether to show gravatar images in revision buffers. + + If ‘nil’, then don’t insert any gravatar images. If ‘t’, then + insert both images. If ‘author’ or ‘committer’, then insert only + the respective image. + + If you have customized the option ‘magit-revision-headers-format’ + and want to insert the images then you might also have to specify + where to do so. In that case the value has to be a cons-cell of + two regular expressions. The car specifies where to insert the + author’s image. The top half of the image is inserted right after + the matched text, the bottom half on the next line in the same + column. The cdr specifies where to insert the committer’s image, + accordingly. Either the car or the cdr may be nil." + + -- User Option: magit-revision-use-hash-sections + Whether to turn hashes inside the commit message into sections. + + If non-nil, then hashes inside the commit message are turned into + ‘commit’ sections. There is a trade off to be made between + performance and reliability: + + • ‘slow’ calls git for every word to be absolutely sure. + • ‘quick’ skips words less than seven characters long. + • ‘quicker’ additionally skips words that don’t contain a + number. + • ‘quickest’ uses all words that are at least seven characters + long and which contain at least one number as well as at least + one letter. + + If nil, then no hashes are turned into sections, but you can still + visit the commit at point using "RET". + + The diffs shown in the revision buffer may be automatically +restricted to a subset of the changed files. If the revision buffer is +displayed from a log buffer, the revision buffer will share the same +file restriction as that log buffer (also see the command +‘magit-diff-toggle-file-filter’). + + -- User Option: magit-revision-filter-files-on-follow + Whether showing a commit from a log buffer honors the log’s file + filter when the log arguments include ‘--follow’. + + When this option is nil, displaying a commit from a log ignores the + log’s file filter if the log arguments include ‘--follow’. Doing + so avoids showing an empty diff in revision buffers for commits + before a rename event. In such cases, the ‘--patch’ argument of + the log transient can be used to show the file-restricted diffs + inline. + + Set this option to non-nil to keep the log’s file restriction even + if ‘--follow’ is present in the log arguments. + + If the revision buffer is not displayed from a log buffer, the file +restriction is determined as usual (see *note Transient Arguments and +Buffer Variables::). + + +File: magit.info, Node: Ediffing, Next: References Buffer, Prev: Diffing, Up: Inspecting + +5.5 Ediffing +============ + +This section describes how to enter Ediff from Magit buffers. For +information on how to use Ediff itself, see *note (ediff)Top::. + +‘e’ (‘magit-ediff-dwim’) + Compare, stage, or resolve using Ediff. + + This command tries to guess what file, and what commit or range the + user wants to compare, stage, or resolve using Ediff. It might + only be able to guess either the file, or range/commit, in which + case the user is asked about the other. It might not always guess + right, in which case the appropriate ‘magit-ediff-*’ command has to + be used explicitly. If it cannot read the user’s mind at all, then + it asks the user for a command to run. + +‘E’ (‘magit-ediff’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + +‘E r’ (‘magit-ediff-compare’) + Compare two revisions of a file using Ediff. + + If the region is active, use the revisions on the first and last + line of the region. With a prefix argument, instead of diffing the + revisions, choose a revision to view changes along, starting at the + common ancestor of both revisions (i.e., use a "..." range). + +‘E m’ (‘magit-ediff-resolve’) + Resolve outstanding conflicts in a file using Ediff, defaulting to + the file at point. + + Provided that the value of ‘merge.conflictstyle’ is ‘diff3’, you + can view the file’s merge-base revision using ‘/’ in the Ediff + control buffer. + + In the rare event that you want to manually resolve all conflicts, + including those already resolved by Git, use + ‘ediff-merge-revisions-with-ancestor’. + +‘E s’ (‘magit-ediff-stage’) + Stage and unstage changes to a file using Ediff, defaulting to the + file at point. + +‘E u’ (‘magit-ediff-show-unstaged’) + Show unstaged changes to a file using Ediff. + +‘E i’ (‘magit-ediff-show-staged’) + Show staged changes to a file using Ediff. + +‘E w’ (‘magit-ediff-show-working-tree’) + Show changes in a file between ‘HEAD’ and working tree using Ediff. + +‘E c’ (‘magit-ediff-show-commit’) + Show changes to a file introduced by a commit using Ediff. + +‘E z’ (‘magit-ediff-show-stash’) + Show changes to a file introduced by a stash using Ediff. + + -- User Option: magit-ediff-dwim-show-on-hunks + This option controls what command ‘magit-ediff-dwim’ calls when + point is on uncommitted hunks. When nil, always run + ‘magit-ediff-stage’. Otherwise, use ‘magit-ediff-show-staged’ and + ‘magit-ediff-show-unstaged’ to show staged and unstaged changes, + respectively. + + -- User Option: magit-ediff-show-stash-with-index + This option controls whether ‘magit-ediff-show-stash’ includes a + buffer containing the file’s state in the index at the time the + stash was created. This makes it possible to tell which changes in + the stash were staged. + + -- User Option: magit-ediff-quit-hook + This hook is run after quitting an Ediff session that was created + using a Magit command. The hook functions are run inside the Ediff + control buffer, and should not change the current buffer. + + This is similar to ‘ediff-quit-hook’ but takes the needs of Magit + into account. The regular ‘ediff-quit-hook’ is ignored by Ediff + sessions that were created using a Magit command. + + +File: magit.info, Node: References Buffer, Next: Bisecting, Prev: Ediffing, Up: Inspecting + +5.6 References Buffer +===================== + +‘y’ (‘magit-show-refs’) + This command lists branches and tags in a dedicated buffer. + + However if this command is invoked again from this buffer or if it + is invoked with a prefix argument, then it acts as a transient + prefix command, which binds the following suffix commands and some + infix arguments. + + All of the following suffix commands list exactly the same branches +and tags. The only difference the optional feature that can be enabled +by changing the value of ‘magit-refs-show-commit-count’ (see below). +These commands specify a different branch or commit against which all +the other references are compared. + +‘y y’ (‘magit-show-refs-head’) + This command lists branches and tags in a dedicated buffer. Each + reference is being compared with ‘HEAD’. + +‘y c’ (‘magit-show-refs-current’) + This command lists branches and tags in a dedicated buffer. Each + reference is being compared with the current branch or ‘HEAD’ if it + is detached. + +‘y o’ (‘magit-show-refs-other’) + This command lists branches and tags in a dedicated buffer. Each + reference is being compared with a branch read from the user. + +‘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. + + • ‘all’ Show counts for branches and tags. + • ‘branch’ Show counts for branches only. + • ‘nil’ Never show counts. + + The default is ‘nil’ because anything else can be very expensive. + + -- User Option: magit-refs-pad-commit-counts + Whether to pad all commit counts on all sides in Magit-Refs mode + buffers. + + If this is nil, then some commit counts are displayed right next to + one of the branches that appear next to the count, without any + space in between. This might look bad if the branch name faces + look too similar to ‘magit-dimmed’. + + If this is non-nil, then spaces are placed on both sides of all + commit counts. + + -- User Option: magit-refs-show-remote-prefix + Whether to show the remote prefix in lists of remote branches. + + Showing the prefix is redundant because the name of the remote is + already shown in the heading preceding the list of its branches. + + -- User Option: magit-refs-primary-column-width + Width of the primary column in ‘magit-refs-mode’ buffers. The + primary column is the column that contains the name of the branch + that the current row is about. + + If this is an integer, then the column is that many columns wide. + Otherwise it has to be a cons-cell of two integers. The first + specifies the minimal width, the second the maximal width. In that + case the actual width is determined using the length of the names + of the shown local branches. (Remote branches and tags are not + taken into account when calculating to optimal width.) + + -- User Option: magit-refs-focus-column-width + Width of the focus column in ‘magit-refs-mode’ buffers. + + The focus column is the first column, which marks one branch + (usually the current branch) as the focused branch using ‘*’ or + ‘@’. For each other reference, this column optionally shows how + many commits it is ahead of the focused branch and ‘<’, or if it + isn’t ahead then the commits it is behind and ‘>’, or if it isn’t + behind either, then a ‘=’. + + This column may also display only ‘*’ or ‘@’ for the focused + branch, in which case this option is ignored. Use ‘L v’ to change + the verbosity of this column. + + -- User Option: magit-refs-margin + This option specifies whether the margin is initially shown in + Magit-Refs mode buffers and how it is formatted. + + The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. + + • If INIT is non-nil, then the margin is shown initially. + • STYLE controls how to format the author or committer date. It + can be one of ‘age’ (to show the age of the commit), + ‘age-abbreviated’ (to abbreviate the time unit to a + character), or a string (suitable for ‘format-time-string’) to + show the actual date. Option + ‘magit-log-margin-show-committer-date’ controls which date is + being displayed. + • WIDTH controls the width of the margin. This exists for + forward compatibility and currently the value should not be + changed. + • AUTHOR controls whether the name of the author is also shown + by default. + • AUTHOR-WIDTH has to be an integer. When the name of the + author is shown, then this specifies how much space is used to + do so. + + -- User Option: magit-refs-margin-for-tags + This option specifies whether to show information about tags in the + margin. This is disabled by default because it is slow if there + are many tags. + + The following variables control how individual refs are displayed. +If you change one of these variables (especially the "%c" part), then +you should also change the others to keep things aligned. The following +%-sequences are supported: + + • ‘%a’ Number of commits this ref has over the one we compare to. + • ‘%b’ Number of commits the ref we compare to has over this one. + • ‘%c’ Number of commits this ref has over the one we compare to. + For the ref which all other refs are compared this is instead "@", + if it is the current branch, or "#" otherwise. + • ‘%C’ For the ref which all other refs are compared this is "@", if + it is the current branch, or "#" otherwise. For all other refs " + ". + • ‘%h’ Hash of this ref’s tip. + • ‘%m’ Commit summary of the tip of this ref. + • ‘%n’ Name of this ref. + • ‘%u’ Upstream of this local branch. + • ‘%U’ Upstream of this local branch and additional local vs. + upstream information. + + -- User Option: magit-refs-filter-alist + The purpose of this option is to forgo displaying certain refs + based on their name. If you want to not display any refs of a + certain type, then you should remove the appropriate function from + ‘magit-refs-sections-hook’ instead. + + This alist controls which tags and branches are omitted from being + displayed in ‘magit-refs-mode’ buffers. If it is ‘nil’, then all + refs are displayed (subject to ‘magit-refs-sections-hook’). + + All keys are tried in order until one matches. Then its value is + used and subsequent elements are ignored. If the value is non-nil, + then the reference is displayed, otherwise it is not. If no + element matches, then the reference is displayed. + + A key can either be a regular expression that the refname has to + match, or a function that takes the refname as only argument and + returns a boolean. A remote branch such as "origin/master" is + displayed as just "master", however for this comparison the former + is used. + +‘’ (‘magit-visit-ref’) + This command visits the reference or revision at point in another + buffer. If there is no revision at point or with a prefix argument + then it prompts for a revision. + + This command behaves just like ‘magit-show-commit’ as described + above, except if point is on a reference in a ‘magit-refs-mode’ + buffer, in which case the behavior may be different, but only if + you have customized the option ‘magit-visit-ref-behavior’. + + -- User Option: magit-visit-ref-behavior + This option controls how ‘magit-visit-ref’ behaves in + ‘magit-refs-mode’ buffers. + + By default ‘magit-visit-ref’ behaves like ‘magit-show-commit’, in + all buffers, including ‘magit-refs-mode’ buffers. When the type of + the section at point is ‘commit’ then "RET" is bound to + ‘magit-show-commit’, and when the type is either ‘branch’ or ‘tag’ + then it is bound to ‘magit-visit-ref’. + + "RET" is one of Magit’s most essential keys and at least by default + it should behave consistently across all of Magit, especially + because users quickly learn that it does something very harmless; + it shows more information about the thing at point in another + buffer. + + However "RET" used to behave differently in ‘magit-refs-mode’ + buffers, doing surprising things, some of which cannot really be + described as "visit this thing". If you’ve grown accustomed this + behavior, you can restore it by adding one or more of the below + symbols to the value of this option. But keep in mind that by + doing so you don’t only introduce inconsistencies, you also lose + some functionality and might have to resort to ‘M-x + magit-show-commit’ to get it back. + + ‘magit-visit-ref’ looks for these symbols in the order in which + they are described here. If the presence of a symbol applies to + the current situation, then the symbols that follow do not affect + the outcome. + + • ‘focus-on-ref’ + + With a prefix argument update the buffer to show commit counts + and lists of cherry commits relative to the reference at point + instead of relative to the current buffer or ‘HEAD’. + + Instead of adding this symbol, consider pressing "C-u y o + RET". + + • ‘create-branch’ + + If point is on a remote branch, then create a new local branch + with the same name, use the remote branch as its upstream, and + then check out the local branch. + + Instead of adding this symbol, consider pressing "b c RET + RET", like you would do in other buffers. + + • ‘checkout-any’ + + Check out the reference at point. If that reference is a tag + or a remote branch, then this results in a detached ‘HEAD’. + + Instead of adding this symbol, consider pressing "b b RET", + like you would do in other buffers. + + • ‘checkout-branch’ + + Check out the local branch at point. + + Instead of adding this symbol, consider pressing "b b RET", + like you would do in other buffers. + +* Menu: + +* References Sections:: + + +File: magit.info, Node: References Sections, Up: References Buffer + +5.6.1 References Sections +------------------------- + +The contents of references buffers is controlled using the hook +‘magit-refs-sections-hook’. See *note Section Hooks:: to learn about +such hooks and how to customize them. All of the below functions are +members of the default value. Note that it makes much less sense to +customize this hook than it does for the respective hook used for the +status buffer. + + -- User Option: magit-refs-sections-hook + Hook run to insert sections into a references buffer. + + -- Function: magit-insert-local-branches + Insert sections showing all local branches. + + -- Function: magit-insert-remote-branches + Insert sections showing all remote-tracking branches. + + -- Function: magit-insert-tags + Insert sections showing all tags. + + +File: magit.info, Node: Bisecting, Next: Visiting Files and Blobs, Prev: References Buffer, Up: Inspecting + +5.7 Bisecting +============= + +Also see *note (gitman)git-bisect::. + +‘B’ (‘magit-bisect’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + + When bisecting is not in progress, then the transient features the +following suffix commands. + +‘B B’ (‘magit-bisect-start’) + 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 known 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. + +‘B s’ (‘magit-bisect-run’) + Bisect automatically by running commands after each step. + + When bisecting in progress, then the transient instead features the +following suffix commands. + +‘B b’ (‘magit-bisect-bad’) + Mark the current commit as bad. Use this after you have asserted + that the commit does contain the bug in question. + +‘B g’ (‘magit-bisect-good’) + Mark the current commit as good. Use this after you have asserted + that the commit does not contain the bug in question. + +‘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. + +‘B k’ (‘magit-bisect-skip’) + Skip the current commit. Use this if for some reason the current + commit is not a good one to test. This command lets Git choose a + different one. + +‘B r’ (‘magit-bisect-reset’) + After bisecting, cleanup bisection state and return to original + ‘HEAD’. + + By default the status buffer shows information about the ongoing +bisect session. + + -- User Option: magit-bisect-show-graph + This option controls whether a graph is displayed for the log of + commits that still have to be bisected. + + +File: magit.info, Node: Visiting Files and Blobs, Next: Blaming, Prev: Bisecting, Up: Inspecting + +5.8 Visiting Files and Blobs +============================ + +Magit provides several commands that visit a file or blob (the version +of a file that is stored in a certain commit). Actually it provides +several *groups* of such commands and the several *variants* within each +group. + +* Menu: + +* General-Purpose Visit Commands:: +* Visiting Files and Blobs from a Diff:: + + +File: magit.info, Node: General-Purpose Visit Commands, Next: Visiting Files and Blobs from a Diff, Up: Visiting Files and Blobs + +5.8.1 General-Purpose Visit Commands +------------------------------------ + +These commands can be used anywhere to open any blob. Currently no keys +are bound to these commands by default, but that is likely to change. + + -- Command: magit-find-file + This command reads a filename and revision from the user and visits + the respective blob in a buffer. The buffer is displayed in the + selected window. + + -- Command: magit-find-file-other-window + This command reads a filename and revision from the user and visits + the respective blob in a buffer. The buffer is displayed in + another window. + + -- Command: magit-find-file-other-frame + This command reads a filename and revision from the user and visits + the respective blob in a buffer. The buffer is displayed in + another frame. + + +File: magit.info, Node: Visiting Files and Blobs from a Diff, Prev: General-Purpose Visit Commands, Up: Visiting Files and Blobs + +5.8.2 Visiting Files and Blobs from a Diff +------------------------------------------ + +These commands can only be used when point is inside a diff. + +‘’ (‘magit-diff-visit-file’) + This command visits the appropriate version of the file that the + diff at point is about. + + This commands visits the worktree version of the appropriate file. + The location of point inside the diff determines which file is + being visited. The visited version depends on what changes the + diff is about. + + 1. If the diff shows uncommitted changes (i.e. staged or + unstaged changes), then visit the file in the working tree + (i.e. the same "real" file that ‘find-file’ would visit. In + all other cases visit a "blob" (i.e. the version of a file as + stored in some commit). + + 2. If point is on a removed line, then visit the blob for the + first parent of the commit that removed that line, i.e. the + last commit where that line still exists. + + 3. If point is on an added or context line, then visit the blob + that adds that line, or if the diff shows from more than a + single commit, then visit the blob from the last of these + commits. + + In the file-visiting buffer this command goes to the line that + corresponds to the line that point is on in the diff. + + The buffer is displayed in the selected window. With a prefix + argument the buffer is displayed in another window instead. + + -- User Option: magit-diff-visit-previous-blob + This option controls whether ‘magit-diff-visit-file’ may visit the + previous blob. When this is ‘t’ (the default) and point is on a + removed line in a diff for a committed change, then + ‘magit-diff-visit-file’ visits the blob from the last revision + which still had that line. + + Currently this is only supported for committed changes, for staged + and unstaged changes ‘magit-diff-visit-file’ always visits the file + in the working tree. + +‘C-’ (‘magit-diff-visit-file-worktree’) + This command visits the worktree version of the appropriate file. + The location of point inside the diff determines which file is + being visited. Unlike ‘magit-diff-visit-file’ it always visits the + "real" file in the working tree, i.e the "current version" of the + file. + + In the file-visiting buffer this command goes to the line that + corresponds to the line that point is on in the diff. Lines that + were added or removed in the working tree, the index and other + commits in between are automatically accounted for. + + The buffer is displayed in the selected window. With a prefix + argument the buffer is displayed in another window instead. + + Variants of the above two commands exist that instead visit the file +in another window or in another frame. If you prefer such behavior, +then you may want to change the above key bindings, but note that the +above commands also use another window when invoked with a prefix +argument. + + -- Command: magit-diff-visit-file-other-window + -- Command: magit-diff-visit-file-other-frame + -- Command: magit-diff-visit-worktree-file-other-window + -- Command: magit-diff-visit-worktree-file-other-frame + + +File: magit.info, Node: Blaming, Prev: Visiting Files and Blobs, Up: Inspecting + +5.9 Blaming +=========== + +Also see *note (gitman)git-blame::. + + To start blaming invoke the ‘magit-file-dispatch’ transient prefix +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 have +to enter the blaming sub-transient first. + + The key bindings shown below assume that you enter the dispatch +transient using the default binding. + +‘C-c M-g B’ (‘magit-blame’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + Note that not all of the following suffixes are available at all +times. For example if ‘magit-blame-mode’ is not enabled, then the +command whose purpose is to turn off that mode would not be of any use +and therefore isn’t available. + +‘C-c M-g b’ (‘magit-blame-addition’) +‘C-c M-g B b’ + This command augments each line or chunk of lines in the current + file-visiting or blob-visiting buffer with information about what + commits last touched these lines. + + If the buffer visits a revision of that file, then history up to + that revision is considered. Otherwise, the file’s full history is + considered, including uncommitted changes. + + If Magit-Blame mode is already turned on in the current buffer then + blaming is done recursively, by visiting REVISION:FILE (using + ‘magit-find-file’), where REVISION is a parent of the revision that + added the current line or chunk of lines. + +‘C-c M-g r’ (‘magit-blame-removal’) +‘C-c M-g B r’ + This command augments each line or chunk of lines in the current + blob-visiting buffer with information about the revision that + removes it. It cannot be used in file-visiting buffers. + + Like ‘magit-blame-addition’, this command can be used recursively. + +‘C-c M-g f’ (‘magit-blame-reverse’) +‘C-c M-g B f’ + This command augments each line or chunk of lines in the current + file-visiting or blob-visiting buffer with information about the + last revision in which a line still existed. + + Like ‘magit-blame-addition’, this command can be used recursively. + +‘C-c M-g e’ (‘magit-blame-echo’) +‘C-c M-g B e’ + This command is like ‘magit-blame-addition’ except that it doesn’t + turn on ‘read-only-mode’ and that it initially uses the + visualization style specified by option ‘magit-blame-echo-style’. + + The following key bindings are available when Magit-Blame mode is +enabled and Read-Only mode is not enabled. These commands are also +available in other buffers; here only the behavior is described that is +relevant in file-visiting buffers that are being blamed. + +‘’ (‘magit-show-commit’) + This command shows the commit that last touched the line at point. + +‘’ (‘magit-diff-show-or-scroll-up’) + This command updates the commit buffer. + + This either shows the commit that last touched the line at point in + the appropriate buffer, or if that buffer is already being + displayed in the current frame and if that buffer contains + information about that commit, then the buffer is scrolled up + instead. + +‘’ (‘magit-diff-show-or-scroll-down’) + This command updates the commit buffer. + + This either shows the commit that last touched the line at point in + the appropriate buffer, or if that buffer is already being + displayed in the current frame and if that buffer contains + information about that commit, then the buffer is scrolled down + instead. + + The following key bindings are available when both Magit-Blame mode +and Read-Only mode are enabled. + +‘b’ (‘magit-blame’) + See above. + +‘n’ (‘magit-blame-next-chunk’) + This command moves to the next chunk. + +‘N’ (‘magit-blame-next-chunk-same-commit’) + This command moves to the next chunk from the same commit. + +‘p’ (‘magit-blame-previous-chunk’) + This command moves to the previous chunk. + +‘P’ (‘magit-blame-previous-chunk-same-commit’) + This command moves to the previous chunk from the same commit. + +‘q’ (‘magit-blame-quit’) + This command turns off Magit-Blame mode. If the buffer was created + during a recursive blame, then it also kills the buffer. + +‘M-w’ (‘magit-blame-copy-hash’) + This command saves the hash of the current chunk’s commit to the + kill ring. + + When the region is active, the command saves the region’s content + instead of the hash, like ‘kill-ring-save’ would. + +‘c’ (‘magit-blame-cycle-style’) + This command changes how blame information is visualized in the + current buffer by cycling through the styles specified using the + option ‘magit-blame-styles’. + + Blaming is also controlled using the following options. + + -- User Option: magit-blame-styles + This option defines a list of styles used to visualize blame + information. For now see its doc-string to learn more. + + -- User Option: magit-blame-echo-style + This option specifies the blame visualization style used by the + command ‘magit-blame-echo’. This must be a symbol that is used as + the identifier for one of the styles defined in + ‘magit-blame-styles’. + + -- User Option: magit-blame-time-format + This option specifies the format string used to display times when + showing blame information. + + -- User Option: magit-blame-read-only + This option controls whether blaming a buffer also makes + temporarily read-only. + + -- User Option: magit-blame-disable-modes + This option lists incompatible minor-modes that should be disabled + temporarily when a buffer contains blame information. They are + enabled again when the buffer no longer shows blame information. + + -- User Option: magit-blame-goto-chunk-hook + This hook is run when moving between chunks. + + +File: magit.info, Node: Manipulating, Next: Transferring, Prev: Inspecting, Up: Top + +6 Manipulating +************** + +* Menu: + +* Creating Repository:: +* Cloning Repository:: +* Staging and Unstaging:: +* Applying:: +* Committing:: +* Branching:: +* Merging:: +* Resolving Conflicts:: +* Rebasing:: +* Cherry Picking:: +* Resetting:: +* Stashing:: + + +File: magit.info, Node: Creating Repository, Next: Cloning Repository, Up: Manipulating + +6.1 Creating Repository +======================= + +‘I’ (‘magit-init’) + This command initializes a repository and then shows the status + buffer for the new repository. + + If the directory is below an existing repository, then the user has + to confirm that a new one should be created inside. If the + directory is the root of the existing repository, then the user has + to confirm that it should be reinitialized. + + +File: magit.info, Node: Cloning Repository, Next: Staging and Unstaging, Prev: Creating Repository, Up: Manipulating + +6.2 Cloning Repository +====================== + +To clone a remote or local repository use ‘C’, which is bound to the +command ‘magit-clone’. This command either act as a transient prefix +command, which binds several infix arguments and suffix commands, or it +can invoke ‘git clone’ directly, depending on whether a prefix argument +is used and on the value of ‘magit-clone-always-transient’. + + -- User Option: magit-clone-always-transient + This option controls whether the command ‘magit-clone’ always acts + as a transient prefix command, regardless of whether a prefix + argument is used or not. If ‘t’, then that command always acts as + a transient prefix. If ‘nil’, then a prefix argument has to be + used for it to act as a transient. + +‘C’ (‘magit-clone’) + This command either acts as a transient prefix command as described + above or does the same thing as ‘transient-clone-regular’ as + described below. + + If it acts as a transient prefix, then it binds the following + suffix commands and several infix arguments. + +‘C C’ (‘magit-clone-regular’) + This command creates a regular clone of an existing repository. + The repository and the target directory are read from the user. + +‘C s’ (‘magit-clone-shallow’) + This command creates a shallow clone of an existing repository. + The repository and the target directory are read from the user. By + default the depth of the cloned history is a single commit, but + with a prefix argument the depth is read from the user. + +‘C b’ (‘magit-clone-bare’) + This command creates a bare clone of an existing repository. The + repository and the target directory are read from the user. + +‘C m’ (‘magit-clone-mirror’) + This command creates a mirror of an existing repository. The + repository and the target directory are read from the user. + + The following suffixes are disabled by default. See *note +(transient)Enabling and Disabling Suffixes:: for how to enable them. + +‘C d’ (‘magit-clone-shallow-since’) + This command creates a shallow clone of an existing repository. + Only commits that were committed after a date are cloned, which is + read from the user. The repository and the target directory are + also read from the user. + +‘C e’ (‘magit-clone-shallow-exclude’) + This command creates a shallow clone of an existing repository. + This reads a branch or tag from the user. Commits that are + reachable from that are not cloned. The repository and the target + directory are also read from the user. + + -- User Option: magit-clone-set-remote-head + This option controls whether cloning causes the reference + ‘refs/remotes//HEAD’ to be created in the clone. The + default is to delete the reference after running ‘git clone’, which + insists on creating it. This is because the reference has not been + found to be particularly useful as it is not automatically updated + when the ‘HEAD’ of the remote changes. Setting this option to ‘t’ + preserves Git’s default behavior of creating the reference. + + -- User Option: magit-clone-set-remote.pushDefault + This option controls whether the value of the Git variable + ‘remote.pushDefault’ is set after cloning. + + • If ‘t’, then it is always set without asking. + • If ‘ask’, then the users are asked every time they clone a + repository. + • If ‘nil’, then it is never set. + + -- User Option: magit-clone-default-directory + This option control the default directory name used when reading + the destination for a cloning operation. + + • If ‘nil’ (the default), then the value of ‘default-directory’ + is used. + • If a directory, then that is used. + • If a function, then that is called with the remote url as the + only argument and the returned value is used. + + -- User Option: magit-clone-name-alist + This option maps regular expressions, which match repository names, + to repository urls, making it possible for users to enter short + names instead of urls when cloning repositories. + + Each element has the form ‘(REGEXP HOSTNAME USER)’. When the user + enters a name when a cloning command asks for a name or url, then + that is looked up in this list. The first element whose REGEXP + matches is used. + + The format specified by option ‘magit-clone-url-format’ is used to + turn the name into an url, using HOSTNAME and the repository name. + If the provided name contains a slash, then that is used. + Otherwise if the name omits the owner of the repository, then the + default user specified in the matched entry is used. + + If USER contains a dot, then it is treated as a Git variable and + the value of that is used as the username. Otherwise it is used as + the username itself. + + -- User Option: magit-clone-url-format + The format specified by this option is used when turning repository + names into urls. ‘%h’ is the hostname and ‘%n’ is the repository + name, including the name of the owner. + + +File: magit.info, Node: Staging and Unstaging, Next: Applying, Prev: Cloning Repository, Up: Manipulating + +6.3 Staging and Unstaging +========================= + +Like Git, Magit can of course stage and unstage complete files. Unlike +Git, it also allows users to gracefully un-/stage individual hunks and +even just part of a hunk. To stage individual hunks and parts of hunks +using Git directly, one has to use the very modal and rather clumsy +interface of a ‘git add --interactive’ session. + + With Magit, on the other hand, one can un-/stage individual hunks by +just moving point into the respective section inside a diff displayed in +the status buffer or a separate diff buffer and typing ‘s’ or ‘u’. To +operate on just parts of a hunk, mark the changes that should be +un-/staged using the region and then press the same key that would be +used to un-/stage. To stage multiple files or hunks at once use a +region that starts inside the heading of such a section and ends inside +the heading of a sibling section of the same type. + + Besides staging and unstaging, Magit also provides several other +"apply variants" that can also operate on a file, multiple files at +once, a hunk, multiple hunks at once, and on parts of a hunk. These +apply variants are described in the next section. + + You can also use Ediff to stage and unstage. See *note Ediffing::. + +‘s’ (‘magit-stage’) + Add the change at point to the staging area. + + With a prefix argument and an untracked file (or files) at point, + stage the file but not its content. This makes it possible to + stage only a subset of the new file’s changes. + +‘S’ (‘magit-stage-modified’) + Stage all changes to files modified in the worktree. Stage all new + content of tracked files and remove tracked files that no longer + exist in the working tree from the index also. With a prefix + argument also stage previously untracked (but not ignored) files. + +‘u’ (‘magit-unstage’) + Remove the change at point from the staging area. + + Only staged changes can be unstaged. But by default this command + performs an action that is somewhat similar to unstaging, when it + is called on a committed change: it reverses the change in the + index but not in the working tree. + +‘U’ (‘magit-unstage-all’) + Remove all changes from the staging area. + + -- User Option: magit-unstage-committed + This option controls whether ‘magit-unstage’ "unstages" committed + changes by reversing them in the index but not the working tree. + The alternative is to raise an error. + +‘M-x magit-reverse-in-index’ + This command reverses the committed change at point in the index + but not the working tree. By default no key is bound directly to + this command, but it is indirectly called when ‘u’ + (‘magit-unstage’) is pressed on a committed change. + + This allows extracting a change from ‘HEAD’, while leaving it in + the working tree, so that it can later be committed using a + separate commit. A typical workflow would be: + + 1. Optionally make sure that there are no uncommitted changes. + 2. Visit the ‘HEAD’ commit and navigate to the change that should + not have been included in that commit. + 3. Type ‘u’ (‘magit-unstage’) to reverse it in the index. This + assumes that ‘magit-unstage-committed-changes’ is non-nil. + 4. Type ‘c e’ to extend ‘HEAD’ with the staged changes, including + those that were already staged before. + 5. Optionally stage the remaining changes using ‘s’ or ‘S’ and + then type ‘c c’ to create a new commit. + +‘M-x magit-reset-index’ + Reset the index to some commit. The commit is read from the user + and defaults to the commit at point. If there is no commit at + point, then it defaults to ‘HEAD’. + +* Menu: + +* Staging from File-Visiting Buffers:: + + +File: magit.info, Node: Staging from File-Visiting Buffers, Up: Staging and Unstaging + +6.3.1 Staging from File-Visiting Buffers +---------------------------------------- + +Fine-grained un-/staging has to be done from the status or a diff +buffer, but it’s also possible to un-/stage all changes made to the file +visited in the current buffer right from inside that buffer. + +‘M-x magit-stage-file’ + When invoked inside a file-visiting buffer, then stage all changes + to that file. In a Magit buffer, stage the file at point if any. + Otherwise prompt for a file to be staged. With a prefix argument + always prompt the user for a file, even in a file-visiting buffer + or when there is a file section at point. + +‘M-x magit-unstage-file’ + When invoked inside a file-visiting buffer, then unstage all + changes to that file. In a Magit buffer, unstage the file at point + if any. Otherwise prompt for a file to be unstaged. With a prefix + argument always prompt the user for a file, even in a file-visiting + buffer or when there is a file section at point. + + +File: magit.info, Node: Applying, Next: Committing, Prev: Staging and Unstaging, Up: Manipulating + +6.4 Applying +============ + +Magit provides several "apply variants": stage, unstage, discard, +reverse, and "regular apply". At least when operating on a hunk they +are all implemented using ‘git apply’, which is why they are called +"apply variants". + + • Stage. Apply a change from the working tree to the index. The + change also remains in the working tree. + + • Unstage. Remove a change from the index. The change remains in + the working tree. + + • Discard. On a staged change, remove it from the working tree and + the index. On an unstaged change, remove it from the working tree + only. + + • Reverse. Reverse a change in the working tree. Both committed and + staged changes can be reversed. Unstaged changes cannot be + reversed. Discard them instead. + + • Apply. Apply a change to the working tree. Both committed and + staged changes can be applied. Unstaged changes cannot be applied + - as they already have been applied. + + The previous section described the staging and unstaging commands. +What follows are the commands which implement the remaining apply +variants. + +‘a’ (‘magit-apply’) + Apply the change at point to the working tree. + + With a prefix argument fallback to a 3-way merge. Doing so causes + the change to be applied to the index as well. + +‘k’ (‘magit-discard’) + 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. + +‘v’ (‘magit-reverse’) + Reverse the change at point in the working tree. + + With a prefix argument fallback to a 3-way merge. Doing so causes + the change to be applied to the index as well. + + With a prefix argument all apply variants attempt a 3-way merge when +appropriate (i.e. when ‘git apply’ is used internally). + + +File: magit.info, Node: Committing, Next: Branching, Prev: Applying, Up: Manipulating + +6.5 Committing +============== + +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 +‘.git/COMMIT_EDITMSG’ and then opens that file in an editor. Magit +arranges for that editor to be the Emacsclient. Once the user finishes +the editing session, the Emacsclient exits and Git creates the commit +using the file’s content as message. + +* Menu: + +* Initiating a Commit:: +* Editing Commit Messages:: + + +File: magit.info, Node: Initiating a Commit, Next: Editing Commit Messages, Up: Committing + +6.5.1 Initiating a Commit +------------------------- + +Also see *note (gitman)git-commit::. + +‘c’ (‘magit-commit’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘c c’ (‘magit-commit-create’) + Create a new commit on ‘HEAD’. With a prefix argument amend to the + commit at ‘HEAD’ instead. + +‘c a’ (‘magit-commit-amend’) + Amend the last commit. + +‘c e’ (‘magit-commit-extend’) + Amend the last commit, without editing the message. With a prefix + argument keep the committer date, otherwise change it. The option + ‘magit-commit-extend-override-date’ can be used to inverse the + meaning of the prefix argument. + + Non-interactively respect the optional OVERRIDE-DATE argument and + ignore the option. + +‘c w’ (‘magit-commit-reword’) + Reword the last commit, ignoring staged changes. With a prefix + argument keep the committer date, otherwise change it. The option + ‘magit-commit-reword-override-date’ can be used to inverse the + meaning of the prefix argument. + + Non-interactively respect the optional OVERRIDE-DATE argument and + ignore the option. + +‘c f’ (‘magit-commit-fixup’) + Create a fixup commit. + + 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’. + +‘c F’ (‘magit-commit-instant-fixup’) + Create a fixup commit and instantly rebase. + +‘c s’ (‘magit-commit-squash’) + Create a squash commit, without editing the squash message. + + 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’. + +‘c S’ (‘magit-commit-instant-squash’) + Create a squash commit and instantly rebase. + +‘c A’ (‘magit-commit-augment’) + Create a squash commit, editing the squash message. + + 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’. + + -- User Option: magit-commit-ask-to-stage + 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. + + -- User Option: magit-commit-reword-override-date + Whether using ‘magit-commit-reword’ changes the committer date. + + -- User Option: magit-commit-squash-confirm + Whether the commit targeted by squash and fixup has to be + confirmed. When non-nil then the commit at point (if any) is used + as default choice. Otherwise it has to be confirmed. This option + only affects ‘magit-commit-squash’ and ‘magit-commit-fixup’. The + "instant" variants 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 . + + +File: magit.info, Node: Editing Commit Messages, Prev: Initiating a Commit, Up: Committing + +6.5.2 Editing Commit Messages +----------------------------- + +After initiating a commit as described in the previous section, two new +buffers appear. One shows the changes that are about to be committed, +while the other is used to write the message. + + Commit messages are edited in an edit session - in the background +‘git’ is waiting for the editor, in our case ‘emacsclient’, to save the +commit message in a file (in most cases ‘.git/COMMIT_EDITMSG’) and then +return. If the editor returns with a non-zero exit status then ‘git’ +does not create the commit. So the most important commands are those +for finishing and aborting the commit. + +‘C-c C-c’ (‘with-editor-finish’) + Finish the current editing session by returning with exit code 0. + Git then creates the commit using the message it finds in the file. + +‘C-c C-k’ (‘with-editor-cancel’) + Cancel the current editing session by returning with exit code 1. + Git then cancels the commit, but leaves the file untouched. + + In addition to being used by ‘git commit’, messages may also be +stored in a ring that persists until Emacs is closed. By default the +message is stored at the beginning and the end of an edit session +(regardless of whether the session is finished successfully or was +canceled). It is sometimes useful to bring back messages from that +ring. + +‘C-c M-s’ (‘git-commit-save-message’) + Save the current buffer content to the commit message ring. + +‘M-p’ (‘git-commit-prev-message’) + Cycle backward through the commit message ring, after saving the + current message to the ring. With a numeric prefix ARG, go back + ARG comments. + +‘M-n’ (‘git-commit-next-message’) + Cycle forward through the commit message ring, after saving the + current message to the ring. With a numeric prefix ARG, go back + ARG comments. + + By default the diff for the changes that are about to be committed +are automatically shown when invoking the commit. To prevent that, +remove ‘magit-commit-diff’ from ‘server-switch-hook’. + + When amending to an existing commit it may be useful to show either +the changes that are about to be added to that commit or to show those +changes alongside those that have already been committed. + +‘C-c C-d’ (‘magit-diff-while-committing’) + While committing, show the changes that are about to be committed. + While amending, invoking the command again toggles between showing + just the new changes or all the changes that will be committed. + +* Menu: + +* Using the Revision Stack:: +* Commit Pseudo Headers:: +* Commit Mode and Hooks:: +* Commit Message Conventions:: + + +File: magit.info, Node: Using the Revision Stack, Next: Commit Pseudo Headers, Up: Editing Commit Messages + +Using the Revision Stack +........................ + +‘C-c C-w’ (‘magit-pop-revision-stack’) + This command inserts a representation of a revision into the + current buffer. It can be used inside buffers used to write commit + messages but also in other buffers such as buffers used to edit + emails or ChangeLog files. + + By default this command pops the revision which was last added to + the ‘magit-revision-stack’ and inserts it into the current buffer + according to ‘magit-pop-revision-stack-format’. Revisions can be + put on the stack using ‘magit-copy-section-value’ and + ‘magit-copy-buffer-revision’. + + If the stack is empty or with a prefix argument it instead reads a + revision in the minibuffer. By using the minibuffer history this + allows selecting an item which was popped earlier or to insert an + arbitrary reference or revision without first pushing it onto the + stack. + + When reading the revision from the minibuffer, then it might not be + possible to guess the correct repository. When this command is + called inside a repository (e.g. while composing a commit + message), then that repository is used. Otherwise (e.g. while + composing an email) then the repository recorded for the top + element of the stack is used (even though we insert another + revision). If not called inside a repository and with an empty + stack, or with two prefix arguments, then read the repository in + the minibuffer too. + + -- User Option: magit-pop-revision-stack-format + This option controls how the command ‘magit-pop-revision-stack’ + inserts a revision into the current buffer. + + The entries on the stack have the format ‘(HASH TOPLEVEL)’ and this + option has the format ‘(POINT-FORMAT EOB-FORMAT INDEX-REGEXP)’, all + of which may be nil or a string (though either one of EOB-FORMAT or + POINT-FORMAT should be a string, and if INDEX-REGEXP is non-nil, + then the two formats should be too). + + First INDEX-REGEXP is used to find the previously inserted entry, + by searching backward from point. The first submatch must match + the index number. That number is incremented by one, and becomes + the index number of the entry to be inserted. If you don’t want to + number the inserted revisions, then use nil for INDEX-REGEXP. + + If INDEX-REGEXP is non-nil then both POINT-FORMAT and EOB-FORMAT + should contain \"%N\", which is replaced with the number that was + determined in the previous step. + + Both formats, if non-nil and after removing %N, are then expanded + using ‘git show --format=FORMAT ...’ inside TOPLEVEL. + + The expansion of POINT-FORMAT is inserted at point, and the + 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). + + +File: magit.info, Node: Commit Pseudo Headers, Next: Commit Mode and Hooks, Prev: Using the Revision Stack, Up: Editing Commit Messages + +Commit Pseudo Headers +..................... + +Some projects use pseudo headers in commit messages. Magit colorizes +such headers and provides some commands to insert such headers. + + -- User Option: git-commit-known-pseudo-headers + A list of Git pseudo headers to be highlighted. + +‘C-c C-i’ (‘git-commit-insert-pseudo-header’) + Insert a commit message pseudo header. + +‘C-c C-a’ (‘git-commit-ack’) + Insert a header acknowledging that you have looked at the commit. + +‘C-c C-r’ (‘git-commit-review’) + Insert a header acknowledging that you have reviewed the commit. + +‘C-c C-s’ (‘git-commit-signoff’) + Insert a header to sign off the commit. + +‘C-c C-t’ (‘git-commit-test’) + Insert a header acknowledging that you have tested the commit. + +‘C-c C-o’ (‘git-commit-cc’) + Insert a header mentioning someone who might be interested. + +‘C-c C-p’ (‘git-commit-reported’) + Insert a header mentioning the person who reported the issue being + fixed by the commit. + +‘C-c M-i’ (‘git-commit-suggested’) + Insert a header mentioning the person who suggested the change. + + +File: magit.info, Node: Commit Mode and Hooks, Next: Commit Message Conventions, Prev: Commit Pseudo Headers, Up: Editing Commit Messages + +Commit Mode and Hooks +..................... + +‘git-commit-mode’ is a minor mode that is only used to establish certain +key bindings. This makes it possible to use an arbitrary major mode in +buffers used to edit commit messages. It is even possible to use +different major modes in different repositories, which is useful when +different projects impose different commit message conventions. + + -- User Option: git-commit-major-mode + The value of this option is the major mode used to edit Git commit + messages. + + Because ‘git-commit-mode’ is a minor mode, we don’t use its mode hook +to setup the buffer, except for the key bindings. All other setup +happens in the function ‘git-commit-setup’, which among other things +runs the hook ‘git-commit-setup-hook’. + + -- User Option: git-commit-setup-hook + Hook run at the end of ‘git-commit-setup’. + +The following functions are suitable for this hook: + + -- Function: git-commit-save-message + Save the current buffer content to the commit message ring. + + -- Function: git-commit-setup-changelog-support + After this function is called, ChangeLog entries are treated as + paragraphs. + + -- Function: git-commit-turn-on-auto-fill + Turn on ‘auto-fill-mode’ and set ‘fill-column’ to the value of + ‘git-commit-fill-column’. + + -- Function: git-commit-turn-on-flyspell + Turn on Flyspell mode. Also prevent comments from being checked + and finally check current non-comment text. + + -- Function: git-commit-propertize-diff + Propertize the diff shown inside the commit message buffer. Git + inserts such diffs into the commit message template when the + ‘--verbose’ argument is used. ‘magit-commit’ by default does not + offer that argument because the diff that is shown in a separate + buffer is more useful. But some users disagree, which is why this + function exists. + + -- Function: bug-reference-mode + Hyperlink bug references in the buffer. + + -- Function: with-editor-usage-message + Show usage information in the echo area. + + -- User Option: git-commit-setup-hook + Hook run after the user finished writing a commit message. + + This hook is only run after pressing ‘C-c C-c’ in a buffer used to + edit a commit message. If a commit is created without the user + typing a message into a buffer, then this hook is not run. + + This hook is not run until the new commit has been created. If + doing so takes Git longer than one second, then this hook isn’t run + at all. For certain commands such as ‘magit-rebase-continue’ this + hook is never run because doing so would lead to a race condition. + + This hook is only run if ‘magit’ is available. + + Also see ‘magit-post-commit-hook’. + + +File: magit.info, Node: Commit Message Conventions, Prev: Commit Mode and Hooks, Up: Editing Commit Messages + +Commit Message Conventions +.......................... + +Git-Commit highlights certain violations of commonly accepted commit +message conventions. Certain violations even cause Git-Commit to ask +you to confirm that you really want to do that. This nagging can of +course be turned off, but the result of doing that usually is that +instead of some code it’s now the human who is reviewing your commits +who has to waste some time telling you to fix your commits. + + -- User Option: git-commit-summary-max-length + The intended maximal length of the summary line of commit messages. + Characters beyond this column are colorized to indicate that this + preference has been violated. + + -- User Option: git-commit-fill-column + Column beyond which automatic line-wrapping should happen in commit + message buffers. + + -- User Option: git-commit-finish-query-functions + List of functions called to query before performing commit. + + The commit message buffer is current while the functions are + called. If any of them returns nil, then the commit is not + performed and the buffer is not killed. The user should then fix + the issue and try again. + + The functions are called with one argument. If it is non-nil then + that indicates that the user used a prefix argument to force + finishing the session despite issues. Functions should usually + honor this wish and return non-nil. + + By default the only member is ‘git-commit-check-style-conventions’. + + -- Function: git-commit-check-style-conventions + This function checks for violations of certain basic style + conventions. For each violation it asks users if they want to + proceed anyway. + + -- User Option: git-commit-style-convention-checks + This option controls what conventions the function by the same name + tries to enforce. The value is a list of self-explanatory symbols + identifying certain conventions; ‘non-empty-second-line’ and + ‘overlong-summary-line’. + + +File: magit.info, Node: Branching, Next: Merging, Prev: Committing, Up: Manipulating + +6.6 Branching +============= + +* Menu: + +* The Two Remotes:: +* Branch Commands:: +* Branch Git Variables:: +* Auxiliary Branch Commands:: + + +File: magit.info, Node: The Two Remotes, Next: Branch Commands, Up: Branching + +6.6.1 The Two Remotes +--------------------- + +The upstream branch of some local branch is the branch into which the +commits on that local branch should eventually be merged, usually +something like ‘origin/master’. For the ‘master’ branch itself the +upstream branch and the branch it is being pushed to, are usually the +same remote branch. But for a feature branch the upstream branch and +the branch it is being pushed to should differ. + + The commits on feature branches too should _eventually_ end up in a +remote branch such as ‘origin/master’ or ‘origin/maint’. Such a branch +should therefore be used as the upstream. But feature branches +shouldn’t be pushed directly to such branches. Instead a feature branch +‘my-feature’ is usually pushed to ‘my-fork/my-feature’ or if you are a +contributor ‘origin/my-feature’. After the new feature has been +reviewed, the maintainer merges the feature into ‘master’. And finally +‘master’ (not ‘my-feature’ itself) is pushed to ‘origin/master’. + + But new features seldom are perfect on the first try, and so feature +branches usually have to be reviewed, improved, and re-pushed several +times. Pushing should therefore be easy to do, and for that reason many +Git users have concluded that it is best to use the remote branch to +which the local feature branch is being pushed as its upstream. + + But luckily Git has long ago gained support for a push-remote which +can be configured separately from the upstream branch, using the +variables ‘branch..pushRemote’ and ‘remote.pushDefault’. So we no +longer have to choose which of the two remotes should be used as "the +remote". + + Each of the fetching, pulling, and pushing transient commands +features three suffix commands that act on the current branch and some +other branch. Of these, ‘p’ is bound to a command which acts on the +push-remote, ‘u’ is bound to a command which acts on the upstream, and +‘e’ is bound to a command which acts on any other branch. The status +buffer shows unpushed and unpulled commits for both the push-remote and +the upstream. + + It’s fairly simple to configure these two remotes. The values of all +the variables that are related to fetching, pulling, and pushing (as +well as some other branch-related variables) can be inspected and +changed using the command ‘magit-branch-configure’, which is available +from many transient prefix commands that deal with branches. It is also +possible to set the push-remote or upstream while pushing (see *note +Pushing::). + + +File: magit.info, Node: Branch Commands, Next: Branch Git Variables, Prev: The Two Remotes, Up: Branching + +6.6.2 Branch Commands +--------------------- + +The transient prefix command ‘magit-branch’ is used to create and +checkout branches, and to make changes to existing branches. It is not +used to fetch, pull, merge, rebase, or push branches, i.e. this command +deals with branches themselves, not with the commits reachable from +them. Those features are available from separate transient command. + +‘b’ (‘magit-branch’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + + By default it also binds and displays the values of some + branch-related Git variables and allows changing their values. + + -- User Option: magit-branch-direct-configure + This option controls whether the transient command ‘magit-branch’ + can 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. + +‘b C’ (‘magit-branch-configure’) +‘f C’ +‘F C’ +‘P C’ + This transient prefix command binds commands that set the value of + branch-related variables and displays them in a temporary buffer + until the transient is exited. + + With a prefix argument, this command always prompts for a branch. + + Without a prefix argument this depends on whether it was invoked as + a suffix of ‘magit-branch’ and on the + ‘magit-branch-direct-configure’ option. If ‘magit-branch’ already + displays the variables for the current branch, then it isn’t useful + to invoke another transient that displays them for the same branch. + In that case this command prompts for a branch. + + The variables are described in *note Branch Git Variables::. + +‘b b’ (‘magit-checkout’) + Checkout a revision read in the minibuffer and defaulting to the + branch or arbitrary revision at point. If the 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. + +‘b n’ (‘magit-branch-create’) + Create a new branch. The user is asked for a branch or arbitrary + revision to use as the starting point of the new branch. When a + branch name is provided, then that becomes the upstream branch of + the new branch. The name of the new branch is also read in the + minibuffer. + + Also see option ‘magit-branch-prefer-remote-upstream’. + +‘b c’ (‘magit-branch-and-checkout’) + This command creates a new branch like ‘magit-branch-create’, but + then also checks it out. + + Also see option ‘magit-branch-prefer-remote-upstream’. + +‘b l’ (‘magit-branch-checkout’) + This command checks out an existing or new local branch. It reads + a branch name from the user offering all local branches and a + subset of remote branches as candidates. Remote branches for which + a local branch by the same name exists are omitted from the list of + candidates. The user can also enter a completely new branch name. + + • If the user selects an existing local branch, then that is + checked out. + + • If the user selects a remote branch, then it creates and + checks out a new local branch with the same name, and + configures the selected remote branch as the push target. + + • If the user enters a new branch name, then it creates and + checks that out, after also reading the starting-point from + the user. + + In the latter two cases the upstream is also set. Whether it is + set to the chosen starting point or something else depends on the + value of ‘magit-branch-adjust-remote-upstream-alist’. + +‘b s’ (‘magit-branch-spinoff’) + This command creates and checks out a new branch starting at and + tracking the current branch. That branch in turn is reset to the + last commit it shares with its upstream. If the current branch has + no upstream or no unpushed commits, then the new branch is created + anyway and the previously current branch is not touched. + + This is useful to create a feature branch after work has already + began on the old branch (likely but not necessarily "master"). + + If the current branch is a member of the value of option + ‘magit-branch-prefer-remote-upstream’ (which see), then the current + branch will be used as the starting point as usual, but the + upstream of the starting-point may be used as the upstream of the + new branch, instead of the starting-point itself. + + If optional FROM is non-nil, then the source branch is reset to + ‘FROM~’, instead of to the last commit it shares with its upstream. + Interactively, FROM is only ever non-nil, if the region selects + some commits, and among those commits, FROM is the commit that is + the fewest commits ahead of the source branch. + + The commit at the other end of the selection actually does not + matter, all commits between FROM and ‘HEAD’ are moved to the new + branch. If FROM is not reachable from ‘HEAD’ or is reachable from + the source branch’s upstream, then an error is raised. + +‘b S’ (‘magit-branch-spinout’) + This command behaves like ‘magit-branch-spinoff’, except that it + does not change the current branch. If there are any uncommitted + changes, then it behaves exactly like ‘magit-branch-spinoff’. + +‘b x’ (‘magit-branch-reset’) + This command resets a branch, defaulting to the branch at point, to + the tip of another branch or any other commit. + + When the branch being reset is the current branch, then a hard + reset is performed. If there are any uncommitted changes, then the + user has to confirm the reset because those changes would be lost. + + This is useful when you have started work on a feature branch but + realize it’s all crap and want to start over. + + When resetting to another branch and a prefix argument is used, + then the target branch is set as the upstream of the branch that is + being reset. + +‘b k’ (‘magit-branch-delete’) + Delete one or multiple branches. If the region marks multiple + branches, then offer to delete those. Otherwise, prompt for a + single branch to be deleted, defaulting to the branch at point. + +‘b r’ (‘magit-branch-rename’) + Rename a branch. The branch and the new name are read in the + minibuffer. With prefix argument the branch is renamed even if + that name conflicts with an existing branch. + + -- 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 ‘t’, + and I recommend you leave it at that. + + -- User Option: magit-branch-prefer-remote-upstream + This option specifies whether remote upstreams are favored over + local upstreams when creating new branches. + + When a new branch is created, then the branch, commit, or stash at + point is suggested as the starting point of the new branch, or if + there is no such revision at point the current branch. In either + case the user may choose another starting point. + + If the chosen starting point is a branch, then it may also be set + as the upstream of the new branch, depending on the value of the + Git variable ‘branch.autoSetupMerge’. By default this is done for + remote branches, but not for local branches. + + You might prefer to always use some remote branch as upstream. If + the chosen starting point is (1) a local branch, (2) whose name + matches a member of the value of this option, (3) the upstream of + that local branch is a remote branch with the same name, and (4) + that remote branch can be fast-forwarded to the local branch, then + the chosen branch is used as starting point, but its own upstream + is used as the upstream of the new branch. + + Members of this option’s value are treated as branch names that + have to match exactly unless they contain a character that makes + them invalid as a branch name. Recommended characters to use to + trigger interpretation as a regexp are "*" and "^". Some other + characters which you might expect to be invalid, actually are not, + e.g. ".+$" are all perfectly valid. More precisely, if ‘git + check-ref-format --branch STRING’ exits with a non-zero status, + then treat STRING as a regexp. + + Assuming the chosen branch matches these conditions you would end + up with with e.g.: + + feature --upstream--> origin/master + + instead of + + feature --upstream--> master --upstream--> origin/master + + Which you prefer is a matter of personal preference. If you do + prefer the former, then you should add branches such as ‘master’, + ‘next’, and ‘maint’ to the value of this options. + + -- User Option: magit-branch-adjust-remote-upstream-alist + The value of this option is an alist of branches to be used as the + upstream when branching a remote branch. + + When creating a local branch from an ephemeral branch located on a + remote, e.g. a feature or hotfix branch, then that remote branch + should usually not be used as the upstream branch, since the + push-remote already allows accessing it and having both the + upstream and the push-remote reference the same related branch + would be wasteful. Instead a branch like "maint" or "master" + should be used as the upstream. + + 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. + + UPSTREAM is the branch to be used as the upstream for branches + specified by RULE. It can be a local or a remote branch. + + RULE can either be a regular expression, matching branches whose + upstream should be the one specified by UPSTREAM. Or it can be a + list of the only branches that should *not* use UPSTREAM; all other + branches will. Matching is done after stripping the remote part of + the name of the branch that is being branched from. + + 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"))) + + Or if the names of all your ephemeral branches contain a slash, at + least in some repositories, then a good value could be: + + (("origin/master" . "/")) + + Of course you can also fine-tune: + + (("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"))) + + -- Command: magit-branch-orphan + This command creates and checks out a new orphan branch with + contents from a given revision. + + -- Command: magit-branch-or-checkout + This command is a hybrid between ‘magit-checkout’ and + ‘magit-branch-and-checkout’ and is intended as a replacement for + the former in ‘magit-branch’. + + It first asks the user for an existing branch or revision. If the + user input actually can be resolved as a branch or revision, then + it checks that out, just like ‘magit-checkout’ would. + + Otherwise it creates and checks out a new branch using the input as + its name. Before doing so it reads the starting-point for the new + branch. This is similar to what ‘magit-branch-and-checkout’ does. + + To use this command instead of ‘magit-checkout’ add this to your + init file: + + (transient-replace-suffix 'magit-branch 'magit-checkout + '("b" "dwim" magit-branch-or-checkout)) + + +File: magit.info, Node: Branch Git Variables, Next: Auxiliary Branch Commands, Prev: Branch Commands, Up: Branching + +6.6.3 Branch Git Variables +-------------------------- + +These variables can be set from the transient prefix command +‘magit-branch-configure’. By default they can also be set from +‘magit-branch’. See *note Branch Commands::. + + -- Variable: branch.NAME.merge + Together with ‘branch.NAME.remote’ this variable defines the + upstream branch of the local branch named NAME. The value of this + variable is the full reference of the upstream _branch_. + + -- Variable: branch.NAME.remote + Together with ‘branch.NAME.merge’ this variable defines the + upstream branch of the local branch named NAME. The value of this + variable is the name of the upstream _remote_. + + -- Variable: branch.NAME.rebase + This variable controls whether pulling into the branch named NAME + is done by rebasing or by merging the fetched branch. + + • When ‘true’ then pulling is done by rebasing. + • When ‘false’ then pulling is done by merging. + • When undefined then the value of ‘pull.rebase’ is used. The + default of that variable is ‘false’. + + -- Variable: branch.NAME.pushRemote + This variable specifies the remote that the branch named NAME is + usually pushed to. The value has to be the name of an existing + remote. + + It is not possible to specify the name of _branch_ to push the + local branch to. The name of the remote branch is always the same + as the name of the local branch. + + If this variable is undefined but ‘remote.pushDefault’ is defined, + then the value of the latter is used. By default + ‘remote.pushDefault’ is undefined. + + -- Variable: branch.NAME.description + This variable can be used to describe the branch named NAME. That + description is used e.g. when turning the branch into a series of + patches. + + The following variables specify defaults which are used if the above +branch-specific variables are not set. + + -- Variable: pull.rebase + This variable specifies whether pulling is done by rebasing or by + merging. It can be overwritten using ‘branch.NAME.rebase’. + + • When ‘true’ then pulling is done by rebasing. + • When ‘false’ (the default) then pulling is done by merging. + + Since it is never a good idea to merge the upstream branch into a + feature or hotfix branch and most branches are such branches, you + should consider setting this to ‘true’, and ‘branch.master.rebase’ + to ‘false’. + + -- Variable: remote.pushDefault + This variable specifies what remote the local branches are usually + pushed to. This can be overwritten per branch using + ‘branch.NAME.pushRemote’. + + The following variables are used during the creation of a branch and +control whether the various branch-specific variables are automatically +set at this time. + + -- Variable: branch.autoSetupMerge + This variable specifies under what circumstances creating a branch + NAME should result in the variables ‘branch.NAME.merge’ and + ‘branch.NAME.remote’ being set according to the starting point used + to create the branch. If the starting point isn’t a branch, then + these variables are never set. + + • When ‘always’ then the variables are set regardless of whether + the starting point is a local or a remote branch. + • When ‘true’ (the default) then the variables are set when the + starting point is a remote branch, but not when it is a local + branch. + • When ‘false’ then the variables are never set. + + -- Variable: branch.autoSetupRebase + This variable specifies whether creating a branch NAME should + result in the variable ‘branch.NAME.rebase’ being set to ‘true’. + + • When ‘always’ then the variable is set regardless of whether + the starting point is a local or a remote branch. + • When ‘local’ then the variable are set when the starting point + is a local branch, but not when it is a remote branch. + • When ‘remote’ then the variable are set when the starting + point is a remote branch, but not when it is a local branch. + • When ‘never’ (the default) then the variable is never set. + + Note that the respective commands always change the repository-local +values. If you want to change the global value, which is used when the +local value is undefined, then you have to do so on the command line, +e.g.: + + git config --global remote.autoSetupMerge always + + For more information about these variables you should also see + + *note (gitman)git-config::. Also see *note (gitman)git-branch::. , +*note (gitman)git-checkout::. and *note Pushing::. + + -- User Option: magit-prefer-remote-upstream + This option controls whether commands that read a branch from the + user and then set it as the upstream branch, offer a local or a + remote branch as default completion candidate, when they have the + choice. + + This affects all commands that use ‘magit-read-upstream-branch’ or + ‘magit-read-starting-point’, which includes all commands that + change the upstream and many which create new branches. + + +File: magit.info, Node: Auxiliary Branch Commands, Prev: Branch Git Variables, Up: Branching + +6.6.4 Auxiliary Branch Commands +------------------------------- + +These commands are not available from the transient ‘magit-branch’ by +default. + + -- Command: magit-branch-shelve + This command shelves a branch. This is done by deleting the + branch, and creating a new reference "refs/shelved/BRANCH-NAME" + pointing at the same commit as the branch pointed at. If the + deleted branch had a reflog, then that is preserved as the reflog + of the new reference. + + This is useful if you want to move a branch out of sight, but are + not ready to completely discard it yet. + + -- Command: magit-branch-unshelve + This command unshelves a branch that was previously shelved using + ‘magit-branch-shelve’. This is done by deleting the reference + "refs/shelved/BRANCH-NAME" and creating a branch "BRANCH-NAME" + pointing at the same commit as the deleted reference pointed at. + If the deleted reference had a reflog, then that is restored as the + reflog of the branch. + + +File: magit.info, Node: Merging, Next: Resolving Conflicts, Prev: Branching, Up: Manipulating + +6.7 Merging +=========== + +Also see *note (gitman)git-merge::. For information on how to resolve +merge conflicts see the next section. + +‘m’ (‘magit-merge’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + When no merge is in progress, then the transient features the +following suffix commands. + +‘m m’ (‘magit-merge-plain’) + This command merges another branch or an arbitrary revision into + the current branch. The branch or revision to be merged is read in + the minibuffer and defaults to the branch at point. + + Unless there are conflicts or a prefix argument is used, then the + resulting merge commit uses a generic commit message, and the user + does not get a chance to inspect or change it before the commit is + created. With a prefix argument this does not actually create the + merge commit, which makes it possible to inspect how conflicts were + resolved and to adjust the commit message. + +‘m e’ (‘magit-merge-editmsg’) + This command merges another branch or an arbitrary revision into + the current branch and opens a commit message buffer, so that the + user can make adjustments. The commit is not actually created + until the user finishes with ‘C-c C-c’. + +‘m n’ (‘magit-merge-nocommit’) + This command merges another branch or an arbitrary revision into + the current branch, but does not actually create the merge commit. + The user can then further adjust the merge, even when automatic + conflict resolution succeeded and/or adjust the commit message. + +‘m a’ (‘magit-merge-absorb’) + This command merges another local branch into the current branch + and then removes the former. + + Before the source branch is merged, it is first force pushed to its + push-remote, provided the respective remote branch already exists. + This ensures that the respective pull-request (if any) won’t get + stuck on some obsolete version of the commits that are being + merged. Finally, if ‘magit-branch-pull-request’ was used to create + the merged branch, then the respective remote branch is also + removed. + +‘m i’ (‘magit-merge-into’) + This command merges the current branch into another local branch + and then removes the former. The latter becomes the new current + branch. + + Before the source branch is merged, it is first force pushed to its + push-remote, provided the respective remote branch already exists. + This ensures that the respective pull-request (if any) won’t get + stuck on some obsolete version of the commits that are being + merged. Finally, if ‘magit-branch-pull-request’ was used to create + the merged branch, then the respective remote branch is also + removed. + +‘m s’ (‘magit-merge-squash’) + This command squashes the changes introduced by another branch or + an arbitrary revision into the current branch. This only applies + the changes made by the squashed commits. No information is + preserved that would allow creating an actual merge commit. + Instead of this command you should probably use a command from the + apply transient. + +‘m p’ (‘magit-merge-preview’) + This command shows a preview of merging another branch or an + arbitrary revision into the current branch. + + When a merge is in progress, then the transient instead features the +following suffix commands. + +‘m m’ (‘magit-merge’) + After the user resolved conflicts, this command proceeds with the + merge. If some conflicts weren’t resolved, then this command + fails. + +‘m a’ (‘magit-merge-abort’) + This command aborts the current merge operation. + + +File: magit.info, Node: Resolving Conflicts, Next: Rebasing, Prev: Merging, Up: Manipulating + +6.8 Resolving Conflicts +======================= + +When merging branches (or otherwise combining or changing history) +conflicts can occur. If you edited two completely different parts of +the same file in two branches and then merge one of these branches into +the other, then Git can resolve that on its own, but if you edit the +same area of a file, then a human is required to decide how the two +versions, or "sides of the conflict", are to be combined into one. + + Here we can only provide a brief introduction to the subject and +point you toward some tools that can help. If you are new to this, then +please also consult Git’s own documentation as well as other resources. + + If a file has conflicts and Git cannot resolve them by itself, then +it puts both versions into the affected file along with special markers +whose purpose is to denote the boundaries of the unresolved part of the +file and between the different versions. These boundary lines begin +with the strings consisting of six times the same character, one of ‘<’, +‘|’, ‘=’ and ‘>’ and are followed by information about the source of the +respective versions, e.g.: + + <<<<<<< HEAD + Take the blue pill. + ======= + Take the red pill. + >>>>>>> feature + + In this case you have chosen to take the red pill on one branch and +on another you picked the blue pill. Now that you are merging these two +diverging branches, Git cannot possibly know which pill you want to +take. + + To resolve that conflict you have to create a version of the affected +area of the file by keeping only one of the sides, possibly by editing +it in order to bring in the changes from the other side, remove the +other versions as well as the markers, and then stage the result. A +possible resolution might be: + + Take both pills. + + Often it is useful to see not only the two sides of the conflict but +also the "original" version from before the same area of the file was +modified twice on different branches. Instruct Git to insert that +version as well by running this command once: + + git config --global merge.conflictStyle diff3 + + The above conflict might then have looked like this: + + <<<<<<< HEAD + Take the blue pill. + ||||||| merged common ancestors + Take either the blue or the red pill, but not both. + ======= + Take the red pill. + >>>>>>> feature + + If that were the case, then the above conflict resolution would not +have been correct, which demonstrates why seeing the original version +alongside the conflicting versions can be useful. + + You can perform the conflict resolution completely by hand, but Emacs +also provides some packages that help in the process: Smerge, Ediff +(*note (ediff)Top::), and Emerge (*note (emacs)Emerge::). Magit does +not provide its own tools for conflict resolution, but it does make +using Smerge and Ediff more convenient. (Ediff supersedes Emerge, so +you probably don’t want to use the latter anyway.) + + In the Magit status buffer, files with unresolved conflicts are +listed in the "Unstaged changes" and/or "Staged changes" sections. They +are prefixed with the word "unmerged", which in this context essentially +is a synonym for "unresolved". + + Pressing ‘RET’ while point is on such a file section shows a buffer +visiting that file, turns on ‘smerge-mode’ in that buffer, and places +point inside the first area with conflicts. You should then resolve +that conflict using regular edit commands and/or Smerge commands. + + Unfortunately Smerge does not have a manual, but you can get a list +of commands and binding ‘C-c ^ C-h’ and press ‘RET’ while point is on a +command name to read its documentation. + + Normally you would edit one version and then tell Smerge to keep only +that version. Use ‘C-c ^ m’ (‘smerge-keep-mine’) to keep the ‘HEAD’ +version or ‘C-c ^ o’ (‘smerge-keep-other’) to keep the version that +follows "|||||||". Then use ‘C-c ^ n’ to move to the next conflicting +area in the same file. Once you are done resolving conflicts, return to +the Magit status buffer. The file should now be shown as "modified", no +longer as "unmerged", because Smerge automatically 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. + + Ediff can be used for other purposes as well. For more information +on how to enter Ediff from Magit, see *note Ediffing::. Explaining how +to use Ediff is beyond the scope of this manual, instead see *note +(ediff)Top::. + + If you are unsure whether you should Smerge or Ediff, then use the +former. It is much easier to understand and use, and except for truly +complex conflicts, the latter is usually overkill. + + +File: magit.info, Node: Rebasing, Next: Cherry Picking, Prev: Resolving Conflicts, Up: Manipulating + +6.9 Rebasing +============ + +Also see *note (gitman)git-rebase::. For information on how to resolve +conflicts that occur during rebases see the preceding section. + +‘r’ (‘magit-rebase’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + When no rebase is in progress, then the transient features the +following suffix commands. + + Using one of these commands _starts_ a rebase sequence. Git might +then stop somewhere along the way, either because you told it to do so, +or because applying a commit failed due to a conflict. When that +happens, then the status buffer shows information about the rebase +sequence which is in progress in a section similar to a log section. +See *note Information About In-Progress Rebase::. + + For information about the upstream and the push-remote, see *note The +Two Remotes::. + +‘r p’ (‘magit-rebase-onto-pushremote’) + This command rebases the current branch onto its push-remote. + + With a prefix argument or when the push-remote is either not + configured or unusable, then let the user first configure the + push-remote. + +‘r u’ (‘magit-rebase-onto-upstream’) + This command rebases the current branch onto its upstream branch. + + With a prefix argument or when the upstream is either not + configured or unusable, then let the user first configure the + upstream. + +‘r e’ (‘magit-rebase-branch’) + This command rebases the current branch onto a branch read in the + minibuffer. All commits that are reachable from head but not from + the selected branch TARGET are being rebased. + +‘r s’ (‘magit-rebase-subset’) + This command starts a non-interactive rebase sequence to transfer + commits from START to ‘HEAD’ onto NEWBASE. START has to be + selected from a list of recent commits. + + By default Magit uses the ‘--autostash’ argument, which causes +uncommitted changes to be stored in a stash before the rebase begins. +These changes are restored after the rebase completes and if possible +the stash is removed. If the stash does not apply cleanly, then the +stash is not removed. In case something goes wrong when resolving the +conflicts, this allows you to start over. + + Even though one of the actions is dedicated to interactive rebases, +the transient also features the infix argument ‘--interactive’. This +can be used to turn one of the other, non-interactive rebase variants +into an interactive rebase. + + For example if you want to clean up a feature branch and at the same +time rebase it onto ‘master’, then you could use ‘r-iu’. But we +recommend that you instead do that in two steps. First use ‘ri’ to +cleanup the feature branch, and then in a second step ‘ru’ to rebase it +onto ‘master’. That way if things turn out to be more complicated than +you thought and/or you make a mistake and have to start over, then you +only have to redo half the work. + + Explicitly enabling ‘--interactive’ won’t have an effect on the +following commands as they always use that argument anyway, even if it +is not enabled in the transient. + +‘r i’ (‘magit-rebase-interactive’) + This command starts an interactive rebase sequence. + +‘r f’ (‘magit-rebase-autosquash’) + This command combines squash and fixup commits with their intended + targets. + +‘r m’ (‘magit-rebase-edit-commit’) + This command starts an interactive rebase sequence that lets the + user edit a single older commit. + +‘r w’ (‘magit-rebase-reword-commit’) + This command starts an interactive rebase sequence that lets the + user reword a single older commit. + +‘r k’ (‘magit-rebase-remove-commit’) + This command removes a single older commit using rebase. + + When a rebase is in progress, then the transient instead features the +following suffix commands. + +‘r r’ (‘magit-rebase-continue’) + This command restart the current rebasing operation. + + In some cases this pops up a commit message buffer for you do edit. + With a prefix argument the old message is reused as-is. + +‘r s’ (‘magit-rebase-skip’) + This command skips the current commit and restarts the current + rebase operation. + +‘r e’ (‘magit-rebase-edit’) + This command lets the user edit the todo list of the current rebase + operation. + +‘r a’ (‘magit-rebase-abort’) + This command aborts the current rebase operation, restoring the + original branch. + +* Menu: + +* Editing Rebase Sequences:: +* Information About In-Progress Rebase:: + + +File: magit.info, Node: Editing Rebase Sequences, Next: Information About In-Progress Rebase, Up: Rebasing + +6.9.1 Editing Rebase Sequences +------------------------------ + +‘C-c C-c’ (‘with-editor-finish’) + Finish the current editing session by returning with exit code 0. + Git then uses the rebase instructions it finds in the file. + +‘C-c C-k’ (‘with-editor-cancel’) + Cancel the current editing session by returning with exit code 1. + Git then forgoes starting the rebase sequence. + +‘’ (‘git-rebase-show-commit’) + Show the commit on the current line in another buffer and select + that buffer. + +‘’ (‘git-rebase-show-or-scroll-up’) + Show the commit on the current line in another buffer without + selecting that buffer. If the revision buffer is already visible + in another window of the current frame, then instead scroll that + window up. + +‘’ (‘git-rebase-show-or-scroll-down’) + Show the commit on the current line in another buffer without + selecting that buffer. If the revision buffer is already visible + in another window of the current frame, then instead scroll that + window down. + +‘p’ (‘git-rebase-backward-line’) + Move to previous line. + +‘n’ (‘forward-line’) + Move to next line. + +‘M-p’ (‘git-rebase-move-line-up’) + Move the current commit (or command) up. + +‘M-n’ (‘git-rebase-move-line-down’) + Move the current commit (or command) down. + +‘r’ (‘git-rebase-reword’) + Edit message of commit on current line. + +‘e’ (‘git-rebase-edit’) + Stop at the commit on the current line. + +‘s’ (‘git-rebase-squash’) + Meld commit on current line into previous commit, and edit message. + +‘f’ (‘git-rebase-fixup’) + Meld commit on current line into previous commit, discarding the + current commit’s message. + +‘k’ (‘git-rebase-kill-line’) + Kill the current action line. + +‘c’ (‘git-rebase-pick’) + Use commit on current line. + +‘x’ (‘git-rebase-exec’) + Insert a shell command to be run after the proceeding commit. + + If there already is such a command on the current line, then edit + that instead. With a prefix argument insert a new command even + when there already is one on the current line. With empty input + remove the command on the current line, if any. + +‘b’ (‘git-rebase-break’) + Insert a break action before the current line, instructing Git to + return control to the user. + +‘y’ (‘git-rebase-insert’) + Read an arbitrary commit and insert it below current line. + +‘C-x u’ (‘git-rebase-undo’) + Undo some previous changes. Like ‘undo’ but works in read-only + buffers. + + -- User Option: git-rebase-auto-advance + Whether to move to next line after changing a line. + + -- User Option: git-rebase-show-instructions + Whether to show usage instructions inside the rebase buffer. + + -- User Option: git-rebase-confirm-cancel + Whether confirmation is required to cancel. + + When a rebase is performed with the ‘--rebase-merges’ option, the +sequence will include a few other types of actions and the following +commands become relevant. + +‘l’ (‘git-rebase-label’) + This commands inserts a label action or edits the one at point. + +‘t’ (‘git-rebase-reset’) + This command inserts a reset action or edits the one at point. The + prompt will offer the labels that are currently present in the + buffer. + +‘MM’ (‘git-rebase-merge’) + The command inserts a merge action or edits the one at point. The + prompt will offer the labels that are currently present in the + buffer. Specifying a message to reuse via ‘-c’ or ‘-C’ is not + supported; an editor will always be invoked for the merge. + +‘Mt’ (‘git-rebase-merge-toggle-editmsg’) + This command toggles between the ‘-C’ and ‘-c’ options of the merge + action at point. These options both specify a commit whose message + should be reused. The lower-case variant instructs Git to invoke + the editor when creating the merge, allowing the user to edit the + message. + + +File: magit.info, Node: Information About In-Progress Rebase, Prev: Editing Rebase Sequences, Up: Rebasing + +6.9.2 Information About In-Progress Rebase +------------------------------------------ + +While a rebase sequence is in progress, the status buffer features a +section that lists the commits that have already been applied as well as +the commits that still have to be applied. + + The commits are split in two halves. When rebase stops at a commit, +either because the user has to deal with a conflict or because s/he +explicitly requested that rebase stops at that commit, then point is +placed on the commit that separates the two groups, i.e. on ‘HEAD’. +The commits above it have not been applied yet, while the ‘HEAD’ and the +commits below it have already been applied. In between these two groups +of applied and yet-to-be applied commits, there sometimes is a commit +which has been dropped. + + Each commit is prefixed with a word and these words are additionally +shown in different colors to indicate the status of the commits. + + The following colors are used: + + • Yellow commits have not been applied yet. + + • Gray commits have already been applied. + + • The blue commit is the ‘HEAD’ commit. + + • The green commit is the commit the rebase sequence stopped at. If + this is the same commit as ‘HEAD’ (e.g. because you haven’t done + anything yet after rebase stopped at the commit, then this commit + is shown in blue, not green). There can only be a green *and* a + blue commit at the same time, if you create one or more new commits + after rebase stops at a commit. + + • Red commits have been dropped. They are shown for reference only, + e.g. to make it easier to diff. + + Of course these colors are subject to the color-theme in use. + + The following words are used: + + • Commits prefixed with ‘pick’, ‘reword’, ‘edit’, ‘squash’, and + ‘fixup’ have not been applied yet. These words have the same + meaning here as they do in the buffer used to edit the rebase + sequence. See *note Editing Rebase Sequences::. When the + ‘--rebase-merges’ option was specified, ‘reset’, ‘label’, and + ‘merge’ lines may also be present. + + • Commits prefixed with ‘done’ and ‘onto’ have already been applied. + It is possible for such a commit to be the ‘HEAD’, in which case it + is blue. Otherwise it is grey. + + • The commit prefixed with ‘onto’ is the commit on top of which + all the other commits are being re-applied. This commit + itself did not have to be re-applied, it is the commit rebase + did rewind to before starting to re-apply other commits. + + • Commits prefixed with ‘done’ have already been re-applied. + This includes commits that have been re-applied but also new + commits that you have created during the rebase. + + • All other commits, those not prefixed with any of the above words, + are in some way related to the commit at which rebase stopped. + + To determine whether a commit is related to the stopped-at commit + their hashes, trees and patch-ids (1) are being compared. The + commit message is not used for this purpose. + + Generally speaking commits that are related to the stopped-at + commit can have any of the used colors, though not all color/word + combinations are possible. + + Words used for stopped-at commits are: + + • When a commit is prefixed with ‘void’, then that indicates + that Magit knows for sure that all the changes in that commit + have been applied using several new commits. This commit is + no longer reachable from ‘HEAD’, and it also isn’t one of the + commits that will be applied when resuming the session. + + • When a commit is prefixed with ‘join’, then that indicates + that the rebase sequence stopped at that commit due to a + conflict - you now have to join (merge) the changes with what + has already been applied. In a sense this is the commit + rebase stopped at, but while its effect is already in the + index and in the worktree (with conflict markers), the commit + itself has not actually been applied yet (it isn’t the + ‘HEAD’). So it is shown in yellow, like the other commits + that still have to be applied. + + • When a commit is prefixed with ‘stop’ or a _blue_ or _green_ + ‘same’, then that indicates that rebase stopped at this + commit, that it is still applied or has been applied again, + and that at least its patch-id is unchanged. + + • When a commit is prefixed with ‘stop’, then that + indicates that rebase stopped at that commit because you + requested that earlier, and its patch-id is unchanged. + It might even still be the exact same commit. + + • When a commit is prefixed with a _blue_ or _green_ + ‘same’, then that indicates that while its tree or hash + changed, its patch-id did not. If it is blue, then it is + the ‘HEAD’ commit (as always for blue). When it is + green, then it no longer is ‘HEAD’ because other commit + have been created since (but before continuing the + rebase). + + • When a commit is prefixed with ‘goal’, a _yellow_ ‘same,’ or + ‘work’, then that indicates that rebase applied that commit + but that you then reset ‘HEAD’ to an earlier commit (likely to + split it up into multiple commits), and that there are some + uncommitted changes remaining which likely (but not + necessarily) originate from that commit. + + • When a commit is prefixed with ‘goal’, then that + indicates that it is still possible to create a new + commit with the exact same tree (the "goal") without + manually editing any files, by committing the index, or + by staging all changes and then committing that. This is + the case when the original tree still exists in the index + or worktree in untainted form. + + • When a commit is prefixed with a yellow ‘same’, then that + indicates that it is no longer possible to create a + commit with the exact same tree, but that it is still + possible to create a commit with the same patch-id. This + would be the case if you created a new commit with other + changes, but the changes from the original commit still + exist in the index or working tree in untainted form. + + • When a commit is prefixed with ‘work’, then that + indicates that you reset ‘HEAD’ to an earlier commit, and + that there are some staged and/or unstaged changes + (likely, but not necessarily) originating from that + commit. However it is no longer possible to create a new + commit with the same tree or at least the same patch-id + because you have already made other changes. + + • When a commit is prefixed with ‘poof’ or ‘gone’, then that + indicates that rebase applied that commit but that you then + reset ‘HEAD’ to an earlier commit (likely to split it up into + multiple commits), and that there are no uncommitted changes. + + • When a commit is prefixed with ‘poof’, then that + indicates that it is no longer reachable from ‘HEAD’, but + that it has been replaced with one or more commits, which + together have the exact same effect. + + • When a commit is prefixed with ‘gone’, then that + indicates that it is no longer reachable from ‘HEAD’ and + that we also cannot determine whether its changes are + still in effect in one or more new commits. They might + be, but if so, then there must also be other changes + which makes it impossible to know for sure. + + Do not worry if you do not fully understand the above. That’s okay, +you will acquire a good enough understanding through practice. + + For other sequence operations such as cherry-picking, a similar +section is displayed, but they lack some of the features described +above, due to limitations in the git commands used to implement them. +Most importantly these sequences only support "picking" a commit but not +other actions such as "rewording", and they do not keep track of the +commits which have already been applied. + + ---------- Footnotes ---------- + + (1) The patch-id is a hash of the _changes_ introduced by a commit. +It differs from the hash of the commit itself, which is a hash of the +result of applying that change (i.e. the resulting trees and blobs) as +well as author and committer information, the commit message, and the +hashes of the parents of the commit. The patch-id hash on the other +hand is created only from the added and removed lines, even line numbers +and whitespace changes are ignored when calculating this hash. The +patch-ids of two commits can be used to answer the question "Do these +commits make the same change?". + + +File: magit.info, Node: Cherry Picking, Next: Resetting, Prev: Rebasing, Up: Manipulating + +6.10 Cherry Picking +=================== + +Also see *note (gitman)git-cherry-pick::. + +‘A’ (‘magit-cherry-pick’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + When no cherry-pick or revert is in progress, then the transient +features the following suffix commands. + +‘A A’ (‘magit-cherry-copy’) + This command copies COMMITS from another branch onto the current + branch. If the region selects multiple commits, then those are + copied, without prompting. Otherwise the user is prompted for a + commit or range, defaulting to the commit at point. + +‘A a’ (‘magit-cherry-apply’) + This command applies the changes in COMMITS from another branch + onto the current branch. If the region selects multiple commits, + then those are used, without prompting. Otherwise the user is + prompted for a commit or range, defaulting to the commit at point. + + This command also has a top-level binding, which can be invoked + without using the transient by typing ‘a’ at the top-level. + + The following commands not only apply some commits to some branch, +but also remove them from some other branch. The removal is performed +using either ‘git-update-ref’ or if necessary ‘git-rebase’. Both +applying commits as well as removing them using ‘git-rebase’ can lead to +conflicts. If that happens, then these commands abort and you not only +have to resolve the conflicts but also finish the process the same way +you would have to if these commands didn’t exist at all. + +‘A h’ (‘magit-cherry-harvest’) + This command moves the selected COMMITS that must be located on + another BRANCH onto the current branch instead, removing them from + the former. When this command succeeds, then the same branch is + current as before. + + Applying the commits on the current branch or removing them from + the other branch can lead to conflicts. When that happens, then + this command stops and you have to resolve the conflicts and then + finish the process manually. + +‘A d’ (‘magit-cherry-donate’) + This command moves the selected COMMITS from the current branch + onto another existing BRANCH, removing them from the former. When + this command succeeds, then the same branch is current as before. + ‘HEAD’ is allowed to be detached initially. + + Applying the commits on the other branch or removing them from the + current branch can lead to conflicts. When that happens, then this + command stops and you have to resolve the conflicts and then finish + the process manually. + +‘A n’ (‘magit-cherry-spinout’) + This command moves the selected COMMITS from the current branch + onto a new branch BRANCH, removing them from the former. When this + command succeeds, then the same branch is current as before. + + Applying the commits on the other branch or removing them from the + current branch can lead to conflicts. When that happens, then this + command stops and you have to resolve the conflicts and then finish + the process manually. + +‘A s’ (‘magit-cherry-spinoff’) + This command moves the selected COMMITS from the current branch + onto a new branch BRANCH, removing them from the former. When this + command succeeds, then the new branch is checked out. + + Applying the commits on the other branch or removing them from the + current branch can lead to conflicts. When that happens, then this + command stops and you have to resolve the conflicts and then finish + the process manually. + + When a cherry-pick or revert is in progress, then the transient +instead features the following suffix commands. + +‘A A’ (‘magit-sequence-continue’) + Resume the current cherry-pick or revert sequence. + +‘A s’ (‘magit-sequence-skip’) + Skip the stopped at commit during a cherry-pick or revert sequence. + +‘A a’ (‘magit-sequence-abort’) + Abort the current cherry-pick or revert sequence. This discards + all changes made since the sequence started. + +* Menu: + +* Reverting:: + + +File: magit.info, Node: Reverting, Up: Cherry Picking + +6.10.1 Reverting +---------------- + +‘V’ (‘magit-revert’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + When no cherry-pick or revert is in progress, then the transient +features the following suffix commands. + +‘V V’ (‘magit-revert-and-commit’) + Revert a commit by creating a new commit. Prompt for a commit, + defaulting to the commit at point. If the region selects multiple + commits, then revert all of them, without prompting. + +‘V v’ (‘magit-revert-no-commit’) + Revert a commit by applying it in reverse to the working tree. + Prompt for a commit, defaulting to the commit at point. If the + region selects multiple commits, then revert all of them, without + prompting. + + When a cherry-pick or revert is in progress, then the transient +instead features the following suffix commands. + +‘V A’ (‘magit-sequence-continue’) + Resume the current cherry-pick or revert sequence. + +‘V s’ (‘magit-sequence-skip’) + Skip the stopped at commit during a cherry-pick or revert sequence. + +‘V a’ (‘magit-sequence-abort’) + Abort the current cherry-pick or revert sequence. This discards + all changes made since the sequence started. + + +File: magit.info, Node: Resetting, Next: Stashing, Prev: Cherry Picking, Up: Manipulating + +6.11 Resetting +============== + +Also see *note (gitman)git-reset::. + +‘x’ (‘magit-reset-quickly’) + Reset the ‘HEAD’ and index to some commit read from the user and + defaulting to the commit at point, and possibly also reset the + working tree. With a prefix argument reset the working tree + otherwise don’t. + +‘X m’ (‘magit-reset-mixed’) + Reset the ‘HEAD’ and index to some commit read from the user and + defaulting to the commit at point. The working tree is kept as-is. + +‘X s’ (‘magit-reset-soft’) + Reset the ‘HEAD’ to some commit read from the user and defaulting + to the commit at point. The index and the working tree are kept + as-is. + +‘X h’ (‘magit-reset-hard’) + Reset the ‘HEAD’, index, and working tree to some commit read from + the user and defaulting to the commit at point. + +‘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. + +‘X i’ (‘magit-reset-index’) + Reset the index to some commit read from the user and defaulting to + the commit at point. Keep the ‘HEAD’ and working tree as-is, so if + the commit refers to the ‘HEAD’, then this effectively unstages all + changes. + +‘X w’ (‘magit-reset-worktree’) + Reset the working tree to some commit read from the user and + defaulting to the commit at point. Keep the ‘HEAD’ and index + as-is. + +‘X f’ (‘magit-file-checkout’) + Update file in the working tree and index to the contents from a + revision. Both the revision and file are read from the user. + + +File: magit.info, Node: Stashing, Prev: Resetting, Up: Manipulating + +6.12 Stashing +============= + +Also see *note (gitman)git-stash::. + +‘z’ (‘magit-stash’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘z z’ (‘magit-stash-both’) + Create a stash of the index and working tree. Untracked files are + included according to infix arguments. One prefix argument is + equivalent to ‘--include-untracked’ while two prefix arguments are + equivalent to ‘--all’. + +‘z i’ (‘magit-stash-index’) + Create a stash of the index only. Unstaged and untracked changes + are not stashed. + +‘z w’ (‘magit-stash-worktree’) + Create a stash of unstaged changes in the working tree. Untracked + files are included according to infix arguments. One prefix + argument is equivalent to ‘--include-untracked’ while two prefix + arguments are equivalent to ‘--all’. + +‘z x’ (‘magit-stash-keep-index’) + Create a stash of the index and working tree, keeping index intact. + Untracked files are included according to infix arguments. One + prefix argument is equivalent to ‘--include-untracked’ while two + prefix arguments are equivalent to ‘--all’. + +‘z Z’ (‘magit-snapshot-both’) + Create a snapshot of the index and working tree. Untracked files + are included according to infix arguments. One prefix argument is + equivalent to ‘--include-untracked’ while two prefix arguments are + equivalent to ‘--all’. + +‘z I’ (‘magit-snapshot-index’) + Create a snapshot of the index only. Unstaged and untracked + changes are not stashed. + +‘z W’ (‘magit-snapshot-worktree’) + Create a snapshot of unstaged changes in the working tree. + Untracked files are included according to infix arguments. One + prefix argument is equivalent to ‘--include-untracked’ while two + prefix arguments are equivalent to ‘--all’-. + +‘z a’ (‘magit-stash-apply’) + Apply a stash to the working tree. Try to preserve the stash + index. If that fails because there are staged changes, apply + without preserving the stash index. + +‘z p’ (‘magit-stash-pop’) + Apply a stash to the working tree and remove it from stash list. + Try to preserve the stash index. If that fails because there are + staged changes, apply without preserving the stash index and forgo + removing the stash. + +‘z k’ (‘magit-stash-drop’) + Remove a stash from the stash list. When the region is active, + offer to drop all contained stashes. + +‘z v’ (‘magit-stash-show’) + Show all diffs of a stash in a buffer. + +‘z b’ (‘magit-stash-branch’) + Create and checkout a new BRANCH from STASH. The branch starts at + the commit that was current when the stash was created. + +‘z B’ (‘magit-stash-branch-here’) + Create and checkout a new BRANCH using ‘magit-branch’ with the + current branch or ‘HEAD’ as the starting-point. Then apply STASH, + dropping it if it applies cleanly. + +‘z f’ (‘magit-stash-format-patch’) + Create a patch from STASH. + +‘k’ (‘magit-stash-clear’) + Remove all stashes saved in REF’s reflog by deleting REF. + +‘z l’ (‘magit-stash-list’) + List all stashes in a buffer. + + -- User Option: magit-stashes-margin + This option specifies whether the margin is initially shown in + stashes buffers and how it is formatted. + + The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’. + + • If INIT is non-nil, then the margin is shown initially. + • STYLE controls how to format the author or committer date. It + can be one of ‘age’ (to show the age of the commit), + ‘age-abbreviated’ (to abbreviate the time unit to a + character), or a string (suitable for ‘format-time-string’) to + show the actual date. Option + ‘magit-log-margin-show-committer-date’ controls which date is + being displayed. + • WIDTH controls the width of the margin. This exists for + forward compatibility and currently the value should not be + changed. + • AUTHOR controls whether the name of the author is also shown + by default. + • AUTHOR-WIDTH has to be an integer. When the name of the + author is shown, then this specifies how much space is used to + do so. + + +File: magit.info, Node: Transferring, Next: Miscellaneous, Prev: Manipulating, Up: Top + +7 Transferring +************** + +* Menu: + +* Remotes:: +* Fetching:: +* Pulling:: +* Pushing:: +* Plain Patches:: +* Maildir Patches:: + + +File: magit.info, Node: Remotes, Next: Fetching, Up: Transferring + +7.1 Remotes +=========== + +* Menu: + +* Remote Commands:: +* Remote Git Variables:: + + +File: magit.info, Node: Remote Commands, Next: Remote Git Variables, Up: Remotes + +7.1.1 Remote Commands +--------------------- + +The transient prefix command ‘magit-remote’ is used to add remotes and +to make changes to existing remotes. This command only deals with +remotes themselves, not with branches or the transfer of commits. Those +features are available from separate transient commands. + + Also see *note (gitman)git-remote::. + +‘M’ (‘magit-remote’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + + By default it also binds and displays the values of some + remote-related Git variables and allows changing their values. + + -- User Option: magit-remote-direct-configure + This option controls whether remote-related Git variables are + accessible directly from the transient ‘magit-remote’. + + If ‘t’ (the default) and a local branch is checked out, then + ‘magit-remote’ features the variables for the upstream remote of + that branch, or if ‘HEAD’ is detached, for ‘origin’, provided that + exists. + + If ‘nil’, then ‘magit-remote-configure’ has to be used to do so. + +‘M C’ (‘magit-remote-configure’) + This transient prefix command binds commands that set the value of + remote-related variables and displays them in a temporary buffer + until the transient is exited. + + With a prefix argument, this command always prompts for a remote. + + Without a prefix argument this depends on whether it was invoked as + a suffix of ‘magit-remote’ and on the + ‘magit-remote-direct-configure’ option. If ‘magit-remote’ already + displays the variables for the upstream, then it does not make + sense to invoke another transient that displays them for the same + remote. In that case this command prompts for a remote. + + The variables are described in *note Remote Git Variables::. + +‘M a’ (‘magit-remote-add’) + This command add a remote and fetches it. The remote name and url + are read in the minibuffer. + +‘M r’ (‘magit-remote-rename’) + This command renames a remote. Both the old and the new names are + read in the minibuffer. + +‘M u’ (‘magit-remote-set-url’) + This command changes the url of a remote. Both the remote and the + new url are read in the minibuffer. + +‘M k’ (‘magit-remote-remove’) + This command deletes a remote, read in the minibuffer. + +‘M p’ (‘magit-remote-prune’) + This command removes stale remote-tracking branches for a remote + read in the minibuffer. + +‘M P’ (‘magit-remote-prune-refspecs’) + This command removes stale refspecs for a remote read in the + minibuffer. + + A refspec is stale if there no longer exists at least one branch on + the remote that would be fetched due to that refspec. A stale + refspec is problematic because its existence causes Git to refuse + to fetch according to the remaining non-stale refspecs. + + If only stale refspecs remain, then this command offers to either + delete the remote or to replace the stale refspecs with the default + refspec ("+refs/heads/*:refs/remotes/REMOTE/*"). + + This command also removes the remote-tracking branches that were + created due to the now stale refspecs. Other stale branches are + not removed. + + -- User Option: magit-remote-add-set-remote.pushDefault + This option controls whether the user is asked whether they want to + set ‘remote.pushDefault’ after adding a remote. + + If ‘ask’, then users is always ask. If ‘ask-if-unset’, then the + user is only if the variable isn’t set already. If ‘nil’, then the + user isn’t asked and the variable isn’t set. If the value is a + string, then the variable is set without the user being asked, + provided that the name of the added remote is equal to that string + and the variable isn’t already set. + + +File: magit.info, Node: Remote Git Variables, Prev: Remote Commands, Up: Remotes + +7.1.2 Remote Git Variables +-------------------------- + +These variables can be set from the transient prefix command +‘magit-remote-configure’. By default they can also be set from +‘magit-remote’. See *note Remote Commands::. + + -- Variable: remote.NAME.url + This variable specifies the url of the remote named NAME. It can + have multiple values. + + -- Variable: remote.NAME.fetch + The refspec used when fetching from the remote named NAME. It can + have multiple values. + + -- Variable: remote.NAME.pushurl + This variable specifies the url used for fetching from the remote + named NAME. If it is not specified, then ‘remote.NAME.url’ is used + instead. It can have multiple values. + + -- Variable: remote.NAME.push + The refspec used when pushing to the remote named NAME. It can + have multiple values. + + -- Variable: remote.NAME.tagOpts + This variable specifies what tags are fetched by default. If the + value is ‘--no-tags’ then no tags are fetched. If the value is + ‘--tags’, then all tags are fetched. If this variable has no + value, then only tags are fetched that are reachable from fetched + branches. + + +File: magit.info, Node: Fetching, Next: Pulling, Prev: Remotes, Up: Transferring + +7.2 Fetching +============ + +Also see *note (gitman)git-fetch::. For information about the upstream +and the push-remote, see *note The Two Remotes::. + +‘f’ (‘magit-fetch’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘f p’ (‘magit-fetch-from-pushremote’) + This command fetches from the current push-remote. + + With a prefix argument or when the push-remote is either not + configured or unusable, then let the user first configure the + push-remote. + +‘f u’ (‘magit-fetch-from-upstream’) + This command fetch from the upstream of the current branch. + + If the upstream is configured for the current branch and names an + existing remote, then use that. Otherwise try to use another + remote: If only a single remote is configured, then use that. + Otherwise if a remote named "origin" exists, then use that. + + If no remote can be determined, then this command is not available + from the ‘magit-fetch’ transient prefix and invoking it directly + results in an error. + +‘f e’ (‘magit-fetch-other’) + This command fetch from a repository read from the minibuffer. + +‘f o’ (‘magit-fetch-branch’) + This command fetches a branch from a remote, both of which are read + from the minibuffer. + +‘f r’ (‘magit-fetch-refspec’) + This command fetches from a remote using an explicit refspec, both + of which are read from the minibuffer. + +‘f a’ (‘magit-fetch-all’) + This command fetches from all remotes. + +‘f m’ (‘magit-submodule-fetch’) + This command fetches all submodules. With a prefix argument it + fetches all remotes of all submodules. + + -- User Option: magit-pull-or-fetch + By default fetch and pull commands are available from separate + transient prefix command. Setting this to ‘t’ adds some (but not + all) of the above suffix commands to the ‘magit-pull’ transient. + + If you do that, then you might also want to change the key binding + for these prefix commands, e.g.: + + (setq magit-pull-or-fetch t) + (define-key magit-mode-map "f" 'magit-pull) ; was magit-fetch + (define-key magit-mode-map "F" nil) ; was magit-pull + + +File: magit.info, Node: Pulling, Next: Pushing, Prev: Fetching, Up: Transferring + +7.3 Pulling +=========== + +Also see *note (gitman)git-pull::. For information about the upstream +and the push-remote, see *note The Two Remotes::. + +‘F’ (‘magit-pull’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + +‘F p’ (‘magit-pull-from-pushremote’) + This command pulls from the push-remote of the current branch. + + With a prefix argument or when the push-remote is either not + configured or unusable, then let the user first configure the + push-remote. + +‘F u’ (‘magit-pull-from-upstream’) + This command pulls from the upstream of the current branch. + + With a prefix argument or when the upstream is either not + configured or unusable, then let the user first configure the + upstream. + +‘F e’ (‘magit-pull-branch’) + This command pulls from a branch read in the minibuffer. + + +File: magit.info, Node: Pushing, Next: Plain Patches, Prev: Pulling, Up: Transferring + +7.4 Pushing +=========== + +Also see *note (gitman)git-push::. For information about the upstream +and the push-remote, see *note The Two Remotes::. + +‘P’ (‘magit-push’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘P p’ (‘magit-push-current-to-pushremote’) + This command pushes the current branch to its push-remote. + + With a prefix argument or when the push-remote is either not + configured or unusable, then let the user first configure the + push-remote. + +‘P u’ (‘magit-push-current-to-upstream’) + This command pushes the current branch to its upstream branch. + + With a prefix argument or when the upstream is either not + configured or unusable, then let the user first configure the + upstream. + +‘P e’ (‘magit-push-current’) + This command pushes the current branch to a branch read in the + minibuffer. + +‘P o’ (‘magit-push-other’) + This command pushes an arbitrary branch or commit somewhere. Both + the source and the target are read in the minibuffer. + +‘P r’ (‘magit-push-refspecs’) + This command pushes one or multiple refspecs to a remote, both of + which are read in the minibuffer. + + To use multiple refspecs, separate them with commas. Completion is + only available for the part before the colon, or when no colon is + used. + +‘P m’ (‘magit-push-matching’) + This command pushes all matching branches to another repository. + + If only one remote exists, then push to that. Otherwise prompt for + a remote, offering the remote configured for the current branch as + default. + +‘P t’ (‘magit-push-tags’) + This command pushes all tags to another repository. + + If only one remote exists, then push to that. Otherwise prompt for + a remote, offering the remote configured for the current branch as + default. + +‘P T’ (‘magit-push-tag’) + 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. + + -- Command: magit-push-implicitly args + This command pushes somewhere without using an explicit refspec. + + This command simply runs ‘git push -v [ARGS]’. ARGS are the infix + arguments. No explicit refspec arguments are used. Instead the + behavior depends on at least these Git variables: ‘push.default’, + ‘remote.pushDefault’, ‘branch..pushRemote’, + ‘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: + + (transient-insert-suffix 'magit-push \"p\" + '(\"i\" magit-push-implicitly))" + + -- Command: magit-push-to-remote remote args + This command pushes to the remote REMOTE without using an explicit + refspec. The remote is read in the minibuffer. + + This command simply runs ‘git push -v [ARGS] REMOTE’. ARGS are the + infix arguments. No refspec arguments are used. Instead the + behavior depends on at least these Git variables: ‘push.default’, + ‘remote.pushDefault’, ‘branch..pushRemote’, + ‘branch..remote’, ‘branch..merge’, and + ‘remote..push’. + + +File: magit.info, Node: Plain Patches, Next: Maildir Patches, Prev: Pushing, Up: Transferring + +7.5 Plain Patches +================= + +‘W’ (‘magit-patch’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘W c’ (‘magit-patch-create’) + This command creates patches for a set commits. If the region + marks several commits, then it creates patches for all of them. + Otherwise it functions as a transient prefix command, which + features several infix arguments and binds itself as a suffix + command. When this command is invoked as a suffix of itself, then + it creates a patch using the specified infix arguments. + +‘w a’ (‘magit-patch-apply’) + This command applies a patch. This is a transient prefix command, + which features several infix arguments and binds itself as a suffix + command. When this command is invoked as a suffix of itself, then + it applies a patch using the specified infix arguments. + +‘W s’ (‘magit-patch-save’) + This command creates a patch from the current diff. + + Inside ‘magit-diff-mode’ or ‘magit-revision-mode’ buffers, ‘C-x + C-w’ is also bound to this command. + + It is also possible to save a plain patch file by using ‘C-x C-w’ +inside a ‘magit-diff-mode’ or ‘magit-revision-mode’ buffer. + + +File: magit.info, Node: Maildir Patches, Prev: Plain Patches, Up: Transferring + +7.6 Maildir Patches +=================== + +Also see *note (gitman)git-am::. and *note (gitman)git-apply::. + +‘w’ (‘magit-am’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘w w’ (‘magit-am-apply-patches’) + This command applies one or more patches. If the region marks + files, then those are applied as patches. Otherwise this command + reads a file-name in the minibuffer, defaulting to the file at + point. + +‘w m’ (‘magit-am-apply-maildir’) + This command applies patches from a maildir. + +‘w a’ (‘magit-patch-apply’) + This command applies a plain patch. For a longer description see + *note Plain Patches::. This command is only available from the + ‘magit-am’ transient for historic reasons. + + When an "am" operation is in progress, then the transient instead +features the following suffix commands. + +‘w w’ (‘magit-am-continue’) + This command resumes the current patch applying sequence. + +‘w s’ (‘magit-am-skip’) + This command skips the stopped at patch during a patch applying + sequence. + +‘w a’ (‘magit-am-abort’) + This command aborts the current patch applying sequence. This + discards all changes made since the sequence started. + + +File: magit.info, Node: Miscellaneous, Next: Customizing, Prev: Transferring, Up: Top + +8 Miscellaneous +*************** + +* Menu: + +* Tagging:: +* Notes:: +* Submodules:: +* Subtree:: +* Worktree:: +* Bundle:: +* Common Commands:: +* Wip Modes:: +* Commands for Buffers Visiting Files:: +* Minor Mode for Buffers Visiting Blobs:: + + +File: magit.info, Node: Tagging, Next: Notes, Up: Miscellaneous + +8.1 Tagging +=========== + +Also see *note (gitman)git-tag::. + +‘t’ (‘magit-tag’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘t t’ (‘magit-tag-create’) + This command creates a new tag with the given NAME at REV. With a + prefix argument it creates an annotated tag. + +‘t r’ (‘magit-tag-release’) + 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 + increment the desired part of the version string. If you use + unconventional release tags or version numbers (e.g., + ‘v1.2.3-custom.1’), you can set the ‘magit-release-tag-regexp’ and + ‘magit-tag-version-regexp-alist’ variables. + + 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". + +‘t k’ (‘magit-tag-delete’) + This command deletes one or more tags. If the region marks + multiple tags (and nothing else), then it offers to delete those. + Otherwise, it prompts for a single tag to be deleted, defaulting to + the tag at point. + +‘t p’ (‘magit-tag-prune’) + This command offers to delete tags missing locally from REMOTE, and + vice versa. + + +File: magit.info, Node: Notes, Next: Submodules, Prev: Tagging, Up: Miscellaneous + +8.2 Notes +========= + +Also see *note (gitman)git-notes::. + +‘T’ (‘magit-notes’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + +‘T T’ (‘magit-notes-edit’) + Edit the note attached to a commit, defaulting to the commit at + point. + + By default use the value of Git variable ‘core.notesRef’ or + "refs/notes/commits" if that is undefined. + +‘T r’ (‘magit-notes-remove’) + Remove the note attached to a commit, defaulting to the commit at + point. + + By default use the value of Git variable ‘core.notesRef’ or + "refs/notes/commits" if that is undefined. + +‘T p’ (‘magit-notes-prune’) + Remove notes about unreachable commits. + + It is possible to merge one note ref into another. That may result +in conflicts which have to resolved in the temporary worktree +".git/NOTES_MERGE_WORKTREE". + +‘T m’ (‘magit-notes-merge’) + Merge the notes of a ref read from the user into the current notes + ref. The current notes ref is the value of Git variable + ‘core.notesRef’ or "refs/notes/commits" if that is undefined. + + When a notes merge is in progress then the transient features the +following suffix commands, instead of those listed above. + +‘T c’ (‘magit-notes-merge-commit’) + Commit the current notes ref merge, after manually resolving + conflicts. + +‘T a’ (‘magit-notes-merge-abort’) + Abort the current notes ref merge. + + The following variables control what notes reference ‘magit-notes-*’, +‘git notes’ and ‘git show’ act on and display. Both the local and +global values are displayed and can be modified. + + -- Variable: core.notesRef + This variable specifies the notes ref that is displayed by default + and which commands act on by default. + + -- Variable: notes.displayRef + This variable specifies additional notes ref to be displayed in + addition to the ref specified by ‘core.notesRef’. It can have + multiple values and may end with ‘*’ to display all refs in the + ‘refs/notes/’ namespace (or ‘**’ if some names contain slashes). + + +File: magit.info, Node: Submodules, Next: Subtree, Prev: Notes, Up: Miscellaneous + +8.3 Submodules +============== + +Also see *note (gitman)git-submodule::. + +* Menu: + +* Listing Submodules:: +* Submodule Transient:: + + +File: magit.info, Node: Listing Submodules, Next: Submodule Transient, Up: Submodules + +8.3.1 Listing Submodules +------------------------ + +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-modules’ to the hook +‘magit-status-sections-hook’ as described in *note Status Module +Sections::. + + -- Command: magit-list-submodules + This command displays a list of the current repository’s submodules + in a separate buffer. + + It can be invoked by pressing ‘RET’ on the section titled + "Modules". + + -- User Option: magit-submodule-list-columns + This option controls what columns are displayed by the command + ‘magit-list-submodules’ and how they are displayed. + + Each element has the form ‘(HEADER WIDTH FORMAT PROPS)’. + + HEADER is the string displayed in the header. WIDTH is the width + of the column. FORMAT is a function that is called with one + 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’. + + +File: magit.info, Node: Submodule Transient, Prev: Listing Submodules, Up: Submodules + +8.3.2 Submodule Transient +------------------------- + +‘o’ (‘magit-submodule’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + Some of the below commands default to act on the modules that are +selected using the region. For brevity their description talk about +"the selected modules", but if no modules are selected, then they act on +the current module instead, or if point isn’t on a module, then the read +a single module to act on. With a prefix argument these commands ignore +the selection and the current module and instead act on all suitable +modules. + +‘o a’ (‘magit-submodule-add’) + This commands adds the repository at URL as a module. Optional + PATH is the path to the module relative to the root of the + super-project. If it is nil then the path is determined based on + URL. + +‘o r’ (‘magit-submodule-register’) + This command registers the selected modules by copying their urls + from ".gitmodules" to "$GIT_DIR/config". These values can then be + edited before running ‘magit-submodule-populate’. If you don’t + need to edit any urls, then use the latter directly. + +‘o p’ (‘magit-submodule-populate’) + This command creates the working directory or directories of the + selected modules, checking out the recorded commits. + +‘o u’ (‘magit-submodule-update’) + This command updates the selected modules checking out the recorded + commits. + +‘o s’ (‘magit-submodule-synchronize’) + This command synchronizes the urls of the selected modules, copying + the values from ".gitmodules" to the ".git/config" of the + super-project as well those of the modules. + +‘o d’ (‘magit-submodule-unpopulate’) + This command removes the working directory of the selected modules. + +‘o l’ (‘magit-list-submodules’) + This command displays a list of the current repository’s modules. + +‘o f’ (‘magit-fetch-modules’) + This command fetches all modules. + + Option ‘magit-fetch-modules-jobs’ controls how many submodules are + being fetched in parallel. Also fetch the super-repository, + because ‘git fetch’ does not support not doing that. With a prefix + argument fetch all remotes. + + +File: magit.info, Node: Subtree, Next: Worktree, Prev: Submodules, Up: Miscellaneous + +8.4 Subtree +=========== + +Also see *note (gitman)git-subtree::. + +‘O’ (‘magit-subtree’) + This transient prefix command binds the two sub-transients; one for + importing a subtree and one for exporting a subtree. + +‘O i’ (‘magit-subtree-import’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + The suffixes of this command import subtrees. + + If the ‘--prefix’ argument is set, then the suffix commands use + that prefix without prompting the user. If it is unset, then they + read the prefix in the minibuffer. + +‘O i a’ (‘magit-subtree-add’) + This command adds COMMIT from REPOSITORY as a new subtree at + PREFIX. + +‘O i c’ (‘magit-subtree-add-commit’) + This command add COMMIT as a new subtree at PREFIX. + +‘O i m’ (‘magit-subtree-merge’) + This command merges COMMIT into the PREFIX subtree. + +‘O i f’ (‘magit-subtree-pull’) + This command pulls COMMIT from REPOSITORY into the PREFIX subtree. + +‘O e’ (‘magit-subtree-export’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + The suffixes of this command export subtrees. + + If the ‘--prefix’ argument is set, then the suffix commands use + that prefix without prompting the user. If it is unset, then they + read the prefix in the minibuffer. + +‘O e p’ (‘magit-subtree-push’) + This command extract the history of the subtree PREFIX and pushes + it to REF on REPOSITORY. + +‘O e s’ (‘magit-subtree-split’) + This command extracts the history of the subtree PREFIX. + + +File: magit.info, Node: Worktree, Next: Bundle, Prev: Subtree, Up: Miscellaneous + +8.5 Worktree +============ + +Also see *note (gitman)git-worktree::. + +‘Z’ (‘magit-worktree’) + This transient prefix command binds the following suffix commands + and displays them in a temporary buffer until a suffix is invoked. + +‘Z b’ (‘magit-worktree-checkout’) + Checkout BRANCH in a new worktree at PATH. + +‘Z c’ (‘magit-worktree-branch’) + Create a new BRANCH and check it out in a new worktree at PATH. + +‘Z m’ (‘magit-worktree-move’) + Move an existing worktree to a new PATH. + +‘Z k’ (‘magit-worktree-delete’) + Delete a worktree, defaulting to the worktree at point. The + primary worktree cannot be deleted. + +‘Z g’ (‘magit-worktree-status’) + Show the status for the worktree at point. + + If there is no worktree at point, then read one in the minibuffer. + If the worktree at point is the one whose status is already being + displayed in the current buffer, then show it in Dired instead. + + +File: magit.info, Node: Bundle, Next: Common Commands, Prev: Worktree, Up: Miscellaneous + +8.6 Bundle +========== + +Also see *note (gitman)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. + + +File: magit.info, Node: Common Commands, Next: Wip Modes, Prev: Bundle, Up: Miscellaneous + +8.7 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. + +‘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, + branch, or tag section, it also pushes the (referenced) revision to + the ‘magit-revision-stack’. + + When the current section is a branch or a tag, and a prefix + argument is used, then it saves the revision at its tip to the + ‘kill-ring’ instead of the reference name. + + 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, then it strips the diff marker column and keeps only + either the added or removed lines, depending on the sign of the + prefix argument. + +‘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 is mainly intended for use in + ‘magit-revision-mode’ buffers, the only buffers where it is always + unambiguous exactly which revision should be saved. + + Most other Magit buffers usually show more than one revision, in + some way or another, so this command has to select one of them, and + that choice might not always be the one you think would have been + the best pick. + + Outside of Magit ‘M-w’ and ‘C-w’ are usually bound to +‘kill-ring-save’ and ‘kill-region’, and these commands would also be +useful in Magit buffers. Therefore when the region is active, then both +of these commands behave like ‘kill-ring-save’ instead of as described +above. + + +File: magit.info, Node: Wip Modes, Next: Commands for Buffers Visiting Files, Prev: Common Commands, Up: Miscellaneous + +8.8 Wip Modes +============= + +Git keeps *committed* changes around long enough for users to recover +changes they have accidentally deleted. It does so by not garbage +collecting any committed but no longer referenced objects for a certain +period of time, by default 30 days. + + But Git does *not* keep track of *uncommitted* changes in the working +tree and not even the index (the staging area). Because Magit makes it +so convenient to modify uncommitted changes, it also makes it easy to +shoot yourself in the foot in the process. + + For that reason Magit provides a global mode that saves *tracked* +files to work-in-progress references after or before certain actions. +(At present untracked files are never saved and for technical reasons +nothing is saved before the first commit has been created). + + Two separate work-in-progress references are used to track the state +of the index and of the working tree: ‘refs/wip/index/’ and +‘refs/wip/wtree/’, where ‘’ is the full ref of the +current branch, e.g. ‘refs/heads/master’. When the ‘HEAD’ is detached +then ‘HEAD’ is used in place of ‘’. + + Checking out another branch (or detaching ‘HEAD’) causes the use of +different wip refs for subsequent changes. + + -- User Option: magit-wip-mode + When this mode is enabled, then uncommitted changes are committed + to dedicated work-in-progress refs whenever appropriate (i.e. when + dataloss would be a possibility otherwise). + + Setting this variable directly does not take effect; either use the + Custom interface to do so or call the respective mode function. + + For historic reasons this mode is implemented on top of four other + ‘magit-wip-*’ modes, which can also be used individually, if you + want finer control over when the wip refs are updated; but that is + discouraged. See *note Legacy Wip Modes::. + + To view the log for a branch and its wip refs use the commands +‘magit-wip-log’ and ‘magit-wip-log-current’. You should use ‘--graph’ +when using these commands. + + -- Command: magit-wip-log + This command shows the log for a branch and its wip refs. With a + negative prefix argument only the worktree wip ref is shown. + + The absolute numeric value of the prefix argument controls how many + "branches" of each wip ref are shown. This is only relevant if the + value of ‘magit-wip-merge-branch’ is ‘nil’. + + -- Command: magit-wip-log-current + This command shows the log for the current branch and its wip refs. + With a negative prefix argument only the worktree wip ref is shown. + + The absolute numeric value of the prefix argument controls how many + "branches" of each wip ref are shown. This is only relevant if the + value of ‘magit-wip-merge-branch’ is ‘nil’. + +‘X w’ (‘magit-reset-worktree’) + This command resets the working tree to some commit read from the + user and defaulting to the commit at point, while keeping the + ‘HEAD’ and index as-is. + + This can be used to restore files to the state committed to a wip + ref. Note that this will discard any unstaged changes that might + have existed before invoking this command (but of course only after + committing that to the working tree wip ref). + + Note that even if you enable ‘magit-wip-mode’ this won’t give you +perfect protection. The most likely scenario for losing changes despite +the use of ‘magit-wip-mode’ is making a change outside Emacs and then +destroying it also outside Emacs. In some such a scenario, Magit, being +an Emacs package, didn’t get the opportunity to keep you from shooting +yourself in the foot. + + When you are unsure whether Magit did commit a change to the wip +refs, then you can explicitly request that all changes to all tracked +files are being committed. + +‘M-x magit-wip-commit’ + This command commits all changes to all tracked files to the index + and working tree work-in-progress refs. Like the modes described + above, it does not commit untracked files, but it does check all + tracked files for changes. Use this command when you suspect that + the modes might have overlooked a change made outside Emacs/Magit. + + -- User Option: magit-wip-namespace + The namespace used for work-in-progress refs. It has to end with a + slash. The wip refs are named ‘index/’ and + ‘wtree/’. When snapshots are created while + the ‘HEAD’ is detached then ‘HEAD’ is used in place of + ‘’. + + -- User Option: magit-wip-mode-lighter + Mode-line lighter for ‘magit-wip--mode’. + +* Menu: + +* Wip Graph:: +* Legacy Wip Modes:: + + +File: magit.info, Node: Wip Graph, Next: Legacy Wip Modes, Up: Wip Modes + +8.8.1 Wip Graph +--------------- + + -- User Option: magit-wip-merge-branch + This option controls whether the current branch is merged into the + wip refs after a new commit was created on the branch. + + If non-nil and the current branch has new commits, then it is + merged into the wip ref before creating a new wip commit. This + makes it easier to inspect wip history and the wip commits are + never garbage collected. + + If nil and the current branch has new commits, then the wip ref is + reset to the tip of the branch before creating a new wip commit. + With this setting wip commits are eventually garbage collected. + + When ‘magit-wip-merge-branch’ is ‘t’, then the history looks like +this: + + *--*--*--*--*--* refs/wip/index/refs/heads/master + / / / + A-----B-----C refs/heads/master + + When ‘magit-wip-merge-branch’ is ‘nil’, then creating a commit on the +real branch and then making a change causes the wip refs to be recreated +to fork from the new commit. But the old commits on the wip refs are +not lost. They are still available from the reflog. To make it easier +to see when the fork point of a wip ref was changed, an additional +commit with the message "restart autosaving" is created on it (‘xxO’ +commits below are such boundary commits). + + Starting with + + BI0---BI1 refs/wip/index/refs/heads/master + / + A---B refs/heads/master + \ + BW0---BW1 refs/wip/wtree/refs/heads/master + + and committing the staged changes and editing and saving a file would +result in + + BI0---BI1 refs/wip/index/refs/heads/master + / + A---B---C refs/heads/master + \ \ + \ CW0---CW1 refs/wip/wtree/refs/heads/master + \ + BW0---BW1 refs/wip/wtree/refs/heads/master@{2} + + The fork-point of the index wip ref is not changed until some change +is being staged. Likewise just checking out a branch or creating a +commit does not change the fork-point of the working tree wip ref. The +fork-points are not adjusted until there actually is a change that +should be committed to the respective wip ref. + + +File: magit.info, Node: Legacy Wip Modes, Prev: Wip Graph, Up: Wip Modes + +8.8.2 Legacy Wip Modes +---------------------- + +It is recommended that you use the mode ‘magit-wip-mode’ (which see) and +ignore the existence of the following modes, which are preserved for +historic reasons. + + Setting the following variables directly does not take effect; either +use the Custom interface to do so or call the respective mode functions. + + -- User Option: magit-wip-after-save-mode + When this mode is enabled, then saving a buffer that visits a file + tracked in a Git repository causes its current state to be + committed to the working tree wip ref for the current branch. + + -- User Option: magit-wip-after-apply-mode + When this mode is enabled, then applying (i.e. staging, unstaging, + discarding, reversing, and regularly applying) a change to a file + tracked in a Git repository causes its current state to be + committed to the index and/or working tree wip refs for the current + branch. + + If you only ever edit files using Emacs and only ever interact with +Git using Magit, then the above two modes should be enough to protect +each and every change from accidental loss. In practice nobody does +that. Two additional modes exists that do commit to the wip refs before +making changes that could cause the loss of earlier changes. + + -- User Option: magit-wip-before-change-mode + When this mode is enabled, then certain commands commit the + existing changes to the files they are about to make changes to. + + -- User Option: magit-wip-initial-backup-mode + When this mode is enabled, then the current version of a file is + committed to the worktree wip ref before the buffer visiting that + file is saved for the first time since the buffer was created. + + This backs up the same version of the file that ‘backup-buffer’ + would save. While ‘backup-buffer’ uses a backup file, this mode + uses the same worktree wip ref as used by the other Magit Wip + modes. Like ‘backup-buffer’, it only does this once; unless you + kill the buffer and visit the file again only one backup will be + created per Emacs session. + + This mode ignores the variables that affect ‘backup-buffer’ and can + be used along-side that function, which is recommended because it + only backs up files that are tracked in a Git repository. + + -- User Option: magit-wip-after-save-local-mode-lighter + Mode-line lighter for ‘magit-wip-after-save-local-mode’. + + -- User Option: magit-wip-after-apply-mode-lighter + Mode-line lighter for ‘magit-wip-after-apply-mode’. + + -- User Option: magit-wip-before-change-mode-lighter + Mode-line lighter for ‘magit-wip-before-change-mode’. + + -- User Option: magit-wip-initial-backup-mode-lighter + Mode-line lighter for ‘magit-wip-initial-backup-mode’. + + +File: magit.info, Node: Commands for Buffers Visiting Files, Next: Minor Mode for Buffers Visiting Blobs, Prev: Wip Modes, Up: Miscellaneous + +8.9 Commands for Buffers Visiting Files +======================================= + +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 *note Default +Bindings:: and *note (elisp)Key Binding Conventions::. + + If you want a better binding, you have to add it yourself: + + (global-set-key (kbd "C-c g") 'magit-file-dispatch) + + The key bindings shown below assume that you have not improved the +binding for ‘magit-file-dispatch’. + +‘C-c M-g’ (‘magit-file-dispatch’) + 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’. + +‘C-c M-g s’ (‘magit-stage-file’) + Stage all changes to the file being visited in the current buffer. + +‘C-c M-g u’ (‘magit-unstage-file’) + Unstage all changes to the file being visited in the current + buffer. + +‘C-c M-g c’ (‘magit-commit’) + This transient prefix command binds the following suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. See *note Initiating a + Commit::. + +‘C-c M-g D’ (‘magit-diff’) + This transient prefix command binds several diff suffix commands + and infix arguments and displays them in a temporary buffer until a + suffix is invoked. See *note Diffing::. + + This is the same command that ‘d’ is bound to in Magit buffers. If + this command is invoked from a file-visiting buffer, then the + initial value of the option (‘--’) that limits the diff to certain + file(s) is set to the visited file. + +‘C-c M-g d’ (‘magit-diff-buffer-file’) + This command shows the diff for the file of blob that the current + buffer visits. + + -- User Option: magit-diff-buffer-file-locked + This option controls whether ‘magit-diff-buffer-file’ uses a + dedicated buffer. See *note Modes and Buffers::. + +‘C-c M-g L’ (‘magit-log’) + This transient prefix command binds several log suffix commands and + infix arguments and displays them in a temporary buffer until a + suffix is invoked. See *note Logging::. + + This is the same command that ‘l’ is bound to in Magit buffers. If + this command is invoked from a file-visiting buffer, then the + initial value of the option (‘--’) that limits the log to certain + file(s) is set to the visited file. + +‘C-c M-g l’ (‘magit-log-buffer-file’) + This command shows the log for the file of blob that the current + buffer visits. Renames are followed when a prefix argument is used + or when ‘--follow’ is an active log argument. When the region is + active, the log is restricted to the selected line range. + +‘C-c M-g t’ (‘magit-log-trace-definition’) + This command shows the log for the definition at point. + + -- User Option: magit-log-buffer-file-locked + This option controls whether ‘magit-log-buffer-file’ uses a + dedicated buffer. See *note Modes and Buffers::. + +‘C-c M-g B’ (‘magit-blame’) + This transient prefix command binds all blaming suffix commands + along with the appropriate infix arguments and displays them in a + temporary buffer until a suffix is invoked. + + For more information about this and the following commands also see + *note Blaming::. + + In addition to the ‘magit-blame’ sub-transient, the dispatch +transient also binds several blaming suffix commands directly. See +*note Blaming:: for information about those commands and bindings. + +‘C-c M-g e’ (‘magit-edit-line-commit’) + This command makes the commit editable that added the current line. + + With a prefix argument it makes the commit editable that removes + the line, if any. The commit is determined using ‘git blame’ and + made editable using ‘git rebase --interactive’ if it is reachable + from ‘HEAD’, or by checking out the commit (or a branch that points + at it) otherwise. + +‘C-c M-g p’ (‘magit-blob-previous’) + Visit the previous blob which modified the current file. + + There are a few additional commands that operate on a single file but +are not enabled in the file transient command by default: + + -- Command: magit-file-rename + This command renames a file read from the user. + + -- Command: magit-file-delete + This command deletes a file read from the user. + + -- Command: magit-file-untrack + This command untracks a file read from the user. + + -- Command: magit-file-checkout + This command updates a file in the working tree and index to the + contents from a revision. Both the revision and file are read from + the user. + + To enable them invoke the transient (‘C-c M-g’), enter "edit mode" +(‘C-x l’), set the "transient level" (‘C-x l’ again), enter ‘5’, and +leave edit mode (‘C-g’). Also see *note (transient)Enabling and +Disabling Suffixes::. + + +File: magit.info, Node: Minor Mode for Buffers Visiting Blobs, Prev: Commands for Buffers Visiting Files, Up: Miscellaneous + +8.10 Minor Mode for Buffers Visiting Blobs +========================================== + +The ‘magit-blob-mode’ enables certain Magit features in blob-visiting +buffers. Such buffers can be created using ‘magit-find-file’ and some +of the commands mentioned below, which also take care of turning on this +minor mode. Currently this mode only establishes a few key bindings, +but this might be extended. + +‘p’ (‘magit-blob-previous’) + Visit the previous blob which modified the current file. + +‘n’ (‘magit-blob-next’) + Visit the next blob which modified the current file. + +‘q’ (‘magit-kill-this-buffer’) + Kill the current buffer. + + +File: magit.info, Node: Customizing, Next: Plumbing, Prev: Miscellaneous, Up: Top + +9 Customizing +************* + +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 it +using both Git variables as well as Emacs options. However this +flexibility doesn’t come without problems, including but not limited to +the following. + + • Some Git variables automatically have an effect in Magit without + requiring any explicit support. Sometimes that is desirable - in + other cases, it breaks Magit. + + When a certain Git setting breaks Magit but you want to keep using + that setting on the command line, then that can be accomplished by + overriding the value for Magit only by appending something like + ‘("-c" "some.variable=compatible-value")’ to + ‘magit-git-global-arguments’. + + • Certain settings like ‘fetch.prune=true’ are respected by Magit + commands (because they simply call the respective Git command) but + their value is not reflected in the respective transient buffers. + In this case the ‘--prune’ argument in ‘magit-fetch’ might be + active or inactive, but that doesn’t keep the Git variable from + being honored by the suffix commands anyway. So pruning might + happen despite the ‘--prune’ arguments being displayed in a way + that seems to indicate that no pruning will happen. + + I intend to address these and similar issues in a future release. + +* Menu: + +* Per-Repository Configuration:: +* Essential Settings:: + + +File: magit.info, Node: Per-Repository Configuration, Next: Essential Settings, Up: Customizing + +9.1 Per-Repository Configuration +================================ + +Magit can be configured on a per-repository level using both Git +variables as well as Emacs options. + + To set a Git variable for one repository only, simply set it in +‘/path/to/repo/.git/config’ instead of ‘$HOME/.gitconfig’ or +‘/etc/gitconfig’. See *note (gitman)git-config::. + + Similarly, Emacs options can be set for one repository only by +editing ‘/path/to/repo/.dir-locals.el’. See *note (emacs)Directory +Variables::. For example to disable automatic refreshes of +file-visiting buffers in just one huge repository use this: + + • ‘/path/to/huge/repo/.dir-locals.el’ + + ((nil . ((magit-refresh-buffers . nil)))) + + It might only be costly to insert certain information into Magit +buffers for repositories that are exceptionally large, in which case you +can disable the respective section inserters just for that repository: + + • ‘/path/to/tag/invested/repo/.dir-locals.el’ + + ((magit-status-mode + . ((eval . (magit-disable-section-inserter 'magit-insert-tags-header))))) + + -- Function: magit-disable-section-inserter fn + This function disables the section inserter FN in the current + repository. It is only intended for use in ‘.dir-locals.el’ and + ‘.dir-locals-2.el’. + + If you want to apply the same settings to several, but not all, +repositories then keeping the repository-local config files in sync +would quickly become annoying. To avoid that you can create config +files for certain classes of repositories (e.g. "huge repositories") +and then include those files in the per-repository config files. For +example: + + • ‘/path/to/huge/repo/.git/config’ + + [include] + path = /path/to/huge-gitconfig + + • ‘/path/to/huge-gitconfig’ + + [status] + showUntrackedFiles = no + + • ‘$HOME/.emacs.d/init.el’ + + (dir-locals-set-class-variables 'huge-git-repository + '((nil . ((magit-refresh-buffers . nil))))) + + (dir-locals-set-directory-class + "/path/to/huge/repo/" 'huge-git-repository) + + +File: magit.info, Node: Essential Settings, Prev: Per-Repository Configuration, Up: Customizing + +9.2 Essential Settings +====================== + +The next two sections list and discuss several variables that many users +might want to customize, for safety and/or performance reasons. + +* Menu: + +* Safety:: +* Performance:: +* Default Bindings:: + + +File: magit.info, Node: Safety, Next: Performance, Up: Essential Settings + +9.2.1 Safety +------------ + +This section discusses various variables that you might want to change +(or *not* change) for safety reasons. + + Git keeps *committed* changes around long enough for users to recover +changes they have accidentally been deleted. It does not do the same +for *uncommitted* changes in the working tree and not even the index +(the staging area). Because Magit makes it so easy to modify +uncommitted changes, it also makes it easy to shoot yourself in the foot +in the process. For that reason Magit provides three global modes that +save *tracked* files to work-in-progress references after or before +certain actions. See *note Wip Modes::. + + These modes are not enabled by default because of performance +concerns. Instead a lot of potentially destructive commands require +confirmation every time they are used. In many cases this can be +disabled by adding a symbol to ‘magit-no-confirm’ (see *note Completion +and Confirmation::). If you enable the various wip modes then you +should add ‘safe-with-wip’ to this list. + + Similarly it isn’t necessary to require confirmation before moving a +file to the system trash - if you trashed a file by mistake then you can +recover it from there. Option ‘magit-delete-by-moving-to-trash’ +controls whether the system trash is used, which is the case by default. +Nevertheless, ‘trash’ isn’t a member of ‘magit-no-confirm’ - you might +want to change that. + + By default buffers visiting files are automatically reverted when the +visited file changes on disk. This isn’t as risky as it might seem, but +to make an informed decision you should see *note Risk of Reverting +Automatically::. + + +File: magit.info, Node: Performance, Next: Default Bindings, Prev: Safety, Up: Essential Settings + +9.2.2 Performance +----------------- + +After Magit has run ‘git’ for side-effects, it also refreshes the +current Magit buffer and the respective status buffer. This is +necessary because otherwise outdated information might be displayed +without the user noticing. Magit buffers are updated by recreating +their content from scratch, which makes updating simpler and less +error-prone, but also more costly. Keeping it simple and just +re-creating everything from scratch is an old design decision and +departing from that will require major refactoring. + + I plan to do that in time for the next major release. I also intend +to create logs and diffs asynchronously, which should also help a lot +but also requires major refactoring. + + Meanwhile you can tell Magit to only automatically refresh the +current Magit buffer, but not the status buffer. If you do that, then +the status buffer is only refreshed automatically if it is the current +buffer. + + (setq magit-refresh-status-buffer nil) + + You should also check whether any third-party packages have added +anything to ‘magit-refresh-buffer-hook’, ‘magit-status-refresh-hook’, +‘magit-pre-refresh-hook’, and ‘magit-post-refresh-hook’. If so, then +check whether those additions impact performance significantly. + + Magit can be told to refresh buffers verbosely using ‘M-x +magit-toggle-verbose-refresh’. Enabling this helps figuring out which +sections are bottlenecks. The additional output can be found in the +‘*Messages*’ buffer. + + Magit also reverts buffers for visited files located inside the +current repository when the visited file changes on disk. That is +implemented on top of ‘auto-revert-mode’ from the built-in library +‘autorevert’. To figure out whether that impacts performance, check +whether performance is significantly worse, when many buffers exist +and/or when some buffers visit files using TRAMP. If so, then this +should help. + + (setq auto-revert-buffer-list-filter + 'magit-auto-revert-repository-buffer-p) + + For alternative approaches see *note Automatic Reverting of +File-Visiting Buffers::. + + If you have enabled any features that are disabled by default, then +you should check whether they impact performance significantly. It’s +likely that they were not enabled by default because it is known that +they reduce performance at least in large repositories. + + If performance is only slow inside certain unusually large +repositories, then you might want to disable certain features on a +per-repository or per-repository-class basis only. See *note +Per-Repository Configuration::. For example it takes a long time to +determine the next and current tag in repository with exceptional +numbers of tags. It would therefore be a good idea to disable +‘magit-insert-tags-headers’, as explained at the mentioned node. + +* Menu: + +* Microsoft Windows Performance:: +* MacOS Performance:: + +Log Performance +............... + +When showing logs, Magit limits the number of commits initially shown in +the hope that this avoids unnecessary work. When using ‘--graph’ is +used, then this unfortunately does not have the desired effect for large +histories. Junio, Git’s maintainer, said on the git mailing list +(): "‘--graph’ wants to +compute the whole history and the max-count only affects the output +phase after ‘--graph’ does its computation". + + In other words, it’s not that Git is slow at outputting the +differences, or that Magit is slow at parsing the output - the problem +is that Git first goes outside and has a smoke. + + We actually work around this issue by limiting the number of commits +not only by using ‘-’ but by also using a range. But unfortunately +that’s not always possible. + + When more than a few thousand commits are shown, then the use of +‘--graph’ can slow things down. + + Using ‘--color --graph’ is even slower. Magit uses code that is part +of Emacs to turn control characters into faces. That code is pretty +slow and this is quite noticeable when showing a log with many branches +and merges. For that reason ‘--color’ is not enabled by default +anymore. Consider leaving it at that. + +Diff Performance +................ + +If diffs are slow, then consider turning off some optional diff features +by setting all or some of the following variables to ‘nil’: +‘magit-diff-highlight-indentation’, ‘magit-diff-highlight-trailing’, +‘magit-diff-paint-whitespace’, ‘magit-diff-highlight-hunk-body’, and +‘magit-diff-refine-hunk’. + + When showing a commit instead of some arbitrary diff, then some +additional information is displayed. Calculating this information can +be quite expensive given certain circumstances. If looking at a commit +using ‘magit-revision-mode’ takes considerably more time than looking at +the same commit in ‘magit-diff-mode’, then consider setting +‘magit-revision-insert-related-refs’ to ‘nil’. + + When you are often confronted with diffs that contain deleted files, +then you might want to enable the ‘--irreversible-delete’ argument. If +you do that then diffs still show that a file was deleted but without +also showing the complete deleted content of the file. This argument is +not available by default, see *note (transient)Enabling and Disabling +Suffixes::. Once you have done that you should enable it and save that +setting, see *note (transient)Saving Values::. You should do this in +both the diff (‘d’) and the diff refresh (‘D’) transient popups. + +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 +address that is to display fewer refs, obviously. + + If you are not, or only mildly, interested in seeing the list of +tags, then start by not displaying them: + + (remove-hook 'magit-refs-sections-hook 'magit-insert-tags) + + Then you should also make sure that the listed remote branches +actually all exist. You can do so by pruning branches which no longer +exist using ‘f-pa’. + +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 can +take a long time, which is especially distracting when you are +committing large amounts of generated data which you don’t actually +intend to inspect before committing. This behavior can be turned off +using: + + (remove-hook 'server-switch-hook 'magit-commit-diff) + + Then you can type ‘C-c C-d’ to show the diff when you actually want +to see it, but only then. Alternatively you can leave the hook alone +and just type ‘C-g’ in those cases when it takes too long to generate +the diff. If you do that, then you will end up with a broken diff +buffer, but doing it this way has the advantage that you usually get to +see the diff, which is useful because it increases the odds that you +spot potential issues. + + +File: magit.info, Node: Microsoft Windows Performance, Next: MacOS Performance, Up: Performance + +Microsoft Windows Performance +............................. + +In order to update the status buffer, ‘git’ has to be run a few dozen +times. That is problematic on Microsoft Windows, because that operating +system is exceptionally slow at starting processes. Sadly this is an +issue that can only be fixed by Microsoft itself, and they don’t appear +to be particularly interested in doing so. + + Beside the subprocess issue, there are also other Windows-specific +performance issues. Some of these have workarounds. The maintainers of +"Git for Windows" try to improve performance on Windows. Always use the +latest release in order to benefit from the latest performance tweaks. +Magit too tries to work around some Windows-specific issues. + + According to some sources, setting the following Git variables can +also help. + + git config --global core.preloadindex true # default since v2.1 + git config --global core.fscache true # default since v2.8 + git config --global gc.auto 256 + + You should also check whether an anti-virus program is affecting +performance. + + +File: magit.info, Node: MacOS Performance, Prev: Microsoft Windows Performance, Up: Performance + +MacOS Performance +................. + +Before Emacs 26.1 child processes were created using ‘fork’ on macOS. +That needlessly copied GUI resources, which is expensive. The result +was that forking took about 30 times as long on Darwin than on Linux, +and because Magit starts many ‘git’ processes that made quite a +difference. + + So make sure that you are using at least Emacs 26.1, in which case +the faster ‘vfork’ will be used. (The creation of child processes still +takes about twice as long on Darwin compared to Linux.) See (1) for +more information. + + ---------- Footnotes ---------- + + (1) + + + +File: magit.info, Node: Default Bindings, Prev: Performance, Up: Essential Settings + +9.2.3 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. + + (global-set-key (kbd "C-c g") 'magit-file-dispatch) + + Also see *note Commands for Buffers Visiting Files:: and *note + (elisp)Key Binding Conventions::. + + +File: magit.info, Node: Plumbing, Next: FAQ, Prev: Customizing, Up: Top + +10 Plumbing +*********** + +The following sections describe how to use several of Magit’s core +abstractions to extend Magit itself or implement a separate extension. + + A few of the low-level features used by Magit have been factored out +into separate libraries/packages, so that they can be used by other +packages, without having to depend on Magit. See *note +(with-editor)Top:: for information about ‘with-editor’. ‘transient’ +doesn’t have a manual yet. + + If you are trying to find an unused key that you can bind to a +command provided by your own Magit extension, then checkout +. + +* Menu: + +* Calling Git:: +* Section Plumbing:: +* Refreshing Buffers:: +* Conventions:: + + +File: magit.info, Node: Calling Git, Next: Section Plumbing, Up: Plumbing + +10.1 Calling Git +================ + +Magit provides many specialized functions for calling Git. All of these +functions are defined in either ‘magit-git.el’ or ‘magit-process.el’ and +have one of the prefixes ‘magit-run-’, ‘magit-call-’, ‘magit-start-’, or +‘magit-git-’ (which is also used for other things). + + All of these functions accept an indefinite number of arguments, +which are strings that specify command line arguments for Git (or in +some cases an arbitrary executable). These arguments are flattened +before being passed on to the executable; so instead of strings they can +also be lists of strings and arguments that are ‘nil’ are silently +dropped. Some of these functions also require a single mandatory +argument before these command line arguments. + + Roughly speaking, these functions run Git either to get some value or +for side-effects. The functions that return a value are useful to +collect the information necessary to populate a Magit buffer, while the +others are used to implement Magit commands. + + The functions in the value-only group always run synchronously, and +they never trigger a refresh. The function in the side-effect group can +be further divided into subgroups depending on whether they run Git +synchronously or asynchronously, and depending on whether they trigger a +refresh when the executable has finished. + +* Menu: + +* Getting a Value from Git:: +* Calling Git for Effect:: + + +File: magit.info, Node: Getting a Value from Git, Next: Calling Git for Effect, Up: Calling Git + +10.1.1 Getting a Value from Git +------------------------------- + +These functions run Git in order to get a value, an exit status, or +output. Of course you could also use them to run Git commands that have +side-effects, but that should be avoided. + + -- Function: magit-git-exit-code &rest args + Executes git with ARGS and returns its exit code. + + -- Function: magit-git-success &rest args + Executes git with ARGS and returns ‘t’ if the exit code is ‘0’, + ‘nil’ otherwise. + + -- Function: magit-git-failure &rest args + Executes git with ARGS and returns ‘t’ if the exit code is ‘1’, + ‘nil’ otherwise. + + -- Function: magit-git-true &rest args + Executes git with ARGS and returns ‘t’ if the first line printed by + git is the string "true", ‘nil’ otherwise. + + -- Function: magit-git-false &rest args + Executes git with ARGS and returns ‘t’ if the first line printed by + git is the string "false", ‘nil’ otherwise. + + -- Function: magit-git-insert &rest args + Executes git with ARGS and inserts its output at point. + + -- Function: magit-git-string &rest args + Executes git with ARGS and returns the first line of its output. + If there is no output or if it begins with a newline character, + then this returns ‘nil’. + + -- Function: magit-git-lines &rest args + Executes git with ARGS and returns its output as a list of lines. + Empty lines anywhere in the output are omitted. + + -- Function: magit-git-items &rest args + Executes git with ARGS and returns its null-separated output as a + list. Empty items anywhere in the output are omitted. + + If the value of option ‘magit-git-debug’ is non-nil and git exits + with a non-zero exit status, then warn about that in the echo area + and 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 they occur we +need to be able to debug them. + + -- User Option: magit-git-debug + Whether to report errors that occur when using ‘magit-git-insert’, + ‘magit-git-string’, ‘magit-git-lines’, or ‘magit-git-items’. This + does not actually raise an error. Instead a message is shown in + the echo area, and git’s standard error is insert into a new + section in the current repository’s process buffer. + + -- Function: magit-git-str &rest args + This is a variant of ‘magit-git-string’ that ignores the option + ‘magit-git-debug’. It is mainly intended to be used while handling + errors in functions that do respect that option. Using such a + function while handing an error could cause yet another error and + therefore lead to an infinite recursion. You probably won’t ever + need to use this function. + + +File: magit.info, Node: Calling Git for Effect, Prev: Getting a Value from Git, Up: Calling Git + +10.1.2 Calling Git for Effect +----------------------------- + +These functions are used to run git to produce some effect. Most Magit +commands that actually run git do so by using such a function. + + Because we do not need to consume git’s output when using these +functions, their output is instead logged into a per-repository buffer, +which can be shown using ‘$’ from a Magit buffer or ‘M-x magit-process’ +elsewhere. + + These functions can have an effect in two distinct ways. Firstly, +running git may change something, i.e. create or push a new commit. +Secondly, that change may require that Magit buffers are refreshed to +reflect the changed state of the repository. But refreshing isn’t +always desirable, so only some of these functions do perform such a +refresh after git has returned. + + Sometimes it is useful to run git asynchronously. For example, when +the user has just initiated a push, then there is no reason to make her +wait until that has completed. In other cases it makes sense to wait +for git to complete before letting the user do something else. For +example after staging a change it is useful to wait until after the +refresh because that also automatically moves to the next change. + + -- Function: magit-call-git &rest args + Calls git synchronously with ARGS. + + -- Function: magit-call-process program &rest args + Calls PROGRAM synchronously with ARGS. + + -- Function: magit-run-git &rest args + Calls git synchronously with ARGS and then refreshes. + + -- Function: magit-run-git-with-input &rest args + Calls git synchronously with ARGS and sends it the content of the + current buffer on standard input. + + 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 + Calls git synchronously with ARGS for side-effects only. This + function does not refresh the buffer. + + -- Function: magit-git-wash washer &rest args + Execute Git with ARGS, inserting washed output at point. Actually + first insert the raw output at point. If there is no output call + ‘magit-cancel-section’. Otherwise temporarily narrow the buffer to + the inserted text, move to its beginning, and then call function + WASHER with ARGS as its sole argument. + + And now for the asynchronous variants. + + -- Function: magit-run-git-async &rest args + Start Git, prepare for refresh, and return the process object. + ARGS is flattened and then used as arguments to Git. + + Display the command line arguments in the echo area. + + After Git returns some buffers are refreshed: the buffer that was + current when this function was called (if it is a Magit buffer and + still alive), as well as the respective Magit status buffer. + Unmodified buffers visiting files that are tracked in the current + repository are reverted if ‘magit-revert-buffers’ is non-nil. + + -- Function: magit-run-git-with-editor &rest args + Export GIT_EDITOR and start Git. Also prepare for refresh and + return the process object. ARGS is flattened and then used as + arguments to Git. + + Display the command line arguments in the echo area. + + After Git returns some buffers are refreshed: the buffer that was + 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 input &rest args + Start Git, prepare for refresh, and return the process object. + + If INPUT is non-nil, it has to be a buffer or the name of an + existing buffer. The buffer content becomes the processes standard + input. + + Option ‘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. + + After Git returns, some buffers are refreshed: the buffer that was + current when this function was called (if it is a Magit buffer and + still alive), as well as the respective Magit status buffer. + Unmodified buffers visiting files that are tracked in the current + repository are reverted if ‘magit-revert-buffers’ is non-nil. + + -- Function: magit-start-process &rest args + Start PROGRAM, prepare for refresh, and return the process object. + + If optional argument INPUT is non-nil, it has to be a buffer or the + name of an existing buffer. The buffer content becomes the + processes standard input. + + The process is started using ‘start-file-process’ and then setup to + use the sentinel ‘magit-process-sentinel’ and the filter + ‘magit-process-filter’. Information required by these functions is + stored in the process object. When this function returns the + process has not started to run yet so it is possible to override + the sentinel and filter. + + After the process returns, ‘magit-process-sentinel’ refreshes the + buffer that was current when ‘magit-start-process’ was called (if + it is a Magit buffer and still alive), as well as the respective + Magit status buffer. Unmodified buffers visiting files that are + tracked in the current repository are reverted if + ‘magit-revert-buffers’ is non-nil. + + -- Variable: magit-this-process + The child process which is about to start. This can be used to + change the filter and sentinel. + + -- Variable: magit-process-raise-error + When this is non-nil, then ‘magit-process-sentinel’ raises an error + if git exits with a non-zero exit status. For debugging purposes. + + +File: magit.info, Node: Section Plumbing, Next: Refreshing Buffers, Prev: Calling Git, Up: Plumbing + +10.2 Section Plumbing +===================== + +* Menu: + +* Creating Sections:: +* Section Selection:: +* Matching Sections:: + + +File: magit.info, Node: Creating Sections, Next: Section Selection, Up: Section Plumbing + +10.2.1 Creating Sections +------------------------ + + -- Macro: magit-insert-section &rest args + 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. Also if + a variable ‘magit-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. + + Optional VALUE is the value of the section, usually a string that + is required when acting on the section. + + When optional HIDE is non-nil collapse the section body by default, + i.e. when first creating the section, but not when refreshing the + buffer. Otherwise, expand it by default. This can be overwritten + using ‘magit-section-set-visibility-hook’. When a section is + recreated during a refresh, then the visibility of predecessor is + inherited and HIDE is ignored (but the hook is still honored). + + BODY is any number of forms that actually insert the section’s + heading and body. Optional NAME, if specified, has to be a symbol, + which is then bound to the struct of the section being inserted. + + Before BODY is evaluated the ‘start’ of the section object is set + to the value of ‘point’ and after BODY was evaluated its ‘end’ is + set to the new value of ‘point’; BODY is responsible for moving + ‘point’ forward. + + If it turns out inside BODY that the section is empty, then + ‘magit-cancel-section’ can be used to abort and remove all traces + 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. + + -- Function: magit-insert-heading &rest args + Insert the heading for the section currently being inserted. + + This function should only be used inside ‘magit-insert-section’. + + When called without any arguments, then just set the ‘content’ slot + of the object representing the section being inserted to a marker + at ‘point’. The section should only contain a single line when + this function is used like this. + + When called with arguments ARGS, which have to be strings, then + insert those strings at point. The section should not contain any + text before this happens and afterwards it should again only + contain a single line. If the ‘face’ property is set anywhere + inside any of these strings, then insert all of them unchanged. + Otherwise use the ‘magit-section-heading’ face for all inserted + text. + + The ‘content’ property of the section struct is the end of the + heading (which lasts from ‘start’ to ‘content’) and the beginning + of the body (which lasts from ‘content’ to ‘end’). If the value of + ‘content’ is nil, then the section has no heading and its body + cannot be collapsed. If a section does have a heading then its + height must be exactly one line, including a trailing newline + character. This isn’t enforced; you are responsible for getting it + right. The only exception is that this function does insert a + newline character if necessary. + + -- Function: magit-cancel-section + Cancel the section currently being inserted. This exits the + innermost call to ‘magit-insert-section’ and removes all traces of + what has already happened inside that call. + + -- Function: magit-define-section-jumper sym title &optional value + Define an interactive function to go to section SYM. TITLE is the + displayed title of the section. + + +File: magit.info, Node: Section Selection, Next: Matching Sections, Prev: Creating Sections, Up: Section Plumbing + +10.2.2 Section Selection +------------------------ + + -- Function: magit-current-section + Return the section at point. + + -- Function: magit-region-sections &optional condition multiple + Return a list of the selected sections. + + When the region is active and constitutes a valid section + selection, then return a list of all selected sections. This is + the case when the region begins in the heading of a section and + ends in the heading of the same section or in that of a sibling + section. If optional MULTIPLE is non-nil, then the region cannot + begin and end in the same section. + + When the selection is not valid, then return nil. In this case, + most commands that can act on the selected sections will instead + act on the section at point. + + When the region looks like it would in any other buffer then the + selection is invalid. When the selection is valid then the region + uses the ‘magit-section-highlight’ face. This does not apply to + diffs where things get a bit more complicated, but even here if the + region looks like it usually does, then that’s not a valid + selection as far as this function is concerned. + + If optional CONDITION is non-nil, then the selection not only has + to be valid; all selected sections additionally have to match + CONDITION, or nil is returned. See ‘magit-section-match’ for the + forms CONDITION can take. + + -- Function: magit-region-values &optional condition multiple + Return a list of the values of the selected sections. + + Return the values that themselves would be returned by + ‘magit-region-sections’ (which see). + + +File: magit.info, Node: Matching Sections, Prev: Section Selection, Up: Section Plumbing + +10.2.3 Matching Sections +------------------------ + +‘M-x magit-describe-section-briefly’ + Show information about the section at point. This command is + intended for debugging purposes. + + -- Function: magit-section-ident section + Return an unique identifier for SECTION. The return value has the + form ‘((TYPE . VALUE)...)’. + + -- Function: magit-get-section ident &optional root + Return the section identified by IDENT. IDENT has to be a list as + returned by ‘magit-section-ident’. + + -- Function: magit-section-match condition &optional section + Return ‘t’ if SECTION matches CONDITION. SECTION defaults to the + section at point. If SECTION is not specified and there also is no + section at point, then return ‘nil’. + + CONDITION can take the following forms: + • ‘(CONDITION...)’ + + matches if any of the CONDITIONs matches. + + • ‘[CLASS...]’ + + matches if the section’s class is the same as the first CLASS + or a subclass of that; the section’s parent class matches the + second CLASS; and so on. + + • ‘[* CLASS...]’ + + matches sections that match ‘[CLASS...]’ and also recursively + all their child sections. + + • ‘CLASS’ + + matches if the section’s class is the same as CLASS or a + subclass of that; regardless of the classes of the parent + sections. + + Each CLASS should be a class symbol, identifying a class that + derives from ‘magit-section’. For backward compatibility CLASS can + also be a "type symbol". A section matches such a symbol if the + value of its ‘type’ slot is ‘eq’. If a type symbol has an entry in + ‘magit--section-type-alist’, then a section also matches that type + if its class is a subclass of the class that corresponds to the + type as per that alist. + + Note that it is not necessary to specify the complete section + lineage as printed by ‘magit-describe-section-briefly’, unless of + course you want to be that precise. + + -- Function: magit-section-value-if condition &optional section + If the section at point matches CONDITION, then return its value. + + If optional SECTION is non-nil then test whether that matches + instead. If there is no section at point and SECTION is nil, then + return nil. If the section does not match, then return nil. + + See ‘magit-section-match’ for the forms CONDITION can take. + + -- Function: magit-section-case &rest clauses + Choose among clauses on the type of the section at point. + + Each clause looks like (CONDITION BODY...). The type of the + section is compared against each CONDITION; the BODY forms of the + first match are evaluated sequentially and the value of the last + form is returned. Inside BODY the symbol ‘it’ is bound to the + section at point. If no clause succeeds or if there is no section + at point return nil. + + See ‘magit-section-match’ for the forms CONDITION can take. + Additionally a CONDITION of t is allowed in the final clause and + matches if no other CONDITION match, even if there is no section at + point. + + -- Variable: magit-root-section + The root section in the current buffer. All other sections are + descendants of this section. The value of this variable is set by + ‘magit-insert-section’ and you should never modify it. + + For diff related sections a few additional tools exist. + + -- Function: magit-diff-type &optional section + Return the diff type of SECTION. + + The returned type is one of the symbols ‘staged’, ‘unstaged’, + ‘committed’, or ‘undefined’. This type serves a similar purpose as + the general type common to all sections (which is stored in the + ‘type’ slot of the corresponding ‘magit-section’ struct) but takes + additional information into account. When the SECTION isn’t + related to diffs and the buffer containing it also isn’t a + diff-only buffer, then return nil. + + Currently the type can also be one of ‘tracked’ and ‘untracked’, + but these values are not handled explicitly in every place they + should be. A possible fix could be to just return nil here. + + The section has to be a ‘diff’ or ‘hunk’ section, or a section + whose children are of type ‘diff’. If optional SECTION is nil, + return the diff type for the current section. In buffers whose + major mode is ‘magit-diff-mode’ SECTION is ignored and the type is + determined using other means. In ‘magit-revision-mode’ buffers the + type is always ‘committed’. + + -- Function: magit-diff-scope &optional section strict + Return the diff scope of SECTION or the selected section(s). + + A diff’s "scope" describes what part of a diff is selected, it is a + symbol, one of ‘region’, ‘hunk’, ‘hunks’, ‘file’, ‘files’, or + ‘list’. Do not confuse this with the diff "type", as returned by + ‘magit-diff-type’. + + If optional SECTION is non-nil, then return the scope of that, + ignoring the sections selected by the region. Otherwise return the + scope of the current section, or if the region is active and + selects a valid group of diff related sections, the type of these + sections, i.e. ‘hunks’ or ‘files’. If SECTION (or if the current + section that is nil) is a ‘hunk’ section and the region starts and + ends inside the body of a that section, then the type is ‘region’. + + If optional STRICT is non-nil then return nil if the diff type of + the section at point is ‘untracked’ or the section at point is not + actually a ‘diff’ but a ‘diffstat’ section. + + +File: magit.info, Node: Refreshing Buffers, Next: Conventions, Prev: Section Plumbing, Up: Plumbing + +10.3 Refreshing Buffers +======================= + +All commands that create a new Magit buffer or change what is being +displayed in an existing buffer do so by calling ‘magit-mode-setup’. +Among other things, that function sets the buffer local values of +‘default-directory’ (to the top-level of the repository), +‘magit-refresh-function’, and ‘magit-refresh-args’. + + Buffers are refreshed by calling the function that is the local value +of ‘magit-refresh-function’ (a function named ‘magit-*-refresh-buffer’, +where ‘*’ may be something like ‘diff’) with the value of +‘magit-refresh-args’ as arguments. + + -- Macro: magit-mode-setup buffer switch-func mode refresh-func + &optional refresh-args + This function displays and selects BUFFER, turns on MODE, and + refreshes a first time. + + This function displays and optionally selects BUFFER by calling + ‘magit-mode-display-buffer’ with BUFFER, MODE and SWITCH-FUNC as + arguments. Then it sets the local value of + ‘magit-refresh-function’ to REFRESH-FUNC and that of + ‘magit-refresh-args’ to REFRESH-ARGS. Finally it creates the + buffer content by calling REFRESH-FUNC with REFRESH-ARGS as + arguments. + + All arguments are evaluated before switching to BUFFER. + + -- Function: magit-mode-display-buffer buffer mode &optional + switch-function + This function display BUFFER in some window and select it. BUFFER + may be a buffer or a string, the name of a buffer. The buffer is + returned. + + Unless BUFFER is already displayed in the selected frame, store the + previous window configuration as a buffer local value, so that it + can later be restored by ‘magit-mode-bury-buffer’. + + The buffer is displayed and selected using SWITCH-FUNCTION. If + that is ‘nil’ then ‘pop-to-buffer’ is used if the current buffer’s + major mode derives from ‘magit-mode’. Otherwise ‘switch-to-buffer’ + is used. + + -- Variable: magit-refresh-function + The value of this buffer-local variable is the function used to + refresh the current buffer. It is called with ‘magit-refresh-args’ + as arguments. + + -- Variable: magit-refresh-args + The list of arguments used by ‘magit-refresh-function’ to refresh + the current buffer. ‘magit-refresh-function’ is called with these + arguments. + + The value is usually set using ‘magit-mode-setup’, but in some + cases it’s also useful to provide commands that can change the + value. For example, the ‘magit-diff-refresh’ transient can be used + to change any of the arguments used to display the diff, without + having to specify again which differences should be shown, but + ‘magit-diff-more-context’, ‘magit-diff-less-context’ and + ‘magit-diff-default-context’ change just the ‘-U’ argument. In + both case this is done by changing the value of this variable and + then calling this ‘magit-refresh-function’. + + +File: magit.info, Node: Conventions, Prev: Refreshing Buffers, Up: Plumbing + +10.4 Conventions +================ + +Also see *note Completion and Confirmation::. + +* Menu: + +* Theming Faces:: + + +File: magit.info, Node: Theming Faces, Up: Conventions + +10.4.1 Theming Faces +-------------------- + +The default theme uses blue for local branches, green for remote +branches, and goldenrod (brownish yellow) for tags. When creating a new +theme, you should probably follow that example. If your theme already +uses other colors, then stick to that. + + In older releases these reference faces used to have a background +color and a box around them. The basic default faces no longer do so, +to make Magit buffers much less noisy, and you should follow that +example at least with regards to boxes. (Boxes were used in the past to +work around a conflict between the highlighting overlay and text +property backgrounds. That’s no longer necessary because highlighting +no longer causes other background colors to disappear.) Alternatively +you can keep the background color and/or box, but then have to take +special care to adjust ‘magit-branch-current’ accordingly. By default +it looks mostly like ‘magit-branch-local’, but with a box (by default +the former is the only face that uses a box, exactly so that it sticks +out). If the former also uses a box, then you have to make sure that it +differs in some other way from the latter. + + The most difficult faces to theme are those related to diffs, +headings, highlighting, and the region. There are faces that fall into +all four groups - expect to spend some time getting this right. + + The ‘region’ face in the default theme, in both the light and dark +variants, as well as in many other themes, distributed with Emacs or by +third-parties, is very ugly. It is common to use a background color +that really sticks out, which is ugly but if that were the only problem +then it would be acceptable. Unfortunately many themes also set the +foreground color, which ensures that all text within the region is +readable. Without doing that there might be cases where some foreground +color is too close to the region background color to still be readable. +But it also means that text within the region loses all syntax +highlighting. + + I consider the work that went into getting the ‘region’ face right to +be a good indicator for the general quality of a theme. My +recommendation for the ‘region’ face is this: use a background color +slightly different from the background color of the ‘default’ face, and +do not set the foreground color at all. So for a light theme you might +use a light (possibly tinted) gray as the background color of ‘default’ +and a somewhat darker gray for the background of ‘region’. That should +usually be enough to not collide with the foreground color of any other +face. But if some other faces also set a light gray as background +color, then you should also make sure it doesn’t collide with those (in +some cases it might be acceptable though). + + Magit only uses the ‘region’ face when the region is "invalid" by its +own definition. In a Magit buffer the region is used to either select +multiple sibling sections, so that commands which support it act on all +of these sections instead of just the current section, or to select +lines within a single hunk section. In all other cases, the section is +considered invalid and Magit won’t act on it. But such invalid sections +happen, either because the user has not moved point enough yet to make +it valid or because she wants to use a non-magit command to act on the +region, e.g. ‘kill-region’. + + So using the regular ‘region’ face for invalid sections is a feature. +It tells the user that Magit won’t be able to act on it. It’s +acceptable if that face looks a bit odd and even (but less so) if it +collides with the background colors of section headings and other things +that have a background color. + + Magit highlights the current section. If a section has subsections, +then all of them are highlighted. This is done using faces that have +"highlight" in their names. For most sections, +‘magit-section-highlight’ is used for both the body and the heading. +Like the ‘region’ face, it should only set the background color to +something similar to that of ‘default’. The highlight background color +must be different from both the ‘region’ background color and the +‘default’ background color. + + For diff related sections Magit uses various faces to highlight +different parts of the selected section(s). Note that hunk headings, +unlike all other section headings, by default have a background color, +because it is useful to have very visible separators between hunks. +That face ‘magit-diff-hunk-heading’, should be different from both +‘magit-diff-hunk-heading-highlight’ and ‘magit-section-highlight’, as +well as from ‘magit-diff-context’ and ‘magit-diff-context-highlight’. +By default we do that by changing the foreground color. Changing the +background color would lead to complications, and there are already +enough we cannot get around. (Also note that it is generally a good +idea for section headings to always be bold, but only for sections that +have subsections). + + When there is a valid region selecting diff-related sibling sections, +i.e. multiple files or hunks, then the bodies of all these sections use +the respective highlight faces, but additionally the headings instead +use one of the faces ‘magit-diff-file-heading-selection’ or +‘magit-diff-hunk-heading-selection’. These faces have to be different +from the regular highlight variants to provide explicit visual +indication that the region is active. + + When theming diff related faces, start by setting the option +‘magit-diff-refine-hunk’ to ‘all’. You might personally prefer to only +refine the current hunk or not use hunk refinement at all, but some of +the users of your theme want all hunks to be refined, so you have to +cater to that. + + (Also turn on ‘magit-diff-highlight-indentation’, +‘magit-diff-highlight-trailing’, and ‘magit-diff-paint-whitespace’; and +insert some whitespace errors into the code you use for testing.) + + For added lines you have to adjust three faces: ‘magit-diff-added’, +‘magit-diff-added-highlight’, and ‘diff-refined-added’. Make sure that +the latter works well with both of the former, as well as ‘smerge-other’ +and ‘diff-added’. Then do the same for the removed lines, context +lines, lines added by us, and lines added by them. Also make sure the +respective added, removed, and context faces use approximately the same +saturation for both the highlighted and unhighlighted variants. Also +make sure the file and diff headings work nicely with context lines +(e.g. make them look different). Line faces should set both the +foreground and the background color. For example, for added lines use +two different greens. + + It’s best if the foreground color of both the highlighted and the +unhighlighted variants are the same, so you will need to have to find a +color that works well on the highlight and unhighlighted background, the +refine background, and the highlight context background. When there is +an hunk internal region, then the added- and removed-lines background +color is used only within that region. Outside the region the +highlighted context background color is used. This makes it easier to +see what is being staged. With an hunk internal region the hunk heading +is shown using ‘magit-diff-hunk-heading-selection’, and so are the thin +lines that are added around the lines that fall within the region. The +background color of that has to be distinct enough from the various +other involved background colors. + + Nobody said this would be easy. If your theme restricts itself to a +certain set of colors, then you should make an exception here. +Otherwise it would be impossible to make the diffs look good in each and +every variation. Actually you might want to just stick to the default +definitions for these faces. You have been warned. Also please note +that if you do not get this right, this will in some cases look to users +like bugs in Magit - so please do it right or not at all. + + +File: magit.info, Node: FAQ, Next: Debugging Tools, Prev: Plumbing, Up: Top + +Appendix A FAQ +************** + +The next two nodes lists frequently asked questions. For a list of +frequently *and recently* asked questions, i.e. questions that haven’t +made it into the manual yet, see +. + + Please also use the *note Debugging Tools::. + +* Menu: + +* FAQ - How to ...?:: +* FAQ - Issues and Errors:: + + +File: magit.info, Node: FAQ - How to ...?, Next: FAQ - Issues and Errors, Up: FAQ + +A.1 FAQ - How to ...? +===================== + +* 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 ediff-version-control-package?:: +* Should I disable VC?:: + + +File: magit.info, Node: How to pronounce Magit?, Next: How to show git's output?, Up: FAQ - How to ...? + +A.1.1 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 . Also see +. + + +File: magit.info, Node: How to show git's output?, Next: How to install the gitman info manual?, Prev: How to pronounce Magit?, Up: FAQ - How to ...? + +A.1.2 How to show git’s output? +------------------------------- + +To show the output of recently run git commands, press ‘$’ (or, if that +isn’t available, ‘M-x magit-process-buffer’). This will show a buffer +containing a section per git invocation; as always press ‘TAB’ to expand +or collapse them. + + By default, git’s output is only inserted into the process buffer if +it is run for side-effects. When the output is consumed in some way, +also inserting it into the process buffer would be too expensive. For +debugging purposes, it’s possible to do so anyway by setting +‘magit-git-debug’ to ‘t’. + + +File: magit.info, Node: How to install the gitman info manual?, Next: How to show diffs for gpg-encrypted files?, Prev: How to show git's output?, Up: FAQ - How to ...? + +A.1.3 How to install the gitman info manual? +-------------------------------------------- + +Git’s manpages can be exported as an info manual called ‘gitman’. +Magit’s own info manual links to nodes in that manual instead of the +actual manpages because Info doesn’t support linking to manpages. + + Unfortunately some distributions do not install the ‘gitman’ manual +by default and you will have to install a separate documentation package +to get it. + + Magit patches Info adding the ability to visit links to the ‘gitman’ +Info manual by instead viewing the respective manpage. If you prefer +that approach, then set the value of ‘magit-view-git-manual-method’ to +one of the supported packages ‘man’ or ‘woman’, e.g.: + + (setq magit-view-git-manual-method 'man) + + +File: magit.info, Node: How to show diffs for gpg-encrypted files?, Next: How does branching and pushing work?, Prev: How to install the gitman info manual?, Up: FAQ - How to ...? + +A.1.4 How to show diffs for gpg-encrypted files? +------------------------------------------------ + +Git supports showing diffs for encrypted files, but has to be told to do +so. Since Magit just uses Git to get the diffs, configuring Git also +affects the diffs displayed inside Magit. + + git config --global diff.gpg.textconv "gpg --no-tty --decrypt" + echo "*.gpg filter=gpg diff=gpg" > .gitattributes + + +File: magit.info, Node: How does branching and pushing work?, Next: Can Magit be used as ediff-version-control-package?, Prev: How to show diffs for gpg-encrypted files?, Up: FAQ - How to ...? + +A.1.5 How does branching and pushing work? +------------------------------------------ + +Please see *note Branching:: and + + + +File: magit.info, Node: Can Magit be used as ediff-version-control-package?, Next: Should I disable VC?, Prev: How does branching and pushing work?, Up: FAQ - How to ...? + +A.1.6 Can Magit be used as ‘ediff-version-control-package’? +----------------------------------------------------------- + +No, it cannot. For that to work the functions ‘ediff-magit-internal’ +and ‘ediff-magit-merge-internal’ would have to be implemented, and they +are not. These two functions are only used by the three commands +‘ediff-revision’, ‘ediff-merge-revisions-with-ancestor’, and +‘ediff-merge-revisions’. + + These commands only delegate the task of populating buffers with +certain revisions to the "internal" functions. The equally important +task of determining which revisions are to be compared/merged is not +delegated. Instead this is done without any support whatsoever from the +version control package/system - meaning that the user has to enter the +revisions explicitly. Instead of implementing ‘ediff-magit-internal’ we +provide ‘magit-ediff-compare’, which handles both tasks like it is 2005. + + The other commands ‘ediff-merge-revisions’ and +‘ediff-merge-revisions-with-ancestor’ are normally not what you want +when using a modern version control system like Git. Instead of letting +the user resolve only those conflicts which Git could not resolve on its +own, they throw away all work done by Git and then expect the user to +manually merge all conflicts, including those that had already been +resolved. That made sense back in the days when version control systems +couldn’t merge (or so I have been told), but not anymore. Once in a +blue moon you might actually want to see all conflicts, in which case +you *can* use these commands, which then use ‘ediff-vc-merge-internal’. +So we don’t actually have to implement ‘ediff-magit-merge-internal’. +Instead we provide the more useful command ‘magit-ediff-resolve’ which +only shows yet-to-be resolved conflicts. + + +File: magit.info, Node: Should I disable VC?, Prev: Can Magit be used as ediff-version-control-package?, Up: FAQ - How to ...? + +A.1.7 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’. + + +File: magit.info, Node: FAQ - Issues and Errors, Prev: FAQ - How to ...?, Up: FAQ + +A.2 FAQ - Issues and Errors +=========================== + +* Menu: + +* Magit is slow:: +* I changed several thousand files at once and now Magit is unusable:: +* I am having problems committing:: +* I am using MS Windows and cannot push with Magit:: +* I am using OS X and SOMETHING works in shell, but not in Magit: I am using OS X and SOMETHING works in shell but not in Magit. +* Expanding a file to show the diff causes it to disappear:: +* Point is wrong in the COMMIT_EDITMSG buffer:: +* The mode-line information isn't always up-to-date:: +* A branch and tag sharing the same name breaks SOMETHING:: +* My Git hooks work on the command-line but not inside Magit:: +* 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:: + + +File: magit.info, Node: Magit is slow, Next: I changed several thousand files at once and now Magit is unusable, Up: FAQ - Issues and Errors + +A.2.1 Magit is slow +------------------- + +See *note Performance::. + + +File: magit.info, Node: I changed several thousand files at once and now Magit is unusable, Next: I am having problems committing, Prev: Magit is slow, Up: FAQ - Issues and Errors + +A.2.2 I changed several thousand files at once and now Magit is unusable +------------------------------------------------------------------------ + +Magit is *currently* not expected to work under such conditions. It +sure would be nice if it did, and v2.5 will hopefully be a big step into +that direction. But it might take until v3.1 to accomplish fully +satisfactory performance, because that requires some heavy refactoring. + + But for now we recommend you use the command line to complete this +one commit. Also see *note Performance::. + + +File: magit.info, Node: I am having problems committing, Next: I am using MS Windows and cannot push with Magit, Prev: I changed several thousand files at once and now Magit is unusable, Up: FAQ - Issues and Errors + +A.2.3 I am having problems committing +------------------------------------- + +That likely means that Magit is having problems finding an appropriate +emacsclient executable. See *note (with-editor)Configuring +With-Editor:: and *note (with-editor)Debugging::. + + +File: magit.info, Node: I am using MS Windows and cannot push with Magit, Next: I am using OS X and SOMETHING works in shell but not in Magit, Prev: I am having problems committing, Up: FAQ - Issues and Errors + +A.2.4 I am using MS Windows and cannot push with Magit +------------------------------------------------------ + +It’s almost certain that Magit is only incidental to this issue. It is +much more likely that this is a configuration issue, even if you can +push on the command line. + + Detailed setup instructions can be found at +. + + +File: magit.info, Node: I am using OS X and SOMETHING works in shell but not in Magit, Next: Expanding a file to show the diff causes it to disappear, Prev: I am using MS Windows and cannot push with Magit, Up: FAQ - Issues and Errors + +A.2.5 I am using OS X and SOMETHING works in shell, but not in Magit +-------------------------------------------------------------------- + +This usually occurs because Emacs doesn’t have the same environment +variables as your shell. Try installing and configuring +. By default it +synchronizes ‘$PATH’, which helps Magit find the same ‘git’ as the one +you are using on the shell. + + If SOMETHING is "passphrase caching with gpg-agent for commit and/or +tag signing", then you’ll also need to synchronize ‘$GPG_AGENT_INFO’. + + +File: magit.info, Node: Expanding a file to show the diff causes it to disappear, Next: Point is wrong in the COMMIT_EDITMSG buffer, Prev: I am using OS X and SOMETHING works in shell but not in Magit, Up: FAQ - Issues and Errors + +A.2.6 Expanding a file to show the diff causes it to disappear +-------------------------------------------------------------- + +This is probably caused by a change of a ‘diff.*’ Git variable. You +probably set that variable for a reason, and should therefore only undo +that setting in Magit by customizing ‘magit-git-global-arguments’. + + +File: magit.info, Node: Point is wrong in the COMMIT_EDITMSG buffer, Next: The mode-line information isn't always up-to-date, Prev: Expanding a file to show the diff causes it to disappear, Up: FAQ - Issues and Errors + +A.2.7 Point is wrong in the ‘COMMIT_EDITMSG’ buffer +--------------------------------------------------- + +Neither Magit nor ‘git-commit‘ fiddle with point in the buffer used to +write commit messages, so something else must be doing it. + + You have probably globally enabled a mode which does restore point in +file-visiting buffers. It might be a bit surprising, but when you write +a commit message, then you are actually editing a file. + + So you have to figure out which package is doing. ‘saveplace’, +‘pointback’, and ‘session’ are likely candidates. These snippets might +help: + + (setq session-name-disable-regexp "\\(?:\\`'\\.git/[A-Z_]+\\'\\)") + + (with-eval-after-load 'pointback + (lambda () + (when (or git-commit-mode git-rebase-mode) + (pointback-mode -1)))) + + +File: magit.info, Node: The mode-line information isn't always up-to-date, Next: A branch and tag sharing the same name breaks SOMETHING, Prev: Point is wrong in the COMMIT_EDITMSG buffer, Up: FAQ - Issues and Errors + +A.2.8 The mode-line information isn’t always up-to-date +------------------------------------------------------- + +Magit is not responsible for the version control information that is +being displayed in the mode-line and looks something like ‘Git-master’. +The built-in "Version Control" package, also known as "VC", updates that +information, and can be told to do so more often: + + (setq auto-revert-check-vc-info t) + + But doing so isn’t good for performance. For more (overly +optimistic) information see *note (emacs)VC Mode Line::. + + 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: + + (setq-default mode-line-format + (delete '(vc-mode vc-mode) mode-line-format)) + + +File: magit.info, Node: A branch and tag sharing the same name breaks SOMETHING, Next: My Git hooks work on the command-line but not inside Magit, Prev: The mode-line information isn't always up-to-date, Up: FAQ - Issues and Errors + +A.2.9 A branch and tag sharing the same name breaks SOMETHING +------------------------------------------------------------- + +Or more generally, ambiguous refnames break SOMETHING. + + Magit assumes that refs are named non-ambiguously across the +"refs/heads/", "refs/tags/", and "refs/remotes/" namespaces (i.e., all +the names remain unique when those prefixes are stripped). We consider +ambiguous refnames unsupported and recommend that you use a +non-ambiguous naming scheme. However, if you do work with a repository +that has ambiguous refnames, please report any issues you encounter so +that we can investigate whether there is a simple fix. + + +File: magit.info, Node: My Git hooks work on the command-line but not inside Magit, Next: git-commit-mode isn't used when committing from the command-line, Prev: A branch and tag sharing the same name breaks SOMETHING, Up: FAQ - Issues and Errors + +A.2.10 My Git hooks work on the command-line but not inside Magit +----------------------------------------------------------------- + +When Magit calls ‘git’ it adds a few global arguments including +‘--literal-pathspecs’ and the ‘git’ process started by Magit then passes +that setting on to other ‘git’ process it starts itself. It does so by +setting the environment variable ‘GIT_LITERAL_PATHSPECS’, not by calling +subprocesses with the ‘--literal-pathspecs’ argument. You can therefore +override this setting in hook scripts using ‘unset +GIT_LITERAL_PATHSPECS’. + + +File: magit.info, Node: git-commit-mode isn't used when committing from the command-line, Next: Point ends up inside invisible text when jumping to a file-visiting buffer, Prev: My Git hooks work on the command-line but not inside Magit, Up: FAQ - Issues and Errors + +A.2.11 ‘git-commit-mode’ isn’t used when committing from the command-line +------------------------------------------------------------------------- + +The reason for this is that ‘git-commit.el’ has not been loaded yet +and/or that the server has not been started yet. These things have +always already been taken care of when you commit from Magit because in +order to do so, Magit has to be loaded and doing that involves loading +‘git-commit’ and starting the server. + + If you want to commit from the command-line, then you have to take +care of these things yourself. Your ‘init.el’ file should contain: + + (require 'git-commit) + (server-mode) + + Instead of ‘(require ’git-commit)‘ you may also use: + + (load "/path/to/magit-autoloads.el") + + You might want to do that because loading ‘git-commit’ causes large +parts of Magit to be loaded. + + There are also some variations of ‘(server-mode)’ that you might want +to try. Personally I use: + + (use-package server + :config (or (server-running-p) (server-mode))) + + Now you can use: + + $ emacs& + $ EDITOR=emacsclient git commit + + However you cannot use: + + $ killall emacs + $ EDITOR="emacsclient --alternate-editor emacs" git commit + + This will actually end up using ‘emacs’, not ‘emacsclient’. If you +do 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, then you cannot use ‘emacsclient’ directly. + + Instead you have to create a script that does something like this: + + Try to use ‘emacsclient’ (without using ‘--alternate-editor’). If +that succeeds, do nothing else. Otherwise start ‘emacs &’ (and +‘init.el’ must call ‘server-start’) and try to use ‘emacsclient’ again. + + +File: magit.info, Node: Point ends up inside invisible text when jumping to a file-visiting buffer, Next: I am unable to stage when using Tramp from MS Windows, Prev: git-commit-mode isn't used when committing from the command-line, Up: FAQ - Issues and Errors + +A.2.12 Point ends up inside invisible text when jumping to a file-visiting buffer +--------------------------------------------------------------------------------- + +This can happen when you type ‘RET’ on a hunk to visit the respective +file at the respective position. One solution to this problem is to use +‘global-reveal-mode’. It makes sure that text around point is always +visible. If that is too drastic for your taste, then you may instead +use ‘magit-diff-visit-file-hook’ to reveal the text, possibly using +‘reveal-post-command’ or for Org buffers ‘org-reveal’. + + +File: magit.info, Node: I am unable to stage when using Tramp from MS Windows, Next: I am no longer able to save popup defaults, Prev: Point ends up inside invisible text when jumping to a file-visiting buffer, Up: FAQ - Issues and Errors + +A.2.13 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 +. + + +File: magit.info, Node: I am no longer able to save popup defaults, Prev: I am unable to stage when using Tramp from MS Windows, Up: FAQ - Issues and Errors + +A.2.14 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 +for more details. + + +File: magit.info, Node: Debugging Tools, Next: Keystroke Index, Prev: FAQ, Up: Top + +B Debugging Tools +***************** + +Magit and its dependencies provide a few debugging tools, and we +appreciate it very much if you use those tools before reporting an +issue. Please include all relevant output when reporting an issue. + +‘M-x 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. + +‘M-x magit-emacs-Q-command’ + This command shows a debugging shell command in the echo area and + adds it to the kill ring. Paste that command into a shell and run + it. + + This shell command starts ‘emacs’ with only ‘magit’ and its + dependencies loaded. Neither your configuration nor other + installed packages are loaded. This makes it easier to determine + whether some issue lays with Magit or something else. + + If you run Magit from its Git repository, then you should be able + to use ‘make emacs-Q’ instead of the output of this command. + +‘M-x magit-toggle-verbose-refresh’ + This command toggles whether Magit refreshes buffers verbosely. + Enabling this helps figuring out which sections are bottlenecks. + The additional output can be found in the ‘*Messages*’ buffer. + +‘M-x magit-debug-git-executable’ + This command displays a buffer containing information about the + available and used ‘git’ executable(s), and can be useful when + investigating ‘exec-path’ issues. + + Also see *note Git Executable::. + +‘M-x with-editor-debug’ + This command displays a buffer containing information about the + available and used ‘emacsclient’ executable(s), and can be useful + when investigating why Magit (or rather ‘with-editor’) cannot find + an appropriate ‘emacsclient’ executable. + + Also see *note (with-editor)Debugging::. + + Please also see the *note FAQ::. + + +File: magit.info, Node: Keystroke Index, Next: Function and Command Index, Prev: Debugging Tools, Up: Top + +Appendix C Keystroke Index +************************** + +[index] +* Menu: + +* !: Running Git Manually. + (line 13) +* ! !: Running Git Manually. + (line 17) +* ! a: Running Git Manually. + (line 53) +* ! b: Running Git Manually. + (line 56) +* ! g: Running Git Manually. + (line 59) +* ! k: Running Git Manually. + (line 50) +* ! p: Running Git Manually. + (line 25) +* ! s: Running Git Manually. + (line 34) +* ! S: Running Git Manually. + (line 38) +* $: Viewing Git Output. (line 17) +* +: Log Buffer. (line 64) +* + <1>: Refreshing Diffs. (line 61) +* -: Log Buffer. (line 67) +* - <1>: Refreshing Diffs. (line 58) +* 0: Refreshing Diffs. (line 64) +* 1: Section Visibility. (line 26) +* 2: Section Visibility. (line 26) +* 3: Section Visibility. (line 26) +* 4: Section Visibility. (line 26) +* :: Running Git Manually. + (line 25) +* =: Log Buffer. (line 59) +* ^: Section Movement. (line 28) +* a: Applying. (line 34) +* A: Cherry Picking. (line 9) +* A A: Cherry Picking. (line 17) +* A a: Cherry Picking. (line 23) +* A A <1>: Cherry Picking. (line 85) +* A a <1>: Cherry Picking. (line 91) +* A d: Cherry Picking. (line 51) +* A h: Cherry Picking. (line 40) +* A n: Cherry Picking. (line 62) +* A s: Cherry Picking. (line 72) +* A s <1>: Cherry Picking. (line 88) +* B: Bisecting. (line 9) +* b: Blaming. (line 95) +* b <1>: Branch Commands. (line 13) +* b <2>: Editing Rebase Sequences. + (line 70) +* B B: Bisecting. (line 16) +* B b: Bisecting. (line 32) +* b b: Branch Commands. (line 47) +* b C: Branch Commands. (line 31) +* b c: Branch Commands. (line 63) +* B g: Bisecting. (line 36) +* B k: Bisecting. (line 46) +* b k: Branch Commands. (line 138) +* b l: Branch Commands. (line 69) +* B m: Bisecting. (line 40) +* b n: Branch Commands. (line 54) +* B r: Bisecting. (line 51) +* b r: Branch Commands. (line 143) +* B s: Bisecting. (line 26) +* b s: Branch Commands. (line 91) +* b S: Branch Commands. (line 118) +* b x: Branch Commands. (line 123) +* c: Blaming. (line 121) +* C: Cloning Repository. (line 20) +* c <1>: Initiating a Commit. (line 9) +* c <2>: Editing Rebase Sequences. + (line 59) +* c a: Initiating a Commit. (line 18) +* c A: Initiating a Commit. (line 59) +* C b: Cloning Repository. (line 38) +* C C: Cloning Repository. (line 28) +* c c: Initiating a Commit. (line 14) +* C d: Cloning Repository. (line 49) +* C e: Cloning Repository. (line 55) +* c e: Initiating a Commit. (line 21) +* c f: Initiating a Commit. (line 39) +* c F: Initiating a Commit. (line 46) +* C m: Cloning Repository. (line 42) +* C s: Cloning Repository. (line 32) +* c s: Initiating a Commit. (line 49) +* c S: Initiating a Commit. (line 56) +* c w: Initiating a Commit. (line 30) +* C-: Visiting Files and Blobs from a Diff. + (line 50) +* C-: Section Visibility. (line 13) +* C-c C-a: Commit Pseudo Headers. + (line 16) +* C-c C-b: Log Buffer. (line 20) +* C-c C-b <1>: Refreshing Diffs. (line 80) +* C-c C-c: Transient Commands. (line 19) +* C-c C-c <1>: Select from Log. (line 21) +* C-c C-c <2>: Editing Commit Messages. + (line 18) +* C-c C-c <3>: Editing Rebase Sequences. + (line 7) +* C-c C-d: Refreshing Diffs. (line 71) +* C-c C-d <1>: Editing Commit Messages. + (line 54) +* C-c C-e: Commands Available in Diffs. + (line 24) +* C-c C-f: Log Buffer. (line 23) +* C-c C-f <1>: Refreshing Diffs. (line 83) +* C-c C-i: Commit Pseudo Headers. + (line 13) +* C-c C-k: Select from Log. (line 26) +* C-c C-k <1>: Editing Commit Messages. + (line 22) +* C-c C-k <2>: Editing Rebase Sequences. + (line 11) +* C-c C-n: Log Buffer. (line 26) +* C-c C-o: Commit Pseudo Headers. + (line 28) +* C-c C-p: Commit Pseudo Headers. + (line 31) +* C-c C-r: Commit Pseudo Headers. + (line 19) +* C-c C-s: Commit Pseudo Headers. + (line 22) +* C-c C-t: Commands Available in Diffs. + (line 15) +* C-c C-t <1>: Commit Pseudo Headers. + (line 25) +* C-c C-w: Using the Revision Stack. + (line 7) +* C-c M-g: Commands for Buffers Visiting Files. + (line 22) +* C-c M-g B: Blaming. (line 19) +* C-c M-g b: Blaming. (line 30) +* C-c M-g B <1>: Commands for Buffers Visiting Files. + (line 83) +* C-c M-g B b: Blaming. (line 30) +* C-c M-g B e: Blaming. (line 61) +* C-c M-g B f: Blaming. (line 53) +* C-c M-g B r: Blaming. (line 45) +* C-c M-g c: Commands for Buffers Visiting Files. + (line 36) +* C-c M-g D: Commands for Buffers Visiting Files. + (line 42) +* C-c M-g d: Commands for Buffers Visiting Files. + (line 52) +* C-c M-g e: Blaming. (line 61) +* C-c M-g e <1>: Commands for Buffers Visiting Files. + (line 95) +* C-c M-g f: Blaming. (line 53) +* C-c M-g L: Commands for Buffers Visiting Files. + (line 60) +* C-c M-g l: Commands for Buffers Visiting Files. + (line 70) +* C-c M-g p: Commands for Buffers Visiting Files. + (line 104) +* C-c M-g r: Blaming. (line 45) +* C-c M-g s: Commands for Buffers Visiting Files. + (line 29) +* C-c M-g t: Commands for Buffers Visiting Files. + (line 76) +* C-c M-g u: Commands for Buffers Visiting Files. + (line 32) +* C-c M-i: Commit Pseudo Headers. + (line 35) +* C-c M-s: Editing Commit Messages. + (line 33) +* C-w: Common Commands. (line 22) +* C-x g: Status Buffer. (line 23) +* C-x u: Editing Rebase Sequences. + (line 77) +* d: Diffing. (line 22) +* D: Refreshing Diffs. (line 12) +* d c: Diffing. (line 63) +* d d: Diffing. (line 27) +* D f: Refreshing Diffs. (line 41) +* D F: Refreshing Diffs. (line 45) +* D g: Refreshing Diffs. (line 17) +* d p: Diffing. (line 56) +* d r: Diffing. (line 30) +* D r: Refreshing Diffs. (line 37) +* d s: Diffing. (line 48) +* D s: Refreshing Diffs. (line 21) +* d t: Diffing. (line 67) +* D t: Refreshing Diffs. (line 34) +* d u: Diffing. (line 53) +* d w: Diffing. (line 43) +* D w: Refreshing Diffs. (line 27) +* DEL: Log Buffer. (line 50) +* DEL <1>: Commands Available in Diffs. + (line 56) +* DEL <2>: Blaming. (line 83) +* DEL <3>: Editing Rebase Sequences. + (line 25) +* e: Ediffing. (line 10) +* E: Ediffing. (line 21) +* e <1>: Editing Rebase Sequences. + (line 46) +* E c: Ediffing. (line 58) +* E i: Ediffing. (line 52) +* E m: Ediffing. (line 33) +* E r: Ediffing. (line 25) +* E s: Ediffing. (line 45) +* E u: Ediffing. (line 49) +* E w: Ediffing. (line 55) +* E z: Ediffing. (line 61) +* f: Editing Rebase Sequences. + (line 52) +* f <1>: Fetching. (line 10) +* F: Pulling. (line 10) +* f a: Fetching. (line 45) +* f C: Branch Commands. (line 31) +* F C: Branch Commands. (line 31) +* f e: Fetching. (line 34) +* F e: Pulling. (line 28) +* f m: Fetching. (line 48) +* f o: Fetching. (line 37) +* f p: Fetching. (line 15) +* F p: Pulling. (line 14) +* f r: Fetching. (line 41) +* f u: Fetching. (line 22) +* F u: Pulling. (line 21) +* g: Automatic Refreshing of Magit Buffers. + (line 26) +* G: Automatic Refreshing of Magit Buffers. + (line 34) +* H: Section Types and Values. + (line 14) +* I: Creating Repository. (line 7) +* j: Log Buffer. (line 31) +* j <1>: Commands Available in Diffs. + (line 43) +* k: Viewing Git Output. (line 24) +* k <1>: Applying. (line 40) +* k <2>: Editing Rebase Sequences. + (line 56) +* k <3>: Stashing. (line 82) +* l: Logging. (line 30) +* L: Refreshing Logs. (line 12) +* L <1>: Log Buffer. (line 7) +* L <2>: Log Margin. (line 52) +* l <1>: Editing Rebase Sequences. + (line 94) +* l a: Logging. (line 55) +* l b: Logging. (line 52) +* L d: Log Margin. (line 66) +* L g: Refreshing Logs. (line 17) +* l h: Logging. (line 46) +* l H: Reflog. (line 18) +* l l: Logging. (line 35) +* l L: Logging. (line 49) +* L L: Log Margin. (line 60) +* L l: Log Margin. (line 63) +* l o: Logging. (line 40) +* l O: Reflog. (line 15) +* l r: Reflog. (line 12) +* L s: Refreshing Logs. (line 21) +* L t: Refreshing Logs. (line 34) +* L w: Refreshing Logs. (line 27) +* m: Merging. (line 10) +* M: Remote Commands. (line 14) +* m a: Merging. (line 42) +* m a <1>: Merging. (line 87) +* M a: Remote Commands. (line 48) +* M C: Remote Commands. (line 32) +* m e: Merging. (line 30) +* m i: Merging. (line 54) +* M k: Remote Commands. (line 60) +* m m: Merging. (line 18) +* m m <1>: Merging. (line 82) +* m n: Merging. (line 36) +* m p: Merging. (line 75) +* M p: Remote Commands. (line 63) +* M P: Remote Commands. (line 67) +* M r: Remote Commands. (line 52) +* m s: Merging. (line 67) +* M u: Remote Commands. (line 56) +* M-1: Section Visibility. (line 32) +* M-2: Section Visibility. (line 32) +* M-3: Section Visibility. (line 32) +* M-4: Section Visibility. (line 32) +* M-: Section Visibility. (line 16) +* M-n: Section Movement. (line 24) +* M-n <1>: Editing Commit Messages. + (line 41) +* M-n <2>: Editing Rebase Sequences. + (line 40) +* M-p: Section Movement. (line 19) +* M-p <1>: Editing Commit Messages. + (line 36) +* M-p <2>: Editing Rebase Sequences. + (line 37) +* M-w: Blaming. (line 114) +* M-w <1>: Common Commands. (line 39) +* MM: Editing Rebase Sequences. + (line 102) +* Mt: Editing Rebase Sequences. + (line 108) +* n: Section Movement. (line 16) +* n <1>: Blaming. (line 98) +* N: Blaming. (line 101) +* n <2>: Editing Rebase Sequences. + (line 34) +* n <3>: Minor Mode for Buffers Visiting Blobs. + (line 16) +* o: Submodule Transient. (line 7) +* O: Subtree. (line 9) +* o a: Submodule Transient. (line 20) +* o d: Submodule Transient. (line 45) +* O e: Subtree. (line 37) +* O e p: Subtree. (line 48) +* O e s: Subtree. (line 52) +* o f: Submodule Transient. (line 51) +* O i: Subtree. (line 13) +* O i a: Subtree. (line 24) +* O i c: Subtree. (line 28) +* O i f: Subtree. (line 34) +* O i m: Subtree. (line 31) +* o l: Submodule Transient. (line 48) +* o p: Submodule Transient. (line 32) +* o r: Submodule Transient. (line 26) +* o s: Submodule Transient. (line 40) +* o u: Submodule Transient. (line 36) +* p: Section Movement. (line 11) +* p <1>: Blaming. (line 104) +* P: Blaming. (line 107) +* p <2>: Editing Rebase Sequences. + (line 31) +* P <1>: Pushing. (line 10) +* p <3>: Minor Mode for Buffers Visiting Blobs. + (line 13) +* P C: Branch Commands. (line 31) +* P e: Pushing. (line 29) +* P m: Pushing. (line 45) +* P o: Pushing. (line 33) +* P p: Pushing. (line 15) +* P r: Pushing. (line 37) +* P t: Pushing. (line 52) +* P T: Pushing. (line 59) +* P u: Pushing. (line 22) +* q: Quitting Windows. (line 7) +* q <1>: Log Buffer. (line 14) +* q <2>: Blaming. (line 110) +* q <3>: Minor Mode for Buffers Visiting Blobs. + (line 19) +* r: Rebasing. (line 10) +* r <1>: Editing Rebase Sequences. + (line 43) +* r a: Rebasing. (line 111) +* r e: Rebasing. (line 42) +* r e <1>: Rebasing. (line 107) +* r f: Rebasing. (line 79) +* r i: Rebasing. (line 76) +* r k: Rebasing. (line 91) +* r m: Rebasing. (line 83) +* r p: Rebasing. (line 28) +* r r: Rebasing. (line 97) +* r s: Rebasing. (line 47) +* r s <1>: Rebasing. (line 103) +* r u: Rebasing. (line 35) +* r w: Rebasing. (line 87) +* RET: References Buffer. (line 159) +* RET <1>: Visiting Files and Blobs from a Diff. + (line 9) +* RET <2>: Blaming. (line 71) +* RET <3>: Editing Rebase Sequences. + (line 15) +* s: Staging and Unstaging. + (line 29) +* S: Staging and Unstaging. + (line 36) +* s <1>: Editing Rebase Sequences. + (line 49) +* S-: Section Visibility. (line 20) +* SPC: Log Buffer. (line 41) +* SPC <1>: Commands Available in Diffs. + (line 53) +* SPC <2>: Blaming. (line 74) +* SPC <3>: Editing Rebase Sequences. + (line 19) +* t: Editing Rebase Sequences. + (line 97) +* t <1>: Tagging. (line 9) +* T: Notes. (line 9) +* T a: Notes. (line 47) +* T c: Notes. (line 43) +* t k: Tagging. (line 37) +* T m: Notes. (line 35) +* t p: Tagging. (line 43) +* T p: Notes. (line 28) +* t r: Tagging. (line 18) +* T r: Notes. (line 21) +* t t: Tagging. (line 14) +* T T: Notes. (line 14) +* TAB: Section Visibility. (line 10) +* u: Staging and Unstaging. + (line 42) +* U: Staging and Unstaging. + (line 50) +* v: Applying. (line 47) +* V: Reverting. (line 7) +* V A: Reverting. (line 29) +* V a: Reverting. (line 35) +* V s: Reverting. (line 32) +* V V: Reverting. (line 15) +* V v: Reverting. (line 20) +* W: Plain Patches. (line 7) +* w: Maildir Patches. (line 9) +* w a: Plain Patches. (line 20) +* w a <1>: Maildir Patches. (line 23) +* w a <2>: Maildir Patches. (line 38) +* W c: Plain Patches. (line 12) +* w m: Maildir Patches. (line 20) +* W s: Plain Patches. (line 26) +* w s: Maildir Patches. (line 34) +* w w: Maildir Patches. (line 14) +* w w <1>: Maildir Patches. (line 31) +* x: Editing Rebase Sequences. + (line 62) +* x <1>: Resetting. (line 9) +* X f: Resetting. (line 44) +* X h: Resetting. (line 24) +* X i: Resetting. (line 33) +* X k: Resetting. (line 28) +* X m: Resetting. (line 15) +* X s: Resetting. (line 19) +* X w: Resetting. (line 39) +* X w <1>: Wip Modes. (line 64) +* Y: Cherries. (line 18) +* y: References Buffer. (line 7) +* y <1>: Editing Rebase Sequences. + (line 74) +* y c: References Buffer. (line 25) +* y o: References Buffer. (line 30) +* y r: References Buffer. (line 34) +* y y: References Buffer. (line 21) +* z: Stashing. (line 9) +* Z: Worktree. (line 9) +* z a: Stashing. (line 52) +* z b: Stashing. (line 70) +* z B: Stashing. (line 74) +* Z b: Worktree. (line 13) +* Z c: Worktree. (line 16) +* z f: Stashing. (line 79) +* Z g: Worktree. (line 26) +* z i: Stashing. (line 20) +* z I: Stashing. (line 42) +* z k: Stashing. (line 63) +* Z k: Worktree. (line 22) +* z l: Stashing. (line 85) +* Z m: Worktree. (line 19) +* z p: Stashing. (line 57) +* z v: Stashing. (line 67) +* z w: Stashing. (line 24) +* z W: Stashing. (line 46) +* z x: Stashing. (line 30) +* z z: Stashing. (line 14) +* z Z: Stashing. (line 36) + + +File: magit.info, Node: Function and Command Index, Next: Variable Index, Prev: Keystroke Index, Up: Top + +Appendix D Function and Command Index +************************************* + +[index] +* Menu: + +* bug-reference-mode: Commit Mode and Hooks. + (line 49) +* forward-line: Editing Rebase Sequences. + (line 34) +* git-commit-ack: Commit Pseudo Headers. + (line 16) +* git-commit-cc: Commit Pseudo Headers. + (line 28) +* git-commit-check-style-conventions: Commit Message Conventions. + (line 37) +* git-commit-insert-pseudo-header: Commit Pseudo Headers. + (line 13) +* git-commit-next-message: Editing Commit Messages. + (line 41) +* git-commit-prev-message: Editing Commit Messages. + (line 36) +* git-commit-propertize-diff: Commit Mode and Hooks. + (line 41) +* git-commit-reported: Commit Pseudo Headers. + (line 31) +* git-commit-review: Commit Pseudo Headers. + (line 19) +* git-commit-save-message: Editing Commit Messages. + (line 33) +* git-commit-save-message <1>: Commit Mode and Hooks. + (line 26) +* git-commit-setup-changelog-support: Commit Mode and Hooks. + (line 29) +* git-commit-signoff: Commit Pseudo Headers. + (line 22) +* git-commit-suggested: Commit Pseudo Headers. + (line 35) +* git-commit-test: Commit Pseudo Headers. + (line 25) +* git-commit-turn-on-auto-fill: Commit Mode and Hooks. + (line 33) +* git-commit-turn-on-flyspell: Commit Mode and Hooks. + (line 37) +* git-rebase-backward-line: Editing Rebase Sequences. + (line 31) +* git-rebase-break: Editing Rebase Sequences. + (line 70) +* git-rebase-edit: Editing Rebase Sequences. + (line 46) +* git-rebase-exec: Editing Rebase Sequences. + (line 62) +* git-rebase-fixup: Editing Rebase Sequences. + (line 52) +* git-rebase-insert: Editing Rebase Sequences. + (line 74) +* git-rebase-kill-line: Editing Rebase Sequences. + (line 56) +* git-rebase-label: Editing Rebase Sequences. + (line 94) +* git-rebase-merge: Editing Rebase Sequences. + (line 102) +* git-rebase-merge-toggle-editmsg: Editing Rebase Sequences. + (line 108) +* git-rebase-move-line-down: Editing Rebase Sequences. + (line 40) +* git-rebase-move-line-up: Editing Rebase Sequences. + (line 37) +* git-rebase-pick: Editing Rebase Sequences. + (line 59) +* git-rebase-reset: Editing Rebase Sequences. + (line 97) +* git-rebase-reword: Editing Rebase Sequences. + (line 43) +* git-rebase-show-commit: Editing Rebase Sequences. + (line 15) +* git-rebase-show-or-scroll-down: Editing Rebase Sequences. + (line 25) +* git-rebase-show-or-scroll-up: Editing Rebase Sequences. + (line 19) +* git-rebase-squash: Editing Rebase Sequences. + (line 49) +* git-rebase-undo: Editing Rebase Sequences. + (line 77) +* ido-enter-magit-status: Status Buffer. (line 96) +* magit-add-section-hook: Section Hooks. (line 20) +* magit-after-save-refresh-status: Automatic Refreshing of Magit Buffers. + (line 55) +* magit-am: Maildir Patches. (line 9) +* magit-am-abort: Maildir Patches. (line 38) +* magit-am-apply-maildir: Maildir Patches. (line 20) +* magit-am-apply-patches: Maildir Patches. (line 14) +* magit-am-continue: Maildir Patches. (line 31) +* magit-am-skip: Maildir Patches. (line 34) +* magit-apply: Applying. (line 34) +* magit-bisect: Bisecting. (line 9) +* magit-bisect-bad: Bisecting. (line 32) +* magit-bisect-good: Bisecting. (line 36) +* magit-bisect-mark: Bisecting. (line 40) +* magit-bisect-reset: Bisecting. (line 51) +* magit-bisect-run: Bisecting. (line 26) +* magit-bisect-skip: Bisecting. (line 46) +* magit-bisect-start: Bisecting. (line 16) +* magit-blame: Blaming. (line 19) +* magit-blame <1>: Blaming. (line 95) +* magit-blame <2>: Commands for Buffers Visiting Files. + (line 83) +* magit-blame-addition: Blaming. (line 30) +* magit-blame-copy-hash: Blaming. (line 114) +* magit-blame-cycle-style: Blaming. (line 121) +* magit-blame-echo: Blaming. (line 61) +* magit-blame-next-chunk: Blaming. (line 98) +* magit-blame-next-chunk-same-commit: Blaming. (line 101) +* magit-blame-previous-chunk: Blaming. (line 104) +* magit-blame-previous-chunk-same-commit: Blaming. (line 107) +* magit-blame-quit: Blaming. (line 110) +* magit-blame-removal: Blaming. (line 45) +* magit-blame-reverse: Blaming. (line 53) +* magit-blob-next: Minor Mode for Buffers Visiting Blobs. + (line 16) +* magit-blob-previous: Commands for Buffers Visiting Files. + (line 104) +* magit-blob-previous <1>: Minor Mode for Buffers Visiting Blobs. + (line 13) +* magit-branch: Branch Commands. (line 13) +* magit-branch-and-checkout: Branch Commands. (line 63) +* magit-branch-checkout: Branch Commands. (line 69) +* magit-branch-configure: Branch Commands. (line 31) +* magit-branch-create: Branch Commands. (line 54) +* magit-branch-delete: Branch Commands. (line 138) +* magit-branch-or-checkout: Branch Commands. (line 251) +* magit-branch-orphan: Branch Commands. (line 247) +* magit-branch-rename: Branch Commands. (line 143) +* magit-branch-reset: Branch Commands. (line 123) +* magit-branch-shelve: Auxiliary Branch Commands. + (line 9) +* magit-branch-spinoff: Branch Commands. (line 91) +* magit-branch-spinout: Branch Commands. (line 118) +* magit-branch-unshelve: Auxiliary Branch Commands. + (line 19) +* magit-builtin-completing-read: Support for Completion Frameworks. + (line 41) +* magit-bundle: Bundle. (line 8) +* magit-call-git: Calling Git for Effect. + (line 28) +* magit-call-process: Calling Git for Effect. + (line 31) +* magit-cancel-section: Creating Sections. (line 69) +* magit-checkout: Branch Commands. (line 47) +* magit-cherry: Cherries. (line 18) +* magit-cherry-apply: Cherry Picking. (line 23) +* magit-cherry-copy: Cherry Picking. (line 17) +* magit-cherry-donate: Cherry Picking. (line 51) +* magit-cherry-harvest: Cherry Picking. (line 40) +* magit-cherry-pick: Cherry Picking. (line 9) +* magit-cherry-spinoff: Cherry Picking. (line 72) +* magit-cherry-spinout: Cherry Picking. (line 62) +* magit-clone: Cloning Repository. (line 20) +* magit-clone-bare: Cloning Repository. (line 38) +* magit-clone-mirror: Cloning Repository. (line 42) +* magit-clone-regular: Cloning Repository. (line 28) +* magit-clone-shallow: Cloning Repository. (line 32) +* magit-clone-shallow-exclude: Cloning Repository. (line 55) +* magit-clone-shallow-since: Cloning Repository. (line 49) +* magit-commit: Initiating a Commit. (line 9) +* magit-commit <1>: Commands for Buffers Visiting Files. + (line 36) +* magit-commit-amend: Initiating a Commit. (line 18) +* magit-commit-augment: Initiating a Commit. (line 59) +* magit-commit-create: Initiating a Commit. (line 14) +* magit-commit-extend: Initiating a Commit. (line 21) +* magit-commit-fixup: Initiating a Commit. (line 39) +* magit-commit-instant-fixup: Initiating a Commit. (line 46) +* magit-commit-instant-squash: Initiating a Commit. (line 56) +* magit-commit-reword: Initiating a Commit. (line 30) +* magit-commit-squash: Initiating a Commit. (line 49) +* magit-completing-read: Support for Completion Frameworks. + (line 57) +* magit-copy-buffer-revision: Common Commands. (line 39) +* magit-copy-section-value: Common Commands. (line 22) +* magit-current-section: Section Selection. (line 6) +* magit-cycle-margin-style: Log Margin. (line 63) +* magit-debug-git-executable: Git Executable. (line 55) +* magit-debug-git-executable <1>: Debugging Tools. (line 34) +* magit-define-section-jumper: Creating Sections. (line 74) +* magit-describe-section: Section Types and Values. + (line 14) +* magit-describe-section-briefly: Section Types and Values. + (line 17) +* magit-describe-section-briefly <1>: Matching Sections. (line 7) +* magit-diff: Diffing. (line 22) +* magit-diff <1>: Commands for Buffers Visiting Files. + (line 42) +* magit-diff-buffer-file: Commands for Buffers Visiting Files. + (line 52) +* magit-diff-default-context: Refreshing Diffs. (line 64) +* magit-diff-dwim: Diffing. (line 27) +* magit-diff-edit-hunk-commit: Commands Available in Diffs. + (line 24) +* magit-diff-flip-revs: Refreshing Diffs. (line 41) +* magit-diff-less-context: Refreshing Diffs. (line 58) +* magit-diff-more-context: Refreshing Diffs. (line 61) +* magit-diff-paths: Diffing. (line 56) +* magit-diff-range: Diffing. (line 30) +* magit-diff-refresh: Refreshing Diffs. (line 12) +* magit-diff-refresh <1>: Refreshing Diffs. (line 17) +* magit-diff-save-default-arguments: Refreshing Diffs. (line 27) +* magit-diff-scope: Matching Sections. (line 110) +* magit-diff-set-default-arguments: Refreshing Diffs. (line 21) +* magit-diff-show-or-scroll-down: Log Buffer. (line 50) +* magit-diff-show-or-scroll-down <1>: Blaming. (line 83) +* magit-diff-show-or-scroll-up: Log Buffer. (line 41) +* magit-diff-show-or-scroll-up <1>: Blaming. (line 74) +* magit-diff-staged: Diffing. (line 48) +* magit-diff-switch-range-type: Refreshing Diffs. (line 37) +* magit-diff-toggle-file-filter: Refreshing Diffs. (line 45) +* magit-diff-toggle-refine-hunk: Refreshing Diffs. (line 34) +* magit-diff-trace-definition: Commands Available in Diffs. + (line 15) +* magit-diff-type: Matching Sections. (line 88) +* magit-diff-unstaged: Diffing. (line 53) +* magit-diff-visit-file: Visiting Files and Blobs from a Diff. + (line 9) +* magit-diff-visit-file-other-frame: Visiting Files and Blobs from a Diff. + (line 71) +* magit-diff-visit-file-other-window: Visiting Files and Blobs from a Diff. + (line 70) +* magit-diff-visit-file-worktree: Visiting Files and Blobs from a Diff. + (line 50) +* magit-diff-visit-worktree-file-other-frame: Visiting Files and Blobs from a Diff. + (line 73) +* magit-diff-visit-worktree-file-other-window: Visiting Files and Blobs from a Diff. + (line 72) +* magit-diff-while-committing: Refreshing Diffs. (line 71) +* magit-diff-while-committing <1>: Editing Commit Messages. + (line 54) +* magit-diff-working-tree: Diffing. (line 43) +* magit-disable-section-inserter: Per-Repository Configuration. + (line 31) +* magit-discard: Applying. (line 40) +* magit-dispatch: Transient Commands. (line 19) +* magit-display-buffer: Switching Buffers. (line 6) +* magit-display-buffer-fullcolumn-most-v1: Switching Buffers. (line 68) +* magit-display-buffer-fullframe-status-topleft-v1: Switching Buffers. + (line 59) +* magit-display-buffer-fullframe-status-v1: Switching Buffers. + (line 54) +* magit-display-buffer-same-window-except-diff-v1: Switching Buffers. + (line 49) +* magit-display-buffer-traditional: Switching Buffers. (line 42) +* magit-display-repository-buffer: Common Commands. (line 9) +* magit-ediff: Ediffing. (line 21) +* magit-ediff-compare: Ediffing. (line 25) +* magit-ediff-dwim: Ediffing. (line 10) +* magit-ediff-resolve: Ediffing. (line 33) +* magit-ediff-show-commit: Ediffing. (line 58) +* magit-ediff-show-staged: Ediffing. (line 52) +* magit-ediff-show-stash: Ediffing. (line 61) +* magit-ediff-show-unstaged: Ediffing. (line 49) +* magit-ediff-show-working-tree: Ediffing. (line 55) +* magit-ediff-stage: Ediffing. (line 45) +* magit-edit-line-commit: Commands for Buffers Visiting Files. + (line 95) +* magit-emacs-Q-command: Debugging Tools. (line 16) +* magit-fetch: Fetching. (line 10) +* magit-fetch-all: Fetching. (line 45) +* magit-fetch-branch: Fetching. (line 37) +* magit-fetch-from-pushremote: Fetching. (line 15) +* magit-fetch-from-upstream: Fetching. (line 22) +* magit-fetch-modules: Submodule Transient. (line 51) +* magit-fetch-other: Fetching. (line 34) +* magit-fetch-refspec: Fetching. (line 41) +* magit-file-checkout: Resetting. (line 44) +* magit-file-checkout <1>: Commands for Buffers Visiting Files. + (line 118) +* magit-file-delete: Commands for Buffers Visiting Files. + (line 112) +* magit-file-dispatch: Commands for Buffers Visiting Files. + (line 22) +* magit-file-rename: Commands for Buffers Visiting Files. + (line 109) +* magit-file-untrack: Commands for Buffers Visiting Files. + (line 115) +* magit-find-file: General-Purpose Visit Commands. + (line 9) +* magit-find-file-other-frame: General-Purpose Visit Commands. + (line 19) +* magit-find-file-other-window: General-Purpose Visit Commands. + (line 14) +* magit-generate-buffer-name-default-function: Naming Buffers. + (line 16) +* magit-get-section: Matching Sections. (line 14) +* magit-git: Calling Git for Effect. + (line 46) +* magit-git-command: Running Git Manually. + (line 25) +* magit-git-command-topdir: Running Git Manually. + (line 17) +* magit-git-exit-code: Getting a Value from Git. + (line 10) +* magit-git-failure: Getting a Value from Git. + (line 17) +* magit-git-false: Getting a Value from Git. + (line 25) +* magit-git-insert: Getting a Value from Git. + (line 29) +* magit-git-items: Getting a Value from Git. + (line 41) +* magit-git-lines: Getting a Value from Git. + (line 37) +* magit-git-str: Getting a Value from Git. + (line 75) +* magit-git-string: Getting a Value from Git. + (line 32) +* magit-git-success: Getting a Value from Git. + (line 13) +* magit-git-true: Getting a Value from Git. + (line 21) +* magit-git-wash: Calling Git for Effect. + (line 50) +* magit-go-backward: Log Buffer. (line 20) +* magit-go-backward <1>: Refreshing Diffs. (line 80) +* magit-go-forward: Log Buffer. (line 23) +* magit-go-forward <1>: Refreshing Diffs. (line 83) +* magit-hunk-set-window-start: Section Movement. (line 45) +* magit-ido-completing-read: Support for Completion Frameworks. + (line 46) +* magit-init: Creating Repository. (line 7) +* magit-insert-am-sequence: Status Sections. (line 25) +* magit-insert-assumed-unchanged-files: Status Sections. (line 98) +* magit-insert-bisect-log: Status Sections. (line 39) +* magit-insert-bisect-output: Status Sections. (line 33) +* magit-insert-bisect-rest: Status Sections. (line 36) +* magit-insert-diff-filter-header: Status Header Sections. + (line 35) +* magit-insert-error-header: Status Header Sections. + (line 26) +* magit-insert-head-branch-header: Status Header Sections. + (line 38) +* magit-insert-heading: Creating Sections. (line 41) +* magit-insert-ignored-files: Status Sections. (line 83) +* magit-insert-local-branches: References Sections. (line 16) +* magit-insert-merge-log: Status Sections. (line 17) +* magit-insert-modules: Status Module Sections. + (line 12) +* magit-insert-modules-overview: Status Module Sections. + (line 30) +* magit-insert-modules-unpulled-from-pushremote: Status Module Sections. + (line 45) +* magit-insert-modules-unpulled-from-upstream: Status Module Sections. + (line 40) +* magit-insert-modules-unpushed-to-pushremote: Status Module Sections. + (line 55) +* magit-insert-modules-unpushed-to-upstream: Status Module Sections. + (line 50) +* magit-insert-push-branch-header: Status Header Sections. + (line 45) +* magit-insert-rebase-sequence: Status Sections. (line 21) +* magit-insert-recent-commits: Status Sections. (line 110) +* magit-insert-remote-branches: References Sections. (line 19) +* magit-insert-remote-header: Status Header Sections. + (line 58) +* magit-insert-repo-header: Status Header Sections. + (line 55) +* magit-insert-section: Creating Sections. (line 6) +* magit-insert-sequencer-sequence: Status Sections. (line 29) +* magit-insert-skip-worktree-files: Status Sections. (line 92) +* magit-insert-staged-changes: Status Sections. (line 53) +* magit-insert-stashes: Status Sections. (line 56) +* magit-insert-status-headers: Status Header Sections. + (line 12) +* magit-insert-tags: References Sections. (line 22) +* magit-insert-tags-header: Status Header Sections. + (line 49) +* magit-insert-tracked-files: Status Sections. (line 80) +* magit-insert-unpulled-cherries: Status Sections. (line 119) +* magit-insert-unpulled-from-pushremote: Status Sections. (line 66) +* magit-insert-unpulled-from-upstream: Status Sections. (line 62) +* magit-insert-unpulled-or-recent-commits: Status Sections. (line 104) +* magit-insert-unpushed-cherries: Status Sections. (line 125) +* magit-insert-unpushed-to-pushremote: Status Sections. (line 74) +* magit-insert-unpushed-to-upstream: Status Sections. (line 70) +* magit-insert-unstaged-changes: Status Sections. (line 50) +* magit-insert-untracked-files: Status Sections. (line 42) +* magit-insert-upstream-branch-header: Status Header Sections. + (line 41) +* magit-insert-user-header: Status Header Sections. + (line 65) +* magit-jump-to-diffstat-or-diff: Commands Available in Diffs. + (line 43) +* magit-kill-this-buffer: Minor Mode for Buffers Visiting Blobs. + (line 19) +* magit-list-repositories: Repository List. (line 6) +* magit-list-submodules: Listing Submodules. (line 13) +* magit-list-submodules <1>: Submodule Transient. (line 48) +* magit-log: Logging. (line 30) +* magit-log <1>: Commands for Buffers Visiting Files. + (line 60) +* magit-log-all: Logging. (line 55) +* magit-log-all-branches: Logging. (line 52) +* magit-log-branches: Logging. (line 49) +* magit-log-buffer-file: Commands for Buffers Visiting Files. + (line 70) +* magit-log-bury-buffer: Log Buffer. (line 14) +* magit-log-current: Logging. (line 35) +* magit-log-double-commit-limit: Log Buffer. (line 64) +* magit-log-half-commit-limit: Log Buffer. (line 67) +* magit-log-head: Logging. (line 46) +* magit-log-maybe-show-more-commits: Section Movement. (line 58) +* magit-log-maybe-update-blob-buffer: Section Movement. (line 72) +* magit-log-maybe-update-revision-buffer: Section Movement. (line 65) +* magit-log-move-to-parent: Log Buffer. (line 26) +* magit-log-move-to-revision: Log Buffer. (line 31) +* magit-log-other: Logging. (line 40) +* magit-log-refresh: Refreshing Logs. (line 12) +* magit-log-refresh <1>: Refreshing Logs. (line 17) +* magit-log-refresh <2>: Log Buffer. (line 7) +* magit-log-save-default-arguments: Refreshing Logs. (line 27) +* magit-log-select-pick: Select from Log. (line 21) +* magit-log-select-quit: Select from Log. (line 26) +* magit-log-set-default-arguments: Refreshing Logs. (line 21) +* magit-log-toggle-commit-limit: Log Buffer. (line 59) +* magit-log-trace-definition: Commands for Buffers Visiting Files. + (line 76) +* magit-margin-settings: Log Margin. (line 52) +* magit-maybe-set-dedicated: Switching Buffers. (line 89) +* magit-merge: Merging. (line 10) +* magit-merge <1>: Merging. (line 82) +* magit-merge-abort: Merging. (line 87) +* magit-merge-absorb: Merging. (line 42) +* magit-merge-editmsg: Merging. (line 30) +* magit-merge-into: Merging. (line 54) +* magit-merge-nocommit: Merging. (line 36) +* magit-merge-plain: Merging. (line 18) +* magit-merge-preview: Merging. (line 75) +* magit-merge-squash: Merging. (line 67) +* magit-mode-bury-buffer: Quitting Windows. (line 7) +* magit-mode-display-buffer: Refreshing Buffers. (line 32) +* magit-mode-quit-window: Quitting Windows. (line 31) +* magit-mode-setup: Refreshing Buffers. (line 17) +* magit-notes: Notes. (line 9) +* magit-notes-edit: Notes. (line 14) +* magit-notes-merge: Notes. (line 35) +* magit-notes-merge-abort: Notes. (line 47) +* magit-notes-merge-commit: Notes. (line 43) +* magit-notes-prune: Notes. (line 28) +* magit-notes-remove: Notes. (line 21) +* magit-patch: Plain Patches. (line 7) +* magit-patch-apply: Plain Patches. (line 20) +* magit-patch-apply <1>: Maildir Patches. (line 23) +* magit-patch-create: Plain Patches. (line 12) +* magit-patch-save: Plain Patches. (line 26) +* magit-pop-revision-stack: Using the Revision Stack. + (line 7) +* magit-process: Viewing Git Output. (line 17) +* magit-process-file: Getting a Value from Git. + (line 57) +* magit-process-git: Getting a Value from Git. + (line 50) +* magit-process-kill: Viewing Git Output. (line 24) +* magit-pull: Pulling. (line 10) +* magit-pull-branch: Pulling. (line 28) +* magit-pull-from-pushremote: Pulling. (line 14) +* magit-pull-from-upstream: Pulling. (line 21) +* magit-push: Pushing. (line 10) +* magit-push-current: Pushing. (line 29) +* magit-push-current-to-pushremote: Pushing. (line 15) +* magit-push-current-to-upstream: Pushing. (line 22) +* magit-push-implicitly: Pushing. (line 74) +* magit-push-matching: Pushing. (line 45) +* magit-push-other: Pushing. (line 33) +* magit-push-refspecs: Pushing. (line 37) +* magit-push-tag: Pushing. (line 59) +* magit-push-tags: Pushing. (line 52) +* magit-push-to-remote: Pushing. (line 91) +* magit-rebase: Rebasing. (line 10) +* magit-rebase-abort: Rebasing. (line 111) +* magit-rebase-autosquash: Rebasing. (line 79) +* magit-rebase-branch: Rebasing. (line 42) +* magit-rebase-continue: Rebasing. (line 97) +* magit-rebase-edit: Rebasing. (line 107) +* magit-rebase-edit-commit: Rebasing. (line 83) +* magit-rebase-interactive: Rebasing. (line 76) +* magit-rebase-onto-pushremote: Rebasing. (line 28) +* magit-rebase-onto-upstream: Rebasing. (line 35) +* magit-rebase-remove-commit: Rebasing. (line 91) +* magit-rebase-reword-commit: Rebasing. (line 87) +* magit-rebase-skip: Rebasing. (line 103) +* magit-rebase-subset: Rebasing. (line 47) +* magit-reflog-current: Reflog. (line 12) +* magit-reflog-head: Reflog. (line 18) +* magit-reflog-other: Reflog. (line 15) +* magit-refresh: Automatic Refreshing of Magit Buffers. + (line 26) +* magit-refresh-all: Automatic Refreshing of Magit Buffers. + (line 34) +* magit-refs-set-show-commit-count: References Buffer. (line 34) +* magit-region-sections: Section Selection. (line 9) +* magit-region-values: Section Selection. (line 35) +* magit-remote: Remote Commands. (line 14) +* magit-remote-add: Remote Commands. (line 48) +* magit-remote-configure: Remote Commands. (line 32) +* magit-remote-prune: Remote Commands. (line 63) +* magit-remote-prune-refspecs: Remote Commands. (line 67) +* magit-remote-remove: Remote Commands. (line 60) +* magit-remote-rename: Remote Commands. (line 52) +* magit-remote-set-url: Remote Commands. (line 56) +* magit-repolist-column-branch: Repository List. (line 45) +* magit-repolist-column-branches: Repository List. (line 52) +* magit-repolist-column-flag: Repository List. (line 58) +* magit-repolist-column-ident: Repository List. (line 34) +* magit-repolist-column-path: Repository List. (line 38) +* magit-repolist-column-stashes: Repository List. (line 55) +* magit-repolist-column-unpulled-from-pushremote: Repository List. + (line 74) +* magit-repolist-column-unpulled-from-upstream: Repository List. + (line 70) +* magit-repolist-column-unpushed-to-pushremote: Repository List. + (line 82) +* magit-repolist-column-unpushed-to-upstream: Repository List. + (line 78) +* magit-repolist-column-upstream: Repository List. (line 48) +* magit-repolist-column-version: Repository List. (line 41) +* magit-reset-hard: Resetting. (line 24) +* magit-reset-index: Staging and Unstaging. + (line 78) +* magit-reset-index <1>: Resetting. (line 33) +* magit-reset-keep: Resetting. (line 28) +* magit-reset-mixed: Resetting. (line 15) +* magit-reset-quickly: Resetting. (line 9) +* magit-reset-soft: Resetting. (line 19) +* magit-reset-worktree: Resetting. (line 39) +* magit-reset-worktree <1>: Wip Modes. (line 64) +* magit-restore-window-configuration: Quitting Windows. (line 21) +* magit-reverse: Applying. (line 47) +* magit-reverse-in-index: Staging and Unstaging. + (line 58) +* magit-revert: Reverting. (line 7) +* magit-revert-and-commit: Reverting. (line 15) +* magit-revert-no-commit: Reverting. (line 20) +* magit-run: Running Git Manually. + (line 13) +* magit-run-git: Calling Git for Effect. + (line 34) +* magit-run-git-async: Calling Git for Effect. + (line 59) +* magit-run-git-gui: Running Git Manually. + (line 59) +* magit-run-git-with-editor: Calling Git for Effect. + (line 71) +* magit-run-git-with-input: Calling Git for Effect. + (line 37) +* magit-run-gitk: Running Git Manually. + (line 50) +* magit-run-gitk-all: Running Git Manually. + (line 53) +* magit-run-gitk-branches: Running Git Manually. + (line 56) +* magit-save-window-configuration: Switching Buffers. (line 80) +* magit-section-backward: Section Movement. (line 11) +* magit-section-backward-siblings: Section Movement. (line 19) +* magit-section-case: Matching Sections. (line 66) +* magit-section-cycle: Section Visibility. (line 13) +* magit-section-cycle-diffs: Section Visibility. (line 16) +* magit-section-cycle-global: Section Visibility. (line 20) +* magit-section-forward: Section Movement. (line 16) +* magit-section-forward-siblings: Section Movement. (line 24) +* magit-section-hide: Section Visibility. (line 42) +* magit-section-hide-children: Section Visibility. (line 54) +* magit-section-ident: Matching Sections. (line 10) +* magit-section-match: Matching Sections. (line 18) +* magit-section-set-window-start: Section Movement. (line 52) +* magit-section-show: Section Visibility. (line 39) +* magit-section-show-children: Section Visibility. (line 49) +* magit-section-show-headings: Section Visibility. (line 45) +* magit-section-show-level-1: Section Visibility. (line 26) +* magit-section-show-level-1-all: Section Visibility. (line 32) +* magit-section-show-level-2: Section Visibility. (line 26) +* magit-section-show-level-2-all: Section Visibility. (line 32) +* magit-section-show-level-3: Section Visibility. (line 26) +* magit-section-show-level-3-all: Section Visibility. (line 32) +* magit-section-show-level-4: Section Visibility. (line 26) +* magit-section-show-level-4-all: Section Visibility. (line 32) +* magit-section-toggle: Section Visibility. (line 10) +* magit-section-toggle-children: Section Visibility. (line 57) +* magit-section-up: Section Movement. (line 28) +* magit-section-value-if: Matching Sections. (line 57) +* magit-sequence-abort: Cherry Picking. (line 91) +* magit-sequence-abort <1>: Reverting. (line 35) +* magit-sequence-continue: Cherry Picking. (line 85) +* magit-sequence-continue <1>: Reverting. (line 29) +* magit-sequence-skip: Cherry Picking. (line 88) +* magit-sequence-skip <1>: Reverting. (line 32) +* magit-shell-command: Running Git Manually. + (line 38) +* magit-shell-command-topdir: Running Git Manually. + (line 34) +* magit-show-commit: Diffing. (line 63) +* magit-show-commit <1>: Blaming. (line 71) +* magit-show-refs: References Buffer. (line 7) +* magit-show-refs-current: References Buffer. (line 25) +* magit-show-refs-head: References Buffer. (line 21) +* magit-show-refs-other: References Buffer. (line 30) +* magit-snapshot-both: Stashing. (line 36) +* magit-snapshot-index: Stashing. (line 42) +* magit-snapshot-worktree: Stashing. (line 46) +* magit-stage: Staging and Unstaging. + (line 29) +* magit-stage-file: Staging from File-Visiting Buffers. + (line 11) +* magit-stage-file <1>: Commands for Buffers Visiting Files. + (line 29) +* magit-stage-modified: Staging and Unstaging. + (line 36) +* magit-start-git: Calling Git for Effect. + (line 82) +* magit-start-process: Calling Git for Effect. + (line 100) +* magit-stash: Stashing. (line 9) +* magit-stash-apply: Stashing. (line 52) +* magit-stash-both: Stashing. (line 14) +* magit-stash-branch: Stashing. (line 70) +* magit-stash-branch-here: Stashing. (line 74) +* magit-stash-clear: Stashing. (line 82) +* magit-stash-drop: Stashing. (line 63) +* magit-stash-format-patch: Stashing. (line 79) +* magit-stash-index: Stashing. (line 20) +* magit-stash-keep-index: Stashing. (line 30) +* magit-stash-list: Stashing. (line 85) +* magit-stash-pop: Stashing. (line 57) +* magit-stash-show: Diffing. (line 67) +* magit-stash-show <1>: Stashing. (line 67) +* magit-stash-worktree: Stashing. (line 24) +* magit-stashes-maybe-update-stash-buffer: Section Movement. (line 92) +* magit-status: Status Buffer. (line 23) +* magit-status-maybe-update-blob-buffer: Section Movement. (line 87) +* magit-status-maybe-update-revision-buffer: Section Movement. + (line 77) +* magit-status-maybe-update-stash-buffer: Section Movement. (line 82) +* magit-status-quick: Status Buffer. (line 70) +* magit-submodule: Submodule Transient. (line 7) +* magit-submodule-add: Submodule Transient. (line 20) +* magit-submodule-fetch: Fetching. (line 48) +* magit-submodule-populate: Submodule Transient. (line 32) +* magit-submodule-register: Submodule Transient. (line 26) +* magit-submodule-synchronize: Submodule Transient. (line 40) +* magit-submodule-unpopulate: Submodule Transient. (line 45) +* magit-submodule-update: Submodule Transient. (line 36) +* magit-subtree: Subtree. (line 9) +* magit-subtree-add: Subtree. (line 24) +* magit-subtree-add-commit: Subtree. (line 28) +* magit-subtree-export: Subtree. (line 37) +* magit-subtree-import: Subtree. (line 13) +* magit-subtree-merge: Subtree. (line 31) +* magit-subtree-pull: Subtree. (line 34) +* magit-subtree-push: Subtree. (line 48) +* magit-subtree-split: Subtree. (line 52) +* magit-switch-to-repository-buffer: Common Commands. (line 6) +* magit-switch-to-repository-buffer-other-frame: Common Commands. + (line 8) +* magit-switch-to-repository-buffer-other-window: Common Commands. + (line 7) +* magit-tag: Tagging. (line 9) +* magit-tag-create: Tagging. (line 14) +* magit-tag-delete: Tagging. (line 37) +* magit-tag-prune: Tagging. (line 43) +* magit-tag-release: Tagging. (line 18) +* magit-toggle-buffer-lock: Modes and Buffers. (line 18) +* magit-toggle-margin: Refreshing Logs. (line 34) +* magit-toggle-margin <1>: Log Margin. (line 60) +* magit-toggle-margin-details: Log Margin. (line 66) +* magit-toggle-verbose-refresh: Debugging Tools. (line 29) +* magit-unstage: Staging and Unstaging. + (line 42) +* magit-unstage-all: Staging and Unstaging. + (line 50) +* magit-unstage-file: Staging from File-Visiting Buffers. + (line 18) +* magit-unstage-file <1>: Commands for Buffers Visiting Files. + (line 32) +* magit-version: Git Executable. (line 59) +* magit-version <1>: Debugging Tools. (line 11) +* magit-visit-ref: References Buffer. (line 159) +* magit-wip-commit: Wip Modes. (line 85) +* magit-wip-log: Wip Modes. (line 47) +* magit-wip-log-current: Wip Modes. (line 55) +* magit-worktree: Worktree. (line 9) +* magit-worktree-branch: Worktree. (line 16) +* magit-worktree-checkout: Worktree. (line 13) +* magit-worktree-delete: Worktree. (line 22) +* magit-worktree-move: Worktree. (line 19) +* magit-worktree-status: Worktree. (line 26) +* scroll-down: Commands Available in Diffs. + (line 56) +* scroll-up: Commands Available in Diffs. + (line 53) +* with-editor-cancel: Editing Commit Messages. + (line 22) +* with-editor-cancel <1>: Editing Rebase Sequences. + (line 11) +* with-editor-debug: Debugging Tools. (line 41) +* with-editor-finish: Editing Commit Messages. + (line 18) +* with-editor-finish <1>: Editing Rebase Sequences. + (line 7) +* with-editor-usage-message: Commit Mode and Hooks. + (line 52) + + +File: magit.info, Node: Variable Index, Prev: Function and Command Index, Up: Top + +Appendix E Variable Index +************************* + +[index] +* Menu: + +* auto-revert-buffer-list-filter: Automatic Reverting of File-Visiting Buffers. + (line 73) +* auto-revert-interval: Automatic Reverting of File-Visiting Buffers. + (line 69) +* auto-revert-mode: Automatic Reverting of File-Visiting Buffers. + (line 57) +* auto-revert-stop-on-user-input: Automatic Reverting of File-Visiting Buffers. + (line 65) +* auto-revert-use-notify: Automatic Reverting of File-Visiting Buffers. + (line 46) +* auto-revert-verbose: Automatic Reverting of File-Visiting Buffers. + (line 94) +* branch.autoSetupMerge: Branch Git Variables. + (line 71) +* branch.autoSetupRebase: Branch Git Variables. + (line 85) +* branch.NAME.description: Branch Git Variables. + (line 42) +* branch.NAME.merge: Branch Git Variables. + (line 10) +* branch.NAME.pushRemote: Branch Git Variables. + (line 29) +* branch.NAME.rebase: Branch Git Variables. + (line 20) +* branch.NAME.remote: Branch Git Variables. + (line 15) +* core.notesRef: Notes. (line 53) +* git-commit-fill-column: Commit Message Conventions. + (line 18) +* git-commit-finish-query-functions: Commit Message Conventions. + (line 22) +* git-commit-known-pseudo-headers: Commit Pseudo Headers. + (line 9) +* git-commit-major-mode: Commit Mode and Hooks. + (line 12) +* git-commit-setup-hook: Commit Mode and Hooks. + (line 21) +* git-commit-setup-hook <1>: Commit Mode and Hooks. + (line 55) +* git-commit-style-convention-checks: Commit Message Conventions. + (line 42) +* git-commit-summary-max-length: Commit Message Conventions. + (line 13) +* git-rebase-auto-advance: Editing Rebase Sequences. + (line 80) +* git-rebase-confirm-cancel: Editing Rebase Sequences. + (line 86) +* git-rebase-show-instructions: Editing Rebase Sequences. + (line 83) +* global-auto-revert-mode: Automatic Reverting of File-Visiting Buffers. + (line 21) +* magit-auto-revert-immediately: Automatic Reverting of File-Visiting Buffers. + (line 30) +* magit-auto-revert-mode: Automatic Reverting of File-Visiting Buffers. + (line 17) +* magit-auto-revert-tracked-only: Automatic Reverting of File-Visiting Buffers. + (line 51) +* magit-bisect-show-graph: Bisecting. (line 57) +* magit-blame-disable-modes: Blaming. (line 145) +* magit-blame-echo-style: Blaming. (line 131) +* magit-blame-goto-chunk-hook: Blaming. (line 150) +* magit-blame-read-only: Blaming. (line 141) +* magit-blame-styles: Blaming. (line 127) +* magit-blame-time-format: Blaming. (line 137) +* magit-branch-adjust-remote-upstream-alist: Branch Commands. (line 196) +* magit-branch-direct-configure: Branch Commands. (line 19) +* magit-branch-prefer-remote-upstream: Branch Commands. (line 152) +* magit-branch-read-upstream-first: Branch Commands. (line 147) +* magit-buffer-name-format: Naming Buffers. (line 25) +* magit-bury-buffer-function: Quitting Windows. (line 13) +* magit-cherry-margin: Cherries. (line 21) +* magit-clone-always-transient: Cloning Repository. (line 12) +* magit-clone-default-directory: Cloning Repository. (line 78) +* magit-clone-name-alist: Cloning Repository. (line 88) +* magit-clone-set-remote-head: Cloning Repository. (line 60) +* magit-clone-set-remote.pushDefault: Cloning Repository. (line 69) +* magit-clone-url-format: Cloning Repository. (line 108) +* magit-commit-ask-to-stage: Initiating a Commit. (line 65) +* magit-commit-diff-inhibit-same-window: Initiating a Commit. (line 97) +* magit-commit-extend-override-date: Initiating a Commit. (line 72) +* magit-commit-reword-override-date: Initiating a Commit. (line 75) +* magit-commit-show-diff: Initiating a Commit. (line 69) +* magit-commit-squash-confirm: Initiating a Commit. (line 78) +* magit-completing-read-function: Support for Completion Frameworks. + (line 27) +* magit-define-global-key-bindings: Default Bindings. (line 6) +* magit-diff-adjust-tab-width: Diff Options. (line 17) +* magit-diff-buffer-file-locked: Commands for Buffers Visiting Files. + (line 55) +* magit-diff-extra-stat-arguments: Diff Options. (line 112) +* magit-diff-hide-trailing-cr-characters: Diff Options. (line 77) +* magit-diff-highlight-hunk-region-functions: Diff Options. (line 80) +* magit-diff-highlight-indentation: Diff Options. (line 63) +* magit-diff-highlight-trailing: Diff Options. (line 59) +* magit-diff-paint-whitespace: Diff Options. (line 38) +* magit-diff-paint-whitespace-lines: Diff Options. (line 52) +* magit-diff-refine-hunk: Diff Options. (line 6) +* magit-diff-refine-ignore-whitespace: Diff Options. (line 13) +* magit-diff-unmarked-lines-keep-foreground: Diff Options. (line 105) +* magit-diff-visit-previous-blob: Visiting Files and Blobs from a Diff. + (line 38) +* magit-direct-use-buffer-arguments: Transient Arguments and Buffer Variables. + (line 72) +* magit-display-buffer-function: Switching Buffers. (line 25) +* magit-display-buffer-noselect: Switching Buffers. (line 17) +* magit-dwim-selection: Completion and Confirmation. + (line 42) +* magit-ediff-dwim-show-on-hunks: Ediffing. (line 63) +* magit-ediff-quit-hook: Ediffing. (line 76) +* magit-ediff-show-stash-with-index: Ediffing. (line 70) +* magit-generate-buffer-name-function: Naming Buffers. (line 6) +* magit-git-debug: Viewing Git Output. (line 26) +* magit-git-debug <1>: Getting a Value from Git. + (line 68) +* magit-git-executable: Git Executable. (line 26) +* magit-git-global-arguments: Global Git Arguments. + (line 6) +* magit-keep-region-overlay: The Selection. (line 52) +* magit-list-refs-sortby: Additional Completion Options. + (line 6) +* magit-log-auto-more: Log Buffer. (line 69) +* magit-log-buffer-file-locked: Commands for Buffers Visiting Files. + (line 78) +* magit-log-margin: Log Margin. (line 12) +* magit-log-margin-show-committer-date: Log Margin. (line 44) +* magit-log-section-commit-count: Status Sections. (line 114) +* magit-log-select-margin: Select from Log. (line 28) +* magit-log-show-refname-after-summary: Log Buffer. (line 74) +* magit-log-trace-definition-function: Commands Available in Diffs. + (line 17) +* magit-module-sections-hook: Status Module Sections. + (line 19) +* magit-module-sections-nested: Status Module Sections. + (line 22) +* magit-no-confirm: Action Confirmation. (line 18) +* magit-pop-revision-stack-format: Using the Revision Stack. + (line 34) +* magit-post-commit-hook: Initiating a Commit. (line 86) +* magit-post-display-buffer-hook: Switching Buffers. (line 85) +* magit-pre-display-buffer-hook: Switching Buffers. (line 76) +* magit-prefer-remote-upstream: Branch Git Variables. + (line 109) +* magit-prefix-use-buffer-arguments: Transient Arguments and Buffer Variables. + (line 64) +* magit-process-extreme-logging: Viewing Git Output. (line 44) +* magit-process-raise-error: Calling Git for Effect. + (line 125) +* magit-pull-or-fetch: Fetching. (line 51) +* magit-reflog-margin: Reflog. (line 20) +* magit-refresh-args: Refreshing Buffers. (line 52) +* magit-refresh-buffer-hook: Automatic Refreshing of Magit Buffers. + (line 41) +* magit-refresh-function: Refreshing Buffers. (line 47) +* magit-refresh-status-buffer: Automatic Refreshing of Magit Buffers. + (line 46) +* magit-refs-filter-alist: References Buffer. (line 137) +* magit-refs-focus-column-width: References Buffer. (line 75) +* magit-refs-margin: References Buffer. (line 89) +* magit-refs-margin-for-tags: References Buffer. (line 112) +* magit-refs-pad-commit-counts: References Buffer. (line 45) +* magit-refs-primary-column-width: References Buffer. (line 63) +* magit-refs-sections-hook: References Sections. (line 13) +* magit-refs-show-commit-count: References Buffer. (line 36) +* magit-refs-show-remote-prefix: References Buffer. (line 57) +* magit-remote-add-set-remote.pushDefault: Remote Commands. (line 83) +* magit-remote-direct-configure: Remote Commands. (line 20) +* magit-remote-git-executable: Git Executable. (line 32) +* magit-repolist-columns: Repository List. (line 13) +* magit-repository-directories: Status Buffer. (line 57) +* magit-revision-filter-files-on-follow: Revision Buffer. (line 55) +* magit-revision-insert-related-refs: Revision Buffer. (line 6) +* magit-revision-show-gravatars: Revision Buffer. (line 15) +* magit-revision-use-hash-sections: Revision Buffer. (line 31) +* magit-root-section: Matching Sections. (line 81) +* magit-save-repository-buffers: Automatic Saving of File-Visiting Buffers. + (line 13) +* magit-section-cache-visibility: Section Visibility. (line 82) +* magit-section-initial-visibility-alist: Section Visibility. (line 66) +* magit-section-movement-hook: Section Movement. (line 41) +* magit-section-set-visibility-hook: Section Visibility. (line 92) +* magit-section-show-child-count: Section Options. (line 9) +* magit-section-visibility-indicator: Section Visibility. (line 109) +* magit-shell-command-verbose-prompt: Running Git Manually. + (line 43) +* magit-stashes-margin: Stashing. (line 87) +* magit-status-headers-hook: Status Header Sections. + (line 17) +* magit-status-margin: Status Options. (line 9) +* magit-status-refresh-hook: Status Options. (line 6) +* magit-status-sections-hook: Status Sections. (line 10) +* magit-submodule-list-columns: Listing Submodules. (line 20) +* magit-this-process: Calling Git for Effect. + (line 121) +* magit-uniquify-buffer-names: Naming Buffers. (line 71) +* magit-unstage-committed: Staging and Unstaging. + (line 52) +* magit-update-other-window-delay: Section Movement. (line 97) +* magit-visit-ref-behavior: References Buffer. (line 168) +* magit-wip-after-apply-mode: Legacy Wip Modes. (line 18) +* magit-wip-after-apply-mode-lighter: Legacy Wip Modes. (line 54) +* magit-wip-after-save-local-mode-lighter: Legacy Wip Modes. (line 51) +* magit-wip-after-save-mode: Legacy Wip Modes. (line 13) +* magit-wip-before-change-mode: Legacy Wip Modes. (line 31) +* magit-wip-before-change-mode-lighter: Legacy Wip Modes. (line 57) +* magit-wip-initial-backup-mode: Legacy Wip Modes. (line 35) +* magit-wip-initial-backup-mode-lighter: Legacy Wip Modes. (line 60) +* magit-wip-merge-branch: Wip Graph. (line 6) +* magit-wip-mode: Wip Modes. (line 30) +* magit-wip-mode-lighter: Wip Modes. (line 98) +* magit-wip-namespace: Wip Modes. (line 91) +* notes.displayRef: Notes. (line 57) +* pull.rebase: Branch Git Variables. + (line 50) +* remote.NAME.fetch: Remote Git Variables. + (line 14) +* remote.NAME.push: Remote Git Variables. + (line 23) +* remote.NAME.pushurl: Remote Git Variables. + (line 18) +* remote.NAME.tagOpts: Remote Git Variables. + (line 27) +* remote.NAME.url: Remote Git Variables. + (line 10) +* remote.pushDefault: Branch Git Variables. + (line 62) + + + +Tag Table: +Node: Top754 +Node: Introduction6610 +Node: Installation11326 +Node: Installing from Melpa11656 +Node: Installing from the Git Repository12729 +Node: Post-Installation Tasks15461 +Node: Getting Started16746 +Node: Interface Concepts21986 +Node: Modes and Buffers22347 +Node: Switching Buffers24058 +Node: Naming Buffers28797 +Node: Quitting Windows32100 +Node: Automatic Refreshing of Magit Buffers33838 +Node: Automatic Saving of File-Visiting Buffers36719 +Node: Automatic Reverting of File-Visiting Buffers37903 +Node: Risk of Reverting Automatically42888 +Node: Sections45270 +Node: Section Movement46196 +Node: Section Visibility51070 +Node: Section Hooks57085 +Node: Section Types and Values59491 +Node: Section Options60906 +Node: Transient Commands61377 +Node: Transient Arguments and Buffer Variables62609 +Node: Completion Confirmation and the Selection69620 +Node: Action Confirmation70064 +Node: Completion and Confirmation77916 +Node: The Selection81101 +Node: The hunk-internal region83999 +Node: Support for Completion Frameworks85088 +Node: Additional Completion Options89991 +Node: Running Git90589 +Node: Viewing Git Output90862 +Node: Git Process Status92956 +Node: Running Git Manually93921 +Node: Git Executable96353 +Node: Global Git Arguments99361 +Node: Inspecting100166 +Node: Status Buffer101323 +Node: Status Sections106333 +Node: Status Header Sections111860 +Node: Status Module Sections114479 +Node: Status Options116976 +Node: Repository List118439 +Node: Logging121765 +Node: Refreshing Logs124291 +Node: Log Buffer125712 +Node: Log Margin129912 +Node: Select from Log133065 +Node: Reflog135275 +Node: Cherries136912 +Node: Diffing138750 +Node: Refreshing Diffs141784 +Node: Commands Available in Diffs145293 +Node: Diff Options147807 +Node: Revision Buffer153271 +Node: Ediffing156591 +Node: References Buffer160186 +Node: References Sections170780 +Node: Bisecting171637 +Node: Visiting Files and Blobs173948 +Node: General-Purpose Visit Commands174418 +Node: Visiting Files and Blobs from a Diff175371 +Node: Blaming178815 +Node: Manipulating184950 +Node: Creating Repository185292 +Node: Cloning Repository185829 +Node: Staging and Unstaging191189 +Node: Staging from File-Visiting Buffers195170 +Node: Applying196276 +Node: Committing198349 +Node: Initiating a Commit198932 +Node: Editing Commit Messages204121 +Node: Using the Revision Stack206894 +Node: Commit Pseudo Headers209939 +Node: Commit Mode and Hooks211234 +Node: Commit Message Conventions214162 +Node: Branching216285 +Node: The Two Remotes216511 +Node: Branch Commands219164 +Node: Branch Git Variables231709 +Node: Auxiliary Branch Commands237082 +Node: Merging238198 +Node: Resolving Conflicts242156 +Node: Rebasing247527 +Node: Editing Rebase Sequences252316 +Node: Information About In-Progress Rebase256532 +Ref: Information About In-Progress Rebase-Footnote-1265414 +Node: Cherry Picking266010 +Node: Reverting270344 +Node: Resetting271763 +Node: Stashing273589 +Node: Transferring278200 +Node: Remotes278422 +Node: Remote Commands278574 +Node: Remote Git Variables282613 +Node: Fetching283887 +Node: Pulling286333 +Node: Pushing287359 +Node: Plain Patches291650 +Node: Maildir Patches293121 +Node: Miscellaneous294600 +Node: Tagging294925 +Node: Notes296818 +Node: Submodules299153 +Node: Listing Submodules299371 +Node: Submodule Transient300775 +Node: Subtree303252 +Node: Worktree305183 +Node: Bundle306249 +Node: Common Commands306616 +Node: Wip Modes309244 +Node: Wip Graph314135 +Node: Legacy Wip Modes316448 +Node: Commands for Buffers Visiting Files319335 +Node: Minor Mode for Buffers Visiting Blobs324891 +Node: Customizing325689 +Node: Per-Repository Configuration327285 +Node: Essential Settings329539 +Node: Safety329884 +Node: Performance331645 +Ref: Log Performance334674 +Ref: Diff Performance335984 +Ref: Refs Buffer Performance337325 +Ref: Committing Performance337900 +Node: Microsoft Windows Performance338813 +Node: MacOS Performance340004 +Ref: MacOS Performance-Footnote-1340709 +Node: Default Bindings340791 +Node: Plumbing343032 +Node: Calling Git343861 +Node: Getting a Value from Git345386 +Node: Calling Git for Effect349114 +Node: Section Plumbing355008 +Node: Creating Sections355236 +Node: Section Selection359132 +Node: Matching Sections360928 +Node: Refreshing Buffers366849 +Node: Conventions369993 +Node: Theming Faces370185 +Node: FAQ378290 +Node: FAQ - How to ...?378732 +Node: How to pronounce Magit?379145 +Node: How to show git's output?379947 +Node: How to install the gitman info manual?380733 +Node: How to show diffs for gpg-encrypted files?381703 +Node: How does branching and pushing work?382299 +Node: Can Magit be used as ediff-version-control-package?382662 +Node: Should I disable VC?384680 +Node: FAQ - Issues and Errors385298 +Node: Magit is slow386299 +Node: I changed several thousand files at once and now Magit is unusable386513 +Node: I am having problems committing387242 +Node: I am using MS Windows and cannot push with Magit387723 +Node: I am using OS X and SOMETHING works in shell but not in Magit388340 +Node: Expanding a file to show the diff causes it to disappear389171 +Node: Point is wrong in the COMMIT_EDITMSG buffer389752 +Node: The mode-line information isn't always up-to-date390798 +Node: A branch and tag sharing the same name breaks SOMETHING391861 +Node: My Git hooks work on the command-line but not inside Magit392747 +Node: git-commit-mode isn't used when committing from the command-line393593 +Node: Point ends up inside invisible text when jumping to a file-visiting buffer395864 +Node: I am unable to stage when using Tramp from MS Windows396724 +Node: I am no longer able to save popup defaults397631 +Node: Debugging Tools398591 +Node: Keystroke Index400595 +Node: Function and Command Index433692 +Node: Variable Index484418 + +End Tag Table + + +Local Variables: +coding: utf-8 +End: diff --git a/elpa/magit-section-20210801.1004/dir b/elpa/magit-section-20210801.1004/dir deleted file mode 100644 index 6e446813..00000000 --- a/elpa/magit-section-20210801.1004/dir +++ /dev/null @@ -1,19 +0,0 @@ -This is the file .../info/dir, which contains the -topmost node of the Info hierarchy, called (dir)Top. -The first time you invoke Info you start off looking at this node. - -File: dir, Node: Top This is the top of the INFO tree - - This (the Directory node) gives a menu of major topics. - Typing "q" exits, "H" lists all Info commands, "d" returns here, - "h" gives a primer for first-timers, - "mEmacs" visits the Emacs manual, etc. - - In Emacs, you can click mouse button 2 on a menu item or cross reference - to select it. - -* Menu: - -Emacs -* Magit-Section: (magit-section). - Use Magit sections in your own packages. diff --git a/elpa/magit-section-20210801.1004/magit-section-autoloads.el b/elpa/magit-section-20210801.1004/magit-section-autoloads.el deleted file mode 100644 index 0899fbfa..00000000 --- a/elpa/magit-section-20210801.1004/magit-section-autoloads.el +++ /dev/null @@ -1,26 +0,0 @@ -;;; magit-section-autoloads.el --- automatically extracted autoloads -;; -;;; Code: - -(add-to-list 'load-path (directory-file-name - (or (file-name-directory #$) (car load-path)))) - - -;;;### (autoloads nil "magit-section" "magit-section.el" (0 0 0 0)) -;;; Generated autoloads from magit-section.el - -(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-section" '("isearch-clean-overlays@magit-mode" "magit-"))) - -;;;*** - -;;;### (autoloads nil nil ("magit-section-pkg.el") (0 0 0 0)) - -;;;*** - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; coding: utf-8 -;; End: -;;; magit-section-autoloads.el ends here diff --git a/elpa/magit-section-20210801.1004/magit-section-pkg.el b/elpa/magit-section-20210801.1004/magit-section-pkg.el deleted file mode 100644 index ba629b0c..00000000 --- a/elpa/magit-section-20210801.1004/magit-section-pkg.el +++ /dev/null @@ -1,13 +0,0 @@ -(define-package "magit-section" "20210801.1004" "Sections for read-only buffers" - '((emacs "25.1") - (dash "20210330")) - :commit "7b46191dedba053f1c44d5f13d4283860e26cbd6" :authors - '(("Jonas Bernoulli" . "jonas@bernoul.li")) - :maintainer - '("Jonas Bernoulli" . "jonas@bernoul.li") - :keywords - '("tools") - :url "https://github.com/magit/magit") -;; Local Variables: -;; no-byte-compile: t -;; End: diff --git a/elpa/magit-section-20210801.1004/magit-section.el b/elpa/magit-section-20210801.1004/magit-section.el deleted file mode 100644 index 482b218e..00000000 --- a/elpa/magit-section-20210801.1004/magit-section.el +++ /dev/null @@ -1,1840 +0,0 @@ -;;; magit-section.el --- Sections for read-only buffers -*- lexical-binding: t -*- - -;; 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. - -;; Author: Jonas Bernoulli -;; Maintainer: Jonas Bernoulli - -;; Keywords: tools -;; Homepage: https://github.com/magit/magit -;; Package-Requires: ((emacs "25.1") (dash "20210330")) -;; Package-Version: 3.2.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 -;; the Free Software Foundation; either version 3, or (at your option) -;; any later version. -;; -;; Magit-Section 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. - -;;; Commentary: - -;; 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. - -;;; Code: - -(require 'cl-lib) -(require 'dash) -(require 'eieio) -(require 'seq) -(require 'subr-x) - -(eval-when-compile (require 'benchmark)) - -;;; Hooks - -(defvar magit-section-movement-hook nil - "Hook run by `magit-section-goto'. -That function in turn is used by all section movement commands.") - -(defvar magit-section-highlight-hook - '(magit-section-highlight - magit-section-highlight-selection) - "Functions used to highlight the current section. -Each function is run with the current section as only argument -until one of them returns non-nil.") - -(defvar magit-section-unhighlight-hook nil - "Functions used to unhighlight the previously current section. -Each function is run with the current section as only argument -until one of them returns non-nil. Most sections are properly -unhighlighted without requiring a specialized unhighlighter, -diff-related sections being the only exception.") - -(defvar magit-section-set-visibility-hook - '(magit-section-cached-visibility) - "Hook used to set the initial visibility of a section. -Stop at the first function that returns non-nil. The returned -value should be `show', `hide' or nil. If no function returns -non-nil, determine the visibility as usual, i.e. use the -hardcoded section specific default (see `magit-insert-section').") - -(defvar magit-section-goto-successor-hook nil - "Hook used to go to the same section as was current before a refresh. -This is only used if the standard mechanism for doing so did not -succeed.") - -;;; Options - -(defgroup magit-section nil - "Expandable sections." - :link '(info-link "(magit)Sections") - :group 'extensions) - -(defcustom magit-section-show-child-count t - "Whether to append the number of children to section headings. -This only applies to sections for which doing so makes sense." - :package-version '(magit . "2.1.0") - :group 'magit-section - :type 'boolean) - -(defcustom magit-section-cache-visibility t - "Whether to cache visibility of sections. - -Sections always retain their visibility state when they are being -recreated during a refresh. But if a section disappears and then -later reappears again, then this option controls whether this is -the case. - -If t, then cache the visibility of all sections. If a list of -section types, then only do so for matching sections. If nil, -then don't do so for any sections." - :package-version '(magit . "2.12.0") - :group 'magit-section - :type '(choice (const :tag "Don't cache visibility" nil) - (const :tag "Cache visibility of all sections" t) - (repeat :tag "Cache visibility for section types" symbol))) - -(defcustom magit-section-initial-visibility-alist - '((stashes . hide)) - "Alist controlling the initial visibility of sections. - -Each element maps a section type or lineage to the initial -visibility state for such sections. The state has to be one of -`show' or `hide', or a function that returns one of these symbols. -A function is called with the section as the only argument. - -Use the command `magit-describe-section' to determine a section's -lineage or type. The vector in the output is the section lineage -and the type is the first element of that vector. Wildcards can -be used, see `magit-section-match'. - -Currently this option is only used to override hardcoded defaults, -but in the future it will also be used set the defaults. - -An entry whose key is `magit-status-initial-section' specifies -the visibility of the section `magit-status-goto-initial-section' -jumps to. This does not only override defaults, but also other -entries of this alist." - :package-version '(magit . "2.12.0") - :group 'magit-section - :type '(alist :key-type (sexp :tag "Section type/lineage") - :value-type (choice (const hide) - (const show) - function))) - -(defcustom magit-section-visibility-indicator - (if (window-system) - '(magit-fringe-bitmap> . magit-fringe-bitmapv) - (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. -Otherwise the value has to have one of these two forms: - -\(EXPANDABLE-BITMAP . COLLAPSIBLE-BITMAP) - - Both values have to be variables whose values are fringe - bitmaps. In this case every section that can be expanded or - collapsed gets an indicator in the left fringe. - - To provide extra padding around the indicator, set - `left-fringe-width' in `magit-mode-hook'. - -\(STRING . BOOLEAN) - - In this case STRING (usually an ellipsis) is shown at the end - of the heading of every collapsed section. Expanded sections - get no indicator. The cdr controls whether the appearance of - these ellipsis take section highlighting into account. Doing - so might potentially have an impact on performance, while not - doing so is kinda ugly." - :package-version '(magit . "3.0.0") - :group 'magit-section - :type '(choice (const :tag "No indicators" nil) - (cons :tag "Use +- fringe indicators" - (const magit-fringe-bitmap+) - (const magit-fringe-bitmap-)) - (cons :tag "Use >v fringe indicators" - (const magit-fringe-bitmap>) - (const magit-fringe-bitmapv)) - (cons :tag "Use bold >v fringe indicators)" - (const magit-fringe-bitmap-bold>) - (const magit-fringe-bitmap-boldv)) - (cons :tag "Use custom fringe indicators" - (variable :tag "Expandable bitmap variable") - (variable :tag "Collapsible bitmap variable")) - (cons :tag "Use ellipses at end of headings" - (string :tag "Ellipsis" "…") - (choice :tag "Use face kludge" - (const :tag "Yes (potentially slow)" t) - (const :tag "No (kinda ugly)" nil))))) - -(defcustom magit-keep-region-overlay nil - "Whether to keep the region overlay when there is a valid selection. - -By default Magit removes the regular region overlay if, and only -if, that region constitutes a valid selection as understood by -Magit commands. Otherwise it does not remove that overlay, and -the region looks like it would in other buffers. - -There are two types of such valid selections: hunk-internal -regions and regions that select two or more sibling sections. -In such cases Magit removes the region overlay and instead -highlights a slightly larger range. All text (for hunk-internal -regions) or the headings of all sections (for sibling selections) -that are inside that range (not just inside the region) are acted -on by commands such as the staging command. This buffer range -begins at the beginning of the line on which the region begins -and ends at the end of the line on which the region ends. - -Because Magit acts on this larger range and not the region, it is -actually quite important to visualize that larger range. If we -don't do that, then one might think that these commands act on -the region instead. If you want to *also* visualize the region, -then set this option to t. But please note that when the region -does *not* constitute a valid selection, then the region is -*always* visualized as usual, and that it is usually under such -circumstances that you want to use a non-magit command to act on -the region. - -Besides keeping the region overlay, setting this option to t also -causes all face properties, except for `:foreground', to be -ignored for the faces used to highlight headings of selected -sections. This avoids the worst conflicts that result from -displaying the region and the selection overlays at the same -time. We are not interested in dealing with other conflicts. -In fact we *already* provide a way to avoid all of these -conflicts: *not* changing the value of this option. - -It should be clear by now that we consider it a mistake to set -this to display the region when the Magit selection is also -visualized, but since it has been requested a few times and -because it doesn't cost much to offer this option we do so. -However that might change. If the existence of this option -starts complicating other things, then it will be removed." - :package-version '(magit . "2.3.0") - :group 'magit-section - :type 'boolean) - -(defcustom magit-section-disable-line-numbers t - "In Magit buffers, whether to disable modes that display line numbers. - -Some users who turn on `global-display-line-numbers-mode' (or -`global-nlinum-mode' or `global-linum-mode') expect line numbers -to be displayed everywhere except in Magit buffers. Other users -do not expect Magit buffers to be treated differently. At least -in theory users in the first group should not use the global mode, -but that ship has sailed, thus this option." - :package-version '(magit . "3.0.0") - :group 'magit-section - :type 'boolean) - -;;; Faces - -(defgroup magit-section-faces nil - "Faces used by Magit-Section." - :group 'magit-section - :group 'faces) - -(defface magit-section-highlight - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "grey95") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :background "grey20")) - "Face for highlighting the current section." - :group 'magit-section-faces) - -(defface magit-section-heading - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :foreground "DarkGoldenrod4" - :weight bold) - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :foreground "LightGoldenrod2" - :weight bold)) - "Face for section headings." - :group 'magit-section-faces) - -(defface magit-section-secondary-heading - `((t ,@(and (>= emacs-major-version 27) '(:extend t)) - :weight bold)) - "Face for section headings of some secondary headings." - :group 'magit-section-faces) - -(defface magit-section-heading-selection - `((((class color) (background light)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :foreground "salmon4") - (((class color) (background dark)) - ,@(and (>= emacs-major-version 27) '(:extend t)) - :foreground "LightSalmon3")) - "Face for selected section headings." - :group 'magit-section-faces) - -;;; Classes - -(defvar magit--current-section-hook nil - "Internal variable used for `magit-describe-section'.") - -(defvar magit--section-type-alist nil) - -(defclass magit-section () - ((keymap :initform nil :allocation :class) - (type :initform nil :initarg :type) - (value :initform nil :initarg :value) - (start :initform nil :initarg :start) - (content :initform nil) - (end :initform nil) - (hidden :initform nil) - (washer :initform nil) - (process :initform nil) - (heading-highlight-face :initform nil) - (inserter :initform (symbol-value 'magit--current-section-hook)) - (parent :initform nil :initarg :parent) - (children :initform nil))) - -;;; Mode - -(defvar symbol-overlay-inhibit-map) - -(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 [C-tab] 'magit-section-cycle) - (define-key map [M-tab] 'magit-section-cycle) - ;; [backtab] is the most portable binding for Shift+Tab. - (define-key map [backtab] 'magit-section-cycle-global) - (define-key map (kbd "^") 'magit-section-up) - (define-key map (kbd "p") 'magit-section-backward) - (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 "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) - (define-key map (kbd "M-4") 'magit-section-show-level-4-all) - map)) - -(define-derived-mode magit-section-mode special-mode "Magit-Sections" - "Parent major mode from which major modes with Magit-like sections inherit. - -Magit-Section is documented in info node `(magit-section)'." - :group 'magit-section - (buffer-disable-undo) - (setq truncate-lines t) - (setq buffer-read-only t) - (setq-local line-move-visual t) ; see #1771 - ;; Turn off syntactic font locking, but not by setting - ;; `font-lock-defaults' because that would enable font locking, and - ;; not all magit plugins may be ready for that (see #3950). - (setq-local font-lock-syntactic-face-function #'ignore) - (setq show-trailing-whitespace nil) - (setq-local symbol-overlay-inhibit-map t) - (setq list-buffers-directory (abbreviate-file-name default-directory)) - ;; (hack-dir-local-variables-non-file-buffer) - (make-local-variable 'text-property-default-nonsticky) - (push (cons 'keymap t) text-property-default-nonsticky) - (add-hook 'post-command-hook #'magit-section-update-highlight t t) - (add-hook 'deactivate-mark-hook #'magit-section-update-highlight t t) - (setq-local redisplay-highlight-region-function - 'magit-section--highlight-region) - (setq-local redisplay-unhighlight-region-function - 'magit-section--unhighlight-region) - (when magit-section-disable-line-numbers - (when (bound-and-true-p global-linum-mode) - (linum-mode -1)) - (when (and (fboundp 'nlinum-mode) - (bound-and-true-p global-nlinum-mode)) - (nlinum-mode -1)) - (when (and (fboundp 'display-line-numbers-mode) - (bound-and-true-p global-display-line-numbers-mode)) - (display-line-numbers-mode -1))) - (when (fboundp 'magit-preserve-section-visibility-cache) - (add-hook 'kill-buffer-hook #'magit-preserve-section-visibility-cache))) - -;;; Core - -(defvar-local magit-root-section nil - "The root section in the current buffer. -All other sections are descendants of this section. The value -of this variable is set by `magit-insert-section' and you should -never modify it.") -(put 'magit-root-section 'permanent-local t) - -(defun magit-current-section () - "Return the section at point." - (or (get-text-property (point) 'magit-section) magit-root-section)) - -(defun magit-section-ident (section) - "Return an unique identifier for SECTION. -The return value has the form ((TYPE . VALUE)...)." - (with-slots (type value parent) section - (cons (cons type - (cond ((eieio-object-p value) - (magit-section-ident-value value)) - ((not (memq type '(unpulled unpushed))) value) - ((string-match-p "@{upstream}" value) value) - ;; Unfortunately Git chokes on "@{push}" when - ;; the value of `push.default' does not allow a - ;; 1:1 mapping. Arbitrary commands may consult - ;; the section value so we cannot use "@{push}". - ;; But `unpushed' and `unpulled' sections should - ;; keep their identity when switching branches - ;; so we have to use another value here. - ((string-match-p "\\`\\.\\." value) "..@{push}") - (t "@{push}.."))) - (and parent - (magit-section-ident parent))))) - -(cl-defgeneric magit-section-ident-value (value) - "Return a constant representation of VALUE. -VALUE is the value of a `magit-section' object. If that is an -object itself, then that is not suitable to be used to identify -the section because two objects may represent the same thing but -not be equal. If possible a method should be added for such -objects, which returns a value that is equal. Otherwise the -catch-all method is used, which just returns the argument -itself.") - -(cl-defmethod magit-section-ident-value (arg) arg) - -(defun magit-get-section (ident &optional root) - "Return the section identified by IDENT. -IDENT has to be a list as returned by `magit-section-ident'. -If optional ROOT is non-nil, then search in that section tree -instead of in the one whose root `magit-root-section' is." - (setq ident (reverse ident)) - (let ((section (or root magit-root-section))) - (when (eq (car (pop ident)) - (oref section type)) - (while (and ident - (pcase-let* ((`(,type . ,value) (car ident)) - (value (magit-section-ident-value value))) - (setq section - (cl-find-if (lambda (section) - (and (eq (oref section type) type) - (equal (magit-section-ident-value - (oref section value)) - value))) - (oref section children))))) - (pop ident)) - section))) - -(defun magit-section-lineage (section) - "Return the lineage of SECTION. -The return value has the form (TYPE...)." - (cons (oref section type) - (when-let ((parent (oref section parent))) - (magit-section-lineage parent)))) - -(defvar magit-insert-section--current nil "For internal use only.") -(defvar magit-insert-section--parent nil "For internal use only.") -(defvar magit-insert-section--oldroot nil "For internal use only.") - -;;; Commands -;;;; Movement - -(defun magit-section-forward () - "Move to the beginning of the next visible section." - (interactive) - (if (eobp) - (user-error "No next section") - (let ((section (magit-current-section))) - (if (oref section parent) - (let ((next (and (not (oref section hidden)) - (not (= (oref section end) - (1+ (point)))) - (car (oref section children))))) - (while (and section (not next)) - (unless (setq next (car (magit-section-siblings section 'next))) - (setq section (oref section parent)))) - (if next - (magit-section-goto next) - (user-error "No next section"))) - (magit-section-goto 1))))) - -(defun magit-section-backward () - "Move to the beginning of the current or the previous visible section. -When point is at the beginning of a section then move to the -beginning of the previous visible section. Otherwise move to -the beginning of the current section." - (interactive) - (if (bobp) - (user-error "No previous section") - (let ((section (magit-current-section)) children) - (cond - ((and (= (point) - (1- (oref section end))) - (setq children (oref section children))) - (magit-section-goto (car (last children)))) - ((and (oref section parent) - (not (= (point) - (oref section start)))) - (magit-section-goto section)) - (t - (let ((prev (car (magit-section-siblings section 'prev)))) - (if prev - (while (and (not (oref prev hidden)) - (setq children (oref prev children))) - (setq prev (car (last children)))) - (setq prev (oref section parent))) - (cond (prev - (magit-section-goto prev)) - ((oref section parent) - (user-error "No previous section")) - ;; Eob special cases. - ((not (get-text-property (1- (point)) 'invisible)) - (magit-section-goto -1)) - (t - (goto-char (previous-single-property-change - (1- (point)) 'invisible)) - (forward-line -1) - (magit-section-goto (magit-current-section)))))))))) - -(defun magit-section-up () - "Move to the beginning of the parent section." - (interactive) - (--if-let (oref (magit-current-section) parent) - (magit-section-goto it) - (user-error "No parent section"))) - -(defun magit-section-forward-sibling () - "Move to the beginning of the next sibling section. -If there is no next sibling section, then move to the parent." - (interactive) - (let ((current (magit-current-section))) - (if (oref current parent) - (--if-let (car (magit-section-siblings current 'next)) - (magit-section-goto it) - (magit-section-forward)) - (magit-section-goto 1)))) - -(defun magit-section-backward-sibling () - "Move to the beginning of the previous sibling section. -If there is no previous sibling section, then move to the parent." - (interactive) - (let ((current (magit-current-section))) - (if (oref current parent) - (--if-let (car (magit-section-siblings current 'prev)) - (magit-section-goto it) - (magit-section-backward)) - (magit-section-goto -1)))) - -(defun magit-section-goto (arg) - (if (integerp arg) - (progn (forward-line arg) - (setq arg (magit-current-section))) - (goto-char (oref arg start))) - (run-hook-with-args 'magit-section-movement-hook arg)) - -(defun magit-section-set-window-start (section) - "Ensure the beginning of SECTION is visible." - (unless (pos-visible-in-window-p (oref section end)) - (set-window-start (selected-window) (oref section start)))) - -(defmacro magit-define-section-jumper (name heading type &optional value) - "Define an interactive function to go some section. -Together TYPE and VALUE identify the section. -HEADING is the displayed heading of the section." - (declare (indent defun)) - `(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))))) - -;;;; Visibility - -(defun magit-section-show (section) - "Show the body of the current section." - (interactive (list (magit-current-section))) - (oset section hidden nil) - (magit-section--maybe-wash section) - (when-let ((beg (oref section content))) - (remove-overlays beg (oref section end) 'invisible t)) - (magit-section-maybe-update-visibility-indicator section) - (magit-section-maybe-cache-visibility section) - (dolist (child (oref section children)) - (if (oref child hidden) - (magit-section-hide child) - (magit-section-show child)))) - -(defun magit-section--maybe-wash (section) - (when-let ((washer (oref section washer))) - (oset section washer nil) - (let ((inhibit-read-only t) - (magit-insert-section--parent section) - (content (oref section content))) - (save-excursion - (if (and content (< content (oref section end))) - (funcall washer section) ; already partially washed (hunk) - (goto-char (oref section end)) - (oset section content (point-marker)) - (funcall washer) - (oset section end (point-marker))))) - (magit-section-update-highlight))) - -(defun magit-section-hide (section) - "Hide the body of the current section." - (interactive (list (magit-current-section))) - (if (eq section magit-root-section) - (user-error "Cannot hide root section") - (oset section hidden t) - (when-let ((beg (oref section content))) - (let ((end (oref section end))) - (remove-overlays beg end 'invisible t) - (let ((o (make-overlay beg end))) - (overlay-put o 'evaporate t) - (overlay-put o 'invisible t)))) - (magit-section-maybe-update-visibility-indicator section) - (magit-section-maybe-cache-visibility section))) - -(defun magit-section-toggle (section) - "Toggle visibility of the body of the current section." - (interactive (list (magit-current-section))) - (if (eq section magit-root-section) - (user-error "Cannot hide root section") - (goto-char (oref section start)) - (if (oref section hidden) - (magit-section-show section) - (magit-section-hide section)))) - -(defun magit-section-toggle-children (section) - "Toggle visibility of bodies of children of the current section." - (interactive (list (magit-current-section))) - (goto-char (oref section start)) - (let* ((children (oref section children)) - (show (--any-p (oref it hidden) children))) - (dolist (c children) - (oset c hidden show))) - (magit-section-show section)) - -(defun magit-section-show-children (section &optional depth) - "Recursively show the bodies of children of the current section. -With a prefix argument show children that deep and hide deeper -children." - (interactive (list (magit-current-section))) - (magit-section-show-children-1 section depth) - (magit-section-show section)) - -(defun magit-section-show-children-1 (section &optional depth) - (dolist (child (oref section children)) - (oset child hidden nil) - (if depth - (if (> depth 0) - (magit-section-show-children-1 child (1- depth)) - (magit-section-hide child)) - (magit-section-show-children-1 child)))) - -(defun magit-section-hide-children (section) - "Recursively hide the bodies of children of the current section." - (interactive (list (magit-current-section))) - (mapc 'magit-section-hide (oref section children))) - -(defun magit-section-show-headings (section) - "Recursively show headings of children of the current section. -Only show the headings, previously shown text-only bodies are -hidden." - (interactive (list (magit-current-section))) - (magit-section-show-headings-1 section) - (magit-section-show section)) - -(defun magit-section-show-headings-1 (section) - (dolist (child (oref section children)) - (oset child hidden nil) - (when (or (oref child children) - (not (oref child content))) - (magit-section-show-headings-1 child)))) - -(defun magit-section-cycle (section) - "Cycle visibility of current section and its children." - (interactive (list (magit-current-section))) - (goto-char (oref section start)) - (if (oref section hidden) - (progn (magit-section-show section) - (magit-section-hide-children section)) - (let ((children (oref section children))) - (cond ((and (--any-p (oref it hidden) children) - (--any-p (oref it children) children)) - (magit-section-show-headings section)) - ((seq-some 'magit-section-hidden-body children) - (magit-section-show-children section)) - (t - (magit-section-hide section)))))) - -(defun magit-section-cycle-global () - "Cycle visibility of all sections in the current buffer." - (interactive) - (let ((children (oref magit-root-section children))) - (cond ((and (--any-p (oref it hidden) children) - (--any-p (oref it children) children)) - (magit-section-show-headings magit-root-section)) - ((seq-some 'magit-section-hidden-body children) - (magit-section-show-children magit-root-section)) - (t - (mapc 'magit-section-hide children))))) - -(defun magit-section-hidden-body (section &optional pred) - (--if-let (oref section children) - (funcall (or pred '-any-p) 'magit-section-hidden-body it) - (and (oref section content) - (oref section hidden)))) - -(defun magit-section-invisible-p (section) - "Return t if the SECTION's body is invisible. -When the body of an ancestor of SECTION is collapsed then -SECTION's body (and heading) obviously cannot be visible." - (or (oref section hidden) - (--when-let (oref section parent) - (magit-section-invisible-p it)))) - -(defun magit-section-show-level (level) - "Show surrounding sections up to LEVEL. -If LEVEL is negative, show up to the absolute value. -Sections at higher levels are hidden." - (if (< level 0) - (let ((s (magit-current-section))) - (setq level (- level)) - (while (> (1- (length (magit-section-ident s))) level) - (setq s (oref s parent)) - (goto-char (oref s start))) - (magit-section-show-children magit-root-section (1- level))) - (cl-do* ((s (magit-current-section) - (oref s parent)) - (i (1- (length (magit-section-ident s))) - (cl-decf i))) - ((cond ((< i level) (magit-section-show-children s (- level i 1)) t) - ((= i level) (magit-section-hide s) t)) - (magit-section-goto s))))) - -(defun magit-section-show-level-1 () - "Show surrounding sections on first level." - (interactive) - (magit-section-show-level 1)) - -(defun magit-section-show-level-1-all () - "Show all sections on first level." - (interactive) - (magit-section-show-level -1)) - -(defun magit-section-show-level-2 () - "Show surrounding sections up to second level." - (interactive) - (magit-section-show-level 2)) - -(defun magit-section-show-level-2-all () - "Show all sections up to second level." - (interactive) - (magit-section-show-level -2)) - -(defun magit-section-show-level-3 () - "Show surrounding sections up to third level." - (interactive) - (magit-section-show-level 3)) - -(defun magit-section-show-level-3-all () - "Show all sections up to third level." - (interactive) - (magit-section-show-level -3)) - -(defun magit-section-show-level-4 () - "Show surrounding sections up to fourth level." - (interactive) - (magit-section-show-level 4)) - -(defun magit-section-show-level-4-all () - "Show all sections up to fourth level." - (interactive) - (magit-section-show-level -4)) - -;;;; Auxiliary - -(defun magit-describe-section-briefly (section &optional ident) - "Show information about the section at point. -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%s>" - (eieio-object-class section) - (let ((val (oref section value))) - (cond ((stringp val) - (substring-no-properties val)) - ((and (eieio-object-p val) - (fboundp 'cl-prin1-to-string)) - (cl-prin1-to-string val)) - (t - val))) - (if ident - (magit-section-ident section) - (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) - (message "%s" str) - str))) - -(cl-defmethod cl-print-object ((section magit-section) stream) - "Print `magit-describe-section' result of SECTION." - ;; Used by debug and edebug as of Emacs 26. - (princ (magit-describe-section-briefly section) stream)) - -(defun magit-describe-section (section &optional interactive-p) - "Show information about the section at point." - (interactive (list (magit-current-section) t)) - (let ((inserter-section section)) - (while (and inserter-section (not (oref inserter-section inserter))) - (setq inserter-section (oref inserter-section parent))) - (when (and inserter-section (oref inserter-section inserter)) - (setq section inserter-section))) - (pcase (oref section inserter) - (`((,hook ,fun) . ,src-src) - (help-setup-xref `(magit-describe-section ,section) interactive-p) - (with-help-window (help-buffer) - (with-current-buffer standard-output - (insert (format-message - "%s\n is inserted by `%s'\n from `%s'" - (magit-describe-section-briefly section) - (make-text-button (symbol-name fun) nil - :type 'help-function - 'help-args (list fun)) - (make-text-button (symbol-name hook) nil - :type 'help-variable - 'help-args (list hook)))) - (pcase-dolist (`(,hook ,fun) src-src) - (insert (format-message - ",\n called by `%s'\n from `%s'" - (make-text-button (symbol-name fun) nil - :type 'help-function - 'help-args (list fun)) - (make-text-button (symbol-name hook) nil - :type 'help-variable - 'help-args (list hook))))) - (insert ".\n\n") - (insert - (format-message - "`%s' is " - (make-text-button (symbol-name fun) nil - :type 'help-function 'help-args (list fun)))) - (describe-function-1 fun)))) - (_ (message "%s, inserter unknown" - (magit-describe-section-briefly section))))) - -;;; Match - -(cl-defun magit-section-match - (condition &optional (section (magit-current-section))) - "Return t if SECTION matches CONDITION. - -SECTION defaults to the section at point. If SECTION is not -specified and there also is no section at point, then return -nil. - -CONDITION can take the following forms: - (CONDITION...) matches if any of the CONDITIONs matches. - [CLASS...] matches if the section's class is the same - as the first CLASS or a subclass of that; - the section's parent class matches the - second CLASS; and so on. - [* CLASS...] matches sections that match [CLASS...] and - also recursively all their child sections. - CLASS matches if the section's class is the same - as CLASS or a subclass of that; regardless - of the classes of the parent sections. - -Each CLASS should be a class symbol, identifying a class that -derives from `magit-section'. For backward compatibility CLASS -can also be a \"type symbol\". A section matches such a symbol -if the value of its `type' slot is `eq'. If a type symbol has -an entry in `magit--section-type-alist', then a section also -matches that type if its class is a subclass of the class that -corresponds to the type as per that alist. - -Note that it is not necessary to specify the complete section -lineage as printed by `magit-describe-section-briefly', unless -of course you want to be that precise." - (and section (magit-section-match-1 condition section))) - -(defun magit-section-match-1 (condition section) - (cl-assert condition) - (and section - (if (listp condition) - (--first (magit-section-match-1 it section) condition) - (magit-section-match-2 (if (symbolp condition) - (list condition) - (cl-coerce condition 'list)) - section)))) - -(defun magit-section-match-2 (condition section) - (if (eq (car condition) '*) - (or (magit-section-match-2 (cdr condition) section) - (when-let ((parent (oref section parent))) - (magit-section-match-2 condition parent))) - (and (let ((c (car condition))) - (if (class-p c) - (cl-typep section c) - (if-let ((class (cdr (assq c magit--section-type-alist)))) - (cl-typep section class) - (eq (oref section type) c)))) - (or (not (setq condition (cdr condition))) - (when-let ((parent (oref section parent))) - (magit-section-match-2 condition parent)))))) - -(defun magit-section-value-if (condition &optional section) - "If the section at point matches CONDITION, then return its value. - -If optional SECTION is non-nil then test whether that matches -instead. If there is no section at point and SECTION is nil, -then return nil. If the section does not match, then return -nil. - -See `magit-section-match' for the forms CONDITION can take." - (when-let ((section (or section (magit-current-section)))) - (and (magit-section-match condition section) - (oref section value)))) - -(defmacro magit-section-when (condition &rest body) - "If the section at point matches CONDITION, evaluate BODY. - -If the section matches, then evaluate BODY forms sequentially -with `it' bound to the section and return the value of the last -form. If there are no BODY forms, then return the value of the -section. If the section does not match or if there is no section -at point, then return nil. - -See `magit-section-match' for the forms CONDITION can take." - (declare (obsolete - "instead use `magit-section-match' or `magit-section-value-if'." - "Magit 2.90.0") - (indent 1) - (debug (sexp body))) - `(--when-let (magit-current-section) - ;; Quoting CONDITION here often leads to double-quotes, which - ;; isn't an issue because `magit-section-match-1' implicitly - ;; deals with that. We shouldn't force users of this function - ;; to not quote CONDITION because that would needlessly break - ;; backward compatibility. - (when (magit-section-match ',condition it) - ,@(or body '((oref it value)))))) - -(defmacro magit-section-case (&rest clauses) - "Choose among clauses on the type of the section at point. - -Each clause looks like (CONDITION BODY...). The type of the -section is compared against each CONDITION; the BODY forms of the -first match are evaluated sequentially and the value of the last -form is returned. Inside BODY the symbol `it' is bound to the -section at point. If no clause succeeds or if there is no -section at point, return nil. - -See `magit-section-match' for the forms CONDITION can take. -Additionally a CONDITION of t is allowed in the final clause, and -matches if no other CONDITION match, even if there is no section -at point." - (declare (indent 0) - (debug (&rest (sexp body)))) - `(let* ((it (magit-current-section))) - (cond ,@(mapcar (lambda (clause) - `(,(or (eq (car clause) t) - `(and it - (magit-section-match-1 ',(car clause) it))) - ,@(cdr clause))) - clauses)))) - -(defun magit-section-match-assoc (section alist) - "Return the value associated with SECTION's type or lineage in ALIST." - (seq-some (pcase-lambda (`(,key . ,val)) - (and (magit-section-match-1 key section) val)) - alist)) - -;;; Create - -(defvar magit-insert-section-hook nil - "Hook run after `magit-insert-section's BODY. -Avoid using this hook and only ever do so if you know -what you are doing and are sure there is no other way.") - -(defmacro magit-insert-section (&rest args) - "Insert a section at point. - -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 -refreshing the buffer. Else expand it by default. This can be -overwritten using `magit-section-set-visibility-hook'. When a -section is recreated during a refresh, then the visibility of -predecessor is inherited and HIDE is ignored (but the hook is -still honored). - -BODY is any number of forms that actually insert the section's -heading and body. Optional NAME, if specified, has to be a -symbol, which is then bound to the object of the section being -inserted. - -Before BODY is evaluated the `start' of the section object is set -to the value of `point' and after BODY was evaluated its `end' is -set to the new value of `point'; BODY is responsible for moving -`point' forward. - -If it turns out inside BODY that the section is empty, then -`magit-cancel-section' can be used to abort and remove all traces -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. - -\(fn [NAME] (CLASS &optional VALUE HIDE) &rest BODY)" - (declare (indent defun) - (debug ([&optional symbolp] - (&or [("eval" form) &optional form form] - [symbolp &optional form form]) - body))) - (let ((tp (cl-gensym "type")) - (s* (and (symbolp (car args)) - (pop args))) - (s (cl-gensym "section"))) - `(let* ((,tp ,(let ((type (nth 0 (car args)))) - (if (eq (car-safe type) 'eval) - (cadr type) - `',type))) - (,s (funcall (if (class-p ,tp) - ,tp - (or (cdr (assq ,tp magit--section-type-alist)) - 'magit-section)) - :type - (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 - (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 - (or magit-insert-section--oldroot - (unless magit-insert-section--parent - (prog1 magit-root-section - (setq magit-root-section ,s)))))) - (catch 'cancel-section - ,@(if s* - `((let ((,s* ,s)) - ,@(cdr args))) - (cdr args)) - ;; `magit-insert-section-hook' should *not* be run with - ;; `magit-run-section-hook' because it's a hook that runs - ;; on section insertion, not a section inserting hook. - (run-hooks 'magit-insert-section-hook) - (magit-insert-child-count ,s) - (set-marker-insertion-type (oref ,s start) t) - (let* ((end (oset ,s end (point-marker))) - (class-map (oref-default ,s keymap)) - (magit-map (intern (format "magit-%s-section-map" - (oref ,s type)))) - (forge-map (intern (format "forge-%s-section-map" - (oref ,s type)))) - (map (or (and class-map (symbol-value class-map)) - (and (boundp magit-map) (symbol-value magit-map)) - (and (boundp forge-map) (symbol-value forge-map))))) - (save-excursion - (goto-char (oref ,s start)) - (while (< (point) end) - (let ((next (or (next-single-property-change - (point) 'magit-section) - end))) - (unless (get-text-property (point) 'magit-section) - (put-text-property (point) next 'magit-section ,s) - (when map - (put-text-property (point) next 'keymap map))) - (goto-char next))))) - (if (eq ,s magit-root-section) - (let ((magit-section-cache-visibility nil)) - (magit-section-show ,s)) - (oset (oref ,s parent) children - (nconc (oref (oref ,s parent) children) - (list ,s))))) - ,s)))) - -(defun magit-cancel-section () - "Cancel inserting the section that is currently being inserted. -Remove all traces of that section." - (when magit-insert-section--current - (if (not (oref magit-insert-section--current parent)) - (insert "(empty)\n") - (delete-region (oref magit-insert-section--current start) - (point)) - (setq magit-insert-section--current nil) - (throw 'cancel-section nil)))) - -(defun magit-insert-heading (&rest args) - "Insert the heading for the section currently being inserted. - -This function should only be used inside `magit-insert-section'. - -When called without any arguments, then just set the `content' -slot of the object representing the section being inserted to -a marker at `point'. The section should only contain a single -line when this function is used like this. - -When called with arguments ARGS, which have to be strings, or -nil, then insert those strings at point. The section should not -contain any text before this happens and afterwards it should -again only contain a single line. If the `face' property is set -anywhere inside any of these strings, then insert all of them -unchanged. Otherwise use the `magit-section-heading' face for -all inserted text. - -The `content' property of the section object is the end of the -heading (which lasts from `start' to `content') and the beginning -of the the body (which lasts from `content' to `end'). If the -value of `content' is nil, then the section has no heading and -its body cannot be collapsed. If a section does have a heading, -then its height must be exactly one line, including a trailing -newline character. This isn't enforced, you are responsible for -getting it right. The only exception is that this function does -insert a newline character if necessary." - (declare (indent defun)) - (when args - (let ((heading (apply #'concat args))) - (insert (if (or (text-property-not-all 0 (length heading) - 'font-lock-face nil heading) - (text-property-not-all 0 (length heading) - 'face nil heading)) - heading - (propertize heading 'font-lock-face 'magit-section-heading))))) - (unless (bolp) - (insert ?\n)) - (when (fboundp 'magit-maybe-make-margin-overlay) - (magit-maybe-make-margin-overlay)) - (oset magit-insert-section--current content (point-marker))) - -(defmacro magit-insert-section-body (&rest body) - "Use BODY to insert the section body, once the section is expanded. -If the section is expanded when it is created, then this is -like `progn'. Otherwise BODY isn't evaluated until the section -is explicitly expanded." - (declare (indent 0)) - (let ((f (cl-gensym)) - (s (cl-gensym))) - `(let ((,f (lambda () ,@body)) - (,s magit-insert-section--current)) - (if (oref ,s hidden) - (oset ,s washer - (lambda () - (funcall ,f) - (magit-section-maybe-remove-visibility-indicator ,s))) - (funcall ,f))))) - -(defun magit-insert-headers (hook) - (let* ((header-sections nil) - (magit-insert-section-hook - (cons (lambda () - (push magit-insert-section--current - header-sections)) - (if (listp magit-insert-section-hook) - magit-insert-section-hook - (list magit-insert-section-hook))))) - (magit-run-section-hook hook) - (when header-sections - (insert "\n") - ;; Make the first header into the parent of the rest. - (when (cdr header-sections) - (cl-callf nreverse header-sections) - (let* ((1st-header (pop header-sections)) - (header-parent (oref 1st-header parent))) - (oset header-parent children (list 1st-header)) - (oset 1st-header children header-sections) - (oset 1st-header content (oref (car header-sections) start)) - (oset 1st-header end (oref (car (last header-sections)) end)) - (dolist (sub-header header-sections) - (oset sub-header parent 1st-header))))))) - -(defun magit-insert-child-count (section) - "Modify SECTION's heading to contain number of child sections. - -If `magit-section-show-child-count' is non-nil and the SECTION -has children and its heading ends with \":\", then replace that -with \" (N)\", where N is the number of child sections. - -This function is called by `magit-insert-section' after that has -evaluated its BODY. Admittedly that's a bit of a hack." - ;; This has to be fast, not pretty! - (let (content count) - (when (and magit-section-show-child-count - (setq count (length (oref section children))) - (> count 0) - (setq content (oref section content)) - (eq (char-before (1- content)) ?:)) - (save-excursion - (goto-char (- content 2)) - (insert (format " (%s)" count)) - (delete-char 1))))) - -;;; Highlight - -(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 () - (let ((section (magit-current-section))) - (unless (eq section magit-section-highlighted-section) - (let ((inhibit-read-only t) - (deactivate-mark nil) - (selection (magit-region-sections))) - (mapc #'delete-overlay magit-section-highlight-overlays) - (setq magit-section-highlight-overlays nil) - (setq magit-section-unhighlight-sections - magit-section-highlighted-sections) - (setq magit-section-highlighted-sections nil) - (unless (eq section magit-root-section) - (run-hook-with-args-until-success - 'magit-section-highlight-hook section selection)) - (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))))) - (magit-section-maybe-paint-visibility-ellipses))) - -(defun magit-section-highlight (section selection) - "Highlight SECTION and if non-nil all sections in SELECTION. -This function works for any section but produces undesirable -effects for diff related sections, which by default are -highlighted using `magit-diff-highlight'. Return t." - (when-let ((face (oref section heading-highlight-face))) - (dolist (section (or selection (list section))) - (magit-section-make-overlay - (oref section start) - (or (oref section content) - (oref section end)) - face))) - (cond (selection - (magit-section-make-overlay (oref (car selection) start) - (oref (car (last selection)) end) - 'magit-section-highlight) - (magit-section-highlight-selection nil selection)) - (t - (magit-section-make-overlay (oref section start) - (oref section end) - 'magit-section-highlight))) - t) - -(defun magit-section-highlight-selection (_ selection) - "Highlight the section-selection region. -If SELECTION is non-nil, then it is a list of sections selected by -the region. The headings of these sections are then highlighted. - -This is a fallback for people who don't want to highlight the -current section and therefore removed `magit-section-highlight' -from `magit-section-highlight-hook'. - -This function is necessary to ensure that a representation of -such a region is visible. If neither of these functions were -part of the hook variable, then such a region would be -invisible." - (when (and selection - (not (and (eq this-command 'mouse-drag-region)))) - (dolist (section selection) - (magit-section-make-overlay (oref section start) - (or (oref section content) - (oref section end)) - 'magit-section-heading-selection)) - t)) - -(defun magit-section-make-overlay (start end face) - ;; Yes, this doesn't belong here. But the alternative of - ;; spreading this hack across the code base is even worse. - (when (and magit-keep-region-overlay - (memq face '(magit-section-heading-selection - magit-diff-file-heading-selection - magit-diff-hunk-heading-selection))) - (setq face (list :foreground (face-foreground face)))) - (let ((ov (make-overlay start end nil t))) - (overlay-put ov 'font-lock-face face) - (overlay-put ov 'evaporate t) - (push ov magit-section-highlight-overlays) - ov)) - -(defun magit-section-goto-successor (section line char arg) - (let ((ident (magit-section-ident section))) - (--if-let (magit-get-section ident) - (let ((start (oref it start))) - (goto-char start) - (unless (eq it magit-root-section) - (ignore-errors - (forward-line line) - (forward-char char)) - (unless (eq (magit-current-section) it) - (goto-char start)))) - (or (run-hook-with-args-until-success - 'magit-section-goto-successor-hook section arg) - (goto-char (--if-let (magit-section-goto-successor-1 section) - (if (eq (oref it type) 'button) - (point-min) - (oref it start)) - (point-min))))))) - -(defun magit-section-goto-successor-1 (section) - (or (--when-let (pcase (oref section type) - (`staged 'unstaged) - (`unstaged 'staged) - (`unpushed 'unpulled) - (`unpulled 'unpushed)) - (magit-get-section `((,it) (status)))) - (--when-let (car (magit-section-siblings section 'next)) - (magit-get-section (magit-section-ident it))) - (--when-let (car (magit-section-siblings section 'prev)) - (magit-get-section (magit-section-ident it))) - (--when-let (oref section parent) - (or (magit-get-section (magit-section-ident it)) - (magit-section-goto-successor-1 it))))) - -;;; Region - -(defvar-local magit-section--region-overlays nil) - -(defun magit-section--delete-region-overlays () - (mapc #'delete-overlay magit-section--region-overlays) - (setq magit-section--region-overlays nil)) - -(defun magit-section--highlight-region (start end window rol) - (magit-section--delete-region-overlays) - (if (and (not magit-keep-region-overlay) - (or (magit-region-sections) - (run-hook-with-args-until-success 'magit-region-highlight-hook - (magit-current-section))) - (not (= (line-number-at-pos start) - (line-number-at-pos end))) - ;; (not (eq (car-safe last-command-event) 'mouse-movement)) - ) - (funcall (default-value 'redisplay-unhighlight-region-function) rol) - (funcall (default-value 'redisplay-highlight-region-function) - 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)) - -;;; Visibility - -(defvar-local magit-section-visibility-cache nil) -(put 'magit-section-visibility-cache 'permanent-local t) - -(defun magit-section-cached-visibility (section) - "Set SECTION's visibility to the cached value." - (cdr (assoc (magit-section-ident section) - magit-section-visibility-cache))) - -(cl-defun magit-section-cache-visibility - (&optional (section magit-insert-section--current)) - ;; Emacs 25's `alist-get' lacks TESTFN. - (let* ((id (magit-section-ident section)) - (elt (assoc id magit-section-visibility-cache)) - (val (if (oref section hidden) 'hide 'show))) - (if elt - (setcdr elt val) - (push (cons id val) magit-section-visibility-cache)))) - -(cl-defun magit-section-maybe-cache-visibility - (&optional (section magit-insert-section--current)) - (when (or (eq magit-section-cache-visibility t) - (memq (oref section type) - magit-section-cache-visibility)) - (magit-section-cache-visibility section))) - -(defun magit-section-maybe-update-visibility-indicator (section) - (when magit-section-visibility-indicator - (let ((beg (oref section start)) - (cnt (oref section content)) - (end (oref section end))) - (when (and cnt (or (not (= cnt end)) (oref section washer))) - (let ((eoh (save-excursion - (goto-char beg) - (line-end-position)))) - (cond - ((symbolp (car-safe magit-section-visibility-indicator)) - ;; It would make more sense to put the overlay only on the - ;; location we actually don't put it on, but then inserting - ;; before that location (while taking care not to mess with - ;; the overlay) would cause the fringe bitmap to disappear - ;; (but not other effects of the overlay). - (let ((ov (magit--overlay-at (1+ beg) 'magit-vis-indicator 'fringe))) - (unless ov - (setq ov (make-overlay (1+ beg) eoh)) - (overlay-put ov 'evaporate t) - (overlay-put ov 'magit-vis-indicator 'fringe)) - (overlay-put - ov 'before-string - (propertize "fringe" 'display - (list 'left-fringe - (if (oref section hidden) - (car magit-section-visibility-indicator) - (cdr magit-section-visibility-indicator)) - 'fringe))))) - ((stringp (car-safe magit-section-visibility-indicator)) - (let ((ov (magit--overlay-at (1- eoh) 'magit-vis-indicator 'eoh))) - (cond ((oref section hidden) - (unless ov - (setq ov (make-overlay (1- eoh) eoh)) - (overlay-put ov 'evaporate t) - (overlay-put ov 'magit-vis-indicator 'eoh)) - (overlay-put ov 'after-string - (car magit-section-visibility-indicator))) - (ov - (delete-overlay ov))))))))))) - -(defvar-local magit--ellipses-sections nil) - -(defun magit-section-maybe-paint-visibility-ellipses () - ;; This is needed because we hide the body instead of "the body - ;; except the final newline and additionally the newline before - ;; the body"; otherwise we could use `buffer-invisibility-spec'. - (when (stringp (car-safe magit-section-visibility-indicator)) - (let* ((sections (append magit--ellipses-sections - (setq magit--ellipses-sections - (or (magit-region-sections) - (list (magit-current-section)))))) - (beg (--map (oref it start) sections)) - (end (--map (oref it end) sections))) - (when (region-active-p) - ;; This ensures that the region face is removed from ellipses - ;; when the region becomes inactive, but fails to ensure that - ;; all ellipses within the active region use the region face, - ;; because the respective overlay has not yet been updated at - ;; this time. The magit-selection face is always applied. - (push (region-beginning) beg) - (push (region-end) end)) - (setq beg (apply #'min beg)) - (setq end (apply #'max end)) - (dolist (ov (overlays-in beg end)) - (when (eq (overlay-get ov 'magit-vis-indicator) 'eoh) - (overlay-put - ov 'after-string - (propertize - (car magit-section-visibility-indicator) 'font-lock-face - (let ((pos (overlay-start ov))) - (delq nil (nconc (--map (overlay-get it 'font-lock-face) - (overlays-at pos)) - (list (get-char-property - pos 'font-lock-face)))))))))))) - -(defun magit-section-maybe-remove-visibility-indicator (section) - (when (and magit-section-visibility-indicator - (= (oref section content) - (oref section end))) - (dolist (o (overlays-in (oref section start) - (save-excursion - (goto-char (oref section start)) - (1+ (line-end-position))))) - (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)) - (and (not (eq section magit-root-section)) - (or (eq section (magit-current-section)) - (memq section (if sselection - selection - (setq selection (magit-region-sections)))) - (--when-let (oref section parent) - (magit-section-selected-p it selection))))) - -(defun magit-section-parent-value (section) - (when-let ((parent (oref section parent))) - (oref parent value))) - -(defun magit-section-siblings (section &optional direction) - "Return a list of the sibling sections of SECTION. - -If optional DIRECTION is `prev', then return siblings that come -before SECTION. If it is `next', then return siblings that come -after SECTION. For all other values, return all siblings -excluding SECTION itself." - (when-let ((parent (oref section parent))) - (let ((siblings (oref parent children))) - (pcase direction - (`prev (cdr (member section (reverse siblings)))) - (`next (cdr (member section siblings))) - (_ (remq section siblings)))))) - -(defun magit-region-values (&optional condition multiple) - "Return a list of the values of the selected sections. - -Return the values that themselves would be returned by -`magit-region-sections' (which see)." - (--map (oref it value) - (magit-region-sections condition multiple))) - -(defun magit-region-sections (&optional condition multiple) - "Return a list of the selected sections. - -When the region is active and constitutes a valid section -selection, then return a list of all selected sections. This is -the case when the region begins in the heading of a section and -ends in the heading of the same section or in that of a sibling -section. If optional MULTIPLE is non-nil, then the region cannot -begin and end in the same section. - -When the selection is not valid, then return nil. In this case, -most commands that can act on the selected sections will instead -act on the section at point. - -When the region looks like it would in any other buffer then -the selection is invalid. When the selection is valid then the -region uses the `magit-section-highlight' face. This does not -apply to diffs where things get a bit more complicated, but even -here if the region looks like it usually does, then that's not -a valid selection as far as this function is concerned. - -If optional CONDITION is non-nil, then the selection not only -has to be valid; all selected sections additionally have to match -CONDITION, or nil is returned. See `magit-section-match' for the -forms CONDITION can take." - (when (region-active-p) - (let* ((rbeg (region-beginning)) - (rend (region-end)) - (sbeg (get-text-property rbeg 'magit-section)) - (send (get-text-property rend 'magit-section))) - (when (and send - (not (eq send magit-root-section)) - (not (and multiple (eq send sbeg)))) - (let ((siblings (cons sbeg (magit-section-siblings sbeg 'next))) - sections) - (when (and (memq send siblings) - (magit-section-position-in-heading-p sbeg rbeg) - (magit-section-position-in-heading-p send rend)) - (while siblings - (push (car siblings) sections) - (when (eq (pop siblings) send) - (setq siblings nil))) - (setq sections (nreverse sections)) - (when (or (not condition) - (--all-p (magit-section-match condition it) sections)) - sections))))))) - -(defun magit-section-position-in-heading-p (&optional section pos) - "Return t if POSITION is inside the heading of SECTION. -POSITION defaults to point and SECTION defaults to the -current section." - (unless section - (setq section (magit-current-section))) - (unless pos - (setq pos (point))) - (and section - (>= pos (oref section start)) - (< pos (or (oref section content) - (oref section end))) - t)) - -(defun magit-section-internal-region-p (&optional section) - "Return t if the region is active and inside SECTION's body. -If optional SECTION is nil, use the current section." - (and (region-active-p) - (or section (setq section (magit-current-section))) - (let ((beg (get-text-property (region-beginning) 'magit-section))) - (and (eq beg (get-text-property (region-end) 'magit-section)) - (eq beg section))) - (not (or (magit-section-position-in-heading-p section (region-beginning)) - (magit-section-position-in-heading-p section (region-end)))) - t)) - -(defun magit-section--backward-protected () - "Move to the beginning of the current or the previous visible section. -Same as `magit-section-backward' but for non-interactive use. -Suppress `magit-section-movement-hook', and return a boolean to -indicate whether a section was found, instead of raising an error -if not." - (condition-case nil - (let ((magit-section-movement-hook nil)) - (magit-section-backward) - t) - (user-error nil))) - -(defun magit-section--backward-find (predicate) - "Move to the first previous section satisfying PREDICATE. -PREDICATE does not take any parameter and should not move -point." - (let (found) - (while (and (setq found (magit-section--backward-protected)) - (not (funcall predicate)))) - found)) - -(defun magit-wash-sequence (function) - "Repeatedly call FUNCTION until it returns nil or eob is reached. -FUNCTION has to move point forward or return nil." - (while (and (not (eobp)) (funcall function)))) - -(defun magit-add-section-hook (hook function &optional at append local) - "Add to the value of section hook HOOK the function FUNCTION. - -Add FUNCTION at the beginning of the hook list unless optional -APPEND is non-nil, in which case FUNCTION is added at the end. -If FUNCTION already is a member, then move it to the new location. - -If optional AT is non-nil and a member of the hook list, then -add FUNCTION next to that instead. Add before or after AT, or -replace AT with FUNCTION depending on APPEND. If APPEND is the -symbol `replace', then replace AT with FUNCTION. For any other -non-nil value place FUNCTION right after AT. If nil, then place -FUNCTION right before AT. If FUNCTION already is a member of the -list but AT is not, then leave FUNCTION where ever it already is. - -If optional LOCAL is non-nil, then modify the hook's buffer-local -value rather than its global value. This makes the hook local by -copying the default value. That copy is then modified. - -HOOK should be a symbol. If HOOK is void, it is first set to nil. -HOOK's value must not be a single hook function. FUNCTION should -be a function that takes no arguments and inserts one or multiple -sections at point, moving point forward. FUNCTION may choose not -to insert its section(s), when doing so would not make sense. It -should not be abused for other side-effects. To remove FUNCTION -again use `remove-hook'." - (unless (boundp hook) - (error "Cannot add function to undefined hook variable %s" hook)) - (unless (default-boundp hook) - (set-default hook nil)) - (let ((value (if local - (if (local-variable-p hook) - (symbol-value hook) - (unless (local-variable-if-set-p hook) - (make-local-variable hook)) - (copy-sequence (default-value hook))) - (default-value hook)))) - (if at - (when (setq at (member at value)) - (setq value (delq function value)) - (cond ((eq append 'replace) - (setcar at function)) - (append - (push function (cdr at))) - (t - (push (car at) (cdr at)) - (setcar at function)))) - (setq value (delq function value))) - (unless (member function value) - (setq value (if append - (append value (list function)) - (cons function value)))) - (when (eq append 'replace) - (setq value (delq at value))) - (if local - (set hook value) - (set-default hook value)))) - -(defvar-local magit-disabled-section-inserters nil) - -(defun magit-disable-section-inserter (fn) - "Disable the section inserter FN in the current repository. -It is only intended for use in \".dir-locals.el\" and -\".dir-locals-2.el\". Also see info node `(magit)Per-Repository -Configuration'." - (cl-pushnew fn magit-disabled-section-inserters)) - -(put 'magit-disable-section-inserter 'safe-local-eval-function t) - -(defun magit-run-section-hook (hook &rest args) - "Run HOOK with ARGS, warning about invalid entries." - (let ((entries (symbol-value hook))) - (unless (listp entries) - (setq entries (list entries))) - (--when-let (-remove #'functionp entries) - (message "`%s' contains entries that are no longer valid. -%s\nUsing standard value instead. Please re-configure hook variable." - hook - (mapconcat (lambda (sym) (format " `%s'" sym)) it "\n")) - (sit-for 5) - (setq entries (eval (car (get hook 'standard-value))))) - (dolist (entry entries) - (let ((magit--current-section-hook (cons (list hook entry) - magit--current-section-hook))) - (unless (memq entry magit-disabled-section-inserters) - (if (bound-and-true-p magit-refresh-verbose) - (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) - (cl-find-if (lambda (o) - (let ((p (overlay-properties o))) - (and (plist-member p prop) - (or (not sval) - (funcall (or testfn #'eql) - (plist-get p prop) - 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 --git a/elpa/magit-section-20210801.1004/magit-section.info b/elpa/magit-section-20210801.1004/magit-section.info deleted file mode 100644 index b98a309e..00000000 --- a/elpa/magit-section-20210801.1004/magit-section.info +++ /dev/null @@ -1,289 +0,0 @@ -This is magit-section.info, produced by makeinfo version 6.7 from -magit-section.texi. - - 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 - Foundation, either version 3 of the License, or (at your option) - any later version. - - This document 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. - -INFO-DIR-SECTION Emacs -START-INFO-DIR-ENTRY -* Magit-Section: (magit-section). Use Magit sections in your own packages. -END-INFO-DIR-ENTRY - - -File: magit-section.info, Node: Top, Next: Introduction, Up: (dir) - -Magit-Section Developer Manual -****************************** - -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 how it can also be used by other -packages that have nothing to do with Magit or Git. - - To learn more about the section abstraction and available commands -and user options see *note (magit)Sections::. This manual documents how -you can use sections in your own packages. - -This manual is for Magit-Section version 3.2.0. - - 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 - Foundation, either version 3 of the License, or (at your option) - any later version. - - This document 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. - -* Menu: - -* Introduction:: -* Creating Sections:: -* Core Functions:: -* Matching Functions:: - - -File: magit-section.info, Node: Introduction, Next: Creating Sections, Prev: Top, Up: Top - -1 Introduction -************** - -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 how it can also be used by other -packages that have nothing to do with Magit or Git. - - To learn more about the section abstraction and available commands -and user options see *note (magit)Sections::. This manual documents how -you can use sections in your own packages. - - When the documentation leaves something unaddressed, then please -consider that Magit uses this library extensively and search its source -for suitable examples before asking me for help. Thanks! - - -File: magit-section.info, Node: Creating Sections, Next: Core Functions, Prev: Introduction, Up: Top - -2 Creating Sections -******************* - - -- Function: magit-insert-section [name] (type &optional value hide) - &rest body - - 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 refreshing the - buffer. Else expand it by default. This can be overwritten using - ‘magit-section-set-visibility-hook’. When a section is recreated - during a refresh, then the visibility of predecessor is inherited - and HIDE is ignored (but the hook is still honored). - - BODY is any number of forms that actually insert the section’s - heading and body. Optional NAME, if specified, has to be a symbol, - which is then bound to the object of the section being inserted. - - Before BODY is evaluated the ‘start’ of the section object is set - to the value of ‘point’ and after BODY was evaluated its ‘end’ is - set to the new value of ‘point’; BODY is responsible for moving - ‘point’ forward. - - If it turns out inside BODY that the section is empty, then - ‘magit-cancel-section’ can be used to abort and remove all traces - 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. - - -- Function: magit-insert-heading &rest args - - Insert the heading for the section currently being inserted. - - This function should only be used inside ‘magit-insert-section’. - - When called without any arguments, then just set the ‘content’ slot - of the object representing the section being inserted to a marker - at ‘point’. The section should only contain a single line when - this function is used like this. - - When called with arguments ARGS, which have to be strings, or nil, - then insert those strings at point. The section should not contain - any text before this happens and afterwards it should again only - contain a single line. If the ‘face’ property is set anywhere - inside any of these strings, then insert all of them unchanged. - Otherwise use the ‘magit-section-heading’ face for all inserted - text. - - The ‘content’ property of the section object is the end of the - heading (which lasts from ‘start’ to ‘content’) and the beginning - of the the body (which lasts from ‘content’ to ‘end’). If the - value of ‘content’ is nil, then the section has no heading and its - body cannot be collapsed. If a section does have a heading, then - its height must be exactly one line, including a trailing newline - character. This isn’t enforced, you are responsible for getting it - right. The only exception is that this function does insert a - newline character if necessary. - - -- Macro: magit-insert-section-body &rest body - - Use BODY to insert the section body, once the section is expanded. - If the section is expanded when it is created, then this is like - ‘progn’. Otherwise BODY isn’t evaluated until the section is - explicitly expanded. - - -- Function: magit-cancel-section - - Cancel inserting the section that is currently being inserted. - Remove all traces of that section. - - -- Function: magit-wash-sequence function - - Repeatedly call FUNCTION until it returns ‘nil’ or the end of the - buffer is reached. FUNCTION has to move point forward or return - ‘nil’. - - -File: magit-section.info, Node: Core Functions, Next: Matching Functions, Prev: Creating Sections, Up: Top - -3 Core Functions -**************** - - -- Function: magit-current-section - - Return the section at point. - - -- Function: magit-section-ident section - - Return an unique identifier for SECTION. The return value has the - form ‘((TYPE . VALUE)...)’. - - -- Function: magit-section-ident-value value - - Return a constant representation of VALUE. - - VALUE is the value of a ‘magit-section’ object. If that is an - object itself, then that is not suitable to be used to identify the - section because two objects may represent the same thing but not be - equal. If possible a method should be added for such objects, - which returns a value that is equal. Otherwise the catch-all - method is used, which just returns the argument itself. - - -- Function: magit-get-section ident &optional root - - Return the section identified by IDENT. IDENT has to be a list as - returned by ‘magit-section-ident’. If optional ROOT is non-nil, - then search in that section tree instead of in the one whose root - ‘magit-root-section’ is. - - -- Function: magit-section-lineage section - - Return the lineage of SECTION. The return value has the form - ‘(TYPE...)’. - - -File: magit-section.info, Node: Matching Functions, Prev: Core Functions, Up: Top - -4 Matching Functions -******************** - - -- Function: magit-section-match condition &optional (section - (magit-current-section)) - - Return t if SECTION matches CONDITION. - - SECTION defaults to the section at point. If SECTION is not - specified and there also is no section at point, then return nil. - - CONDITION can take the following forms: - - • ‘(CONDITION...)’ matches if any of the CONDITIONs matches. - - • ‘[CLASS...]’ matches if the section’s class is the same as the - first CLASS or a subclass of that; the section’s parent class - matches the second CLASS; and so on. - - • ‘[* CLASS...]’ matches sections that match [CLASS...] and also - recursively all their child sections. - - • ‘CLASS’ matches if the section’s class is the same as CLASS or - a subclass of that; regardless of the classes of the parent - sections. - - Each CLASS should be a class symbol, identifying a class that - derives from ‘magit-section’. For backward compatibility CLASS can - also be a "type symbol". A section matches such a symbol if the - value of its ‘type’ slot is ‘eq’. If a type symbol has an entry in - ‘magit--section-type-alist’, then a section also matches that type - if its class is a subclass of the class that corresponds to the - type as per that alist. - - Note that it is not necessary to specify the complete section - lineage as printed by ‘magit-describe-section-briefly’, unless of - course you want to be that precise. - - -- Function: magit-section-value-if condition &optional section - - If the section at point matches CONDITION, then return its value. - - If optional SECTION is non-nil then test whether that matches - instead. If there is no section at point and SECTION is nil, then - return nil. If the section does not match, then return nil. - - See ‘magit-section-match’ for the forms CONDITION can take. - - -- Macro: magit-section-case &rest clauses - - Choose among clauses on the type of the section at point. - - Each clause looks like ‘(CONDITION BODY...)’. The type of the - section is compared against each CONDITION; the BODY forms of the - first match are evaluated sequentially and the value of the last - form is returned. Inside BODY the symbol ‘it’ is bound to the - section at point. If no clause succeeds or if there is no section - at point, return nil. - - See ‘magit-section-match’ for the forms CONDITION can take. - Additionally a CONDITION of t is allowed in the final clause, and - matches if no other CONDITION match, even if there is no section at - point. - - - -Tag Table: -Node: Top788 -Node: Introduction2069 -Node: Creating Sections2839 -Node: Core Functions7356 -Node: Matching Functions8682 - -End Tag Table - - -Local Variables: -coding: utf-8 -End: diff --git a/elpa/magit-section-20220101.841/dir b/elpa/magit-section-20220101.841/dir new file mode 100644 index 00000000..6e446813 --- /dev/null +++ b/elpa/magit-section-20220101.841/dir @@ -0,0 +1,19 @@ +This is the file .../info/dir, which contains the +topmost node of the Info hierarchy, called (dir)Top. +The first time you invoke Info you start off looking at this node. + +File: dir, Node: Top This is the top of the INFO tree + + This (the Directory node) gives a menu of major topics. + Typing "q" exits, "H" lists all Info commands, "d" returns here, + "h" gives a primer for first-timers, + "mEmacs" visits the Emacs manual, etc. + + In Emacs, you can click mouse button 2 on a menu item or cross reference + to select it. + +* Menu: + +Emacs +* Magit-Section: (magit-section). + Use Magit sections in your own packages. diff --git a/elpa/magit-section-20220101.841/magit-section-autoloads.el b/elpa/magit-section-20220101.841/magit-section-autoloads.el new file mode 100644 index 00000000..0899fbfa --- /dev/null +++ b/elpa/magit-section-20220101.841/magit-section-autoloads.el @@ -0,0 +1,26 @@ +;;; magit-section-autoloads.el --- automatically extracted autoloads +;; +;;; Code: + +(add-to-list 'load-path (directory-file-name + (or (file-name-directory #$) (car load-path)))) + + +;;;### (autoloads nil "magit-section" "magit-section.el" (0 0 0 0)) +;;; Generated autoloads from magit-section.el + +(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-section" '("isearch-clean-overlays@magit-mode" "magit-"))) + +;;;*** + +;;;### (autoloads nil nil ("magit-section-pkg.el") (0 0 0 0)) + +;;;*** + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; coding: utf-8 +;; End: +;;; magit-section-autoloads.el ends here diff --git a/elpa/magit-section-20220101.841/magit-section-pkg.el b/elpa/magit-section-20220101.841/magit-section-pkg.el new file mode 100644 index 00000000..4610002a --- /dev/null +++ b/elpa/magit-section-20220101.841/magit-section-pkg.el @@ -0,0 +1,13 @@ +(define-package "magit-section" "20220101.841" "Sections for read-only buffers" + '((emacs "25.1") + (dash "20210826")) + :commit "2a7812705f5cf4b864bb162576415863f4116285" :authors + '(("Jonas Bernoulli" . "jonas@bernoul.li")) + :maintainer + '("Jonas Bernoulli" . "jonas@bernoul.li") + :keywords + '("tools") + :url "https://github.com/magit/magit") +;; Local Variables: +;; no-byte-compile: t +;; End: diff --git a/elpa/magit-section-20220101.841/magit-section.el b/elpa/magit-section-20220101.841/magit-section.el new file mode 100644 index 00000000..3daf4dc1 --- /dev/null +++ b/elpa/magit-section-20220101.841/magit-section.el @@ -0,0 +1,1851 @@ +;;; magit-section.el --- Sections for read-only buffers -*- lexical-binding: t -*- + +;; Copyright (C) 2010-2022 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 + +;; 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 +;; the Free Software Foundation; either version 3, or (at your option) +;; any later version. +;; +;; Magit-Section 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. + +;;; Commentary: + +;; 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. + +;;; Code: + +(require 'cl-lib) +(require 'dash) +(require 'eieio) +(require 'seq) +(require 'subr-x) + +(eval-when-compile (require 'benchmark)) + +;;; Hooks + +(defvar magit-section-movement-hook nil + "Hook run by `magit-section-goto'. +That function in turn is used by all section movement commands.") + +(defvar magit-section-highlight-hook + '(magit-section-highlight + magit-section-highlight-selection) + "Functions used to highlight the current section. +Each function is run with the current section as only argument +until one of them returns non-nil.") + +(defvar magit-section-unhighlight-hook nil + "Functions used to unhighlight the previously current section. +Each function is run with the current section as only argument +until one of them returns non-nil. Most sections are properly +unhighlighted without requiring a specialized unhighlighter, +diff-related sections being the only exception.") + +(defvar magit-section-set-visibility-hook + '(magit-section-cached-visibility) + "Hook used to set the initial visibility of a section. +Stop at the first function that returns non-nil. The returned +value should be `show', `hide' or nil. If no function returns +non-nil, determine the visibility as usual, i.e. use the +hardcoded section specific default (see `magit-insert-section').") + +(defvar magit-section-goto-successor-hook nil + "Hook used to go to the same section as was current before a refresh. +This is only used if the standard mechanism for doing so did not +succeed.") + +;;; Options + +(defgroup magit-section nil + "Expandable sections." + :link '(info-link "(magit)Sections") + :group 'extensions) + +(defcustom magit-section-show-child-count t + "Whether to append the number of children to section headings. +This only applies to sections for which doing so makes sense." + :package-version '(magit-section . "2.1.0") + :group 'magit-section + :type 'boolean) + +(defcustom magit-section-cache-visibility t + "Whether to cache visibility of sections. + +Sections always retain their visibility state when they are being +recreated during a refresh. But if a section disappears and then +later reappears again, then this option controls whether this is +the case. + +If t, then cache the visibility of all sections. If a list of +section types, then only do so for matching sections. If nil, +then don't do so for any sections." + :package-version '(magit-section . "2.12.0") + :group 'magit-section + :type '(choice (const :tag "Don't cache visibility" nil) + (const :tag "Cache visibility of all sections" t) + (repeat :tag "Cache visibility for section types" symbol))) + +(defcustom magit-section-initial-visibility-alist + '((stashes . hide)) + "Alist controlling the initial visibility of sections. + +Each element maps a section type or lineage to the initial +visibility state for such sections. The state has to be one of +`show' or `hide', or a function that returns one of these symbols. +A function is called with the section as the only argument. + +Use the command `magit-describe-section' to determine a section's +lineage or type. The vector in the output is the section lineage +and the type is the first element of that vector. Wildcards can +be used, see `magit-section-match'. + +Currently this option is only used to override hardcoded defaults, +but in the future it will also be used set the defaults. + +An entry whose key is `magit-status-initial-section' specifies +the visibility of the section `magit-status-goto-initial-section' +jumps to. This does not only override defaults, but also other +entries of this alist." + :package-version '(magit-section . "2.12.0") + :group 'magit-section + :type '(alist :key-type (sexp :tag "Section type/lineage") + :value-type (choice (const hide) + (const show) + function))) + +(defcustom magit-section-visibility-indicator + (if (window-system) + '(magit-fringe-bitmap> . magit-fringe-bitmapv) + (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. +Otherwise the value has to have one of these two forms: + +\(EXPANDABLE-BITMAP . COLLAPSIBLE-BITMAP) + + Both values have to be variables whose values are fringe + bitmaps. In this case every section that can be expanded or + collapsed gets an indicator in the left fringe. + + To provide extra padding around the indicator, set + `left-fringe-width' in `magit-mode-hook'. + +\(STRING . BOOLEAN) + + In this case STRING (usually an ellipsis) is shown at the end + of the heading of every collapsed section. Expanded sections + get no indicator. The cdr controls whether the appearance of + these ellipsis take section highlighting into account. Doing + so might potentially have an impact on performance, while not + doing so is kinda ugly." + :package-version '(magit-section . "3.0.0") + :group 'magit-section + :type '(choice (const :tag "No indicators" nil) + (cons :tag "Use +- fringe indicators" + (const magit-fringe-bitmap+) + (const magit-fringe-bitmap-)) + (cons :tag "Use >v fringe indicators" + (const magit-fringe-bitmap>) + (const magit-fringe-bitmapv)) + (cons :tag "Use bold >v fringe indicators)" + (const magit-fringe-bitmap-bold>) + (const magit-fringe-bitmap-boldv)) + (cons :tag "Use custom fringe indicators" + (variable :tag "Expandable bitmap variable") + (variable :tag "Collapsible bitmap variable")) + (cons :tag "Use ellipses at end of headings" + (string :tag "Ellipsis" "…") + (choice :tag "Use face kludge" + (const :tag "Yes (potentially slow)" t) + (const :tag "No (kinda ugly)" nil))))) + +(define-obsolete-variable-alias 'magit-keep-region-overlay + 'magit-section-keep-region-overlay "Magit-Section 3.4.0") +(defcustom magit-section-keep-region-overlay nil + "Whether to keep the region overlay when there is a valid selection. + +By default Magit removes the regular region overlay if, and only +if, that region constitutes a valid selection as understood by +Magit commands. Otherwise it does not remove that overlay, and +the region looks like it would in other buffers. + +There are two types of such valid selections: hunk-internal +regions and regions that select two or more sibling sections. +In such cases Magit removes the region overlay and instead +highlights a slightly larger range. All text (for hunk-internal +regions) or the headings of all sections (for sibling selections) +that are inside that range (not just inside the region) are acted +on by commands such as the staging command. This buffer range +begins at the beginning of the line on which the region begins +and ends at the end of the line on which the region ends. + +Because Magit acts on this larger range and not the region, it is +actually quite important to visualize that larger range. If we +don't do that, then one might think that these commands act on +the region instead. If you want to *also* visualize the region, +then set this option to t. But please note that when the region +does *not* constitute a valid selection, then the region is +*always* visualized as usual, and that it is usually under such +circumstances that you want to use a non-magit command to act on +the region. + +Besides keeping the region overlay, setting this option to t also +causes all face properties, except for `:foreground', to be +ignored for the faces used to highlight headings of selected +sections. This avoids the worst conflicts that result from +displaying the region and the selection overlays at the same +time. We are not interested in dealing with other conflicts. +In fact we *already* provide a way to avoid all of these +conflicts: *not* changing the value of this option. + +It should be clear by now that we consider it a mistake to set +this to display the region when the Magit selection is also +visualized, but since it has been requested a few times and +because it doesn't cost much to offer this option we do so. +However that might change. If the existence of this option +starts complicating other things, then it will be removed." + :package-version '(magit-section . "2.3.0") + :group 'magit-section + :type 'boolean) + +(defcustom magit-section-disable-line-numbers t + "In Magit buffers, whether to disable modes that display line numbers. + +Some users who turn on `global-display-line-numbers-mode' (or +`global-nlinum-mode' or `global-linum-mode') expect line numbers +to be displayed everywhere except in Magit buffers. Other users +do not expect Magit buffers to be treated differently. At least +in theory users in the first group should not use the global mode, +but that ship has sailed, thus this option." + :package-version '(magit-section . "3.0.0") + :group 'magit-section + :type 'boolean) + +;;; Faces + +(defgroup magit-section-faces nil + "Faces used by Magit-Section." + :group 'magit-section + :group 'faces) + +(defface magit-section-highlight + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "grey95") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :background "grey20")) + "Face for highlighting the current section." + :group 'magit-section-faces) + +(defface magit-section-heading + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :foreground "DarkGoldenrod4" + :weight bold) + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :foreground "LightGoldenrod2" + :weight bold)) + "Face for section headings." + :group 'magit-section-faces) + +(defface magit-section-secondary-heading + `((t ,@(and (>= emacs-major-version 27) '(:extend t)) + :weight bold)) + "Face for section headings of some secondary headings." + :group 'magit-section-faces) + +(defface magit-section-heading-selection + `((((class color) (background light)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :foreground "salmon4") + (((class color) (background dark)) + ,@(and (>= emacs-major-version 27) '(:extend t)) + :foreground "LightSalmon3")) + "Face for selected section headings." + :group 'magit-section-faces) + +;;; Classes + +(defvar magit--current-section-hook nil + "Internal variable used for `magit-describe-section'.") + +(defvar magit--section-type-alist nil) + +(defclass magit-section () + ((keymap :initform nil :allocation :class) + (type :initform nil :initarg :type) + (value :initform nil :initarg :value) + (start :initform nil :initarg :start) + (content :initform nil) + (end :initform nil) + (hidden :initform nil) + (washer :initform nil) + (process :initform nil) + (heading-highlight-face :initform nil) + (inserter :initform (symbol-value 'magit--current-section-hook)) + (parent :initform nil :initarg :parent) + (children :initform nil))) + +;;; Mode + +(defvar symbol-overlay-inhibit-map) + +(defvar magit-section-mode-map + (let ((map (make-keymap))) + (suppress-keymap map t) + (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. + (define-key map [backtab] 'magit-section-cycle-global) + (define-key map (kbd "^") 'magit-section-up) + (define-key map (kbd "p") 'magit-section-backward) + (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 (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) + (define-key map (kbd "M-4") 'magit-section-show-level-4-all) + map)) + +(define-derived-mode magit-section-mode special-mode "Magit-Sections" + "Parent major mode from which major modes with Magit-like sections inherit. + +Magit-Section is documented in info node `(magit-section)'." + :group 'magit-section + (buffer-disable-undo) + (setq truncate-lines t) + (setq buffer-read-only t) + (setq-local line-move-visual t) ; see #1771 + ;; Turn off syntactic font locking, but not by setting + ;; `font-lock-defaults' because that would enable font locking, and + ;; not all magit plugins may be ready for that (see #3950). + (setq-local font-lock-syntactic-face-function #'ignore) + (setq show-trailing-whitespace nil) + (setq-local symbol-overlay-inhibit-map t) + (setq list-buffers-directory (abbreviate-file-name default-directory)) + ;; (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-deactivate-mark t t) + (setq-local redisplay-highlight-region-function + 'magit-section--highlight-region) + (setq-local redisplay-unhighlight-region-function + 'magit-section--unhighlight-region) + (when magit-section-disable-line-numbers + (when (bound-and-true-p global-linum-mode) + (linum-mode -1)) + (when (and (fboundp 'nlinum-mode) + (bound-and-true-p global-nlinum-mode)) + (nlinum-mode -1)) + (when (and (fboundp 'display-line-numbers-mode) + (bound-and-true-p global-display-line-numbers-mode)) + (display-line-numbers-mode -1))) + (when (fboundp 'magit-preserve-section-visibility-cache) + (add-hook 'kill-buffer-hook #'magit-preserve-section-visibility-cache))) + +;;; Core + +(defvar-local magit-root-section nil + "The root section in the current buffer. +All other sections are descendants of this section. The value +of this variable is set by `magit-insert-section' and you should +never modify it.") +(put 'magit-root-section 'permanent-local t) + +(defun magit-current-section () + "Return the section at point." + (or (get-text-property (point) 'magit-section) magit-root-section)) + +(defun magit-section-ident (section) + "Return an unique identifier for SECTION. +The return value has the form ((TYPE . VALUE)...)." + (with-slots (type value parent) section + (cons (cons type + (cond ((eieio-object-p value) + (magit-section-ident-value value)) + ((not (memq type '(unpulled unpushed))) value) + ((string-match-p "@{upstream}" value) value) + ;; Unfortunately Git chokes on "@{push}" when + ;; the value of `push.default' does not allow a + ;; 1:1 mapping. Arbitrary commands may consult + ;; the section value so we cannot use "@{push}". + ;; But `unpushed' and `unpulled' sections should + ;; keep their identity when switching branches + ;; so we have to use another value here. + ((string-match-p "\\`\\.\\." value) "..@{push}") + (t "@{push}.."))) + (and parent + (magit-section-ident parent))))) + +(cl-defgeneric magit-section-ident-value (value) + "Return a constant representation of VALUE. +VALUE is the value of a `magit-section' object. If that is an +object itself, then that is not suitable to be used to identify +the section because two objects may represent the same thing but +not be equal. If possible a method should be added for such +objects, which returns a value that is equal. Otherwise the +catch-all method is used, which just returns the argument +itself.") + +(cl-defmethod magit-section-ident-value (arg) arg) + +(defun magit-get-section (ident &optional root) + "Return the section identified by IDENT. +IDENT has to be a list as returned by `magit-section-ident'. +If optional ROOT is non-nil, then search in that section tree +instead of in the one whose root `magit-root-section' is." + (setq ident (reverse ident)) + (let ((section (or root magit-root-section))) + (when (eq (car (pop ident)) + (oref section type)) + (while (and ident + (pcase-let* ((`(,type . ,value) (car ident)) + (value (magit-section-ident-value value))) + (setq section + (cl-find-if (lambda (section) + (and (eq (oref section type) type) + (equal (magit-section-ident-value + (oref section value)) + value))) + (oref section children))))) + (pop ident)) + section))) + +(defun magit-section-lineage (section) + "Return the lineage of SECTION. +The return value has the form (TYPE...)." + (cons (oref section type) + (when-let ((parent (oref section parent))) + (magit-section-lineage parent)))) + +(defvar magit-insert-section--current nil "For internal use only.") +(defvar magit-insert-section--parent nil "For internal use only.") +(defvar magit-insert-section--oldroot nil "For internal use only.") + +;;; Commands +;;;; Movement + +(defun magit-section-forward () + "Move to the beginning of the next visible section." + (interactive) + (if (eobp) + (user-error "No next section") + (let ((section (magit-current-section))) + (if (oref section parent) + (let ((next (and (not (oref section hidden)) + (not (= (oref section end) + (1+ (point)))) + (car (oref section children))))) + (while (and section (not next)) + (unless (setq next (car (magit-section-siblings section 'next))) + (setq section (oref section parent)))) + (if next + (magit-section-goto next) + (user-error "No next section"))) + (magit-section-goto 1))))) + +(defun magit-section-backward () + "Move to the beginning of the current or the previous visible section. +When point is at the beginning of a section then move to the +beginning of the previous visible section. Otherwise move to +the beginning of the current section." + (interactive) + (if (bobp) + (user-error "No previous section") + (let ((section (magit-current-section)) children) + (cond + ((and (= (point) + (1- (oref section end))) + (setq children (oref section children))) + (magit-section-goto (car (last children)))) + ((and (oref section parent) + (not (= (point) + (oref section start)))) + (magit-section-goto section)) + (t + (let ((prev (car (magit-section-siblings section 'prev)))) + (if prev + (while (and (not (oref prev hidden)) + (setq children (oref prev children))) + (setq prev (car (last children)))) + (setq prev (oref section parent))) + (cond (prev + (magit-section-goto prev)) + ((oref section parent) + (user-error "No previous section")) + ;; Eob special cases. + ((not (get-text-property (1- (point)) 'invisible)) + (magit-section-goto -1)) + (t + (goto-char (previous-single-property-change + (1- (point)) 'invisible)) + (forward-line -1) + (magit-section-goto (magit-current-section)))))))))) + +(defun magit-section-up () + "Move to the beginning of the parent section." + (interactive) + (--if-let (oref (magit-current-section) parent) + (magit-section-goto it) + (user-error "No parent section"))) + +(defun magit-section-forward-sibling () + "Move to the beginning of the next sibling section. +If there is no next sibling section, then move to the parent." + (interactive) + (let ((current (magit-current-section))) + (if (oref current parent) + (--if-let (car (magit-section-siblings current 'next)) + (magit-section-goto it) + (magit-section-forward)) + (magit-section-goto 1)))) + +(defun magit-section-backward-sibling () + "Move to the beginning of the previous sibling section. +If there is no previous sibling section, then move to the parent." + (interactive) + (let ((current (magit-current-section))) + (if (oref current parent) + (--if-let (car (magit-section-siblings current 'prev)) + (magit-section-goto it) + (magit-section-backward)) + (magit-section-goto -1)))) + +(defun magit-section-goto (arg) + (if (integerp arg) + (progn (forward-line arg) + (setq arg (magit-current-section))) + (goto-char (oref arg start))) + (run-hook-with-args 'magit-section-movement-hook arg)) + +(defun magit-section-set-window-start (section) + "Ensure the beginning of SECTION is visible." + (unless (pos-visible-in-window-p (oref section end)) + (set-window-start (selected-window) (oref section start)))) + +(defmacro magit-define-section-jumper (name heading type &optional value) + "Define an interactive function to go some section. +Together TYPE and VALUE identify the section. +HEADING is the displayed heading of the section." + (declare (indent defun)) + `(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))))) + +;;;; Visibility + +(defun magit-section-show (section) + "Show the body of the current section." + (interactive (list (magit-current-section))) + (oset section hidden nil) + (magit-section--maybe-wash section) + (when-let ((beg (oref section content))) + (remove-overlays beg (oref section end) 'invisible t)) + (magit-section-maybe-update-visibility-indicator section) + (magit-section-maybe-cache-visibility section) + (dolist (child (oref section children)) + (if (oref child hidden) + (magit-section-hide child) + (magit-section-show child)))) + +(defun magit-section--maybe-wash (section) + (when-let ((washer (oref section washer))) + (oset section washer nil) + (let ((inhibit-read-only t) + (magit-insert-section--parent section) + (content (oref section content))) + (save-excursion + (if (and content (< content (oref section end))) + (funcall washer section) ; already partially washed (hunk) + (goto-char (oref section end)) + (oset section content (point-marker)) + (funcall washer) + (oset section end (point-marker))))) + (magit-section-update-highlight t))) + +(defun magit-section-hide (section) + "Hide the body of the current section." + (interactive (list (magit-current-section))) + (if (eq section magit-root-section) + (user-error "Cannot hide root section") + (oset section hidden t) + (when-let ((beg (oref section content))) + (let ((end (oref section end))) + (remove-overlays beg end 'invisible t) + (let ((o (make-overlay beg end))) + (overlay-put o 'evaporate t) + (overlay-put o 'invisible t)))) + (magit-section-maybe-update-visibility-indicator section) + (magit-section-maybe-cache-visibility section))) + +(defun magit-section-toggle (section) + "Toggle visibility of the body of the current section." + (interactive (list (magit-current-section))) + (if (eq section magit-root-section) + (user-error "Cannot hide root section") + (goto-char (oref section start)) + (if (oref section hidden) + (magit-section-show section) + (magit-section-hide section)))) + +(defun magit-section-toggle-children (section) + "Toggle visibility of bodies of children of the current section." + (interactive (list (magit-current-section))) + (goto-char (oref section start)) + (let* ((children (oref section children)) + (show (--any-p (oref it hidden) children))) + (dolist (c children) + (oset c hidden show))) + (magit-section-show section)) + +(defun magit-section-show-children (section &optional depth) + "Recursively show the bodies of children of the current section. +With a prefix argument show children that deep and hide deeper +children." + (interactive (list (magit-current-section))) + (magit-section-show-children-1 section depth) + (magit-section-show section)) + +(defun magit-section-show-children-1 (section &optional depth) + (dolist (child (oref section children)) + (oset child hidden nil) + (if depth + (if (> depth 0) + (magit-section-show-children-1 child (1- depth)) + (magit-section-hide child)) + (magit-section-show-children-1 child)))) + +(defun magit-section-hide-children (section) + "Recursively hide the bodies of children of the current section." + (interactive (list (magit-current-section))) + (mapc 'magit-section-hide (oref section children))) + +(defun magit-section-show-headings (section) + "Recursively show headings of children of the current section. +Only show the headings, previously shown text-only bodies are +hidden." + (interactive (list (magit-current-section))) + (magit-section-show-headings-1 section) + (magit-section-show section)) + +(defun magit-section-show-headings-1 (section) + (dolist (child (oref section children)) + (oset child hidden nil) + (when (or (oref child children) + (not (oref child content))) + (magit-section-show-headings-1 child)))) + +(defun magit-section-cycle (section) + "Cycle visibility of current section and its children." + (interactive (list (magit-current-section))) + (goto-char (oref section start)) + (if (oref section hidden) + (progn (magit-section-show section) + (magit-section-hide-children section)) + (let ((children (oref section children))) + (cond ((and (--any-p (oref it hidden) children) + (--any-p (oref it children) children)) + (magit-section-show-headings section)) + ((seq-some 'magit-section-hidden-body children) + (magit-section-show-children section)) + (t + (magit-section-hide section)))))) + +(defun magit-section-cycle-global () + "Cycle visibility of all sections in the current buffer." + (interactive) + (let ((children (oref magit-root-section children))) + (cond ((and (--any-p (oref it hidden) children) + (--any-p (oref it children) children)) + (magit-section-show-headings magit-root-section)) + ((seq-some 'magit-section-hidden-body children) + (magit-section-show-children magit-root-section)) + (t + (mapc 'magit-section-hide children))))) + +(defun magit-section-hidden-body (section &optional pred) + (--if-let (oref section children) + (funcall (or pred '-any-p) 'magit-section-hidden-body it) + (and (oref section content) + (oref section hidden)))) + +(defun magit-section-invisible-p (section) + "Return t if the SECTION's body is invisible. +When the body of an ancestor of SECTION is collapsed then +SECTION's body (and heading) obviously cannot be visible." + (or (oref section hidden) + (--when-let (oref section parent) + (magit-section-invisible-p it)))) + +(defun magit-section-show-level (level) + "Show surrounding sections up to LEVEL. +If LEVEL is negative, show up to the absolute value. +Sections at higher levels are hidden." + (if (< level 0) + (let ((s (magit-current-section))) + (setq level (- level)) + (while (> (1- (length (magit-section-ident s))) level) + (setq s (oref s parent)) + (goto-char (oref s start))) + (magit-section-show-children magit-root-section (1- level))) + (cl-do* ((s (magit-current-section) + (oref s parent)) + (i (1- (length (magit-section-ident s))) + (cl-decf i))) + ((cond ((< i level) (magit-section-show-children s (- level i 1)) t) + ((= i level) (magit-section-hide s) t)) + (magit-section-goto s))))) + +(defun magit-section-show-level-1 () + "Show surrounding sections on first level." + (interactive) + (magit-section-show-level 1)) + +(defun magit-section-show-level-1-all () + "Show all sections on first level." + (interactive) + (magit-section-show-level -1)) + +(defun magit-section-show-level-2 () + "Show surrounding sections up to second level." + (interactive) + (magit-section-show-level 2)) + +(defun magit-section-show-level-2-all () + "Show all sections up to second level." + (interactive) + (magit-section-show-level -2)) + +(defun magit-section-show-level-3 () + "Show surrounding sections up to third level." + (interactive) + (magit-section-show-level 3)) + +(defun magit-section-show-level-3-all () + "Show all sections up to third level." + (interactive) + (magit-section-show-level -3)) + +(defun magit-section-show-level-4 () + "Show surrounding sections up to fourth level." + (interactive) + (magit-section-show-level 4)) + +(defun magit-section-show-level-4-all () + "Show all sections up to fourth level." + (interactive) + (magit-section-show-level -4)) + +;;;; Auxiliary + +(defun magit-describe-section-briefly (section &optional ident) + "Show information about the section at point. +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%s>" + (eieio-object-class section) + (let ((val (oref section value))) + (cond ((stringp val) + (substring-no-properties val)) + ((and (eieio-object-p val) + (fboundp 'cl-prin1-to-string)) + (cl-prin1-to-string val)) + (t + val))) + (if ident + (magit-section-ident section) + (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) + (message "%s" str) + str))) + +(cl-defmethod cl-print-object ((section magit-section) stream) + "Print `magit-describe-section' result of SECTION." + ;; Used by debug and edebug as of Emacs 26. + (princ (magit-describe-section-briefly section) stream)) + +(defun magit-describe-section (section &optional interactive-p) + "Show information about the section at point." + (interactive (list (magit-current-section) t)) + (let ((inserter-section section)) + (while (and inserter-section (not (oref inserter-section inserter))) + (setq inserter-section (oref inserter-section parent))) + (when (and inserter-section (oref inserter-section inserter)) + (setq section inserter-section))) + (pcase (oref section inserter) + (`((,hook ,fun) . ,src-src) + (help-setup-xref `(magit-describe-section ,section) interactive-p) + (with-help-window (help-buffer) + (with-current-buffer standard-output + (insert (format-message + "%s\n is inserted by `%s'\n from `%s'" + (magit-describe-section-briefly section) + (make-text-button (symbol-name fun) nil + :type 'help-function + 'help-args (list fun)) + (make-text-button (symbol-name hook) nil + :type 'help-variable + 'help-args (list hook)))) + (pcase-dolist (`(,hook ,fun) src-src) + (insert (format-message + ",\n called by `%s'\n from `%s'" + (make-text-button (symbol-name fun) nil + :type 'help-function + 'help-args (list fun)) + (make-text-button (symbol-name hook) nil + :type 'help-variable + 'help-args (list hook))))) + (insert ".\n\n") + (insert + (format-message + "`%s' is " + (make-text-button (symbol-name fun) nil + :type 'help-function 'help-args (list fun)))) + (describe-function-1 fun)))) + (_ (message "%s, inserter unknown" + (magit-describe-section-briefly section))))) + +;;; Match + +(cl-defun magit-section-match + (condition &optional (section (magit-current-section))) + "Return t if SECTION matches CONDITION. + +SECTION defaults to the section at point. If SECTION is not +specified and there also is no section at point, then return +nil. + +CONDITION can take the following forms: + (CONDITION...) matches if any of the CONDITIONs matches. + [CLASS...] matches if the section's class is the same + as the first CLASS or a subclass of that; + the section's parent class matches the + second CLASS; and so on. + [* CLASS...] matches sections that match [CLASS...] and + also recursively all their child sections. + CLASS matches if the section's class is the same + as CLASS or a subclass of that; regardless + of the classes of the parent sections. + +Each CLASS should be a class symbol, identifying a class that +derives from `magit-section'. For backward compatibility CLASS +can also be a \"type symbol\". A section matches such a symbol +if the value of its `type' slot is `eq'. If a type symbol has +an entry in `magit--section-type-alist', then a section also +matches that type if its class is a subclass of the class that +corresponds to the type as per that alist. + +Note that it is not necessary to specify the complete section +lineage as printed by `magit-describe-section-briefly', unless +of course you want to be that precise." + (and section (magit-section-match-1 condition section))) + +(defun magit-section-match-1 (condition section) + (cl-assert condition) + (and section + (if (listp condition) + (--first (magit-section-match-1 it section) condition) + (magit-section-match-2 (if (symbolp condition) + (list condition) + (cl-coerce condition 'list)) + section)))) + +(defun magit-section-match-2 (condition section) + (if (eq (car condition) '*) + (or (magit-section-match-2 (cdr condition) section) + (when-let ((parent (oref section parent))) + (magit-section-match-2 condition parent))) + (and (let ((c (car condition))) + (if (class-p c) + (cl-typep section c) + (if-let ((class (cdr (assq c magit--section-type-alist)))) + (cl-typep section class) + (eq (oref section type) c)))) + (or (not (setq condition (cdr condition))) + (when-let ((parent (oref section parent))) + (magit-section-match-2 condition parent)))))) + +(defun magit-section-value-if (condition &optional section) + "If the section at point matches CONDITION, then return its value. + +If optional SECTION is non-nil then test whether that matches +instead. If there is no section at point and SECTION is nil, +then return nil. If the section does not match, then return +nil. + +See `magit-section-match' for the forms CONDITION can take." + (when-let ((section (or section (magit-current-section)))) + (and (magit-section-match condition section) + (oref section value)))) + +(defmacro magit-section-when (condition &rest body) + "If the section at point matches CONDITION, evaluate BODY. + +If the section matches, then evaluate BODY forms sequentially +with `it' bound to the section and return the value of the last +form. If there are no BODY forms, then return the value of the +section. If the section does not match or if there is no section +at point, then return nil. + +See `magit-section-match' for the forms CONDITION can take." + (declare (obsolete + "instead use `magit-section-match' or `magit-section-value-if'." + "Magit 2.90.0") + (indent 1) + (debug (sexp body))) + `(--when-let (magit-current-section) + ;; Quoting CONDITION here often leads to double-quotes, which + ;; isn't an issue because `magit-section-match-1' implicitly + ;; deals with that. We shouldn't force users of this function + ;; to not quote CONDITION because that would needlessly break + ;; backward compatibility. + (when (magit-section-match ',condition it) + ,@(or body '((oref it value)))))) + +(defmacro magit-section-case (&rest clauses) + "Choose among clauses on the type of the section at point. + +Each clause looks like (CONDITION BODY...). The type of the +section is compared against each CONDITION; the BODY forms of the +first match are evaluated sequentially and the value of the last +form is returned. Inside BODY the symbol `it' is bound to the +section at point. If no clause succeeds or if there is no +section at point, return nil. + +See `magit-section-match' for the forms CONDITION can take. +Additionally a CONDITION of t is allowed in the final clause, and +matches if no other CONDITION match, even if there is no section +at point." + (declare (indent 0) + (debug (&rest (sexp body)))) + `(let* ((it (magit-current-section))) + (cond ,@(mapcar (lambda (clause) + `(,(or (eq (car clause) t) + `(and it + (magit-section-match-1 ',(car clause) it))) + ,@(cdr clause))) + clauses)))) + +(defun magit-section-match-assoc (section alist) + "Return the value associated with SECTION's type or lineage in ALIST." + (seq-some (pcase-lambda (`(,key . ,val)) + (and (magit-section-match-1 key section) val)) + alist)) + +;;; Create + +(defvar magit-insert-section-hook nil + "Hook run after `magit-insert-section's BODY. +Avoid using this hook and only ever do so if you know +what you are doing and are sure there is no other way.") + +(defmacro magit-insert-section (&rest args) + "Insert a section at point. + +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 +refreshing the buffer. Else expand it by default. This can be +overwritten using `magit-section-set-visibility-hook'. When a +section is recreated during a refresh, then the visibility of +predecessor is inherited and HIDE is ignored (but the hook is +still honored). + +BODY is any number of forms that actually insert the section's +heading and body. Optional NAME, if specified, has to be a +symbol, which is then bound to the object of the section being +inserted. + +Before BODY is evaluated the `start' of the section object is set +to the value of `point' and after BODY was evaluated its `end' is +set to the new value of `point'; BODY is responsible for moving +`point' forward. + +If it turns out inside BODY that the section is empty, then +`magit-cancel-section' can be used to abort and remove all traces +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. + +\(fn [NAME] (CLASS &optional VALUE HIDE) &rest BODY)" + (declare (indent defun) + (debug ([&optional symbolp] + (&or [("eval" form) &optional form form] + [symbolp &optional form form]) + body))) + (let ((tp (cl-gensym "type")) + (s* (and (symbolp (car args)) + (pop args))) + (s (cl-gensym "section"))) + `(let* ((,tp ,(let ((type (nth 0 (car args)))) + (if (eq (car-safe type) 'eval) + (cadr type) + `',type))) + (,s (funcall (if (class-p ,tp) + ,tp + (or (cdr (assq ,tp magit--section-type-alist)) + 'magit-section)) + :type + (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 + (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 + (or magit-insert-section--oldroot + (unless magit-insert-section--parent + (prog1 magit-root-section + (setq magit-root-section ,s)))))) + (catch 'cancel-section + ,@(if s* + `((let ((,s* ,s)) + ,@(cdr args))) + (cdr args)) + ;; `magit-insert-section-hook' should *not* be run with + ;; `magit-run-section-hook' because it's a hook that runs + ;; on section insertion, not a section inserting hook. + (run-hooks 'magit-insert-section-hook) + (magit-insert-child-count ,s) + (set-marker-insertion-type (oref ,s start) t) + (let* ((end (oset ,s end (point-marker))) + (class-map (oref-default ,s keymap)) + (magit-map (intern (format "magit-%s-section-map" + (oref ,s type)))) + (forge-map (intern (format "forge-%s-section-map" + (oref ,s type)))) + (map (or (and class-map (symbol-value class-map)) + (and (boundp magit-map) (symbol-value magit-map)) + (and (boundp forge-map) (symbol-value forge-map))))) + (save-excursion + (goto-char (oref ,s start)) + (while (< (point) end) + (let ((next (or (next-single-property-change + (point) 'magit-section) + end))) + (unless (get-text-property (point) 'magit-section) + (put-text-property (point) next 'magit-section ,s) + (when map + (put-text-property (point) next 'keymap map))) + (goto-char next))))) + (if (eq ,s magit-root-section) + (let ((magit-section-cache-visibility nil)) + (magit-section-show ,s)) + (oset (oref ,s parent) children + (nconc (oref (oref ,s parent) children) + (list ,s))))) + ,s)))) + +(defun magit-cancel-section () + "Cancel inserting the section that is currently being inserted. +Remove all traces of that section." + (when magit-insert-section--current + (if (not (oref magit-insert-section--current parent)) + (insert "(empty)\n") + (delete-region (oref magit-insert-section--current start) + (point)) + (setq magit-insert-section--current nil) + (throw 'cancel-section nil)))) + +(defun magit-insert-heading (&rest args) + "Insert the heading for the section currently being inserted. + +This function should only be used inside `magit-insert-section'. + +When called without any arguments, then just set the `content' +slot of the object representing the section being inserted to +a marker at `point'. The section should only contain a single +line when this function is used like this. + +When called with arguments ARGS, which have to be strings, or +nil, then insert those strings at point. The section should not +contain any text before this happens and afterwards it should +again only contain a single line. If the `face' property is set +anywhere inside any of these strings, then insert all of them +unchanged. Otherwise use the `magit-section-heading' face for +all inserted text. + +The `content' property of the section object is the end of the +heading (which lasts from `start' to `content') and the beginning +of the the body (which lasts from `content' to `end'). If the +value of `content' is nil, then the section has no heading and +its body cannot be collapsed. If a section does have a heading, +then its height must be exactly one line, including a trailing +newline character. This isn't enforced, you are responsible for +getting it right. The only exception is that this function does +insert a newline character if necessary." + (declare (indent defun)) + (when args + (let ((heading (apply #'concat args))) + (insert (if (or (text-property-not-all 0 (length heading) + 'font-lock-face nil heading) + (text-property-not-all 0 (length heading) + 'face nil heading)) + heading + (propertize heading 'font-lock-face 'magit-section-heading))))) + (unless (bolp) + (insert ?\n)) + (when (fboundp 'magit-maybe-make-margin-overlay) + (magit-maybe-make-margin-overlay)) + (oset magit-insert-section--current content (point-marker))) + +(defmacro magit-insert-section-body (&rest body) + "Use BODY to insert the section body, once the section is expanded. +If the section is expanded when it is created, then this is +like `progn'. Otherwise BODY isn't evaluated until the section +is explicitly expanded." + (declare (indent 0)) + (let ((f (cl-gensym)) + (s (cl-gensym))) + `(let ((,f (lambda () ,@body)) + (,s magit-insert-section--current)) + (if (oref ,s hidden) + (oset ,s washer + (lambda () + (funcall ,f) + (magit-section-maybe-remove-visibility-indicator ,s))) + (funcall ,f))))) + +(defun magit-insert-headers (hook) + (let* ((header-sections nil) + (magit-insert-section-hook + (cons (lambda () + (push magit-insert-section--current + header-sections)) + (if (listp magit-insert-section-hook) + magit-insert-section-hook + (list magit-insert-section-hook))))) + (magit-run-section-hook hook) + (when header-sections + (insert "\n") + ;; Make the first header into the parent of the rest. + (when (cdr header-sections) + (cl-callf nreverse header-sections) + (let* ((1st-header (pop header-sections)) + (header-parent (oref 1st-header parent))) + (oset header-parent children (list 1st-header)) + (oset 1st-header children header-sections) + (oset 1st-header content (oref (car header-sections) start)) + (oset 1st-header end (oref (car (last header-sections)) end)) + (dolist (sub-header header-sections) + (oset sub-header parent 1st-header))))))) + +(defun magit-insert-child-count (section) + "Modify SECTION's heading to contain number of child sections. + +If `magit-section-show-child-count' is non-nil and the SECTION +has children and its heading ends with \":\", then replace that +with \" (N)\", where N is the number of child sections. + +This function is called by `magit-insert-section' after that has +evaluated its BODY. Admittedly that's a bit of a hack." + ;; This has to be fast, not pretty! + (let (content count) + (when (and magit-section-show-child-count + (setq count (length (oref section children))) + (> count 0) + (setq content (oref section content)) + (eq (char-before (1- content)) ?:)) + (save-excursion + (goto-char (- content 2)) + (insert (format " (%s)" count)) + (delete-char 1))))) + +;;; Highlight + +(defvar-local magit-section-pre-command-region-p nil) +(defvar-local magit-section-pre-command-section nil) +(defvar-local magit-section-highlight-overlays nil) +(defvar-local magit-section-highlighted-sections nil) +(defvar-local magit-section-unhighlight-sections nil) + +(defun magit-section-pre-command-hook () + (setq magit-section-pre-command-region-p (region-active-p)) + (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))) + (when (or force + (cond ; `xor' wasn't added until 27.1. + ((not magit-section-pre-command-region-p) (region-active-p)) + ((not (region-active-p)) magit-section-pre-command-region-p)) + (not (eq magit-section-pre-command-section section))) + (let ((inhibit-read-only t) + (deactivate-mark nil) + (selection (magit-region-sections))) + (mapc #'delete-overlay magit-section-highlight-overlays) + (setq magit-section-highlight-overlays nil) + (setq magit-section-unhighlight-sections + magit-section-highlighted-sections) + (setq magit-section-highlighted-sections nil) + (unless (eq section magit-root-section) + (run-hook-with-args-until-success + 'magit-section-highlight-hook section selection)) + (dolist (s magit-section-unhighlight-sections) + (run-hook-with-args-until-success + 'magit-section-unhighlight-hook s selection)) + (restore-buffer-modified-p nil))) + (magit-section-maybe-paint-visibility-ellipses))) + +(defun magit-section-highlight (section selection) + "Highlight SECTION and if non-nil all sections in SELECTION. +This function works for any section but produces undesirable +effects for diff related sections, which by default are +highlighted using `magit-diff-highlight'. Return t." + (when-let ((face (oref section heading-highlight-face))) + (dolist (section (or selection (list section))) + (magit-section-make-overlay + (oref section start) + (or (oref section content) + (oref section end)) + face))) + (cond (selection + (magit-section-make-overlay (oref (car selection) start) + (oref (car (last selection)) end) + 'magit-section-highlight) + (magit-section-highlight-selection nil selection)) + (t + (magit-section-make-overlay (oref section start) + (oref section end) + 'magit-section-highlight))) + t) + +(defun magit-section-highlight-selection (_ selection) + "Highlight the section-selection region. +If SELECTION is non-nil, then it is a list of sections selected by +the region. The headings of these sections are then highlighted. + +This is a fallback for people who don't want to highlight the +current section and therefore removed `magit-section-highlight' +from `magit-section-highlight-hook'. + +This function is necessary to ensure that a representation of +such a region is visible. If neither of these functions were +part of the hook variable, then such a region would be +invisible." + (when (and selection + (not (and (eq this-command 'mouse-drag-region)))) + (dolist (section selection) + (magit-section-make-overlay (oref section start) + (or (oref section content) + (oref section end)) + 'magit-section-heading-selection)) + t)) + +(defun magit-section-make-overlay (start end face) + ;; Yes, this doesn't belong here. But the alternative of + ;; spreading this hack across the code base is even worse. + (when (and magit-section-keep-region-overlay + (memq face '(magit-section-heading-selection + magit-diff-file-heading-selection + magit-diff-hunk-heading-selection))) + (setq face (list :foreground (face-foreground face)))) + (let ((ov (make-overlay start end nil t))) + (overlay-put ov 'font-lock-face face) + (overlay-put ov 'evaporate t) + (push ov magit-section-highlight-overlays) + ov)) + +(defun magit-section-goto-successor (section line char arg) + (let ((ident (magit-section-ident section))) + (--if-let (magit-get-section ident) + (let ((start (oref it start))) + (goto-char start) + (unless (eq it magit-root-section) + (ignore-errors + (forward-line line) + (forward-char char)) + (unless (eq (magit-current-section) it) + (goto-char start)))) + (or (run-hook-with-args-until-success + 'magit-section-goto-successor-hook section arg) + (goto-char (--if-let (magit-section-goto-successor-1 section) + (if (eq (oref it type) 'button) + (point-min) + (oref it start)) + (point-min))))))) + +(defun magit-section-goto-successor-1 (section) + (or (--when-let (pcase (oref section type) + (`staged 'unstaged) + (`unstaged 'staged) + (`unpushed 'unpulled) + (`unpulled 'unpushed)) + (magit-get-section `((,it) (status)))) + (--when-let (car (magit-section-siblings section 'next)) + (magit-get-section (magit-section-ident it))) + (--when-let (car (magit-section-siblings section 'prev)) + (magit-get-section (magit-section-ident it))) + (--when-let (oref section parent) + (or (magit-get-section (magit-section-ident it)) + (magit-section-goto-successor-1 it))))) + +;;; Region + +(defvar-local magit-section--region-overlays nil) + +(defun magit-section--delete-region-overlays () + (mapc #'delete-overlay magit-section--region-overlays) + (setq magit-section--region-overlays nil)) + +(defun magit-section--highlight-region (start end window rol) + (magit-section--delete-region-overlays) + (if (and (not magit-section-keep-region-overlay) + (or (magit-region-sections) + (run-hook-with-args-until-success 'magit-region-highlight-hook + (magit-current-section))) + (not (= (line-number-at-pos start) + (line-number-at-pos end))) + ;; (not (eq (car-safe last-command-event) 'mouse-movement)) + ) + (funcall (default-value 'redisplay-unhighlight-region-function) rol) + (funcall (default-value 'redisplay-highlight-region-function) + start end window rol))) + +(defun magit-section--unhighlight-region (rol) + (magit-section--delete-region-overlays) + (funcall (default-value 'redisplay-unhighlight-region-function) rol)) + +;;; Visibility + +(defvar-local magit-section-visibility-cache nil) +(put 'magit-section-visibility-cache 'permanent-local t) + +(defun magit-section-cached-visibility (section) + "Set SECTION's visibility to the cached value." + (cdr (assoc (magit-section-ident section) + magit-section-visibility-cache))) + +(cl-defun magit-section-cache-visibility + (&optional (section magit-insert-section--current)) + ;; Emacs 25's `alist-get' lacks TESTFN. + (let* ((id (magit-section-ident section)) + (elt (assoc id magit-section-visibility-cache)) + (val (if (oref section hidden) 'hide 'show))) + (if elt + (setcdr elt val) + (push (cons id val) magit-section-visibility-cache)))) + +(cl-defun magit-section-maybe-cache-visibility + (&optional (section magit-insert-section--current)) + (when (or (eq magit-section-cache-visibility t) + (memq (oref section type) + magit-section-cache-visibility)) + (magit-section-cache-visibility section))) + +(defun magit-section-maybe-update-visibility-indicator (section) + (when magit-section-visibility-indicator + (let ((beg (oref section start)) + (cnt (oref section content)) + (end (oref section end))) + (when (and cnt (or (not (= cnt end)) (oref section washer))) + (let ((eoh (save-excursion + (goto-char beg) + (line-end-position)))) + (cond + ((symbolp (car-safe magit-section-visibility-indicator)) + ;; It would make more sense to put the overlay only on the + ;; location we actually don't put it on, but then inserting + ;; before that location (while taking care not to mess with + ;; the overlay) would cause the fringe bitmap to disappear + ;; (but not other effects of the overlay). + (let ((ov (magit--overlay-at (1+ beg) 'magit-vis-indicator 'fringe))) + (unless ov + (setq ov (make-overlay (1+ beg) eoh)) + (overlay-put ov 'evaporate t) + (overlay-put ov 'magit-vis-indicator 'fringe)) + (overlay-put + ov 'before-string + (propertize "fringe" 'display + (list 'left-fringe + (if (oref section hidden) + (car magit-section-visibility-indicator) + (cdr magit-section-visibility-indicator)) + 'fringe))))) + ((stringp (car-safe magit-section-visibility-indicator)) + (let ((ov (magit--overlay-at (1- eoh) 'magit-vis-indicator 'eoh))) + (cond ((oref section hidden) + (unless ov + (setq ov (make-overlay (1- eoh) eoh)) + (overlay-put ov 'evaporate t) + (overlay-put ov 'magit-vis-indicator 'eoh)) + (overlay-put ov 'after-string + (car magit-section-visibility-indicator))) + (ov + (delete-overlay ov))))))))))) + +(defvar-local magit--ellipses-sections nil) + +(defun magit-section-maybe-paint-visibility-ellipses () + ;; This is needed because we hide the body instead of "the body + ;; except the final newline and additionally the newline before + ;; the body"; otherwise we could use `buffer-invisibility-spec'. + (when (stringp (car-safe magit-section-visibility-indicator)) + (let* ((sections (append magit--ellipses-sections + (setq magit--ellipses-sections + (or (magit-region-sections) + (list (magit-current-section)))))) + (beg (--map (oref it start) sections)) + (end (--map (oref it end) sections))) + (when (region-active-p) + ;; This ensures that the region face is removed from ellipses + ;; when the region becomes inactive, but fails to ensure that + ;; all ellipses within the active region use the region face, + ;; because the respective overlay has not yet been updated at + ;; this time. The magit-selection face is always applied. + (push (region-beginning) beg) + (push (region-end) end)) + (setq beg (apply #'min beg)) + (setq end (apply #'max end)) + (dolist (ov (overlays-in beg end)) + (when (eq (overlay-get ov 'magit-vis-indicator) 'eoh) + (overlay-put + ov 'after-string + (propertize + (car magit-section-visibility-indicator) 'font-lock-face + (let ((pos (overlay-start ov))) + (delq nil (nconc (--map (overlay-get it 'font-lock-face) + (overlays-at pos)) + (list (get-char-property + pos 'font-lock-face)))))))))))) + +(defun magit-section-maybe-remove-visibility-indicator (section) + (when (and magit-section-visibility-indicator + (= (oref section content) + (oref section end))) + (dolist (o (overlays-in (oref section start) + (save-excursion + (goto-char (oref section start)) + (1+ (line-end-position))))) + (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)) + (and (not (eq section magit-root-section)) + (or (eq section (magit-current-section)) + (memq section (if sselection + selection + (setq selection (magit-region-sections)))) + (--when-let (oref section parent) + (magit-section-selected-p it selection))))) + +(defun magit-section-parent-value (section) + (when-let ((parent (oref section parent))) + (oref parent value))) + +(defun magit-section-siblings (section &optional direction) + "Return a list of the sibling sections of SECTION. + +If optional DIRECTION is `prev', then return siblings that come +before SECTION. If it is `next', then return siblings that come +after SECTION. For all other values, return all siblings +excluding SECTION itself." + (when-let ((parent (oref section parent))) + (let ((siblings (oref parent children))) + (pcase direction + (`prev (cdr (member section (reverse siblings)))) + (`next (cdr (member section siblings))) + (_ (remq section siblings)))))) + +(defun magit-region-values (&optional condition multiple) + "Return a list of the values of the selected sections. + +Return the values that themselves would be returned by +`magit-region-sections' (which see)." + (--map (oref it value) + (magit-region-sections condition multiple))) + +(defun magit-region-sections (&optional condition multiple) + "Return a list of the selected sections. + +When the region is active and constitutes a valid section +selection, then return a list of all selected sections. This is +the case when the region begins in the heading of a section and +ends in the heading of the same section or in that of a sibling +section. If optional MULTIPLE is non-nil, then the region cannot +begin and end in the same section. + +When the selection is not valid, then return nil. In this case, +most commands that can act on the selected sections will instead +act on the section at point. + +When the region looks like it would in any other buffer then +the selection is invalid. When the selection is valid then the +region uses the `magit-section-highlight' face. This does not +apply to diffs where things get a bit more complicated, but even +here if the region looks like it usually does, then that's not +a valid selection as far as this function is concerned. + +If optional CONDITION is non-nil, then the selection not only +has to be valid; all selected sections additionally have to match +CONDITION, or nil is returned. See `magit-section-match' for the +forms CONDITION can take." + (when (region-active-p) + (let* ((rbeg (region-beginning)) + (rend (region-end)) + (sbeg (get-text-property rbeg 'magit-section)) + (send (get-text-property rend 'magit-section))) + (when (and send + (not (eq send magit-root-section)) + (not (and multiple (eq send sbeg)))) + (let ((siblings (cons sbeg (magit-section-siblings sbeg 'next))) + sections) + (when (and (memq send siblings) + (magit-section-position-in-heading-p sbeg rbeg) + (magit-section-position-in-heading-p send rend)) + (while siblings + (push (car siblings) sections) + (when (eq (pop siblings) send) + (setq siblings nil))) + (setq sections (nreverse sections)) + (when (or (not condition) + (--all-p (magit-section-match condition it) sections)) + sections))))))) + +(defun magit-section-position-in-heading-p (&optional section pos) + "Return t if POSITION is inside the heading of SECTION. +POSITION defaults to point and SECTION defaults to the +current section." + (unless section + (setq section (magit-current-section))) + (unless pos + (setq pos (point))) + (and section + (>= pos (oref section start)) + (< pos (or (oref section content) + (oref section end))) + t)) + +(defun magit-section-internal-region-p (&optional section) + "Return t if the region is active and inside SECTION's body. +If optional SECTION is nil, use the current section." + (and (region-active-p) + (or section (setq section (magit-current-section))) + (let ((beg (get-text-property (region-beginning) 'magit-section))) + (and (eq beg (get-text-property (region-end) 'magit-section)) + (eq beg section))) + (not (or (magit-section-position-in-heading-p section (region-beginning)) + (magit-section-position-in-heading-p section (region-end)))) + t)) + +(defun magit-section--backward-protected () + "Move to the beginning of the current or the previous visible section. +Same as `magit-section-backward' but for non-interactive use. +Suppress `magit-section-movement-hook', and return a boolean to +indicate whether a section was found, instead of raising an error +if not." + (condition-case nil + (let ((magit-section-movement-hook nil)) + (magit-section-backward) + t) + (user-error nil))) + +(defun magit-section--backward-find (predicate) + "Move to the first previous section satisfying PREDICATE. +PREDICATE does not take any parameter and should not move +point." + (let (found) + (while (and (setq found (magit-section--backward-protected)) + (not (funcall predicate)))) + found)) + +(defun magit-wash-sequence (function) + "Repeatedly call FUNCTION until it returns nil or eob is reached. +FUNCTION has to move point forward or return nil." + (while (and (not (eobp)) (funcall function)))) + +(defun magit-add-section-hook (hook function &optional at append local) + "Add to the value of section hook HOOK the function FUNCTION. + +Add FUNCTION at the beginning of the hook list unless optional +APPEND is non-nil, in which case FUNCTION is added at the end. +If FUNCTION already is a member, then move it to the new location. + +If optional AT is non-nil and a member of the hook list, then +add FUNCTION next to that instead. Add before or after AT, or +replace AT with FUNCTION depending on APPEND. If APPEND is the +symbol `replace', then replace AT with FUNCTION. For any other +non-nil value place FUNCTION right after AT. If nil, then place +FUNCTION right before AT. If FUNCTION already is a member of the +list but AT is not, then leave FUNCTION where ever it already is. + +If optional LOCAL is non-nil, then modify the hook's buffer-local +value rather than its global value. This makes the hook local by +copying the default value. That copy is then modified. + +HOOK should be a symbol. If HOOK is void, it is first set to nil. +HOOK's value must not be a single hook function. FUNCTION should +be a function that takes no arguments and inserts one or multiple +sections at point, moving point forward. FUNCTION may choose not +to insert its section(s), when doing so would not make sense. It +should not be abused for other side-effects. To remove FUNCTION +again use `remove-hook'." + (unless (boundp hook) + (error "Cannot add function to undefined hook variable %s" hook)) + (unless (default-boundp hook) + (set-default hook nil)) + (let ((value (if local + (if (local-variable-p hook) + (symbol-value hook) + (unless (local-variable-if-set-p hook) + (make-local-variable hook)) + (copy-sequence (default-value hook))) + (default-value hook)))) + (if at + (when (setq at (member at value)) + (setq value (delq function value)) + (cond ((eq append 'replace) + (setcar at function)) + (append + (push function (cdr at))) + (t + (push (car at) (cdr at)) + (setcar at function)))) + (setq value (delq function value))) + (unless (member function value) + (setq value (if append + (append value (list function)) + (cons function value)))) + (when (eq append 'replace) + (setq value (delq at value))) + (if local + (set hook value) + (set-default hook value)))) + +(defvar-local magit-disabled-section-inserters nil) + +(defun magit-disable-section-inserter (fn) + "Disable the section inserter FN in the current repository. +It is only intended for use in \".dir-locals.el\" and +\".dir-locals-2.el\". Also see info node `(magit)Per-Repository +Configuration'." + (cl-pushnew fn magit-disabled-section-inserters)) + +(put 'magit-disable-section-inserter 'safe-local-eval-function t) + +(defun magit-run-section-hook (hook &rest args) + "Run HOOK with ARGS, warning about invalid entries." + (let ((entries (symbol-value hook))) + (unless (listp entries) + (setq entries (list entries))) + (--when-let (-remove #'functionp entries) + (message "`%s' contains entries that are no longer valid. +%s\nUsing standard value instead. Please re-configure hook variable." + hook + (mapconcat (lambda (sym) (format " `%s'" sym)) it "\n")) + (sit-for 5) + (setq entries (eval (car (get hook 'standard-value))))) + (dolist (entry entries) + (let ((magit--current-section-hook (cons (list hook entry) + magit--current-section-hook))) + (unless (memq entry magit-disabled-section-inserters) + (if (bound-and-true-p magit-refresh-verbose) + (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) + (cl-find-if (lambda (o) + (let ((p (overlay-properties o))) + (and (plist-member p prop) + (or (not sval) + (funcall (or testfn #'eql) + (plist-get p prop) + 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 --git a/elpa/magit-section-20220101.841/magit-section.info b/elpa/magit-section-20220101.841/magit-section.info new file mode 100644 index 00000000..e75d7ee5 --- /dev/null +++ b/elpa/magit-section-20220101.841/magit-section.info @@ -0,0 +1,274 @@ +This is magit-section.info, produced by makeinfo version 6.7 from +magit-section.texi. + + Copyright (C) 2015-2022 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 + Foundation, either version 3 of the License, or (at your option) + any later version. + + This document 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. + +INFO-DIR-SECTION Emacs +START-INFO-DIR-ENTRY +* Magit-Section: (magit-section). Use Magit sections in your own packages. +END-INFO-DIR-ENTRY + + +File: magit-section.info, Node: Top, Next: Introduction, Up: (dir) + +Magit-Section Developer Manual +****************************** + +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 how it can also be used by other +packages that have nothing to do with Magit or Git. + + To learn more about the section abstraction and available commands +and user options see *note (magit)Sections::. This manual documents how +you can use sections in your own packages. + +This manual is for Magit-Section version v3.3.0-73-g03f495f35+1. + + Copyright (C) 2015-2022 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 + Foundation, either version 3 of the License, or (at your option) + any later version. + + This document 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. + +* Menu: + +* Introduction:: +* Creating Sections:: +* Core Functions:: +* Matching Functions:: + + +File: magit-section.info, Node: Introduction, Next: Creating Sections, Prev: Top, Up: Top + +1 Introduction +************** + +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 how it can also be used by other +packages that have nothing to do with Magit or Git. + + To learn more about the section abstraction and available commands +and user options see *note (magit)Sections::. This manual documents how +you can use sections in your own packages. + + When the documentation leaves something unaddressed, then please +consider that Magit uses this library extensively and search its source +for suitable examples before asking me for help. Thanks! + + +File: magit-section.info, Node: Creating Sections, Next: Core Functions, Prev: Introduction, Up: Top + +2 Creating Sections +******************* + + -- Macro: magit-insert-section [name] (type &optional value hide) &rest + body + 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 refreshing the + buffer. Else expand it by default. This can be overwritten using + ‘magit-section-set-visibility-hook’. When a section is recreated + during a refresh, then the visibility of predecessor is inherited + and HIDE is ignored (but the hook is still honored). + + BODY is any number of forms that actually insert the section’s + heading and body. Optional NAME, if specified, has to be a symbol, + which is then bound to the object of the section being inserted. + + Before BODY is evaluated the ‘start’ of the section object is set + to the value of ‘point’ and after BODY was evaluated its ‘end’ is + set to the new value of ‘point’; BODY is responsible for moving + ‘point’ forward. + + If it turns out inside BODY that the section is empty, then + ‘magit-cancel-section’ can be used to abort and remove all traces + 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. + + -- Function: magit-insert-heading &rest args + Insert the heading for the section currently being inserted. + + This function should only be used inside ‘magit-insert-section’. + + When called without any arguments, then just set the ‘content’ slot + of the object representing the section being inserted to a marker + at ‘point’. The section should only contain a single line when + this function is used like this. + + When called with arguments ARGS, which have to be strings, or nil, + then insert those strings at point. The section should not contain + any text before this happens and afterwards it should again only + contain a single line. If the ‘face’ property is set anywhere + inside any of these strings, then insert all of them unchanged. + Otherwise use the ‘magit-section-heading’ face for all inserted + text. + + The ‘content’ property of the section object is the end of the + heading (which lasts from ‘start’ to ‘content’) and the beginning + of the the body (which lasts from ‘content’ to ‘end’). If the + value of ‘content’ is nil, then the section has no heading and its + body cannot be collapsed. If a section does have a heading, then + its height must be exactly one line, including a trailing newline + character. This isn’t enforced, you are responsible for getting it + right. The only exception is that this function does insert a + newline character if necessary. + + -- Macro: magit-insert-section-body &rest body + Use BODY to insert the section body, once the section is expanded. + If the section is expanded when it is created, then this is like + ‘progn’. Otherwise BODY isn’t evaluated until the section is + explicitly expanded. + + -- Function: magit-cancel-section + Cancel inserting the section that is currently being inserted. + Remove all traces of that section. + + -- Function: magit-wash-sequence function + Repeatedly call FUNCTION until it returns ‘nil’ or the end of the + buffer is reached. FUNCTION has to move point forward or return + ‘nil’. + + +File: magit-section.info, Node: Core Functions, Next: Matching Functions, Prev: Creating Sections, Up: Top + +3 Core Functions +**************** + + -- Function: magit-current-section + Return the section at point. + + -- Function: magit-section-ident section + Return an unique identifier for SECTION. The return value has the + form ‘((TYPE . VALUE)...)’. + + -- Function: magit-section-ident-value value + Return a constant representation of VALUE. + + VALUE is the value of a ‘magit-section’ object. If that is an + object itself, then that is not suitable to be used to identify the + section because two objects may represent the same thing but not be + equal. If possible a method should be added for such objects, + which returns a value that is equal. Otherwise the catch-all + method is used, which just returns the argument itself. + + -- Function: magit-get-section ident &optional root + Return the section identified by IDENT. IDENT has to be a list as + returned by ‘magit-section-ident’. If optional ROOT is non-nil, + then search in that section tree instead of in the one whose root + ‘magit-root-section’ is. + + -- Function: magit-section-lineage section + Return the lineage of SECTION. The return value has the form + ‘(TYPE...)’. + + +File: magit-section.info, Node: Matching Functions, Prev: Core Functions, Up: Top + +4 Matching Functions +******************** + + -- Function: magit-section-match condition &optional (section + (magit-current-section)) + Return t if SECTION matches CONDITION. + + SECTION defaults to the section at point. If SECTION is not + specified and there also is no section at point, then return nil. + + CONDITION can take the following forms: + + • ‘(CONDITION...)’ matches if any of the CONDITIONs matches. + • ‘[CLASS...]’ matches if the section’s class is the same as the + first CLASS or a subclass of that; the section’s parent class + matches the second CLASS; and so on. + + • ‘[* CLASS...]’ matches sections that match [CLASS...] and also + recursively all their child sections. + • ‘CLASS’ matches if the section’s class is the same as CLASS or + a subclass of that; regardless of the classes of the parent + sections. + + Each CLASS should be a class symbol, identifying a class that + derives from ‘magit-section’. For backward compatibility CLASS can + also be a "type symbol". A section matches such a symbol if the + value of its ‘type’ slot is ‘eq’. If a type symbol has an entry in + ‘magit--section-type-alist’, then a section also matches that type + if its class is a subclass of the class that corresponds to the + type as per that alist. + + Note that it is not necessary to specify the complete section + lineage as printed by ‘magit-describe-section-briefly’, unless of + course you want to be that precise. + + -- Function: magit-section-value-if condition &optional section + If the section at point matches CONDITION, then return its value. + + If optional SECTION is non-nil then test whether that matches + instead. If there is no section at point and SECTION is nil, then + return nil. If the section does not match, then return nil. + + See ‘magit-section-match’ for the forms CONDITION can take. + + -- Macro: magit-section-case &rest clauses + Choose among clauses on the type of the section at point. + + Each clause looks like ‘(CONDITION BODY...)’. The type of the + section is compared against each CONDITION; the BODY forms of the + first match are evaluated sequentially and the value of the last + form is returned. Inside BODY the symbol ‘it’ is bound to the + section at point. If no clause succeeds or if there is no section + at point, return nil. + + See ‘magit-section-match’ for the forms CONDITION can take. + Additionally a CONDITION of t is allowed in the final clause, and + matches if no other CONDITION match, even if there is no section at + point. + + + +Tag Table: +Node: Top788 +Node: Introduction2086 +Node: Creating Sections2856 +Node: Core Functions7365 +Node: Matching Functions8686 + +End Tag Table + + +Local Variables: +coding: utf-8 +End: