From: Andreas Gerler Date: Tue, 25 Nov 2025 18:35:56 +0000 (+0100) Subject: update magit X-Git-Url: http://git.bundesbrandschatzamt.de/?a=commitdiff_plain;h=a53715eff1e16c21e7493289031991ae0f17a1f3;p=emacsconfig.git update magit --- diff --git a/elpa/magit-20250519.1537/.dir-locals.el b/elpa/magit-20250519.1537/.dir-locals.el deleted file mode 100644 index ea760dc2..00000000 --- a/elpa/magit-20250519.1537/.dir-locals.el +++ /dev/null @@ -1,15 +0,0 @@ -((nil - (indent-tabs-mode . nil)) - (makefile-mode - (indent-tabs-mode . t) - (outline-regexp . "#\\(#+\\)") - (mode . outline-minor)) - (emacs-lisp-mode - (checkdoc-allow-quoting-nil-and-t . t)) - (git-commit-mode - (git-commit-major-mode . git-commit-elisp-text-mode)) - (".github/PULL_REQUEST_TEMPLATE" - (nil (truncate-lines . nil))) - ("CHANGELOG" - (nil (fill-column . 70) - (mode . display-fill-column-indicator)))) diff --git a/elpa/magit-20250519.1537/AUTHORS.md b/elpa/magit-20250519.1537/AUTHORS.md deleted file mode 100644 index e0b88d92..00000000 --- a/elpa/magit-20250519.1537/AUTHORS.md +++ /dev/null @@ -1,425 +0,0 @@ -The following people have contributed to Magit. -For statistics see https://magit.vc/stats/magit/authors.html. - -Authors -------- - -- Marius Vollmer -- Jonas Bernoulli - -Active Maintainers ------------------- - -- Jonas Bernoulli -- Kyle Meyer - -Former Maintainers ------------------- - -- Nicolas Dudebout -- Noam Postavsky -- Peter J. Weisberg -- Phil Jackson -- Rémi Vanicat -- Yann Hodique - -All Contributors ----------------- - -- Aaron Culich -- Aaron L. Zeng -- Aaron Madlon-Kay -- Abdo Roig-Maranges -- Adam Benanti -- Adam Jones -- 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 Kreisher -- Alex Ott -- Allen Li -- Andreas Fuchs -- Andreas Liljeqvist -- Andreas Rottmann -- Andrei Chițu -- Andrew Eggenberger -- Andrew Kirkpatrick -- Andrew Psaltis -- Andrew Schwartzmeyer -- Andrew Zipperer -- Andrey Smirnov -- Andriy Kmit' -- Andy Sawyer -- Angel de Vicente -- 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 -- Ben Zanin -- Bob Uhl -- Boruch Baum -- Bradley Wright -- Brandon W Maister -- Brennan Vincent -- Brian Leung -- Brian Warner -- Bryan Shell -- Buster Copley -- Cameron Chaparro -- Carl Lieberman -- Chillar Anand -- Chris Bernard -- Chris Done -- Chris LaRose -- Chris Moore -- Chris Ring -- Chris Shoemaker -- Christian Dietrich -- Christian Kluge -- Christian Tietze -- Christophe Junke -- Christopher Carlile -- Christopher Monsanto -- Clément Pit-Claudel -- Cornelius Mika -- Craig Andera -- Curt Brune -- Daanturo -- 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 Mendler -- Daniel Nagy -- Dan Kessler -- Dan LaManna -- Danny Zhu -- Dato Simó -- David Abrahams -- David Ellison -- David Hull -- David L. Rager -- David Wallin -- Dean Kariniemi -- Dennis Paskorz -- Divye Kapoor -- Dominique Quatravaux -- Duianto Vebotci -- Eli Barzilay -- Ellis Kenyo -- Eric -- Eric Davis -- Eric Prud'hommeaux -- Eric Schulte -- Erik Anderson -- Eugene Mikhaylov -- Evan Torrie -- Evgkeni Sampelnikof -- Eyal Lotem -- Eyal Soha -- Fabian Wiget -- Felix Geller -- Felix Yan -- Feng Li -- Florian Ragwitz -- Franklin Delehelle -- Frédéric Giquel -- Fritz Grabo -- Fritz Stelzer -- gemmaro -- Geoff Shannon -- George Kadianakis -- Géza Herman -- Graham Clark -- Graham Dobbins -- Greg A. Woods -- Greg Lucas -- Gregory Heytings -- Greg Sexton -- Greg Steuck -- Guillaume Martres -- Hannu Koivisto -- Hans-Peter Deifel -- hokomo -- Hussein Ait-Lahcen -- Ian Eure -- Ian Milligan -- Ilya Grigoriev -- Iñaki Arenaza -- Ingmar Sittl -- Ingo Lohmar -- Ioan-Adrian Ratiu -- Ivan Brennan -- Jacob Ilsø -- Jan Tatarik -- Jasper St. Pierre -- JD Smith -- Jean-Louis Giordano -- Jeff Bellegarde -- Jeff Dairiki -- Jeremy Meng -- Jeremy Sowden -- Jesse Alama -- Jim Blandy -- Joakim Jalap -- Johannes Altmanninger -- Johannes Maier -- 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 -- Jorge Israel Peña -- 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 -- Lénaïc Huard -- Leo Liu -- Leonardo Etcheverry -- Leo Vivier -- Li Chen -- Lingchao Xin -- Lin Sun -- Li-Yun Chang -- Lluís Vilanova -- Loic Dachary -- Louis Roché -- Luís Oliveira -- Luke Amdor -- Magnar Sveen -- 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 -- Markus Beppler -- Martin Joerg -- Martin Polden -- Matt Beshara -- 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 -- Nacho Barrientos -- Naoya Yamashita -- Natalie Weizenbaum -- Nguyễn Tuấn Anh -- Nic Ferier -- Nicholas Vollmer -- Nick Alcock -- Nick Alexander -- Nick Dimiduk -- Nicklas Lindgren -- Nicolas Dudebout -- Nicolas Petton -- Nicolas Richard -- Nikita Leshenko -- Nikolay Martynov -- Noam Postavsky -- N. Troy de Freitas -- Ola Nilsson -- Ole Arndt -- Oleh Krehel -- Orivej Desh -- Óscar Fuentes -- Pancho Horrillo -- Park Zhou -- Paul Pogonyshev -- Paul Stadig -- Pavel Holejsovsky -- Pekka Pessi -- Pengji Zhang -- 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 -- Pieter van Oostrum -- Prathamesh Sonpatki -- Pratyush Yadav -- Pritam Baral -- rabio -- Radon Rosborough -- Rafael Laboissiere -- Rahul Rameshbabu -- Raimon Grau -- Ramkumar Ramachandra -- Remco van 't Veer -- Rémi Vanicat -- René Stadler -- Richard Kim -- Richard Sent -- Robert Boone -- Robert Irelan -- Robin Green -- Roey Darwish Dror -- Roger Crew -- Roland Marchand -- 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 Farley -- Sean Whitton -- Sebastian Wiesner -- Sébastien Gross -- Seong-Kook Shin -- Sergey Pashinin -- Sergey Vinokurov -- Servilio Afre Puentes -- shoefone -- Shuguang Sun -- Siavash Askari Nasr -- Silent Sphere -- Simon Pintarelli -- Stefan Kangas -- Štěpán Němec -- Steven Chow -- Steven E. Harris -- Steven Thomas -- Steven Vancoillie -- Steve Purcell -- StrawberryTea -- 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 -- Ulrich Müller -- Vineet Naik -- Vitaly Ostashov -- Vladimir Ivanov -- Vladimir Panteleev -- Vladimir Sedach -- Waqar Hameed -- Wei Huang -- Wilfred Hughes -- Win Treese -- Wojciech Siewierski -- Wouter Bolsterlee -- X4lldux -- Xavier Noria -- Xu Chunyang -- Yann Herklotz -- Yann Hodique -- Ynilu -- York Zhao -- Yuichi Higashi -- Yuri Khan -- Zach Latta -- zakora -- Zhu Zihao -- ziggy -- zilongshanren diff --git a/elpa/magit-20250519.1537/LICENSE b/elpa/magit-20250519.1537/LICENSE deleted file mode 100644 index f288702d..00000000 --- a/elpa/magit-20250519.1537/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-20250519.1537/dir b/elpa/magit-20250519.1537/dir deleted file mode 100644 index dfdbd715..00000000 --- a/elpa/magit-20250519.1537/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-20250519.1537/git-commit.el b/elpa/magit-20250519.1537/git-commit.el deleted file mode 100644 index 206cef88..00000000 --- a/elpa/magit-20250519.1537/git-commit.el +++ /dev/null @@ -1,1224 +0,0 @@ -;;; git-commit.el --- Edit Git commit messages -*- lexical-binding:t; coding:utf-8 -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; Author: Jonas Bernoulli -;; Sebastian Wiesner -;; Florian Ragwitz -;; Marius Vollmer -;; 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 of the License, -;; 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 . - -;; You should have received a copy of the AUTHORS.md file, which -;; lists all contributors. If not, see https://magit.vc/authors. - -;;; Commentary: - -;; This package assists the user in writing good Git commit messages. - -;; While Git allows for the message to be provided on the command -;; line, it is preferable to tell Git to create the commit without -;; actually passing it a message. Git then invokes the `$GIT_EDITOR' -;; (or if that is undefined `$EDITOR') asking the user to provide the -;; message by editing the file ".git/COMMIT_EDITMSG" (or another file -;; in that directory, e.g., ".git/MERGE_MSG" for merge commits). - -;; When `global-git-commit-mode' is enabled, which it is by default, -;; then opening such a file causes the features described below, to -;; be enabled in that buffer. Normally this would be done using a -;; major-mode but to allow the use of any major-mode, as the user sees -;; fit, it is done here by running a setup function, which among other -;; things turns on the preferred major-mode, by default `text-mode'. - -;; Git waits for the `$EDITOR' to finish and then either creates the -;; commit using the contents of the file as commit message, or, if the -;; editor process exited with a non-zero exit status, aborts without -;; creating a commit. Unfortunately Emacsclient (which is what Emacs -;; users should be using as `$EDITOR' or at least as `$GIT_EDITOR') -;; does not differentiate between "successfully" editing a file and -;; aborting; not out of the box that is. - -;; By making use of the `with-editor' package this package provides -;; both ways of finish an editing session. In either case the file -;; is saved, but Emacseditor's exit code differs. -;; -;; C-c C-c Finish the editing session successfully by returning -;; with exit code 0. Git then creates the commit using -;; the message it finds in the file. -;; -;; C-c C-k Aborts the edit editing session by returning with exit -;; code 1. Git then aborts the commit. - -;; Aborting the commit does not cause the message to be lost, but -;; relying solely on the file not being tampered with is risky. This -;; package additionally stores all aborted messages for the duration -;; of the current session (i.e., until you close Emacs). To get back -;; an aborted message use M-p and M-n while editing a message. -;; -;; M-p Replace the buffer contents with the previous message -;; from the message ring. Of course only after storing -;; the current content there too. -;; -;; M-n Replace the buffer contents with the next message from -;; the message ring, after storing the current content. - -;; Support for inserting Git trailers (as described in the manpage -;; git-interpret-trailers(1)) is available. -;; -;; C-c C-i Insert a trailer selected from a transient menu. - -;; When Git requests a commit message from the user, it does so by -;; having her edit a file which initially contains some comments, -;; instructing her what to do, and providing useful information, such -;; as which files were modified. These comments, even when left -;; intact by the user, do not become part of the commit message. This -;; package ensures these comments are propertizes as such and further -;; prettifies them by using different faces for various parts, such as -;; files. - -;; Finally this package highlights style errors, like lines that are -;; too long, or when the second line is not empty. It may even nag -;; you when you attempt to finish the commit without having fixed -;; these issues. The style checks and many other settings can easily -;; be configured: -;; -;; M-x customize-group RET git-commit RET - -;;; Code: - -(require 'magit-git) -(require 'magit-mode) -(require 'magit-process) - -(require 'log-edit) -(require 'ring) -(require 'server) -(require 'transient) -(require 'with-editor) - -(defvar diff-default-read-only) -(defvar flyspell-generic-check-word-predicate) -(defvar font-lock-beg) -(defvar font-lock-end) -(defvar recentf-exclude) - -(defvar git-commit-need-summary-line) - -(define-obsolete-variable-alias - 'git-commit-known-pseudo-headers - 'git-commit-trailers - "git-commit 4.0.0") - -;;; Options -;;;; Variables - -(defgroup git-commit nil - "Edit Git commit messages." - :prefix "git-commit-" - :link '(info-link "(magit)Editing Commit Messages") - :group 'tools) - -(define-minor-mode global-git-commit-mode - "Edit Git commit messages. - -This global mode arranges for `git-commit-setup' to be called -when a Git commit message file is opened. That usually happens -when Git uses the Emacsclient as $GIT_EDITOR to have the user -provide such a commit message. - -Loading the library `git-commit' by default enables this mode, -but the library is not automatically loaded because doing that -would pull in many dependencies and increase startup time too -much. You can either rely on `magit' loading this library or -you can load it explicitly. Autoloading is not an alternative -because in this case autoloading would immediately trigger -full loading." - :group 'git-commit - :type 'boolean - :global t - :init-value t - :initialize - (lambda (symbol exp) - (custom-initialize-default symbol exp) - (when global-git-commit-mode - (add-hook 'find-file-hook #'git-commit-setup-check-buffer) - (remove-hook 'after-change-major-mode-hook - #'git-commit-setup-font-lock-in-buffer))) - (cond - (global-git-commit-mode - (add-hook 'find-file-hook #'git-commit-setup-check-buffer) - (add-hook 'after-change-major-mode-hook - #'git-commit-setup-font-lock-in-buffer)) - (t - (remove-hook 'find-file-hook #'git-commit-setup-check-buffer) - (remove-hook 'after-change-major-mode-hook - #'git-commit-setup-font-lock-in-buffer)))) - -(defcustom git-commit-major-mode #'text-mode - "Major mode used to edit Git commit messages. - -The major mode configured here is turned on by the minor mode -`git-commit-mode'." - :group 'git-commit - :type '(radio (function-item text-mode) - (function-item markdown-mode) - (function-item org-mode) - (function-item fundamental-mode) - (function-item log-edit-mode) - (function-item git-commit-elisp-text-mode) - (function :tag "Another mode") - (const :tag "No major mode"))) -;;;###autoload(put 'git-commit-major-mode 'safe-local-variable -;;;###autoload (lambda (val) -;;;###autoload (memq val '(text-mode -;;;###autoload markdown-mode -;;;###autoload org-mode -;;;###autoload fundamental-mode -;;;###autoload log-edit-mode -;;;###autoload git-commit-elisp-text-mode)))) - -(defvaralias 'git-commit-mode-hook 'git-commit-setup-hook - "This variable is an alias for `git-commit-setup-hook' (which see). -Also note that `git-commit-mode' (which see) is not a major-mode.") - -(defcustom git-commit-setup-hook - (list #'git-commit-ensure-comment-gap - #'git-commit-save-message - #'git-commit-setup-changelog-support - #'git-commit-turn-on-auto-fill - #'git-commit-propertize-diff - #'bug-reference-mode) - "Hook run at the end of `git-commit-setup'." - :group 'git-commit - :type 'hook - :get #'magit-hook-custom-get - :options '(git-commit-ensure-comment-gap - git-commit-save-message - git-commit-setup-changelog-support - magit-generate-changelog - git-commit-turn-on-auto-fill - git-commit-turn-on-orglink - git-commit-turn-on-flyspell - git-commit-propertize-diff - bug-reference-mode)) - -(defcustom git-commit-post-finish-hook nil - "Hook run after the user finished writing a commit message. - -\\\ -This hook is only run after pressing \\[with-editor-finish] 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 -that takes Git longer than `git-commit-post-finish-hook-timeout' -seconds, 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. - -Also see `magit-post-commit-hook'." - :group 'git-commit - :type 'hook - :get #'magit-hook-custom-get) - -(defcustom git-commit-post-finish-hook-timeout 1 - "Time in seconds to wait for git to create a commit. - -The hook `git-commit-post-finish-hook' (which see) is run only -after git is done creating a commit. If it takes longer than -`git-commit-post-finish-hook-timeout' seconds to create the -commit, then the hook is not run at all." - :group 'git-commit - :safe 'numberp - :type 'number) - -(defcustom git-commit-finish-query-functions - (list #'git-commit-check-style-conventions) - "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." - :options '(git-commit-check-style-conventions) - :type 'hook - :group 'git-commit) - -(defcustom git-commit-style-convention-checks '(non-empty-second-line) - "List of checks performed by `git-commit-check-style-conventions'. - -Valid members are `non-empty-second-line' and `overlong-summary-line'. -That function is a member of `git-commit-finish-query-functions'." - :options '(non-empty-second-line overlong-summary-line) - :type '(list :convert-widget custom-hook-convert-widget) - :group 'git-commit) - -(defcustom git-commit-summary-max-length 68 - "Column beyond which characters in the summary lines are highlighted. - -The highlighting indicates that the summary is getting too long -by some standards. It does in no way imply that going over the -limit a few characters or in some cases even many characters is -anything that deserves shaming. It's just a friendly reminder -that if you can make the summary shorter, then you might want -to consider doing so." - :group 'git-commit - :safe 'numberp - :type 'number) - -(defcustom git-commit-trailers - '("Acked-by" - "Modified-by" - "Reviewed-by" - "Signed-off-by" - "Tested-by" - "Cc" - "Reported-by" - "Suggested-by" - "Co-authored-by" - "Co-developed-by") - "A list of Git trailers to be highlighted. - -See also manpage git-interpret-trailer(1). This package does -not use that Git command, but the initial description still -serves as a good introduction." - :group 'git-commit - :safe (##and (listp %) (seq-every-p #'stringp %)) - :type '(repeat string)) - -(defcustom git-commit-use-local-message-ring nil - "Whether to use a local message ring instead of the global one. - -This can be set globally, in which case every repository gets its -own commit message ring, or locally for a single repository." - :group 'git-commit - :safe 'booleanp - :type 'boolean) - -(defcustom git-commit-cd-to-toplevel nil - "Whether to set `default-directory' to the worktree in message buffer. - -Editing a commit message is done by visiting a file located in the git -directory, usually \"COMMIT_EDITMSG\". As is done when visiting any -file, the local value of `default-directory' is set to the directory -that contains the file. - -If this option is non-nil, then the local `default-directory' is changed -to the working tree from which the commit command was invoked. You may -wish to do that, to make it easier to open a file that is located in the -working tree, directly from the commit message buffer. - -If the git variable `safe.bareRepository' is set to \"explicit\", then -you have to enable this, to be able to commit at all. See issue #5100. - -This option only has an effect if the commit was initiated from Magit." - :group 'git-commit - :type 'boolean) - -;;;; Faces - -(defgroup git-commit-faces nil - "Faces used for highlighting Git commit messages." - :prefix "git-commit-" - :group 'git-commit - :group 'faces) - -(defface git-commit-summary - '((t :inherit font-lock-type-face)) - "Face used for the summary in commit messages." - :group 'git-commit-faces) - -(defface git-commit-overlong-summary - '((t :inherit font-lock-warning-face)) - "Face used for the tail of overlong commit message summaries." - :group 'git-commit-faces) - -(defface git-commit-nonempty-second-line - '((t :inherit font-lock-warning-face)) - "Face used for non-whitespace on the second line of commit messages." - :group 'git-commit-faces) - -(defface git-commit-keyword - '((t :inherit font-lock-string-face)) - "Face used for keywords in commit messages. -In this context a \"keyword\" is text surrounded by brackets." - :group 'git-commit-faces) - -(defface git-commit-trailer-token - '((t :inherit font-lock-keyword-face)) - "Face used for Git trailer tokens in commit messages." - :group 'git-commit-faces) - -(defface git-commit-trailer-value - '((t :inherit font-lock-string-face)) - "Face used for Git trailer values in commit messages." - :group 'git-commit-faces) - -(defface git-commit-comment-branch-local - '((t :inherit magit-branch-local)) - "Face used for names of local branches in commit message comments." - :group 'git-commit-faces) - -(defface git-commit-comment-branch-remote - '((t :inherit magit-branch-remote)) - "Face used for names of remote branches in commit message comments." - :group 'git-commit-faces) - -(defface git-commit-comment-detached - '((t :inherit git-commit-comment-branch-local)) - "Face used for detached `HEAD' in commit message comments." - :group 'git-commit-faces) - -(defface git-commit-comment-heading - '((t :inherit git-commit-trailer-token)) - "Face used for headings in commit message comments." - :group 'git-commit-faces) - -(defface git-commit-comment-file - '((t :inherit git-commit-trailer-value)) - "Face used for file names in commit message comments." - :group 'git-commit-faces) - -(defface git-commit-comment-action - '((t :inherit bold)) - "Face used for actions in commit message comments." - :group 'git-commit-faces) - -;;; Keymap - -(defvar-keymap git-commit-redundant-bindings - :doc "Bindings made redundant by `git-commit-insert-trailer'. -This keymap is used as the parent of `git-commit-mode-map', -to avoid upsetting muscle-memory. If you would rather avoid -the redundant bindings, then set this to nil, before loading -`git-commit'." - "C-c C-a" #'git-commit-ack - "C-c M-i" #'git-commit-suggested - "C-c C-m" #'git-commit-modified - "C-c C-o" #'git-commit-cc - "C-c C-p" #'git-commit-reported - "C-c C-r" #'git-commit-review - "C-c C-s" #'git-commit-signoff - "C-c C-t" #'git-commit-test) - -(defvar-keymap git-commit-mode-map - :doc "Keymap used by `git-commit-mode'." - :parent git-commit-redundant-bindings - "M-p" #'git-commit-prev-message - "M-n" #'git-commit-next-message - "C-c M-p" #'git-commit-search-message-backward - "C-c M-n" #'git-commit-search-message-forward - "C-c C-i" #'git-commit-insert-trailer - "C-c M-s" #'git-commit-save-message - "C-c C-d" 'magit-diff-while-committing - "C-c C-w" 'magit-pop-revision-stack) - -;;; Menu - -(require 'easymenu) -(easy-menu-define git-commit-mode-menu git-commit-mode-map - "Git Commit Mode Menu." - '("Commit" - ["Previous" git-commit-prev-message t] - ["Next" git-commit-next-message t] - "-" - ["Ack" git-commit-ack t - :help "Insert an 'Acked-by' trailer"] - ["Modified-by" git-commit-modified t - :help "Insert a 'Modified-by' trailer"] - ["Reviewed-by" git-commit-review t - :help "Insert a 'Reviewed-by' trailer"] - ["Sign-Off" git-commit-signoff t - :help "Insert a 'Signed-off-by' trailer"] - ["Tested-by" git-commit-test t - :help "Insert a 'Tested-by' trailer"] - "-" - ["CC" git-commit-cc t - :help "Insert a 'Cc' trailer"] - ["Reported" git-commit-reported t - :help "Insert a 'Reported-by' trailer"] - ["Suggested" git-commit-suggested t - :help "Insert a 'Suggested-by' trailer"] - ["Co-authored-by" git-commit-co-authored t - :help "Insert a 'Co-authored-by' trailer"] - ["Co-developed-by" git-commit-co-developed t - :help "Insert a 'Co-developed-by' trailer"] - "-" - ["Save" git-commit-save-message t] - ["Cancel" with-editor-cancel t] - ["Commit" with-editor-finish t])) - -;;; Hooks - -(defconst git-commit-filename-regexp "/\\(\ -\\(\\(COMMIT\\|NOTES\\|PULLREQ\\|MERGEREQ\\|TAG\\)_EDIT\\|MERGE_\\|\\)MSG\ -\\|\\(BRANCH\\|EDIT\\)_DESCRIPTION\\)\\'") - -(with-eval-after-load 'recentf - (add-to-list 'recentf-exclude git-commit-filename-regexp)) - -(add-to-list 'with-editor-file-name-history-exclude git-commit-filename-regexp) - -(defun git-commit-setup-font-lock-in-buffer () - (when (and buffer-file-name - (string-match-p git-commit-filename-regexp buffer-file-name)) - (git-commit-setup-font-lock))) - -(defun git-commit-setup-check-buffer () - (when (and buffer-file-name - (string-match-p git-commit-filename-regexp buffer-file-name)) - (git-commit-setup))) - -(defvar git-commit-mode) - -(defun git-commit-file-not-found () - ;; cygwin git will pass a cygwin path (/cygdrive/c/foo/.git/...), - ;; try to handle this in window-nt Emacs. - (when-let* - ((file (and (or (string-match-p git-commit-filename-regexp - buffer-file-name) - (and (boundp 'git-rebase-filename-regexp) - (string-match-p git-rebase-filename-regexp - buffer-file-name))) - (not (file-accessible-directory-p - (file-name-directory buffer-file-name))) - (magit-expand-git-file-name (substring buffer-file-name 2)))) - ((file-accessible-directory-p (file-name-directory file))) - (inhibit-read-only t)) - (insert-file-contents file t) - t)) - -(when (eq system-type 'windows-nt) - (add-hook 'find-file-not-found-functions #'git-commit-file-not-found)) - -(defconst git-commit-default-usage-message "\ -Type \\[with-editor-finish] to finish, \ -\\[with-editor-cancel] to cancel, and \ -\\[git-commit-prev-message] and \\[git-commit-next-message] \ -to recover older messages") - -(defvar git-commit-usage-message git-commit-default-usage-message - "Message displayed when editing a commit message. -When this is nil, then `with-editor-usage-message' is displayed -instead. One of these messages has to be displayed; otherwise -the user gets to see the message displayed by `server-execute'. -That message is misleading and because we cannot prevent it from -being displayed, we have to immediately show another message to -prevent the user from seeing it.") - -(defvar git-commit-header-line-format nil - "If non-nil, header line format used by `git-commit-mode'. -Used as the local value of `header-line-format', in buffer using -`git-commit-mode'. If it is a string, then it is passed through -`substitute-command-keys' first. A useful setting may be: - (setq git-commit-header-line-format git-commit-default-usage-message) - (setq git-commit-usage-message nil) ; show a shorter message") - -(defun git-commit-setup () - (let ((gitdir default-directory) - (cd (and git-commit-cd-to-toplevel - (or (car (rassoc default-directory magit--separated-gitdirs)) - (magit-toplevel))))) - ;; Pretend that git-commit-mode is a major-mode, - ;; so that directory-local settings can be used. - (let ((default-directory - (or (and (not (file-exists-p - (expand-file-name ".dir-locals.el" gitdir))) - ;; When $GIT_DIR/.dir-locals.el doesn't exist, - ;; fallback to $GIT_WORK_TREE/.dir-locals.el, - ;; because the maintainer can use the latter - ;; to enforce conventions, while s/he has no - ;; control over the former. - (or cd (magit-toplevel))) - gitdir))) - (let ((buffer-file-name nil) ; trick hack-dir-local-variables - (major-mode 'git-commit-mode)) ; trick dir-locals-collect-variables - (hack-dir-local-variables) - (hack-local-variables-apply))) - (when cd - (setq default-directory cd))) - (when git-commit-major-mode - (let ((auto-mode-alist - ;; `set-auto-mode--apply-alist' removes the remote part from - ;; the file-name before looking it up in `auto-mode-alist'. - ;; For our temporary entry to be found, we have to modify the - ;; file-name the same way. - (list (cons (concat "\\`" - (regexp-quote - (or (file-remote-p buffer-file-name 'localname) - buffer-file-name)) - "\\'") - git-commit-major-mode))) - ;; The major-mode hook might want to consult these minor - ;; modes, while the minor-mode hooks might want to consider - ;; the major mode. - (git-commit-mode t) - (with-editor-mode t)) - (normal-mode t))) - ;; Below we instead explicitly show a message. - (setq with-editor-show-usage nil) - (unless with-editor-mode - ;; Maybe already enabled when using `shell-command' or an Emacs shell. - (with-editor-mode 1)) - (add-hook 'with-editor-finish-query-functions - #'git-commit-finish-query-functions nil t) - (add-hook 'with-editor-pre-finish-hook #'git-commit-save-message nil t) - (add-hook 'with-editor-pre-cancel-hook #'git-commit-save-message nil t) - (when (fboundp 'magit-commit--reset-command) - (add-hook 'with-editor-post-finish-hook #'magit-commit--reset-command) - (add-hook 'with-editor-post-cancel-hook #'magit-commit--reset-command)) - (unless (memq last-command - '(magit-sequencer-continue - magit-sequencer-skip - magit-am-continue - magit-am-skip - magit-rebase-continue - magit-rebase-skip)) - (add-hook 'with-editor-post-finish-hook - (apply-partially #'git-commit-run-post-finish-hook - (magit-rev-parse "HEAD")) - nil t) - (when (fboundp 'magit-wip-maybe-add-commit-hook) - (magit-wip-maybe-add-commit-hook))) - (setq with-editor-cancel-message - #'git-commit-cancel-message) - (git-commit-setup-font-lock) - (git-commit-prepare-message-ring) - (when (boundp 'save-place) - (setq save-place nil)) - (let ((git-commit-mode-hook nil)) - (git-commit-mode 1)) - (with-demoted-errors "Error running git-commit-setup-hook: %S" - (run-hooks 'git-commit-setup-hook)) - (set-buffer-modified-p nil) - (when-let ((format git-commit-header-line-format)) - (setq header-line-format - (if (stringp format) (substitute-command-keys format) format))) - (when git-commit-usage-message - (setq with-editor-usage-message git-commit-usage-message)) - (with-editor-usage-message)) - -(defun git-commit-run-post-finish-hook (previous) - (when git-commit-post-finish-hook - (cl-block nil - (let ((break (time-add (current-time) - (seconds-to-time - git-commit-post-finish-hook-timeout)))) - (while (equal (magit-rev-parse "HEAD") previous) - (if (time-less-p (current-time) break) - (sit-for 0.01) - (message "No commit created after 1 second. Not running %s." - 'git-commit-post-finish-hook) - (cl-return)))) - (run-hooks 'git-commit-post-finish-hook)))) - -(define-minor-mode git-commit-mode - "Auxiliary minor mode used when editing Git commit messages. -This mode is only responsible for setting up some key bindings. -Don't use it directly; instead enable `global-git-commit-mode'. -Variable `git-commit-major-mode' controls which major-mode is -used." - :lighter "") - -(put 'git-commit-mode 'permanent-local t) - -(defun git-commit-ensure-comment-gap () - "Separate initial empty line from initial comment. -If the buffer begins with an empty line followed by a comment, insert -an additional newline in between, so that once the users start typing, -the input isn't tacked to the comment." - (save-excursion - (goto-char (point-min)) - (when (looking-at (format "\\`\n%s" comment-start)) - (open-line 1)))) - -(defun git-commit-setup-changelog-support () - "Treat ChangeLog entries as unindented paragraphs." - (setq-local fill-paragraph-function #'log-edit-fill-entry) - (setq-local fill-indent-according-to-mode t) - (setq-local paragraph-start (concat paragraph-start "\\|\\*\\|("))) - -(defun git-commit-turn-on-auto-fill () - "Unconditionally turn on Auto Fill mode. -Ensure auto filling happens everywhere, except in the summary line." - (auto-fill-mode 1) - (setq-local comment-auto-fill-only-comments nil) - (when git-commit-need-summary-line - (setq-local auto-fill-function #'git-commit-auto-fill-except-summary))) - -(defun git-commit-auto-fill-except-summary () - (unless (eq (line-beginning-position) 1) - (do-auto-fill))) - -(defun git-commit-turn-on-orglink () - "Turn on Orglink mode if it is available. -If `git-commit-major-mode' is `org-mode', then silently forgo -turning on `orglink-mode'." - (when (and (not (derived-mode-p 'org-mode)) - (boundp 'orglink-match-anywhere) - (fboundp 'orglink-mode)) - (setq-local orglink-match-anywhere t) - (orglink-mode 1))) - -(defun git-commit-turn-on-flyspell () - "Unconditionally turn on Flyspell mode. -Also check text that is already in the buffer, while avoiding to check -most text that Git will strip from the final message, such as the last -comment and anything below the cut line (\"--- >8 ---\")." - (require 'flyspell) - (flyspell-mode 1) - (setq flyspell-generic-check-word-predicate - #'git-commit-flyspell-verify) - (let ((end nil) - ;; The "cut line" is defined in "git/wt-status.c". It appears - ;; in the commit message when `commit.verbose' is set to true. - (cut-line-regex (format "^%s -\\{8,\\} >8 -\\{8,\\}$" comment-start)) - (comment-start-regex (format "^\\(%s\\|$\\)" comment-start))) - (save-excursion - (goto-char (or (re-search-forward cut-line-regex nil t) - (point-max))) - (while (and (not (bobp)) (looking-at comment-start-regex)) - (forward-line -1)) - (unless (looking-at comment-start-regex) - (forward-line)) - (setq end (point))) - (flyspell-region (point-min) end))) - -(defun git-commit-flyspell-verify () - (not (= (char-after (line-beginning-position)) - (aref comment-start 0)))) - -(defun git-commit-finish-query-functions (force) - (run-hook-with-args-until-failure - 'git-commit-finish-query-functions force)) - -(defun git-commit-check-style-conventions (force) - "Check for violations of certain basic style conventions. - -For each violation ask the user if she wants to proceed anyway. -Option `git-commit-style-convention-checks' controls which -conventions are checked." - (or force - (save-excursion - (goto-char (point-min)) - (re-search-forward (git-commit-summary-regexp) nil t) - (if (equal (match-string 1) "") - t ; Just try; we don't know whether --allow-empty-message was used. - (and (or (not (memq 'overlong-summary-line - git-commit-style-convention-checks)) - (equal (match-string 2) "") - (y-or-n-p "Summary line is too long. Commit anyway? ")) - (or (not (memq 'non-empty-second-line - git-commit-style-convention-checks)) - (not (match-string 3)) - (y-or-n-p "Second line is not empty. Commit anyway? "))))))) - -(defun git-commit-cancel-message () - (message - (concat "Commit canceled" - (and (memq 'git-commit-save-message with-editor-pre-cancel-hook) - ". Message saved to `log-edit-comment-ring'")))) - -;;; History - -(defun git-commit-prev-message (arg) - "Cycle backward through message history, after saving current message. -With a numeric prefix ARG, go back ARG messages." - (interactive "*p") - (let ((len (ring-length log-edit-comment-ring))) - (if (<= len 0) - (progn (message "Empty comment ring") (ding)) - ;; Unlike `log-edit-previous-comment' we save the current - ;; non-empty and newly written comment, because otherwise - ;; it would be irreversibly lost. - (when-let* ((message (git-commit-buffer-message)) - ((not (ring-member log-edit-comment-ring message)))) - (ring-insert log-edit-comment-ring message) - (cl-incf arg) - (setq len (ring-length log-edit-comment-ring))) - ;; Delete the message but not the instructions at the end. - (save-restriction - (goto-char (point-min)) - (narrow-to-region - (point) - (if (re-search-forward (concat "^" comment-start) nil t) - (max 1 (- (point) 2)) - (point-max))) - (delete-region (point-min) (point))) - (setq log-edit-comment-ring-index (log-edit-new-comment-index arg len)) - (message "Comment %d" (1+ log-edit-comment-ring-index)) - (insert (ring-ref log-edit-comment-ring log-edit-comment-ring-index))))) - -(defun git-commit-next-message (arg) - "Cycle forward through message history, after saving current message. -With a numeric prefix ARG, go forward ARG messages." - (interactive "*p") - (git-commit-prev-message (- arg))) - -(defun git-commit-search-message-backward (string) - "Search backward through message history for a match for STRING. -Save current message first." - (interactive - (list (read-string (format-prompt "Comment substring" - log-edit-last-comment-match) - nil nil log-edit-last-comment-match))) - (cl-letf (((symbol-function #'log-edit-previous-comment) - (symbol-function #'git-commit-prev-message))) - (log-edit-comment-search-backward string))) - -(defun git-commit-search-message-forward (string) - "Search forward through message history for a match for STRING. -Save current message first." - (interactive - (list (read-string (format-prompt "Comment substring" - log-edit-last-comment-match) - nil nil log-edit-last-comment-match))) - (cl-letf (((symbol-function #'log-edit-previous-comment) - (symbol-function #'git-commit-prev-message))) - (log-edit-comment-search-forward string))) - -(defun git-commit-save-message () - "Save current message to `log-edit-comment-ring'." - (interactive) - (if-let ((message (git-commit-buffer-message))) - (progn - (when-let ((index (ring-member log-edit-comment-ring message))) - (ring-remove log-edit-comment-ring index)) - (ring-insert log-edit-comment-ring message) - (when git-commit-use-local-message-ring - (magit-repository-local-set 'log-edit-comment-ring - log-edit-comment-ring)) - (message "Message saved")) - (message "Only whitespace and/or comments; message not saved"))) - -(defun git-commit-prepare-message-ring () - (make-local-variable 'log-edit-comment-ring-index) - (when git-commit-use-local-message-ring - (setq-local log-edit-comment-ring - (magit-repository-local-get - 'log-edit-comment-ring - (make-ring log-edit-maximum-comment-ring-size))))) - -(defun git-commit-buffer-message () - (let ((flush (concat "^" comment-start)) - (str (buffer-substring-no-properties (point-min) (point-max)))) - (with-temp-buffer - (insert str) - (goto-char (point-min)) - (when (re-search-forward (concat flush " -+ >8 -+$") nil t) - (delete-region (line-beginning-position) (point-max))) - (goto-char (point-min)) - (flush-lines flush) - (goto-char (point-max)) - (unless (eq (char-before) ?\n) - (insert ?\n)) - (setq str (buffer-string))) - (and (not (string-match "\\`[ \t\n\r]*\\'" str)) - (progn - (when (string-match "\\`\n\\{2,\\}" str) - (setq str (replace-match "\n" t t str))) - (when (string-match "\n\\{2,\\}\\'" str) - (setq str (replace-match "\n" t t str))) - str)))) - -;;; Trailers - -(transient-define-prefix git-commit-insert-trailer () - "Insert a commit message trailer. - -See also manpage git-interpret-trailer(1). This command does -not use that Git command, but the initial description still -serves as a good introduction." - [[:description (##cond (prefix-arg - "Insert ... by someone ") - ("Insert ... by yourself")) - ("a" "Ack" git-commit-ack) - ("m" "Modified" git-commit-modified) - ("r" "Reviewed" git-commit-review) - ("s" "Signed-off" git-commit-signoff) - ("t" "Tested" git-commit-test)] - ["Insert ... by someone" - ("C-c" "Cc" git-commit-cc) - ("C-r" "Reported" git-commit-reported) - ("C-i" "Suggested" git-commit-suggested) - ("C-a" "Co-authored" git-commit-co-authored) - ("C-d" "Co-developed" git-commit-co-developed)]]) - -(defun git-commit-ack (name mail) - "Insert a trailer acknowledging that you have looked at the commit." - (interactive (git-commit-get-ident "Acked-by")) - (git-commit--insert-ident-trailer "Acked-by" name mail)) - -(defun git-commit-modified (name mail) - "Insert a trailer to signal that you have modified the commit." - (interactive (git-commit-get-ident "Modified-by")) - (git-commit--insert-ident-trailer "Modified-by" name mail)) - -(defun git-commit-review (name mail) - "Insert a trailer acknowledging that you have reviewed the commit. -With a prefix argument, prompt for another person who performed a -review." - (interactive (git-commit-get-ident "Reviewed-by")) - (git-commit--insert-ident-trailer "Reviewed-by" name mail)) - -(defun git-commit-signoff (name mail) - "Insert a trailer to sign off the commit. -With a prefix argument, prompt for another person who signed off." - (interactive (git-commit-get-ident "Signed-off-by")) - (git-commit--insert-ident-trailer "Signed-off-by" name mail)) - -(defun git-commit-test (name mail) - "Insert a trailer acknowledging that you have tested the commit. -With a prefix argument, prompt for another person who tested." - (interactive (git-commit-get-ident "Tested-by")) - (git-commit--insert-ident-trailer "Tested-by" name mail)) - -(defun git-commit-cc (name mail) - "Insert a trailer mentioning someone who might be interested." - (interactive (git-commit-read-ident "Cc")) - (git-commit--insert-ident-trailer "Cc" name mail)) - -(defun git-commit-reported (name mail) - "Insert a trailer mentioning the person who reported the issue." - (interactive (git-commit-read-ident "Reported-by")) - (git-commit--insert-ident-trailer "Reported-by" name mail)) - -(defun git-commit-suggested (name mail) - "Insert a trailer mentioning the person who suggested the change." - (interactive (git-commit-read-ident "Suggested-by")) - (git-commit--insert-ident-trailer "Suggested-by" name mail)) - -(defun git-commit-co-authored (name mail) - "Insert a trailer mentioning the person who co-authored the commit." - (interactive (git-commit-read-ident "Co-authored-by")) - (git-commit--insert-ident-trailer "Co-authored-by" name mail)) - -(defun git-commit-co-developed (name mail) - "Insert a trailer mentioning the person who co-developed the commit." - (interactive (git-commit-read-ident "Co-developed-by")) - (git-commit--insert-ident-trailer "Co-developed-by" name mail)) - -(defun git-commit-get-ident (&optional prompt) - "Return name and email of the user or read another name and email. -If PROMPT and `current-prefix-arg' are both non-nil, read name -and email using `git-commit-read-ident' (which see), otherwise -return name and email of the current user (you)." - (if (and prompt current-prefix-arg) - (git-commit-read-ident prompt) - (list (or (getenv "GIT_AUTHOR_NAME") - (getenv "GIT_COMMITTER_NAME") - (with-demoted-errors "Error running 'git config user.name': %S" - (magit-get "user.name")) - user-full-name - (read-string "Name: ")) - (or (getenv "GIT_AUTHOR_EMAIL") - (getenv "GIT_COMMITTER_EMAIL") - (getenv "EMAIL") - (with-demoted-errors "Error running 'git config user.email': %S" - (magit-get "user.email")) - (read-string "Email: "))))) - -(defalias 'git-commit-self-ident #'git-commit-get-ident) - -(defvar git-commit-read-ident-history nil) - -(defun git-commit-read-ident (prompt) - "Read a name and email, prompting with PROMPT, and return them. -Read them using a single prompt, offering past commit authors as -completion candidates. The input must have the form \"NAME \"." - (let ((str (magit-completing-read - prompt - (sort (delete-dups - (magit-git-lines "log" "-n9999" "--format=%aN <%ae>")) - #'string<) - nil nil nil 'git-commit-read-ident-history))) - (save-match-data - (if (string-match "\\`\\([^<]+\\) *<\\([^>]+\\)>\\'" str) - (list (save-match-data (string-trim (match-string 1 str))) - (string-trim (match-string 2 str))) - (user-error "Invalid input"))))) - -(defun git-commit--insert-ident-trailer (trailer name email) - (git-commit--insert-trailer trailer (format "%s <%s>" name email))) - -(defun git-commit--insert-trailer (trailer value) - (save-excursion - (let ((string (format "%s: %s" trailer value)) - (leading-comment-end nil)) - ;; Make sure we skip forward past any leading comments. - (goto-char (point-min)) - (while (looking-at comment-start) - (forward-line)) - (setq leading-comment-end (point)) - (goto-char (point-max)) - (cond - ;; Look backwards for existing trailers. - ((re-search-backward (git-commit--trailer-regexp) nil t) - (end-of-line) - (insert ?\n string) - (unless (= (char-after) ?\n) - (insert ?\n))) - ;; Or place the new trailer right before the first non-leading - ;; comments. - (t - (while (re-search-backward (concat "^" comment-start) - leading-comment-end t)) - (unless (looking-back "\n\n" nil) - (insert ?\n)) - (insert string ?\n)))) - (unless (or (eobp) (= (char-after) ?\n)) - (insert ?\n)))) - -;;; Font-Lock - -(defvar-local git-commit-need-summary-line t - "Whether the text should have a heading that is separated from the body. - -For commit messages that is a convention that should not -be violated. For notes it is up to the user. If you do -not want to insist on an empty second line here, then use -something like: - - (add-hook \\='git-commit-setup-hook - (lambda () - (when (equal (file-name-nondirectory (buffer-file-name)) - \"NOTES_EDITMSG\") - (setq git-commit-need-summary-line nil))))") - -(defun git-commit--trailer-regexp () - (format - "^\\(?:\\(%s:\\)\\( .*\\)\\|\\([-a-zA-Z]+\\): \\([^<\n]+? <[^>\n]+>\\)\\)" - (regexp-opt git-commit-trailers))) - -(defun git-commit-summary-regexp () - (if git-commit-need-summary-line - (concat - ;; Leading empty lines and comments - (format "\\`\\(?:^\\(?:\\s-*\\|%s.*\\)\n\\)*" comment-start) - ;; Summary line - (format "\\(.\\{0,%d\\}\\)\\(.*\\)" git-commit-summary-max-length) - ;; Non-empty non-comment second line - (format "\\(?:\n%s\\|\n\\(.+\\)\\)?" comment-start)) - "\\(EASTER\\) \\(EGG\\)")) - -(defun git-commit-extend-region-summary-line () - "Identify the multiline summary-regexp construct. -Added to `font-lock-extend-region-functions'." - (save-excursion - (save-match-data - (goto-char (point-min)) - (when (looking-at (git-commit-summary-regexp)) - (let ((summary-beg (match-beginning 0)) - (summary-end (match-end 0))) - (when (or (< summary-beg font-lock-beg summary-end) - (< summary-beg font-lock-end summary-end)) - (setq font-lock-beg (min font-lock-beg summary-beg)) - (setq font-lock-end (max font-lock-end summary-end)))))))) - -(defvar-local git-commit--branch-name-regexp nil) - -(defconst git-commit-comment-headings - '("Changes to be committed:" - "Untracked files:" - "Changed but not updated:" - "Changes not staged for commit:" - "Unmerged paths:" - "Author:" - "Date:") - "Also fontified outside of comments in `git-commit-font-lock-keywords-2'.") - -(defconst git-commit-font-lock-keywords-1 - '(;; Trailers - (eval . `(,(git-commit--trailer-regexp) - (1 'git-commit-trailer-token nil t) - (2 'git-commit-trailer-value nil t) - (3 'git-commit-trailer-token nil t) - (4 'git-commit-trailer-value nil t))) - ;; Summary - (eval . `(,(git-commit-summary-regexp) - (1 'git-commit-summary))) - ;; - Keyword [aka "text in brackets"] (overrides summary) - ("\\[[^][]+?\\]" - (0 'git-commit-keyword t)) - ;; - Non-empty second line (overrides summary and note) - (eval . `(,(git-commit-summary-regexp) - (2 'git-commit-overlong-summary t t) - (3 'git-commit-nonempty-second-line t t))))) - -(defconst git-commit-font-lock-keywords-2 - `(,@git-commit-font-lock-keywords-1 - ;; Comments - (eval . `(,(format "^%s.*" comment-start) - (0 'font-lock-comment-face append))) - (eval . `(,(format "^%s On branch \\(.*\\)" comment-start) - (1 'git-commit-comment-branch-local t))) - (eval . `(,(format "^%s \\(HEAD\\) detached at" comment-start) - (1 'git-commit-comment-detached t))) - (eval . `(,(format "^%s %s" comment-start - (regexp-opt git-commit-comment-headings t)) - (1 'git-commit-comment-heading t))) - (eval . `(,(format "^%s\t\\(?:\\([^:\n]+\\):\\s-+\\)?\\(.*\\)" comment-start) - (1 'git-commit-comment-action t t) - (2 'git-commit-comment-file t))) - ;; "commit HASH" - (eval . '("^commit [[:alnum:]]+$" - (0 'git-commit-trailer-value))) - ;; `git-commit-comment-headings' (but not in commented lines) - (eval . `(,(format "\\(?:^%s[[:blank:]]+.+$\\)" - (regexp-opt git-commit-comment-headings)) - (0 'git-commit-trailer-value))))) - -(defconst git-commit-font-lock-keywords-3 - `(,@git-commit-font-lock-keywords-2 - ;; More comments - (eval - ;; Your branch is ahead of 'master' by 3 commits. - ;; Your branch is behind 'master' by 2 commits, and can be fast-forwarded. - . `(,(format - "^%s Your branch is \\(?:ahead\\|behind\\) of '%s' by \\([0-9]*\\)" - comment-start git-commit--branch-name-regexp) - (1 'git-commit-comment-branch-local t) - (2 'git-commit-comment-branch-remote t) - (3 'bold t))) - (eval - ;; Your branch is up to date with 'master'. - ;; Your branch and 'master' have diverged, - . `(,(format - "^%s Your branch \\(?:is up[- ]to[- ]date with\\|and\\) '%s'" - comment-start git-commit--branch-name-regexp) - (1 'git-commit-comment-branch-local t) - (2 'git-commit-comment-branch-remote t))) - (eval - ;; and have 1 and 2 different commits each, respectively. - . `(,(format - "^%s and have \\([0-9]*\\) and \\([0-9]*\\) commits each" - comment-start) - (1 'bold t) - (2 'bold t))))) - -(defvar git-commit-font-lock-keywords git-commit-font-lock-keywords-3 - "Font-Lock keywords for Git-Commit mode.") - -(defun git-commit-setup-font-lock () - (with-demoted-errors "Error running git-commit-setup-font-lock: %S" - (let ((table (make-syntax-table (syntax-table)))) - (when comment-start - (modify-syntax-entry (string-to-char comment-start) "." table)) - (modify-syntax-entry ?# "." table) - (modify-syntax-entry ?\" "." table) - (modify-syntax-entry ?\' "." table) - (modify-syntax-entry ?` "." table) - (set-syntax-table table)) - (setq-local comment-start (or (magit-get "core.commentchar") "#")) - (setq-local comment-start-skip (format "^%s+[\s\t]*" comment-start)) - (setq-local comment-end "") - (setq-local comment-end-skip "\n") - (setq-local comment-use-syntax nil) - (when (and (derived-mode-p 'markdown-mode) - (fboundp 'markdown-fill-paragraph)) - (setq-local fill-paragraph-function - (lambda (&optional justify) - (and (not (= (char-after (line-beginning-position)) - (aref comment-start 0))) - (markdown-fill-paragraph justify))))) - (setq-local git-commit--branch-name-regexp - ;; When using cygwin git, we may end up in a - ;; non-existing directory, which would cause - ;; any git calls to signal an error. - (if (file-accessible-directory-p default-directory) - ;; Font-Lock wants every submatch to succeed, so - ;; also match the empty string. Avoid listing - ;; remote branches and using `regexp-quote', - ;; because in repositories that have thousands of - ;; branches that would be very slow. See #4353. - (format "\\(\\(?:%s\\)\\|\\)\\([^']+\\)" - (string-join (magit-list-local-branch-names) "\\|")) - "\\([^']*\\)")) - (setq-local font-lock-multiline t) - (add-hook 'font-lock-extend-region-functions - #'git-commit-extend-region-summary-line - t t) - (font-lock-add-keywords nil git-commit-font-lock-keywords))) - -(defun git-commit-propertize-diff () - (require 'diff-mode) - (save-excursion - (goto-char (point-min)) - (when (re-search-forward "^diff --git" nil t) - (beginning-of-line) - (let ((buffer (current-buffer))) - (insert - (with-temp-buffer - (insert - (with-current-buffer buffer - (prog1 (buffer-substring-no-properties (point) (point-max)) - (delete-region (point) (point-max))))) - (let ((diff-default-read-only nil)) - (diff-mode)) - (let ((font-lock-verbose nil) - (font-lock-support-mode nil)) - (font-lock-ensure)) - (let ((pos (point-min))) - (while-let ((next (next-single-property-change pos 'face))) - (put-text-property pos next 'font-lock-face - (get-text-property pos 'face)) - (setq pos next)) - (put-text-property pos (point-max) 'font-lock-face - (get-text-property pos 'face))) - (buffer-string))))))) - -;;; Elisp Text Mode - -(define-derived-mode git-commit-elisp-text-mode text-mode "ElText" - "Major mode for editing commit messages of elisp projects. -This is intended for use as `git-commit-major-mode' for projects -that expect `symbols' to look like this. I.e., like they look in -Elisp doc-strings, including this one. Unlike in doc-strings, -\"strings\" also look different than the other text." - (setq font-lock-defaults '(git-commit-elisp-text-mode-keywords))) - -(defvar git-commit-elisp-text-mode-keywords - `((,(concat "[`‘]\\(" lisp-mode-symbol-regexp "\\)['’]") - (1 font-lock-constant-face prepend)) - ("\"[^\"]*\"" (0 font-lock-string-face prepend)))) - -;;; _ - -(define-obsolete-function-alias - 'git-commit-insert-pseudo-header - 'git-commit-insert-trailer - "git-commit 4.0.0") -(define-obsolete-function-alias - 'git-commit-insert-header - 'git-commit--insert-ident-trailer - "git-commit 4.0.0") -(define-obsolete-face-alias - 'git-commit-pseudo-header - 'git-commit-trailer-value - "git-commit 4.0.0") -(define-obsolete-face-alias - 'git-commit-known-pseudo-header - 'git-commit-trailer-token - "git-commit 4.0.0") - -(provide 'git-commit) -;;; git-commit.el ends here diff --git a/elpa/magit-20250519.1537/git-rebase.el b/elpa/magit-20250519.1537/git-rebase.el deleted file mode 100644 index 65441f89..00000000 --- a/elpa/magit-20250519.1537/git-rebase.el +++ /dev/null @@ -1,875 +0,0 @@ -;;; git-rebase.el --- Edit Git rebase files -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; Author: Phil Jackson -;; 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 of the License, 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 . - -;;; 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-keymap git-rebase-mode-map - :doc "Keymap for Git-Rebase mode." - :parent special-mode-map - "C-m" #'git-rebase-show-commit - "p" #'git-rebase-backward-line - "n" #'forward-line - "M-p" #'git-rebase-move-line-up - "M-n" #'git-rebase-move-line-down - "c" #'git-rebase-pick - "k" #'git-rebase-kill-line - "C-k" #'git-rebase-kill-line - "b" #'git-rebase-break - "e" #'git-rebase-edit - "l" #'git-rebase-label - "M M" #'git-rebase-merge - "M t" #'git-rebase-merge-toggle-editmsg - "m" #'git-rebase-edit - "f" #'git-rebase-fixup - "q" #'undefined - "r" #'git-rebase-reword - "w" #'git-rebase-reword - "s" #'git-rebase-squash - "t" #'git-rebase-reset - "u" #'git-rebase-update-ref - "x" #'git-rebase-exec - "y" #'git-rebase-insert - "z" #'git-rebase-noop - "SPC" #'git-rebase-show-or-scroll-up - "DEL" #'git-rebase-show-or-scroll-down - "C-x C-t" #'git-rebase-move-line-up - "M-" #'git-rebase-move-line-up - "M-" #'git-rebase-move-line-down - " " #'git-rebase-undo) -(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") - (?u . "update-ref") - (?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) - (abbrev))) - -(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" - "u" "update-ref") - "\\(?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 (and-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 or uncomments 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 (not action) action-type) - (let ((inhibit-read-only t)) - (if comment-p - (delete-region beg (+ beg 2)) - (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 (magit--bol-position (region-beginning))) - (end (magit--eol-position (region-end)))) - (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-highlight-range (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 () - "Comment the current action line. -If the action line is already commented, then uncomment it. -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 ((info (magit-rev-format "%h %s" rev))) - (let ((inhibit-read-only t)) - (insert "pick " info ?\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-update-ref (arg) - "Insert an update-ref action after the current line. -If there is already an update-ref action on the current line, -then edit that instead. With a prefix argument, insert a new -action even when there is already one on the current line. With -empty input, remove the action on the current line, if any." - (interactive "P") - (git-rebase-set-noncommit-action - "update-ref" - (lambda (initial) - (or (magit-completing-read "Ref" (magit-list-refs) nil nil 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]" (##if (equal % "-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 ((magit--disable-save-buffers t)) - (save-excursion - (goto-char (line-beginning-position)) - (if-let ((rev (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 rev - (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." - :interactive nil - :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 ((rev (magit-file-line - (expand-file-name "rebase-merge/autostash" (magit-gitdir))))) - (push (cons 'stash rev) with-editor-cancel-alist))) - -(defun git-rebase-autostash-apply () - (when-let ((rev (cdr (assq 'stash with-editor-cancel-alist)))) - (magit-stash-apply rev))) - -(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!\\|amend!\\)" - 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. -Modify that section to replace Git's one-letter command abbreviation, -with the key bindings used in Magit. By default, these are 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 (propertize "%s %s %s\n" - 'font-lock-face 'font-lock-comment-face) - comment-start - (string-pad - (substitute-command-keys (format "\\[%s]" cmd)) 8) - desc))) - (while (re-search-forward - (concat git-rebase-comment-re "\\(?:" - "\\( \\.? *\\)\\|" - "\\( +\\)\\([^\n,],\\) \\([^\n ]+\\) \\)") - nil t) - (if (match-string 1) - (replace-match (make-string 10 ?\s) t t nil 1) - (let ((cmd (intern (concat "git-rebase-" (match-string 4))))) - (if (not (fboundp cmd)) - (delete-region (line-beginning-position) - (1+ (line-end-position))) - (add-text-properties (line-beginning-position) - (1+ (line-end-position)) - '(font-lock-face font-lock-comment-face)) - (replace-match " " t t nil 2) - (replace-match - (string-pad - (save-match-data - (substitute-command-keys (format "\\[%s]" cmd))) - 8) - t t nil 3))))))))) - -(add-hook 'git-rebase-mode-hook #'git-rebase-mode-show-keybindings t) - -(defun git-rebase-mode-disable-before-save-hook () - (setq-local 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) - -;;; Imenu Support - -(defun magit-imenu--rebase-prev-index-position-function () - "Move point to previous commit in git-rebase buffer. -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))))) - -(defun magit-imenu--rebase-extract-index-name-function () - "Return imenu name for line at point. -Point should be at the beginning of the line. This function -is used as a value for `imenu-extract-index-name-function'." - (buffer-substring-no-properties (line-beginning-position) - (line-end-position))) - -;;; _ -(provide 'git-rebase) -;;; git-rebase.el ends here diff --git a/elpa/magit-20250519.1537/magit-apply.el b/elpa/magit-20250519.1537/magit-apply.el deleted file mode 100644 index 3f6f5bd0..00000000 --- a/elpa/magit-20250519.1537/magit-apply.el +++ /dev/null @@ -1,830 +0,0 @@ -;;; magit-apply.el --- Apply Git diffs -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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)) -(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) - -(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) - -;;; 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 ((s (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 s args)) - (`(,_ hunk) (magit-apply-hunk s args)) - (`(,_ hunks) (magit-apply-hunks s args)) - (`(rebase-sequence file) - (call-interactively #'magit-patch-apply)) - (`(,_ file) (magit-apply-diff s args)) - (`(,_ files) (magit-apply-diffs s 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 (##concat (magit-diff-file-header %) - (magit-apply--section-content %)) - 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 (hunks &rest args) - (let ((file (oref (car hunks) parent))) - (when (magit-diff--combined-p file) - (user-error "Cannot un-/stage resolution hunks. Stage the whole file")) - (magit-apply-patch - file args - (concat (oref file header) - (string-join (magit-apply--adjust-hunk-new-starts - (mapcar #'magit-apply--section-content hunks))))))) - -(defun magit-apply-hunk (hunk &rest args) - (let ((file (oref hunk parent))) - (when (magit-diff--combined-p file) - (user-error "Cannot un-/stage resolution hunks. Stage the whole file")) - (let* ((header (car (oref hunk value))) - (header (and (symbolp header) header)) - (content (magit-apply--section-content hunk))) - (magit-apply-patch - file args - (concat (magit-diff-file-header hunk (not (eq header 'rename))) - (if header - content - (magit-apply--adjust-hunk-new-start content))))))) - -(defun magit-apply-region (hunk &rest args) - (let ((file (oref hunk parent))) - (when (magit-diff--combined-p file) - (user-error "Cannot un-/stage resolution hunks. Stage the whole file")) - (magit-apply-patch - file args - (concat (magit-diff-file-header hunk) - (magit-apply--adjust-hunk-new-start - (magit-diff-hunk-region-patch hunk args)))))) - -(defun magit-apply-patch (section:s args patch) - (let* ((files (if (atom section:s) - (list (oref section:s value)) - (mapcar (##oref % 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) - (let ((magit-inhibit-refresh t)) - (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 - 'stashed-index 'stashed-worktree 'stashed-untracked) - (oref section children)) - ('untracked t) - (_ (user-error "Cannot apply this, it's not a change")))))) - -(defun magit-apply--get-diffs (sections) - (magit-section-case - ([file diffstat] - (mapcar (lambda (section) - (or (magit-get-section - (append `((file . ,(oref section value))) - (magit-section-ident magit-root-section))) - (error "Cannot get required diff headers"))) - sections)) - (t sections))) - -(defun magit-apply--ignore-whitespace-p (selection type scope) - "Return t if it is necessary and possible to ignore whitespace. -It is necessary to do so when the diff ignores whitespace changes -and whole files are being applied. It is possible when no binary -files are involved. If it is both necessary and impossible, then -return nil, possibly causing whitespace changes to be applied." - (and (memq type '(unstaged staged)) - (memq scope '(file files list)) - (cl-find-if (lambda (arg) - (member arg '("--ignore-space-at-eol" - "--ignore-space-change" - "--ignore-all-space" - "--ignore-blank-lines"))) - magit-buffer-diff-args) - (not (cl-find-if (##oref % binary) - (ensure-list selection))))) - -;;;; 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 ((s (and (derived-mode-p 'magit-mode) - (magit-apply--get-selection))) - (type (magit-diff-type)) - (scope (magit-diff-scope))) - (pcase (list type scope - (magit-apply--ignore-whitespace-p s type scope)) - (`(untracked ,_ ,_) (magit-stage-untracked intent)) - (`(unstaged region ,_) (magit-apply-region s "--cached")) - (`(unstaged hunk ,_) (magit-apply-hunk s "--cached")) - (`(unstaged hunks ,_) (magit-apply-hunks s "--cached")) - ('(unstaged file t) (magit-apply-diff s "--cached")) - ('(unstaged files t) (magit-apply-diffs s "--cached")) - ('(unstaged list t) (magit-apply-diffs s "--cached")) - ('(unstaged file nil) (magit-stage-1 "-u" (list (oref s 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-files))) - -;;;###autoload -(defun magit-stage-files (files &optional force) - "Read one or more files and stage all changes in those files. -With prefix argument FORCE, offer ignored files for completion." - (interactive - (let* ((choices (if current-prefix-arg - (magit-ignored-files) - (nconc (magit-unstaged-files) - (magit-untracked-files)))) - (default (or (magit-section-value-if 'file) - (magit-file-relative-name))) - (default (car (member default choices)))) - (list (magit-completing-read-multiple - (if current-prefix-arg "Stage ignored file,s: " "Stage file,s: ") - choices nil t nil nil default) - current-prefix-arg))) - (magit-with-toplevel - (magit-stage-1 (and force "--force") files))) - -;;;###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))) - (when (and (fboundp 'borg-assimilate) - (fboundp 'borg--maybe-absorb-gitdir) - (fboundp 'borg--sort-submodule-sections)) - (dolist (repo repos) - (save-excursion - (when-let ((section (magit-get-section - `((file . ,repo) (untracked) (status))))) - (goto-char (oref section 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 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"))) - -(defvar magit-post-stage-hook-commands - (list #'magit-stage - #'magit-stage-files - #'magit-stage-modified - 'magit-file-stage)) - -(defun magit-run-post-stage-hook () - (when (memq this-command magit-post-stage-hook-commands) - (magit-run-hook-with-benchmark 'magit-post-stage-hook))) - -;;;; Unstage - -(defun magit-unstage () - "Remove the change at point from the staging area." - (interactive) - (when-let ((s (magit-apply--get-selection)) - (type (magit-diff-type)) - (scope (magit-diff-scope))) - (pcase (list type scope - (magit-apply--ignore-whitespace-p s type scope)) - (`(untracked ,_ ,_) (user-error "Cannot unstage untracked changes")) - (`(unstaged file ,_) (magit-unstage-intent (list (oref s value)))) - (`(unstaged files ,_) (magit-unstage-intent (magit-region-values nil t))) - (`(unstaged ,_ ,_) (user-error "Already unstaged")) - (`(staged region ,_) (magit-apply-region s "--reverse" "--cached")) - (`(staged hunk ,_) (magit-apply-hunk s "--reverse" "--cached")) - (`(staged hunks ,_) (magit-apply-hunks s "--reverse" "--cached")) - ('(staged file t) (magit-apply-diff s "--reverse" "--cached")) - ('(staged files t) (magit-apply-diffs s "--reverse" "--cached")) - ('(staged list t) (magit-apply-diffs s "--reverse" "--cached")) - ('(staged file nil) (magit-unstage-1 (list (oref s 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-files (files) - "Read one or more files and unstage all changes to those files." - (interactive - (let* ((choices (magit-staged-files)) - (default (or (magit-section-value-if 'file) - (magit-file-relative-name))) - (default (car (member default choices)))) - (list (magit-completing-read-multiple "Unstage file,s: " choices - nil t nil nil default)))) - (magit-with-toplevel - (magit-unstage-1 files))) - -(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 (seq-filter (##member % 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")) - -(defvar magit-post-unstage-hook-commands - (list #'magit-unstage - #'magit-unstage-files - #'magit-unstage-all - 'magit-file-unstage)) - -(defun magit-run-post-unstage-hook () - (when (memq this-command magit-post-unstage-hook-commands) - (magit-run-hook-with-benchmark 'magit-post-unstage-hook))) - -;;;; 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 ((s (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")) - (`(untracked list) (magit-discard-files--delete - (magit-with-toplevel - (magit-untracked-files nil nil "--directory")) - nil)) - (`(,_ region) (magit-discard-region s)) - (`(,_ hunk) (magit-discard-hunk s)) - (`(,_ hunks) (magit-discard-hunks s)) - (`(,_ file) (magit-discard-file s)) - (`(,_ files) (magit-discard-files s)) - (`(,_ list) (magit-discard-files s))))) - -(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 - (list "Discard %d 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)) - ('(?Z ?D ? ) (push file delete)) - (`(,_ ?D ?D) (push file resolve)) - ((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 %d files\n%s\ncheckout:\n" - (length files) - (mapconcat (##concat " " %) 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 %d 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 ((path (file-name-directory orig))) - (make-directory path 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 (mapcar (##oref % 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 - (seq-remove (##member (oref % 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 (magit--separate (##member % 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 ((s (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 s args)) - (`(,_ hunk) (magit-reverse-hunk s args)) - (`(,_ hunks) (magit-reverse-hunks s args)) - (`(,_ file) (magit-reverse-file s args)) - (`(,_ files) (magit-reverse-files s args)) - (`(,_ list) (magit-reverse-files s 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 - (list "Reverse %d 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"))))) - (magit--separate (##member (oref % value) bs) - sections)))) - (magit-confirm-files 'reverse (mapcar (##oref % 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' 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-smerge-keep-all () - "Keep all versions of the conflict at point." - (interactive) - (magit-call-smerge #'smerge-keep-all)) - -(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-20250519.1537/magit-autoloads.el b/elpa/magit-20250519.1537/magit-autoloads.el deleted file mode 100644 index b070d97e..00000000 --- a/elpa/magit-20250519.1537/magit-autoloads.el +++ /dev/null @@ -1,2354 +0,0 @@ -;;; magit-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- -;; Generated by the `loaddefs-generate' function. - -;; This file is part of GNU Emacs. - -;;; Code: - -(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) - - - -;;; Generated autoloads from git-commit.el - -(put 'git-commit-major-mode 'safe-local-variable - (lambda (val) - (memq val '(text-mode - markdown-mode - org-mode - fundamental-mode - log-edit-mode - git-commit-elisp-text-mode)))) -(register-definition-prefixes "git-commit" '("git-commit-" "global-git-commit-mode")) - - -;;; 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.") -(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) -(defconst git-rebase-filename-regexp "/git-rebase-todo\\'") -(add-to-list 'auto-mode-alist (cons git-rebase-filename-regexp #'git-rebase-mode)) -(register-definition-prefixes "git-rebase" '("git-rebase-" "magit-imenu--rebase-")) - - -;;; Generated autoloads from magit.el - -(defvar magit-define-global-key-bindings 'default "\ -Which set of key bindings to add to the global keymap, if any. - -This option controls which set of Magit key bindings, if any, may -be added to the global keymap, even before Magit is first used in -the current Emacs session. - -If the value is nil, no bindings are added. - -If \\+`default', maybe add: - - \\`C-x' \\`g' `magit-status' - \\`C-x' \\`M-g' `magit-dispatch' - \\`C-c' \\`M-g' `magit-file-dispatch' - -If `recommended', maybe add: - - \\`C-x' \\`g' `magit-status' - \\`C-c' \\`g' `magit-dispatch' - \\`C-c' \\`f' `magit-file-dispatch' - - These bindings are strongly recommended, but we cannot use - them by default, because the \\`C-c ' namespace is - strictly reserved for bindings added by the user. - -The bindings in the chosen set 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 these bindings is delayed until `after-init-hook' is -run 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 has no effect if `after-init-hook' has -already been run.") -(custom-autoload 'magit-define-global-key-bindings "magit" t) -(defun magit-maybe-define-global-key-bindings (&optional force) "\ -See variable `magit-define-global-key-bindings'." (when magit-define-global-key-bindings (let ((map (current-global-map))) (pcase-dolist (`(,key \, def) (cond ((eq magit-define-global-key-bindings 'recommended) '(("C-x g" . magit-status) ("C-c g" . magit-dispatch) ("C-c f" . magit-file-dispatch))) ('(("C-x g" . magit-status) ("C-x M-g" . magit-dispatch) ("C-c M-g" . magit-file-dispatch))))) (when (or force (not (or (lookup-key map (kbd key)) (where-is-internal def (make-sparse-keymap) t)))) (define-key map (kbd 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) -(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) -(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) -(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) -(autoload 'magit-version "magit" "\ -Return the version of Magit currently in use. - -If optional argument PRINT-DEST is non-nil, also print the used -versions of Magit, Transient, Git and Emacs to the output stream -selected by that argument. Interactively use the echo area, or -with a prefix argument use the current buffer. Additionally put -the output in the kill ring. - -(fn &optional PRINT-DEST)" t) -(register-definition-prefixes "magit" '("magit-")) - - -;;; Generated autoloads from magit-apply.el - -(autoload 'magit-stage-files "magit-apply" "\ -Read one or more files and stage all changes in those files. -With prefix argument FORCE, offer ignored files for completion. - -(fn FILES &optional FORCE)" t) -(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) -(autoload 'magit-unstage-files "magit-apply" "\ -Read one or more files and unstage all changes to those files. - -(fn FILES)" t) -(autoload 'magit-unstage-all "magit-apply" "\ -Remove all changes from the staging area." t) -(register-definition-prefixes "magit-apply" '("magit-")) - - -;;; 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, toggle the mode if ARG is `toggle'. -Enable the mode if ARG is nil, omitted, or is a positive number. -Disable the mode if ARG is a negative number. - -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) -(register-definition-prefixes "magit-autorevert" '("auto-revert-buffer" "magit-")) - - -;;; Generated autoloads from magit-base.el - -(autoload 'magit-emacs-Q-command "magit-base" "\ -Show a shell command that runs an uncustomized Emacs with only Magit loaded. -See info node `(magit)Debugging Tools' for more information." t) -(define-advice Info-follow-nearest-node (:around (fn &optional fork) gitman) (let ((node (Info-get-token (point) "\\*note[ - ]+" "\\*note[ - ]+\\([^:]*\\):\\(:\\|[ - ]*(\\)?"))) (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)))) -(define-advice org-man-export (:around (fn link description format) gitman) (if (and (eq format 'texinfo) (string-prefix-p "git" link)) (string-replace "%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))) -(register-definition-prefixes "magit-base" '("magit-")) - - -;;; 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) -(autoload 'magit-bisect-reset "magit-bisect" "\ -After bisecting, cleanup bisection state and return to original `HEAD'." t) -(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) -(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) -(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) -(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) -(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) -(register-definition-prefixes "magit-bisect" '("magit-")) - - -;;; 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) -(register-definition-prefixes "magit-blame" '("magit-")) - - -;;; 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) -(function-put 'magit-checkout 'interactive-only 'magit--checkout) -(autoload 'magit-branch-create "magit-branch" "\ -Create BRANCH at branch or revision START-POINT. - -(fn BRANCH START-POINT)" t) -(function-put 'magit-branch-create 'interactive-only 'magit-call-git) -(autoload 'magit-branch-and-checkout "magit-branch" "\ -Create and checkout BRANCH at branch or revision START-POINT. - -(fn BRANCH START-POINT &optional ARGS)" t) -(function-put 'magit-branch-and-checkout 'interactive-only 'magit-call-git) -(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) -(function-put 'magit-branch-or-checkout 'interactive-only 'magit-call-git) -(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) -(function-put 'magit-branch-checkout 'interactive-only 'magit-call-git) -(autoload 'magit-branch-orphan "magit-branch" "\ -Create and checkout an orphan BRANCH with contents from revision START-POINT. - -(fn BRANCH START-POINT)" t) -(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) -(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) -(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) -(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. - -Require confirmation when deleting branches is dangerous in some -way. Option `magit-no-confirm' can be customized to not require -confirmation in certain cases. See its docstring to learn why -confirmation is required by default in certain cases or if a -prompt is confusing. - -(fn BRANCHES &optional FORCE)" t) -(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) -(autoload 'magit-branch-shelve "magit-branch" "\ -Shelve a BRANCH. -Rename \"refs/heads/BRANCH\" to \"refs/shelved/YYYY-MM-DD-BRANCH\", -and also rename the respective reflog file. - -(fn BRANCH)" t) -(autoload 'magit-branch-unshelve "magit-branch" "\ -Unshelve a BRANCH. -Rename \"refs/shelved/BRANCH\" to \"refs/heads/BRANCH\". If BRANCH -is prefixed with \"YYYY-MM-DD\", then drop that part of the name. -Also rename the respective reflog file. - -(fn BRANCH)" t) - (autoload 'magit-branch-configure "magit-branch" nil t) -(register-definition-prefixes "magit-branch" '("magit-")) - - -;;; 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) -(autoload 'magit-bundle-update-tracked "magit-bundle" "\ -Update a bundle that is being tracked using TAG. - -(fn TAG)" t) -(autoload 'magit-bundle-verify "magit-bundle" "\ -Check whether FILE is valid and applies to the current repository. - -(fn FILE)" t) -(autoload 'magit-bundle-list-heads "magit-bundle" "\ -List the refs in FILE. - -(fn FILE)" t) -(register-definition-prefixes "magit-bundle" '("magit-")) - - -;;; 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) -(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) -(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) -(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) -(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) -(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) -(autoload 'magit-clone-sparse "magit-clone" "\ -Clone REPOSITORY into DIRECTORY and create a sparse checkout. - -(fn REPOSITORY DIRECTORY ARGS)" t) -(register-definition-prefixes "magit-clone" '("magit-")) - - -;;; Generated autoloads from magit-commit.el - - (autoload 'magit-commit "magit-commit" nil t) -(autoload 'magit-commit-create "magit-commit" "\ -Create a new commit. - -(fn &optional ARGS)" t) -(autoload 'magit-commit-extend "magit-commit" "\ -Amend staged changes to the last commit, without editing its message. - -With a prefix argument do not update the committer date; without an -argument update it. The option `magit-commit-extend-override-date' -can be used to inverse the meaning of the prefix argument. Called -non-interactively, the optional OVERRIDE-DATE argument controls this -behavior, and the option is of no relevance. - -(fn &optional ARGS OVERRIDE-DATE)" t) -(autoload 'magit-commit-amend "magit-commit" "\ -Amend staged changes (if any) to the last commit, and edit its message. - -(fn &optional ARGS)" t) -(autoload 'magit-commit-reword "magit-commit" "\ -Reword the message of the last commit, without amending its tree. - -With a prefix argument do not update the committer date; without an -argument update it. The option `magit-commit-reword-override-date' -can be used to inverse the meaning of the prefix argument. Called -non-interactively, the optional OVERRIDE-DATE argument controls this -behavior, and the option is of no relevance. - -(fn &optional ARGS OVERRIDE-DATE)" t) -(autoload 'magit-commit-fixup "magit-commit" "\ -Create a fixup commit, leaving the original commit message untouched. - -If there is a reachable commit at point, target that. Otherwise prompt -for a commit. If `magit-commit-squash-confirm' is non-nil, always make -the user explicitly select a commit, in a buffer dedicated to that task. - -During a later rebase, when this commit gets squashed into its targeted -commit, the original message of the targeted commit is used as-is. - -In other words, call \"git commit --fixup=COMMIT --no-edit\". - -(fn &optional COMMIT ARGS)" t) -(autoload 'magit-commit-squash "magit-commit" "\ -Create a squash commit, without the user authoring a commit message. - -If there is a reachable commit at point, target that. Otherwise prompt -for a commit. If `magit-commit-squash-confirm' is non-nil, always make -the user explicitly select a commit, in a buffer dedicated to that task. - -During a later rebase, when this commit gets squashed into its targeted -commit, the user is given a chance to edit the original message to take -the changes from the squash commit into account. - -In other words, call \"git commit --squash=COMMIT --no-edit\". - -(fn &optional COMMIT ARGS)" t) -(autoload 'magit-commit-alter "magit-commit" "\ -Create a squash commit, authoring the final commit message now. - -If there is a reachable commit at point, target that. Otherwise prompt -for a commit. If `magit-commit-squash-confirm' is non-nil, always make -the user explicitly select a commit, in a buffer dedicated to that task. - -During a later rebase, when this commit gets squashed into its targeted -commit, the original message of the targeted commit is replaced with the -message of this commit, without the user automatically being given a -chance to edit again. - -In other words, call \"git commit --fixup=amend:COMMIT --edit\". - -(fn &optional COMMIT ARGS)" t) -(autoload 'magit-commit-augment "magit-commit" "\ -Create a squash commit, authoring a new temporary commit message. - -If there is a reachable commit at point, target that. Otherwise prompt -for a commit. If `magit-commit-squash-confirm' is non-nil, always make -the user explicitly select a commit, in a buffer dedicated to that task. - -During a later rebase, when this commit gets squashed into its targeted -commit, the user is asked to write a final commit message, in a buffer -that starts out containing both the original commit message, as well as -the temporary commit message of the squash commit. - -In other words, call \"git commit --squash=COMMIT --edit\". - -(fn &optional COMMIT ARGS)" t) -(autoload 'magit-commit-revise "magit-commit" "\ -Reword the message of an existing commit, without editing its tree. - -If there is a reachable commit at point, target that. Otherwise prompt -for a commit. If `magit-commit-squash-confirm' is non-nil, always make -the user explicitly select a commit, in a buffer dedicated to that task. - -During a later rebase, when this commit gets squashed into its targeted -commit, a combined commit is created which uses the message of the fixup -commit and the tree of the targeted commit. - -In other words, call \"git commit --fixup=reword:COMMIT --edit\". - -(fn &optional COMMIT ARGS)" t) -(autoload 'magit-commit-instant-fixup "magit-commit" "\ -Create a fixup commit, and immediately combine it with its target. - -If there is a reachable commit at point, target that. Otherwise prompt -for a commit. If `magit-commit-squash-confirm' is non-nil, always make -the user explicitly select a commit, in a buffer dedicated to that task. - -Leave the original commit message of the targeted commit untouched. - -Like `magit-commit-fixup' but also run a `--autofixup' rebase. - -(fn &optional COMMIT ARGS)" t) -(autoload 'magit-commit-instant-squash "magit-commit" "\ -Create a squash commit, and immediately combine it with its target. - -If there is a reachable commit at point, target that. Otherwise prompt -for a commit. If `magit-commit-squash-confirm' is non-nil, always make -the user explicitly select a commit, in a buffer dedicated to that task. - -Turing the rebase phase, when the two commits are being squashed, ask -the user to author the final commit message, based on the original -message of the targeted commit. - -Like `magit-commit-squash' but also run a `--autofixup' rebase. - -(fn &optional COMMIT ARGS)" t) -(autoload 'magit-commit-reshelve "magit-commit" "\ -Change committer (and possibly author) date of the last commit. - -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 changed, 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) -(autoload 'magit-commit-absorb-modules "magit-commit" "\ -Spread modified modules across recent commits. - -(fn PHASE COMMIT)" t) - (autoload 'magit-commit-absorb "magit-commit" nil t) - (autoload 'magit-commit-autofixup "magit-commit" nil t) -(register-definition-prefixes "magit-commit" '("magit-")) - - -;;; 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. - -For example, if point is on a commit, show the changes introduced by -that commit. Likewise if point is on the section titled \"Unstaged -changes\", then show those changes in a separate buffer. Generally -speaking, compare the thing at point with the most logical, trivial -and (in *any* situation) at least potentially useful other thing it -could be compared to. - -When the region selects commits, then compare the two commits at -either end. There are different ways two commits can be compared. -In the buffer showing the diff, you can control how the comparison, -is done, using \"D r\" and \"D f\". - -This function does not always show the changes that you might want -to view in any given situation. You can think of the changes being -shown as the smallest common denominator. There is no AI involved. -If this command never does what you want, then ignore it, and instead -use the commands that allow you to explicitly specify what you need. - -(fn &optional ARGS FILES)" t) -(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) -(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) -(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) -(autoload 'magit-diff-unstaged "magit-diff" "\ -Show changes between the working tree and the index. - -(fn &optional ARGS FILES)" t) -(autoload 'magit-diff-unmerged "magit-diff" "\ -Show changes that are being merged. - -(fn &optional ARGS FILES)" t) -(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." t) -(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 differences between -`HEAD' and the working tree. In both cases limit the diff to -the file or blob." t) -(autoload 'magit-diff-paths "magit-diff" "\ -Show changes between any two files on disk. - -(fn A B)" t) -(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) -(register-definition-prefixes "magit-diff" '("magit-")) - - -;;; Generated autoloads from magit-dired.el - -(autoload 'magit-dired-jump "magit-dired" "\ -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) -(autoload 'magit-dired-stage "magit-dired" "\ -In Dired, staged all marked files or the file at point." t) -(autoload 'magit-dired-unstage "magit-dired" "\ -In Dired, unstaged all marked files or the file at point." t) -(autoload 'magit-dired-log "magit-dired" "\ -In Dired, show log for all marked files or the directory if none are marked. - -(fn &optional FOLLOW)" t) -(autoload 'magit-dired-am-apply-patches "magit-dired" "\ -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) -(autoload 'magit-do-async-shell-command "magit-dired" "\ -Open FILE with `dired-do-async-shell-command'. -Interactively, open the file at point. - -(fn FILE)" t) - - -;;; Generated autoloads from magit-ediff.el - - (autoload 'magit-ediff "magit-ediff" nil) -(autoload 'magit-ediff-resolve-all "magit-ediff" "\ -Resolve all conflicts in the FILE at point using Ediff. - -If there is no file at point or if it doesn't have any unmerged -changes, then prompt for a file. - -See info node `(magit) Ediffing' for more information about this -and alternative commands. - -(fn FILE)" t) -(autoload 'magit-ediff-resolve-rest "magit-ediff" "\ -Resolve outstanding conflicts in the FILE at point using Ediff. - -If there is no file at point or if it doesn't have any unmerged -changes, then prompt for a file. - -See info node `(magit) Ediffing' for more information about this -and alternative commands. - -(fn FILE)" t) -(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) -(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) -(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) -(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) -(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) -(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) -(autoload 'magit-ediff-show-commit "magit-ediff" "\ -Show changes introduced by COMMIT using Ediff. - -(fn COMMIT)" t) -(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) -(register-definition-prefixes "magit-ediff" '("magit-ediff-")) - - -;;; Generated autoloads from magit-extras.el - - (autoload 'magit-git-mergetool "magit-extras" nil t) -(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) -(autoload 'magit-run-git-gui "magit-extras" "\ -Run `git gui' for the current git repository." t) -(autoload 'magit-run-gitk "magit-extras" "\ -Run `gitk' in the current repository." t) -(autoload 'magit-run-gitk-branches "magit-extras" "\ -Run `gitk --branches' in the current repository." t) -(autoload 'magit-run-gitk-all "magit-extras" "\ -Run `gitk --all' in the current repository." t) -(autoload 'magit-project-status "magit-extras" "\ -Run `magit-status' in the current project's root." t) -(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) -(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) -(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) -(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) -(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) -(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) -(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) -(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-commit' instead of this command. - -(fn FILE)" t) -(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) -(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) -(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) -(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) -(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) -(autoload 'magit-switch-to-repository-buffer "magit-extras" "\ -Switch to a Magit buffer belonging to the current Git repository. - -(fn BUFFER)" t) -(autoload 'magit-switch-to-repository-buffer-other-window "magit-extras" "\ -Switch to a Magit buffer belonging to the current Git repository. - -(fn BUFFER)" t) -(autoload 'magit-switch-to-repository-buffer-other-frame "magit-extras" "\ -Switch to a Magit buffer belonging to the current Git repository. - -(fn BUFFER)" t) -(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) -(autoload 'magit-back-to-indentation "magit-extras" "\ -Move point to the first non-whitespace character on this line. -In Magit diffs, also skip over - and + at the beginning of the line." t) -(register-definition-prefixes "magit-extras" '("magit-")) - - -;;; 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) -(autoload 'magit-fetch-branch "magit-fetch" "\ -Fetch a BRANCH from a REMOTE. - -(fn REMOTE BRANCH ARGS)" t) -(autoload 'magit-fetch-refspec "magit-fetch" "\ -Fetch a REFSPEC from a REMOTE. - -(fn REMOTE REFSPEC ARGS)" t) -(autoload 'magit-fetch-all "magit-fetch" "\ -Fetch from all remotes. - -(fn ARGS)" t) -(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) -(autoload 'magit-fetch-all-no-prune "magit-fetch" "\ -Fetch from all remotes." t) - (autoload 'magit-fetch-modules "magit-fetch" nil t) -(register-definition-prefixes "magit-fetch" '("magit-")) - - -;;; 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) -(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) -(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) - (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) -(autoload 'magit-file-stage "magit-files" "\ -Stage all changes to the file being visited in the current buffer." t) -(autoload 'magit-file-unstage "magit-files" "\ -Unstage all changes to the file being visited in the current buffer." t) -(autoload 'magit-file-untrack "magit-files" "\ -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. - -(fn FILES &optional FORCE)" t) -(autoload 'magit-file-rename "magit-files" "\ -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'. - -(fn FILE NEWNAME)" t) -(autoload 'magit-file-delete "magit-files" "\ -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'. - -(fn FILES &optional FORCE)" t) -(autoload 'magit-file-checkout "magit-files" "\ -Checkout FILE from REV. - -(fn REV FILE)" t) -(register-definition-prefixes "magit-files" '("lsp" "magit-")) - - -;;; Generated autoloads from magit-git.el - -(register-definition-prefixes "magit-git" '("magit-")) - - -;;; 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) -(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) -(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) -(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) -(autoload 'magit-skip-worktree "magit-gitignore" "\ -Call \"git update-index --skip-worktree -- FILE\". - -(fn FILE)" t) -(autoload 'magit-no-skip-worktree "magit-gitignore" "\ -Call \"git update-index --no-skip-worktree -- FILE\". - -(fn FILE)" t) -(autoload 'magit-assume-unchanged "magit-gitignore" "\ -Call \"git update-index --assume-unchanged -- FILE\". - -(fn FILE)" t) -(autoload 'magit-no-assume-unchanged "magit-gitignore" "\ -Call \"git update-index --no-assume-unchanged -- FILE\". - -(fn FILE)" t) -(register-definition-prefixes "magit-gitignore" '("magit-")) - - -;;; 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" nil t) -(autoload 'magit-log-head "magit-log" "\ -Show log for `HEAD'. - -(fn &optional ARGS FILES)" t) -(autoload 'magit-log-related "magit-log" "\ -Show log for the current branch, its upstream and its push target. -When the upstream is a local branch, then also show its own -upstream. When `HEAD' is detached, then show log for that, the -previously checked out branch and its upstream and push-target. - -(fn REVS &optional ARGS FILES)" t) -(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) -(autoload 'magit-log-branches "magit-log" "\ -Show log for all local branches and `HEAD'. - -(fn &optional ARGS FILES)" t) -(autoload 'magit-log-matching-branches "magit-log" "\ -Show log for all branches matching PATTERN and `HEAD'. - -(fn PATTERN &optional ARGS FILES)" t) -(autoload 'magit-log-matching-tags "magit-log" "\ -Show log for all tags matching PATTERN and `HEAD'. - -(fn PATTERN &optional ARGS FILES)" t) -(autoload 'magit-log-all-branches "magit-log" "\ -Show log for all local and remote branches and `HEAD'. - -(fn &optional ARGS FILES)" t) -(autoload 'magit-log-all "magit-log" "\ -Show log for all references and `HEAD'. - -(fn &optional ARGS FILES)" t) -(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) -(autoload 'magit-log-trace-definition "magit-log" "\ -Show log for the definition at point. - -(fn FILE FN REV)" t) -(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 -`magit-log-merged-commit-count' 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) -(autoload 'magit-log-move-to-parent "magit-log" "\ -Move to the Nth parent of the current commit. - -(fn &optional N)" t) - (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) -(autoload 'magit-shortlog-range "magit-log" "\ -Show a history summary for commit or range REV-OR-RANGE. - -(fn REV-OR-RANGE ARGS)" t) -(autoload 'magit-cherry "magit-log" "\ -Show commits in a branch that are not merged in the upstream branch. - -(fn HEAD UPSTREAM)" t) -(register-definition-prefixes "magit-log" '("magit-")) - - -;;; Generated autoloads from magit-margin.el - -(register-definition-prefixes "magit-margin" '("magit-")) - - -;;; 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) -(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) -(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) -(autoload 'magit-merge-dissolve "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) -(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) -(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) -(autoload 'magit-merge-preview "magit-merge" "\ -Preview result of merging REV into the current branch. - -(fn REV)" t) -(autoload 'magit-merge-abort "magit-merge" "\ -Abort the current merge operation. - -(git merge --abort)" t) -(register-definition-prefixes "magit-merge" '("magit-")) - - -;;; Generated autoloads from magit-mode.el - -(autoload 'magit-info "magit-mode" "\ -Visit the Magit manual." t) -(register-definition-prefixes "magit-mode" '("magit-")) - - -;;; Generated autoloads from magit-notes.el - - (autoload 'magit-notes "magit" nil t) -(register-definition-prefixes "magit-notes" '("magit-notes-")) - - -;;; 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) -(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) -(register-definition-prefixes "magit-patch" '("magit-")) - - -;;; Generated autoloads from magit-process.el - -(register-definition-prefixes "magit-process" '("magit-")) - - -;;; 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) -(register-definition-prefixes "magit-pull" '("magit-pull-")) - - -;;; 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) -(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) -(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) -(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) -(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) -(autoload 'magit-push-tag "magit-push" "\ -Push a tag to another repository. - -(fn TAG REMOTE &optional ARGS)" t) -(autoload 'magit-push-notes-ref "magit-push" "\ -Push a notes ref to another repository. - -(fn REF REMOTE &optional ARGS)" t) - (autoload 'magit-push-implicitly "magit-push" nil t) - (autoload 'magit-push-to-remote "magit-push" nil t) -(register-definition-prefixes "magit-push" '("magit-")) - - -;;; 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) -(autoload 'magit-reflog-other "magit-reflog" "\ -Display the reflog of a branch or another ref. - -(fn REF)" t) -(autoload 'magit-reflog-head "magit-reflog" "\ -Display the `HEAD' reflog." t) -(register-definition-prefixes "magit-reflog" '("magit-reflog-")) - - -;;; 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) -(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) -(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) -(register-definition-prefixes "magit-refs" '("magit-")) - - -;;; 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) -(autoload 'magit-remote-rename "magit-remote" "\ -Rename the remote named OLD to NEW. - -(fn OLD NEW)" t) -(autoload 'magit-remote-remove "magit-remote" "\ -Delete the remote named REMOTE. - -(fn REMOTE)" t) -(autoload 'magit-remote-prune "magit-remote" "\ -Remove stale remote-tracking branches for REMOTE. - -(fn REMOTE)" t) -(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) -(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) -(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) - (autoload 'magit-update-default-branch "magit-remote" nil t) -(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) - (autoload 'magit-remote-configure "magit-remote" nil t) -(register-definition-prefixes "magit-remote" '("magit-")) - - -;;; Generated autoloads from magit-repos.el - -(autoload 'magit-list-repositories "magit-repos" "\ -Display a list of repositories. - -Use the option `magit-repository-directories' to control which -repositories are displayed." t) -(register-definition-prefixes "magit-repos" '("magit-")) - - -;;; 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) -(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) -(autoload 'magit-reset-hard "magit-reset" "\ -Reset the `HEAD', index, and working tree to COMMIT. - -(git reset --hard REVISION) - -(fn COMMIT)" t) -(autoload 'magit-reset-keep "magit-reset" "\ -Reset the `HEAD' and index to COMMIT, while keeping uncommitted changes. - -(git reset --keep REVISION) - -(fn COMMIT)" t) -(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) -(autoload 'magit-reset-worktree "magit-reset" "\ -Reset the worktree to COMMIT. -Keep the `HEAD' and index as-is. - -(fn COMMIT)" t) -(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) -(register-definition-prefixes "magit-reset" '("magit-reset-")) - - -;;; Generated autoloads from magit-sequence.el - -(autoload 'magit-sequencer-continue "magit-sequence" "\ -Resume the current cherry-pick or revert sequence." t) -(autoload 'magit-sequencer-skip "magit-sequence" "\ -Skip the stopped at commit during a cherry-pick or revert sequence." t) -(autoload 'magit-sequencer-abort "magit-sequence" "\ -Abort the current cherry-pick or revert sequence. -This discards all changes made since the sequence started." t) - (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) -(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) -(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) -(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) -(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) -(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) - (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) -(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) - (autoload 'magit-am "magit-sequence" nil t) -(autoload 'magit-am-apply-patches "magit-sequence" "\ -Apply the patches FILES. - -(fn &optional FILES ARGS)" t) -(autoload 'magit-am-apply-maildir "magit-sequence" "\ -Apply the patches from MAILDIR. - -(fn &optional MAILDIR ARGS)" t) -(autoload 'magit-am-continue "magit-sequence" "\ -Resume the current patch applying sequence." t) -(autoload 'magit-am-skip "magit-sequence" "\ -Skip the stopped at patch during a patch applying sequence." t) -(autoload 'magit-am-abort "magit-sequence" "\ -Abort the current patch applying sequence. -This discards all changes made since the sequence started." t) - (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) -(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) -(autoload 'magit-rebase-interactive "magit-sequence" "\ -Start an interactive rebase sequence. - -(fn COMMIT ARGS)" t) -(autoload 'magit-rebase-autosquash "magit-sequence" "\ -Combine squash and fixup commits with their intended targets. -By default only squash into commits that are not reachable from -the upstream branch. If no upstream is configured or with a prefix -argument, prompt for the first commit to potentially squash into. - -(fn SELECT ARGS)" t) -(autoload 'magit-rebase-edit-commit "magit-sequence" "\ -Edit a single older commit using rebase. - -(fn COMMIT ARGS)" t) -(autoload 'magit-rebase-reword-commit "magit-sequence" "\ -Reword a single older commit using rebase. - -(fn COMMIT ARGS)" t) -(autoload 'magit-rebase-remove-commit "magit-sequence" "\ -Remove a single older commit using rebase. - -(fn COMMIT ARGS)" t) -(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) -(autoload 'magit-rebase-skip "magit-sequence" "\ -Skip the current commit and restart the current rebase operation." t) -(autoload 'magit-rebase-edit "magit-sequence" "\ -Edit the todo list of the current rebase operation." t) -(autoload 'magit-rebase-abort "magit-sequence" "\ -Abort the current rebase operation, restoring the original branch." t) -(register-definition-prefixes "magit-sequence" '("magit-")) - - -;;; Generated autoloads from magit-sparse-checkout.el - - (autoload 'magit-sparse-checkout "magit-sparse-checkout" nil t) -(autoload 'magit-sparse-checkout-enable "magit-sparse-checkout" "\ -Convert the working tree to a sparse checkout. - -(fn &optional ARGS)" t) -(autoload 'magit-sparse-checkout-set "magit-sparse-checkout" "\ -Restrict working tree to DIRECTORIES. -To extend rather than override the currently configured -directories, call `magit-sparse-checkout-add' instead. - -(fn DIRECTORIES)" t) -(autoload 'magit-sparse-checkout-add "magit-sparse-checkout" "\ -Add DIRECTORIES to the working tree. -To override rather than extend the currently configured -directories, call `magit-sparse-checkout-set' instead. - -(fn DIRECTORIES)" t) -(autoload 'magit-sparse-checkout-reapply "magit-sparse-checkout" "\ -Reapply the sparse checkout rules to the working tree. -Some operations such as merging or rebasing may need to check out -files that aren't included in the sparse checkout. Call this -command to reset to the sparse checkout state." t) -(autoload 'magit-sparse-checkout-disable "magit-sparse-checkout" "\ -Convert sparse checkout to full checkout. -Note that disabling the sparse checkout does not clear the -configured directories. Call `magit-sparse-checkout-enable' to -restore the previous sparse checkout." t) -(register-definition-prefixes "magit-sparse-checkout" '("magit-sparse-checkout-")) - - -;;; 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) -(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) -(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) -(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) -(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) -(autoload 'magit-snapshot-index "magit-stash" "\ -Create a snapshot of the index only. -Unstaged and untracked changes are not stashed." t) -(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) - (autoload 'magit-stash-push "magit-stash" nil t) -(autoload 'magit-stash-apply "magit-stash" "\ -Apply a stash to the working tree. - -When using a Git release before v2.38.0, simply run \"git stash -apply\" or with a prefix argument \"git stash apply --index\". - -When using Git v2.38.0 or later, behave more intelligently: - -First try \"git stash apply --index\", which tries to preserve the -index stored in the stash, if any. This may fail because applying -the stash could result in conflicts and those have to be stored in -the index, making it impossible to also store the stash's index -there. - -If \"git stash\" fails, then potentially fall back to using \"git -apply\". If the stash does not touch any unstaged files, then pass -\"--3way\" to that command. Otherwise ask the user whether to use -that argument or \"--reject\". Customize `magit-no-confirm' if you -want to fall back to using \"--3way\", without being prompted. - -(fn STASH)" t) -(autoload 'magit-stash-pop "magit-stash" "\ -Apply a stash to the working tree, on success remove it from stash list. - -When using a Git release before v2.38.0, simply run \"git stash -pop\" or with a prefix argument \"git stash pop --index\". - -When using Git v2.38.0 or later, behave more intelligently: - -First try \"git stash apply --index\", which tries to preserve the -index stored in the stash, if any. This may fail because applying -the stash could result in conflicts and those have to be stored in -the index, making it impossible to also store the stash's index -there. - -If \"git stash\" fails, then potentially fall back to using \"git -apply\". If the stash does not touch any unstaged files, then pass -\"--3way\" to that command. Otherwise ask the user whether to use -that argument or \"--reject\". Customize `magit-no-confirm' if you -want to fall back to using \"--3way\", without being prompted. - -(fn STASH)" t) -(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) -(autoload 'magit-stash-clear "magit-stash" "\ -Remove all stashes saved in REF's reflog by deleting REF. - -(fn REF)" t) -(autoload 'magit-stash-branch "magit-stash" "\ -Create and checkout a new BRANCH from an existing STASH. -The new branch starts at the commit that was current when the -stash was created. If the stash applies cleanly, then drop it. - -(fn STASH BRANCH)" t) -(autoload 'magit-stash-branch-here "magit-stash" "\ -Create and checkout a new BRANCH from an existing STASH. -Use the current branch or `HEAD' as the starting-point of BRANCH. -Then apply STASH, dropping it if it applies cleanly. - -(fn STASH BRANCH)" t) -(autoload 'magit-stash-format-patch "magit-stash" "\ -Create a patch from STASH. - -(fn STASH)" t) -(autoload 'magit-stash-list "magit-stash" "\ -List all stashes in a buffer." t) -(autoload 'magit-stash-show "magit-stash" "\ -Show all diffs of a stash in a buffer. - -(fn STASH &optional ARGS FILES)" t) -(register-definition-prefixes "magit-stash" '("magit-")) - - -;;; 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) -(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) -(defalias 'magit #'magit-status "\ -Begin using Magit. - -This alias for `magit-status' exists 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) -(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) -(autoload 'magit-status-setup-buffer "magit-status" "\ - - -(fn &optional DIRECTORY)") -(register-definition-prefixes "magit-status" '("magit-")) - - -;;; 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)") - (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) -(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.") -(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.") -(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.") -(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.") -(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.") -(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.") -(autoload 'magit-list-submodules "magit-submodule" "\ -Display a list of the current repository's populated submodules." t) -(register-definition-prefixes "magit-submodule" '("magit-")) - - -;;; 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) -(autoload 'magit-subtree-add-commit "magit-subtree" "\ -Add COMMIT as a new subtree at PREFIX. - -(fn PREFIX COMMIT ARGS)" t) -(autoload 'magit-subtree-merge "magit-subtree" "\ -Merge COMMIT into the PREFIX subtree. - -(fn PREFIX COMMIT ARGS)" t) -(autoload 'magit-subtree-pull "magit-subtree" "\ -Pull REF from REPOSITORY into the PREFIX subtree. - -(fn PREFIX REPOSITORY REF ARGS)" t) -(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) -(autoload 'magit-subtree-split "magit-subtree" "\ -Extract the history of the subtree PREFIX. - -(fn PREFIX COMMIT ARGS)" t) -(register-definition-prefixes "magit-subtree" '("magit-")) - - -;;; 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) -(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) -(autoload 'magit-tag-prune "magit-tag" "\ -Offer to delete tags missing locally from REMOTE, and vice versa. - -(fn TAGS REMOTE-TAGS REMOTE)" t) -(autoload 'magit-tag-release "magit-tag" "\ -Create a release tag for `HEAD'. - -Assume that release tags match `magit-release-tag-regexp'. - -If `HEAD's message matches `magit-release-commit-regexp', then -base the tag on the version string specified by that. Otherwise -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. - -When creating an annotated tag, prepare a message based on the message -of the highest existing tag, provided that contains the corresponding -version string, and substituting the new version string for that. If -that is not the case, propose a message using a reasonable format. - -(fn TAG MSG &optional ARGS)" t) -(register-definition-prefixes "magit-tag" '("magit-")) - - -;;; Generated autoloads from magit-transient.el - -(register-definition-prefixes "magit-transient" '("magit-")) - - -;;; 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. - -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. - -This is a global minor mode. If called interactively, toggle the -`Magit-Wip mode' mode. If the prefix argument is positive, enable the -mode, and if it is zero or negative, disable the mode. - -If called from Lisp, toggle the mode if ARG is `toggle'. Enable the -mode if ARG is nil, omitted, or is a positive number. Disable the mode -if ARG is a negative number. - -To check whether the minor mode is enabled in the current buffer, -evaluate `(default-value \\='magit-wip-mode)'. - -The mode's hook is called both when the mode is enabled and when it is -disabled. - -(fn &optional ARG)" t) -(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, toggle the mode if ARG is `toggle'. -Enable the mode if ARG is nil, omitted, or is a positive number. -Disable the mode if ARG is a negative number. - -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) -(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. - -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. - -This is a global minor mode. If called interactively, toggle the -`Magit-Wip-After-Apply mode' mode. If the prefix argument is positive, -enable the mode, and if it is zero or negative, disable the mode. - -If called from Lisp, toggle the mode if ARG is `toggle'. Enable the -mode if ARG is nil, omitted, or is a positive number. Disable the mode -if ARG is a negative number. - -To check whether the minor mode is enabled in the current buffer, -evaluate `(default-value \\='magit-wip-after-apply-mode)'. - -The mode's hook is called both when the mode is enabled and when it is -disabled. - -(fn &optional ARG)" t) -(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. - -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. - -This is a global minor mode. If called interactively, toggle the -`Magit-Wip-Before-Change mode' mode. If the prefix argument is -positive, enable the mode, and if it is zero or negative, disable the -mode. - -If called from Lisp, toggle the mode if ARG is `toggle'. Enable the -mode if ARG is nil, omitted, or is a positive number. Disable the mode -if ARG is a negative number. - -To check whether the minor mode is enabled in the current buffer, -evaluate `(default-value \\='magit-wip-before-change-mode)'. - -The mode's hook is called both when the mode is enabled and when it is -disabled. - -(fn &optional ARG)" t) -(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.") -(register-definition-prefixes "magit-wip" '("magit-")) - - -;;; 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) -(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)" t) -(autoload 'magit-worktree-move "magit-worktree" "\ -Move WORKTREE to PATH. - -(fn WORKTREE PATH)" t) -(register-definition-prefixes "magit-worktree" '("magit-")) - -;;; End of scraped data - -(provide 'magit-autoloads) - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; no-native-compile: t -;; coding: utf-8-emacs-unix -;; End: - -;;; magit-autoloads.el ends here diff --git a/elpa/magit-20250519.1537/magit-autorevert.el b/elpa/magit-20250519.1537/magit-autorevert.el deleted file mode 100644 index 3579bf2e..00000000 --- a/elpa/magit-20250519.1537/magit-autorevert.el +++ /dev/null @@ -1,271 +0,0 @@ -;;; magit-autorevert.el --- Revert buffers when files in repository change -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; Commentary: - -;; This library implements support for automatically reverting buffers -;; when visited files in the repository change. - -;; See (info "(magit)Automatic Reverting of File-Visiting Buffers"). - -;;; Code: - -(require 'magit-process) - -(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) - (cond (file - (when-let ((buffer (find-buffer-visiting file))) - (with-current-buffer buffer - (magit-turn-on-auto-revert-mode-if-desired)))) - ((and (not auto-revert-mode) ; see #3014 - (not global-auto-revert-mode) ; see #3460 - buffer-file-name - (or auto-revert-remote-files ; see #5422 - (not (file-remote-p buffer-file-name))) - (file-readable-p buffer-file-name) - (compat-call executable-find (magit-git-executable) t) - (magit-toplevel) - (or (not magit-auto-revert-tracked-only) - (magit-file-tracked-p buffer-file-name))) - (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 enables `global-auto-revert-mode' after loading magit -;; and after `after-init-hook' has run, then `magit-auto-revert-mode' -;; remains enabled; and there is nothing we can do about it. -;; - However if the init file causes `magit-autorevert' to be loaded -;; and only later it enables `global-auto-revert-mode', then we can -;; and should leave `magit-auto-revert-mode' disabled. -(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 (or (not magit-auto-revert-mode) - (and global-auto-revert-mode (not after-init-time))) - (magit-auto-revert-mode -1) - (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-since start)))) - (if (> elapsed 0.2) - (format " (%.3fs, %s buffers checked)" elapsed - (length (buffer-list))) - "")))))) -(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)))))) - -(define-advice auto-revert-buffers (:around (fn) buffer-list-filter) - (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 - (seq-filter auto-revert-buffer-list-filter - auto-revert-buffer-list))) - (funcall fn)) - (unless auto-revert-timer - (auto-revert-set-timer)))) - -;;; _ -(provide 'magit-autorevert) -;;; magit-autorevert.el ends here diff --git a/elpa/magit-20250519.1537/magit-base.el b/elpa/magit-20250519.1537/magit-base.el deleted file mode 100644 index 40245465..00000000 --- a/elpa/magit-20250519.1537/magit-base.el +++ /dev/null @@ -1,1201 +0,0 @@ -;;; magit-base.el --- Early birds -*- lexical-binding:t; coding:utf-8 -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;; This file contains code taken from GNU Emacs, which is -;; Copyright (C) 1976-2023 Free Software Foundation, Inc. - -;;; Commentary: - -;; This library defines utility functions, options and other things that -;; have to be available early on because they are used by several other -;; libraries, which cannot depend on one another, because that would lead -;; to circular dependencies. - -;;; Code: - -;; Also update EMACS_VERSION in "default.mk". -(defconst magit--minimal-emacs "27.1") -(defconst magit--minimal-git "2.25.0") - -(require 'cl-lib) -(require 'compat) -(require 'eieio) -(require 'llama) -(require 'subr-x) - -;; For older Emacs releases we depend on an updated `seq' release from -;; GNU ELPA, for `seq-keep'. Unfortunately something else may already -;; have required `seq', before `package' had a chance to put the more -;; recent version earlier on the `load-path'. -(when (and (featurep 'seq) - (not (fboundp 'seq-keep))) - (unload-feature 'seq 'force)) -(require 'seq) - -(require 'crm) - -(require 'magit-section) - -(eval-when-compile (require 'info)) -(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" ()) - -;;; Options - -(defcustom magit-completing-read-function #'magit-builtin-completing-read - "Function to be called when requesting input from the user. - -The default, `magit-builtin-completing-read', support third-party -completion frameworks, including `vertico-mode', `ivy-mode' and -`helm-mode'. - -However, 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 still use `ido-mode', you'll likely need the `magit-ido' package." - :group 'magit-essentials - :type `(radio (function-item ,#'magit-builtin-completing-read) - (function-item ivy-completing-read) - (function-item helm--completing-read-default) - (function :tag "Other function"))) - -(defcustom magit-dwim-selection - ;; Do not function-quote to avoid circular dependencies. - '((magit-stash-apply nil t) - (magit-ediff-resolve-all nil t) - (magit-ediff-resolve-rest 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)) - "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-cherry-pick) - (const abort-revert) - (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 stash-apply-3way) - (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-cherry-pick' Aborting a cherry-pick throws away all - conflict resolutions which has already been carried out by the - user. - - `abort-revert' Aborting a revert throws away all conflict - resolutions which has already been carried out by the user. - - `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: - - `stash-apply-3way' When a stash cannot be applied using \"git - stash apply\", then Magit uses \"git apply\" instead, possibly - using the \"--3way\" argument, which isn't always perfectly - safe. See also `magit-stash-apply'. - - `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-verbose-messages nil - "Whether to make certain prompts and messages more verbose. - -Occasionally a user suggests that a certain prompt or message -should be more verbose, but I would prefer to keep it as-is -because I don't think that the fact that that one user did not -understand the existing prompt/message means that a large number -of users would have the same difficulty, and that making it more -verbose would actually do a disservice to users who understand -the shorter prompt well enough. - -Going forward I will start offering both messages when I feel the -suggested longer message is reasonable enough, and the value of -this option decides which will be used. Note that changing the -value of this option affects all such messages and that I do not -intend to add an option per prompt." - :package-version '(magit . "4.0.0") - :group 'magit-miscellaneous - :type 'boolean) - -(defcustom magit-ellipsis - '((margin (?… . ">")) - (t (?… . "..."))) - "Characters or strings used to abbreviate text in some buffers. - -Each element has the form (WHERE (FANCY . UNIVERSAL)). - -FANCY is a single character or nil whereas UNIVERSAL is a string -of any length. The ellipsis produced by `magit--ellipsis' will -be FANCY if it's a non-nil character that can be displayed with -the available fonts, otherwise UNIVERSAL will be used. FANCY is -meant to be a rich character like a horizontal ellipsis symbol or -an emoji whereas UNIVERSAL something simpler available in a less -rich environment like the CLI. WHERE determines the use-case for -the ellipsis definition. Currently the only acceptable values -for WHERE are `margin' or t (representing the default). - -Whether collapsed sections are indicated using ellipsis is -controlled by `magit-section-visibility-indicator'." - :package-version '(magit . "4.0.0") - :group 'magit-miscellaneous - :type '(repeat (list (symbol :tag "Where") - (cons (choice :tag "Fancy" character (const nil)) - (string :tag "Universal"))))) - -(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))) - -;;; Section Classes - -(defclass magit-commit-section (magit-section) - ((keymap :initform 'magit-commit-section-map))) - -(setf (alist-get 'commit magit--section-type-alist) 'magit-commit-section) - -(defclass magit-diff-section (magit-section) - ((keymap :initform 'magit-diff-section-map)) - :abstract t) - -(defclass magit-file-section (magit-diff-section) - ((keymap :initform 'magit-file-section-map) - (source :initform nil :initarg :source) - (header :initform nil :initarg :header) - (binary :initform nil :initarg :binary) - (heading-highlight-face :initform 'magit-diff-file-heading-highlight) - (heading-selection-face :initform 'magit-diff-file-heading-selection))) - -(defclass magit-module-section (magit-file-section) - ((keymap :initform 'magit-module-section-map) - (range :initform nil :initarg :range))) - -(defclass magit-hunk-section (magit-diff-section) - ((keymap :initform 'magit-hunk-section-map) - (painted :initform nil) - (refined :initform nil) - (combined :initform nil :initarg :combined) - (from-range :initform nil :initarg :from-range) - (from-ranges :initform nil) - (to-range :initform nil :initarg :to-range) - (about :initform nil :initarg :about) - (heading-highlight-face :initform 'magit-diff-hunk-heading-highlight) - (heading-selection-face :initform 'magit-diff-hunk-heading-selection))) - -(setf (alist-get 'file magit--section-type-alist) 'magit-file-section) -(setf (alist-get 'module magit--section-type-alist) 'magit-module-section) -(setf (alist-get 'hunk magit--section-type-alist) 'magit-hunk-section) - -(defclass magit-log-section (magit-section) - ((keymap :initform 'magit-log-section-map)) - :abstract t) -(defclass magit-unpulled-section (magit-log-section) ()) -(defclass magit-unpushed-section (magit-log-section) ()) -(defclass magit-unmerged-section (magit-log-section) ()) - -(setf (alist-get 'unpulled magit--section-type-alist) 'magit-unpulled-section) -(setf (alist-get 'unpushed magit--section-type-alist) 'magit-unpushed-section) -(setf (alist-get 'unmerged magit--section-type-alist) 'magit-unmerged-section) - -;;; 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 vertico-sort-function) - -(defvar magit-completing-read--silent-default nil) - -(defvar magit-completing-read-default-prompt-predicate - (lambda () - (and (eq magit-completing-read-function - 'magit-builtin-completing-read) - (not (or (bound-and-true-p helm-mode) - (bound-and-true-p ivy-mode) - (bound-and-true-p selectrum-mode) - (bound-and-true-p vertico-mode))))) - "Function used to determine whether to add default to prompt. - -This is used by `magit-completing-read' (which see). - -The default function returns nil, when a completion frameworks is used -for which this is undesirable. More precisely, it returns nil, when -`magit-completing-read-function' is not `magit-builtin-completing-read', -or one of `helm-mode', `ivy-mode', `selectrum-mode' or `vertico-mode' -is enabled. When this function returns nil, then nil is passed to -`format-prompt' (which see), instead of the default (DEF or FALLBACK).") - -(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. - -- `format-prompt' is called on PROMPT and DEF (or FALLBACK if - DEF is nil). This appends \": \" to the prompt and may also - add the default to the prompt, using the format specified by - `minibuffer-default-prompt-format' and depending on - `magit-completing-read-default-prompt-predicate'." - (setq magit-completing-read--silent-default nil) - (if-let ((dwim (and def - (nth 2 (seq-find (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)) - (when (and def - (not (functionp collection)) - (not (member def collection))) - (setq collection (cons def collection))) - (let ((command this-command) - (reply (funcall magit-completing-read-function - (magit--format-prompt prompt def) - 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 (and require-match - (not (and (listp collection) - (member "" collection)))) - (user-error "Nothing selected") - nil) - reply)))) - -(defun magit--format-prompt (prompt default) - (format-prompt (if (string-suffix-p ": " prompt) - (substring prompt 0 -2) - prompt) - (and (funcall magit-completing-read-default-prompt-predicate) - default))) - -(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)) - (setq choices (magit--completion-table choices))) - (let ((ivy-sort-functions-alist nil)) - (completing-read prompt - (lambda (str pred action) - (if (eq action 'metadata) - '(metadata (display-sort-function . identity) - (cycle-sort-function . identity)) - (complete-with-action action choices str pred))) - predicate require-match - initial-input hist def))) - -(define-obsolete-function-alias 'magit-completing-read-multiple* - 'magit-completing-read-multiple "Magit-Section 4.0.0") - -(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))) - ;; 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))) - ;; And now, the moment we have all been waiting for... - (values (completing-read-multiple - (magit--format-prompt prompt def) - table predicate require-match initial-input - hist def inherit-input-method))) - (if no-split input values))) - -(defvar-keymap magit-minibuffer-local-ns-map - :parent minibuffer-local-map - "SPC" #'magit-whitespace-disallowed - "TAB" #'magit-whitespace-disallowed) - -(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, -* `format-prompt' is used internally. -* 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 - (format-prompt 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 - (let ((parts (nconc (list ,@(mapcar #'cadr clauses)) - ,(and verbose '(list "[C-g] to abort"))))) - (concat ,prompt - (string-join (butlast parts) ", ") - ", or " (car (last parts)) " ")) - ',(mapcar #'car clauses)) - ,@(mapcar (##`(,(car %) ,@(cddr %))) 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) prompt-suffix) - (declare (indent defun)) - (when (and prompt (listp prompt)) - (setq prompt - (apply #'format (car prompt) - (mapcar (##if (stringp %) (string-replace "%" "%%" %) %) - (cdr prompt))))) - (when (and prompt-n (listp prompt-n)) - (setq prompt-n - (apply #'format (car prompt-n) - (mapcar (##if (stringp %) (string-replace "%" "%%" %) %) - (cdr prompt-n))))) - (setq prompt-n (format (concat (or prompt-n prompt) "? ") (length items))) - (setq prompt (format (concat (or prompt (magit-confirm-make-prompt action)) - "? ") - (car items))) - (when prompt-suffix - (setq prompt (concat prompt prompt-suffix))) - (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 (string-join items "\n") - "\n\n" prompt-n) - action) - items))) - (if noabort nil (user-error "Abort")))) - -(defun magit-confirm-files (action files &optional prompt prompt-suffix noabort) - (when files - (unless prompt - (setq prompt (magit-confirm-make-prompt action))) - (magit-confirm action - (concat prompt " \"%s\"") - (concat prompt " %d files") - noabort files prompt-suffix))) - -(defun magit-confirm-make-prompt (action) - (let ((prompt (symbol-name action))) - (string-replace "-" " " - (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)" - ,@(mapcan - (##list "-L" %) - (delete-dups - (mapcan - (lambda (lib) - (if-let ((path (locate-library lib))) - (list (file-name-directory path)) - (error "Cannot find mandatory dependency %s" lib))) - '(;; Like `LOAD_PATH' in `default.mk'. - "compat" - "llama" - "seq" - "transient" - "with-editor" - ;; Obviously `magit' itself is needed too. - "magit" - ;; While this is part of the Magit repository, - ;; it is distributed as a separate package. - "magit-section")))) - ;; 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 (gensym "string")) - (i 0)) - `(let ((,s ,string)) - (let ,(save-match-data - (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." - (and (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." - (and (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 `header-line-format' in the current buffer based on STRING. -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--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--separate (pred list) - "Separate elements of LIST that do and don't satisfy PRED. -Return a list of two lists; the first containing the elements that -do satisfy PRED and the second containing the elements that don't." - (let (y n) - (dolist (elt list) - (push elt (if (funcall pred elt) y n))) - (list (nreverse y) - (nreverse n)))) - -(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-which-function () - "Return current function name based on point, without caching. - -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 value of the variable 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 -(define-advice Info-follow-nearest-node (:around (fn &optional fork) gitman) - (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)))) - -;; When making changes here, then also adjust the copy in docs/Makefile. -;;;###autoload -(define-advice org-man-export (:around (fn link description format) gitman) - (if (and (eq format 'texinfo) - (string-prefix-p "git" link)) - (string-replace "%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))) - -;;; Kludges for Package Managers - -(defun magit--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 some source based package managers -\(Elpaca and Straight) on Windows. - -See ." - (when-let* - ((manager (cond ((bound-and-true-p straight-symlink-mode) 'straight) - ((bound-and-true-p elpaca-no-symlink-mode) 'elpaca))) - (build (pcase manager - ('straight (bound-and-true-p straight-build-dir)) - ('elpaca (bound-and-true-p elpaca-builds-directory)))) - ((string-prefix-p build filename)) - (repo (pcase manager - ('straight - (and (bound-and-true-p straight-base-dir) - (expand-file-name "repos/magit/lisp/" straight-base-dir))) - ('elpaca - (and (bound-and-true-p elpaca-repos-directory) - (expand-file-name "magit/lisp/" elpaca-repos-directory)))))) - (setq filename (expand-file-name (file-name-nondirectory filename) repo))) - (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 (seq-find (##string-prefix-p % 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)))) - -(defun magit--ellipsis (&optional where) - "Build an ellipsis always as string, depending on WHERE." - (if (stringp magit-ellipsis) - magit-ellipsis - (if-let ((pair (car (or - (alist-get (or where t) magit-ellipsis) - (alist-get t magit-ellipsis))))) - (pcase-let ((`(,fancy . ,universal) pair)) - (let ((ellipsis (if (and fancy (char-displayable-p fancy)) - fancy - universal))) - (if (characterp ellipsis) - (char-to-string ellipsis) - ellipsis))) - (user-error "Variable magit-ellipsis is invalid")))) - -(defun magit--ext-regexp-quote (string) - "Like `reqexp-quote', but for Extended Regular Expressions." - (let ((special (string-to-list "[*.\\?+^$({")) - (quoted nil)) - (dolist (char string) - (when (memq char special) - (push ?\\ quoted)) - (push char quoted)) - (concat (nreverse quoted)))) - -;;; _ -(provide 'magit-base) -;;; magit-base.el ends here diff --git a/elpa/magit-20250519.1537/magit-bisect.el b/elpa/magit-20250519.1537/magit-bisect.el deleted file mode 100644 index 8c737c13..00000000 --- a/elpa/magit-20250519.1537/magit-bisect.el +++ /dev/null @@ -1,318 +0,0 @@ -;;; magit-bisect.el --- Bisect support for Magit -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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 (##magit-git-version>= "2.29")) - (magit-bisect:--term-old :level 6) - (magit-bisect:--term-new :level 6)] - ["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) - ("m" "Mark" magit-bisect-mark :level 6) - ("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))) - (magit-bisect-start--assert bad good args) - (magit-repository-local-set 'bisect--first-parent - (transient-arg-value "--first-parent" args)) - (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))) - -(defun magit-bisect-start--assert (bad good 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"))) - -;;;###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") - (magit-repository-local-delete 'bisect--first-parent) - (ignore-errors - (delete-file (expand-file-name "BISECT_CMD_OUTPUT" (magit-gitdir))))) - -;;;###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) - (magit-bisect-start--assert bad good args) - ;; 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 (expand-file-name "BISECT_CMD_OUTPUT" (magit-gitdir))) - "bisect" "start" bad good args) - (magit-refresh))) - (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 (magit-section-at)) - (output (buffer-substring-no-properties - (oref section content) - (oref section end)))) - (with-temp-file - (expand-file-name "BISECT_CMD_OUTPUT" (magit-gitdir)) - (insert output))))) - (magit-refresh)) - (message "Bisecting...done"))))) - -;;; Sections - -(defun magit-bisect-in-progress-p () - (file-exists-p (expand-file-name "BISECT_LOG" (magit-gitdir)))) - -(defun magit-bisect-terms () - (magit-file-lines (expand-file-name "BISECT_TERMS" (magit-gitdir)))) - -(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 - (expand-file-name "BISECT_CMD_OUTPUT" (magit-gitdir))) - (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)) - (seq-find (##string-match done-re %) 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 t "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") - (and (magit-repository-local-get 'bisect--first-parent) - "--first-parent"))))) - -(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 t "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\\|# status:\\) [^\n]+\n\\)" nil t)) - (if (string-prefix-p "# status:" (match-string 1)) - (magit-delete-match) - (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) - (magit-insert-heading - (propertize heading 'font-lock-face - 'magit-section-secondary-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-20250519.1537/magit-blame.el b/elpa/magit-20250519.1537/magit-blame.el deleted file mode 100644 index e87bd4fc..00000000 --- a/elpa/magit-20250519.1537/magit-blame.el +++ /dev/null @@ -1,1005 +0,0 @@ -;;; magit-blame.el --- Blame support for Magit -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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")) - (highlight - (highlight-face . magit-blame-highlight)) - (lines - (show-lines . t) - (show-message . t))) - "List of styles used to visualize blame information. - -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. - -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. WARNING: Adding this key affects performance; - see the note at the end of this docstring. - `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' - %h truncated 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' - -Note that for performance reasons %h results in truncated -hashes, as opposed to properly abbreviated hashes that are -guaranteed to uniquely identify a commit. - -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. - -Blame information is displayed using overlays. Such extensive -use of overlays is known to slow down even basic operations, such -as moving the cursor. To reduce the number of overlays the margin -style had to be removed from the default value of this option. - -Note that the margin overlays are created even if another style -is currently active. This can only be prevented by not even -defining a style that uses the margin. If you want to use this -style anyway, you can restore this definition, which used to be -part of the default value: - - (margin - (margin-format . (\" %s%f\" \" %C %a\" \" %H\")) - (margin-width . 42) - (margin-face . magit-blame-margin) - (margin-body-face . (magit-blame-dimmed)))" - :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 - (list #'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 (list #'magit-blame-maybe-update-revision-buffer - #'magit-blame-maybe-show-message)) - -;;; Faces - -(defface magit-blame-highlight - '((((class color) (background light)) - :extend t - :background "grey80" - :foreground "black") - (((class color) (background dark)) - :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 :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) - -;;; 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--make-margin-overlays nil) -(defvar-local magit-blame--style nil) - -;;; 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 "%d,+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)) - (if (eobp) - (unless noerror - (error "Cannot get blame chunk at eob")) - (car (magit-blame--parse-chunk type)))))) - (noerror nil) - ((error "Buffer does not visit a tracked file"))))))) - -(defun magit-blame-chunk-at (pos) - (seq-some (##overlay-get % 'magit-blame-chunk) - (overlays-at pos))) - -(defun magit-blame--overlay-at (&optional pos key) - (unless pos - (setq pos (point))) - (seq-find (##overlay-get % (or key 'magit-blame-chunk)) - (nconc (overlays-at pos) - (overlays-in pos pos)))) - -;;; Keymaps - -(defvar-keymap magit-blame-mode-map - :doc "Keymap for `magit-blame-mode'. -Note that most blaming key bindings are defined -in `magit-blame-read-only-mode-map' instead." - "C-c C-q" #'magit-blame-quit) - -(defvar-keymap magit-blame-read-only-mode-map - :doc "Keymap for `magit-blame-read-only-mode'." - "C-m" #'magit-show-commit - "p" #'magit-blame-previous-chunk - "P" #'magit-blame-previous-chunk-same-commit - "n" #'magit-blame-next-chunk - "N" #'magit-blame-next-chunk-same-commit - "b" #'magit-blame-addition - "r" #'magit-blame-removal - "f" #'magit-blame-reverse - "B" #'magit-blame - "c" #'magit-blame-cycle-style - "q" #'magit-blame-quit - "M-w" #'magit-blame-copy-hash - "SPC" #'magit-diff-show-or-scroll-up - "S-SPC" #'magit-diff-show-or-scroll-down - "DEL" #'magit-diff-show-or-scroll-down) - -;;; Modes -;;;; Base Mode - -(define-minor-mode magit-blame-mode - "Display blame information inline." - :lighter magit-blame-mode-lighter - :interactive nil - (cond (magit-blame-mode - (unless arg - ;; Emacs < 28.1 doesn't support `:interactive'. - (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))) - (setq magit-blame--make-margin-overlays - (and (cl-find-if (##assq 'margin-format (cdr %)) - magit-blame-styles))) - (magit-blame--update-margin 'enable)) - (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 'disable) - (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 ((entry (assq 'magit-blame-read-only-mode - (cl-member 'view-mode minor-mode-map-alist - :key #'car)))) - (setq minor-mode-map-alist - (cons entry - (delq entry 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)) - (kill-buffer (process-get process 'stderr-buf)) - (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 - -(defvar-local magit-blame--previous-margin-width nil) - -(defsubst magit-blame--style-get (key) - (cdr (assoc key (cdr magit-blame--style)))) - -(defun magit-blame--make-overlays (buf chunk revinfo) - (with-current-buffer buf - (save-excursion - (save-restriction - (widen) - (let* ((line (oref chunk final-line)) - (beg (magit-blame--line-beginning-position line)) - (end (magit-blame--line-beginning-position - (+ line (oref chunk num-lines)))) - (before (magit-blame-chunk-at (1- beg)))) - (when (and before - (equal (oref before orig-rev) - (oref chunk orig-rev))) - (setq beg (magit-blame--line-beginning-position - (oset chunk final-line (oref before final-line)))) - (cl-incf (oref chunk num-lines) - (oref before num-lines))) - (magit-blame--remove-overlays beg end) - (when magit-blame--make-margin-overlays - (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--line-beginning-position (line) - (save-excursion - (goto-char (point-min)) - (forward-line (1- line)) - (point))) - -(defun magit-blame--make-margin-overlays (chunk revinfo beg end) - (save-excursion - (let ((line 0)) - (goto-char beg) - (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+ (magit--eol-position beg))))) - (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 (&optional action) - (when (eq action 'enable) - (setq magit-blame--previous-margin-width left-margin-width)) - (setq left-margin-width - (if (eq action 'disable) - (prog1 magit-blame--previous-margin-width - (setq magit-blame--previous-margin-width nil)) - (or (magit-blame--style-get 'margin-width) - magit-blame--previous-margin-width))) - (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 ((format (magit-blame--style-get 'heading-format))) - ;; Use `default' as the last face to avoid picking up any face - ;; attributes from the first character of the text on which we - ;; put the overlay. See #5233. - (magit-blame--format-string ov format '(magit-blame-heading default)) - (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 too 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 (string-match-p "\\`0\\{40,\\}\\'" rev) - (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 (cons f (ensure-list 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)) - (?h . ,(p0 (magit-blame--abbrev-hash 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 - `( :extend t - :background - ,(face-attribute 'magit-blame-heading :background nil 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-search "%z" time-format) - (car (last (parse-time-string tz)))))) - (format-time-string time-format - (seconds-to-time (string-to-number time)) - tz-in-second))) - -(defvar-local magit-blame--abbrev-length nil) - -(defun magit-blame--abbrev-hash (rev) - (substring rev 0 (or magit-blame--abbrev-length - (setq magit-blame--abbrev-length - (magit-abbrev-length))))) - -(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) - (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) - (magit-msg "%S" msg)) - (magit-msg "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 (##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 "Still blaming, commit data not available yet")) - (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 (next-single-char-property-change - (point) 'magit-blame-chunk))) - (goto-char next) - (user-error "No more chunks"))) - -(defun magit-blame-previous-chunk () - "Move to the previous chunk." - (interactive) - (if-let ((prev (previous-single-char-property-change - (point) 'magit-blame-chunk))) - (goto-char prev) - (user-error "No more chunks"))) - -(defun magit-blame-next-chunk-same-commit (&optional previous) - "Move to the next chunk from the same commit. -\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 ((o (magit-blame--overlay-at pos)) - ((equal (oref (magit-blame-chunk-at pos) orig-rev) rev))) - (setq ov o)))) - (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-20250519.1537/magit-bookmark.el b/elpa/magit-20250519.1537/magit-bookmark.el deleted file mode 100644 index 963b7e1c..00000000 --- a/elpa/magit-20250519.1537/magit-bookmark.el +++ /dev/null @@ -1,154 +0,0 @@ -;;; magit-bookmark.el --- Bookmarks for Magit buffers -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; Inspired by an earlier implementation by Yuri Khan. - -;; 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 of the License, 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 . - -;;; Commentary: - -;; Support for bookmarks for most Magit buffers. - -;;; Code: - -(require 'magit) - -(require 'bookmark) - -;;; Common - -(cl-defmethod magit-bookmark-get-filename (&context (major-mode magit-mode)) - (magit-toplevel)) - -(cl-defmethod magit-bookmark-get-buffer-create - (bookmark (mode (derived-mode magit-mode))) - (let ((default-directory (bookmark-get-filename bookmark)) - (magit-display-buffer-function #'identity) - (magit-display-buffer-noselect t)) - (apply (intern (format "%s-setup-buffer" - (substring (symbol-name mode) 0 -5))) - (mapcar (##bookmark-prop-get bookmark %) - (get mode 'magit-bookmark-variables))))) - -;;; 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 " -- " (string-join 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 - (string-join 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 - (string-join magit-buffer-diff-files " ") - (magit-rev-format "%s" magit-buffer-revision)))) - -(cl-defmethod magit-bookmark--get-child-value - (section &context (major-mode magit-stash-mode)) - (string-replace magit-buffer-revision - magit-buffer-revision-hash - (oref section value))) - -;;; 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)" - (string-join magit-buffer-revisions " ") - (if magit-buffer-log-files - (concat " -- " (string-join 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-20250519.1537/magit-branch.el b/elpa/magit-20250519.1537/magit-branch.el deleted file mode 100644 index 56a754e5..00000000 --- a/elpa/magit-20250519.1537/magit-branch.el +++ /dev/null @@ -1,982 +0,0 @@ -;;; magit-branch.el --- Branch support -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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'." - :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" - [:if (##and magit-branch-direct-configure (transient-scope)) - :description (##concat - (propertize "Configure " 'face 'transient-heading) - (propertize (transient-scope) 'face 'magit-branch-local)) - ("d" magit-branch..description) - ("u" magit-branch..merge/remote) - ("r" magit-branch..rebase) - ("p" magit-branch..pushRemote)] - [:if-non-nil magit-branch-direct-configure - :description "Configure repository defaults" - ("R" magit-pull.rebase) - ("P" magit-remote.pushDefault) - ("B" "Update default branch" magit-update-default-branch - :inapt-if-not magit-get-some-remote)] - ["Arguments" - (7 "-r" "Recurse submodules when checking out an existing branch" - "--recurse-submodules")] - [["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)." - (declare (interactive-only magit--checkout)) - (interactive (list (magit-read-other-branch-or-commit "Checkout") - (magit-branch-arguments))) - (when (string-match "\\`heads/\\(.+\\)" revision) - (setq revision (match-string 1 revision))) - (magit-run-git-async "checkout" args revision)) - -(defun magit--checkout (revision &optional args) - (when (string-match "\\`heads/\\(.+\\)" revision) - (setq revision (match-string 1 revision))) - (magit-call-git "checkout" args revision)) - -;;;###autoload -(defun magit-branch-create (branch start-point) - "Create BRANCH at branch or revision START-POINT." - (declare (interactive-only magit-call-git)) - (interactive (magit-branch-read-args "Create branch")) - (magit-run-git-async "branch" branch start-point) - (set-process-sentinel - magit-this-process - (lambda (process event) - (when (memq (process-status process) '(exit signal)) - (magit-branch-maybe-adjust-upstream branch start-point) - (magit-process-sentinel process event))))) - -;;;###autoload -(defun magit-branch-and-checkout (branch start-point &optional args) - "Create and checkout BRANCH at branch or revision START-POINT." - (declare (interactive-only magit-call-git)) - (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-run-git-async "checkout" args "-b" branch start-point) - (set-process-sentinel - magit-this-process - (lambda (process event) - (when (memq (process-status process) '(exit signal)) - (magit-branch-maybe-adjust-upstream branch start-point) - (magit-process-sentinel process event)))))) - -;;;###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." - (declare (interactive-only magit-call-git)) - (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 - (with-suppressed-warnings ((interactive-only magit-branch-and-checkout)) - (magit-branch-and-checkout arg start-point)) - (magit--checkout arg) - (magit-refresh))) - -;;;###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'." - (declare (interactive-only magit-call-git)) - (interactive - (let* ((current (magit-get-current-branch)) - (local (magit-list-local-branch-names)) - (remote (seq-filter (##and (string-match "[^/]+/" %) - (not (member (substring % (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)))))) - (cond - ((not start-point) - (magit--checkout branch (magit-branch-arguments)) - (magit-refresh)) - (t - (when (magit-anything-modified-p t) - (user-error "Cannot checkout when there are uncommitted changes")) - (magit-run-git-async "checkout" (magit-branch-arguments) - "-b" branch start-point) - (set-process-sentinel - magit-this-process - (lambda (process event) - (when (memq (process-status process) '(exit signal)) - (magit-branch-maybe-adjust-upstream 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-process-sentinel process event))))))) - -(defun magit-branch-maybe-adjust-upstream (branch start-point) - (when-let ((upstream - (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)))) - (seq-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=" upstream) 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))) - (cond - ((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 (string-join (cdr (split-string choice "/")) "/"))) - (and (member choice (magit-list-remote-branch-names)) - (not (member def (magit-list-local-branch-names))) - def))) - choice)) - ((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")))) - (if (magit-branch-p branch) - (magit-branch-read-args - (format "Branch `%s' already exists; pick another name" branch) - default-start) - (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 ((upstream (magit-get-indirect-upstream-branch current))) - (magit-call-git "branch" "--set-upstream-to" upstream 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 ((branch (magit-read-local-branch "Reset branch" - (magit-local-branch-at-point)))) - (list branch - (magit-read-branch-or-commit (format "Reset %s to" branch) - (magit-get-upstream-branch 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. - -Require confirmation when deleting branches is dangerous in some -way. Option `magit-no-confirm' can be customized to not require -confirmation in certain cases. See its docstring to learn why -confirmation is required by default in certain cases or if a -prompt is confusing." - ;; 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 %d branches" nil branches) - (setq branches - (list (magit-read-branch-prefer-other - (if force "Force delete branch" "Delete branch"))))) - (when-let (((not force)) - (unmerged (seq-remove #'magit-branch-merged-p branches))) - (if (magit-confirm 'delete-unmerged-branch - "Delete unmerged branch %s" - "Delete %d unmerged branches" - 'noabort unmerged) - (setq force branches) - (or (setq branches - (cl-set-difference branches unmerged :test #'equal)) - (user-error "Abort")))) - (list branches force))) - (let ((refs (mapcar #'magit-ref-fullname branches))) - ;; If a member of refs is nil, that means that - ;; the respective branch name is ambiguous. - (when-let ((ambiguous (seq-filter #'null refs))) - (user-error - "%s ambiguous; please cleanup using git directly" - (let ((len (length ambiguous))) - (cond - ((= len 1) - (format "%s is" (seq-find #'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 - (list "Deleting local %s. Also delete on %s" - (magit-ref-fullname (car branches)) - remote) - (list "Deleting %d local refs. Also delete on %s" - (length refs) - remote) - 'noabort refs) - ;; 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 - (mapcar (##concat ":" (substring % 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-indirect-upstream-branch branch t))) - (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 - (list "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 (mapcar (##concat "refs/remotes/" remote "/" %) - (magit-remote-list-branches remote))) - (rest (seq-filter (##and (not (member % on-remote)) - (magit-ref-exists-p %)) - 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 (eq magit-branch-rename-push-target 'forge-only)) - (and (require (quote forge) nil t) - (fboundp 'forge--split-forge-url) - (and-let* ((url (magit-git-string - "remote" "get-url" remote))) - (forge--split-forge-url url))))) - (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/YYYY-MM-DD-BRANCH\", -and also rename the respective reflog file." - (interactive (list (magit-read-other-local-branch "Shelve branch"))) - (let ((old (concat "refs/heads/" branch)) - (new (format "refs/shelved/%s-%s" - (magit-rev-format "%cs" branch) - 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\". If BRANCH -is prefixed with \"YYYY-MM-DD\", then drop that part of the name. -Also rename the respective reflog file." - (interactive - (list (magit-completing-read - "Unshelve branch" - (mapcar (##substring % 8) - (nreverse (magit-list-refnames "refs/shelved"))) - nil t))) - (let ((old (concat "refs/shelved/" branch)) - (new (concat "refs/heads/" - (if (string-match-p - "\\`[0-9]\\{4\\}-[0-9]\\{2\\}-[0-9]\\{2\\}-" branch) - (substring branch 11) - 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* ((dir (magit-gitdir)) - (old (expand-file-name (concat "logs/" old) dir)) - (new (expand-file-name (concat "logs/" new) dir))) - (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 (##concat - (propertize "Configure " 'face 'transient-heading) - (propertize (transient-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) - ("B" "Update default branch" magit-update-default-branch - :inapt-if-not magit-get-some-remote)] - ["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)) - -(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 (transient-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 (transient-scope) "Upstream"))) - -(cl-defmethod transient-infix-set ((obj magit--git-branch:upstream) refname) - (magit-set-upstream-branch (transient-scope) refname) - (oset obj value - (and-let* ((branch (transient-scope)) - (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 (transient-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-20250519.1537/magit-bundle.el b/elpa/magit-20250519.1537/magit-bundle.el deleted file mode 100644 index 1cd98d55..00000000 --- a/elpa/magit-20250519.1537/magit-bundle.el +++ /dev/null @@ -1,139 +0,0 @@ -;;; magit-bundle.el --- Bundle support for Magit -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; Commentary: - -;; This library implements support for "git bundle". -;; The entry point is the `magit-bundle' menu command. - -;; See (man "git-bundle"). - -;;; 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-20250519.1537/magit-clone.el b/elpa/magit-20250519.1537/magit-clone.el deleted file mode 100644 index 42187eb3..00000000 --- a/elpa/magit-20250519.1537/magit-clone.el +++ /dev/null @@ -1,351 +0,0 @@ -;;; magit-clone.el --- Clone a repository -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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") - ("\\`\\(?:sourcehut:\\|sh:\\)\\([^:]+\\)\\'" "git.sr.ht" "sourcehut.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 . "4.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.sr.ht" . "git@%h:%n") - (t . "git@%h:%n.git")) - "Format(s) used when turning repository names into urls. - -In a format string, %h is the hostname and %n is the repository -name, including the name of the owner. - -The value can be a string (representing a single static format) -or an alist with elements (HOSTNAME . FORMAT) mapping hostnames -to formats. When an alist is used, the t key represents the -default. Also see `magit-clone-name-alist'." - :package-version '(magit . "4.0.0") - :group 'magit-commands - :type '(choice (string :tag "Format") - (alist :key-type (choice (string :tag "Host") - (const :tag "Default" t)) - :value-type (string :tag "Format")))) - -(defcustom magit-post-clone-hook nil - "Hook run after the repository has been successfully cloned. - -When the hook is called, `default-directory' is let-bound to the -directory where the repository has been cloned." - :package-version '(magit . "4.0.0") - :group 'magit-commands - :type 'hook) - -;;; 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=")) - (magit-clone:--filter :level 7) - ("-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) - (">" "sparse checkout" magit-clone-sparse :level 6) - ("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))) - -(transient-define-argument magit-clone:--filter () - :description "Filter some objects" - :class 'transient-option - :key "-f" - :argument "--filter=" - :reader #'magit-clone-read-filter) - -(defun magit-clone-read-filter (prompt initial-input history) - (magit-completing-read prompt - (list "blob:none" "tree:0") - nil nil initial-input history)) - -;;;###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))) - -;;;###autoload -(defun magit-clone-sparse (repository directory args) - "Clone REPOSITORY into DIRECTORY and create a sparse checkout." - (interactive (magit-clone-read-args)) - (magit-clone-internal repository directory (cons "--no-checkout" args) - 'sparse)) - -(defun magit-clone-internal (repository directory args &optional sparse) - (let* ((checkout (not (member (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)))) - (when (and sparse checkout) - (let ((default-directory directory)) - (magit-call-git "sparse-checkout" "init" "--cone") - (magit-call-git "checkout" (magit-get-current-branch)))) - (let ((default-directory directory)) - (run-hooks 'magit-post-clone-hook)) - (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 "[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) - (if-let ((url-format - (cond ((listp magit-clone-url-format) - (cdr (or (assoc host magit-clone-url-format) - (assoc t magit-clone-url-format)))) - ((stringp magit-clone-url-format) - magit-clone-url-format)))) - (format-spec - url-format - `((?h . ,host) - (?n . ,(if (string-search "/" repo) - repo - (if (string-search "." user) - (if-let ((user (magit-get user))) - (concat user "/" repo) - (user-error "Set %S or specify owner explicitly" user)) - (concat user "/" repo)))))) - (user-error - "Bogus `magit-clone-url-format' (bad type or missing default)"))) - -;;; _ -(provide 'magit-clone) -;;; magit-clone.el ends here diff --git a/elpa/magit-20250519.1537/magit-commit.el b/elpa/magit-20250519.1537/magit-commit.el deleted file mode 100644 index e8b84383..00000000 --- a/elpa/magit-20250519.1537/magit-commit.el +++ /dev/null @@ -1,816 +0,0 @@ -;;; magit-commit.el --- Create Git commits -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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) - -;;; 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-commit-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) - -;;; 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") - (magit-commit:--date :level 7) - (magit:--gpg-sign :level 5) - (magit:--signoff) - (magit-commit:--reuse-message)] - [["Create" - ("c" "Commit" magit-commit-create)] - ["Edit HEAD" - ("e" "Extend" magit-commit-extend) - "" - ("a" "Amend" magit-commit-amend) - "" - ("w" "Reword" magit-commit-reword) - ("d" "Reshelve" magit-commit-reshelve :level 0)] - ["Edit" - ("f" "Fixup" magit-commit-fixup) - ("s" "Squash" magit-commit-squash) - ("A" "Alter" magit-commit-alter) - ("n" "Augment" magit-commit-augment) - ("W" "Revise" magit-commit-revise)] - ["Edit and rebase" - ("F" "Instant fixup" magit-commit-instant-fixup) - ("S" "Instant squash" magit-commit-instant-squash) - "" - "" - ("R" "Reword past" magit-rebase-reword-commit :level 0)] - ["Spread across commits" - ("x" "Modified files" magit-commit-autofixup :level 6) - ("X" "Updated modules" magit-commit-absorb-modules :level 6)]] - (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-commit:--date () - :description "Override the author date" - :class 'transient-option - :shortarg "-D" - :argument "--date=" - :reader #'transient-read-date) - -(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 -;;;; Create - -;;;###autoload -(defun magit-commit-create (&optional args) - "Create a new commit." - (interactive (list (magit-commit-arguments))) - (cond ((member "--all" args) - (setq this-command 'magit-commit--all)) - ((member "--allow-empty" args) - (setq this-command 'magit-commit--allow-empty))) - (when (setq args (magit-commit-assert args)) - (let ((default-directory (magit-toplevel))) - (magit-run-git-with-editor "commit" args)))) - -;;;; Edit HEAD - -;;;###autoload -(defun magit-commit-extend (&optional args override-date) - "Amend staged changes to the last commit, without editing its message. - -With a prefix argument do not update the committer date; without an -argument update it. The option `magit-commit-extend-override-date' -can be used to inverse the meaning of the prefix argument. Called -non-interactively, the optional OVERRIDE-DATE argument controls this -behavior, and the option is of no relevance." - (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) - (if override-date - (magit-run-git-with-editor "commit" "--amend" "--no-edit" args) - (with-environment-variables - (("GIT_COMMITTER_DATE" (magit-rev-format "%cD"))) - (magit-run-git-with-editor "commit" "--amend" "--no-edit" args))))) - -;;;###autoload -(defun magit-commit-amend (&optional args) - "Amend staged changes (if any) to the last commit, and edit its message." - (interactive (list (magit-commit-arguments))) - (magit-commit-amend-assert) - (magit-run-git-with-editor "commit" "--amend" args)) - -;;;###autoload -(defun magit-commit-reword (&optional args override-date) - "Reword the message of the last commit, without amending its tree. - -With a prefix argument do not update the committer date; without an -argument update it. The option `magit-commit-reword-override-date' -can be used to inverse the meaning of the prefix argument. Called -non-interactively, the optional OVERRIDE-DATE argument controls this -behavior, and the option is of no relevance." - (interactive (list (magit-commit-arguments) - (if current-prefix-arg - (not magit-commit-reword-override-date) - magit-commit-reword-override-date))) - (magit-commit-amend-assert) - (cl-pushnew "--allow-empty" args :test #'equal) - (if override-date - (magit-run-git-with-editor "commit" "--amend" "--only" args) - (with-environment-variables - (("GIT_COMMITTER_DATE" (magit-rev-format "%cD"))) - (magit-run-git-with-editor "commit" "--amend" "--only" args)))) - -;;;; Edit - -;;;###autoload -(defun magit-commit-fixup (&optional commit args) - "Create a fixup commit, leaving the original commit message untouched. - -If there is a reachable commit at point, target that. Otherwise prompt -for a commit. If `magit-commit-squash-confirm' is non-nil, always make -the user explicitly select a commit, in a buffer dedicated to that task. - -During a later rebase, when this commit gets squashed into its targeted -commit, the original message of the targeted commit is used as-is. - -In other words, call \"git commit --fixup=COMMIT --no-edit\"." - (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 the user authoring a commit message. - -If there is a reachable commit at point, target that. Otherwise prompt -for a commit. If `magit-commit-squash-confirm' is non-nil, always make -the user explicitly select a commit, in a buffer dedicated to that task. - -During a later rebase, when this commit gets squashed into its targeted -commit, the user is given a chance to edit the original message to take -the changes from the squash commit into account. - -In other words, call \"git commit --squash=COMMIT --no-edit\"." - (interactive (list (magit-commit-at-point) - (magit-commit-arguments))) - (magit-commit-squash-internal "--squash=" commit args)) - -;;;###autoload -(defun magit-commit-alter (&optional commit args) - "Create a squash commit, authoring the final commit message now. - -If there is a reachable commit at point, target that. Otherwise prompt -for a commit. If `magit-commit-squash-confirm' is non-nil, always make -the user explicitly select a commit, in a buffer dedicated to that task. - -During a later rebase, when this commit gets squashed into its targeted -commit, the original message of the targeted commit is replaced with the -message of this commit, without the user automatically being given a -chance to edit again. - -In other words, call \"git commit --fixup=amend:COMMIT --edit\"." - (interactive (list (magit-commit-at-point) - (magit-commit-arguments))) - (magit-commit-squash-internal "--fixup=amend:" commit args nil 'edit)) - -;;;###autoload -(defun magit-commit-augment (&optional commit args) - "Create a squash commit, authoring a new temporary commit message. - -If there is a reachable commit at point, target that. Otherwise prompt -for a commit. If `magit-commit-squash-confirm' is non-nil, always make -the user explicitly select a commit, in a buffer dedicated to that task. - -During a later rebase, when this commit gets squashed into its targeted -commit, the user is asked to write a final commit message, in a buffer -that starts out containing both the original commit message, as well as -the temporary commit message of the squash commit. - -In other words, call \"git commit --squash=COMMIT --edit\"." - (interactive (list (magit-commit-at-point) - (magit-commit-arguments))) - (magit-commit-squash-internal "--squash=" commit args nil 'edit)) - -;;;###autoload -(defun magit-commit-revise (&optional commit args) - "Reword the message of an existing commit, without editing its tree. - -If there is a reachable commit at point, target that. Otherwise prompt -for a commit. If `magit-commit-squash-confirm' is non-nil, always make -the user explicitly select a commit, in a buffer dedicated to that task. - -During a later rebase, when this commit gets squashed into its targeted -commit, a combined commit is created which uses the message of the fixup -commit and the tree of the targeted commit. - -In other words, call \"git commit --fixup=reword:COMMIT --edit\"." - (interactive (list (magit-commit-at-point) - (magit-commit-arguments))) - (magit-commit-squash-internal "--fixup=reword:" commit args 'nopatch 'edit)) - -;;;; Edit and Rebase - -;;;###autoload -(defun magit-commit-instant-fixup (&optional commit args) - "Create a fixup commit, and immediately combine it with its target. - -If there is a reachable commit at point, target that. Otherwise prompt -for a commit. If `magit-commit-squash-confirm' is non-nil, always make -the user explicitly select a commit, in a buffer dedicated to that task. - -Leave the original commit message of the targeted commit untouched. - -Like `magit-commit-fixup' but also run a `--autofixup' rebase." - (interactive (list (magit-commit-at-point) - (magit-commit-arguments))) - (magit-commit-squash-internal "--fixup=" commit args nil nil 'rebase)) - -;;;###autoload -(defun magit-commit-instant-squash (&optional commit args) - "Create a squash commit, and immediately combine it with its target. - -If there is a reachable commit at point, target that. Otherwise prompt -for a commit. If `magit-commit-squash-confirm' is non-nil, always make -the user explicitly select a commit, in a buffer dedicated to that task. - -Turing the rebase phase, when the two commits are being squashed, ask -the user to author the final commit message, based on the original -message of the targeted commit. - -Like `magit-commit-squash' but also run a `--autofixup' rebase." - (interactive (list (magit-commit-at-point) - (magit-commit-arguments))) - (magit-commit-squash-internal "--squash=" commit args nil nil 'rebase)) - -;;;; Internal - -(defun magit-commit-squash-internal - (option commit &optional args nopatch edit rebase confirmed) - (when-let ((args (magit-commit-assert args nopatch (not edit)))) - (when (and commit 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) - (push (if edit "--edit" "--no-edit") args) - (if rebase - (magit-with-editor - (magit-call-git - "commit" "--no-gpg-sign" - (seq-remove (apply-partially #'string-prefix-p "--gpg-sign=") - args))) - (magit-run-git-with-editor "commit" args)) - t) ; The commit was created; used by below lambda. - (let ((winconf (and magit-commit-show-diff - (current-window-configuration)))) - (magit-log-select - (lambda (commit) - (when (and (magit-commit-squash-internal option commit args - nopatch edit rebase t) - rebase) - (magit-commit-amend-assert commit) - (magit-rebase-interactive-1 commit - (list "--autosquash" "--autostash" "--keep-empty") - "" "true" nil t)) - (when winconf - (set-window-configuration winconf))) - (format "Type %%p on a commit to %s into it," - (substring option 2)) - nil nil nil commit)) - (when (and magit-commit-show-diff (not nopatch)) - (let ((magit-display-buffer-noselect t)) - (apply #'magit-diff-staged nil (magit-diff-arguments))))))) - -(defun magit-commit-amend-assert (&optional commit) - (when-let ((branches (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 "%d public branches" m2) - nil branches)))) - -(defun magit-commit-assert (args &optional nopatch strict) - (cond - (nopatch (or args (list "--"))) - ((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) - ((file-exists-p (expand-file-name "MERGE_MSG" (magit-gitdir))) - (cond ((magit-anything-unmerged-p) - (user-error "Unresolved conflicts")) - ((and (magit-anything-unstaged-p) - (not (y-or-n-p - "Proceed with merge despite unstaged changes? "))) - (user-error "Abort")) - ((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) - (apply #'magit-diff-unstaged (magit-diff-arguments))) - (prog1 (when (or (eq magit-commit-ask-to-stage 'stage) - (y-or-n-p - "Nothing staged. Commit all uncommitted changes? ")) - (setq this-command 'magit-commit--all) - (cons "--all" (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")))) - -;;;; Reshelve - -(defvar magit--reshelve-history nil) - -;;;###autoload -(defun magit-commit-reshelve (date update-author &optional args) - "Change committer (and possibly author) date of the last commit. - -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 changed, 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)))) - (with-environment-variables (("GIT_COMMITTER_DATE" date)) - (magit-run-git "commit" "--amend" "--no-edit" - (and update-author (concat "--date=" date)) - args))) - -;;;; Spread - -;;;###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." - :value '("-v") - ["Arguments" - ("-f" "Skip safety checks" ("-f" "--force")) - ("-v" "Increase verbosity" ("-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 (magit-git-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" 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)))) - -(transient-augment-suffix magit-commit-absorb :transient 'transient--do-exit) - -;;;###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." - :value '("-vv") - ["Arguments" - (magit-autofixup:--context) - (magit-autofixup:--strict) - ("-v" "Increase verbosity" "-vv")] - ["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 (magit-git-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" 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-augment-suffix magit-commit-autofixup :transient 'transient--do-exit) - -(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) - -;;;; Hooks - -(defvar magit-post-commit-hook-commands - (list #'magit-commit-extend - #'magit-commit-fixup - #'magit-commit-augment - #'magit-commit-instant-fixup - #'magit-commit-instant-squash)) - -(defun magit-run-post-commit-hook () - (when (and (not this-command) - (memq last-command magit-post-commit-hook-commands)) - (run-hooks 'magit-post-commit-hook))) - -;;; Pending Diff - -(defun magit-commit-diff () - (magit-repository-local-set 'this-commit-command - (if (eq this-command 'with-editor-finish) - 'magit-commit--rebase - last-command)) - (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)) - (message "Diffing changes to be committed (C-g to abort diffing)") - (let ((inhibit-quit nil)) - (condition-case nil - (magit-commit-diff-1) - (quit))))) - -(defun magit-commit-diff-1 () - (let ((rev nil) - (arg "--cached") - (command (magit-repository-local-get 'this-commit-command)) - (staged (magit-anything-staged-p)) - (unstaged - ;; Escape $GIT_DIR because `magit-anything-unstaged-p' - ;; requires a working tree. - (magit-with-toplevel - (magit-anything-unstaged-p))) - (squash (let ((f (expand-file-name "rebase-merge/rewritten-pending" - (magit-gitdir)))) - (and (file-exists-p f) (length (magit-file-lines f))))) - (noalt nil)) - (pcase (list staged unstaged command) - ((and `(,_ ,_ magit-commit--rebase) - (guard (integerp squash))) - (setq rev (format "HEAD~%s" squash))) - (`(,_ ,_ magit-commit-amend) - (setq rev "HEAD^")) - (`(nil nil magit-commit--allow-empty) - (setq rev "HEAD") - (setq arg nil)) - ((or `(,_ ,_ magit-commit-reword) - `(nil nil ,_)) - (setq rev "HEAD^..HEAD") - (setq arg nil)) - (`(,_ t magit-commit--all) - (setq rev "HEAD") - (setq arg nil)) - (`(nil t handle-switch-frame) - ;; Either --all or --allow-empty. Assume it is the former. - (setq rev "HEAD") - (setq arg nil))) - (cond - ((not - (and (eq this-command 'magit-diff-while-committing) - (and-let* ((buf (magit-get-mode-buffer - 'magit-diff-mode nil 'selected))) - (and (equal rev (buffer-local-value 'magit-buffer-range buf)) - (equal arg (buffer-local-value 'magit-buffer-typearg buf))))))) - ((eq command 'magit-commit-amend) - (setq rev nil)) - ((or squash - (file-exists-p (expand-file-name "rebase-merge/amend" (magit-gitdir)))) - (setq rev "HEAD^")) - (t - (message "No alternative diff while committing") - (setq noalt t))) - (unless noalt - (let ((magit-inhibit-save-previous-winconf 'unset) - (magit-display-buffer-noselect t) - (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)))) - (magit-diff-setup-buffer rev arg (car (magit-diff-arguments)) nil - (cond ((equal rev "HEAD") 'staged) - ((equal rev "HEAD^..HEAD") 'committed) - ('undefined))))))) - -(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)) - -(defun magit-commit--reset-command () - (magit-repository-local-delete 'this-commit-command)) - -;;; Message Utilities - -(defun magit-commit-message-buffer () - (let* ((find-file-visit-truename t) ; git uses truename of COMMIT_EDITMSG - (topdir (magit-toplevel))) - (seq-find (##equal topdir (with-current-buffer % - (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-20250519.1537/magit-core.el b/elpa/magit-20250519.1537/magit-core.el deleted file mode 100644 index a7ff47e7..00000000 --- a/elpa/magit-20250519.1537/magit-core.el +++ /dev/null @@ -1,123 +0,0 @@ -;;; magit-core.el --- Core functionality -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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-base) -(require 'magit-git) -(require 'magit-mode) -(require 'magit-margin) -(require 'magit-process) -(require 'magit-transient) -(require 'magit-autorevert) - -;;; Options - -(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-20250519.1537/magit-diff.el b/elpa/magit-20250519.1537/magit-diff.el deleted file mode 100644 index 02cbbc71..00000000 --- a/elpa/magit-20250519.1537/magit-diff.el +++ /dev/null @@ -1,3576 +0,0 @@ -;;; magit-diff.el --- Inspect Git diffs -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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 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-diff-1 "magit-commit" ()) -(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 "ext:forge-pullreq" - (pullreq &optional endpoints)) -(declare-function forge--pullreq-ref "ext:forge-pullreq" (pullreq)) -;; For `magit-diff-wash-diff' -(declare-function ansi-color-apply-on-region "ansi-color") -;; For `magit-diff-wash-submodule' -(declare-function magit-log-wash-log "magit-log" (style args)) -;; For keymaps and menus -(declare-function magit-apply "magit-apply" (&rest args)) -(declare-function magit-stage "magit-apply" (&optional indent)) -(declare-function magit-unstage "magit-apply" ()) -(declare-function magit-discard "magit-apply" ()) -(declare-function magit-reverse "magit-apply" (&rest args)) -(declare-function magit-file-rename "magit-files" (file newname)) -(declare-function magit-file-untrack "magit-files" (files &optional force)) -(declare-function magit-commit-add-log "magit-commit" ()) -(declare-function magit-diff-trace-definition "magit-log" ()) -(declare-function magit-patch-save "magit-patch" (files &optional arg)) -(declare-function magit-do-async-shell-command "magit-dired" (file)) -(declare-function magit-add-change-log-entry "magit-extras" - (&optional whoami file-name other-window)) -(declare-function magit-add-change-log-entry-other-window "magit-extras" - (&optional whoami file-name)) -(declare-function magit-diff-edit-hunk-commit "magit-extras" (file)) -(declare-function magit-smerge-keep-current "magit-apply" ()) -(declare-function magit-smerge-keep-all "magit-apply" ()) -(declare-function magit-smerge-keep-upper "magit-apply" ()) -(declare-function magit-smerge-keep-base "magit-apply" ()) -(declare-function magit-smerge-keep-lower "magit-apply" ()) - -(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)) - -(define-obsolete-variable-alias 'magit-diff-section-base-map - 'magit-diff-section-map "Magit 4.0.0") - -(define-obsolete-variable-alias 'magit-wash-message-hook - 'magit-revision-wash-message-hook "Magit 4.3.0") - -(make-obsolete-variable 'magit-diff-highlight-keywords - 'magit-revision-wash-message-hook - "Magit 4.3.0") - -;;; 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 - (list #'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." - :package-version '(magit . "2.1.0") - :group 'magit-diff - :type 'boolean) - -(defcustom magit-diff-highlight-hunk-region-functions - (list #'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 wish 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 (list #'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 (##memq % '(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 (##memq % '(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 (##memq % '(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-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))) - -(defcustom magit-format-file-function #'magit-format-file-default - "Function used to format lines representing a file. - -This function is used for file headings in diffs, in diffstats and for -lists of files (such as the untracked files). Depending on the caller, -it receives either three or five arguments; the signature has to be -\(kind file face &optional status orig). KIND is one of `diff', -`module', `stat' and `list'." - :package-version '(magit . "4.3.1") - :group 'magit-diff - :type `(radio (function-item ,#'magit-format-file-default) - (function-item ,#'magit-format-file-all-the-icons) - (function-item ,#'magit-format-file-nerd-icons) - function)) - -;;;; 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 - (list #'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 - (list #'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-wash-message-hook - (list #'magit-highlight-squash-markers - #'magit-highlight-bracket-keywords) - "Functions used to highlight parts of a commit message. - -These functions are called in order, in a buffer narrowed to the commit -message. They should set text properties as they see fit, usually just -`font-lock-face'. Before each function is called, point is at the -beginning of the narrowed region of the buffer. - -See also the related `magit-log-wash-summary-hook'. You likely want to -use the same functions for both hooks." - :package-version '(magit . "4.3.0") - :group 'magit-log - :type 'hook - :options (list #'magit-highlight-squash-markers - #'magit-highlight-bracket-keywords)) - -(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. - -See user option `magit-revision-insert-related-refs-display-alist' -to hide specific sets of related branches." - :package-version '(magit . "2.1.0") - :group 'magit-revision - :type '(choice (const :tag "Do not" nil) - (const :tag "Local only" t) - (const :tag "All related" all) - (const :tag "All containing, local merged" mixed))) - -(defcustom magit-revision-insert-related-refs-display-alist nil - "How `magit-insert-revision-headers' displays related branch types. - -This is an alist, with recognised keys being the symbols -`parents', `merged', `contained', `follows', and `precedes'; -and the supported values for each key being: - -`nil' Hide these related branches. -`t' Show these related branches. - -Keys which are not present in the alist have an implicit value `t' -\(so the default alist value of `nil' means all related branch types -will be shown.) - -The types to be shown are additionally subject to user option -`magit-revision-insert-related-refs'." - :package-version '(magit . "3.3.1") - :group 'magit-revision - :type '(alist :key-type (symbol :tag "Type of related branch") - :value-type (boolean :tag "Display")) - :options (mapcar (lambda (sym) - `(,sym (choice (const :tag "Hide" nil) - (const :tag "Show" t)))) - '(parents merged contained follows precedes))) - -(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 regexps" - (choice (const :tag "No author image" nil) - (regexp :tag "Author regexp" "^Author: ")) - (choice (const :tag "No committer image" nil) - (regexp :tag "Committer regexp" "^Commit: "))))) - -(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 :extend t :weight bold)) - "Face for diff file headings." - :group 'magit-faces) - -(defface magit-diff-file-heading-highlight - '((t :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)) - :extend t - :inherit magit-diff-file-heading-highlight - :foreground "salmon4") - (((class color) (background dark)) - :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)) - :extend t - :background "grey90" - :foreground "grey20") - (((class color) (background dark)) - :extend t - :background "grey25" - :foreground "grey95")) - "Face for diff hunk headings." - :group 'magit-faces) - -(defface magit-diff-hunk-heading-highlight - '((((class color) (background light)) - :extend t - :background "grey80" - :foreground "grey20") - (((class color) (background dark)) - :extend t - :background "grey35" - :foreground "grey95")) - "Face for current diff hunk headings." - :group 'magit-faces) - -(defface magit-diff-hunk-heading-selection - '((((class color) (background light)) - :extend t - :inherit magit-diff-hunk-heading-highlight - :foreground "salmon4") - (((class color) (background dark)) - :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 - :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)) - :extend t - :inherit magit-diff-hunk-heading-highlight - :background "LightSalmon3") - (((class color) (background dark)) - :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 :extend t :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)) - :extend t - :background "#ddffdd" - :foreground "#22aa22") - (((class color) (background dark)) - :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)) - :extend t - :background "#ffdddd" - :foreground "#aa2222") - (((class color) (background dark)) - :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)) - :extend t - :background "#ffffcc" - :foreground "#aaaa11") - (((class color) (background dark)) - :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)) - :extend t - :foreground "grey50") - (((class color) (background dark)) - :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)) - :extend t - :background "#cceecc" - :foreground "#22aa22") - (((class color) (background dark)) - :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)) - :extend t - :background "#eecccc" - :foreground "#aa2222") - (((class color) (background dark)) - :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)) - :extend t - :background "#eeeebb" - :foreground "#aaaa11") - (((class color) (background dark)) - :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)) - :extend t - :background "grey95" - :foreground "grey50") - (((class color) (background dark)) - :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))) - (when-let (((not (eq transient-current-command 'magit-dispatch))) - (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)) - (magit--transient-args-and-files) - (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)) - ((when-let (((memq use-buffer-args '(always selected))) - (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 ,files) (magit--transient-args-and-files))) - (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))) - -;;; Commands -;;;; Prefix Commands - -(transient-define-group magit-diff-infix-arguments - ["Limit arguments" - (magit:--) - (magit-diff:--ignore-submodules) - ("-b" "Ignore whitespace changes" ("-b" "--ignore-space-change")) - ("-w" "Ignore all whitespace" ("-w" "--ignore-all-space")) - ("-D" "Omit preimage for deletes" ("-D" "--irreversible-delete") - :level 5)] - ["Context arguments" - (magit-diff:-U) - ("-W" "Show surrounding functions" ("-W" "--function-context"))] - ["Tune arguments" - (magit-diff:--diff-algorithm) - (magit-diff:--diff-merges) - (magit-diff:-M) - (magit-diff:-C) - (magit-diff:-R :level 5) - (magit-diff:--color-moved :level 5) - (magit-diff:--color-moved-ws :level 5) - (magit-diff:--no-ext-diff) - (magit-diff:--stat) - (magit-diff:--show-signature)]) - -;;;###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 - 'magit-diff-infix-arguments - ["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 - 'magit-diff-infix-arguments - [["Refresh" - ("g" "buffer" magit-diff-refresh) - ("s" "buffer and set defaults" transient-set-and-exit) - ("w" "buffer and save defaults" transient-save-and-exit)] - ["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) - (when (derived-mode-p 'magit-merge-preview-mode) - (user-error "Cannot use %s in %s" this-command major-mode)) - (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 &optional list-fn) - (magit-with-toplevel - (magit-completing-read-multiple prompt - (funcall (or list-fn #'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 - :always-read t) - -(defun magit-diff-select-algorithm (&rest _ignore) - (magit-read-char-case nil t - (?u "[u]nspecified" nil) - (?d "[d]efault" "default") - (?m "[m]inimal" "minimal") - (?p "[p]atience" "patience") - (?h "[h]istogram" "histogram"))) - -(transient-define-argument magit-diff:--diff-merges () - :description "Diff merges" - :class 'transient-option - :key "-X" - :argument "--diff-merges=" - :reader #'magit-diff-select-merges - :always-read t) - -(defun magit-diff-select-merges (&rest _ignore) - (magit-read-char-case nil t - (?u "[u]nspecified" nil) - (?o "[o]ff" "off") - (?f "[f]irst-parent" "first-parent") - (?c "[c]ombined" "combined") - (?d "[d]ense-combined" "dense-combined"))) - -(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"))) - -(transient-define-argument magit-diff:-R () - :description "Reverse sides" - :class 'transient-switch - :argument "-R" - :if 'magit-diff-argument-predicate) - -(transient-define-argument magit-diff:--no-ext-diff () - :description "Disallow external diff drivers" - :class 'transient-switch - :argument "--no-ext-diff" - :key "-x") - -(transient-define-argument magit-diff:--stat () - :description "Show stats" - :class 'transient-switch - :argument "--stat" - :key "-s" - :if 'magit-diff-argument-predicate) - -(transient-define-argument magit-diff:--show-signature () - :description "Show signature" - :class 'transient-switch - :argument "--show-signature" - :key "=g" - :if 'magit-diff-argument-predicate) - -(defun magit-diff-argument-predicate () - (or (eq (oref transient--prefix command) 'magit-diff) - (derived-mode-p 'magit-diff-mode))) - -;;;; Setup Commands - -;;;###autoload -(defun magit-diff-dwim (&optional args files) - "Show changes for the thing at point. - -For example, if point is on a commit, show the changes introduced by -that commit. Likewise if point is on the section titled \"Unstaged -changes\", then show those changes in a separate buffer. Generally -speaking, compare the thing at point with the most logical, trivial -and (in *any* situation) at least potentially useful other thing it -could be compared to. - -When the region selects commits, then compare the two commits at -either end. There are different ways two commits can be compared. -In the buffer showing the diff, you can control how the comparison, -is done, using \"D r\" and \"D f\". - -This function does not always show the changes that you might want -to view in any given situation. You can think of the changes being -shown as the smallest common denominator. There is no AI involved. -If this command never does what you want, then ignore it, and instead -use the commands that allow you to explicitly specify what you need." - (interactive (magit-diff-arguments)) - (let ((default-directory default-directory) - (section (magit-current-section))) - (cond - ((magit-section-match 'module section) - (setq default-directory - (expand-file-name - (file-name-as-directory (oref section value)))) - (magit-diff-range (oref section range))) - (t - (when (magit-section-match 'module-commit section) - (setq args nil) - (setq files nil) - (setq default-directory - (expand-file-name - (file-name-as-directory (magit-section-parent-value section))))) - (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)))) - (`(stash . ,value) (magit-stash-show value args)) - (`(commit . ,value) - (magit-diff-range (format "%s^..%s" value value) args files)) - ((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 - ((and-let* ((commits (magit-region-values '(commit branch) t))) - (progn - (deactivate-mark) - (concat (car (last commits)) ".." (car commits))))) - (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 ((upstream (magit-get-upstream-branch))) - (format "%s...%s" upstream 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--region-range (&optional interactive mbase) - (and-let* ((commits (magit-region-values '(commit branch) t)) - (revA (car (last commits))) - (revB (car commits))) - (progn - (when interactive - (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)) - (interactive - (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))) - (t "%s...%s" revA revB))) - (format "%s..%s" revA revB))))) - -(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." - (or (magit-diff--region-range t mbase) - (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 'committed)) - -;;;###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 'committed)) - -;;;###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 'staged)) - -;;;###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 'unstaged)) - -;;;###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 'committed)) - -;;;###autoload -(defun 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." - (interactive) - (unless (magit-commit-message-buffer) - (user-error "No commit in progress")) - (magit-commit-diff-1)) - -;;;###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 differences 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) - 'unstaged - 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))) - 'undefined)) - -(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 - (magit-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)) - (ln (and file (line-number-at-pos)))) - (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)) - (when file - (save-buffer)) - (let ((buf (magit-revision-setup-buffer rev args files))) - (when file - (let ((line (magit-diff-visit--offset file (list "-R" rev) ln)) - (col (current-column))) - (with-current-buffer buf - (magit-diff--goto-position file line col)))))))) - -(defun magit-diff--locate-hunk (file line &optional parent) - (and-let* ((diff (cl-find-if (##and (cl-typep % 'magit-file-section) - (equal (oref % value) file)) - (oref (or parent magit-root-section) children)))) - (let ((hunks (oref diff children))) - (cl-block nil - (while-let ((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)))) - 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 (##max 0 (- (or % 0) count)))) - -(defun magit-diff-more-context (&optional count) - "Increase the context for diff hunks by COUNT lines." - (interactive "p") - (magit-diff-set-context (##+ (or % 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) - (when (derived-mode-p 'magit-merge-preview-mode) - (user-error "Cannot use %s in %s" this-command major-mode)) - (let* ((def (if-let ((context (magit-get "diff.context"))) - (string-to-number context) - 3)) - (val magit-buffer-diff-args) - (arg (seq-find (##string-match "^-U\\([0-9]+\\)?$" %) val)) - (num (if-let ((str (and arg (match-string 1 arg)))) - (string-to-number str) - def)) - (val (delete arg val)) - (num (funcall fn num)) - (arg (and num (not (= num def)) (format "-U%d" num))) - (val (if arg (cons arg val) val))) - (setq magit-buffer-diff-args val)) - (magit-refresh)) - -(defun magit-diff-context-p () - (if-let ((arg (seq-find (##string-match "^-U\\([0-9]+\\)$" %) - magit-buffer-diff-args))) - (not (equal arg "-U0")) - t)) - -(defun magit-diff-ignore-any-space-p () - (seq-some (##member % 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. - -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-diff--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-diff--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-diff--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 (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-diff--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 - (equal magit-buffer-typearg "--no-index") - (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--file-at-point (&optional expand assert) - ;; This is a variation of magit-file-at-point. - (if-let* ((file-section (magit-section-case - (file it) - (hunk (oref it parent)))) - (file (or (and (magit-section-match 'hunk) - (magit-diff-visit--goto-from-p - (magit-current-section) nil) - (oref file-section source)) - (oref file-section value)))) - (cond ((equal magit-buffer-typearg "--no-index") - (concat "/" file)) - (expand (expand-file-name file (magit-toplevel))) - (file)) - (when assert - (user-error "No file at point")))) - -(defun magit-diff-visit--hunk () - (and-let* ((scope (magit-diff-scope)) - (section (magit-current-section))) - (progn - (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. - (not (equal (oref section value) '(chmod))) - 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 (< (magit-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 (or from-range to-range) - (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-search - (if goto-from "+" "-") - (buffer-substring (point) (+ (point) prefix))) - (cl-incf offset)) - (forward-line)) - offset)))))) - -(defun magit-diff-hunk-column (section goto-from) - (if (or (< (magit-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))) - -;;;;; Movement - -(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 ((section (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 section) - (user-error "No diffstat in this buffer"))) - -;;;; 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 - ((and (bound-and-true-p magit-blame-mode) - (fboundp 'magit-current-blame-chunk)) - (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))) - (tag - (setq rev (magit-rev-hash (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) - (mapcan (lambda (section) - (and section - (progn - (when (oref section hidden) - (magit-section-show section)) - (oref section children)))) - (list (magit-get-section '((staged) (status))) - (magit-get-section '((unstaged) (status)))))) - ((derived-mode-p 'magit-diff-mode) - (seq-filter #'magit-file-section-p - (oref magit-root-section children)))))) - (if (seq-some (##oref % hidden) sections) - (dolist (s sections) - (magit-section-show s) - (magit-section-hide-children s)) - (let ((children (mapcan (##copy-sequence (oref % children)) sections))) - (cond ((and (seq-some (##oref % hidden) children) - (seq-some (##oref % 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-keymap magit-diff-mode-map - :doc "Keymap for `magit-diff-mode'." - :parent magit-mode-map - "C-c C-d" #'magit-diff-while-committing - "C-c C-b" #'magit-go-backward - "C-c C-f" #'magit-go-forward - "SPC" #'scroll-up - "DEL" #'scroll-down - "j" #'magit-jump-to-diffstat-or-diff - " " #'magit-patch-save) - -(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}" - :interactive nil - :group 'magit-diff - (magit-hack-dir-local-variables) - (setq magit--imenu-item-types 'file)) - -(put 'magit-diff-mode 'magit-diff-default-arguments - '("--stat" "--no-ext-diff")) - -(defun magit-diff-setup-buffer ( range typearg args files - &optional type locked) - (require 'magit) - (magit-setup-buffer #'magit-diff-mode locked - (magit-buffer-range range) - (magit-buffer-typearg typearg) - (magit-buffer-diff-type type) - (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 - (if (string-match-p "\\(\\.\\.\\|\\^-\\)" - magit-buffer-range) - (format "Changes in %s" magit-buffer-range) - (let ((msg "Changes from %s to %s") - (end (if (equal magit-buffer-typearg "--cached") - "index" - "working tree"))) - (if (member "-R" magit-buffer-diff-args) - (format msg end magit-buffer-range) - (format msg magit-buffer-range end)))) - (cond ((equal magit-buffer-typearg "--cached") - "Staged changes") - ((and (magit-repository-local-get 'this-commit-command) - (not (magit-anything-staged-p))) - "Uncommitting changes") - (t "Unstaged changes"))) - (pcase (length magit-buffer-diff-files) - (0) - (1 (concat " in file " (car magit-buffer-diff-files))) - (_ (concat " in files " - (string-join 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)))) - -(cl-defmethod magit-menu-common-value ((_section magit-diff-section)) - (magit-diff-scope)) - -(defvar-keymap magit-diff-section-map - :doc "Keymap for diff sections. -The classes `magit-file-section' and `magit-hunk-section' derive -from the abstract `magit-diff-section' class. Accordingly this -keymap is the parent of their keymaps." - "C-j" #'magit-diff-visit-worktree-file - "C-" #'magit-diff-visit-worktree-file - "C-x 4 " #'magit-diff-visit-file-other-window - "C-x 5 " #'magit-diff-visit-file-other-frame - "&" #'magit-do-async-shell-command - "C" #'magit-commit-add-log - "C-x a" #'magit-add-change-log-entry - "C-x 4 a" #'magit-add-change-log-entry-other-window - "C-c C-t" #'magit-diff-trace-definition - "C-c C-e" #'magit-diff-edit-hunk-commit - " " #'magit-file-rename - " " #'magit-file-untrack - " " #'magit-diff-visit-file - " " #'magit-reverse - " " #'magit-discard - " " #'magit-unstage - " " #'magit-stage - " " #'magit-apply - "<8>" (magit-menu-item "Rename file" #'magit-file-rename - '(:enable (eq (magit-diff-scope) 'file))) - "<7>" (magit-menu-item "Untrack %x" #'magit-file-untrack) - "<6>" (magit-menu-item "Visit file" #'magit-diff-visit-file - '(:enable (memq (magit-diff-scope) '(file files)))) - "<5>" (magit-menu-item "Reverse %x" #'magit-reverse - '(:enable (not (memq (magit-diff-type) - '(untracked unstaged))))) - "<4>" (magit-menu-item "Discard %x" #'magit-discard - '(:enable (not (memq (magit-diff-type) - '(committed undefined))))) - "<3>" (magit-menu-item "Unstage %x" #'magit-unstage - '(:enable (eq (magit-diff-type) 'staged))) - "<2>" (magit-menu-item "Stage %x" #'magit-stage - '(:enable (eq (magit-diff-type) 'unstaged))) - "<1>" (magit-menu-item "Apply %x" #'magit-apply - '(:enable (not (memq (magit-diff-type) - '(unstaged staged)))))) - -(defvar-keymap magit-file-section-map - ;; Even though this derived map doesn't add any bindings by default, - ;; it is quite possible that some users would want to add their own. - :doc "Keymap for `file' sections." - :parent magit-diff-section-base-map) - -(defvar-keymap magit-hunk-section-smerge-map - :doc "Keymap bound to `smerge-command-prefix' in `magit-hunk-section-map'." - "RET" #'magit-smerge-keep-current - "a" #'magit-smerge-keep-all - "u" #'magit-smerge-keep-upper - "b" #'magit-smerge-keep-base - "l" #'magit-smerge-keep-lower) - -(defvar magit-hunk-section-map - (let ((map (make-sparse-keymap)) - (key (key-description smerge-command-prefix))) - (when (key-valid-p key) - (keymap-set map key magit-hunk-section-smerge-map)) - (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 t - "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 (keep-error &rest args) - (declare (indent 1)) - (pcase-let ((`(,cmd . ,args) - (flatten-tree args)) - (magit-git-global-arguments - (remove "--literal-pathspecs" magit-git-global-arguments))) - ;; We need to generate diffs with --ita-visible-in-index so that - ;; `magit-stage' can work with intent-to-add files (see #4026). - (unless (equal cmd "merge-tree") - (push "--ita-visible-in-index" args)) - (setq args (magit-diff--maybe-add-stat-arguments args)) - (when (cl-member-if (##string-prefix-p "--color-moved" %) 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 - (if (member "--no-index" args) - 'wash-anyway - (or keep-error t)) - 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'." - (and-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 magit-buffer-revision-hash)) - (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 (##magit-diff-wash-diff args)) - (insert ?\n))) - -(defun magit-diff-wash-signature (object) - (cond - ((looking-at "^No signature") - (delete-line)) - ((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 object title) - (when title - (magit-insert-heading title)) - (goto-char end) - (set-marker end nil) - (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) - (magit-insert-heading - (propertize heading 'font-lock-face 'magit-diff-file-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) - (replace-match (match-string 1 f) nil t 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 (magit-format-file 'stat file 'magit-filename)) - (insert 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 (##string-prefix-p "--color-moved" %) 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 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) - (binary 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") - (setq binary t)) - ((looking-at "Binary files differ\n") - (setq binary t)) - ;; TODO Use all combined diff extended headers. - ((looking-at "mode .+\n")) - ((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)) - (when orig - (setq orig (magit-decode-git-path orig))) - (setq file (magit-decode-git-path file)) - (setq header (nreverse header)) - ;; KLUDGE `git-log' ignores `--no-prefix' when `-L' is used. - (when (and (derived-mode-p 'magit-log-mode) - (seq-some (##string-prefix-p "-L" %) - magit-buffer-log-args)) - (when orig - (setq orig (substring orig 2))) - (setq file (substring file 2)) - (setq header (list (save-excursion - (string-match "diff [^ ]+" (car header)) - (format "%s %s %s\n" - (match-string 0 (car header)) - (or orig file) - (or file orig))) - (format "--- %s\n" (or orig "/dev/null")) - (format "+++ %s\n" (or file "/dev/null"))))) - (setq header (string-join header)) - (magit-diff-insert-file-section - file orig status modes rename header binary nil))))) - -(defun magit-diff-insert-file-section - (file orig status modes rename header binary long-status) - (magit-insert-section - ( file file - (or (equal status "deleted") (derived-mode-p 'magit-status-mode)) - :source (and (not (equal orig file)) orig) - :header header - :binary binary) - (magit-insert-heading - (magit-format-file 'diff file 'magit-diff-file-heading status - (and (not (equal orig file)) orig)) - (cond ((and binary long-status) - (format " (%s, binary)" long-status)) - ((or binary long-status) - (format " (%s)" (if binary "binary" long-status))))) - (when modes - (magit-insert-section (hunk '(chmod)) - (magit-insert-heading (propertize modes 'face 'default)))) - (when rename - (magit-insert-section (hunk '(rename)) - (magit-insert-heading (propertize rename 'face 'default)))) - (magit-wash-sequence #'magit-diff-wash-hunk))) - -(defun magit-format-file (kind file face &optional status orig) - (funcall magit-format-file-function kind file face status orig)) - -(defun magit-format-file-default (_kind file face &optional status orig) - "Show only the Git status and the filename." - (propertize (concat (and status (format "%-11s" status)) - (if orig (format "%s -> %s" orig file) file)) - 'font-lock-face face)) - -(defun magit-format-file-all-the-icons (kind file face &optional status orig) - "Show the status, filename and icon (using the `all-the-icons' package). -You have to explicitly install the `all-the-icons' package, else this -function errors." - (cl-flet ((icon (if (or (eq kind 'module) (string-suffix-p "/" file)) - 'all-the-icons-icon-for-dir - 'all-the-icons-icon-for-file))) - (cl-letf (((symbol-function 'all-the-icons-dir-is-submodule) - (if (eq kind 'module) - (lambda (_) t) - (symbol-function 'all-the-icons-dir-is-submodule)))) - (propertize (concat (and status (format "%-11s" status)) - (if orig - (format "%s %s -> %s %s" - (icon orig) orig - (icon file) file) - (format "%s %s" (icon file) file))) - 'font-lock-face face)))) - -(defun magit-format-file-nerd-icons (kind file face &optional status orig) - "Show the status, filename and icon (using the `nerd-icons' package). -You have to explicitly install the `nerd-icons' package, else this -function errors." - (cl-flet ((icon (if (or (eq kind 'module) (string-suffix-p "/" file)) - 'nerd-icons-icon-for-dir - 'nerd-icons-icon-for-file))) - (cl-letf (((symbol-function 'nerd-icons-dir-is-submodule) - (if (eq kind 'module) - (lambda (_) t) - (symbol-function 'nerd-icons-dir-is-submodule)))) - (propertize (concat (and status (format "%-11s" status)) - (if orig - (format "%s %s -> %s %s" - (icon orig) orig - (icon file) file) - (format "%s %s" (icon file) file))) - 'font-lock-face face)))) - -(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 (module module t) - (magit-insert-heading - (magit-format-file 'module module 'magit-diff-file-heading - "modified") - " (" - (cond (rewind "rewind") - ((string-search "..." range) "non-ff") - (t "new commits")) - (and (or modified untracked) - (concat ", " - (and modified "modified") - (and modified untracked " and ") - (and untracked "untracked") - " content")) - ")") - (magit-insert-section-body - (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 (module module) - (magit-insert-heading - (magit-format-file 'module module 'magit-diff-file-heading - "submodule") - " (" msg ")")))) - (t - (magit-insert-section (module module) - (magit-insert-heading - (magit-format-file 'module module 'magit-diff-file-heading - "modified") - " (" - (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) - (let ((range - (mapcar #'string-to-number - (split-string (substring str 1) ",")))) - ;; A single line is +1 rather than +1,1. - (if (length= range 1) - (nconc range (list 1)) - range))) - (split-string (match-string 1)))) - (about (match-string 2)) - (combined (length= ranges 3)) - (value (cons about ranges))) - (magit-delete-line) - (magit-insert-section - ( hunk value nil - :combined combined - :from-range (if combined (butlast ranges) (car ranges)) - :to-range (car (last ranges)) - :about about) - (magit-insert-heading - (propertize (concat heading "\n") - 'font-lock-face 'magit-diff-hunk-heading)) - (while (not (or (eobp) (looking-at "^[^-+\s\\]"))) - (forward-line)))) - 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-since 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}" - :interactive nil - :group 'magit-revision - (magit-hack-dir-local-variables)) - -(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-type 'committed) - (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-hash 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 " - (string-join 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 t - "show" "-p" "--format=" "--no-prefix" - (and (member "--stat" magit-buffer-diff-args) "--numstat") - magit-buffer-diff-args - (magit--rev-dereference magit-buffer-revision) - "--" 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) - (magit-insert-heading - (propertize heading 'font-lock-face - 'magit-section-secondary-heading))) - (forward-line) - (magit-insert-section - ( message nil nil - :heading-highlight-face 'magit-diff-revision-summary-highlight) - (let ((beg (point))) - (forward-line) - (magit--add-face-text-property - beg (point) 'magit-diff-revision-summary)) - (magit-insert-heading) - (if (re-search-forward "-----BEGIN PGP SIGNATURE-----" nil t) - (goto-char (match-beginning 0)) - (goto-char (point-max))) - (insert ?\n)) - (if (re-search-forward "-----BEGIN PGP SIGNATURE-----" nil t) - (progn - (let ((beg (match-beginning 0))) - (re-search-forward "-----END PGP SIGNATURE-----\n") - (delete-region beg (point))) - (save-excursion - (magit-process-git t "verify-tag" magit-buffer-revision)) - (magit-diff-wash-signature magit-buffer-revision)) - (goto-char (point-max))) - (insert ?\n)))) - -(defvar-keymap magit-commit-message-section-map - :doc "Keymap for `commit-message' sections." - " " #'magit-show-commit - "<1>" (magit-menu-item "Visit %t" #'magit-show-commit - '(:enable (magit-thing-at-point 'git-revision t)))) - -(defun magit-insert-revision-message () - "Insert the commit message into a revision buffer." - (magit-insert-section - ( commit-message nil nil - :heading-highlight-face 'magit-diff-revision-summary-highlight) - (if-let* ((rev magit-buffer-revision) - (msg (with-temp-buffer - (save-excursion (magit-rev-insert-format "%B" rev)) - (magit-revision--wash-message)))) - (progn - (save-excursion (insert msg)) - (magit-revision--wash-message-hashes) - (save-excursion - (magit--add-face-text-property (point) - (progn (forward-line) (point)) - 'magit-diff-revision-summary - t nil t) - (magit-insert-heading)) - (goto-char (point-max))) - (insert "(no message)\n")))) - -(defun magit-insert-revision-notes () - "Insert commit notes into a revision buffer." - (let ((default (or (magit-get "core.notesRef") "refs/notes/commits"))) - (dolist (ref (magit-list-active-notes-refs)) - (when-let* ((rev magit-buffer-revision) - (msg (with-temp-buffer - (save-excursion - (magit-git-insert "-c" (concat "core.notesRef=" ref) - "notes" "show" rev)) - (magit-revision--wash-message)))) - (magit-insert-section - ( notes ref (not (equal ref default)) - :heading-highlight-face 'magit-diff-hunk-heading-highlight) - (save-excursion (insert msg)) - (magit-revision--wash-message-hashes) - (save-excursion - (end-of-line) - (insert (format " (%s)" - (propertize (if (string-prefix-p "refs/notes/" ref) - (substring ref 11) - ref) - 'font-lock-face 'magit-refname)))) - (magit--add-face-text-property (point) - (progn (forward-line) (point)) - 'magit-diff-revision-summary - t nil t) - (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)) - (when (> (point-max) (point-min)) - (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 (get-buffer-window nil t))))) - (fill-region (point) (line-end-position)))) - (run-hook-wrapped 'magit-revision-wash-message-hook - (lambda (fn) (prog1 nil (save-excursion (funcall fn))))) - (buffer-string))) - -(defun magit-highlight-squash-markers () - "Highlight \"squash!\" and similar markers." - (when (looking-at "\\(?:squash!\\|fixup!\\|amend!\\)") - (magit--add-face-text-property (match-beginning 0) (match-end 0) - 'magit-keyword-squash))) - -(defun magit-highlight-bracket-keywords () - "Highlight text between brackets." - (while (re-search-forward "\\[[^][]*]" nil t) - (put-text-property (match-beginning 0) - (match-end 0) - 'font-lock-face 'magit-keyword))) - -(defun magit-revision--wash-message-hashes () - (when magit-revision-use-hash-sections - (save-excursion - ;; Start after beg to prevent a (commit text) section from - ;; starting at the same point as the (commit-message) - ;; section. - (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))))))))))) - -(defun magit-insert-revision-headers () - "Insert headers about the commit into a revision buffer." - (magit-insert-section (headers) - (magit-insert-heading nil - (and-let* ((string (magit-rev-format "%D" magit-buffer-revision - "--decorate=full"))) - (concat (magit-format-ref-labels string) " ")) - (propertize - (magit-rev-parse (magit--rev-dereference magit-buffer-revision)) - 'font-lock-face 'magit-hash)) - (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 - (when (magit-revision-insert-related-refs-display-p 'parents) - (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")))))) - (when (magit-revision-insert-related-refs-display-p 'merged) - (magit--insert-related-refs - magit-buffer-revision "--merged" "Merged" - (eq magit-revision-insert-related-refs 'all))) - (when (magit-revision-insert-related-refs-display-p 'contained) - (magit--insert-related-refs - magit-buffer-revision "--contains" "Contained" - (memq magit-revision-insert-related-refs '(all mixed)))) - (when-let (((magit-revision-insert-related-refs-display-p 'follows)) - (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 (((magit-revision-insert-related-refs-display-p 'precedes)) - (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-revision-insert-related-refs-display-p (sym) - "Whether to display related branches of type SYM. -Refer to user option `magit-revision-insert-related-refs-display-alist'." - (if-let ((elt (assq sym magit-revision-insert-related-refs-display-alist))) - (cdr elt) - t)) - -(defun magit--insert-related-refs (rev arg title remote) - (when-let ((refs (magit-list-related-branches arg rev (and remote "-a")))) - (magit-insert-section (related-refs) - (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))) - (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 ((email (and author (magit-rev-format "%aE" rev)))) - (magit-insert-revision-gravatar beg rev email author)) - (when-let ((email (and committer (magit-rev-format "%cE" rev)))) - (magit-insert-revision-gravatar beg rev email committer))))) - -(defun magit-insert-revision-gravatar (beg rev email regexp) - (save-excursion - (goto-char beg) - (when-let (((re-search-forward regexp nil t)) - (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))) - (setf (image-property image :ascent) 'center) - (setf (image-property image :relief) 1) - (setf (image-property image :scale) 1) - (setf (image-property 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)))) - (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." - :interactive nil - :group 'magit-diff - (magit-hack-dir-local-variables)) - -(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 t - "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) - -;;; Hunk Section - -(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) - -(cl-defmethod magit-section-get-relative-position ((_section magit-hunk-section)) - (nconc (cl-call-next-method) - (and (region-active-p) - (progn - (goto-char (line-beginning-position)) - (when (looking-at "^[-+]") (forward-line)) - (while (looking-at "^[ @]") (forward-line)) - (let ((beg (magit-point))) - (list (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)))))))) - -(cl-defmethod magit-section-goto-successor ((section magit-hunk-section) - line char &optional arg) - (or (magit-section-goto-successor--same section line char) - (and-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 ((sibling (or previous (car (last children))))) - (magit-section-goto sibling) - 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))))) - (magit-section-goto-successor--related section))) - -;;; Diff Sections - -(defvar-keymap magit-unstaged-section-map - :doc "Keymap for the `unstaged' section." - " " #'magit-diff-unstaged - " " #'magit-stage - " " #'magit-discard - "<3>" (magit-menu-item "Discard all" #'magit-discard) - "<2>" (magit-menu-item "Stage all" #'magit-stage) - "<1>" (magit-menu-item "Visit diff" #'magit-diff-unstaged)) - -(magit-define-section-jumper magit-jump-to-unstaged - "Unstaged changes" unstaged nil magit-insert-unstaged-changes) - -(defun magit-insert-unstaged-changes () - "Insert section showing unstaged changes." - (magit-insert-section (unstaged) - (magit-insert-heading t "Unstaged changes") - (magit--insert-diff nil - "diff" magit-buffer-diff-args "--no-prefix" - "--" magit-buffer-diff-files))) - -(defvar-keymap magit-staged-section-map - :doc "Keymap for the `staged' section." - " " #'magit-reverse - " " #'magit-discard - " " #'magit-unstage - " " #'magit-diff-staged - "<4>" (magit-menu-item "Reverse all" #'magit-reverse) - "<3>" (magit-menu-item "Discard all" #'magit-discard) - "<2>" (magit-menu-item "Unstage all" #'magit-unstage) - "<1>" (magit-menu-item "Visit diff" #'magit-diff-staged)) - -(magit-define-section-jumper magit-jump-to-staged - "Staged changes" staged nil magit-insert-staged-changes) - -(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 t "Staged changes") - (magit--insert-diff nil - "diff" "--cached" magit-buffer-diff-args "--no-prefix" - "--" magit-buffer-diff-files)))) - -;;; Diff Type - -(defvar magit--diff-use-recorded-type-p t) - -(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 ((section (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 ((and magit--diff-use-recorded-type-p - magit-buffer-diff-type)) - ((equal const "--no-index") 'undefined) - ((or (not range) - (equal range "HEAD") - (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 section type))) - (if (memq stype '(staged unstaged tracked untracked)) - stype - (pcase stype - ((or 'file 'module) - (let* ((parent (oref section parent)) - (type (oref parent type))) - (if (memq type '(file module)) - (magit-diff-type parent) - type))) - ('hunk (thread-first section - (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 (and-let* ((parent (oref section parent))) - (oref parent 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)))))) - -;;; Hunk Paint - -(cl-defmethod magit-section-paint ((section magit-hunk-section) highlight) - (unless magit-diff-highlight-hunk-body - (setq highlight nil)) - (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) - (oset section painted (if highlight 'highlight 'plain))) - -(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) - ((and-let* ((buffer (find-buffer-visiting file))) - (cache (buffer-local-value 'tab-width buffer)))) - ((and-let* ((elt (assoc file magit-diff--tab-width-cache))) - (or (cdr elt) - 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 (seq-find (##string-match-p (car %) 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 () - (magit--bol-position (region-beginning))) - -(defun magit-diff-hunk-region-end () - (magit--eol-position (region-end))) - -(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 `(: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)) - -;;; 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) - (and-let* ((content (oref (magit-current-section) content))) - (> (magit-point) content)))) - -(defun magit-diff--combined-p (section) - (cl-assert (cl-typep section 'magit-file-section)) - (string-match-p "\\`diff --\\(combined\\|cc\\)" (oref section value))) - -;;; 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 (string-join (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-20250519.1537/magit-dired.el b/elpa/magit-20250519.1537/magit-dired.el deleted file mode 100644 index 5e361ac9..00000000 --- a/elpa/magit-20250519.1537/magit-dired.el +++ /dev/null @@ -1,109 +0,0 @@ -;;; magit-dired.el --- Dired support for Magit -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; Commentary: - -;; Dired support for Magit. - -;;; Code: - -(require 'magit) - -;; For `magit-do-async-shell-command'. -(declare-function dired-read-shell-command "dired-aux" (prompt arg files)) - -;;; Open Dired from Magit - -;;;###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 - (and-let* ((file (magit-file-at-point))) - (expand-file-name (if (file-directory-p file) - (file-name-as-directory file) - file))))) - -;;; Commands for Dired Buffers - -;;;###autoload -(defun magit-dired-stage () - "In Dired, staged all marked files or the file at point." - (interactive) - (magit-stage-files (dired-get-marked-files))) - -;;;###autoload -(defun magit-dired-unstage () - "In Dired, unstaged all marked files or the file at point." - (interactive) - (magit-unstage-files (dired-get-marked-files))) - -;;;###autoload -(defun magit-dired-log (&optional follow) - "In Dired, show log for all marked files or the directory if none are marked." - (interactive "P") - (if-let ((topdir (magit-toplevel default-directory))) - (let ((args (car (magit-log-arguments))) - (files (or (dired-get-marked-files nil 'marked) - (list default-directory)))) - (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)) - (let ((files (dired-get-marked-files nil arg nil nil t))) - (magit-status-setup-buffer repo) - (magit-am-apply-patches files))) - -;;; Miscellaneous Commands - -;;;###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) - (magit-read-file "Act on file")))) - (require 'dired-aux) - (dired-do-async-shell-command - (dired-read-shell-command "& on %s: " current-prefix-arg (list file)) - nil (list file))) - -;;; _ -(provide 'magit-dired) -;;; magit-dired.el ends here diff --git a/elpa/magit-20250519.1537/magit-ediff.el b/elpa/magit-20250519.1537/magit-ediff.el deleted file mode 100644 index 16e38b78..00000000 --- a/elpa/magit-20250519.1537/magit-ediff.el +++ /dev/null @@ -1,605 +0,0 @@ -;;; magit-ediff.el --- Ediff extension for Magit -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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 - (list #'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 (list #'magit-ediff-cleanup-auxiliary-buffers - #'magit-ediff-restore-previous-winconf)) - -(defcustom magit-ediff-dwim-resolve-function #'magit-ediff-resolve-rest - "The function `magit-ediff-dwim' uses to resolve conflicts." - :package-version '(magit . "4.0.0") - :group 'magit-ediff - :type '(choice (const magit-ediff-resolve-rest) - (const magit-ediff-resolve-all) - (const magit-git-mergetool))) - -(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) - -(defvar magit-ediff-use-indirect-buffers nil - "Whether to use indirect buffers. -Ediff already does a lot of buffer and file shuffling and I -recommend you do not further complicate that by enabling this.") - -;;; 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 rest" magit-ediff-resolve-rest) - ("M" "Resolve all conflicts" magit-ediff-resolve-all) - ("t" "Resolve using mergetool" magit-git-mergetool)] - [("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)]]) - -(defmacro magit-ediff-buffers (a b &optional c setup quit file) - "Run Ediff on two or three buffers. -This is a wrapper around `ediff-buffers-internal'. - -A, B and C have the form (GET-BUFFER CREATE-BUFFER). If -GET-BUFFER returns a non-nil value, then that buffer is used and -it is not killed when exiting Ediff. Otherwise CREATE-BUFFER -must return a buffer and that is killed when exiting Ediff. - -If non-nil, SETUP must be a function. It is called without -arguments after Ediff is done setting up buffers. - -If non-nil, QUIT must be a function. It is added to -`ediff-quit-hook' and is called without arguments. - -If FILE is non-nil, then perform a merge. The merge result -is put in FILE." - (let (get make kill (char ?A)) - (dolist (spec (list a b c)) - (if (not spec) - (push nil make) - (pcase-let ((`(,g ,m) spec)) - (let ((b (intern (format "buf%c" char)))) - (push `(,b ,g) get) - ;; This is an unfortunate complication that I have added for - ;; the benefit of one user. Pretend we used this instead: - ;; (push `(or ,b ,m) make) - (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 - ;; For merge jobs Ediff switches buffer names around. - ;; See (if ediff-merge-job ...) in `ediff-setup'. - (let ((var ,(if (and file (= char ?C)) - 'ediff-ancestor-buffer - (intern (format "ediff-buffer-%c" char))))) - (ediff-kill-buffer-carefully var))) - kill)) - (cl-incf char)))) - (setq get (nreverse get)) - (setq make (nreverse make)) - (setq kill (nreverse kill)) - (let ((mconf (gensym "conf")) - (mfile (gensym "file"))) - `(magit-with-toplevel - (let ((,mconf (current-window-configuration)) - (,mfile ,file) - ,@get) - (ediff-buffers-internal - ,@make - (list ,@(and setup (list setup)) - (lambda () - ;; We do not want to kill buffers that existed before - ;; Ediff was invoked, so we cannot use Ediff's default - ;; quit functions. Ediff splits quitting across two - ;; hooks for merge jobs but we only ever use one. - (setq-local ediff-quit-merge-hook nil) - (setq-local ediff-quit-hook - (list - ,@(and quit (list quit)) - (lambda () - ,@kill - (let ((magit-ediff-previous-winconf ,mconf)) - (run-hooks 'magit-ediff-quit-hook))))))) - (pcase (list ,(and c t) (and ,mfile t)) - ('(nil nil) 'ediff-buffers) - ('(nil t) 'ediff-merge-buffers) - ('(t nil) 'ediff-buffers3) - ('(t t) 'ediff-merge-buffers-with-ancestor)) - ,mfile)))))) - -;;;###autoload -(defun magit-ediff-resolve-all (file) - "Resolve all conflicts in the FILE at point using Ediff. - -If there is no file at point or if it doesn't have any unmerged -changes, then prompt for a file. - -See info node `(magit) Ediffing' for more information about this -and alternative commands." - (interactive (list (magit-read-unmerged-file))) - (magit-with-toplevel - (let* ((dir (magit-gitdir)) - (revA (or (magit-name-branch "HEAD") - (magit-commit-p "HEAD"))) - (revB (cl-find-if (##file-exists-p (expand-file-name % dir)) - '("MERGE_HEAD" "CHERRY_PICK_HEAD" "REVERT_HEAD"))) - (revB (or (magit-name-branch revB) - (magit-commit-p revB))) - (revC (magit-commit-p (magit-git-string "merge-base" revA revB))) - (fileA (magit--rev-file-name file revA revB)) - (fileB (magit--rev-file-name file revB revA)) - (fileC (or (magit--rev-file-name file revC revA) - (magit--rev-file-name file revC revB)))) - ;; Ediff assumes that the FILE where it is going to store the merge - ;; result does not exist yet, so move the existing file out of the - ;; way. If a buffer visits FILE, then we have to kill that upfront. - (when-let ((buffer (find-buffer-visiting file))) - (when (and (buffer-modified-p buffer) - (not (y-or-n-p (format "Save buffer %s %s? " - (buffer-name buffer) - "(cannot continue otherwise)")))) - (user-error "Abort")) - (kill-buffer buffer)) - (let ((orig (concat file ".ORIG"))) - (when (file-exists-p orig) - (rename-file orig (make-temp-name (concat orig "_")))) - (rename-file file orig)) - (let ((setup (lambda () - ;; Use the same conflict marker style as Git uses. - (setq-local ediff-combination-pattern - '("<<<<<<< HEAD" A - ,(format "||||||| %s" revC) Ancestor - "=======" B - ,(format ">>>>>>> %s" revB))))) - (quit (lambda () - ;; For merge jobs Ediff switches buffer names around. - ;; At this point `ediff-buffer-C' no longer refer to - ;; the ancestor buffer but to the merge result buffer. - ;; See (if ediff-merge-job ...) in `ediff-setup'. - (when (buffer-live-p ediff-buffer-C) - (with-current-buffer ediff-buffer-C - (save-buffer) - (save-excursion - (goto-char (point-min)) - (unless (re-search-forward "^<<<<<<< " nil t) - (magit-stage-files (list file))))))))) - (if fileC - (magit-ediff-buffers - ((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)) - setup quit file) - (magit-ediff-buffers - ((magit-get-revision-buffer revA fileA) - (magit-find-file-noselect revA fileA)) - ((magit-get-revision-buffer revB fileB) - (magit-find-file-noselect revB fileB)) - nil setup quit file)))))) - -;;;###autoload -(defun magit-ediff-resolve-rest (file) - "Resolve outstanding conflicts in the FILE at point using Ediff. - -If there is no file at point or if it doesn't have any unmerged -changes, then prompt for a file. - -See info node `(magit) Ediffing' for more information about this -and alternative commands." - (interactive (list (magit-read-unmerged-file))) - (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))))))) - -;;;###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))) - (with-current-buffer bufB* (setq buffer-read-only nil)) - (magit-ediff-buffers - (bufA bufA*) - (bufB bufB*) - (bufC bufC*) - nil - (lambda () - (when (buffer-live-p ediff-buffer-B) - (when lockB - (with-current-buffer bufB (setq buffer-read-only 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))))))))) - -;;;###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 - ((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 ((range (magit-split-range input))) - (list (car range) (cdr range)) - (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 (and fileB (member fileB (magit-revision-files revB))) - (setq fileB - (or (and fileB - magit-buffer-log-files - (derived-mode-p 'magit-log-mode) - (member "--follow" magit-buffer-log-args) - (cdr (assoc fileB - (magit-renamed-files - revB - (oref (car (oref magit-root-section children)) - value))))) - (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-dwim-resolve-function - #'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) - (?m "[m] resolve remaining conflicts" - #'magit-ediff-resolve-rest) - (?M "[M] resolve all conflicts" - #'magit-ediff-resolve-all)))) - ((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 ((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 ((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 ((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 - ((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 (display-graphic-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-20250519.1537/magit-extras.el b/elpa/magit-20250519.1537/magit-extras.el deleted file mode 100644 index 7e346a68..00000000 --- a/elpa/magit-20250519.1537/magit-extras.el +++ /dev/null @@ -1,838 +0,0 @@ -;;; magit-extras.el --- Additional functionality for Magit -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; Commentary: - -;; Additional functionality for Magit. - -;;; Code: - -(require 'magit) - -;; For `magit-project-status'. -(declare-function vc-git-command "vc-git" - (buffer okstatus file-or-list &rest flags)) - -(defvar project-prefix-map) -(defvar project-switch-commands) - -(defgroup magit-extras nil - "Additional functionality for Magit." - :group 'magit-extensions) - -;;; Git Tools -;;;; Git-Mergetool - -;;;###autoload (autoload 'magit-git-mergetool "magit-extras" nil t) -(transient-define-prefix magit-git-mergetool (file args &optional transient) - "Resolve conflicts in FILE using \"git mergetool --gui\". -With a prefix argument allow changing ARGS using a transient -popup. See info node `(magit) Ediffing' for information about -alternative commands." - :man-page "git-mergetool" - ["Settings" - ("-t" magit-git-mergetool:--tool) - ("=t" magit-merge.guitool) - ("=T" magit-merge.tool) - ("-r" magit-mergetool.hideResolved) - ("-b" magit-mergetool.keepBackup) - ("-k" magit-mergetool.keepTemporaries) - ("-w" magit-mergetool.writeToTemp)] - ["Actions" - (" m" "Invoke mergetool" magit-git-mergetool)] - (interactive - (if (and (not (eq transient-current-command 'magit-git-mergetool)) - current-prefix-arg) - (list nil nil t) - (list (magit-read-unmerged-file "Resolve") - (transient-args 'magit-git-mergetool)))) - (if transient - (transient-setup 'magit-git-mergetool) - (magit-run-git-async "mergetool" "--gui" args "--" file))) - -(transient-define-infix magit-git-mergetool:--tool () - :description "Override mergetool" - :class 'transient-option - :shortarg "-t" - :argument "--tool=" - :reader #'magit--read-mergetool) - -(transient-define-infix magit-merge.guitool () - :class 'magit--git-variable - :variable "merge.guitool" - :global t - :reader #'magit--read-mergetool) - -(transient-define-infix magit-merge.tool () - :class 'magit--git-variable - :variable "merge.tool" - :global t - :reader #'magit--read-mergetool) - -(defun magit--read-mergetool (prompt _initial-input history) - (let ((choices nil) - (lines (cdr (magit-git-lines "mergetool" "--tool-help")))) - (while (string-prefix-p "\t\t" (car lines)) - (push (substring (pop lines) 2) choices)) - (setq choices (nreverse choices)) - (magit-completing-read (or prompt "Select mergetool") - choices nil t nil history))) - -(transient-define-infix magit-mergetool.hideResolved () - :class 'magit--git-variable:boolean - :variable "mergetool.hideResolved" - :default "false" - :global t) - -(transient-define-infix magit-mergetool.keepBackup () - :class 'magit--git-variable:boolean - :variable "mergetool.keepBackup" - :default "true" - :global t) - -(transient-define-infix magit-mergetool.keepTemporaries () - :class 'magit--git-variable:boolean - :variable "mergetool.keepTemporaries" - :default "false" - :global t) - -(transient-define-infix magit-mergetool.writeToTemp () - :class 'magit--git-variable:boolean - :variable "mergetool.writeToTemp" - :default "false" - :global t) - -;;;; Git-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 - (progn - (setq revision "HEAD") - (not (setq 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))) - -;;;; Gitk - -(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-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 magit-project-status () - "Run `magit-status' in the current project's root." - (interactive) - (if (fboundp 'project-root) - (magit-status-setup-buffer (project-root (project-current t))) - (user-error "`magit-project-status' requires `project' 0.3.0 or greater"))) - -(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 - (when (and magit-bind-magit-project-status - ;; Added in Emacs 28.1. - (boundp 'project-prefix-map) - (boundp 'project-switch-commands) - ;; Only modify if it hasn't already been modified. - (equal project-switch-commands - (eval (car (get 'project-switch-commands 'standard-value)) - t))) - (keymap-set project-prefix-map "m" #'magit-project-status) - (add-to-list 'project-switch-commands '(magit-project-status "Magit") t))) - -;;; 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'. - (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 (string-match-p "\\`0\\{40,\\}\\'" rev) - (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-commit' 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)))))) - (with-environment-variables (("FILTER_BRANCH_SQUELCH_WARNING" "1")) - (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 - (string-replace "%N" idx pnt-format))) - (magit-rev-insert-format pnt-format rev pnt-args) - (delete-char -1)) - (when eob-format - (when idx-format - (setq eob-format - (string-replace "%N" idx eob-format))) - (save-excursion - (goto-char (point-max)) - (skip-syntax-backward ">-") - (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) - (delete-char -1))))) - (user-error "Revision stack is empty"))) - -;;;###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 (get-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)))) - -;;;###autoload -(defun magit-back-to-indentation () - "Move point to the first non-whitespace character on this line. -In Magit diffs, also skip over - and + at the beginning of the line." - (interactive "^") - (beginning-of-line 1) - (when (and (magit-section-match 'hunk) - (looking-at (if (oref (magit-current-section) combined) - "^ ?[-+]+" - "^[-+]"))) - (goto-char (match-end 0))) - (skip-syntax-forward " " (line-end-position)) - (backward-prefix-chars)) - -;;; _ -(provide 'magit-extras) -;;; magit-extras.el ends here diff --git a/elpa/magit-20250519.1537/magit-fetch.el b/elpa/magit-20250519.1537/magit-fetch.el deleted file mode 100644 index 7ef4504b..00000000 --- a/elpa/magit-20250519.1537/magit-fetch.el +++ /dev/null @@ -1,186 +0,0 @@ -;;; magit-fetch.el --- Download objects and refs -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; Commentary: - -;; This library implements fetch commands. - -;;; Code: - -(require 'magit) - -;;; 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")) - ("-u" "Fetch full history" "--unshallow" :level 7) - ("-F" "Force" ("-f" "--force"))] - ["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 (##magit-get-current-remote t) - :description (##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 populated 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" "--jobs=4") - ["Arguments" - ("-v" "verbose" "--verbose") - ("-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) - (magit-with-toplevel - (magit-run-git-async "fetch" "--recurse-submodules" args)))) - -;;; _ -(provide 'magit-fetch) -;;; magit-fetch.el ends here diff --git a/elpa/magit-20250519.1537/magit-files.el b/elpa/magit-20250519.1537/magit-files.el deleted file mode 100644 index ed65c0ea..00000000 --- a/elpa/magit-20250519.1537/magit-files.el +++ /dev/null @@ -1,595 +0,0 @@ -;;; magit-files.el --- Finding files -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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 - (seq-difference after-change-major-mode-hook - '(global-diff-hl-mode-enable-in-buffer ; Emacs >= 30 - global-diff-hl-mode-enable-in-buffers ; Emacs < 30 - eglot--maybe-activate-editing-mode) - #'eq))) - (normal-mode t)) - (setq buffer-read-only t) - (set-buffer-modified-p nil) - (goto-char (point-min)))) - -(define-advice lsp (:around (fn &rest args) magit-find-file) - "Do nothing when visiting blob using `magit-find-file' and similar. -See also https://github.com/doomemacs/doomemacs/pull/6309." - (unless magit-buffer-revision - (apply fn args))) - -;;; 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 - (expand-file-name "magit-update-index-" (magit-gitdir)))) - (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 ((buffer (magit-get-mode-buffer 'magit-status-mode))) - (with-current-buffer buffer - (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-gitdir))) - (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-gitdir))) - (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-gitdir))) - (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" - [:if magit-file-relative-name - ["File actions" - (" s" "Stage" magit-file-stage :if-not-derived dired-mode) - (" s" "Stage" magit-dired-stage :if-derived dired-mode) - (" u" "Unstage" magit-file-unstage :if-not-derived dired-mode) - (" u" "Unstage" magit-dired-unstage :if-derived dired-mode) - (", x" "Untrack" magit-file-untrack) - (", r" "Rename" magit-file-rename) - (", k" "Delete" magit-file-delete) - (", c" "Checkout" magit-file-checkout)] - ["Inspect" - ("D" "Diff..." magit-diff) - ("d" "Diff" magit-diff-buffer-file)] - ["" - ("L" "Log..." magit-log) - ("l" "Log" magit-log-buffer-file :if-not-derived dired-mode) - ("l" "Log" magit-dired-log :if-derived dired-mode) - ("t" "Trace" magit-log-trace-definition) - ("M" "Merged" magit-log-merged :level 7)] - ["" - ("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)] - ["Navigate" - ("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) - ("g" "Goto status" magit-status-here) - ("G" "Goto magit" magit-display-repository-buffer)] - ["More actions" - ("c" "Commit" magit-commit) - ("e" "Edit line" magit-edit-line-commit)]] - [:if-not magit-file-relative-name - ["File actions" - ("s" "Stage" magit-stage-files) - ("u" "Unstage" magit-unstage-files) - ("x" "Untrack" magit-file-untrack) - ("r" "Rename" magit-file-rename) - ("k" "Delete" magit-file-delete) - ("c" "Checkout" magit-file-checkout)] - ["Navigate" - ("g" "Goto status" magit-status-here :if-not-mode magit-status-mode) - ("G" "Goto magit" magit-display-repository-buffer)]]) - -;;; Blob Mode - -(defvar-keymap magit-blob-mode-map - :doc "Keymap for `magit-blob-mode'." - "p" #'magit-blob-previous - "n" #'magit-blob-next - "b" #'magit-blame-addition - "r" #'magit-blame-removal - "f" #'magit-blame-reverse - "q" #'magit-kill-this-buffer) - -(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 ((ancestor (magit-blob-ancestor magit-buffer-revision file))) - (magit-blob-visit ancestor) - (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 - -;;;###autoload -(defun magit-file-stage () - "Stage all changes to the file being visited in the current buffer." - (interactive) - (unless buffer-file-name - (user-error "Not visiting a file")) - (magit-with-toplevel - (magit-stage-1 (and (magit-file-ignored-p buffer-file-name) - (if (y-or-n-p "Visited file is ignored; stage anyway?") - "--force" - (user-error "Abort"))) - (list (magit-file-relative-name))))) - -;;;###autoload -(defun magit-file-unstage () - "Unstage all changes to the file being visited in the current buffer." - (interactive) - (unless buffer-file-name - (user-error "Not visiting a file")) - (magit-with-toplevel - (magit-unstage-1 (list (magit-file-relative-name))))) - -;;;###autoload -(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 ((files (magit-region-values 'file t))) - (if (magit-file-tracked-p (car files)) - (magit-confirm-files 'untrack files "Untrack") - (user-error "Already untracked")) - (list (magit-read-tracked-file "Untrack file")))) - current-prefix-arg)) - (magit-with-toplevel - (magit-run-git "rm" "--cached" (and force "--force") "--" files))) - -;;;###autoload -(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")) - (path (expand-file-name file (magit-toplevel)))) - (list path (expand-file-name - (read-file-name (format "Move %s to destination: " file) - (file-name-directory path)))))) - (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 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)) - -;;;###autoload -(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 ((files (magit-region-values 'file t))) - (magit-confirm-files 'delete files "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" nil t)))) - (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 include-dirs) - (let ((files (magit-revision-files rev))) - (when include-dirs - (setq files (sort (nconc files (magit-revision-directories rev)) - #'string<))) - (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) - (magit-with-toplevel - (let ((choices (nconc (magit-list-files) - (and (not 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-unmerged-file (&optional prompt) - (let ((current (magit-current-file)) - (unmerged (magit-unmerged-files))) - (unless unmerged - (user-error "There are no unresolved conflicts")) - (magit-completing-read (or prompt "Resolve file") - unmerged nil t nil nil - (car (member current unmerged))))) - -(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))) - -;;; _ - -(define-obsolete-function-alias 'magit-stage-buffer-file - 'magit-file-stage "Magit 4.3.2") - -(define-obsolete-function-alias 'magit-unstage-buffer-file - 'magit-file-unstage "Magit 4.3.2") - -(provide 'magit-files) -;;; magit-files.el ends here diff --git a/elpa/magit-20250519.1537/magit-git.el b/elpa/magit-20250519.1537/magit-git.el deleted file mode 100644 index 2e6a14c5..00000000 --- a/elpa/magit-20250519.1537/magit-git.el +++ /dev/null @@ -1,2865 +0,0 @@ -;;; magit-git.el --- Git functionality -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; Commentary: - -;; This library implements wrappers for various Git plumbing commands. - -;;; Code: - -(require 'magit-base) - -(require 'format-spec) - -;; 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-type) -(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-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-finish-section "magit-process" - (section exit-code)) -(declare-function magit-process-git "magit-process" (destination &rest args)) -(declare-function magit-process-insert-section "magit-process" - (pwd program args &optional errcode errlog face)) -(defvar magit-this-error) -(defvar magit-process-error-message-regexps) - -(eval-when-compile - (cl-pushnew 'orig-rev eieio--known-slot-names) - (cl-pushnew 'number eieio--known-slot-names)) - -;;; 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. - (and-let* ((exec (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 - exec "-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 - exec "-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" - "-c" "diff.noPrefix=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 . "4.3.2") - :group 'magit-commands - :group 'magit-process - :type '(repeat string)) - -(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-git-debug nil - "Whether and how to enable additional debugging of git errors. - -Use `magit-toggle-git-debug' (which see) to toggle the boolean value of -this variable. This can also manually be set to `include-success', in -which case successful git invocations are also logged. - -This can also be a function, which takes one argument, the error output -as a string. This is intended for internal use and is established using -let-bindings around critical code (i.e., in `magit--assert-usable-git').") - -(defun magit-toggle-git-debug () - "Toggle whether additional git errors are reported. - -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-buffer]. - -When git's output is consumed in some way, then it would be too -expensive to also insert it into this buffer, but with this command -that can be enabled temporarily. In that case, if git returns with -a non-zero exit status, then at least its standard error is inserted -into this buffer. - -See info node `(magit)Debugging Tools' for more information." - (interactive) - (setq magit-git-debug (not magit-git-debug)) - (message "Additional reporting of Git errors %s" - (if magit-git-debug "enabled" "disabled"))) - -(defvar magit--refresh-cache nil) - -(defmacro magit--with-refresh-cache (key &rest body) - (declare (indent 1) (debug (form body))) - (let ((k (gensym)) - (hit (gensym))) - `(if magit--refresh-cache - (let ((,k ,key)) - (if-let ((,hit (assoc ,k (cdr magit--refresh-cache)))) - (progn (cl-incf (caar magit--refresh-cache)) - (cdr ,hit)) - (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 (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-tree 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 - 'magit-section-secondary-heading))) - (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-tree 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-tree 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, insert stdout at point and return exit code. -If `magit-git-debug' is non-nil and the exit code is non-zero, then -insert the run command and stderr into the process buffer." - (apply #'magit--git-insert nil args)) - -(defun magit--git-insert (return-error &rest args) - (setq args (flatten-tree args)) - (if (or return-error magit-git-debug) - (let (log) - (unwind-protect - (let (exit errmsg) - (setq log (make-temp-file "magit-stderr")) - (delete-file log) - (setq exit (magit-process-git (list t log) args)) - (when (or (> exit 0) (eq magit-git-debug 'include-success)) - (when (file-exists-p log) - (with-temp-buffer - (insert-file-contents log) - (goto-char (point-max)) - (setq errmsg - (cond - ((eq return-error 'full) - (let ((str (buffer-string))) - (and (not (equal str "")) str))) - ((functionp magit-git-debug) - (funcall magit-git-debug (buffer-string))) - ((magit--locate-error-message))))) - (when magit-git-debug - (let ((magit-git-debug nil)) - (with-current-buffer (magit-process-buffer t) - (magit-process-finish-section - (magit-process-insert-section - default-directory magit-git-executable - (magit-process-git-arguments args) - exit log 'magit-section-secondary-heading) - exit))))) - (cond ((not magit-git-debug)) - (errmsg (message "%s" errmsg)) - ((zerop exit)) - ((message "Git returned with exit-code %s" exit)))) - (or errmsg 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 - (##re-search-backward % 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-tree 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, 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, 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. - -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 finally call function -WASHER with ARGS as its sole argument. - -If git exits with a non-zero exit status, apply the `error' face to -the error message, instead of calling WASHER. To instead cancel the -section use `magit--git-wash'." - (declare (indent 1)) - (apply #'magit--git-wash washer t args)) - -(defun magit--git-wash (washer keep-error &rest args) - "Execute git with ARGS, inserting washed output at point. - -Like `magit-git-wash' but if KEEP-ERROR is nil and an error occurs, also -insert standard error. If KEEP-ERROR is `wash-anyway', insert and wash -standard output even in case of an error." - (declare (indent 2)) - (setq args (flatten-tree args)) - (let ((beg (point)) - (exit (magit--git-insert (and keep-error 'full) args))) - (when (stringp exit) - (goto-char beg) - (insert (propertize exit 'face 'error)) - (insert (if (bolp) "\n" "\n\n"))) - (if (= (point) beg) - (magit-cancel-section) - (unless (bolp) - (insert "\n")) - (when (or (equal exit 0) - (eq keep-error 'wash-anyway)) - (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))) - exit)) - -(defun magit-git-executable-find (command) - "Search for COMMAND in Git's exec path, falling back to `exec-path'. -Like `executable-find', return the absolute file name of the -executable." - (or (locate-file command - (list (concat - (file-remote-p default-directory) - (or (magit-git-string "--exec-path") - (error "`git --exec-path' failed")))) - exec-suffixes - #'file-executable-p) - (compat-call executable-find command t))) - -;;; Git Version - -(defconst magit--git-version-regexp - "\\`git version \\([0-9]+\\(\\.[0-9]+\\)\\{1,2\\}\\)") - -(defvar magit--host-git-version-cache nil) - -(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)) - -(defun magit-git-version () - "Return the Git version used for `default-directory'. -Raise an error if Git cannot be found, if it exits with a -non-zero status, or the output does not have the expected -format." - (magit--with-refresh-cache default-directory - (let ((host (file-remote-p default-directory))) - (or (cdr (assoc host magit--host-git-version-cache)) - (magit--with-temp-process-buffer - ;; Unset global arguments for ancient Git versions. - (let* ((magit-git-global-arguments nil) - (status (magit-process-git t "version")) - (output (buffer-string))) - (cond - ((not (zerop status)) - (display-warning - 'magit - (format "%S\n\nRunning \"%s --version\" failed with output:\n\n%s" - (if host - (format "Magit cannot find Git on host %S.\n -Check the value of `magit-remote-git-executable' using -`magit-debug-git-executable' and consult the info node -`(tramp)Remote programs'." host) - "Magit cannot find Git.\n -Check the values of `magit-git-executable' and `exec-path' -using `magit-debug-git-executable'.") - (magit-git-executable) - output))) - ((save-match-data - (and (string-match magit--git-version-regexp output) - (let ((version (match-string 1 output))) - (push (cons host version) - magit--host-git-version-cache) - version)))) - ((error "Unexpected \"%s --version\" output: %S" - (magit-git-executable) - output))))))))) - -(defun magit-git-version-assert (&optional minimal who) - "Assert that the used Git version is greater than or equal to MINIMAL. -If optional MINIMAL is nil, compare with `magit--minimal-git' -instead. Optional WHO if non-nil specifies what functionality -needs at least MINIMAL, otherwise it defaults to \"Magit\"." - (when (magit-git-version< (or minimal magit--minimal-git)) - (let* ((host (file-remote-p default-directory)) - (msg (format-spec - (cond (host "\ -%w requires Git %m or greater, but on %h the version is %v. - -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'.\n") - (t "\ -%w requires Git %m or greater, but you are using %v. - -If you have multiple Git versions installed, then check the -values of `magit-remote-git-executable' and `exec-path'.\n")) - `((?w . ,(or who "Magit")) - (?m . ,(or minimal magit--minimal-git)) - (?v . ,(magit-git-version)) - (?h . ,host))))) - (display-warning 'magit msg :error)))) - -(defun magit--safe-git-version () - "Return the Git version used for `default-directory' or an error message." - (magit--with-temp-process-buffer - (let* ((magit-git-global-arguments nil) - (status (magit-process-git t "version")) - (output (buffer-string))) - (cond ((not (zerop status)) output) - ((save-match-data - (and (string-match magit--git-version-regexp output) - (match-string 1 output)))) - (t output))))) - -(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-executable*") - (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" (magit--safe-git-version)))) - (insert (format "exec-path: %S\n" exec-path)) - (when-let ((diff (cl-set-difference - (seq-filter #'file-exists-p (remq nil (parse-colon-path - (getenv "PATH")))) - (seq-filter #'file-exists-p (remq nil exec-path)) - :test #'file-equal-p))) - (insert (format " entries in PATH, but not in exec-path: %S\n" diff))) - (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 - (magit--safe-git-version)))))))) - -;;; Variables - -(defun magit-config-get-from-cached-list (key) - (gethash - ;; `git config --list' downcases first and last components of the key. - (let* ((key (replace-regexp-in-string "\\`[^.]+" #'downcase key t t)) - (key (replace-regexp-in-string "[^.]+\\'" #'downcase key t t))) - key) - (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 (string-join keys "."))) - (if (and magit--refresh-cache (not arg)) - (magit-config-get-from-cached-list key) - (magit-git-items "config" arg "-z" "--get-all" "--include" 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 ((arg (and (or (null (car keys)) - (string-prefix-p "--" (car keys))) - (pop keys))) - (key (string-join keys "."))) - (equal (if magit--refresh-cache - (car (last (magit-config-get-from-cached-list key))) - (magit-git-str "config" arg "--bool" "--include" 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 (string-join 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 (string-join 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 (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-git-dir (&optional path) - "Like (expand-file-name PATH (magit-gitdir)) or just (magit-gitdir)." - (declare (obsolete magit-gitdir "Magit 4.0.0")) - (and-let* ((dir (magit-gitdir))) - (if path - (expand-file-name (convert-standard-filename path) dir) - dir))) - -(defun magit-gitdir (&optional directory) - "Return the absolute and resolved path of the .git directory. - -If the `GIT_DIR' environment variable is defined, 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--with-refresh-cache (list default-directory 'magit-gitdir) - (magit--with-safe-default-directory nil - (and-let* - ((dir (magit-rev-parse-safe "--git-dir")) - (dir (file-name-as-directory (magit-expand-git-file-name dir)))) - (if (file-remote-p dir) - dir - (concat (file-remote-p default-directory) dir))))))) - -(defvar magit--separated-gitdirs nil) - -(defun magit--record-separated-gitdir () - (let ((topdir (magit-toplevel)) - (gitdir (magit-gitdir))) - ;; 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." - (or - (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)) - (cond - ((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))) - (and-let* - ((default-directory updir) - (top (and (string-equal - (magit-rev-parse-safe "--show-cdup") "") - (magit-rev-parse-safe "--show-toplevel")))) - (string-equal (magit-expand-git-file-name top) topdir)))) - updir) - ((concat (file-remote-p default-directory) - (file-name-as-directory topdir))))) - (and-let* ((gitdir (magit-rev-parse-safe "--git-dir")) - (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))) - (;; Step outside the control directory to enter the - ;; working tree. - (file-name-directory (directory-file-name gitdir)))))))))))) - -(defun magit--toplevel-safe () - (or (magit-toplevel) - (magit--not-inside-repository-error))) - -(defmacro magit-with-toplevel (&rest body) - (declare (indent defun) (debug (body))) - `(let ((default-directory (magit--toplevel-safe))) - ,@body)) - -(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 - (concat "Git executable cannot be found " - "(see https://magit.vc/goto/e6a78ed2)")) - -(defun magit--assert-usable-git () - (if (not (compat-call executable-find (magit-git-executable) t)) - (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-gitdir))) - (cond (gitdir (file-in-directory-p default-directory gitdir)) - (noerror nil) - ((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." - (and-let* ((file (or file - magit-buffer-file-name - buffer-file-name - (and (derived-mode-p 'dired-mode) - default-directory))) - ((or (not tracked) - (magit-file-tracked-p (file-relative-name file)))) - (dir (magit-toplevel - (magit--safe-default-directory - (directory-file-name (file-name-directory file)))))) - (file-relative-name file dir))) - -(defun magit-file-ignored-p (file) - (magit-git-string-p "ls-files" "--others" "--ignored" "--exclude-standard" - "--" (magit-convert-filename-for-git file))) - -(defun magit-file-tracked-p (file) - (magit-git-success "ls-files" "--error-unmatch" - "--" (magit-convert-filename-for-git file))) - -(defun magit-list-files (&rest args) - (apply #'magit-git-items "ls-files" "-z" "--full-name" args)) - -(defun magit-tracked-files (&rest args) - (magit-list-files "--cached" args)) - -(defun magit-untracked-files (&optional all files &rest args) - (magit-list-files "--other" args - (and (not all) "--exclude-standard") - "--" files)) - -(defun magit-ignored-files (&rest args) - (magit-list-files "--others" "--ignored" "--exclude-standard" args)) - -(defun magit-modified-files (&optional nomodules files) - (magit-git-items "diff-index" "-z" "--name-only" - ;; Work around a bug in Git v2.46.0. See #5212 and #5221. - (if nomodules "--ignore-submodules" "--submodule=short") - (magit-headish) "--" files)) - -(defun magit-unstaged-files (&optional nomodules files) - (magit-git-items "diff-files" "-z" "--name-only" "--diff-filter=u" - ;; Work around a bug in Git v2.46.0. See #5212 and #5221. - (if nomodules "--ignore-submodules" "--submodule=short") - "--" files)) - -(defun magit-staged-files (&optional nomodules files) - (magit-git-items "diff-index" "-z" "--name-only" "--cached" - ;; Work around a bug in Git v2.46.0. See #5212 and #5221. - (if nomodules "--ignore-submodules" "--submodule=short") - (magit-headish) "--" files)) - -(defun magit-binary-files (&rest args) - (mapcan (##and (string-match "^-\t-\t\\(.+\\)" %) - (list (match-string 1 %))) - (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-stashed-files (stash) - (magit-git-items "stash" "show" "-z" "--name-only" stash)) - -(defun magit-skip-worktree-files (&rest args) - (seq-keep (##and (= (aref % 0) ?S) - (substring % 2)) - (magit-list-files "-t" args))) - -(defun magit-assume-unchanged-files (&rest args) - (seq-keep (##and (memq (aref % 0) '(?h ?s ?m ?r ?c ?k)) - (substring % 2)) - (magit-list-files "-v" args))) - -(defun magit-revision-files (rev) - (magit-with-toplevel - (magit-git-items "ls-tree" "-z" "-r" "--name-only" rev))) - -(defun magit-revision-directories (rev) - "List directories that contain a tracked file in revision REV." - (magit-with-toplevel - (mapcar #'file-name-as-directory - (magit-git-items "ls-tree" "-z" "-r" "-d" "--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) - (mapcar (pcase-lambda (`(,_status ,fileA ,fileB)) - (cons fileA fileB)) - (seq-partition (magit-git-items "diff" "-z" "--name-status" - "--find-renames" - "--diff-filter=R" revA revB) - 3))) - -(defun magit--rev-file-name (file rev other-rev) - "For FILE, potentially renamed between REV and OTHER-REV, return name in REV. -Return nil, if FILE appears neither in REV nor OTHER-REV, -or if no rename is detected." - (or (car (member file (magit-revision-files rev))) - (and-let* ((renamed (magit-renamed-files rev other-rev))) - (car (rassoc file renamed))))) - -(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 - (and (eq system-type 'windows-nt) - (cl-sort (mapcar - (lambda (mount) - (if (string-match "^\\(.*\\) on \\(.*\\) type" mount) - (cons (file-name-as-directory (match-string 2 mount)) - (file-name-as-directory (match-string 1 mount))) - (lwarn '(magit) :error - "Failed to parse Cygwin mount: %S" mount))) - ;; 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 (and (not (file-remote-p default-directory)) ; see #4976 - (cl-assoc filename magit-cygwin-mount-points - :test (##string-prefix-p %2 %1))))) - (concat (cdr cyg:win) - (substring filename (length (car cyg:win)))) - filename)) - -(defun magit-convert-filename-for-git (filename) - "Convert FILENAME so that it can be passed to git. -1. If it is a absolute filename, then pass it through - `expand-file-name' to replace things such as \"~/\" that - Git does not understand. -2. If it is 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 (##string-prefix-p %2 %1)))) - (concat (car cyg:win) - (substring filename (length (cdr cyg: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." - ;; The "--submodule=short" is needed to work around a bug in Git v2.46.0 - ;; and v2.46.1. See #5212 and #5221. There are actually two related - ;; bugs, both of which are fixed in v2.46.2, with the following commits, - ;; but there is no workaround for the second bug. - ;; 11591850dd diff: report dirty submodules as changes in builtin_diff() - ;; 87cf96094a diff: report copies and renames as changes in run_diff_cmd() - (magit-git-failure "diff" "--quiet" "--cached" - (if ignore-submodules - "--ignore-submodules" - "--submodule=short") - "--" 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" - (if ignore-submodules - "--ignore-submodules" - ;; Work around a bug in Git v2.46.0. See #5212 and #5221. - "--submodule=short") - "--" 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 ".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 (##string-prefix-p "--ignore-submodules" %) - magit-buffer-diff-args) - (and-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 (magit--rev-dereference rev))) - -(defalias 'magit-rev-verify-commit #'magit-commit-p) - -(defalias 'magit-rev-hash #'magit-commit-p) - -(defun magit--rev-dereference (rev) - "Return a rev that forces Git to interpret REV as a commit. -If REV is nil or has the form \":/TEXT\", return REV itself." - (cond ((not rev) nil) - ((string-match-p "^:/" rev) rev) - ((concat rev "^{commit}")))) - -(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-search ".." 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." - (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) - (and-let* ((name (magit-rev-name rev "refs/heads/*"))) - (and (not (string-match-p "[~^]" name)) name))) - -(defun magit-rev-fixup-target (rev) - (let ((msg (magit-rev-format "%s" rev))) - (save-match-data - (and (string-match "\\`\\(squash!\\|fixup!\\|amend!\\) \\(.+\\)" msg) - (magit-rev-format - "%h" (format "%s^{/^%s}" rev - (magit--ext-regexp-quote (match-string 2 msg)))))))) - -(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))) - ((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) - (and-let* ((name (magit-rev-name rev "refs/heads/*"))) - (and (or lax (not (string-match-p "[~^]" name))) name))) - -(defun magit-name-remote-branch (rev &optional lax) - (and-let* ((name (magit-rev-name rev "refs/remotes/*"))) - (and (or lax (not (string-match-p "[~^]" name))) - (substring name 8)))) - -(defun magit-name-tag (rev &optional lax) - (and-let* ((name (magit-rev-name rev "refs/tags/*"))) - (progn - (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)))) - (pullreq (and (fboundp 'forge--pullreq-branch) - (magit-branch-p - (forge--pullreq-branch (oref it value))))) - (related-refs (magit--painted-branch-at-point)) - ((unpulled unpushed) - (magit-ref-abbrev - (replace-regexp-in-string "\\.\\.\\.?" "" (oref it value)))))) - -(defun magit--painted-branch-at-point (&optional type) - (or (and (not (eq type 'remote)) - (memq (get-text-property (magit-point) 'font-lock-face) - (list 'magit-branch-local - 'magit-branch-current)) - (and-let* ((branch (magit-thing-at-point 'git-revision t))) - (cdr (magit-split-branch-name branch)))) - (and (not (eq type 'local)) - (memq (get-text-property (magit-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) - (magit-thing-at-point 'git-revision t) - (and-let* ((chunk (and (bound-and-true-p magit-blame-mode) - (fboundp 'magit-current-blame-chunk) - (magit-current-blame-chunk)))) - (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))))) - ((unpulled unpushed) - (magit-ref-abbrev - (replace-regexp-in-string "\\.\\.\\.?" "" (oref it value))))) - (magit-thing-at-point 'git-revision t) - (and-let* ((chunk (and (bound-and-true-p magit-blame-mode) - (fboundp 'magit-current-blame-chunk) - (magit-current-blame-chunk)))) - (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 'module) - (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 "@{-%d}" i))) - (or (not (setq prev (magit-rev-branch prev))) - (equal prev current)))) - (cl-incf i)) - prev)) - -(defun magit--set-default-branch (newname oldname) - (let ((remote (or (magit-primary-remote) - (user-error "Cannot determine primary remote"))) - (branches (mapcar (##split-string % "\t") - (magit-git-lines - "for-each-ref" "refs/heads" - "--format=%(refname:short)\t%(upstream:short)")))) - (when-let ((old (assoc oldname branches)) - ((not (assoc newname branches)))) - (magit-call-git "branch" "-m" oldname newname) - (setcar old newname)) - (let ((new (if (magit-branch-p newname) - newname - (concat remote "/" newname)))) - (pcase-dolist (`(,branch ,upstream) branches) - (cond - ((equal upstream oldname) - (magit-set-upstream-branch branch new)) - ((equal upstream (concat remote "/" oldname)) - (magit-set-upstream-branch branch (concat remote "/" newname)))))))) - -(defun magit--get-default-branch (&optional update) - (let ((remote (magit-primary-remote))) - (when update - (if (not remote) - (user-error "Cannot determine primary remote") - (message "Determining default branch...") - (magit-git "fetch" "--prune") - (magit-git "remote" "set-head" "--auto" remote) - (message "Determining default branch...done"))) - (let ((branch (magit-git-string "symbolic-ref" "--short" - (format "refs/remotes/%s/HEAD" remote)))) - (when (and update (not branch)) - (error "Cannot determine new default branch")) - (list remote (and branch (cdr (magit-split-branch-name branch))))))) - -(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." - (and-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 default-directory 'magit-get-upstream-branch branch) - (and-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-local-upstream-branch (&optional branch) - (and-let* ((upstream (magit-get-upstream-branch branch)) - (upstream (cdr (magit-split-branch-name upstream)))) - (and (magit-branch-p upstream) upstream))) - -(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 - (seq-some (##if (magit-git-success "check-ref-format" "--branch" %) - (equal % branch) - (string-match-p % 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) - (and-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) - (and-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) - (and-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) - (and-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 default-directory 'magit-get-push-branch branch verify) - (and-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}")))) - (and ref - (string-prefix-p "refs/remotes/" ref) - (substring ref 13)))) - -(defun magit-get-remote (&optional branch) - (and (or branch (setq branch (magit-get-current-branch))) - (let ((remote (magit-get "branch" branch "remote"))) - (and (not (equal remote ".")) - remote)))) - -(defun magit-get-some-remote (&optional branch) - (or (magit-get-remote branch) - (and-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 (##member % 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 ((upstream (and (magit-branch-p branch) - (magit-get-upstream-branch branch)))) - (magit-rev-ancestor-p branch upstream) - t) - (if (eq target t) - (delete (magit-name-local-branch branch) - (magit-list-containing-branches branch)) - (and-let* ((target (or target (magit-get-current-branch)))) - (magit-rev-ancestor-p branch target))))) - -(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." - (and-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\\'" - (string-replace - "*" "\\(.+\\)" dst)) - ref) - (cons rmt (string-replace - "*" (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." - (and-let* ((str (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\\)?$" str) - (if with-distance - `(,(match-string 1 str) - ,(string-to-number (or (match-string 2 str) "0")) - ,@(and (match-string 3 str) (list t))) - (match-string 1 str))))) - -(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." - (and-let* ((str (magit-git-str "describe" "--contains" (or rev "HEAD")))) - (save-match-data - (when (string-match "^[^^~]+" str) - (setq str (match-string 0 str)) - (unless (equal str (magit-get-current-tag rev)) - (if with-distance - (list str (car (magit-rev-diff-count str rev))) - str)))))) - -(defun magit-list-refs (&optional namespaces format sortby) - "Return list of references, excluding symbolic 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)\". - -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)")) - (seq-keep (lambda (line) - (pcase-let* ((`(,symrefp ,value) - (split-string line " ")) - (symrefp (not (equal symrefp "")))) - (and (not symrefp) value))) - (magit-git-lines "for-each-ref" - (concat "--format=%(symref) " format) - (mapcar (##concat "--sort=" %) - (pcase (or sortby magit-list-refs-sortby) - ((and val (pred stringp)) (list val)) - ((and val (pred listp)) val))) - (or namespaces magit-list-refs-namespaces)))) - -(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) - (seq-remove (##string-match-p "\\(\\`(HEAD\\|HEAD -> \\)" %) - (mapcar (##substring % 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) - (seq-filter (##magit-rev-ancestor-p (or commit "HEAD") %) - 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 () - (seq-filter (##and-let* ((upstream (magit-get-upstream-branch %))) - (member % (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)))) - (seq-keep (##and (string-match re %) - (let ((name (match-string 2 %))) - (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-remove-if-not (##file-exists-p (expand-file-name % gitdir)) - 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))) - (mapcan (##when (string-match regexp %) - (list (match-string 1 %))) - (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-search "\f" format) - (mapcar (##split-string % "\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 () - (mapcar (##substring % 6) (magit-list-refnames "refs/notes"))) - -(defun magit-remote-list-tags (remote) - (seq-keep (##and (not (string-suffix-p "^{}" %)) - (substring % 51)) - (magit-git-lines "ls-remote" "--tags" remote))) - -(defun magit-remote-list-branches (remote) - (seq-keep (##and (not (string-suffix-p "^{}" %)) - (substring % 52)) - (magit-git-lines "ls-remote" "--heads" remote))) - -(defun magit-remote-list-refs (remote) - (seq-keep (##and (not (string-suffix-p "^{}" %)) - (substring % 41)) - (magit-git-lines "ls-remote" remote))) - -(defun magit-remote-head (remote) - (and-let* ((line (cl-find-if - (##string-match - "\\`ref: refs/heads/\\([^\s\t]+\\)[\s\t]HEAD\\'" %) - (magit-git-lines "ls-remote" "--symref" remote "HEAD")))) - (match-string 1 line))) - -(defun magit-list-modified-modules () - (seq-keep (##and (string-match "\\`\\+\\([^ ]+\\) \\(.+\\) (.+)\\'" %) - (match-string 2 %)) - (magit-git-lines "submodule" "status"))) - -(defun magit-list-module-paths () - (magit-with-toplevel - (mapcan (##and (string-match "^160000 [0-9a-z]\\{40,\\} 0\t\\(.+\\)$" %) - (list (match-string 1 %))) - (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." - (if (magit-git-version>= "2.38.0") - ;; "git submodule--helper name" was removed, - ;; but might still come back in another form. - (substring - (car (split-string - (car (or (magit-git-items - "config" "-z" - "-f" (expand-file-name ".gitmodules" (magit-toplevel)) - "--get-regexp" "^submodule\\..*\\.path$" - (concat "^" (regexp-quote (directory-file-name path)) "$")) - (error "No such submodule `%s'" path))) - "\n")) - 10 -5) - (magit-git-string "submodule--helper" "name" path))) - -(defun magit-list-worktrees () - "Return list of the worktrees of this repository. - -The returned list has the form (PATH COMMIT BRANCH BARE DETACHED -LOCKED PRUNABLE). The last four elements are booleans, with the -exception of LOCKED and PRUNABLE, which may also be strings. -See git-worktree(1) manpage for the meaning of the various parts. - -This function corrects a situation where \"git worktree list\" -would claim a worktree is bare, even though the working tree is -specified using `core.worktree'." - (let ((remote (file-remote-p default-directory)) - worktrees worktree) - (dolist (line (if (magit-git-version>= "2.36") - (magit-git-items "worktree" "list" "--porcelain" "-z") - (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. - ;; However, if the worktree has been removed, then - ;; we want to return it anyway; instead of nil. - (setq path (or (magit-toplevel path) path)) - (setq worktree (list path nil nil nil nil nil nil)) - (push worktree worktrees))) - ((string-prefix-p "HEAD" line) - (setf (nth 1 worktree) (substring line 5))) - ((string-prefix-p "branch" line) - (setf (nth 2 worktree) (substring line 18))) - ((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 3 worktree) t)))) - ((string-equal line "detached") - (setf (nth 4 worktree) t)) - ((string-prefix-p line "locked") - (setf (nth 5 worktree) - (if (> (length line) 6) (substring line 7) t))) - ((string-prefix-p line "prunable") - (setf (nth 6 worktree) - (if (> (length line) 8) (substring line 9) t))))) - (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 - '("main" "master" "trunk" "development") - "Branch names reserved for use by the primary branch. -Use function `magit-main-branch' to get the name actually used in -the current repository.") - -(defvar magit-long-lived-branches - (append magit-main-branch-names (list "maint" "next")) - "Branch names reserved for use by long lived branches.") - -(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 (##member % branches) - (delete-dups - (delq nil - (cons (magit-get "init.defaultBranch") - magit-main-branch-names)))))) - -(defun magit-rev-diff-count (a b &optional first-parent) - "Return the commits in A but not B and vice versa. -Return a list of two integers: (A>B B>A). - -If `first-parent' is set, traverse only first parents." - (mapcar #'string-to-number - (split-string (magit-git-string "rev-list" - "--count" "--left-right" - (and first-parent "--first-parent") - (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 ((rev (magit-rev-parse "--short" "HEAD~"))) - (length rev) - 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) - (seq-keep (lambda (line) - (pcase-let ((`(,child . ,parents) (split-string line " "))) - (and (member commit parents) child))) - (magit-git-lines "log" "--format=%H %P" - (or args (list "--branches" "--tags" "--remotes")) - "--not" commit))) - -(defun magit-commit-parents (commit) - (and-let* ((str (magit-git-string "rev-list" "-1" "--parents" commit))) - (cdr (split-string str)))) - -(defun magit-patch-id (rev) - (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) - ;; Prefer `git log --no-walk' to `git show --no-patch' because it - ;; performs better in some scenarios. - (let ((str (magit-git-string "log" "--no-walk" - (concat "--format=" format) args - (if rev (magit--rev-dereference rev) "HEAD") - "--"))) - (and (not (string-equal str "")) - str))) - -(defun magit-rev-insert-format (format &optional rev args) - ;; Prefer `git log --no-walk' to `git show --no-patch' because it - ;; performs better in some scenarios. - (magit-git-insert "log" "--no-walk" - (concat "--format=" format) args - (if rev (magit--rev-dereference rev) "HEAD") - "--")) - -(defun magit-format-rev-summary (rev) - (and-let* ((str (magit-rev-format "%h %s" rev))) - (progn - (magit--put-face 0 (string-match " " str) 'magit-hash str) - str))) - -(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 ((refs (split-string - (replace-regexp-in-string "\\(tag: \\|HEAD -> \\)" "" string) - ", " t)) - state head upstream tags branches remotes other combined) - (dolist (ref refs) - (let* ((face (cdr (seq-find (##string-match (car %) ref) - magit-ref-namespaces))) - (name (match-string 1 ref)) - (name (if (and name - (not (string-prefix-p "refs/tags/" ref)) - (magit-rev-verify (concat "refs/tags/" name))) - (magit-ref-abbrev ref) - (or name ref))) - (name (magit--propertize-face name 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 - (seq-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)))))) - (string-join (flatten-tree `(,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 (gensym "file"))) - `(let ((magit--refresh-cache nil) - (,file (magit-convert-filename-for-git - (make-temp-name - (expand-file-name "index.magit." (magit-gitdir)))))) - (unwind-protect - (magit-with-toplevel - (when-let* ((tree ,tree) - ((not (magit-git-success - "read-tree" ,arg tree - (concat "--index-output=" ,file))))) - (error "Cannot read tree %s" tree)) - (with-environment-variables (("GIT_INDEX_FILE" ,file)) - ,@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 - (mapcan (##list "-p" %) (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) - (let ((magit--refresh-cache nil)) - (unless (zerop (magit-call-git "update-ref" "--create-reflog" - "-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) - (pcase-let ((`(,beg ,end ,sep) (magit--split-range-raw range))) - (and sep - (let ((beg (or beg "HEAD")) - (end (or end "HEAD"))) - (if (string-equal (match-string 2 range) "...") - (and-let* ((base (magit-git-string "merge-base" beg end))) - (cons base end)) - (cons beg end)))))) - -(defun magit--split-range-raw (range) - (and (string-match magit-range-re range) - (let ((beg (match-string 1 range)) - (end (match-string 3 range))) - (and (or beg end) - (list beg end (match-string 2 range)))))) - -(defun magit-hash-range (range) - (if (string-match magit-range-re range) - (let ((beg (match-string 1 range)) - (end (match-string 3 range))) - (and (or beg end) - (let ((beg-hash (and beg (magit-rev-hash (match-string 1 range)))) - (end-hash (and end (magit-rev-hash (match-string 3 range))))) - (and (or (not beg) beg-hash) - (or (not end) end-hash) - (concat beg-hash (match-string 2 range) end-hash))))) - (magit-rev-hash range))) - -(defvar magit-revision-faces - '(magit-hash - magit-tag - magit-branch-remote - magit-branch-remote-head - magit-branch-local - magit-branch-current - magit-branch-upstream - magit-branch-warning - magit-head - magit-refname - magit-refname-stash - magit-refname-wip - magit-refname-pullreq)) - -(put 'git-revision 'thing-at-point #'magit-thingatpt--git-revision) -(defun magit-thingatpt--git-revision (&optional disallow) - ;; Support hashes and references. - (and-let* ((bounds - (let ((c (concat "\s\n\t~^:?*[\\" disallow))) - (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)))) - (string (buffer-substring-no-properties (car bounds) (cdr bounds))) - ;; References are allowed to contain most parentheses and - ;; most punctuation, but if those characters appear at the - ;; edges of a possible reference in arbitrary text, then - ;; they are much more likely to be intended as just that: - ;; punctuation and delimiters. - (string (thread-first string - (string-trim-left "[(/.,;!]")))) - (let (disallow) - (when (or (string-match-p "\\.\\." string) - (string-match-p "/\\." string)) - (setq disallow (concat disallow "."))) - (when (string-match-p "@{" string) - (setq disallow (concat disallow "@{"))) - (if disallow - ;; These additional restrictions overcompensate, - ;; but that only matters in rare cases. - (magit-thingatpt--git-revision disallow) - (and (not (equal string "@")) - (or (and (>= (length string) 7) - (string-match-p "[a-z]" string) - (magit-commit-p string)) - (and (magit-ref-p string) - (member (get-text-property (point) 'face) - magit-revision-faces))) - string))))) - -(put 'git-revision-range 'thing-at-point #'magit-thingatpt--git-revision-range) -(defun magit-thingatpt--git-revision-range () - ;; Support hashes but no references. - (and-let* ((bounds - (cl-letf (((get 'git-revision 'beginning-op) - (lambda () - (if (re-search-backward "[^a-z0-9.]" nil t) - (forward-char) - (goto-char (point-min))))) - ((get 'git-revision 'end-op) - (lambda () - (and (re-search-forward "[^a-z0-9.]" nil t) - (backward-char))))) - (bounds-of-thing-at-point 'git-revision))) - (range (buffer-substring-no-properties (car bounds) (cdr bounds)))) - ;; Validate but return as-is. - (and (magit-hash-range range) range))) - -;;; Completion - -(defvar magit-revision-history nil) - -(defun magit--minibuf-default-add-commit () - (let ((fn minibuffer-default-add-function)) - (setq-local - minibuffer-default-add-function - (lambda () - (let ((rest (and (functionp fn) (funcall fn)))) - (if-let ((commit (with-selected-window (minibuffer-selected-window) - (or (magit-thing-at-point 'git-revision-range t) - (magit-commit-at-point))))) - (let ((rest (cons commit (delete commit rest))) - (def minibuffer-default)) - (if (listp def) - (append def rest) - (cons def (delete def rest)))) - rest)))))) - -(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 exclude) - (let ((current (magit-get-current-branch)) - (branch-at-point (magit-branch-at-point)) - (commit-at-point (magit-commit-at-point)) - (choices (delete exclude (magit-list-refnames nil t)))) - (when (equal current exclude) - (setq current nil)) - (when (equal branch-at-point exclude) - (setq branch-at-point nil)) - (when (and commit-at-point (not branch-at-point)) - (setq choices (cons commit-at-point choices))) - (minibuffer-with-setup-hook #'magit--minibuf-default-add-commit - (or (magit-completing-read - prompt choices nil nil nil 'magit-revision-history - (or branch-at-point commit-at-point secondary-default current)) - (user-error "Nothing selected"))))) - -(defun magit-read-range-or-commit (prompt &optional secondary-default) - (magit-read-range - prompt - (or (and-let* ((revs (magit-region-values '(commit branch) t))) - (progn - (deactivate-mark) - (concat (car (last revs)) ".." (car revs)))) - (magit-branch-or-commit-at-point) - secondary-default - (magit-get-current-branch)))) - -(defun magit-read-range (prompt &optional default) - (minibuffer-with-setup-hook - (lambda () - (magit--minibuf-default-add-commit) - (setq-local 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 - (cl-union (and local-branch - (if remote - (list local-branch) - (mapcar (##concat % "/" local-branch) - (magit-list-remotes)))) - (magit-list-remote-branch-names remote t) - :test #'equal) - 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)) - (minibuffer-with-setup-hook #'magit--minibuf-default-add-commit - (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)))) - (minibuffer-with-setup-hook #'magit--minibuf-default-add-commit - (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)) - (seq-find (##not (equal % 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))) - (and-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-gitdir) 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) - ;; Some predicates use the inefficient `magit-toplevel' - ;; and some repositories have thousands of submodules. - (let ((magit--refresh-cache (list (cons 0 0))) - (modules nil)) - (if current-prefix-arg - (progn - (setq modules (magit-list-module-paths)) - (when predicate - (setq modules (seq-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 'module)) - (when modules - (when predicate - (setq modules (seq-filter predicate modules))) - (unless modules - (user-error "No modules satisfying %s selected" predicate)))) - (if (or (length> modules 1) current-prefix-arg) - (magit-confirm t nil (format "%s %%d 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-20250519.1537/magit-gitignore.el b/elpa/magit-20250519.1537/magit-gitignore.el deleted file mode 100644 index 0ee63df0..00000000 --- a/elpa/magit-20250519.1537/magit-gitignore.el +++ /dev/null @@ -1,195 +0,0 @@ -;;; magit-gitignore.el --- Intentionally untracked files -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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 (##magit-get "core.excludesfile") - :description (##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 (expand-file-name "info/exclude" (magit-gitdir))) - (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 - (mapcan - (lambda (file) - (cons (concat "/" file) - (and-let* ((ext (file-name-extension file))) - (list (concat "/" (file-name-directory file) "*." 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. - (seq-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-20250519.1537/magit-log.el b/elpa/magit-20250519.1537/magit-log.el deleted file mode 100644 index 3c4ac21d..00000000 --- a/elpa/magit-20250519.1537/magit-log.el +++ /dev/null @@ -1,2051 +0,0 @@ -;;; magit-log.el --- Inspect Git history -*- lexical-binding:t; coding:utf-8 -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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--any-wip-mode-enabled-p "magit-wip" ()) -(declare-function magit-blob-visit "magit-files" (blob-or-file)) -(declare-function magit-cherry-apply "magit-sequence" (commit &optional args)) -(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 include-dirs)) -(declare-function magit-rebase--get-state-lines "magit-sequence" - (file)) -(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) - -(make-obsolete-variable 'magit-log-highlight-keywords - 'magit-log-wash-summary-hook - "Magit 4.3.0") - -(make-obsolete-variable 'magit-log-format-message-function - 'magit-log-wash-summary-hook - "Magit 4.3.0") - -;;; 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. - -The default value lists the arguments that are incompatible with -`--graph' and therefore must be dropped when that is used. You -can add additional arguments that are available in `magit-log', -but I recommend that you don't do that. Nowadays I would define -this as a constant, but I am preserving it as an option, in case -someone actually customized it." - :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-wash-summary-hook - (list #'magit-highlight-squash-markers - #'magit-highlight-bracket-keywords) - "Functions used to highlight parts of each individual commit summary. - -These functions are called in order, in a buffer that containing the -first line of the commit message. They should set text properties as -they see fit, usually just `font-lock-face'. Before each function is -called, point is at the beginning of the buffer. - -See also the related `magit-revision-wash-message-hook'. You likely -want to use the same functions for both hooks." - :package-version '(magit . "4.3.0") - :group 'magit-log - :type 'hook - :options (list #'magit-highlight-squash-markers - #'magit-highlight-bracket-keywords)) - -(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 `(radio (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 `(radio (function-item ,#'magit-which-function) - (function-item ,#'which-function) - (function-item ,#'add-log-current-defun) - function)) - -(defcustom magit-log-color-graph-limit 256 - "Number of commits over which log graphs are not colored. -When showing more commits than specified, then the `--color' -argument is silently dropped. This is necessary because the -`ansi-color' library, which is used to turn control sequences -into faces, is just too slow." - :package-version '(magit . "4.0.0") - :group 'magit-log - :type 'number) - -(defcustom magit-log-show-signatures-limit 256 - "Number of commits over which signatures are not verified. -When showing more commits than specified by this option, then the -`--show-signature' argument, if specified, is silently dropped. -This is necessary because checking the signature of a large -number of commits is just too slow." - :package-version '(magit . "4.0.0") - :group 'magit-log - :type 'number) - -(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 - (list #'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) - -(defcustom magit-log-merged-commit-count 20 - "How many surrounding commits to show for `magit-log-merged'. -`magit-log-merged' will shows approximately half of this number -commits before and half after." - :package-version '(magit . "3.3.0") - :group 'magit-log - :type 'integer) - -;;; 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))) - (when-let (((not (eq transient-current-command 'magit-dispatch))) - (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)) - (magit--transient-args-and-files) - (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)) - ((when-let (((memq use-buffer-args '(always selected))) - (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 ,files) (magit--transient-args-and-files))) - (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 - -(transient-define-group magit-log-infix-arguments - ;; 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" - :if magit-log-infix-arguments--show-p - (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" - :if magit-log-infix-arguments--show-p - ( "-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" - :if magit-log-infix-arguments--show-p - (magit-log:--*-order) - ("-r" "Reverse order" "--reverse")] - ["Formatting" - :if magit-log-infix-arguments--show-p - ("-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 - -(defun magit-log-infix-arguments--show-p () - (if (eq (oref (transient-prefix-object) command) 'magit-log-refresh) - (eq major-mode 'magit-log-mode) - t)) - -;;;###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 - 'magit-log-infix-arguments - [["Log" - ("l" magit-log-current) - ("o" "other" magit-log-other) - ("h" "HEAD" magit-log-head :level 0) - ("u" "related" magit-log-related)] - ["" - ("L" "local branches" magit-log-branches) - ("b" "all branches" magit-log-all-branches) - ("a" "all references" magit-log-all) - ("B" "matching branches" magit-log-matching-branches :level 7) - ("T" "matching tags" magit-log-matching-tags :level 7) - ("m" "merged" magit-log-merged :level 7)] - ["Reflog" - ("r" "current" magit-reflog-current) - ("O" "other" magit-reflog-other) - ("H" "HEAD" magit-reflog-head)] - [:if magit--any-wip-mode-enabled-p - :description "Wiplog" - ("i" "index" magit-wip-log-index) - ("w" "worktree" magit-wip-log-worktree)] - ["Other" - ("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 - magit-log-infix-arguments - [: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-and-exit) - ("w" "buffer and save defaults" transient-save-and-exit)] - ["Margin" - (magit-toggle-margin) - (magit-cycle-margin-style) - (magit-toggle-margin-details) - (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-keymap magit-log-read-revs-map - :parent crm-local-completion-map - "SPC" #'self-insert-command) - -(defun magit-log-read-revs (&optional use-current) - (or (and use-current (and-let* ((buf (magit-get-current-branch))) (list buf))) - (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) - (and (not 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 (autoload 'magit-log-current "magit-log" nil t) -(transient-define-suffix magit-log-current (&optional args files) - "Show log for the current branch, or `HEAD' if no branch is checked out." - :description (##if (magit-get-current-branch) "current" "HEAD") - (interactive (magit-log-arguments)) - (magit-log-setup-buffer (list (or (magit-get-current-branch) "HEAD")) - 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-related (revs &optional args files) - "Show log for the current branch, its upstream and its push target. -When the upstream is a local branch, then also show its own -upstream. When `HEAD' is detached, then show log for that, the -previously checked out branch and its upstream and push-target." - (interactive - (cons (let ((current (magit-get-current-branch)) - head rebase target upstream upup) - (unless current - (setq rebase (magit-rebase--get-state-lines "head-name")) - (cond (rebase - (setq rebase (magit-ref-abbrev rebase)) - (setq current rebase) - (setq head "HEAD")) - ((setq current (magit-get-previous-branch))))) - (cond (current - (setq current - (magit--propertize-face current 'magit-branch-local)) - (setq target (magit-get-push-branch current t)) - (setq upstream (magit-get-upstream-branch current)) - (when upstream - (setq upup (and (magit-local-branch-p upstream) - (magit-get-upstream-branch upstream))))) - ((setq head "HEAD"))) - (delq nil (list current head target upstream upup))) - (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-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 (magit-file-region-line-numbers))) - (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 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" - (string-replace ":" "\\:" (regexp-quote fn)) - (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 -`magit-log-merged-commit-count' 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 (magit-git-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) - ;; Output: "". - ;; This is not the same as `string-trim'. - (setq m (string-trim-left (substring m (string-match " " m)))) - (if (equal m "Commit is directly on this branch.") - (let* ((from (format "%s~%d" commit - (/ magit-log-merged-commit-count 2))) - (to (- (car (magit-rev-diff-count branch commit t)) - (/ magit-log-merged-commit-count 2))) - (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 (seq-find (##string-match "^-n\\([0-9]+\\)?$" %) val)) - (num (and arg (string-to-number (match-string 1 arg)))) - (num (if num (funcall fn num 2) 256))) - (setq val (remove arg val)) - (setq magit-buffer-log-args - (if (and num (> num 0)) - (cons (format "-n%d" num) val) - val))) - (magit-refresh)) - -(defun magit-log-get-commit-limit (&optional args) - (and-let* ((str (seq-find (##string-match "^-n\\([0-9]+\\)?$" %) - (or args magit-buffer-log-args)))) - (string-to-number (match-string 1 str)))) - -;;;; 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 (and (derived-mode-p 'magit-log-mode) - (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 (seq-find (##equal (oref % 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 (or (magit-completing-read - "In log, jump to" - (magit-list-refnames nil t) - nil nil nil 'magit-revision-history - (or (and-let* ((rev (magit-commit-at-point))) - (magit-rev-fixup-target rev)) - (magit-get-current-branch))) - (user-error "Nothing selected")))) - (with-current-buffer - (cond ((derived-mode-p 'magit-log-mode) - (current-buffer)) - ((and-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)) - -;;;; Movement Commands - -(defvar magit-reference-movement-faces - '(magit-tag - magit-branch-remote - magit-branch-remote-head - magit-branch-local - magit-branch-current - magit-branch-upstream - magit-branch-warning - magit-head - magit-refname - magit-refname-stash - magit-refname-wip - magit-refname-pullreq)) - -(defvar-keymap magit-reference-navigation-repeat-map - :repeat t - "p" #'magit-previous-reference - "n" #'magit-next-reference - "r" #'magit-next-reference) - -(defun magit-previous-reference () - "Move to the previous Git reference appearing in the current buffer. - -Move to the previous location that uses a face appearing in -`magit-reference-movement-faces'. If `repeat-mode' is enabled, -this command and its counterpart can be repeated using \ -\\\ -\\[magit-previous-reference] and \\[magit-next-reference]." - (interactive) - (magit-next-reference t)) - -(defun magit-next-reference (&optional previous) - "Move to the next Git reference appearing in the current buffer. - -Move to the next location that uses a face appearing in -`magit-reference-movement-faces'. If `repeat-mode' is enabled, -this command and its counterpart can be repeated using \ -\\\ -\\[magit-previous-reference] and \\[magit-next-reference]." - (interactive) - (catch 'found - (let ((pos (point))) - (while (and (not (eobp)) - (setq pos (if previous - (previous-single-property-change pos 'face) - (next-single-property-change pos 'face)))) - (when (cl-intersection (ensure-list (get-text-property pos 'face)) - magit-reference-movement-faces) - (throw 'found (goto-char pos)))) - (message "No more references")))) - -;;; Log Mode - -(defvar magit-log-disable-graph-hack-args - '("-G" "--grep" "--author") - "Arguments which disable the graph speedup hack.") - -(defvar-keymap magit-log-mode-map - :doc "Keymap for `magit-log-mode'." - :parent magit-mode-map - "C-c C-b" #'magit-go-backward - "C-c C-f" #'magit-go-forward - "C-c C-n" #'magit-log-move-to-parent - "j" #'magit-log-move-to-revision - "=" #'magit-log-toggle-commit-limit - "+" #'magit-log-double-commit-limit - "-" #'magit-log-half-commit-limit - "q" #'magit-log-bury-buffer) - -(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}" - :interactive nil - :group 'magit-log - (magit-hack-dir-local-variables) - (setq magit--imenu-item-types 'commit)) - -(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) - (limit (magit-log-get-commit-limit))) - (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) - (let ((re (concat "^" (regexp-opt magit-log-remove-graph-args)))) - (seq-some (##string-match-p re %) args))) - (setq args (remove "--graph" args))) - (setq args (magit-log--maybe-drop-color-graph args limit)) - (when-let* ((limit 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-search ".." revs)) - (not (member revs '("--all" "--branches"))) - (not (seq-some - (lambda (arg) - (seq-some (##string-prefix-p % 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)))) - (let ((delay (cl-find-if (##member % '("++header" "--patch" "--stat")) - args))) - (setq magit-section-inhibit-markers (if delay 'delay t)) - (setq magit-section-insert-in-reverse (not delay))) - (magit-insert-section (logbuf) - (magit--insert-log t revs args files)))) - -(defvar-local magit-log--color-graph nil) - -(defun magit-log--maybe-drop-color-graph (args limit) - (if (member "--color" args) - (if (cond ((not (member "--graph" args))) - ((not magit-log-color-graph-limit) nil) - ((not limit) - (message "Dropping --color because -n isn't set (see %s)" - 'magit-log-color-graph-limit)) - ((> limit magit-log-color-graph-limit) - (message "Dropping --color because -n is larger than %s" - 'magit-log-color-graph-limit))) - (progn (setq args (remove "--color" args)) - (setq magit-log--color-graph nil)) - (setq magit-log--color-graph t)) - (setq magit-log--color-graph nil)) - args) - -(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 (##if (string-search " " %) (prin1 %) %) - `("git" "log" ,@args ,@revs "--" ,@files) - " ")) - -(defun magit-log-header-line-sentence (revs args files) - "Return string containing all arguments." - (concat "Commits in " - (string-join revs " ") - (and (member "--reverse" args) - " in reverse") - (and files (concat " touching " - (string-join files " "))) - (seq-some (##and (string-prefix-p "-L" %) - (concat " " %)) - args))) - -(defun magit-insert-log (revs &optional args files) - (declare (obsolete magit--insert-log "Magit 4.0.0")) - (magit--insert-log nil revs args files)) - -(defun magit--insert-log (keep-error revs &optional args files) - "Insert a log section. -Do not add this to a hook variable." - (declare (indent defun)) - (setq magit-section-preserve-visibility t) ; TODO do it here? - (let ((magit-git-global-arguments - (remove "--literal-pathspecs" magit-git-global-arguments))) - (magit--git-wash (apply-partially #'magit-log-wash-log 'log) keep-error - "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 (not (member "--show-signature" args)) - "" - (setq args (remove "--show-signature" args)) - (let ((limit (magit-log-get-commit-limit args))) - (cond - ((not limit) - (message - "Dropping --show-signature because -n isn't set (see %s)" - 'magit-log-show-signatures-limit) - "") - ((> limit magit-log-show-signatures-limit) - (message - "Dropping --show-signature because -n is larger than %s" - 'magit-log-show-signatures-limit) - "") - ("%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 ((order (seq-find (##string-match "^\\+\\+order=\\(.+\\)$" %) - args))) - (setq args (cons (format "--%s-order" (match-string 1 order)) - (remove order 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))) - -(cl-defmethod magit-menu-common-value ((_section magit-commit-section)) - (or (magit-diff--region-range) - (oref (magit-current-section) value))) - -(defvar-keymap magit-commit-section-map - :doc "Keymap for `commit' sections." - " " #'magit-show-commit - "<3>" (magit-menu-item "Apply %x" #'magit-cherry-apply) - "<2>" (magit-menu-item "Show commit %x" #'magit-show-commit - '(:visible (not (region-active-p)))) - "<1>" (magit-menu-item "Diff %x" #'magit-diff-range - '(:visible (region-active-p)))) - -(defvar-keymap magit-module-commit-section-map - :doc "Keymap for `module-commit' sections." - :parent magit-commit-section-map) - -(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]+\\)? " ; hash - "\\(?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]+\\) " ; hash - "\\(?2:.*\\)$")) ; msg - -(defconst magit-log-module-re - (concat "^" - "\\(?:\\(?11:[<>]\\) \\)?" ; side - "\\(?1:[0-9a-fA-F]+\\) " ; hash - "\\(?2:.*\\)$")) ; msg - -(defconst magit-log-bisect-vis-re - (concat "^" - "\\(?4:[-_/|\\*o<>. ]*\\)" ; graph - "\\(?1:[0-9a-fA-F]+\\)?\0" ; hash - "\\(?3:[^\0\n]+\\)?\0" ; refs - "\\(?2:.*\\)$")) ; msg - -(defconst magit-log-bisect-log-re - (concat "^# " - "\\(?3:[^: \n]+:\\) " ; "refs" - "\\[\\(?1:[^]\n]+\\)\\] " ; hash - "\\(?2:.*\\)$")) ; msg - -(defconst magit-log-reflog-re - (concat "^" - "\\(?1:[^\0\n]+\\)\0" ; hash - "\\(?5:[^\0\n]*\\)\0" ; author - "\\(?:\\(?:[^@\n]+@{\\(?6:[^}\n]+\\)}\0" ; date - ;;; refsub - "\\(?10:merge \\|autosave \\|restart \\|rewritten \\|[^:\n]+: \\)?" - "\\(?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" ; "hash" - "\\(?5:[^\0\n]*\\)\0" ; author - "\\(?6:[^\0\n]+\\)\0" ; date - "\\(?2:.*\\)$")) ; msg - -(defvar magit-log-count nil) - -(defun magit-log-wash-log (style args) - (setq args (flatten-tree args)) - (when (if (derived-mode-p 'magit-log-mode) - magit-log--color-graph - (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 - ((eval (pcase style - ('stash 'stash) - ('module 'module-commit) - (_ 'commit))) - hash) - (setq hash (propertize (if (eq style 'bisect-log) - (magit-rev-parse "--short" hash) - 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-search ":" refsub) -2 -1)))))) - (insert (magit-log--wash-summary 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)))) - (magit-log-format-margin hash author date)) - (when (and (eq style 'cherry) - (magit-buffer-margin-p)) - (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 "") - (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))) - (forward-line) - (magit-make-margin-overlay)) - ;; 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--wash-summary (summary) - (with-temp-buffer - (save-excursion (insert summary)) - (run-hook-wrapped 'magit-log-wash-summary-hook - (lambda (fn) (prog1 nil (save-excursion (funcall fn))))) - (buffer-string))) - -(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 (seq-find (##with-current-buffer % - (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 (seq-find (##equal (oref % 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) - -(transient-define-suffix magit-toggle-log-margin-style () - "Toggle between the regular and the shortstat margin style. -The shortstat style is experimental and rather slow." - :description "Toggle shortstat" - :key "x" - :transient t - (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) - (pcase-let ((`(,_ ,style ,width ,details ,details-width) - (or magit-buffer-margin - (symbol-value (magit-margin-option)) - (error "No margin format specified for %s" major-mode)))) - (magit-make-margin-overlay - (concat (and details - (concat (magit--propertize-face - (truncate-string-to-width - (or author "") - details-width - nil ?\s - (magit--ellipsis 'margin)) - '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 "%%2d%%-%dc" "%%2d %%-%ds") - (- width (if details (1+ details-width) 0))) - cnt unit))) - 'magit-log-date))))) - -(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 (mapcar (##max (length (nth 1 %)) - (length (nth 2 %))) - magit--age-spec))))))))) - -;;; Select Mode - -(defvar-keymap magit-log-select-mode-map - :doc "Keymap for `magit-log-select-mode'." - :parent magit-log-mode-map - "C-c C-b" #'undefined - "C-c C-f" #'undefined - "." #'magit-log-select-pick - "e" #'magit-log-select-pick - "C-c C-c" #'magit-log-select-pick - "q" #'magit-log-select-quit - "C-c C-k" #'magit-log-select-quit) -(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 - (magit-hack-dir-local-variables)) - -(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 () - (setq magit-section-inhibit-markers t) - (setq magit-section-insert-in-reverse t) - (magit-insert-section (logbuf) - (magit--insert-log t magit-buffer-revisions - (magit-log--maybe-drop-color-graph - magit-buffer-log-args - (magit-log-get-commit-limit))))) - -(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)))) - (if initial - (magit-log-goto-commit-section initial) - (while-let ((rev (magit-section-value-if 'commit)) - ((string-match-p "\\`\\(squash!\\|fixup!\\|amend!\\)" - (magit-rev-format "%s" rev))) - (section (magit-current-section)) - (next (car (magit-section-siblings section 'next)))) - (magit-section-goto next))) - (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-keymap magit-cherry-mode-map - :doc "Keymap for `magit-cherry-mode'." - :parent magit-mode-map - "q" #'magit-log-bury-buffer - "L" #'magit-margin-settings) - -(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}" - :interactive nil - :group 'magit-log - (magit-hack-dir-local-variables) - (setq magit--imenu-group-types 'cherries)) - -(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 () - (setq magit-section-insert-in-reverse t) - (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 t "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-keymap magit-log-section-map - :doc "Keymap for log sections. -The classes `magit-{unpulled,unpushed,unmerged}-section' derive -from the abstract `magit-log-section' class. Accordingly this -keymap is the parent of their keymaps." - " " #'magit-diff-dwim - "<1>" (magit-menu-item "Visit diff" #'magit-diff-dwim)) - -(cl-defmethod magit-section-ident-value ((section magit-unpulled-section)) - "Return \"..@{push}\". -\"..@{push}\" cannot be used as the value because that is ambiguous -if `push.default' does not allow a 1:1 mapping, and many commands -would fail because of that. But here that does not matter and we -need an unique value, so we use that string in the pushremote case." - (let ((value (oref section value))) - (if (equal value "..@{upstream}") value "..@{push}"))) - -(magit-define-section-jumper magit-jump-to-unpulled-from-upstream - "Unpulled from @{upstream}" unpulled "..@{upstream}" - magit-insert-unpulled-from-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 nil "..@{upstream}" magit-buffer-log-args) - (magit-log-insert-child-count)))) - -(magit-define-section-jumper magit-jump-to-unpulled-from-pushremote - "Unpulled from " unpulled "..@{push}" - magit-insert-unpulled-from-pushremote) - -(defun magit-insert-unpulled-from-pushremote () - "Insert commits that haven't been pulled from the push-remote yet." - (when-let* ((target (magit-get-push-branch)) - (range (concat ".." target)) - ((magit--insert-pushremote-log-p))) - (magit-insert-section (unpulled range t) - (magit-insert-heading - (format (propertize "Unpulled from %s." - 'font-lock-face 'magit-section-heading) - (propertize target 'font-lock-face 'magit-branch-remote))) - (magit--insert-log nil range magit-buffer-log-args) - (magit-log-insert-child-count)))) - -(cl-defmethod magit-section-ident-value ((section magit-unpushed-section)) - "Return \"..@{push}\". -\"..@{push}\" cannot be used as the value because that is ambiguous -if `push.default' does not allow a 1:1 mapping, and many commands -would fail because of that. But here that does not matter and we -need an unique value, so we use that string in the pushremote case." - (let ((value (oref section value))) - (if (equal value "@{upstream}..") value "@{push}.."))) - -(magit-define-section-jumper magit-jump-to-unpushed-to-upstream - "Unpushed to @{upstream}" unpushed "@{upstream}.." nil - :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")))) - -(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 nil "@{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 nil - (and (member "--graph" magit-buffer-log-args) range) - (cons (format "-n%d" magit-log-section-commit-count) - (seq-remove (##string-prefix-p "-n" %) - magit-buffer-log-args)))))) - -(magit-define-section-jumper magit-jump-to-unpushed-to-pushremote - "Unpushed to " unpushed "@{push}.." - magit-insert-unpushed-to-pushremote) - -(defun magit-insert-unpushed-to-pushremote () - "Insert commits that haven't been pushed to the push-remote yet." - (when-let* ((target (magit-get-push-branch)) - (range (concat target "..")) - ((magit--insert-pushremote-log-p))) - (magit-insert-section (unpushed range t) - (magit-insert-heading - (format (propertize "Unpushed to %s." - 'font-lock-face 'magit-section-heading) - (propertize target 'font-lock-face 'magit-branch-remote))) - (magit--insert-log nil range magit-buffer-log-args) - (magit-log-insert-child-count)))) - -(defun magit--insert-pushremote-log-p () - (magit--with-refresh-cache - (cons default-directory '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 (eq 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 t "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 t "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-20250519.1537/magit-margin.el b/elpa/magit-20250519.1537/magit-margin.el deleted file mode 100644 index b710fbdd..00000000 --- a/elpa/magit-20250519.1537/magit-margin.el +++ /dev/null @@ -1,253 +0,0 @@ -;;; magit-margin.el --- Margins in Magit buffers -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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-base) -(require 'magit-transient) -(require 'magit-mode) - -;;; Options - -(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" - (magit-toggle-margin) - (magit-cycle-margin-style) - (magit-toggle-margin-details) - (magit-refs-set-show-commit-count)]) - -(transient-define-suffix magit-toggle-margin () - "Show or hide the Magit margin." - :description "Toggle visibility" - :key "L" - :transient t - (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)) - -(defvar magit-margin-default-time-format nil - "See https://github.com/magit/magit/pull/4605.") - -(transient-define-suffix magit-cycle-margin-style () - "Cycle style used for the Magit margin." - :description "Cycle style" - :key "l" - :transient t - (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 (or magit-margin-default-time-format - (cadr (symbol-value (magit-margin-option)))))) - (if (stringp default) default "%Y-%m-%d %H:%M "))) - (_ 'age))) - (magit-set-buffer-margin nil t)) - -(transient-define-suffix magit-toggle-margin-details () - "Show or hide details in the Magit margin." - :description "Toggle details" - :key "d" - :transient t - (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) - ('forge-topics-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)))))) - -(cl-defun magit-make-margin-overlay (&optional string (previous-line nil sline)) - "Display STRING in the margin of the previous (or current) line. -If point is at the beginning of a line, set the margin string for -the previous line, otherwise for the current line. Semi-obsolete -optional PREVIOUS-LINE can be used to explicitly specify which -line is affected." - (save-excursion - (forward-line (if (if sline previous-line (bolp)) -1 0)) - ;; Don't put the overlay on the complete line to work around #1880. - (let ((o (make-overlay (1+ (point)) (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 " "))))))) - -(defvar magit-margin-overlay-conditions - '( unpulled unpushed recent stashes local cherries - [remote branchbuf] - [shelved branchbuf] - [tags branchbuf] - topics issues pullreqs)) - -(defun magit-maybe-make-margin-overlay () - (when (magit-section-match magit-margin-overlay-conditions - magit-insert-section--current) - (magit-make-margin-overlay))) - -;;; 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-20250519.1537/magit-merge.el b/elpa/magit-20250519.1537/magit-merge.el deleted file mode 100644 index 4dc003ff..00000000 --- a/elpa/magit-20250519.1537/magit-merge.el +++ /dev/null @@ -1,315 +0,0 @@ -;;; magit-merge.el --- Merge functionality -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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=") - (magit:--gpg-sign) - (magit:--signoff)] - ["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) - ("d" "Dissolve" magit-merge-dissolve)]] - ["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-dissolve (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 (let ((branch (magit-get-current-branch))) - (magit-read-other-local-branch - (format "Merge `%s' into" (or branch (magit-rev-parse "HEAD"))) - nil - (and branch (magit-get-local-upstream-branch branch)))) - (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 &optional message) - (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)) - (when message - (message message)))))) - (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 (expand-file-name "MERGE_HEAD" (magit-gitdir))) - (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 ,_) - '("--ours" ?U ?A) - `("--theirs" ,_ ?D) - '("--theirs" ?A ?U)) - (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 (expand-file-name "MERGE_HEAD" (magit-gitdir)))) - -(defun magit--merge-range (&optional head) - (unless head - (setq head (magit-get-shortname - (car (magit-file-lines - (expand-file-name "MERGE_HEAD" (magit-gitdir))))))) - (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 (if magit-verbose-messages "restore [c]onflict" "[c]onflict") - "--merge"))) - -;;; 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 - (expand-file-name "MERGE_HEAD" (magit-gitdir))))) - (range (magit--merge-range (car heads)))) - (magit-insert-section (unmerged range) - (magit-insert-heading - (format "Merging %s:" (string-join heads ", "))) - (magit--insert-log nil - 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-20250519.1537/magit-mode.el b/elpa/magit-20250519.1537/magit-mode.el deleted file mode 100644 index 34af2422..00000000 --- a/elpa/magit-20250519.1537/magit-mode.el +++ /dev/null @@ -1,1546 +0,0 @@ -;;; magit-mode.el --- Create and refresh Magit buffers -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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-base) -(require 'magit-git) - -(require 'benchmark) -(require 'browse-url) -(require 'format-spec) -(require 'help-mode) - -(require 'transient) - -(defvar bookmark-make-record-function) - -(eval-when-compile (require 'elp)) -(declare-function elp-reset-all "elp" ()) -(declare-function elp-instrument-package "elp" (prefix)) -(declare-function elp-results "elp" ()) -(declare-function elp-restore-all "elp" ()) - -(defvar magit--wip-inhibit-autosave) -(defvar magit-wip-after-save-local-mode) -(declare-function magit-wip-get-ref "magit-wip" ()) -(declare-function magit-wip-commit-worktree "magit-wip" (ref files msg)) - -;;; Options - -(defcustom magit-mode-hook - (list #'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 (list #'magit-load-config-extensions - #'bug-reference-mode)) - -(defcustom magit-setup-buffer-hook - (list #'magit-maybe-save-repository-buffers - 'magit-set-buffer-margin) ; from magit-margin.el - "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 (list #'magit-maybe-save-repository-buffers - 'magit-set-buffer-margin)) - -(defcustom magit-pre-refresh-hook - (list #'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 (list #'magit-maybe-save-repository-buffers)) - -(defcustom magit-post-refresh-hook - ;; Do not function-quote to avoid circular dependencies. - '(magit-auto-revert-buffers - magit-run-post-commit-hook - magit-run-post-stage-hook - magit-run-post-unstage-hook) - "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 - :options '(magit-auto-revert-buffers - magit-run-post-commit-hook - magit-run-post-stage-hook - magit-run-post-unstage-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 - (list #'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 (list #'magit-save-window-configuration)) - -(defcustom magit-post-display-buffer-hook (list #'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 (list #'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. - -The value should always contain \"%m\" or \"%M\", \"%v\" or \"%V\", and -\"%t\". If `magit-uniquify-buffer-names' is non-nil, then the -value must end with \"%t\" or \"%t%x\". 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) ; from magit-diff.el - "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 while creating a new `magit-mode' buffer. -Runs before the buffer is populated with sections. Also see -`magit-post-create-buffer-hook'." - :package-version '(magit . "2.90.0") - :group 'magit-refresh - :type 'hook) - -(defcustom magit-post-create-buffer-hook nil - "Normal hook run after creating a new `magit-mode' buffer. -Runs after the buffer is populated with sections for the first -time. Also see `magit-create-buffer-hook' (which runs earlier) -and `magit-refresh-buffer-hook' (which runs on every refresh)." - :package-version '(magit . "4.0.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-keymap magit-mode-map - :doc "Parent keymap for all keymaps of modes derived from `magit-mode'." - :parent magit-section-mode-map - ;; Don't function-quote but make sure all commands are autoloaded. - "C-" 'magit-visit-thing - "RET" 'magit-visit-thing - "M-TAB" 'magit-dired-jump - "M-" 'magit-section-cycle-diffs - "SPC" 'magit-diff-show-or-scroll-up - "S-SPC" 'magit-diff-show-or-scroll-down - "DEL" 'magit-diff-show-or-scroll-down - "+" 'magit-diff-more-context - "-" 'magit-diff-less-context - "0" 'magit-diff-default-context - "a" 'magit-cherry-apply - "A" 'magit-cherry-pick - "b" 'magit-branch - "B" 'magit-bisect - "c" 'magit-commit - "C" 'magit-clone - "d" 'magit-diff - "D" 'magit-diff-refresh - "e" 'magit-ediff-dwim - "E" 'magit-ediff - "f" 'magit-fetch - "F" 'magit-pull - "g" 'magit-refresh - "G" 'magit-refresh-all - "h" 'magit-dispatch - "?" 'magit-dispatch - "H" 'magit-describe-section - "i" 'magit-gitignore - "I" 'magit-init - "j" 'magit-status-quick - "J" 'magit-display-repository-buffer - "k" 'magit-delete-thing - "K" 'magit-file-untrack - "l" 'magit-log - "L" 'magit-log-refresh - "m" 'magit-merge - "M" 'magit-remote - ;; "n" magit-section-forward in magit-section-mode-map - ;; "N" forge-dispatch, added by forge package - "o" 'magit-submodule - "O" 'magit-subtree - ;; "p" magit-section-backward in magit-section-mode-map - "P" 'magit-push - "q" 'magit-mode-bury-buffer - "Q" 'magit-git-command - ":" 'magit-git-command - "r" 'magit-rebase - "R" 'magit-file-rename - "s" 'magit-stage-files - "S" 'magit-stage-modified - "t" 'magit-tag - "T" 'magit-notes - "u" 'magit-unstage-files - "U" 'magit-unstage-all - "v" 'magit-revert-no-commit - "V" 'magit-revert - "w" 'magit-am - "W" 'magit-patch - "x" 'magit-reset-quickly - "X" 'magit-reset - "y" 'magit-show-refs - "Y" 'magit-cherry - "z" 'magit-stash - "Z" 'magit-worktree - "%" 'magit-worktree - "$" 'magit-process-buffer - "!" 'magit-run - ">" 'magit-sparse-checkout - "C-c C-c" 'magit-dispatch - "C-c C-r" 'magit-next-reference - "C-c C-e" 'magit-edit-thing - "C-c C-o" 'magit-browse-thing - "C-c C-w" 'magit-copy-thing - "C-w" 'magit-copy-section-value - "M-w" 'magit-copy-buffer-revision - " " 'magit-back-to-indentation - " " 'magit-previous-line - " " 'magit-next-line - " " 'evil-previous-visual-line - " " 'evil-next-visual-line) - -(defun magit-delete-thing () - "This is a placeholder command, which signals an error if called. -Where applicable, other keymaps remap this command to another, -which actually deletes the thing at point." - (interactive) - (user-error "There is no thing at point that could be deleted")) -;; Starting with Emacs 28.1 we could use (declare (completion ignore)). -(put 'magit-delete-thing 'completion-predicate #'ignore) - -(defun magit-visit-thing () - "This is a placeholder command, which may signal an error if called. -Where applicable, other keymaps remap this command to another, -which actually visits the thing at point." - (interactive) - (if (eq transient-current-command 'magit-dispatch) - (call-interactively (key-binding (this-command-keys))) - (if-let ((url (thing-at-point 'url t))) - (browse-url url) - (user-error "There is no thing at point that could be visited")))) -(put 'magit-visit-thing 'completion-predicate #'ignore) - -(defun magit-edit-thing () - "This is a placeholder command, which may signal an error if called. -Where applicable, other keymaps remap this command to another, -which actually 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"))) -(put 'magit-edit-thing 'completion-predicate #'ignore) - -(defun magit-browse-thing () - "This is a placeholder command, which may signal an error if called. -Where applicable, other keymaps remap this command to another, -which actually visits thing at point using `browse-url'." - (interactive) - (if-let ((url (thing-at-point 'url t))) - (browse-url url) - (user-error "There is no thing at point that could be browsed"))) -(put 'magit-browse-thing 'completion-predicate #'ignore) - -(defun magit-copy-thing () - "This is a placeholder command, which signals an error if called. -Where applicable, other keymaps remap this command to another, -which actually copies some representation of the thing at point -to the kill ring." - (interactive) - (user-error "There is no thing at point that we know how to copy")) -(put 'magit-copy-thing 'completion-predicate #'ignore) - -;;;###autoload -(defun magit-info () - "Visit the Magit manual." - (interactive) - (info "magit")) - -(defvar bug-reference-map) -(with-eval-after-load 'bug-reference - (keymap-set bug-reference-map " " - 'bug-reference-push-button)) - -(easy-menu-define magit-mode-menu magit-mode-map - "Magit menu." - ;; Similar to `magit-dispatch' but exclude: - ;; - commands that are available from context menus: - ;; apply, reverse, discard, stage, unstage, - ;; cherry-pick, revert, reset, - ;; describe-section - ;; - commands that are available from submenus: - ;; git-command, ediff-dwim - ;; - and: refresh-all, status-jump, status-quick. - '("Magit" - "---" "Inspect" - [" Bisect..." magit-bisect t] - [" Cherries..." magit-cherry t] - [" Diff..." magit-diff t] - [" Ediff..." magit-ediff t] - [" Log..." magit-log t] - [" References..." magit-show-refs t] - "---" "Manipulate" - [" Commit..." magit-commit t] - [" Stash..." magit-stash t] - [" Tag..." magit-tag t] - "---" - [" Branch..." magit-branch t] - [" Remote..." magit-remote t] - "---" - [" Merge..." magit-merge t] - [" Rebase..." magit-rebase t] - "---" "Transfer" - [" Fetch..." magit-fetch t] - [" Pull..." magit-pull t] - [" Push..." magit-push t] - "---" "Setup" - [" Clone..." magit-clone t] - [" Ignore..." magit-gitignore t] - [" Init..." magit-init t] - "---" - ("Advanced" - ["Run..." magit-run t] - "---" - ["Apply patches..." magit-am t] - ["Format patches..." magit-patch t] - "---" - ["Note..." magit-notes t] - "---" - ["Submodule..." magit-submodule t] - ["Subtree..." magit-subtree t] - ["Worktree..." magit-worktree t]) - "---" - ["Show command dispatcher..." magit-dispatch t] - ["Show manual" magit-info t] - ["Show another buffer" magit-display-repository-buffer t] - "---" - ("Change buffer arguments" - ["Diff arguments" magit-diff-refresh t] - ["Log arguments" magit-log-refresh t]) - ["Refresh buffer" magit-refresh t] - ["Bury buffer" 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)'." - :interactive nil - :group 'magit - (magit-hack-dir-local-variables) - (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-revert-buffer) - (setq-local bookmark-make-record-function #'magit--make-bookmark) - (setq-local imenu-create-index-function #'magit--imenu-create-index) - (setq-local imenu-default-goto-function #'magit--imenu-goto-function) - (setq-local isearch-filter-predicate #'magit-section--open-temporarily)) - -(defun magit-hack-dir-local-variables () - "Like `hack-dir-local-variables-non-file-buffer' but ignore some variables." - (let ((ignored-local-variables - `(show-trailing-whitespace - ,@ignored-local-variables))) - (hack-dir-local-variables-non-file-buffer))) - -;;; Local Variables - -(defvar-local magit-buffer-arguments nil) -(defvar-local magit-buffer-diff-type 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) - -(cl-defgeneric magit-buffer-value () - "Return the value of the current buffer. -The \"value\" identifies what is being displayed in the buffer. -The buffer's major-mode should derive from `magit-section-mode'." - nil) - -(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 - &optional buffer-or-name directory) - (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 (if buffer-or-name - (get-buffer-create buffer-or-name) - (magit-get-mode-buffer mode value))) - (section (and buffer (magit-current-section))) - (created (not buffer))) - (unless buffer - (setq buffer (magit-generate-new-buffer mode value))) - (with-current-buffer buffer - (setq magit-previous-section section) - (when directory - (setq default-directory directory)) - (funcall mode) - (magit-xref-setup #'magit-setup-buffer-internal bindings) - (pcase-dolist (`(,var ,val) bindings) - (set (make-local-variable var) val)) - (when created - (run-hooks 'magit-create-buffer-hook))) - (magit-display-buffer buffer) - (with-current-buffer buffer - (run-hooks 'magit-setup-buffer-hook) - (magit-refresh-buffer created) - (when created - (run-hooks 'magit-post-create-buffer-hook))) - 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 (bound-and-true-p 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))) - (seq-filter (##with-current-buffer % - (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." - (let ((topdir (magit--toplevel-safe))) - (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))))))) - -(defun magit-generate-new-buffer (mode &optional value directory) - (let* ((default-directory (or directory (magit--toplevel-safe))) - (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)) - (magit--maybe-uniquify-buffer-names buffer name mode) - 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" (ensure-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 "" "*")))))) - -(defun magit--maybe-uniquify-buffer-names (buffer name mode) - (when magit-uniquify-buffer-names - (cl-pushnew mode uniquify-list-buffers-directory-modes) - (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 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) - (let ((name (funcall magit-generate-buffer-name-function major-mode)) - (buffer (current-buffer)) - (mode major-mode)) - (rename-buffer (generate-new-buffer-name name)) - (with-temp-buffer - (magit--maybe-uniquify-buffer-names buffer name 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) - (let ((name (funcall magit-generate-buffer-name-function - major-mode value)) - (buffer (current-buffer)) - (mode major-mode)) - (rename-buffer (generate-new-buffer-name name)) - (with-temp-buffer - (magit--maybe-uniquify-buffer-names buffer name mode)))) - (user-error "Buffer has no value it could be locked to")))) - -;;; Bury Buffer - -(defun magit-mode-bury-buffer (&optional kill-buffer) - "Bury or kill the current buffer. - -Use `magit-bury-buffer-function' to bury the buffer when called -without a prefix argument or to kill it when called with a single -prefix argument. - -With two prefix arguments, always kill the current and all other -Magit buffers, associated with this repository." - (interactive "P") - (if (>= (prefix-numeric-value kill-buffer) 16) - (mapc #'kill-buffer (magit-mode-get-buffers)) - (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) - (seq-find (pcase-lambda (`(,buffer)) - (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', `magit-post-refresh-hook' -and `magit-unwind-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 ((buffer (and magit-refresh-status-buffer - (not (derived-mode-p 'magit-status-mode)) - (magit-get-mode-buffer 'magit-status-mode)))) - (with-current-buffer buffer - (magit-refresh-buffer))) - (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-since 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-run-hook-with-benchmark 'magit-post-refresh-hook)) - -(defvar-local magit--refresh-start-time nil) - -(defvar magit--initial-section-hook nil) - -(defun magit-refresh-buffer (&optional created) - "Refresh the current Magit buffer." - (interactive) - (let ((magit--refreshing-buffer-p t) - (magit--refresh-start-time (current-time)) - (magit--refresh-cache (or magit--refresh-cache (list (cons 0 0)))) - (refresh (intern (format "%s-refresh-buffer" - (substring (symbol-name major-mode) 0 -5))))) - (when (functionp refresh) - (when magit-refresh-verbose - (message "Refreshing buffer `%s'..." (buffer-name))) - (let* ((buffer (current-buffer)) - (windows (mapcan - (lambda (window) - (with-selected-window window - (with-current-buffer buffer - (and-let* ((section (magit-section-at))) - `(( ,window - ,section - ,@(magit-section-get-relative-position - section))))))) - ;; 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-selection-overlays nil) - (setq magit-section-highlighted-sections nil) - (let ((inhibit-read-only t)) - (erase-buffer) - (save-excursion - (funcall refresh))) - (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))))) - (when created - (run-hooks 'magit--initial-section-hook) - (setq-local magit--initial-section-hook nil)) - (let ((magit-section-cache-visibility nil)) - (magit-section-show magit-root-section)) - (run-hooks 'magit-refresh-buffer-hook) - (magit-section-update-highlight) - (set-buffer-modified-p nil) - (push buffer magit-section--refreshed-buffers)) - (when magit-refresh-verbose - (message "Refreshing buffer `%s'...done (%.3fs)" (buffer-name) - (float-time (time-since magit--refresh-start-time))))))) - -(defun magit-revert-buffer (_ignore-auto _noconfirm) - "Wrapper around `magit-refresh-buffer' suitable as `revert-buffer-function'." - (magit-refresh-buffer)) - -(defun magit-profile-refresh-buffer () - "Profile refreshing the current Magit buffer." - (interactive) - (require (quote elp)) - (elp-reset-all) - (message "Profiling Magit and Forge...") - (elp-instrument-package "magit-") - (elp-instrument-package "forge-") - (magit-refresh-buffer) - (message "Profiling Magit and Forge...done") - (elp-results) - (elp-reset-all)) - -(defun magit-toggle-profiling () - "Start profiling Magit, or if in progress, stop and display the results." - (interactive) - (require (quote elp)) - (cond ((catch 'in-progress - (mapatoms (##and (get % elp-timer-info-property) - (throw 'in-progress t)))) - (message "Stop profiling and display results...") - (elp-results) - (elp-restore-all)) - (t - (message "Start profiling Magit and Forge...") - (elp-reset-all) - (elp-instrument-package "magit-") - (elp-instrument-package "forge-")))) - -;;; Save File-Visiting Buffers - -(defvar magit--disable-save-buffers nil) - -(defun magit-pre-command-hook () - (setq magit--disable-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 () - (unless magit-inhibit-refresh - (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-let (((and (not magit--disable-save-buffers) - (magit-inside-worktree-p t))) - (buf (ignore-errors (magit-get-mode-buffer 'magit-status-mode)))) - (cl-pushnew buf magit-after-save-refresh-buffers) - (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 magit--disable-save-buffers)) - (setq magit--disable-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))))) - -(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 (##with-current-buffer % - (setq buffer-save-without-query t) - (save-buffer)) - "to save the current buffer and remember choice") - (?N (##with-current-buffer % - (setq magit-inhibit-refresh-save t)) - "to skip the current buffer and remember choice") - ,@save-some-buffers-action-alist)) - (topdirs nil) - (unwiped nil) - (magit--wip-inhibit-autosave t)) - (unwind-protect - (save-some-buffers - arg - (lambda () - ;; If the current file is modified and resides inside - ;; a repository, and a let-binding is in effect, which - ;; places us in another repository, then this binding - ;; is needed to prevent that file from being saved. - (and-let* ((default-directory - (and buffer-file-name - (file-name-directory buffer-file-name)))) - (and - ;; Check whether the repository still exists. - (file-exists-p default-directory) - ;; 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 (or (cdr (assoc default-directory topdirs)) - (let ((top (magit-rev-parse-safe "--show-toplevel"))) - (push (cons default-directory top) topdirs) - top)) - topdir) - ;; Check whether the file is actually writable. - (file-writable-p buffer-file-name) - (prog1 t - ;; Schedule for wip commit, if appropriate. - (when magit-wip-after-save-local-mode - (push (expand-file-name buffer-file-name) unwiped))))))) - (when unwiped - (let ((default-directory topdir)) - (magit-wip-commit-worktree - (magit-wip-get-ref) - unwiped - (if (cdr unwiped) - (format "autosave %s files after save" (length unwiped)) - (format "autosave %s after save" - (file-relative-name (car unwiped))))))))))) - -;;; 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))) - (set-buffer (with-selected-window (selected-window) - (current-buffer)))))) - -;;; 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 - ;; Do not function-quote to avoid circular dependencies. - '(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-let ((tail (nthcdr 30 help-xref-stack))) - (setcdr tail 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." - (and-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. -If REPOSITORY is `all', then delete the value for KEY for all -repositories." - (if (eq repository 'all) - (dolist (cache magit-repository-local-cache) - (setf cache (compat-call assoc-delete-all key cache))) - (when-let ((cache (assoc (or repository - (magit-repository-local-repository)) - magit-repository-local-cache))) - (setf cache (compat-call assoc-delete-all key cache))))) - -(defmacro magit--with-repository-local-cache (key &rest body) - (declare (indent 1) (debug (form body))) - (let ((k (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 (&optional all) - "Zap caches for the current repository. - -Remove the repository's entry from `magit-repository-local-cache', -remove the host's entry from `magit--host-git-version-cache', and -set `magit-section-visibility-cache' to nil for all Magit buffers -of the repository. - -With a prefix argument or if optional ALL is non-nil, discard the -mentioned caches completely." - (interactive) - (cond (all - (setq magit-repository-local-cache nil) - (setq magit--host-git-version-cache nil) - (dolist (buffer (buffer-list)) - (with-current-buffer buffer - (when (derived-mode-p 'magit-mode) - (setq magit-section-visibility-cache nil))))) - (t - (magit-with-toplevel - (setq magit-repository-local-cache - (cl-delete default-directory - magit-repository-local-cache - :key #'car :test #'equal)) - (setq magit--host-git-version-cache - (cl-delete (file-remote-p default-directory) - magit--host-git-version-cache - :key #'car :test #'equal))) - (dolist (buffer (magit-mode-get-buffers)) - (with-current-buffer buffer - (setq magit-section-visibility-cache nil)))))) - -;;; 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) - (cond - ((not hook)) - (magit-refresh-verbose - (message "Running %s..." hook) - (message "Running %s...done (%.3fs)" hook - (benchmark-elapse - (run-hook-wrapped - hook - (lambda (fn) - (message " %-50s %f" fn (benchmark-elapse (funcall fn)))))))) - ((run-hooks hook)))) - -(defun magit-file-region-line-numbers () - "Return the bounds of the region as line numbers. -The returned value has the form (BEGINNING-LINE END-LINE). If -the region end at the beginning of a line, do not include that -line. Avoid including the line after the end of the file." - (and (or magit-buffer-file-name buffer-file-name) - (region-active-p) - (not (= (region-beginning) (region-end) (1+ (buffer-size)))) - (let ((beg (region-beginning)) - (end (min (region-end) (buffer-size)))) - (list (line-number-at-pos beg t) - (line-number-at-pos (if (= (magit--bol-position end) end) - (max beg (1- end)) - end) - t))))) - -;;; _ -(provide 'magit-mode) -;;; magit-mode.el ends here diff --git a/elpa/magit-20250519.1537/magit-notes.el b/elpa/magit-20250519.1537/magit-notes.el deleted file mode 100644 index 0b262158..00000000 --- a/elpa/magit-20250519.1537/magit-notes.el +++ /dev/null @@ -1,201 +0,0 @@ -;;; magit-notes.el --- Notes support -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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 (expand-file-name "NOTES_MERGE_WORKTREE" (magit-gitdir)))) - (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" - :global t - :reader #'magit-notes-read-ref - :prompt "Set global core.notesRef") - -(transient-define-infix magit-global-notes.displayRef () - :class 'magit--git-variable - :variable "notes.displayRef" - :global t - :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) - (and-let* ((ref (magit-completing-read - prompt (magit-list-notes-refnames) nil nil - (and-let* ((def (magit-get "core.notesRef"))) - (if (string-prefix-p "refs/notes/" def) - (substring def 11) - def)) - history))) - (if (string-prefix-p "refs/" ref) - ref - (concat "refs/notes/" ref)))) - -(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)) - (and-let* ((str (seq-find (##string-match "^--ref=\\(.+\\)" %) - (transient-args 'magit-notes)))) - (match-string 1 str)))) - -;;; _ -(provide 'magit-notes) -;;; magit-notes.el ends here diff --git a/elpa/magit-20250519.1537/magit-patch.el b/elpa/magit-20250519.1537/magit-patch.el deleted file mode 100644 index 88641d51..00000000 --- a/elpa/magit-20250519.1537/magit-patch.el +++ /dev/null @@ -1,328 +0,0 @@ -;;; magit-patch.el --- Creating and applying patches -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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 - "Create patches for range or commit"))) - (if (string-search ".." range) - range - (format "%s~..%s" range range)))) - (let ((args (transient-args 'magit-patch-create))) - (list (seq-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 (and-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 - (and-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 - (cl-set-difference args (cdr magit-patch-save-arguments) - :test #'equal)))) - ((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-20250519.1537/magit-pkg.el b/elpa/magit-20250519.1537/magit-pkg.el deleted file mode 100644 index 3a09fdd3..00000000 --- a/elpa/magit-20250519.1537/magit-pkg.el +++ /dev/null @@ -1,18 +0,0 @@ -;; -*- no-byte-compile: t; lexical-binding: nil -*- -(define-package "magit" "20250519.1537" - "A Git porcelain inside Emacs." - '((emacs "27.1") - (compat "30.1.0.0") - (llama "0.6.2") - (magit-section "4.3.5") - (seq "2.24") - (transient "0.8.8") - (with-editor "3.4.3")) - :url "https://github.com/magit/magit" - :commit "9b81df36b4eb6d2443632cb44c67acd8ea1f366f" - :revdesc "9b81df36b4eb" - :keywords '("git" "tools" "vc") - :authors '(("Marius Vollmer" . "marius.vollmer@gmail.com") - ("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev")) - :maintainers '(("Jonas Bernoulli" . "emacs.magit@jonas.bernoulli.dev") - ("Kyle Meyer" . "kyle@kyleam.com"))) diff --git a/elpa/magit-20250519.1537/magit-process.el b/elpa/magit-20250519.1537/magit-process.el deleted file mode 100644 index 2a4083ed..00000000 --- a/elpa/magit-20250519.1537/magit-process.el +++ /dev/null @@ -1,1333 +0,0 @@ -;;; magit-process.el --- Process functionality -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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-base) -(require 'magit-git) -(require 'magit-mode) - -(require 'ansi-color) -(require 'auth-source) -(require 'with-editor) - -(defvar messages-buffer-name) -(defvar y-or-n-p-map) - -(define-obsolete-variable-alias 'magit-process-finish-apply-ansi-colors - 'magit-process-apply-ansi-colors "Magit-Section 4.3.2") - -(defclass magit-process-section (magit-section) - ((process :initform nil))) - -;;; 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)) - -(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 - (seq-some (lambda (line) - (pcase-let ((`(,prog . ,args) (split-string line))) - (and prog - (string-match-p - "\\`\\(?:\\(?:/.*/\\)?git-credential-\\)?cache\\'" prog) - (or (cadr (member "--socket" args)) - (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 - (eval-when-compile - (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 - ;; See also history in test `magit-process:password-prompt-regexps'. - '(;; * CLI-prompt for passphrase for key: - "^\\(\\(Please e\\|E\\)nter \\(the \\)?p\\|P\\)assphrase.*: ?$" - ;; * Password for something other than a host: - "^\\(\\(Please e\\|E\\)nter \\(the \\)?p\\|P\\)assword: ?$" - ;; * Password for [user@]host (which we put in match group 99): - "^\\(\\(Please e\\|E\\)nter \\(the \\)?p\\|P\\)assword for \ -[\"']?\\(https?://\\)?\\(?99:[^\"']+\\)[\"']?: ?$" - "^(\\(?1:[^) ]+\\)) Password for \\(?99:\\1\\): ?$" ;#4992 - "^\\(?99:[^']+\\)\\('s\\)? password: ?$" - ;; * Token for git-credential-manager-core (#4318): - "^Token: ?$" - ;; * Secret for card: - "^Yubikey for .*: ?$" - "^Enter PIN for .*: ?$" - ;; * Unanchored TUI-prompt for passphrase for key: - "Please enter the passphrase for the ssh key" - "Please enter the passphrase to unlock the OpenPGP secret key") - "List of regexps matching password prompts of Git and its subprocesses. -Also see `magit-process-find-password-functions'." - :package-version '(magit . "4.3.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 (list #'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) - -(defcustom magit-process-apply-ansi-colors nil - "Whether and when to apply color escapes in the process buffer. - -Magit instructs Git to not colorize its output, but third-party Git -hooks may do so anyway. We recommend you figure out how to prevent -such hooks from colorizing their output instead of customizing this -option. - -If `nil' (the default), do not apply color escape sequences. If `t', -apply them once the subprocess has finished. If `filter', apply them -as input arrives (which is more expensive and potentially fragile). -This is a footgun; starter-kits should leave this option untouched." - :package-version '(magit . "4.3.2") - :group 'magit-process - :type '(choice (const :tag "Do not apply" nil) - (const :tag "Apply when subprocess has finished" t) - (const :tag "Apply using process filter" filter))) - -(defcustom magit-process-timestamp-format nil - "Format of timestamp for each process in the process buffer. -If non-nil, pass this to `format-time-string' when creating a -process section in the process buffer, and insert the returned -string in the heading of its section." - :package-version '(magit . "4.0.0") - :group 'magit-process - :type '(choice (const :tag "None" nil) string)) - -(defvar tramp-pipe-stty-settings) -(defvar magit-tramp-pipe-stty-settings "" - "Override `tramp-pipe-stty-settings' in `magit-start-process'. - -The default for that Tramp variable is \"-icanon min 1 time 0\", -which causes staging of individual hunks to hang. Using \"\" -prevents that, but apparently has other issues, which is why it -isn't the default. - -This variable defaults to \"\" and is used to override the Tramp -variable in `magit-start-process'. This only has an effect when -using Tramp 2.6.2 or greater. This can also be set to `pty', in -which case a pty is used instead of a pipe. That also prevents -the hanging, but doesn't work for files with DOS line endings -\(see #20). - -For connections that have `tramp-direct-async-process' enabled, -staging hunks hangs, unless this variable is set to `pty' (see -#5220). - -To fall back to the value of `tramp-pipe-stty-settings', set this -variable to nil. - -Also see https://github.com/magit/magit/issues/4720 -and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=62093.") - -(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-keymap magit-process-mode-map - :doc "Keymap for `magit-process-mode'." - :parent magit-mode-map - " " #'undefined - " " #'magit-process-kill) - -(define-derived-mode magit-process-mode magit-mode "Magit Process" - "Mode for looking at Git process output." - :interactive nil - :group 'magit-process - (magit-hack-dir-local-variables) - (setq magit--imenu-item-types 'process)) - -(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 (seq-find (##with-current-buffer % - (and (eq major-mode 'magit-process-mode) - (equal default-directory topdir))) - (buffer-list)) - (magit-generate-new-buffer 'magit-process-mode - nil topdir)))) - (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) - -(defvar magit-process-record-invocations nil) -(defvar magit-process-record-buffer-name " *magit-process-file record*") -(defvar magit-process-record-entry-format "%T %%d $ %%a") - -(defun magit-toggle-subprocess-record () - "Toggle whether subprocess invocations are recorded. - -When enabled, all subprocesses started by `magit-process-file' are -logged into the buffer specified by `magit-process-record-buffer-name' -using the format `magit-process-record-entry-format'. This is for -debugging purposes. - -This is in addition to and distinct from the default logging done by -default, and additional logging enabled with ~magit-toggle-git-debug~. - -For alternatives, see info node `(magit)Debugging Tools'." - (interactive) - (setq magit-process-record-invocations (not magit-process-record-invocations)) - (message "Recording of subprocess invocations %s" - (if magit-process-record-invocations "enabled" "disabled"))) - -(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)))) - (prog1 (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 (list #'magit-maybe-save-repository-buffers)) - -(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. -Similar to `process-file' but temporarily enable Cygwin's -\"noglob\" option during the call and ensure unix eol conversion." - (when magit-process-record-invocations - (let ((messages-buffer-name magit-process-record-buffer-name) - (inhibit-message t)) - (message "%s" - (format-spec - (format-time-string magit-process-record-entry-format) - `((?d . ,(abbreviate-file-name default-directory)) - (?a . ,(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. A local binding of process-environment different from the - ;; top-level value affects the environment used by Tramp. - (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 ((val (getenv var))) - (concat val " 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." - (magit-msg "Running %s %s" (magit-git-executable) - (let ((m (string-join (flatten-tree 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 (list #'magit-maybe-save-repository-buffers)) - -(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 ;t=pty nil=pipe - (or - ;; With Tramp, maybe force use a pty. #4720 - (and (file-remote-p default-directory) - (eq magit-tramp-pipe-stty-settings 'pty)) - ;; Without input, don't use a pty, because it would - ;; set icrnl, which would modify the input. #20 - (and (not input) magit-process-connection-type))) - (tramp-pipe-stty-settings - (or (and (not (eq magit-tramp-pipe-stty-settings 'pty)) - ;; Defaults to "", to allow staging hunks over - ;; Tramp again. #4720 - magit-tramp-pipe-stty-settings) - (bound-and-true-p tramp-pipe-stty-settings))) - (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' appears to be broken over - ;; Tramp from Windows. See #3624 and bug#43226. - (if (and (eq system-type 'windows-nt) - (file-remote-p (process-get process 'default-dir) nil t)) - (process-send-string process "") - (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)) - (stdout-buf (generate-new-buffer " *git-stdout*")) - (stderr-buf (generate-new-buffer " *git-stderr*")) - (toplevel (magit-toplevel))) - (with-current-buffer stdout-buf - (setq default-directory toplevel) - (let ((process - (let ((process-environment (magit-process-environment))) - (make-process :name "git" - :buffer stdout-buf - :stderr stderr-buf - :command (cons (magit-git-executable) args) - :coding (magit--process-coding-system) - :file-handler t)))) - (process-put process 'command-buf command-buf) - (process-put process 'stderr-buf stderr-buf) - (process-put process 'parsed (point)) - (setq magit-this-process process) - process)))) - -;;; Process Internals - -(setf (alist-get 'process magit--section-type-alist) 'magit-process-section) - -(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 face) - (let ((inhibit-read-only t) - (magit-insert-section--current nil) - (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 ")) - (when magit-process-timestamp-format - (insert (format-time-string magit-process-timestamp-format) " ")) - (let ((cmd (concat - (and (not (equal - (file-name-as-directory (expand-file-name pwd)) - (file-name-as-directory (expand-file-name - default-directory)))) - (concat (file-relative-name pwd default-directory) " ")) - (magit-process--format-arguments program args)))) - (magit-insert-heading (if face (propertize cmd 'face face) cmd))) - (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))) - (let ((global (length magit-git-global-arguments))) - (concat - (propertize (file-name-nondirectory program) - 'font-lock-face 'magit-section-heading) - " " - (propertize (magit--ellipsis) - 'font-lock-face 'magit-section-heading - 'help-echo (string-join (seq-take args global) " ")) - " " - (propertize (mapconcat #'shell-quote-argument (seq-drop args global) " ") - '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)) - ((buffer-live-p process-buf)) - (status-buf (with-current-buffer process-buf - (magit-get-mode-buffer 'magit-status-mode)))) - (with-current-buffer status-buf - (when-let ((section - (magit-get-section - `((commit . ,(magit-rev-parse "HEAD")) - (,(pcase (car (seq-drop - (process-command process) - (1+ (length magit-git-global-arguments)))) - ((or "rebase" "am") 'rebase-sequence) - ((or "cherry-pick" "revert") 'sequence))) - (status))))) - (goto-char (oref section 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))) - (setq string (substring string (1+ ret-pos))) - (delete-region (line-beginning-position) (point))) - (setq string (magit-process-remove-bogus-errors string)) - (when (eq magit-process-apply-ansi-colors 'filter) - (setq string (ansi-color-apply string))) - (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)))) - -(defun magit-process-make-keymap (process parent) - "Remap `abort-minibuffers' to a command that also kills PROCESS. -PARENT is used as the parent of the returned keymap." - (let ((cmd (lambda () - (interactive) - (ignore-errors (kill-process process)) - (if (fboundp 'abort-minibuffers) - (abort-minibuffers) - (abort-recursive-edit))))) - (define-keymap :parent parent - "C-g" cmd - " " cmd - " " cmd))) - -(defmacro magit-process-kill-on-abort (process &rest body) - (declare (indent 1) - (debug (form body)) - (obsolete magit-process-make-keymap "Magit 4.0.0")) - `(let ((minibuffer-local-map - (magit-process-make-keymap ,process minibuffer-local-map))) - ,@body)) - -(defun magit-process-remove-bogus-errors (str) - (save-match-data - (when (string-match "^\\(\\*ERROR\\*: \\)Canceled by user" str) - (setq str (replace-match "" nil nil str 1))) - (when (string-match "^error: There was a problem with the editor.*\n" str) - (setq str (replace-match "" nil nil str))) - (when (string-match - "^Please supply the message using either -m or -F option\\.\n" str) - (setq str (replace-match "" nil nil str)))) - str) - -(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))) - (process-send-string - process - (if (save-match-data - (let ((max-mini-window-height 30) - (minibuffer-local-map - (magit-process-make-keymap process minibuffer-local-map)) - ;; In case yes-or-no-p is fset to that, but does - ;; not cover use-dialog-box-p and y-or-n-p-read-key. - (y-or-n-p-map - (magit-process-make-keymap process y-or-n-p-map))) - (yes-or-no-p (substring string 0 beg)))) - (concat (downcase (match-string 1 string)) "\n") - (concat (downcase (match-string 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. - -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 (fboundp 'auth-source-search) - (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 - (concat (or (and-let* ((key (match-string 99 string))) - (run-hook-with-args-until-success - 'magit-process-find-password-functions key)) - (let ((read-passwd-map - (magit-process-make-keymap process read-passwd-map))) - (read-passwd prompt))) - "\n")))) - -(defun magit-process-username-prompt (process string) - "Forward username prompts to the user." - (when-let ((prompt (magit-process-match-prompt - magit-process-username-prompt-regexps string))) - (process-send-string - process - (let ((minibuffer-local-map - (magit-process-make-keymap process minibuffer-local-map))) - (concat (read-string prompt 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, appending \": \" if needed." - (when (seq-some (##string-match % 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 (seq-find (lambda (process) - (let* ((attr (process-attributes process)) - (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) - -(defvar-keymap magit-mode-line-process-map - :doc "Keymap for `mode-line-process'." - " " 'magit-process-buffer) - -(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)))) - -(add-hook 'magit-refresh-buffer-hook - #'magit-process-unset-mode-line-error-status) - -(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) - -(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 - (magit-process-finish-section section arg))) - (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-finish-section (section exit-code) - (let ((inhibit-read-only t) - (buffer (current-buffer)) - (marker (oref section start))) - (goto-char marker) - (save-excursion - (delete-char 3) - (set-marker-insertion-type marker nil) - (insert (propertize (format "%3s" exit-code) - 'magit-section section - 'font-lock-face (if (= exit-code 0) - 'magit-process-ok - 'magit-process-ng))) - (set-marker-insertion-type marker t)) - (when (eq magit-process-apply-ansi-colors t) - (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)) - (when (and (= exit-code 0) - (not (seq-some (##eq (window-buffer %) buffer) - (window-list)))) - (magit-section-hide section))))) - -(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 (string-join lines "\n")))))) - -;;; _ -(provide 'magit-process) -;;; magit-process.el ends here diff --git a/elpa/magit-20250519.1537/magit-pull.el b/elpa/magit-20250519.1537/magit-pull.el deleted file mode 100644 index 7116c29d..00000000 --- a/elpa/magit-20250519.1537/magit-pull.el +++ /dev/null @@ -1,166 +0,0 @@ -;;; magit-pull.el --- Update local objects and refs -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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) - ("-F" "Force" ("-f" "--force"))] - [: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-with-editor "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 () - (and-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-20250519.1537/magit-push.el b/elpa/magit-20250519.1537/magit-push.el deleted file mode 100644 index 1b8acb42..00000000 --- a/elpa/magit-20250519.1537/magit-push.el +++ /dev/null @@ -1,373 +0,0 @@ -;;; magit-push.el --- Update remote objects and refs -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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")) - ("-u" "Set upstream" "--set-upstream" :level 5) - ("-T" "Include all tags" "--tags") - ("-t" "Include related annotated tags" "--follow-tags")] - [:if magit-get-current-branch - :description (##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 - (list "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 (cl-union (mapcar (##concat % "/" branch) - (magit-list-remotes)) - (magit-list-remote-branch-names) - :test #'equal)) - (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 - (list "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 () - (and-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 ((current (magit-get-current-branch))) - (list (magit-read-remote-branch (format "Push %s to" current) - nil nil current '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. To add it use something like: - - (transient-insert-suffix \\='magit-push \"o\" - \\='(\"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 () - ;; This implements the logic for git push as documented. - ;; First, we resolve a remote to use based on various remote and - ;; pushRemote options. - ;; Then, we resolve the refspec to use for the remote based on push - ;; and pushDefault options. - ;; Note that the remote and refspec to push are handled separately, - ;; so it doesn't make sense to talk about "pushing to upstream". - ;; Depending on the options, you could end up pushing to the - ;; "upstream" remote but not the "upstream" branch, and vice versa. - (let* ((branch (magit-get-current-branch)) - (remote (or (magit-get-push-remote branch) - ;; Note: Avoid `magit-get-remote' because it - ;; filters out the local repo case ("."). - (magit-get "branch" branch "remote") - (let ((remotes (magit-list-remotes))) - (cond - ((and (magit-git-version>= "2.27") - (length= remotes 1)) - (car remotes)) - ((member "origin" remotes) "origin")))))) - (if (null remote) - "nothing (no remote)" - (let ((refspec (magit-get "remote" remote "push"))) - (if refspec - (format "to %s with refspecs %s" - (magit--propertize-face remote 'bold) - (magit--propertize-face refspec 'bold)) - (pcase (or (magit-get "push.default") "simple") - ("nothing" "nothing (due to push.default)") - ((or "current" "simple") - (format "%s to %s" - (magit--propertize-face branch 'magit-branch-current) - (magit--propertize-face (format "%s/%s" remote branch) - 'magit-branch-remote))) - ((or "upstream" "tracking") - (let ((ref (magit-get "branch" branch "merge"))) - (if ref - (format "%s to %s" - (magit--propertize-face branch 'magit-branch-current) - (cond - ((string-prefix-p "refs/heads/" ref) - (magit--propertize-face - (format "%s/%s" remote - (substring ref (length "refs/heads/"))) - 'magit-branch-remote)) - ((not (string-match "/" ref)) - (magit--propertize-face (format "%s/%s" remote ref) - 'magit-branch-remote)) - ((format "%s as %s" - (magit--propertize-face remote 'bold) - (magit--propertize-face ref 'bold))))) - "nothing (no upstream)"))) - ("matching" (format "all matching to %s" - (magit--propertize-face remote 'bold))))))))) - -;;;###autoload (autoload 'magit-push-to-remote "magit-push" nil t) -(transient-define-suffix 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'. - -You can add this command as a suffix using something like: - - (transient-insert-suffix \\='magit-push \"o\" - \\='(\"x\" magit-push-to-remote))" - :description #'magit-push-to-remote--desc - (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" (magit--propertize-face "git push " 'bold))) - -;;; _ -(provide 'magit-push) -;;; magit-push.el ends here diff --git a/elpa/magit-20250519.1537/magit-reflog.el b/elpa/magit-20250519.1537/magit-reflog.el deleted file mode 100644 index 7ffce3e0..00000000 --- a/elpa/magit-20250519.1537/magit-reflog.el +++ /dev/null @@ -1,208 +0,0 @@ -;;; magit-reflog.el --- Inspect ref history -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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-keymap magit-reflog-mode-map - :doc "Keymap for `magit-reflog-mode'." - :parent magit-log-mode-map - "C-c C-n" #'undefined - "L" #'magit-margin-settings) - -(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}" - :interactive nil - :group 'magit-log - (magit-hack-dir-local-variables) - (setq magit--imenu-item-types 'commit)) - -(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) - ("rewritten" . 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 - (string-join (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-20250519.1537/magit-refs.el b/elpa/magit-20250519.1537/magit-refs.el deleted file mode 100644 index 2bcee3e7..00000000 --- a/elpa/magit-20250519.1537/magit-refs.el +++ /dev/null @@ -1,814 +0,0 @@ -;;; magit-refs.el --- Listing references -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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 - (list #'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 (##memq % '(all branch nil)) - :type '(choice (const :tag "For branches and tags" all) - (const :tag "For branches only" branch) - (const :tag "Never" nil))) -(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-show-branch-descriptions nil - "Whether to show the description, if any, of local branches. -To distinguish branch descriptions from the commit summary of the tip, -which is shown when there is no description or this option is disabled, -descriptions use the bold face." - :package-version '(magit . "4.3.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 (##memq % '(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 '(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-keymap magit-refs-mode-map - :doc "Keymap for `magit-refs-mode'." - :parent magit-mode-map - "C-y" #'magit-refs-set-show-commit-count - "L" #'magit-margin-settings) - -(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}" - :interactive nil - :group 'magit-refs - (magit-hack-dir-local-variables) - (setq magit--imenu-group-types '(local remote tags))) - -(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 - (string-join 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 (##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)) - (and-let* ((buffer (magit-get-mode-buffer - 'magit-refs-mode nil - (eq use-buffer-args 'selected)))) - (progn - (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)) - -(transient-define-suffix magit-refs-set-show-commit-count () - "Change for which refs the commit count is shown." - :description "Change verbosity" - :key "v" - :transient nil - :if-derived 'magit-refs-mode - (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). When invoked from a -menu this command always behaves like `magit-show-commit'." - (interactive) - (if (and (derived-mode-p 'magit-refs-mode) - (magit-section-match '(branch tag)) - (not (magit-menu-position))) - (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-keymap magit-remote-section-map - :doc "Keymap for `remote' sections." - " " #'magit-remote-rename - " " #'magit-remote-remove - "<2>" (magit-menu-item "Rename %s" #'magit-remote-rename) - "<1>" (magit-menu-item "Remove %m" #'magit-remote-remove)) - -(defvar-keymap magit-branch-section-map - :doc "Keymap for `branch' sections." - " " #'magit-branch-rename - " " #'magit-branch-delete - " " #'magit-visit-ref - "<3>" (magit-menu-item "Rename %s" #'magit-branch-rename) - "<2>" (magit-menu-item "Delete %m" #'magit-branch-delete) - "<1>" (magit-menu-item "Visit commit" #'magit-visit-ref)) - -(defvar-keymap magit-tag-section-map - :doc "Keymap for `tag' sections." - " " #'magit-tag-delete - " " #'magit-visit-ref - "<2>" (magit-menu-item "Delete %m" #'magit-tag-delete) - "<1>" (magit-menu-item "Visit %s" #'magit-visit-ref)) - -(defun magit--painted-branch-as-menu-section (section) - (and-let* ((branch (and (magit-section-match 'commit) - (magit--painted-branch-at-point)))) - (let ((dummy (magit-section :type 'branch :value branch))) - (oset dummy keymap magit-branch-section-map) - (dolist (slot '(start content hidden parent children)) - (when (slot-boundp section slot) - (setf (eieio-oref dummy slot) - (eieio-oref section slot)))) - dummy))) - -(add-hook 'magit-menu-alternative-section-hook - #'magit--painted-branch-as-menu-section) - -(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 (string-join (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 (length tags) "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--wash-summary 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))))) - -(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) - (cl-substitute nil "" - (split-string line "\0") - :test #'equal))) - (cond - (head-branch - ;; Note: Use `ref' instead of `branch' for the check - ;; below because 'refname:short' shortens the remote - ;; HEAD to '' instead of '/HEAD' as of - ;; Git v2.40.0. - (cl-assert - (equal ref (concat "refs/remotes/" remote "/HEAD"))) - (setq head head-branch)) - ((not (equal ref (concat "refs/remotes/" remote "/HEAD"))) - ;; ^ Skip mis-configured remotes where HEAD is not a - ;; symref. See #5092. - (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--wash-summary msg)))) - (when (magit-buffer-margin-p) - (magit-refs--format-margin branch)) - (magit-refs--insert-cherry-commits branch)))))))) - (insert ?\n) - (magit-make-margin-overlay)))) - -(defun magit-insert-local-branches () - "Insert sections showing all local branches." - (magit-insert-section (local nil) - (magit-insert-heading t "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))) - -(defun magit-insert-shelved-branches () - "Insert sections showing all shelved branches." - (when-let ((refs (magit-list-refs "refs/shelved/"))) - (magit-insert-section (shelved nil) - (magit-insert-heading t "Shelved branches") - (dolist (ref (nreverse refs)) - (magit-insert-section (shelved-branch ref t) - (magit-insert-heading - " " (magit--propertize-face (substring ref 13) 'magit-refname)) - (when (magit-buffer-margin-p) - (magit-refs--format-margin ref)) - (magit-refs--insert-cherry-commits ref))) - (insert ?\n) - (magit-make-margin-overlay)))) - -(defun magit-refs--format-local-branches () - (let ((lines (seq-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 ,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 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) - (cl-substitute nil "" (split-string line "\0") :test #'equal))) - (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-pretty - (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-pretty u:ahead p:ahead u:behind))) - branch - (magit-refs--format-focus-column branch headp) - branch-pretty 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) - " ")) - (if-let ((magit-refs-show-branch-descriptions) - (desc (magit-get "branch" branch "description"))) - (magit--propertize-face desc 'bold) - (and msg (magit-log--wash-summary 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 ((entry (seq-find (pcase-lambda (`(,key . ,_)) - (if (functionp key) - (funcall key refname) - (string-match-p key refname))) - magit-refs-filter-alist))) - (cdr entry) - 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))))) - -(defun magit-refs--format-margin (commit) - (if-let ((line (magit-rev-format "%cN%x00%ct" commit))) - (apply #'magit-log-format-margin commit (split-string line "\0")) - (magit-make-margin-overlay))) - -;;; _ -(provide 'magit-refs) -;;; magit-refs.el ends here diff --git a/elpa/magit-20250519.1537/magit-remote.el b/elpa/magit-20250519.1537/magit-remote.el deleted file mode 100644 index e4cdab79..00000000 --- a/elpa/magit-20250519.1537/magit-remote.el +++ /dev/null @@ -1,396 +0,0 @@ -;;; magit-remote.el --- Transfer Git commits -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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 (##and magit-remote-direct-configure (transient-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)] - [("d u" magit-update-default-branch)]] - (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))) - (seq-some (##string-match-p re %) remote-refs)) - (member theirs remote-refs)) - (push (cons refspec - (if (string-match "\\*" ours) - (let ((re (replace-match ".*" t t ours))) - (seq-filter (##string-match-p re %) - 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 "[a]abort" - (user-error "Abort"))) - (if (if (length= stale 1) - (pcase-let ((`(,refspec . ,refs) (car stale))) - (magit-confirm 'prune-stale-refspecs - (list "Prune stale refspec %s and branch %%s" refspec) - (list "Prune stale refspec %s and %%d branches" refspec) - nil refs)) - (magit-confirm 'prune-stale-refspecs nil - (format "Prune %%d stale refspecs and %d branches" - (length (mapcan (##copy-sequence (cdr %)) stale))) - nil - (mapcar (pcase-lambda (`(,refspec . ,refs)) - (concat refspec "\n" - (mapconcat (##concat " " %) refs "\n"))) - stale))) - (pcase-dolist (`(,refspec . ,refs) stale) - (magit-call-git "config" "--unset" variable - (regexp-quote refspec)) - (magit--log-action - (lambda (refs) - (format "Deleting %d 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 (autoload 'magit-update-default-branch "magit-remote" nil t) -(transient-define-suffix magit-update-default-branch () - "Update name of the default branch after upstream changed it." - :description "Update default branch" - :inapt-if-not #'magit-get-some-remote - (interactive) - (pcase-let ((`(,_remote ,oldname) (magit--get-default-branch)) - (`( ,remote ,newname) (magit--get-default-branch t))) - (cond - ((equal oldname newname) - (setq oldname - (read-string - (format - "Name of default branch is still `%s', %s\n%s `%s': " oldname - "but the upstreams of some local branches might need updating." - "Name of upstream branches to replace with" newname))) - (magit--set-default-branch newname oldname) - (magit-refresh)) - (t - (unless oldname - (setq oldname - (magit-read-other-local-branch - (format "Name of old default branch to be renamed to `%s'" - newname) - newname "master"))) - (cond - ((y-or-n-p (format "Default branch changed from `%s' to `%s' on %s.%s?" - oldname newname remote " Do the same locally")) - (magit--set-default-branch newname oldname) - (magit-refresh)) - ((user-error "Abort"))))))) - -;;;###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-search "*" (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 (##concat - (propertize "Configure " 'face 'transient-heading) - (propertize (transient-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-20250519.1537/magit-repos.el b/elpa/magit-20250519.1537/magit-repos.el deleted file mode 100644 index b815757c..00000000 --- a/elpa/magit-20250519.1537/magit-repos.el +++ /dev/null @@ -1,547 +0,0 @@ -;;; magit-repos.el --- Listing repositories -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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 (list #'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 (list #'hl-line-mode)) - -(defcustom magit-repolist-columns - `(("Name" 25 ,#'magit-repolist-column-ident - ()) - ("Version" 25 ,#'magit-repolist-column-version - ((:sort magit-repolist-version<))) - ("BU" 3 ,#'magit-repolist-column-unpushed-to-upstream - (;; (:help-echo "Local changes not in upstream") - (:right-align t) - (:sort <))) - ("Path" 99 ,#'magit-repolist-column-path - ())) - "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', `:pad-right' and -`:sort'. - -The `:sort' function has a weird interface described in the -docstring of `tabulated-list--get-sort'. Alternatively `<' and -`magit-repolist-version<' can be used as those functions are -automatically replaced with functions that satisfy the interface. -Set `:sort' to nil to inhibit sorting; if unspecified, then the -column is sortable using the default sorter. - -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." - :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) - (const :sort) - (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 -;;;; List Commands -;;;###autoload -(defun magit-list-repositories () - "Display a list of repositories. - -Use the option `magit-repository-directories' to control which -repositories are displayed." - (interactive) - (magit-repolist-setup (default-value 'magit-repolist-columns))) - -;;;; Mode Commands - -(defun magit-repolist-status (&optional _button) - "Show the status for the repository at point." - (interactive) - (if-let ((id (tabulated-list-get-id))) - (magit-status-setup-buffer (expand-file-name id)) - (user-error "There is no repository at point"))) - -(defun magit-repolist-mark () - "Mark a repository and move to the next line." - (interactive) - (magit-repolist--ensure-padding) - (tabulated-list-put-tag "*" t)) - -(defun magit-repolist-unmark () - "Unmark a repository and move to the next line." - (interactive) - (tabulated-list-put-tag " " t)) - -(defun magit-repolist-fetch (repos) - "Fetch all marked or listed repositories." - (interactive (list (magit-repolist--get-repos ?*))) - (run-hooks 'magit-credential-hook) - (magit-repolist--mapc (##magit-run-git "remote" "update") - repos "Fetching in %s...")) - -(defun magit-repolist-find-file-other-frame (repos file) - "Find a file in all marked or listed repositories." - (interactive (list (magit-repolist--get-repos ?*) - (read-string "Find file in repositories: "))) - (magit-repolist--mapc (##find-file-other-frame file) repos)) - -(defun magit-repolist--ensure-padding () - "Set `tabulated-list-padding' to 2, unless that is already non-zero." - (when (zerop tabulated-list-padding) - (setq tabulated-list-padding 2) - (tabulated-list-init-header) - (tabulated-list-print t))) - -(defun magit-repolist--get-repos (&optional char) - "Return marked repositories or `all' if none are marked. -If optional CHAR is non-nil, then only return repositories -marked with that character. If no repositories are marked -then ask whether to act on all repositories instead." - (or (magit-repolist--marked-repos char) - (if (magit-confirm 'repolist-all - "Nothing selected. Act on ALL displayed repositories") - 'all - (user-error "Abort")))) - -(defun magit-repolist--marked-repos (&optional char) - "Return marked repositories. -If optional CHAR is non-nil, then only return repositories -marked with that character." - (let (c list) - (save-excursion - (goto-char (point-min)) - (while (not (eobp)) - (setq c (char-after)) - (unless (eq c ?\s) - (if char - (when (eq c char) - (push (tabulated-list-get-id) list)) - (push (cons c (tabulated-list-get-id)) list))) - (forward-line))) - list)) - -(defun magit-repolist--mapc (fn repos &optional msg) - "Apply FN to each directory in REPOS for side effects only. -If REPOS is the symbol `all', then call FN for all displayed -repositories. When FN is called, `default-directory' is bound to -the top-level directory of the current repository. If optional -MSG is non-nil then that is displayed around each call to FN. -If it contains \"%s\" then the directory is substituted for that." - (when (eq repos 'all) - (setq repos nil) - (save-excursion - (goto-char (point-min)) - (while (not (eobp)) - (push (tabulated-list-get-id) repos) - (forward-line))) - (setq repos (nreverse repos))) - (let ((base default-directory) - (len (length repos)) - (i 0)) - (dolist (repo repos) - (let ((default-directory - (file-name-as-directory (expand-file-name repo base)))) - (if msg - (let ((msg (concat (format "(%s/%s) " (cl-incf i) len) - (format msg default-directory)))) - (message msg) - (funcall fn) - (message (concat msg "done"))) - (funcall fn)))))) - -;;;; Mode - -(defvar-keymap magit-repolist-mode-map - :doc "Local keymap for Magit-Repolist mode buffers." - :parent tabulated-list-mode-map - "C-m" #'magit-repolist-status - "m" #'magit-repolist-mark - "u" #'magit-repolist-unmark - "f" #'magit-repolist-fetch - "5" #'magit-repolist-find-file-other-frame) - -(define-derived-mode magit-repolist-mode tabulated-list-mode "Repos" - "Major mode for browsing a list of Git repositories." - :interactive nil - :group 'magit-repolist - (setq-local x-stretch-cursor nil) - (setq tabulated-list-padding 0) - (setq-local tabulated-list-revert-hook (list #'magit-repolist-refresh t)) - (setq imenu-prev-index-position-function - #'magit-repolist--imenu-prev-index-position) - (setq imenu-extract-index-name-function #'tabulated-list-get-id)) - -(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-setup-1) - (magit-repolist-refresh) - (switch-to-buffer (current-buffer)))) - -(defun magit-repolist-setup-1 () - (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 (seq-map-indexed - (lambda (column idx) - (pcase-let* ((`(,title ,width ,_fn ,props) column) - (sort-set (assoc :sort props)) - (sort-fn (cadr sort-set))) - (nconc (list title width - (cond ((eq sort-fn '<) - (magit-repolist-make-sorter - sort-fn #'string-to-number idx)) - ((eq sort-fn 'magit-repolist-version<) - (magit-repolist-make-sorter - sort-fn #'identity idx)) - (sort-fn sort-fn) - (sort-set nil) - (t t))) - (flatten-tree props)))) - magit-repolist-columns)))) - -(defun magit-repolist-refresh () - (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 - (mapcar (##cons (file-name-nondirectory (directory-file-name %)) - %) - (magit-list-repos))))) - (message "Listing repositories...") - (tabulated-list-init-header) - (tabulated-list-print t) - (message "Listing repositories...done")) - -(defun magit-repolist--imenu-prev-index-position () - (and (not (bobp)) - (forward-line -1))) - -;;;; Columns - -(defun magit-repolist-make-sorter (sort-predicate convert-cell column-idx) - "Return a function suitable as a sorter for tabulated lists. -See `tabulated-list--get-sorter'. Given a more reasonable API -this would not be necessary and one could just use SORT-PREDICATE -directly. CONVERT-CELL can be used to turn the cell value, which -is always a string back into, e.g., a number. COLUMN-IDX has to -be the index of the column that uses the returned sorter function." - (lambda (a b) - (funcall sort-predicate - (funcall convert-cell (aref (cadr a) column-idx)) - (funcall convert-cell (aref (cadr b) column-idx))))) - -(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)) - -(defvar magit-repolist-column-version-regexp "\ -\\(?1:-\\(?2:[0-9]*\\)\ -\\(?3:-g[a-z0-9]*\\)\\)?\ -\\(?:-\\(?4:dirty\\)\\)\ -?\\'") - -(defvar magit-repolist-column-version-resume-regexp - "\\`Resume development\\'") - -(defun magit-repolist-column-version (_) - "Insert a description of the repository's `HEAD' revision." - (and-let* ((v (or (magit-git-string "describe" "--tags" "--dirty") - ;; If there are no tags, use the date in MELPA format. - (magit-rev-format "%cd-g%h" nil - "--date=format:%Y%m%d.%H%M")))) - (save-match-data - (when (string-match magit-repolist-column-version-regexp v) - (magit--put-face (match-beginning 0) (match-end 0) 'shadow v) - (when (match-end 2) - (magit--put-face (match-beginning 2) (match-end 2) 'bold v)) - (when (match-end 4) - (magit--put-face (or (match-beginning 3) (match-beginning 4)) - (match-end 4) 'error v)) - (when (and (equal (match-string 2 v) "1") - (string-match-p magit-repolist-column-version-resume-regexp - (magit-rev-format "%s"))) - (setq v (replace-match (propertize "+" 'face 'shadow) t t v 1)))) - (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-version< (a b) - (save-match-data - (let ((re "[0-9]+\\(\\.[0-9]*\\)*")) - (setq a (and (string-match re a) (match-string 0 a))) - (setq b (and (string-match re b) (match-string 0 b))) - (cond ((and a b) (version< a b)) - (b nil) - (t t))))) - -(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." - (and-let* ((br (magit-get-upstream-branch))) - (magit-repolist-insert-count (cadr (magit-rev-diff-count "HEAD" br)) spec))) - -(defun magit-repolist-column-unpulled-from-pushremote (spec) - "Insert number of commits in the push branch but not the current branch." - (and-let* ((br (magit-get-push-branch nil t))) - (magit-repolist-insert-count (cadr (magit-rev-diff-count "HEAD" br)) spec))) - -(defun magit-repolist-column-unpushed-to-upstream (spec) - "Insert number of commits in the current branch but not its upstream." - (and-let* ((br (magit-get-upstream-branch))) - (magit-repolist-insert-count (car (magit-rev-diff-count "HEAD" br)) spec))) - -(defun magit-repolist-column-unpushed-to-pushremote (spec) - "Insert number of commits in the current branch but not its push branch." - (and-let* ((br (magit-get-push-branch nil t))) - (magit-repolist-insert-count (car (magit-rev-diff-count "HEAD" br)) 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 () - (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) (file-accessible-directory-p directory)) - (mapcan (##and (file-directory-p %) - (magit-list-repos-1 % (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 - (mapcar (lambda (v) - (cons (concat - key "\\" - (file-name-nondirectory - (directory-file-name - (substring v 0 (- (1+ (length key))))))) - v)) - value)))))) - dict) - result)) - -(defun magit-repos-alist () - (magit-list-repos-uniquify - (mapcar (##cons (file-name-nondirectory (directory-file-name %)) %) - (magit-list-repos)))) - -;;; _ -(provide 'magit-repos) -;;; magit-repos.el ends here diff --git a/elpa/magit-20250519.1537/magit-reset.el b/elpa/magit-20250519.1537/magit-reset.el deleted file mode 100644 index 4baa64b2..00000000 --- a/elpa/magit-20250519.1537/magit-reset.el +++ /dev/null @@ -1,137 +0,0 @@ -;;; magit-reset.el --- Reset functionality -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; Commentary: - -;; This library implements reset commands. - -;;; Code: - -(require 'magit) - -;;; Commands - -;;;###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" - ("b" "branch" magit-branch-reset) - ("f" "file" magit-file-checkout)] - ["Reset this" - ("m" "mixed (HEAD and index)" magit-reset-mixed) - ("s" "soft (HEAD only)" magit-reset-soft) - ("h" "hard (HEAD, index and worktree)" 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)]]) - -;;;###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-20250519.1537/magit-sequence.el b/elpa/magit-20250519.1537/magit-sequence.el deleted file mode 100644 index 90e352a7..00000000 --- a/elpa/magit-20250519.1537/magit-sequence.el +++ /dev/null @@ -1,1144 +0,0 @@ -;;; magit-sequence.el --- History manipulation in Magit -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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) - (cond - ((not (magit-sequencer-in-progress-p)) - (user-error "No cherry-pick or revert in progress")) - ((magit-anything-unmerged-p) - (user-error "Cannot continue due to unresolved conflicts")) - ((magit-run-git-sequencer - (if (magit-revert-in-progress-p) "revert" "cherry-pick") "--continue")))) - -;;;###autoload -(defun magit-sequencer-skip () - "Skip the stopped at commit during a cherry-pick or revert sequence." - (interactive) - (unless (magit-sequencer-in-progress-p) - (user-error "No cherry-pick or revert in progress")) - (magit-call-git "reset" "--hard") - (magit-sequencer-continue)) - -;;;###autoload -(defun magit-sequencer-abort () - "Abort the current cherry-pick or revert sequence. -This discards all changes made since the sequence started." - (interactive) - (cond - ((not (magit-sequencer-in-progress-p)) - (user-error "No cherry-pick or revert in progress")) - ((magit-revert-in-progress-p) - (magit-confirm 'abort-revert "Really abort revert") - (magit-run-git-sequencer "revert" "--abort")) - ((magit-confirm 'abort-cherry-pick "Really abort cherry-pick") - (magit-run-git-sequencer "cherry-pick" "--abort")))) - -(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")) - (magit:--gpg-sign) - (magit:--signoff)] - [: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 ((upstream (magit-get-indirect-upstream-branch start-point))) - (magit-call-git "branch" "--set-upstream-to" upstream 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) - (with-environment-variables - (("GIT_SEQUENCE_EDITOR" - (format "%s -i -ne '/^pick (%s)/ or print'" - magit-perl-executable - (mapconcat #'magit-rev-abbrev commits "|")))) - (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-search ".." commits) - (split-string commits "\\.\\.") - (list commits)))) - (magit-run-git-sequencer - (if revert "revert" "cherry-pick") - (let ((merges (seq-filter #'magit-merge-commit-p commits))) - (cond - ((not merges) - (seq-remove (##string-prefix-p "--mainline=" %) args)) - ((cl-set-difference commits merges :test #'equal) - (user-error "Cannot %s merge and non-merge commits at once" - command)) - ((seq-find (##string-prefix-p "--mainline=" %) 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. - (let ((dir (magit-gitdir))) - (or (file-exists-p (expand-file-name "CHERRY_PICK_HEAD" dir)) - ;; And CHERRY_PICK_HEAD does not exist when a conflict happens - ;; while picking a series of commits with --no-commit. - (and-let* ((line (magit-file-line - (expand-file-name "sequencer/todo" dir)))) - (string-prefix-p "pick" line))))) - -;;; 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) - (magit:--gpg-sign) - (magit:--signoff)] - ["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. - (let ((dir (magit-gitdir))) - (or (file-exists-p (expand-file-name "REVERT_HEAD" dir)) - ;; And REVERT_HEAD does not exist when a conflict happens - ;; while reverting a series of commits with --no-commit. - (and-let* ((line (magit-file-line - (expand-file-name "sequencer/todo" dir)))) - (string-prefix-p "revert" line))))) - -;;; 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") - (magit:--gpg-sign) - (magit:--signoff)] - ["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 "--" - (mapcar (##magit-convert-filename-for-git - (expand-file-name %)) - 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) - (cond - ((not (magit-am-in-progress-p)) - (user-error "Not applying any patches")) - ((magit-anything-unstaged-p t) - (user-error "Cannot continue due to unstaged changes")) - ((magit-run-git-sequencer "am" "--continue")))) - -;;;###autoload -(defun magit-am-skip () - "Skip the stopped at patch during a patch applying sequence." - (interactive) - (unless (magit-am-in-progress-p) - (user-error "Not applying any patches")) - (magit-run-git-sequencer "am" "--skip")) - -;;;###autoload -(defun magit-am-abort () - "Abort the current patch applying sequence. -This discards all changes made since the sequence started." - (interactive) - (unless (magit-am-in-progress-p) - (user-error "Not applying any patches")) - (magit-run-git "am" "--abort")) - -(defun magit-am-in-progress-p () - (file-exists-p (expand-file-name "rebase-apply/applying" (magit-gitdir)))) - -;;; 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 (##magit-git-version< "2.33.0")) - ("-r" "Rebase merges" ("-r" "--rebase-merges=") - magit-rebase-merges-select-mode) - ("-u" "Update branches" "--update-refs" - :if (##magit-git-version>= "2.38.0")) - (7 magit-merge:--strategy) - (7 magit-merge:--strategy-option) - (7 "=X" magit-diff:--diff-algorithm :argument "-Xdiff-algorithm=") - (7 "-f" "Force rebase" ("-f" "--force-rebase")) - ("-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) - (magit:--gpg-sign) - (magit:--signoff)] - [:if-not magit-rebase-in-progress-p - :description (##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 () - (and-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 - (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 - (seq-some (##string-prefix-p "--rebase-merges" %) 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 - (and (not (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 (seq-every-p (##magit-rev-equal % 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 "%d 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 (select args) - "Combine squash and fixup commits with their intended targets. -By default only squash into commits that are not reachable from -the upstream branch. If no upstream is configured or with a prefix -argument, prompt for the first commit to potentially squash into." - (interactive (list current-prefix-arg - (magit-rebase-arguments))) - (magit-rebase-interactive-1 - (and-let* (((not select)) - (upstream (magit-get-upstream-branch))) - (magit-git-string "merge-base" upstream "HEAD")) - (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") - (let ((dir (magit-gitdir))) - (when (and (magit-anything-staged-p) - (file-exists-p (expand-file-name "rebase-merge" dir)) - (not (member (magit-toplevel) - magit--rebase-public-edit-confirmed))) - (magit-commit-amend-assert - (magit-file-line - (expand-file-name "rebase-merge/orig-head" dir))))) - (if noedit - (with-environment-variables (("GIT_EDITOR" "true")) - (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." - (let ((dir (magit-gitdir))) - (or (file-exists-p (expand-file-name "rebase-merge" dir)) - (file-exists-p (expand-file-name "rebase-apply/onto" dir))))) - -(defun magit--rebase-resume-command () - (if (file-exists-p (expand-file-name "rebase-recursive" (magit-gitdir))) - "rbr" - "rebase")) - -(defun magit-rebase--get-state-lines (file) - (and (magit-rebase-in-progress-p) - (let ((dir (magit-gitdir))) - (magit-file-line - (expand-file-name - (concat (if (file-directory-p (expand-file-name "rebase-merge" dir)) - "rebase-merge/" - "rebase-apply/") - file) - dir))))) - -;;; 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)) - (let ((dir (magit-gitdir))) - (magit-insert-section (sequence) - (magit-insert-heading (if picking "Cherry Picking" "Reverting")) - (when-let ((lines (cdr (magit-file-lines - (expand-file-name "sequencer/todo" dir))))) - (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 - (expand-file-name (if picking "CHERRY_PICK_HEAD" "REVERT_HEAD") - dir)) - (magit-file-line (expand-file-name "sequencer/head" dir))) - (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))) - (dir (expand-file-name "rebase-apply" (magit-gitdir))) - (i (string-to-number - (magit-file-line (expand-file-name "last" dir)))) - (cur (string-to-number - (magit-file-line (expand-file-name "next" dir)))) - patch commit) - (while (and patches (>= i cur)) - (setq patch (pop patches)) - (setq commit (magit-commit-p - (cadr (split-string (magit-file-line patch))))) - (cond ((and commit (= i cur)) - (magit-sequence-insert-commit - "stop" commit 'magit-sequence-stop)) - ((= i cur) - (magit-sequence-insert-am-patch - "stop" patch 'magit-sequence-stop)) - (commit - (magit-sequence-insert-commit - "pick" commit 'magit-sequence-pick)) - (t - (magit-sequence-insert-am-patch - "pick" patch 'magit-sequence-pick))) - (cl-decf i))) - (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* ((gitdir (magit-gitdir)) - (mergep (file-directory-p (expand-file-name "rebase-merge" gitdir))) - (dir (if mergep "rebase-merge/" "rebase-apply/")) - (name (thread-first (concat dir "head-name") - (expand-file-name gitdir) - magit-file-line)) - (onto (thread-first (concat dir "onto") - (expand-file-name gitdir) - 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 mergep - (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") "#")) - (commits ()) - (actions ())) - (with-temp-buffer - (insert-file-contents - (expand-file-name "rebase-merge/git-rebase-todo" (magit-gitdir))) - (while (not (eobp)) - (when-let ((obj (git-rebase-current-line))) - (push obj actions) - (when (memq (oref obj action-type) '(commit merge)) - (push obj commits))) - (forward-line))) - (let ((abbrevs - (and commits - (magit-git-lines - "log" "--no-walk=unsorted" "--format=%h" - (mapcar (lambda (obj) - (if (eq (oref obj action-type) 'merge) - (let ((options (oref obj action-options))) - (and (string-match "-[cC] \\([^ ]+\\)" options) - (match-string 1 options))) - (oref obj target))) - commits))))) - (cl-assert (equal (length commits) (length abbrevs))) - (while-let ((obj (pop commits)) - (val (pop abbrevs))) - (oset obj abbrev val))) - actions)) - -(defun magit-rebase-insert-merge-sequence (onto) - (dolist (obj (magit-rebase--todo)) - (with-slots (action-type action action-options target abbrev trailer) obj - (pcase action-type - ((or 'commit (and 'merge (guard abbrev))) - (magit-sequence-insert-commit action target 'magit-sequence-pick - abbrev trailer)) - ((guard action) (magit-sequence-insert-step action target))))) - (let ((dir (magit-gitdir))) - (magit-sequence-insert-sequence - (magit-file-line (expand-file-name "rebase-merge/stopped-sha" dir)) - onto - (and-let* ((lines (magit-file-lines - (expand-file-name "rebase-merge/done" dir)))) - (cadr (split-string (car (last lines)))))))) - -(defun magit-rebase-insert-apply-sequence (onto) - (let* ((dir (magit-gitdir)) - (rewritten - (mapcar (##car (split-string %)) - (magit-file-lines - (expand-file-name "rebase-apply/rewritten" dir)))) - (stop (magit-file-line - (expand-file-name "rebase-apply/original-commit" dir)))) - (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 (expand-file-name "rebase-apply/original-commit" dir)) - onto))) - -(defun magit-rebase-patches () - (directory-files (expand-file-name "rebase-apply" (magit-gitdir)) - 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 (mapcar (##split-string % "\0") - (magit-git-lines "log" "--format=%H%x00%h%x00%s" - (concat onto "..HEAD")))) - (when (and stop (not (assoc (magit-rev-parse stop) done))) - (let ((id (magit-patch-id stop))) - (if-let ((matched (car (assoc (##equal (magit-patch-id %) id) done)))) - (setq stop matched) - (cond - ((assoc (##magit-rev-equal % 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... - ((assoc (##magit-rev-equal % 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)))) - (pcase-dolist (`(,rev ,abbrev ,msg) 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) - abbrev msg)) - ((equal rev head) - (list "done" rev 'magit-sequence-head abbrev msg)) - (t - (list "done" rev 'magit-sequence-done abbrev msg))))) - (magit-sequence-insert-commit "onto" onto - (if (equal onto head) - 'magit-sequence-head - 'magit-sequence-onto)))) - -(defun magit-sequence-insert-commit (type hash face &optional abbrev msg) - (magit-insert-section (commit hash) - (magit-insert-heading - (propertize type 'font-lock-face face) " " - (if abbrev - (concat (propertize abbrev 'face 'magit-hash) " " msg "\n") - (concat (magit-format-rev-summary hash) "\n"))))) - -(defun magit-sequence-insert-step (type target) - (magit-insert-section (rebase-step (cons type target)) - (magit-insert-heading - (propertize type 'font-lock-face 'magit-sequence-pick) - (and target - (concat "\s" - (propertize target 'font-lock-face 'git-rebase-label)))))) - -;;; _ -(provide 'magit-sequence) -;;; magit-sequence.el ends here diff --git a/elpa/magit-20250519.1537/magit-sparse-checkout.el b/elpa/magit-20250519.1537/magit-sparse-checkout.el deleted file mode 100644 index 1df657a7..00000000 --- a/elpa/magit-20250519.1537/magit-sparse-checkout.el +++ /dev/null @@ -1,158 +0,0 @@ -;;; magit-sparse-checkout.el --- Sparse checkout support for Magit -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; Author: Kyle Meyer -;; 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 of the License, 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 . - -;;; Commentary: - -;; This library provides an interface to the `git sparse-checkout' -;; command. It's been possible to define sparse checkouts since Git -;; v1.7.0 by adding patterns to $GIT_DIR/info/sparse-checkout and -;; calling `git read-tree -mu HEAD' to update the index and working -;; tree. However, Git v2.25 introduced the `git sparse-checkout' -;; command along with "cone mode", which restricts the possible -;; patterns to directories to provide better performance. -;; -;; The goal of this library is to support the `git sparse-checkout' -;; command operating in cone mode. - -;;; Code: - -(require 'magit) - -;;; Utilities - -(defun magit-sparse-checkout-enabled-p () - "Return non-nil if working tree is a sparse checkout." - (magit-get-boolean "core.sparsecheckout")) - -(defun magit-sparse-checkout--auto-enable () - (if (magit-sparse-checkout-enabled-p) - (unless (magit-get-boolean "core.sparsecheckoutcone") - (user-error - "Magit's sparse checkout functionality requires cone mode")) - ;; Note: Don't use `magit-sparse-checkout-enable' because it's - ;; asynchronous. - (magit-run-git "sparse-checkout" "init" "--cone"))) - -(defun magit-sparse-checkout-directories () - "Return directories that are recursively included in the sparse checkout. -See the `git sparse-checkout' manpage for details about -\"recursive\" versus \"parent\" directories in cone mode." - (and (magit-get-boolean "core.sparsecheckoutcone") - (mapcar #'file-name-as-directory - (magit-git-lines "sparse-checkout" "list")))) - -;;; Commands - -;;;###autoload (autoload 'magit-sparse-checkout "magit-sparse-checkout" nil t) -(transient-define-prefix magit-sparse-checkout () - "Create and manage sparse checkouts." - :man-page "git-sparse-checkout" - ["Arguments for enabling" - :if-not magit-sparse-checkout-enabled-p - ("-i" "Use sparse index" "--sparse-index")] - ["Actions" - [:if-not magit-sparse-checkout-enabled-p - ("e" "Enable sparse checkout" magit-sparse-checkout-enable)] - [:if magit-sparse-checkout-enabled-p - ("d" "Disable sparse checkout" magit-sparse-checkout-disable) - ("r" "Reapply rules" magit-sparse-checkout-reapply)] - [("s" "Set directories" magit-sparse-checkout-set) - ("a" "Add directories" magit-sparse-checkout-add)]]) - -;;;###autoload -(defun magit-sparse-checkout-enable (&optional args) - "Convert the working tree to a sparse checkout." - (interactive (list (transient-args 'magit-sparse-checkout))) - (magit-run-git-async "sparse-checkout" "init" "--cone" args)) - -;;;###autoload -(defun magit-sparse-checkout-set (directories) - "Restrict working tree to DIRECTORIES. -To extend rather than override the currently configured -directories, call `magit-sparse-checkout-add' instead." - (interactive - (list (magit-completing-read-multiple - "Include these directories: " - ;; Note: Given that the appeal of sparse checkouts is - ;; dealing with very large trees, listing all subdirectories - ;; may need to be reconsidered. - (magit-revision-directories "HEAD")))) - (magit-sparse-checkout--auto-enable) - (magit-run-git-async "sparse-checkout" "set" directories)) - -;;;###autoload -(defun magit-sparse-checkout-add (directories) - "Add DIRECTORIES to the working tree. -To override rather than extend the currently configured -directories, call `magit-sparse-checkout-set' instead." - (interactive - (list (magit-completing-read-multiple - "Add these directories: " - ;; Same performance note as in `magit-sparse-checkout-set', - ;; but even more so given the additional processing. - (seq-remove - (let ((re (concat - "\\`" - (regexp-opt (magit-sparse-checkout-directories))))) - (##string-match-p re %)) - (magit-revision-directories "HEAD"))))) - (magit-sparse-checkout--auto-enable) - (magit-run-git-async "sparse-checkout" "add" directories)) - -;;;###autoload -(defun magit-sparse-checkout-reapply () - "Reapply the sparse checkout rules to the working tree. -Some operations such as merging or rebasing may need to check out -files that aren't included in the sparse checkout. Call this -command to reset to the sparse checkout state." - (interactive) - (magit-run-git-async "sparse-checkout" "reapply")) - -;;;###autoload -(defun magit-sparse-checkout-disable () - "Convert sparse checkout to full checkout. -Note that disabling the sparse checkout does not clear the -configured directories. Call `magit-sparse-checkout-enable' to -restore the previous sparse checkout." - (interactive) - (magit-run-git-async "sparse-checkout" "disable")) - -;;; Miscellaneous - -(defun magit-sparse-checkout-insert-header () - "Insert header line with sparse checkout information. -This header is not inserted by default. To enable it, add it to -`magit-status-headers-hook'." - (when (magit-sparse-checkout-enabled-p) - (insert (propertize (format "%-10s" "Sparse! ") - 'font-lock-face 'magit-section-heading)) - (insert - (let ((dirs (magit-sparse-checkout-directories))) - (pcase (length dirs) - (0 "top-level directory") - (1 (car dirs)) - (n (format "%d directories" n))))) - (insert ?\n))) - -;;; _ -(provide 'magit-sparse-checkout) -;;; magit-sparse-checkout.el ends here diff --git a/elpa/magit-20250519.1537/magit-stash.el b/elpa/magit-20250519.1537/magit-stash.el deleted file mode 100644 index 4ceea526..00000000 --- a/elpa/magit-20250519.1537/magit-stash.el +++ /dev/null @@ -1,683 +0,0 @@ -;;; magit-stash.el --- Stash support for Magit -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; Commentary: - -;; Support for Git stashes. - -;;; Code: - -(require 'magit) -(require 'magit-reflog) -(require 'magit-sequence) - -;;; Options - -(defgroup magit-stash nil - "List stashes and show stash diffs." - :group 'magit-modes) - -;;;; Diff options - -(defcustom magit-stash-sections-hook - (list #'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)) - -;;;; Variables - -(defvar magit-stash-read-message-function #'magit-stash-read-message - "Function used to read the message when creating a stash.") - -;;; 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) - ("P" "push" magit-stash-push :level 5)] - ["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 (funcall magit-stash-read-message-function))) - (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 (funcall magit-stash-read-message-function) - (magit-stash-read-untracked))) - -(defun magit-stash-read-message () - "Read a message from the minibuffer, to be used for a stash. - -The message that Git would have picked, is available as the -default (used when the user enters the empty string) and as -the first future history element. The second future history -element is just \"On BRANCH: \". Future history elements can -be accessed using \\\\[next-history-element])." - (let ((branch (or (magit-get-current-branch) "(no branch)")) - (ellipsis (magit--ellipsis))) - (read-string (format "Stash message (default: On%s:%s): " ellipsis ellipsis) - nil nil - (list (format "On %s: %s" branch (magit-rev-format "%h %s")) - (format "On %s: " branch))))) - -(defun magit-stash-read-message-traditional () - "Read a message from the minibuffer, to be used for a stash. - -If the user confirms the initial-input unmodified, then the -abbreviated commit hash and commit summary are appended. -The resulting message is what Git would have used." - (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))) - -(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)))) - -;;;###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 (autoload 'magit-stash-push "magit-stash" nil t) -(transient-define-prefix magit-stash-push (&optional transient args) - "Create stash using \"git stash push\". - -This differs from Magit's other stashing commands, which don't -use \"git stash\" and are generally more flexible but don't allow -specifying a list of files to be stashed." - :man-page "git-stash" - ["Arguments" - (magit:-- :reader (lambda (prompt initial-input history) - (magit-read-files prompt initial-input history - #'magit-modified-files))) - ("-u" "Also save untracked files" ("-u" "--include-untracked")) - ("-a" "Also save untracked and ignored files" ("-a" "--all")) - ("-k" "Keep index" ("-k" "--keep-index")) - ("-K" "Don't keep index" "--no-keep-index")] - ["Actions" - ("P" "push" magit-stash-push)] - (interactive (if (eq transient-current-command 'magit-stash-push) - (list nil (transient-args 'magit-stash-push)) - (list t))) - (if transient - (transient-setup 'magit-stash-push) - (magit-run-git "stash" "push" - (seq-filter #'atom args) - (assoc "--" args)))) - -;;;###autoload -(defun magit-stash-apply (stash) - "Apply a stash to the working tree. - -When using a Git release before v2.38.0, simply run \"git stash -apply\" or with a prefix argument \"git stash apply --index\". - -When using Git v2.38.0 or later, behave more intelligently: - -First try \"git stash apply --index\", which tries to preserve the -index stored in the stash, if any. This may fail because applying -the stash could result in conflicts and those have to be stored in -the index, making it impossible to also store the stash's index -there. - -If \"git stash\" fails, then potentially fall back to using \"git -apply\". If the stash does not touch any unstaged files, then pass -\"--3way\" to that command. Otherwise ask the user whether to use -that argument or \"--reject\". Customize `magit-no-confirm' if you -want to fall back to using \"--3way\", without being prompted." - (interactive (list (magit-read-stash "Apply stash"))) - (magit-stash--apply "apply" stash)) - -;;;###autoload -(defun magit-stash-pop (stash) - "Apply a stash to the working tree, on success remove it from stash list. - -When using a Git release before v2.38.0, simply run \"git stash -pop\" or with a prefix argument \"git stash pop --index\". - -When using Git v2.38.0 or later, behave more intelligently: - -First try \"git stash apply --index\", which tries to preserve the -index stored in the stash, if any. This may fail because applying -the stash could result in conflicts and those have to be stored in -the index, making it impossible to also store the stash's index -there. - -If \"git stash\" fails, then potentially fall back to using \"git -apply\". If the stash does not touch any unstaged files, then pass -\"--3way\" to that command. Otherwise ask the user whether to use -that argument or \"--reject\". Customize `magit-no-confirm' if you -want to fall back to using \"--3way\", without being prompted." - (interactive (list (magit-read-stash "Pop stash"))) - (magit-stash--apply "pop" stash)) - -(defun magit-stash--apply (action stash) - (if (magit-git-version< "2.38.0") - (magit-run-git "stash" action stash (and current-prefix-arg "--index")) - (magit-stash--apply-1 action stash) - (magit-refresh))) - -(defun magit-stash--apply-1 (action stash) - (or - (magit--run-git-stash action "--index" stash) - ;; The stash's index could not be applied, so always keep the stash. - (magit--run-git-stash "apply" stash) - (let* ((range (format "%s^..%s" stash stash)) - (stashed (magit-git-items "diff" "-z" "--name-only" range "--")) - (conflicts (cl-sort (cl-union (magit-unstaged-files t stashed) - (magit-untracked-files t stashed) - :test #'equal) - #'string<)) - (arg (if (or (not conflicts) - (memq 'stash-apply-3way magit-no-confirm)) - "--3way" - (magit-read-char-case - (concat - "Could not apply stash because of unstaged changes.\n\n" - "To do a tree-way merge, these files have to be staged\n" - (mapconcat (##format " %s" %) conflicts "\n") - "\n") - nil - (?s (format - "\n[s] stage file%s and apply with \"git apply --3way\"" - (if (length> conflicts 1) "s" "")) - "--3way") - (?r "\n[r] apply with \"git apply --reject\"" "--reject") - (?c "\n[c] cancel" nil))))) - (when arg - (when (and (equal arg "--3way") conflicts) - (magit-stage-1 nil conflicts)) - (with-temp-buffer - (magit-git-insert "diff" range) - (magit-run-git-with-input "apply" arg "-")))))) - -(defun magit--run-git-stash (&rest args) - (magit--with-temp-process-buffer - (let ((exit (save-excursion - (with-environment-variables (("LC_ALL" "en_US.utf8")) - (magit-process-git t "stash" args)))) - (buffer (current-buffer)) - (failed (looking-at "\\`error: "))) - (with-current-buffer (magit-process-buffer t) - (magit-process-finish-section - (magit-process-insert-section default-directory magit-git-executable - (magit-process-git-arguments args) - exit buffer) - exit)) - (pcase (list exit failed) - (`(0 ,_) t) ; no conflict - (`(1 nil) t) ; successfully installed conflict - (_ nil))))) ; could not install conflict, or genuine error - -;;;###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 ((values (magit-region-values 'stash))) - (magit-confirm 'drop-stashes nil "Drop %d stashes" nil values) - (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 (list "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 an existing STASH. -The new branch starts at the commit that was current when the -stash was created. If the stash applies cleanly, then drop it." - (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 from an existing STASH. -Use the current branch or `HEAD' as the starting-point of BRANCH. -Then apply STASH, dropping it if it applies cleanly." - (interactive (list (magit-read-stash "Branch stash") - (magit-read-string-ns "Branch name"))) - (let ((start-point (or (magit-get-current-branch) "HEAD"))) - (magit-call-git "checkout" "-b" branch start-point) - (magit-branch-maybe-adjust-upstream branch start-point)) - (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" "--no-ext-diff") - (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)) - -(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-keymap magit-stashes-section-map - :doc "Keymap for `stashes' section." - " " #'magit-stash-clear - " " #'magit-stash-list - "<2>" (magit-menu-item "Clear %t" #'magit-stash-clear) - "<1>" (magit-menu-item "List %t" #'magit-stash-list)) - -(defvar-keymap magit-stash-section-map - :doc "Keymap for `stash' sections." - " " #'magit-stash-pop - " " #'magit-stash-apply - " " #'magit-stash-drop - " " #'magit-stash-show - "<4>" (magit-menu-item "Pop %M" #'magit-stash-pop) - "<3>" (magit-menu-item "Apply %M" #'magit-stash-apply) - "<2>" (magit-menu-item "Delete %M" #'magit-stash-drop) - "<1>" (magit-menu-item "Visit %v" #'magit-stash-show)) - -(magit-define-section-jumper magit-jump-to-stashes - "Stashes" stashes "refs/stash" magit-insert-stashes) - -(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 (magit-rebase--get-state-lines "autostash"))) - (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") - (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) - (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." - :interactive nil - :group 'magit-log - (magit-hack-dir-local-variables)) - -(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 t - (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." - :interactive nil - :group 'magit-diff - (magit-hack-dir-local-variables) - (setq magit--imenu-group-types '(commit))) - -(put 'magit-stash-mode 'magit-diff-default-arguments - '("--no-ext-diff")) - -(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 nil - "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 (note) - (magit-insert-heading t "Notes") - (magit-git-insert "notes" "show" magit-buffer-revision) - (magit-cancel-section 'if-empty) - (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-20250519.1537/magit-status.el b/elpa/magit-20250519.1537/magit-status.el deleted file mode 100644 index 970d7274..00000000 --- a/elpa/magit-20250519.1537/magit-status.el +++ /dev/null @@ -1,827 +0,0 @@ -;;; magit-status.el --- The grand overview -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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 - (list #'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 (list #'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 - (list #'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-show-untracked-files t - "Whether to list untracked files in the status buffer. - -- If nil, do not list any untracked files. -- If t, list untracked files, but if a directory does not contain any - untracked files, then only list that directory, not the contained - untracked files. -- If all, then list each individual untracked files. This is can be - very slow and is discouraged. - -The corresponding values for the Git variable are \"no\", \"normal\" -and \"all\". - -To disable listing untracked files in a specific repository only, add -the following to \".dir-locals.el\": - - ((magit-status-mode - (magit-status-show-untracked-files . \"no\"))) - -Alternatively (and mostly for historic reasons), it is possible to use -`git-config' to set the repository-local value: - - git config set --local status.showUntrackedFiles no - -This does *not* override the (if any) local value of this Lisp variable, -but it does override its global value. - -See the last section in the git-status(1) manpage, to speed up the part -of the work Git is responsible for. Turning that list into sections is -also not free, so Magit only lists `magit-status-file-list-limit' files." - :package-version '(magit . "4.3.0") - :group 'magit-status - :type '(choice (const :tag "Do not list untracked files" nil) - (const :tag "List mixture of files and directories" t) - (const :tag "List individual files (slow)" all)) - :safe (##memq % '(nil t all))) - -(defcustom magit-status-file-list-limit 100 - "How many files to list in file list sections in the status buffer. -For performance reasons, it is recommended that you do not -increase this limit." - :package-version '(magit . "4.3.0") - :group 'magit-status - :type 'natnum) - -(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 - "Begin using Magit. - -This alias for `magit-status' exists 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))) - -;;; Mode - -(defvar-keymap magit-status-mode-map - :doc "Keymap for `magit-status-mode'." - :parent magit-mode-map - "j" #'magit-status-jump - " " #'magit-dired-jump) - -(transient-define-prefix magit-status-jump () - "In a Magit-Status buffer, jump to a section." - [["Jump to" - ("z " magit-jump-to-stashes) - ("t " magit-jump-to-tracked) - ("n " magit-jump-to-untracked) - ("i " magit-jump-to-ignored) - ("u " magit-jump-to-unstaged) - ("s " magit-jump-to-staged)] - ["" - ("fu" magit-jump-to-unpulled-from-upstream) - ("fp" magit-jump-to-unpulled-from-pushremote) - ("pu" magit-jump-to-unpushed-to-upstream) - ("pp" magit-jump-to-unpushed-to-pushremote) - ("a " magit-jump-to-assume-unchanged) - ("w " magit-jump-to-skip-worktree)] - ["Jump using" - ("j" "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}" - :interactive nil - :group 'magit-status - (magit-hack-dir-local-variables) - (when magit-status-initial-section - (add-hook 'magit--initial-section-hook - #'magit-status-goto-initial-section nil t)) - (setq magit--imenu-group-types '(not branch commit))) - -(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)) - (when (file-remote-p directory) - (magit-git-version-assert)) - (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 (save-restriction (widen) (line-number-at-pos)))) - (col (and file (save-restriction (widen) (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 () - "Jump to the section specified by `magit-status-initial-section'." - (when-let ((section - (seq-some (lambda (initial) - (if (integerp initial) - (nth (1- initial) - (magit-section-siblings - (magit-current-section) 'next)) - (magit-get-section initial))) - 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))))) - -(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-keymap magit-error-section-map - :doc "Keymap for `error' sections." - " " #'magit-process-buffer - "<1>" (magit-menu-item "Visit process output" #'magit-process-buffer)) - -(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 (string-join 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 ((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-let ((branch (or branch (magit-get-current-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 (magit-log--wash-summary summary)) - (insert ?\n)) - (magit-insert-section (commit commit) - (insert (format "%-10s" "Head: ")) - (insert (propertize commit 'font-lock-face 'magit-hash)) - (insert ?\s) - (insert (magit-log--wash-summary 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 " " - (magit-log--wash-summary - (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 (and magit-status-show-hashes-in-headers - (concat (propertize (magit-rev-format "%h" target) - 'font-lock-face 'magit-hash) - " ")) - target " " - (magit-log--wash-summary (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-keymap magit-untracked-section-map - :doc "Keymap for the `untracked' section." - " " #'magit-discard - " " #'magit-stage - "<2>" (magit-menu-item "Discard files" #'magit-discard) - "<1>" (magit-menu-item "Stage files" #'magit-stage)) - -(magit-define-section-jumper magit-jump-to-untracked - "Untracked files" untracked nil magit-insert-untracked-files) - -(magit-define-section-jumper magit-jump-to-tracked - "Tracked files" tracked nil magit-insert-tracked-files) - -(magit-define-section-jumper magit-jump-to-ignored - "Ignored files" ignored nil magit-insert-ignored-files) - -(magit-define-section-jumper magit-jump-to-skip-worktree - "Skip-worktree files" skip-worktree nil magit-insert-skip-worktree-files) - -(magit-define-section-jumper magit-jump-to-assume-unchanged - "Assume-unchanged files" assume-unchanged nil - magit-insert-assume-unchanged-files) - -(defun magit-insert-untracked-files () - "Maybe insert list of untracked files. - -List files if `magit-status-show-untracked-files' is non-nil, but also -take the local value of Git variable `status.showUntrackedFiles' into -account. The local value of the Lisp variable takes precedence over the -local value of the Git variable. The global value of the Git variable -is always ignored." - (when-let* - ((value (or (and (local-variable-p 'magit-status-show-untracked-files) - magit-status-show-untracked-files) - (pcase (magit-get "--local" "status.showUntrackedFiles") - ((or "no" "off" "false" "0") 'no) - ((or "yes" "on" "true" "1") t) - ("all" 'all)) - magit-status-show-untracked-files)) - ((not (eq value 'no)))) - (magit-insert-files - 'untracked - (lambda (files) - (mapcan (##and (eq (aref % 0) ??) - (list (substring % 3))) - (apply #'magit-git-items "status" "-z" "--porcelain" - (format "--untracked-files=%s" - (if (eq value 'all) "all" "normal")) - "--" files)))))) - -(defun magit-insert-tracked-files () - "Insert a list of tracked files. -Honor the buffer's file filter, which can be set using \"D - -\"." - (magit-insert-files 'tracked #'magit-list-files)) - -(defun magit-insert-ignored-files () - "Insert a list of ignored files. -Honor the buffer's file filter, which can be set using \"D - -\"." - (magit-insert-files 'ignored (##magit-ignored-files "--directory" %))) - -(defun magit-insert-skip-worktree-files () - "Insert a list of skip-worktree files. -Honor the buffer's file filter, which can be set using \"D - -\"." - (magit-insert-files 'skip-worktree #'magit-skip-worktree-files)) - -(defun magit-insert-assume-unchanged-files () - "Insert a list of files that are assumed to be unchanged. -Honor the buffer's file filter, which can be set using \"D - -\"." - (magit-insert-files 'assume-unchanged #'magit-assume-unchanged-files)) - -(defun magit-insert-files (type fn) - (when-let ((files (funcall fn - (and magit-buffer-diff-files - (cons "--" magit-buffer-diff-files))))) - (magit-insert-section section ((eval type) nil t) - (magit-insert-heading (length files) - (let ((title (symbol-name type))) - (format "%c%s files" - (capitalize (aref title 0)) - (substring title 1)))) - (magit-insert-section-body - (let ((magit-section-insert-in-reverse t) - (limit magit-status-file-list-limit)) - (while (and files (> limit 0)) - (cl-decf limit) - (let ((file (pop files))) - (magit-insert-section (file file) - (insert (funcall magit-format-file-function - 'list file 'magit-filename)) - (insert ?\n)))) - (when files - (magit-insert-section (info) - (insert (propertize - (format "%s files not listed\n" (length files)) - 'face 'warning))))) - (insert ?\n) - (oset section children (nreverse (oref section children))))))) - -;;; _ -(provide 'magit-status) -;;; magit-status.el ends here diff --git a/elpa/magit-20250519.1537/magit-submodule.el b/elpa/magit-20250519.1537/magit-submodule.el deleted file mode 100644 index 9d2b3368..00000000 --- a/elpa/magit-20250519.1537/magit-submodule.el +++ /dev/null @@ -1,716 +0,0 @@ -;;; magit-submodule.el --- Submodule support for Magit -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; Commentary: - -;; This library implements support for "git submodule". - -;; See (info "(magit)Submodules"). - -;;; Code: - -(require 'magit) - -;;; Options - -(defcustom magit-module-sections-hook - (list #'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 (list #'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 (list #'hl-line-mode)) - -(defcustom magit-submodule-list-columns - `(("Path" 25 ,#'magit-modulelist-column-path - ()) - ("Version" 25 ,#'magit-repolist-column-version - ((:sort magit-repolist-version<))) - ("Branch" 20 ,#'magit-repolist-column-branch - ()) - ("BP" 3 ,#'magit-repolist-column-unpushed-to-pushremote - ((:right-align t) - (:sort <))) - ("B>U" 3 ,#'magit-repolist-column-unpushed-to-upstream - ((:right-align t) - (:sort <))) - ("S" 3 ,#'magit-repolist-column-stashes - ((:right-align t) - (:sort <))) - ("B" 3 ,#'magit-repolist-column-branches - ((:right-align t) - (:sort <)))) - "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', `:pad-right' and -`:sort'. - -The `:sort' function has a weird interface described in the -docstring of `tabulated-list--get-sort'. Alternatively `<' and -`magit-repolist-version<' can be used as those functions are -automatically replaced with functions that satisfy the interface. -Set `:sort' to nil to inhibit sorting; if unspecified, then the -column is sortable using the default sorter. - -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." - :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) - (const :sort) - (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")))) - -(defvar magit-submodule-list-format-path-functions nil) - -(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)] - ["Populated modules actions" - ("l" "List modules" magit-list-submodules) - ("f" "Fetch modules" magit-fetch-modules)]) - -(defun magit-submodule-arguments (&rest filters) - (seq-filter (##and (member % filters) %) - (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 (magit-submodule-read-path "Add submodules at path: " 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-read-path (prompt url) - (directory-file-name - (file-relative-name - (read-directory-name prompt nil nil nil - (and (string-match "\\([^./]+\\)\\(\\.git\\)?$" url) - (match-string 1 url)))))) - -(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) - (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 (seq-keep (##pcase-let ((`(,var ,val) (split-string % "="))) - (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 args) - "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. - :class 'magit--git-submodule-suffix - :description "Populate git submodule update --init [--recursive]" - (interactive - (list (magit-module-confirm "Populate" 'magit-module-no-worktree-p) - (magit-submodule-arguments "--recursive"))) - (magit-with-toplevel - (magit-run-git-async "submodule" "update" "--init" args "--" 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 when a submodule is "uninitialized" (it has no worktree) - ;; the super-project's $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 %d modules" nil modules) - (list (magit-read-module-path "Remove module"))) - (magit-submodule-arguments "--force") - current-prefix-arg)) - (when magit-submodule-remove-trash-gitdirs - (setq trash-gitdirs t)) - (magit-with-toplevel - (when-let - ((modified - (seq-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 %d 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) - (string-join 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 - (mapcar (##split-string % "\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 %d 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 (convert-standard-filename - (expand-file-name - (concat "modules/" name) - (magit-gitdir))) - 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 "%%-%ds " - (min (apply #'max (mapcar #'length modules)) - (/ (window-width) 2)))) - (branch-format (format "%%-%ds " (min 25 (/ (window-width) 3))))) - (dolist (module modules) - (let ((default-directory - (expand-file-name (file-name-as-directory module)))) - (magit-insert-section (module 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 ((branch (magit-get-current-branch))) - (propertize branch 'font-lock-face 'magit-branch-local) - (propertize "(detached)" 'font-lock-face 'warning)))) - (if-let ((desc (magit-git-string "describe" "--tags"))) - (progn (when (and magit-modules-overview-align-numbers - (string-match-p "\\`[0-9]" desc)) - (insert ?\s)) - (insert (propertize desc 'font-lock-face 'magit-tag))) - (when-let ((abbrev (magit-rev-format "%h"))) - (insert (propertize abbrev 'font-lock-face 'magit-hash))))) - (insert ?\n)))))) - (insert ?\n)) - -(defvar-keymap magit-modules-section-map - :doc "Keymap for `modules' sections." - " " #'magit-list-submodules - "<1>" (magit-menu-item "List %t" #'magit-list-submodules)) - -(defvar-keymap magit-module-section-map - :doc "Keymap for `module' sections." - "C-j" #'magit-submodule-visit - "C-" #'magit-submodule-visit - " " #'magit-unstage - " " #'magit-stage - " " #'magit-submodule-visit - "<5>" (magit-menu-item "Module commands..." #'magit-submodule) - "<4>" '(menu-item "--") - "<3>" (magit-menu-item "Unstage %T" #'magit-unstage - '(:visible (eq (magit-diff-type) 'staged))) - "<2>" (magit-menu-item "Stage %T" #'magit-stage - '(:visible (eq (magit-diff-type) 'unstaged))) - "<1>" (magit-menu-item "Visit %s" #'magit-submodule-visit)) - -(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." - (when-let (((not (magit-ignore-submodules-p))) - (modules (magit-list-module-paths))) - (magit-insert-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) - ":") - (dolist (module modules) - (when-let* ((default-directory (expand-file-name module)) - ((file-exists-p (expand-file-name ".git"))) - (lines (magit-git-lines "-c" "push.default=current" - "log" "--oneline" range)) - (count (length lines)) - ((> count 0))) - (magit-insert-section - ( module module t - :range range) - (magit-insert-heading count - (propertize module 'font-lock-face 'magit-diff-file-heading)) - (dolist (line lines) - (string-match magit-log-module-re line) - (let ((rev (match-string 1 line)) - (msg (match-string 2 line))) - (magit-insert-section (module-commit rev t) - (insert (propertize rev 'font-lock-face 'magit-hash) " " - (magit-log--wash-summary msg) "\n"))))))) - (magit-cancel-section 'if-empty) - (insert ?\n)))) - -;;; List - -;;;###autoload -(defun magit-list-submodules () - "Display a list of the current repository's populated submodules." - (interactive) - (magit-submodule-list-setup magit-submodule-list-columns)) - -(defvar-keymap magit-submodule-list-mode-map - :doc "Local keymap for Magit-Submodule-List mode buffers." - :parent magit-repolist-mode-map) - -(define-derived-mode magit-submodule-list-mode magit-repolist-mode "Modules" - "Major mode for browsing a list of Git submodules." - :interactive nil - :group 'magit-repolist - (setq-local tabulated-list-revert-hook - (list #'magit-submodule-list-refresh t))) - -(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-generate-new-buffer 'magit-submodule-list-mode))) - (magit-submodule-list-mode) - (setq-local magit-repolist-columns columns) - (setq-local magit-repolist-sort-key magit-submodule-list-sort-key) - (setq-local magit-submodule-list-predicate predicate) - (magit-repolist-setup-1) - (magit-submodule-list-refresh)) - -(defun magit-submodule-list-refresh () - (setq tabulated-list-entries - (seq-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 default-directory - (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." - (let ((path (cadr (assq :path spec)))) - (or (run-hook-with-args-until-success - 'magit-submodule-list-format-path-functions path) - path))) - -;;; Utilities - -(defun magit-submodule--maybe-reuse-gitdir (name path) - (let ((gitdir (convert-standard-filename - (expand-file-name (concat "modules/" name) - (magit-gitdir))))) - (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-20250519.1537/magit-subtree.el b/elpa/magit-20250519.1537/magit-subtree.el deleted file mode 100644 index b771a23e..00000000 --- a/elpa/magit-20250519.1537/magit-subtree.el +++ /dev/null @@ -1,187 +0,0 @@ -;;; magit-subtree.el --- Subtree support for Magit -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; Commentary: - -;; This library implements support for "git subtree". -;; The entry point is the `magit-subtree' menu command. - -;; See (info "(magit)Subtree"). - -;;; 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" - ["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")] - ["Subtree import 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")] - ["Subtree export 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) - (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 ((arg (seq-find (##string-prefix-p "--prefix=" %) - (transient-args transient)))) - (substring arg 9) - (magit-subtree-read-prefix prompt))) - -(defun magit-subtree-arguments (transient) - (seq-remove (##string-prefix-p "--prefix=" %) - (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-20250519.1537/magit-tag.el b/elpa/magit-20250519.1537/magit-tag.el deleted file mode 100644 index 78c87b27..00000000 --- a/elpa/magit-20250519.1537/magit-tag.el +++ /dev/null @@ -1,248 +0,0 @@ -;;; magit-tag.el --- Tag functionality -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; Commentary: - -;; This library implements tag commands. - -;;; Code: - -(require 'magit) - -;; For `magit-tag-delete'. -(defvar helm-comp-read-use-marked) - -;;; Commands - -;;;###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")) - ("-e" "Edit message" ("-e" "--edit")) - ("-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 :test #'equal)) - 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 ((tags (magit-region-values 'tag))) - (magit-confirm t nil "Delete %d tags" nil tags) - (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 (cl-set-difference tags rtags :test #'equal)) - (rtags (cl-set-difference rtags tags :test #'equal))) - (unless (or ltags rtags) - (message "Same tags exist locally and remotely")) - (unless (magit-confirm t - "Delete %s locally" - "Delete %d tags locally" - 'noabort ltags) - (setq ltags nil)) - (unless (magit-confirm t - "Delete %s from remote" - "Delete %d 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 (mapcar (##concat ":" %) 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.") - -(defvar magit-release-commit-regexp "\\`Release version \\(.+\\)\\'" - "Regexp used by `magit-tag-release' to parse release commit messages. -The first submatch must match the version string.") - -;;;###autoload -(defun magit-tag-release (tag msg &optional args) - "Create a release tag for `HEAD'. - -Assume that release tags match `magit-release-tag-regexp'. - -If `HEAD's message matches `magit-release-commit-regexp', then -base the tag on the version string specified by that. Otherwise -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. - -When creating an annotated tag, prepare a message based on the message -of the highest existing tag, provided that contains the corresponding -version string, and substituting the new version string for that. If -that is not the case, propose a message using a reasonable format." - (interactive - (save-match-data - (pcase-let* - ((args (magit-tag-arguments)) - (`(,pver ,ptag ,pmsg) (car (magit--list-releases))) - (msg (magit-rev-format "%s")) - (ver (and (string-match magit-release-commit-regexp msg) - (match-string 1 msg))) - (_ (and (not ver) - (require (quote sisyphus) nil t) - (string-match magit-release-commit-regexp - (magit-rev-format "%s" ptag)) - (user-error "Use `sisyphus-create-release' first"))) - (tag (cond - ((not ptag) - ;; Force the user to review the message used for the - ;; initial release tag, in case they do not like the - ;; default format. - (cl-pushnew "--edit" args :test #'equal) - (read-string "Create first release tag: " - (if (and ver (string-match-p "\\`[0-9]" ver)) - (concat "v" ver) - ver))) - (ver - (concat (and (string-match magit-release-tag-regexp ptag) - (match-string 1 ptag)) - ver)) - (t - (read-string - (format "Create release tag (previous was %s): " ptag) - ptag)))) - (ver (and (string-match magit-release-tag-regexp tag) - (match-string 2 tag)))) - (list tag - (and (seq-some (apply-partially - #'string-match-p - "\\`--\\(annotate\\|local-user\\|sign\\)") - args) - (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)) - ((format "%s %s" - (capitalize - (file-name-nondirectory - (directory-file-name (magit-toplevel)))) - ver)))) - args)))) - (magit-run-git-with-editor "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 (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-20250519.1537/magit-transient.el b/elpa/magit-20250519.1537/magit-transient.el deleted file mode 100644 index 7ebd10cd..00000000 --- a/elpa/magit-20250519.1537/magit-transient.el +++ /dev/null @@ -1,243 +0,0 @@ -;;; magit-transient.el --- Support for transients -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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) - (global :initarg :global :initform nil) - (default :initarg :default :initform nil))) - -(defclass magit--git-variable:choices (magit--git-variable) - ((choices :initarg :choices) - (fallback :initarg :fallback :initform nil))) - -(defclass magit--git-variable:boolean (magit--git-variable:choices) - ((choices :initarg :choices :initform '("true" "false")))) - -(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))) - (arg (if (oref obj global) "--global" "--local"))) - (oset obj variable variable) - (oset obj value - (cond ((oref obj multi-value) - (magit-get-all arg variable)) - (t - (magit-get arg variable)))))) - -(cl-defmethod transient-init-value ((obj magit--git-variable:boolean)) - (let ((variable (format (oref obj variable) - (oref obj scope))) - (arg (if (oref obj global) "--global" "--local"))) - (oset obj variable variable) - (oset obj value (if (magit-get-boolean arg variable) "true" "false")))) - -;;;; Read - -(cl-defmethod transient-infix-read :around ((obj magit--git-variable:urls)) - (transient--with-emergency-exit - (transient--with-suspended-override - (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 current-prefix-arg - (pcase-let* - ((`(,fallback . ,choices) - (magit--git-variable-list-choices obj)) - (choice (magit-completing-read - (format "Set `%s' to" (oref obj variable)) - (if fallback (nconc choices (list fallback)) choices) - nil t))) - (if (equal choice fallback) nil choice)) - (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 (##save-excursion - (and (string-match "\\`[\s\t]+[0-9]+\t" %) - (list (substring % (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)) - (arg (if (oref obj global) "--global" "--local"))) - (oset obj value value) - (if (oref obj multi-value) - (magit-set-all value arg variable) - (magit-set value arg 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 (cl-set-difference values previous :test #'equal)) - (magit-call-git "remote" "set-url" seturl "--add" remote v)) - (dolist (v (cl-set-difference previous values :test #'equal)) - (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 (##concat "\n " - (propertize % 'face 'transient-value)) - value "") - (propertize (car value) 'face 'transient-value)) - (propertize (car (split-string value "\n")) - 'face 'transient-value)) - (if-let* ((default (oref obj default)) - (default (if (functionp default) (funcall default) default))) - (concat (propertize "default:" 'face 'transient-inactive-value) - (propertize default 'face 'transient-value)) - (propertize "unset" 'face 'transient-inactive-value)))) - -(cl-defmethod transient-format-value ((obj magit--git-variable:choices)) - (pcase-let ((`(,fallback . ,choices) (magit--git-variable-list-choices obj))) - (concat - (propertize "[" 'face 'transient-inactive-value) - (mapconcat #'identity choices - (propertize "|" 'face 'transient-inactive-value)) - (and fallback (propertize "|" 'face 'transient-inactive-value)) - fallback - (propertize "]" 'face 'transient-inactive-value)))) - -(defun magit--git-variable-list-choices (obj) - (let* ((variable (oref obj variable)) - (choices (oref obj choices)) - (globalp (oref obj global)) - (value nil) - (global (magit-git-string "config" "--global" variable)) - (defaultp (oref obj default)) - (default (if (functionp defaultp) (funcall defaultp obj) defaultp)) - (fallback (oref obj fallback)) - (fallback (and fallback - (and-let* ((val (magit-get fallback))) - (concat fallback ":" val))))) - (if (not globalp) - (setq value (magit-git-string "config" "--local" variable)) - (setq value global) - (setq global nil)) - (when (functionp choices) - (setq choices (funcall choices))) - (cons (cond (global - (propertize (concat "global:" global) - 'face (cond (value - 'transient-inactive-value) - ((member global choices) - 'transient-value) - (t - 'font-lock-warning-face)))) - (fallback - (propertize fallback - 'face (if value - 'transient-inactive-value - 'transient-value))) - (default - (propertize (if (functionp defaultp) - (concat "dwim:" default) - (concat "default:" default)) - 'face (if value - 'transient-inactive-value - 'transient-value)))) - (mapcar (lambda (choice) - (propertize choice 'face (if (equal choice value) - (if (member choice choices) - 'transient-value - 'font-lock-warning-face) - 'transient-inactive-value))) - (if (and value (not (member value choices))) - (cons value choices) - choices))))) - -;;; Utilities - -(defun magit--transient-args-and-files () - "Return (args files) for use by log and diff functions. -The value derives from that returned by `transient-get-value'." - (let ((args (transient-get-value))) - (list (seq-filter #'atom args) - (cdr (assoc "--" args))))) - -;;; _ -(provide 'magit-transient) -;;; magit-transient.el ends here diff --git a/elpa/magit-20250519.1537/magit-wip.el b/elpa/magit-20250519.1537/magit-wip.el deleted file mode 100644 index 712b7845..00000000 --- a/elpa/magit-20250519.1537/magit-wip.el +++ /dev/null @@ -1,461 +0,0 @@ -;;; magit-wip.el --- Commit snapshots to work-in-progress refs -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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) - -(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-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 - -(defvar magit--wip-activation-cache nil) -(defvar magit--wip-inhibit-autosave nil) - -;;;###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))) - (let ((magit--wip-activation-cache (list t))) - (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") - (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 () - (when (and buffer-file-name - (if magit--wip-activation-cache - (if-let ((elt (assoc default-directory - magit--wip-activation-cache))) - (and-let* ((top (cadr elt))) - (member (file-relative-name buffer-file-name top) - (cddr elt))) - (if-let ((top (magit-toplevel))) - (let (files) - (if-let ((elt (assoc top magit--wip-activation-cache))) - (setq files (cddr elt)) - (setq files (let ((default-directory top)) - (magit-tracked-files))) - (push `(,top ,top ,@files) - magit--wip-activation-cache) - (unless (eq default-directory top) - (push `(,default-directory ,top ,@files) - magit--wip-activation-cache))) - (member (file-relative-name buffer-file-name) files)) - (push (list default-directory nil) - magit--wip-activation-cache) - nil)) - (and (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 (list "wip-save %s after save")) - (when-let (((not magit--wip-inhibit-autosave)) - (ref (magit-wip-get-ref))) - (magit-with-toplevel - (let ((file (file-relative-name buffer-file-name))) - (magit-wip-commit-worktree - ref (list file) - (format (or msg "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 - :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 - :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 - :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 ((ref (magit-wip-get-ref))) - (magit-wip-commit-index ref files msg) - (magit-wip-commit-worktree ref 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" - "--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)) - ((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) - (and-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" - (nconc (magit-list-local-branch-names) - (list "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) - (and-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 set 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))))) - -(defun magit-wip-purge () - "Ask to delete all wip-refs that no longer have a corresponding ref." - (interactive) - (if-let ((wiprefs (thread-last - (cl-set-difference (magit-list-refs "refs/wip/") - (magit-list-refs) - :test (##equal (substring %1 15) %2)) - (delete "refs/wip/index/HEAD") - (delete "refs/wip/wtree/HEAD")))) - (progn - (magit-confirm 'purge-dangling-wiprefs - "Delete wip-ref %s without corresponding ref" - "Delete %d wip-refs without corresponding ref" - nil wiprefs) - (message "Deleting wip-refs...") - (dolist (wipref wiprefs) - (magit-call-git "update-ref" "-d" wipref)) - (message "Deleting wip-refs...done") - (magit-refresh)) - (message "All wip-refs have a corresponding ref"))) - -;;; _ -(provide 'magit-wip) -;;; magit-wip.el ends here diff --git a/elpa/magit-20250519.1537/magit-worktree.el b/elpa/magit-20250519.1537/magit-worktree.el deleted file mode 100644 index f38cad52..00000000 --- a/elpa/magit-20250519.1537/magit-worktree.el +++ /dev/null @@ -1,207 +0,0 @@ -;;; magit-worktree.el --- Worktree support -*- lexical-binding:t -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; 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 of the License, 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 . - -;;; 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))) - (when (zerop (magit-run-git "worktree" "add" - (magit--expand-worktree path) branch)) - (magit-diff-visit-directory path))) - -;;;###autoload -(defun magit-worktree-branch (path branch start-point) - "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"))) - (when (zerop (magit-run-git "worktree" "add" "-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-keymap magit-worktree-section-map - :doc "Keymap for `worktree' sections." - " " #'magit-worktree-delete - " " #'magit-worktree-status - "<4>" (magit-menu-item "Worktree commands..." #'magit-worktree) - "<3>" '(menu-item "--") - "<2>" (magit-menu-item "Delete %m" #'magit-worktree-delete) - "<1>" (magit-menu-item "Visit %s" #'magit-worktree-status)) - -(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 t "Worktrees") - (let* ((cols - (mapcar - (lambda (config) - (pcase-let ((`(,_ ,commit ,branch ,bare) config)) - (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)) - (bare "(bare)")) - config))) - worktrees)) - (align (1+ (apply #'max (mapcar (##string-width (car %)) cols))))) - (pcase-dolist (`(,head . ,config) cols) - (magit--insert-worktree - config - (concat head (make-string (- align (length head)) ?\s))))) - (insert ?\n))))) - -(defun magit--insert-worktree (config head) - "Insert worktree section for CONFIG. -See `magit-list-worktrees' for the format of CONFIG. HEAD is -a prettified reference or revision representing the worktree, -with padding for alignment." - ;; #4926 Before changing the signature, inform @vermiculus. - (let ((path (car config))) - (magit-insert-section (worktree path) - (insert head) - (insert (let ((relative (file-relative-name path)) - (absolute (abbreviate-file-name path))) - (if (or (> (string-width relative) (string-width absolute)) - (equal relative "./")) - absolute - relative))) - (insert ?\n)))) - -;;; _ -(provide 'magit-worktree) -;;; magit-worktree.el ends here diff --git a/elpa/magit-20250519.1537/magit.el b/elpa/magit-20250519.1537/magit.el deleted file mode 100644 index 3eb52650..00000000 --- a/elpa/magit-20250519.1537/magit.el +++ /dev/null @@ -1,800 +0,0 @@ -;;; magit.el --- A Git porcelain inside Emacs -*- lexical-binding:t; coding:utf-8 -*- - -;; Copyright (C) 2008-2025 The Magit Project Contributors - -;; Author: Marius Vollmer -;; Jonas Bernoulli -;; Maintainer: Jonas Bernoulli -;; Kyle Meyer -;; Former-Maintainers: -;; Nicolas Dudebout -;; Noam Postavsky -;; Peter J. Weisberg -;; Phil Jackson -;; Rémi Vanicat -;; Yann Hodique - -;; Homepage: https://github.com/magit/magit -;; Keywords: git tools vc - -;; Package-Version: 20250519.1537 -;; Package-Revision: 9b81df36b4eb -;; Package-Requires: ( -;; (emacs "27.1") -;; (compat "30.1.0.0") -;; (llama "0.6.2") -;; (magit-section "4.3.5") -;; (seq "2.24") -;; (transient "0.8.8") -;; (with-editor "3.4.3")) - -;; 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 of the License, -;; 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 . - -;; You should have received a copy of the AUTHORS.md file, which -;; lists all contributors. If not, see https://magit.vc/authors. - -;;; 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) - -;; For `magit:--gpg-sign' -(declare-function epg-list-keys "epg" (context &optional name mode)) -(declare-function epg-decode-dn "epg" (alist)) -(defvar epa-protocol) - -;;; Options - -(defcustom magit-openpgp-default-signing-key nil - "Fingerprint of your default Openpgp key used for signing. -If the specified primary key has signing capacity then it is used -as the value of the `--gpg-sign' argument without prompting, even -when other such keys exist. To be able to select another key you -must then use a prefix argument." - :package-version '(magit . "4.0.0") - :group 'magit-commands - :type 'string) - -;;; 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 commit object name in 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 similar 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 -(defcustom magit-define-global-key-bindings 'default - "Which set of key bindings to add to the global keymap, if any. - -This option controls which set of Magit key bindings, if any, may -be added to the global keymap, even before Magit is first used in -the current Emacs session. - -If the value is nil, no bindings are added. - -If \\+`default', maybe add: - - \\`C-x' \\`g' `magit-status' - \\`C-x' \\`M-g' `magit-dispatch' - \\`C-c' \\`M-g' `magit-file-dispatch' - -If `recommended', maybe add: - - \\`C-x' \\`g' `magit-status' - \\`C-c' \\`g' `magit-dispatch' - \\`C-c' \\`f' `magit-file-dispatch' - - These bindings are strongly recommended, but we cannot use - them by default, because the \\`C-c ' namespace is - strictly reserved for bindings added by the user. - -The bindings in the chosen set 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 these bindings is delayed until `after-init-hook' is -run 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 has no effect if `after-init-hook' has -already been run." - :package-version '(magit . "4.0.0") - :group 'magit-essentials - :type '(choice (const :tag "Add no binding" nil) - (const :tag "Use default bindings" default) - (const :tag "Use recommended bindings" recommended))) - -;;;###autoload -(progn - (defun magit-maybe-define-global-key-bindings (&optional force) - "See variable `magit-define-global-key-bindings'." - (when magit-define-global-key-bindings - (let ((map (current-global-map))) - (pcase-dolist (`(,key . ,def) - (cond ((eq magit-define-global-key-bindings 'recommended) - '(("C-x g" . magit-status) - ("C-c g" . magit-dispatch) - ("C-c f" . magit-file-dispatch))) - ('(("C-x g" . magit-status) - ("C-x M-g" . magit-dispatch) - ("C-c M-g" . magit-file-dispatch))))) - ;; This is autoloaded and thus is used before `compat' is - ;; loaded, so we cannot use `keymap-lookup' and `keymap-set'. - (when (or force - (not (or (lookup-key map (kbd key)) - (where-is-internal def (make-sparse-keymap) t)))) - (define-key map (kbd 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-info) - ("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) - ("q" " Bury current buffer" magit-mode-bury-buffer) - ("" " Toggle section at point" magit-section-toggle) - ("" "Visit thing at point" magit-visit-thing)] - [("C-x m" "Show all key bindings" describe-mode) - ("C-x i" "Show Info manual" magit-info)]]) - -;;; 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) - ("m" "git mergetool --gui" magit-git-mergetool)]]) - -;;;###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))) - (with-environment-variables (("GIT_PAGER" "cat")) - (with-connection-local-variables - (magit-with-editor - (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))) - -;;; Shared Infix Arguments - -(transient-define-argument magit:--signoff () - :description "Add Signed-off-by trailer" - :class 'transient-switch - :key "+s" - :shortarg "-s" - :argument "--signoff" - :level 6) - -(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 - :level 5) - -(defvar magit-gpg-secret-key-hist nil) - -(defun magit-read-gpg-secret-key - (prompt &optional initial-input history predicate default) - (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 - (and-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 (or (and (not current-prefix-arg) - (or (and (length= keys 1) (car keys)) - (and default (car (member default keys))))) - (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))) - magit-openpgp-default-signing-key)) - -;;; 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-insert-heading" - "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 interactive nowarn) - "Return the version of Magit currently in use. - -If optional argument PRINT-DEST is non-nil, also print the used -versions of Magit, Transient, Git and Emacs to the output stream -selected by that argument. Interactively use the echo area, or -with a prefix argument use the current buffer. Additionally put -the output in the kill ring. -\n(fn &optional PRINT-DEST)" - (interactive (list (if current-prefix-arg (current-buffer) t) 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--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--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 ((version (cadr (assq 'magit package-alist)))) - (push t debug) - (setq magit-version - (and (fboundp 'package-desc-version) - (package-version-join - (package-desc-version version))))))) - (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 - (let ((str (format - "Magit %s%s, Transient %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 (ignore-errors - (require 'lisp-mnt) - (and (fboundp 'lm-header) - (with-temp-buffer - (insert-file-contents - (locate-library "transient.el" t)) - (lm-header "Package-Version")))) - "(unknown)") - (let ((lib (locate-library "forge.el" t))) - (or (and lib - (format - " Forge %s," - (or (ignore-errors - (require 'lisp-mnt) - (with-temp-buffer - (insert-file-contents lib) - (and (fboundp 'lm-header) - (lm-header "Package-Version")))) - "(unknown)"))) - "")) - (magit--safe-git-version) - emacs-version - system-type))) - (when interactive - (kill-new str)) - (princ str print-dest))) - (setq debug (reverse debug)) - (setq magit-version 'error) - (when magit-version - (push magit-version debug)) - (unless (or nowarn (equal (getenv "CI") "true")) - (message "Cannot determine Magit's version %S" debug))) - magit-version)) - -;;; Startup Asserts - -(defun magit-startup-asserts () - (when-let ((val (getenv "GIT_DIR"))) - (setenv "GIT_DIR") - (message - "Magit unset $GIT_DIR (was %S). See %s" val - ;; Note: Pass URL as argument rather than embedding in the format - ;; string to prevent the single quote from being rendered - ;; according to `text-quoting-style'. - "https://github.com/magit/magit/wiki/Don't-set-$GIT_DIR-and-alike")) - (when-let ((val (getenv "GIT_WORK_TREE"))) - (setenv "GIT_WORK_TREE") - (message - "Magit unset $GIT_WORK_TREE (was %S). See %s" val - ;; See comment above. - "https://github.com/magit/magit/wiki/Don't-set-$GIT_DIR-and-alike")) - ;; Git isn't required while building Magit. - (unless (bound-and-true-p byte-compile-current-file) - (magit-git-version-assert)) - (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-submodule) - (unless (load "magit-autoloads" t t) - (require 'magit-patch) - (require 'magit-subtree) - (require 'magit-ediff) - (require 'magit-gitignore) - (require 'magit-sparse-checkout) - (require 'magit-extras) - (require 'magit-dired) - (require 'git-rebase) - (require 'magit-bookmark))) - -(with-eval-after-load 'bookmark - (require 'magit-bookmark)) - -(unless (bound-and-true-p byte-compile-current-file) - (if after-init-time - (progn (magit-startup-asserts) - (magit-version nil nil t)) - (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-20250519.1537/magit.info b/elpa/magit-20250519.1537/magit.info deleted file mode 100644 index efd5f29c..00000000 --- a/elpa/magit-20250519.1537/magit.info +++ /dev/null @@ -1,11014 +0,0 @@ -This is magit.info, produced by makeinfo version 6.8 from magit.texi. - - Copyright (C) 2015-2025 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 4.3.5. - - Copyright (C) 2015-2025 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. -* Mouse Support:: -* Running Git:: - -Inspecting - -* Status Buffer:: -* Repository List:: -* Logging:: -* Diffing:: -* Ediffing:: -* References Buffer:: -* Bisecting:: -* Visiting Files and Blobs:: -* Blaming:: - -Manipulating - -* Creating Repository:: -* Cloning Repository:: -* Staging and Unstaging:: -* Applying:: -* Committing:: -* Branching:: -* Merging:: -* Resolving Conflicts:: -* Rebasing:: -* Cherry Picking:: -* Resetting:: -* Stashing:: - -Transferring - -* Remotes:: -* Fetching:: -* Pulling:: -* Pushing:: -* Plain Patches:: -* Maildir Patches:: - -Miscellaneous - -* Tagging:: -* Notes:: -* Submodules:: -* Subtree:: -* Worktree:: -* Sparse checkouts:: -* Bundle:: -* Common Commands:: -* Wip Modes:: -* Commands for Buffers Visiting Files:: -* Minor Mode for Buffers Visiting Blobs:: - -Customizing - -* Per-Repository Configuration:: -* Essential Settings:: - -Plumbing - -* Calling Git:: -* Section Plumbing:: -* Refreshing Buffers:: -* Conventions:: - -FAQ - -* FAQ - How to ...?:: -* FAQ - Issues and Errors:: - - - -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" . "https://melpa.org/packages/") t) - - • To use Melpa-Stable: - - (require 'package) - (add-to-list 'package-archives - '("melpa-stable" . "https://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 ‘compat’, ‘llama’, ‘seq’ (the built-in version is -enough when using Emacs >= 29.1), ‘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 ‘compat’, ‘llama’, ‘seq’ (for Emacs < 29.1), -‘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/compat - LOAD_PATH += -L ~/.emacs.d/site-lisp/llama - LOAD_PATH += -L ~/.emacs.d/site-lisp/seq - LOAD_PATH += -L ~/.emacs.d/site-lisp/transient/lisp - LOAD_PATH += -L ~/.emacs.d/site-lisp/with-editor/lisp - - 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/docs/")) - - 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/compat") - (add-to-list 'load-path "~/.emacs.d/site-lisp/llama") - (add-to-list 'load-path "~/.emacs.d/site-lisp/seq") - (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 and push 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’. - - 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. So, by default, it is globally bound to ‘C-x M-g’. - - A similar menu featuring (for the most part) commands that act on -just the file being visited in the current buffer, is globally bound to -‘C-c M-g’. That binding can also be used in buffers, which do not visit -a file, but then only a subset of the commands is available. - - The global key bindings mentioned in the previous two paragraphs are -quite inconvenient. We recommend using ‘C-c g’ and ‘C-c f’ instead, but -cannot use those key sequences by default because they are strictly -reserved for bindings added by the user. See *note Global Bindings::, -if you want to explicitly opt-in to the recommended key bindings. - - Magit also provides context menus and other mouse commands, see *note -Mouse Support::. - - 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. -* Mouse Support:: -* 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. - -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. - -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. - - The value should always contain ‘%m’ or ‘%M’, ‘%v’ or ‘%V’, and - ‘%t’. If ‘magit-uniquify-buffer-names’ is non-nil, then the value - must end with ‘%t’ or ‘%t%x’. 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. - -4.1.3 Quitting Windows ----------------------- - -‘q’ (‘magit-mode-bury-buffer’) - This command buries or kills the current Magit buffer. The - function specified by option ‘magit-bury-buffer-function’ is used - to bury the buffer when called without a prefix argument or to kill - it when called with a single prefix argument. - - When called with two or more prefix arguments then it always kills - all Magit buffers, associated with the current project, including - the current buffer. - - -- 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-mode-quit-window’. - - -- 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. - -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. - -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. - -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. - -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. - -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. - -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-c ’ (‘magit-section-cycle’) -‘C-’ (‘magit-section-cycle’) - Cycle the visibility of current section and its children. - - If this command is invoked using ‘C-’ and that is globally - bound to ‘tab-next’, then this command pivots to behave like that - command, and you must instead use ‘C-c TAB’ to cycle section - visibility. - - If you would like to keep using ‘C-’ to cycle section - visibility but also want to use ‘tab-bar-mode’, then you have to - prevent that mode from using this key and instead bind another key - to ‘tab-next’. Because ‘tab-bar-mode’ does not use a mode map but - instead manipulates the global map, this involves advising - ‘tab-bar--define-keys’. - -‘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. - -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’. - -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. - -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-x M-g’ (‘magit-dispatch’) -‘C-c g’ (‘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 Magit by default binds it to ‘C-c M-g’ in the global keymap. - ‘C-c g’ would be a better binding, but we cannot use that by - default, because that key sequence is reserved for the user. See - *note Global Bindings:: to learn more default and recommended key - bindings. - - -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 ‘C-M-p’ and ‘C-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 ‘C-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: Mouse Support, Prev: Transient Arguments and Buffer Variables, Up: Interface Concepts - -4.5 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-cherry-pick’ Aborting a cherry-pick throws away - all conflict resolutions which have already been carried - out by the user. - - • ‘abort-revert’ Aborting a revert throws away all conflict - resolutions which have already been carried out by the - user. - - • ‘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: - - • ‘stash-apply-3way’ When a stash cannot be applied using - ‘git stash apply’, then Magit uses ‘git apply’ instead, - possibly using the ‘--3way’ argument, which isn’t always - perfectly safe. See also ‘magit-stash-apply’. - - • ‘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. - -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. - -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. - -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. - -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’. - - • ‘format-prompt’ is called on PROMPT and DEF (or FALLBACK if - DEF is ‘nil’). This appends ": " to the prompt and may also - add the default to the prompt, using the format specified by - ‘minibuffer-default-prompt-format’ and depending on - ‘magit-completing-read-default-prompt-predicate’. - -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: Mouse Support, Next: Running Git, Prev: Completion Confirmation and the Selection, Up: Interface Concepts - -4.6 Mouse Support -================= - -Double clicking on a section heading toggles the visibility of its body, -if any. Likewise clicking in the left fringe toggles the visibility of -the appropriate section. - - A context menu is provided but has to be enabled explicitly. In -Emacs 28 and greater, enable the global mode ‘context-menu-mode’. If -you use an older Emacs release, set -‘magit-section-show-context-menu-for-emacs<28’. - - -File: magit.info, Node: Running Git, Prev: Mouse Support, Up: Interface Concepts - -4.7 Running Git -=============== - -4.7.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. - -‘M-x magit-toggle-git-debug’ - This command toggles whether additional git errors are reported. - - 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 with this command - that can be enabled temporarily. In that case, if git returns with - a non-zero exit status, then at least its standard error is - inserted into this buffer. - - Also note that just because git exits with a non-zero status and - prints an error message, that usually doesn’t mean that it is an - error as far as Magit is concerned, which is another reason we - usually hide these error messages. Whether some error message is - relevant in the context of some unexpected behavior has to be - judged on a case by case basis. - -4.7.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. - -4.7.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. - -‘! m’ (‘magit-git-mergetool’) - This command runs ‘git mergetool --gui’ in the current repository. - - With a prefix argument this acts as a transient prefix command, - allowing the user to select the mergetool and change some settings. - -4.7.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. - -4.7.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) - -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 - This hook is run to insert sections into a status buffer. - - The functions described in this section, and the functions - ‘magit-insert-status-headers’ and ‘magit-insert-untracked-files’, - which are described in subsequent sections, are members of this - hook. - - Some additional functions that can be added to this hook, but are - by default added to another hooks, are listed in *note References - Buffer::. - - -- 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-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. - -5.1.2 Status File List Sections -------------------------------- - -These functions honor the buffer’s file filter, which can be set using -‘D - -’. - - -- Function: magit-insert-untracked-files - This function may insert a list of untracked files. Whether it - actually does so, depends on the option described next. - - -- User Option: magit-status-show-untracked-files - This option controls whether the above function inserts a list of - untracked files in the status buffer. - - • If ‘nil’, do not list any untracked files. - • If ‘t’, list untracked files, but if a directory does not - contain any untracked files, then only list that directory, - not the contained untracked files. - • If ‘all’, then list each individual untracked files. This is - can be very slow and is discouraged. - - The corresponding values for the Git variable are "no", "normal" - and "all". - - To disable listing untracked files in a specific repository only, - add the following to ‘.dir-locals.el’: - - ((magit-status-mode - (magit-status-show-untracked-files . "no"))) - - Alternatively (and mostly for historic reasons), it is possible to - use ‘git config’ to set the repository-local value: - - git config set --local status.showUntrackedFiles no - - This does *not* override the (if any) local value of this Lisp - variable, but it does override its global value. - - See the last section in the git-status(1) manpage, to speed up the - part of the work Git is responsible for. Turning that list into - sections is also not free, so Magit only lists - ‘magit-status-file-list-limit’ files. - - -- User Option: magit-status-file-list-limit - This option controls many files are listed at most in each section - that lists files in the status buffer. For performance reasons, it - is recommended that you do not increase this limit. - - While the above function is a member of ‘magit-status-section-hook’ -by default, the following functions have to be explicitly added by the -user. Because that negatively affects performance, it is recommended -that you don’t do that. - - -- Function: magit-insert-tracked-files - Insert a list of tracked files. - - -- Function: magit-insert-ignored-files - Insert a list of ignored files. - - -- Function: magit-insert-skip-worktree-files - Insert a list of skip-worktree files. - - -- Function: magit-insert-assumed-unchanged-files - Insert a list of files that are assumed to be unchanged. - -5.1.3 Status Log Sections -------------------------- - - -- 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 - "-". - -5.1.4 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. - -5.1.5 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. - -5.1.6 Status Options --------------------- - - -- 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 option ‘magit-repository-directories’ controls 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’, ‘:pad-right’ and ‘:sort’. - - The ‘:sort’ function has a weird interface described in the - docstring of ‘tabulated-list--get-sort’. Alternatively ‘<’ and - ‘magit-repolist-version<’ can be used as those functions are - automatically replaced with functions that satisfy the interface. - Set ‘:sort’ to ‘nil’ to inhibit sorting; if unspecified, then the - column is sortable using the default sorter. - - 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 9. ‘+’ 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-flags - This functions 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. - - -- 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. - -The following commands are available in repolist buffers: - -‘’ (‘magit-repolist-status’) - This command shows the status for the repository at point. - -‘m’ (‘magit-repolist-mark’) - This command marks the repository at point. - -‘u’ (‘magit-repolist-unmark’) - This command unmarks the repository at point. - -‘f’ (‘magit-repolist-fetch’) - This command fetches all marked repositories. If no repositories - are marked, then it offers to fetch all displayed repositories. - -‘5’ (‘magit-repolist-find-file-other-frame’) - This command reads a relative file-name (without completion) and - opens the respective file in each marked repository in a new frame. - If no repositories are marked, then it offers to do this for all - displayed repositories. - - -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 h’ (‘magit-log-head’) - Show log for ‘HEAD’. - -‘l u’ (‘magit-log-related’) - Show log for the current branch, its upstream and its push target. - When the upstream is a local branch, then also show its own - upstream. When ‘HEAD’ is detached, then show log for that, the - previously checked out branch and its upstream and push-target. - -‘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 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::. - -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 L’ (‘magit-toggle-margin’) - Show or hide the margin. - -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. - - -- User Option: magit-log-show-color-graph-limit - When showing more commits than specified by this option, then the - ‘--color’ argument, if specified, is silently dropped. This is - necessary because the ‘ansi-color’ library, which is used to turn - control sequences into faces, is just too slow. - - -- User Option: magit-log-show-signatures-limit - When showing more commits than specified by this option, then the - ‘--show-signature’ argument, if specified, is silently dropped. - This is necessary because checking the signature of a large number - of commits is just too slow. - - 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::. - -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. - -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. - -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. - -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. - - For example, if point is on a commit, show the changes introduced - by that commit. Likewise if point is on the section titled - "Unstaged changes", then show those changes in a separate buffer. - Generally speaking, compare the thing at point with the most - logical, trivial and (in *any* situation) at least potentially - useful other thing it could be compared to. - - When the region selects commits, then compare the two commits at - either end. There are different ways two commits can be compared. - In the buffer showing the diff, you can control how the comparison, - is done, using "D r" and "D f". - - This function does not always show the changes that you might want - to view in any given situation. You can think of the changes being - shown as the smallest common denominator. There is no AI involved. - If this command never does what you want, then ignore it, and - instead use the commands that allow you to explicitly specify what - you need. - -‘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::. - -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. - - (There is one exception; diff arguments cannot be changed in buffers -created by ‘magit-merge-preview’ because the underlying Git command does -not support these arguments.) - -‘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. - -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-commit’ 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. - -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 wish 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::. - - -- User Option: magit-format-file-function - This function is used to format lines representing a file. It is - used for file headings in diffs, in diffstats and for lists of - files (such as the untracked files). Depending on the caller, it - receives either three or five arguments; the signature has to be - ‘(kind file face &optional status orig)’. KIND is one of ‘diff’, - ‘module’, ‘stat’ and ‘list’. - -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-rest’) - This command allows you to resolve outstanding conflicts in the - file at point using Ediff. If there is no file at point or if it - doesn’t have any unmerged changes, then this command prompts for a - file. - - Provided that the value of ‘merge.conflictstyle’ is ‘diff3’, you - can view the file’s merge-base revision using ‘/’ in the Ediff - control buffer. - - The A, B and Ancestor buffers are constructed from the conflict - markers in the worktree file. Because you and/or Git may have - already resolved some conflicts, that means that these buffers may - not contain the actual versions from the respective blobs. - -‘E M’ (‘magit-ediff-resolve-all’) - This command allows you to resolve all conflicts in the file at - point using Ediff. If there is no file at point or if it doesn’t - have any unmerged changes, then this command prompts for a file. - - Provided that the value of ‘merge.conflictstyle’ is ‘diff3’, you - can view the file’s merge-base revision using ‘/’ in the Ediff - control buffer. - - First the file in the worktree is moved aside, appending the suffix - ‘.ORIG’, so that you could later go back to that version. Then it - is reconstructed from the two sides of the conflict and the - merge-base, if available. - - It would be nice if the worktree file were just used as-is, but - Ediff does not support that. This means that all conflicts, that - Git has already resolved, are restored. On the other hand Ediff - also tries to resolve conflicts, and in many cases Ediff and Git - should produce similar results. - - However if you have already resolved some conflicts manually, then - those changes are discarded (though you can recover them from the - backup file). In such cases ‘magit-ediff-resolve-rest’ might be - more suitable. - - The advantage that this command has over ‘magit-ediff-resolve-rest’ - is that the A, B and Ancestor buffers correspond to blobs from the - respective commits, allowing you to inspect a side in context and - to use Magit commands in these buffers to do so. Blame and log - commands are particularly useful here. - -‘E t’ (‘magit-git-mergetool’) - This command does not actually use Ediff. While it serves the same - purpose as ‘magit-ediff-resolve-rest’, it uses ‘git mergetool - --gui’ to resolve conflicts. - - With a prefix argument this acts as a transient prefix command, - allowing the user to select the mergetool and change some settings. - -‘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-resolve-function - This option controls which function ‘magit-ediff-dwim’ uses to - resolve conflicts. One of ‘magit-ediff-resolve-rest’, - ‘magit-ediff-resolve-all’ or ‘magit-git-mergetool’; which are all - discussed above. - - -- 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. - -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. - - Also see *note Commands for Buffers Visiting Files::. - -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. - -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. 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. When using the default key bindings, that can be done by -pressing ‘C-c M-g’. When using the recommended bindings, this command -is instead bound to ‘C-c f’. Also see *note Global Bindings::. - - The blaming suffix commands can be invoked directly from the file -dispatch transient. However if you want to set an infix argument, then -you have to enter the blaming sub-prefix first. - -‘C-c f B’ (‘magit-blame’) -‘C-c f b’ (‘magit-blame-addition’) -‘C-c f B b’ -‘C-c f r’ (‘magit-blame-removal’) -‘C-c f B r’ -‘C-c f f’ (‘magit-blame-reverse’) -‘C-c f B f’ -‘C-c f e’ (‘magit-blame-echo’) -‘C-c f B e’ -‘C-c f q’ (‘magit-blame-quit’) -‘C-c f B q’ - Each of these commands is documented individually right below, - alongside their default key bindings. The bindings shown above are - the recommended bindings, which you can enable by following the - instructions in *note Global Bindings::. - -‘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. - -‘C-c M-g q’ (‘magit-blame-quit’) -‘C-c M-g B q’ - This command turns off Magit-Blame mode. If the buffer was created - during a recursive blame, then it also kills the buffer. - -‘’ (‘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 >’ (‘magit-clone-sparse’) - This command creates a clone of an existing repository and - initializes a sparse checkout, avoiding a checkout of the full - working tree. To add more directories, use the - ‘magit-sparse-checkout’ transient (see *note Sparse checkouts::). - -‘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. The value can be a string - (representing a single static format) or an alist with elements - ‘(HOSTNAME . FORMAT)’ mapping hostnames to formats. When an alist - is used, the ‘t’ key represents the default format. - - Example of a single format string: - - (setq magit-clone-url-format - "git@%h:%n.git") - - Example of by-hostname format strings: - - (setq magit-clone-url-format - '(("git.example.com" . "git@%h:~%n") - (nil . "git@%h:%n.git"))) - - -- User Option: magit-post-clone-hook - Hook run after the Git process has successfully finished cloning - the repository. When the hook is called, ‘default-directory’ is - let-bound to the directory where the repository has been cloned. - - -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’ 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’. - -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 the -‘--message’ argument, so Git has to get the message from the user. To -do so, it creates a file such as ‘.git/COMMIT_EDITMSG’ and then opens -that file in the editor specified by ‘$EDITOR’ (or ‘$GIT_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 the commit message. - -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. - -Creating a new commit -..................... - -‘c c’ (‘magit-commit-create’) - Create a new commit. - -Editing the last commit -....................... - -These commands modify the last (a.k.a., "HEAD") commit. The commit is -modified (a.k.a., replaced) immediately. Similar commands exist for -modifying other (non-HEAD) commits. Those commands are described in the -following two sections. For each command in this section, we mention -the respective non-HEAD commands, to make the relation explicit. - - The command descriptions below mention the specific arguments they -use when calling ‘git commit’. The arguments specified in the menu are -appended to those arguments. - -‘c e’ (‘magit-commit-extend’) - This command amends the staged changes to the last commit, without - editing its commit message. - - This command calls ‘git commit --amend --no-edit’. - - With a prefix argument the committer date is not updated; without - an argument it is updated. - - The option ‘magit-commit-extend-override-date’ can be used to - inverse the meaning of the prefix argument. Non-interactively, the - optional OVERRIDE-DATE argument controls this behavior, and the - option is of no relevance. - -‘c a’ (‘magit-commit-amend’) - This command amends the staged changes to the last commit, and pops - up a buffer to let the user edit its commit message. - - This command calls ‘git commit --amend --edit’. - -‘c w’ (‘magit-commit-reword’) - This command pops up a buffer to let the user edit the message of - the latest commit. The commit tree remains unchanged and staged - changes remain staged. - - This command calls ‘git commit --amend --only --edit’. - - With a prefix argument the committer date is not updated; without - an argument it is updated. - - The option ‘magit-commit-reword-override-date’ can be used to - inverse the meaning of the prefix argument. Non-interactively, the - optional OVERRIDE-DATE argument controls this behavior, and the - option is of no relevance. - -Editing any reachable commit -............................ - -These commands create a new commit, which targets an existing commit, -from the staged changes and/or using a new commit message. Any commit -that is reachable from HEAD, including HEAD itself, can be the target. - - The new commit is intended to be eventually squashed into the -targeted commit, but this is *not* done immediately. The squashing is -done at a later time, when you explicitly call -‘magit-rebase-autosquash’, or use ‘--autosquash’ with another rebase -command. - - Some of these commands require that you immediately write a new -commit message, or that you immediately edit an existing message. - - The new commits are called "squash" and "fixup" commits. The -difference is that when a "squash" commit is squashed into its targeted -commit, the user gets a chance to modify the message to be used for the -final commit; while for "fixup" commits the existing message of the -targeted commit is used as-is and the message of the "fixup" commit is -discarded. - - If point is on a reachable commit, then all of these commands target -that commit, without requiring confirmation. If point is on some -reachable commit, but you want to target another commit, use a prefix -argument, to select a commit in a log buffer dedicated to that task. -The meaning of the prefix argument can be inverted by customizing -‘magit-commit-squash-confirm’. - - The command descriptions below mention the specific arguments they -use when calling ‘git commit’. The arguments specified in the menu are -appended to those arguments. - - The next two commands also exist in "instant" variants, which are -described in the next section. Those variants behave the same as the -variants described here, except that they immediately initiate an -‘--autosquash’ rebase. - -‘c f’ (‘magit-commit-fixup’) - This command creates a new fixup commit from the staged changes, - targeting the reachable commit at point, if any. Otherwise the - user is prompted for a commit. - - Use this variant if you want to correct some minor defect in the - targeted commit, which does not require changes to the existing - message of the targeted commit. - - This command calls ‘git commit --fixup=COMMIT --no-edit’. - -‘c s’ (‘magit-commit-squash’) - This command creates a new squash commit from the staged changes, - targeting the reachable commit at point, if any. Otherwise the - user is prompted for a commit. - - Use this variant if you want a chance to make changes to the final - commit message, but not until the two commits are being squashed - into the final combined commit. - - This command calls ‘git commit --squash=COMMIT --no-edit’. - -‘c A’ (‘magit-commit-alter’) - This command creates a new fixup commit from the staged changes, - targeting the reachable commit at point, if any. Otherwise the - user is prompted for a commit. - - Use this variant if you want to write the final commit message now, - but (as for all variants in this section) do not want to - immediately squash the fixup and targeted commits into a final - combined commit. - - This command calls ‘git commit --fixup=amend:COMMIT --edit’. - -‘c n’ (‘magit-commit-augment’) - This command creates a new squash commit from the staged changes, - targeting the reachable commit at point, if any. Otherwise the - user is prompted for a commit. - - Use this variant if you want to describe the new changes now, but - want to delay writing the final message, which describes the - changes in the combined commit, until you actually combine the - squash and target commits into the final commit. You can think of - the new message, which you write here, as a "note", to be - integrated once once you write the final commit message. - - This command calls ‘git commit --squash=COMMIT --edit’. - -‘c W’ (‘magit-commit-revise’) - This command pops up a buffer containing the commit message of the - reachable commit at point, if any. Otherwise the user is prompted - for a commit to target. - - Use this variant if you want to correct the message of the targeted - commit, but want to delay performing the ‘--autosquash’ rebase, - which actually changes that commit. - - This command calls ‘git commit --fixup=reword:COMMIT --edit’. - -Editing any reachable commit and rebasing immediately -..................................................... - -These commands create a new commit, which targets an existing commit, -from the staged changes. Any commit that is reachable from HEAD, -including HEAD itself, can be the target. - - The new commit is immediately squashed into its target commit, using -an ‘--autosquash’ rebase. - - The command descriptions below mention the specific arguments they -use when calling ‘git commit’. The arguments specified in the menu are -appended to those arguments when calling ‘git commit’. - -‘c F’ (‘magit-commit-instant-fixup’) - This command creates a fixup commit, targeting the reachable commit - at point, if any. Otherwise the user is prompted for a commit. - Then it instantly performs a rebase, to squash the new commit into - the targeted commit. - - The original commit message of the targeted commit is left - untouched. - - This command calls ‘git commit --fixup=COMMIT --no-edit’ and then - ‘git rebase --autosquash MERGE-BASE’. - -‘c S’ (‘magit-commit-instant-squash’) - This command creates a squash commit, targeting the reachable - commit at point, if any. Otherwise the user is prompted for a - commit. Then it instantly performs a rebase, to squash the new - commit into the targeted commit. - - During the rebase phase the user is asked to author the final - commit message, based on the original message of the targeted - commit. - - This command calls ‘git commit --squash=COMMIT --no-edit’ and then - ‘git rebase --autosquash MERGE-BASE’. - -Options used by commit commands -............................... - - • Used by all or most commit commands - - -- User Option: magit-commit-show-diff - Whether the relevant diff is automatically shown when - committing. - - -- User Option: magit-commit-ask-to-stage - Whether to ask to stage all unstaged changes when committing - and nothing is staged. - - -- 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-commit-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 . - - • Used by all squash and fixup commands - - -- 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. - - • Used by specific commit commands - - -- 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. - -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. - -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). - -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. - -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’. - - -- 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-post-finish-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’. - -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-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 -============= - -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::). - -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 - begun 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. - - Require confirmation when deleting branches is dangerous in some - way. Option ‘magit-no-confirm’ can be customized to not require - confirmation in certain cases. See its docstring to learn why - confirmation is required by default in certain cases or if a prompt - is confusing. - -‘b m’ (‘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)) - -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. - -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 d’ (‘magit-merge-dissolve’) - 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. - - Note that commands, that normally change how a diff is displayed, - do not work in buffers created by this command, because the - underlying Git command does not support diff arguments. - - 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 seven 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. - - By default only commits that are not reachable from the upstream - branch are potentially squashed into. If no upstream is configured - or with a prefix argument, the user is prompted for the first - commit to potentially squash into. - -‘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. - -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’) - Comment the current action line, or if it is already commented, - then uncomment it. - -‘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. - -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: - - • Commits that use the same foreground color as the ‘default’ face - have not been applied yet. - - • Yellow commits have some special relationship to the commit rebase - stopped at. This is used for the words "join", "goal", "same" and - "work" (see below). - - • 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. - -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 V’ (‘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. - - When using a Git release before v2.38.0, simply run ‘git stash - apply’ or with a prefix argument ‘git stash apply --index’. - - When using Git v2.38.0 or later, behave more intelligently: - - First try ‘git stash apply --index’, which tries to preserve the - index stored in the stash, if any. This may fail because applying - the stash could result in conflicts and those have to be stored in - the index, making it impossible to also store the stash’s index - there. - - If ‘git stash’ fails, then potentially fall back to using ‘git - apply’. If the stash does not touch any unstaged files, then pass - ‘--3way’ to that command. Otherwise ask the user whether to use - that argument or ‘--reject’. Customize ‘magit-no-confirm’ if you - want to fall back to using ‘--3way’, without being prompted. - -‘z p’ (‘magit-stash-pop’) - Apply a stash to the working tree. On complete success (if the - stash can be applied without any conflicts, and while preserving - the stash’s index) then remove the stash from stash list. - - When using a Git release before v2.38.0, simply run ‘git stash pop’ - or with a prefix argument ‘git stash pop --index’. - - When using Git v2.38.0 or later, behave more intelligently: - - First try ‘git stash pop --index’, which tries to preserve the - index stored in the stash, if any. This may fail because applying - the stash could result in conflicts and those have to be stored in - the index, making it impossible to also store the stash’s index - there. - - If ‘git stash’ fails, then potentially fall back to using ‘git - apply’. If the stash does not touch any unstaged files, then pass - ‘--3way’ to that command. Otherwise ask the user whether to use - that argument or ‘--reject’. Customize ‘magit-no-confirm’ if you - want to fall back to using ‘--3way’, without being prompted. - -‘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 an existing stash. The new - 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 from an existing stash. Use the - current branch or ‘HEAD’ as the starting-point of the new branch. - Then apply the 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 -=========== - -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. - -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 pushing to 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-fetch-modules’) - This command fetches all submodules. With a prefix argument, it - acts as a transient prefix command, allowing the caller to set - options. - - -- 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:: -* Sparse checkouts:: -* 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::. - -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 populated - 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’, ‘:pad-right’ and ‘:sort’. - - The ‘:sort’ function has a weird interface described in the - docstring of ‘tabulated-list--get-sort’. Alternatively ‘<’ and - ‘magit-repolist-version<’ can be used as those functions are - automatically replaced with functions that satisfy the interface. - Set ‘:sort’ to ‘nil’ to inhibit sorting; if unspecified, then the - column is sortable using the default sorter. - - 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 9. ‘+’ is substituted for numbers higher - than 9. - -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 populated modules. With a prefix - argument, it acts as a transient prefix command, allowing the - caller to set options. - - Also fetch the super-repository, because ‘git fetch’ does not - support not doing that. - - -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: Sparse checkouts, 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: Sparse checkouts, Next: Bundle, Prev: Worktree, Up: Miscellaneous - -8.6 Sparse checkouts -==================== - -Sparse checkouts provide a way to restrict the working tree to a subset -of directories. See *note (gitman)git-sparse-checkout::. - - *Warning*: Git introduced the ‘git sparse-checkout’ command in -version 2.25 and still advertises it as experimental and subject to -change. Magit’s interface should be considered the same. In -particular, if Git introduces a backward incompatible change, Magit’s -sparse checkout functionality may be updated in a way that requires a -more recent Git version. - -‘>’ (‘magit-sparse-checkout’) - This transient prefix command binds the following suffix commands - and displays them in a temporary buffer until a suffix is invoked. - -‘> e’ (‘magit-sparse-checkout-enable’) - This command initializes a sparse checkout that includes only the - files in the top-level directory. - - Note that ‘magit-sparse-checkout-set’ and - ‘magit-sparse-checkout-add’ automatically initialize a sparse - checkout if necessary. However, you may want to call - ‘magit-sparse-checkout-enable’ explicitly to re-initialize a sparse - checkout after calling ‘magit-sparse-checkout-disable’, to pass - additional arguments to ‘git sparse-checkout init’, or to execute - the initialization asynchronously. - -‘> s’ (‘magit-sparse-checkout-set’) - This command takes a list of directories and configures the sparse - checkout to include only files in those subdirectories. Any - previously included directories are excluded unless they are in the - provided list of directories. - -‘> a’ (‘magit-sparse-checkout-add’) - This command is like ‘magit-sparse-checkout-set’, but instead adds - the specified list of directories to the set of directories that is - already included in the sparse checkout. - -‘> r’ (‘magit-sparse-checkout-reapply’) - This command applies the currently configured sparse checkout - patterns to the working tree. This is useful to call if excluded - files have been checked out after operations such as merging or - rebasing. - -‘> d’ (‘magit-sparse-checkout-disable’) - This command restores the full checkout. To return to the previous - sparse checkout, call ‘magit-sparse-checkout-enable’. - - A sparse checkout can also be initiated when cloning a repository by -using the ‘magit-clone-sparse’ command in the ‘magit-clone’ transient -(see *note Cloning Repository::). - - If you want the status buffer to indicate when a sparse checkout is -enabled, add the function ‘magit-sparse-checkout-insert-header’ to -‘magit-status-headers-hook’. - - -File: magit.info, Node: Bundle, Next: Common Commands, Prev: Sparse checkouts, Up: Miscellaneous - -8.7 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.8 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.9 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’. - -8.9.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. - -8.9.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.10 Commands for Buffers Visiting Files -======================================== - -By default Magit defines a few global key bindings. These bindings are -a compromise between providing no bindings at all and providing the -better bindings I would have liked to use instead. Magit cannot provide -the set of recommended bindings by default because those key sequences -are strictly reserved for bindings added by the user. Also see *note -Global Bindings:: and *note (elisp)Key Binding Conventions::. - - To use the recommended bindings, add this to your init file and -restart Emacs. - - (setq magit-define-global-key-bindings 'recommended) - - If you don’t want Magit to add any bindings to the global keymap at -all, add this to your init file and restart Emacs. - - (setq magit-define-global-key-bindings nil) - -‘C-c f’ (‘magit-file-dispatch’) -‘C-c f s’ (‘magit-stage-file’) -‘C-c f s’ (‘magit-stage-buffer-file’) -‘C-c f u’ (‘magit-unstage-file’) -‘C-c f u’ (‘magit-unstage-buffer-file’) -‘C-c f , x’ (‘magit-file-untrack’) -‘C-c f , r’ (‘magit-file-rename’) -‘C-c f , k’ (‘magit-file-delete’) -‘C-c f , c’ (‘magit-file-checkout’) -‘C-c f D’ (‘magit-diff’) -‘C-c f d’ (‘magit-diff-buffer-file’) -‘C-c f L’ (‘magit-log’) -‘C-c f l’ (‘magit-log-buffer-file’) -‘C-c f t’ (‘magit-log-trace-definition’) -‘C-c f M’ (‘magit-log-merged’) -‘C-c f B’ (‘magit-blame’) -‘C-c f b’ (‘magit-blame-additions’) -‘C-c f r’ (‘magit-blame-removal’) -‘C-c f f’ (‘magit-blame-reverse’) -‘C-c f m’ (‘magit-blame-echo’) -‘C-c f q’ (‘magit-blame-quit’) -‘C-c f p’ (‘magit-blob-previous’) -‘C-c f n’ (‘magit-blob-next’) -‘C-c f v’ (‘magit-find-file’) -‘C-c f V’ (‘magit-blob-visit-file’) -‘C-c f g’ (‘magit-status-here’) -‘C-c f G’ (‘magit-display-repository-buffer’) -‘C-c f c’ (‘magit-commit’) -‘C-c f e’ (‘magit-edit-line-commit’) - Each of these commands is documented individually right below, - alongside their default key bindings. The bindings shown above are - the recommended bindings, which you can enable by following the - instructions further up. - -‘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. - -‘C-c M-g s’ (‘magit-stage-file’) -‘C-c M-g s’ (‘magit-stage-buffer-file’) - Stage all changes to the file being visited in the current buffer. - When not visiting a file, then the first command is used, which - prompts for a file. - -‘C-c M-g u’ (‘magit-unstage-file’) -‘C-c M-g u’ (‘magit-unstage-buffer-file’) - Unstage all changes to the file being visited in the current - buffer. When not visiting a file, then the first command is used, - which prompts for a file. - -‘C-c M-g , x’ (‘magit-file-untrack’) - This command untracks a file read from the user, defaulting to the - visited file. - -‘C-c M-g , r’ (‘magit-file-rename’) - This command renames a file read from the user, defaulting to the - visited file. - -‘C-c M-g , k’ (‘magit-file-delete’) - This command deletes a file read from the user, defaulting to the - visited file. - -‘C-c M-g , c’ (‘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. - -‘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. - - -- 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 t’ (‘magit-log-trace-definition’) - This command shows the log for the definition at point. - -‘C-c M-g M’ (‘magit-log-merged’) - This command reads a commit and a branch in shows a log concerning - the merge of the former into the latter. This shows multiple - commits even in case of a fast-forward merge. - -‘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 p’ (‘magit-blob-previous’) - This command visits the previous blob which modified the current - file. - -‘C-c M-g n’ (‘magit-blob-next’) - This command visits the next blob which modified the current file. - -‘C-c M-g v’ (‘magit-find-file’) - This command reads a revision and file and visits the respective - blob. - -‘C-c M-g V’ (‘magit-blob-visit-file’) - This command visits the file from the working tree, corresponding - to the current blob. When visiting a blob or the version from the - index, then it goes to the same location in the respective file in - the working tree. - -‘C-c M-g g’ (‘magit-status-here’) - This command displays the status of the current repository in a - buffer, like ‘magit-status’ does. Additionally it tries to go to - the position in that buffer, which corresponds to the position in - the current file-visiting buffer (if any). - -‘C-c M-g G’ (‘magit-display-repository-buffer’) - This command reads and displays a Magit buffer belonging to the - current repository, without refreshing it. - -‘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 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. - - -File: magit.info, Node: Minor Mode for Buffers Visiting Blobs, Prev: Commands for Buffers Visiting Files, Up: Miscellaneous - -8.11 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 three sections list and discuss several variables that many -users might want to customize, for safety and/or performance reasons. - -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::. - -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. - - 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-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. Each line printed to the ‘*Messages*’ buffer -contains a section name, the number of seconds it took to show this -section, and from 0 to 2 exclamation marks: the more exclamation marks -the slower the section is. - - 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. - -Log Performance -............... - -When showing logs, Magit limits the number of commits initially shown in -the hope that this avoids unnecessary work. When ‘--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) - (remove-hook 'with-editor-filter-visit-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. - -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. - -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. - - Additionally, ‘git’ installed from a package manager like ‘brew’ or -‘nix’ seems to be slower than the native executable. Profile the ‘git’ -executable you’re running against the one at ‘/usr/bin/git’, and if you -notice a notable difference try using the latter as -‘magit-git-executable’. - -9.2.3 Global Bindings ---------------------- - - -- User Option: magit-define-global-key-bindings - This option controls which set of Magit key bindings, if any, may - be added to the global keymap, even before Magit is first used in - the current Emacs session. - - • If the value is ‘nil’, no bindings are added. - - • If ‘default’, maybe add: - - ‘C-x g’ ‘magit-status’ - ‘C-x M-g’ ‘magit-dispatch’ - ‘C-c M-g’ ‘magit-file-dispatch’ - - • If ‘recommended’, maybe add: - - ‘C-x g’ ‘magit-status’ - ‘C-c g’ ‘magit-dispatch’ - ‘C-c f’ ‘magit-file-dispatch’ - - These bindings are strongly recommended, but we cannot use - them by default, because the ‘C-c ’ namespace is - strictly reserved for bindings added by the user (see *note - (elisp)Key Binding Conventions::). - - The bindings in the chosen set 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 these bindings is delayed until ‘after-init-hook’ is run 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 has no effect if ‘after-init-hook’ has - already been run. - - ---------- Footnotes ---------- - - (1) - - - -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. - -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. - -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 -===================== - -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. - -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). - -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::. - -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 see *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 ...? -===================== - -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 rationale 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 -. - -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, use ‘M-x magit-process-buffer’). This shows 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, using ‘M-x -magit-toggle-git-debug’. - -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, simply because Info doesn’t support linking to -manpages. - - Unfortunately some distributions do not install the ‘gitman’ manual -by default and you would 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 Emacs packages ‘man’ or ‘woman’, e.g.: - - (setq magit-view-git-manual-method 'man) - -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 - -A.1.5 How does branching and pushing work? ------------------------------------------- - -Please see *note Branching:: and - - -A.1.6 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 -=========================== - -A.2.1 Magit is slow -------------------- - -See *note Performance:: and *note I changed several thousand files at -once and now Magit is unusable::. - -A.2.2 I changed several thousand files at once and now Magit is unusable ------------------------------------------------------------------------- - -Magit is currently not expected to work well under such conditions. It -sure would be nice if it did. Reaching satisfactory performance under -such conditions will require some heavy refactoring. This is no small -task but I hope to eventually find the time to make it happen. - - But for now we recommend you use the command line to complete this -one commit. Also see *note Performance::. - -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::. - -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 -. - -A.2.5 I am using macOS 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’. - -A.2.6 Expanding a file to show the diff causes it to disappear --------------------------------------------------------------- - -This is probably caused by a customization 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’. - -A.2.7 Point is wrong in the ‘COMMIT_EDITMSG’ buffer ---------------------------------------------------- - -Neither Magit nor ‘git-commit.el’ 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 restores 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 it. ‘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)))) - -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)) - -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. - -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’. - -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. - -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’. - -A.2.13 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-git-debug’ - This command toggles whether additional git errors are reported. - - 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 with this command - that can be enabled temporarily. In that case, if git returns with - a non-zero exit status, then at least its standard error is - inserted into this buffer. - - Also note that just because git exits with a non-zero status and - prints an error message, that usually doesn’t mean that it is an - error as far as Magit is concerned, which is another reason we - usually hide these error messages. Whether some error message is - relevant in the context of some unexpected behavior has to be - judged on a case by case basis. - -‘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-toggle-subprocess-record’ - This command toggles whether subprocess invocations are recorded. - - When enabled, all subprocesses started by ‘magit-process-file’ are - logged into the buffer specified by - ‘magit-process-record-buffer-name’ using the format - ‘magit-process-record-entry-format’. This is for debugging - purposes. - - This is in addition to and distinct from the default logging done - by default, and additional logging enabled with - ‘magit-toggle-git-debug’. - -‘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 magit-profile-refresh-buffer’ - This command profiles refreshing the current Magit buffer and then - displays the results. - -‘M-x magit-toggle-profiling’ - This command starts profiling Magit and Forge, or if profiling is - already in progress, it instead stops that and displays the - results. - -‘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 *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. (line 82) -* ! !: Running Git. (line 86) -* ! a: Running Git. (line 122) -* ! b: Running Git. (line 125) -* ! g: Running Git. (line 128) -* ! k: Running Git. (line 119) -* ! m: Running Git. (line 131) -* ! p: Running Git. (line 94) -* ! s: Running Git. (line 103) -* ! S: Running Git. (line 107) -* $: Running Git. (line 20) -* +: Logging. (line 160) -* + <1>: Diffing. (line 154) -* -: Logging. (line 163) -* - <1>: Diffing. (line 151) -* 0: Diffing. (line 157) -* 1: Sections. (line 163) -* 2: Sections. (line 163) -* 3: Sections. (line 163) -* 4: Sections. (line 163) -* 5: Repository List. (line 115) -* :: Running Git. (line 94) -* =: Logging. (line 155) -* >: Sparse checkouts. (line 17) -* > a: Sparse checkouts. (line 39) -* > d: Sparse checkouts. (line 50) -* > e: Sparse checkouts. (line 21) -* > r: Sparse checkouts. (line 44) -* > s: Sparse checkouts. (line 33) -* ^: Sections. (line 44) -* 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 115) -* b <1>: Branching. (line 63) -* b <2>: Rebasing. (line 187) -* B B: Bisecting. (line 16) -* B b: Bisecting. (line 32) -* b b: Branching. (line 97) -* b C: Branching. (line 81) -* b c: Branching. (line 113) -* B g: Bisecting. (line 36) -* B k: Bisecting. (line 46) -* b k: Branching. (line 188) -* b l: Branching. (line 119) -* B m: Bisecting. (line 40) -* b m: Branching. (line 199) -* b n: Branching. (line 104) -* B r: Bisecting. (line 51) -* B s: Bisecting. (line 26) -* b s: Branching. (line 141) -* b S: Branching. (line 168) -* b x: Branching. (line 173) -* c: Blaming. (line 141) -* C: Cloning Repository. (line 20) -* c <1>: Committing. (line 21) -* c <2>: Rebasing. (line 176) -* C >: Cloning Repository. (line 38) -* c a: Committing. (line 59) -* c A: Committing. (line 141) -* C b: Cloning Repository. (line 44) -* C C: Cloning Repository. (line 28) -* c c: Committing. (line 29) -* C d: Cloning Repository. (line 55) -* C e: Cloning Repository. (line 61) -* c e: Committing. (line 45) -* c f: Committing. (line 119) -* c F: Committing. (line 192) -* C m: Cloning Repository. (line 48) -* c n: Committing. (line 153) -* C s: Cloning Repository. (line 32) -* c s: Committing. (line 130) -* c S: Committing. (line 204) -* c w: Committing. (line 65) -* c W: Committing. (line 167) -* C-: Visiting Files and Blobs. - (line 78) -* C-: Sections. (line 138) -* C-c C-a: Committing. (line 415) -* C-c C-b: Logging. (line 116) -* C-c C-b <1>: Diffing. (line 173) -* C-c C-c: Logging. (line 297) -* C-c C-c <1>: Committing. (line 303) -* C-c C-c <2>: Rebasing. (line 123) -* C-c C-d: Diffing. (line 164) -* C-c C-d <1>: Committing. (line 339) -* C-c C-e: Diffing. (line 199) -* C-c C-f: Logging. (line 119) -* C-c C-f <1>: Diffing. (line 176) -* C-c C-i: Committing. (line 412) -* C-c C-k: Logging. (line 302) -* C-c C-k <1>: Committing. (line 307) -* C-c C-k <2>: Rebasing. (line 127) -* C-c C-n: Logging. (line 122) -* C-c C-o: Committing. (line 427) -* C-c C-p: Committing. (line 430) -* C-c C-r: Committing. (line 418) -* C-c C-s: Committing. (line 421) -* C-c C-t: Diffing. (line 190) -* C-c C-t <1>: Committing. (line 424) -* C-c C-w: Committing. (line 347) -* C-c f: Commands for Buffers Visiting Files. - (line 52) -* C-c f , c: Commands for Buffers Visiting Files. - (line 52) -* C-c f , k: Commands for Buffers Visiting Files. - (line 52) -* C-c f , r: Commands for Buffers Visiting Files. - (line 52) -* C-c f , x: Commands for Buffers Visiting Files. - (line 52) -* C-c f B: Blaming. (line 28) -* C-c f b: Blaming. (line 28) -* C-c f B <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f b <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f B b: Blaming. (line 28) -* C-c f B e: Blaming. (line 28) -* C-c f B f: Blaming. (line 28) -* C-c f B q: Blaming. (line 28) -* C-c f B r: Blaming. (line 28) -* C-c f c: Commands for Buffers Visiting Files. - (line 52) -* C-c f D: Commands for Buffers Visiting Files. - (line 52) -* C-c f d: Commands for Buffers Visiting Files. - (line 52) -* C-c f e: Blaming. (line 28) -* C-c f e <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f f: Blaming. (line 28) -* C-c f f <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f g: Commands for Buffers Visiting Files. - (line 52) -* C-c f G: Commands for Buffers Visiting Files. - (line 52) -* C-c f L: Commands for Buffers Visiting Files. - (line 52) -* C-c f l: Commands for Buffers Visiting Files. - (line 52) -* C-c f M: Commands for Buffers Visiting Files. - (line 52) -* C-c f m: Commands for Buffers Visiting Files. - (line 52) -* C-c f n: Commands for Buffers Visiting Files. - (line 52) -* C-c f p: Commands for Buffers Visiting Files. - (line 52) -* C-c f q: Blaming. (line 28) -* C-c f q <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f r: Blaming. (line 28) -* C-c f r <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f s: Commands for Buffers Visiting Files. - (line 52) -* C-c f s <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f t: Commands for Buffers Visiting Files. - (line 52) -* C-c f u: Commands for Buffers Visiting Files. - (line 52) -* C-c f u <1>: Commands for Buffers Visiting Files. - (line 52) -* C-c f v: Commands for Buffers Visiting Files. - (line 52) -* C-c f V: Commands for Buffers Visiting Files. - (line 52) -* C-c g: Transient Commands. (line 20) -* C-c M-g: Commands for Buffers Visiting Files. - (line 58) -* C-c M-g , c: Commands for Buffers Visiting Files. - (line 86) -* C-c M-g , k: Commands for Buffers Visiting Files. - (line 82) -* C-c M-g , r: Commands for Buffers Visiting Files. - (line 78) -* C-c M-g , x: Commands for Buffers Visiting Files. - (line 74) -* C-c M-g B: Blaming. (line 34) -* C-c M-g b: Blaming. (line 45) -* C-c M-g B <1>: Commands for Buffers Visiting Files. - (line 137) -* C-c M-g B b: Blaming. (line 45) -* C-c M-g B e: Blaming. (line 76) -* C-c M-g B f: Blaming. (line 68) -* C-c M-g B q: Blaming. (line 87) -* C-c M-g B r: Blaming. (line 60) -* C-c M-g c: Commands for Buffers Visiting Files. - (line 176) -* C-c M-g D: Commands for Buffers Visiting Files. - (line 91) -* C-c M-g d: Commands for Buffers Visiting Files. - (line 101) -* C-c M-g e: Blaming. (line 76) -* C-c M-g e <1>: Commands for Buffers Visiting Files. - (line 182) -* C-c M-g f: Blaming. (line 68) -* C-c M-g g: Commands for Buffers Visiting Files. - (line 166) -* C-c M-g G: Commands for Buffers Visiting Files. - (line 172) -* C-c M-g L: Commands for Buffers Visiting Files. - (line 109) -* C-c M-g l: Commands for Buffers Visiting Files. - (line 119) -* C-c M-g M: Commands for Buffers Visiting Files. - (line 132) -* C-c M-g n: Commands for Buffers Visiting Files. - (line 153) -* C-c M-g p: Commands for Buffers Visiting Files. - (line 149) -* C-c M-g q: Blaming. (line 87) -* C-c M-g r: Blaming. (line 60) -* C-c M-g s: Commands for Buffers Visiting Files. - (line 63) -* C-c M-g s <1>: Commands for Buffers Visiting Files. - (line 63) -* C-c M-g t: Commands for Buffers Visiting Files. - (line 129) -* C-c M-g u: Commands for Buffers Visiting Files. - (line 69) -* C-c M-g u <1>: Commands for Buffers Visiting Files. - (line 69) -* C-c M-g v: Commands for Buffers Visiting Files. - (line 156) -* C-c M-g V: Commands for Buffers Visiting Files. - (line 160) -* C-c M-i: Committing. (line 434) -* C-c M-s: Committing. (line 318) -* C-c TAB: Sections. (line 138) -* C-w: Common Commands. (line 22) -* C-x g: Status Buffer. (line 23) -* C-x M-g: Transient Commands. (line 20) -* C-x u: Rebasing. (line 194) -* d: Diffing. (line 22) -* D: Diffing. (line 105) -* d c: Diffing. (line 82) -* d d: Diffing. (line 27) -* D f: Diffing. (line 134) -* D F: Diffing. (line 138) -* D g: Diffing. (line 110) -* d p: Diffing. (line 75) -* d r: Diffing. (line 49) -* D r: Diffing. (line 130) -* d s: Diffing. (line 67) -* D s: Diffing. (line 114) -* d t: Diffing. (line 86) -* D t: Diffing. (line 127) -* d u: Diffing. (line 72) -* d w: Diffing. (line 62) -* D w: Diffing. (line 120) -* DEL: Logging. (line 146) -* DEL <1>: Diffing. (line 231) -* DEL <2>: Blaming. (line 103) -* DEL <3>: Rebasing. (line 141) -* e: Ediffing. (line 10) -* E: Ediffing. (line 21) -* e <1>: Rebasing. (line 162) -* E c: Ediffing. (line 100) -* E i: Ediffing. (line 94) -* E m: Ediffing. (line 33) -* E M: Ediffing. (line 48) -* E r: Ediffing. (line 25) -* E s: Ediffing. (line 87) -* E t: Ediffing. (line 79) -* E u: Ediffing. (line 91) -* E w: Ediffing. (line 97) -* E z: Ediffing. (line 103) -* f: Repository List. (line 111) -* f <1>: Rebasing. (line 168) -* f <2>: Fetching. (line 10) -* F: Pulling. (line 10) -* f a: Fetching. (line 45) -* f C: Branching. (line 81) -* F C: Branching. (line 81) -* 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: Modes and Buffers. (line 265) -* G: Modes and Buffers. (line 273) -* H: Sections. (line 331) -* I: Creating Repository. (line 7) -* j: Logging. (line 127) -* j <1>: Diffing. (line 218) -* k: Running Git. (line 27) -* k <1>: Applying. (line 40) -* k <2>: Rebasing. (line 172) -* k <3>: Stashing. (line 114) -* l: Logging. (line 28) -* L: Logging. (line 75) -* L <1>: Logging. (line 103) -* L <2>: Logging. (line 263) -* l <1>: Rebasing. (line 211) -* l a: Logging. (line 59) -* l b: Logging. (line 56) -* L d: Logging. (line 277) -* L g: Logging. (line 80) -* l h: Logging. (line 38) -* l H: Logging. (line 342) -* l l: Logging. (line 33) -* l L: Logging. (line 53) -* L L: Logging. (line 97) -* L L <1>: Logging. (line 271) -* L l: Logging. (line 274) -* l o: Logging. (line 47) -* l O: Logging. (line 339) -* l r: Logging. (line 336) -* L s: Logging. (line 84) -* l u: Logging. (line 41) -* L w: Logging. (line 90) -* m: Repository List. (line 105) -* m <1>: Merging. (line 10) -* M: Remotes. (line 17) -* m a: Merging. (line 42) -* m a <1>: Merging. (line 91) -* M a: Remotes. (line 51) -* M C: Remotes. (line 35) -* m d: Merging. (line 54) -* m e: Merging. (line 30) -* M k: Remotes. (line 63) -* m m: Merging. (line 18) -* m m <1>: Merging. (line 86) -* m n: Merging. (line 36) -* m p: Merging. (line 75) -* M p: Remotes. (line 66) -* M P: Remotes. (line 70) -* M r: Remotes. (line 55) -* m s: Merging. (line 67) -* M u: Remotes. (line 59) -* M-1: Sections. (line 169) -* M-2: Sections. (line 169) -* M-3: Sections. (line 169) -* M-4: Sections. (line 169) -* M-: Sections. (line 153) -* M-n: Sections. (line 40) -* M-n <1>: Committing. (line 326) -* M-n <2>: Rebasing. (line 156) -* M-p: Sections. (line 35) -* M-p <1>: Committing. (line 321) -* M-p <2>: Rebasing. (line 153) -* M-w: Blaming. (line 134) -* M-w <1>: Common Commands. (line 39) -* MM: Rebasing. (line 219) -* Mt: Rebasing. (line 225) -* n: Sections. (line 32) -* n <1>: Blaming. (line 118) -* N: Blaming. (line 121) -* n <2>: Rebasing. (line 150) -* n <3>: Minor Mode for Buffers Visiting Blobs. - (line 16) -* o: Submodules. (line 55) -* O: Subtree. (line 9) -* o a: Submodules. (line 68) -* o d: Submodules. (line 93) -* O e: Subtree. (line 37) -* O e p: Subtree. (line 48) -* O e s: Subtree. (line 52) -* o f: Submodules. (line 99) -* 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: Submodules. (line 96) -* o p: Submodules. (line 80) -* o r: Submodules. (line 74) -* o s: Submodules. (line 88) -* o u: Submodules. (line 84) -* p: Sections. (line 27) -* p <1>: Blaming. (line 124) -* P: Blaming. (line 127) -* p <2>: Rebasing. (line 147) -* P <1>: Pushing. (line 10) -* p <3>: Minor Mode for Buffers Visiting Blobs. - (line 13) -* P C: Branching. (line 81) -* 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: Modes and Buffers. (line 206) -* q <1>: Logging. (line 110) -* q <2>: Blaming. (line 130) -* q <3>: Minor Mode for Buffers Visiting Blobs. - (line 19) -* r: Rebasing. (line 10) -* r <1>: Rebasing. (line 159) -* r a: Rebasing. (line 116) -* r e: Rebasing. (line 42) -* r e <1>: Rebasing. (line 112) -* r f: Rebasing. (line 79) -* r i: Rebasing. (line 76) -* r k: Rebasing. (line 96) -* r m: Rebasing. (line 88) -* r p: Rebasing. (line 28) -* r r: Rebasing. (line 102) -* r s: Rebasing. (line 47) -* r s <1>: Rebasing. (line 108) -* r u: Rebasing. (line 35) -* r w: Rebasing. (line 92) -* RET: Repository List. (line 102) -* RET <1>: References Buffer. (line 159) -* RET <2>: Visiting Files and Blobs. - (line 40) -* RET <3>: Blaming. (line 91) -* RET <4>: Rebasing. (line 131) -* s: Staging and Unstaging. - (line 29) -* S: Staging and Unstaging. - (line 36) -* s <1>: Rebasing. (line 165) -* S-: Sections. (line 157) -* SPC: Logging. (line 137) -* SPC <1>: Diffing. (line 228) -* SPC <2>: Blaming. (line 94) -* SPC <3>: Rebasing. (line 135) -* t: Rebasing. (line 214) -* 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: Sections. (line 134) -* u: Repository List. (line 108) -* u <1>: Staging and Unstaging. - (line 42) -* U: Staging and Unstaging. - (line 50) -* v: Applying. (line 47) -* V: Cherry Picking. (line 98) -* V a: Cherry Picking. (line 126) -* V s: Cherry Picking. (line 123) -* V V: Cherry Picking. (line 106) -* V v: Cherry Picking. (line 111) -* V V <1>: Cherry Picking. (line 120) -* 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: Rebasing. (line 179) -* 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: Logging. (line 382) -* y: References Buffer. (line 7) -* y <1>: Rebasing. (line 191) -* 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 101) -* z B: Stashing. (line 106) -* Z b: Worktree. (line 13) -* Z c: Worktree. (line 16) -* z f: Stashing. (line 111) -* Z g: Worktree. (line 26) -* z i: Stashing. (line 20) -* z I: Stashing. (line 42) -* z k: Stashing. (line 94) -* Z k: Worktree. (line 22) -* z l: Stashing. (line 117) -* Z m: Worktree. (line 19) -* z p: Stashing. (line 72) -* z v: Stashing. (line 98) -* 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: Committing. (line 481) -* forward-line: Rebasing. (line 150) -* git-commit-ack: Committing. (line 415) -* git-commit-cc: Committing. (line 427) -* git-commit-check-style-conventions: Committing. (line 533) -* git-commit-insert-pseudo-header: Committing. (line 412) -* git-commit-next-message: Committing. (line 326) -* git-commit-prev-message: Committing. (line 321) -* git-commit-propertize-diff: Committing. (line 473) -* git-commit-reported: Committing. (line 430) -* git-commit-review: Committing. (line 418) -* git-commit-save-message: Committing. (line 318) -* git-commit-save-message <1>: Committing. (line 459) -* git-commit-setup-changelog-support: Committing. (line 462) -* git-commit-signoff: Committing. (line 421) -* git-commit-suggested: Committing. (line 434) -* git-commit-test: Committing. (line 424) -* git-commit-turn-on-auto-fill: Committing. (line 466) -* git-commit-turn-on-flyspell: Committing. (line 469) -* git-rebase-backward-line: Rebasing. (line 147) -* git-rebase-break: Rebasing. (line 187) -* git-rebase-edit: Rebasing. (line 162) -* git-rebase-exec: Rebasing. (line 179) -* git-rebase-fixup: Rebasing. (line 168) -* git-rebase-insert: Rebasing. (line 191) -* git-rebase-kill-line: Rebasing. (line 172) -* git-rebase-label: Rebasing. (line 211) -* git-rebase-merge: Rebasing. (line 219) -* git-rebase-merge-toggle-editmsg: Rebasing. (line 225) -* git-rebase-move-line-down: Rebasing. (line 156) -* git-rebase-move-line-up: Rebasing. (line 153) -* git-rebase-pick: Rebasing. (line 176) -* git-rebase-reset: Rebasing. (line 214) -* git-rebase-reword: Rebasing. (line 159) -* git-rebase-show-commit: Rebasing. (line 131) -* git-rebase-show-or-scroll-down: Rebasing. (line 141) -* git-rebase-show-or-scroll-up: Rebasing. (line 135) -* git-rebase-squash: Rebasing. (line 165) -* git-rebase-undo: Rebasing. (line 194) -* ido-enter-magit-status: Status Buffer. (line 96) -* magit-add-section-hook: Sections. (line 291) -* magit-after-save-refresh-status: Modes and Buffers. (line 294) -* 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 28) -* magit-blame <1>: Blaming. (line 34) -* magit-blame <2>: Blaming. (line 115) -* magit-blame <3>: Commands for Buffers Visiting Files. - (line 52) -* magit-blame <4>: Commands for Buffers Visiting Files. - (line 137) -* magit-blame-addition: Blaming. (line 28) -* magit-blame-addition <1>: Blaming. (line 45) -* magit-blame-additions: Commands for Buffers Visiting Files. - (line 52) -* magit-blame-copy-hash: Blaming. (line 134) -* magit-blame-cycle-style: Blaming. (line 141) -* magit-blame-echo: Blaming. (line 28) -* magit-blame-echo <1>: Blaming. (line 76) -* magit-blame-echo <2>: Commands for Buffers Visiting Files. - (line 52) -* magit-blame-next-chunk: Blaming. (line 118) -* magit-blame-next-chunk-same-commit: Blaming. (line 121) -* magit-blame-previous-chunk: Blaming. (line 124) -* magit-blame-previous-chunk-same-commit: Blaming. (line 127) -* magit-blame-quit: Blaming. (line 28) -* magit-blame-quit <1>: Blaming. (line 87) -* magit-blame-quit <2>: Blaming. (line 130) -* magit-blame-quit <3>: Commands for Buffers Visiting Files. - (line 52) -* magit-blame-removal: Blaming. (line 28) -* magit-blame-removal <1>: Blaming. (line 60) -* magit-blame-removal <2>: Commands for Buffers Visiting Files. - (line 52) -* magit-blame-reverse: Blaming. (line 28) -* magit-blame-reverse <1>: Blaming. (line 68) -* magit-blame-reverse <2>: Commands for Buffers Visiting Files. - (line 52) -* magit-blob-next: Commands for Buffers Visiting Files. - (line 52) -* magit-blob-next <1>: Commands for Buffers Visiting Files. - (line 153) -* magit-blob-next <2>: Minor Mode for Buffers Visiting Blobs. - (line 16) -* magit-blob-previous: Commands for Buffers Visiting Files. - (line 52) -* magit-blob-previous <1>: Commands for Buffers Visiting Files. - (line 149) -* magit-blob-previous <2>: Minor Mode for Buffers Visiting Blobs. - (line 13) -* magit-blob-visit-file: Commands for Buffers Visiting Files. - (line 52) -* magit-blob-visit-file <1>: Commands for Buffers Visiting Files. - (line 160) -* magit-branch: Branching. (line 63) -* magit-branch-and-checkout: Branching. (line 113) -* magit-branch-checkout: Branching. (line 119) -* magit-branch-configure: Branching. (line 81) -* magit-branch-create: Branching. (line 104) -* magit-branch-delete: Branching. (line 188) -* magit-branch-or-checkout: Branching. (line 307) -* magit-branch-orphan: Branching. (line 303) -* magit-branch-rename: Branching. (line 199) -* magit-branch-reset: Branching. (line 173) -* magit-branch-shelve: Branching. (line 447) -* magit-branch-spinoff: Branching. (line 141) -* magit-branch-spinout: Branching. (line 168) -* magit-branch-unshelve: Branching. (line 457) -* magit-builtin-completing-read: Completion Confirmation and the Selection. - (line 358) -* magit-bundle: Bundle. (line 8) -* magit-call-git: Calling Git. (line 135) -* magit-call-process: Calling Git. (line 138) -* magit-cancel-section: Section Plumbing. (line 72) -* magit-checkout: Branching. (line 97) -* magit-cherry: Logging. (line 382) -* 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 44) -* magit-clone-mirror: Cloning Repository. (line 48) -* magit-clone-regular: Cloning Repository. (line 28) -* magit-clone-shallow: Cloning Repository. (line 32) -* magit-clone-shallow-exclude: Cloning Repository. (line 61) -* magit-clone-shallow-since: Cloning Repository. (line 55) -* magit-clone-sparse: Cloning Repository. (line 38) -* magit-commit: Committing. (line 21) -* magit-commit <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-commit <2>: Commands for Buffers Visiting Files. - (line 176) -* magit-commit-alter: Committing. (line 141) -* magit-commit-amend: Committing. (line 59) -* magit-commit-augment: Committing. (line 153) -* magit-commit-create: Committing. (line 29) -* magit-commit-extend: Committing. (line 45) -* magit-commit-fixup: Committing. (line 119) -* magit-commit-instant-fixup: Committing. (line 192) -* magit-commit-instant-squash: Committing. (line 204) -* magit-commit-revise: Committing. (line 167) -* magit-commit-reword: Committing. (line 65) -* magit-commit-squash: Committing. (line 130) -* magit-completing-read: Completion Confirmation and the Selection. - (line 374) -* magit-copy-buffer-revision: Common Commands. (line 39) -* magit-copy-section-value: Common Commands. (line 22) -* magit-current-section: Section Plumbing. (line 84) -* magit-cycle-margin-style: Logging. (line 274) -* magit-debug-git-executable: Running Git. (line 188) -* magit-debug-git-executable <1>: Debugging Tools. (line 69) -* magit-define-section-jumper: Section Plumbing. (line 77) -* magit-describe-section: Sections. (line 331) -* magit-describe-section-briefly: Sections. (line 334) -* magit-describe-section-briefly <1>: Section Plumbing. (line 123) -* magit-diff: Diffing. (line 22) -* magit-diff <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-diff <2>: Commands for Buffers Visiting Files. - (line 91) -* magit-diff-buffer-file: Commands for Buffers Visiting Files. - (line 52) -* magit-diff-buffer-file <1>: Commands for Buffers Visiting Files. - (line 101) -* magit-diff-default-context: Diffing. (line 157) -* magit-diff-dwim: Diffing. (line 27) -* magit-diff-edit-hunk-commit: Diffing. (line 199) -* magit-diff-flip-revs: Diffing. (line 134) -* magit-diff-less-context: Diffing. (line 151) -* magit-diff-more-context: Diffing. (line 154) -* magit-diff-paths: Diffing. (line 75) -* magit-diff-range: Diffing. (line 49) -* magit-diff-refresh: Diffing. (line 105) -* magit-diff-refresh <1>: Diffing. (line 110) -* magit-diff-save-default-arguments: Diffing. (line 120) -* magit-diff-scope: Section Plumbing. (line 226) -* magit-diff-set-default-arguments: Diffing. (line 114) -* magit-diff-show-or-scroll-down: Logging. (line 146) -* magit-diff-show-or-scroll-down <1>: Blaming. (line 103) -* magit-diff-show-or-scroll-up: Logging. (line 137) -* magit-diff-show-or-scroll-up <1>: Blaming. (line 94) -* magit-diff-staged: Diffing. (line 67) -* magit-diff-switch-range-type: Diffing. (line 130) -* magit-diff-toggle-file-filter: Diffing. (line 138) -* magit-diff-toggle-refine-hunk: Diffing. (line 127) -* magit-diff-trace-definition: Diffing. (line 190) -* magit-diff-type: Section Plumbing. (line 204) -* magit-diff-unstaged: Diffing. (line 72) -* magit-diff-visit-file: Visiting Files and Blobs. - (line 40) -* magit-diff-visit-file-other-frame: Visiting Files and Blobs. - (line 99) -* magit-diff-visit-file-other-window: Visiting Files and Blobs. - (line 98) -* magit-diff-visit-file-worktree: Visiting Files and Blobs. - (line 78) -* magit-diff-visit-worktree-file-other-frame: Visiting Files and Blobs. - (line 101) -* magit-diff-visit-worktree-file-other-window: Visiting Files and Blobs. - (line 100) -* magit-diff-while-committing: Diffing. (line 164) -* magit-diff-while-committing <1>: Committing. (line 339) -* magit-diff-working-tree: Diffing. (line 62) -* magit-disable-section-inserter: Per-Repository Configuration. - (line 31) -* magit-discard: Applying. (line 40) -* magit-dispatch: Transient Commands. (line 20) -* magit-display-buffer: Modes and Buffers. (line 38) -* magit-display-buffer-fullcolumn-most-v1: Modes and Buffers. (line 100) -* magit-display-buffer-fullframe-status-topleft-v1: Modes and Buffers. - (line 91) -* magit-display-buffer-fullframe-status-v1: Modes and Buffers. - (line 86) -* magit-display-buffer-same-window-except-diff-v1: Modes and Buffers. - (line 81) -* magit-display-buffer-traditional: Modes and Buffers. (line 74) -* magit-display-repository-buffer: Common Commands. (line 9) -* magit-display-repository-buffer <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-display-repository-buffer <2>: Commands for Buffers Visiting Files. - (line 172) -* magit-ediff: Ediffing. (line 21) -* magit-ediff-compare: Ediffing. (line 25) -* magit-ediff-dwim: Ediffing. (line 10) -* magit-ediff-resolve-all: Ediffing. (line 48) -* magit-ediff-resolve-rest: Ediffing. (line 33) -* magit-ediff-show-commit: Ediffing. (line 100) -* magit-ediff-show-staged: Ediffing. (line 94) -* magit-ediff-show-stash: Ediffing. (line 103) -* magit-ediff-show-unstaged: Ediffing. (line 91) -* magit-ediff-show-working-tree: Ediffing. (line 97) -* magit-ediff-stage: Ediffing. (line 87) -* magit-edit-line-commit: Commands for Buffers Visiting Files. - (line 52) -* magit-edit-line-commit <1>: Commands for Buffers Visiting Files. - (line 182) -* 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: Fetching. (line 48) -* magit-fetch-modules <1>: Submodules. (line 99) -* 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 52) -* magit-file-checkout <2>: Commands for Buffers Visiting Files. - (line 86) -* magit-file-delete: Commands for Buffers Visiting Files. - (line 52) -* magit-file-delete <1>: Commands for Buffers Visiting Files. - (line 82) -* magit-file-dispatch: Commands for Buffers Visiting Files. - (line 52) -* magit-file-dispatch <1>: Commands for Buffers Visiting Files. - (line 58) -* magit-file-rename: Commands for Buffers Visiting Files. - (line 52) -* magit-file-rename <1>: Commands for Buffers Visiting Files. - (line 78) -* magit-file-untrack: Commands for Buffers Visiting Files. - (line 52) -* magit-file-untrack <1>: Commands for Buffers Visiting Files. - (line 74) -* magit-find-file: Visiting Files and Blobs. - (line 19) -* magit-find-file <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-find-file <2>: Commands for Buffers Visiting Files. - (line 156) -* magit-find-file-other-frame: Visiting Files and Blobs. - (line 29) -* magit-find-file-other-window: Visiting Files and Blobs. - (line 24) -* magit-generate-buffer-name-default-function: Modes and Buffers. - (line 141) -* magit-get-section: Section Plumbing. (line 130) -* magit-git: Calling Git. (line 153) -* magit-git-command: Running Git. (line 94) -* magit-git-command-topdir: Running Git. (line 86) -* magit-git-exit-code: Calling Git. (line 37) -* magit-git-failure: Calling Git. (line 44) -* magit-git-false: Calling Git. (line 52) -* magit-git-insert: Calling Git. (line 56) -* magit-git-items: Calling Git. (line 68) -* magit-git-lines: Calling Git. (line 64) -* magit-git-mergetool: Running Git. (line 131) -* magit-git-mergetool <1>: Ediffing. (line 79) -* magit-git-str: Calling Git. (line 102) -* magit-git-string: Calling Git. (line 59) -* magit-git-success: Calling Git. (line 40) -* magit-git-true: Calling Git. (line 48) -* magit-git-wash: Calling Git. (line 157) -* magit-go-backward: Logging. (line 116) -* magit-go-backward <1>: Diffing. (line 173) -* magit-go-forward: Logging. (line 119) -* magit-go-forward <1>: Diffing. (line 176) -* magit-hunk-set-window-start: Sections. (line 61) -* magit-ido-completing-read: Completion Confirmation and the Selection. - (line 363) -* magit-init: Creating Repository. (line 7) -* magit-insert-am-sequence: Status Buffer. (line 142) -* magit-insert-assumed-unchanged-files: Status Buffer. (line 249) -* magit-insert-bisect-log: Status Buffer. (line 156) -* magit-insert-bisect-output: Status Buffer. (line 150) -* magit-insert-bisect-rest: Status Buffer. (line 153) -* magit-insert-diff-filter-header: Status Buffer. (line 315) -* magit-insert-error-header: Status Buffer. (line 306) -* magit-insert-head-branch-header: Status Buffer. (line 318) -* magit-insert-heading: Section Plumbing. (line 44) -* magit-insert-ignored-files: Status Buffer. (line 243) -* magit-insert-local-branches: References Buffer. (line 244) -* magit-insert-merge-log: Status Buffer. (line 134) -* magit-insert-modules: Status Buffer. (line 357) -* magit-insert-modules-overview: Status Buffer. (line 375) -* magit-insert-modules-unpulled-from-pushremote: Status Buffer. - (line 390) -* magit-insert-modules-unpulled-from-upstream: Status Buffer. (line 385) -* magit-insert-modules-unpushed-to-pushremote: Status Buffer. (line 400) -* magit-insert-modules-unpushed-to-upstream: Status Buffer. (line 395) -* magit-insert-push-branch-header: Status Buffer. (line 325) -* magit-insert-rebase-sequence: Status Buffer. (line 138) -* magit-insert-recent-commits: Status Buffer. (line 261) -* magit-insert-remote-branches: References Buffer. (line 247) -* magit-insert-remote-header: Status Buffer. (line 338) -* magit-insert-repo-header: Status Buffer. (line 335) -* magit-insert-section: Section Plumbing. (line 9) -* magit-insert-sequencer-sequence: Status Buffer. (line 146) -* magit-insert-skip-worktree-files: Status Buffer. (line 246) -* magit-insert-staged-changes: Status Buffer. (line 162) -* magit-insert-stashes: Status Buffer. (line 165) -* magit-insert-status-headers: Status Buffer. (line 292) -* magit-insert-tags: References Buffer. (line 250) -* magit-insert-tags-header: Status Buffer. (line 329) -* magit-insert-tracked-files: Status Buffer. (line 240) -* magit-insert-unpulled-cherries: Status Buffer. (line 270) -* magit-insert-unpulled-from-pushremote: Status Buffer. (line 175) -* magit-insert-unpulled-from-upstream: Status Buffer. (line 171) -* magit-insert-unpulled-or-recent-commits: Status Buffer. (line 255) -* magit-insert-unpushed-cherries: Status Buffer. (line 276) -* magit-insert-unpushed-to-pushremote: Status Buffer. (line 183) -* magit-insert-unpushed-to-upstream: Status Buffer. (line 179) -* magit-insert-unstaged-changes: Status Buffer. (line 159) -* magit-insert-untracked-files: Status Buffer. (line 193) -* magit-insert-upstream-branch-header: Status Buffer. (line 321) -* magit-insert-user-header: Status Buffer. (line 345) -* magit-jump-to-diffstat-or-diff: Diffing. (line 218) -* magit-kill-this-buffer: Minor Mode for Buffers Visiting Blobs. - (line 19) -* magit-list-repositories: Repository List. (line 6) -* magit-list-submodules: Submodules. (line 18) -* magit-list-submodules <1>: Submodules. (line 96) -* magit-log: Logging. (line 28) -* magit-log <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-log <2>: Commands for Buffers Visiting Files. - (line 109) -* magit-log-all: Logging. (line 59) -* magit-log-all-branches: Logging. (line 56) -* magit-log-branches: Logging. (line 53) -* magit-log-buffer-file: Commands for Buffers Visiting Files. - (line 52) -* magit-log-buffer-file <1>: Commands for Buffers Visiting Files. - (line 119) -* magit-log-bury-buffer: Logging. (line 110) -* magit-log-current: Logging. (line 33) -* magit-log-double-commit-limit: Logging. (line 160) -* magit-log-half-commit-limit: Logging. (line 163) -* magit-log-head: Logging. (line 38) -* magit-log-maybe-show-more-commits: Sections. (line 74) -* magit-log-maybe-update-blob-buffer: Sections. (line 88) -* magit-log-maybe-update-revision-buffer: Sections. (line 81) -* magit-log-merged: Commands for Buffers Visiting Files. - (line 52) -* magit-log-merged <1>: Commands for Buffers Visiting Files. - (line 132) -* magit-log-move-to-parent: Logging. (line 122) -* magit-log-move-to-revision: Logging. (line 127) -* magit-log-other: Logging. (line 47) -* magit-log-refresh: Logging. (line 75) -* magit-log-refresh <1>: Logging. (line 80) -* magit-log-refresh <2>: Logging. (line 103) -* magit-log-related: Logging. (line 41) -* magit-log-save-default-arguments: Logging. (line 90) -* magit-log-select-pick: Logging. (line 297) -* magit-log-select-quit: Logging. (line 302) -* magit-log-set-default-arguments: Logging. (line 84) -* magit-log-toggle-commit-limit: Logging. (line 155) -* magit-log-trace-definition: Commands for Buffers Visiting Files. - (line 52) -* magit-log-trace-definition <1>: Commands for Buffers Visiting Files. - (line 129) -* magit-margin-settings: Logging. (line 263) -* magit-maybe-set-dedicated: Modes and Buffers. (line 121) -* magit-merge: Merging. (line 10) -* magit-merge <1>: Merging. (line 86) -* magit-merge-abort: Merging. (line 91) -* magit-merge-absorb: Merging. (line 42) -* magit-merge-dissolve: Merging. (line 54) -* magit-merge-editmsg: Merging. (line 30) -* 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: Modes and Buffers. (line 206) -* magit-mode-display-buffer: Refreshing Buffers. (line 32) -* magit-mode-quit-window: Modes and Buffers. (line 233) -* 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: Committing. (line 347) -* magit-process: Running Git. (line 20) -* magit-process-file: Calling Git. (line 84) -* magit-process-git: Calling Git. (line 77) -* magit-process-kill: Running Git. (line 27) -* magit-profile-refresh-buffer: Debugging Tools. (line 76) -* 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 116) -* magit-rebase-autosquash: Rebasing. (line 79) -* magit-rebase-branch: Rebasing. (line 42) -* magit-rebase-continue: Rebasing. (line 102) -* magit-rebase-edit: Rebasing. (line 112) -* magit-rebase-edit-commit: Rebasing. (line 88) -* 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 96) -* magit-rebase-reword-commit: Rebasing. (line 92) -* magit-rebase-skip: Rebasing. (line 108) -* magit-rebase-subset: Rebasing. (line 47) -* magit-reflog-current: Logging. (line 336) -* magit-reflog-head: Logging. (line 342) -* magit-reflog-other: Logging. (line 339) -* magit-refresh: Modes and Buffers. (line 265) -* magit-refresh-all: Modes and Buffers. (line 273) -* magit-refs-set-show-commit-count: References Buffer. (line 34) -* magit-region-sections: Section Plumbing. (line 87) -* magit-region-values: Section Plumbing. (line 113) -* magit-remote: Remotes. (line 17) -* magit-remote-add: Remotes. (line 51) -* magit-remote-configure: Remotes. (line 35) -* magit-remote-prune: Remotes. (line 66) -* magit-remote-prune-refspecs: Remotes. (line 70) -* magit-remote-remove: Remotes. (line 63) -* magit-remote-rename: Remotes. (line 55) -* magit-remote-set-url: Remotes. (line 59) -* magit-repolist-column-branch: Repository List. (line 51) -* magit-repolist-column-branches: Repository List. (line 58) -* magit-repolist-column-flag: Repository List. (line 64) -* magit-repolist-column-flags: Repository List. (line 76) -* magit-repolist-column-ident: Repository List. (line 40) -* magit-repolist-column-path: Repository List. (line 44) -* magit-repolist-column-stashes: Repository List. (line 61) -* magit-repolist-column-unpulled-from-pushremote: Repository List. - (line 87) -* magit-repolist-column-unpulled-from-upstream: Repository List. - (line 83) -* magit-repolist-column-unpushed-to-pushremote: Repository List. - (line 95) -* magit-repolist-column-unpushed-to-upstream: Repository List. - (line 91) -* magit-repolist-column-upstream: Repository List. (line 54) -* magit-repolist-column-version: Repository List. (line 47) -* magit-repolist-fetch: Repository List. (line 111) -* magit-repolist-find-file-other-frame: Repository List. (line 115) -* magit-repolist-mark: Repository List. (line 105) -* magit-repolist-status: Repository List. (line 102) -* magit-repolist-unmark: Repository List. (line 108) -* 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: Modes and Buffers. (line 223) -* magit-reverse: Applying. (line 47) -* magit-reverse-in-index: Staging and Unstaging. - (line 58) -* magit-revert: Cherry Picking. (line 98) -* magit-revert-and-commit: Cherry Picking. (line 106) -* magit-revert-no-commit: Cherry Picking. (line 111) -* magit-run: Running Git. (line 82) -* magit-run-git: Calling Git. (line 141) -* magit-run-git-async: Calling Git. (line 166) -* magit-run-git-gui: Running Git. (line 128) -* magit-run-git-with-editor: Calling Git. (line 178) -* magit-run-git-with-input: Calling Git. (line 144) -* magit-run-gitk: Running Git. (line 119) -* magit-run-gitk-all: Running Git. (line 122) -* magit-run-gitk-branches: Running Git. (line 125) -* magit-save-window-configuration: Modes and Buffers. (line 112) -* magit-section-backward: Sections. (line 27) -* magit-section-backward-siblings: Sections. (line 35) -* magit-section-case: Section Plumbing. (line 182) -* magit-section-cycle: Sections. (line 138) -* magit-section-cycle-diffs: Sections. (line 153) -* magit-section-cycle-global: Sections. (line 157) -* magit-section-forward: Sections. (line 32) -* magit-section-forward-siblings: Sections. (line 40) -* magit-section-hide: Sections. (line 179) -* magit-section-hide-children: Sections. (line 191) -* magit-section-ident: Section Plumbing. (line 126) -* magit-section-match: Section Plumbing. (line 134) -* magit-section-set-window-start: Sections. (line 68) -* magit-section-show: Sections. (line 176) -* magit-section-show-children: Sections. (line 186) -* magit-section-show-headings: Sections. (line 182) -* magit-section-show-level-1: Sections. (line 163) -* magit-section-show-level-1-all: Sections. (line 169) -* magit-section-show-level-2: Sections. (line 163) -* magit-section-show-level-2-all: Sections. (line 169) -* magit-section-show-level-3: Sections. (line 163) -* magit-section-show-level-3-all: Sections. (line 169) -* magit-section-show-level-4: Sections. (line 163) -* magit-section-show-level-4-all: Sections. (line 169) -* magit-section-toggle: Sections. (line 134) -* magit-section-toggle-children: Sections. (line 194) -* magit-section-up: Sections. (line 44) -* magit-section-value-if: Section Plumbing. (line 173) -* magit-sequence-abort: Cherry Picking. (line 91) -* magit-sequence-abort <1>: Cherry Picking. (line 126) -* magit-sequence-continue: Cherry Picking. (line 85) -* magit-sequence-continue <1>: Cherry Picking. (line 120) -* magit-sequence-skip: Cherry Picking. (line 88) -* magit-sequence-skip <1>: Cherry Picking. (line 123) -* magit-shell-command: Running Git. (line 107) -* magit-shell-command-topdir: Running Git. (line 103) -* magit-show-commit: Diffing. (line 82) -* magit-show-commit <1>: Blaming. (line 91) -* 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-sparse-checkout: Sparse checkouts. (line 17) -* magit-sparse-checkout-add: Sparse checkouts. (line 39) -* magit-sparse-checkout-disable: Sparse checkouts. (line 50) -* magit-sparse-checkout-enable: Sparse checkouts. (line 21) -* magit-sparse-checkout-reapply: Sparse checkouts. (line 44) -* magit-sparse-checkout-set: Sparse checkouts. (line 33) -* magit-stage: Staging and Unstaging. - (line 29) -* magit-stage-buffer-file: Commands for Buffers Visiting Files. - (line 52) -* magit-stage-buffer-file <1>: Commands for Buffers Visiting Files. - (line 63) -* magit-stage-file: Staging and Unstaging. - (line 90) -* magit-stage-file <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-stage-file <2>: Commands for Buffers Visiting Files. - (line 63) -* magit-stage-modified: Staging and Unstaging. - (line 36) -* magit-start-git: Calling Git. (line 189) -* magit-start-process: Calling Git. (line 207) -* magit-stash: Stashing. (line 9) -* magit-stash-apply: Stashing. (line 52) -* magit-stash-both: Stashing. (line 14) -* magit-stash-branch: Stashing. (line 101) -* magit-stash-branch-here: Stashing. (line 106) -* magit-stash-clear: Stashing. (line 114) -* magit-stash-drop: Stashing. (line 94) -* magit-stash-format-patch: Stashing. (line 111) -* magit-stash-index: Stashing. (line 20) -* magit-stash-keep-index: Stashing. (line 30) -* magit-stash-list: Stashing. (line 117) -* magit-stash-pop: Stashing. (line 72) -* magit-stash-show: Diffing. (line 86) -* magit-stash-show <1>: Stashing. (line 98) -* magit-stash-worktree: Stashing. (line 24) -* magit-stashes-maybe-update-stash-buffer: Sections. (line 108) -* magit-status: Status Buffer. (line 23) -* magit-status-here: Commands for Buffers Visiting Files. - (line 52) -* magit-status-here <1>: Commands for Buffers Visiting Files. - (line 166) -* magit-status-maybe-update-blob-buffer: Sections. (line 103) -* magit-status-maybe-update-revision-buffer: Sections. (line 93) -* magit-status-maybe-update-stash-buffer: Sections. (line 98) -* magit-status-quick: Status Buffer. (line 70) -* magit-submodule: Submodules. (line 55) -* magit-submodule-add: Submodules. (line 68) -* magit-submodule-populate: Submodules. (line 80) -* magit-submodule-register: Submodules. (line 74) -* magit-submodule-synchronize: Submodules. (line 88) -* magit-submodule-unpopulate: Submodules. (line 93) -* magit-submodule-update: Submodules. (line 84) -* 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-git-debug: Running Git. (line 30) -* magit-toggle-git-debug <1>: Debugging Tools. (line 29) -* magit-toggle-margin: Logging. (line 97) -* magit-toggle-margin <1>: Logging. (line 271) -* magit-toggle-margin-details: Logging. (line 277) -* magit-toggle-profiling: Debugging Tools. (line 80) -* magit-toggle-subprocess-record: Debugging Tools. (line 56) -* magit-toggle-verbose-refresh: Debugging Tools. (line 51) -* magit-unstage: Staging and Unstaging. - (line 42) -* magit-unstage-all: Staging and Unstaging. - (line 50) -* magit-unstage-buffer-file: Commands for Buffers Visiting Files. - (line 52) -* magit-unstage-buffer-file <1>: Commands for Buffers Visiting Files. - (line 69) -* magit-unstage-file: Staging and Unstaging. - (line 97) -* magit-unstage-file <1>: Commands for Buffers Visiting Files. - (line 52) -* magit-unstage-file <2>: Commands for Buffers Visiting Files. - (line 69) -* magit-version: Running Git. (line 192) -* 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: Diffing. (line 231) -* scroll-up: Diffing. (line 228) -* with-editor-cancel: Committing. (line 307) -* with-editor-cancel <1>: Rebasing. (line 127) -* with-editor-debug: Debugging Tools. (line 85) -* with-editor-finish: Committing. (line 303) -* with-editor-finish <1>: Rebasing. (line 123) -* with-editor-usage-message: Committing. (line 484) - - -File: magit.info, Node: Variable Index, Prev: Function and Command Index, Up: Top - -Appendix E Variable Index -************************* - -[index] -* Menu: - -* auto-revert-buffer-list-filter: Modes and Buffers. (line 395) -* auto-revert-interval: Modes and Buffers. (line 391) -* auto-revert-mode: Modes and Buffers. (line 379) -* auto-revert-stop-on-user-input: Modes and Buffers. (line 387) -* auto-revert-use-notify: Modes and Buffers. (line 368) -* auto-revert-verbose: Modes and Buffers. (line 416) -* branch.autoSetupMerge: Branching. (line 394) -* branch.autoSetupRebase: Branching. (line 408) -* branch.NAME.description: Branching. (line 365) -* branch.NAME.merge: Branching. (line 333) -* branch.NAME.pushRemote: Branching. (line 352) -* branch.NAME.rebase: Branching. (line 343) -* branch.NAME.remote: Branching. (line 338) -* core.notesRef: Notes. (line 53) -* git-commit-finish-query-functions: Committing. (line 518) -* git-commit-known-pseudo-headers: Committing. (line 408) -* git-commit-major-mode: Committing. (line 445) -* git-commit-post-finish-hook: Committing. (line 487) -* git-commit-setup-hook: Committing. (line 454) -* git-commit-style-convention-checks: Committing. (line 538) -* git-commit-summary-max-length: Committing. (line 513) -* git-rebase-auto-advance: Rebasing. (line 197) -* git-rebase-confirm-cancel: Rebasing. (line 203) -* git-rebase-show-instructions: Rebasing. (line 200) -* global-auto-revert-mode: Modes and Buffers. (line 343) -* magit-auto-revert-immediately: Modes and Buffers. (line 352) -* magit-auto-revert-mode: Modes and Buffers. (line 339) -* magit-auto-revert-tracked-only: Modes and Buffers. (line 373) -* magit-bisect-show-graph: Bisecting. (line 57) -* magit-blame-disable-modes: Blaming. (line 165) -* magit-blame-echo-style: Blaming. (line 151) -* magit-blame-goto-chunk-hook: Blaming. (line 170) -* magit-blame-read-only: Blaming. (line 161) -* magit-blame-styles: Blaming. (line 147) -* magit-blame-time-format: Blaming. (line 157) -* magit-branch-adjust-remote-upstream-alist: Branching. (line 252) -* magit-branch-direct-configure: Branching. (line 69) -* magit-branch-prefer-remote-upstream: Branching. (line 208) -* magit-branch-read-upstream-first: Branching. (line 203) -* magit-buffer-name-format: Modes and Buffers. (line 150) -* magit-bury-buffer-function: Modes and Buffers. (line 215) -* magit-cherry-margin: Logging. (line 385) -* magit-clone-always-transient: Cloning Repository. (line 12) -* magit-clone-default-directory: Cloning Repository. (line 84) -* magit-clone-name-alist: Cloning Repository. (line 94) -* magit-clone-set-remote-head: Cloning Repository. (line 66) -* magit-clone-set-remote.pushDefault: Cloning Repository. (line 75) -* magit-clone-url-format: Cloning Repository. (line 114) -* magit-commit-ask-to-stage: Committing. (line 225) -* magit-commit-diff-inhibit-same-window: Committing. (line 240) -* magit-commit-extend-override-date: Committing. (line 280) -* magit-commit-reword-override-date: Committing. (line 284) -* magit-commit-show-diff: Committing. (line 221) -* magit-commit-squash-confirm: Committing. (line 269) -* magit-completing-read-function: Completion Confirmation and the Selection. - (line 344) -* magit-define-global-key-bindings: Essential Settings. (line 239) -* magit-diff-adjust-tab-width: Diffing. (line 247) -* magit-diff-buffer-file-locked: Commands for Buffers Visiting Files. - (line 104) -* magit-diff-extra-stat-arguments: Diffing. (line 342) -* magit-diff-hide-trailing-cr-characters: Diffing. (line 307) -* magit-diff-highlight-hunk-region-functions: Diffing. (line 310) -* magit-diff-highlight-indentation: Diffing. (line 293) -* magit-diff-highlight-trailing: Diffing. (line 289) -* magit-diff-paint-whitespace: Diffing. (line 268) -* magit-diff-paint-whitespace-lines: Diffing. (line 282) -* magit-diff-refine-hunk: Diffing. (line 236) -* magit-diff-refine-ignore-whitespace: Diffing. (line 243) -* magit-diff-unmarked-lines-keep-foreground: Diffing. (line 335) -* magit-diff-visit-previous-blob: Visiting Files and Blobs. - (line 66) -* magit-direct-use-buffer-arguments: Transient Arguments and Buffer Variables. - (line 73) -* magit-display-buffer-function: Modes and Buffers. (line 57) -* magit-display-buffer-noselect: Modes and Buffers. (line 49) -* magit-dwim-selection: Completion Confirmation and the Selection. - (line 222) -* magit-ediff-dwim-resolve-function: Ediffing. (line 105) -* magit-ediff-dwim-show-on-hunks: Ediffing. (line 111) -* magit-ediff-quit-hook: Ediffing. (line 124) -* magit-ediff-show-stash-with-index: Ediffing. (line 118) -* magit-format-file-function: Diffing. (line 352) -* magit-generate-buffer-name-function: Modes and Buffers. (line 131) -* magit-git-debug: Calling Git. (line 95) -* magit-git-executable: Running Git. (line 159) -* magit-git-global-arguments: Running Git. (line 199) -* magit-keep-region-overlay: Completion Confirmation and the Selection. - (line 294) -* magit-list-refs-sortby: Completion Confirmation and the Selection. - (line 415) -* magit-log-auto-more: Logging. (line 165) -* magit-log-buffer-file-locked: Commands for Buffers Visiting Files. - (line 124) -* magit-log-margin: Logging. (line 223) -* magit-log-margin-show-committer-date: Logging. (line 255) -* magit-log-section-commit-count: Status Buffer. (line 265) -* magit-log-select-margin: Logging. (line 304) -* magit-log-show-color-graph-limit: Logging. (line 174) -* magit-log-show-refname-after-summary: Logging. (line 170) -* magit-log-show-signatures-limit: Logging. (line 180) -* magit-log-trace-definition-function: Diffing. (line 192) -* magit-module-sections-hook: Status Buffer. (line 364) -* magit-module-sections-nested: Status Buffer. (line 367) -* magit-no-confirm: Completion Confirmation and the Selection. - (line 21) -* magit-pop-revision-stack-format: Committing. (line 374) -* magit-post-clone-hook: Cloning Repository. (line 133) -* magit-post-commit-hook: Committing. (line 229) -* magit-post-display-buffer-hook: Modes and Buffers. (line 117) -* magit-pre-display-buffer-hook: Modes and Buffers. (line 108) -* magit-prefer-remote-upstream: Branching. (line 431) -* magit-prefix-use-buffer-arguments: Transient Arguments and Buffer Variables. - (line 65) -* magit-process-raise-error: Calling Git. (line 232) -* magit-pull-or-fetch: Fetching. (line 52) -* magit-reflog-margin: Logging. (line 344) -* magit-refresh-args: Refreshing Buffers. (line 52) -* magit-refresh-buffer-hook: Modes and Buffers. (line 280) -* magit-refresh-function: Refreshing Buffers. (line 47) -* magit-refresh-status-buffer: Modes and Buffers. (line 285) -* 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 Buffer. (line 241) -* magit-refs-show-commit-count: References Buffer. (line 36) -* magit-refs-show-remote-prefix: References Buffer. (line 57) -* magit-remote-add-set-remote.pushDefault: Remotes. (line 86) -* magit-remote-direct-configure: Remotes. (line 23) -* magit-remote-git-executable: Running Git. (line 165) -* magit-repolist-columns: Repository List. (line 12) -* magit-repository-directories: Status Buffer. (line 57) -* magit-revision-filter-files-on-follow: Diffing. (line 412) -* magit-revision-insert-related-refs: Diffing. (line 363) -* magit-revision-show-gravatars: Diffing. (line 372) -* magit-revision-use-hash-sections: Diffing. (line 388) -* magit-root-section: Section Plumbing. (line 197) -* magit-save-repository-buffers: Modes and Buffers. (line 314) -* magit-section-cache-visibility: Sections. (line 219) -* magit-section-initial-visibility-alist: Sections. (line 203) -* magit-section-movement-hook: Sections. (line 57) -* magit-section-set-visibility-hook: Sections. (line 229) -* magit-section-show-child-count: Sections. (line 356) -* magit-section-visibility-indicator: Sections. (line 246) -* magit-shell-command-verbose-prompt: Running Git. (line 112) -* magit-stashes-margin: Stashing. (line 119) -* magit-status-file-list-limit: Status Buffer. (line 230) -* magit-status-headers-hook: Status Buffer. (line 297) -* magit-status-margin: Status Buffer. (line 408) -* magit-status-sections-hook: Status Buffer. (line 122) -* magit-status-show-untracked-files: Status Buffer. (line 197) -* magit-submodule-list-columns: Submodules. (line 25) -* magit-this-process: Calling Git. (line 228) -* magit-uniquify-buffer-names: Modes and Buffers. (line 190) -* magit-unstage-committed: Staging and Unstaging. - (line 52) -* magit-update-other-window-delay: Sections. (line 113) -* magit-visit-ref-behavior: References Buffer. (line 168) -* magit-wip-after-apply-mode: Wip Modes. (line 172) -* magit-wip-after-apply-mode-lighter: Wip Modes. (line 208) -* magit-wip-after-save-local-mode-lighter: Wip Modes. (line 205) -* magit-wip-after-save-mode: Wip Modes. (line 167) -* magit-wip-before-change-mode: Wip Modes. (line 185) -* magit-wip-before-change-mode-lighter: Wip Modes. (line 211) -* magit-wip-initial-backup-mode: Wip Modes. (line 189) -* magit-wip-initial-backup-mode-lighter: Wip Modes. (line 214) -* magit-wip-merge-branch: Wip Modes. (line 104) -* 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: Branching. (line 373) -* remote.NAME.fetch: Remotes. (line 108) -* remote.NAME.push: Remotes. (line 117) -* remote.NAME.pushurl: Remotes. (line 112) -* remote.NAME.tagOpts: Remotes. (line 121) -* remote.NAME.url: Remotes. (line 104) -* remote.pushDefault: Branching. (line 385) - - - -Tag Table: -Node: Top774 -Node: Introduction3572 -Node: Installation8288 -Node: Installing from Melpa8618 -Node: Installing from the Git Repository9693 -Node: Post-Installation Tasks12745 -Node: Getting Started14028 -Node: Interface Concepts19839 -Node: Modes and Buffers20218 -Ref: Switching Buffers21720 -Ref: Naming Buffers26366 -Ref: Quitting Windows29323 -Ref: Automatic Refreshing of Magit Buffers31120 -Ref: Automatic Saving of File-Visiting Buffers33836 -Ref: Automatic Reverting of File-Visiting Buffers34827 -Ref: Risk of Reverting Automatically39619 -Node: Sections41890 -Ref: Section Movement42695 -Ref: Section Visibility47482 -Ref: Section Hooks54060 -Ref: Section Types and Values56349 -Ref: Section Options57650 -Node: Transient Commands58029 -Node: Transient Arguments and Buffer Variables59505 -Node: Completion Confirmation and the Selection66522 -Ref: Action Confirmation66783 -Ref: Completion and Confirmation75156 -Ref: The Selection78187 -Ref: The hunk-internal region80926 -Ref: Support for Completion Frameworks81850 -Ref: Additional Completion Options86554 -Node: Mouse Support87004 -Node: Running Git87580 -Ref: Viewing Git Output87700 -Ref: Git Process Status89591 -Ref: Running Git Manually90435 -Ref: Git Executable93008 -Ref: Global Git Arguments95897 -Node: Inspecting96612 -Node: Status Buffer97769 -Ref: Status Sections102677 -Ref: Status File List Sections105404 -Ref: Status Log Sections107981 -Ref: Status Header Sections109331 -Ref: Status Module Sections111824 -Ref: Status Options114196 -Node: Repository List115465 -Node: Logging120243 -Ref: Refreshing Logs122978 -Ref: Log Buffer124322 -Ref: Log Margin129049 -Ref: Select from Log132106 -Ref: Reflog134224 -Ref: Cherries135771 -Node: Diffing137543 -Ref: Refreshing Diffs141494 -Ref: Commands Available in Diffs145088 -Ref: Diff Options147485 -Ref: Revision Buffer153283 -Node: Ediffing156524 -Node: References Buffer162574 -Ref: References Sections173134 -Node: Bisecting173919 -Node: Visiting Files and Blobs176230 -Ref: General-Purpose Visit Commands176672 -Ref: Visiting Files and Blobs from a Diff177490 -Node: Blaming180722 -Node: Manipulating187710 -Node: Creating Repository188052 -Node: Cloning Repository188589 -Node: Staging and Unstaging195030 -Ref: Staging from File-Visiting Buffers198954 -Node: Applying199969 -Node: Committing202042 -Ref: Initiating a Commit202669 -Ref: Creating a new commit202981 -Ref: Editing the last commit203091 -Ref: Editing any reachable commit205070 -Ref: Editing any reachable commit and rebasing immediately209483 -Ref: Options used by commit commands211131 -Ref: Used by all or most commit commands211203 -Ref: Used by all squash and fixup commands213434 -Ref: Used by specific commit commands213982 -Ref: Editing Commit Messages214306 -Ref: Using the Revision Stack216860 -Ref: Commit Pseudo Headers219792 -Ref: Commit Mode and Hooks220944 -Ref: Commit Message Conventions223657 -Node: Branching225529 -Ref: The Two Remotes225650 -Ref: Branch Commands228219 -Ref: Branch Git Variables240956 -Ref: Auxiliary Branch Commands246203 -Node: Merging247220 -Node: Resolving Conflicts251380 -Node: Rebasing256754 -Ref: Editing Rebase Sequences261714 -Ref: Information About In-Progress Rebase265875 -Ref: Rebasing-Footnote-1274875 -Node: Cherry Picking275471 -Ref: Reverting279781 -Node: Resetting281141 -Node: Stashing282967 -Node: Transferring289208 -Node: Remotes289430 -Ref: Remote Commands289527 -Ref: Remote Git Variables293479 -Node: Fetching294663 -Node: Pulling297146 -Node: Pushing298172 -Node: Plain Patches302463 -Node: Maildir Patches303934 -Node: Miscellaneous305413 -Node: Tagging305759 -Node: Notes307652 -Node: Submodules309987 -Ref: Listing Submodules310148 -Ref: Submodule Transient312204 -Node: Subtree314557 -Node: Worktree316488 -Node: Sparse checkouts317564 -Node: Bundle320340 -Node: Common Commands320715 -Node: Wip Modes323343 -Ref: Wip Graph328189 -Ref: Legacy Wip Modes330423 -Node: Commands for Buffers Visiting Files333231 -Node: Minor Mode for Buffers Visiting Blobs341458 -Node: Customizing342256 -Node: Per-Repository Configuration343852 -Node: Essential Settings346106 -Ref: Safety346395 -Ref: Performance348076 -Ref: Log Performance350869 -Ref: Diff Performance352174 -Ref: Refs Buffer Performance353515 -Ref: Committing Performance354090 -Ref: Microsoft Windows Performance355072 -Ref: MacOS Performance356161 -Ref: Global Bindings357046 -Ref: Essential Settings-Footnote-1359221 -Node: Plumbing359303 -Node: Calling Git360132 -Ref: Getting a Value from Git361591 -Ref: Calling Git for Effect365217 -Node: Section Plumbing371009 -Ref: Creating Sections371161 -Ref: Section Selection374962 -Ref: Matching Sections376637 -Node: Refreshing Buffers382463 -Node: Conventions385607 -Ref: Theming Faces385771 -Node: FAQ393816 -Node: FAQ - How to ...?394254 -Ref: How to pronounce Magit?394387 -Ref: How to show git's output?395081 -Ref: How to install the gitman info manual?395706 -Ref: How to show diffs for gpg-encrypted files?396517 -Ref: How does branching and pushing work?396926 -Ref: Should I disable VC?397090 -Node: FAQ - Issues and Errors397575 -Ref: Magit is slow397720 -Ref: I changed several thousand files at once and now Magit is unusable397866 -Ref: I am having problems committing398405 -Ref: I am using MS Windows and cannot push with Magit398670 -Ref: I am using macOS and SOMETHING works in shell but not in Magit399070 -Ref: Expanding a file to show the diff causes it to disappear399661 -Ref: Point is wrong in the COMMIT_EDITMSG buffer400011 -Ref: The mode-line information isn't always up-to-date400835 -Ref: A branch and tag sharing the same name breaks SOMETHING401674 -Ref: My Git hooks work on the command-line but not inside Magit402322 -Ref: git-commit-mode isn't used when committing from the command-line402914 -Ref: Point ends up inside invisible text when jumping to a file-visiting buffer404912 -Ref: I am no longer able to save popup defaults405504 -Node: Debugging Tools406301 -Node: Keystroke Index410240 -Node: Function and Command Index448190 -Node: Variable Index499700 - -End Tag Table - - -Local Variables: -coding: utf-8 -End: diff --git a/elpa/magit-20251103.1130/.dir-locals.el b/elpa/magit-20251103.1130/.dir-locals.el new file mode 100644 index 00000000..ea760dc2 --- /dev/null +++ b/elpa/magit-20251103.1130/.dir-locals.el @@ -0,0 +1,15 @@ +((nil + (indent-tabs-mode . nil)) + (makefile-mode + (indent-tabs-mode . t) + (outline-regexp . "#\\(#+\\)") + (mode . outline-minor)) + (emacs-lisp-mode + (checkdoc-allow-quoting-nil-and-t . t)) + (git-commit-mode + (git-commit-major-mode . git-commit-elisp-text-mode)) + (".github/PULL_REQUEST_TEMPLATE" + (nil (truncate-lines . nil))) + ("CHANGELOG" + (nil (fill-column . 70) + (mode . display-fill-column-indicator)))) diff --git a/elpa/magit-20251103.1130/AUTHORS.md b/elpa/magit-20251103.1130/AUTHORS.md new file mode 100644 index 00000000..ba62bdf3 --- /dev/null +++ b/elpa/magit-20251103.1130/AUTHORS.md @@ -0,0 +1,426 @@ +The following people have contributed to Magit. +For statistics see https://magit.vc/stats/magit/authors.html. + +Authors +------- + +- Marius Vollmer +- Jonas Bernoulli + +Active Maintainers +------------------ + +- Jonas Bernoulli +- Kyle Meyer + +Former Maintainers +------------------ + +- Nicolas Dudebout +- Noam Postavsky +- Peter J. Weisberg +- Phil Jackson +- Rémi Vanicat +- Yann Hodique + +All Contributors +---------------- + +- Aaron Culich +- Aaron L. Zeng +- Aaron Madlon-Kay +- Abdo Roig-Maranges +- Adam Benanti +- Adam Jones +- 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 Kreisher +- Alex Ott +- Allen Li +- Andreas Fuchs +- Andreas Liljeqvist +- Andreas Rottmann +- Andrei Chițu +- Andrew Eggenberger +- Andrew Kirkpatrick +- Andrew Psaltis +- Andrew Schwartzmeyer +- Andrew Zipperer +- Andrey Smirnov +- Andriy Kmit' +- Andy Sawyer +- Angel de Vicente +- 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 +- Ben Zanin +- Bob Uhl +- Boruch Baum +- Bradley Wright +- Brandon W Maister +- Brennan Vincent +- Brian Leung +- Brian Warner +- Bryan Shell +- Buster Copley +- Cameron Chaparro +- Carl Lieberman +- Chillar Anand +- Chris Bernard +- Chris Done +- Chris LaRose +- Chris Moore +- Chris Ring +- Chris Shoemaker +- Christian Dietrich +- Christian Kluge +- Christian Tietze +- Christophe Junke +- Christopher Carlile +- Christopher Monsanto +- Clément Pit-Claudel +- Cornelius Mika +- Craig Andera +- Curt Brune +- Daanturo +- 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 Mendler +- Daniel Nagy +- Dan Kessler +- Dan LaManna +- Danny Zhu +- Dato Simó +- David Abrahams +- David Ellison +- David Hull +- David L. Rager +- David Wallin +- Dean Kariniemi +- Dennis Paskorz +- Divye Kapoor +- Dominique Quatravaux +- Duianto Vebotci +- Eli Barzilay +- Ellis Kenyo +- Eric +- Eric Davis +- Eric Prud'hommeaux +- Eric Schulte +- Erik Anderson +- Eugene Mikhaylov +- Evan Torrie +- Evgkeni Sampelnikof +- Eyal Lotem +- Eyal Soha +- Fabian Wiget +- Felix Geller +- Felix Yan +- Feng Li +- Florian Ragwitz +- Franklin Delehelle +- Frédéric Giquel +- Fritz Grabo +- Fritz Stelzer +- gemmaro +- Geoff Shannon +- George Kadianakis +- Géza Herman +- Graham Clark +- Graham Dobbins +- Greg A. Woods +- Greg Lucas +- Gregory Heytings +- Greg Sexton +- Greg Steuck +- Guillaume Martres +- Hannu Koivisto +- Hans-Peter Deifel +- hokomo +- Hussein Ait-Lahcen +- Ian Eure +- Ian Milligan +- Ilya Grigoriev +- Iñaki Arenaza +- Ingmar Sittl +- Ingo Lohmar +- Ioan-Adrian Ratiu +- Ivan Brennan +- Jacob Ilsø +- Jan Tatarik +- Jasper St. Pierre +- JD Smith +- Jean-Louis Giordano +- Jeff Bellegarde +- Jeff Dairiki +- Jeremy Meng +- Jeremy Sowden +- Jesse Alama +- Jim Blandy +- Joakim Jalap +- Johannes Altmanninger +- Johannes Maier +- 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 +- Jorge Israel Peña +- 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 +- Lénaïc Huard +- Leo Liu +- Leonardo Etcheverry +- Leo Vivier +- Li Chen +- Lingchao Xin +- Lin Sun +- Li-Yun Chang +- Lluís Vilanova +- Loic Dachary +- Louis Roché +- Luís Oliveira +- Luke Amdor +- Magnar Sveen +- 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 +- Markus Beppler +- Martin Joerg +- Martin Polden +- Matt Beshara +- 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 +- Nacho Barrientos +- Naoya Yamashita +- Natalie Weizenbaum +- Nguyễn Tuấn Anh +- Nic Ferier +- Nicholas Vollmer +- Nick Alcock +- Nick Alexander +- Nick Dimiduk +- Nicklas Lindgren +- Nicolas Dudebout +- Nicolas Petton +- Nicolas Richard +- Nikita Leshenko +- Nikolay Martynov +- Noam Postavsky +- N. Troy de Freitas +- Ola Nilsson +- Ole Arndt +- Oleh Krehel +- Orivej Desh +- Óscar Fuentes +- Pancho Horrillo +- Park Zhou +- Paul Pogonyshev +- Paul Stadig +- Pavel Holejsovsky +- Pekka Pessi +- Pengji Zhang +- 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 +- Pieter van Oostrum +- Prathamesh Sonpatki +- Pratyush Yadav +- Pritam Baral +- rabio +- Radon Rosborough +- Rafael Laboissiere +- Rahul Rameshbabu +- Raimon Grau +- Ramkumar Ramachandra +- Remco van 't Veer +- Rémi Vanicat +- René Stadler +- Richard Kim +- Richard Sent +- Robert Boone +- Robert Irelan +- Robin Green +- Roey Darwish Dror +- Roger Crew +- Roland Marchand +- 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 Farley +- Sean Whitton +- Sebastian Wiesner +- Sébastien Gross +- Seong-Kook Shin +- Sergey Pashinin +- Sergey Vinokurov +- Servilio Afre Puentes +- shoefone +- Shuguang Sun +- Siavash Askari Nasr +- Silent Sphere +- Simon Pintarelli +- Stefan Kangas +- Štěpán Němec +- Steven Chow +- Steven E. Harris +- Steven Thomas +- Steven Vancoillie +- Steve Purcell +- StrawberryTea +- 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 +- Ulrich Müller +- Vineet Naik +- Vitaly Ostashov +- Vladimir Ivanov +- Vladimir Panteleev +- Vladimir Sedach +- Waqar Hameed +- Wei Huang +- Wilfred Hughes +- Win Treese +- Wojciech Siewierski +- Wouter Bolsterlee +- X4lldux +- Xavier Noria +- Xavier Young +- Xu Chunyang +- Yann Herklotz +- Yann Hodique +- Ynilu +- York Zhao +- Yuichi Higashi +- Yuri Khan +- Zach Latta +- zakora +- Zhu Zihao +- ziggy +- zilongshanren diff --git a/elpa/magit-20251103.1130/LICENSE b/elpa/magit-20251103.1130/LICENSE new file mode 100644 index 00000000..f288702d --- /dev/null +++ b/elpa/magit-20251103.1130/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-20251103.1130/dir b/elpa/magit-20251103.1130/dir new file mode 100644 index 00000000..dfdbd715 --- /dev/null +++ b/elpa/magit-20251103.1130/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-20251103.1130/git-commit.el b/elpa/magit-20251103.1130/git-commit.el new file mode 100644 index 00000000..0bcad3d3 --- /dev/null +++ b/elpa/magit-20251103.1130/git-commit.el @@ -0,0 +1,1232 @@ +;;; git-commit.el --- Edit Git commit messages -*- lexical-binding:t; coding:utf-8 -*- + +;; Copyright (C) 2008-2025 The Magit Project Contributors + +;; Author: Jonas Bernoulli +;; Sebastian Wiesner +;; Florian Ragwitz +;; Marius Vollmer +;; 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 of the License, +;; 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 . + +;; You should have received a copy of the AUTHORS.md file, which +;; lists all contributors. If not, see https://magit.vc/authors. + +;;; Commentary: + +;; This package assists the user in writing good Git commit messages. + +;; While Git allows for the message to be provided on the command +;; line, it is preferable to tell Git to create the commit without +;; actually passing it a message. Git then invokes the `$GIT_EDITOR' +;; (or if that is undefined `$EDITOR') asking the user to provide the +;; message by editing the file ".git/COMMIT_EDITMSG" (or another file +;; in that directory, e.g., ".git/MERGE_MSG" for merge commits). + +;; When `global-git-commit-mode' is enabled, which it is by default, +;; then opening such a file causes the features described below, to +;; be enabled in that buffer. Normally this would be done using a +;; major-mode but to allow the use of any major-mode, as the user sees +;; fit, it is done here by running a setup function, which among other +;; things turns on the preferred major-mode, by default `text-mode'. + +;; Git waits for the `$EDITOR' to finish and then either creates the +;; commit using the contents of the file as commit message, or, if the +;; editor process exited with a non-zero exit status, aborts without +;; creating a commit. Unfortunately Emacsclient (which is what Emacs +;; users should be using as `$EDITOR' or at least as `$GIT_EDITOR') +;; does not differentiate between "successfully" editing a file and +;; aborting; not out of the box that is. + +;; By making use of the `with-editor' package this package provides +;; both ways of finish an editing session. In either case the file +;; is saved, but Emacseditor's exit code differs. +;; +;; C-c C-c Finish the editing session successfully by returning +;; with exit code 0. Git then creates the commit using +;; the message it finds in the file. +;; +;; C-c C-k Aborts the edit editing session by returning with exit +;; code 1. Git then aborts the commit. + +;; Aborting the commit does not cause the message to be lost, but +;; relying solely on the file not being tampered with is risky. This +;; package additionally stores all aborted messages for the duration +;; of the current session (i.e., until you close Emacs). To get back +;; an aborted message use M-p and M-n while editing a message. +;; +;; M-p Replace the buffer contents with the previous message +;; from the message ring. Of course only after storing +;; the current content there too. +;; +;; M-n Replace the buffer contents with the next message from +;; the message ring, after storing the current content. + +;; Support for inserting Git trailers (as described in the manpage +;; git-interpret-trailers(1)) is available. +;; +;; C-c C-i Insert a trailer selected from a transient menu. + +;; When Git requests a commit message from the user, it does so by +;; having her edit a file which initially contains some comments, +;; instructing her what to do, and providing useful information, such +;; as which files were modified. These comments, even when left +;; intact by the user, do not become part of the commit message. This +;; package ensures these comments are propertizes as such and further +;; prettifies them by using different faces for various parts, such as +;; files. + +;; Finally this package highlights style errors, like lines that are +;; too long, or when the second line is not empty. It may even nag +;; you when you attempt to finish the commit without having fixed +;; these issues. The style checks and many other settings can easily +;; be configured: +;; +;; M-x customize-group RET git-commit RET + +;;; Code: + +(require 'magit-git) +(require 'magit-mode) +(require 'magit-process) + +(require 'log-edit) +(require 'ring) +(require 'server) +(require 'transient) +(require 'with-editor) + +(defvar diff-default-read-only) +(defvar flyspell-generic-check-word-predicate) +(defvar font-lock-beg) +(defvar font-lock-end) +(defvar recentf-exclude) + +(defvar git-commit-need-summary-line) + +(define-obsolete-variable-alias + 'git-commit-known-pseudo-headers + 'git-commit-trailers + "git-commit 4.0.0") + +;;; Options +;;;; Variables + +(defgroup git-commit nil + "Edit Git commit messages." + :prefix "git-commit-" + :link '(info-link "(magit)Editing Commit Messages") + :group 'tools) + +(define-minor-mode global-git-commit-mode + "Edit Git commit messages. + +This global mode arranges for `git-commit-setup' to be called +when a Git commit message file is opened. That usually happens +when Git uses the Emacsclient as $GIT_EDITOR to have the user +provide such a commit message. + +Loading the library `git-commit' by default enables this mode, +but the library is not automatically loaded because doing that +would pull in many dependencies and increase startup time too +much. You can either rely on `magit' loading this library or +you can load it explicitly. Autoloading is not an alternative +because in this case autoloading would immediately trigger +full loading." + :group 'git-commit + :type 'boolean + :global t + :init-value t + :initialize + (lambda (symbol exp) + (custom-initialize-default symbol exp) + (when global-git-commit-mode + (add-hook 'find-file-hook #'git-commit-setup-check-buffer) + (remove-hook 'after-change-major-mode-hook + #'git-commit-setup-font-lock-in-buffer))) + (cond + (global-git-commit-mode + (add-hook 'find-file-hook #'git-commit-setup-check-buffer) + (add-hook 'after-change-major-mode-hook + #'git-commit-setup-font-lock-in-buffer)) + (t + (remove-hook 'find-file-hook #'git-commit-setup-check-buffer) + (remove-hook 'after-change-major-mode-hook + #'git-commit-setup-font-lock-in-buffer)))) + +(defcustom git-commit-major-mode #'text-mode + "Major mode used to edit Git commit messages. + +The major mode configured here is turned on by the minor mode +`git-commit-mode'." + :group 'git-commit + :type '(radio (function-item text-mode) + (function-item markdown-mode) + (function-item org-mode) + (function-item fundamental-mode) + (function-item log-edit-mode) + (function-item git-commit-elisp-text-mode) + (function :tag "Another mode") + (const :tag "No major mode"))) +;;;###autoload(put 'git-commit-major-mode 'safe-local-variable +;;;###autoload (lambda (val) +;;;###autoload (memq val '(text-mode +;;;###autoload markdown-mode +;;;###autoload org-mode +;;;###autoload fundamental-mode +;;;###autoload log-edit-mode +;;;###autoload git-commit-elisp-text-mode)))) + +(defvaralias 'git-commit-mode-hook 'git-commit-setup-hook + "This variable is an alias for `git-commit-setup-hook' (which see). +Also note that `git-commit-mode' (which see) is not a major-mode.") + +(defcustom git-commit-setup-hook + (list #'git-commit-ensure-comment-gap + #'git-commit-save-message + #'git-commit-setup-changelog-support + #'git-commit-turn-on-auto-fill + #'git-commit-propertize-diff + #'bug-reference-mode) + "Hook run at the end of `git-commit-setup'." + :group 'git-commit + :type 'hook + :get #'magit-hook-custom-get + :options '(git-commit-ensure-comment-gap + git-commit-save-message + git-commit-setup-changelog-support + magit-generate-changelog + git-commit-turn-on-auto-fill + git-commit-turn-on-orglink + git-commit-turn-on-flyspell + git-commit-propertize-diff + bug-reference-mode)) + +(defcustom git-commit-post-finish-hook nil + "Hook run after the user finished writing a commit message. + +\\\ +This hook is only run after pressing \\[with-editor-finish] 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 +that takes Git longer than `git-commit-post-finish-hook-timeout' +seconds, 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. + +Also see `magit-post-commit-hook'." + :group 'git-commit + :type 'hook + :get #'magit-hook-custom-get) + +(defcustom git-commit-post-finish-hook-timeout 2 + "Time in seconds to wait for git to create a commit. + +The hook `git-commit-post-finish-hook' (which see) is run only +after git is done creating a commit. If it takes longer than +`git-commit-post-finish-hook-timeout' seconds to create the +commit, then the hook is not run at all." + :group 'git-commit + :safe 'numberp + :type 'number) + +(defcustom git-commit-finish-query-functions + (list #'git-commit-check-style-conventions) + "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." + :options '(git-commit-check-style-conventions) + :type 'hook + :group 'git-commit) + +(defcustom git-commit-style-convention-checks '(non-empty-second-line) + "List of checks performed by `git-commit-check-style-conventions'. + +Valid members are `non-empty-second-line' and `overlong-summary-line'. +That function is a member of `git-commit-finish-query-functions'." + :options '(non-empty-second-line overlong-summary-line) + :type '(list :convert-widget custom-hook-convert-widget) + :group 'git-commit) + +(defcustom git-commit-summary-max-length 68 + "Column beyond which characters in the summary lines are highlighted. + +The highlighting indicates that the summary is getting too long +by some standards. It does in no way imply that going over the +limit a few characters or in some cases even many characters is +anything that deserves shaming. It's just a friendly reminder +that if you can make the summary shorter, then you might want +to consider doing so." + :group 'git-commit + :safe 'numberp + :type 'number) + +(defcustom git-commit-trailers + '("Acked-by" + "Modified-by" + "Reviewed-by" + "Signed-off-by" + "Tested-by" + "Cc" + "Reported-by" + "Suggested-by" + "Co-authored-by" + "Co-developed-by") + "A list of Git trailers to be highlighted. + +See also manpage git-interpret-trailer(1). This package does +not use that Git command, but the initial description still +serves as a good introduction." + :group 'git-commit + :safe (##and (listp %) (seq-every-p #'stringp %)) + :type '(repeat string)) + +(defcustom git-commit-use-local-message-ring nil + "Whether to use a local message ring instead of the global one. + +This can be set globally, in which case every repository gets its +own commit message ring, or locally for a single repository." + :group 'git-commit + :safe 'booleanp + :type 'boolean) + +(defcustom git-commit-cd-to-toplevel nil + "Whether to set `default-directory' to the worktree in message buffer. + +Editing a commit message is done by visiting a file located in the git +directory, usually \"COMMIT_EDITMSG\". As is done when visiting any +file, the local value of `default-directory' is set to the directory +that contains the file. + +If this option is non-nil, then the local `default-directory' is changed +to the working tree from which the commit command was invoked. You may +wish to do that, to make it easier to open a file that is located in the +working tree, directly from the commit message buffer. + +If the git variable `safe.bareRepository' is set to \"explicit\", then +you have to enable this, to be able to commit at all. See issue #5100. + +This option only has an effect if the commit was initiated from Magit." + :group 'git-commit + :type 'boolean) + +;;;; Faces + +(defgroup git-commit-faces nil + "Faces used for highlighting Git commit messages." + :prefix "git-commit-" + :group 'git-commit + :group 'faces) + +(defface git-commit-summary + '((t :inherit font-lock-type-face)) + "Face used for the summary in commit messages." + :group 'git-commit-faces) + +(defface git-commit-overlong-summary + '((t :inherit font-lock-warning-face)) + "Face used for the tail of overlong commit message summaries." + :group 'git-commit-faces) + +(defface git-commit-nonempty-second-line + '((t :inherit font-lock-warning-face)) + "Face used for non-whitespace on the second line of commit messages." + :group 'git-commit-faces) + +(defface git-commit-keyword + '((t :inherit font-lock-string-face)) + "Face used for keywords in commit messages. +In this context a \"keyword\" is text surrounded by brackets." + :group 'git-commit-faces) + +(defface git-commit-trailer-token + '((t :inherit font-lock-keyword-face)) + "Face used for Git trailer tokens in commit messages." + :group 'git-commit-faces) + +(defface git-commit-trailer-value + '((t :inherit font-lock-string-face)) + "Face used for Git trailer values in commit messages." + :group 'git-commit-faces) + +(defface git-commit-comment-branch-local + '((t :inherit magit-branch-local)) + "Face used for names of local branches in commit message comments." + :group 'git-commit-faces) + +(defface git-commit-comment-branch-remote + '((t :inherit magit-branch-remote)) + "Face used for names of remote branches in commit message comments." + :group 'git-commit-faces) + +(defface git-commit-comment-detached + '((t :inherit git-commit-comment-branch-local)) + "Face used for detached `HEAD' in commit message comments." + :group 'git-commit-faces) + +(defface git-commit-comment-heading + '((t :inherit git-commit-trailer-token)) + "Face used for headings in commit message comments." + :group 'git-commit-faces) + +(defface git-commit-comment-file + '((t :inherit git-commit-trailer-value)) + "Face used for file names in commit message comments." + :group 'git-commit-faces) + +(defface git-commit-comment-action + '((t :inherit bold)) + "Face used for actions in commit message comments." + :group 'git-commit-faces) + +;;; Keymap + +(defvar-keymap git-commit-redundant-bindings + :doc "Bindings made redundant by `git-commit-insert-trailer'. +This keymap is used as the parent of `git-commit-mode-map', +to avoid upsetting muscle-memory. If you would rather avoid +the redundant bindings, then set this to nil, before loading +`git-commit'." + "C-c C-a" #'git-commit-ack + "C-c M-i" #'git-commit-suggested + "C-c C-m" #'git-commit-modified + "C-c C-o" #'git-commit-cc + "C-c C-p" #'git-commit-reported + "C-c C-r" #'git-commit-review + "C-c C-s" #'git-commit-signoff + "C-c C-t" #'git-commit-test) + +(defvar-keymap git-commit-mode-map + :doc "Keymap used by `git-commit-mode'." + :parent git-commit-redundant-bindings + "M-p" #'git-commit-prev-message + "M-n" #'git-commit-next-message + "C-c M-p" #'git-commit-search-message-backward + "C-c M-n" #'git-commit-search-message-forward + "C-c C-i" #'git-commit-insert-trailer + "C-c M-s" #'git-commit-save-message + "C-c C-d" 'magit-diff-while-committing + "C-c C-w" 'magit-pop-revision-stack) + +;;; Menu + +(require 'easymenu) +(easy-menu-define git-commit-mode-menu git-commit-mode-map + "Git Commit Mode Menu." + '("Commit" + ["Previous" git-commit-prev-message t] + ["Next" git-commit-next-message t] + "-" + ["Ack" git-commit-ack t + :help "Insert an 'Acked-by' trailer"] + ["Modified-by" git-commit-modified t + :help "Insert a 'Modified-by' trailer"] + ["Reviewed-by" git-commit-review t + :help "Insert a 'Reviewed-by' trailer"] + ["Sign-Off" git-commit-signoff t + :help "Insert a 'Signed-off-by' trailer"] + ["Tested-by" git-commit-test t + :help "Insert a 'Tested-by' trailer"] + "-" + ["CC" git-commit-cc t + :help "Insert a 'Cc' trailer"] + ["Reported" git-commit-reported t + :help "Insert a 'Reported-by' trailer"] + ["Suggested" git-commit-suggested t + :help "Insert a 'Suggested-by' trailer"] + ["Co-authored-by" git-commit-co-authored t + :help "Insert a 'Co-authored-by' trailer"] + ["Co-developed-by" git-commit-co-developed t + :help "Insert a 'Co-developed-by' trailer"] + "-" + ["Save" git-commit-save-message t] + ["Cancel" with-editor-cancel t] + ["Commit" with-editor-finish t])) + +;;; Hooks + +(defconst git-commit-filename-regexp "/\\(\ +\\(\\(COMMIT\\|NOTES\\|PULLREQ\\|MERGEREQ\\|TAG\\)_EDIT\\|MERGE_\\|\\)MSG\ +\\|\\(BRANCH\\|EDIT\\)_DESCRIPTION\\)\\'") + +(with-eval-after-load 'recentf + (add-to-list 'recentf-exclude git-commit-filename-regexp)) + +(add-to-list 'with-editor-file-name-history-exclude git-commit-filename-regexp) + +(defun git-commit-setup-font-lock-in-buffer () + (when (and buffer-file-name + (string-match-p git-commit-filename-regexp buffer-file-name)) + (git-commit-setup-font-lock))) + +(defun git-commit-setup-check-buffer () + (when (and buffer-file-name + (string-match-p git-commit-filename-regexp buffer-file-name)) + (git-commit-setup))) + +(defvar git-commit-mode) + +(defun git-commit-file-not-found () + ;; cygwin git will pass a cygwin path (/cygdrive/c/foo/.git/...), + ;; try to handle this in window-nt Emacs. + (when-let* + ((file (and (or (string-match-p git-commit-filename-regexp + buffer-file-name) + (and (boundp 'git-rebase-filename-regexp) + (string-match-p git-rebase-filename-regexp + buffer-file-name))) + (not (file-accessible-directory-p + (file-name-directory buffer-file-name))) + (magit-expand-git-file-name (substring buffer-file-name 2)))) + (_(file-accessible-directory-p (file-name-directory file))) + (inhibit-read-only t)) + (insert-file-contents file t) + t)) + +(when (eq system-type 'windows-nt) + (add-hook 'find-file-not-found-functions #'git-commit-file-not-found)) + +(defconst git-commit-default-usage-message "\ +Type \\[with-editor-finish] to finish, \ +\\[with-editor-cancel] to cancel, and \ +\\[git-commit-prev-message] and \\[git-commit-next-message] \ +to recover older messages") + +(defvar git-commit-usage-message git-commit-default-usage-message + "Message displayed when editing a commit message. +When this is nil, then `with-editor-usage-message' is displayed +instead. One of these messages has to be displayed; otherwise +the user gets to see the message displayed by `server-execute'. +That message is misleading and because we cannot prevent it from +being displayed, we have to immediately show another message to +prevent the user from seeing it.") + +(defvar git-commit-header-line-format nil + "If non-nil, header line format used by `git-commit-mode'. +Used as the local value of `header-line-format', in buffer using +`git-commit-mode'. If it is a string, then it is passed through +`substitute-command-keys' first. A useful setting may be: + (setq git-commit-header-line-format git-commit-default-usage-message) + (setq git-commit-usage-message nil) ; show a shorter message") + +(defun git-commit-setup () + (let ((gitdir default-directory) + (cd (and git-commit-cd-to-toplevel + (or (car (rassoc default-directory magit--separated-gitdirs)) + (magit-toplevel))))) + ;; Pretend that git-commit-mode is a major-mode, + ;; so that directory-local settings can be used. + (let ((default-directory + (or (and (not (file-exists-p + (expand-file-name ".dir-locals.el" gitdir))) + ;; When $GIT_DIR/.dir-locals.el doesn't exist, + ;; fallback to $GIT_WORK_TREE/.dir-locals.el, + ;; because the maintainer can use the latter + ;; to enforce conventions, while s/he has no + ;; control over the former. + (or cd (magit-toplevel))) + gitdir))) + (let ((buffer-file-name nil) ; trick hack-dir-local-variables + (major-mode 'git-commit-mode)) ; trick dir-locals-collect-variables + (hack-dir-local-variables) + (hack-local-variables-apply))) + (when cd + (setq default-directory cd))) + (when git-commit-major-mode + (let ((auto-mode-alist + ;; `set-auto-mode--apply-alist' removes the remote part from + ;; the file-name before looking it up in `auto-mode-alist'. + ;; For our temporary entry to be found, we have to modify the + ;; file-name the same way. + (list (cons (concat "\\`" + (regexp-quote + (or (file-remote-p buffer-file-name 'localname) + buffer-file-name)) + "\\'") + git-commit-major-mode))) + ;; The major-mode hook might want to consult these minor + ;; modes, while the minor-mode hooks might want to consider + ;; the major mode. + (git-commit-mode t) + (with-editor-mode t)) + (normal-mode t))) + ;; Below we instead explicitly show a message. + (setq with-editor-show-usage nil) + (unless with-editor-mode + ;; Maybe already enabled when using `shell-command' or an Emacs shell. + (with-editor-mode 1)) + (add-hook 'with-editor-finish-query-functions + #'git-commit-finish-query-functions nil t) + (add-hook 'with-editor-pre-finish-hook #'git-commit-save-message nil t) + (add-hook 'with-editor-pre-cancel-hook #'git-commit-save-message nil t) + (when (fboundp 'magit-commit--reset-command) + (add-hook 'with-editor-post-finish-hook #'magit-commit--reset-command) + (add-hook 'with-editor-post-cancel-hook #'magit-commit--reset-command)) + (unless (memq last-command + '(magit-sequencer-continue + magit-sequencer-skip + magit-am-continue + magit-am-skip + magit-rebase-continue + magit-rebase-skip)) + (add-hook 'with-editor-post-finish-hook + (apply-partially #'git-commit-run-post-finish-hook + (magit-rev-parse "HEAD")) + nil t) + (when (fboundp 'magit-wip-maybe-add-commit-hook) + (magit-wip-maybe-add-commit-hook))) + (setq with-editor-cancel-message + #'git-commit-cancel-message) + (git-commit-setup-font-lock) + (git-commit-prepare-message-ring) + (when (boundp 'save-place) + (setq save-place nil)) + (let ((git-commit-mode-hook nil)) + (git-commit-mode 1)) + (with-demoted-errors "Error running git-commit-setup-hook: %S" + (run-hooks 'git-commit-setup-hook)) + (set-buffer-modified-p nil) + (when-let ((format git-commit-header-line-format)) + (setq header-line-format + (if (stringp format) (substitute-command-keys format) format))) + (when git-commit-usage-message + (setq with-editor-usage-message git-commit-usage-message)) + (with-editor-usage-message)) + +(defun git-commit-run-post-finish-hook (previous) + (when git-commit-post-finish-hook + (if (with-timeout (git-commit-post-finish-hook-timeout) + (while (equal (magit-rev-parse "HEAD") previous) + (sit-for 0.01)) + t) + (run-hooks 'git-commit-post-finish-hook) + (message "No commit created after %s second. Not running %s." + git-commit-post-finish-hook-timeout + 'git-commit-post-finish-hook)))) + +(define-minor-mode git-commit-mode + "Auxiliary minor mode used when editing Git commit messages. +This mode is only responsible for setting up some key bindings. +Don't use it directly; instead enable `global-git-commit-mode'. +Variable `git-commit-major-mode' controls which major-mode is +used." + :lighter "") + +(put 'git-commit-mode 'permanent-local t) + +(defun git-commit-ensure-comment-gap () + "Separate initial empty line from initial comment. +If the buffer begins with an empty line followed by a comment, insert +an additional newline in between, so that once the users start typing, +the input isn't tacked to the comment." + (save-excursion + (goto-char (point-min)) + (when (looking-at (format "\\`\n%s" comment-start)) + (open-line 1)))) + +(defun git-commit-setup-changelog-support () + "Treat ChangeLog entries as unindented paragraphs." + (setq-local fill-paragraph-function #'log-edit-fill-entry) + (setq-local fill-indent-according-to-mode t) + (setq-local paragraph-start (concat paragraph-start "\\|\\*\\|("))) + +(defun git-commit-turn-on-auto-fill () + "Unconditionally turn on Auto Fill mode. +Ensure auto filling happens everywhere, except in the summary line." + (auto-fill-mode 1) + (setq-local comment-auto-fill-only-comments nil) + (when git-commit-need-summary-line + (setq-local auto-fill-function #'git-commit-auto-fill-except-summary))) + +(defun git-commit-auto-fill-except-summary () + (unless (eq (line-beginning-position) 1) + (do-auto-fill))) + +(defun git-commit-turn-on-orglink () + "Turn on Orglink mode if it is available. +If `git-commit-major-mode' is `org-mode', then silently forgo +turning on `orglink-mode'." + (when (and (not (derived-mode-p 'org-mode)) + (boundp 'orglink-match-anywhere) + (fboundp 'orglink-mode)) + (setq-local orglink-match-anywhere t) + (orglink-mode 1))) + +(defun git-commit-turn-on-flyspell () + "Unconditionally turn on Flyspell mode. +Also check text that is already in the buffer, while avoiding to check +most text that Git will strip from the final message, such as the last +comment and anything below the cut line (\"--- >8 ---\")." + (require 'flyspell) + (flyspell-mode 1) + (setq flyspell-generic-check-word-predicate + #'git-commit-flyspell-verify) + (let ((end nil) + ;; The "cut line" is defined in "git/wt-status.c". It appears + ;; in the commit message when `commit.verbose' is set to true. + (cut-line-regex (format "^%s -\\{8,\\} >8 -\\{8,\\}$" comment-start)) + (comment-start-regex (format "^\\(%s\\|$\\)" comment-start))) + (save-excursion + (goto-char (or (re-search-forward cut-line-regex nil t) + (point-max))) + (while (and (not (bobp)) (looking-at comment-start-regex)) + (forward-line -1)) + (unless (looking-at comment-start-regex) + (forward-line)) + (setq end (point))) + (flyspell-region (point-min) end))) + +(defun git-commit-flyspell-verify () + (not (= (char-after (line-beginning-position)) + (aref comment-start 0)))) + +(defun git-commit-finish-query-functions (force) + (run-hook-with-args-until-failure + 'git-commit-finish-query-functions force)) + +(defun git-commit-check-style-conventions (force) + "Check for violations of certain basic style conventions. + +For each violation ask the user if she wants to proceed anyway. +Option `git-commit-style-convention-checks' controls which +conventions are checked." + (or force + (save-excursion + (goto-char (point-min)) + (re-search-forward (git-commit-summary-regexp) nil t) + (if (equal (match-str 1) "") + t ; Just try; we don't know whether --allow-empty-message was used. + (and (or (not (memq 'overlong-summary-line + git-commit-style-convention-checks)) + (equal (match-str 2) "") + (y-or-n-p "Summary line is too long. Commit anyway? ")) + (or (not (memq 'non-empty-second-line + git-commit-style-convention-checks)) + (not (match-str 3)) + (y-or-n-p "Second line is not empty. Commit anyway? "))))))) + +(defun git-commit-cancel-message () + (message + (concat "Commit canceled" + (and (memq 'git-commit-save-message with-editor-pre-cancel-hook) + ". Message saved to `log-edit-comment-ring'")))) + +;;; History + +(defun git-commit-prev-message (arg) + "Cycle backward through message history, after saving current message. +With a numeric prefix ARG, go back ARG messages." + (interactive "*p") + (let ((len (ring-length log-edit-comment-ring))) + (if (<= len 0) + (progn (message "Empty comment ring") (ding)) + ;; Unlike `log-edit-previous-comment' we save the current + ;; non-empty and newly written comment, because otherwise + ;; it would be irreversibly lost. + (when-let* ((message (git-commit-buffer-message)) + (_(not (ring-member log-edit-comment-ring message)))) + (ring-insert log-edit-comment-ring message) + (cl-incf arg) + (setq len (ring-length log-edit-comment-ring))) + ;; Delete the message but not the instructions at the end. + (save-restriction + (goto-char (point-min)) + (narrow-to-region + (point) + (if (re-search-forward (concat "^" comment-start) nil t) + (max 1 (- (point) 2)) + (point-max))) + (delete-region (point-min) (point))) + (setq log-edit-comment-ring-index (log-edit-new-comment-index arg len)) + (message "Comment %d" (1+ log-edit-comment-ring-index)) + (insert (ring-ref log-edit-comment-ring log-edit-comment-ring-index))))) + +(defun git-commit-next-message (arg) + "Cycle forward through message history, after saving current message. +With a numeric prefix ARG, go forward ARG messages." + (interactive "*p") + (git-commit-prev-message (- arg))) + +(defun git-commit-search-message-backward (string) + "Search backward through message history for a match for STRING. +Save current message first." + (interactive + (list (read-string (format-prompt "Comment substring" + log-edit-last-comment-match) + nil nil log-edit-last-comment-match))) + (cl-letf (((symbol-function #'log-edit-previous-comment) + (symbol-function #'git-commit-prev-message))) + (log-edit-comment-search-backward string))) + +(defun git-commit-search-message-forward (string) + "Search forward through message history for a match for STRING. +Save current message first." + (interactive + (list (read-string (format-prompt "Comment substring" + log-edit-last-comment-match) + nil nil log-edit-last-comment-match))) + (cl-letf (((symbol-function #'log-edit-previous-comment) + (symbol-function #'git-commit-prev-message))) + (log-edit-comment-search-forward string))) + +(defun git-commit-save-message () + "Save current message to `log-edit-comment-ring'." + (interactive) + (cond-let + ([message (git-commit-buffer-message)] + (when-let ((index (ring-member log-edit-comment-ring message))) + (ring-remove log-edit-comment-ring index)) + (ring-insert log-edit-comment-ring message) + (when git-commit-use-local-message-ring + (magit-repository-local-set 'log-edit-comment-ring + log-edit-comment-ring)) + (message "Message saved")) + ((message "Only whitespace and/or comments; message not saved")))) + +(defun git-commit-prepare-message-ring () + (make-local-variable 'log-edit-comment-ring-index) + (when git-commit-use-local-message-ring + (setq-local log-edit-comment-ring + (magit-repository-local-get + 'log-edit-comment-ring + (make-ring log-edit-maximum-comment-ring-size))))) + +(defun git-commit-buffer-message () + (let ((flush (concat "^" comment-start)) + (str (buffer-substring-no-properties (point-min) (point-max)))) + (with-temp-buffer + (insert str) + (goto-char (point-min)) + (when (re-search-forward (concat flush " -+ >8 -+$") nil t) + (delete-region (line-beginning-position) (point-max))) + (goto-char (point-min)) + (flush-lines flush) + (goto-char (point-max)) + (unless (eq (char-before) ?\n) + (insert ?\n)) + (setq str (buffer-string))) + (and (not (string-match "\\`[ \t\n\r]*\\'" str)) + (progn + (when (string-match "\\`\n\\{2,\\}" str) + (setq str (replace-match "\n" t t str))) + (when (string-match "\n\\{2,\\}\\'" str) + (setq str (replace-match "\n" t t str))) + str)))) + +;;; Trailers + +(transient-define-prefix git-commit-insert-trailer () + "Insert a commit message trailer. + +See also manpage git-interpret-trailer(1). This command does +not use that Git command, but the initial description still +serves as a good introduction." + [[:description (##cond (prefix-arg + "Insert ... by someone ") + ("Insert ... by yourself")) + ("a" "Ack" git-commit-ack) + ("m" "Modified" git-commit-modified) + ("r" "Reviewed" git-commit-review) + ("s" "Signed-off" git-commit-signoff) + ("t" "Tested" git-commit-test)] + ["Insert ... by someone" + ("C-c" "Cc" git-commit-cc) + ("C-r" "Reported" git-commit-reported) + ("C-i" "Suggested" git-commit-suggested) + ("C-a" "Co-authored" git-commit-co-authored) + ("C-d" "Co-developed" git-commit-co-developed)]]) + +(defun git-commit-ack (name mail) + "Insert a trailer acknowledging that you have looked at the commit." + (interactive (git-commit-get-ident "Acked-by")) + (git-commit--insert-ident-trailer "Acked-by" name mail)) + +(defun git-commit-modified (name mail) + "Insert a trailer to signal that you have modified the commit." + (interactive (git-commit-get-ident "Modified-by")) + (git-commit--insert-ident-trailer "Modified-by" name mail)) + +(defun git-commit-review (name mail) + "Insert a trailer acknowledging that you have reviewed the commit. +With a prefix argument, prompt for another person who performed a +review." + (interactive (git-commit-get-ident "Reviewed-by")) + (git-commit--insert-ident-trailer "Reviewed-by" name mail)) + +(defun git-commit-signoff (name mail) + "Insert a trailer to sign off the commit. +With a prefix argument, prompt for another person who signed off." + (interactive (git-commit-get-ident "Signed-off-by")) + (git-commit--insert-ident-trailer "Signed-off-by" name mail)) + +(defun git-commit-test (name mail) + "Insert a trailer acknowledging that you have tested the commit. +With a prefix argument, prompt for another person who tested." + (interactive (git-commit-get-ident "Tested-by")) + (git-commit--insert-ident-trailer "Tested-by" name mail)) + +(defun git-commit-cc (name mail) + "Insert a trailer mentioning someone who might be interested." + (interactive (git-commit-read-ident "Cc")) + (git-commit--insert-ident-trailer "Cc" name mail)) + +(defun git-commit-reported (name mail) + "Insert a trailer mentioning the person who reported the issue." + (interactive (git-commit-read-ident "Reported-by")) + (git-commit--insert-ident-trailer "Reported-by" name mail)) + +(defun git-commit-suggested (name mail) + "Insert a trailer mentioning the person who suggested the change." + (interactive (git-commit-read-ident "Suggested-by")) + (git-commit--insert-ident-trailer "Suggested-by" name mail)) + +(defun git-commit-co-authored (name mail) + "Insert a trailer mentioning the person who co-authored the commit." + (interactive (git-commit-read-ident "Co-authored-by")) + (git-commit--insert-ident-trailer "Co-authored-by" name mail)) + +(defun git-commit-co-developed (name mail) + "Insert a trailer mentioning the person who co-developed the commit." + (interactive (git-commit-read-ident "Co-developed-by")) + (git-commit--insert-ident-trailer "Co-developed-by" name mail)) + +(defun git-commit-get-ident (&optional prompt) + "Return name and email of the user or read another name and email. +If PROMPT and `current-prefix-arg' are both non-nil, read name +and email using `git-commit-read-ident' (which see), otherwise +return name and email of the current user (you)." + (if (and prompt current-prefix-arg) + (git-commit-read-ident prompt) + (list (or (getenv "GIT_AUTHOR_NAME") + (getenv "GIT_COMMITTER_NAME") + (with-demoted-errors "Error running 'git config user.name': %S" + (magit-get "user.name")) + user-full-name + (read-string "Name: ")) + (or (getenv "GIT_AUTHOR_EMAIL") + (getenv "GIT_COMMITTER_EMAIL") + (getenv "EMAIL") + (with-demoted-errors "Error running 'git config user.email': %S" + (magit-get "user.email")) + (read-string "Email: "))))) + +(defalias 'git-commit-self-ident #'git-commit-get-ident) + +(defvar git-commit-read-ident-history nil) + +(defun git-commit-read-ident (prompt) + "Read a name and email, prompting with PROMPT, and return them. +Read them using a single prompt, offering past commit authors as +completion candidates. The input must have the form \"NAME \"." + (let ((str (magit-completing-read + prompt + (sort (delete-dups + (magit-git-lines "log" "-n9999" "--format=%aN <%ae>")) + #'string<) + nil 'any nil 'git-commit-read-ident-history))) + (save-match-data + (if (string-match "\\`\\([^<]+\\) *<\\([^>]+\\)>\\'" str) + (list (save-match-data (string-trim (match-str 1 str))) + (string-trim (match-str 2 str))) + (user-error "Invalid input"))))) + +(defun git-commit--insert-ident-trailer (trailer name email) + (git-commit--insert-trailer trailer (format "%s <%s>" name email))) + +(defun git-commit--insert-trailer (trailer value) + (save-excursion + (let ((string (format "%s: %s" trailer value)) + (leading-comment-end nil)) + ;; Make sure we skip forward past any leading comments. + (goto-char (point-min)) + (while (looking-at comment-start) + (forward-line)) + (setq leading-comment-end (point)) + (goto-char (point-max)) + (cond + ;; Look backwards for existing trailers. + ((re-search-backward (git-commit--trailer-regexp) nil t) + (end-of-line) + (insert ?\n string) + (unless (= (char-after) ?\n) + (insert ?\n))) + ;; Or place the new trailer right before the first non-leading + ;; comments. + (t + (while (re-search-backward (concat "^" comment-start) + leading-comment-end t)) + (unless (looking-back "\n\n" nil) + (insert ?\n)) + (insert string ?\n)))) + (unless (or (eobp) (= (char-after) ?\n)) + (insert ?\n)))) + +;;; Font-Lock + +(defvar-local git-commit-need-summary-line t + "Whether the text should have a heading that is separated from the body. + +For commit messages that is a convention that should not +be violated. For notes it is up to the user. If you do +not want to insist on an empty second line here, then use +something like: + + (add-hook \\='git-commit-setup-hook + (lambda () + (when (equal (file-name-nondirectory (buffer-file-name)) + \"NOTES_EDITMSG\") + (setq git-commit-need-summary-line nil))))") + +(defun git-commit--trailer-regexp () + (format + "^\\(?:\\(%s:\\)\\( .*\\)\\|\\([-a-zA-Z]+\\): \\([^<\n]+? <[^>\n]+>\\)\\)" + (regexp-opt git-commit-trailers))) + +(defun git-commit-summary-regexp () + (if git-commit-need-summary-line + (concat + ;; Leading empty lines and comments + (format "\\`\\(?:^\\(?:\\s-*\\|%s.*\\)\n\\)*" comment-start) + ;; Summary line + (format "\\(.\\{0,%d\\}\\)\\(.*\\)" git-commit-summary-max-length) + ;; Non-empty non-comment second line + (format "\\(?:\n%s\\|\n\\(.+\\)\\)?" comment-start)) + "\\(EASTER\\) \\(EGG\\)")) + +(defun git-commit-extend-region-summary-line () + "Identify the multiline summary-regexp construct. +Added to `font-lock-extend-region-functions'." + (save-excursion + (save-match-data + (goto-char (point-min)) + (when (looking-at (git-commit-summary-regexp)) + (let ((summary-beg (match-beginning 0)) + (summary-end (match-end 0))) + (when (or (< summary-beg font-lock-beg summary-end) + (< summary-beg font-lock-end summary-end)) + (setq font-lock-beg (min font-lock-beg summary-beg)) + (setq font-lock-end (max font-lock-end summary-end)))))))) + +(defvar-local git-commit--branch-name-regexp nil) + +(defconst git-commit-comment-headings + '("Changes to be committed:" + "Untracked files:" + "Changed but not updated:" + "Changes not staged for commit:" + "Unmerged paths:" + "Author:" + "Date:") + "Also fontified outside of comments in `git-commit-font-lock-keywords-2'.") + +(defconst git-commit-font-lock-keywords-1 + '(;; Trailers + (eval . `(,(git-commit--trailer-regexp) + (1 'git-commit-trailer-token nil t) + (2 'git-commit-trailer-value nil t) + (3 'git-commit-trailer-token nil t) + (4 'git-commit-trailer-value nil t))) + ;; Summary + (eval . `(,(git-commit-summary-regexp) + (1 'git-commit-summary))) + ;; - Keyword [aka "text in brackets"] (overrides summary) + ("\\[[^][]+?\\]" + (0 'git-commit-keyword t)) + ;; - Non-empty second line (overrides summary and note) + (eval . `(,(git-commit-summary-regexp) + (2 'git-commit-overlong-summary t t) + (3 'git-commit-nonempty-second-line t t))))) + +(defconst git-commit-font-lock-keywords-2 + `(,@git-commit-font-lock-keywords-1 + ;; Comments + (eval . `(,(format "^%s.*" comment-start) + (0 'font-lock-comment-face append))) + (eval . `(,(format "^%s On branch \\(.*\\)" comment-start) + (1 'git-commit-comment-branch-local t))) + (eval . `(,(format "^%s \\(HEAD\\) detached at" comment-start) + (1 'git-commit-comment-detached t))) + (eval . `(,(format "^%s %s" comment-start + (regexp-opt git-commit-comment-headings t)) + (1 'git-commit-comment-heading t))) + (eval . `(,(format "^%s\t\\(?:\\([^:\n]+\\):\\s-+\\)?\\(.*\\)" comment-start) + (1 'git-commit-comment-action t t) + (2 'git-commit-comment-file t))) + ;; "commit HASH" + (eval . '("^commit [[:alnum:]]+$" + (0 'git-commit-trailer-value))) + ;; `git-commit-comment-headings' (but not in commented lines) + (eval . `(,(format "\\(?:^%s[[:blank:]]+.+$\\)" + (regexp-opt git-commit-comment-headings)) + (0 'git-commit-trailer-value))))) + +(defconst git-commit-font-lock-keywords-3 + `(,@git-commit-font-lock-keywords-2 + ;; More comments + (eval + ;; Your branch is ahead of 'master' by 3 commits. + ;; Your branch is behind 'master' by 2 commits, and can be fast-forwarded. + . `(,(format + "^%s Your branch is \\(?:ahead\\|behind\\) of '%s' by \\([0-9]*\\)" + comment-start git-commit--branch-name-regexp) + (1 'git-commit-comment-branch-local t) + (2 'git-commit-comment-branch-remote t) + (3 'bold t))) + (eval + ;; Your branch is up to date with 'master'. + ;; Your branch and 'master' have diverged, + . `(,(format + "^%s Your branch \\(?:is up[- ]to[- ]date with\\|and\\) '%s'" + comment-start git-commit--branch-name-regexp) + (1 'git-commit-comment-branch-local t) + (2 'git-commit-comment-branch-remote t))) + (eval + ;; and have 1 and 2 different commits each, respectively. + . `(,(format + "^%s and have \\([0-9]*\\) and \\([0-9]*\\) commits each" + comment-start) + (1 'bold t) + (2 'bold t))))) + +(defvar git-commit-font-lock-keywords git-commit-font-lock-keywords-3 + "Font-Lock keywords for Git-Commit mode.") + +(defun git-commit-setup-font-lock () + (with-demoted-errors "Error running git-commit-setup-font-lock: %S" + (let ((table (make-syntax-table (syntax-table)))) + (when comment-start + (modify-syntax-entry (string-to-char comment-start) "." table)) + (modify-syntax-entry ?# "." table) + (modify-syntax-entry ?\" "." table) + (modify-syntax-entry ?\' "." table) + (modify-syntax-entry ?` "." table) + (set-syntax-table table)) + (setq-local comment-start (or (magit-get "core.commentchar") "#")) + (setq-local comment-start-skip (format "^%s+[\s\t]*" comment-start)) + (setq-local comment-end "") + (setq-local comment-end-skip "\n") + (setq-local comment-use-syntax nil) + (when (and (derived-mode-p 'markdown-mode) + (fboundp 'markdown-fill-paragraph)) + (setq-local fill-paragraph-function + (lambda (&optional justify) + (and (not (= (char-after (line-beginning-position)) + (aref comment-start 0))) + (markdown-fill-paragraph justify))))) + (setq-local git-commit--branch-name-regexp + ;; When using cygwin git, we may end up in a + ;; non-existing directory, which would cause + ;; any git calls to signal an error. + (if (file-accessible-directory-p default-directory) + ;; Font-Lock wants every submatch to succeed, so + ;; also match the empty string. Avoid listing + ;; remote branches and using `regexp-quote', + ;; because in repositories that have thousands of + ;; branches that would be very slow. See #4353. + (format "\\(\\(?:%s\\)\\|\\)\\([^']+\\)" + (string-join (magit-list-local-branch-names) "\\|")) + "\\([^']*\\)")) + (setq-local font-lock-multiline t) + (add-hook 'font-lock-extend-region-functions + #'git-commit-extend-region-summary-line + t t) + (font-lock-add-keywords nil git-commit-font-lock-keywords))) + +(defun git-commit-propertize-diff () + (require 'diff-mode) + (save-excursion + (goto-char (point-min)) + (when (re-search-forward "^diff --git" nil t) + (beginning-of-line) + (let ((buffer (current-buffer))) + (insert + (with-temp-buffer + (insert + (with-current-buffer buffer + (prog1 (buffer-substring-no-properties (point) (point-max)) + (delete-region (point) (point-max))))) + (let ((diff-default-read-only nil)) + (diff-mode)) + (let ((font-lock-verbose nil) + (font-lock-support-mode nil)) + (font-lock-ensure)) + (let ((pos (point-min))) + (while-let ((next (next-single-property-change pos 'face))) + (put-text-property pos next 'font-lock-face + (get-text-property pos 'face)) + (setq pos next)) + (put-text-property pos (point-max) 'font-lock-face + (get-text-property pos 'face))) + (buffer-string))))))) + +;;; Elisp Text Mode + +(define-derived-mode git-commit-elisp-text-mode text-mode "ElText" + "Major mode for editing commit messages of elisp projects. +This is intended for use as `git-commit-major-mode' for projects +that expect `symbols' to look like this. I.e., like they look in +Elisp doc-strings, including this one. Unlike in doc-strings, +\"strings\" also look different than the other text." + (setq font-lock-defaults '(git-commit-elisp-text-mode-keywords))) + +(defvar git-commit-elisp-text-mode-keywords + `((,(concat "[`‘]\\(" lisp-mode-symbol-regexp "\\)['’]") + (1 font-lock-constant-face prepend)) + ("\"[^\"]*\"" (0 font-lock-string-face prepend)))) + +;;; _ + +(define-obsolete-function-alias + 'git-commit-insert-pseudo-header + 'git-commit-insert-trailer + "git-commit 4.0.0") +(define-obsolete-function-alias + 'git-commit-insert-header + 'git-commit--insert-ident-trailer + "git-commit 4.0.0") +(define-obsolete-face-alias + 'git-commit-pseudo-header + 'git-commit-trailer-value + "git-commit 4.0.0") +(define-obsolete-face-alias + 'git-commit-known-pseudo-header + 'git-commit-trailer-token + "git-commit 4.0.0") + +(provide 'git-commit) +;; Local Variables: +;; read-symbol-shorthands: ( +;; ("and$" . "cond-let--and$") +;; ("and>" . "cond-let--and>") +;; ("and-let" . "cond-let--and-let") +;; ("if-let" . "cond-let--if-let") +;; ("when-let" . "cond-let--when-let") +;; ("while-let" . "cond-let--while-let") +;; ("match-string" . "match-string") +;; ("match-str" . "match-string-no-properties")) +;; End: +;;; git-commit.el ends here diff --git a/elpa/magit-20251103.1130/git-rebase.el b/elpa/magit-20251103.1130/git-rebase.el new file mode 100644 index 00000000..614887f0 --- /dev/null +++ b/elpa/magit-20251103.1130/git-rebase.el @@ -0,0 +1,956 @@ +;;; git-rebase.el --- Edit Git rebase files -*- lexical-binding:t -*- + +;; Copyright (C) 2008-2025 The Magit Project Contributors + +;; Author: Phil Jackson +;; 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 of the License, 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 . + +;;; 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. +;; +;; d Drop the commit at point. +;; c Keep 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. +;; k Un-/comment current line. +;; 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-keymap git-rebase-mode-map + :doc "Keymap for Git-Rebase mode." + :parent special-mode-map + "C-m" #'git-rebase-show-commit + "p" #'git-rebase-backward-line + "n" #'forward-line + "M-p" #'git-rebase-move-line-up + "M-n" #'git-rebase-move-line-down + "c" #'git-rebase-pick + "d" #'git-rebase-drop + "k" #'git-rebase-kill-line + "C-k" #'git-rebase-kill-line + "b" #'git-rebase-break + "e" #'git-rebase-edit + "l" #'git-rebase-label + "M M" #'git-rebase-merge + "M t" #'git-rebase-merge-toggle-editmsg + "m" #'git-rebase-edit + "s" #'git-rebase-squash + "S" #'git-rebase-squish + "f" #'git-rebase-fixup + "F" #'git-rebase-alter + "A" #'git-rebase-alter + "q" #'undefined + "r" #'git-rebase-reword + "w" #'git-rebase-reword + "t" #'git-rebase-reset + "u" #'git-rebase-update-ref + "x" #'git-rebase-exec + "y" #'git-rebase-insert + "z" #'git-rebase-noop + "SPC" #'git-rebase-show-or-scroll-up + "DEL" #'git-rebase-show-or-scroll-down + "C-x C-t" #'git-rebase-move-line-up + "M-" #'git-rebase-move-line-up + "M-" #'git-rebase-move-line-down + " " #'git-rebase-undo) +(put 'git-rebase-alter :advertised-binding (kbd "F")) +(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] + ["Drop" git-rebase-drop 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-drop . "drop the commit at point") + (git-rebase-kill-line . "un-/comment current line") + (git-rebase-insert . "insert a line for an arbitrary commit") + (git-rebase-noop . "add noop action at point"))) + +(defvar git-rebase-fixup-descriptions + '((git-rebase-squish + . "fixup -c = use commit, but meld into previous commit,\n#\ + dropping previous commit's message, and open the editor") + (git-rebase-fixup + . "fixup = use commit, but meld into previous commit,\n#\ + dropping 's message") + (git-rebase-alter + . "fixup -C = use commit, but meld into previous commit,\n#\ + dropping previous commit's message"))) + +;;; 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-drop () + "Drop commit on current line. +If the region is active, act on all lines touched by the region." + (interactive) + (git-rebase-set-action "drop")) + +(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 () + "Fold commit on current line into previous commit, edit combined message. +If the region is active, act on all lines touched by the region." + (interactive) + (git-rebase-set-action "squash")) + +(defun git-rebase-squish () + "Fold current into previous commit, discard previous message and edit current. +This is like `git-rebase-squash', except that the other message is kept. +The action indicatore shown in the list commits is \"fixup -c\". If the +region is active, act on all lines touched by the region." + (interactive) + (git-rebase-set-action "fixup -c")) + +(defun git-rebase-fixup () + "Fold commit on current line into previous commit, discard current message. +If the region is active, act on all lines touched by the region." + (interactive) + (git-rebase-set-action "fixup")) + +(defun git-rebase-alter () + "Meld current into previous commit, discard previous message and use current. +This is like `git-rebase-fixup', except that the other message is kept. +The action indicatore shown in the list commits is \"fixup -C\". If the +region is active, act on all lines touched by the region." + (interactive) + (git-rebase-set-action "fixup -C")) + +(defvar-local git-rebase-comment-re nil) + +(defvar git-rebase-short-options + '((?b . "break") + (?d . "drop") + (?e . "edit") + (?f . "fixup") + (?l . "label") + (?m . "merge") + (?p . "pick") + (?r . "reword") + (?s . "squash") + (?t . "reset") + (?u . "update-ref") + (?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) + (abbrev))) + +(defvar git-rebase-line-regexps + ;; 1: action, 2: option, 3: target, 4: "#", 5: description. + ;; + ;; [[# ] ] + ;; fixup [-C|-c] [[# ] ] + `((commit . ,(concat + (regexp-opt '("d" "drop" + "e" "edit" + "f" "fixup" + "f -C" "fixup -C" + "f -c" "fixup -c" + "p" "pick" + "r" "reword" + "s" "squash") + "\\(?1:") + " \\(?3:[^ \n]+\\)" + "\\(?: \\(?4:# \\)?\\(?5:.*\\)\\)?")) + (exec . "\\(?1:x\\|exec\\) \\(?3:.*\\)") + (bare . ,(concat (regexp-opt '("b" "break" "noop") "\\(?1:") + " *$")) + (label . ,(concat (regexp-opt '("l" "label" + "t" "reset" + "u" "update-ref") + "\\(?1:") + " \\(?3:[^ \n]+\\)" + "\\(?: \\(?4:# \\)?\\(?5:.*\\)\\)?")) + ;; merge [-C | -c ]