+++ /dev/null
-Authors
-=======
-
-The following people have contributed to Magit, including the
-libraries `git-commit.el`, `magit-popup.el`, and `with-editor.el`
-which are distributed as separate Elpa packages.
-
-For statistics see https://magit.vc/stats/authors.html.
-
-Names below are sorted alphabetically.
-
-Author
-------
-
-- Marius Vollmer <marius.vollmerNOSPAMgmail.com>
-
-Maintainer
-----------
-
-- Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-Developers
-----------
-
-- Kyle Meyer <kyleNOSPAMkyleam.com>
-- Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
-
-Retired Maintainers and Developers
-----------------------------------
-
-- Nicolas Dudebout <nicolas.dudeboutNOSPAMgatech.edu>
-- Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
-- Pieter Praet <pieterNOSPAMpraet.org>
-- Phil Jackson <philNOSPAMshellarchive.co.uk>
-- Rémi Vanicat <vanicatNOSPAMdebian.org>
-- Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-
-Contributors
-------------
-
-- Aaron Culich <aculichNOSPAMgmail.com>
-- Aaron Madlon-Kay <aaronNOSPAMmadlon-kay.com>
-- Abdo Roig-Maranges <abdo.roigNOSPAMgmail.com>
-- Adam Benanti <0entropyNOSPAMprotonmail.com>
-- Adam Kruszewski <adamNOSPAMkruszewski.name>
-- Adam Porter <adamNOSPAMalphapapa.net>
-- Adam Spiers <emacsNOSPAMadamspiers.org>
-- Adeodato Simó <datoNOSPAMnet.com.org.es>
-- Ævar Arnfjörð Bjarmason <avarabNOSPAMgmail.com>
-- Alan Falloon <alan.falloonNOSPAMgmail.com>
-- Alban Gruin <albanNOSPAMpa1ch.fr>
-- Aleksey Uimanov <s9gf4ultNOSPAMgmail.com>
-- Alexander Gramiak <fice-tNOSPAMprotonmail.com>
-- Alexander Miller <alexandermNOSPAMweb.de>
-- Alex Branham <alex.branhamNOSPAMgmail.com>
-- Alex Dunn <adunnNOSPAMucsb.edu>
-- Alexey Voinov <alexey.v.voinovNOSPAMgmail.com>
-- Alex Kost <alezostNOSPAMgmail.com>
-- Alex Ott <alexottNOSPAMgmail.com>
-- Allen <darkfelineNOSPAMfelesatra.moe>
-- Allen Li <darkfelineNOSPAMfelesatra.moe>
-- Andreas Fuchs <asfNOSPAMboinkor.net>
-- Andreas Liljeqvist <andreas.liljeqvistNOSPAMrobacks.se>
-- Andreas Rottmann <a.rottmannNOSPAMgmx.at>
-- Andrei Chițu <andrei.chitu1NOSPAMgmail.com>
-- Andrew Eggenberger <andrew.eggenbergerNOSPAMgmail.com>
-- Andrew Kirkpatrick <andrew.kirkpatrickNOSPAMadelaide.edu.au>
-- Andrew Schwartzmeyer <andrewNOSPAMschwartzmeyer.com>
-- Andrey Smirnov <andrew.smirnovNOSPAMgmail.com>
-- Andriy Kmit' <devNOSPAMmadand.net>
-- Andy Sawyer <gitNOSPAMpureabstract.org>
-- Aria Edmonds <ariaNOSPAMar1as.space>
-- Arialdo Martini <arialdomartiniNOSPAMgmail.com>
-- Arnau Roig Ninerola <arnau.ninerolaNOSPAMoutlook.com>
-- Barak A. Pearlmutter <barak+gitNOSPAMpearlmutter.net>
-- Bar Magal <bmagambNOSPAMgmail.com>
-- Bart Bakker <bartNOSPAMthesoftwarecraft.com>
-- Basil L. Contovounesios <contovobNOSPAMtcd.ie>
-- Bastian Beischer <beischerNOSPAMphysik.rwth-aachen.de>
-- Benjamin Motz <benjamin.motzNOSPAMmailbox.org>
-- Ben North <benNOSPAMredfrontdoor.org>
-- Ben Walton <bwaltonNOSPAMartsci.utoronto.ca>
-- Bob Uhl <buhlNOSPAMzvelo.com>
-- Bradley Wright <bradNOSPAMintranation.com>
-- Brandon W Maister <quodlibetorNOSPAMgmail.com>
-- Brian Leung <leungbkNOSPAMmailfence.com>
-- Brian Warner <warnerNOSPAMlothar.com>
-- Bryan Shell <bryan.shellNOSPAMorbitz.com>
-- Buster Copley <busterNOSPAMbuster.me.uk>
-- Carl Lieberman <liebermancarlNOSPAMgmail.com>
-- Chillar Anand <anand21nandaNOSPAMgmail.com>
-- Chris Bernard <cebernardNOSPAMgmail.com>
-- Chris Done <chrisdoneNOSPAMgmail.com>
-- Chris LaRose <cjlaroseNOSPAMgmail.com>
-- Chris Moore <dooglusNOSPAMgmail.com>
-- Chris Ring <chrisNOSPAMringthis.com>
-- Chris Shoemaker <chrisNOSPAMmojotech.com>
-- Christian Dietrich <christian.dietrichNOSPAMinformatik.uni-erlangen.de>
-- Christian Kluge <ckfrakturfreakNOSPAMweb.de>
-- Christophe Junke <junke.christopheNOSPAMgmail.com>
-- Christopher Monsanto <chrisNOSPAMmonsan.to>
-- Clément Pit-Claudel <clement.pitclaudelNOSPAMlive.com>
-- Cornelius Mika <cornelius.mikaNOSPAMgmail.com>
-- Craig Andera <canderaNOSPAMwangdera.com>
-- Dale Hagglund <dale.hagglundNOSPAMgmail.com>
-- Damien Cassou <damienNOSPAMcassou.me>
-- Dan Davison <dandavison7NOSPAMgmail.com>
-- Dan Erikson <derikson3NOSPAMgmail.com>
-- Daniel Brockman <danielNOSPAMgointeractive.se>
-- Daniel Farina <drfarinaNOSPAMacm.org>
-- Daniel Gröber <danielNOSPAMdps.uibk.ac.at>
-- Daniel Hackney <danNOSPAMhaxney.org>
-- Daniel Kraus <danielNOSPAMkraus.my>
-- Daniel Mai <danielNOSPAMdanielmai.net>
-- Daniel MartÃn <mardani29NOSPAMyahoo.es>
-- Dan LaManna <dan.lamannaNOSPAMgmail.com>
-- Danny Zhu <dzhuNOSPAMdzhu.us>
-- Dato Simó <datoNOSPAMnet.com.org.es>
-- David Abrahams <daveNOSPAMboostpro.com>
-- David Ellison <davidehellisonNOSPAMgmail.com>
-- David Ellison <davideNOSPAMvoicebox.com>
-- David Hull <david.hullNOSPAMopenx.com>
-- David L. Rager <ragerdlNOSPAMgmail.com>
-- David Wallin <david.wallinNOSPAMgmail.com>
-- Dean Kariniemi <8913263+d3k4rNOSPAMusers.noreply.github.com>
-- Dennis Paskorz <dennisNOSPAMwalltowall.com>
-- Divye Kapoor <divyeNOSPAMgoogle.com>
-- Dominique Quatravaux <dominique.quatravauxNOSPAMepfl.ch>
-- Dominique Quatravaux <domqNOSPAMgoogle.com>
-- Duianto Vebotci <vebotciNOSPAMopenmailbox.org>
-- Eli Barzilay <eliNOSPAMbarzilay.org>
-- Eric Davis <edNOSPAMnpri.org>
-- Eric <e.a.gebhartNOSPAMgmail.com>
-- Eric Prud'hommeaux <ericNOSPAMw3.org>
-- Eric Schulte <schulte.ericNOSPAMgmail.com>
-- Erik Anderson <erikbpandersonNOSPAMgmail.com>
-- Evan Torrie <etorrieNOSPAMgmail.com>
-- Evgkeni Sampelnikof <esabofNOSPAMgmail.com>
-- Eyal Lotem <eyal.lotemNOSPAMgmail.com>
-- Fabian Wiget <fabacinoNOSPAMgmail.com>
-- Felix Geller <fgellerNOSPAMgmail.com>
-- Felix Yan <felixonmarsNOSPAMarchlinux.org>
-- Feng Li <fengliNOSPAMblackmagicdesign.com>
-- Florian Ragwitz <raflNOSPAMdebian.org>
-- Fritz Grabo <fritz.graboNOSPAMgmail.com>
-- Fritz Stelzer <brotzeitmacherNOSPAMgmail.com>
-- Geoff Shannon <geoffpshannonNOSPAMgmail.com>
-- George Kadianakis <desnackedNOSPAMgmail.com>
-- Graham Clark <grclarkNOSPAMgmail.com>
-- Graham Dobbins <gdobbinsNOSPAMprotonmail.com>
-- Greg A. Woods <woodsNOSPAMplanix.com>
-- Greg Lucas <gregNOSPAMglucas.net>
-- Gregory Heytings <gheNOSPAMsdf.org>
-- Greg Sexton <gregsextonNOSPAMgmail.com>
-- Guillaume Martres <smarterNOSPAMubuntu.com>
-- Hannu Koivisto <azureNOSPAMiki.fi>
-- Hans-Peter Deifel <hpdeifelNOSPAMgmx.de>
-- Hussein Ait-Lahcen <hussein.ait-lahcen@fretlink.com>
-- Ian Eure <ian.eureNOSPAMgmail.com>
-- Ian Milligan <ianmllgnNOSPAMgmail.com>
-- Ingo Lohmar <i.lohmarNOSPAMgmail.com>
-- Ioan-Adrian Ratiu <adiNOSPAMadirat.com>
-- Ivan Brennan <ivan.brennanNOSPAMgmail.com>
-- Jan Tatarik <jan.tatarikNOSPAMxing.com>
-- Jasper St. Pierre <jstpierreNOSPAMmecheye.net>
-- Jeff Bellegarde <jbellegardeNOSPAMwhitepages.com>
-- Jeff Dairiki <dairikiNOSPAMdairiki.org>
-- Jeremy Meng <yumengNOSPAMmicrosoft.com>
-- Jesse Alama <jesse.alamaNOSPAMgmail.com>
-- Jim Blandy <jimbNOSPAMred-bean.com>
-- Joakim Jalap <JOJANOSPAMstoneridge.com>
-- Johannes Altmanninger <aclopteNOSPAMgmail.com>
-- Johann Klähn <johannNOSPAMjklaehn.de>
-- John Mastro <john.b.mastroNOSPAMgmail.com>
-- John Morris <johnNOSPAMzultron.com>
-- John Wiegley <johnwNOSPAMnewartisans.com>
-- Jonas Bernoulli <jonasNOSPAMbernoul.li>
-- Jonas Galvão Xavier <jonas.agxNOSPAMgmail.com>
-- Jonathan Arnett <jonathanNOSPAMscriptdrop.co>
-- Jonathan del Strother <meNOSPAMdelstrother.com>
-- Jonathan Leech-Pepin <jonathan.leechpepinNOSPAMgmail.com>
-- Jonathan Roes <jroesNOSPAMjroes.net>
-- Jon Vanderwijk <jonathnNOSPAMgithub.com>
-- Jordan Galby <gravemind2aNOSPAMgmail.com>
-- Jordan Greenberg <jordanNOSPAMsoftwareslave.com>
-- Josh Elsasser <jelsasserNOSPAMappneta.com>
-- Josiah Schwab <jschwabNOSPAMgmail.com>
-- Julien Danjou <julienNOSPAMdanjou.info>
-- Justin Burkett <justinNOSPAMburkett.cc>
-- Justin Caratzas <justin.caratzasNOSPAMgmail.com>
-- Justin Guenther <jguentherNOSPAMgmail.com>
-- Justin Thomas <justin.thomas1NOSPAMgmail.com>
-- Kan-Ru Chen <kanruNOSPAMkanru.info>
-- Kenny Ballou <kballouNOSPAMdevnulllabs.io>
-- Keshav Kini <keshav.kiniNOSPAMgmail.com>
-- Kevin Brubeck Unhammer <unhammerNOSPAMfsfe.org>
-- Kevin J. Foley <kfoley15NOSPAMgmail.com>
-- Kévin Le Gouguec <kevin.legouguecNOSPAMgmail.com>
-- Kimberly Wolk <kimwolkNOSPAMhotmail.com>
-- Knut Olav Bøhmer <bohmerNOSPAMgmail.com>
-- Kyle Meyer <kyleNOSPAMkyleam.com>
-- Laurent Laffont <laurent.laffontNOSPAMgmail.com>
-- Laverne Schrock <laverneNOSPAMschrock.email>
-- Leandro Facchinetti <meNOSPAMleafac.com>
-- Lele Gaifax <leleNOSPAMmetapensiero.it>
-- Leo Liu <sdl.webNOSPAMgmail.com>
-- Leonardo Etcheverry <leoNOSPAMkalio.net>
-- Leo Vivier <leo.vivier+devNOSPAMgmail.com>
-- Lingchao Xin <douglarekNOSPAMusers.noreply.github.com>
-- Li-Yun Chang <michael142536NOSPAMgmail.com>
-- LluÃs Vilanova <vilanovaNOSPAMac.upc.edu>
-- Loic Dachary <loicNOSPAMdachary.org>
-- Louis Roché <louisNOSPAMlouisroche.net>
-- LuÃs Oliveira <luismboNOSPAMgmail.com>
-- Luke Amdor <luke.amdorNOSPAMgmail.com>
-- Magnus Malm <magnusmalmNOSPAMgmail.com>
-- Mak Kolybabi <makNOSPAMkolybabi.com>
-- Manuel Vázquez Acosta <mva.ledNOSPAMgmail.com>
-- Marcel Wolf <mwolfNOSPAMml1.net>
-- Marc Herbert <marc.herbertNOSPAMgmail.com>
-- Marcin Bachry <hegel666NOSPAMgmail.com>
-- Marco Craveiro <marco.craveiroNOSPAMgmail.com>
-- Marco Wahl <marcowahlsoftNOSPAMgmail.com>
-- Marc Sherry <msherryNOSPAMgmail.com>
-- Marian Schubert <marian.schubertNOSPAMgmail.com>
-- Mario Rodas <marsamNOSPAMusers.noreply.github.com>
-- Marius Vollmer <marius.vollmerNOSPAMgmail.com>
-- Mark Hepburn <Mark.HepburnNOSPAMcsiro.au>
-- Mark Karpov <markkarpovNOSPAMopmbx.org>
-- Mark Oteiza <mvoteizaNOSPAMudel.edu>
-- Matthew Fluet <matthew.fluetNOSPAMgmail.com>
-- Matthieu Hauglustaine <matt.hauglustaineNOSPAMgmail.com>
-- Matus Goljer <dota.keysNOSPAMgmail.com>
-- Maxim Cournoyer <maxim.cournoyerNOSPAMgmail.com>
-- Michael Fogleman <michaelwfoglemanNOSPAMgmail.com>
-- Michael Griffiths <mikeyNOSPAMcich.li>
-- Michael Heerdegen <michael_heerdegenNOSPAMweb.de>
-- Michal Sojka <sojkam1NOSPAMfel.cvut.cz>
-- Miciah Masters <miciah.mastersNOSPAMgmail.com>
-- Miles Bader <milesNOSPAMgnu.org>
-- Miloš Mošić <mosic.milosNOSPAMgmail.com>
-- Mitchel Humpherys <mitch.specialNOSPAMgmail.com>
-- Moritz Bunkus <moritzNOSPAMbunkus.org>
-- Naoya Yamashita <conao3NOSPAMgmail.com>
-- Natalie Weizenbaum <nex342NOSPAMgmail.com>
-- Nguyễn Tuấn Anh <ubolontonNOSPAMgmail.com>
-- Nic Ferier <nicNOSPAMferrier.me.uk>
-- Nick Alcock <nick.alcockNOSPAMoracle.com>
-- Nick Alexander <nalexanderNOSPAMmozilla.com>
-- Nick Dimiduk <ndimidukNOSPAMgmail.com>
-- Nicklas Lindgren <niliNOSPAMgulmohar.se>
-- Nicolas Dudebout <nicolas.dudeboutNOSPAMgatech.edu>
-- Nicolas Petton <nicolasNOSPAMpetton.fr>
-- Nicolas Richard <theonewiththeevillookNOSPAMyahoo.fr>
-- Nikolay Martynov <mar.kolyaNOSPAMgmail.com>
-- Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
-- N. Troy de Freitas <meNOSPAMntdef.com>
-- Ole Arndt <oliver.arndtNOSPAMcegedim.com>
-- Oleh Krehel <ohwoeowhoNOSPAMgmail.com>
-- Orivej Desh <orivejNOSPAMgmx.fr>
-- Óscar Fuentes <ofvNOSPAMwanadoo.es>
-- Paul Stadig <paulNOSPAMstadig.name>
-- Pavel Holejsovsky <pavel.holejsovskyNOSPAMupek.com>
-- Pekka Pessi <nospamNOSPAMpessi.fi>
-- Peter Eisentraut <peterNOSPAMeisentraut.org>
-- Peter Jaros <peter.a.jarosNOSPAMgmail.com>
-- Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
-- Peter Vasil <mailNOSPAMpetervasil.net>
-- Philippe Vaucher <philippe.vaucherNOSPAMgmail.com>
-- Philipp Fehre <pfehreNOSPAMtwitter.com>
-- Philipp Haselwarter <philippNOSPAMhaselwarter.org>
-- Philipp Stephani <phstNOSPAMgoogle.com>
-- Philip Weaver <philip.weaverNOSPAMgmail.com>
-- Phil Jackson <philNOSPAMshellarchive.co.uk>
-- Phil Sainty <philNOSPAMcatalyst.net.nz>
-- Pierre Neidhardt <ambrevarNOSPAMgmail.com>
-- Pieter Praet <pieterNOSPAMpraet.org>
-- Prathamesh Sonpatki <csonpatkiNOSPAMgmail.com>
-- rabio <rabiodevNOSPAMo2.pl>
-- Radon Rosborough <radon.neonNOSPAMgmail.com>
-- Rafael Laboissiere <rafaelNOSPAMlaboissiere.net>
-- Raimon Grau <raimonNOSPAM3scale.net>
-- Ramkumar Ramachandra <artagnonNOSPAMgmail.com>
-- Remco van 't Veer <rwvtveerNOSPAMxs4all.nl>
-- Rémi Vanicat <vanicatNOSPAMdebian.org>
-- René Stadler <mailNOSPAMrenestadler.de>
-- Richard Kim <emacs18NOSPAMgmail.com>
-- Robert Boone <robo4288NOSPAMgmail.com>
-- Robin Green <greenrdNOSPAMgreenrd.org>
-- Roey Darwish Dror <roey.ghostNOSPAMgmail.com>
-- Roger Crew <crewNOSPAMcs.stanford.edu>
-- Romain Francoise <romainNOSPAMorebokech.com>
-- Ron Parker <rparkerNOSPAMa123systems.com>
-- Roy Crihfield <rscrihfNOSPAMgmail.com>
-- Rüdiger Sonderfeld <ruedigerNOSPAMc-plusplus.net>
-- Russell Black <black.russellNOSPAMgmail.com>
-- Ryan C. Thompson <rctNOSPAMthompsonclan.org>
-- Samuel Bronson <naestenNOSPAMgmail.com>
-- Samuel W. Flint <swflintNOSPAMflintfam.org>
-- Sanjoy Das <sanjoyNOSPAMplayingwithpointers.com>
-- Sean Allred <codeNOSPAMseanallred.com>
-- Sean Bryant <sbryantNOSPAMhackinggibsons.com>
-- Sean Whitton <spwhittonNOSPAMspwhitton.name>
-- Sebastian Wiesner <lunaryornNOSPAMgmail.com>
-- Sébastien Gross <sebNOSPAMchezwam.org>
-- Seong-Kook Shin <cinskyNOSPAMgmail.com>
-- Sergey Pashinin <sergeyNOSPAMpashinin.com>
-- Sergey Vinokurov <serg.fooNOSPAMgmail.com>
-- Servilio Afre Puentes <afrepuesNOSPAMmcmaster.ca>
-- Silent Sphere <silentsphere110NOSPAMgmail.com>
-- Simon Pintarelli <simon.pintarelliNOSPAMcscs.ch>
-- Štěpán Němec <stepnemNOSPAMgmail.com>
-- Steven Chow <steveNOSPAMmyfreestuffapp.com>
-- Steven E. Harris <sehNOSPAMpanix.com>
-- Steven Thomas <sthomas314NOSPAMgmail.com>
-- Steven Vancoillie <steven.vancoillieNOSPAMrunbox.com>
-- Steve Purcell <steveNOSPAMsanityinc.com>
-- Suhail Shergill <suhailshergillNOSPAMgmail.com>
-- Sylvain Rousseau <thisirsNOSPAMgmail.com>
-- Syohei Yoshida <syohexNOSPAMgmail.com>
-- Takafumi Arakaki <aka.tkfNOSPAMgmail.com>
-- Tassilo Horn <tsdhNOSPAMgnu.org>
-- Teemu Likonen <tlikonenNOSPAMiki.fi>
-- Teruki Shigitani <teruki.shigitaniNOSPAMgmail.com>
-- Thierry Volpiatto <thievolNOSPAMposteo.net>
-- Thomas A Caswell <tcaswellNOSPAMgmail.com>
-- Thomas Fini Hansen <xenNOSPAMxen.dk>
-- Thomas Frössman <thomasfNOSPAMjossystem.se>
-- Thomas Jost <thomas.jostNOSPAMgmail.com>
-- Thomas Riccardi <riccardi.thomasNOSPAMgmail.com>
-- Tibor Simko <tibor.simkoNOSPAMcern.ch>
-- Timo Juhani Lindfors <timo.lindforsNOSPAMiki.fi>
-- Tim Perkins <tprk77NOSPAMgmail.com>
-- Tim Wraight <timNOSPAMwraight.net>
-- Ting-Yu Lin <aethanycNOSPAMgmail.com>
-- Tom Feist <shabbleNOSPAMmetavore.org>
-- Topi Miettinen <toiwotonNOSPAMgmail.com>
-- Troy Hinckley <t.macmanNOSPAMgmail.com>
-- Tsuyoshi Kitamoto <tsuyoshi.kitamotoNOSPAMgmail.com>
-- Tunc Uzlu <bb2020NOSPAMusers.noreply.github.com>
-- Vineet Naik <vineetNOSPAMhelpshift.com>
-- Vitaly Ostashov <hotoshoNOSPAMyandex-team.ru>
-- Vladimir Panteleev <gitNOSPAMthecybershadow.net>
-- Vladimir Sedach <vasNOSPAMoneofus.la>
-- Wei Huang <weihNOSPAMopera.com>
-- Wilfred Hughes <meNOSPAMwilfred.me.uk>
-- Win Treese <treeseNOSPAMacm.org>
-- Wojciech Siewierski <wojciechNOSPAMsiewierski.eu>
-- Wouter Bolsterlee <wouterNOSPAMbolsterl.ee>
-- Xavier Noria <fxnNOSPAMhashref.com>
-- Xu Chunyang <mail@xuchunyang.me>
-- Yann Herklotz <gitNOSPAMyannherklotz.com>
-- Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-- Ynilu <ynilu.changNOSPAMgmail.com>
-- York Zhao <gtdplatformNOSPAMgmail.com>
-- Yuichi Higashi <aaa707bNOSPAMgmail.com>
-- Yuri Khan <yurivkhanNOSPAMgmail.com>
-- Zach Latta <zachNOSPAMzachlatta.com>
-- zakora <zakoraNOSPAMusers.noreply.github.com>
-- Zhu Zihao <all_but_lastNOSPAM163.com>
-- zilongshanren <guanghui8827NOSPAM126.com>
+++ /dev/null
-
- GNU GENERAL PUBLIC LICENSE
- Version 3, 29 June 2007
-
- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
- 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.
-
- <one line to give the program's name and a brief idea of what it does.>
- Copyright (C) <year> <name of author>
-
- 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 <http://www.gnu.org/licenses/>.
-
-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:
-
- <program> Copyright (C) <year> <name of author>
- 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
-<http://www.gnu.org/licenses/>.
-
- 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
-<http://www.gnu.org/philosophy/why-not-lgpl.html>.
-
+++ /dev/null
-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.
-\1f
-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<Return>" 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.
+++ /dev/null
-;;; git-rebase.el --- Edit Git rebase files -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Phil Jackson <philNOSPAMshellarchive.co.uk>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; This file is not part of GNU Emacs.
-
-;; This file is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-
-;; This file is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with this file. If not, see <http://www.gnu.org/licenses/>.
-
-;;; 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 'dash)
-(require 'easymenu)
-(require 'server)
-(require 'with-editor)
-(require 'magit)
-
-(and (require 'async-bytecomp nil t)
- (let ((pkgs (bound-and-true-p async-bytecomp-allowed-packages)))
- (if (consp pkgs)
- (cl-intersection '(all magit) pkgs)
- (memq pkgs '(all t))))
- (fboundp 'async-bytecomp-package-mode)
- (async-bytecomp-package-mode 1))
-
-(eval-when-compile (require 'recentf))
-
-;;; Options
-;;;; Variables
-
-(defgroup git-rebase nil
- "Edit Git rebase sequences."
- :link '(info-link "(magit)Editing Rebase Sequences")
- :group 'tools)
-
-(defcustom git-rebase-auto-advance t
- "Whether to move to next line after changing a line."
- :group 'git-rebase
- :type 'boolean)
-
-(defcustom git-rebase-show-instructions t
- "Whether to show usage instructions inside the rebase buffer."
- :group 'git-rebase
- :type 'boolean)
-
-(defcustom git-rebase-confirm-cancel t
- "Whether confirmation is required to cancel."
- :group 'git-rebase
- :type 'boolean)
-
-;;;; Faces
-
-(defgroup git-rebase-faces nil
- "Faces used by Git-Rebase mode."
- :group 'faces
- :group 'git-rebase)
-
-(defface git-rebase-hash '((t (:inherit magit-hash)))
- "Face for commit hashes."
- :group 'git-rebase-faces)
-
-(defface git-rebase-label '((t (:inherit magit-refname)))
- "Face for labels in label, merge, and reset lines."
- :group 'git-rebase-faces)
-
-(defface git-rebase-description nil
- "Face for commit descriptions."
- :group 'git-rebase-faces)
-
-(defface git-rebase-killed-action
- '((t (:inherit font-lock-comment-face :strike-through t)))
- "Face for commented commit action lines."
- :group 'git-rebase-faces)
-
-(defface git-rebase-comment-hash
- '((t (:inherit git-rebase-hash :weight bold)))
- "Face for commit hashes in commit message comments."
- :group 'git-rebase-faces)
-
-(defface git-rebase-comment-heading
- '((t :inherit font-lock-keyword-face))
- "Face for headings in rebase message comments."
- :group 'git-commit-faces)
-
-;;; Keymaps
-
-(defvar git-rebase-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map special-mode-map)
- (define-key map (kbd "C-m") 'git-rebase-show-commit)
- (define-key map (kbd "p") 'git-rebase-backward-line)
- (define-key map (kbd "n") 'forward-line)
- (define-key map (kbd "M-p") 'git-rebase-move-line-up)
- (define-key map (kbd "M-n") 'git-rebase-move-line-down)
- (define-key map (kbd "c") 'git-rebase-pick)
- (define-key map (kbd "k") 'git-rebase-kill-line)
- (define-key map (kbd "C-k") 'git-rebase-kill-line)
- (define-key map (kbd "b") 'git-rebase-break)
- (define-key map (kbd "e") 'git-rebase-edit)
- (define-key map (kbd "l") 'git-rebase-label)
- (define-key map (kbd "MM") 'git-rebase-merge)
- (define-key map (kbd "Mt") 'git-rebase-merge-toggle-editmsg)
- (define-key map (kbd "m") 'git-rebase-edit)
- (define-key map (kbd "f") 'git-rebase-fixup)
- (define-key map (kbd "q") 'undefined)
- (define-key map (kbd "r") 'git-rebase-reword)
- (define-key map (kbd "w") 'git-rebase-reword)
- (define-key map (kbd "s") 'git-rebase-squash)
- (define-key map (kbd "t") 'git-rebase-reset)
- (define-key map (kbd "x") 'git-rebase-exec)
- (define-key map (kbd "y") 'git-rebase-insert)
- (define-key map (kbd "z") 'git-rebase-noop)
- (define-key map (kbd "SPC") 'git-rebase-show-or-scroll-up)
- (define-key map (kbd "DEL") 'git-rebase-show-or-scroll-down)
- (define-key map (kbd "C-x C-t") 'git-rebase-move-line-up)
- (define-key map [M-up] 'git-rebase-move-line-up)
- (define-key map [M-down] 'git-rebase-move-line-down)
- (define-key map [remap undo] 'git-rebase-undo)
- map)
- "Keymap for Git-Rebase mode.")
-
-(put 'git-rebase-reword :advertised-binding (kbd "r"))
-(put 'git-rebase-move-line-up :advertised-binding (kbd "M-p"))
-(put 'git-rebase-kill-line :advertised-binding (kbd "k"))
-
-(easy-menu-define git-rebase-mode-menu git-rebase-mode-map
- "Git-Rebase mode menu"
- '("Rebase"
- ["Pick" git-rebase-pick t]
- ["Reword" git-rebase-reword t]
- ["Edit" git-rebase-edit t]
- ["Squash" git-rebase-squash t]
- ["Fixup" git-rebase-fixup t]
- ["Kill" git-rebase-kill-line t]
- ["Noop" git-rebase-noop t]
- ["Execute" git-rebase-exec t]
- ["Move Down" git-rebase-move-line-down t]
- ["Move Up" git-rebase-move-line-up t]
- "---"
- ["Cancel" with-editor-cancel t]
- ["Finish" with-editor-finish t]))
-
-(defvar git-rebase-command-descriptions
- '((with-editor-finish . "tell Git to make it happen")
- (with-editor-cancel . "tell Git that you changed your mind, i.e. abort")
- (git-rebase-backward-line . "move point to previous line")
- (forward-line . "move point to next line")
- (git-rebase-move-line-up . "move the commit at point up")
- (git-rebase-move-line-down . "move the commit at point down")
- (git-rebase-show-or-scroll-up . "show the commit at point in another buffer")
- (git-rebase-show-commit
- . "show the commit at point in another buffer and select its window")
- (undo . "undo last change")
- (git-rebase-kill-line . "drop the commit at point")
- (git-rebase-insert . "insert a line for an arbitrary commit")
- (git-rebase-noop . "add noop action at point")))
-
-;;; Commands
-
-(defun git-rebase-pick ()
- "Use commit on current line.
-If the region is active, act on all lines touched by the region."
- (interactive)
- (git-rebase-set-action "pick"))
-
-(defun git-rebase-reword ()
- "Edit message of commit on current line.
-If the region is active, act on all lines touched by the region."
- (interactive)
- (git-rebase-set-action "reword"))
-
-(defun git-rebase-edit ()
- "Stop at the commit on the current line.
-If the region is active, act on all lines touched by the region."
- (interactive)
- (git-rebase-set-action "edit"))
-
-(defun git-rebase-squash ()
- "Meld commit on current line into previous commit, edit message.
-If the region is active, act on all lines touched by the region."
- (interactive)
- (git-rebase-set-action "squash"))
-
-(defun git-rebase-fixup ()
- "Meld commit on current line into previous commit, discard its message.
-If the region is active, act on all lines touched by the region."
- (interactive)
- (git-rebase-set-action "fixup"))
-
-(defvar-local git-rebase-comment-re nil)
-
-(defvar git-rebase-short-options
- '((?b . "break")
- (?e . "edit")
- (?f . "fixup")
- (?l . "label")
- (?m . "merge")
- (?p . "pick")
- (?r . "reword")
- (?s . "squash")
- (?t . "reset")
- (?x . "exec"))
- "Alist mapping single key of an action to the full name.")
-
-(defclass git-rebase-action ()
- (;; action-type: commit, exec, bare, label, merge
- (action-type :initarg :action-type :initform nil)
- ;; Examples for each action type:
- ;; | action | action options | target | trailer |
- ;; |--------+----------------+---------+---------|
- ;; | pick | | hash | subject |
- ;; | exec | | command | |
- ;; | noop | | | |
- ;; | reset | | name | subject |
- ;; | merge | -C hash | name | subject |
- (action :initarg :action :initform nil)
- (action-options :initarg :action-options :initform nil)
- (target :initarg :target :initform nil)
- (trailer :initarg :trailer :initform nil)
- (comment-p :initarg :comment-p :initform nil)))
-
-(defvar git-rebase-line-regexps
- `((commit . ,(concat
- (regexp-opt '("e" "edit"
- "f" "fixup"
- "p" "pick"
- "r" "reword"
- "s" "squash")
- "\\(?1:")
- " \\(?3:[^ \n]+\\) ?\\(?4:.*\\)"))
- (exec . "\\(?1:x\\|exec\\) \\(?3:.*\\)")
- (bare . ,(concat (regexp-opt '("b" "break" "noop") "\\(?1:")
- " *$"))
- (label . ,(concat (regexp-opt '("l" "label"
- "t" "reset")
- "\\(?1:")
- " \\(?3:[^ \n]+\\) ?\\(?4:.*\\)"))
- (merge . ,(concat "\\(?1:m\\|merge\\) "
- "\\(?:\\(?2:-[cC] [^ \n]+\\) \\)?"
- "\\(?3:[^ \n]+\\)"
- " ?\\(?4:.*\\)"))))
-
-;;;###autoload
-(defun git-rebase-current-line ()
- "Parse current line into a `git-rebase-action' instance.
-If the current line isn't recognized as a rebase line, an
-instance with all nil values is returned."
- (save-excursion
- (goto-char (line-beginning-position))
- (if-let ((re-start (concat "^\\(?5:" (regexp-quote comment-start)
- "\\)? *"))
- (type (seq-some (lambda (arg)
- (let ((case-fold-search nil))
- (and (looking-at (concat re-start (cdr arg)))
- (car arg))))
- git-rebase-line-regexps)))
- (git-rebase-action
- :action-type type
- :action (when-let ((action (match-string-no-properties 1)))
- (or (cdr (assoc action git-rebase-short-options))
- action))
- :action-options (match-string-no-properties 2)
- :target (match-string-no-properties 3)
- :trailer (match-string-no-properties 4)
- :comment-p (and (match-string 5) t))
- ;; Use default empty class rather than nil to ease handling.
- (git-rebase-action))))
-
-(defun git-rebase-set-action (action)
- "Set action of commit line to ACTION.
-If the region is active, operate on all lines that it touches.
-Otherwise, operate on the current line. As a special case, an
-ACTION of nil comments the rebase line, regardless of its action
-type."
- (pcase (git-rebase-region-bounds t)
- (`(,beg ,end)
- (let ((end-marker (copy-marker end))
- (pt-below-p (and mark-active (< (mark) (point)))))
- (set-marker-insertion-type end-marker t)
- (goto-char beg)
- (while (< (point) end-marker)
- (with-slots (action-type target trailer comment-p)
- (git-rebase-current-line)
- (cond
- ((and action (eq action-type 'commit))
- (let ((inhibit-read-only t))
- (magit-delete-line)
- (insert (concat action " " target " " trailer "\n"))))
- ((and action-type (not (or action comment-p)))
- (let ((inhibit-read-only t))
- (insert comment-start " "))
- (forward-line))
- (t
- ;; In the case of --rebase-merges, commit lines may have
- ;; other lines with other action types, empty lines, and
- ;; "Branch" comments interspersed. Move along.
- (forward-line)))))
- (goto-char
- (if git-rebase-auto-advance
- end-marker
- (if pt-below-p (1- end-marker) beg)))
- (goto-char (line-beginning-position))))
- (_ (ding))))
-
-(defun git-rebase-line-p (&optional pos)
- (save-excursion
- (when pos (goto-char pos))
- (and (oref (git-rebase-current-line) action-type)
- t)))
-
-(defun git-rebase-region-bounds (&optional fallback)
- "Return region bounds if both ends touch rebase lines.
-Each bound is extended to include the entire line touched by the
-point or mark. If the region isn't active and FALLBACK is
-non-nil, return the beginning and end of the current rebase line,
-if any."
- (cond
- ((use-region-p)
- (let ((beg (save-excursion (goto-char (region-beginning))
- (line-beginning-position)))
- (end (save-excursion (goto-char (region-end))
- (line-end-position))))
- (when (and (git-rebase-line-p beg)
- (git-rebase-line-p end))
- (list beg (1+ end)))))
- ((and fallback (git-rebase-line-p))
- (list (line-beginning-position)
- (1+ (line-end-position))))))
-
-(defun git-rebase-move-line-down (n)
- "Move the current commit (or command) N lines down.
-If N is negative, move the commit up instead. With an active
-region, move all the lines that the region touches, not just the
-current line."
- (interactive "p")
- (pcase-let* ((`(,beg ,end)
- (or (git-rebase-region-bounds)
- (list (line-beginning-position)
- (1+ (line-end-position)))))
- (pt-offset (- (point) beg))
- (mark-offset (and mark-active (- (mark) beg))))
- (save-restriction
- (narrow-to-region
- (point-min)
- (1-
- (if git-rebase-show-instructions
- (save-excursion
- (goto-char (point-min))
- (while (or (git-rebase-line-p)
- ;; The output for --rebase-merges has empty
- ;; lines and "Branch" comments interspersed.
- (looking-at-p "^$")
- (looking-at-p (concat git-rebase-comment-re
- " Branch")))
- (forward-line))
- (line-beginning-position))
- (point-max))))
- (if (or (and (< n 0) (= beg (point-min)))
- (and (> n 0) (= end (point-max)))
- (> end (point-max)))
- (ding)
- (goto-char (if (< n 0) beg end))
- (forward-line n)
- (atomic-change-group
- (let ((inhibit-read-only t))
- (insert (delete-and-extract-region beg end)))
- (let ((new-beg (- (point) (- end beg))))
- (when (use-region-p)
- (setq deactivate-mark nil)
- (set-mark (+ new-beg mark-offset)))
- (goto-char (+ new-beg pt-offset))))))))
-
-(defun git-rebase-move-line-up (n)
- "Move the current commit (or command) N lines up.
-If N is negative, move the commit down instead. With an active
-region, move all the lines that the region touches, not just the
-current line."
- (interactive "p")
- (git-rebase-move-line-down (- n)))
-
-(defun git-rebase-highlight-region (start end window rol)
- (let ((inhibit-read-only t)
- (deactivate-mark nil)
- (bounds (git-rebase-region-bounds)))
- (mapc #'delete-overlay magit-section-highlight-overlays)
- (when bounds
- (magit-section-make-overlay (car bounds) (cadr bounds)
- 'magit-section-heading-selection))
- (if (and bounds (not magit-keep-region-overlay))
- (funcall (default-value 'redisplay-unhighlight-region-function) rol)
- (funcall (default-value 'redisplay-highlight-region-function)
- start end window rol))))
-
-(defun git-rebase-unhighlight-region (rol)
- (mapc #'delete-overlay magit-section-highlight-overlays)
- (funcall (default-value 'redisplay-unhighlight-region-function) rol))
-
-(defun git-rebase-kill-line ()
- "Kill the current action line.
-If the region is active, act on all lines touched by the region."
- (interactive)
- (git-rebase-set-action nil))
-
-(defun git-rebase-insert (rev)
- "Read an arbitrary commit and insert it below current line."
- (interactive (list (magit-read-branch-or-commit "Insert revision")))
- (forward-line)
- (--if-let (magit-rev-format "%h %s" rev)
- (let ((inhibit-read-only t))
- (insert "pick " it ?\n))
- (user-error "Unknown revision")))
-
-(defun git-rebase-set-noncommit-action (action value-fn arg)
- (goto-char (line-beginning-position))
- (pcase-let* ((inhibit-read-only t)
- (`(,initial ,trailer ,comment-p)
- (and (not arg)
- (with-slots ((ln-action action)
- target trailer comment-p)
- (git-rebase-current-line)
- (and (equal ln-action action)
- (list target trailer comment-p)))))
- (value (funcall value-fn initial)))
- (pcase (list value initial comment-p)
- (`("" nil ,_)
- (ding))
- (`("" ,_ ,_)
- (magit-delete-line))
- (_
- (if initial
- (magit-delete-line)
- (forward-line))
- (insert (concat action " " value
- (and (equal value initial)
- trailer
- (concat " " trailer))
- "\n"))
- (unless git-rebase-auto-advance
- (forward-line -1))))))
-
-(defun git-rebase-exec (arg)
- "Insert a shell command to be run after the current commit.
-
-If there already is such a command on the current line, then edit
-that instead. With a prefix argument insert a new command even
-when there already is one on the current line. With empty input
-remove the command on the current line, if any."
- (interactive "P")
- (git-rebase-set-noncommit-action
- "exec"
- (lambda (initial) (read-shell-command "Execute: " initial))
- arg))
-
-(defun git-rebase-label (arg)
- "Add a label after the current commit.
-If there already is a label on the current line, then edit that
-instead. With a prefix argument, insert a new label even when
-there is already a label on the current line. With empty input,
-remove the label on the current line, if any."
- (interactive "P")
- (git-rebase-set-noncommit-action
- "label"
- (lambda (initial)
- (read-from-minibuffer
- "Label: " initial magit-minibuffer-local-ns-map))
- arg))
-
-(defun git-rebase-buffer-labels ()
- (let (labels)
- (save-excursion
- (goto-char (point-min))
- (while (re-search-forward "^\\(?:l\\|label\\) \\([^ \n]+\\)" nil t)
- (push (match-string-no-properties 1) labels)))
- (nreverse labels)))
-
-(defun git-rebase-reset (arg)
- "Reset the current HEAD to a label.
-If there already is a reset command on the current line, then
-edit that instead. With a prefix argument, insert a new reset
-line even when point is already on a reset line. With empty
-input, remove the reset command on the current line, if any."
- (interactive "P")
- (git-rebase-set-noncommit-action
- "reset"
- (lambda (initial)
- (or (magit-completing-read "Label" (git-rebase-buffer-labels)
- nil t initial)
- ""))
- arg))
-
-(defun git-rebase-merge (arg)
- "Add a merge command after the current commit.
-If there is already a merge command on the current line, then
-replace that command instead. With a prefix argument, insert a
-new merge command even when there is already one on the current
-line. With empty input, remove the merge command on the current
-line, if any."
- (interactive "P")
- (git-rebase-set-noncommit-action
- "merge"
- (lambda (_)
- (or (magit-completing-read "Merge" (git-rebase-buffer-labels))
- ""))
- arg))
-
-(defun git-rebase-merge-toggle-editmsg ()
- "Toggle whether an editor is invoked when performing the merge at point.
-When a merge command uses a lower-case -c, the message for the
-specified commit will be opened in an editor before creating the
-commit. For an upper-case -C, the message will be used as is."
- (interactive)
- (with-slots (action-type target action-options trailer)
- (git-rebase-current-line)
- (if (eq action-type 'merge)
- (let ((inhibit-read-only t))
- (magit-delete-line)
- (insert
- (format "merge %s %s %s\n"
- (replace-regexp-in-string
- "-[cC]" (lambda (c)
- (if (equal c "-c") "-C" "-c"))
- action-options t t)
- target
- trailer)))
- (ding))))
-
-(defun git-rebase-set-bare-action (action arg)
- (goto-char (line-beginning-position))
- (with-slots ((ln-action action) comment-p)
- (git-rebase-current-line)
- (let ((same-action-p (equal action ln-action))
- (inhibit-read-only t))
- (when (or arg
- (not ln-action)
- (not same-action-p)
- (and same-action-p comment-p))
- (unless (or arg (not same-action-p))
- (magit-delete-line))
- (insert action ?\n)
- (unless git-rebase-auto-advance
- (forward-line -1))))))
-
-(defun git-rebase-noop (&optional arg)
- "Add noop action at point.
-
-If the current line already contains a noop action, leave it
-unchanged. If there is a commented noop action present, remove
-the comment. Otherwise add a new noop action. With a prefix
-argument insert a new noop action regardless of what is already
-present on the current line.
-
-A noop action can be used to make git perform a rebase even if
-no commits are selected. Without the noop action present, git
-would see an empty file and therefore do nothing."
- (interactive "P")
- (git-rebase-set-bare-action "noop" arg))
-
-(defun git-rebase-break (&optional arg)
- "Add break action at point.
-
-If there is a commented break action present, remove the comment.
-If the current line already contains a break action, add another
-break action only if a prefix argument is given.
-
-A break action can be used to interrupt the rebase at the
-specified point. It is particularly useful for pausing before
-the first commit in the sequence. For other cases, the
-equivalent behavior can be achieved with `git-rebase-edit'."
- (interactive "P")
- (git-rebase-set-bare-action "break" arg))
-
-(defun git-rebase-undo (&optional arg)
- "Undo some previous changes.
-Like `undo' but works in read-only buffers."
- (interactive "P")
- (let ((inhibit-read-only t))
- (undo arg)))
-
-(defun git-rebase--show-commit (&optional scroll)
- (let ((disable-magit-save-buffers t))
- (save-excursion
- (goto-char (line-beginning-position))
- (--if-let (with-slots (action-type target) (git-rebase-current-line)
- (and (eq action-type 'commit)
- target))
- (pcase scroll
- (`up (magit-diff-show-or-scroll-up))
- (`down (magit-diff-show-or-scroll-down))
- (_ (apply #'magit-show-commit it
- (magit-diff-arguments 'magit-revision-mode))))
- (ding)))))
-
-(defun git-rebase-show-commit ()
- "Show the commit on the current line if any."
- (interactive)
- (git-rebase--show-commit))
-
-(defun git-rebase-show-or-scroll-up ()
- "Update the commit buffer for commit on current line.
-
-Either show the commit at point in the appropriate buffer, or if
-that buffer is already being displayed in the current frame and
-contains information about that commit, then instead scroll the
-buffer up."
- (interactive)
- (git-rebase--show-commit 'up))
-
-(defun git-rebase-show-or-scroll-down ()
- "Update the commit buffer for commit on current line.
-
-Either show the commit at point in the appropriate buffer, or if
-that buffer is already being displayed in the current frame and
-contains information about that commit, then instead scroll the
-buffer down."
- (interactive)
- (git-rebase--show-commit 'down))
-
-(defun git-rebase-backward-line (&optional n)
- "Move N lines backward (forward if N is negative).
-Like `forward-line' but go into the opposite direction."
- (interactive "p")
- (forward-line (- (or n 1))))
-
-;;; Mode
-
-;;;###autoload
-(define-derived-mode git-rebase-mode special-mode "Git Rebase"
- "Major mode for editing of a Git rebase file.
-
-Rebase files are generated when you run 'git rebase -i' or run
-`magit-interactive-rebase'. They describe how Git should perform
-the rebase. See the documentation for git-rebase (e.g., by
-running 'man git-rebase' at the command line) for details."
- :group 'git-rebase
- (setq comment-start (or (magit-get "core.commentChar") "#"))
- (setq git-rebase-comment-re (concat "^" (regexp-quote comment-start)))
- (setq font-lock-defaults (list (git-rebase-mode-font-lock-keywords) t t))
- (unless git-rebase-show-instructions
- (let ((inhibit-read-only t))
- (flush-lines git-rebase-comment-re)))
- (unless with-editor-mode
- ;; Maybe already enabled when using `shell-command' or an Emacs shell.
- (with-editor-mode 1))
- (when git-rebase-confirm-cancel
- (add-hook 'with-editor-cancel-query-functions
- 'git-rebase-cancel-confirm nil t))
- (setq-local redisplay-highlight-region-function 'git-rebase-highlight-region)
- (setq-local redisplay-unhighlight-region-function 'git-rebase-unhighlight-region)
- (add-hook 'with-editor-pre-cancel-hook 'git-rebase-autostash-save nil t)
- (add-hook 'with-editor-post-cancel-hook 'git-rebase-autostash-apply nil t)
- (setq imenu-prev-index-position-function
- #'magit-imenu--rebase-prev-index-position-function)
- (setq imenu-extract-index-name-function
- #'magit-imenu--rebase-extract-index-name-function)
- (when (boundp 'save-place)
- (setq save-place nil)))
-
-(defun git-rebase-cancel-confirm (force)
- (or (not (buffer-modified-p))
- force
- (magit-confirm 'abort-rebase "Abort this rebase" nil 'noabort)))
-
-(defun git-rebase-autostash-save ()
- (--when-let (magit-file-line (magit-git-dir "rebase-merge/autostash"))
- (push (cons 'stash it) with-editor-cancel-alist)))
-
-(defun git-rebase-autostash-apply ()
- (--when-let (cdr (assq 'stash with-editor-cancel-alist))
- (magit-stash-apply it)))
-
-(defun git-rebase-match-comment-line (limit)
- (re-search-forward (concat git-rebase-comment-re ".*") limit t))
-
-(defun git-rebase-mode-font-lock-keywords ()
- "Font lock keywords for Git-Rebase mode."
- `((,(concat "^" (cdr (assq 'commit git-rebase-line-regexps)))
- (1 'font-lock-keyword-face)
- (3 'git-rebase-hash)
- (4 'git-rebase-description))
- (,(concat "^" (cdr (assq 'exec git-rebase-line-regexps)))
- (1 'font-lock-keyword-face)
- (3 'git-rebase-description))
- (,(concat "^" (cdr (assq 'bare git-rebase-line-regexps)))
- (1 'font-lock-keyword-face))
- (,(concat "^" (cdr (assq 'label git-rebase-line-regexps)))
- (1 'font-lock-keyword-face)
- (3 'git-rebase-label)
- (4 'font-lock-comment-face))
- ("^\\(m\\(?:erge\\)?\\) -[Cc] \\([^ \n]+\\) \\([^ \n]+\\)\\( #.*\\)?"
- (1 'font-lock-keyword-face)
- (2 'git-rebase-hash)
- (3 'git-rebase-label)
- (4 'font-lock-comment-face))
- ("^\\(m\\(?:erge\\)?\\) \\([^ \n]+\\)"
- (1 'font-lock-keyword-face)
- (2 'git-rebase-label))
- (,(concat git-rebase-comment-re " *"
- (cdr (assq 'commit git-rebase-line-regexps)))
- 0 'git-rebase-killed-action t)
- (git-rebase-match-comment-line 0 'font-lock-comment-face)
- ("\\[[^[]*\\]"
- 0 'magit-keyword t)
- ("\\(?:fixup!\\|squash!\\)"
- 0 'magit-keyword-squash t)
- (,(format "^%s Rebase \\([^ ]*\\) onto \\([^ ]*\\)" comment-start)
- (1 'git-rebase-comment-hash t)
- (2 'git-rebase-comment-hash t))
- (,(format "^%s \\(Commands:\\)" comment-start)
- (1 'git-rebase-comment-heading t))
- (,(format "^%s Branch \\(.*\\)" comment-start)
- (1 'git-rebase-label t))))
-
-(defun git-rebase-mode-show-keybindings ()
- "Modify the \"Commands:\" section of the comment Git generates
-at the bottom of the file so that in place of the one-letter
-abbreviation for the command, it shows the command's keybinding.
-By default, this is the same except for the \"pick\" command."
- (let ((inhibit-read-only t))
- (save-excursion
- (goto-char (point-min))
- (when (and git-rebase-show-instructions
- (re-search-forward
- (concat git-rebase-comment-re "\\s-+p, pick")
- nil t))
- (goto-char (line-beginning-position))
- (pcase-dolist (`(,cmd . ,desc) git-rebase-command-descriptions)
- (insert (format "%s %-8s %s\n"
- comment-start
- (substitute-command-keys (format "\\[%s]" cmd))
- desc)))
- (while (re-search-forward (concat git-rebase-comment-re
- "\\( ?\\)\\([^\n,],\\) "
- "\\([^\n ]+\\) ")
- nil t)
- (let ((cmd (intern (concat "git-rebase-" (match-string 3)))))
- (if (not (fboundp cmd))
- (delete-region (line-beginning-position) (1+ (line-end-position)))
- (replace-match " " t t nil 1)
- (replace-match
- (format "%-8s"
- (mapconcat #'key-description
- (--remove (eq (elt it 0) 'menu-bar)
- (reverse (where-is-internal
- cmd git-rebase-mode-map)))
- ", "))
- t t nil 2))))))))
-
-(add-hook 'git-rebase-mode-hook 'git-rebase-mode-show-keybindings t)
-
-(defun git-rebase-mode-disable-before-save-hook ()
- (set (make-local-variable 'before-save-hook) nil))
-
-(add-hook 'git-rebase-mode-hook 'git-rebase-mode-disable-before-save-hook)
-
-;;;###autoload
-(defconst git-rebase-filename-regexp "/git-rebase-todo\\'")
-;;;###autoload
-(add-to-list 'auto-mode-alist
- (cons git-rebase-filename-regexp 'git-rebase-mode))
-
-(add-to-list 'with-editor-server-window-alist
- (cons git-rebase-filename-regexp 'switch-to-buffer))
-
-(eval-after-load 'recentf
- '(add-to-list 'recentf-exclude git-rebase-filename-regexp))
-
-(add-to-list 'with-editor-file-name-history-exclude git-rebase-filename-regexp)
-
-;;; _
-(provide 'git-rebase)
-;;; git-rebase.el ends here
+++ /dev/null
-;;; magit-apply.el --- apply Git diffs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements commands for applying Git diffs or parts
-;; of such a diff. The supported "apply variants" are apply, stage,
-;; unstage, discard, and reverse - more than Git itself knows about,
-;; at least at the porcelain level.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit-core)
-(require 'magit-diff)
-(require 'magit-wip)
-
-(require 'transient) ; See #3732.
-
-;; For `magit-apply'
-(declare-function magit-am "magit-sequence" ())
-(declare-function magit-patch-apply "magit-files" ())
-;; For `magit-discard-files'
-(declare-function magit-checkout-stage "magit-merge" (file arg))
-(declare-function magit-checkout-read-stage "magit-merge" (file))
-(defvar auto-revert-verbose)
-;; For `magit-stage-untracked'
-(declare-function magit-submodule-add-1 "magit-submodule"
- (url &optional path name args))
-(declare-function magit-submodule-read-name-for-path "magit-submodule"
- (path &optional prefer-short))
-(declare-function borg--maybe-absorb-gitdir "borg" (pkg))
-(declare-function borg--sort-submodule-sections "borg" (file))
-(declare-function borg-assimilate "borg" (package url &optional partially))
-(defvar borg-user-emacs-directory)
-
-;;; Options
-
-(defcustom magit-delete-by-moving-to-trash t
- "Whether Magit uses the system's trash can.
-
-You should absolutely not disable this and also remove `discard'
-from `magit-no-confirm'. You shouldn't do that even if you have
-all of the Magit-Wip modes enabled, because those modes do not
-track any files that are not tracked in the proper branch."
- :package-version '(magit . "2.1.0")
- :group 'magit-essentials
- :type 'boolean)
-
-(defcustom magit-unstage-committed t
- "Whether unstaging a committed change reverts it instead.
-
-A committed change cannot be unstaged, because staging and
-unstaging are actions that are concerned with the differences
-between the index and the working tree, not with committed
-changes.
-
-If this option is non-nil (the default), then typing \"u\"
-\(`magit-unstage') on a committed change, causes it to be
-reversed in the index but not the working tree. For more
-information see command `magit-reverse-in-index'."
- :package-version '(magit . "2.4.1")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-reverse-atomically nil
- "Whether to reverse changes atomically.
-
-If some changes can be reversed while others cannot, then nothing
-is reversed if the value of this option is non-nil. But when it
-is nil, then the changes that can be reversed are reversed and
-for the other changes diff files are created that contain the
-rejected reversals."
- :package-version '(magit . "2.7.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-post-stage-hook nil
- "Hook run after staging changes.
-This hook is run by `magit-refresh' if `this-command'
-is a member of `magit-post-stage-hook-commands'."
- :package-version '(magit . "2.90.0")
- :group 'magit-commands
- :type 'hook)
-
-(defvar magit-post-stage-hook-commands
- '(magit-stage magit-stage-file magit-stage-modified))
-
-(defcustom magit-post-unstage-hook nil
- "Hook run after unstaging changes.
-This hook is run by `magit-refresh' if `this-command'
-is a member of `magit-post-unstage-hook-commands'."
- :package-version '(magit . "2.90.0")
- :group 'magit-commands
- :type 'hook)
-
-(defvar magit-post-unstage-hook-commands
- '(magit-unstage magit-unstage-file magit-unstage-all))
-
-;;; Commands
-;;;; Apply
-
-(defun magit-apply (&rest args)
- "Apply the change at point to the working tree.
-With a prefix argument fallback to a 3-way merge. Doing
-so causes the change to be applied to the index as well."
- (interactive (and current-prefix-arg (list "--3way")))
- (--when-let (magit-apply--get-selection)
- (pcase (list (magit-diff-type) (magit-diff-scope))
- (`(,(or `unstaged `staged) ,_)
- (user-error "Change is already in the working tree"))
- (`(untracked ,(or `file `files))
- (call-interactively 'magit-am))
- (`(,_ region) (magit-apply-region it args))
- (`(,_ hunk) (magit-apply-hunk it args))
- (`(,_ hunks) (magit-apply-hunks it args))
- (`(rebase-sequence file)
- (call-interactively 'magit-patch-apply))
- (`(,_ file) (magit-apply-diff it args))
- (`(,_ files) (magit-apply-diffs it args)))))
-
-(defun magit-apply--section-content (section)
- (buffer-substring-no-properties (if (magit-hunk-section-p section)
- (oref section start)
- (oref section content))
- (oref section end)))
-
-(defun magit-apply-diffs (sections &rest args)
- (setq sections (magit-apply--get-diffs sections))
- (magit-apply-patch sections args
- (mapconcat
- (lambda (s)
- (concat (magit-diff-file-header s)
- (magit-apply--section-content s)))
- sections "")))
-
-(defun magit-apply-diff (section &rest args)
- (setq section (car (magit-apply--get-diffs (list section))))
- (magit-apply-patch section args
- (concat (magit-diff-file-header section)
- (magit-apply--section-content section))))
-
-(defun magit-apply--adjust-hunk-new-starts (hunks)
- "Adjust new line numbers in headers of HUNKS for partial application.
-HUNKS should be a list of ordered, contiguous hunks to be applied
-from a file. For example, if there is a sequence of hunks with
-the headers
-
- @@ -2,6 +2,7 @@
- @@ -10,6 +11,7 @@
- @@ -18,6 +20,7 @@
-
-and only the second and third are to be applied, they would be
-adjusted as \"@@ -10,6 +10,7 @@\" and \"@@ -18,6 +19,7 @@\"."
- (let* ((first-hunk (car hunks))
- (offset (if (string-match diff-hunk-header-re-unified first-hunk)
- (- (string-to-number (match-string 3 first-hunk))
- (string-to-number (match-string 1 first-hunk)))
- (error "Hunk does not have expected header"))))
- (if (= offset 0)
- hunks
- (mapcar (lambda (hunk)
- (if (string-match diff-hunk-header-re-unified hunk)
- (replace-match (number-to-string
- (- (string-to-number (match-string 3 hunk))
- offset))
- t t hunk 3)
- (error "Hunk does not have expected header")))
- hunks))))
-
-(defun magit-apply--adjust-hunk-new-start (hunk)
- (car (magit-apply--adjust-hunk-new-starts (list hunk))))
-
-(defun magit-apply-hunks (sections &rest args)
- (let ((section (oref (car sections) parent)))
- (when (string-match "^diff --cc" (oref section value))
- (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
- (magit-apply-patch
- section args
- (concat (oref section header)
- (mapconcat #'identity
- (magit-apply--adjust-hunk-new-starts
- (mapcar #'magit-apply--section-content sections))
- "")))))
-
-(defun magit-apply-hunk (section &rest args)
- (when (string-match "^diff --cc" (magit-section-parent-value section))
- (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
- (magit-apply-patch (oref section parent) args
- (concat (magit-diff-file-header section)
- (magit-apply--adjust-hunk-new-start
- (magit-apply--section-content section)))))
-
-(defun magit-apply-region (section &rest args)
- (when (string-match "^diff --cc" (magit-section-parent-value section))
- (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
- (magit-apply-patch (oref section parent) args
- (concat (magit-diff-file-header section)
- (magit-apply--adjust-hunk-new-start
- (magit-diff-hunk-region-patch section args)))))
-
-(defun magit-apply-patch (section:s args patch)
- (let* ((files (if (atom section:s)
- (list (oref section:s value))
- (--map (oref it value) section:s)))
- (command (symbol-name this-command))
- (command (if (and command (string-match "^magit-\\([^-]+\\)" command))
- (match-string 1 command)
- "apply"))
- (ignore-context (magit-diff-ignore-any-space-p)))
- (unless (magit-diff-context-p)
- (user-error "Not enough context to apply patch. Increase the context"))
- (when (and magit-wip-before-change-mode (not inhibit-magit-refresh))
- (magit-wip-commit-before-change files (concat " before " command)))
- (with-temp-buffer
- (insert patch)
- (magit-run-git-with-input
- "apply" args "-p0"
- (and ignore-context "-C0")
- "--ignore-space-change" "-"))
- (unless inhibit-magit-refresh
- (when magit-wip-after-apply-mode
- (magit-wip-commit-after-apply files (concat " after " command)))
- (magit-refresh))))
-
-(defun magit-apply--get-selection ()
- (or (magit-region-sections '(hunk file module) t)
- (let ((section (magit-current-section)))
- (pcase (oref section type)
- ((or `hunk `file `module) section)
- ((or `staged `unstaged `untracked
- `stashed-index `stashed-worktree `stashed-untracked)
- (oref section children))
- (_ (user-error "Cannot apply this, it's not a change"))))))
-
-(defun magit-apply--get-diffs (sections)
- (magit-section-case
- ([file diffstat]
- (--map (or (magit-get-section
- (append `((file . ,(oref it value)))
- (magit-section-ident magit-root-section)))
- (error "Cannot get required diff headers"))
- sections))
- (t sections)))
-
-(defun magit-apply--diff-ignores-whitespace-p ()
- (and (cl-intersection magit-buffer-diff-args
- '("--ignore-space-at-eol"
- "--ignore-space-change"
- "--ignore-all-space"
- "--ignore-blank-lines")
- :test #'equal)
- t))
-
-;;;; Stage
-
-(defun magit-stage (&optional intent)
- "Add the change at point to the staging area.
-With a prefix argument, INTENT, and an untracked file (or files)
-at point, stage the file but not its content."
- (interactive "P")
- (--if-let (and (derived-mode-p 'magit-mode) (magit-apply--get-selection))
- (pcase (list (magit-diff-type)
- (magit-diff-scope)
- (magit-apply--diff-ignores-whitespace-p))
- (`(untracked ,_ ,_) (magit-stage-untracked intent))
- (`(unstaged region ,_) (magit-apply-region it "--cached"))
- (`(unstaged hunk ,_) (magit-apply-hunk it "--cached"))
- (`(unstaged hunks ,_) (magit-apply-hunks it "--cached"))
- (`(unstaged file t) (magit-apply-diff it "--cached"))
- (`(unstaged files t) (magit-apply-diffs it "--cached"))
- (`(unstaged list t) (magit-apply-diffs it "--cached"))
- (`(unstaged file nil) (magit-stage-1 "-u" (list (oref it value))))
- (`(unstaged files nil) (magit-stage-1 "-u" (magit-region-values nil t)))
- (`(unstaged list nil) (magit-stage-modified))
- (`(staged ,_ ,_) (user-error "Already staged"))
- (`(committed ,_ ,_) (user-error "Cannot stage committed changes"))
- (`(undefined ,_ ,_) (user-error "Cannot stage this change")))
- (call-interactively 'magit-stage-file)))
-
-;;;###autoload
-(defun magit-stage-file (file)
- "Stage all changes to FILE.
-With a prefix argument or when there is no file at point ask for
-the file to be staged. Otherwise stage the file at point without
-requiring confirmation."
- (interactive
- (let* ((atpoint (magit-section-value-if 'file))
- (current (magit-file-relative-name))
- (choices (nconc (magit-unstaged-files)
- (magit-untracked-files)))
- (default (car (member (or atpoint current) choices))))
- (list (if (or current-prefix-arg (not default))
- (magit-completing-read "Stage file" choices
- nil t nil nil default)
- default))))
- (magit-with-toplevel
- (magit-stage-1 nil (list file))))
-
-;;;###autoload
-(defun magit-stage-modified (&optional all)
- "Stage all changes to files modified in the worktree.
-Stage all new content of tracked files and remove tracked files
-that no longer exist in the working tree from the index also.
-With a prefix argument also stage previously untracked (but not
-ignored) files."
- (interactive "P")
- (when (magit-anything-staged-p)
- (magit-confirm 'stage-all-changes))
- (magit-with-toplevel
- (magit-stage-1 (if all "--all" "-u") magit-buffer-diff-files)))
-
-(defun magit-stage-1 (arg &optional files)
- (magit-wip-commit-before-change files " before stage")
- (magit-run-git "add" arg (if files (cons "--" files) "."))
- (when magit-auto-revert-mode
- (mapc #'magit-turn-on-auto-revert-mode-if-desired files))
- (magit-wip-commit-after-apply files " after stage"))
-
-(defun magit-stage-untracked (&optional intent)
- (let* ((section (magit-current-section))
- (files (pcase (magit-diff-scope)
- (`file (list (oref section value)))
- (`files (magit-region-values nil t))
- (`list (magit-untracked-files))))
- plain repos)
- (dolist (file files)
- (if (and (not (file-symlink-p file))
- (magit-git-repo-p file t))
- (push file repos)
- (push file plain)))
- (magit-wip-commit-before-change files " before stage")
- (when plain
- (magit-run-git "add" (and intent "--intent-to-add")
- "--" plain)
- (when magit-auto-revert-mode
- (mapc #'magit-turn-on-auto-revert-mode-if-desired plain)))
- (dolist (repo repos)
- (save-excursion
- (goto-char (oref (magit-get-section
- `((file . ,repo) (untracked) (status)))
- start))
- (let* ((topdir (magit-toplevel))
- (url (let ((default-directory
- (file-name-as-directory (expand-file-name repo))))
- (or (magit-get "remote" (magit-get-some-remote) "url")
- (concat (file-name-as-directory ".") repo))))
- (package
- (and (equal (bound-and-true-p borg-user-emacs-directory)
- topdir)
- (file-name-nondirectory (directory-file-name repo)))))
- (if (and package
- (y-or-n-p (format "Also assimilate `%s' drone?" package)))
- (borg-assimilate package url)
- (magit-submodule-add-1
- url repo (magit-submodule-read-name-for-path repo package))
- (when package
- (borg--sort-submodule-sections
- (expand-file-name ".gitmodules" topdir))
- (let ((default-directory borg-user-emacs-directory))
- (borg--maybe-absorb-gitdir package)))))))
- (magit-wip-commit-after-apply files " after stage")))
-
-;;;; Unstage
-
-(defun magit-unstage ()
- "Remove the change at point from the staging area."
- (interactive)
- (--when-let (magit-apply--get-selection)
- (pcase (list (magit-diff-type)
- (magit-diff-scope)
- (magit-apply--diff-ignores-whitespace-p))
- (`(untracked ,_ ,_) (user-error "Cannot unstage untracked changes"))
- (`(unstaged file ,_) (magit-unstage-intent (list (oref it value))))
- (`(unstaged files ,_) (magit-unstage-intent (magit-region-values nil t)))
- (`(unstaged ,_ ,_) (user-error "Already unstaged"))
- (`(staged region ,_) (magit-apply-region it "--reverse" "--cached"))
- (`(staged hunk ,_) (magit-apply-hunk it "--reverse" "--cached"))
- (`(staged hunks ,_) (magit-apply-hunks it "--reverse" "--cached"))
- (`(staged file t) (magit-apply-diff it "--reverse" "--cached"))
- (`(staged files t) (magit-apply-diffs it "--reverse" "--cached"))
- (`(staged list t) (magit-apply-diffs it "--reverse" "--cached"))
- (`(staged file nil) (magit-unstage-1 (list (oref it value))))
- (`(staged files nil) (magit-unstage-1 (magit-region-values nil t)))
- (`(staged list nil) (magit-unstage-all))
- (`(committed ,_ ,_) (if magit-unstage-committed
- (magit-reverse-in-index)
- (user-error "Cannot unstage committed changes")))
- (`(undefined ,_ ,_) (user-error "Cannot unstage this change")))))
-
-;;;###autoload
-(defun magit-unstage-file (file)
- "Unstage all changes to FILE.
-With a prefix argument or when there is no file at point ask for
-the file to be unstaged. Otherwise unstage the file at point
-without requiring confirmation."
- (interactive
- (let* ((atpoint (magit-section-value-if 'file))
- (current (magit-file-relative-name))
- (choices (magit-staged-files))
- (default (car (member (or atpoint current) choices))))
- (list (if (or current-prefix-arg (not default))
- (magit-completing-read "Unstage file" choices
- nil t nil nil default)
- default))))
- (magit-with-toplevel
- (magit-unstage-1 (list file))))
-
-(defun magit-unstage-1 (files)
- (magit-wip-commit-before-change files " before unstage")
- (if (magit-no-commit-p)
- (magit-run-git "rm" "--cached" "--" files)
- (magit-run-git "reset" "HEAD" "--" files))
- (magit-wip-commit-after-apply files " after unstage"))
-
-(defun magit-unstage-intent (files)
- (if-let ((staged (magit-staged-files))
- (intent (--filter (member it staged) files)))
- (magit-unstage-1 intent)
- (user-error "Already unstaged")))
-
-;;;###autoload
-(defun magit-unstage-all ()
- "Remove all changes from the staging area."
- (interactive)
- (when (or (magit-anything-unstaged-p)
- (magit-untracked-files))
- (magit-confirm 'unstage-all-changes))
- (magit-wip-commit-before-change nil " before unstage")
- (magit-run-git "reset" "HEAD" "--" magit-buffer-diff-files)
- (magit-wip-commit-after-apply nil " after unstage"))
-
-;;;; Discard
-
-(defun magit-discard ()
- "Remove the change at point."
- (interactive)
- (--when-let (magit-apply--get-selection)
- (pcase (list (magit-diff-type) (magit-diff-scope))
- (`(committed ,_) (user-error "Cannot discard committed changes"))
- (`(undefined ,_) (user-error "Cannot discard this change"))
- (`(,_ region) (magit-discard-region it))
- (`(,_ hunk) (magit-discard-hunk it))
- (`(,_ hunks) (magit-discard-hunks it))
- (`(,_ file) (magit-discard-file it))
- (`(,_ files) (magit-discard-files it))
- (`(,_ list) (magit-discard-files it)))))
-
-(defun magit-discard-region (section)
- (magit-confirm 'discard "Discard region")
- (magit-discard-apply section 'magit-apply-region))
-
-(defun magit-discard-hunk (section)
- (magit-confirm 'discard "Discard hunk")
- (magit-discard-apply section 'magit-apply-hunk))
-
-(defun magit-discard-apply (section apply)
- (if (eq (magit-diff-type section) 'unstaged)
- (funcall apply section "--reverse")
- (if (magit-anything-unstaged-p
- nil (if (magit-file-section-p section)
- (oref section value)
- (magit-section-parent-value section)))
- (progn (let ((inhibit-magit-refresh t))
- (funcall apply section "--reverse" "--cached")
- (funcall apply section "--reverse" "--reject"))
- (magit-refresh))
- (funcall apply section "--reverse" "--index"))))
-
-(defun magit-discard-hunks (sections)
- (magit-confirm 'discard (format "Discard %s hunks from %s"
- (length sections)
- (magit-section-parent-value (car sections))))
- (magit-discard-apply-n sections 'magit-apply-hunks))
-
-(defun magit-discard-apply-n (sections apply)
- (let ((section (car sections)))
- (if (eq (magit-diff-type section) 'unstaged)
- (funcall apply sections "--reverse")
- (if (magit-anything-unstaged-p
- nil (if (magit-file-section-p section)
- (oref section value)
- (magit-section-parent-value section)))
- (progn (let ((inhibit-magit-refresh t))
- (funcall apply sections "--reverse" "--cached")
- (funcall apply sections "--reverse" "--reject"))
- (magit-refresh))
- (funcall apply sections "--reverse" "--index")))))
-
-(defun magit-discard-file (section)
- (magit-discard-files (list section)))
-
-(defun magit-discard-files (sections)
- (let ((auto-revert-verbose nil)
- (type (magit-diff-type (car sections)))
- (status (magit-file-status))
- files delete resurrect rename discard discard-new resolve)
- (dolist (section sections)
- (let ((file (oref section value)))
- (push file files)
- (pcase (cons (pcase type
- (`staged ?X)
- (`unstaged ?Y)
- (`untracked ?Z))
- (cddr (assoc file status)))
- (`(?Z) (dolist (f (magit-untracked-files nil file))
- (push f delete)))
- ((or `(?Z ?? ??) `(?Z ?! ?!)) (push file delete))
- ((or `(?Z ?D ? ) `(,_ ?D ?D)) (push file delete))
- ((or `(,_ ?U ,_) `(,_ ,_ ?U)) (push file resolve))
- (`(,_ ?A ?A) (push file resolve))
- (`(?X ?M ,(or ? ?M ?D)) (push section discard))
- (`(?Y ,_ ?M ) (push section discard))
- (`(?X ?A ?M ) (push file discard-new))
- (`(?X ?C ?M ) (push file discard-new))
- (`(?X ?A ,(or ? ?D)) (push file delete))
- (`(?X ?C ,(or ? ?D)) (push file delete))
- (`(?X ?D ,(or ? ?M )) (push file resurrect))
- (`(?Y ,_ ?D ) (push file resurrect))
- (`(?X ?R ,(or ? ?M ?D)) (push file rename)))))
- (unwind-protect
- (let ((inhibit-magit-refresh t))
- (magit-wip-commit-before-change files " before discard")
- (when resolve
- (magit-discard-files--resolve (nreverse resolve)))
- (when resurrect
- (magit-discard-files--resurrect (nreverse resurrect)))
- (when delete
- (magit-discard-files--delete (nreverse delete) status))
- (when rename
- (magit-discard-files--rename (nreverse rename) status))
- (when (or discard discard-new)
- (magit-discard-files--discard (nreverse discard)
- (nreverse discard-new)))
- (magit-wip-commit-after-apply files " after discard"))
- (magit-refresh))))
-
-(defun magit-discard-files--resolve (files)
- (if-let ((arg (and (cdr files)
- (magit-read-char-case
- (format "For these %i files\n%s\ncheckout:\n"
- (length files)
- (mapconcat (lambda (file)
- (concat " " file))
- files "\n"))
- t
- (?o "[o]ur stage" "--ours")
- (?t "[t]heir stage" "--theirs")
- (?c "[c]onflict" "--merge")
- (?i "decide [i]ndividually" nil)))))
- (dolist (file files)
- (magit-checkout-stage file arg))
- (dolist (file files)
- (magit-checkout-stage file (magit-checkout-read-stage file)))))
-
-(defun magit-discard-files--resurrect (files)
- (magit-confirm-files 'resurrect files)
- (if (eq (magit-diff-type) 'staged)
- (magit-call-git "reset" "--" files)
- (magit-call-git "checkout" "--" files)))
-
-(defun magit-discard-files--delete (files status)
- (magit-confirm-files (if magit-delete-by-moving-to-trash 'trash 'delete)
- files)
- (let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash))
- (dolist (file files)
- (when (string-match-p "\\`\\\\?~" file)
- (error "Refusing to delete %S, too dangerous" file))
- (pcase (nth 3 (assoc file status))
- ((guard (memq (magit-diff-type) '(unstaged untracked)))
- (dired-delete-file file dired-recursive-deletes
- magit-delete-by-moving-to-trash)
- (dired-clean-up-after-deletion file))
- (?\s (delete-file file t)
- (magit-call-git "rm" "--cached" "--" file))
- (?M (let ((temp (magit-git-string "checkout-index" "--temp" file)))
- (string-match
- (format "\\(.+?\\)\t%s" (regexp-quote file)) temp)
- (rename-file (match-string 1 temp)
- (setq temp (concat file ".~{index}~")))
- (delete-file temp t))
- (magit-call-git "rm" "--cached" "--force" "--" file))
- (?D (magit-call-git "checkout" "--" file)
- (delete-file file t)
- (magit-call-git "rm" "--cached" "--force" "--" file))))))
-
-(defun magit-discard-files--rename (files status)
- (magit-confirm 'rename "Undo rename %s" "Undo %i renames" nil
- (mapcar (lambda (file)
- (setq file (assoc file status))
- (format "%s -> %s" (cadr file) (car file)))
- files))
- (dolist (file files)
- (let ((orig (cadr (assoc file status))))
- (if (file-exists-p file)
- (progn
- (--when-let (file-name-directory orig)
- (make-directory it t))
- (magit-call-git "mv" file orig))
- (magit-call-git "rm" "--cached" "--" file)
- (magit-call-git "reset" "--" orig)))))
-
-(defun magit-discard-files--discard (sections new-files)
- (let ((files (--map (oref it value) sections)))
- (magit-confirm-files 'discard (append files new-files)
- (format "Discard %s changes in" (magit-diff-type)))
- (if (eq (magit-diff-type (car sections)) 'unstaged)
- (magit-call-git "checkout" "--" files)
- (when new-files
- (magit-call-git "add" "--" new-files)
- (magit-call-git "reset" "--" new-files))
- (let ((binaries (magit-binary-files "--cached")))
- (when binaries
- (setq sections
- (--remove (member (oref it value) binaries)
- sections)))
- (cond ((= (length sections) 1)
- (magit-discard-apply (car sections) 'magit-apply-diff))
- (sections
- (magit-discard-apply-n sections 'magit-apply-diffs)))
- (when binaries
- (let ((modified (magit-unstaged-files t)))
- (setq binaries (--separate (member it modified) binaries)))
- (when (cadr binaries)
- (magit-call-git "reset" "--" (cadr binaries)))
- (when (car binaries)
- (user-error
- (concat
- "Cannot discard staged changes to binary files, "
- "which also have unstaged changes. Unstage instead."))))))))
-
-;;;; Reverse
-
-(defun magit-reverse (&rest args)
- "Reverse the change at point in the working tree.
-With a prefix argument fallback to a 3-way merge. Doing
-so causes the change to be applied to the index as well."
- (interactive (and current-prefix-arg (list "--3way")))
- (--when-let (magit-apply--get-selection)
- (pcase (list (magit-diff-type) (magit-diff-scope))
- (`(untracked ,_) (user-error "Cannot reverse untracked changes"))
- (`(unstaged ,_) (user-error "Cannot reverse unstaged changes"))
- (`(,_ region) (magit-reverse-region it args))
- (`(,_ hunk) (magit-reverse-hunk it args))
- (`(,_ hunks) (magit-reverse-hunks it args))
- (`(,_ file) (magit-reverse-file it args))
- (`(,_ files) (magit-reverse-files it args))
- (`(,_ list) (magit-reverse-files it args)))))
-
-(defun magit-reverse-region (section args)
- (magit-confirm 'reverse "Reverse region")
- (magit-reverse-apply section 'magit-apply-region args))
-
-(defun magit-reverse-hunk (section args)
- (magit-confirm 'reverse "Reverse hunk")
- (magit-reverse-apply section 'magit-apply-hunk args))
-
-(defun magit-reverse-hunks (sections args)
- (magit-confirm 'reverse
- (format "Reverse %s hunks from %s"
- (length sections)
- (magit-section-parent-value (car sections))))
- (magit-reverse-apply sections 'magit-apply-hunks args))
-
-(defun magit-reverse-file (section args)
- (magit-reverse-files (list section) args))
-
-(defun magit-reverse-files (sections args)
- (pcase-let ((`(,binaries ,sections)
- (let ((bs (magit-binary-files
- (cond ((derived-mode-p 'magit-revision-mode)
- magit-buffer-range)
- ((derived-mode-p 'magit-diff-mode)
- magit-buffer-range)
- (t
- "--cached")))))
- (--separate (member (oref it value) bs)
- sections))))
- (magit-confirm-files 'reverse (--map (oref it value) sections))
- (cond ((= (length sections) 1)
- (magit-reverse-apply (car sections) 'magit-apply-diff args))
- (sections
- (magit-reverse-apply sections 'magit-apply-diffs args)))
- (when binaries
- (user-error "Cannot reverse binary files"))))
-
-(defun magit-reverse-apply (section:s apply args)
- (funcall apply section:s "--reverse" args
- (and (not magit-reverse-atomically)
- (not (member "--3way" args))
- "--reject")))
-
-(defun magit-reverse-in-index (&rest args)
- "Reverse the change at point in the index but not the working tree.
-
-Use this command to extract a change from `HEAD', while leaving
-it in the working tree, so that it can later be committed using
-a separate commit. A typical workflow would be:
-
-0. Optionally make sure that there are no uncommitted changes.
-1. Visit the `HEAD' commit and navigate to the change that should
- not have been included in that commit.
-2. Type \"u\" (`magit-unstage') to reverse it in the index.
- This assumes that `magit-unstage-committed-changes' is non-nil.
-3. Type \"c e\" to extend `HEAD' with the staged changes,
- including those that were already staged before.
-4. Optionally stage the remaining changes using \"s\" or \"S\"
- and then type \"c c\" to create a new commit."
- (interactive)
- (magit-reverse (cons "--cached" args)))
-
-;;; _
-(provide 'magit-apply)
-;;; magit-apply.el ends here
+++ /dev/null
-;;; magit-autoloads.el --- automatically extracted autoloads
-;;
-;;; Code:
-
-(add-to-list 'load-path (directory-file-name
- (or (file-name-directory #$) (car load-path))))
-
-\f
-;;;### (autoloads nil "git-rebase" "git-rebase.el" (0 0 0 0))
-;;; Generated autoloads from git-rebase.el
-
-(autoload 'git-rebase-current-line "git-rebase" "\
-Parse current line into a `git-rebase-action' instance.
-If the current line isn't recognized as a rebase line, an
-instance with all nil values is returned." nil nil)
-
-(autoload 'git-rebase-mode "git-rebase" "\
-Major mode for editing of a Git rebase file.
-
-Rebase files are generated when you run 'git rebase -i' or run
-`magit-interactive-rebase'. They describe how Git should perform
-the rebase. See the documentation for git-rebase (e.g., by
-running 'man git-rebase' at the command line) for details.
-
-\(fn)" t nil)
-
-(defconst git-rebase-filename-regexp "/git-rebase-todo\\'")
-
-(add-to-list 'auto-mode-alist (cons git-rebase-filename-regexp 'git-rebase-mode))
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "git-rebase" '("git-rebase-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit" "magit.el" (0 0 0 0))
-;;; Generated autoloads from magit.el
-
-(define-obsolete-variable-alias 'global-magit-file-mode 'magit-define-global-key-bindings "Magit 3.0.0")
-
-(defvar magit-define-global-key-bindings t "\
-Whether to bind some Magit commands in the global keymap.
-
-If this variable is non-nil, then the following bindings may
-be added to the global keymap. The default is t.
-
-key binding
---- -------
-C-x g magit-status
-C-x M-g magit-dispatch
-C-c M-g magit-file-dispatch
-
-These bindings may be added when `after-init-hook' is called.
-Each binding is added if and only if at that time no other key
-is bound to the same command and no other command is bound to
-the same key. In other words we try to avoid adding bindings
-that are unnecessary, as well as bindings that conflict with
-other bindings.
-
-Adding the above bindings is delayed until `after-init-hook'
-is called to allow users to set the variable anywhere in their
-init file (without having to make sure to do so before `magit'
-is loaded or autoloaded) and to increase the likelihood that
-all the potentially conflicting user bindings have already
-been added.
-
-Setting this variable after the hook has already been called
-has no effect.
-
-We recommend that you bind \"C-c g\" instead of \"C-c M-g\" to
-`magit-file-dispatch'. The former is a much better binding
-but the \"C-c <letter>\" namespace is strictly reserved for
-users; preventing Magit from using it by default.
-
-Also see info node `(magit)Commands for Buffers Visiting Files'.")
-
-(custom-autoload 'magit-define-global-key-bindings "magit" t)
-
-(defun magit-maybe-define-global-key-bindings nil (when magit-define-global-key-bindings (let ((map (current-global-map))) (dolist (elt '(("C-x g" . magit-status) ("C-x M-g" . magit-dispatch) ("C-c M-g" . magit-file-dispatch))) (let ((key (kbd (car elt))) (def (cdr elt))) (unless (or (lookup-key map key) (where-is-internal def (make-sparse-keymap) t)) (define-key map key def)))))))
-
-(if after-init-time (magit-maybe-define-global-key-bindings) (add-hook 'after-init-hook 'magit-maybe-define-global-key-bindings t))
- (autoload 'magit-dispatch "magit" nil t)
- (autoload 'magit-run "magit" nil t)
-
-(autoload 'magit-git-command "magit" "\
-Execute COMMAND asynchronously; display output.
-
-Interactively, prompt for COMMAND in the minibuffer. \"git \" is
-used as initial input, but can be deleted to run another command.
-
-With a prefix argument COMMAND is run in the top-level directory
-of the current working tree, otherwise in `default-directory'.
-
-\(fn COMMAND)" t nil)
-
-(autoload 'magit-git-command-topdir "magit" "\
-Execute COMMAND asynchronously; display output.
-
-Interactively, prompt for COMMAND in the minibuffer. \"git \" is
-used as initial input, but can be deleted to run another command.
-
-COMMAND is run in the top-level directory of the current
-working tree.
-
-\(fn COMMAND)" t nil)
-
-(autoload 'magit-shell-command "magit" "\
-Execute COMMAND asynchronously; display output.
-
-Interactively, prompt for COMMAND in the minibuffer. With a
-prefix argument COMMAND is run in the top-level directory of
-the current working tree, otherwise in `default-directory'.
-
-\(fn COMMAND)" t nil)
-
-(autoload 'magit-shell-command-topdir "magit" "\
-Execute COMMAND asynchronously; display output.
-
-Interactively, prompt for COMMAND in the minibuffer. COMMAND
-is run in the top-level directory of the current working tree.
-
-\(fn COMMAND)" t nil)
-
-(autoload 'magit-version "magit" "\
-Return the version of Magit currently in use.
-If optional argument PRINT-DEST is non-nil, output
-stream (interactively, the echo area, or the current buffer with
-a prefix argument), also print the used versions of Magit, Git,
-and Emacs to it.
-
-\(fn &optional PRINT-DEST)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-apply" "magit-apply.el" (0 0 0 0))
-;;; Generated autoloads from magit-apply.el
-
-(autoload 'magit-stage-file "magit-apply" "\
-Stage all changes to FILE.
-With a prefix argument or when there is no file at point ask for
-the file to be staged. Otherwise stage the file at point without
-requiring confirmation.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-stage-modified "magit-apply" "\
-Stage all changes to files modified in the worktree.
-Stage all new content of tracked files and remove tracked files
-that no longer exist in the working tree from the index also.
-With a prefix argument also stage previously untracked (but not
-ignored) files.
-
-\(fn &optional ALL)" t nil)
-
-(autoload 'magit-unstage-file "magit-apply" "\
-Unstage all changes to FILE.
-With a prefix argument or when there is no file at point ask for
-the file to be unstaged. Otherwise unstage the file at point
-without requiring confirmation.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-unstage-all "magit-apply" "\
-Remove all changes from the staging area." t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-apply" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-autorevert" "magit-autorevert.el" (0
-;;;;;; 0 0 0))
-;;; Generated autoloads from magit-autorevert.el
-
-(put 'magit-auto-revert-mode 'globalized-minor-mode t)
-
-(defvar magit-auto-revert-mode (not (or global-auto-revert-mode noninteractive)) "\
-Non-nil if Magit-Auto-Revert mode is enabled.
-See the `magit-auto-revert-mode' command
-for a description of this minor mode.
-Setting this variable directly does not take effect;
-either customize it (see the info node `Easy Customization')
-or call the function `magit-auto-revert-mode'.")
-
-(custom-autoload 'magit-auto-revert-mode "magit-autorevert" nil)
-
-(autoload 'magit-auto-revert-mode "magit-autorevert" "\
-Toggle Auto-Revert mode in all buffers.
-With prefix ARG, enable Magit-Auto-Revert mode if ARG is positive;
-otherwise, disable it. If called from Lisp, enable the mode if
-ARG is omitted or nil.
-
-Auto-Revert mode is enabled in all buffers where
-`magit-turn-on-auto-revert-mode-if-desired' would do it.
-See `auto-revert-mode' for more information on Auto-Revert mode.
-
-\(fn &optional ARG)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-autorevert" '("auto-revert-buffer" "magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-bisect" "magit-bisect.el" (0 0 0 0))
-;;; Generated autoloads from magit-bisect.el
- (autoload 'magit-bisect "magit-bisect" nil t)
-
-(autoload 'magit-bisect-start "magit-bisect" "\
-Start a bisect session.
-
-Bisecting a bug means to find the commit that introduced it.
-This command starts such a bisect session by asking for a know
-good and a bad commit. To move the session forward use the
-other actions from the bisect transient command (\\<magit-status-mode-map>\\[magit-bisect]).
-
-\(fn BAD GOOD ARGS)" t nil)
-
-(autoload 'magit-bisect-reset "magit-bisect" "\
-After bisecting, cleanup bisection state and return to original `HEAD'." t nil)
-
-(autoload 'magit-bisect-good "magit-bisect" "\
-While bisecting, mark the current commit as good.
-Use this after you have asserted that the commit does not contain
-the bug in question." t nil)
-
-(autoload 'magit-bisect-bad "magit-bisect" "\
-While bisecting, mark the current commit as bad.
-Use this after you have asserted that the commit does contain the
-bug in question." t nil)
-
-(autoload 'magit-bisect-skip "magit-bisect" "\
-While bisecting, skip the current commit.
-Use this if for some reason the current commit is not a good one
-to test. This command lets Git choose a different one." t nil)
-
-(autoload 'magit-bisect-run "magit-bisect" "\
-Bisect automatically by running commands after each step.
-
-Unlike `git bisect run' this can be used before bisecting has
-begun. In that case it behaves like `git bisect start; git
-bisect run'.
-
-\(fn CMDLINE &optional BAD GOOD ARGS)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-bisect" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-blame" "magit-blame.el" (0 0 0 0))
-;;; Generated autoloads from magit-blame.el
- (autoload 'magit-blame-echo "magit-blame" nil t)
- (autoload 'magit-blame-addition "magit-blame" nil t)
- (autoload 'magit-blame-removal "magit-blame" nil t)
- (autoload 'magit-blame-reverse "magit-blame" nil t)
- (autoload 'magit-blame "magit-blame" nil t)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-blame" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-bookmark" "magit-bookmark.el" (0 0 0
-;;;;;; 0))
-;;; Generated autoloads from magit-bookmark.el
-
-(autoload 'magit--handle-bookmark "magit-bookmark" "\
-Open a bookmark created by `magit--make-bookmark'.
-Call the `magit-*-setup-buffer' function of the the major-mode
-with the variables' values as arguments, which were recorded by
-`magit--make-bookmark'. Ignore `magit-display-buffer-function'.
-
-\(fn BOOKMARK)" nil nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-bookmark" '("magit--make-bookmark")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-branch" "magit-branch.el" (0 0 0 0))
-;;; Generated autoloads from magit-branch.el
- (autoload 'magit-branch "magit" nil t)
-
-(autoload 'magit-checkout "magit-branch" "\
-Checkout REVISION, updating the index and the working tree.
-If REVISION is a local branch, then that becomes the current
-branch. If it is something else, then `HEAD' becomes detached.
-Checkout fails if the working tree or the staging area contain
-changes.
-
-\(git checkout REVISION).
-
-\(fn REVISION)" t nil)
-
-(autoload 'magit-branch-create "magit-branch" "\
-Create BRANCH at branch or revision START-POINT.
-
-\(fn BRANCH START-POINT)" t nil)
-
-(autoload 'magit-branch-and-checkout "magit-branch" "\
-Create and checkout BRANCH at branch or revision START-POINT.
-
-\(fn BRANCH START-POINT)" t nil)
-
-(autoload 'magit-branch-or-checkout "magit-branch" "\
-Hybrid between `magit-checkout' and `magit-branch-and-checkout'.
-
-Ask the user for an existing branch or revision. If the user
-input actually can be resolved as a branch or revision, then
-check that out, just like `magit-checkout' would.
-
-Otherwise create and checkout a new branch using the input as
-its name. Before doing so read the starting-point for the new
-branch. This is similar to what `magit-branch-and-checkout'
-does.
-
-\(fn ARG &optional START-POINT)" t nil)
-
-(autoload 'magit-branch-checkout "magit-branch" "\
-Checkout an existing or new local branch.
-
-Read a branch name from the user offering all local branches and
-a subset of remote branches as candidates. Omit remote branches
-for which a local branch by the same name exists from the list
-of candidates. The user can also enter a completely new branch
-name.
-
-- If the user selects an existing local branch, then check that
- out.
-
-- If the user selects a remote branch, then create and checkout
- a new local branch with the same name. Configure the selected
- remote branch as push target.
-
-- If the user enters a new branch name, then create and check
- that out, after also reading the starting-point from the user.
-
-In the latter two cases the upstream is also set. Whether it is
-set to the chosen START-POINT or something else depends on the
-value of `magit-branch-adjust-remote-upstream-alist', just like
-when using `magit-branch-and-checkout'.
-
-\(fn BRANCH &optional START-POINT)" t nil)
-
-(autoload 'magit-branch-orphan "magit-branch" "\
-Create and checkout an orphan BRANCH with contents from revision START-POINT.
-
-\(fn BRANCH START-POINT)" t nil)
-
-(autoload 'magit-branch-spinout "magit-branch" "\
-Create new branch from the unpushed commits.
-Like `magit-branch-spinoff' but remain on the current branch.
-If there are any uncommitted changes, then behave exactly like
-`magit-branch-spinoff'.
-
-\(fn BRANCH &optional FROM)" t nil)
-
-(autoload 'magit-branch-spinoff "magit-branch" "\
-Create new branch from the unpushed commits.
-
-Create and checkout a new branch starting at and tracking the
-current branch. That branch in turn is reset to the last commit
-it shares with its upstream. If the current branch has no
-upstream or no unpushed commits, then the new branch is created
-anyway and the previously current branch is not touched.
-
-This is useful to create a feature branch after work has already
-began on the old branch (likely but not necessarily \"master\").
-
-If the current branch is a member of the value of option
-`magit-branch-prefer-remote-upstream' (which see), then the
-current branch will be used as the starting point as usual, but
-the upstream of the starting-point may be used as the upstream
-of the new branch, instead of the starting-point itself.
-
-If optional FROM is non-nil, then the source branch is reset
-to `FROM~', instead of to the last commit it shares with its
-upstream. Interactively, FROM is only ever non-nil, if the
-region selects some commits, and among those commits, FROM is
-the commit that is the fewest commits ahead of the source
-branch.
-
-The commit at the other end of the selection actually does not
-matter, all commits between FROM and `HEAD' are moved to the new
-branch. If FROM is not reachable from `HEAD' or is reachable
-from the source branch's upstream, then an error is raised.
-
-\(fn BRANCH &optional FROM)" t nil)
-
-(autoload 'magit-branch-reset "magit-branch" "\
-Reset a branch to the tip of another branch or any other commit.
-
-When the branch being reset is the current branch, then do a
-hard reset. If there are any uncommitted changes, then the user
-has to confirm the reset because those changes would be lost.
-
-This is useful when you have started work on a feature branch but
-realize it's all crap and want to start over.
-
-When resetting to another branch and a prefix argument is used,
-then also set the target branch as the upstream of the branch
-that is being reset.
-
-\(fn BRANCH TO &optional SET-UPSTREAM)" t nil)
-
-(autoload 'magit-branch-delete "magit-branch" "\
-Delete one or multiple branches.
-If the region marks multiple branches, then offer to delete
-those, otherwise prompt for a single branch to be deleted,
-defaulting to the branch at point.
-
-\(fn BRANCHES &optional FORCE)" t nil)
-
-(autoload 'magit-branch-rename "magit-branch" "\
-Rename the branch named OLD to NEW.
-
-With a prefix argument FORCE, rename even if a branch named NEW
-already exists.
-
-If `branch.OLD.pushRemote' is set, then unset it. Depending on
-the value of `magit-branch-rename-push-target' (which see) maybe
-set `branch.NEW.pushRemote' and maybe rename the push-target on
-the remote.
-
-\(fn OLD NEW &optional FORCE)" t nil)
-
-(autoload 'magit-branch-shelve "magit-branch" "\
-Shelve a BRANCH.
-Rename \"refs/heads/BRANCH\" to \"refs/shelved/BRANCH\",
-and also rename the respective reflog file.
-
-\(fn BRANCH)" t nil)
-
-(autoload 'magit-branch-unshelve "magit-branch" "\
-Unshelve a BRANCH
-Rename \"refs/shelved/BRANCH\" to \"refs/heads/BRANCH\",
-and also rename the respective reflog file.
-
-\(fn BRANCH)" t nil)
- (autoload 'magit-branch-configure "magit-branch" nil t)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-branch" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-clone" "magit-clone.el" (0 0 0 0))
-;;; Generated autoloads from magit-clone.el
- (autoload 'magit-clone "magit-clone" nil t)
-
-(autoload 'magit-clone-regular "magit-clone" "\
-Create a clone of REPOSITORY in DIRECTORY.
-Then show the status buffer for the new repository.
-
-\(fn REPOSITORY DIRECTORY ARGS)" t nil)
-
-(autoload 'magit-clone-shallow "magit-clone" "\
-Create a shallow clone of REPOSITORY in DIRECTORY.
-Then show the status buffer for the new repository.
-With a prefix argument read the DEPTH of the clone;
-otherwise use 1.
-
-\(fn REPOSITORY DIRECTORY ARGS DEPTH)" t nil)
-
-(autoload 'magit-clone-shallow-since "magit-clone" "\
-Create a shallow clone of REPOSITORY in DIRECTORY.
-Then show the status buffer for the new repository.
-Exclude commits before DATE, which is read from the
-user.
-
-\(fn REPOSITORY DIRECTORY ARGS DATE)" t nil)
-
-(autoload 'magit-clone-shallow-exclude "magit-clone" "\
-Create a shallow clone of REPOSITORY in DIRECTORY.
-Then show the status buffer for the new repository.
-Exclude commits reachable from EXCLUDE, which is a
-branch or tag read from the user.
-
-\(fn REPOSITORY DIRECTORY ARGS EXCLUDE)" t nil)
-
-(autoload 'magit-clone-bare "magit-clone" "\
-Create a bare clone of REPOSITORY in DIRECTORY.
-Then show the status buffer for the new repository.
-
-\(fn REPOSITORY DIRECTORY ARGS)" t nil)
-
-(autoload 'magit-clone-mirror "magit-clone" "\
-Create a mirror of REPOSITORY in DIRECTORY.
-Then show the status buffer for the new repository.
-
-\(fn REPOSITORY DIRECTORY ARGS)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-clone" '("magit-clone-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-commit" "magit-commit.el" (0 0 0 0))
-;;; Generated autoloads from magit-commit.el
- (autoload 'magit-commit "magit-commit" nil t)
-
-(autoload 'magit-commit-create "magit-commit" "\
-Create a new commit on `HEAD'.
-With a prefix argument, amend to the commit at `HEAD' instead.
-
-\(git commit [--amend] ARGS)
-
-\(fn &optional ARGS)" t nil)
-
-(autoload 'magit-commit-amend "magit-commit" "\
-Amend the last commit.
-
-\(git commit --amend ARGS)
-
-\(fn &optional ARGS)" t nil)
-
-(autoload 'magit-commit-extend "magit-commit" "\
-Amend the last commit, without editing the message.
-
-With a prefix argument keep the committer date, otherwise change
-it. The option `magit-commit-extend-override-date' can be used
-to inverse the meaning of the prefix argument.
-\(git commit
---amend --no-edit)
-
-\(fn &optional ARGS OVERRIDE-DATE)" t nil)
-
-(autoload 'magit-commit-reword "magit-commit" "\
-Reword the last commit, ignoring staged changes.
-
-With a prefix argument keep the committer date, otherwise change
-it. The option `magit-commit-reword-override-date' can be used
-to inverse the meaning of the prefix argument.
-
-Non-interactively respect the optional OVERRIDE-DATE argument
-and ignore the option.
-
-\(git commit --amend --only)
-
-\(fn &optional ARGS OVERRIDE-DATE)" t nil)
-
-(autoload 'magit-commit-fixup "magit-commit" "\
-Create a fixup commit.
-
-With a prefix argument the target COMMIT has to be confirmed.
-Otherwise the commit at point may be used without confirmation
-depending on the value of option `magit-commit-squash-confirm'.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-(autoload 'magit-commit-squash "magit-commit" "\
-Create a squash commit, without editing the squash message.
-
-With a prefix argument the target COMMIT has to be confirmed.
-Otherwise the commit at point may be used without confirmation
-depending on the value of option `magit-commit-squash-confirm'.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-(autoload 'magit-commit-augment "magit-commit" "\
-Create a squash commit, editing the squash message.
-
-With a prefix argument the target COMMIT has to be confirmed.
-Otherwise the commit at point may be used without confirmation
-depending on the value of option `magit-commit-squash-confirm'.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-(autoload 'magit-commit-instant-fixup "magit-commit" "\
-Create a fixup commit targeting COMMIT and instantly rebase.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-(autoload 'magit-commit-instant-squash "magit-commit" "\
-Create a squash commit targeting COMMIT and instantly rebase.
-
-\(fn &optional COMMIT ARGS)" t nil)
-
-(autoload 'magit-commit-reshelve "magit-commit" "\
-Change the committer date and possibly the author date of `HEAD'.
-
-If you are the author of `HEAD', then both dates are changed,
-otherwise only the committer date. The current time is used
-as the initial minibuffer input and the original author (if
-that is you) or committer date is available as the previous
-history element.
-
-\(fn DATE)" t nil)
-
-(autoload 'magit-commit-absorb-modules "magit-commit" "\
-Spread modified modules across recent commits.
-
-\(fn PHASE COMMIT)" t nil)
- (autoload 'magit-commit-absorb "magit-commit" nil t)
- (autoload 'magit-commit-autofixup "magit-commit" nil t)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-commit" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-diff" "magit-diff.el" (0 0 0 0))
-;;; Generated autoloads from magit-diff.el
- (autoload 'magit-diff "magit-diff" nil t)
- (autoload 'magit-diff-refresh "magit-diff" nil t)
-
-(autoload 'magit-diff-dwim "magit-diff" "\
-Show changes for the thing at point.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-diff-range "magit-diff" "\
-Show differences between two commits.
-
-REV-OR-RANGE should be a range or a single revision. If it is a
-revision, then show changes in the working tree relative to that
-revision. If it is a range, but one side is omitted, then show
-changes relative to `HEAD'.
-
-If the region is active, use the revisions on the first and last
-line of the region as the two sides of the range. With a prefix
-argument, instead of diffing the revisions, choose a revision to
-view changes along, starting at the common ancestor of both
-revisions (i.e., use a \"...\" range).
-
-\(fn REV-OR-RANGE &optional ARGS FILES)" t nil)
-
-(autoload 'magit-diff-working-tree "magit-diff" "\
-Show changes between the current working tree and the `HEAD' commit.
-With a prefix argument show changes between the working tree and
-a commit read from the minibuffer.
-
-\(fn &optional REV ARGS FILES)" t nil)
-
-(autoload 'magit-diff-staged "magit-diff" "\
-Show changes between the index and the `HEAD' commit.
-With a prefix argument show changes between the index and
-a commit read from the minibuffer.
-
-\(fn &optional REV ARGS FILES)" t nil)
-
-(autoload 'magit-diff-unstaged "magit-diff" "\
-Show changes between the working tree and the index.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-diff-unmerged "magit-diff" "\
-Show changes that are being merged.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-diff-while-committing "magit-diff" "\
-While committing, show the changes that are about to be committed.
-While amending, invoking the command again toggles between
-showing just the new changes or all the changes that will
-be committed.
-
-\(fn &optional ARGS)" t nil)
-
-(autoload 'magit-diff-buffer-file "magit-diff" "\
-Show diff for the blob or file visited in the current buffer.
-
-When the buffer visits a blob, then show the respective commit.
-When the buffer visits a file, then show the differenced between
-`HEAD' and the working tree. In both cases limit the diff to
-the file or blob." t nil)
-
-(autoload 'magit-diff-paths "magit-diff" "\
-Show changes between any two files on disk.
-
-\(fn A B)" t nil)
-
-(autoload 'magit-show-commit "magit-diff" "\
-Visit the revision at point in another buffer.
-If there is no revision at point or with a prefix argument prompt
-for a revision.
-
-\(fn REV &optional ARGS FILES MODULE)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-diff" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-ediff" "magit-ediff.el" (0 0 0 0))
-;;; Generated autoloads from magit-ediff.el
- (autoload 'magit-ediff "magit-ediff" nil)
-
-(autoload 'magit-ediff-resolve "magit-ediff" "\
-Resolve outstanding conflicts in FILE using Ediff.
-FILE has to be relative to the top directory of the repository.
-
-In the rare event that you want to manually resolve all
-conflicts, including those already resolved by Git, use
-`ediff-merge-revisions-with-ancestor'.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-stage "magit-ediff" "\
-Stage and unstage changes to FILE using Ediff.
-FILE has to be relative to the top directory of the repository.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-compare "magit-ediff" "\
-Compare REVA:FILEA with REVB:FILEB using Ediff.
-
-FILEA and FILEB have to be relative to the top directory of the
-repository. If REVA or REVB is nil, then this stands for the
-working tree state.
-
-If the region is active, use the revisions on the first and last
-line of the region. With a prefix argument, instead of diffing
-the revisions, choose a revision to view changes along, starting
-at the common ancestor of both revisions (i.e., use a \"...\"
-range).
-
-\(fn REVA REVB FILEA FILEB)" t nil)
-
-(autoload 'magit-ediff-dwim "magit-ediff" "\
-Compare, stage, or resolve using Ediff.
-This command tries to guess what file, and what commit or range
-the user wants to compare, stage, or resolve using Ediff. It
-might only be able to guess either the file, or range or commit,
-in which case the user is asked about the other. It might not
-always guess right, in which case the appropriate `magit-ediff-*'
-command has to be used explicitly. If it cannot read the user's
-mind at all, then it asks the user for a command to run." t nil)
-
-(autoload 'magit-ediff-show-staged "magit-ediff" "\
-Show staged changes using Ediff.
-
-This only allows looking at the changes; to stage, unstage,
-and discard changes using Ediff, use `magit-ediff-stage'.
-
-FILE must be relative to the top directory of the repository.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-show-unstaged "magit-ediff" "\
-Show unstaged changes using Ediff.
-
-This only allows looking at the changes; to stage, unstage,
-and discard changes using Ediff, use `magit-ediff-stage'.
-
-FILE must be relative to the top directory of the repository.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-show-working-tree "magit-ediff" "\
-Show changes between `HEAD' and working tree using Ediff.
-FILE must be relative to the top directory of the repository.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-ediff-show-commit "magit-ediff" "\
-Show changes introduced by COMMIT using Ediff.
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-ediff-show-stash "magit-ediff" "\
-Show changes introduced by STASH using Ediff.
-`magit-ediff-show-stash-with-index' controls whether a
-three-buffer Ediff is used in order to distinguish changes in the
-stash that were staged.
-
-\(fn STASH)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-ediff" '("magit-ediff-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-extras" "magit-extras.el" (0 0 0 0))
-;;; Generated autoloads from magit-extras.el
-
-(autoload 'magit-run-git-gui "magit-extras" "\
-Run `git gui' for the current git repository." t nil)
-
-(autoload 'magit-run-git-gui-blame "magit-extras" "\
-Run `git gui blame' on the given FILENAME and COMMIT.
-Interactively run it for the current file and the `HEAD', with a
-prefix or when the current file cannot be determined let the user
-choose. When the current buffer is visiting FILENAME instruct
-blame to center around the line point is on.
-
-\(fn COMMIT FILENAME &optional LINENUM)" t nil)
-
-(autoload 'magit-run-gitk "magit-extras" "\
-Run `gitk' in the current repository." t nil)
-
-(autoload 'magit-run-gitk-branches "magit-extras" "\
-Run `gitk --branches' in the current repository." t nil)
-
-(autoload 'magit-run-gitk-all "magit-extras" "\
-Run `gitk --all' in the current repository." t nil)
-
-(autoload 'ido-enter-magit-status "magit-extras" "\
-Drop into `magit-status' from file switching.
-
-This command does not work in Emacs 26.1.
-See https://github.com/magit/magit/issues/3634
-and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31707.
-
-To make this command available use something like:
-
- (add-hook \\='ido-setup-hook
- (lambda ()
- (define-key ido-completion-map
- (kbd \"C-x g\") \\='ido-enter-magit-status)))
-
-Starting with Emacs 25.1 the Ido keymaps are defined just once
-instead of every time Ido is invoked, so now you can modify it
-like pretty much every other keymap:
-
- (define-key ido-common-completion-map
- (kbd \"C-x g\") \\='ido-enter-magit-status)" t nil)
-
-(autoload 'magit-project-status "magit-extras" "\
-Run `magit-status' in the current project's root." t nil)
-
-(autoload 'magit-dired-jump "magit-extras" "\
-Visit file at point using Dired.
-With a prefix argument, visit in another window. If there
-is no file at point, then instead visit `default-directory'.
-
-\(fn &optional OTHER-WINDOW)" t nil)
-
-(autoload 'magit-dired-log "magit-extras" "\
-Show log for all marked files, or the current file.
-
-\(fn &optional FOLLOW)" t nil)
-
-(autoload 'magit-do-async-shell-command "magit-extras" "\
-Open FILE with `dired-do-async-shell-command'.
-Interactively, open the file at point.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-previous-line "magit-extras" "\
-Like `previous-line' but with Magit-specific shift-selection.
-
-Magit's selection mechanism is based on the region but selects an
-area that is larger than the region. This causes `previous-line'
-when invoked while holding the shift key to move up one line and
-thereby select two lines. When invoked inside a hunk body this
-command does not move point on the first invocation and thereby
-it only selects a single line. Which inconsistency you prefer
-is a matter of preference.
-
-\(fn &optional ARG TRY-VSCROLL)" t nil)
-
-(function-put 'magit-previous-line 'interactive-only '"use `forward-line' with negative argument instead.")
-
-(autoload 'magit-next-line "magit-extras" "\
-Like `next-line' but with Magit-specific shift-selection.
-
-Magit's selection mechanism is based on the region but selects
-an area that is larger than the region. This causes `next-line'
-when invoked while holding the shift key to move down one line
-and thereby select two lines. When invoked inside a hunk body
-this command does not move point on the first invocation and
-thereby it only selects a single line. Which inconsistency you
-prefer is a matter of preference.
-
-\(fn &optional ARG TRY-VSCROLL)" t nil)
-
-(function-put 'magit-next-line 'interactive-only 'forward-line)
-
-(autoload 'magit-clean "magit-extras" "\
-Remove untracked files from the working tree.
-With a prefix argument also remove ignored files,
-with two prefix arguments remove ignored files only.
-
-\(git clean -f -d [-x|-X])
-
-\(fn &optional ARG)" t nil)
-
-(autoload 'magit-add-change-log-entry "magit-extras" "\
-Find change log file and add date entry and item for current change.
-This differs from `add-change-log-entry' (which see) in that
-it acts on the current hunk in a Magit buffer instead of on
-a position in a file-visiting buffer.
-
-\(fn &optional WHOAMI FILE-NAME OTHER-WINDOW)" t nil)
-
-(autoload 'magit-add-change-log-entry-other-window "magit-extras" "\
-Find change log file in other window and add entry and item.
-This differs from `add-change-log-entry-other-window' (which see)
-in that it acts on the current hunk in a Magit buffer instead of
-on a position in a file-visiting buffer.
-
-\(fn &optional WHOAMI FILE-NAME)" t nil)
-
-(autoload 'magit-edit-line-commit "magit-extras" "\
-Edit the commit that added the current line.
-
-With a prefix argument edit the commit that removes the line,
-if any. The commit is determined using `git blame' and made
-editable using `git rebase --interactive' if it is reachable
-from `HEAD', or by checking out the commit (or a branch that
-points at it) otherwise.
-
-\(fn &optional TYPE)" t nil)
-
-(autoload 'magit-diff-edit-hunk-commit "magit-extras" "\
-From a hunk, edit the respective commit and visit the file.
-
-First visit the file being modified by the hunk at the correct
-location using `magit-diff-visit-file'. This actually visits a
-blob. When point is on a diff header, not within an individual
-hunk, then this visits the blob the first hunk is about.
-
-Then invoke `magit-edit-line-commit', which uses an interactive
-rebase to make the commit editable, or if that is not possible
-because the commit is not reachable from `HEAD' by checking out
-that commit directly. This also causes the actual worktree file
-to be visited.
-
-Neither the blob nor the file buffer are killed when finishing
-the rebase. If that is undesirable, then it might be better to
-use `magit-rebase-edit-command' instead of this command.
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-reshelve-since "magit-extras" "\
-Change the author and committer dates of the commits since REV.
-
-Ask the user for the first reachable commit whose dates should
-be changed. Then read the new date for that commit. The initial
-minibuffer input and the previous history element offer good
-values. The next commit will be created one minute later and so
-on.
-
-This command is only intended for interactive use and should only
-be used on highly rearranged and unpublished history.
-
-\(fn REV)" t nil)
-
-(autoload 'magit-pop-revision-stack "magit-extras" "\
-Insert a representation of a revision into the current buffer.
-
-Pop a revision from the `magit-revision-stack' and insert it into
-the current buffer according to `magit-pop-revision-stack-format'.
-Revisions can be put on the stack using `magit-copy-section-value'
-and `magit-copy-buffer-revision'.
-
-If the stack is empty or with a prefix argument, instead read a
-revision in the minibuffer. By using the minibuffer history this
-allows selecting an item which was popped earlier or to insert an
-arbitrary reference or revision without first pushing it onto the
-stack.
-
-When reading the revision from the minibuffer, then it might not
-be possible to guess the correct repository. When this command
-is called inside a repository (e.g. while composing a commit
-message), then that repository is used. Otherwise (e.g. while
-composing an email) then the repository recorded for the top
-element of the stack is used (even though we insert another
-revision). If not called inside a repository and with an empty
-stack, or with two prefix arguments, then read the repository in
-the minibuffer too.
-
-\(fn REV TOPLEVEL)" t nil)
-
-(autoload 'magit-copy-section-value "magit-extras" "\
-Save the value of the current section for later use.
-
-Save the section value to the `kill-ring', and, provided that
-the current section is a commit, branch, or tag section, push
-the (referenced) revision to the `magit-revision-stack' for use
-with `magit-pop-revision-stack'.
-
-When `magit-copy-revision-abbreviated' is non-nil, save the
-abbreviated revision to the `kill-ring' and the
-`magit-revision-stack'.
-
-When the current section is a branch or a tag, and a prefix
-argument is used, then save the revision at its tip to the
-`kill-ring' instead of the reference name.
-
-When the region is active, then save that to the `kill-ring',
-like `kill-ring-save' would, instead of behaving as described
-above. If a prefix argument is used and the region is within
-a hunk, then strip the diff marker column and keep only either
-the added or removed lines, depending on the sign of the prefix
-argument.
-
-\(fn ARG)" t nil)
-
-(autoload 'magit-copy-buffer-revision "magit-extras" "\
-Save the revision of the current buffer for later use.
-
-Save the revision shown in the current buffer to the `kill-ring'
-and push it to the `magit-revision-stack'.
-
-This command is mainly intended for use in `magit-revision-mode'
-buffers, the only buffers where it is always unambiguous exactly
-which revision should be saved.
-
-Most other Magit buffers usually show more than one revision, in
-some way or another, so this command has to select one of them,
-and that choice might not always be the one you think would have
-been the best pick.
-
-In such buffers it is often more useful to save the value of
-the current section instead, using `magit-copy-section-value'.
-
-When the region is active, then save that to the `kill-ring',
-like `kill-ring-save' would, instead of behaving as described
-above.
-
-When `magit-copy-revision-abbreviated' is non-nil, save the
-abbreviated revision to the `kill-ring' and the
-`magit-revision-stack'." t nil)
-
-(autoload 'magit-abort-dwim "magit-extras" "\
-Abort current operation.
-Depending on the context, this will abort a merge, a rebase, a
-patch application, a cherry-pick, a revert, or a bisect." t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-extras" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-fetch" "magit-fetch.el" (0 0 0 0))
-;;; Generated autoloads from magit-fetch.el
- (autoload 'magit-fetch "magit-fetch" nil t)
- (autoload 'magit-fetch-from-pushremote "magit-fetch" nil t)
- (autoload 'magit-fetch-from-upstream "magit-fetch" nil t)
-
-(autoload 'magit-fetch-other "magit-fetch" "\
-Fetch from another repository.
-
-\(fn REMOTE ARGS)" t nil)
-
-(autoload 'magit-fetch-branch "magit-fetch" "\
-Fetch a BRANCH from a REMOTE.
-
-\(fn REMOTE BRANCH ARGS)" t nil)
-
-(autoload 'magit-fetch-refspec "magit-fetch" "\
-Fetch a REFSPEC from a REMOTE.
-
-\(fn REMOTE REFSPEC ARGS)" t nil)
-
-(autoload 'magit-fetch-all "magit-fetch" "\
-Fetch from all remotes.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-fetch-all-prune "magit-fetch" "\
-Fetch from all remotes, and prune.
-Prune remote tracking branches for branches that have been
-removed on the respective remote." t nil)
-
-(autoload 'magit-fetch-all-no-prune "magit-fetch" "\
-Fetch from all remotes." t nil)
-
-(autoload 'magit-fetch-modules "magit-fetch" "\
-Fetch all submodules.
-
-Option `magit-fetch-modules-jobs' controls how many submodules
-are being fetched in parallel. Also fetch the super-repository,
-because `git-fetch' does not support not doing that. With a
-prefix argument fetch all remotes.
-
-\(fn &optional ALL)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-fetch" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-files" "magit-files.el" (0 0 0 0))
-;;; Generated autoloads from magit-files.el
-
-(autoload 'magit-find-file "magit-files" "\
-View FILE from REV.
-Switch to a buffer visiting blob REV:FILE, creating one if none
-already exists. If prior to calling this command the current
-buffer and/or cursor position is about the same file, then go
-to the line and column corresponding to that location.
-
-\(fn REV FILE)" t nil)
-
-(autoload 'magit-find-file-other-window "magit-files" "\
-View FILE from REV, in another window.
-Switch to a buffer visiting blob REV:FILE, creating one if none
-already exists. If prior to calling this command the current
-buffer and/or cursor position is about the same file, then go to
-the line and column corresponding to that location.
-
-\(fn REV FILE)" t nil)
-
-(autoload 'magit-find-file-other-frame "magit-files" "\
-View FILE from REV, in another frame.
-Switch to a buffer visiting blob REV:FILE, creating one if none
-already exists. If prior to calling this command the current
-buffer and/or cursor position is about the same file, then go to
-the line and column corresponding to that location.
-
-\(fn REV FILE)" t nil)
- (autoload 'magit-file-dispatch "magit" nil t)
-
-(autoload 'magit-blob-visit-file "magit-files" "\
-View the file from the worktree corresponding to the current blob.
-When visiting a blob or the version from the index, then go to
-the same location in the respective file in the working tree." t nil)
-
-(autoload 'magit-file-checkout "magit-files" "\
-Checkout FILE from REV.
-
-\(fn REV FILE)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-files" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-git" "magit-git.el" (0 0 0 0))
-;;; Generated autoloads from magit-git.el
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-git" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-gitignore" "magit-gitignore.el" (0 0
-;;;;;; 0 0))
-;;; Generated autoloads from magit-gitignore.el
- (autoload 'magit-gitignore "magit-gitignore" nil t)
-
-(autoload 'magit-gitignore-in-topdir "magit-gitignore" "\
-Add the Git ignore RULE to the top-level \".gitignore\" file.
-Since this file is tracked, it is shared with other clones of the
-repository. Also stage the file.
-
-\(fn RULE)" t nil)
-
-(autoload 'magit-gitignore-in-subdir "magit-gitignore" "\
-Add the Git ignore RULE to a \".gitignore\" file.
-Prompted the user for a directory and add the rule to the
-\".gitignore\" file in that directory. Since such files are
-tracked, they are shared with other clones of the repository.
-Also stage the file.
-
-\(fn RULE DIRECTORY)" t nil)
-
-(autoload 'magit-gitignore-in-gitdir "magit-gitignore" "\
-Add the Git ignore RULE to \"$GIT_DIR/info/exclude\".
-Rules in that file only affects this clone of the repository.
-
-\(fn RULE)" t nil)
-
-(autoload 'magit-gitignore-on-system "magit-gitignore" "\
-Add the Git ignore RULE to the file specified by `core.excludesFile'.
-Rules that are defined in that file affect all local repositories.
-
-\(fn RULE)" t nil)
-
-(autoload 'magit-skip-worktree "magit-gitignore" "\
-Call \"git update-index --skip-worktree -- FILE\".
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-no-skip-worktree "magit-gitignore" "\
-Call \"git update-index --no-skip-worktree -- FILE\".
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-assume-unchanged "magit-gitignore" "\
-Call \"git update-index --assume-unchanged -- FILE\".
-
-\(fn FILE)" t nil)
-
-(autoload 'magit-no-assume-unchanged "magit-gitignore" "\
-Call \"git update-index --no-assume-unchanged -- FILE\".
-
-\(fn FILE)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-gitignore" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-imenu" "magit-imenu.el" (0 0 0 0))
-;;; Generated autoloads from magit-imenu.el
-
-(autoload 'magit-imenu--log-prev-index-position-function "magit-imenu" "\
-Move point to previous line in current buffer.
-This function is used as a value for
-`imenu-prev-index-position-function'." nil nil)
-
-(autoload 'magit-imenu--log-extract-index-name-function "magit-imenu" "\
-Return imenu name for line at point.
-This function is used as a value for
-`imenu-extract-index-name-function'. Point should be at the
-beginning of the line." nil nil)
-
-(autoload 'magit-imenu--diff-prev-index-position-function "magit-imenu" "\
-Move point to previous file line in current buffer.
-This function is used as a value for
-`imenu-prev-index-position-function'." nil nil)
-
-(autoload 'magit-imenu--diff-extract-index-name-function "magit-imenu" "\
-Return imenu name for line at point.
-This function is used as a value for
-`imenu-extract-index-name-function'. Point should be at the
-beginning of the line." nil nil)
-
-(autoload 'magit-imenu--status-create-index-function "magit-imenu" "\
-Return an alist of all imenu entries in current buffer.
-This function is used as a value for
-`imenu-create-index-function'." nil nil)
-
-(autoload 'magit-imenu--refs-create-index-function "magit-imenu" "\
-Return an alist of all imenu entries in current buffer.
-This function is used as a value for
-`imenu-create-index-function'." nil nil)
-
-(autoload 'magit-imenu--cherry-create-index-function "magit-imenu" "\
-Return an alist of all imenu entries in current buffer.
-This function is used as a value for
-`imenu-create-index-function'." nil nil)
-
-(autoload 'magit-imenu--submodule-prev-index-position-function "magit-imenu" "\
-Move point to previous line in magit-submodule-list buffer.
-This function is used as a value for
-`imenu-prev-index-position-function'." nil nil)
-
-(autoload 'magit-imenu--submodule-extract-index-name-function "magit-imenu" "\
-Return imenu name for line at point.
-This function is used as a value for
-`imenu-extract-index-name-function'. Point should be at the
-beginning of the line." nil nil)
-
-(autoload 'magit-imenu--repolist-prev-index-position-function "magit-imenu" "\
-Move point to previous line in magit-repolist buffer.
-This function is used as a value for
-`imenu-prev-index-position-function'." nil nil)
-
-(autoload 'magit-imenu--repolist-extract-index-name-function "magit-imenu" "\
-Return imenu name for line at point.
-This function is used as a value for
-`imenu-extract-index-name-function'. Point should be at the
-beginning of the line." nil nil)
-
-(autoload 'magit-imenu--process-prev-index-position-function "magit-imenu" "\
-Move point to previous process in magit-process buffer.
-This function is used as a value for
-`imenu-prev-index-position-function'." nil nil)
-
-(autoload 'magit-imenu--process-extract-index-name-function "magit-imenu" "\
-Return imenu name for line at point.
-This function is used as a value for
-`imenu-extract-index-name-function'. Point should be at the
-beginning of the line." nil nil)
-
-(autoload 'magit-imenu--rebase-prev-index-position-function "magit-imenu" "\
-Move point to previous commit in git-rebase buffer.
-This function is used as a value for
-`imenu-prev-index-position-function'." nil nil)
-
-(autoload 'magit-imenu--rebase-extract-index-name-function "magit-imenu" "\
-Return imenu name for line at point.
-This function is used as a value for
-`imenu-extract-index-name-function'. Point should be at the
-beginning of the line." nil nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-imenu" '("magit-imenu--index-function")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-log" "magit-log.el" (0 0 0 0))
-;;; Generated autoloads from magit-log.el
- (autoload 'magit-log "magit-log" nil t)
- (autoload 'magit-log-refresh "magit-log" nil t)
-
-(autoload 'magit-log-current "magit-log" "\
-Show log for the current branch.
-When `HEAD' is detached or with a prefix argument show log for
-one or more revs read from the minibuffer.
-
-\(fn REVS &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-other "magit-log" "\
-Show log for one or more revs read from the minibuffer.
-The user can input any revision or revisions separated by a
-space, or even ranges, but only branches and tags, and a
-representation of the commit at point, are available as
-completion candidates.
-
-\(fn REVS &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-head "magit-log" "\
-Show log for `HEAD'.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-branches "magit-log" "\
-Show log for all local branches and `HEAD'.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-matching-branches "magit-log" "\
-Show log for all branches matching PATTERN and `HEAD'.
-
-\(fn PATTERN &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-matching-tags "magit-log" "\
-Show log for all tags matching PATTERN and `HEAD'.
-
-\(fn PATTERN &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-all-branches "magit-log" "\
-Show log for all local and remote branches and `HEAD'.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-all "magit-log" "\
-Show log for all references and `HEAD'.
-
-\(fn &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-buffer-file "magit-log" "\
-Show log for the blob or file visited in the current buffer.
-With a prefix argument or when `--follow' is an active log
-argument, then follow renames. When the region is active,
-restrict the log to the lines that the region touches.
-
-\(fn &optional FOLLOW BEG END)" t nil)
-
-(autoload 'magit-log-trace-definition "magit-log" "\
-Show log for the definition at point.
-
-\(fn FILE FN REV)" t nil)
-
-(autoload 'magit-log-merged "magit-log" "\
-Show log for the merge of COMMIT into BRANCH.
-
-More precisely, find merge commit M that brought COMMIT into
-BRANCH, and show the log of the range \"M^1..M\". If COMMIT is
-directly on BRANCH, then show approximately twenty surrounding
-commits instead.
-
-This command requires git-when-merged, which is available from
-https://github.com/mhagger/git-when-merged.
-
-\(fn COMMIT BRANCH &optional ARGS FILES)" t nil)
-
-(autoload 'magit-log-move-to-parent "magit-log" "\
-Move to the Nth parent of the current commit.
-
-\(fn &optional N)" t nil)
- (autoload 'magit-shortlog "magit-log" nil t)
-
-(autoload 'magit-shortlog-since "magit-log" "\
-Show a history summary for commits since REV.
-
-\(fn REV ARGS)" t nil)
-
-(autoload 'magit-shortlog-range "magit-log" "\
-Show a history summary for commit or range REV-OR-RANGE.
-
-\(fn REV-OR-RANGE ARGS)" t nil)
-
-(autoload 'magit-cherry "magit-log" "\
-Show commits in a branch that are not merged in the upstream branch.
-
-\(fn HEAD UPSTREAM)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-log" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-margin" "magit-margin.el" (0 0 0 0))
-;;; Generated autoloads from magit-margin.el
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-margin" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-merge" "magit-merge.el" (0 0 0 0))
-;;; Generated autoloads from magit-merge.el
- (autoload 'magit-merge "magit" nil t)
-
-(autoload 'magit-merge-plain "magit-merge" "\
-Merge commit REV into the current branch; using default message.
-
-Unless there are conflicts or a prefix argument is used create a
-merge commit using a generic commit message and without letting
-the user inspect the result. With a prefix argument pretend the
-merge failed to give the user the opportunity to inspect the
-merge.
-
-\(git merge --no-edit|--no-commit [ARGS] REV)
-
-\(fn REV &optional ARGS NOCOMMIT)" t nil)
-
-(autoload 'magit-merge-editmsg "magit-merge" "\
-Merge commit REV into the current branch; and edit message.
-Perform the merge and prepare a commit message but let the user
-edit it.
-
-\(git merge --edit --no-ff [ARGS] REV)
-
-\(fn REV &optional ARGS)" t nil)
-
-(autoload 'magit-merge-nocommit "magit-merge" "\
-Merge commit REV into the current branch; pretending it failed.
-Pretend the merge failed to give the user the opportunity to
-inspect the merge and change the commit message.
-
-\(git merge --no-commit --no-ff [ARGS] REV)
-
-\(fn REV &optional ARGS)" t nil)
-
-(autoload 'magit-merge-into "magit-merge" "\
-Merge the current branch into BRANCH and remove the former.
-
-Before merging, force push the source branch to its push-remote,
-provided the respective remote branch already exists, ensuring
-that the respective pull-request (if any) won't get stuck on some
-obsolete version of the commits that are being merged. Finally
-if `forge-branch-pullreq' was used to create the merged branch,
-branch, then also remove the respective remote branch.
-
-\(fn BRANCH &optional ARGS)" t nil)
-
-(autoload 'magit-merge-absorb "magit-merge" "\
-Merge BRANCH into the current branch and remove the former.
-
-Before merging, force push the source branch to its push-remote,
-provided the respective remote branch already exists, ensuring
-that the respective pull-request (if any) won't get stuck on some
-obsolete version of the commits that are being merged. Finally
-if `forge-branch-pullreq' was used to create the merged branch,
-then also remove the respective remote branch.
-
-\(fn BRANCH &optional ARGS)" t nil)
-
-(autoload 'magit-merge-squash "magit-merge" "\
-Squash commit REV into the current branch; don't create a commit.
-
-\(git merge --squash REV)
-
-\(fn REV)" t nil)
-
-(autoload 'magit-merge-preview "magit-merge" "\
-Preview result of merging REV into the current branch.
-
-\(fn REV)" t nil)
-
-(autoload 'magit-merge-abort "magit-merge" "\
-Abort the current merge operation.
-
-\(git merge --abort)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-merge" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-mode" "magit-mode.el" (0 0 0 0))
-;;; Generated autoloads from magit-mode.el
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-mode" '("disable-magit-save-buffers" "inhibit-magit-refresh" "magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-notes" "magit-notes.el" (0 0 0 0))
-;;; Generated autoloads from magit-notes.el
- (autoload 'magit-notes "magit" nil t)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-notes" '("magit-notes-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-obsolete" "magit-obsolete.el" (0 0 0
-;;;;;; 0))
-;;; Generated autoloads from magit-obsolete.el
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-obsolete" '("magit--magit-popup-warning")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-patch" "magit-patch.el" (0 0 0 0))
-;;; Generated autoloads from magit-patch.el
- (autoload 'magit-patch "magit-patch" nil t)
- (autoload 'magit-patch-create "magit-patch" nil t)
- (autoload 'magit-patch-apply "magit-patch" nil t)
-
-(autoload 'magit-patch-save "magit-patch" "\
-Write current diff into patch FILE.
-
-What arguments are used to create the patch depends on the value
-of `magit-patch-save-arguments' and whether a prefix argument is
-used.
-
-If the value is the symbol `buffer', then use the same arguments
-as the buffer. With a prefix argument use no arguments.
-
-If the value is a list beginning with the symbol `exclude', then
-use the same arguments as the buffer except for those matched by
-entries in the cdr of the list. The comparison is done using
-`string-prefix-p'. With a prefix argument use the same arguments
-as the buffer.
-
-If the value is a list of strings (including the empty list),
-then use those arguments. With a prefix argument use the same
-arguments as the buffer.
-
-Of course the arguments that are required to actually show the
-same differences as those shown in the buffer are always used.
-
-\(fn FILE &optional ARG)" t nil)
-
-(autoload 'magit-request-pull "magit-patch" "\
-Request upstream to pull from your public repository.
-
-URL is the url of your publicly accessible repository.
-START is a commit that already is in the upstream repository.
-END is the last commit, usually a branch name, which upstream
-is asked to pull. START has to be reachable from that commit.
-
-\(fn URL START END)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-patch" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-process" "magit-process.el" (0 0 0 0))
-;;; Generated autoloads from magit-process.el
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-process" '("magit-" "tramp-sh-handle-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-pull" "magit-pull.el" (0 0 0 0))
-;;; Generated autoloads from magit-pull.el
- (autoload 'magit-pull "magit-pull" nil t)
- (autoload 'magit-pull-from-pushremote "magit-pull" nil t)
- (autoload 'magit-pull-from-upstream "magit-pull" nil t)
-
-(autoload 'magit-pull-branch "magit-pull" "\
-Pull from a branch read in the minibuffer.
-
-\(fn SOURCE ARGS)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-pull" '("magit-pull-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-push" "magit-push.el" (0 0 0 0))
-;;; Generated autoloads from magit-push.el
- (autoload 'magit-push "magit-push" nil t)
- (autoload 'magit-push-current-to-pushremote "magit-push" nil t)
- (autoload 'magit-push-current-to-upstream "magit-push" nil t)
-
-(autoload 'magit-push-current "magit-push" "\
-Push the current branch to a branch read in the minibuffer.
-
-\(fn TARGET ARGS)" t nil)
-
-(autoload 'magit-push-other "magit-push" "\
-Push an arbitrary branch or commit somewhere.
-Both the source and the target are read in the minibuffer.
-
-\(fn SOURCE TARGET ARGS)" t nil)
-
-(autoload 'magit-push-refspecs "magit-push" "\
-Push one or multiple REFSPECS to a REMOTE.
-Both the REMOTE and the REFSPECS are read in the minibuffer. To
-use multiple REFSPECS, separate them with commas. Completion is
-only available for the part before the colon, or when no colon
-is used.
-
-\(fn REMOTE REFSPECS ARGS)" t nil)
-
-(autoload 'magit-push-matching "magit-push" "\
-Push all matching branches to another repository.
-If multiple remotes exist, then read one from the user.
-If just one exists, use that without requiring confirmation.
-
-\(fn REMOTE &optional ARGS)" t nil)
-
-(autoload 'magit-push-tags "magit-push" "\
-Push all tags to another repository.
-If only one remote exists, then push to that. Otherwise prompt
-for a remote, offering the remote configured for the current
-branch as default.
-
-\(fn REMOTE &optional ARGS)" t nil)
-
-(autoload 'magit-push-tag "magit-push" "\
-Push a tag to another repository.
-
-\(fn TAG REMOTE &optional ARGS)" t nil)
-
-(autoload 'magit-push-notes-ref "magit-push" "\
-Push a notes ref to another repository.
-
-\(fn REF REMOTE &optional ARGS)" t nil)
- (autoload 'magit-push-implicitly "magit-push" nil t)
-
-(autoload 'magit-push-to-remote "magit-push" "\
-Push to REMOTE without using an explicit refspec.
-The REMOTE is read in the minibuffer.
-
-This command simply runs \"git push -v [ARGS] REMOTE\". ARGS
-are the arguments specified in the popup buffer. No refspec
-arguments are used. Instead the behavior depends on at least
-these Git variables: `push.default', `remote.pushDefault',
-`branch.<branch>.pushRemote', `branch.<branch>.remote',
-`branch.<branch>.merge', and `remote.<remote>.push'.
-
-\(fn REMOTE ARGS)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-push" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-reflog" "magit-reflog.el" (0 0 0 0))
-;;; Generated autoloads from magit-reflog.el
-
-(autoload 'magit-reflog-current "magit-reflog" "\
-Display the reflog of the current branch.
-If `HEAD' is detached, then show the reflog for that instead." t nil)
-
-(autoload 'magit-reflog-other "magit-reflog" "\
-Display the reflog of a branch or another ref.
-
-\(fn REF)" t nil)
-
-(autoload 'magit-reflog-head "magit-reflog" "\
-Display the `HEAD' reflog." t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-reflog" '("magit-reflog-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-refs" "magit-refs.el" (0 0 0 0))
-;;; Generated autoloads from magit-refs.el
- (autoload 'magit-show-refs "magit-refs" nil t)
-
-(autoload 'magit-show-refs-head "magit-refs" "\
-List and compare references in a dedicated buffer.
-Compared with `HEAD'.
-
-\(fn &optional ARGS)" t nil)
-
-(autoload 'magit-show-refs-current "magit-refs" "\
-List and compare references in a dedicated buffer.
-Compare with the current branch or `HEAD' if it is detached.
-
-\(fn &optional ARGS)" t nil)
-
-(autoload 'magit-show-refs-other "magit-refs" "\
-List and compare references in a dedicated buffer.
-Compared with a branch read from the user.
-
-\(fn &optional REF ARGS)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-refs" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-remote" "magit-remote.el" (0 0 0 0))
-;;; Generated autoloads from magit-remote.el
- (autoload 'magit-remote "magit-remote" nil t)
-
-(autoload 'magit-remote-add "magit-remote" "\
-Add a remote named REMOTE and fetch it.
-
-\(fn REMOTE URL &optional ARGS)" t nil)
-
-(autoload 'magit-remote-rename "magit-remote" "\
-Rename the remote named OLD to NEW.
-
-\(fn OLD NEW)" t nil)
-
-(autoload 'magit-remote-remove "magit-remote" "\
-Delete the remote named REMOTE.
-
-\(fn REMOTE)" t nil)
-
-(autoload 'magit-remote-prune "magit-remote" "\
-Remove stale remote-tracking branches for REMOTE.
-
-\(fn REMOTE)" t nil)
-
-(autoload 'magit-remote-prune-refspecs "magit-remote" "\
-Remove stale refspecs for REMOTE.
-
-A refspec is stale if there no longer exists at least one branch
-on the remote that would be fetched due to that refspec. A stale
-refspec is problematic because its existence causes Git to refuse
-to fetch according to the remaining non-stale refspecs.
-
-If only stale refspecs remain, then offer to either delete the
-remote or to replace the stale refspecs with the default refspec.
-
-Also remove the remote-tracking branches that were created due to
-the now stale refspecs. Other stale branches are not removed.
-
-\(fn REMOTE)" t nil)
-
-(autoload 'magit-remote-set-head "magit-remote" "\
-Set the local representation of REMOTE's default branch.
-Query REMOTE and set the symbolic-ref refs/remotes/<remote>/HEAD
-accordingly. With a prefix argument query for the branch to be
-used, which allows you to select an incorrect value if you fancy
-doing that.
-
-\(fn REMOTE &optional BRANCH)" t nil)
-
-(autoload 'magit-remote-unset-head "magit-remote" "\
-Unset the local representation of REMOTE's default branch.
-Delete the symbolic-ref \"refs/remotes/<remote>/HEAD\".
-
-\(fn REMOTE)" t nil)
- (autoload 'magit-remote-configure "magit-remote" nil t)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-remote" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-repos" "magit-repos.el" (0 0 0 0))
-;;; Generated autoloads from magit-repos.el
-
-(autoload 'magit-list-repositories "magit-repos" "\
-Display a list of repositories.
-
-Use the options `magit-repository-directories' to control which
-repositories are displayed." t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-repos" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-reset" "magit-reset.el" (0 0 0 0))
-;;; Generated autoloads from magit-reset.el
- (autoload 'magit-reset "magit" nil t)
-
-(autoload 'magit-reset-mixed "magit-reset" "\
-Reset the `HEAD' and index to COMMIT, but not the working tree.
-
-\(git reset --mixed COMMIT)
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-reset-soft "magit-reset" "\
-Reset the `HEAD' to COMMIT, but not the index and working tree.
-
-\(git reset --soft REVISION)
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-reset-hard "magit-reset" "\
-Reset the `HEAD', index, and working tree to COMMIT.
-
-\(git reset --hard REVISION)
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-reset-keep "magit-reset" "\
-Reset the `HEAD' and index to COMMIT, while keeping uncommitted changes.
-
-\(git reset --keep REVISION)
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-reset-index "magit-reset" "\
-Reset the index to COMMIT.
-Keep the `HEAD' and working tree as-is, so if COMMIT refers to the
-head this effectively unstages all changes.
-
-\(git reset COMMIT .)
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-reset-worktree "magit-reset" "\
-Reset the worktree to COMMIT.
-Keep the `HEAD' and index as-is.
-
-\(fn COMMIT)" t nil)
-
-(autoload 'magit-reset-quickly "magit-reset" "\
-Reset the `HEAD' and index to COMMIT, and possibly the working tree.
-With a prefix argument reset the working tree otherwise don't.
-
-\(git reset --mixed|--hard COMMIT)
-
-\(fn COMMIT &optional HARD)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-reset" '("magit-reset-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-section" "magit-section.el" (0 0 0 0))
-;;; Generated autoloads from magit-section.el
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-section" '("isearch-clean-overlays@magit-mode" "magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-sequence" "magit-sequence.el" (0 0 0
-;;;;;; 0))
-;;; Generated autoloads from magit-sequence.el
-
-(autoload 'magit-sequencer-continue "magit-sequence" "\
-Resume the current cherry-pick or revert sequence." t nil)
-
-(autoload 'magit-sequencer-skip "magit-sequence" "\
-Skip the stopped at commit during a cherry-pick or revert sequence." t nil)
-
-(autoload 'magit-sequencer-abort "magit-sequence" "\
-Abort the current cherry-pick or revert sequence.
-This discards all changes made since the sequence started." t nil)
- (autoload 'magit-cherry-pick "magit-sequence" nil t)
-
-(autoload 'magit-cherry-copy "magit-sequence" "\
-Copy COMMITS from another branch onto the current branch.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then pick all of them,
-without prompting.
-
-\(fn COMMITS &optional ARGS)" t nil)
-
-(autoload 'magit-cherry-apply "magit-sequence" "\
-Apply the changes in COMMITS but do not commit them.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then apply all of them,
-without prompting.
-
-\(fn COMMITS &optional ARGS)" t nil)
-
-(autoload 'magit-cherry-harvest "magit-sequence" "\
-Move COMMITS from another BRANCH onto the current branch.
-Remove the COMMITS from BRANCH and stay on the current branch.
-If a conflict occurs, then you have to fix that and finish the
-process manually.
-
-\(fn COMMITS BRANCH &optional ARGS)" t nil)
-
-(autoload 'magit-cherry-donate "magit-sequence" "\
-Move COMMITS from the current branch onto another existing BRANCH.
-Remove COMMITS from the current branch and stay on that branch.
-If a conflict occurs, then you have to fix that and finish the
-process manually.
-
-\(fn COMMITS BRANCH &optional ARGS)" t nil)
-
-(autoload 'magit-cherry-spinout "magit-sequence" "\
-Move COMMITS from the current branch onto a new BRANCH.
-Remove COMMITS from the current branch and stay on that branch.
-If a conflict occurs, then you have to fix that and finish the
-process manually.
-
-\(fn COMMITS BRANCH START-POINT &optional ARGS)" t nil)
-
-(autoload 'magit-cherry-spinoff "magit-sequence" "\
-Move COMMITS from the current branch onto a new BRANCH.
-Remove COMMITS from the current branch and checkout BRANCH.
-If a conflict occurs, then you have to fix that and finish
-the process manually.
-
-\(fn COMMITS BRANCH START-POINT &optional ARGS)" t nil)
- (autoload 'magit-revert "magit-sequence" nil t)
-
-(autoload 'magit-revert-and-commit "magit-sequence" "\
-Revert COMMIT by creating a new commit.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then revert all of them,
-without prompting.
-
-\(fn COMMIT &optional ARGS)" t nil)
-
-(autoload 'magit-revert-no-commit "magit-sequence" "\
-Revert COMMIT by applying it in reverse to the worktree.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then revert all of them,
-without prompting.
-
-\(fn COMMIT &optional ARGS)" t nil)
- (autoload 'magit-am "magit-sequence" nil t)
-
-(autoload 'magit-am-apply-patches "magit-sequence" "\
-Apply the patches FILES.
-
-\(fn &optional FILES ARGS)" t nil)
-
-(autoload 'magit-am-apply-maildir "magit-sequence" "\
-Apply the patches from MAILDIR.
-
-\(fn &optional MAILDIR ARGS)" t nil)
-
-(autoload 'magit-am-continue "magit-sequence" "\
-Resume the current patch applying sequence." t nil)
-
-(autoload 'magit-am-skip "magit-sequence" "\
-Skip the stopped at patch during a patch applying sequence." t nil)
-
-(autoload 'magit-am-abort "magit-sequence" "\
-Abort the current patch applying sequence.
-This discards all changes made since the sequence started." t nil)
- (autoload 'magit-rebase "magit-sequence" nil t)
- (autoload 'magit-rebase-onto-pushremote "magit-sequence" nil t)
- (autoload 'magit-rebase-onto-upstream "magit-sequence" nil t)
-
-(autoload 'magit-rebase-branch "magit-sequence" "\
-Rebase the current branch onto a branch read in the minibuffer.
-All commits that are reachable from `HEAD' but not from the
-selected branch TARGET are being rebased.
-
-\(fn TARGET ARGS)" t nil)
-
-(autoload 'magit-rebase-subset "magit-sequence" "\
-Rebase a subset of the current branch's history onto a new base.
-Rebase commits from START to `HEAD' onto NEWBASE.
-START has to be selected from a list of recent commits.
-
-\(fn NEWBASE START ARGS)" t nil)
-
-(autoload 'magit-rebase-interactive "magit-sequence" "\
-Start an interactive rebase sequence.
-
-\(fn COMMIT ARGS)" t nil)
-
-(autoload 'magit-rebase-autosquash "magit-sequence" "\
-Combine squash and fixup commits with their intended targets.
-
-\(fn ARGS)" t nil)
-
-(autoload 'magit-rebase-edit-commit "magit-sequence" "\
-Edit a single older commit using rebase.
-
-\(fn COMMIT ARGS)" t nil)
-
-(autoload 'magit-rebase-reword-commit "magit-sequence" "\
-Reword a single older commit using rebase.
-
-\(fn COMMIT ARGS)" t nil)
-
-(autoload 'magit-rebase-remove-commit "magit-sequence" "\
-Remove a single older commit using rebase.
-
-\(fn COMMIT ARGS)" t nil)
-
-(autoload 'magit-rebase-continue "magit-sequence" "\
-Restart the current rebasing operation.
-In some cases this pops up a commit message buffer for you do
-edit. With a prefix argument the old message is reused as-is.
-
-\(fn &optional NOEDIT)" t nil)
-
-(autoload 'magit-rebase-skip "magit-sequence" "\
-Skip the current commit and restart the current rebase operation." t nil)
-
-(autoload 'magit-rebase-edit "magit-sequence" "\
-Edit the todo list of the current rebase operation." t nil)
-
-(autoload 'magit-rebase-abort "magit-sequence" "\
-Abort the current rebase operation, restoring the original branch." t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-sequence" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-stash" "magit-stash.el" (0 0 0 0))
-;;; Generated autoloads from magit-stash.el
- (autoload 'magit-stash "magit-stash" nil t)
-
-(autoload 'magit-stash-both "magit-stash" "\
-Create a stash of the index and working tree.
-Untracked files are included according to infix arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-stash-index "magit-stash" "\
-Create a stash of the index only.
-Unstaged and untracked changes are not stashed. The stashed
-changes are applied in reverse to both the index and the
-worktree. This command can fail when the worktree is not clean.
-Applying the resulting stash has the inverse effect.
-
-\(fn MESSAGE)" t nil)
-
-(autoload 'magit-stash-worktree "magit-stash" "\
-Create a stash of unstaged changes in the working tree.
-Untracked files are included according to infix arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-stash-keep-index "magit-stash" "\
-Create a stash of the index and working tree, keeping index intact.
-Untracked files are included according to infix arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-snapshot-both "magit-stash" "\
-Create a snapshot of the index and working tree.
-Untracked files are included according to infix arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-snapshot-index "magit-stash" "\
-Create a snapshot of the index only.
-Unstaged and untracked changes are not stashed." t nil)
-
-(autoload 'magit-snapshot-worktree "magit-stash" "\
-Create a snapshot of unstaged changes in the working tree.
-Untracked files are included according to infix arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'.
-
-\(fn &optional INCLUDE-UNTRACKED)" t nil)
-
-(autoload 'magit-stash-apply "magit-stash" "\
-Apply a stash to the working tree.
-Try to preserve the stash index. If that fails because there
-are staged changes, apply without preserving the stash index.
-
-\(fn STASH)" t nil)
-
-(autoload 'magit-stash-drop "magit-stash" "\
-Remove a stash from the stash list.
-When the region is active offer to drop all contained stashes.
-
-\(fn STASH)" t nil)
-
-(autoload 'magit-stash-clear "magit-stash" "\
-Remove all stashes saved in REF's reflog by deleting REF.
-
-\(fn REF)" t nil)
-
-(autoload 'magit-stash-branch "magit-stash" "\
-Create and checkout a new BRANCH from STASH.
-
-\(fn STASH BRANCH)" t nil)
-
-(autoload 'magit-stash-branch-here "magit-stash" "\
-Create and checkout a new BRANCH and apply STASH.
-The branch is created using `magit-branch-and-checkout', using the
-current branch or `HEAD' as the start-point.
-
-\(fn STASH BRANCH)" t nil)
-
-(autoload 'magit-stash-format-patch "magit-stash" "\
-Create a patch from STASH
-
-\(fn STASH)" t nil)
-
-(autoload 'magit-stash-list "magit-stash" "\
-List all stashes in a buffer." t nil)
-
-(autoload 'magit-stash-show "magit-stash" "\
-Show all diffs of a stash in a buffer.
-
-\(fn STASH &optional ARGS FILES)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-stash" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-status" "magit-status.el" (0 0 0 0))
-;;; Generated autoloads from magit-status.el
-
-(autoload 'magit-init "magit-status" "\
-Initialize a Git repository, then show its status.
-
-If the directory is below an existing repository, then the user
-has to confirm that a new one should be created inside. If the
-directory is the root of the existing repository, then the user
-has to confirm that it should be reinitialized.
-
-Non-interactively DIRECTORY is (re-)initialized unconditionally.
-
-\(fn DIRECTORY)" t nil)
-
-(autoload 'magit-status "magit-status" "\
-Show the status of the current Git repository in a buffer.
-
-If the current directory isn't located within a Git repository,
-then prompt for an existing repository or an arbitrary directory,
-depending on option `magit-repository-directories', and show the
-status of the selected repository instead.
-
-* If that option specifies any existing repositories, then offer
- those for completion and show the status buffer for the
- selected one.
-
-* Otherwise read an arbitrary directory using regular file-name
- completion. If the selected directory is the top-level of an
- existing working tree, then show the status buffer for that.
-
-* Otherwise offer to initialize the selected directory as a new
- repository. After creating the repository show its status
- buffer.
-
-These fallback behaviors can also be forced using one or more
-prefix arguments:
-
-* With two prefix arguments (or more precisely a numeric prefix
- value of 16 or greater) read an arbitrary directory and act on
- it as described above. The same could be accomplished using
- the command `magit-init'.
-
-* With a single prefix argument read an existing repository, or
- if none can be found based on `magit-repository-directories',
- then fall back to the same behavior as with two prefix
- arguments.
-
-\(fn &optional DIRECTORY CACHE)" t nil)
-
-(defalias 'magit 'magit-status "\
-An alias for `magit-status' for better discoverability.
-
-Instead of invoking this alias for `magit-status' using
-\"M-x magit RET\", you should bind a key to `magit-status'
-and read the info node `(magit)Getting Started', which
-also contains other useful hints.")
-
-(autoload 'magit-status-here "magit-status" "\
-Like `magit-status' but with non-nil `magit-status-goto-file-position'." t nil)
-
-(autoload 'magit-status-setup-buffer "magit-status" "\
-
-
-\(fn &optional DIRECTORY)" nil nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-status" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-submodule" "magit-submodule.el" (0 0
-;;;;;; 0 0))
-;;; Generated autoloads from magit-submodule.el
- (autoload 'magit-submodule "magit-submodule" nil t)
- (autoload 'magit-submodule-add "magit-submodule" nil t)
-
-(autoload 'magit-submodule-read-name-for-path "magit-submodule" "\
-
-
-\(fn PATH &optional PREFER-SHORT)" nil nil)
- (autoload 'magit-submodule-register "magit-submodule" nil t)
- (autoload 'magit-submodule-populate "magit-submodule" nil t)
- (autoload 'magit-submodule-update "magit-submodule" nil t)
- (autoload 'magit-submodule-synchronize "magit-submodule" nil t)
- (autoload 'magit-submodule-unpopulate "magit-submodule" nil t)
-
-(autoload 'magit-submodule-remove "magit-submodule" "\
-Unregister MODULES and remove their working directories.
-
-For safety reasons, do not remove the gitdirs and if a module has
-uncommitted changes, then do not remove it at all. If a module's
-gitdir is located inside the working directory, then move it into
-the gitdir of the superproject first.
-
-With the \"--force\" argument offer to remove dirty working
-directories and with a prefix argument offer to delete gitdirs.
-Both actions are very dangerous and have to be confirmed. There
-are additional safety precautions in place, so you might be able
-to recover from making a mistake here, but don't count on it.
-
-\(fn MODULES ARGS TRASH-GITDIRS)" t nil)
-
-(autoload 'magit-insert-modules "magit-submodule" "\
-Insert submodule sections.
-Hook `magit-module-sections-hook' controls which module sections
-are inserted, and option `magit-module-sections-nested' controls
-whether they are wrapped in an additional section." nil nil)
-
-(autoload 'magit-insert-modules-overview "magit-submodule" "\
-Insert sections for all modules.
-For each section insert the path and the output of `git describe --tags',
-or, failing that, the abbreviated HEAD commit hash." nil nil)
-
-(autoload 'magit-insert-modules-unpulled-from-upstream "magit-submodule" "\
-Insert sections for modules that haven't been pulled from the upstream.
-These sections can be expanded to show the respective commits." nil nil)
-
-(autoload 'magit-insert-modules-unpulled-from-pushremote "magit-submodule" "\
-Insert sections for modules that haven't been pulled from the push-remote.
-These sections can be expanded to show the respective commits." nil nil)
-
-(autoload 'magit-insert-modules-unpushed-to-upstream "magit-submodule" "\
-Insert sections for modules that haven't been pushed to the upstream.
-These sections can be expanded to show the respective commits." nil nil)
-
-(autoload 'magit-insert-modules-unpushed-to-pushremote "magit-submodule" "\
-Insert sections for modules that haven't been pushed to the push-remote.
-These sections can be expanded to show the respective commits." nil nil)
-
-(autoload 'magit-list-submodules "magit-submodule" "\
-Display a list of the current repository's submodules." t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-submodule" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-subtree" "magit-subtree.el" (0 0 0 0))
-;;; Generated autoloads from magit-subtree.el
- (autoload 'magit-subtree "magit-subtree" nil t)
- (autoload 'magit-subtree-import "magit-subtree" nil t)
- (autoload 'magit-subtree-export "magit-subtree" nil t)
-
-(autoload 'magit-subtree-add "magit-subtree" "\
-Add REF from REPOSITORY as a new subtree at PREFIX.
-
-\(fn PREFIX REPOSITORY REF ARGS)" t nil)
-
-(autoload 'magit-subtree-add-commit "magit-subtree" "\
-Add COMMIT as a new subtree at PREFIX.
-
-\(fn PREFIX COMMIT ARGS)" t nil)
-
-(autoload 'magit-subtree-merge "magit-subtree" "\
-Merge COMMIT into the PREFIX subtree.
-
-\(fn PREFIX COMMIT ARGS)" t nil)
-
-(autoload 'magit-subtree-pull "magit-subtree" "\
-Pull REF from REPOSITORY into the PREFIX subtree.
-
-\(fn PREFIX REPOSITORY REF ARGS)" t nil)
-
-(autoload 'magit-subtree-push "magit-subtree" "\
-Extract the history of the subtree PREFIX and push it to REF on REPOSITORY.
-
-\(fn PREFIX REPOSITORY REF ARGS)" t nil)
-
-(autoload 'magit-subtree-split "magit-subtree" "\
-Extract the history of the subtree PREFIX.
-
-\(fn PREFIX COMMIT ARGS)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-subtree" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-tag" "magit-tag.el" (0 0 0 0))
-;;; Generated autoloads from magit-tag.el
- (autoload 'magit-tag "magit" nil t)
-
-(autoload 'magit-tag-create "magit-tag" "\
-Create a new tag with the given NAME at REV.
-With a prefix argument annotate the tag.
-
-\(git tag [--annotate] NAME REV)
-
-\(fn NAME REV &optional ARGS)" t nil)
-
-(autoload 'magit-tag-delete "magit-tag" "\
-Delete one or more tags.
-If the region marks multiple tags (and nothing else), then offer
-to delete those, otherwise prompt for a single tag to be deleted,
-defaulting to the tag at point.
-
-\(git tag -d TAGS)
-
-\(fn TAGS)" t nil)
-
-(autoload 'magit-tag-prune "magit-tag" "\
-Offer to delete tags missing locally from REMOTE, and vice versa.
-
-\(fn TAGS REMOTE-TAGS REMOTE)" t nil)
-
-(autoload 'magit-tag-release "magit-tag" "\
-Create a release tag.
-
-Assume that release tags match `magit-release-tag-regexp'.
-
-First prompt for the name of the new tag using the highest
-existing tag as initial input and leaving it to the user to
-increment the desired part of the version string.
-
-If `--annotate' is enabled, then prompt for the message of the
-new tag. Base the proposed tag message on the message of the
-highest tag, provided that that contains the corresponding
-version string and substituting the new version string for that.
-Otherwise propose something like \"Foo-Bar 1.2.3\", given, for
-example, a TAG \"v1.2.3\" and a repository located at something
-like \"/path/to/foo-bar\".
-
-\(fn TAG MSG &optional ARGS)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-tag" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-transient" "magit-transient.el" (0 0
-;;;;;; 0 0))
-;;; Generated autoloads from magit-transient.el
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-transient" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-utils" "magit-utils.el" (0 0 0 0))
-;;; Generated autoloads from magit-utils.el
-
-(autoload 'magit-emacs-Q-command "magit-utils" "\
-Show a shell command that runs an uncustomized Emacs with only Magit loaded.
-See info node `(magit)Debugging Tools' for more information." t nil)
-
-(autoload 'Info-follow-nearest-node--magit-gitman "magit-utils" "\
-
-
-\(fn FN &optional FORK)" nil nil)
-
-(advice-add 'Info-follow-nearest-node :around 'Info-follow-nearest-node--magit-gitman)
-
-(autoload 'org-man-export--magit-gitman "magit-utils" "\
-
-
-\(fn FN LINK DESCRIPTION FORMAT)" nil nil)
-
-(advice-add 'org-man-export :around 'org-man-export--magit-gitman)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-utils" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-wip" "magit-wip.el" (0 0 0 0))
-;;; Generated autoloads from magit-wip.el
-
-(defvar magit-wip-mode nil "\
-Non-nil if Magit-Wip mode is enabled.
-See the `magit-wip-mode' command
-for a description of this minor mode.
-Setting this variable directly does not take effect;
-either customize it (see the info node `Easy Customization')
-or call the function `magit-wip-mode'.")
-
-(custom-autoload 'magit-wip-mode "magit-wip" nil)
-
-(autoload 'magit-wip-mode "magit-wip" "\
-Save uncommitted changes to work-in-progress refs.
-
-If called interactively, enable Magit-Wip mode if ARG is
-positive, and disable it if ARG is zero or negative. If called
-from Lisp, also enable the mode if ARG is omitted or nil, and
-toggle it if ARG is `toggle'; disable the mode otherwise.
-
-Whenever appropriate (i.e. when dataloss would be a possibility
-otherwise) this mode causes uncommitted changes to be committed
-to dedicated work-in-progress refs.
-
-For historic reasons this mode is implemented on top of four
-other `magit-wip-*' modes, which can also be used individually,
-if you want finer control over when the wip refs are updated;
-but that is discouraged.
-
-\(fn &optional ARG)" t nil)
-
-(put 'magit-wip-after-save-mode 'globalized-minor-mode t)
-
-(defvar magit-wip-after-save-mode nil "\
-Non-nil if Magit-Wip-After-Save mode is enabled.
-See the `magit-wip-after-save-mode' command
-for a description of this minor mode.
-Setting this variable directly does not take effect;
-either customize it (see the info node `Easy Customization')
-or call the function `magit-wip-after-save-mode'.")
-
-(custom-autoload 'magit-wip-after-save-mode "magit-wip" nil)
-
-(autoload 'magit-wip-after-save-mode "magit-wip" "\
-Toggle Magit-Wip-After-Save-Local mode in all buffers.
-With prefix ARG, enable Magit-Wip-After-Save mode if ARG is positive;
-otherwise, disable it. If called from Lisp, enable the mode if
-ARG is omitted or nil.
-
-Magit-Wip-After-Save-Local mode is enabled in all buffers where
-`magit-wip-after-save-local-mode-turn-on' would do it.
-See `magit-wip-after-save-local-mode' for more information on Magit-Wip-After-Save-Local mode.
-
-\(fn &optional ARG)" t nil)
-
-(defvar magit-wip-after-apply-mode nil "\
-Non-nil if Magit-Wip-After-Apply mode is enabled.
-See the `magit-wip-after-apply-mode' command
-for a description of this minor mode.")
-
-(custom-autoload 'magit-wip-after-apply-mode "magit-wip" nil)
-
-(autoload 'magit-wip-after-apply-mode "magit-wip" "\
-Commit to work-in-progress refs.
-
-If called interactively, enable Magit-Wip-After-Apply mode if ARG
-is positive, and disable it if ARG is zero or negative. If
-called from Lisp, also enable the mode if ARG is omitted or nil,
-and toggle it if ARG is `toggle'; disable the mode otherwise.
-
-After applying a change using any \"apply variant\"
-command (apply, stage, unstage, discard, and reverse) commit the
-affected files to the current wip refs. For each branch there
-may be two wip refs; one contains snapshots of the files as found
-in the worktree and the other contains snapshots of the entries
-in the index.
-
-\(fn &optional ARG)" t nil)
-
-(defvar magit-wip-before-change-mode nil "\
-Non-nil if Magit-Wip-Before-Change mode is enabled.
-See the `magit-wip-before-change-mode' command
-for a description of this minor mode.")
-
-(custom-autoload 'magit-wip-before-change-mode "magit-wip" nil)
-
-(autoload 'magit-wip-before-change-mode "magit-wip" "\
-Commit to work-in-progress refs before certain destructive changes.
-
-If called interactively, enable Magit-Wip-Before-Change mode if
-ARG is positive, and disable it if ARG is zero or negative. If
-called from Lisp, also enable the mode if ARG is omitted or nil,
-and toggle it if ARG is `toggle'; disable the mode otherwise.
-
-Before invoking a revert command or an \"apply variant\"
-command (apply, stage, unstage, discard, and reverse) commit the
-affected tracked files to the current wip refs. For each branch
-there may be two wip refs; one contains snapshots of the files
-as found in the worktree and the other contains snapshots of the
-entries in the index.
-
-Only changes to files which could potentially be affected by the
-command which is about to be called are committed.
-
-\(fn &optional ARG)" t nil)
-
-(autoload 'magit-wip-commit-initial-backup "magit-wip" "\
-Before saving, commit current file to a worktree wip ref.
-
-The user has to add this function to `before-save-hook'.
-
-Commit the current state of the visited file before saving the
-current buffer to that file. This backs up the same version of
-the file as `backup-buffer' would, but stores the backup in the
-worktree wip ref, which is also used by the various Magit Wip
-modes, instead of in a backup file as `backup-buffer' would.
-
-This function ignores the variables that affect `backup-buffer'
-and can be used along-side that function, which is recommended
-because this function only backs up files that are tracked in
-a Git repository." nil nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-wip" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil "magit-worktree" "magit-worktree.el" (0 0 0
-;;;;;; 0))
-;;; Generated autoloads from magit-worktree.el
- (autoload 'magit-worktree "magit-worktree" nil t)
-
-(autoload 'magit-worktree-checkout "magit-worktree" "\
-Checkout BRANCH in a new worktree at PATH.
-
-\(fn PATH BRANCH)" t nil)
-
-(autoload 'magit-worktree-branch "magit-worktree" "\
-Create a new BRANCH and check it out in a new worktree at PATH.
-
-\(fn PATH BRANCH START-POINT &optional FORCE)" t nil)
-
-(autoload 'magit-worktree-move "magit-worktree" "\
-Move WORKTREE to PATH.
-
-\(fn WORKTREE PATH)" t nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-worktree" '("magit-")))
-
-;;;***
-\f
-;;;### (autoloads nil nil ("magit-core.el" "magit-pkg.el") (0 0 0
-;;;;;; 0))
-
-;;;***
-\f
-;; Local Variables:
-;; version-control: never
-;; no-byte-compile: t
-;; no-update-autoloads: t
-;; coding: utf-8
-;; End:
-;;; magit-autoloads.el ends here
+++ /dev/null
-;;; magit-autorevert.el --- revert buffers when files in repository change -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(require 'magit-git)
-
-(require 'autorevert)
-
-;;; Options
-
-(defgroup magit-auto-revert nil
- "Revert buffers when files in repository change."
- :link '(custom-group-link auto-revert)
- :link '(info-link "(magit)Automatic Reverting of File-Visiting Buffers")
- :group 'auto-revert
- :group 'magit-essentials
- :group 'magit-modes)
-
-(defcustom auto-revert-buffer-list-filter nil
- "Filter that determines which buffers `auto-revert-buffers' reverts.
-
-This option is provided by Magit, which also advises
-`auto-revert-buffers' to respect it. Magit users who do not turn
-on the local mode `auto-revert-mode' themselves, are best served
-by setting the value to `magit-auto-revert-repository-buffer-p'.
-
-However the default is nil, so as not to disturb users who do use
-the local mode directly. If you experience delays when running
-Magit commands, then you should consider using one of the
-predicates provided by Magit - especially if you also use Tramp.
-
-Users who do turn on `auto-revert-mode' in buffers in which Magit
-doesn't do that for them, should likely not use any filter.
-Users who turn on `global-auto-revert-mode', do not have to worry
-about this option, because it is disregarded if the global mode
-is enabled."
- :package-version '(magit . "2.4.2")
- :group 'auto-revert
- :group 'magit-auto-revert
- :group 'magit-related
- :type '(radio (const :tag "No filter" nil)
- (function-item magit-auto-revert-buffer-p)
- (function-item magit-auto-revert-repository-buffer-p)
- function))
-
-(defcustom magit-auto-revert-tracked-only t
- "Whether `magit-auto-revert-mode' only reverts tracked files."
- :package-version '(magit . "2.4.0")
- :group 'magit-auto-revert
- :type 'boolean
- :set (lambda (var val)
- (set var val)
- (when (and (bound-and-true-p magit-auto-revert-mode)
- (featurep 'magit-autorevert))
- (magit-auto-revert-mode -1)
- (magit-auto-revert-mode))))
-
-(defcustom magit-auto-revert-immediately t
- "Whether Magit reverts buffers immediately.
-
-If this is non-nil and either `global-auto-revert-mode' or
-`magit-auto-revert-mode' is enabled, then Magit immediately
-reverts buffers by explicitly calling `auto-revert-buffers'
-after running Git for side-effects.
-
-If `auto-revert-use-notify' is non-nil (and file notifications
-are actually supported), then `magit-auto-revert-immediately'
-does not have to be non-nil, because the reverts happen
-immediately anyway.
-
-If `magit-auto-revert-immediately' and `auto-revert-use-notify'
-are both nil, then reverts happen after `auto-revert-interval'
-seconds of user inactivity. That is not desirable."
- :package-version '(magit . "2.4.0")
- :group 'magit-auto-revert
- :type 'boolean)
-
-;;; Mode
-
-(defun magit-turn-on-auto-revert-mode-if-desired (&optional file)
- (if file
- (--when-let (find-buffer-visiting file)
- (with-current-buffer it
- (magit-turn-on-auto-revert-mode-if-desired)))
- (when (and buffer-file-name
- (file-readable-p buffer-file-name)
- (or (< emacs-major-version 27)
- (with-no-warnings
- (condition-case nil
- (executable-find magit-git-executable t) ; see #3684
- (wrong-number-of-arguments t)))) ; very old 27 built
- (magit-toplevel)
- (or (not magit-auto-revert-tracked-only)
- (magit-file-tracked-p buffer-file-name))
- (not auto-revert-mode) ; see #3014
- (not global-auto-revert-mode)) ; see #3460
- (auto-revert-mode 1))))
-
-;;;###autoload
-(define-globalized-minor-mode magit-auto-revert-mode auto-revert-mode
- magit-turn-on-auto-revert-mode-if-desired
- :package-version '(magit . "2.4.0")
- :link '(info-link "(magit)Automatic Reverting of File-Visiting Buffers")
- :group 'magit-auto-revert
- :group 'magit-essentials
- ;; - When `global-auto-revert-mode' is enabled, then this mode is
- ;; redundant.
- ;; - In all other cases enable the mode because if buffers are not
- ;; automatically reverted that would make many very common tasks
- ;; much more cumbersome.
- :init-value (not (or global-auto-revert-mode
- noninteractive)))
-;; - Unfortunately `:init-value t' only sets the value of the mode
-;; variable but does not cause the mode function to be called.
-;; - I don't think it works like this on purpose, but since one usually
-;; should not enable global modes by default, it is understandable.
-;; - If the user has set the variable `magit-auto-revert-mode' to nil
-;; after loading magit (instead of doing so before loading magit or
-;; by using the function), then we should still respect that setting.
-;; - If the user sets one of these variables after loading magit and
-;; after `after-init-hook' has run, then that won't have an effect
-;; and there is nothing we can do about it.
-(defun magit-auto-revert-mode--init-kludge ()
- "This is an internal kludge to be used on `after-init-hook'.
-Do not use this function elsewhere, and don't remove it from
-the `after-init-hook'. For more information see the comments
-and code surrounding the definition of this function."
- (if magit-auto-revert-mode
- (let ((start (current-time)))
- (magit-message "Turning on magit-auto-revert-mode...")
- (magit-auto-revert-mode 1)
- (magit-message
- "Turning on magit-auto-revert-mode...done%s"
- (let ((elapsed (float-time (time-subtract nil start))))
- (if (> elapsed 0.2)
- (format " (%.3fs, %s buffers checked)" elapsed
- (length (buffer-list)))
- ""))))
- (magit-auto-revert-mode -1)))
-(if after-init-time
- ;; Since `after-init-hook' has already been
- ;; run, turn the mode on or off right now.
- (magit-auto-revert-mode--init-kludge)
- ;; By the time the init file has been fully loaded the
- ;; values of the relevant variables might have changed.
- (add-hook 'after-init-hook #'magit-auto-revert-mode--init-kludge t))
-
-(put 'magit-auto-revert-mode 'function-documentation
- "Toggle Magit Auto Revert mode.
-If called interactively, enable Magit Auto Revert mode if ARG is
-positive, and disable it if ARG is zero or negative. If called
-from Lisp, also enable the mode if ARG is omitted or nil, and
-toggle it if ARG is `toggle'; disable the mode otherwise.
-
-Magit Auto Revert mode is a global minor mode that reverts
-buffers associated with a file that is located inside a Git
-repository when the file changes on disk. Use `auto-revert-mode'
-to revert a particular buffer. Or use `global-auto-revert-mode'
-to revert all file-visiting buffers, not just those that visit
-a file located inside a Git repository.
-
-This global mode works by turning on the buffer-local mode
-`auto-revert-mode' at the time a buffer is first created. The
-local mode is turned on if the visited file is being tracked in
-a Git repository at the time when the buffer is created.
-
-If `magit-auto-revert-tracked-only' is non-nil (the default),
-then only tracked files are reverted. But if you stage a
-previously untracked file using `magit-stage', then this mode
-notices that.
-
-Unlike `global-auto-revert-mode', this mode never reverts any
-buffers that are not visiting files.
-
-The behavior of this mode can be customized using the options
-in the `autorevert' and `magit-autorevert' groups.
-
-This function calls the hook `magit-auto-revert-mode-hook'.
-
-Like nearly every mode, this mode should be enabled or disabled
-by calling the respective mode function, the reason being that
-changing the state of a mode involves more than merely toggling
-a single switch, so setting the mode variable is not enough.
-Also, you should not use `after-init-hook' to disable this mode.")
-
-(defun magit-auto-revert-buffers ()
- (when (and magit-auto-revert-immediately
- (or global-auto-revert-mode
- (and magit-auto-revert-mode auto-revert-buffer-list)))
- (let ((auto-revert-buffer-list-filter
- (or auto-revert-buffer-list-filter
- #'magit-auto-revert-repository-buffer-p)))
- (auto-revert-buffers))))
-
-(defvar magit-auto-revert-toplevel nil)
-
-(defvar magit-auto-revert-counter 1
- "Incremented each time `auto-revert-buffers' is called.")
-
-(defun magit-auto-revert-buffer-p (buffer)
- "Return non-nil if BUFFER visits a file inside the current repository.
-The current repository is the one containing `default-directory'.
-If there is no current repository, then return t for any BUFFER."
- (magit-auto-revert-repository-buffer-p buffer t))
-
-(defun magit-auto-revert-repository-buffer-p (buffer &optional fallback)
- "Return non-nil if BUFFER visits a file inside the current repository.
-The current repository is the one containing `default-directory'.
-If there is no current repository, then return FALLBACK (which
-defaults to nil) for any BUFFER."
- ;; Call `magit-toplevel' just once per cycle.
- (unless (and magit-auto-revert-toplevel
- (= (cdr magit-auto-revert-toplevel)
- magit-auto-revert-counter))
- (setq magit-auto-revert-toplevel
- (cons (or (magit-toplevel) 'no-repo)
- magit-auto-revert-counter)))
- (let ((top (car magit-auto-revert-toplevel)))
- (if (eq top 'no-repo)
- fallback
- (let ((dir (buffer-local-value 'default-directory buffer)))
- (and (equal (file-remote-p dir)
- (file-remote-p top))
- ;; ^ `tramp-handle-file-in-directory-p' lacks this optimization.
- (file-in-directory-p dir top))))))
-
-(defun auto-revert-buffers--buffer-list-filter (fn)
- (cl-incf magit-auto-revert-counter)
- (if (or global-auto-revert-mode
- (not auto-revert-buffer-list)
- (not auto-revert-buffer-list-filter))
- (funcall fn)
- (let ((auto-revert-buffer-list
- (-filter auto-revert-buffer-list-filter
- auto-revert-buffer-list)))
- (funcall fn))
- (unless auto-revert-timer
- (auto-revert-set-timer))))
-
-(advice-add 'auto-revert-buffers :around
- 'auto-revert-buffers--buffer-list-filter)
-
-;;; _
-(provide 'magit-autorevert)
-;;; magit-autorevert.el ends here
+++ /dev/null
-;;; magit-bisect.el --- bisect support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2011-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Use a binary search to find the commit that introduced a bug.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Options
-
-(defcustom magit-bisect-show-graph t
- "Whether to use `--graph' in the log showing commits yet to be bisected."
- :package-version '(magit . "2.8.0")
- :group 'magit-status
- :type 'boolean)
-
-(defface magit-bisect-good
- '((t :foreground "DarkOliveGreen"))
- "Face for good bisect revisions."
- :group 'magit-faces)
-
-(defface magit-bisect-skip
- '((t :foreground "DarkGoldenrod"))
- "Face for skipped bisect revisions."
- :group 'magit-faces)
-
-(defface magit-bisect-bad
- '((t :foreground "IndianRed4"))
- "Face for bad bisect revisions."
- :group 'magit-faces)
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-bisect "magit-bisect" nil t)
-(transient-define-prefix magit-bisect ()
- "Narrow in on the commit that introduced a bug."
- :man-page "git-bisect"
- [:class transient-subgroups
- :if-not magit-bisect-in-progress-p
- ["Arguments"
- ("-n" "Don't checkout commits" "--no-checkout")
- ("-p" "Follow only first parent of a merge" "--first-parent"
- :if (lambda () (version<= "2.29" (magit-git-version))))]
- ["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)
- ("k" "Skip" magit-bisect-skip)
- ("r" "Reset" magit-bisect-reset)
- ("s" "Run script" magit-bisect-run)])
-
-;;;###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 know
-good and a bad commit. To move the session forward use the
-other actions from the bisect transient command (\
-\\<magit-status-mode-map>\\[magit-bisect])."
- (interactive (if (magit-bisect-in-progress-p)
- (user-error "Already bisecting")
- (magit-bisect-start-read-args)))
- (unless (magit-rev-ancestor-p good bad)
- (user-error
- "The good revision (%s) has to be an ancestor of the bad one (%s)"
- good bad))
- (when (magit-anything-modified-p)
- (user-error "Cannot bisect with uncommitted changes"))
- (magit-git-bisect "start" (list args bad good) t))
-
-(defun magit-bisect-start-read-args ()
- (let ((bad (magit-read-branch-or-commit "Start bisect with bad revision")))
- (list bad
- (magit-read-other-branch-or-commit "Good revision" bad)
- (transient-args 'magit-bisect))))
-
-;;;###autoload
-(defun magit-bisect-reset ()
- "After bisecting, cleanup bisection state and return to original `HEAD'."
- (interactive)
- (magit-confirm 'reset-bisect)
- (magit-run-git "bisect" "reset")
- (ignore-errors (delete-file (magit-git-dir "BISECT_CMD_OUTPUT"))))
-
-;;;###autoload
-(defun magit-bisect-good ()
- "While bisecting, mark the current commit as good.
-Use this after you have asserted that the commit does not contain
-the bug in question."
- (interactive)
- (magit-git-bisect "good"))
-
-;;;###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 "bad"))
-
-;;;###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 bad good args))
- (magit-git-bisect "run" (list shell-file-name shell-command-switch cmdline)))
-
-(defun magit-git-bisect (subcommand &optional args no-assert)
- (unless (or no-assert (magit-bisect-in-progress-p))
- (user-error "Not bisecting"))
- (message "Bisecting...")
- (magit-with-toplevel
- (magit-run-git-async "bisect" subcommand args))
- (set-process-sentinel
- magit-this-process
- (lambda (process event)
- (when (memq (process-status process) '(exit signal))
- (if (> (process-exit-status process) 0)
- (magit-process-sentinel process event)
- (process-put process 'inhibit-refresh t)
- (magit-process-sentinel process event)
- (when (buffer-live-p (process-buffer process))
- (with-current-buffer (process-buffer process)
- (when-let ((section (get-text-property (point) 'magit-section))
- (output (buffer-substring-no-properties
- (oref section content)
- (oref section end))))
- (with-temp-file (magit-git-dir "BISECT_CMD_OUTPUT")
- (insert output)))))
- (magit-refresh))
- (message "Bisecting...done")))))
-
-;;; Sections
-
-(defun magit-bisect-in-progress-p ()
- (file-exists-p (magit-git-dir "BISECT_LOG")))
-
-(defun magit-insert-bisect-output ()
- "While bisecting, insert section with output from `git bisect'."
- (when (magit-bisect-in-progress-p)
- (let* ((lines
- (or (magit-file-lines (magit-git-dir "BISECT_CMD_OUTPUT"))
- (list "Bisecting: (no saved bisect output)"
- "It appears you have invoked `git bisect' from a shell."
- "There is nothing wrong with that, we just cannot display"
- "anything useful here. Consult the shell output instead.")))
- (done-re "^\\([a-z0-9]\\{40\\}\\) is the first bad commit$")
- (bad-line (or (and (string-match done-re (car lines))
- (pop lines))
- (--first (string-match done-re it) lines))))
- (magit-insert-section ((eval (if bad-line 'commit 'bisect-output))
- (and bad-line (match-string 1 bad-line)))
- (magit-insert-heading
- (propertize (or bad-line (pop lines))
- 'font-lock-face 'magit-section-heading))
- (dolist (line lines)
- (insert line "\n"))))
- (insert "\n")))
-
-(defun magit-insert-bisect-rest ()
- "While bisecting, insert section visualizing the bisect state."
- (when (magit-bisect-in-progress-p)
- (magit-insert-section (bisect-view)
- (magit-insert-heading "Bisect Rest:")
- (magit-git-wash (apply-partially 'magit-log-wash-log 'bisect-vis)
- "bisect" "visualize" "git" "log"
- "--format=%h%x00%D%x00%s" "--decorate=full"
- (and magit-bisect-show-graph "--graph")))))
-
-(defun magit-insert-bisect-log ()
- "While bisecting, insert section logging bisect progress."
- (when (magit-bisect-in-progress-p)
- (magit-insert-section (bisect-log)
- (magit-insert-heading "Bisect Log:")
- (magit-git-wash #'magit-wash-bisect-log "bisect" "log")
- (insert ?\n))))
-
-(defun magit-wash-bisect-log (_args)
- (let (beg)
- (while (progn (setq beg (point-marker))
- (re-search-forward "^\\(git bisect [^\n]+\n\\)" nil t))
- (magit-bind-match-strings (heading) nil
- (magit-delete-match)
- (save-restriction
- (narrow-to-region beg (point))
- (goto-char (point-min))
- (magit-insert-section (bisect-item heading t)
- (insert (propertize heading 'font-lock-face
- 'magit-section-secondary-heading))
- (magit-insert-heading)
- (magit-wash-sequence
- (apply-partially 'magit-log-wash-rev 'bisect-log
- (magit-abbrev-length)))
- (insert ?\n)))))
- (when (re-search-forward
- "# first bad commit: \\[\\([a-z0-9]\\{40\\}\\)\\] [^\n]+\n" nil t)
- (magit-bind-match-strings (hash) nil
- (magit-delete-match)
- (magit-insert-section (bisect-item)
- (insert hash " is the first bad commit\n"))))))
-
-;;; _
-(provide 'magit-bisect)
-;;; magit-bisect.el ends here
+++ /dev/null
-;;; magit-blame.el --- blame support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2012-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Annotates each line in file-visiting buffer with information from
-;; the revision which last modified the line.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit)
-
-;;; Options
-
-(defgroup magit-blame nil
- "Blame support for Magit."
- :link '(info-link "(magit)Blaming")
- :group 'magit-modes)
-
-(defcustom magit-blame-styles
- '((headings
- (heading-format . "%-20a %C %s\n"))
- (margin
- (margin-format . (" %s%f" " %C %a" " %H"))
- (margin-width . 42)
- (margin-face . magit-blame-margin)
- (margin-body-face . (magit-blame-dimmed)))
- (highlight
- (highlight-face . magit-blame-highlight))
- (lines
- (show-lines . t)
- (show-message . t)))
- "List of styles used to visualize blame information.
-
-Each entry has the form (IDENT (KEY . VALUE)...). IDENT has
-to be a symbol uniquely identifying the style. The following
-KEYs are recognized:
-
- `show-lines'
- Whether to prefix each chunk of lines with a thin line.
- This has no effect if `heading-format' is non-nil.
- `show-message'
- Whether to display a commit's summary line in the echo area
- when crossing chunks.
- `highlight-face'
- Face used to highlight the first line of each chunk.
- If this is nil, then those lines are not highlighted.
- `heading-format'
- String specifying the information to be shown above each
- chunk of lines. It must end with a newline character.
- `margin-format'
- String specifying the information to be shown in the left
- buffer margin. It must NOT end with a newline character.
- This can also be a list of formats used for the lines at
- the same positions within the chunk. If the chunk has
- more lines than formats are specified, then the last is
- repeated.
- `margin-width'
- Width of the margin, provided `margin-format' is non-nil.
- `margin-face'
- Face used in the margin, provided `margin-format' is
- non-nil. This face is used in combination with the faces
- that are specific to the used %-specs. If this is nil,
- then `magit-blame-margin' is used.
- `margin-body-face'
- Face used in the margin for all but first line of a chunk.
- This face is used in combination with the faces that are
- specific to the used %-specs. This can also be a list of
- faces (usually one face), in which case only these faces
- are used and the %-spec faces are ignored. A good value
- might be `(magit-blame-dimmed)'. If this is nil, then
- the same face as for the first line is used.
-
-The following %-specs can be used in `heading-format' and
-`margin-format':
-
- %H hash using face `magit-blame-hash'
- %s summary using face `magit-blame-summary'
- %a author using face `magit-blame-name'
- %A author time using face `magit-blame-date'
- %c committer using face `magit-blame-name'
- %C committer time using face `magit-blame-date'
-
-Additionally if `margin-format' ends with %f, then the string
-that is displayed in the margin is made at least `margin-width'
-characters wide, which may be desirable if the used face sets
-the background color.
-
-The style used in the current buffer can be cycled from the blame
-popup. Blame commands (except `magit-blame-echo') use the first
-style as the initial style when beginning to blame in a buffer."
- :package-version '(magit . "2.13.0")
- :group 'magit-blame
- :type 'string)
-
-(defcustom magit-blame-echo-style 'lines
- "The blame visualization style used by `magit-blame-echo'.
-A symbol that has to be used as the identifier for one of the
-styles defined in `magit-blame-styles'."
- :package-version '(magit . "2.13.0")
- :group 'magit-blame
- :type 'symbol)
-
-(defcustom magit-blame-time-format "%F %H:%M"
- "Format for time strings in blame headings."
- :group 'magit-blame
- :type 'string)
-
-(defcustom magit-blame-read-only t
- "Whether to initially make the blamed buffer read-only."
- :package-version '(magit . "2.13.0")
- :group 'magit-blame
- :type 'boolean)
-
-(defcustom magit-blame-disable-modes '(fci-mode yascroll-bar-mode)
- "List of modes not compatible with Magit-Blame mode.
-This modes are turned off when Magit-Blame mode is turned on,
-and then turned on again when turning off the latter."
- :group 'magit-blame
- :type '(repeat (symbol :tag "Mode")))
-
-(defcustom magit-blame-mode-lighter " Blame"
- "The mode-line lighter of the Magit-Blame mode."
- :group 'magit-blame
- :type '(choice (const :tag "No lighter" "") string))
-
-(defcustom magit-blame-goto-chunk-hook
- '(magit-blame-maybe-update-revision-buffer
- magit-blame-maybe-show-message)
- "Hook run after point entered another chunk."
- :package-version '(magit . "2.13.0")
- :group 'magit-blame
- :type 'hook
- :get 'magit-hook-custom-get
- :options '(magit-blame-maybe-update-revision-buffer
- magit-blame-maybe-show-message))
-
-;;; Faces
-
-(defface magit-blame-highlight
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "grey80"
- :foreground "black")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "grey25"
- :foreground "white"))
- "Face used for highlighting when blaming.
-Also see option `magit-blame-styles'."
- :group 'magit-faces)
-
-(defface magit-blame-margin
- '((t :inherit magit-blame-highlight
- :weight normal
- :slant normal))
- "Face used for the blame margin by default when blaming.
-Also see option `magit-blame-styles'."
- :group 'magit-faces)
-
-(defface magit-blame-dimmed
- '((t :inherit magit-dimmed
- :weight normal
- :slant normal))
- "Face used for the blame margin in some cases when blaming.
-Also see option `magit-blame-styles'."
- :group 'magit-faces)
-
-(defface magit-blame-heading
- `((t ,@(and (>= emacs-major-version 27) '(:extend t))
- :inherit magit-blame-highlight
- :weight normal
- :slant normal))
- "Face used for blame headings by default when blaming.
-Also see option `magit-blame-styles'."
- :group 'magit-faces)
-
-(defface magit-blame-summary nil
- "Face used for commit summaries when blaming."
- :group 'magit-faces)
-
-(defface magit-blame-hash nil
- "Face used for commit hashes when blaming."
- :group 'magit-faces)
-
-(defface magit-blame-name nil
- "Face used for author and committer names when blaming."
- :group 'magit-faces)
-
-(defface magit-blame-date nil
- "Face used for dates when blaming."
- :group 'magit-faces)
-
-;;; Chunks
-
-(defclass magit-blame-chunk ()
- (;; <orig-rev> <orig-line> <final-line> <num-lines>
- (orig-rev :initarg :orig-rev)
- (orig-line :initarg :orig-line)
- (final-line :initarg :final-line)
- (num-lines :initarg :num-lines)
- ;; previous <prev-rev> <prev-file>
- (prev-rev :initform nil)
- (prev-file :initform nil)
- ;; filename <orig-file>
- (orig-file)))
-
-(defun magit-current-blame-chunk (&optional type)
- (or (and (not (and type (not (eq type magit-blame-type))))
- (magit-blame-chunk-at (point)))
- (and type
- (let ((rev (or magit-buffer-refname magit-buffer-revision))
- (file (magit-file-relative-name nil (not magit-buffer-file-name)))
- (line (format "%i,+1" (line-number-at-pos))))
- (unless file
- (error "Buffer does not visit a tracked file"))
- (with-temp-buffer
- (magit-with-toplevel
- (magit-git-insert
- "blame" "--porcelain"
- (if (memq magit-blame-type '(final removal))
- (cons "--reverse" (magit-blame-arguments))
- (magit-blame-arguments))
- "-L" line rev "--" file)
- (goto-char (point-min))
- (car (magit-blame--parse-chunk type))))))))
-
-(defun magit-blame-chunk-at (pos)
- (--some (overlay-get it 'magit-blame-chunk)
- (overlays-at pos)))
-
-(defun magit-blame--overlay-at (&optional pos key)
- (unless pos
- (setq pos (point)))
- (--first (overlay-get it (or key 'magit-blame-chunk))
- (nconc (overlays-at pos)
- (overlays-in pos pos))))
-
-;;; Keymaps
-
-(defvar magit-blame-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "C-c C-q") 'magit-blame-quit)
- map)
- "Keymap for `magit-blame-mode'.
-Note that most blaming key bindings are defined
-in `magit-blame-read-only-mode-map' instead.")
-
-(defvar magit-blame-read-only-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "C-m") 'magit-show-commit)
- (define-key map (kbd "p") 'magit-blame-previous-chunk)
- (define-key map (kbd "P") 'magit-blame-previous-chunk-same-commit)
- (define-key map (kbd "n") 'magit-blame-next-chunk)
- (define-key map (kbd "N") 'magit-blame-next-chunk-same-commit)
- (define-key map (kbd "b") 'magit-blame-addition)
- (define-key map (kbd "r") 'magit-blame-removal)
- (define-key map (kbd "f") 'magit-blame-reverse)
- (define-key map (kbd "B") 'magit-blame)
- (define-key map (kbd "c") 'magit-blame-cycle-style)
- (define-key map (kbd "q") 'magit-blame-quit)
- (define-key map (kbd "M-w") 'magit-blame-copy-hash)
- (define-key map (kbd "SPC") 'magit-diff-show-or-scroll-up)
- (define-key map (kbd "S-SPC") 'magit-diff-show-or-scroll-down)
- (define-key map (kbd "DEL") 'magit-diff-show-or-scroll-down)
- map)
- "Keymap for `magit-blame-read-only-mode'.")
-
-;;; Modes
-;;;; Variables
-
-(defvar-local magit-blame-buffer-read-only nil)
-(defvar-local magit-blame-cache nil)
-(defvar-local magit-blame-disabled-modes nil)
-(defvar-local magit-blame-process nil)
-(defvar-local magit-blame-recursive-p nil)
-(defvar-local magit-blame-type nil)
-(defvar-local magit-blame-separator nil)
-(defvar-local magit-blame-previous-chunk nil)
-
-(defvar-local magit-blame--style nil)
-
-(defsubst magit-blame--style-get (key)
- (cdr (assoc key (cdr magit-blame--style))))
-
-;;;; Base Mode
-
-(define-minor-mode magit-blame-mode
- "Display blame information inline."
- :lighter magit-blame-mode-lighter
- (cond (magit-blame-mode
- (when (called-interactively-p 'any)
- (setq magit-blame-mode nil)
- (user-error
- (concat "Don't call `magit-blame-mode' directly; "
- "instead use `magit-blame'")))
- (add-hook 'after-save-hook 'magit-blame--refresh t t)
- (add-hook 'post-command-hook 'magit-blame-goto-chunk-hook t t)
- (add-hook 'before-revert-hook 'magit-blame--remove-overlays t t)
- (add-hook 'after-revert-hook 'magit-blame--refresh t t)
- (add-hook 'read-only-mode-hook 'magit-blame-toggle-read-only t t)
- (setq magit-blame-buffer-read-only buffer-read-only)
- (when (or magit-blame-read-only magit-buffer-file-name)
- (read-only-mode 1))
- (dolist (mode magit-blame-disable-modes)
- (when (and (boundp mode) (symbol-value mode))
- (funcall mode -1)
- (push mode magit-blame-disabled-modes)))
- (setq magit-blame-separator (magit-blame--format-separator))
- (unless magit-blame--style
- (setq magit-blame--style (car magit-blame-styles)))
- (magit-blame--update-margin))
- (t
- (when (process-live-p magit-blame-process)
- (kill-process magit-blame-process)
- (while magit-blame-process
- (sit-for 0.01))) ; avoid racing the sentinel
- (remove-hook 'after-save-hook 'magit-blame--refresh t)
- (remove-hook 'post-command-hook 'magit-blame-goto-chunk-hook t)
- (remove-hook 'before-revert-hook 'magit-blame--remove-overlays t)
- (remove-hook 'after-revert-hook 'magit-blame--refresh t)
- (remove-hook 'read-only-mode-hook 'magit-blame-toggle-read-only t)
- (unless magit-blame-buffer-read-only
- (read-only-mode -1))
- (magit-blame-read-only-mode -1)
- (dolist (mode magit-blame-disabled-modes)
- (funcall mode 1))
- (kill-local-variable 'magit-blame-disabled-modes)
- (kill-local-variable 'magit-blame-type)
- (kill-local-variable 'magit-blame--style)
- (magit-blame--update-margin)
- (magit-blame--remove-overlays))))
-
-(defun magit-blame--refresh ()
- (magit-blame--run (magit-blame-arguments)))
-
-(defun magit-blame-goto-chunk-hook ()
- (let ((chunk (magit-blame-chunk-at (point))))
- (when (cl-typep chunk 'magit-blame-chunk)
- (unless (eq chunk magit-blame-previous-chunk)
- (run-hooks 'magit-blame-goto-chunk-hook))
- (setq magit-blame-previous-chunk chunk))))
-
-(defun magit-blame-toggle-read-only ()
- (magit-blame-read-only-mode (if buffer-read-only 1 -1)))
-
-;;;; Read-Only Mode
-
-(define-minor-mode magit-blame-read-only-mode
- "Provide keybindings for Magit-Blame mode.
-
-This minor-mode provides the key bindings for Magit-Blame mode,
-but only when Read-Only mode is also enabled because these key
-bindings would otherwise conflict badly with regular bindings.
-
-When both Magit-Blame mode and Read-Only mode are enabled, then
-this mode gets automatically enabled too and when one of these
-modes is toggled, then this mode also gets toggled automatically.
-
-\\{magit-blame-read-only-mode-map}")
-
-;;;; Kludges
-
-(defun magit-blame-put-keymap-before-view-mode ()
- "Put `magit-blame-read-only-mode' ahead of `view-mode' in `minor-mode-map-alist'."
- (--when-let (assq 'magit-blame-read-only-mode
- (cl-member 'view-mode minor-mode-map-alist :key #'car))
- (setq minor-mode-map-alist
- (cons it (delq it minor-mode-map-alist))))
- (remove-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode))
-
-(add-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode)
-
-;;; Process
-
-(defun magit-blame--run (args)
- (magit-with-toplevel
- (unless magit-blame-mode
- (magit-blame-mode 1))
- (message "Blaming...")
- (magit-blame-run-process
- (or magit-buffer-refname magit-buffer-revision)
- (magit-file-relative-name nil (not magit-buffer-file-name))
- (if (memq magit-blame-type '(final removal))
- (cons "--reverse" args)
- args)
- (list (line-number-at-pos (window-start))
- (line-number-at-pos (1- (window-end nil t)))))
- (set-process-sentinel magit-this-process
- 'magit-blame-process-quickstart-sentinel)))
-
-(defun magit-blame-run-process (revision file args &optional lines)
- (let ((process (magit-parse-git-async
- "blame" "--incremental" args
- (and lines (list "-L" (apply #'format "%s,%s" lines)))
- revision "--" file)))
- (set-process-filter process 'magit-blame-process-filter)
- (set-process-sentinel process 'magit-blame-process-sentinel)
- (process-put process 'arguments (list revision file args))
- (setq magit-blame-cache (make-hash-table :test 'equal))
- (setq magit-blame-process process)))
-
-(defun magit-blame-process-quickstart-sentinel (process event)
- (when (memq (process-status process) '(exit signal))
- (magit-blame-process-sentinel process event t)
- (magit-blame-assert-buffer process)
- (with-current-buffer (process-get process 'command-buf)
- (when magit-blame-mode
- (let ((default-directory (magit-toplevel)))
- (apply #'magit-blame-run-process
- (process-get process 'arguments)))))))
-
-(defun magit-blame-process-sentinel (process _event &optional quiet)
- (let ((status (process-status process)))
- (when (memq status '(exit signal))
- (kill-buffer (process-buffer process))
- (if (and (eq status 'exit)
- (zerop (process-exit-status process)))
- (unless quiet
- (message "Blaming...done"))
- (magit-blame-assert-buffer process)
- (with-current-buffer (process-get process 'command-buf)
- (if magit-blame-mode
- (progn (magit-blame-mode -1)
- (message "Blaming...failed"))
- (message "Blaming...aborted"))))
- (kill-local-variable 'magit-blame-process))))
-
-(defun magit-blame-process-filter (process string)
- (internal-default-process-filter process string)
- (let ((buf (process-get process 'command-buf))
- (pos (process-get process 'parsed))
- (mark (process-mark process))
- type cache)
- (with-current-buffer buf
- (setq type magit-blame-type)
- (setq cache magit-blame-cache))
- (with-current-buffer (process-buffer process)
- (goto-char pos)
- (while (and (< (point) mark)
- (save-excursion (re-search-forward "^filename .+\n" nil t)))
- (pcase-let* ((`(,chunk ,revinfo)
- (magit-blame--parse-chunk type))
- (rev (oref chunk orig-rev)))
- (if revinfo
- (puthash rev revinfo cache)
- (setq revinfo
- (or (gethash rev cache)
- (puthash rev (magit-blame--commit-alist rev) cache))))
- (magit-blame--make-overlays buf chunk revinfo))
- (process-put process 'parsed (point))))))
-
-(defun magit-blame--parse-chunk (type)
- (let (chunk revinfo)
- (unless (looking-at "^\\(.\\{40\\}\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)")
- (error "Blaming failed due to unexpected output: %s"
- (buffer-substring-no-properties (point) (line-end-position))))
- (with-slots (orig-rev orig-file prev-rev prev-file)
- (setq chunk (magit-blame-chunk
- :orig-rev (match-string 1)
- :orig-line (string-to-number (match-string 2))
- :final-line (string-to-number (match-string 3))
- :num-lines (string-to-number (match-string 4))))
- (forward-line)
- (let (done)
- (while (not done)
- (cond ((looking-at "^filename \\(.+\\)")
- (setq done t)
- (setf orig-file (match-string 1)))
- ((looking-at "^previous \\(.\\{40\\}\\) \\(.+\\)")
- (setf prev-rev (match-string 1))
- (setf prev-file (match-string 2)))
- ((looking-at "^\\([^ ]+\\) \\(.+\\)")
- (push (cons (match-string 1)
- (match-string 2)) revinfo)))
- (forward-line)))
- (when (and (eq type 'removal) prev-rev)
- (cl-rotatef orig-rev prev-rev)
- (cl-rotatef orig-file prev-file)
- (setq revinfo nil)))
- (list chunk revinfo)))
-
-(defun magit-blame--commit-alist (rev)
- (cl-mapcar 'cons
- '("summary"
- "author" "author-time" "author-tz"
- "committer" "committer-time" "committer-tz")
- (split-string (magit-rev-format "%s\v%an\v%ad\v%cn\v%cd" rev
- "--date=format:%s\v%z")
- "\v")))
-
-(defun magit-blame-assert-buffer (process)
- (unless (buffer-live-p (process-get process 'command-buf))
- (kill-process process)
- (user-error "Buffer being blamed has been killed")))
-
-;;; Display
-
-(defun magit-blame--make-overlays (buf chunk revinfo)
- (with-current-buffer buf
- (save-excursion
- (save-restriction
- (widen)
- (goto-char (point-min))
- (forward-line (1- (oref chunk final-line)))
- (let ((beg (point))
- (end (save-excursion
- (forward-line (oref chunk num-lines))
- (point))))
- (magit-blame--remove-overlays beg end)
- (magit-blame--make-margin-overlays chunk revinfo beg end)
- (magit-blame--make-heading-overlay chunk revinfo beg end)
- (magit-blame--make-highlight-overlay chunk beg))))))
-
-(defun magit-blame--make-margin-overlays (chunk revinfo _beg end)
- (save-excursion
- (let ((line 0))
- (while (< (point) end)
- (magit-blame--make-margin-overlay chunk revinfo line)
- (forward-line)
- (cl-incf line)))))
-
-(defun magit-blame--make-margin-overlay (chunk revinfo line)
- (let* ((end (line-end-position))
- ;; If possible avoid putting this on the first character
- ;; of the line to avoid a conflict with the line overlay.
- (beg (min (1+ (line-beginning-position)) end))
- (ov (make-overlay beg end)))
- (overlay-put ov 'magit-blame-chunk chunk)
- (overlay-put ov 'magit-blame-revinfo revinfo)
- (overlay-put ov 'magit-blame-margin line)
- (magit-blame--update-margin-overlay ov)))
-
-(defun magit-blame--make-heading-overlay (chunk revinfo beg end)
- (let ((ov (make-overlay beg end)))
- (overlay-put ov 'magit-blame-chunk chunk)
- (overlay-put ov 'magit-blame-revinfo revinfo)
- (overlay-put ov 'magit-blame-heading t)
- (magit-blame--update-heading-overlay ov)))
-
-(defun magit-blame--make-highlight-overlay (chunk beg)
- (let ((ov (make-overlay beg (1+ (line-end-position)))))
- (overlay-put ov 'magit-blame-chunk chunk)
- (overlay-put ov 'magit-blame-highlight t)
- (magit-blame--update-highlight-overlay ov)))
-
-(defun magit-blame--update-margin ()
- (setq left-margin-width (or (magit-blame--style-get 'margin-width) 0))
- (set-window-buffer (selected-window) (current-buffer)))
-
-(defun magit-blame--update-overlays ()
- (save-restriction
- (widen)
- (dolist (ov (overlays-in (point-min) (point-max)))
- (cond ((overlay-get ov 'magit-blame-heading)
- (magit-blame--update-heading-overlay ov))
- ((overlay-get ov 'magit-blame-margin)
- (magit-blame--update-margin-overlay ov))
- ((overlay-get ov 'magit-blame-highlight)
- (magit-blame--update-highlight-overlay ov))))))
-
-(defun magit-blame--update-margin-overlay (ov)
- (overlay-put
- ov 'before-string
- (and (magit-blame--style-get 'margin-width)
- (propertize
- "o" 'display
- (list (list 'margin 'left-margin)
- (let ((line (overlay-get ov 'magit-blame-margin))
- (format (magit-blame--style-get 'margin-format))
- (face (magit-blame--style-get 'margin-face)))
- (magit-blame--format-string
- ov
- (or (and (atom format)
- format)
- (nth line format)
- (car (last format)))
- (or (and (not (zerop line))
- (magit-blame--style-get 'margin-body-face))
- face
- 'magit-blame-margin))))))))
-
-(defun magit-blame--update-heading-overlay (ov)
- (overlay-put
- ov 'before-string
- (--if-let (magit-blame--style-get 'heading-format)
- (magit-blame--format-string ov it 'magit-blame-heading)
- (and (magit-blame--style-get 'show-lines)
- (or (not (magit-blame--style-get 'margin-format))
- (save-excursion
- (goto-char (overlay-start ov))
- ;; Special case of the special case described in
- ;; `magit-blame--make-margin-overlay'. For empty
- ;; lines it is not possible to show both overlays
- ;; without the line being to high.
- (not (= (point) (line-end-position)))))
- magit-blame-separator))))
-
-(defun magit-blame--update-highlight-overlay (ov)
- (overlay-put ov 'font-lock-face (magit-blame--style-get 'highlight-face)))
-
-(defun magit-blame--format-string (ov format face)
- (let* ((chunk (overlay-get ov 'magit-blame-chunk))
- (revinfo (overlay-get ov 'magit-blame-revinfo))
- (key (list format face))
- (string (cdr (assoc key revinfo))))
- (unless string
- (setq string
- (and format
- (magit-blame--format-string-1 (oref chunk orig-rev)
- revinfo format face)))
- (nconc revinfo (list (cons key string))))
- string))
-
-(defun magit-blame--format-string-1 (rev revinfo format face)
- (let ((str
- (if (equal rev "0000000000000000000000000000000000000000")
- (propertize (concat (if (string-prefix-p "\s" format) "\s" "")
- "Not Yet Committed"
- (if (string-suffix-p "\n" format) "\n" ""))
- 'font-lock-face face)
- (magit--format-spec
- (propertize format 'font-lock-face face)
- (cl-flet* ((p0 (s f)
- (propertize s 'font-lock-face
- (if face
- (if (listp face)
- face
- (list f face))
- f)))
- (p1 (k f)
- (p0 (cdr (assoc k revinfo)) f))
- (p2 (k1 k2 f)
- (p0 (magit-blame--format-time-string
- (cdr (assoc k1 revinfo))
- (cdr (assoc k2 revinfo)))
- f)))
- `((?H . ,(p0 rev 'magit-blame-hash))
- (?s . ,(p1 "summary" 'magit-blame-summary))
- (?a . ,(p1 "author" 'magit-blame-name))
- (?c . ,(p1 "committer" 'magit-blame-name))
- (?A . ,(p2 "author-time" "author-tz" 'magit-blame-date))
- (?C . ,(p2 "committer-time" "committer-tz" 'magit-blame-date))
- (?f . "")))))))
- (if-let ((width (and (string-suffix-p "%f" format)
- (magit-blame--style-get 'margin-width))))
- (concat str
- (propertize (make-string (max 0 (- width (length str))) ?\s)
- 'font-lock-face face))
- str)))
-
-(defun magit-blame--format-separator ()
- (propertize
- (concat (propertize "\s" 'display '(space :height (2)))
- (propertize "\n" 'line-height t))
- 'font-lock-face `(:background
- ,(face-attribute 'magit-blame-heading
- :background nil t)
- ,@(and (>= emacs-major-version 27) '(:extend t)))))
-
-(defun magit-blame--format-time-string (time tz)
- (let* ((time-format (or (magit-blame--style-get 'time-format)
- magit-blame-time-format))
- (tz-in-second (and (string-match "%z" time-format)
- (car (last (parse-time-string tz))))))
- (format-time-string time-format
- (seconds-to-time (string-to-number time))
- tz-in-second)))
-
-(defun magit-blame--remove-overlays (&optional beg end)
- (save-restriction
- (widen)
- (dolist (ov (overlays-in (or beg (point-min))
- (or end (point-max))))
- (when (overlay-get ov 'magit-blame-chunk)
- (delete-overlay ov)))))
-
-(defun magit-blame-maybe-show-message ()
- (when (magit-blame--style-get 'show-message)
- (let ((message-log-max 0))
- (if-let ((msg (cdr (assoc "summary"
- (gethash (oref (magit-current-blame-chunk)
- orig-rev)
- magit-blame-cache)))))
- (progn (set-text-properties 0 (length msg) nil msg)
- (message msg))
- (message "Commit data not available yet. Still blaming.")))))
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-blame-echo "magit-blame" nil t)
-(transient-define-suffix magit-blame-echo (args)
- "For each line show the revision in which it was added.
-Show the information about the chunk at point in the echo area
-when moving between chunks. Unlike other blaming commands, do
-not turn on `read-only-mode'."
- :if (lambda ()
- (and buffer-file-name
- (or (not magit-blame-mode)
- buffer-read-only)))
- (interactive (list (magit-blame-arguments)))
- (when magit-buffer-file-name
- (user-error "Blob buffers aren't supported"))
- (setq-local magit-blame--style
- (assq magit-blame-echo-style magit-blame-styles))
- (setq-local magit-blame-disable-modes
- (cons 'eldoc-mode magit-blame-disable-modes))
- (if (not magit-blame-mode)
- (let ((magit-blame-read-only nil))
- (magit-blame--pre-blame-assert 'addition)
- (magit-blame--pre-blame-setup 'addition)
- (magit-blame--run args))
- (read-only-mode -1)
- (magit-blame--update-overlays)))
-
-;;;###autoload (autoload 'magit-blame-addition "magit-blame" nil t)
-(transient-define-suffix magit-blame-addition (args)
- "For each line show the revision in which it was added."
- (interactive (list (magit-blame-arguments)))
- (magit-blame--pre-blame-assert 'addition)
- (magit-blame--pre-blame-setup 'addition)
- (magit-blame--run args))
-
-;;;###autoload (autoload 'magit-blame-removal "magit-blame" nil t)
-(transient-define-suffix magit-blame-removal (args)
- "For each line show the revision in which it was removed."
- :if-nil 'buffer-file-name
- (interactive (list (magit-blame-arguments)))
- (unless magit-buffer-file-name
- (user-error "Only blob buffers can be blamed in reverse"))
- (magit-blame--pre-blame-assert 'removal)
- (magit-blame--pre-blame-setup 'removal)
- (magit-blame--run args))
-
-;;;###autoload (autoload 'magit-blame-reverse "magit-blame" nil t)
-(transient-define-suffix magit-blame-reverse (args)
- "For each line show the last revision in which it still exists."
- :if-nil 'buffer-file-name
- (interactive (list (magit-blame-arguments)))
- (unless magit-buffer-file-name
- (user-error "Only blob buffers can be blamed in reverse"))
- (magit-blame--pre-blame-assert 'final)
- (magit-blame--pre-blame-setup 'final)
- (magit-blame--run args))
-
-(defun magit-blame--pre-blame-assert (type)
- (unless (magit-toplevel)
- (magit--not-inside-repository-error))
- (if (and magit-blame-mode
- (eq type magit-blame-type))
- (if-let ((chunk (magit-current-blame-chunk)))
- (unless (oref chunk prev-rev)
- (user-error "Chunk has no further history"))
- (user-error "Commit data not available yet. Still blaming."))
- (unless (magit-file-relative-name nil (not magit-buffer-file-name))
- (if buffer-file-name
- (user-error "Buffer isn't visiting a tracked file")
- (user-error "Buffer isn't visiting a file")))))
-
-(defun magit-blame--pre-blame-setup (type)
- (when magit-blame-mode
- (if (eq type magit-blame-type)
- (let ((style magit-blame--style))
- (magit-blame-visit-other-file)
- (setq-local magit-blame--style style)
- (setq-local magit-blame-recursive-p t)
- ;; Set window-start for the benefit of quickstart.
- (redisplay))
- (magit-blame--remove-overlays)))
- (setq magit-blame-type type))
-
-(defun magit-blame-visit-other-file ()
- "Visit another blob related to the current chunk."
- (interactive)
- (with-slots (prev-rev prev-file orig-line)
- (magit-current-blame-chunk)
- (unless prev-rev
- (user-error "Chunk has no further history"))
- (magit-with-toplevel
- (magit-find-file prev-rev prev-file))
- ;; TODO Adjust line like magit-diff-visit-file.
- (goto-char (point-min))
- (forward-line (1- orig-line))))
-
-(defun magit-blame-visit-file ()
- "Visit the blob related to the current chunk."
- (interactive)
- (with-slots (orig-rev orig-file orig-line)
- (magit-current-blame-chunk)
- (magit-with-toplevel
- (magit-find-file orig-rev orig-file))
- (goto-char (point-min))
- (forward-line (1- orig-line))))
-
-(transient-define-suffix magit-blame-quit ()
- "Turn off Magit-Blame mode.
-If the buffer was created during a recursive blame,
-then also kill the buffer."
- :if-non-nil 'magit-blame-mode
- (interactive)
- (magit-blame-mode -1)
- (when magit-blame-recursive-p
- (kill-buffer)))
-
-(defun magit-blame-next-chunk ()
- "Move to the next chunk."
- (interactive)
- (--if-let (next-single-char-property-change (point) 'magit-blame-chunk)
- (goto-char it)
- (user-error "No more chunks")))
-
-(defun magit-blame-previous-chunk ()
- "Move to the previous chunk."
- (interactive)
- (--if-let (previous-single-char-property-change (point) 'magit-blame-chunk)
- (goto-char it)
- (user-error "No more chunks")))
-
-(defun magit-blame-next-chunk-same-commit (&optional previous)
- "Move to the next chunk from the same commit.\n\n(fn)"
- (interactive)
- (if-let ((rev (oref (magit-current-blame-chunk) orig-rev)))
- (let ((pos (point)) ov)
- (save-excursion
- (while (and (not ov)
- (not (= pos (if previous (point-min) (point-max))))
- (setq pos (funcall
- (if previous
- 'previous-single-char-property-change
- 'next-single-char-property-change)
- pos 'magit-blame-chunk)))
- (--when-let (magit-blame--overlay-at pos)
- (when (equal (oref (magit-blame-chunk-at pos) orig-rev) rev)
- (setq ov it)))))
- (if ov
- (goto-char (overlay-start ov))
- (user-error "No more chunks from same commit")))
- (user-error "This chunk hasn't been blamed yet")))
-
-(defun magit-blame-previous-chunk-same-commit ()
- "Move to the previous chunk from the same commit."
- (interactive)
- (magit-blame-next-chunk-same-commit 'previous-single-char-property-change))
-
-(defun magit-blame-cycle-style ()
- "Change how blame information is visualized.
-Cycle through the elements of option `magit-blame-styles'."
- (interactive)
- (setq magit-blame--style
- (or (cadr (cl-member (car magit-blame--style)
- magit-blame-styles :key #'car))
- (car magit-blame-styles)))
- (magit-blame--update-margin)
- (magit-blame--update-overlays))
-
-(defun magit-blame-copy-hash ()
- "Save hash of the current chunk's commit to the kill ring.
-
-When the region is active, then save the region's content
-instead of the hash, like `kill-ring-save' would."
- (interactive)
- (if (use-region-p)
- (call-interactively #'copy-region-as-kill)
- (kill-new (message "%s" (oref (magit-current-blame-chunk) orig-rev)))))
-
-;;; Popup
-
-;;;###autoload (autoload 'magit-blame "magit-blame" nil t)
-(transient-define-prefix magit-blame ()
- "Show the commits that added or removed lines in the visited file."
- :man-page "git-blame"
- :value '("-w")
- ["Arguments"
- ("-w" "Ignore whitespace" "-w")
- ("-r" "Do not treat root commits as boundaries" "--root")
- (magit-blame:-M)
- (magit-blame:-C)]
- ["Actions"
- ("b" "Show commits adding lines" magit-blame-addition)
- ("r" "Show commits removing lines" magit-blame-removal)
- ("f" "Show last commits that still have lines" magit-blame-reverse)
- ("m" "Blame echo" magit-blame-echo)
- ("q" "Quit blaming" magit-blame-quit)]
- ["Refresh"
- :if-non-nil magit-blame-mode
- ("c" "Cycle style" magit-blame-cycle-style :transient t)])
-
-(defun magit-blame-arguments ()
- (transient-args 'magit-blame))
-
-(transient-define-argument magit-blame:-M ()
- :description "Detect lines moved or copied within a file"
- :class 'transient-option
- :argument "-M"
- :reader 'transient-read-number-N+)
-
-(transient-define-argument magit-blame:-C ()
- :description "Detect lines moved or copied between files"
- :class 'transient-option
- :argument "-C"
- :reader 'transient-read-number-N+)
-
-;;; Utilities
-
-(defun magit-blame-maybe-update-revision-buffer ()
- (when-let ((chunk (magit-current-blame-chunk))
- (commit (oref chunk orig-rev))
- (buffer (magit-get-mode-buffer 'magit-revision-mode nil t)))
- (if magit--update-revision-buffer
- (setq magit--update-revision-buffer (list commit buffer))
- (setq magit--update-revision-buffer (list commit buffer))
- (run-with-idle-timer
- magit-update-other-window-delay nil
- (lambda ()
- (pcase-let ((`(,rev ,buf) magit--update-revision-buffer))
- (setq magit--update-revision-buffer nil)
- (when (buffer-live-p buf)
- (let ((magit-display-buffer-noselect t))
- (apply #'magit-show-commit rev
- (magit-diff-arguments 'magit-revision-mode))))))))))
-
-;;; _
-(provide 'magit-blame)
-;;; magit-blame.el ends here
+++ /dev/null
-;;; magit-bookmark.el --- bookmark support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Inspired by an earlier implementation by Yuri Khan.
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Support for bookmarks for most Magit buffers.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit)
-(require 'bookmark)
-
-;;; Core
-
-(defun magit--make-bookmark ()
- "Create a bookmark for the current Magit buffer.
-Input values are the major-mode's `magit-bookmark-name' method,
-and the buffer-local values of the variables referenced in its
-`magit-bookmark-variables' property."
- (if (plist-member (symbol-plist major-mode) 'magit-bookmark-variables)
- (let ((bookmark (bookmark-make-record-default 'no-file)))
- (bookmark-prop-set bookmark 'handler 'magit--handle-bookmark)
- (bookmark-prop-set bookmark 'mode major-mode)
- (bookmark-prop-set bookmark 'filename (magit-toplevel))
- (bookmark-prop-set bookmark 'defaults (list (magit-bookmark-name)))
- (dolist (var (get major-mode 'magit-bookmark-variables))
- (bookmark-prop-set bookmark var (symbol-value var)))
- (bookmark-prop-set
- bookmark 'magit-hidden-sections
- (--keep (and (oref it hidden)
- (cons (oref it type)
- (if (derived-mode-p 'magit-stash-mode)
- (replace-regexp-in-string
- (regexp-quote magit-buffer-revision)
- magit-buffer-revision-hash
- (oref it value))
- (oref it value))))
- (oref magit-root-section children)))
- bookmark)
- (user-error "Bookmarking is not implemented for %s buffers" major-mode)))
-
-;;;###autoload
-(defun magit--handle-bookmark (bookmark)
- "Open a bookmark created by `magit--make-bookmark'.
-Call the `magit-*-setup-buffer' function of the the major-mode
-with the variables' values as arguments, which were recorded by
-`magit--make-bookmark'. Ignore `magit-display-buffer-function'."
- (let ((buffer (let ((default-directory (bookmark-get-filename bookmark))
- (mode (bookmark-prop-get bookmark 'mode))
- (magit-display-buffer-function #'identity)
- (magit-display-buffer-noselect t))
- (apply (intern (format "%s-setup-buffer"
- (substring (symbol-name mode) 0 -5)))
- (--map (bookmark-prop-get bookmark it)
- (get mode 'magit-bookmark-variables))))))
- (set-buffer buffer) ; That is the interface we have to adhere to.
- (when-let ((hidden (bookmark-prop-get bookmark 'magit-hidden-sections)))
- (with-current-buffer buffer
- (dolist (child (oref magit-root-section children))
- (if (member (cons (oref child type)
- (oref child value))
- hidden)
- (magit-section-hide child)
- (magit-section-show child)))))
- nil))
-
-(cl-defgeneric magit-bookmark-name ()
- "Return name for bookmark to current buffer."
- (format "%s%s"
- (substring (symbol-name major-mode) 0 -5)
- (if-let ((vars (get major-mode 'magit-bookmark-variables)))
- (cl-mapcan (lambda (var)
- (let ((val (symbol-value var)))
- (if (and val (atom val))
- (list val)
- val)))
- vars)
- "")))
-
-;;; Diff
-;;;; Diff
-
-(put 'magit-diff-mode 'magit-bookmark-variables
- '(magit-buffer-range-hashed
- magit-buffer-typearg
- magit-buffer-diff-args
- magit-buffer-diff-files))
-
-(cl-defmethod magit-bookmark-name (&context (major-mode magit-diff-mode))
- (format "magit-diff(%s%s)"
- (pcase (magit-diff-type)
- (`staged "staged")
- (`unstaged "unstaged")
- (`committed magit-buffer-range)
- (`undefined
- (delq nil (list magit-buffer-typearg magit-buffer-range-hashed))))
- (if magit-buffer-diff-files
- (concat " -- " (mapconcat #'identity magit-buffer-diff-files " "))
- "")))
-
-;;;; Revision
-
-(put 'magit-revision-mode 'magit-bookmark-variables
- '(magit-buffer-revision-hash
- magit-buffer-diff-args
- magit-buffer-diff-files))
-
-(cl-defmethod magit-bookmark-name (&context (major-mode magit-revision-mode))
- (format "magit-revision(%s %s)"
- (magit-rev-abbrev magit-buffer-revision)
- (if magit-buffer-diff-files
- (mapconcat #'identity magit-buffer-diff-files " ")
- (magit-rev-format "%s" magit-buffer-revision))))
-
-;;;; Stash
-
-(put 'magit-stash-mode 'magit-bookmark-variables
- '(magit-buffer-revision-hash
- magit-buffer-diff-args
- magit-buffer-diff-files))
-
-(cl-defmethod magit-bookmark-name (&context (major-mode magit-stash-mode))
- (format "magit-stash(%s %s)"
- (magit-rev-abbrev magit-buffer-revision)
- (if magit-buffer-diff-files
- (mapconcat #'identity magit-buffer-diff-files " ")
- (magit-rev-format "%s" magit-buffer-revision))))
-
-;;; Log
-;;;; Log
-
-(put 'magit-log-mode 'magit-bookmark-variables
- '(magit-buffer-revisions
- magit-buffer-log-args
- magit-buffer-log-files))
-
-(cl-defmethod magit-bookmark-name (&context (major-mode magit-log-mode))
- (format "magit-log(%s%s)"
- (mapconcat #'identity magit-buffer-revisions " ")
- (if magit-buffer-log-files
- (concat " -- " (mapconcat #'identity magit-buffer-log-files " "))
- "")))
-
-;;;; Cherry
-
-(put 'magit-cherry-mode 'magit-bookmark-variables
- '(magit-buffer-refname
- magit-buffer-upstream))
-
-(cl-defmethod magit-bookmark-name (&context (major-mode magit-cherry-mode))
- (format "magit-cherry(%s > %s)"
- magit-buffer-refname
- magit-buffer-upstream))
-
-;;;; Reflog
-
-(put 'magit-reflog-mode 'magit-bookmark-variables
- '(magit-buffer-refname))
-
-(cl-defmethod magit-bookmark-name (&context (major-mode magit-reflog-mode))
- (format "magit-reflog(%s)" magit-buffer-refname))
-
-;;; Misc
-
-(put 'magit-status-mode 'magit-bookmark-variables nil)
-
-(put 'magit-refs-mode 'magit-bookmark-variables
- '(magit-buffer-upstream
- magit-buffer-arguments))
-
-(put 'magit-stashes-mode 'magit-bookmark-variables nil)
-
-(cl-defmethod magit-bookmark-name (&context (major-mode magit-stashes-mode))
- (format "magit-states(%s)" magit-buffer-refname))
-
-;;; _
-(provide 'magit-bookmark)
-;;; magit-bookmark.el ends here
+++ /dev/null
-;;; magit-branch.el --- branch support -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for branches. It defines commands
-;; for creating, checking out, manipulating, and configuring branches.
-;; Commands defined here are mainly concerned with branches as
-;; pointers, commands that deal with what a branch points at, are
-;; defined elsewhere.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(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
-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/\"))
-
-If you use remote branches as UPSTREAM, then you might also want
-to set `magit-branch-prefer-remote-upstream' to a non-nil value.
-However, I recommend that you use local branches as UPSTREAM."
- :package-version '(magit . "2.9.0")
- :group 'magit-commands
- :type '(repeat (cons (string :tag "Use upstream")
- (choice :tag "for branches"
- (regexp :tag "matching")
- (repeat :tag "except"
- (string :tag "branch"))))))
-
-(defcustom magit-branch-rename-push-target t
- "Whether the push-remote setup is preserved when renaming a branch.
-
-The command `magit-branch-rename' renames a branch named OLD to
-NEW. This option controls how much of the push-remote setup is
-preserved when doing so.
-
-When nil, then preserve nothing and unset `branch.OLD.pushRemote'.
-
-When `local-only', then first set `branch.NEW.pushRemote' to the
- same value as `branch.OLD.pushRemote', provided the latter is
- actually set and unless the former already has another value.
-
-When t, then rename the branch named OLD on the remote specified
- by `branch.OLD.pushRemote' to NEW, provided OLD exists on that
- remote and unless NEW already exists on the remote.
-
-When `forge-only' and the `forge' package is available, then
- behave like `t' if the remote points to a repository on a forge
- (currently Github or Gitlab), otherwise like `local-only'.
-
-Another supported but obsolete value is `github-only'. It is a
- misnomer because it now treated as an alias for `forge-only'."
- :package-version '(magit . "2.90.0")
- :group 'magit-commands
- :type '(choice
- (const :tag "Don't preserve push-remote setup" nil)
- (const :tag "Preserve push-remote setup" local-only)
- (const :tag "... and rename corresponding branch on remote" t)
- (const :tag "... but only if remote is on a forge" forge-only)))
-
-(defcustom magit-branch-direct-configure t
- "Whether the command `magit-branch' shows Git variables.
-When set to nil, no variables are displayed by this transient
-command, instead the sub-transient `magit-branch-configure'
-has to be used to view and change branch related variables."
- :package-version '(magit . "2.7.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-published-branches '("origin/master")
- "List of branches that are considered to be published."
- :package-version '(magit . "2.13.0")
- :group 'magit-commands
- :type '(repeat string))
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-branch "magit" nil t)
-(transient-define-prefix magit-branch (branch)
- "Add, configure or remove a branch."
- :man-page "git-branch"
- ["Variables"
- :if (lambda ()
- (and magit-branch-direct-configure
- (oref transient--prefix scope)))
- ("d" magit-branch.<branch>.description)
- ("u" magit-branch.<branch>.merge/remote)
- ("r" magit-branch.<branch>.rebase)
- ("p" magit-branch.<branch>.pushRemote)]
- [["Checkout"
- ("b" "branch/revision" magit-checkout)
- ("l" "local branch" magit-branch-checkout)
- (6 "o" "new orphan" magit-branch-orphan)]
- [""
- ("c" "new branch" magit-branch-and-checkout)
- ("s" "new spin-off" magit-branch-spinoff)
- (5 "w" "new worktree" magit-worktree-checkout)]
- ["Create"
- ("n" "new branch" magit-branch-create)
- ("S" "new spin-out" magit-branch-spinout)
- (5 "W" "new worktree" magit-worktree-branch)]
- ["Do"
- ("C" "configure..." magit-branch-configure)
- ("m" "rename" magit-branch-rename)
- ("x" "reset" magit-branch-reset)
- ("k" "delete" magit-branch-delete)]
- [""
- (7 "h" "shelve" magit-branch-shelve)
- (7 "H" "unshelve" magit-branch-unshelve)]]
- (interactive (list (magit-get-current-branch)))
- (transient-setup 'magit-branch nil nil :scope branch))
-
-;;;###autoload
-(defun magit-checkout (revision)
- "Checkout REVISION, updating the index and the working tree.
-If REVISION is a local branch, then that becomes the current
-branch. If it is something else, then `HEAD' becomes detached.
-Checkout fails if the working tree or the staging area contain
-changes.
-\n(git checkout REVISION)."
- (interactive (list (magit-read-other-branch-or-commit "Checkout")))
- (when (string-match "\\`heads/\\(.+\\)" revision)
- (setq revision (match-string 1 revision)))
- (magit-run-git "checkout" revision))
-
-;;;###autoload
-(defun magit-branch-create (branch start-point)
- "Create BRANCH at branch or revision START-POINT."
- (interactive (magit-branch-read-args "Create branch"))
- (magit-call-git "branch" branch start-point)
- (magit-branch-maybe-adjust-upstream branch start-point)
- (magit-refresh))
-
-;;;###autoload
-(defun magit-branch-and-checkout (branch start-point)
- "Create and checkout BRANCH at branch or revision START-POINT."
- (interactive (magit-branch-read-args "Create and checkout branch"))
- (if (string-match-p "^stash@{[0-9]+}$" start-point)
- (magit-run-git "stash" "branch" branch start-point)
- (magit-call-git "checkout" "-b" branch start-point)
- (magit-branch-maybe-adjust-upstream branch start-point)
- (magit-refresh)))
-
-;;;###autoload
-(defun magit-branch-or-checkout (arg &optional start-point)
- "Hybrid between `magit-checkout' and `magit-branch-and-checkout'.
-
-Ask the user for an existing branch or revision. If the user
-input actually can be resolved as a branch or revision, then
-check that out, just like `magit-checkout' would.
-
-Otherwise create and checkout a new branch using the input as
-its name. Before doing so read the starting-point for the new
-branch. This is similar to what `magit-branch-and-checkout'
-does."
- (interactive
- (let ((arg (magit-read-other-branch-or-commit "Checkout")))
- (list arg
- (and (not (magit-commit-p arg))
- (magit-read-starting-point "Create and checkout branch" arg)))))
- (when (string-match "\\`heads/\\(.+\\)" arg)
- (setq arg (match-string 1 arg)))
- (if start-point
- (magit-branch-and-checkout arg start-point)
- (magit-checkout arg)))
-
-;;;###autoload
-(defun magit-branch-checkout (branch &optional start-point)
- "Checkout an existing or new local branch.
-
-Read a branch name from the user offering all local branches and
-a subset of remote branches as candidates. Omit remote branches
-for which a local branch by the same name exists from the list
-of candidates. The user can also enter a completely new branch
-name.
-
-- If the user selects an existing local branch, then check that
- out.
-
-- If the user selects a remote branch, then create and checkout
- a new local branch with the same name. Configure the selected
- remote branch as push target.
-
-- If the user enters a new branch name, then create and check
- that out, after also reading the starting-point from the user.
-
-In the latter two cases the upstream is also set. Whether it is
-set to the chosen START-POINT or something else depends on the
-value of `magit-branch-adjust-remote-upstream-alist', just like
-when using `magit-branch-and-checkout'."
- (interactive
- (let* ((current (magit-get-current-branch))
- (local (magit-list-local-branch-names))
- (remote (--filter (and (string-match "[^/]+/" it)
- (not (member (substring it (match-end 0))
- (cons "HEAD" local))))
- (magit-list-remote-branch-names)))
- (choices (nconc (delete current local) remote))
- (atpoint (magit-branch-at-point))
- (choice (magit-completing-read
- "Checkout branch" choices
- nil nil nil 'magit-revision-history
- (or (car (member atpoint choices))
- (and atpoint
- (car (member (and (string-match "[^/]+/" atpoint)
- (substring atpoint (match-end 0)))
- choices)))))))
- (cond ((member choice remote)
- (list (and (string-match "[^/]+/" choice)
- (substring choice (match-end 0)))
- choice))
- ((member choice local)
- (list choice))
- (t
- (list choice (magit-read-starting-point "Create" choice))))))
- (if (not start-point)
- (magit-checkout branch)
- (when (magit-anything-modified-p t)
- (user-error "Cannot checkout when there are uncommitted changes"))
- (magit-branch-and-checkout branch start-point)
- (when (magit-remote-branch-p start-point)
- (pcase-let ((`(,remote . ,remote-branch)
- (magit-split-branch-name start-point)))
- (when (and (equal branch remote-branch)
- (not (equal remote (magit-get "remote.pushDefault"))))
- (magit-set remote "branch" branch "pushRemote"))))))
-
-(defun magit-branch-maybe-adjust-upstream (branch start-point)
- (--when-let
- (or (and (magit-get-upstream-branch branch)
- (magit-get-indirect-upstream-branch start-point))
- (and (magit-remote-branch-p start-point)
- (let ((name (cdr (magit-split-branch-name start-point))))
- (car (--first (if (listp (cdr it))
- (not (member name (cdr it)))
- (string-match-p (cdr it) name))
- magit-branch-adjust-remote-upstream-alist)))))
- (magit-call-git "branch" (concat "--set-upstream-to=" it) branch)))
-
-;;;###autoload
-(defun magit-branch-orphan (branch start-point)
- "Create and checkout an orphan BRANCH with contents from revision START-POINT."
- (interactive (magit-branch-read-args "Create and checkout orphan branch"))
- (magit-run-git "checkout" "--orphan" branch start-point))
-
-(defun magit-branch-read-args (prompt &optional default-start)
- (if magit-branch-read-upstream-first
- (let ((choice (magit-read-starting-point prompt nil default-start)))
- (if (magit-rev-verify choice)
- (list (magit-read-string-ns
- (if magit-completing-read--silent-default
- (format "%s (starting at `%s')" prompt choice)
- "Name for new branch")
- (let ((def (mapconcat #'identity
- (cdr (split-string choice "/"))
- "/")))
- (and (member choice (magit-list-remote-branch-names))
- (not (member def (magit-list-local-branch-names)))
- def)))
- choice)
- (if (eq magit-branch-read-upstream-first 'fallback)
- (list choice
- (magit-read-starting-point prompt choice default-start))
- (user-error "Not a valid starting-point: %s" choice))))
- (let ((branch (magit-read-string-ns (concat prompt " named"))))
- (list branch (magit-read-starting-point prompt branch default-start)))))
-
-;;;###autoload
-(defun magit-branch-spinout (branch &optional from)
- "Create new branch from the unpushed commits.
-Like `magit-branch-spinoff' but remain on the current branch.
-If there are any uncommitted changes, then behave exactly like
-`magit-branch-spinoff'."
- (interactive (list (magit-read-string-ns "Spin out branch")
- (car (last (magit-region-values 'commit)))))
- (magit--branch-spinoff branch from nil))
-
-;;;###autoload
-(defun magit-branch-spinoff (branch &optional from)
- "Create new branch from the unpushed commits.
-
-Create and checkout a new branch starting at and tracking the
-current branch. That branch in turn is reset to the last commit
-it shares with its upstream. If the current branch has no
-upstream or no unpushed commits, then the new branch is created
-anyway and the previously current branch is not touched.
-
-This is useful to create a feature branch after work has already
-began on the old branch (likely but not necessarily \"master\").
-
-If the current branch is a member of the value of option
-`magit-branch-prefer-remote-upstream' (which see), then the
-current branch will be used as the starting point as usual, but
-the upstream of the starting-point may be used as the upstream
-of the new branch, instead of the starting-point itself.
-
-If optional FROM is non-nil, then the source branch is reset
-to `FROM~', instead of to the last commit it shares with its
-upstream. Interactively, FROM is only ever non-nil, if the
-region selects some commits, and among those commits, FROM is
-the commit that is the fewest commits ahead of the source
-branch.
-
-The commit at the other end of the selection actually does not
-matter, all commits between FROM and `HEAD' are moved to the new
-branch. If FROM is not reachable from `HEAD' or is reachable
-from the source branch's upstream, then an error is raised."
- (interactive (list (magit-read-string-ns "Spin off branch")
- (car (last (magit-region-values 'commit)))))
- (magit--branch-spinoff branch from t))
-
-(defun magit--branch-spinoff (branch from checkout)
- (when (magit-branch-p branch)
- (user-error "Cannot spin off %s. It already exists" branch))
- (when (and (not checkout)
- (magit-anything-modified-p))
- (message "Staying on HEAD due to uncommitted changes")
- (setq checkout t))
- (if-let ((current (magit-get-current-branch)))
- (let ((tracked (magit-get-upstream-branch current))
- base)
- (when from
- (unless (magit-rev-ancestor-p from current)
- (user-error "Cannot spin off %s. %s is not reachable from %s"
- branch from current))
- (when (and tracked
- (magit-rev-ancestor-p from tracked))
- (user-error "Cannot spin off %s. %s is ancestor of upstream %s"
- branch from tracked)))
- (let ((magit-process-raise-error t))
- (if checkout
- (magit-call-git "checkout" "-b" branch current)
- (magit-call-git "branch" branch current)))
- (--when-let (magit-get-indirect-upstream-branch current)
- (magit-call-git "branch" "--set-upstream-to" it branch))
- (when (and tracked
- (setq base
- (if from
- (concat from "^")
- (magit-git-string "merge-base" current tracked)))
- (not (magit-rev-eq base current)))
- (if checkout
- (magit-call-git "update-ref" "-m"
- (format "reset: moving to %s" base)
- (concat "refs/heads/" current) base)
- (magit-call-git "reset" "--hard" base))))
- (if checkout
- (magit-call-git "checkout" "-b" branch)
- (magit-call-git "branch" branch)))
- (magit-refresh))
-
-;;;###autoload
-(defun magit-branch-reset (branch to &optional set-upstream)
- "Reset a branch to the tip of another branch or any other commit.
-
-When the branch being reset is the current branch, then do a
-hard reset. If there are any uncommitted changes, then the user
-has to confirm the reset because those changes would be lost.
-
-This is useful when you have started work on a feature branch but
-realize it's all crap and want to start over.
-
-When resetting to another branch and a prefix argument is used,
-then also set the target branch as the upstream of the branch
-that is being reset."
- (interactive
- (let* ((atpoint (magit-local-branch-at-point))
- (branch (magit-read-local-branch "Reset branch" atpoint)))
- (list branch
- (magit-completing-read (format "Reset %s to" branch)
- (delete branch (magit-list-branch-names))
- nil nil nil 'magit-revision-history
- (or (and (not (equal branch atpoint)) atpoint)
- (magit-get-upstream-branch branch)))
- current-prefix-arg)))
- (let ((inhibit-magit-refresh t))
- (if (equal branch (magit-get-current-branch))
- (if (and (magit-anything-modified-p)
- (not (yes-or-no-p
- "Uncommitted changes will be lost. Proceed? ")))
- (user-error "Abort")
- (magit-reset-hard to))
- (magit-call-git "update-ref"
- "-m" (format "reset: moving to %s" to)
- (magit-git-string "rev-parse" "--symbolic-full-name"
- branch)
- to))
- (when (and set-upstream (magit-branch-p to))
- (magit-set-upstream-branch branch to)
- (magit-branch-maybe-adjust-upstream branch to)))
- (magit-refresh))
-
-(defvar magit-branch-delete-never-verify nil
- "Whether `magit-branch-delete' always pushes with \"--no-verify\".")
-
-;;;###autoload
-(defun magit-branch-delete (branches &optional force)
- "Delete one or multiple branches.
-If the region marks multiple branches, then offer to delete
-those, otherwise prompt for a single branch to be deleted,
-defaulting to the branch at point."
- ;; One would expect this to be a command as simple as, for example,
- ;; `magit-branch-rename'; but it turns out everyone wants to squeeze
- ;; a bit of extra functionality into this one, including myself.
- (interactive
- (let ((branches (magit-region-values 'branch t))
- (force current-prefix-arg))
- (if (> (length branches) 1)
- (magit-confirm t nil "Delete %i branches" nil branches)
- (setq branches
- (list (magit-read-branch-prefer-other
- (if force "Force delete branch" "Delete branch")))))
- (unless force
- (when-let ((unmerged (-remove #'magit-branch-merged-p branches)))
- (if (magit-confirm 'delete-unmerged-branch
- "Delete unmerged branch %s"
- "Delete %i unmerged branches"
- 'noabort unmerged)
- (setq force branches)
- (or (setq branches (-difference branches unmerged))
- (user-error "Abort")))))
- (list branches force)))
- (let* ((refs (mapcar #'magit-ref-fullname branches))
- (ambiguous (--remove it refs)))
- (when ambiguous
- (user-error
- "%s ambiguous. Please cleanup using git directly."
- (let ((len (length ambiguous)))
- (cond
- ((= len 1)
- (format "%s is" (-first #'magit-ref-ambiguous-p branches)))
- ((= len (length refs))
- (format "These %s names are" len))
- (t
- (format "%s of these names are" len))))))
- (cond
- ((string-match "^refs/remotes/\\([^/]+\\)" (car refs))
- (let* ((remote (match-string 1 (car refs)))
- (offset (1+ (length remote))))
- ;; Assume the branches actually still exists on the remote.
- (magit-run-git-async
- "push"
- (and (or force magit-branch-delete-never-verify) "--no-verify")
- remote
- (--map (concat ":" (substring it offset)) branches))
- ;; If that is not the case, then this deletes the tracking branches.
- (set-process-sentinel
- magit-this-process
- (apply-partially 'magit-delete-remote-branch-sentinel remote refs))))
- ((> (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)))
- (when (equal branch (magit-get-current-branch))
- (pcase (if (or (equal branch "master")
- (not (magit-rev-verify "master")))
- (magit-read-char-case prompt nil
- (?d "[d]etach HEAD & delete" 'detach)
- (?a "[a]bort" 'abort))
- (magit-read-char-case prompt nil
- (?d "[d]etach HEAD & delete" 'detach)
- (?c "[c]heckout master & delete" 'master)
- (?a "[a]bort" 'abort)))
- (`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"))
- (`master (unless (or (equal force '(4))
- (member branch force)
- (magit-branch-merged-p branch "master"))
- (magit-confirm 'delete-unmerged-branch
- "Delete unmerged branch %s" ""
- nil (list branch)))
- (magit-call-git "checkout" "master"))
- (`abort (user-error "Abort")))
- (setq force t))
- (magit-branch-maybe-delete-pr-remote branch)
- (magit-branch-unset-pushRemote branch)
- (magit-run-git "branch" (if force "-D" "-d") branch))))))
-
-(put 'magit-branch-delete 'interactive-only t)
-
-(defun magit-branch-maybe-delete-pr-remote (branch)
- (when-let ((remote (magit-get "branch" branch "pullRequestRemote")))
- (let* ((variable (format "remote.%s.fetch" remote))
- (refspecs (magit-get-all variable)))
- (unless (member (format "+refs/heads/*:refs/remotes/%s/*" remote)
- refspecs)
- (let ((refspec
- (if (equal (magit-get "branch" branch "pushRemote") remote)
- (format "+refs/heads/%s:refs/remotes/%s/%s"
- branch remote branch)
- (let ((merge (magit-get "branch" branch "merge")))
- (and merge
- (string-prefix-p "refs/heads/" merge)
- (setq merge (substring merge 11))
- (format "+refs/heads/%s:refs/remotes/%s/%s"
- merge remote merge))))))
- (when (member refspec refspecs)
- (if (and (= (length refspecs) 1)
- (magit-confirm 'delete-pr-remote
- (format "Also delete remote %s (%s)" remote
- "no pull-request branch remains")
- nil t))
- (magit-call-git "remote" "rm" remote)
- (magit-call-git "config" "--unset-all" variable
- (format "^%s$" (regexp-quote refspec))))))))))
-
-(defun magit-branch-unset-pushRemote (branch)
- (magit-set nil "branch" branch "pushRemote"))
-
-(defun magit-delete-remote-branch-sentinel (remote refs process event)
- (when (memq (process-status process) '(exit signal))
- (if (= (process-exit-status process) 1)
- (if-let ((on-remote (--map (concat "refs/remotes/" remote "/" it)
- (magit-remote-list-branches remote)))
- (rest (--filter (and (not (member it on-remote))
- (magit-ref-exists-p it))
- refs)))
- (progn
- (process-put process 'inhibit-refresh t)
- (magit-process-sentinel process event)
- (setq magit-this-error nil)
- (message "Some remote branches no longer exist. %s"
- "Deleting just the local tracking refs instead...")
- (dolist (ref rest)
- (magit-call-git "update-ref" "-d" ref))
- (magit-refresh)
- (message "Deleting local remote-tracking refs...done"))
- (magit-process-sentinel process event))
- (magit-process-sentinel process event))))
-
-;;;###autoload
-(defun magit-branch-rename (old new &optional force)
- "Rename the branch named OLD to NEW.
-
-With a prefix argument FORCE, rename even if a branch named NEW
-already exists.
-
-If `branch.OLD.pushRemote' is set, then unset it. Depending on
-the value of `magit-branch-rename-push-target' (which see) maybe
-set `branch.NEW.pushRemote' and maybe rename the push-target on
-the remote."
- (interactive
- (let ((branch (magit-read-local-branch "Rename branch")))
- (list branch
- (magit-read-string-ns (format "Rename branch '%s' to" branch)
- nil 'magit-revision-history)
- current-prefix-arg)))
- (when (string-match "\\`heads/\\(.+\\)" old)
- (setq old (match-string 1 old)))
- (when (equal old new)
- (user-error "Old and new branch names are the same"))
- (magit-call-git "branch" (if force "-M" "-m") old new)
- (when magit-branch-rename-push-target
- (let ((remote (magit-get-push-remote old))
- (old-specific (magit-get "branch" old "pushRemote"))
- (new-specific (magit-get "branch" new "pushRemote")))
- (when (and old-specific (or force (not new-specific)))
- ;; Keep the target setting branch specific, even if that is
- ;; redundant. But if a branch by the same name existed before
- ;; and the rename isn't forced, then do not change a leftover
- ;; setting. Such a leftover setting may or may not conform to
- ;; what we expect here...
- (magit-set old-specific "branch" new "pushRemote"))
- (when (and (equal (magit-get-push-remote new) remote)
- ;; ...and if it does not, then we must abort.
- (not (eq magit-branch-rename-push-target 'local-only))
- (or (not (memq magit-branch-rename-push-target
- '(forge-only github-only)))
- (and (require (quote forge) nil t)
- (fboundp 'forge--forge-remote-p)
- (forge--forge-remote-p remote))))
- (let ((old-target (magit-get-push-branch old t))
- (new-target (magit-get-push-branch new t))
- (remote (magit-get-push-remote new)))
- (when (and old-target
- (not new-target)
- (magit-y-or-n-p (format "Also rename %S to %S on \"%s\""
- old new remote)))
- ;; Rename on (i.e. within) the remote, but only if the
- ;; destination ref doesn't exist yet. If that ref already
- ;; exists, then it probably is of some value and we better
- ;; not touch it. Ignore what the local ref points at,
- ;; i.e. if the local and the remote ref didn't point at
- ;; the same commit before the rename then keep it that way.
- (magit-call-git "push" "-v" remote
- (format "%s:refs/heads/%s" old-target new)
- (format ":refs/heads/%s" old)))))))
- (magit-branch-unset-pushRemote old)
- (magit-refresh))
-
-;;;###autoload
-(defun magit-branch-shelve (branch)
- "Shelve a BRANCH.
-Rename \"refs/heads/BRANCH\" to \"refs/shelved/BRANCH\",
-and also rename the respective reflog file."
- (interactive (list (magit-read-other-local-branch "Shelve branch")))
- (let ((old (concat "refs/heads/" branch))
- (new (concat "refs/shelved/" branch)))
- (magit-git "update-ref" new old "")
- (magit--rename-reflog-file old new)
- (magit-branch-unset-pushRemote branch)
- (magit-run-git "branch" "-D" branch)))
-
-;;;###autoload
-(defun magit-branch-unshelve (branch)
- "Unshelve a BRANCH
-Rename \"refs/shelved/BRANCH\" to \"refs/heads/BRANCH\",
-and also rename the respective reflog file."
- (interactive
- (list (magit-completing-read
- "Unshelve branch"
- (--map (substring it 8)
- (magit-list-refnames "refs/shelved"))
- nil t)))
- (let ((old (concat "refs/shelved/" branch))
- (new (concat "refs/heads/" branch)))
- (magit-git "update-ref" new old "")
- (magit--rename-reflog-file old new)
- (magit-run-git "update-ref" "-d" old)))
-
-(defun magit--rename-reflog-file (old new)
- (let ((old (magit-git-dir (concat "logs/" old)))
- (new (magit-git-dir (concat "logs/" new))))
- (when (file-exists-p old)
- (make-directory (file-name-directory new) t)
- (rename-file old new t))))
-
-;;; Configure
-
-;;;###autoload (autoload 'magit-branch-configure "magit-branch" nil t)
-(transient-define-prefix magit-branch-configure (branch)
- "Configure a branch."
- :man-page "git-branch"
- [:description
- (lambda ()
- (concat
- (propertize "Configure " 'face 'transient-heading)
- (propertize (oref transient--prefix scope) 'face 'magit-branch-local)))
- ("d" magit-branch.<branch>.description)
- ("u" magit-branch.<branch>.merge/remote)
- ("r" magit-branch.<branch>.rebase)
- ("p" magit-branch.<branch>.pushRemote)]
- ["Configure repository defaults"
- ("R" magit-pull.rebase)
- ("P" magit-remote.pushDefault)]
- ["Configure branch creation"
- ("a m" magit-branch.autoSetupMerge)
- ("a r" magit-branch.autoSetupRebase)]
- (interactive
- (list (or (and (not current-prefix-arg)
- (not (and magit-branch-direct-configure
- (eq transient-current-command 'magit-branch)))
- (magit-get-current-branch))
- (magit--read-branch-scope))))
- (transient-setup 'magit-branch-configure nil nil :scope branch))
-
-(defun magit--read-branch-scope (&optional obj)
- (magit-read-local-branch
- (if obj
- (format "Set %s for branch"
- (format (oref obj variable) "<name>"))
- "Configure branch")))
-
-(transient-define-suffix magit-branch.<branch>.description (branch)
- "Edit the description of BRANCH."
- :class 'magit--git-variable
- :transient nil
- :variable "branch.%s.description"
- (interactive (list (oref transient-current-prefix scope)))
- (magit-run-git-with-editor "branch" "--edit-description" branch))
-
-(add-hook 'find-file-hook 'magit-branch-description-check-buffers)
-
-(defun magit-branch-description-check-buffers ()
- (and buffer-file-name
- (string-match-p "/\\(BRANCH\\|EDIT\\)_DESCRIPTION\\'" buffer-file-name)))
-
-(defclass magit--git-branch:upstream (magit--git-variable)
- ((format :initform " %k %m %M\n %r %R")))
-
-(transient-define-infix magit-branch.<branch>.merge/remote ()
- :class 'magit--git-branch:upstream)
-
-(cl-defmethod transient-init-value ((obj magit--git-branch:upstream))
- (when-let ((branch (oref transient--prefix scope))
- (remote (magit-get "branch" branch "remote"))
- (merge (magit-get "branch" branch "merge")))
- (oset obj value (list remote merge))))
-
-(cl-defmethod transient-infix-read ((obj magit--git-branch:upstream))
- (if (oref obj value)
- (oset obj value nil)
- (magit-read-upstream-branch (oref transient--prefix scope) "Upstream")))
-
-(cl-defmethod transient-infix-set ((obj magit--git-branch:upstream) refname)
- (magit-set-upstream-branch (oref transient--prefix scope) refname)
- (oset obj value
- (let ((branch (oref transient--prefix scope)))
- (when-let ((r (magit-get "branch" branch "remote"))
- (m (magit-get "branch" branch "merge")))
- (list r m))))
- (magit-refresh))
-
-(cl-defmethod transient-format ((obj magit--git-branch:upstream))
- (let ((branch (oref transient--prefix scope)))
- (format-spec
- (oref obj format)
- `((?k . ,(transient-format-key obj))
- (?r . ,(format "branch.%s.remote" branch))
- (?m . ,(format "branch.%s.merge" branch))
- (?R . ,(transient-format-value obj #'car))
- (?M . ,(transient-format-value obj #'cadr))))))
-
-(cl-defmethod transient-format-value ((obj magit--git-branch:upstream) key)
- (if-let ((value (funcall key (oref obj value))))
- (propertize value 'face 'transient-argument)
- (propertize "unset" 'face 'transient-inactive-argument)))
-
-(transient-define-infix magit-branch.<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.<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
+++ /dev/null
-;;; magit-clone.el --- clone a repository -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements clone commands.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Options
-
-(defcustom magit-clone-set-remote-head nil
- "Whether cloning creates the symbolic-ref `<remote>/HEAD'."
- :package-version '(magit . "2.4.2")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-clone-set-remote.pushDefault 'ask
- "Whether to set the value of `remote.pushDefault' after cloning.
-
-If t, then set without asking. If nil, then don't set. If
-`ask', then ask."
- :package-version '(magit . "2.4.0")
- :group 'magit-commands
- :type '(choice (const :tag "set" t)
- (const :tag "ask" ask)
- (const :tag "don't set" nil)))
-
-(defcustom magit-clone-default-directory nil
- "Default directory to use when `magit-clone' reads destination.
-If nil (the default), then use the value of `default-directory'.
-If a directory, then use that. If a function, then call that
-with the remote url as only argument and use the returned value."
- :package-version '(magit . "2.90.0")
- :group 'magit-commands
- :type '(choice (const :tag "value of default-directory")
- (directory :tag "constant directory")
- (function :tag "function's value")))
-
-(defcustom magit-clone-always-transient nil
- "Whether `magit-clone' always acts as a transient prefix command.
-If nil, then a prefix argument has to be used to show the transient
-popup instead of invoking the default suffix `magit-clone-regular'
-directly."
- :package-version '(magit . "3.0.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-clone-name-alist
- '(("\\`\\(?:github:\\|gh:\\)?\\([^:]+\\)\\'" "github.com" "github.user")
- ("\\`\\(?:gitlab:\\|gl:\\)\\([^:]+\\)\\'" "gitlab.com" "gitlab.user"))
- "Alist mapping repository names to repository urls.
-
-Each element has the form (REGEXP HOSTNAME USER). When the user
-enters a name when a cloning command asks for a name or url, then
-that is looked up in this list. The first element whose REGEXP
-matches is used.
-
-The format specified by option `magit-clone-url-format' is used
-to turn the name into an url, using HOSTNAME and the repository
-name. If the provided name contains a slash, then that is used.
-Otherwise if the name omits the owner of the repository, then the
-default user specified in the matched entry is used.
-
-If USER contains a dot, then it is treated as a Git variable and
-the value of that is used as the username. Otherwise it is used
-as the username itself."
- :package-version '(magit . "3.0.0")
- :group 'magit-commands
- :type '(repeat (list regexp
- (string :tag "hostname")
- (string :tag "user name or git variable"))))
-
-(defcustom magit-clone-url-format "git@%h:%n.git"
- "Format used when turning repository names into urls.
-%h is the hostname and %n is the repository name, including
-the name of the owner. Also see `magit-clone-name-alist'."
- :package-version '(magit . "3.0.0")
- :group 'magit-commands
- :type 'regexp)
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-clone "magit-clone" nil t)
-(transient-define-prefix magit-clone (&optional transient)
- "Clone a repository."
- :man-page "git-clone"
- ["Fetch arguments"
- ("-B" "Clone a single branch" "--single-branch")
- ("-n" "Do not clone tags" "--no-tags")
- ("-S" "Clones submodules" "--recurse-submodules" :level 6)
- ("-l" "Do not optimize" "--no-local" :level 7)]
- ["Setup arguments"
- ("-o" "Set name of remote" ("-o" "--origin="))
- ("-b" "Set HEAD branch" ("-b" "--branch="))
- ("-g" "Separate git directory" "--separate-git-dir="
- transient-read-directory :level 7)
- ("-t" "Use template directory" "--template="
- transient-read-existing-directory :level 6)]
- ["Local sharing arguments"
- ("-s" "Share objects" ("-s" "--shared" :level 7))
- ("-h" "Do not use hardlinks" "--no-hardlinks")]
- ["Clone"
- ("C" "regular" magit-clone-regular)
- ("s" "shallow" magit-clone-shallow)
- ("d" "shallow since date" magit-clone-shallow-since :level 7)
- ("e" "shallow excluding" magit-clone-shallow-exclude :level 7)
- ("b" "bare" magit-clone-bare)
- ("m" "mirror" magit-clone-mirror)]
- (interactive (list (or magit-clone-always-transient current-prefix-arg)))
- (if transient
- (transient-setup #'magit-clone)
- (call-interactively #'magit-clone-regular)))
-
-;;;###autoload
-(defun magit-clone-regular (repository directory args)
- "Create a clone of REPOSITORY in DIRECTORY.
-Then show the status buffer for the new repository."
- (interactive (magit-clone-read-args))
- (magit-clone-internal repository directory args))
-
-;;;###autoload
-(defun magit-clone-shallow (repository directory args depth)
- "Create a shallow clone of REPOSITORY in DIRECTORY.
-Then show the status buffer for the new repository.
-With a prefix argument read the DEPTH of the clone;
-otherwise use 1."
- (interactive (append (magit-clone-read-args)
- (list (if current-prefix-arg
- (read-number "Depth: " 1)
- 1))))
- (magit-clone-internal repository directory
- (cons (format "--depth=%s" depth) args)))
-
-;;;###autoload
-(defun magit-clone-shallow-since (repository directory args date)
- "Create a shallow clone of REPOSITORY in DIRECTORY.
-Then show the status buffer for the new repository.
-Exclude commits before DATE, which is read from the
-user."
- (interactive (append (magit-clone-read-args)
- (list (transient-read-date "Exclude commits before: "
- nil nil))))
- (magit-clone-internal repository directory
- (cons (format "--shallow-since=%s" date) args)))
-
-;;;###autoload
-(defun magit-clone-shallow-exclude (repository directory args exclude)
- "Create a shallow clone of REPOSITORY in DIRECTORY.
-Then show the status buffer for the new repository.
-Exclude commits reachable from EXCLUDE, which is a
-branch or tag read from the user."
- (interactive (append (magit-clone-read-args)
- (list (read-string "Exclude commits reachable from: "))))
- (magit-clone-internal repository directory
- (cons (format "--shallow-exclude=%s" exclude) args)))
-
-;;;###autoload
-(defun magit-clone-bare (repository directory args)
- "Create a bare clone of REPOSITORY in DIRECTORY.
-Then show the status buffer for the new repository."
- (interactive (magit-clone-read-args))
- (magit-clone-internal repository directory (cons "--bare" args)))
-
-;;;###autoload
-(defun magit-clone-mirror (repository directory args)
- "Create a mirror of REPOSITORY in DIRECTORY.
-Then show the status buffer for the new repository."
- (interactive (magit-clone-read-args))
- (magit-clone-internal repository directory (cons "--mirror" args)))
-
-(defun magit-clone-internal (repository directory args)
- (let* ((checkout (not (memq (car args) '("--bare" "--mirror"))))
- (set-push-default
- (and checkout
- (or (eq magit-clone-set-remote.pushDefault t)
- (and magit-clone-set-remote.pushDefault
- (y-or-n-p "Set `remote.pushDefault' to \"origin\"? "))))))
- (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") "origin"))
- (unless magit-clone-set-remote-head
- (magit-remote-unset-head "origin"))))
- (with-current-buffer (process-get process 'command-buf)
- (magit-status-setup-buffer directory)))))))
-
-(defun magit-clone-read-args ()
- (let ((repo (magit-clone-read-repository)))
- (list repo
- (read-directory-name
- "Clone to: "
- (if (functionp magit-clone-default-directory)
- (funcall magit-clone-default-directory repo)
- magit-clone-default-directory)
- nil nil
- (magit-clone--url-to-name repo))
- (transient-args 'magit-clone))))
-
-(defun magit-clone-read-repository ()
- (magit-read-char-case "Clone from " nil
- (?u "[u]rl or name"
- (let ((str (magit-read-string-ns "Clone from url or name")))
- (if (string-match-p "\\(://\\|@\\)" str)
- str
- (magit-clone--name-to-url str))))
- (?p "[p]ath"
- (read-directory-name "Clone repository: "))
- (?l "or [l]ocal url"
- (concat "file://" (read-directory-name "Clone repository: file://")))))
-
-(defun magit-clone--url-to-name (url)
- (and (string-match "\\([^/:]+?\\)\\(/?\\.git\\)?$" url)
- (match-string 1 url)))
-
-(defun magit-clone--name-to-url (name)
- (or (seq-some
- (pcase-lambda (`(,re ,host ,user))
- (and (string-match re name)
- (let ((repo (match-string 1 name)))
- (magit-clone--format-url host user repo))))
- magit-clone-name-alist)
- (user-error "Not an url and no matching entry in `%s'"
- 'magit-clone-name-alist)))
-
-(defun magit-clone--format-url (host user repo)
- (format-spec
- magit-clone-url-format
- `((?h . ,host)
- (?n . ,(if (string-match-p "/" repo)
- repo
- (if (string-match-p "\\." user)
- (if-let ((user (magit-get user)))
- (concat user "/" repo)
- (user-error "Set %S or specify owner explicitly" user))
- (concat user "/" repo)))))))
-
-;;; _
-(provide 'magit-clone)
-;;; magit-clone.el ends here
+++ /dev/null
-;;; magit-commit.el --- create Git commits -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements commands for creating Git commits. These
-;; commands just initiate the commit, support for writing the commit
-;; messages is implemented in `git-commit.el'.
-
-;;; Code:
-
-(require 'magit)
-(require 'magit-sequence)
-
-(eval-when-compile (require 'epa)) ; for `epa-protocol'
-(eval-when-compile (require 'epg))
-(eval-when-compile (require 'subr-x))
-
-;;; Options
-
-(defcustom magit-commit-ask-to-stage 'verbose
- "Whether to ask to stage all unstaged changes when committing and nothing is staged."
- :package-version '(magit . "2.3.0")
- :group 'magit-commands
- :type '(choice (const :tag "Ask" t)
- (const :tag "Ask showing diff" verbose)
- (const :tag "Stage without confirmation" stage)
- (const :tag "Don't ask" nil)))
-
-(defcustom magit-commit-show-diff t
- "Whether the relevant diff is automatically shown when committing."
- :package-version '(magit . "2.3.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-commit-extend-override-date t
- "Whether using `magit-commit-extend' changes the committer date."
- :package-version '(magit . "2.3.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-commit-reword-override-date t
- "Whether using `magit-commit-reword' changes the committer date."
- :package-version '(magit . "2.3.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-commit-squash-confirm t
- "Whether the commit targeted by squash and fixup has to be confirmed.
-When non-nil then the commit at point (if any) is used as default
-choice, otherwise it has to be confirmed. This option only
-affects `magit-commit-squash' and `magit-commit-fixup'. The
-\"instant\" variants always require confirmation because making
-an error while using those is harder to recover from."
- :package-version '(magit . "2.1.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-post-commit-hook nil
- "Hook run after creating a commit without the user editing a message.
-
-This hook is run by `magit-refresh' if `this-command' is a member
-of `magit-post-stage-hook-commands'. This only includes commands
-named `magit-commit-*' that do *not* require that the user edits
-the commit message in a buffer and then finishes by pressing
-\\<with-editor-mode-map>\\[with-editor-finish].
-
-Also see `git-commit-post-finish-hook'."
- :package-version '(magit . "2.90.0")
- :group 'magit-commands
- :type 'hook)
-
-(defvar magit-post-commit-hook-commands
- '(magit-commit-extend
- magit-commit-fixup
- magit-commit-augment
- magit-commit-instant-fixup
- magit-commit-instant-squash))
-
-;;; Popup
-
-;;;###autoload (autoload 'magit-commit "magit-commit" nil t)
-(transient-define-prefix magit-commit ()
- "Create a new commit or replace an existing commit."
- :info-manual "(magit)Initiating a Commit"
- :man-page "git-commit"
- ["Arguments"
- ("-a" "Stage all modified and deleted files" ("-a" "--all"))
- ("-e" "Allow empty commit" "--allow-empty")
- ("-v" "Show diff of changes to be committed" ("-v" "--verbose"))
- ("-n" "Disable hooks" ("-n" "--no-verify"))
- ("-R" "Claim authorship and reset author date" "--reset-author")
- (magit:--author :description "Override the author")
- (7 "-D" "Override the author date" "--date=" transient-read-date)
- ("-s" "Add Signed-off-by line" ("-s" "--signoff"))
- (5 magit:--gpg-sign)
- (magit-commit:--reuse-message)]
- [["Create"
- ("c" "Commit" magit-commit-create)]
- ["Edit HEAD"
- ("e" "Extend" magit-commit-extend)
- ("w" "Reword" magit-commit-reword)
- ("a" "Amend" magit-commit-amend)
- (6 "n" "Reshelve" magit-commit-reshelve)]
- ["Edit"
- ("f" "Fixup" magit-commit-fixup)
- ("s" "Squash" magit-commit-squash)
- ("A" "Augment" magit-commit-augment)
- (6 "x" "Absorb changes" magit-commit-autofixup)
- (6 "X" "Absorb modules" magit-commit-absorb-modules)]
- [""
- ("F" "Instant fixup" magit-commit-instant-fixup)
- ("S" "Instant squash" magit-commit-instant-squash)]]
- (interactive)
- (if-let ((buffer (magit-commit-message-buffer)))
- (switch-to-buffer buffer)
- (transient-setup 'magit-commit)))
-
-(defun magit-commit-arguments nil
- (transient-args 'magit-commit))
-
-(transient-define-argument magit:--gpg-sign ()
- :description "Sign using gpg"
- :class 'transient-option
- :shortarg "-S"
- :argument "--gpg-sign="
- :allow-empty t
- :reader 'magit-read-gpg-secret-key)
-
-(defvar magit-gpg-secret-key-hist nil)
-
-(defun magit-read-gpg-secret-key (prompt &optional initial-input history)
- (require 'epa)
- (let* ((keys (mapcar
- (lambda (obj)
- (let ((key (epg-sub-key-id (car (epg-key-sub-key-list obj))))
- (author
- (when-let ((id-obj (car (epg-key-user-id-list obj))))
- (let ((id-str (epg-user-id-string id-obj)))
- (if (stringp id-str)
- id-str
- (epg-decode-dn id-obj))))))
- (propertize key 'display (concat key " " author))))
- (epg-list-keys (epg-make-context epa-protocol) nil t)))
- (choice (completing-read prompt keys nil nil nil
- history nil initial-input)))
- (set-text-properties 0 (length choice) nil choice)
- choice))
-
-(transient-define-argument magit-commit:--reuse-message ()
- :description "Reuse commit message"
- :class 'transient-option
- :shortarg "-C"
- :argument "--reuse-message="
- :reader 'magit-read-reuse-message
- :history-key 'magit-revision-history)
-
-(defun magit-read-reuse-message (prompt &optional default history)
- (magit-completing-read prompt (magit-list-refnames)
- nil nil nil history
- (or default
- (and (magit-rev-verify "ORIG_HEAD")
- "ORIG_HEAD"))))
-
-;;; Commands
-
-;;;###autoload
-(defun magit-commit-create (&optional args)
- "Create a new commit on `HEAD'.
-With a prefix argument, amend to the commit at `HEAD' instead.
-\n(git commit [--amend] ARGS)"
- (interactive (if current-prefix-arg
- (list (cons "--amend" (magit-commit-arguments)))
- (list (magit-commit-arguments))))
- (when (member "--all" args)
- (setq this-command 'magit-commit-all))
- (when (setq args (magit-commit-assert args))
- (let ((default-directory (magit-toplevel)))
- (magit-run-git-with-editor "commit" args))))
-
-;;;###autoload
-(defun magit-commit-amend (&optional args)
- "Amend the last commit.
-\n(git commit --amend ARGS)"
- (interactive (list (magit-commit-arguments)))
- (magit-commit-amend-assert)
- (magit-run-git-with-editor "commit" "--amend" args))
-
-;;;###autoload
-(defun magit-commit-extend (&optional args override-date)
- "Amend the last commit, without editing the message.
-
-With a prefix argument keep the committer date, otherwise change
-it. The option `magit-commit-extend-override-date' can be used
-to inverse the meaning of the prefix argument. \n(git commit
---amend --no-edit)"
- (interactive (list (magit-commit-arguments)
- (if current-prefix-arg
- (not magit-commit-extend-override-date)
- magit-commit-extend-override-date)))
- (when (setq args (magit-commit-assert args))
- (magit-commit-amend-assert)
- (let ((process-environment process-environment))
- (unless override-date
- (push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment))
- (magit-run-git-with-editor "commit" "--amend" "--no-edit" args))))
-
-;;;###autoload
-(defun magit-commit-reword (&optional args override-date)
- "Reword the last commit, ignoring staged changes.
-
-With a prefix argument keep the committer date, otherwise change
-it. The option `magit-commit-reword-override-date' can be used
-to inverse the meaning of the prefix argument.
-
-Non-interactively respect the optional OVERRIDE-DATE argument
-and ignore the option.
-\n(git commit --amend --only)"
- (interactive (list (magit-commit-arguments)
- (if current-prefix-arg
- (not magit-commit-reword-override-date)
- magit-commit-reword-override-date)))
- (magit-commit-amend-assert)
- (let ((process-environment process-environment))
- (unless override-date
- (push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment))
- (cl-pushnew "--allow-empty" args :test #'equal)
- (magit-run-git-with-editor "commit" "--amend" "--only" args)))
-
-;;;###autoload
-(defun magit-commit-fixup (&optional commit args)
- "Create a fixup commit.
-
-With a prefix argument the target COMMIT has to be confirmed.
-Otherwise the commit at point may be used without confirmation
-depending on the value of option `magit-commit-squash-confirm'."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--fixup" commit args))
-
-;;;###autoload
-(defun magit-commit-squash (&optional commit args)
- "Create a squash commit, without editing the squash message.
-
-With a prefix argument the target COMMIT has to be confirmed.
-Otherwise the commit at point may be used without confirmation
-depending on the value of option `magit-commit-squash-confirm'."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--squash" commit args))
-
-;;;###autoload
-(defun magit-commit-augment (&optional commit args)
- "Create a squash commit, editing the squash message.
-
-With a prefix argument the target COMMIT has to be confirmed.
-Otherwise the commit at point may be used without confirmation
-depending on the value of option `magit-commit-squash-confirm'."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--squash" commit args nil t))
-
-;;;###autoload
-(defun magit-commit-instant-fixup (&optional commit args)
- "Create a fixup commit targeting COMMIT and instantly rebase."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--fixup" commit args t))
-
-;;;###autoload
-(defun magit-commit-instant-squash (&optional commit args)
- "Create a squash commit targeting COMMIT and instantly rebase."
- (interactive (list (magit-commit-at-point)
- (magit-commit-arguments)))
- (magit-commit-squash-internal "--squash" commit args t))
-
-(defun magit-commit-squash-internal
- (option commit &optional args rebase edit confirmed)
- (when-let ((args (magit-commit-assert args t)))
- (when commit
- (when (and rebase (not (magit-rev-ancestor-p commit "HEAD")))
- (magit-read-char-case
- (format "%s isn't an ancestor of HEAD. " commit) nil
- (?c "[c]reate without rebasing" (setq rebase nil))
- (?s "[s]elect other" (setq commit nil))
- (?a "[a]bort" (user-error "Quit")))))
- (when commit
- (setq commit (magit-rebase-interactive-assert commit t)))
- (if (and commit
- (or confirmed
- (not (or rebase
- current-prefix-arg
- magit-commit-squash-confirm))))
- (let ((magit-commit-show-diff nil))
- (push (concat option "=" commit) args)
- (unless edit
- (push "--no-edit" args))
- (if rebase
- (magit-with-editor
- (magit-call-git
- "commit" "--no-gpg-sign"
- (-remove-first
- (apply-partially #'string-match-p "\\`--gpg-sign=")
- args)))
- (magit-run-git-with-editor "commit" args))
- t) ; The commit was created; used by below lambda.
- (magit-log-select
- (lambda (commit)
- (when (and (magit-commit-squash-internal option commit args
- rebase edit t)
- rebase)
- (magit-commit-amend-assert commit)
- (magit-rebase-interactive-1 commit
- (list "--autosquash" "--autostash" "--keep-empty")
- "" "true" nil t)))
- (format "Type %%p on a commit to %s into it,"
- (substring option 2))
- nil nil nil commit)
- (when magit-commit-show-diff
- (let ((magit-display-buffer-noselect t))
- (apply #'magit-diff-staged nil (magit-diff-arguments)))))))
-
-(defun magit-commit-amend-assert (&optional commit)
- (--when-let (magit-list-publishing-branches commit)
- (let ((m1 "This commit has already been published to ")
- (m2 ".\nDo you really want to modify it"))
- (magit-confirm 'amend-published
- (concat m1 "%s" m2)
- (concat m1 "%i public branches" m2)
- nil it))))
-
-(defun magit-commit-assert (args &optional strict)
- (cond
- ((or (magit-anything-staged-p)
- (and (magit-anything-unstaged-p)
- ;; ^ Everything of nothing is still nothing.
- (member "--all" args))
- (and (not strict)
- ;; ^ For amend variants that don't make sense otherwise.
- (or (member "--amend" args)
- (member "--allow-empty" args)
- (member "--reset-author" args)
- (member "--author" args)
- (member "--signoff" args)
- (cl-find-if (lambda (a) (string-match-p "\\`--date=" a)) args))))
- (or args (list "--")))
- ((and (magit-rebase-in-progress-p)
- (not (magit-anything-unstaged-p))
- (y-or-n-p "Nothing staged. Continue in-progress rebase? "))
- (setq this-command 'magit-rebase-continue)
- (magit-run-git-sequencer "rebase" "--continue")
- nil)
- ((and (file-exists-p (magit-git-dir "MERGE_MSG"))
- (not (magit-anything-unstaged-p)))
- (or args (list "--")))
- ((not (magit-anything-unstaged-p))
- (user-error "Nothing staged (or unstaged)"))
- (magit-commit-ask-to-stage
- (when (eq magit-commit-ask-to-stage 'verbose)
- (magit-diff-unstaged))
- (prog1 (when (or (eq magit-commit-ask-to-stage 'stage)
- (y-or-n-p "Nothing staged. Stage and commit all unstaged changes? "))
- (magit-run-git "add" "-u" ".")
- (or args (list "--")))
- (when (and (eq magit-commit-ask-to-stage 'verbose)
- (derived-mode-p 'magit-diff-mode))
- (magit-mode-bury-buffer))))
- (t
- (user-error "Nothing staged"))))
-
-(defvar magit--reshelve-history nil)
-
-;;;###autoload
-(defun magit-commit-reshelve (date)
- "Change the committer date and possibly the author date of `HEAD'.
-
-If you are the author of `HEAD', then both dates are changed,
-otherwise only the committer date. The current time is used
-as the initial minibuffer input and the original author (if
-that is you) or committer date is available as the previous
-history element."
- (interactive
- (let ((author-p (magit-rev-author-p "HEAD")))
- (push (magit-rev-format (if author-p "%ad" "%cd") "HEAD"
- (concat "--date=format:%F %T %z"))
- magit--reshelve-history)
- (list (read-string (if author-p
- "Change author and committer dates to: "
- "Change committer date to: ")
- (cons (format-time-string "%F %T %z") 17)
- 'magit--reshelve-history))))
- (let ((process-environment process-environment))
- (push (concat "GIT_COMMITTER_DATE=" date) process-environment)
- (magit-run-git "commit" "--amend" "--no-edit"
- (and (magit-rev-author-p "HEAD")
- (concat "--date=" date)))))
-
-;;;###autoload
-(defun magit-commit-absorb-modules (phase commit)
- "Spread modified modules across recent commits."
- (interactive (list 'select (magit-get-upstream-branch)))
- (let ((modules (magit-list-modified-modules)))
- (unless modules
- (user-error "There are no modified modules that could be absorbed"))
- (when commit
- (setq commit (magit-rebase-interactive-assert commit t)))
- (if (and commit (eq phase 'run))
- (progn
- (dolist (module modules)
- (when-let ((msg (magit-git-string
- "log" "-1" "--format=%s"
- (concat commit "..") "--" module)))
- (magit-git "commit" "-m" (concat "fixup! " msg)
- "--only" "--" module)))
- (magit-refresh)
- t)
- (magit-log-select
- (lambda (commit)
- (magit-commit-absorb-modules 'run commit))
- nil nil nil nil commit))))
-
-;;;###autoload (autoload 'magit-commit-absorb "magit-commit" nil t)
-(transient-define-prefix magit-commit-absorb (phase commit args)
- "Spread staged changes across recent commits.
-With a prefix argument use a transient command to select infix
-arguments. This command requires git-absorb executable, which
-is available from https://github.com/tummychow/git-absorb.
-See `magit-commit-autofixup' for an alternative implementation."
- ["Arguments"
- ("-f" "Skip safety checks" ("-f" "--force"))
- ("-v" "Display more output" ("-v" "--verbose"))]
- ["Actions"
- ("x" "Absorb" magit-commit-absorb)]
- (interactive (if current-prefix-arg
- (list 'transient nil nil)
- (list 'select
- (magit-get-upstream-branch)
- (transient-args 'magit-commit-absorb))))
- (if (eq phase 'transient)
- (transient-setup 'magit-commit-absorb)
- (unless (executable-find "git-absorb")
- (user-error "This command requires the git-absorb executable, which %s"
- "is available from https://github.com/tummychow/git-absorb"))
- (unless (magit-anything-staged-p)
- (if (magit-anything-unstaged-p)
- (if (y-or-n-p "Nothing staged. Absorb all unstaged changes? ")
- (magit-with-toplevel
- (magit-run-git "add" "-u" "."))
- (user-error "Abort"))
- (user-error "There are no changes that could be absorbed")))
- (when commit
- (setq commit (magit-rebase-interactive-assert commit t)))
- (if (and commit (eq phase 'run))
- (progn (magit-run-git-async "absorb" "-v" args "-b" commit) t)
- (magit-log-select
- (lambda (commit)
- (with-no-warnings ; about non-interactive use
- (magit-commit-absorb 'run commit args)))
- nil nil nil nil commit))))
-
-;;;###autoload (autoload 'magit-commit-autofixup "magit-commit" nil t)
-(transient-define-prefix magit-commit-autofixup (phase commit args)
- "Spread staged or unstaged changes across recent commits.
-
-If there are any staged then spread only those, otherwise
-spread all unstaged changes. With a prefix argument use a
-transient command to select infix arguments.
-
-This command requires the git-autofixup script, which is
-available from https://github.com/torbiak/git-autofixup.
-See `magit-commit-absorb' for an alternative implementation."
- ["Arguments"
- (magit-autofixup:--context)
- (magit-autofixup:--strict)]
- ["Actions"
- ("x" "Absorb" magit-commit-autofixup)]
- (interactive (if current-prefix-arg
- (list 'transient nil nil)
- (list 'select
- (magit-get-upstream-branch)
- (transient-args 'magit-commit-autofixup))))
- (if (eq phase 'transient)
- (transient-setup 'magit-commit-autofixup)
- (unless (executable-find "git-autofixup")
- (user-error "This command requires the git-autofixup script, which %s"
- "is available from https://github.com/torbiak/git-autofixup"))
- (unless (magit-anything-modified-p)
- (user-error "There are no changes that could be absorbed"))
- (when commit
- (setq commit (magit-rebase-interactive-assert commit t)))
- (if (and commit (eq phase 'run))
- (progn (magit-run-git-async "autofixup" "-vv" args commit) t)
- (magit-log-select
- (lambda (commit)
- (with-no-warnings ; about non-interactive use
- (magit-commit-autofixup 'run commit args)))
- nil nil nil nil commit))))
-
-(transient-define-argument magit-autofixup:--context ()
- :description "Diff context lines"
- :class 'transient-option
- :shortarg "-c"
- :argument "--context="
- :reader 'transient-read-number-N0)
-
-(transient-define-argument magit-autofixup:--strict ()
- :description "Strictness"
- :class 'transient-option
- :shortarg "-s"
- :argument "--strict="
- :reader 'transient-read-number-N0)
-
-;;; Pending Diff
-
-(defun magit-commit-diff ()
- (when (and git-commit-mode magit-commit-show-diff)
- (when-let ((diff-buffer (magit-get-mode-buffer 'magit-diff-mode)))
- ;; This window just started displaying the commit message
- ;; buffer. Without this that buffer would immediately be
- ;; replaced with the diff buffer. See #2632.
- (unrecord-window-buffer nil diff-buffer))
- (condition-case nil
- (let ((args (car (magit-diff-arguments)))
- (magit-inhibit-save-previous-winconf 'unset)
- (magit-display-buffer-noselect t)
- (inhibit-quit nil)
- (display-buffer-overriding-action '(nil (inhibit-same-window t))))
- (message "Diffing changes to be committed (C-g to abort diffing)")
- (cl-case last-command
- (magit-commit
- (magit-diff-staged nil args))
- (magit-commit-all
- (magit-diff-working-tree nil args))
- ((magit-commit-amend
- magit-commit-reword
- magit-rebase-reword-commit)
- (magit-diff-while-amending args))
- (t (if (magit-anything-staged-p)
- (magit-diff-staged nil args)
- (magit-diff-while-amending args)))))
- (quit))))
-
-;; Mention `magit-diff-while-committing' because that's
-;; always what I search for when I try to find this line.
-(add-hook 'server-switch-hook 'magit-commit-diff)
-(add-hook 'with-editor-filter-visit-hook 'magit-commit-diff)
-
-(add-to-list 'with-editor-server-window-alist
- (cons git-commit-filename-regexp 'switch-to-buffer))
-
-;;; Message Utilities
-
-(defun magit-commit-message-buffer ()
- (let* ((find-file-visit-truename t) ; git uses truename of COMMIT_EDITMSG
- (topdir (magit-toplevel)))
- (--first (equal topdir (with-current-buffer it
- (and git-commit-mode (magit-toplevel))))
- (append (buffer-list (selected-frame))
- (buffer-list)))))
-
-(defvar magit-commit-add-log-insert-function 'magit-commit-add-log-insert
- "Used by `magit-commit-add-log' to insert a single entry.")
-
-(defun magit-commit-add-log ()
- "Add a stub for the current change into the commit message buffer.
-If no commit is in progress, then initiate it. Use the function
-specified by variable `magit-commit-add-log-insert-function' to
-actually insert the entry."
- (interactive)
- (pcase-let* ((hunk (and (magit-section-match 'hunk)
- (magit-current-section)))
- (log (magit-commit-message-buffer))
- (`(,buf ,pos) (magit-diff-visit-file--noselect)))
- (unless log
- (unless (magit-commit-assert nil)
- (user-error "Abort"))
- (magit-commit-create)
- (while (not (setq log (magit-commit-message-buffer)))
- (sit-for 0.01)))
- (magit--with-temp-position buf pos
- (funcall magit-commit-add-log-insert-function log
- (magit-file-relative-name)
- (and hunk (add-log-current-defun))))))
-
-(defun magit-commit-add-log-insert (buffer file defun)
- (with-current-buffer buffer
- (undo-boundary)
- (goto-char (point-max))
- (while (re-search-backward (concat "^" comment-start) nil t))
- (save-restriction
- (narrow-to-region (point-min) (point))
- (cond ((re-search-backward (format "* %s\\(?: (\\([^)]+\\))\\)?: " file)
- nil t)
- (when (equal (match-string 1) defun)
- (setq defun nil))
- (re-search-forward ": "))
- (t
- (when (re-search-backward "^[\\*(].+\n" nil t)
- (goto-char (match-end 0)))
- (while (re-search-forward "^[^\\*\n].*\n" nil t))
- (if defun
- (progn (insert (format "* %s (%s): \n" file defun))
- (setq defun nil))
- (insert (format "* %s: \n" file)))
- (backward-char)
- (unless (looking-at "\n[\n\\']")
- (insert ?\n)
- (backward-char))))
- (when defun
- (forward-line)
- (let ((limit (save-excursion
- (and (re-search-forward "^\\*" nil t)
- (point)))))
- (unless (or (looking-back (format "(%s): " defun)
- (line-beginning-position))
- (re-search-forward (format "^(%s): " defun) limit t))
- (while (re-search-forward "^[^\\*\n].*\n" limit t))
- (insert (format "(%s): \n" defun))
- (backward-char)))))))
-
-;;; _
-(provide 'magit-commit)
-;;; magit-commit.el ends here
+++ /dev/null
-;;; magit-core.el --- core functionality -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library requires several other libraries, so that yet other
-;; libraries can just require this one, instead of having to require
-;; all the other ones. In other words this separates the low-level
-;; stuff from the rest. It also defines some Custom groups.
-
-;;; Code:
-
-(require 'magit-utils)
-(require 'magit-section)
-(require 'magit-git)
-(require 'magit-mode)
-(require 'magit-margin)
-(require 'magit-process)
-(require 'magit-transient)
-(require 'magit-autorevert)
-
-(when (magit--libgit-available-p)
- (condition-case err
- (require 'magit-libgit)
- (error
- (setq magit-inhibit-libgit 'error)
- (message "Error while loading `magit-libgit': %S" err)
- (message "That is not fatal. The `libegit2' module just won't be used."))))
-
-(defgroup magit nil
- "Controlling Git from Emacs."
- :link '(url-link "https://magit.vc")
- :link '(info-link "(magit)FAQ")
- :link '(info-link "(magit)")
- :group 'tools)
-
-(defgroup magit-essentials nil
- "Options that every Magit user should briefly think about.
-
-Each of these options falls into one or more of these categories:
-
-* Options that affect Magit's behavior in fundamental ways.
-* Options that affect safety.
-* Options that affect performance.
-* Options that are of a personal nature."
- :link '(info-link "(magit)Essential Settings")
- :group 'magit)
-
-(defgroup magit-miscellaneous nil
- "Miscellaneous Magit options."
- :group 'magit)
-
-(defgroup magit-commands nil
- "Options controlling behavior of certain commands."
- :group 'magit)
-
-(defgroup magit-modes nil
- "Modes used or provided by Magit."
- :group 'magit)
-
-(defgroup magit-buffers nil
- "Options concerning Magit buffers."
- :link '(info-link "(magit)Modes and Buffers")
- :group 'magit)
-
-(defgroup magit-refresh nil
- "Options controlling how Magit buffers are refreshed."
- :link '(info-link "(magit)Automatic Refreshing of Magit Buffers")
- :group 'magit
- :group 'magit-buffers)
-
-(defgroup magit-faces nil
- "Faces used by Magit."
- :group 'magit
- :group 'faces)
-
-(defgroup magit-extensions nil
- "Extensions to Magit."
- :group 'magit)
-
-(custom-add-to-group 'magit-modes 'git-commit 'custom-group)
-(custom-add-to-group 'magit-faces 'git-commit-faces 'custom-group)
-(custom-add-to-group 'magit-modes 'git-rebase 'custom-group)
-(custom-add-to-group 'magit-faces 'git-rebase-faces 'custom-group)
-(custom-add-to-group 'magit 'magit-section 'custom-group)
-(custom-add-to-group 'magit-faces 'magit-section-faces 'custom-group)
-(custom-add-to-group 'magit-process 'with-editor 'custom-group)
-
-(defgroup magit-related nil
- "Options that are relevant to Magit but that are defined elsewhere."
- :link '(custom-group-link vc)
- :link '(custom-group-link smerge)
- :link '(custom-group-link ediff)
- :link '(custom-group-link auto-revert)
- :group 'magit
- :group 'magit-extensions
- :group 'magit-essentials)
-
-(custom-add-to-group 'magit-related 'auto-revert-check-vc-info 'custom-variable)
-(custom-add-to-group 'magit-auto-revert 'auto-revert-check-vc-info 'custom-variable)
-
-(custom-add-to-group 'magit-related 'ediff-window-setup-function 'custom-variable)
-(custom-add-to-group 'magit-related 'smerge-refine-ignore-whitespace 'custom-variable)
-(custom-add-to-group 'magit-related 'vc-follow-symlinks 'custom-variable)
-
-;;; _
-(provide 'magit-core)
-;;; magit-core.el ends here
+++ /dev/null
-;;; magit-diff.el --- inspect Git diffs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for looking at Git diffs and
-;; commits.
-
-;;; Code:
-
-(eval-when-compile
- (require 'ansi-color)
- (require 'subr-x))
-
-(require 'git-commit)
-(require 'magit-core)
-
-;; For `magit-diff-popup'
-(declare-function magit-stash-show "magit-stash" (stash &optional args files))
-;; For `magit-diff-visit-file'
-(declare-function dired-jump "dired-x" (&optional other-window file-name))
-(declare-function magit-find-file-noselect "magit-files" (rev file))
-(declare-function magit-status-setup-buffer "magit-status" (directory))
-;; For `magit-diff-while-committing'
-(declare-function magit-commit-message-buffer "magit-commit" ())
-;; For `magit-insert-revision-gravatar'
-(defvar gravatar-size)
-;; For `magit-show-commit' and `magit-diff-show-or-scroll'
-(declare-function magit-current-blame-chunk "magit-blame" ())
-(declare-function magit-blame-mode "magit-blame" (&optional arg))
-(defvar magit-blame-mode)
-;; For `magit-diff-show-or-scroll'
-(declare-function git-rebase-current-line "git-rebase" ())
-;; For `magit-diff-unmerged'
-(declare-function magit-merge-in-progress-p "magit-merge" ())
-(declare-function magit--merge-range "magit-merge" (&optional head))
-;; For `magit-diff--dwim'
-(declare-function forge--pullreq-range "forge-pullreq"
- (pullreq &optional endpoints))
-(declare-function forge--pullreq-ref "forge-pullreq" (pullreq))
-;; For `magit-diff-wash-diff'
-(declare-function ansi-color-apply-on-region "ansi-color" (begin end))
-
-(eval-when-compile
- (cl-pushnew 'orig-rev eieio--known-slot-names)
- (cl-pushnew 'action-type eieio--known-slot-names)
- (cl-pushnew 'target eieio--known-slot-names))
-
-(require 'diff-mode)
-(require 'smerge-mode)
-
-;;; Options
-;;;; Diff Mode
-
-(defgroup magit-diff nil
- "Inspect and manipulate Git diffs."
- :link '(info-link "(magit)Diffing")
- :group 'magit-commands
- :group 'magit-modes)
-
-(defcustom magit-diff-mode-hook nil
- "Hook run after entering Magit-Diff mode."
- :group 'magit-diff
- :type 'hook)
-
-(defcustom magit-diff-sections-hook
- '(magit-insert-diff
- magit-insert-xref-buttons)
- "Hook run to insert sections into a `magit-diff-mode' buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-diff
- :type 'hook)
-
-(defcustom magit-diff-expansion-threshold 60
- "After how many seconds not to expand anymore diffs.
-
-Except in status buffers, diffs are usually start out fully
-expanded. Because that can take a long time, all diffs that
-haven't been fontified during a refresh before the threshold
-defined here are instead displayed with their bodies collapsed.
-
-Note that this can cause sections that were previously expanded
-to be collapsed. So you should not pick a very low value here.
-
-The hook function `magit-diff-expansion-threshold' has to be a
-member of `magit-section-set-visibility-hook' for this option
-to have any effect."
- :package-version '(magit . "2.9.0")
- :group 'magit-diff
- :type 'float)
-
-(defcustom magit-diff-highlight-hunk-body t
- "Whether to highlight bodies of selected hunk sections.
-This only has an effect if `magit-diff-highlight' is a
-member of `magit-section-highlight-hook', which see."
- :package-version '(magit . "2.1.0")
- :group 'magit-diff
- :type 'boolean)
-
-(defcustom magit-diff-highlight-hunk-region-functions
- '(magit-diff-highlight-hunk-region-dim-outside
- magit-diff-highlight-hunk-region-using-overlays)
- "The functions used to highlight the hunk-internal region.
-
-`magit-diff-highlight-hunk-region-dim-outside' overlays the outside
-of the hunk internal selection with a face that causes the added and
-removed lines to have the same background color as context lines.
-This function should not be removed from the value of this option.
-
-`magit-diff-highlight-hunk-region-using-overlays' and
-`magit-diff-highlight-hunk-region-using-underline' emphasize the
-region by placing delimiting horizontal lines before and after it.
-The underline variant was implemented because Eli said that is
-how we should do it. However the overlay variant actually works
-better. Also see https://github.com/magit/magit/issues/2758.
-
-Instead of, or in addition to, using delimiting horizontal lines,
-to emphasize the boundaries, you may which to emphasize the text
-itself, using `magit-diff-highlight-hunk-region-using-face'.
-
-In terminal frames it's not possible to draw lines as the overlay
-and underline variants normally do, so there they fall back to
-calling the face function instead."
- :package-version '(magit . "2.9.0")
- :set-after '(magit-diff-show-lines-boundaries)
- :group 'magit-diff
- :type 'hook
- :options '(magit-diff-highlight-hunk-region-dim-outside
- magit-diff-highlight-hunk-region-using-underline
- magit-diff-highlight-hunk-region-using-overlays
- magit-diff-highlight-hunk-region-using-face))
-
-(defcustom magit-diff-unmarked-lines-keep-foreground t
- "Whether `magit-diff-highlight-hunk-region-dim-outside' preserves foreground.
-When this is set to nil, then that function only adjusts the
-foreground color but added and removed lines outside the region
-keep their distinct foreground colors."
- :package-version '(magit . "2.9.0")
- :group 'magit-diff
- :type 'boolean)
-
-(defcustom magit-diff-refine-hunk nil
- "Whether to show word-granularity differences within diff hunks.
-
-nil Never show fine differences.
-t Show fine differences for the current diff hunk only.
-`all' Show fine differences for all displayed diff hunks."
- :group 'magit-diff
- :safe (lambda (val) (memq val '(nil t all)))
- :type '(choice (const :tag "Never" nil)
- (const :tag "Current" t)
- (const :tag "All" all)))
-
-(defcustom magit-diff-refine-ignore-whitespace smerge-refine-ignore-whitespace
- "Whether to ignore whitespace changes in word-granularity differences."
- :package-version '(magit . "3.0.0")
- :set-after '(smerge-refine-ignore-whitespace)
- :group 'magit-diff
- :safe 'booleanp
- :type 'boolean)
-
-(put 'magit-diff-refine-hunk 'permanent-local t)
-
-(defcustom magit-diff-adjust-tab-width nil
- "Whether to adjust the width of tabs in diffs.
-
-Determining the correct width can be expensive if it requires
-opening large and/or many files, so the widths are cached in
-the variable `magit-diff--tab-width-cache'. Set that to nil
-to invalidate the cache.
-
-nil Never adjust tab width. Use `tab-width's value from
- the Magit buffer itself instead.
-
-t If the corresponding file-visiting buffer exits, then
- use `tab-width's value from that buffer. Doing this is
- cheap, so this value is used even if a corresponding
- cache entry exists.
-
-`always' If there is no such buffer, then temporarily visit the
- file to determine the value.
-
-NUMBER Like `always', but don't visit files larger than NUMBER
- bytes."
- :package-version '(magit . "2.12.0")
- :group 'magit-diff
- :type '(choice (const :tag "Never" nil)
- (const :tag "If file-visiting buffer exists" t)
- (integer :tag "If file isn't larger than N bytes")
- (const :tag "Always" always)))
-
-(defcustom magit-diff-paint-whitespace t
- "Specify where to highlight whitespace errors.
-
-nil Never highlight whitespace errors.
-t Highlight whitespace errors everywhere.
-`uncommitted' Only highlight whitespace errors in diffs
- showing uncommitted changes.
-
-For backward compatibility `status' is treated as a synonym
-for `uncommitted'.
-
-The option `magit-diff-paint-whitespace-lines' controls for
-what lines (added/remove/context) errors are highlighted.
-
-The options `magit-diff-highlight-trailing' and
-`magit-diff-highlight-indentation' control what kind of
-whitespace errors are highlighted."
- :group 'magit-diff
- :safe (lambda (val) (memq val '(t nil uncommitted status)))
- :type '(choice (const :tag "In all diffs" t)
- (const :tag "Only in uncommitted changes" uncommitted)
- (const :tag "Never" nil)))
-
-(defcustom magit-diff-paint-whitespace-lines t
- "Specify in what kind of lines to highlight whitespace errors.
-
-t Highlight only in added lines.
-`both' Highlight in added and removed lines.
-`all' Highlight in added, removed and context lines."
- :package-version '(magit . "3.0.0")
- :group 'magit-diff
- :safe (lambda (val) (memq val '(t both all)))
- :type '(choice (const :tag "in added lines" t)
- (const :tag "in added and removed lines" both)
- (const :tag "in added, removed and context lines" all)))
-
-(defcustom magit-diff-highlight-trailing t
- "Whether to highlight whitespace at the end of a line in diffs.
-Used only when `magit-diff-paint-whitespace' is non-nil."
- :group 'magit-diff
- :safe 'booleanp
- :type 'boolean)
-
-(defcustom magit-diff-highlight-indentation nil
- "Highlight the \"wrong\" indentation style.
-Used only when `magit-diff-paint-whitespace' is non-nil.
-
-The value is an alist of the form ((REGEXP . INDENT)...). The
-path to the current repository is matched against each element
-in reverse order. Therefore if a REGEXP matches, then earlier
-elements are not tried.
-
-If the used INDENT is `tabs', highlight indentation with tabs.
-If INDENT is an integer, highlight indentation with at least
-that many spaces. Otherwise, highlight neither."
- :group 'magit-diff
- :type `(repeat (cons (string :tag "Directory regexp")
- (choice (const :tag "Tabs" tabs)
- (integer :tag "Spaces" :value ,tab-width)
- (const :tag "Neither" nil)))))
-
-(defcustom magit-diff-hide-trailing-cr-characters
- (and (memq system-type '(ms-dos windows-nt)) t)
- "Whether to hide ^M characters at the end of a line in diffs."
- :package-version '(magit . "2.6.0")
- :group 'magit-diff
- :type 'boolean)
-
-(defcustom magit-diff-highlight-keywords t
- "Whether to highlight bracketed keywords in commit messages."
- :package-version '(magit . "2.12.0")
- :group 'magit-diff
- :type 'boolean)
-
-;;;; File Diff
-
-(defcustom magit-diff-buffer-file-locked t
- "Whether `magit-diff-buffer-file' uses a dedicated buffer."
- :package-version '(magit . "2.7.0")
- :group 'magit-commands
- :group 'magit-diff
- :type 'boolean)
-
-;;;; Revision Mode
-
-(defgroup magit-revision nil
- "Inspect and manipulate Git commits."
- :link '(info-link "(magit)Revision Buffer")
- :group 'magit-modes)
-
-(defcustom magit-revision-mode-hook
- '(bug-reference-mode
- goto-address-mode)
- "Hook run after entering Magit-Revision mode."
- :group 'magit-revision
- :type 'hook
- :options '(bug-reference-mode
- goto-address-mode))
-
-(defcustom magit-revision-sections-hook
- '(magit-insert-revision-tag
- magit-insert-revision-headers
- magit-insert-revision-message
- magit-insert-revision-notes
- magit-insert-revision-diff
- magit-insert-xref-buttons)
- "Hook run to insert sections into a `magit-revision-mode' buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-revision
- :type 'hook)
-
-(defcustom magit-revision-headers-format "\
-Author: %aN <%aE>
-AuthorDate: %ad
-Commit: %cN <%cE>
-CommitDate: %cd
-"
- "Format string used to insert headers in revision buffers.
-
-All headers in revision buffers are inserted by the section
-inserter `magit-insert-revision-headers'. Some of the headers
-are created by calling `git show --format=FORMAT' where FORMAT
-is the format specified here. Other headers are hard coded or
-subject to option `magit-revision-insert-related-refs'."
- :package-version '(magit . "2.3.0")
- :group 'magit-revision
- :type 'string)
-
-(defcustom magit-revision-insert-related-refs t
- "Whether to show related branches in revision buffers
-
-`nil' Don't show any related branches.
-`t' Show related local branches.
-`all' Show related local and remote branches.
-`mixed' Show all containing branches and local merged branches."
- :package-version '(magit . "2.1.0")
- :group 'magit-revision
- :type '(choice (const :tag "don't" nil)
- (const :tag "local only" t)
- (const :tag "all related" all)
- (const :tag "all containing, local merged" mixed)))
-
-(defcustom magit-revision-use-hash-sections 'quicker
- "Whether to turn hashes inside the commit message into sections.
-
-If non-nil, then hashes inside the commit message are turned into
-`commit' sections. There is a trade off to be made between
-performance and reliability:
-
-- `slow' calls git for every word to be absolutely sure.
-- `quick' skips words less than seven characters long.
-- `quicker' additionally skips words that don't contain a number.
-- `quickest' uses all words that are at least seven characters
- long and which contain at least one number as well as at least
- one letter.
-
-If nil, then no hashes are turned into sections, but you can
-still visit the commit at point using \"RET\"."
- :package-version '(magit . "2.12.0")
- :group 'magit-revision
- :type '(choice (const :tag "Use sections, quickest" quickest)
- (const :tag "Use sections, quicker" quicker)
- (const :tag "Use sections, quick" quick)
- (const :tag "Use sections, slow" slow)
- (const :tag "Don't use sections" nil)))
-
-(defcustom magit-revision-show-gravatars nil
- "Whether to show gravatar images in revision buffers.
-
-If nil, then don't insert any gravatar images. If t, then insert
-both images. If `author' or `committer', then insert only the
-respective image.
-
-If you have customized the option `magit-revision-header-format'
-and want to insert the images then you might also have to specify
-where to do so. In that case the value has to be a cons-cell of
-two regular expressions. The car specifies where to insert the
-author's image. The top half of the image is inserted right
-after the matched text, the bottom half on the next line in the
-same column. The cdr specifies where to insert the committer's
-image, accordingly. Either the car or the cdr may be nil."
- :package-version '(magit . "2.3.0")
- :group 'magit-revision
- :type '(choice (const :tag "Don't show gravatars" nil)
- (const :tag "Show gravatars" t)
- (const :tag "Show author gravatar" author)
- (const :tag "Show committer gravatar" committer)
- (cons :tag "Show gravatars using custom pattern."
- (regexp :tag "Author regexp" "^Author: ")
- (regexp :tag "Committer regexp" "^Commit: "))))
-
-(defcustom magit-revision-use-gravatar-kludge nil
- "Whether to work around a bug which affects display of gravatars.
-
-Gravatar images are spliced into two halves which are then
-displayed on separate lines. On OS X the splicing has a bug in
-some Emacs builds, which causes the top and bottom halves to be
-interchanged. Enabling this option works around this issue by
-interchanging the halves once more, which cancels out the effect
-of the bug.
-
-See https://github.com/magit/magit/issues/2265
-and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=7847.
-
-Starting with Emacs 26.1 this kludge should not be required for
-any build."
- :package-version '(magit . "2.3.0")
- :group 'magit-revision
- :type 'boolean)
-
-(defcustom magit-revision-fill-summary-line nil
- "Whether to fill excessively long summary lines.
-
-If this is an integer, then the summary line is filled if it is
-longer than either the limit specified here or `window-width'.
-
-You may want to only set this locally in \".dir-locals-2.el\" for
-repositories known to contain bad commit messages.
-
-The body of the message is left alone because (a) most people who
-write excessively long summary lines usually don't add a body and
-(b) even people who have the decency to wrap their lines may have
-a good reason to include a long line in the body sometimes."
- :package-version '(magit . "2.90.0")
- :group 'magit-revision
- :type '(choice (const :tag "Don't fill" nil)
- (integer :tag "Fill if longer than")))
-
-(defcustom magit-revision-filter-files-on-follow nil
- "Whether to honor file filter if log arguments include --follow.
-
-When a commit is displayed from a log buffer, the resulting
-revision buffer usually shares the log's file arguments,
-restricting the diff to those files. However, there's a
-complication when the log arguments include --follow: if the log
-follows a file across a rename event, keeping the file
-restriction would mean showing an empty diff in revision buffers
-for commits before the rename event.
-
-When this option is nil, the revision buffer ignores the log's
-filter if the log arguments include --follow. If non-nil, the
-log's file filter is always honored."
- :package-version '(magit . "3.0.0")
- :group 'magit-revision
- :type 'boolean)
-
-;;;; Visit Commands
-
-(defcustom magit-diff-visit-previous-blob t
- "Whether `magit-diff-visit-file' may visit the previous blob.
-
-When this is t and point is on a removed line in a diff for a
-committed change, then `magit-diff-visit-file' visits the blob
-from the last revision which still had that line.
-
-Currently this is only supported for committed changes, for
-staged and unstaged changes `magit-diff-visit-file' always
-visits the file in the working tree."
- :package-version '(magit . "2.9.0")
- :group 'magit-diff
- :type 'boolean)
-
-(defcustom magit-diff-visit-avoid-head-blob nil
- "Whether `magit-diff-visit-file' avoids visiting a blob from `HEAD'.
-
-By default `magit-diff-visit-file' always visits the blob that
-added the current line, while `magit-diff-visit-worktree-file'
-visits the respective file in the working tree. For the `HEAD'
-commit, the former command used to visit the worktree file too,
-but that made it impossible to visit a blob from `HEAD'.
-
-When point is on a removed line and that change has not been
-committed yet, then `magit-diff-visit-file' now visits the last
-blob that still had that line, which is a blob from `HEAD'.
-Previously this function used to visit the worktree file not
-only for added lines but also for such removed lines.
-
-If you prefer the old behaviors, then set this to t."
- :package-version '(magit . "3.0.0")
- :group 'magit-diff
- :type 'boolean)
-
-;;; Faces
-
-(defface magit-diff-file-heading
- `((t ,@(and (>= emacs-major-version 27) '(:extend t))
- :weight bold))
- "Face for diff file headings."
- :group 'magit-faces)
-
-(defface magit-diff-file-heading-highlight
- `((t ,@(and (>= emacs-major-version 27) '(:extend t))
- :inherit magit-section-highlight))
- "Face for current diff file headings."
- :group 'magit-faces)
-
-(defface magit-diff-file-heading-selection
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :inherit magit-diff-file-heading-highlight
- :foreground "salmon4")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :inherit magit-diff-file-heading-highlight
- :foreground "LightSalmon3"))
- "Face for selected diff file headings."
- :group 'magit-faces)
-
-(defface magit-diff-hunk-heading
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "grey80"
- :foreground "grey30")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "grey25"
- :foreground "grey70"))
- "Face for diff hunk headings."
- :group 'magit-faces)
-
-(defface magit-diff-hunk-heading-highlight
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "grey75"
- :foreground "grey30")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "grey35"
- :foreground "grey70"))
- "Face for current diff hunk headings."
- :group 'magit-faces)
-
-(defface magit-diff-hunk-heading-selection
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :inherit magit-diff-hunk-heading-highlight
- :foreground "salmon4")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :inherit magit-diff-hunk-heading-highlight
- :foreground "LightSalmon3"))
- "Face for selected diff hunk headings."
- :group 'magit-faces)
-
-(defface magit-diff-hunk-region
- `((t :inherit bold
- ,@(and (>= emacs-major-version 27)
- (list :extend (ignore-errors (face-attribute 'region :extend))))))
- "Face used by `magit-diff-highlight-hunk-region-using-face'.
-
-This face is overlaid over text that uses other hunk faces,
-and those normally set the foreground and background colors.
-The `:foreground' and especially the `:background' properties
-should be avoided here. Setting the latter would cause the
-loss of information. Good properties to set here are `:weight'
-and `:slant'."
- :group 'magit-faces)
-
-(defface magit-diff-revision-summary
- '((t :inherit magit-diff-hunk-heading))
- "Face for commit message summaries."
- :group 'magit-faces)
-
-(defface magit-diff-revision-summary-highlight
- '((t :inherit magit-diff-hunk-heading-highlight))
- "Face for highlighted commit message summaries."
- :group 'magit-faces)
-
-(defface magit-diff-lines-heading
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :inherit magit-diff-hunk-heading-highlight
- :background "LightSalmon3")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :inherit magit-diff-hunk-heading-highlight
- :foreground "grey80"
- :background "salmon4"))
- "Face for diff hunk heading when lines are marked."
- :group 'magit-faces)
-
-(defface magit-diff-lines-boundary
- `((t ,@(and (>= emacs-major-version 27) '(:extend t)) ; !important
- :inherit magit-diff-lines-heading))
- "Face for boundary of marked lines in diff hunk."
- :group 'magit-faces)
-
-(defface magit-diff-conflict-heading
- '((t :inherit magit-diff-hunk-heading))
- "Face for conflict markers."
- :group 'magit-faces)
-
-(defface magit-diff-added
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "#ddffdd"
- :foreground "#22aa22")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "#335533"
- :foreground "#ddffdd"))
- "Face for lines in a diff that have been added."
- :group 'magit-faces)
-
-(defface magit-diff-removed
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "#ffdddd"
- :foreground "#aa2222")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "#553333"
- :foreground "#ffdddd"))
- "Face for lines in a diff that have been removed."
- :group 'magit-faces)
-
-(defface magit-diff-our
- '((t :inherit magit-diff-removed))
- "Face for lines in a diff for our side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-base
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "#ffffcc"
- :foreground "#aaaa11")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "#555522"
- :foreground "#ffffcc"))
- "Face for lines in a diff for the base side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-their
- '((t :inherit magit-diff-added))
- "Face for lines in a diff for their side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-context
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :foreground "grey50")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :foreground "grey70"))
- "Face for lines in a diff that are unchanged."
- :group 'magit-faces)
-
-(defface magit-diff-added-highlight
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "#cceecc"
- :foreground "#22aa22")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "#336633"
- :foreground "#cceecc"))
- "Face for lines in a diff that have been added."
- :group 'magit-faces)
-
-(defface magit-diff-removed-highlight
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "#eecccc"
- :foreground "#aa2222")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "#663333"
- :foreground "#eecccc"))
- "Face for lines in a diff that have been removed."
- :group 'magit-faces)
-
-(defface magit-diff-our-highlight
- '((t :inherit magit-diff-removed-highlight))
- "Face for lines in a diff for our side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-base-highlight
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "#eeeebb"
- :foreground "#aaaa11")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "#666622"
- :foreground "#eeeebb"))
- "Face for lines in a diff for the base side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-their-highlight
- '((t :inherit magit-diff-added-highlight))
- "Face for lines in a diff for their side in a conflict."
- :group 'magit-faces)
-
-(defface magit-diff-context-highlight
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "grey95"
- :foreground "grey50")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "grey20"
- :foreground "grey70"))
- "Face for lines in the current context in a diff."
- :group 'magit-faces)
-
-(defface magit-diff-whitespace-warning
- '((t :inherit trailing-whitespace))
- "Face for highlighting whitespace errors added lines."
- :group 'magit-faces)
-
-(defface magit-diffstat-added
- '((((class color) (background light)) :foreground "#22aa22")
- (((class color) (background dark)) :foreground "#448844"))
- "Face for plus sign in diffstat."
- :group 'magit-faces)
-
-(defface magit-diffstat-removed
- '((((class color) (background light)) :foreground "#aa2222")
- (((class color) (background dark)) :foreground "#aa4444"))
- "Face for minus sign in diffstat."
- :group 'magit-faces)
-
-;;; Arguments
-;;;; Prefix Classes
-
-(defclass magit-diff-prefix (transient-prefix)
- ((history-key :initform 'magit-diff)
- (major-mode :initform 'magit-diff-mode)))
-
-(defclass magit-diff-refresh-prefix (magit-diff-prefix)
- ((history-key :initform 'magit-diff)
- (major-mode :initform nil)))
-
-;;;; Prefix Methods
-
-(cl-defmethod transient-init-value ((obj magit-diff-prefix))
- (pcase-let ((`(,args ,files)
- (magit-diff--get-value 'magit-diff-mode
- magit-prefix-use-buffer-arguments)))
- (unless (eq transient-current-command 'magit-dispatch)
- (when-let ((file (magit-file-relative-name)))
- (setq files (list file))))
- (oset obj value (if files `(("--" ,@files) ,args) args))))
-
-(cl-defmethod transient-init-value ((obj magit-diff-refresh-prefix))
- (oset obj value (if magit-buffer-diff-files
- `(("--" ,@magit-buffer-diff-files)
- ,magit-buffer-diff-args)
- magit-buffer-diff-args)))
-
-(cl-defmethod transient-set-value ((obj magit-diff-prefix))
- (magit-diff--set-value obj))
-
-(cl-defmethod transient-save-value ((obj magit-diff-prefix))
- (magit-diff--set-value obj 'save))
-
-;;;; Argument Access
-
-(defun magit-diff-arguments (&optional mode)
- "Return the current diff arguments."
- (if (memq transient-current-command '(magit-diff magit-diff-refresh))
- (pcase-let ((`(,args ,alist)
- (-separate #'atom (transient-get-value))))
- (list args (cdr (assoc "--" alist))))
- (magit-diff--get-value (or mode 'magit-diff-mode))))
-
-(defun magit-diff--get-value (mode &optional use-buffer-args)
- (unless use-buffer-args
- (setq use-buffer-args magit-direct-use-buffer-arguments))
- (let (args files)
- (cond
- ((and (memq use-buffer-args '(always selected current))
- (eq major-mode mode))
- (setq args magit-buffer-diff-args)
- (setq files magit-buffer-diff-files))
- ((and (memq use-buffer-args '(always selected))
- (when-let ((buffer (magit-get-mode-buffer
- mode nil
- (eq use-buffer-args 'selected))))
- (setq args (buffer-local-value 'magit-buffer-diff-args buffer))
- (setq files (buffer-local-value 'magit-buffer-diff-files buffer))
- t)))
- ((plist-member (symbol-plist mode) 'magit-diff-current-arguments)
- (setq args (get mode 'magit-diff-current-arguments)))
- ((when-let ((elt (assq (intern (format "magit-diff:%s" mode))
- transient-values)))
- (setq args (cdr elt))
- t))
- (t
- (setq args (get mode 'magit-diff-default-arguments))))
- (list args files)))
-
-(defun magit-diff--set-value (obj &optional save)
- (pcase-let* ((obj (oref obj prototype))
- (mode (or (oref obj major-mode) major-mode))
- (key (intern (format "magit-diff:%s" mode)))
- (`(,args ,alist)
- (-separate #'atom (transient-get-value)))
- (files (cdr (assoc "--" alist))))
- (put mode 'magit-diff-current-arguments args)
- (when save
- (setf (alist-get key transient-values) args)
- (transient-save-values))
- (transient--history-push obj)
- (setq magit-buffer-diff-args args)
- (setq magit-buffer-diff-files files)
- (magit-refresh)))
-
-;;; Section Classes
-
-(defclass magit-file-section (magit-section)
- ((keymap :initform magit-file-section-map)
- (source :initform nil)
- (header :initform nil)))
-
-(defclass magit-module-section (magit-file-section)
- ((keymap :initform magit-hunk-section-map)))
-
-(defclass magit-hunk-section (magit-section)
- ((keymap :initform magit-hunk-section-map)
- (refined :initform nil)
- (combined :initform nil)
- (from-range :initform nil)
- (from-ranges :initform nil)
- (to-range :initform nil)
- (about :initform nil)))
-
-(setf (alist-get 'hunk magit--section-type-alist) 'magit-hunk-section)
-(setf (alist-get 'module magit--section-type-alist) 'magit-module-section)
-(setf (alist-get 'file magit--section-type-alist) 'magit-file-section)
-
-;;; Commands
-;;;; Prefix Commands
-
-;;;###autoload (autoload 'magit-diff "magit-diff" nil t)
-(transient-define-prefix magit-diff ()
- "Show changes between different versions."
- :man-page "git-diff"
- :class 'magit-diff-prefix
- ["Limit arguments"
- (magit:--)
- (magit-diff:--ignore-submodules)
- ("-b" "Ignore whitespace changes" ("-b" "--ignore-space-change"))
- ("-w" "Ignore all whitespace" ("-w" "--ignore-all-space"))
- (5 "-D" "Omit preimage for deletes" ("-D" "--irreversible-delete"))]
- ["Context arguments"
- (magit-diff:-U)
- ("-W" "Show surrounding functions" ("-W" "--function-context"))]
- ["Tune arguments"
- (magit-diff:--diff-algorithm)
- (magit-diff:-M)
- (magit-diff:-C)
- ("-x" "Disallow external diff drivers" "--no-ext-diff")
- ("-s" "Show stats" "--stat")
- ("=g" "Show signature" "--show-signature")
- (5 magit-diff:--color-moved)
- (5 magit-diff:--color-moved-ws)]
- ["Actions"
- [("d" "Dwim" magit-diff-dwim)
- ("r" "Diff range" magit-diff-range)
- ("p" "Diff paths" magit-diff-paths)]
- [("u" "Diff unstaged" magit-diff-unstaged)
- ("s" "Diff staged" magit-diff-staged)
- ("w" "Diff worktree" magit-diff-working-tree)]
- [("c" "Show commit" magit-show-commit)
- ("t" "Show stash" magit-stash-show)]])
-
-;;;###autoload (autoload 'magit-diff-refresh "magit-diff" nil t)
-(transient-define-prefix magit-diff-refresh ()
- "Change the arguments used for the diff(s) in the current buffer."
- :man-page "git-diff"
- :class 'magit-diff-refresh-prefix
- ["Limit arguments"
- (magit:--)
- (magit-diff:--ignore-submodules)
- ("-b" "Ignore whitespace changes" ("-b" "--ignore-space-change"))
- ("-w" "Ignore all whitespace" ("-w" "--ignore-all-space"))
- (5 "-D" "Omit preimage for deletes" ("-D" "--irreversible-delete"))]
- ["Context arguments"
- (magit-diff:-U)
- ("-W" "Show surrounding functions" ("-W" "--function-context"))]
- ["Tune arguments"
- (magit-diff:--diff-algorithm)
- (magit-diff:-M)
- (magit-diff:-C)
- ("-x" "Disallow external diff drivers" "--no-ext-diff")
- ("-s" "Show stats" "--stat"
- :if-derived magit-diff-mode)
- ("=g" "Show signature" "--show-signature"
- :if-derived magit-diff-mode)
- (5 magit-diff:--color-moved)
- (5 magit-diff:--color-moved-ws)]
- [["Refresh"
- ("g" "buffer" magit-diff-refresh)
- ("s" "buffer and set defaults" transient-set :transient nil)
- ("w" "buffer and save defaults" transient-save :transient nil)]
- ["Toggle"
- ("t" "hunk refinement" magit-diff-toggle-refine-hunk)
- ("F" "file filter" magit-diff-toggle-file-filter)
- ("b" "buffer lock" magit-toggle-buffer-lock
- :if-mode (magit-diff-mode magit-revision-mode magit-stash-mode))]
- [:if-mode magit-diff-mode
- :description "Do"
- ("r" "switch range type" magit-diff-switch-range-type)
- ("f" "flip revisions" magit-diff-flip-revs)]]
- (interactive)
- (if (not (eq transient-current-command 'magit-diff-refresh))
- (transient-setup 'magit-diff-refresh)
- (pcase-let ((`(,args ,files) (magit-diff-arguments)))
- (setq magit-buffer-diff-args args)
- (setq magit-buffer-diff-files files))
- (magit-refresh)))
-
-;;;; Infix Commands
-
-(transient-define-argument magit:-- ()
- :description "Limit to files"
- :class 'transient-files
- :key "--"
- :argument "--"
- :prompt "Limit to file(s): "
- :reader 'magit-read-files
- :multi-value t)
-
-(defun magit-read-files (prompt initial-input history)
- (magit-completing-read-multiple* prompt
- (magit-list-files)
- nil nil
- (or initial-input (magit-file-at-point))
- history))
-
-(transient-define-argument magit-diff:-U ()
- :description "Context lines"
- :class 'transient-option
- :argument "-U"
- :reader 'transient-read-number-N0)
-
-(transient-define-argument magit-diff:-M ()
- :description "Detect renames"
- :class 'transient-option
- :argument "-M"
- :reader 'transient-read-number-N+)
-
-(transient-define-argument magit-diff:-C ()
- :description "Detect copies"
- :class 'transient-option
- :argument "-C"
- :reader 'transient-read-number-N+)
-
-(transient-define-argument magit-diff:--diff-algorithm ()
- :description "Diff algorithm"
- :class 'transient-option
- :key "-A"
- :argument "--diff-algorithm="
- :reader 'magit-diff-select-algorithm)
-
-(defun magit-diff-select-algorithm (&rest _ignore)
- (magit-read-char-case nil t
- (?d "[d]efault" "default")
- (?m "[m]inimal" "minimal")
- (?p "[p]atience" "patience")
- (?h "[h]istogram" "histogram")))
-
-(transient-define-argument magit-diff:--ignore-submodules ()
- :description "Ignore submodules"
- :class 'transient-option
- :key "-i"
- :argument "--ignore-submodules="
- :reader 'magit-diff-select-ignore-submodules)
-
-(defun magit-diff-select-ignore-submodules (&rest _ignored)
- (magit-read-char-case "Ignore submodules " t
- (?u "[u]ntracked" "untracked")
- (?d "[d]irty" "dirty")
- (?a "[a]ll" "all")))
-
-(transient-define-argument magit-diff:--color-moved ()
- :description "Color moved lines"
- :class 'transient-option
- :key "-m"
- :argument "--color-moved="
- :reader 'magit-diff-select-color-moved-mode)
-
-(defun magit-diff-select-color-moved-mode (&rest _ignore)
- (magit-read-char-case "Color moved " t
- (?d "[d]efault" "default")
- (?p "[p]lain" "plain")
- (?b "[b]locks" "blocks")
- (?z "[z]ebra" "zebra")
- (?Z "[Z] dimmed-zebra" "dimmed-zebra")))
-
-(transient-define-argument magit-diff:--color-moved-ws ()
- :description "Whitespace treatment for --color-moved"
- :class 'transient-option
- :key "=w"
- :argument "--color-moved-ws="
- :reader 'magit-diff-select-color-moved-ws-mode)
-
-(defun magit-diff-select-color-moved-ws-mode (&rest _ignore)
- (magit-read-char-case "Ignore whitespace " t
- (?i "[i]ndentation" "allow-indentation-change")
- (?e "[e]nd of line" "ignore-space-at-eol")
- (?s "[s]pace change" "ignore-space-change")
- (?a "[a]ll space" "ignore-all-space")
- (?n "[n]o" "no")))
-
-;;;; Setup Commands
-
-;;;###autoload
-(defun magit-diff-dwim (&optional args files)
- "Show changes for the thing at point."
- (interactive (magit-diff-arguments))
- (pcase (magit-diff--dwim)
- (`unmerged (magit-diff-unmerged args files))
- (`unstaged (magit-diff-unstaged args files))
- (`staged
- (let ((file (magit-file-at-point)))
- (if (and file (equal (cddr (car (magit-file-status file))) '(?D ?U)))
- ;; File was deleted by us and modified by them. Show the latter.
- (magit-diff-unmerged args (list file))
- (magit-diff-staged nil args files))))
- (`(commit . ,value)
- (magit-diff-range (format "%s^..%s" value value) args files))
- (`(stash . ,value) (magit-stash-show value args))
- ((and range (pred stringp))
- (magit-diff-range range args files))
- (_
- (call-interactively #'magit-diff-range))))
-
-(defun magit-diff--dwim ()
- "Return information for performing DWIM diff.
-
-The information can be in three forms:
-1. TYPE
- A symbol describing a type of diff where no additional information
- is needed to generate the diff. Currently, this includes `staged',
- `unstaged' and `unmerged'.
-2. (TYPE . VALUE)
- Like #1 but the diff requires additional information, which is
- given by VALUE. Currently, this includes `commit' and `stash',
- where VALUE is the given commit or stash, respectively.
-3. RANGE
- A string indicating a diff range.
-
-If no DWIM context is found, nil is returned."
- (cond
- ((--when-let (magit-region-values '(commit branch) t)
- (deactivate-mark)
- (concat (car (last it)) ".." (car it))))
- (magit-buffer-refname
- (cons 'commit magit-buffer-refname))
- ((derived-mode-p 'magit-stash-mode)
- (cons 'commit
- (magit-section-case
- (commit (oref it value))
- (file (thread-first it
- (oref parent)
- (oref value)))
- (hunk (thread-first it
- (oref parent)
- (oref parent)
- (oref value))))))
- ((derived-mode-p 'magit-revision-mode)
- (cons 'commit magit-buffer-revision))
- ((derived-mode-p 'magit-diff-mode)
- magit-buffer-range)
- (t
- (magit-section-case
- ([* unstaged] 'unstaged)
- ([* staged] 'staged)
- (unmerged 'unmerged)
- (unpushed (oref it value))
- (unpulled (oref it value))
- (branch (let ((current (magit-get-current-branch))
- (atpoint (oref it value)))
- (if (equal atpoint current)
- (--if-let (magit-get-upstream-branch)
- (format "%s...%s" it current)
- (if (magit-anything-modified-p)
- current
- (cons 'commit current)))
- (format "%s...%s"
- (or current "HEAD")
- atpoint))))
- (commit (cons 'commit (oref it value)))
- (stash (cons 'stash (oref it value)))
- (pullreq (forge--pullreq-range (oref it value) t))))))
-
-(defun magit-diff-read-range-or-commit (prompt &optional secondary-default mbase)
- "Read range or revision with special diff range treatment.
-If MBASE is non-nil, prompt for which rev to place at the end of
-a \"revA...revB\" range. Otherwise, always construct
-\"revA..revB\" range."
- (--if-let (magit-region-values '(commit branch) t)
- (let ((revA (car (last it)))
- (revB (car it)))
- (deactivate-mark)
- (if mbase
- (let ((base (magit-git-string "merge-base" revA revB)))
- (cond
- ((string= (magit-rev-parse revA) base)
- (format "%s..%s" revA revB))
- ((string= (magit-rev-parse revB) base)
- (format "%s..%s" revB revA))
- (t
- (let ((main (magit-completing-read "View changes along"
- (list revA revB)
- nil t nil nil revB)))
- (format "%s...%s"
- (if (string= main revB) revA revB) main)))))
- (format "%s..%s" revA revB)))
- (magit-read-range prompt
- (or (pcase (magit-diff--dwim)
- (`(commit . ,value)
- (format "%s^..%s" value value))
- ((and range (pred stringp))
- range))
- secondary-default
- (magit-get-current-branch)))))
-
-;;;###autoload
-(defun magit-diff-range (rev-or-range &optional args files)
- "Show differences between two commits.
-
-REV-OR-RANGE should be a range or a single revision. If it is a
-revision, then show changes in the working tree relative to that
-revision. If it is a range, but one side is omitted, then show
-changes relative to `HEAD'.
-
-If the region is active, use the revisions on the first and last
-line of the region as the two sides of the range. With a prefix
-argument, instead of diffing the revisions, choose a revision to
-view changes along, starting at the common ancestor of both
-revisions (i.e., use a \"...\" range)."
- (interactive (cons (magit-diff-read-range-or-commit "Diff for range"
- nil current-prefix-arg)
- (magit-diff-arguments)))
- (magit-diff-setup-buffer rev-or-range nil args files))
-
-;;;###autoload
-(defun magit-diff-working-tree (&optional rev args files)
- "Show changes between the current working tree and the `HEAD' commit.
-With a prefix argument show changes between the working tree and
-a commit read from the minibuffer."
- (interactive
- (cons (and current-prefix-arg
- (magit-read-branch-or-commit "Diff working tree and commit"))
- (magit-diff-arguments)))
- (magit-diff-setup-buffer (or rev "HEAD") nil args files))
-
-;;;###autoload
-(defun magit-diff-staged (&optional rev args files)
- "Show changes between the index and the `HEAD' commit.
-With a prefix argument show changes between the index and
-a commit read from the minibuffer."
- (interactive
- (cons (and current-prefix-arg
- (magit-read-branch-or-commit "Diff index and commit"))
- (magit-diff-arguments)))
- (magit-diff-setup-buffer rev "--cached" args files))
-
-;;;###autoload
-(defun magit-diff-unstaged (&optional args files)
- "Show changes between the working tree and the index."
- (interactive (magit-diff-arguments))
- (magit-diff-setup-buffer nil nil args files))
-
-;;;###autoload
-(defun magit-diff-unmerged (&optional args files)
- "Show changes that are being merged."
- (interactive (magit-diff-arguments))
- (unless (magit-merge-in-progress-p)
- (user-error "No merge is in progress"))
- (magit-diff-setup-buffer (magit--merge-range) nil args files))
-
-;;;###autoload
-(defun magit-diff-while-committing (&optional args)
- "While committing, show the changes that are about to be committed.
-While amending, invoking the command again toggles between
-showing just the new changes or all the changes that will
-be committed."
- (interactive (list (car (magit-diff-arguments))))
- (unless (magit-commit-message-buffer)
- (user-error "No commit in progress"))
- (let ((magit-display-buffer-noselect t))
- (if-let ((diff-buf (magit-get-mode-buffer 'magit-diff-mode 'selected)))
- (with-current-buffer diff-buf
- (cond ((and (equal magit-buffer-range "HEAD^")
- (equal magit-buffer-typearg "--cached"))
- (magit-diff-staged nil args))
- ((and (equal magit-buffer-range nil)
- (equal magit-buffer-typearg "--cached"))
- (magit-diff-while-amending args))
- ((magit-anything-staged-p)
- (magit-diff-staged nil args))
- (t
- (magit-diff-while-amending args))))
- (if (magit-anything-staged-p)
- (magit-diff-staged nil args)
- (magit-diff-while-amending args)))))
-
-(define-key git-commit-mode-map
- (kbd "C-c C-d") 'magit-diff-while-committing)
-
-(defun magit-diff-while-amending (&optional args)
- (magit-diff-setup-buffer "HEAD^" "--cached" args nil))
-
-;;;###autoload
-(defun magit-diff-buffer-file ()
- "Show diff for the blob or file visited in the current buffer.
-
-When the buffer visits a blob, then show the respective commit.
-When the buffer visits a file, then show the differenced between
-`HEAD' and the working tree. In both cases limit the diff to
-the file or blob."
- (interactive)
- (require 'magit)
- (if-let ((file (magit-file-relative-name)))
- (if magit-buffer-refname
- (magit-show-commit magit-buffer-refname
- (car (magit-show-commit--arguments))
- (list file))
- (save-buffer)
- (let ((line (line-number-at-pos))
- (col (current-column)))
- (with-current-buffer
- (magit-diff-setup-buffer (or (magit-get-current-branch) "HEAD")
- nil
- (car (magit-diff-arguments))
- (list file)
- magit-diff-buffer-file-locked)
- (magit-diff--goto-position file line col))))
- (user-error "Buffer isn't visiting a file")))
-
-;;;###autoload
-(defun magit-diff-paths (a b)
- "Show changes between any two files on disk."
- (interactive (list (read-file-name "First file: " nil nil t)
- (read-file-name "Second file: " nil nil t)))
- (magit-diff-setup-buffer nil "--no-index"
- nil (list (magit-convert-filename-for-git
- (expand-file-name a))
- (magit-convert-filename-for-git
- (expand-file-name b)))))
-
-(defun magit-show-commit--arguments ()
- (pcase-let ((`(,args ,diff-files)
- (magit-diff-arguments 'magit-revision-mode)))
- (list args (if (derived-mode-p 'magit-log-mode)
- (and (or magit-revision-filter-files-on-follow
- (not (member "--follow" magit-buffer-log-args)))
- magit-buffer-log-files)
- diff-files))))
-
-;;;###autoload
-(defun magit-show-commit (rev &optional args files module)
- "Visit the revision at point in another buffer.
-If there is no revision at point or with a prefix argument prompt
-for a revision."
- (interactive
- (pcase-let* ((mcommit (magit-section-value-if 'module-commit))
- (atpoint (or (and (bound-and-true-p magit-blame-mode)
- (oref (magit-current-blame-chunk) orig-rev))
- mcommit
- (thing-at-point 'git-revision t)
- (magit-branch-or-commit-at-point)))
- (`(,args ,files) (magit-show-commit--arguments)))
- (list (or (and (not current-prefix-arg) atpoint)
- (magit-read-branch-or-commit "Show commit" atpoint))
- args
- files
- (and mcommit
- (magit-section-parent-value (magit-current-section))))))
- (require 'magit)
- (let ((file (magit-file-relative-name)))
- (magit-with-toplevel
- (when module
- (setq default-directory
- (expand-file-name (file-name-as-directory module))))
- (unless (magit-commit-p rev)
- (user-error "%s is not a commit" rev))
- (let ((buf (magit-revision-setup-buffer rev args files)))
- (when file
- (save-buffer)
- (let ((line (magit-diff-visit--offset file (list "-R" rev)
- (line-number-at-pos)))
- (col (current-column)))
- (with-current-buffer buf
- (magit-diff--goto-position file line col))))))))
-
-(defun magit-diff--locate-hunk (file line &optional parent)
- (when-let ((diff (cl-find-if (lambda (section)
- (and (cl-typep section 'magit-file-section)
- (equal (oref section value) file)))
- (oref (or parent magit-root-section) children))))
- (let (hunk (hunks (oref diff children)))
- (cl-block nil
- (while (setq hunk (pop hunks))
- (pcase-let* ((`(,beg ,len) (oref hunk to-range))
- (end (+ beg len)))
- (cond ((> beg line) (cl-return (list diff nil)))
- ((<= beg line end) (cl-return (list hunk t)))
- ((null hunks) (cl-return (list hunk nil))))))))))
-
-(defun magit-diff--goto-position (file line column &optional parent)
- (when-let ((pos (magit-diff--locate-hunk file line parent)))
- (pcase-let ((`(,section ,exact) pos))
- (cond ((cl-typep section 'magit-file-section)
- (goto-char (oref section start)))
- (exact
- (goto-char (oref section content))
- (let ((pos (car (oref section to-range))))
- (while (or (< pos line)
- (= (char-after) ?-))
- (unless (= (char-after) ?-)
- (cl-incf pos))
- (forward-line)))
- (forward-char (1+ column)))
- (t
- (goto-char (oref section start))
- (setq section (oref section parent))))
- (while section
- (when (oref section hidden)
- (magit-section-show section))
- (setq section (oref section parent))))
- (magit-section-update-highlight)
- t))
-
-;;;; Setting Commands
-
-(defun magit-diff-switch-range-type ()
- "Convert diff range type.
-Change \"revA..revB\" to \"revA...revB\", or vice versa."
- (interactive)
- (if (and magit-buffer-range
- (derived-mode-p 'magit-diff-mode)
- (string-match magit-range-re magit-buffer-range))
- (setq magit-buffer-range
- (replace-match (if (string= (match-string 2 magit-buffer-range) "..")
- "..."
- "..")
- t t magit-buffer-range 2))
- (user-error "No range to change"))
- (magit-refresh))
-
-(defun magit-diff-flip-revs ()
- "Swap revisions in diff range.
-Change \"revA..revB\" to \"revB..revA\"."
- (interactive)
- (if (and magit-buffer-range
- (derived-mode-p 'magit-diff-mode)
- (string-match magit-range-re magit-buffer-range))
- (progn
- (setq magit-buffer-range
- (concat (match-string 3 magit-buffer-range)
- (match-string 2 magit-buffer-range)
- (match-string 1 magit-buffer-range)))
- (magit-refresh))
- (user-error "No range to swap")))
-
-(defun magit-diff-toggle-file-filter ()
- "Toggle the file restriction of the current buffer's diffs.
-If the current buffer's mode is derived from `magit-log-mode',
-toggle the file restriction in the repository's revision buffer
-instead."
- (interactive)
- (cl-flet ((toggle ()
- (if (or magit-buffer-diff-files
- magit-buffer-diff-files-suspended)
- (cl-rotatef magit-buffer-diff-files
- magit-buffer-diff-files-suspended)
- (setq magit-buffer-diff-files
- (transient-infix-read 'magit:--)))
- (magit-refresh)))
- (cond
- ((derived-mode-p 'magit-log-mode
- 'magit-cherry-mode
- 'magit-reflog-mode)
- (if-let ((buffer (magit-get-mode-buffer 'magit-revision-mode)))
- (with-current-buffer buffer (toggle))
- (message "No revision buffer")))
- ((local-variable-p 'magit-buffer-diff-files)
- (toggle))
- (t
- (user-error "Cannot toggle file filter in this buffer")))))
-
-(defun magit-diff-less-context (&optional count)
- "Decrease the context for diff hunks by COUNT lines."
- (interactive "p")
- (magit-diff-set-context `(lambda (cur) (max 0 (- (or cur 0) ,count)))))
-
-(defun magit-diff-more-context (&optional count)
- "Increase the context for diff hunks by COUNT lines."
- (interactive "p")
- (magit-diff-set-context `(lambda (cur) (+ (or cur 0) ,count))))
-
-(defun magit-diff-default-context ()
- "Reset context for diff hunks to the default height."
- (interactive)
- (magit-diff-set-context #'ignore))
-
-(defun magit-diff-set-context (fn)
- (let* ((def (--if-let (magit-get "diff.context") (string-to-number it) 3))
- (val magit-buffer-diff-args)
- (arg (--first (string-match "^-U\\([0-9]+\\)?$" it) val))
- (num (--if-let (and arg (match-string 1 arg)) (string-to-number it) def))
- (val (delete arg val))
- (num (funcall fn num))
- (arg (and num (not (= num def)) (format "-U%i" num)))
- (val (if arg (cons arg val) val)))
- (setq magit-buffer-diff-args val))
- (magit-refresh))
-
-(defun magit-diff-context-p ()
- (if-let ((arg (--first (string-match "^-U\\([0-9]+\\)$" it)
- magit-buffer-diff-args)))
- (not (equal arg "-U0"))
- t))
-
-(defun magit-diff-ignore-any-space-p ()
- (--any-p (member it magit-buffer-diff-args)
- '("--ignore-cr-at-eol"
- "--ignore-space-at-eol"
- "--ignore-space-change" "-b"
- "--ignore-all-space" "-w"
- "--ignore-blank-space")))
-
-(defun magit-diff-toggle-refine-hunk (&optional style)
- "Turn diff-hunk refining on or off.
-
-If hunk refining is currently on, then hunk refining is turned off.
-If hunk refining is off, then hunk refining is turned on, in
-`selected' mode (only the currently selected hunk is refined).
-
-With a prefix argument, the \"third choice\" is used instead:
-If hunk refining is currently on, then refining is kept on, but
-the refining mode (`selected' or `all') is switched.
-If hunk refining is off, then hunk refining is turned on, in
-`all' mode (all hunks refined).
-
-Customize variable `magit-diff-refine-hunk' to change the default mode."
- (interactive "P")
- (setq-local magit-diff-refine-hunk
- (if style
- (if (eq magit-diff-refine-hunk 'all) t 'all)
- (not magit-diff-refine-hunk)))
- (magit-diff-update-hunk-refinement))
-
-;;;; Visit Commands
-;;;;; Dwim Variants
-
-(defun magit-diff-visit-file (file &optional other-window)
- "From a diff visit the appropriate version of FILE.
-
-Display the buffer in the selected window. With a prefix
-argument OTHER-WINDOW display the buffer in another window
-instead.
-
-Visit the worktree version of the appropriate file. The location
-of point inside the diff determines which file is being visited.
-The visited version depends on what changes the diff is about.
-
-1. If the diff shows uncommitted changes (i.e. stage or unstaged
- changes), then visit the file in the working tree (i.e. the
- same \"real\" file that `find-file' would visit. In all other
- cases visit a \"blob\" (i.e. the version of a file as stored
- in some commit).
-
-2. If point is on a removed line, then visit the blob for the
- first parent of the commit that removed that line, i.e. the
- last commit where that line still exists.
-
-3. If point is on an added or context line, then visit the blob
- that adds that line, or if the diff shows from more than a
- single commit, then visit the blob from the last of these
- commits.
-
-In the file-visiting buffer also go to the line that corresponds
-to the line that point is on in the diff.
-
-Note that this command only works if point is inside a diff. In
-other cases `magit-find-file' (which see) had to be used."
- (interactive (list (magit-file-at-point t t) current-prefix-arg))
- (magit-diff-visit-file--internal file nil
- (if other-window
- #'switch-to-buffer-other-window
- #'pop-to-buffer-same-window)))
-
-(defun magit-diff-visit-file-other-window (file)
- "From a diff visit the appropriate version of FILE in another window.
-Like `magit-diff-visit-file' but use
-`switch-to-buffer-other-window'."
- (interactive (list (magit-file-at-point t t)))
- (magit-diff-visit-file--internal file nil #'switch-to-buffer-other-window))
-
-(defun magit-diff-visit-file-other-frame (file)
- "From a diff visit the appropriate version of FILE in another frame.
-Like `magit-diff-visit-file' but use
-`switch-to-buffer-other-frame'."
- (interactive (list (magit-file-at-point t t)))
- (magit-diff-visit-file--internal file nil #'switch-to-buffer-other-frame))
-
-;;;;; Worktree Variants
-
-(defun magit-diff-visit-worktree-file (file &optional other-window)
- "From a diff visit the worktree version of FILE.
-
-Display the buffer in the selected window. With a prefix
-argument OTHER-WINDOW display the buffer in another window
-instead.
-
-Visit the worktree version of the appropriate file. The location
-of point inside the diff determines which file is being visited.
-
-Unlike `magit-diff-visit-file' always visits the \"real\" file in
-the working tree, i.e the \"current version\" of the file.
-
-In the file-visiting buffer also go to the line that corresponds
-to the line that point is on in the diff. Lines that were added
-or removed in the working tree, the index and other commits in
-between are automatically accounted for."
- (interactive (list (magit-file-at-point t t) current-prefix-arg))
- (magit-diff-visit-file--internal file t
- (if other-window
- #'switch-to-buffer-other-window
- #'pop-to-buffer-same-window)))
-
-(defun magit-diff-visit-worktree-file-other-window (file)
- "From a diff visit the worktree version of FILE in another window.
-Like `magit-diff-visit-worktree-file' but use
-`switch-to-buffer-other-window'."
- (interactive (list (magit-file-at-point t t)))
- (magit-diff-visit-file--internal file t #'switch-to-buffer-other-window))
-
-(defun magit-diff-visit-worktree-file-other-frame (file)
- "From a diff visit the worktree version of FILE in another frame.
-Like `magit-diff-visit-worktree-file' but use
-`switch-to-buffer-other-frame'."
- (interactive (list (magit-file-at-point t t)))
- (magit-diff-visit-file--internal file t #'switch-to-buffer-other-frame))
-
-;;;;; Internal
-
-(defun magit-diff-visit-file--internal (file force-worktree fn)
- "From a diff visit the appropriate version of FILE.
-If FORCE-WORKTREE is non-nil, then visit the worktree version of
-the file, even if the diff is about a committed change. Use FN
-to display the buffer in some window."
- (if (magit-file-accessible-directory-p file)
- (magit-diff-visit-directory file force-worktree)
- (pcase-let ((`(,buf ,pos)
- (magit-diff-visit-file--noselect file force-worktree)))
- (funcall fn buf)
- (magit-diff-visit-file--setup buf pos)
- buf)))
-
-(defun magit-diff-visit-directory (directory &optional other-window)
- "Visit DIRECTORY in some window.
-Display the buffer in the selected window unless OTHER-WINDOW is
-non-nil. If DIRECTORY is the top-level directory of the current
-repository, then visit the containing directory using Dired and
-in the Dired buffer put point on DIRECTORY. Otherwise display
-the Magit-Status buffer for DIRECTORY."
- (if (equal (magit-toplevel directory)
- (magit-toplevel))
- (dired-jump other-window (concat directory "/."))
- (let ((display-buffer-overriding-action
- (if other-window
- '(nil (inhibit-same-window t))
- '(display-buffer-same-window))))
- (magit-status-setup-buffer directory))))
-
-(defun magit-diff-visit-file--setup (buf pos)
- (if-let ((win (get-buffer-window buf 'visible)))
- (with-selected-window win
- (when pos
- (unless (<= (point-min) pos (point-max))
- (widen))
- (goto-char pos))
- (when (and buffer-file-name
- (magit-anything-unmerged-p buffer-file-name))
- (smerge-start-session))
- (run-hooks 'magit-diff-visit-file-hook))
- (error "File buffer is not visible")))
-
-(defun magit-diff-visit-file--noselect (&optional file goto-worktree)
- (unless file
- (setq file (magit-file-at-point t t)))
- (let* ((hunk (magit-diff-visit--hunk))
- (goto-from (and hunk
- (magit-diff-visit--goto-from-p hunk goto-worktree)))
- (line (and hunk (magit-diff-hunk-line hunk goto-from)))
- (col (and hunk (magit-diff-hunk-column hunk goto-from)))
- (spec (magit-diff--dwim))
- (rev (if goto-from
- (magit-diff-visit--range-from spec)
- (magit-diff-visit--range-to spec)))
- (buf (if (or goto-worktree
- (and (not (stringp rev))
- (or magit-diff-visit-avoid-head-blob
- (not goto-from))))
- (or (get-file-buffer file)
- (find-file-noselect file))
- (magit-find-file-noselect (if (stringp rev) rev "HEAD")
- file))))
- (if line
- (with-current-buffer buf
- (cond ((eq rev 'staged)
- (setq line (magit-diff-visit--offset file nil line)))
- ((and goto-worktree
- (stringp rev))
- (setq line (magit-diff-visit--offset file rev line))))
- (list buf (save-restriction
- (widen)
- (goto-char (point-min))
- (forward-line (1- line))
- (move-to-column col)
- (point))))
- (list buf nil))))
-
-(defun magit-diff-visit--hunk ()
- (when-let ((scope (magit-diff-scope)))
- (let ((section (magit-current-section)))
- (cl-case scope
- ((file files)
- (setq section (car (oref section children))))
- (list
- (setq section (car (oref section children)))
- (when section
- (setq section (car (oref section children))))))
- (and
- ;; Unmerged files appear in the list of staged changes
- ;; but unlike in the list of unstaged changes no diffs
- ;; are shown here. In that case `section' is nil.
- section
- ;; Currently the `hunk' type is also abused for file
- ;; mode changes, which we are not interested in here.
- ;; Such sections have no value.
- (oref section value)
- section))))
-
-(defun magit-diff-visit--goto-from-p (section in-worktree)
- (and magit-diff-visit-previous-blob
- (not in-worktree)
- (not (oref section combined))
- (not (< (point) (oref section content)))
- (= (char-after (line-beginning-position)) ?-)))
-
-(defun magit-diff-hunk-line (section goto-from)
- (save-excursion
- (goto-char (line-beginning-position))
- (with-slots (content combined from-ranges from-range to-range) section
- (when (< (point) content)
- (goto-char content)
- (re-search-forward "^[-+]"))
- (+ (car (if goto-from from-range to-range))
- (let ((prefix (if combined (length from-ranges) 1))
- (target (point))
- (offset 0))
- (goto-char content)
- (while (< (point) target)
- (unless (string-match-p
- (if goto-from "\\+" "-")
- (buffer-substring (point) (+ (point) prefix)))
- (cl-incf offset))
- (forward-line))
- offset)))))
-
-(defun magit-diff-hunk-column (section goto-from)
- (if (or (< (point)
- (oref section content))
- (and (not goto-from)
- (= (char-after (line-beginning-position)) ?-)))
- 0
- (max 0 (- (+ (current-column) 2)
- (length (oref section value))))))
-
-(defun magit-diff-visit--range-from (spec)
- (cond ((consp spec)
- (concat (cdr spec) "^"))
- ((stringp spec)
- (car (magit-split-range spec)))
- (t
- spec)))
-
-(defun magit-diff-visit--range-to (spec)
- (if (symbolp spec)
- spec
- (let ((rev (if (consp spec)
- (cdr spec)
- (cdr (magit-split-range spec)))))
- (if (and magit-diff-visit-avoid-head-blob
- (magit-rev-head-p rev))
- 'unstaged
- rev))))
-
-(defun magit-diff-visit--offset (file rev line)
- (let ((offset 0))
- (with-temp-buffer
- (save-excursion
- (magit-with-toplevel
- (magit-git-insert "diff" rev "--" file)))
- (catch 'found
- (while (re-search-forward
- "^@@ -\\([0-9]+\\),\\([0-9]+\\) \\+\\([0-9]+\\),\\([0-9]+\\) @@.*\n"
- nil t)
- (let ((from-beg (string-to-number (match-string 1)))
- (from-len (string-to-number (match-string 2)))
- ( to-len (string-to-number (match-string 4))))
- (if (<= from-beg line)
- (if (< (+ from-beg from-len) line)
- (cl-incf offset (- to-len from-len))
- (let ((rest (- line from-beg)))
- (while (> rest 0)
- (pcase (char-after)
- (?\s (cl-decf rest))
- (?- (cl-decf offset) (cl-decf rest))
- (?+ (cl-incf offset)))
- (forward-line))))
- (throw 'found nil))))))
- (+ line offset)))
-
-;;;; Scroll Commands
-
-(defun magit-diff-show-or-scroll-up ()
- "Update the commit or diff buffer for the thing at point.
-
-Either show the commit or stash at point in the appropriate
-buffer, or if that buffer is already being displayed in the
-current frame and contains information about that commit or
-stash, then instead scroll the buffer up. If there is no
-commit or stash at point, then prompt for a commit."
- (interactive)
- (magit-diff-show-or-scroll 'scroll-up))
-
-(defun magit-diff-show-or-scroll-down ()
- "Update the commit or diff buffer for the thing at point.
-
-Either show the commit or stash at point in the appropriate
-buffer, or if that buffer is already being displayed in the
-current frame and contains information about that commit or
-stash, then instead scroll the buffer down. If there is no
-commit or stash at point, then prompt for a commit."
- (interactive)
- (magit-diff-show-or-scroll 'scroll-down))
-
-(defun magit-diff-show-or-scroll (fn)
- (let (rev cmd buf win)
- (cond
- (magit-blame-mode
- (setq rev (oref (magit-current-blame-chunk) orig-rev))
- (setq cmd 'magit-show-commit)
- (setq buf (magit-get-mode-buffer 'magit-revision-mode)))
- ((derived-mode-p 'git-rebase-mode)
- (with-slots (action-type target)
- (git-rebase-current-line)
- (if (not (eq action-type 'commit))
- (user-error "No commit on this line")
- (setq rev target)
- (setq cmd 'magit-show-commit)
- (setq buf (magit-get-mode-buffer 'magit-revision-mode)))))
- (t
- (magit-section-case
- (branch
- (setq rev (magit-ref-maybe-qualify (oref it value)))
- (setq cmd 'magit-show-commit)
- (setq buf (magit-get-mode-buffer 'magit-revision-mode)))
- (commit
- (setq rev (oref it value))
- (setq cmd 'magit-show-commit)
- (setq buf (magit-get-mode-buffer 'magit-revision-mode)))
- (stash
- (setq rev (oref it value))
- (setq cmd 'magit-stash-show)
- (setq buf (magit-get-mode-buffer 'magit-stash-mode))))))
- (if rev
- (if (and buf
- (setq win (get-buffer-window buf))
- (with-current-buffer buf
- (and (equal rev magit-buffer-revision)
- (equal (magit-rev-parse rev)
- magit-buffer-revision-hash))))
- (with-selected-window win
- (condition-case nil
- (funcall fn)
- (error
- (goto-char (pcase fn
- (`scroll-up (point-min))
- (`scroll-down (point-max)))))))
- (let ((magit-display-buffer-noselect t))
- (if (eq cmd 'magit-show-commit)
- (apply #'magit-show-commit rev (magit-show-commit--arguments))
- (funcall cmd rev))))
- (call-interactively #'magit-show-commit))))
-
-;;;; Section Commands
-
-(defun magit-section-cycle-diffs ()
- "Cycle visibility of diff-related sections in the current buffer."
- (interactive)
- (when-let ((sections
- (cond ((derived-mode-p 'magit-status-mode)
- (--mapcat
- (when it
- (when (oref it hidden)
- (magit-section-show it))
- (oref it children))
- (list (magit-get-section '((staged) (status)))
- (magit-get-section '((unstaged) (status))))))
- ((derived-mode-p 'magit-diff-mode)
- (-filter #'magit-file-section-p
- (oref magit-root-section children))))))
- (if (--any-p (oref it hidden) sections)
- (dolist (s sections)
- (magit-section-show s)
- (magit-section-hide-children s))
- (let ((children (--mapcat (oref it children) sections)))
- (cond ((and (--any-p (oref it hidden) children)
- (--any-p (oref it children) children))
- (mapc 'magit-section-show-headings sections))
- ((seq-some 'magit-section-hidden-body children)
- (mapc 'magit-section-show-children sections))
- (t
- (mapc 'magit-section-hide sections)))))))
-
-;;; Diff Mode
-
-(defvar magit-diff-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map (kbd "C-c C-d") 'magit-diff-while-committing)
- (define-key map (kbd "C-c C-b") 'magit-go-backward)
- (define-key map (kbd "C-c C-f") 'magit-go-forward)
- (define-key map (kbd "SPC") 'scroll-up)
- (define-key map (kbd "DEL") 'scroll-down)
- (define-key map (kbd "j") 'magit-jump-to-diffstat-or-diff)
- (define-key map [remap write-file] 'magit-patch-save)
- map)
- "Keymap for `magit-diff-mode'.")
-
-(define-derived-mode magit-diff-mode magit-mode "Magit Diff"
- "Mode for looking at a Git diff.
-
-This mode is documented in info node `(magit)Diff Buffer'.
-
-\\<magit-mode-map>\
-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'.
-
-\\<magit-hunk-section-map>Type \
-\\[magit-apply] to apply the change at point, \
-\\[magit-stage] to stage,
-\\[magit-unstage] to unstage, \
-\\[magit-discard] to discard, or \
-\\[magit-reverse] to reverse it.
-
-\\{magit-diff-mode-map}"
- :group 'magit-diff
- (hack-dir-local-variables-non-file-buffer)
- (setq imenu-prev-index-position-function
- 'magit-imenu--diff-prev-index-position-function)
- (setq imenu-extract-index-name-function
- 'magit-imenu--diff-extract-index-name-function))
-
-(put 'magit-diff-mode 'magit-diff-default-arguments
- '("--stat" "--no-ext-diff"))
-
-(defun magit-diff-setup-buffer (range typearg args files &optional locked)
- (require 'magit)
- (magit-setup-buffer #'magit-diff-mode locked
- (magit-buffer-range range)
- (magit-buffer-typearg typearg)
- (magit-buffer-diff-args args)
- (magit-buffer-diff-files files)
- (magit-buffer-diff-files-suspended nil)))
-
-(defun magit-diff-refresh-buffer ()
- "Refresh the current `magit-diff-mode' buffer."
- (magit-set-header-line-format
- (if (equal magit-buffer-typearg "--no-index")
- (apply #'format "Differences between %s and %s" magit-buffer-diff-files)
- (concat (if magit-buffer-range
- (if (string-match-p "\\(\\.\\.\\|\\^-\\)"
- magit-buffer-range)
- (format "Changes in %s" magit-buffer-range)
- (format "Changes from %s to working tree" magit-buffer-range))
- (if (equal magit-buffer-typearg "--cached")
- "Staged changes"
- "Unstaged changes"))
- (pcase (length magit-buffer-diff-files)
- (0)
- (1 (concat " in file " (car magit-buffer-diff-files)))
- (_ (concat " in files "
- (mapconcat #'identity magit-buffer-diff-files ", ")))))))
- (setq magit-buffer-range-hashed
- (and magit-buffer-range (magit-hash-range magit-buffer-range)))
- (magit-insert-section (diffbuf)
- (magit-run-section-hook 'magit-diff-sections-hook)))
-
-(cl-defmethod magit-buffer-value (&context (major-mode magit-diff-mode))
- (nconc (cond (magit-buffer-range
- (delq nil (list magit-buffer-range magit-buffer-typearg)))
- ((equal magit-buffer-typearg "--cached")
- (list 'staged))
- (t
- (list 'unstaged magit-buffer-typearg)))
- (and magit-buffer-diff-files (cons "--" magit-buffer-diff-files))))
-
-(defvar magit-diff-section-base-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "C-j") 'magit-diff-visit-worktree-file)
- (define-key map [C-return] 'magit-diff-visit-worktree-file)
- (define-key map [remap magit-visit-thing] 'magit-diff-visit-file)
- (define-key map [remap magit-delete-thing] 'magit-discard)
- (define-key map [remap magit-revert-no-commit] 'magit-reverse)
- (define-key map "a" 'magit-apply)
- (define-key map "s" 'magit-stage)
- (define-key map "u" 'magit-unstage)
- (define-key map "&" 'magit-do-async-shell-command)
- (define-key map "C" 'magit-commit-add-log)
- (define-key map (kbd "C-x a") 'magit-add-change-log-entry)
- (define-key map (kbd "C-x 4 a") 'magit-add-change-log-entry-other-window)
- (define-key map (kbd "C-c C-t") 'magit-diff-trace-definition)
- (define-key map (kbd "C-c C-e") 'magit-diff-edit-hunk-commit)
- map)
- "Parent of `magit-{hunk,file}-section-map'.")
-
-(defvar magit-file-section-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-diff-section-base-map)
- map)
- "Keymap for `file' sections.")
-
-(defvar magit-hunk-section-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-diff-section-base-map)
- map)
- "Keymap for `hunk' sections.")
-
-(defconst magit-diff-conflict-headline-re
- (concat "^" (regexp-opt
- ;; Defined in merge-tree.c in this order.
- '("merged"
- "added in remote"
- "added in both"
- "added in local"
- "removed in both"
- "changed in both"
- "removed in local"
- "removed in remote"))))
-
-(defconst magit-diff-headline-re
- (concat "^\\(@@@?\\|diff\\|Submodule\\|"
- "\\* Unmerged path\\|"
- (substring magit-diff-conflict-headline-re 1)
- "\\)"))
-
-(defconst magit-diff-statline-re
- (concat "^ ?"
- "\\(.*\\)" ; file
- "\\( +| +\\)" ; separator
- "\\([0-9]+\\|Bin\\(?: +[0-9]+ -> [0-9]+ bytes\\)?$\\) ?"
- "\\(\\+*\\)" ; add
- "\\(-*\\)$")) ; del
-
-(defvar magit-diff--reset-non-color-moved
- (list
- "-c" "color.diff.context=normal"
- "-c" "color.diff.plain=normal" ; historical synonym for context
- "-c" "color.diff.meta=normal"
- "-c" "color.diff.frag=normal"
- "-c" "color.diff.func=normal"
- "-c" "color.diff.old=normal"
- "-c" "color.diff.new=normal"
- "-c" "color.diff.commit=normal"
- "-c" "color.diff.whitespace=normal"
- ;; "git-range-diff" does not support "--color-moved", so we don't
- ;; need to reset contextDimmed, oldDimmed, newDimmed, contextBold,
- ;; oldBold, and newBold.
- ))
-
-(defun magit-insert-diff ()
- "Insert the diff into this `magit-diff-mode' buffer."
- (magit--insert-diff
- "diff" magit-buffer-range "-p" "--no-prefix"
- (and (member "--stat" magit-buffer-diff-args) "--numstat")
- magit-buffer-typearg
- magit-buffer-diff-args "--"
- magit-buffer-diff-files))
-
-(defun magit--insert-diff (&rest args)
- (declare (indent 0))
- (let ((magit-git-global-arguments
- (remove "--literal-pathspecs" magit-git-global-arguments)))
- (setq args (-flatten args))
- ;; As of Git 2.19.0, we need to generate diffs with
- ;; --ita-visible-in-index so that `magit-stage' can work with
- ;; intent-to-add files (see #4026). Cache the result for each
- ;; repo to avoid a `git version' call for every diff insertion.
- (when (and (not (equal (car args) "merge-tree"))
- (pcase (magit-repository-local-get 'diff-ita-kludge-p 'unset)
- (`unset
- (let ((val (version<= "2.19.0" (magit-git-version))))
- (magit-repository-local-set 'diff-ita-kludge-p val)
- val))
- (val val)))
- (push "--ita-visible-in-index" (cdr args)))
- (when (cl-member-if (lambda (arg) (string-prefix-p "--color-moved" arg)) args)
- (push "--color=always" (cdr args))
- (setq magit-git-global-arguments
- (append magit-diff--reset-non-color-moved
- magit-git-global-arguments)))
- (magit-git-wash #'magit-diff-wash-diffs args)))
-
-(defun magit-diff-wash-diffs (args &optional limit)
- (run-hooks 'magit-diff-wash-diffs-hook)
- (when (member "--show-signature" args)
- (magit-diff-wash-signature))
- (when (member "--stat" args)
- (magit-diff-wash-diffstat))
- (when (re-search-forward magit-diff-headline-re limit t)
- (goto-char (line-beginning-position))
- (magit-wash-sequence (apply-partially 'magit-diff-wash-diff args))
- (insert ?\n)))
-
-(defun magit-jump-to-diffstat-or-diff ()
- "Jump to the diffstat or diff.
-When point is on a file inside the diffstat section, then jump
-to the respective diff section, otherwise jump to the diffstat
-section or a child thereof."
- (interactive)
- (--if-let (magit-get-section
- (append (magit-section-case
- ([file diffstat] `((file . ,(oref it value))))
- (file `((file . ,(oref it value)) (diffstat)))
- (t '((diffstat))))
- (magit-section-ident magit-root-section)))
- (magit-section-goto it)
- (user-error "No diffstat in this buffer")))
-
-(defun magit-diff-wash-signature ()
- (when (looking-at "^gpg: ")
- (magit-insert-section (signature)
- (while (looking-at "^gpg: ")
- (forward-line))
- (insert "\n"))))
-
-(defun magit-diff-wash-diffstat ()
- (let (heading (beg (point)))
- (when (re-search-forward "^ ?\\([0-9]+ +files? change[^\n]*\n\\)" nil t)
- (setq heading (match-string 1))
- (magit-delete-match)
- (goto-char beg)
- (magit-insert-section (diffstat)
- (insert (propertize heading 'font-lock-face 'magit-diff-file-heading))
- (magit-insert-heading)
- (let (files)
- (while (looking-at "^[-0-9]+\t[-0-9]+\t\\(.+\\)$")
- (push (magit-decode-git-path
- (let ((f (match-string 1)))
- (cond
- ((string-match "\\`\\([^{]+\\){\\(.+\\) => \\(.+\\)}\\'" f)
- (concat (match-string 1 f)
- (match-string 3 f)))
- ((string-match " => " f)
- (substring f (match-end 0)))
- (t f))))
- files)
- (magit-delete-line))
- (setq files (nreverse files))
- (while (looking-at magit-diff-statline-re)
- (magit-bind-match-strings (file sep cnt add del) nil
- (magit-delete-line)
- (when (string-match " +$" file)
- (setq sep (concat (match-string 0 file) sep))
- (setq file (substring file 0 (match-beginning 0))))
- (let ((le (length file)) ld)
- (setq file (magit-decode-git-path file))
- (setq ld (length file))
- (when (> le ld)
- (setq sep (concat (make-string (- le ld) ?\s) sep))))
- (magit-insert-section (file (pop files))
- (insert (propertize file 'font-lock-face 'magit-filename)
- sep cnt " ")
- (when add
- (insert (propertize add 'font-lock-face
- 'magit-diffstat-added)))
- (when del
- (insert (propertize del 'font-lock-face
- 'magit-diffstat-removed)))
- (insert "\n")))))
- (if (looking-at "^$") (forward-line) (insert "\n"))))))
-
-(defun magit-diff-wash-diff (args)
- (when (cl-member-if (lambda (arg) (string-prefix-p "--color-moved" arg)) args)
- (require 'ansi-color)
- (ansi-color-apply-on-region (point-min) (point-max)))
- (cond
- ((looking-at "^Submodule")
- (magit-diff-wash-submodule))
- ((looking-at "^\\* Unmerged path \\(.*\\)")
- (let ((file (magit-decode-git-path (match-string 1))))
- (magit-delete-line)
- (unless (and (derived-mode-p 'magit-status-mode)
- (not (member "--cached" args)))
- (magit-insert-section (file file)
- (insert (propertize
- (format "unmerged %s%s" file
- (pcase (cddr (car (magit-file-status file)))
- (`(?D ?D) " (both deleted)")
- (`(?D ?U) " (deleted by us)")
- (`(?U ?D) " (deleted by them)")
- (`(?A ?A) " (both added)")
- (`(?A ?U) " (added by us)")
- (`(?U ?A) " (added by them)")
- (`(?U ?U) "")))
- 'font-lock-face 'magit-diff-file-heading))
- (insert ?\n))))
- t)
- ((looking-at magit-diff-conflict-headline-re)
- (let ((long-status (match-string 0))
- (status "BUG")
- file orig base modes)
- (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 modes nil long-status)))
- ((looking-at
- "^diff --\\(?:\\(git\\) \\(?:\\(.+?\\) \\2\\)?\\|\\(cc\\|combined\\) \\(.+\\)\\)")
- (let ((status (cond ((equal (match-string 1) "git") "modified")
- ((derived-mode-p 'magit-revision-mode) "resolved")
- (t "unmerged")))
- (file (or (match-string 2) (match-string 4)))
- (beg (point))
- orig header modes)
- (save-excursion
- (forward-line 1)
- (setq header (buffer-substring
- beg (if (re-search-forward magit-diff-headline-re nil t)
- (match-beginning 0)
- (point-max)))))
- (magit-delete-line)
- (while (not (or (eobp) (looking-at magit-diff-headline-re)))
- (if (looking-at "^old mode \\([^\n]+\\)\nnew mode \\([^\n]+\\)\n")
- (progn (setq modes (match-string 0))
- (magit-delete-match))
- (cond
- ((looking-at "^--- \\([^/].*?\\)\t?$") ; i.e. not /dev/null
- (setq orig (match-string 1)))
- ((looking-at "^\\+\\+\\+ \\([^/].*?\\)\t?$")
- (setq file (match-string 1)))
- ((looking-at "^\\(copy\\|rename\\) from \\(.+\\)$")
- (setq orig (match-string 2)))
- ((looking-at "^\\(copy\\|rename\\) to \\(.+\\)$")
- (setq file (match-string 2))
- (setq status (if (equal (match-string 1) "copy") "new file" "renamed")))
- ((looking-at "^\\(new file\\|deleted\\)")
- (setq status (match-string 1))))
- (magit-delete-line)))
- (when orig
- (setq orig (magit-decode-git-path orig)))
- (setq file (magit-decode-git-path file))
- ;; KLUDGE `git-log' ignores `--no-prefix' when `-L' is used.
- (when (and (derived-mode-p 'magit-log-mode)
- (--first (string-match-p "\\`-L" it) magit-buffer-log-args))
- (setq file (substring file 2))
- (when orig
- (setq orig (substring orig 2))))
- (magit-diff-insert-file-section file orig status modes header)))))
-
-(defun magit-diff-insert-file-section
- (file orig status modes header &optional long-status)
- (magit-insert-section section
- (file file (or (equal status "deleted")
- (derived-mode-p 'magit-status-mode)))
- (insert (propertize (format "%-10s %s" status
- (if (or (not orig) (equal orig file))
- file
- (format "%s -> %s" orig file)))
- 'font-lock-face 'magit-diff-file-heading))
- (when long-status
- (insert (format " (%s)" long-status)))
- (magit-insert-heading)
- (unless (equal orig file)
- (oset section source orig))
- (oset section header header)
- (when modes
- (magit-insert-section (hunk)
- (insert modes)
- (magit-insert-heading)))
- (magit-wash-sequence #'magit-diff-wash-hunk)))
-
-(defun magit-diff-wash-submodule ()
- ;; See `show_submodule_summary' in submodule.c and "this" commit.
- (when (looking-at "^Submodule \\([^ ]+\\)")
- (let ((module (match-string 1))
- untracked modified)
- (when (looking-at "^Submodule [^ ]+ contains untracked content$")
- (magit-delete-line)
- (setq untracked t))
- (when (looking-at "^Submodule [^ ]+ contains modified content$")
- (magit-delete-line)
- (setq modified t))
- (cond
- ((and (looking-at "^Submodule \\([^ ]+\\) \\([^ :]+\\)\\( (rewind)\\)?:$")
- (equal (match-string 1) module))
- (magit-bind-match-strings (_module range rewind) nil
- (magit-delete-line)
- (while (looking-at "^ \\([<>]\\) \\(.+\\)$")
- (magit-delete-line))
- (when rewind
- (setq range (replace-regexp-in-string "[^.]\\(\\.\\.\\)[^.]"
- "..." range t t 1)))
- (magit-insert-section (magit-module-section module t)
- (magit-insert-heading
- (propertize (concat "modified " module)
- 'font-lock-face 'magit-diff-file-heading)
- " ("
- (cond (rewind "rewind")
- ((string-match-p "\\.\\.\\." range) "non-ff")
- (t "new commits"))
- (and (or modified untracked)
- (concat ", "
- (and modified "modified")
- (and modified untracked " and ")
- (and untracked "untracked")
- " content"))
- ")")
- (let ((default-directory
- (file-name-as-directory
- (expand-file-name module (magit-toplevel)))))
- (magit-git-wash (apply-partially 'magit-log-wash-log 'module)
- "log" "--oneline" "--left-right" range)
- (delete-char -1)))))
- ((and (looking-at "^Submodule \\([^ ]+\\) \\([^ ]+\\) (\\([^)]+\\))$")
- (equal (match-string 1) module))
- (magit-bind-match-strings (_module _range msg) nil
- (magit-delete-line)
- (magit-insert-section (magit-module-section module)
- (magit-insert-heading
- (propertize (concat "submodule " module)
- 'font-lock-face 'magit-diff-file-heading)
- " (" msg ")"))))
- (t
- (magit-insert-section (magit-module-section module)
- (magit-insert-heading
- (propertize (concat "modified " module)
- 'font-lock-face 'magit-diff-file-heading)
- " ("
- (and modified "modified")
- (and modified untracked " and ")
- (and untracked "untracked")
- " content)")))))))
-
-(defun magit-diff-wash-hunk ()
- (when (looking-at "^@\\{2,\\} \\(.+?\\) @\\{2,\\}\\(?: \\(.*\\)\\)?")
- (let* ((heading (match-string 0))
- (ranges (mapcar (lambda (str)
- (mapcar (lambda (n) (string-to-number n))
- (split-string (substring str 1) ",")))
- (split-string (match-string 1))))
- (about (match-string 2))
- (combined (= (length ranges) 3))
- (value (cons about ranges)))
- (magit-delete-line)
- (magit-insert-section section (hunk value)
- (insert (propertize (concat heading "\n")
- 'font-lock-face 'magit-diff-hunk-heading))
- (magit-insert-heading)
- (while (not (or (eobp) (looking-at "^[^-+\s\\]")))
- (forward-line))
- (oset section end (point))
- (oset section washer 'magit-diff-paint-hunk)
- (oset section combined combined)
- (if combined
- (oset section from-ranges (butlast ranges))
- (oset section from-range (car ranges)))
- (oset section to-range (car (last ranges)))
- (oset section about about)))
- t))
-
-(defun magit-diff-expansion-threshold (section)
- "Keep new diff sections collapsed if washing takes too long."
- (and (magit-file-section-p section)
- (> (float-time (time-subtract (current-time) magit-refresh-start-time))
- magit-diff-expansion-threshold)
- 'hide))
-
-(add-hook 'magit-section-set-visibility-hook #'magit-diff-expansion-threshold)
-
-;;; Revision Mode
-
-(define-derived-mode magit-revision-mode magit-diff-mode "Magit Rev"
- "Mode for looking at a Git commit.
-
-This mode is documented in info node `(magit)Revision Buffer'.
-
-\\<magit-mode-map>\
-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'.
-
-\\<magit-hunk-section-map>Type \
-\\[magit-apply] to apply the change at point, \
-\\[magit-stage] to stage,
-\\[magit-unstage] to unstage, \
-\\[magit-discard] to discard, or \
-\\[magit-reverse] to reverse it.
-
-\\{magit-revision-mode-map}"
- :group 'magit-revision
- (hack-dir-local-variables-non-file-buffer))
-
-(put 'magit-revision-mode 'magit-diff-default-arguments
- '("--stat" "--no-ext-diff"))
-
-(defun magit-revision-setup-buffer (rev args files)
- (magit-setup-buffer #'magit-revision-mode nil
- (magit-buffer-revision rev)
- (magit-buffer-range (format "%s^..%s" rev rev))
- (magit-buffer-diff-args args)
- (magit-buffer-diff-files files)
- (magit-buffer-diff-files-suspended nil)))
-
-(defun magit-revision-refresh-buffer ()
- (magit-set-header-line-format
- (concat (capitalize (magit-object-type magit-buffer-revision))
- " " magit-buffer-revision
- (pcase (length magit-buffer-diff-files)
- (0)
- (1 (concat " limited to file " (car magit-buffer-diff-files)))
- (_ (concat " limited to files "
- (mapconcat #'identity magit-buffer-diff-files ", "))))))
- (setq magit-buffer-revision-hash (magit-rev-parse magit-buffer-revision))
- (magit-insert-section (commitbuf)
- (magit-run-section-hook 'magit-revision-sections-hook)))
-
-(cl-defmethod magit-buffer-value (&context (major-mode magit-revision-mode))
- (cons magit-buffer-revision magit-buffer-diff-files))
-
-(defun magit-insert-revision-diff ()
- "Insert the diff into this `magit-revision-mode' buffer."
- (magit--insert-diff
- "show" "-p" "--cc" "--format=" "--no-prefix"
- (and (member "--stat" magit-buffer-diff-args) "--numstat")
- magit-buffer-diff-args
- (concat magit-buffer-revision "^{commit}")
- "--" magit-buffer-diff-files))
-
-(defun magit-insert-revision-tag ()
- "Insert tag message and headers into a revision buffer.
-This function only inserts anything when `magit-show-commit' is
-called with a tag as argument, when that is called with a commit
-or a ref which is not a branch, then it inserts nothing."
- (when (equal (magit-object-type magit-buffer-revision) "tag")
- (magit-insert-section (taginfo)
- (let ((beg (point)))
- ;; "git verify-tag -v" would output what we need, but the gpg
- ;; output is send to stderr and we have no control over the
- ;; order in which stdout and stderr are inserted, which would
- ;; make parsing hard. We are forced to use "git cat-file tag"
- ;; instead, which inserts the signature instead of verifying
- ;; it. We remove that later and then insert the verification
- ;; output using "git verify-tag" (without the "-v").
- (magit-git-insert "cat-file" "tag" magit-buffer-revision)
- (goto-char beg)
- (forward-line 3)
- (delete-region beg (point)))
- (looking-at "^tagger \\([^<]+\\) <\\([^>]+\\)")
- (let ((heading (format "Tagger: %s <%s>"
- (match-string 1)
- (match-string 2))))
- (magit-delete-line)
- (insert (propertize heading 'font-lock-face
- 'magit-section-secondary-heading)))
- (magit-insert-heading)
- (if (re-search-forward "-----BEGIN PGP SIGNATURE-----" nil t)
- (progn
- (let ((beg (match-beginning 0)))
- (re-search-forward "-----END PGP SIGNATURE-----")
- (delete-region beg (point)))
- (insert ?\n)
- (process-file magit-git-executable nil t nil
- "verify-tag" magit-buffer-revision))
- (goto-char (point-max)))
- (insert ?\n))))
-
-(defvar magit-commit-message-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-show-commit)
- map)
- "Keymap for `commit-message' sections.")
-
-(defun magit-insert-revision-message ()
- "Insert the commit message into a revision buffer."
- (magit-insert-section section (commit-message)
- (oset section heading-highlight-face 'magit-diff-revision-summary-highlight)
- (let ((beg (point))
- (rev magit-buffer-revision))
- (insert (with-temp-buffer
- (magit-rev-insert-format "%B" rev)
- (magit-revision--wash-message)))
- (if (= (point) (+ beg 2))
- (progn (backward-delete-char 2)
- (insert "(no message)\n"))
- (goto-char beg)
- (save-excursion
- (while (search-forward "\r\n" nil t) ; Remove trailing CRs.
- (delete-region (match-beginning 0) (1+ (match-beginning 0)))))
- (when magit-revision-fill-summary-line
- (let ((fill-column (min magit-revision-fill-summary-line
- (window-width))))
- (fill-region (point) (line-end-position))))
- (when magit-revision-use-hash-sections
- (save-excursion
- (while (not (eobp))
- (re-search-forward "\\_<" nil 'move)
- (let ((beg (point)))
- (re-search-forward "\\_>" nil t)
- (when (> (point) beg)
- (let ((text (buffer-substring-no-properties beg (point))))
- (when (pcase magit-revision-use-hash-sections
- (`quickest ; false negatives and positives
- (and (>= (length text) 7)
- (string-match-p "[0-9]" text)
- (string-match-p "[a-z]" text)))
- (`quicker ; false negatives (number-less hashes)
- (and (>= (length text) 7)
- (string-match-p "[0-9]" text)
- (magit-commit-p text)))
- (`quick ; false negatives (short hashes)
- (and (>= (length text) 7)
- (magit-commit-p text)))
- (`slow
- (magit-commit-p text)))
- (put-text-property beg (point)
- 'font-lock-face 'magit-hash)
- (let ((end (point)))
- (goto-char beg)
- (magit-insert-section (commit text)
- (goto-char end))))))))))
- (save-excursion
- (forward-line)
- (magit--add-face-text-property
- beg (point) 'magit-diff-revision-summary)
- (magit-insert-heading))
- (when magit-diff-highlight-keywords
- (save-excursion
- (while (re-search-forward "\\[[^[]*\\]" nil t)
- (let ((beg (match-beginning 0))
- (end (match-end 0)))
- (put-text-property
- beg end 'font-lock-face
- (if-let ((face (get-text-property beg 'font-lock-face)))
- (list face 'magit-keyword)
- 'magit-keyword))))))
- (goto-char (point-max))))))
-
-(defun magit-insert-revision-notes ()
- "Insert commit notes into a revision buffer."
- (let* ((var "core.notesRef")
- (def (or (magit-get var) "refs/notes/commits")))
- (dolist (ref (or (magit-list-active-notes-refs)))
- (magit-insert-section section (notes ref (not (equal ref def)))
- (oset section heading-highlight-face 'magit-diff-hunk-heading-highlight)
- (let ((beg (point))
- (rev magit-buffer-revision))
- (insert (with-temp-buffer
- (magit-git-insert "-c" (concat "core.notesRef=" ref)
- "notes" "show" rev)
- (magit-revision--wash-message)))
- (if (= (point) beg)
- (magit-cancel-section)
- (goto-char beg)
- (end-of-line)
- (insert (format " (%s)"
- (propertize (if (string-prefix-p "refs/notes/" ref)
- (substring ref 11)
- ref)
- 'font-lock-face 'magit-refname)))
- (forward-char)
- (magit--add-face-text-property beg (point) 'magit-diff-hunk-heading)
- (magit-insert-heading)
- (goto-char (point-max))
- (insert ?\n)))))))
-
-(defun magit-revision--wash-message ()
- (let ((major-mode 'git-commit-mode))
- (hack-dir-local-variables)
- (hack-local-variables-apply))
- (unless (memq git-commit-major-mode '(nil text-mode))
- (funcall git-commit-major-mode)
- (font-lock-ensure))
- (buffer-string))
-
-(defun magit-insert-revision-headers ()
- "Insert headers about the commit into a revision buffer."
- (magit-insert-section (headers)
- (--when-let (magit-rev-format "%D" magit-buffer-revision "--decorate=full")
- (insert (magit-format-ref-labels it) ?\s))
- (insert (propertize
- (magit-rev-parse (concat magit-buffer-revision "^{commit}"))
- 'font-lock-face 'magit-hash))
- (magit-insert-heading)
- (let ((beg (point)))
- (magit-rev-insert-format magit-revision-headers-format
- magit-buffer-revision)
- (magit-insert-revision-gravatars magit-buffer-revision beg))
- (when magit-revision-insert-related-refs
- (dolist (parent (magit-commit-parents magit-buffer-revision))
- (magit-insert-section (commit parent)
- (let ((line (magit-rev-format "%h %s" parent)))
- (string-match "^\\([^ ]+\\) \\(.*\\)" line)
- (magit-bind-match-strings (hash msg) line
- (insert "Parent: ")
- (insert (propertize hash 'font-lock-face 'magit-hash))
- (insert " " msg "\n")))))
- (magit--insert-related-refs
- magit-buffer-revision "--merged" "Merged"
- (eq magit-revision-insert-related-refs 'all))
- (magit--insert-related-refs
- magit-buffer-revision "--contains" "Contained"
- (memq magit-revision-insert-related-refs '(all mixed)))
- (when-let ((follows (magit-get-current-tag magit-buffer-revision t)))
- (let ((tag (car follows))
- (cnt (cadr follows)))
- (magit-insert-section (tag tag)
- (insert
- (format "Follows: %s (%s)\n"
- (propertize tag 'font-lock-face 'magit-tag)
- (propertize (number-to-string cnt)
- 'font-lock-face 'magit-branch-local))))))
- (when-let ((precedes (magit-get-next-tag magit-buffer-revision t)))
- (let ((tag (car precedes))
- (cnt (cadr precedes)))
- (magit-insert-section (tag tag)
- (insert (format "Precedes: %s (%s)\n"
- (propertize tag 'font-lock-face 'magit-tag)
- (propertize (number-to-string cnt)
- 'font-lock-face 'magit-tag))))))
- (insert ?\n))))
-
-(defun magit--insert-related-refs (rev arg title remote)
- (when-let ((refs (magit-list-related-branches arg rev (and remote "-a"))))
- (insert title ":" (make-string (- 10 (length title)) ?\s))
- (dolist (branch refs)
- (if (<= (+ (current-column) 1 (length branch))
- (window-width))
- (insert ?\s)
- (insert ?\n (make-string 12 ?\s)))
- (magit-insert-section (branch branch)
- (insert (propertize branch 'font-lock-face
- (if (string-prefix-p "remotes/" branch)
- 'magit-branch-remote
- 'magit-branch-local)))))
- (insert ?\n)))
-
-(defun magit-insert-revision-gravatars (rev beg)
- (when (and magit-revision-show-gravatars
- (window-system))
- (require 'gravatar)
- (pcase-let ((`(,author . ,committer)
- (pcase magit-revision-show-gravatars
- (`t '("^Author: " . "^Commit: "))
- (`author '("^Author: " . nil))
- (`committer '(nil . "^Commit: "))
- (_ magit-revision-show-gravatars))))
- (--when-let (and author (magit-rev-format "%aE" rev))
- (magit-insert-revision-gravatar beg rev it author))
- (--when-let (and committer (magit-rev-format "%cE" rev))
- (magit-insert-revision-gravatar beg rev it committer)))))
-
-(defun magit-insert-revision-gravatar (beg rev email regexp)
- (save-excursion
- (goto-char beg)
- (when (re-search-forward regexp nil t)
- (when-let ((window (get-buffer-window)))
- (let* ((column (length (match-string 0)))
- (font-obj (query-font (font-at (point) window)))
- (size (* 2 (+ (aref font-obj 4)
- (aref font-obj 5))))
- (align-to (+ column
- (ceiling (/ size (aref font-obj 7) 1.0))
- 1))
- (gravatar-size (- size 2)))
- (ignore-errors ; service may be unreachable
- (gravatar-retrieve email 'magit-insert-revision-gravatar-cb
- (list rev (point-marker) align-to column))))))))
-
-(defun magit-insert-revision-gravatar-cb (image rev marker align-to column)
- (unless (eq image 'error)
- (when-let ((buffer (marker-buffer marker)))
- (with-current-buffer buffer
- (save-excursion
- (goto-char marker)
- ;; The buffer might display another revision by now or
- ;; it might have been refreshed, in which case another
- ;; process might already have inserted the image.
- (when (and (equal rev magit-buffer-revision)
- (not (eq (car-safe
- (car-safe
- (get-text-property (point) 'display)))
- 'image)))
- (let ((top `((,@image :ascent center :relief 1)
- (slice 0.0 0.0 1.0 0.5)))
- (bot `((,@image :ascent center :relief 1)
- (slice 0.0 0.5 1.0 1.0)))
- (align `((space :align-to ,align-to))))
- (when magit-revision-use-gravatar-kludge
- (cl-rotatef top bot))
- (let ((inhibit-read-only t))
- (insert (propertize " " 'display top))
- (insert (propertize " " 'display align))
- (forward-line)
- (forward-char column)
- (insert (propertize " " 'display bot))
- (insert (propertize " " 'display align))))))))))
-
-;;; Merge-Preview Mode
-
-(define-derived-mode magit-merge-preview-mode magit-diff-mode "Magit Merge"
- "Mode for previewing a merge."
- :group 'magit-diff
- (hack-dir-local-variables-non-file-buffer))
-
-(put 'magit-merge-preview-mode 'magit-diff-default-arguments
- '("--no-ext-diff"))
-
-(defun magit-merge-preview-setup-buffer (rev)
- (magit-setup-buffer #'magit-merge-preview-mode nil
- (magit-buffer-revision rev)
- (magit-buffer-range (format "%s^..%s" rev rev))))
-
-(defun magit-merge-preview-refresh-buffer ()
- (let* ((branch (magit-get-current-branch))
- (head (or branch (magit-rev-verify "HEAD"))))
- (magit-set-header-line-format (format "Preview merge of %s into %s"
- magit-buffer-revision
- (or branch "HEAD")))
- (magit-insert-section (diffbuf)
- (magit--insert-diff
- "merge-tree" (magit-git-string "merge-base" head magit-buffer-revision)
- head magit-buffer-revision))))
-
-(cl-defmethod magit-buffer-value (&context (major-mode magit-merge-preview-mode))
- magit-buffer-revision)
-
-;;; Diff Sections
-
-(defun magit-hunk-set-window-start (section)
- "When SECTION is a `hunk', ensure that its beginning is visible.
-It the SECTION has a different type, then do nothing."
- (when (magit-hunk-section-p section)
- (magit-section-set-window-start section)))
-
-(add-hook 'magit-section-movement-hook #'magit-hunk-set-window-start)
-
-(defun magit-hunk-goto-successor (section arg)
- (and (magit-hunk-section-p section)
- (when-let ((parent (magit-get-section
- (magit-section-ident
- (oref section parent)))))
- (let* ((children (oref parent children))
- (siblings (magit-section-siblings section 'prev))
- (previous (nth (length siblings) children)))
- (if (not arg)
- (--when-let (or previous (car (last children)))
- (magit-section-goto it)
- t)
- (when previous
- (magit-section-goto previous))
- (if (and (stringp arg)
- (re-search-forward arg (oref parent end) t))
- (goto-char (match-beginning 0))
- (goto-char (oref (car (last children)) end))
- (forward-line -1)
- (while (looking-at "^ ") (forward-line -1))
- (while (looking-at "^[-+]") (forward-line -1))
- (forward-line)))))))
-
-(add-hook 'magit-section-goto-successor-hook #'magit-hunk-goto-successor)
-
-(defvar magit-unstaged-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-diff-unstaged)
- (define-key map [remap magit-delete-thing] 'magit-discard)
- (define-key map "s" 'magit-stage)
- (define-key map "u" 'magit-unstage)
- map)
- "Keymap for the `unstaged' section.")
-
-(magit-define-section-jumper magit-jump-to-unstaged "Unstaged changes" unstaged)
-
-(defun magit-insert-unstaged-changes ()
- "Insert section showing unstaged changes."
- (magit-insert-section (unstaged)
- (magit-insert-heading "Unstaged changes:")
- (magit--insert-diff
- "diff" magit-buffer-diff-args "--no-prefix"
- "--" magit-buffer-diff-files)))
-
-(defvar magit-staged-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-diff-staged)
- (define-key map [remap magit-delete-thing] 'magit-discard)
- (define-key map [remap magit-revert-no-commit] 'magit-reverse)
- (define-key map "s" 'magit-stage)
- (define-key map "u" 'magit-unstage)
- map)
- "Keymap for the `staged' section.")
-
-(magit-define-section-jumper magit-jump-to-staged "Staged changes" staged)
-
-(defun magit-insert-staged-changes ()
- "Insert section showing staged changes."
- ;; Avoid listing all files as deleted when visiting a bare repo.
- (unless (magit-bare-repo-p)
- (magit-insert-section (staged)
- (magit-insert-heading "Staged changes:")
- (magit--insert-diff
- "diff" "--cached" magit-buffer-diff-args "--no-prefix"
- "--" magit-buffer-diff-files))))
-
-;;; Diff Type
-
-(defun magit-diff-type (&optional section)
- "Return the diff type of SECTION.
-
-The returned type is one of the symbols `staged', `unstaged',
-`committed', or `undefined'. This type serves a similar purpose
-as the general type common to all sections (which is stored in
-the `type' slot of the corresponding `magit-section' struct) but
-takes additional information into account. When the SECTION
-isn't related to diffs and the buffer containing it also isn't
-a diff-only buffer, then return nil.
-
-Currently the type can also be one of `tracked' and `untracked'
-but these values are not handled explicitly everywhere they
-should be and a possible fix could be to just return nil here.
-
-The section has to be a `diff' or `hunk' section, or a section
-whose children are of type `diff'. If optional SECTION is nil,
-return the diff type for the current section. In buffers whose
-major mode is `magit-diff-mode' SECTION is ignored and the type
-is determined using other means. In `magit-revision-mode'
-buffers the type is always `committed'.
-
-Do not confuse this with `magit-diff-scope' (which see)."
- (--when-let (or section (magit-current-section))
- (cond ((derived-mode-p 'magit-revision-mode 'magit-stash-mode) 'committed)
- ((derived-mode-p 'magit-diff-mode)
- (let ((range magit-buffer-range)
- (const magit-buffer-typearg))
- (cond ((equal const "--no-index") 'undefined)
- ((or (not range)
- (magit-rev-eq range "HEAD"))
- (if (equal const "--cached")
- 'staged
- 'unstaged))
- ((equal const "--cached")
- (if (magit-rev-head-p range)
- 'staged
- 'undefined)) ; i.e. committed and staged
- (t 'committed))))
- ((derived-mode-p 'magit-status-mode)
- (let ((stype (oref it type)))
- (if (memq stype '(staged unstaged tracked untracked))
- stype
- (pcase stype
- ((or `file `module)
- (let* ((parent (oref it parent))
- (type (oref parent type)))
- (if (memq type '(file module))
- (magit-diff-type parent)
- type)))
- (`hunk (thread-first it
- (oref parent)
- (oref parent)
- (oref type)))))))
- ((derived-mode-p 'magit-log-mode)
- (if (or (and (magit-section-match 'commit section)
- (oref section children))
- (magit-section-match [* file commit] section))
- 'committed
- 'undefined))
- (t 'undefined))))
-
-(cl-defun magit-diff-scope (&optional (section nil ssection) strict)
- "Return the diff scope of SECTION or the selected section(s).
-
-A diff's \"scope\" describes what part of a diff is selected, it is
-a symbol, one of `region', `hunk', `hunks', `file', `files', or
-`list'. Do not confuse this with the diff \"type\", as returned by
-`magit-diff-type'.
-
-If optional SECTION is non-nil, then return the scope of that,
-ignoring the sections selected by the region. Otherwise return
-the scope of the current section, or if the region is active and
-selects a valid group of diff related sections, the type of these
-sections, i.e. `hunks' or `files'. If SECTION, or if that is nil
-the current section, is a `hunk' section; and the region region
-starts and ends inside the body of a that section, then the type
-is `region'. If the region is empty after a mouse click, then
-`hunk' is returned instead of `region'.
-
-If optional STRICT is non-nil, then return nil if the diff type of
-the section at point is `untracked' or the section at point is not
-actually a `diff' but a `diffstat' section."
- (let ((siblings (and (not ssection) (magit-region-sections nil t))))
- (setq section (or section (car siblings) (magit-current-section)))
- (when (and section
- (or (not strict)
- (and (not (eq (magit-diff-type section) 'untracked))
- (not (eq (--when-let (oref section parent)
- (oref it type))
- 'diffstat)))))
- (pcase (list (oref section type)
- (and siblings t)
- (magit-diff-use-hunk-region-p)
- ssection)
- (`(hunk nil t ,_)
- (if (magit-section-internal-region-p section) 'region 'hunk))
- (`(hunk t t nil) 'hunks)
- (`(hunk ,_ ,_ ,_) 'hunk)
- (`(file t t nil) 'files)
- (`(file ,_ ,_ ,_) 'file)
- (`(module t t nil) 'files)
- (`(module ,_ ,_ ,_) 'file)
- (`(,(or `staged `unstaged `untracked)
- nil ,_ ,_) 'list)))))
-
-(defun magit-diff-use-hunk-region-p ()
- (and (region-active-p)
- ;; TODO implement this from first principals
- ;; currently it's trial-and-error
- (not (and (or (eq this-command 'mouse-drag-region)
- (eq last-command 'mouse-drag-region)
- ;; When another window was previously
- ;; selected then the last-command is
- ;; some byte-code function.
- (byte-code-function-p last-command))
- (eq (region-end) (region-beginning))))))
-
-;;; Diff Highlight
-
-(add-hook 'magit-section-unhighlight-hook #'magit-diff-unhighlight)
-(add-hook 'magit-section-highlight-hook #'magit-diff-highlight)
-
-(defun magit-diff-unhighlight (section selection)
- "Remove the highlighting of the diff-related SECTION."
- (when (magit-hunk-section-p section)
- (magit-diff-paint-hunk section selection nil)
- t))
-
-(defun magit-diff-highlight (section selection)
- "Highlight the diff-related SECTION.
-If SECTION is not a diff-related section, then do nothing and
-return nil. If SELECTION is non-nil, then it is a list of sections
-selected by the region, including SECTION. All of these sections
-are highlighted."
- (if (and (magit-section-match 'commit section)
- (oref section children))
- (progn (if selection
- (dolist (section selection)
- (magit-diff-highlight-list section selection))
- (magit-diff-highlight-list section))
- t)
- (when-let ((scope (magit-diff-scope section t)))
- (cond ((eq scope 'region)
- (magit-diff-paint-hunk section selection t))
- (selection
- (dolist (section selection)
- (magit-diff-highlight-recursive section selection)))
- (t
- (magit-diff-highlight-recursive section)))
- t)))
-
-(defun magit-diff-highlight-recursive (section &optional selection)
- (pcase (magit-diff-scope section)
- (`list (magit-diff-highlight-list section selection))
- (`file (magit-diff-highlight-file section selection))
- (`hunk (magit-diff-highlight-heading section selection)
- (magit-diff-paint-hunk section selection t))
- (_ (magit-section-highlight section nil))))
-
-(defun magit-diff-highlight-list (section &optional selection)
- (let ((beg (oref section start))
- (cnt (oref section content))
- (end (oref section end)))
- (when (or (eq this-command 'mouse-drag-region)
- (not selection))
- (unless (and (region-active-p)
- (<= (region-beginning) beg))
- (magit-section-make-overlay beg cnt 'magit-section-highlight))
- (unless (oref section hidden)
- (dolist (child (oref section children))
- (when (or (eq this-command 'mouse-drag-region)
- (not (and (region-active-p)
- (<= (region-beginning)
- (oref child start)))))
- (magit-diff-highlight-recursive child selection)))))
- (when magit-diff-highlight-hunk-body
- (magit-section-make-overlay (1- end) end 'magit-section-highlight))))
-
-(defun magit-diff-highlight-file (section &optional selection)
- (magit-diff-highlight-heading section selection)
- (unless (oref section hidden)
- (dolist (child (oref section children))
- (magit-diff-highlight-recursive child selection))))
-
-(defun magit-diff-highlight-heading (section &optional selection)
- (magit-section-make-overlay
- (oref section start)
- (or (oref section content)
- (oref section end))
- (pcase (list (oref section type)
- (and (member section selection)
- (not (eq this-command 'mouse-drag-region))))
- (`(file t) 'magit-diff-file-heading-selection)
- (`(file nil) 'magit-diff-file-heading-highlight)
- (`(module t) 'magit-diff-file-heading-selection)
- (`(module nil) 'magit-diff-file-heading-highlight)
- (`(hunk t) 'magit-diff-hunk-heading-selection)
- (`(hunk nil) 'magit-diff-hunk-heading-highlight))))
-
-;;; Hunk Paint
-
-(cl-defun magit-diff-paint-hunk
- (section &optional selection
- (highlight (magit-section-selected-p section selection)))
- (let (paint)
- (unless magit-diff-highlight-hunk-body
- (setq highlight nil))
- (cond (highlight
- (unless (oref section hidden)
- (add-to-list 'magit-section-highlighted-sections section)
- (cond ((memq section magit-section-unhighlight-sections)
- (setq magit-section-unhighlight-sections
- (delq section magit-section-unhighlight-sections)))
- (magit-diff-highlight-hunk-body
- (setq paint t)))))
- (t
- (cond ((and (oref section hidden)
- (memq section magit-section-unhighlight-sections))
- (add-to-list 'magit-section-highlighted-sections section)
- (setq magit-section-unhighlight-sections
- (delq section magit-section-unhighlight-sections)))
- (t
- (setq paint t)))))
- (when paint
- (save-excursion
- (goto-char (oref section start))
- (let ((end (oref section end))
- (merging (looking-at "@@@"))
- (diff-type (magit-diff-type))
- (stage nil)
- (tab-width (magit-diff-tab-width
- (magit-section-parent-value section))))
- (forward-line)
- (while (< (point) end)
- (when (and magit-diff-hide-trailing-cr-characters
- (char-equal ?\r (char-before (line-end-position))))
- (put-text-property (1- (line-end-position)) (line-end-position)
- 'invisible t))
- (put-text-property
- (point) (1+ (line-end-position)) 'font-lock-face
- (cond
- ((looking-at "^\\+\\+?\\([<=|>]\\)\\{7\\}")
- (setq stage (pcase (list (match-string 1) highlight)
- (`("<" nil) 'magit-diff-our)
- (`("<" t) 'magit-diff-our-highlight)
- (`("|" nil) 'magit-diff-base)
- (`("|" t) 'magit-diff-base-highlight)
- (`("=" nil) 'magit-diff-their)
- (`("=" t) 'magit-diff-their-highlight)
- (`(">" nil) nil)))
- 'magit-diff-conflict-heading)
- ((looking-at (if merging "^\\(\\+\\| \\+\\)" "^\\+"))
- (magit-diff-paint-tab merging tab-width)
- (magit-diff-paint-whitespace merging 'added diff-type)
- (or stage
- (if highlight 'magit-diff-added-highlight 'magit-diff-added)))
- ((looking-at (if merging "^\\(-\\| -\\)" "^-"))
- (magit-diff-paint-tab merging tab-width)
- (magit-diff-paint-whitespace merging 'removed diff-type)
- (if highlight 'magit-diff-removed-highlight 'magit-diff-removed))
- (t
- (magit-diff-paint-tab merging tab-width)
- (magit-diff-paint-whitespace merging 'context diff-type)
- (if highlight 'magit-diff-context-highlight 'magit-diff-context))))
- (forward-line))))))
- (magit-diff-update-hunk-refinement section))
-
-(defvar magit-diff--tab-width-cache nil)
-
-(defun magit-diff-tab-width (file)
- (setq file (expand-file-name file))
- (cl-flet ((cache (value)
- (let ((elt (assoc file magit-diff--tab-width-cache)))
- (if elt
- (setcdr elt value)
- (setq magit-diff--tab-width-cache
- (cons (cons file value)
- magit-diff--tab-width-cache))))
- value))
- (cond
- ((not magit-diff-adjust-tab-width)
- tab-width)
- ((--when-let (find-buffer-visiting file)
- (cache (buffer-local-value 'tab-width it))))
- ((--when-let (assoc file magit-diff--tab-width-cache)
- (or (cdr it)
- tab-width)))
- ((or (eq magit-diff-adjust-tab-width 'always)
- (and (numberp magit-diff-adjust-tab-width)
- (>= magit-diff-adjust-tab-width
- (nth 7 (file-attributes file)))))
- (cache (buffer-local-value 'tab-width (find-file-noselect file))))
- (t
- (cache nil)
- tab-width))))
-
-(defun magit-diff-paint-tab (merging width)
- (save-excursion
- (forward-char (if merging 2 1))
- (while (= (char-after) ?\t)
- (put-text-property (point) (1+ (point))
- 'display (list (list 'space :width width)))
- (forward-char))))
-
-(defun magit-diff-paint-whitespace (merging line-type diff-type)
- (when (and magit-diff-paint-whitespace
- (or (not (memq magit-diff-paint-whitespace '(uncommitted status)))
- (memq diff-type '(staged unstaged)))
- (cl-case line-type
- (added t)
- (removed (memq magit-diff-paint-whitespace-lines '(all both)))
- (context (memq magit-diff-paint-whitespace-lines '(all)))))
- (let ((prefix (if merging "^[-\\+\s]\\{2\\}" "^[-\\+\s]"))
- (indent
- (if (local-variable-p 'magit-diff-highlight-indentation)
- magit-diff-highlight-indentation
- (setq-local
- magit-diff-highlight-indentation
- (cdr (--first (string-match-p (car it) default-directory)
- (nreverse
- (default-value
- 'magit-diff-highlight-indentation))))))))
- (when (and magit-diff-highlight-trailing
- (looking-at (concat prefix ".*?\\([ \t]+\\)$")))
- (let ((ov (make-overlay (match-beginning 1) (match-end 1) nil t)))
- (overlay-put ov 'font-lock-face 'magit-diff-whitespace-warning)
- (overlay-put ov 'priority 2)
- (overlay-put ov 'evaporate t)))
- (when (or (and (eq indent 'tabs)
- (looking-at (concat prefix "\\( *\t[ \t]*\\)")))
- (and (integerp indent)
- (looking-at (format "%s\\([ \t]* \\{%s,\\}[ \t]*\\)"
- prefix indent))))
- (let ((ov (make-overlay (match-beginning 1) (match-end 1) nil t)))
- (overlay-put ov 'font-lock-face 'magit-diff-whitespace-warning)
- (overlay-put ov 'priority 2)
- (overlay-put ov 'evaporate t))))))
-
-(defun magit-diff-update-hunk-refinement (&optional section)
- (if section
- (unless (oref section hidden)
- (pcase (list magit-diff-refine-hunk
- (oref section refined)
- (eq section (magit-current-section)))
- ((or `(all nil ,_) `(t nil t))
- (oset section refined t)
- (save-excursion
- (goto-char (oref section start))
- ;; `diff-refine-hunk' does not handle combined diffs.
- (unless (looking-at "@@@")
- (let ((smerge-refine-ignore-whitespace
- magit-diff-refine-ignore-whitespace)
- ;; Avoid fsyncing many small temp files
- (write-region-inhibit-fsync t))
- (diff-refine-hunk)))))
- ((or `(nil t ,_) `(t t nil))
- (oset section refined nil)
- (remove-overlays (oref section start)
- (oref section end)
- 'diff-mode 'fine))))
- (cl-labels ((recurse (section)
- (if (magit-section-match 'hunk section)
- (magit-diff-update-hunk-refinement section)
- (dolist (child (oref section children))
- (recurse child)))))
- (recurse magit-root-section))))
-
-
-;;; Hunk Region
-
-(defun magit-diff-hunk-region-beginning ()
- (save-excursion (goto-char (region-beginning))
- (line-beginning-position)))
-
-(defun magit-diff-hunk-region-end ()
- (save-excursion (goto-char (region-end))
- (line-end-position)))
-
-(defun magit-diff-update-hunk-region (section)
- "Highlight the hunk-internal region if any."
- (when (eq (magit-diff-scope section t) 'region)
- (magit-diff--make-hunk-overlay
- (oref section start)
- (1- (oref section content))
- 'font-lock-face 'magit-diff-lines-heading
- 'display (magit-diff-hunk-region-header section)
- 'after-string (magit-diff--hunk-after-string 'magit-diff-lines-heading))
- (run-hook-with-args 'magit-diff-highlight-hunk-region-functions section)
- t))
-
-(defun magit-diff-highlight-hunk-region-dim-outside (section)
- "Dim the parts of the hunk that are outside the hunk-internal region.
-This is done by using the same foreground and background color
-for added and removed lines as for context lines."
- (let ((face (if magit-diff-highlight-hunk-body
- 'magit-diff-context-highlight
- 'magit-diff-context)))
- (when magit-diff-unmarked-lines-keep-foreground
- (setq face `(,@(and (>= emacs-major-version 27) '(:extend t))
- :background ,(face-attribute face :background))))
- (magit-diff--make-hunk-overlay (oref section content)
- (magit-diff-hunk-region-beginning)
- 'font-lock-face face
- 'priority 2)
- (magit-diff--make-hunk-overlay (1+ (magit-diff-hunk-region-end))
- (oref section end)
- 'font-lock-face face
- 'priority 2)))
-
-(defun magit-diff-highlight-hunk-region-using-face (_section)
- "Highlight the hunk-internal region by making it bold.
-Or rather highlight using the face `magit-diff-hunk-region', though
-changing only the `:weight' and/or `:slant' is recommended for that
-face."
- (magit-diff--make-hunk-overlay (magit-diff-hunk-region-beginning)
- (1+ (magit-diff-hunk-region-end))
- 'font-lock-face 'magit-diff-hunk-region))
-
-(defun magit-diff-highlight-hunk-region-using-overlays (section)
- "Emphasize the hunk-internal region using delimiting horizontal lines.
-This is implemented as single-pixel newlines places inside overlays."
- (if (window-system)
- (let ((beg (magit-diff-hunk-region-beginning))
- (end (magit-diff-hunk-region-end))
- (str (propertize
- (concat (propertize "\s" 'display '(space :height (1)))
- (propertize "\n" 'line-height t))
- 'font-lock-face 'magit-diff-lines-boundary)))
- (magit-diff--make-hunk-overlay beg (1+ beg) 'before-string str)
- (magit-diff--make-hunk-overlay end (1+ end) 'after-string str))
- (magit-diff-highlight-hunk-region-using-face section)))
-
-(defun magit-diff-highlight-hunk-region-using-underline (section)
- "Emphasize the hunk-internal region using delimiting horizontal lines.
-This is implemented by overlining and underlining the first and
-last (visual) lines of the region."
- (if (window-system)
- (let* ((beg (magit-diff-hunk-region-beginning))
- (end (magit-diff-hunk-region-end))
- (beg-eol (save-excursion (goto-char beg)
- (end-of-visual-line)
- (point)))
- (end-bol (save-excursion (goto-char end)
- (beginning-of-visual-line)
- (point)))
- (color (face-background 'magit-diff-lines-boundary nil t)))
- (cl-flet ((ln (b e &rest face)
- (magit-diff--make-hunk-overlay
- b e 'font-lock-face face 'after-string
- (magit-diff--hunk-after-string face))))
- (if (= beg end-bol)
- (ln beg beg-eol :overline color :underline color)
- (ln beg beg-eol :overline color)
- (ln end-bol end :underline color))))
- (magit-diff-highlight-hunk-region-using-face section)))
-
-(defun magit-diff--make-hunk-overlay (start end &rest args)
- (let ((ov (make-overlay start end nil t)))
- (overlay-put ov 'evaporate t)
- (while args (overlay-put ov (pop args) (pop args)))
- (push ov magit-section--region-overlays)
- ov))
-
-(defun magit-diff--hunk-after-string (face)
- (propertize "\s"
- 'font-lock-face face
- 'display (list 'space :align-to
- `(+ (0 . right)
- ,(min (window-hscroll)
- (- (line-end-position)
- (line-beginning-position)))))
- ;; This prevents the cursor from being rendered at the
- ;; edge of the window.
- 'cursor t))
-
-;;; Hunk Utilities
-
-(defun magit-diff-inside-hunk-body-p ()
- "Return non-nil if point is inside the body of a hunk."
- (and (magit-section-match 'hunk)
- (when-let ((content (oref (magit-current-section) content)))
- (> (point) content))))
-
-;;; Diff Extract
-
-(defun magit-diff-file-header (section)
- (when (magit-hunk-section-p section)
- (setq section (oref section parent)))
- (when (magit-file-section-p section)
- (oref section header)))
-
-(defun magit-diff-hunk-region-header (section)
- (let ((patch (magit-diff-hunk-region-patch section)))
- (string-match "\n" patch)
- (substring patch 0 (1- (match-end 0)))))
-
-(defun magit-diff-hunk-region-patch (section &optional args)
- (let ((op (if (member "--reverse" args) "+" "-"))
- (sbeg (oref section start))
- (rbeg (magit-diff-hunk-region-beginning))
- (rend (region-end))
- (send (oref section end))
- (patch nil))
- (save-excursion
- (goto-char sbeg)
- (while (< (point) send)
- (looking-at "\\(.\\)\\([^\n]*\n\\)")
- (cond ((or (string-match-p "[@ ]" (match-string-no-properties 1))
- (and (>= (point) rbeg)
- (<= (point) rend)))
- (push (match-string-no-properties 0) patch))
- ((equal op (match-string-no-properties 1))
- (push (concat " " (match-string-no-properties 2)) patch)))
- (forward-line)))
- (let ((buffer-list-update-hook nil)) ; #3759
- (with-temp-buffer
- (insert (mapconcat #'identity (reverse patch) ""))
- (diff-fixup-modifs (point-min) (point-max))
- (setq patch (buffer-string))))
- patch))
-
-;;; _
-(provide 'magit-diff)
-;;; magit-diff.el ends here
+++ /dev/null
-;;; magit-ediff.el --- Ediff extension for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library provides basic support for Ediff.
-
-;;; Code:
-
-(require 'magit)
-
-(require 'ediff)
-(require 'smerge-mode)
-
-(defvar smerge-ediff-buf)
-(defvar smerge-ediff-windows)
-
-;;; Options
-
-(defgroup magit-ediff nil
- "Ediff support for Magit."
- :link '(info-link "(magit)Ediffing")
- :group 'magit-extensions)
-
-(defcustom magit-ediff-quit-hook
- '(magit-ediff-cleanup-auxiliary-buffers
- magit-ediff-restore-previous-winconf)
- "Hooks to run after finishing Ediff, when that was invoked using Magit.
-The hooks are run in the Ediff control buffer. This is similar
-to `ediff-quit-hook' but takes the needs of Magit into account.
-The `ediff-quit-hook' is ignored by Ediff sessions which were
-invoked using Magit."
- :package-version '(magit . "2.2.0")
- :group 'magit-ediff
- :type 'hook
- :get 'magit-hook-custom-get
- :options '(magit-ediff-cleanup-auxiliary-buffers
- magit-ediff-restore-previous-winconf))
-
-(defcustom magit-ediff-dwim-show-on-hunks nil
- "Whether `magit-ediff-dwim' runs show variants on hunks.
-If non-nil, `magit-ediff-show-staged' or
-`magit-ediff-show-unstaged' are called based on what section the
-hunk is in. Otherwise, `magit-ediff-dwim' runs
-`magit-ediff-stage' when point is on an uncommitted hunk."
- :package-version '(magit . "2.2.0")
- :group 'magit-ediff
- :type 'boolean)
-
-(defcustom magit-ediff-show-stash-with-index t
- "Whether `magit-ediff-show-stash' shows the state of the index.
-
-If non-nil, use a third Ediff buffer to distinguish which changes
-in the stash were staged. In cases where the stash contains no
-staged changes, fall back to a two-buffer Ediff.
-
-More specifically, a stash is a merge commit, stash@{N}, with
-potentially three parents.
-
-* stash@{N}^1 represents the `HEAD' commit at the time the stash
- was created.
-
-* stash@{N}^2 records any changes that were staged when the stash
- was made.
-
-* stash@{N}^3, if it exists, contains files that were untracked
- when stashing.
-
-If this option is non-nil, `magit-ediff-show-stash' will run
-Ediff on a file using three buffers: one for stash@{N}, another
-for stash@{N}^1, and a third for stash@{N}^2.
-
-Otherwise, Ediff uses two buffers, comparing
-stash@{N}^1..stash@{N}. Along with any unstaged changes, changes
-in the index commit, stash@{N}^2, will be shown in this
-comparison unless they conflicted with changes in the working
-tree at the time of stashing."
- :package-version '(magit . "2.6.0")
- :group 'magit-ediff
- :type 'boolean)
-
-;;; Commands
-
-(defvar magit-ediff-previous-winconf nil)
-
-;;;###autoload (autoload 'magit-ediff "magit-ediff" nil)
-(transient-define-prefix magit-ediff ()
- "Show differences using the Ediff package."
- :info-manual "(ediff)"
- ["Ediff"
- [("E" "Dwim" magit-ediff-dwim)
- ("s" "Stage" magit-ediff-stage)
- ("m" "Resolve" magit-ediff-resolve)]
- [("u" "Show unstaged" magit-ediff-show-unstaged)
- ("i" "Show staged" magit-ediff-show-staged)
- ("w" "Show worktree" magit-ediff-show-working-tree)]
- [("c" "Show commit" magit-ediff-show-commit)
- ("r" "Show range" magit-ediff-compare)
- ("z" "Show stash" magit-ediff-show-stash)]])
-
-;;;###autoload
-(defun magit-ediff-resolve (file)
- "Resolve outstanding conflicts in FILE using Ediff.
-FILE has to be relative to the top directory of the repository.
-
-In the rare event that you want to manually resolve all
-conflicts, including those already resolved by Git, use
-`ediff-merge-revisions-with-ancestor'."
- (interactive
- (let ((current (magit-current-file))
- (unmerged (magit-unmerged-files)))
- (unless unmerged
- (user-error "There are no unresolved conflicts"))
- (list (magit-completing-read "Resolve file" unmerged nil t nil nil
- (car (member current unmerged))))))
- (magit-with-toplevel
- (with-current-buffer (find-file-noselect file)
- (smerge-ediff)
- (setq-local
- ediff-quit-hook
- (lambda ()
- (let ((bufC ediff-buffer-C)
- (bufS smerge-ediff-buf))
- (with-current-buffer bufS
- (when (yes-or-no-p (format "Conflict resolution finished; save %s? "
- buffer-file-name))
- (erase-buffer)
- (insert-buffer-substring bufC)
- (save-buffer))))
- (when (buffer-live-p ediff-buffer-A) (kill-buffer ediff-buffer-A))
- (when (buffer-live-p ediff-buffer-B) (kill-buffer ediff-buffer-B))
- (when (buffer-live-p ediff-buffer-C) (kill-buffer ediff-buffer-C))
- (when (buffer-live-p ediff-ancestor-buffer)
- (kill-buffer ediff-ancestor-buffer))
- (let ((magit-ediff-previous-winconf smerge-ediff-windows))
- (run-hooks 'magit-ediff-quit-hook)))))))
-
-;;;###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* ((conf (current-window-configuration))
- (bufA (magit-get-revision-buffer "HEAD" file))
- (bufB (magit-get-revision-buffer "{index}" file))
- (bufBrw (and bufB (with-current-buffer bufB (not buffer-read-only))))
- (bufC (get-file-buffer file))
- (fileBufC (or bufC (find-file-noselect file)))
- (coding-system-for-read
- (with-current-buffer fileBufC buffer-file-coding-system)))
- (ediff-buffers3
- (or bufA (magit-find-file-noselect "HEAD" file))
- (with-current-buffer (magit-find-file-index-noselect file t)
- (setq buffer-read-only nil)
- (current-buffer))
- fileBufC
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- (and (buffer-live-p ediff-buffer-B)
- (buffer-modified-p ediff-buffer-B)
- (with-current-buffer ediff-buffer-B
- (magit-update-index)))
- (and (buffer-live-p ediff-buffer-C)
- (buffer-modified-p ediff-buffer-C)
- (with-current-buffer ediff-buffer-C
- (when (y-or-n-p
- (format "Save file %s? " buffer-file-name))
- (save-buffer))))
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(if bufB
- (unless bufBrw '((with-current-buffer ediff-buffer-B
- (setq buffer-read-only t))))
- '((ediff-kill-buffer-carefully ediff-buffer-B)))
- ,@(unless bufC '((ediff-kill-buffer-carefully ediff-buffer-C)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-buffers3))))
-
-;;;###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-with-toplevel
- (let ((conf (current-window-configuration))
- (bufA (if revA
- (magit-get-revision-buffer revA fileA)
- (get-file-buffer fileA)))
- (bufB (if revB
- (magit-get-revision-buffer revB fileB)
- (get-file-buffer fileB))))
- (ediff-buffers
- (or bufA (if revA
- (magit-find-file-noselect revA fileA)
- (find-file-noselect fileA)))
- (or bufB (if revB
- (magit-find-file-noselect revB fileB)
- (find-file-noselect fileB)))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-revision))))
-
-(defun magit-ediff-compare--read-revisions (&optional arg mbase)
- (let ((input (or arg (magit-diff-read-range-or-commit
- "Compare range or commit"
- nil mbase))))
- (--if-let (magit-split-range input)
- (-cons-to-list it)
- (list input nil))))
-
-(defun magit-ediff-read-files (revA revB &optional fileB)
- "Read file in REVB, return it and the corresponding file in REVA.
-When FILEB is non-nil, use this as REVB's file instead of
-prompting for it."
- (unless fileB
- (setq fileB (magit-read-file-choice
- (format "File to compare between %s and %s"
- revA (or revB "the working tree"))
- (magit-changed-files revA revB)
- (format "No changed files between %s and %s"
- revA (or revB "the working tree")))))
- (list (or (car (member fileB (magit-revision-files revA)))
- (cdr (assoc fileB (magit-renamed-files revB revA)))
- (magit-read-file-choice
- (format "File in %s to compare with %s in %s"
- revA fileB (or revB "the working tree"))
- (magit-changed-files revB revA)
- (format "No files have changed between %s and %s"
- revA revB)))
- fileB))
-
-;;;###autoload
-(defun magit-ediff-dwim ()
- "Compare, stage, or resolve using Ediff.
-This command tries to guess what file, and what commit or range
-the user wants to compare, stage, or resolve using Ediff. It
-might only be able to guess either the file, or range or commit,
-in which case the user is asked about the other. It might not
-always guess right, in which case the appropriate `magit-ediff-*'
-command has to be used explicitly. If it cannot read the user's
-mind at all, then it asks the user for a command to run."
- (interactive)
- (magit-section-case
- (hunk (save-excursion
- (goto-char (oref (oref it parent) start))
- (magit-ediff-dwim)))
- (t
- (let ((range (magit-diff--dwim))
- (file (magit-current-file))
- command revA revB)
- (pcase range
- ((and (guard (not magit-ediff-dwim-show-on-hunks))
- (or `unstaged `staged))
- (setq command (if (magit-anything-unmerged-p)
- #'magit-ediff-resolve
- #'magit-ediff-stage)))
- (`unstaged (setq command #'magit-ediff-show-unstaged))
- (`staged (setq command #'magit-ediff-show-staged))
- (`(commit . ,value)
- (setq command #'magit-ediff-show-commit)
- (setq revB value))
- (`(stash . ,value)
- (setq command #'magit-ediff-show-stash)
- (setq revB value))
- ((pred stringp)
- (pcase-let ((`(,a ,b) (magit-ediff-compare--read-revisions range)))
- (setq command #'magit-ediff-compare)
- (setq revA a)
- (setq revB b)))
- (_
- (when (derived-mode-p 'magit-diff-mode)
- (pcase (magit-diff-type)
- (`committed (pcase-let ((`(,a ,b)
- (magit-ediff-compare--read-revisions
- magit-buffer-range)))
- (setq revA a)
- (setq revB b)))
- ((guard (not magit-ediff-dwim-show-on-hunks))
- (setq command #'magit-ediff-stage))
- (`unstaged (setq command #'magit-ediff-show-unstaged))
- (`staged (setq command #'magit-ediff-show-staged))
- (`undefined (setq command nil))
- (_ (setq command nil))))))
- (cond ((not command)
- (call-interactively
- (magit-read-char-case
- "Failed to read your mind; do you want to " t
- (?c "[c]ommit" 'magit-ediff-show-commit)
- (?r "[r]ange" 'magit-ediff-compare)
- (?s "[s]tage" 'magit-ediff-stage)
- (?v "resol[v]e" 'magit-ediff-resolve))))
- ((eq command 'magit-ediff-compare)
- (apply 'magit-ediff-compare revA revB
- (magit-ediff-read-files revA revB file)))
- ((eq command 'magit-ediff-show-commit)
- (magit-ediff-show-commit revB))
- ((eq command 'magit-ediff-show-stash)
- (magit-ediff-show-stash revB))
- (file
- (funcall command file))
- (t
- (call-interactively command)))))))
-
-;;;###autoload
-(defun magit-ediff-show-staged (file)
- "Show staged changes using Ediff.
-
-This only allows looking at the changes; to stage, unstage,
-and discard changes using Ediff, use `magit-ediff-stage'.
-
-FILE must be relative to the top directory of the repository."
- (interactive
- (list (magit-read-file-choice "Show staged changes for file"
- (magit-staged-files)
- "No staged files")))
- (let ((conf (current-window-configuration))
- (bufA (magit-get-revision-buffer "HEAD" file))
- (bufB (get-buffer (concat file ".~{index}~"))))
- (ediff-buffers
- (or bufA (magit-find-file-noselect "HEAD" file))
- (or bufB (magit-find-file-index-noselect file t))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-buffers)))
-
-;;;###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-with-toplevel
- (let ((conf (current-window-configuration))
- (bufA (get-buffer (concat file ".~{index}~")))
- (bufB (get-file-buffer file)))
- (ediff-buffers
- (or bufA (magit-find-file-index-noselect file t))
- (or bufB (find-file-noselect file))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-buffers))))
-
-;;;###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-with-toplevel
- (let ((conf (current-window-configuration))
- (bufA (magit-get-revision-buffer "HEAD" file))
- (bufB (get-file-buffer file)))
- (ediff-buffers
- (or bufA (magit-find-file-noselect "HEAD" file))
- (or bufB (find-file-noselect file))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-buffers))))
-
-;;;###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)))
- (let ((conf (current-window-configuration))
- (bufA (magit-get-revision-buffer revA fileA))
- (bufB (magit-get-revision-buffer revB fileB))
- (bufC (magit-get-revision-buffer revC fileC)))
- (ediff-buffers3
- (or bufA (magit-find-file-noselect revA fileA))
- (or bufB (magit-find-file-noselect revB fileB))
- (or bufC (magit-find-file-noselect revC fileC))
- `((lambda ()
- (setq-local
- ediff-quit-hook
- (lambda ()
- ,@(unless bufA
- '((ediff-kill-buffer-carefully ediff-buffer-A)))
- ,@(unless bufB
- '((ediff-kill-buffer-carefully ediff-buffer-B)))
- ,@(unless bufC
- '((ediff-kill-buffer-carefully ediff-buffer-C)))
- (let ((magit-ediff-previous-winconf ,conf))
- (run-hooks 'magit-ediff-quit-hook))))))
- 'ediff-buffers3))
- (magit-ediff-compare revA revC fileA fileC))))
-
-(defun magit-ediff-cleanup-auxiliary-buffers ()
- (let* ((ctl-buf ediff-control-buffer)
- (ctl-win (ediff-get-visible-buffer-window ctl-buf))
- (ctl-frm ediff-control-frame)
- (main-frame (cond ((window-live-p ediff-window-A)
- (window-frame ediff-window-A))
- ((window-live-p ediff-window-B)
- (window-frame ediff-window-B)))))
- (ediff-kill-buffer-carefully ediff-diff-buffer)
- (ediff-kill-buffer-carefully ediff-custom-diff-buffer)
- (ediff-kill-buffer-carefully ediff-fine-diff-buffer)
- (ediff-kill-buffer-carefully ediff-tmp-buffer)
- (ediff-kill-buffer-carefully ediff-error-buffer)
- (ediff-kill-buffer-carefully ediff-msg-buffer)
- (ediff-kill-buffer-carefully ediff-debug-buffer)
- (when (boundp 'ediff-patch-diagnostics)
- (ediff-kill-buffer-carefully ediff-patch-diagnostics))
- (cond ((and (ediff-window-display-p)
- (frame-live-p ctl-frm))
- (delete-frame ctl-frm))
- ((window-live-p ctl-win)
- (delete-window ctl-win)))
- (ediff-kill-buffer-carefully ctl-buf)
- (when (frame-live-p main-frame)
- (select-frame main-frame))))
-
-(defun magit-ediff-restore-previous-winconf ()
- (set-window-configuration magit-ediff-previous-winconf))
-
-;;; _
-(provide 'magit-ediff)
-;;; magit-ediff.el ends here
+++ /dev/null
-;;; magit-extras.el --- additional functionality for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Additional functionality for Magit.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit)
-
-(declare-function dired-read-shell-command "dired-aux" (prompt arg files))
-;; For `magit-project-status'.
-(declare-function project-root "project" (project))
-(declare-function vc-git-command "vc-git" (buffer okstatus file-or-list &rest flags))
-
-(defvar ido-exit)
-(defvar ido-fallback)
-(defvar project-prefix-map)
-(defvar project-switch-commands)
-
-(defgroup magit-extras nil
- "Additional functionality for Magit."
- :group 'magit-extensions)
-
-;;; External Tools
-
-(defcustom magit-gitk-executable
- (or (and (eq system-type 'windows-nt)
- (let ((exe (magit-git-string
- "-c" "alias.X=!x() { which \"$1\" | cygpath -mf -; }; x"
- "X" "gitk.exe")))
- (and exe (file-executable-p exe) exe)))
- (executable-find "gitk") "gitk")
- "The Gitk executable."
- :group 'magit-extras
- :set-after '(magit-git-executable)
- :type 'string)
-
-;;;###autoload
-(defun magit-run-git-gui ()
- "Run `git gui' for the current git repository."
- (interactive)
- (magit-with-toplevel
- (magit-process-file magit-git-executable nil 0 nil "gui")))
-
-;;;###autoload
-(defun magit-run-git-gui-blame (commit filename &optional linenum)
- "Run `git gui blame' on the given FILENAME and COMMIT.
-Interactively run it for the current file and the `HEAD', with a
-prefix or when the current file cannot be determined let the user
-choose. When the current buffer is visiting FILENAME instruct
-blame to center around the line point is on."
- (interactive
- (let (revision filename)
- (when (or current-prefix-arg
- (not (setq revision "HEAD"
- filename (magit-file-relative-name nil 'tracked))))
- (setq revision (magit-read-branch-or-commit "Blame from revision"))
- (setq filename (magit-read-file-from-rev revision "Blame file")))
- (list revision filename
- (and (equal filename
- (ignore-errors
- (magit-file-relative-name buffer-file-name)))
- (line-number-at-pos)))))
- (magit-with-toplevel
- (apply #'magit-process-file magit-git-executable nil 0 nil "gui" "blame"
- `(,@(and linenum (list (format "--line=%d" linenum)))
- ,commit
- ,filename))))
-
-;;;###autoload
-(defun magit-run-gitk ()
- "Run `gitk' in the current repository."
- (interactive)
- (magit-process-file magit-gitk-executable nil 0))
-
-;;;###autoload
-(defun magit-run-gitk-branches ()
- "Run `gitk --branches' in the current repository."
- (interactive)
- (magit-process-file magit-gitk-executable nil 0 nil "--branches"))
-
-;;;###autoload
-(defun magit-run-gitk-all ()
- "Run `gitk --all' in the current repository."
- (interactive)
- (magit-process-file magit-gitk-executable nil 0 nil "--all"))
-
-;;; Emacs Tools
-
-;;;###autoload
-(defun ido-enter-magit-status ()
- "Drop into `magit-status' from file switching.
-
-This command does not work in Emacs 26.1.
-See https://github.com/magit/magit/issues/3634
-and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31707.
-
-To make this command available use something like:
-
- (add-hook \\='ido-setup-hook
- (lambda ()
- (define-key ido-completion-map
- (kbd \"C-x g\") \\='ido-enter-magit-status)))
-
-Starting with Emacs 25.1 the Ido keymaps are defined just once
-instead of every time Ido is invoked, so now you can modify it
-like pretty much every other keymap:
-
- (define-key ido-common-completion-map
- (kbd \"C-x g\") \\='ido-enter-magit-status)"
- (interactive)
- (setq ido-exit 'fallback)
- (setq ido-fallback 'magit-status) ; for Emacs >= 26.2
- (with-no-warnings (setq fallback 'magit-status)) ; for Emacs 25
- (exit-minibuffer))
-
-;;;###autoload
-(defun magit-project-status ()
- "Run `magit-status' in the current project's root."
- (interactive)
- (magit-status-setup-buffer (project-root (project-current t))))
-
-(with-eval-after-load 'project
- ;; Only more recent versions of project.el have `project-prefix-map' and
- ;; `project-switch-commands', though project.el is available in Emacs 25.
- (when (boundp 'project-prefix-map)
- (define-key project-prefix-map "m" #'magit-project-status))
- (when (boundp 'project-switch-commands)
- (add-to-list 'project-switch-commands '(?m "Magit" magit-status))))
-
-;;;###autoload
-(defun magit-dired-jump (&optional other-window)
- "Visit file at point using Dired.
-With a prefix argument, visit in another window. If there
-is no file at point, then instead visit `default-directory'."
- (interactive "P")
- (dired-jump other-window
- (when-let ((file (magit-file-at-point)))
- (expand-file-name (if (file-directory-p file)
- (file-name-as-directory file)
- file)))))
-
-;;;###autoload
-(defun magit-dired-log (&optional follow)
- "Show log for all marked files, or the current file."
- (interactive "P")
- (if-let ((topdir (magit-toplevel default-directory)))
- (let ((args (car (magit-log-arguments)))
- (files (dired-get-marked-files nil nil #'magit-file-tracked-p)))
- (unless files
- (user-error "No marked file is being tracked by Git"))
- (when (and follow
- (not (member "--follow" args))
- (not (cdr files)))
- (push "--follow" args))
- (magit-log-setup-buffer
- (list (or (magit-get-current-branch) "HEAD"))
- args
- (let ((default-directory topdir))
- (mapcar #'file-relative-name files))
- magit-log-buffer-file-locked))
- (magit--not-inside-repository-error)))
-
-;;;###autoload
-(defun magit-do-async-shell-command (file)
- "Open FILE with `dired-do-async-shell-command'.
-Interactively, open the file at point."
- (interactive (list (or (magit-file-at-point)
- (completing-read "Act on file: "
- (magit-list-files)))))
- (require 'dired-aux)
- (dired-do-async-shell-command
- (dired-read-shell-command "& on %s: " current-prefix-arg (list file))
- nil (list file)))
-
-;;; Shift Selection
-
-(defun magit--turn-on-shift-select-mode-p ()
- (and shift-select-mode
- this-command-keys-shift-translated
- (not mark-active)
- (not (eq (car-safe transient-mark-mode) 'only))))
-
-;;;###autoload
-(defun magit-previous-line (&optional arg try-vscroll)
- "Like `previous-line' but with Magit-specific shift-selection.
-
-Magit's selection mechanism is based on the region but selects an
-area that is larger than the region. This causes `previous-line'
-when invoked while holding the shift key to move up one line and
-thereby select two lines. When invoked inside a hunk body this
-command does not move point on the first invocation and thereby
-it only selects a single line. Which inconsistency you prefer
-is a matter of preference."
- (declare (interactive-only
- "use `forward-line' with negative argument instead."))
- (interactive "p\np")
- (unless arg (setq arg 1))
- (let ((stay (or (magit-diff-inside-hunk-body-p)
- (magit-section-position-in-heading-p))))
- (if (and stay (= arg 1) (magit--turn-on-shift-select-mode-p))
- (push-mark nil nil t)
- (with-no-warnings
- (handle-shift-selection)
- (previous-line (if stay (max (1- arg) 1) arg) try-vscroll)))))
-
-;;;###autoload
-(defun magit-next-line (&optional arg try-vscroll)
- "Like `next-line' but with Magit-specific shift-selection.
-
-Magit's selection mechanism is based on the region but selects
-an area that is larger than the region. This causes `next-line'
-when invoked while holding the shift key to move down one line
-and thereby select two lines. When invoked inside a hunk body
-this command does not move point on the first invocation and
-thereby it only selects a single line. Which inconsistency you
-prefer is a matter of preference."
- (declare (interactive-only forward-line))
- (interactive "p\np")
- (unless arg (setq arg 1))
- (let ((stay (or (magit-diff-inside-hunk-body-p)
- (magit-section-position-in-heading-p))))
- (if (and stay (= arg 1) (magit--turn-on-shift-select-mode-p))
- (push-mark nil nil t)
- (with-no-warnings
- (handle-shift-selection)
- (next-line (if stay (max (1- arg) 1) arg) try-vscroll)))))
-
-;;; Clean
-
-;;;###autoload
-(defun magit-clean (&optional arg)
- "Remove untracked files from the working tree.
-With a prefix argument also remove ignored files,
-with two prefix arguments remove ignored files only.
-\n(git clean -f -d [-x|-X])"
- (interactive "p")
- (when (yes-or-no-p (format "Remove %s files? "
- (pcase arg
- (1 "untracked")
- (4 "untracked and ignored")
- (_ "ignored"))))
- (magit-wip-commit-before-change)
- (magit-run-git "clean" "-f" "-d" (pcase arg (4 "-x") (16 "-X")))))
-
-(put 'magit-clean 'disabled t)
-
-;;; ChangeLog
-
-(defun magit-generate-changelog (&optional amending)
- "Insert ChangeLog entries into the current buffer.
-
-The entries are generated from the diff being committed.
-If prefix argument, AMENDING, is non-nil, include changes
-in HEAD as well as staged changes in the diff to check."
- (interactive "P")
- (unless (magit-commit-message-buffer)
- (user-error "No commit in progress"))
- (require 'diff-mode) ; `diff-add-log-current-defuns'.
- (require 'vc-git) ; `vc-git-diff'.
- (require 'add-log) ; `change-log-insert-entries'.
- (unless (and (fboundp 'change-log-insert-entries)
- (fboundp 'diff-add-log-current-defuns))
- (user-error "`magit-generate-changelog' requires Emacs 27 or better"))
- (setq default-directory
- (if (and (file-regular-p "gitdir")
- (not (magit-git-true "rev-parse" "--is-inside-work-tree"))
- (magit-git-true "rev-parse" "--is-inside-git-dir"))
- (file-name-directory (magit-file-line "gitdir"))
- (magit-toplevel)))
- (let ((rev1 (if amending "HEAD^1" "HEAD"))
- (rev2 nil))
- ;; Magit may have updated the files without notifying vc, but
- ;; `diff-add-log-current-defuns' relies on vc being up-to-date.
- (mapc #'vc-file-clearprops (magit-staged-files))
- (change-log-insert-entries
- (with-temp-buffer
- (vc-git-command (current-buffer) 1 nil
- "diff-index" "--exit-code" "--patch"
- (and (magit-anything-staged-p) "--cached")
- rev1 "--")
- ;; `diff-find-source-location' consults these vars.
- (defvar diff-vc-revisions)
- (setq-local diff-vc-revisions (list rev1 rev2))
- (setq-local diff-vc-backend 'Git)
- (diff-add-log-current-defuns)))))
-
-;;;###autoload
-(defun magit-add-change-log-entry (&optional whoami file-name other-window)
- "Find change log file and add date entry and item for current change.
-This differs from `add-change-log-entry' (which see) in that
-it acts on the current hunk in a Magit buffer instead of on
-a position in a file-visiting buffer."
- (interactive (list current-prefix-arg
- (prompt-for-change-log-name)))
- (pcase-let ((`(,buf ,pos) (magit-diff-visit-file--noselect)))
- (magit--with-temp-position buf pos
- (let ((add-log-buffer-file-name-function
- (lambda ()
- (or magit-buffer-file-name
- (buffer-file-name)))))
- (add-change-log-entry whoami file-name other-window)))))
-
-;;;###autoload
-(defun magit-add-change-log-entry-other-window (&optional whoami file-name)
- "Find change log file in other window and add entry and item.
-This differs from `add-change-log-entry-other-window' (which see)
-in that it acts on the current hunk in a Magit buffer instead of
-on a position in a file-visiting buffer."
- (interactive (and current-prefix-arg
- (list current-prefix-arg
- (prompt-for-change-log-name))))
- (magit-add-change-log-entry whoami file-name t))
-
-;;; Edit Line Commit
-
-;;;###autoload
-(defun magit-edit-line-commit (&optional type)
- "Edit the commit that added the current line.
-
-With a prefix argument edit the commit that removes the line,
-if any. The commit is determined using `git blame' and made
-editable using `git rebase --interactive' if it is reachable
-from `HEAD', or by checking out the commit (or a branch that
-points at it) otherwise."
- (interactive (list (and current-prefix-arg 'removal)))
- (let* ((chunk (magit-current-blame-chunk (or type 'addition)))
- (rev (oref chunk orig-rev)))
- (if (equal rev "0000000000000000000000000000000000000000")
- (message "This line has not been committed yet")
- (let ((rebase (magit-rev-ancestor-p rev "HEAD"))
- (file (expand-file-name (oref chunk orig-file)
- (magit-toplevel))))
- (if rebase
- (let ((magit--rebase-published-symbol 'edit-published))
- (magit-rebase-edit-commit rev (magit-rebase-arguments)))
- (magit-checkout (or (magit-rev-branch rev) rev)))
- (unless (and buffer-file-name
- (file-equal-p file buffer-file-name))
- (let ((blame-type (and magit-blame-mode magit-blame-type)))
- (if rebase
- (set-process-sentinel
- magit-this-process
- (lambda (process event)
- (magit-sequencer-process-sentinel process event)
- (when (eq (process-status process) 'exit)
- (find-file file)
- (when blame-type
- (magit-blame--pre-blame-setup blame-type)
- (magit-blame--run (magit-blame-arguments))))))
- (find-file file)
- (when blame-type
- (magit-blame--pre-blame-setup blame-type)
- (magit-blame--run (magit-blame-arguments))))))))))
-
-(put 'magit-edit-line-commit 'disabled t)
-
-;;;###autoload
-(defun magit-diff-edit-hunk-commit (file)
- "From a hunk, edit the respective commit and visit the file.
-
-First visit the file being modified by the hunk at the correct
-location using `magit-diff-visit-file'. This actually visits a
-blob. When point is on a diff header, not within an individual
-hunk, then this visits the blob the first hunk is about.
-
-Then invoke `magit-edit-line-commit', which uses an interactive
-rebase to make the commit editable, or if that is not possible
-because the commit is not reachable from `HEAD' by checking out
-that commit directly. This also causes the actual worktree file
-to be visited.
-
-Neither the blob nor the file buffer are killed when finishing
-the rebase. If that is undesirable, then it might be better to
-use `magit-rebase-edit-command' instead of this command."
- (interactive (list (magit-file-at-point t t)))
- (let ((magit-diff-visit-previous-blob nil))
- (with-current-buffer
- (magit-diff-visit-file--internal file nil #'pop-to-buffer-same-window)
- (magit-edit-line-commit))))
-
-(put 'magit-diff-edit-hunk-commit 'disabled t)
-
-;;; Reshelve
-
-(defcustom magit-reshelve-since-committer-only nil
- "Whether `magit-reshelve-since' changes only the committer dates.
-Otherwise the author dates are also changed."
- :package-version '(magit . "3.0.0")
- :group 'magit-commands
- :type 'boolean)
-
-;;;###autoload
-(defun magit-reshelve-since (rev)
- "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."
- (interactive (list nil))
- (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 'magit-reshelve-since
- "Type %p on a commit to reshelve it and the commits above it,"))
- (t
- (cl-flet ((adjust (time offset)
- (format-time-string
- "%F %T %z"
- (+ (floor time)
- (* offset 60)
- (- (car (decode-time time)))))))
- (let* ((start (concat rev "^"))
- (range (concat start ".." current))
- (time-rev (adjust (float-time (string-to-number
- (magit-rev-format "%at" start)))
- 1))
- (time-now (adjust (float-time)
- (- (string-to-number
- (magit-git-string "rev-list" "--count"
- range))))))
- (push time-rev magit--reshelve-history)
- (let ((date (floor
- (float-time
- (date-to-time
- (read-string "Date for first commit: "
- time-now 'magit--reshelve-history)))))
- (process-environment process-environment))
- (push "FILTER_BRANCH_SQUELCH_WARNING=1" process-environment)
- (magit-with-toplevel
- (magit-run-git-async
- "filter-branch" "--force" "--env-filter"
- (format
- "case $GIT_COMMIT in %s\nesac"
- (mapconcat
- (lambda (rev)
- (prog1 (concat
- (format "%s) " rev)
- (and (not magit-reshelve-since-committer-only)
- (format "export GIT_AUTHOR_DATE=\"%s\"; " date))
- (format "export GIT_COMMITTER_DATE=\"%s\";;" date))
- (cl-incf date 60)))
- (magit-git-lines "rev-list" "--reverse" range)
- " "))
- 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: %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 . "2.3.0")
- :group 'magit-commands
- :type '(list (choice (string :tag "Insert at point format")
- (cons (string :tag "Insert at point format")
- (repeat (string :tag "Argument to git show")))
- (const :tag "Don't insert at point" nil))
- (choice (string :tag "Insert at eob format")
- (cons (string :tag "Insert at eob format")
- (repeat (string :tag "Argument to git show")))
- (const :tag "Don't insert at eob" nil))
- (choice (regexp :tag "Find index regexp")
- (const :tag "Don't number entries" nil))))
-
-(defcustom magit-copy-revision-abbreviated nil
- "Whether to save abbreviated revision to `kill-ring' and `magit-revision-stack'."
- :package-version '(magit . "3.0.0")
- :group 'magit-miscellaneous
- :type 'boolean)
-
-;;;###autoload
-(defun magit-pop-revision-stack (rev toplevel)
- "Insert a representation of a revision into the current buffer.
-
-Pop a revision from the `magit-revision-stack' and insert it into
-the current buffer according to `magit-pop-revision-stack-format'.
-Revisions can be put on the stack using `magit-copy-section-value'
-and `magit-copy-buffer-revision'.
-
-If the stack is empty or with a prefix argument, instead read a
-revision in the minibuffer. By using the minibuffer history this
-allows selecting an item which was popped earlier or to insert an
-arbitrary reference or revision without first pushing it onto the
-stack.
-
-When reading the revision from the minibuffer, then it might not
-be possible to guess the correct repository. When this command
-is called inside a repository (e.g. while composing a commit
-message), then that repository is used. Otherwise (e.g. while
-composing an email) then the repository recorded for the top
-element of the stack is used (even though we insert another
-revision). If not called inside a repository and with an empty
-stack, or with two prefix arguments, then read the repository in
-the minibuffer too."
- (interactive
- (if (or current-prefix-arg (not magit-revision-stack))
- (let ((default-directory
- (or (and (not (= (prefix-numeric-value current-prefix-arg) 16))
- (or (magit-toplevel)
- (cadr (car magit-revision-stack))))
- (magit-read-repository))))
- (list (magit-read-branch-or-commit "Insert revision")
- default-directory))
- (push (caar magit-revision-stack) magit-revision-history)
- (pop magit-revision-stack)))
- (if rev
- (pcase-let ((`(,pnt-format ,eob-format ,idx-format)
- magit-pop-revision-stack-format))
- (let ((default-directory toplevel)
- (idx (and idx-format
- (save-excursion
- (if (re-search-backward idx-format nil t)
- (number-to-string
- (1+ (string-to-number (match-string 1))))
- "1"))))
- pnt-args eob-args)
- (when (listp pnt-format)
- (setq pnt-args (cdr pnt-format))
- (setq pnt-format (car pnt-format)))
- (when (listp eob-format)
- (setq eob-args (cdr eob-format))
- (setq eob-format (car eob-format)))
- (when pnt-format
- (when idx-format
- (setq pnt-format
- (replace-regexp-in-string "%N" idx pnt-format t t)))
- (magit-rev-insert-format pnt-format rev pnt-args)
- (backward-delete-char 1))
- (when eob-format
- (when idx-format
- (setq eob-format
- (replace-regexp-in-string "%N" idx eob-format t t)))
- (save-excursion
- (goto-char (point-max))
- (skip-syntax-backward ">s-")
- (beginning-of-line)
- (if (and comment-start (looking-at comment-start))
- (while (looking-at comment-start)
- (forward-line -1))
- (forward-line)
- (unless (= (current-column) 0)
- (insert ?\n)))
- (insert ?\n)
- (magit-rev-insert-format eob-format rev eob-args)
- (backward-delete-char 1)))))
- (user-error "Revision stack is empty")))
-
-(define-key git-commit-mode-map
- (kbd "C-c C-w") 'magit-pop-revision-stack)
-
-;;;###autoload
-(defun magit-copy-section-value (arg)
- "Save the value of the current section for later use.
-
-Save the section value to the `kill-ring', and, provided that
-the current section is a commit, branch, or tag section, push
-the (referenced) revision to the `magit-revision-stack' for use
-with `magit-pop-revision-stack'.
-
-When `magit-copy-revision-abbreviated' is non-nil, save the
-abbreviated revision to the `kill-ring' and the
-`magit-revision-stack'.
-
-When the current section is a branch or a tag, and a prefix
-argument is used, then save the revision at its tip to the
-`kill-ring' instead of the reference name.
-
-When the region is active, then save that to the `kill-ring',
-like `kill-ring-save' would, instead of behaving as described
-above. If a prefix argument is used and the region is within
-a hunk, then strip the diff marker column and keep only either
-the added or removed lines, depending on the sign of the prefix
-argument."
- (interactive "P")
- (cond
- ((and arg
- (magit-section-internal-region-p)
- (magit-section-match 'hunk))
- (kill-new
- (thread-last (buffer-substring-no-properties
- (region-beginning)
- (region-end))
- (replace-regexp-in-string
- (format "^\\%c.*\n?" (if (< (prefix-numeric-value arg) 0) ?+ ?-))
- "")
- (replace-regexp-in-string "^[ \\+\\-]" "")))
- (deactivate-mark))
- ((use-region-p)
- (call-interactively #'copy-region-as-kill))
- (t
- (when-let ((section (magit-current-section))
- (value (oref section value)))
- (magit-section-case
- ((branch commit module-commit tag)
- (let ((default-directory default-directory) ref)
- (magit-section-case
- ((branch tag)
- (setq ref value))
- (module-commit
- (setq default-directory
- (file-name-as-directory
- (expand-file-name (magit-section-parent-value section)
- (magit-toplevel))))))
- (setq value (magit-rev-parse
- (and magit-copy-revision-abbreviated "--short")
- value))
- (push (list value default-directory) magit-revision-stack)
- (kill-new (message "%s" (or (and current-prefix-arg ref)
- value)))))
- (t (kill-new (message "%s" value))))))))
-
-;;;###autoload
-(defun magit-copy-buffer-revision ()
- "Save the revision of the current buffer for later use.
-
-Save the revision shown in the current buffer to the `kill-ring'
-and push it to the `magit-revision-stack'.
-
-This command is mainly intended for use in `magit-revision-mode'
-buffers, the only buffers where it is always unambiguous exactly
-which revision should be saved.
-
-Most other Magit buffers usually show more than one revision, in
-some way or another, so this command has to select one of them,
-and that choice might not always be the one you think would have
-been the best pick.
-
-In such buffers it is often more useful to save the value of
-the current section instead, using `magit-copy-section-value'.
-
-When the region is active, then save that to the `kill-ring',
-like `kill-ring-save' would, instead of behaving as described
-above.
-
-When `magit-copy-revision-abbreviated' is non-nil, save the
-abbreviated revision to the `kill-ring' and the
-`magit-revision-stack'."
- (interactive)
- (if (use-region-p)
- (call-interactively #'copy-region-as-kill)
- (when-let ((rev (or magit-buffer-revision
- (cl-case major-mode
- (magit-diff-mode
- (if (string-match "\\.\\.\\.?\\(.+\\)"
- magit-buffer-range)
- (match-string 1 magit-buffer-range)
- magit-buffer-range))
- (magit-status-mode "HEAD")))))
- (when (magit-commit-p rev)
- (setq rev (magit-rev-parse
- (and magit-copy-revision-abbreviated "--short")
- rev))
- (push (list rev default-directory) magit-revision-stack)
- (kill-new (message "%s" rev))))))
-
-;;; Miscellaneous
-
-;;;###autoload
-(defun magit-abort-dwim ()
- "Abort current operation.
-Depending on the context, this will abort a merge, a rebase, a
-patch application, a cherry-pick, a revert, or a bisect."
- (interactive)
- (cond ((magit-merge-in-progress-p) (magit-merge-abort))
- ((magit-rebase-in-progress-p) (magit-rebase-abort))
- ((magit-am-in-progress-p) (magit-am-abort))
- ((magit-sequencer-in-progress-p) (magit-sequencer-abort))
- ((magit-bisect-in-progress-p) (magit-bisect-reset))))
-
-;;; _
-(provide 'magit-extras)
-;;; magit-extras.el ends here
+++ /dev/null
-;;; magit-fetch.el --- download objects and refs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements fetch commands.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Options
-
-(defcustom magit-fetch-modules-jobs 4
- "Number of submodules to fetch in parallel.
-Ignored for Git versions before v2.8.0."
- :package-version '(magit . "2.12.0")
- :group 'magit-commands
- :type '(choice (const :tag "one at a time" nil) number))
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-fetch "magit-fetch" nil t)
-(transient-define-prefix magit-fetch ()
- "Fetch from another repository."
- :man-page "git-fetch"
- ["Arguments"
- ("-p" "Prune deleted branches" ("-p" "--prune"))
- ("-t" "Fetch all tags" ("-t" "--tags"))
- (7 "-u" "Fetch full history" "--unshallow")]
- ["Fetch from"
- ("p" magit-fetch-from-pushremote)
- ("u" magit-fetch-from-upstream)
- ("e" "elsewhere" magit-fetch-other)
- ("a" "all remotes" magit-fetch-all)]
- ["Fetch"
- ("o" "another branch" magit-fetch-branch)
- ("r" "explicit refspec" magit-fetch-refspec)
- ("m" "submodules" magit-fetch-modules)]
- ["Configure"
- ("C" "variables..." magit-branch-configure)])
-
-(defun magit-fetch-arguments ()
- (transient-args 'magit-fetch))
-
-(defun magit-git-fetch (remote args)
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "fetch" remote args))
-
-;;;###autoload (autoload 'magit-fetch-from-pushremote "magit-fetch" nil t)
-(transient-define-suffix magit-fetch-from-pushremote (args)
- "Fetch from the current push-remote.
-
-With a prefix argument or when the push-remote is either not
-configured or unusable, then let the user first configure the
-push-remote."
- :description 'magit-fetch--pushremote-description
- (interactive (list (magit-fetch-arguments)))
- (let ((remote (magit-get-push-remote)))
- (when (or current-prefix-arg
- (not (member remote (magit-list-remotes))))
- (let ((var (magit--push-remote-variable)))
- (setq remote
- (magit-read-remote (format "Set %s and fetch from there" var)))
- (magit-set remote var)))
- (magit-git-fetch remote args)))
-
-(defun magit-fetch--pushremote-description ()
- (let* ((branch (magit-get-current-branch))
- (remote (magit-get-push-remote branch))
- (v (magit--push-remote-variable branch t)))
- (cond
- ((member remote (magit-list-remotes)) remote)
- (remote
- (format "%s, replacing invalid" v))
- (t
- (format "%s, setting that" v)))))
-
-;;;###autoload (autoload 'magit-fetch-from-upstream "magit-fetch" nil t)
-(transient-define-suffix magit-fetch-from-upstream (remote args)
- "Fetch from the \"current\" remote, usually the upstream.
-
-If the upstream is configured for the current branch and names
-an existing remote, then use that. Otherwise try to use another
-remote: If only a single remote is configured, then use that.
-Otherwise if a remote named \"origin\" exists, then use that.
-
-If no remote can be determined, then this command is not available
-from the `magit-fetch' transient prefix and invoking it directly
-results in an error."
- :if (lambda () (magit-get-current-remote t))
- :description (lambda () (magit-get-current-remote t))
- (interactive (list (magit-get-current-remote t)
- (magit-fetch-arguments)))
- (unless remote
- (error "The \"current\" remote could not be determined"))
- (magit-git-fetch remote args))
-
-;;;###autoload
-(defun magit-fetch-other (remote args)
- "Fetch from another repository."
- (interactive (list (magit-read-remote "Fetch remote")
- (magit-fetch-arguments)))
- (magit-git-fetch remote args))
-
-;;;###autoload
-(defun magit-fetch-branch (remote branch args)
- "Fetch a BRANCH from a REMOTE."
- (interactive
- (let ((remote (magit-read-remote-or-url "Fetch from remote or url")))
- (list remote
- (magit-read-remote-branch "Fetch branch" remote)
- (magit-fetch-arguments))))
- (magit-git-fetch remote (cons branch args)))
-
-;;;###autoload
-(defun magit-fetch-refspec (remote refspec args)
- "Fetch a REFSPEC from a REMOTE."
- (interactive
- (let ((remote (magit-read-remote-or-url "Fetch from remote or url")))
- (list remote
- (magit-read-refspec "Fetch using refspec" remote)
- (magit-fetch-arguments))))
- (magit-git-fetch remote (cons refspec args)))
-
-;;;###autoload
-(defun magit-fetch-all (args)
- "Fetch from all remotes."
- (interactive (list (magit-fetch-arguments)))
- (magit-git-fetch nil (cons "--all" args)))
-
-;;;###autoload
-(defun magit-fetch-all-prune ()
- "Fetch from all remotes, and prune.
-Prune remote tracking branches for branches that have been
-removed on the respective remote."
- (interactive)
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "remote" "update" "--prune"))
-
-;;;###autoload
-(defun magit-fetch-all-no-prune ()
- "Fetch from all remotes."
- (interactive)
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "remote" "update"))
-
-;;;###autoload
-(defun magit-fetch-modules (&optional all)
- "Fetch all submodules.
-
-Option `magit-fetch-modules-jobs' controls how many submodules
-are being fetched in parallel. Also fetch the super-repository,
-because `git-fetch' does not support not doing that. With a
-prefix argument fetch all remotes."
- (interactive "P")
- (magit-with-toplevel
- (magit-run-git-async
- "fetch" "--verbose" "--recurse-submodules"
- (and magit-fetch-modules-jobs
- (version<= "2.8.0" (magit-git-version))
- (list "-j" (number-to-string magit-fetch-modules-jobs)))
- (and all "--all"))))
-
-;;; _
-(provide 'magit-fetch)
-;;; magit-fetch.el ends here
+++ /dev/null
-;;; magit-files.el --- finding files -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for finding blobs, staged files,
-;; and Git configuration files. It also implements modes useful in
-;; buffers visiting files and blobs, and the commands used by those
-;; modes.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit)
-
-;;; Find Blob
-
-(defvar magit-find-file-hook nil)
-(add-hook 'magit-find-file-hook #'magit-blob-mode)
-
-;;;###autoload
-(defun magit-find-file (rev file)
- "View FILE from REV.
-Switch to a buffer visiting blob REV:FILE, creating one if none
-already exists. If prior to calling this command the current
-buffer and/or cursor position is about the same file, then go
-to the line and column corresponding to that location."
- (interactive (magit-find-file-read-args "Find file"))
- (magit-find-file--internal rev file #'pop-to-buffer-same-window))
-
-;;;###autoload
-(defun magit-find-file-other-window (rev file)
- "View FILE from REV, in another window.
-Switch to a buffer visiting blob REV:FILE, creating one if none
-already exists. If prior to calling this command the current
-buffer and/or cursor position is about the same file, then go to
-the line and column corresponding to that location."
- (interactive (magit-find-file-read-args "Find file in other window"))
- (magit-find-file--internal rev file #'switch-to-buffer-other-window))
-
-;;;###autoload
-(defun magit-find-file-other-frame (rev file)
- "View FILE from REV, in another frame.
-Switch to a buffer visiting blob REV:FILE, creating one if none
-already exists. If prior to calling this command the current
-buffer and/or cursor position is about the same file, then go to
-the line and column corresponding to that location."
- (interactive (magit-find-file-read-args "Find file in other frame"))
- (magit-find-file--internal rev file #'switch-to-buffer-other-frame))
-
-(defun magit-find-file-read-args (prompt)
- (let ((pseudo-revs '("{worktree}" "{index}")))
- (if-let ((rev (magit-completing-read "Find file from revision"
- (append pseudo-revs
- (magit-list-refnames nil t))
- nil nil nil 'magit-revision-history
- (or (magit-branch-or-commit-at-point)
- (magit-get-current-branch)))))
- (list rev (magit-read-file-from-rev (if (member rev pseudo-revs)
- "HEAD"
- rev)
- prompt))
- (user-error "Nothing selected"))))
-
-(defun magit-find-file--internal (rev file fn)
- (let ((buf (magit-find-file-noselect rev file))
- line col)
- (when-let ((visited-file (magit-file-relative-name)))
- (setq line (line-number-at-pos))
- (setq col (current-column))
- (cond
- ((not (equal visited-file file)))
- ((equal magit-buffer-revision rev))
- ((equal rev "{worktree}")
- (setq line (magit-diff-visit--offset file magit-buffer-revision line)))
- ((equal rev "{index}")
- (setq line (magit-diff-visit--offset file nil line)))
- (magit-buffer-revision
- (setq line (magit-diff-visit--offset
- file (concat magit-buffer-revision ".." rev) line)))
- (t
- (setq line (magit-diff-visit--offset file (list "-R" rev) line)))))
- (funcall fn buf)
- (when line
- (with-current-buffer buf
- (widen)
- (goto-char (point-min))
- (forward-line (1- line))
- (move-to-column col)))
- buf))
-
-(defun magit-find-file-noselect (rev file)
- "Read FILE from REV into a buffer and return the buffer.
-REV is a revision or one of \"{worktree}\" or \"{index}\".
-FILE must be relative to the top directory of the repository."
- (magit-find-file-noselect-1 rev file))
-
-(defun magit-find-file-noselect-1 (rev file &optional revert)
- "Read FILE from REV into a buffer and return the buffer.
-REV is a revision or one of \"{worktree}\" or \"{index}\".
-FILE must be relative to the top directory of the repository.
-Non-nil REVERT means to revert the buffer. If `ask-revert',
-then only after asking. A non-nil value for REVERT is ignored if REV is
-\"{worktree}\"."
- (if (equal rev "{worktree}")
- (find-file-noselect (expand-file-name file (magit-toplevel)))
- (let ((topdir (magit-toplevel)))
- (when (file-name-absolute-p file)
- (setq file (file-relative-name file topdir)))
- (with-current-buffer (magit-get-revision-buffer-create rev file)
- (when (or (not magit-buffer-file-name)
- (if (eq revert 'ask-revert)
- (y-or-n-p (format "%s already exists; revert it? "
- (buffer-name))))
- revert)
- (setq magit-buffer-revision
- (if (equal rev "{index}")
- "{index}"
- (magit-rev-format "%H" rev)))
- (setq magit-buffer-refname rev)
- (setq magit-buffer-file-name (expand-file-name file topdir))
- (setq default-directory
- (let ((dir (file-name-directory magit-buffer-file-name)))
- (if (file-exists-p dir) dir topdir)))
- (setq-local revert-buffer-function #'magit-revert-rev-file-buffer)
- (revert-buffer t t)
- (run-hooks (if (equal rev "{index}")
- 'magit-find-index-hook
- 'magit-find-file-hook)))
- (current-buffer)))))
-
-(defun magit-get-revision-buffer-create (rev file)
- (magit-get-revision-buffer rev file t))
-
-(defun magit-get-revision-buffer (rev file &optional create)
- (funcall (if create 'get-buffer-create 'get-buffer)
- (format "%s.~%s~" file (subst-char-in-string ?/ ?_ rev))))
-
-(defun magit-revert-rev-file-buffer (_ignore-auto noconfirm)
- (when (or noconfirm
- (and (not (buffer-modified-p))
- (catch 'found
- (dolist (regexp revert-without-query)
- (when (string-match regexp magit-buffer-file-name)
- (throw 'found t)))))
- (yes-or-no-p (format "Revert buffer from Git %s? "
- (if (equal magit-buffer-refname "{index}")
- "index"
- (concat "revision " magit-buffer-refname)))))
- (let* ((inhibit-read-only t)
- (default-directory (magit-toplevel))
- (file (file-relative-name magit-buffer-file-name))
- (coding-system-for-read (or coding-system-for-read 'undecided)))
- (erase-buffer)
- (magit-git-insert "cat-file" "-p"
- (if (equal magit-buffer-refname "{index}")
- (concat ":" file)
- (concat magit-buffer-refname ":" file)))
- (setq buffer-file-coding-system last-coding-system-used))
- (let ((buffer-file-name magit-buffer-file-name)
- (after-change-major-mode-hook
- (remq 'global-diff-hl-mode-enable-in-buffers
- after-change-major-mode-hook)))
- (normal-mode t))
- (setq buffer-read-only t)
- (set-buffer-modified-p nil)
- (goto-char (point-min))))
-
-;;; Find Index
-
-(defvar magit-find-index-hook nil)
-
-(defun magit-find-file-index-noselect (file &optional revert)
- "Read FILE from the index into a buffer and return the buffer.
-FILE must to be relative to the top directory of the repository."
- (magit-find-file-noselect-1 "{index}" file (or revert 'ask-revert)))
-
-(defun magit-update-index ()
- "Update the index with the contents of the current buffer.
-The current buffer has to be visiting a file in the index, which
-is done using `magit-find-index-noselect'."
- (interactive)
- (let ((file (magit-file-relative-name)))
- (unless (equal magit-buffer-refname "{index}")
- (user-error "%s isn't visiting the index" file))
- (if (y-or-n-p (format "Update index with contents of %s" (buffer-name)))
- (let ((index (make-temp-file "index"))
- (buffer (current-buffer)))
- (when magit-wip-before-change-mode
- (magit-wip-commit-before-change (list file) " before un-/stage"))
- (let ((coding-system-for-write buffer-file-coding-system))
- (with-temp-file index
- (insert-buffer-substring buffer)))
- (magit-with-toplevel
- (magit-call-git "update-index" "--cacheinfo"
- (substring (magit-git-string "ls-files" "-s" file)
- 0 6)
- (magit-git-string "hash-object" "-t" "blob" "-w"
- (concat "--path=" file)
- "--" index)
- file))
- (set-buffer-modified-p nil)
- (when magit-wip-after-apply-mode
- (magit-wip-commit-after-apply (list file) " after un-/stage")))
- (message "Abort")))
- (--when-let (magit-get-mode-buffer 'magit-status-mode)
- (with-current-buffer it (magit-refresh)))
- t)
-
-;;; Find Config File
-
-(defun magit-find-git-config-file (filename &optional wildcards)
- "Edit a file located in the current repository's git directory.
-
-When \".git\", located at the root of the working tree, is a
-regular file, then that makes it cumbersome to open a file
-located in the actual git directory.
-
-This command is like `find-file', except that it temporarily
-binds `default-directory' to the actual git directory, while
-reading the FILENAME."
- (interactive
- (let ((default-directory (magit-git-dir)))
- (find-file-read-args "Find file: "
- (confirm-nonexistent-file-or-buffer))))
- (find-file filename wildcards))
-
-(defun magit-find-git-config-file-other-window (filename &optional wildcards)
- "Edit a file located in the current repository's git directory, in another window.
-
-When \".git\", located at the root of the working tree, is a
-regular file, then that makes it cumbersome to open a file
-located in the actual git directory.
-
-This command is like `find-file-other-window', except that it
-temporarily binds `default-directory' to the actual git
-directory, while reading the FILENAME."
- (interactive
- (let ((default-directory (magit-git-dir)))
- (find-file-read-args "Find file in other window: "
- (confirm-nonexistent-file-or-buffer))))
- (find-file-other-window filename wildcards))
-
-(defun magit-find-git-config-file-other-frame (filename &optional wildcards)
- "Edit a file located in the current repository's git directory, in another frame.
-
-When \".git\", located at the root of the working tree, is a
-regular file, then that makes it cumbersome to open a file
-located in the actual git directory.
-
-This command is like `find-file-other-frame', except that it
-temporarily binds `default-directory' to the actual git
-directory, while reading the FILENAME."
- (interactive
- (let ((default-directory (magit-git-dir)))
- (find-file-read-args "Find file in other frame: "
- (confirm-nonexistent-file-or-buffer))))
- (find-file-other-frame filename wildcards))
-
-;;; File Dispatch
-
-;;;###autoload (autoload 'magit-file-dispatch "magit" nil t)
-(transient-define-prefix magit-file-dispatch ()
- "Invoke a Magit command that acts on the visited file.
-When invoked outside a file-visiting buffer, then fall back
-to `magit-dispatch'."
- :info-manual "(magit) Minor Mode for Buffers Visiting Files"
- ["Actions"
- [("s" "Stage" magit-stage-file)
- ("u" "Unstage" magit-unstage-file)
- ("c" "Commit" magit-commit)
- ("e" "Edit line" magit-edit-line-commit)]
- [("D" "Diff..." magit-diff)
- ("d" "Diff" magit-diff-buffer-file)
- ("g" "Status" magit-status-here)]
- [("L" "Log..." magit-log)
- ("l" "Log" magit-log-buffer-file)
- ("t" "Trace" magit-log-trace-definition)]
- [("B" "Blame..." magit-blame)
- ("b" "Blame" magit-blame-addition)
- ("r" "...removal" magit-blame-removal)
- ("f" "...reverse" magit-blame-reverse)
- ("m" "Blame echo" magit-blame-echo)
- ("q" "Quit blame" magit-blame-quit)]
- [("p" "Prev blob" magit-blob-previous)
- ("n" "Next blob" magit-blob-next)
- ("v" "Goto blob" magit-find-file)
- ("V" "Goto file" magit-blob-visit-file)]
- [(5 "C-c r" "Rename file" magit-file-rename)
- (5 "C-c d" "Delete file" magit-file-delete)
- (5 "C-c u" "Untrack file" magit-file-untrack)
- (5 "C-c c" "Checkout file" magit-file-checkout)]]
- (interactive)
- (transient-setup
- (if (or buffer-file-name magit-buffer-file-name)
- 'magit-file-dispatch
- 'magit-dispatch)))
-
-;;; Blob Mode
-
-(defvar magit-blob-mode-map
- (let ((map (make-sparse-keymap)))
- (define-key map "p" 'magit-blob-previous)
- (define-key map "n" 'magit-blob-next)
- (define-key map "b" 'magit-blame-addition)
- (define-key map "r" 'magit-blame-removal)
- (define-key map "f" 'magit-blame-reverse)
- (define-key map "q" 'magit-kill-this-buffer)
- map)
- "Keymap for `magit-blob-mode'.")
-
-(define-minor-mode magit-blob-mode
- "Enable some Magit features in blob-visiting buffers.
-
-Currently this only adds the following key bindings.
-\n\\{magit-blob-mode-map}"
- :package-version '(magit . "2.3.0"))
-
-(defun magit-blob-next ()
- "Visit the next blob which modified the current file."
- (interactive)
- (if magit-buffer-file-name
- (magit-blob-visit (or (magit-blob-successor magit-buffer-revision
- magit-buffer-file-name)
- magit-buffer-file-name))
- (if (buffer-file-name (buffer-base-buffer))
- (user-error "You have reached the end of time")
- (user-error "Buffer isn't visiting a file or blob"))))
-
-(defun magit-blob-previous ()
- "Visit the previous blob which modified the current file."
- (interactive)
- (if-let ((file (or magit-buffer-file-name
- (buffer-file-name (buffer-base-buffer)))))
- (--if-let (magit-blob-ancestor magit-buffer-revision file)
- (magit-blob-visit it)
- (user-error "You have reached the beginning of time"))
- (user-error "Buffer isn't visiting a file or blob")))
-
-;;;###autoload
-(defun magit-blob-visit-file ()
- "View the file from the worktree corresponding to the current blob.
-When visiting a blob or the version from the index, then go to
-the same location in the respective file in the working tree."
- (interactive)
- (if-let ((file (magit-file-relative-name)))
- (magit-find-file--internal "{worktree}" file #'pop-to-buffer-same-window)
- (user-error "Not visiting a blob")))
-
-(defun magit-blob-visit (blob-or-file)
- (if (stringp blob-or-file)
- (find-file blob-or-file)
- (pcase-let ((`(,rev ,file) blob-or-file))
- (magit-find-file rev file)
- (apply #'message "%s (%s %s ago)"
- (magit-rev-format "%s" rev)
- (magit--age (magit-rev-format "%ct" rev))))))
-
-(defun magit-blob-ancestor (rev file)
- (let ((lines (magit-with-toplevel
- (magit-git-lines "log" "-2" "--format=%H" "--name-only"
- "--follow" (or rev "HEAD") "--" file))))
- (if rev (cddr lines) (butlast lines 2))))
-
-(defun magit-blob-successor (rev file)
- (let ((lines (magit-with-toplevel
- (magit-git-lines "log" "--format=%H" "--name-only" "--follow"
- "HEAD" "--" file))))
- (catch 'found
- (while lines
- (if (equal (nth 2 lines) rev)
- (throw 'found (list (nth 0 lines) (nth 1 lines)))
- (setq lines (nthcdr 2 lines)))))))
-
-;;; File Commands
-
-(defun magit-file-rename (file newname)
- "Rename or move FILE to NEWNAME.
-NEWNAME may be a file or directory name. If FILE isn't tracked in
-Git, fallback to using `rename-file'."
- (interactive
- (let* ((file (magit-read-file "Rename file"))
- (dir (file-name-directory file))
- (newname (read-file-name (format "Move %s to destination: " file)
- (and dir (expand-file-name dir)))))
- (list (expand-file-name file (magit-toplevel))
- (expand-file-name newname))))
- (let ((oldbuf (get-file-buffer file))
- (dstdir (file-name-directory newname))
- (dstfile (if (directory-name-p newname)
- (concat newname (file-name-nondirectory file))
- newname)))
- (when (and oldbuf (buffer-modified-p oldbuf))
- (user-error "Save %s before moving it" file))
- (when (file-exists-p dstfile)
- (user-error "%s already exists" dstfile))
- (unless (file-exists-p dstdir)
- (user-error "Destination directory %s does not exist" dstdir))
- (if (magit-file-tracked-p (magit-convert-filename-for-git file))
- (magit-call-git "mv"
- (magit-convert-filename-for-git file)
- (magit-convert-filename-for-git newname))
- (rename-file file newname current-prefix-arg))
- (when oldbuf
- (with-current-buffer oldbuf
- (let ((buffer-read-only buffer-read-only))
- (set-visited-file-name dstfile nil t))
- (if (fboundp 'vc-refresh-state)
- (vc-refresh-state)
- (with-no-warnings
- (vc-find-file-hook))))))
- (magit-refresh))
-
-(defun magit-file-untrack (files &optional force)
- "Untrack the selected FILES or one file read in the minibuffer.
-
-With a prefix argument FORCE do so even when the files have
-staged as well as unstaged changes."
- (interactive (list (or (--if-let (magit-region-values 'file t)
- (progn
- (unless (magit-file-tracked-p (car it))
- (user-error "Already untracked"))
- (magit-confirm-files 'untrack it "Untrack"))
- (list (magit-read-tracked-file "Untrack file"))))
- current-prefix-arg))
- (magit-with-toplevel
- (magit-run-git "rm" "--cached" (and force "--force") "--" files)))
-
-(defun magit-file-delete (files &optional force)
- "Delete the selected FILES or one file read in the minibuffer.
-
-With a prefix argument FORCE do so even when the files have
-uncommitted changes. When the files aren't being tracked in
-Git, then fallback to using `delete-file'."
- (interactive (list (--if-let (magit-region-values 'file t)
- (magit-confirm-files 'delete it "Delete")
- (list (magit-read-file "Delete file")))
- current-prefix-arg))
- (if (magit-file-tracked-p (car files))
- (magit-call-git "rm" (and force "--force") "--" files)
- (let ((topdir (magit-toplevel)))
- (dolist (file files)
- (delete-file (expand-file-name file topdir) t))))
- (magit-refresh))
-
-;;;###autoload
-(defun magit-file-checkout (rev file)
- "Checkout FILE from REV."
- (interactive
- (let ((rev (magit-read-branch-or-commit
- "Checkout from revision" magit-buffer-revision)))
- (list rev (magit-read-file-from-rev rev "Checkout file"))))
- (magit-with-toplevel
- (magit-run-git "checkout" rev "--" file)))
-
-;;; Read File
-
-(defvar magit-read-file-hist nil)
-
-(defun magit-read-file-from-rev (rev prompt &optional default)
- (let ((files (magit-revision-files rev)))
- (magit-completing-read
- prompt files nil t nil 'magit-read-file-hist
- (car (member (or default (magit-current-file)) files)))))
-
-(defun magit-read-file (prompt &optional tracked-only)
- (let ((choices (nconc (magit-list-files)
- (unless tracked-only (magit-untracked-files)))))
- (magit-completing-read
- prompt choices nil t nil nil
- (car (member (or (magit-section-value-if '(file submodule))
- (magit-file-relative-name nil tracked-only))
- choices)))))
-
-(defun magit-read-tracked-file (prompt)
- (magit-read-file prompt t))
-
-(defun magit-read-file-choice (prompt files &optional error default)
- "Read file from FILES.
-
-If FILES has only one member, return that instead of prompting.
-If FILES has no members, give a user error. ERROR can be given
-to provide a more informative error.
-
-If DEFAULT is non-nil, use this as the default value instead of
-`magit-current-file'."
- (pcase (length files)
- (0 (user-error (or error "No file choices")))
- (1 (car files))
- (_ (magit-completing-read
- prompt files nil t nil 'magit-read-file-hist
- (car (member (or default (magit-current-file)) files))))))
-
-(defun magit-read-changed-file (rev-or-range prompt &optional default)
- (magit-read-file-choice
- prompt
- (magit-changed-files rev-or-range)
- default
- (concat "No file changed in " rev-or-range)))
-
-;;; _
-(provide 'magit-files)
-;;; magit-files.el ends here
+++ /dev/null
-;;; magit-git.el --- Git functionality -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements wrappers for various Git plumbing commands.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit-utils)
-(require 'magit-section)
-
-;; From `magit-branch'.
-(defvar magit-branch-prefer-remote-upstream)
-(defvar magit-published-branches)
-
-;; From `magit-margin'.
-(declare-function magit-maybe-make-margin-overlay "magit-margin" ())
-
-;; From `magit-mode'.
-(declare-function magit-get-mode-buffer "magit-mode"
- (mode &optional value frame))
-(declare-function magit-refresh "magit-mode" ())
-(defvar magit-buffer-diff-args)
-(defvar magit-buffer-file-name)
-(defvar magit-buffer-log-args)
-(defvar magit-buffer-log-files)
-(defvar magit-buffer-refname)
-(defvar magit-buffer-revision)
-
-;; From `magit-process'.
-(declare-function magit-call-git "magit-process" (&rest args))
-(declare-function magit-process-buffer "magit-process" (&optional nodisplay))
-(declare-function magit-process-file "magit-process" (&rest args))
-(declare-function magit-process-insert-section "magit-process"
- (pwd program args &optional errcode errlog))
-(defvar magit-this-error)
-(defvar magit-process-error-message-regexps)
-
-;; From later in `magit-git'.
-(defvar magit-tramp-process-environment nil)
-
-(eval-when-compile
- (cl-pushnew 'number eieio--known-slot-names))
-
-;;; Git implementations
-
-(defvar magit-inhibit-libgit nil
- "Whether to inhibit the use of libgit.")
-
-(defvar magit--libgit-available-p eieio-unbound
- "Whether libgit is available.
-Use the function by the same name instead of this variable.")
-
-(defun magit--libgit-available-p ()
- (if (eq magit--libgit-available-p eieio-unbound)
- (setq magit--libgit-available-p
- (and module-file-suffix
- (let ((libgit (locate-library "libgit")))
- (and libgit
- (or (locate-library "libegit2")
- (let ((load-path
- (cons (expand-file-name
- (convert-standard-filename "build")
- (file-name-directory libgit))
- load-path)))
- (locate-library "libegit2")))))))
- magit--libgit-available-p))
-
-(defun magit-gitimpl ()
- "Return the Git implementation used in this repository."
- (if (and (not magit-inhibit-libgit)
- (not (file-remote-p default-directory))
- (magit--libgit-available-p))
- 'libgit
- 'git))
-
-;;; Options
-
-;; For now this is shared between `magit-process' and `magit-git'.
-(defgroup magit-process nil
- "Git and other external processes used by Magit."
- :group 'magit)
-
-(defvar magit-git-environment
- (list (format "INSIDE_EMACS=%s,magit" emacs-version))
- "Prepended to `process-environment' while running git.")
-
-(defcustom magit-git-output-coding-system
- (and (eq system-type 'windows-nt) 'utf-8)
- "Coding system for receiving output from Git.
-
-If non-nil, the Git config value `i18n.logOutputEncoding' should
-be set via `magit-git-global-arguments' to value consistent with
-this."
- :package-version '(magit . "2.9.0")
- :group 'magit-process
- :type '(choice (coding-system :tag "Coding system to decode Git output")
- (const :tag "Use system default" nil)))
-
-(defvar magit-git-w32-path-hack nil
- "Alist of (EXE . (PATHENTRY)).
-This specifies what additional PATH setting needs to be added to
-the environment in order to run the non-wrapper git executables
-successfully.")
-
-(defcustom magit-git-executable
- ;; Git might be installed in a different location on a remote, so
- ;; it is better not to use the full path to the executable, except
- ;; on Window where we would otherwise end up using one of the
- ;; wrappers "cmd/git.exe" or "cmd/git.cmd", which are much slower
- ;; than using "bin/git.exe" directly.
- (or (and (eq system-type 'windows-nt)
- (--when-let (executable-find "git")
- (ignore-errors
- ;; Git for Windows 2.x provides cygpath so we can
- ;; ask it for native paths.
- (let* ((core-exe
- (car
- (process-lines
- it "-c"
- "alias.X=!x() { which \"$1\" | cygpath -mf -; }; x"
- "X" "git")))
- (hack-entry (assoc core-exe magit-git-w32-path-hack))
- ;; Running the libexec/git-core executable
- ;; requires some extra PATH entries.
- (path-hack
- (list (concat "PATH="
- (car (process-lines
- it "-c"
- "alias.P=!cygpath -wp \"$PATH\""
- "P"))))))
- ;; The defcustom STANDARD expression can be
- ;; evaluated many times, so make sure it is
- ;; idempotent.
- (if hack-entry
- (setcdr hack-entry path-hack)
- (push (cons core-exe path-hack) magit-git-w32-path-hack))
- core-exe))))
- "git")
- "The Git executable used by Magit."
- :group 'magit-process
- :type 'string)
-
-(defcustom magit-git-global-arguments
- `("--no-pager" "--literal-pathspecs"
- "-c" "core.preloadindex=true"
- "-c" "log.showSignature=false"
- "-c" "color.ui=false"
- "-c" "color.diff=false"
- ,@(and (eq system-type 'windows-nt)
- (list "-c" "i18n.logOutputEncoding=UTF-8")))
- "Global Git arguments.
-
-The arguments set here are used every time the git executable is
-run as a subprocess. They are placed right after the executable
-itself and before the git command - as in `git HERE... COMMAND
-REST'. See the manpage `git(1)' for valid arguments.
-
-Be careful what you add here, especially if you are using Tramp
-to connect to servers with ancient Git versions. Never remove
-anything that is part of the default value, unless you really
-know what you are doing. And think very hard before adding
-something; it will be used every time Magit runs Git for any
-purpose."
- :package-version '(magit . "2.9.0")
- :group 'magit-commands
- :group 'magit-process
- :type '(repeat string))
-
-(defvar magit-git-debug nil
- "Whether to enable additional reporting of git errors.
-
-Magit basically calls git for one of these two reasons: for
-side-effects or to do something with its standard output.
-
-When git is run for side-effects then its output, including error
-messages, go into the process buffer which is shown when using \
-\\<magit-status-mode-map>\\[magit-process].
-
-When git's output is consumed in some way, then it would be too
-expensive to also insert it into this buffer, but when this
-option is non-nil and git returns with a non-zero exit status,
-then at least its standard error is inserted into this buffer.
-
-This is only intended for debugging purposes. Do not enable this
-permanently, that would negatively affect performance.")
-
-
-(defcustom magit-prefer-remote-upstream nil
- "Whether to favor remote branches when reading the upstream branch.
-
-This controls whether commands that read a branch from the user
-and then set it as the upstream branch, offer a local or a remote
-branch as default completion candidate, when they have the choice.
-
-This affects all commands that use `magit-read-upstream-branch'
-or `magit-read-starting-point', which includes most commands
-that change the upstream and many that create new branches."
- :package-version '(magit . "2.4.2")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-list-refs-sortby nil
- "How to sort the ref collection in the prompt.
-
-This affects commands that read a ref. More specifically, it
-controls the order of refs returned by `magit-list-refs', which
-is called by functions like `magit-list-branch-names' to generate
-the collection of refs. By default, refs are sorted according to
-their full refname (i.e., 'refs/...').
-
-Any value accepted by the `--sort' flag of `git for-each-ref' can
-be used. For example, \"-creatordate\" places refs with more
-recent committer or tagger dates earlier in the list. A list of
-strings can also be given in order to pass multiple sort keys to
-`git for-each-ref'.
-
-Note that, depending on the completion framework you use, this
-may not be sufficient to change the order in which the refs are
-displayed. It only controls the order of the collection passed
-to `magit-completing-read' or, for commands that support reading
-multiple strings, `read-from-minibuffer'. The completion
-framework ultimately determines how the collection is displayed."
- :package-version '(magit . "2.11.0")
- :group 'magit-miscellaneous
- :type '(choice string (repeat string)))
-
-;;; Git
-
-(defvar magit--refresh-cache nil)
-
-(defmacro magit--with-refresh-cache (key &rest body)
- (declare (indent 1) (debug (form body)))
- (let ((k (cl-gensym)))
- `(if magit--refresh-cache
- (let ((,k ,key))
- (--if-let (assoc ,k (cdr magit--refresh-cache))
- (progn (cl-incf (caar magit--refresh-cache))
- (cdr it))
- (cl-incf (cdar magit--refresh-cache))
- (let ((value ,(macroexp-progn body)))
- (push (cons ,k value)
- (cdr magit--refresh-cache))
- value)))
- ,@body)))
-
-(defvar magit-with-editor-envvar "GIT_EDITOR"
- "The environment variable exported by `magit-with-editor'.
-Set this to \"GIT_SEQUENCE_EDITOR\" if you do not want to use
-Emacs to edit commit messages but would like to do so to edit
-rebase sequences.")
-
-(defmacro magit-with-editor (&rest body)
- "Like `with-editor' but let-bind some more variables.
-Also respect the value of `magit-with-editor-envvar'."
- (declare (indent 0) (debug (body)))
- `(let ((magit-process-popup-time -1)
- ;; The user may have customized `shell-file-name' to
- ;; something which results in `w32-shell-dos-semantics' nil
- ;; (which changes the quoting style used by
- ;; `shell-quote-argument'), but Git for Windows expects shell
- ;; quoting in the dos style.
- (shell-file-name (if (and (eq system-type 'windows-nt)
- ;; If we have Cygwin mount points,
- ;; the git flavor is cygwin, so dos
- ;; shell quoting is probably wrong.
- (not magit-cygwin-mount-points))
- "cmdproxy"
- shell-file-name)))
- (with-editor* magit-with-editor-envvar
- ,@body)))
-
-(defmacro magit--with-temp-process-buffer (&rest body)
- "Like `with-temp-buffer', but always propagate `process-environment'.
-When that var is buffer-local in the calling buffer, it is not
-propagated by `with-temp-buffer', so we explicitly ensure that
-happens, so that processes will be invoked consistently. BODY is
-as for that macro."
- (declare (indent 0) (debug (body)))
- (let ((p (cl-gensym)))
- `(let ((,p process-environment))
- (with-temp-buffer
- (setq-local process-environment ,p)
- ,@body))))
-
-(defun magit-process-git-arguments (args)
- "Prepare ARGS for a function that invokes Git.
-
-Magit has many specialized functions for running Git; they all
-pass arguments through this function before handing them to Git,
-to do the following.
-
-* Flatten ARGS, removing nil arguments.
-* Prepend `magit-git-global-arguments' to ARGS.
-* On w32 systems, encode to `w32-ansi-code-page'."
- (setq args (append magit-git-global-arguments (-flatten args)))
- (if (and (eq system-type 'windows-nt) (boundp 'w32-ansi-code-page))
- ;; On w32, the process arguments *must* be encoded in the
- ;; current code-page (see #3250).
- (mapcar (lambda (arg)
- (encode-coding-string
- arg (intern (format "cp%d" w32-ansi-code-page))))
- args)
- args))
-
-(defun magit-git-exit-code (&rest args)
- "Execute Git with ARGS, returning its exit code."
- (apply #'magit-process-file magit-git-executable nil nil nil
- (magit-process-git-arguments 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 (apply #'magit-process-file magit-git-executable nil t nil
- (magit-process-git-arguments 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 (apply #'magit-process-file magit-git-executable
- nil t nil args)))
- (if (zerop status)
- (and (not (bobp))
- (progn
- (goto-char (point-min))
- (buffer-substring-no-properties
- (point) (line-end-position))))
- (let ((buf (current-buffer)))
- (with-current-buffer (magit-process-buffer t)
- (magit-process-insert-section default-directory
- magit-git-executable args
- status buf)))
- (when-let ((status-buf (magit-get-mode-buffer 'magit-status-mode)))
- (let ((msg (magit--locate-error-message)))
- (with-current-buffer status-buf
- (setq magit-this-error msg))))
- nil)))))
-
-(defun magit-git-str (&rest args)
- "Execute Git with ARGS, returning the first line of its output.
-If there is no output, return nil. If the output begins with a
-newline, return an empty string. Like `magit-git-string' but
-ignore `magit-git-debug'."
- (setq args (-flatten args))
- (magit--with-refresh-cache (cons default-directory args)
- (magit--with-temp-process-buffer
- (apply #'magit-process-file magit-git-executable nil (list t nil) nil
- (magit-process-git-arguments args))
- (unless (bobp)
- (goto-char (point-min))
- (buffer-substring-no-properties (point) (line-end-position))))))
-
-(defun magit-git-output (&rest args)
- "Execute Git with ARGS, returning its output."
- (setq args (-flatten args))
- (magit--with-refresh-cache (cons default-directory args)
- (magit--with-temp-process-buffer
- (apply #'magit-process-file magit-git-executable nil (list t nil) nil
- (magit-process-git-arguments 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 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 output))))
-
-(defun magit-git-insert (&rest args)
- "Execute Git with ARGS, inserting its output at point.
-If Git exits with a non-zero exit status, then show a message and
-add a section in the respective process buffer."
- (setq args (magit-process-git-arguments args))
- (if magit-git-debug
- (let (log)
- (unwind-protect
- (progn
- (setq log (make-temp-file "magit-stderr"))
- (delete-file log)
- (let ((exit (apply #'magit-process-file magit-git-executable
- nil (list t log) nil args)))
- (when (> exit 0)
- (let ((msg "Git failed"))
- (when (file-exists-p log)
- (setq msg (with-temp-buffer
- (insert-file-contents log)
- (goto-char (point-max))
- (if (functionp magit-git-debug)
- (funcall magit-git-debug (buffer-string))
- (magit--locate-error-message))))
- (let ((magit-git-debug nil))
- (with-current-buffer (magit-process-buffer t)
- (magit-process-insert-section default-directory
- magit-git-executable
- args exit log))))
- (message "%s" msg)))
- exit))
- (ignore-errors (delete-file log))))
- (apply #'magit-process-file magit-git-executable
- nil (list t nil) nil args)))
-
-(defun magit--locate-error-message ()
- (goto-char (point-max))
- (and (run-hook-wrapped 'magit-process-error-message-regexps
- (lambda (re) (re-search-backward re nil t)))
- (match-string-no-properties 1)))
-
-(defun magit-git-string (&rest args)
- "Execute Git with ARGS, returning the first line of its output.
-If there is no output, return nil. If the output begins with a
-newline, return an empty string."
- (setq args (-flatten args))
- (magit--with-refresh-cache (cons default-directory args)
- (magit--with-temp-process-buffer
- (apply #'magit-git-insert args)
- (unless (bobp)
- (goto-char (point-min))
- (buffer-substring-no-properties (point) (line-end-position))))))
-
-(defun magit-git-lines (&rest args)
- "Execute Git with ARGS, returning its output as a list of lines.
-Empty lines anywhere in the output are omitted.
-
-If Git exits with a non-zero exit status, then report show a
-message and add a section in the respective process buffer."
- (magit--with-temp-process-buffer
- (apply #'magit-git-insert args)
- (split-string (buffer-string) "\n" t)))
-
-(defun magit-git-items (&rest args)
- "Execute Git with ARGS, returning its null-separated output as a list.
-Empty items anywhere in the output are omitted.
-
-If Git exits with a non-zero exit status, then report show a
-message and add a section in the respective process buffer."
- (magit--with-temp-process-buffer
- (apply #'magit-git-insert args)
- (split-string (buffer-string) "\0" t)))
-
-(defun magit-git-wash (washer &rest args)
- "Execute Git with ARGS, inserting washed output at point.
-Actually first insert the raw output at point. If there is no
-output, call `magit-cancel-section'. Otherwise temporarily narrow
-the buffer to the inserted text, move to its beginning, and then
-call function WASHER with ARGS as its sole argument."
- (declare (indent 1))
- (let ((beg (point)))
- (setq args (-flatten args))
- (magit-git-insert args)
- (if (= (point) beg)
- (magit-cancel-section)
- (unless (bolp)
- (insert "\n"))
- (save-restriction
- (narrow-to-region beg (point))
- (goto-char beg)
- (funcall washer args))
- (when (or (= (point) beg)
- (= (point) (1+ beg)))
- (magit-cancel-section))
- (magit-maybe-make-margin-overlay))))
-
-(defun magit-git-version (&optional raw)
- (--when-let (let (magit-git-global-arguments)
- (ignore-errors (substring (magit-git-string "version") 12)))
- (if raw it (and (string-match "\\`\\([0-9]+\\(\\.[0-9]+\\)\\{1,2\\}\\)" it)
- (match-string 1 it)))))
-
-;;; Variables
-
-(defun magit-config-get-from-cached-list (key)
- (gethash
- ;; `git config --list' downcases first and last components of the key.
- (--> key
- (replace-regexp-in-string "\\`[^.]+" #'downcase it t t)
- (replace-regexp-in-string "[^.]+\\'" #'downcase it t t))
- (magit--with-refresh-cache (cons (magit-toplevel) 'config)
- (let ((configs (make-hash-table :test 'equal)))
- (dolist (conf (magit-git-items "config" "--list" "-z"))
- (let* ((nl-pos (cl-position ?\n conf))
- (key (substring conf 0 nl-pos))
- (val (if nl-pos (substring conf (1+ nl-pos)) "")))
- (puthash key (nconc (gethash key configs) (list val)) configs)))
- configs))))
-
-(defun magit-get (&rest keys)
- "Return the value of the Git variable specified by KEYS."
- (car (last (apply 'magit-get-all keys))))
-
-(defun magit-get-all (&rest keys)
- "Return all values of the Git variable specified by KEYS."
- (let ((magit-git-debug nil)
- (arg (and (or (null (car keys))
- (string-prefix-p "--" (car keys)))
- (pop keys)))
- (key (mapconcat 'identity keys ".")))
- (if (and magit--refresh-cache (not arg))
- (magit-config-get-from-cached-list key)
- (magit-git-items "config" arg "-z" "--get-all" key))))
-
-(defun magit-get-boolean (&rest keys)
- "Return the boolean value of the Git variable specified by KEYS."
- (let ((key (mapconcat 'identity keys ".")))
- (if magit--refresh-cache
- (equal "true" (car (last (magit-config-get-from-cached-list key))))
- (equal (magit-git-str "config" "--bool" key) "true"))))
-
-(defun magit-set (value &rest keys)
- "Set the value of the Git variable specified by KEYS to VALUE."
- (let ((arg (and (or (null (car keys))
- (string-prefix-p "--" (car keys)))
- (pop keys)))
- (key (mapconcat 'identity keys ".")))
- (if value
- (magit-git-success "config" arg key value)
- (magit-git-success "config" arg "--unset" key))
- value))
-
-(gv-define-setter magit-get (val &rest keys)
- `(magit-set ,val ,@keys))
-
-(defun magit-set-all (values &rest keys)
- "Set all values of the Git variable specified by KEYS to VALUES."
- (let ((arg (and (or (null (car keys))
- (string-prefix-p "--" (car keys)))
- (pop keys)))
- (var (mapconcat 'identity keys ".")))
- (when (magit-get var)
- (magit-call-git "config" arg "--unset-all" var))
- (dolist (v values)
- (magit-call-git "config" arg "--add" var v))))
-
-;;; Files
-
-(defun magit--safe-default-directory (&optional file)
- (catch 'unsafe-default-dir
- (let ((dir (file-name-as-directory
- (expand-file-name (or file default-directory))))
- (previous nil))
- (while (not (magit-file-accessible-directory-p dir))
- (setq dir (file-name-directory (directory-file-name dir)))
- (when (equal dir previous)
- (throw 'unsafe-default-dir nil))
- (setq previous dir))
- dir)))
-
-(defmacro magit--with-safe-default-directory (file &rest body)
- (declare (indent 1) (debug (form body)))
- `(when-let ((default-directory (magit--safe-default-directory ,file)))
- ,@body))
-
-(defun magit-gitdir (&optional directory)
- "Return the absolute and resolved path of the .git directory.
-
-If the `GIT_DIR' environment variable is define then return that.
-Otherwise return the .git directory for DIRECTORY, or if that is
-nil, then for `default-directory' instead. If the directory is
-not located inside a Git repository, then return nil."
- (let ((default-directory (or directory default-directory)))
- (magit-git-dir)))
-
-(defun magit-git-dir (&optional path)
- "Return the absolute and resolved path of the .git directory.
-
-If the `GIT_DIR' environment variable is define then return that.
-Otherwise return the .git directory for `default-directory'. If
-the directory is not located inside a Git repository, then return
-nil."
- (magit--with-refresh-cache (list default-directory 'magit-git-dir path)
- (magit--with-safe-default-directory nil
- (when-let ((dir (magit-rev-parse-safe "--git-dir")))
- (setq dir (file-name-as-directory (magit-expand-git-file-name dir)))
- (unless (file-remote-p dir)
- (setq dir (concat (file-remote-p default-directory) dir)))
- (if path (expand-file-name (convert-standard-filename path) dir) dir)))))
-
-(defvar magit--separated-gitdirs nil)
-
-(defun magit--record-separated-gitdir ()
- (let ((topdir (magit-toplevel))
- (gitdir (magit-git-dir)))
- ;; Kludge: git-annex converts submodule gitdirs to symlinks. See #3599.
- (when (file-symlink-p (directory-file-name gitdir))
- (setq gitdir (file-truename gitdir)))
- ;; We want to delete the entry for `topdir' here, rather than within
- ;; (unless ...), in case a `--separate-git-dir' repository was switched to
- ;; the standard structure (i.e., "topdir/.git/").
- (setq magit--separated-gitdirs (cl-delete topdir
- magit--separated-gitdirs
- :key #'car :test #'equal))
- (unless (equal (file-name-as-directory (expand-file-name ".git" topdir))
- gitdir)
- (push (cons topdir gitdir) magit--separated-gitdirs))))
-
-(defun magit-toplevel (&optional directory)
- "Return the absolute path to the toplevel of the current repository.
-
-From within the working tree or control directory of a repository
-return the absolute path to the toplevel directory of the working
-tree. As a special case, from within a bare repository return
-the control directory instead. When called outside a repository
-then return nil.
-
-When optional DIRECTORY is non-nil then return the toplevel for
-that directory instead of the one for `default-directory'.
-
-Try to respect the option `find-file-visit-truename', i.e. when
-the value of that option is nil, then avoid needlessly returning
-the truename. When a symlink to a sub-directory of the working
-tree is involved, or when called from within a sub-directory of
-the gitdir or from the toplevel of a gitdir, which itself is not
-located within the working tree, then it is not possible to avoid
-returning the truename."
- (magit--with-refresh-cache
- (cons (or directory default-directory) 'magit-toplevel)
- (magit--with-safe-default-directory directory
- (if-let ((topdir (magit-rev-parse-safe "--show-toplevel")))
- (let (updir)
- (setq topdir (magit-expand-git-file-name topdir))
- (if (and
- ;; Always honor these settings.
- (not find-file-visit-truename)
- (not (getenv "GIT_WORK_TREE"))
- ;; `--show-cdup' is the relative path to the toplevel
- ;; from `(file-truename default-directory)'. Here we
- ;; pretend it is relative to `default-directory', and
- ;; go to that directory. Then we check whether
- ;; `--show-toplevel' still returns the same value and
- ;; whether `--show-cdup' now is the empty string. If
- ;; both is the case, then we are at the toplevel of
- ;; the same working tree, but also avoided needlessly
- ;; following any symlinks.
- (progn
- (setq updir (file-name-as-directory
- (magit-rev-parse-safe "--show-cdup")))
- (setq updir (if (file-name-absolute-p updir)
- (concat (file-remote-p default-directory) updir)
- (expand-file-name updir)))
- (let ((default-directory updir))
- (and (string-equal (magit-rev-parse-safe "--show-cdup") "")
- (--when-let (magit-rev-parse-safe "--show-toplevel")
- (string-equal (magit-expand-git-file-name it)
- topdir))))))
- updir
- (concat (file-remote-p default-directory)
- (file-name-as-directory topdir))))
- (when-let ((gitdir (magit-rev-parse-safe "--git-dir")))
- (setq gitdir (file-name-as-directory
- (if (file-name-absolute-p gitdir)
- ;; We might have followed a symlink.
- (concat (file-remote-p default-directory)
- (magit-expand-git-file-name gitdir))
- (expand-file-name gitdir))))
- (if (magit-bare-repo-p)
- gitdir
- (let* ((link (expand-file-name "gitdir" gitdir))
- (wtree (and (file-exists-p link)
- (magit-file-line link))))
- (cond
- ((and wtree
- ;; Ignore .git/gitdir files that result from a
- ;; Git bug. See #2364.
- (not (equal wtree ".git")))
- ;; Return the linked working tree.
- (concat (file-remote-p default-directory)
- (file-name-directory wtree)))
- ;; The working directory may not be the parent directory of
- ;; .git if it was set up with `git init --separate-git-dir'.
- ;; See #2955.
- ((car (rassoc gitdir magit--separated-gitdirs)))
- (t
- ;; Step outside the control directory to enter the working tree.
- (file-name-directory (directory-file-name gitdir)))))))))))
-
-(defmacro magit-with-toplevel (&rest body)
- (declare (indent defun) (debug (body)))
- (let ((toplevel (cl-gensym "toplevel")))
- `(let ((,toplevel (magit-toplevel)))
- (if ,toplevel
- (let ((default-directory ,toplevel))
- ,@body)
- (magit--not-inside-repository-error)))))
-
-(define-error 'magit-outside-git-repo "Not inside Git repository")
-(define-error 'magit-git-executable-not-found
- "Git executable cannot be found (see https://magit.vc/goto/e6a78ed2)")
-
-(defun magit--not-inside-repository-error ()
- (if (executable-find magit-git-executable)
- (signal 'magit-outside-git-repo default-directory)
- (signal 'magit-git-executable-not-found magit-git-executable)))
-
-(defun magit-inside-gitdir-p (&optional noerror)
- "Return t if `default-directory' is below the repository directory.
-If it is below the working directory, then return nil.
-If it isn't below either, then signal an error unless NOERROR
-is non-nil, in which case return nil."
- (and (magit--assert-default-directory noerror)
- ;; Below a repository directory that is not located below the
- ;; working directory "git rev-parse --is-inside-git-dir" prints
- ;; "false", which is wrong.
- (let ((gitdir (magit-git-dir)))
- (cond (gitdir (file-in-directory-p default-directory gitdir))
- (noerror nil)
- (t (signal 'magit-outside-git-repo default-directory))))))
-
-(defun magit-inside-worktree-p (&optional noerror)
- "Return t if `default-directory' is below the working directory.
-If it is below the repository directory, then return nil.
-If it isn't below either, then signal an error unless NOERROR
-is non-nil, in which case return nil."
- (and (magit--assert-default-directory noerror)
- (condition-case nil
- (magit-rev-parse-true "--is-inside-work-tree")
- (magit-invalid-git-boolean
- (and (not noerror)
- (signal 'magit-outside-git-repo default-directory))))))
-
-(cl-defgeneric magit-bare-repo-p (&optional noerror)
- "Return t if the current repository is bare.
-If it is non-bare, then return nil. If `default-directory'
-isn't below a Git repository, then signal an error unless
-NOERROR is non-nil, in which case return nil."
- (and (magit--assert-default-directory noerror)
- (condition-case nil
- (magit-rev-parse-true "--is-bare-repository")
- (magit-invalid-git-boolean
- (and (not noerror)
- (signal 'magit-outside-git-repo default-directory))))))
-
-(defun magit--assert-default-directory (&optional noerror)
- (or (file-directory-p default-directory)
- (and (not noerror)
- (let ((exists (file-exists-p default-directory)))
- (signal (if exists 'file-error 'file-missing)
- (list "Running git in directory"
- (if exists
- "Not a directory"
- "No such file or directory")
- default-directory))))))
-
-(defun magit-git-repo-p (directory &optional non-bare)
- "Return t if DIRECTORY is a Git repository.
-When optional NON-BARE is non-nil also return nil if DIRECTORY is
-a bare repository."
- (and (file-directory-p directory) ; Avoid archives, see #3397.
- (or (file-regular-p (expand-file-name ".git" directory))
- (file-directory-p (expand-file-name ".git" directory))
- (and (not non-bare)
- (file-regular-p (expand-file-name "HEAD" directory))
- (file-directory-p (expand-file-name "refs" directory))
- (file-directory-p (expand-file-name "objects" directory))))))
-
-(defun magit-file-relative-name (&optional file tracked)
- "Return the path of FILE relative to the repository root.
-
-If optional FILE is nil or omitted, return the relative path of
-the file being visited in the current buffer, if any, else nil.
-If the file is not inside a Git repository, then return nil.
-
-If TRACKED is non-nil, return the path only if it matches a
-tracked file."
- (unless file
- (with-current-buffer (or (buffer-base-buffer)
- (current-buffer))
- (setq file (or magit-buffer-file-name buffer-file-name
- (and (derived-mode-p 'dired-mode) default-directory)))))
- (when (and file (or (not tracked)
- (magit-file-tracked-p (file-relative-name file))))
- (--when-let (magit-toplevel
- (magit--safe-default-directory
- (directory-file-name (file-name-directory file))))
- (file-relative-name file it))))
-
-(defun magit-file-tracked-p (file)
- (magit-git-success "ls-files" "--error-unmatch" file))
-
-(defun magit-list-files (&rest args)
- (apply #'magit-git-items "ls-files" "-z" "--full-name" args))
-
-(defun magit-tracked-files ()
- (magit-list-files "--cached"))
-
-(defun magit-untracked-files (&optional all files)
- (magit-list-files "--other" (unless all "--exclude-standard") "--" files))
-
-(defun magit-unstaged-files (&optional nomodules files)
- (magit-git-items "diff-files" "-z" "--name-only"
- (and nomodules "--ignore-submodules")
- "--" files))
-
-(defun magit-staged-files (&optional nomodules files)
- (magit-git-items "diff-index" "-z" "--name-only" "--cached"
- (and nomodules "--ignore-submodules")
- (magit-headish) "--" files))
-
-(defun magit-binary-files (&rest args)
- (--mapcat (and (string-match "^-\t-\t\\(.+\\)" it)
- (list (match-string 1 it)))
- (apply #'magit-git-items
- "diff" "-z" "--numstat" "--ignore-submodules"
- args)))
-
-(defun magit-unmerged-files ()
- (magit-git-items "diff-files" "-z" "--name-only" "--diff-filter=U"))
-
-(defun magit-ignored-files ()
- (magit-git-items "ls-files" "-z" "--others" "--ignored"
- "--exclude-standard" "--directory"))
-
-(defun magit-skip-worktree-files ()
- (--keep (and (and (= (aref it 0) ?S)
- (substring it 2)))
- (magit-list-files "-t")))
-
-(defun magit-assume-unchanged-files ()
- (--keep (and (and (memq (aref it 0) '(?h ?s ?m ?r ?c ?k))
- (substring it 2)))
- (magit-list-files "-v")))
-
-(defun magit-revision-files (rev)
- (magit-with-toplevel
- (magit-git-items "ls-tree" "-z" "-r" "--name-only" rev)))
-
-(defun magit-changed-files (rev-or-range &optional other-rev)
- "Return list of files the have changed between two revisions.
-If OTHER-REV is non-nil, REV-OR-RANGE should be a revision, not a
-range. Otherwise, it can be any revision or range accepted by
-\"git diff\" (i.e., <rev>, <revA>..<revB>, or <revA>...<revB>)."
- (magit-with-toplevel
- (magit-git-items "diff" "-z" "--name-only" rev-or-range other-rev)))
-
-(defun magit-renamed-files (revA revB)
- (--map (cons (nth 1 it) (nth 2 it))
- (-partition 3 (magit-git-items
- "diff-tree" "-r" "--diff-filter=R" "-z" "-M"
- revA revB))))
-
-(defun magit-file-status (&rest args)
- (magit--with-temp-process-buffer
- (save-excursion (magit-git-insert "status" "-z" args))
- (let ((pos (point)) status)
- (while (> (skip-chars-forward "[:print:]") 0)
- (let ((x (char-after pos))
- (y (char-after (1+ pos)))
- (file (buffer-substring (+ pos 3) (point))))
- (forward-char)
- (if (memq x '(?R ?C))
- (progn
- (setq pos (point))
- (skip-chars-forward "[:print:]")
- (push (list file (buffer-substring pos (point)) x y) status)
- (forward-char))
- (push (list file nil x y) status)))
- (setq pos (point)))
- status)))
-
-(defcustom magit-cygwin-mount-points
- (when (eq system-type 'windows-nt)
- (cl-sort (--map (if (string-match "^\\(.*\\) on \\(.*\\) type" it)
- (cons (file-name-as-directory (match-string 2 it))
- (file-name-as-directory (match-string 1 it)))
- (lwarn '(magit) :error
- "Failed to parse Cygwin mount: %S" it))
- ;; If --exec-path is not a native Windows path,
- ;; then we probably have a cygwin git.
- (let ((process-environment
- (append magit-git-environment process-environment)))
- (and (not (string-match-p
- "\\`[a-zA-Z]:"
- (car (process-lines
- magit-git-executable "--exec-path"))))
- (ignore-errors (process-lines "mount")))))
- #'> :key (pcase-lambda (`(,cyg . ,_win)) (length cyg))))
- "Alist of (CYGWIN . WIN32) directory names.
-Sorted from longest to shortest CYGWIN name."
- :package-version '(magit . "2.3.0")
- :group 'magit-process
- :type '(alist :key-type string :value-type directory))
-
-(defun magit-expand-git-file-name (filename)
- (unless (file-name-absolute-p filename)
- (setq filename (expand-file-name filename)))
- (-if-let ((cyg . win)
- (cl-assoc filename magit-cygwin-mount-points
- :test (lambda (f cyg) (string-prefix-p cyg f))))
- (concat win (substring filename (length cyg)))
- filename))
-
-(defun magit-convert-filename-for-git (filename)
- "Convert FILENAME so that it can be passed to git.
-1. If it's a remote filename, then remove the remote part.
-2. Deal with an `windows-nt' Emacs vs. Cygwin Git incompatibility."
- (if (file-name-absolute-p filename)
- (-if-let ((cyg . win)
- (cl-rassoc filename magit-cygwin-mount-points
- :test (lambda (f win) (string-prefix-p win f))))
- (concat cyg (substring filename (length win)))
- (or (file-remote-p filename 'localname)
- filename))
- filename))
-
-(defun magit-decode-git-path (path)
- (if (eq (aref path 0) ?\")
- (decode-coding-string (read path)
- (or magit-git-output-coding-system
- (car default-process-coding-system))
- t)
- path))
-
-(defun magit-file-at-point (&optional expand assert)
- (if-let ((file (magit-section-case
- (file (oref it value))
- (hunk (magit-section-parent-value it)))))
- (if expand
- (expand-file-name file (magit-toplevel))
- file)
- (when assert
- (user-error "No file at point"))))
-
-(defun magit-current-file ()
- (or (magit-file-relative-name)
- (magit-file-at-point)
- (and (derived-mode-p 'magit-log-mode)
- (car magit-buffer-log-files))))
-
-;;; Predicates
-
-(defun magit-no-commit-p ()
- "Return t if there is no commit in the current Git repository."
- (not (magit-rev-verify "HEAD")))
-
-(defun magit-merge-commit-p (commit)
- "Return t if COMMIT is a merge commit."
- (> (length (magit-commit-parents commit)) 1))
-
-(defun magit-anything-staged-p (&optional ignore-submodules &rest files)
- "Return t if there are any staged changes.
-If optional FILES is non-nil, then only changes to those files
-are considered."
- (magit-git-failure "diff" "--quiet" "--cached"
- (and ignore-submodules "--ignore-submodules")
- "--" files))
-
-(defun magit-anything-unstaged-p (&optional ignore-submodules &rest files)
- "Return t if there are any unstaged changes.
-If optional FILES is non-nil, then only changes to those files
-are considered."
- (magit-git-failure "diff" "--quiet"
- (and ignore-submodules "--ignore-submodules")
- "--" files))
-
-(defun magit-anything-modified-p (&optional ignore-submodules &rest files)
- "Return t if there are any staged or unstaged changes.
-If optional FILES is non-nil, then only changes to those files
-are considered."
- (or (apply 'magit-anything-staged-p ignore-submodules files)
- (apply 'magit-anything-unstaged-p ignore-submodules files)))
-
-(defun magit-anything-unmerged-p (&rest files)
- "Return t if there are any merge conflicts.
-If optional FILES is non-nil, then only conflicts in those files
-are considered."
- (and (magit-git-string "ls-files" "--unmerged" files) t))
-
-(defun magit-module-worktree-p (module)
- (magit-with-toplevel
- (file-exists-p (expand-file-name (expand-file-name ".git" module)))))
-
-(defun magit-module-no-worktree-p (module)
- (not (magit-module-worktree-p module)))
-
-(defun magit-ignore-submodules-p (&optional return-argument)
- (or (cl-find-if (lambda (arg)
- (string-prefix-p "--ignore-submodules" arg))
- magit-buffer-diff-args)
- (when-let ((value (magit-get "diff.ignoreSubmodules")))
- (if return-argument
- (concat "--ignore-submodules=" value)
- (concat "diff.ignoreSubmodules=" value)))))
-
-;;; Revisions and References
-
-(defun magit-rev-parse (&rest args)
- "Execute `git rev-parse ARGS', returning first line of output.
-If there is no output, return nil."
- (apply #'magit-git-string "rev-parse" args))
-
-(defun magit-rev-parse-safe (&rest args)
- "Execute `git rev-parse ARGS', returning first line of output.
-If there is no output, return nil. Like `magit-rev-parse' but
-ignore `magit-git-debug'."
- (apply #'magit-git-str "rev-parse" args))
-
-(defun magit-rev-parse-true (&rest args)
- "Execute `git rev-parse ARGS', returning t if it prints \"true\".
-If it prints \"false\", then return nil. For any other output
-signal an error."
- (magit-git-true "rev-parse" args))
-
-(defun magit-rev-parse-false (&rest args)
- "Execute `git rev-parse ARGS', returning t if it prints \"false\".
-If it prints \"true\", then return nil. For any other output
-signal an error."
- (magit-git-false "rev-parse" args))
-
-(defun magit-rev-parse-p (&rest args)
- "Execute `git rev-parse ARGS', returning t if it prints \"true\".
-Return t if the first (and usually only) output line is the
-string \"true\", otherwise return nil."
- (equal (magit-git-str "rev-parse" args) "true"))
-
-(defun magit-rev-verify (rev)
- (magit-git-string-p "rev-parse" "--verify" rev))
-
-(defun magit-commit-p (rev)
- "Return full hash for REV if it names an existing commit."
- (magit-rev-verify (concat rev "^{commit}")))
-
-(defalias 'magit-rev-verify-commit 'magit-commit-p)
-
-(defalias 'magit-rev-hash 'magit-commit-p)
-
-(defun magit-rev-equal (a b)
- "Return t if there are no differences between the commits A and B."
- (magit-git-success "diff" "--quiet" a b))
-
-(defun magit-rev-eq (a b)
- "Return t if A and B refer to the same commit."
- (let ((a (magit-commit-p a))
- (b (magit-commit-p b)))
- (and a b (equal a b))))
-
-(defun magit-rev-ancestor-p (a b)
- "Return non-nil if commit A is an ancestor of commit B."
- (magit-git-success "merge-base" "--is-ancestor" a b))
-
-(defun magit-rev-head-p (rev)
- (or (equal rev "HEAD")
- (and rev
- (not (string-match-p "\\.\\." rev))
- (equal (magit-rev-parse rev)
- (magit-rev-parse "HEAD")))))
-
-(defun magit-rev-author-p (rev)
- "Return t if the user is the author of REV.
-More precisely return t if `user.name' is equal to the author
-name of REV and/or `user.email' is equal to the author email
-of REV."
- (or (equal (magit-get "user.name") (magit-rev-format "%an" rev))
- (equal (magit-get "user.email") (magit-rev-format "%ae" rev))))
-
-(defun magit-rev-name (rev &optional pattern not-anchored)
- "Return a symbolic name for REV using `git-name-rev'.
-
-PATTERN can be used to limit the result to a matching ref.
-Unless NOT-ANCHORED is non-nil, the beginning of the ref must
-match PATTERN.
-
-An anchored lookup is done using the arguments
-\"--exclude=*/<PATTERN> --exclude=*/HEAD\" in addition to
-\"--refs=<PATTERN>\", provided at least version v2.13 of Git is
-used. Older versions did not support the \"--exclude\" argument.
-When \"--exclude\" cannot be used and `git-name-rev' returns a
-ref that should have been excluded, then that is discarded and
-this function returns nil instead. This is unfortunate because
-there might be other refs that do match. To fix that, update
-Git."
- (if (version< (magit-git-version) "2.13")
- (when-let
- ((ref (magit-git-string "name-rev" "--name-only" "--no-undefined"
- (and pattern (concat "--refs=" pattern))
- rev)))
- (if (and pattern
- (string-match-p "\\`refs/[^/]+/\\*\\'" pattern))
- (let ((namespace (substring pattern 0 -1)))
- (and (not (or (string-suffix-p "HEAD" ref)
- (and (string-match-p namespace ref)
- (not (magit-rev-verify
- (concat namespace ref))))))
- ref))
- ref))
- (magit-git-string "name-rev" "--name-only" "--no-undefined"
- (and pattern (concat "--refs=" pattern))
- (and pattern
- (not not-anchored)
- (list "--exclude=*/HEAD"
- (concat "--exclude=*/" pattern)))
- rev)))
-
-(defun magit-rev-branch (rev)
- (--when-let (magit-rev-name rev "refs/heads/*")
- (unless (string-match-p "[~^]" it) it)))
-
-(defun magit-get-shortname (rev)
- (let* ((fn (apply-partially 'magit-rev-name rev))
- (name (or (funcall fn "refs/tags/*")
- (funcall fn "refs/heads/*")
- (funcall fn "refs/remotes/*"))))
- (cond ((not name)
- (magit-rev-parse "--short" rev))
- ((string-match "^\\(?:tags\\|remotes\\)/\\(.+\\)" name)
- (if (magit-ref-ambiguous-p (match-string 1 name))
- name
- (match-string 1 name)))
- (t (magit-ref-maybe-qualify name)))))
-
-(defun magit-name-branch (rev &optional lax)
- (or (magit-name-local-branch rev)
- (magit-name-remote-branch rev)
- (and lax (or (magit-name-local-branch rev t)
- (magit-name-remote-branch rev t)))))
-
-(defun magit-name-local-branch (rev &optional lax)
- (--when-let (magit-rev-name rev "refs/heads/*")
- (and (or lax (not (string-match-p "[~^]" it))) it)))
-
-(defun magit-name-remote-branch (rev &optional lax)
- (--when-let (magit-rev-name rev "refs/remotes/*")
- (and (or lax (not (string-match-p "[~^]" it)))
- (substring it 8))))
-
-(defun magit-name-tag (rev &optional lax)
- (--when-let (magit-rev-name rev "refs/tags/*")
- (and (or lax (not (string-match-p "[~^]" it)))
- (substring it 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 \"HEAD\" or if that doesn't exist the hash of the empty tree."
- (if (magit-no-commit-p)
- (magit-git-string "mktree")
- "HEAD"))
-
-(defun magit-branch-at-point ()
- (magit-section-case
- (branch (oref it value))
- (commit (or (magit--painted-branch-at-point)
- (magit-name-branch (oref it value))))))
-
-(defun magit--painted-branch-at-point (&optional type)
- (or (and (not (eq type 'remote))
- (memq (get-text-property (point) 'font-lock-face)
- (list 'magit-branch-local
- 'magit-branch-current))
- (when-let ((branch (thing-at-point 'git-revision t)))
- (cdr (magit-split-branch-name branch))))
- (and (not (eq type 'local))
- (memq (get-text-property (point) 'font-lock-face)
- (list 'magit-branch-remote
- 'magit-branch-remote-head))
- (thing-at-point 'git-revision t))))
-
-(defun magit-local-branch-at-point ()
- (magit-section-case
- (branch (let ((branch (magit-ref-maybe-qualify (oref it value))))
- (when (member branch (magit-list-local-branch-names))
- branch)))
- (commit (or (magit--painted-branch-at-point 'local)
- (magit-name-local-branch (oref it value))))))
-
-(defun magit-remote-branch-at-point ()
- (magit-section-case
- (branch (let ((branch (oref it value)))
- (when (member branch (magit-list-remote-branch-names))
- branch)))
- (commit (or (magit--painted-branch-at-point 'remote)
- (magit-name-remote-branch (oref it value))))))
-
-(defun magit-commit-at-point ()
- (or (magit-section-value-if 'commit)
- (and (derived-mode-p 'magit-stash-mode
- 'magit-merge-preview-mode
- 'magit-revision-mode)
- magit-buffer-revision)))
-
-(defun magit-branch-or-commit-at-point ()
- (or (and magit-buffer-file-name
- magit-buffer-refname)
- (magit-section-case
- (branch (magit-ref-maybe-qualify (oref it value)))
- (commit (or (magit--painted-branch-at-point)
- (let ((rev (oref it value)))
- (or (magit-name-branch rev) rev))))
- (tag (magit-ref-maybe-qualify (oref it value) "tags/"))
- (pullreq (or (and (fboundp 'forge--pullreq-branch)
- (magit-branch-p
- (forge--pullreq-branch (oref it value))))
- (magit-ref-p (format "refs/pullreqs/%s"
- (oref (oref it value) number))))))
- (thing-at-point 'git-revision t)
- (and (derived-mode-p 'magit-stash-mode
- 'magit-merge-preview-mode
- 'magit-revision-mode)
- magit-buffer-revision)))
-
-(defun magit-tag-at-point ()
- (magit-section-case
- (tag (oref it value))
- (commit (magit-name-tag (oref it value)))))
-
-(defun magit-stash-at-point ()
- (magit-section-value-if 'stash))
-
-(defun magit-remote-at-point ()
- (magit-section-case
- (remote (oref it value))
- (branch (magit-section-parent-value it))))
-
-(defun magit-module-at-point (&optional predicate)
- (when (magit-section-match 'magit-module-section)
- (let ((module (oref (magit-current-section) value)))
- (and (or (not predicate)
- (funcall predicate module))
- module))))
-
-(defun magit-get-current-branch ()
- "Return the refname of the currently checked out branch.
-Return nil if no branch is currently checked out."
- (magit-git-string "symbolic-ref" "--short" "HEAD"))
-
-(defvar magit-get-previous-branch-timeout 0.5
- "Maximum time to spend in `magit-get-previous-branch'.
-Given as a number of seconds.")
-
-(defun magit-get-previous-branch ()
- "Return the refname of the previously checked out branch.
-Return nil if no branch can be found in the `HEAD' reflog
-which is different from the current branch and still exists.
-The amount of time spent searching is limited by
-`magit-get-previous-branch-timeout'."
- (let ((t0 (float-time))
- (current (magit-get-current-branch))
- (i 1) prev)
- (while (if (> (- (float-time) t0) magit-get-previous-branch-timeout)
- (setq prev nil) ;; Timed out.
- (and (setq prev (magit-rev-verify (format "@{-%i}" i)))
- (or (not (setq prev (magit-rev-branch prev)))
- (equal prev current))))
- (cl-incf i))
- prev))
-
-(defun magit-set-upstream-branch (branch upstream)
- "Set UPSTREAM as the upstream of BRANCH.
-If UPSTREAM is nil, then unset BRANCH's upstream.
-Otherwise UPSTREAM has to be an existing branch."
- (if upstream
- (magit-call-git "branch" "--set-upstream-to" upstream branch)
- (magit-call-git "branch" "--unset-upstream" branch)))
-
-(defun magit-get-upstream-ref (&optional branch)
- "Return the upstream branch of BRANCH as a fully qualified ref.
-It BRANCH is nil, then return the upstream of the current branch,
-if any, nil otherwise. If the upstream is not configured, the
-configured remote is an url, or the named branch does not exist,
-then return nil. I.e. return an existing local or
-remote-tracking branch ref."
- (when-let ((branch (or branch (magit-get-current-branch))))
- (magit-ref-fullname (concat branch "@{upstream}"))))
-
-(defun magit-get-upstream-branch (&optional branch)
- "Return the name of the upstream branch of BRANCH.
-It BRANCH is nil, then return the upstream of the current branch
-if any, nil otherwise. If the upstream is not configured, the
-configured remote is an url, or the named branch does not exist,
-then return nil. I.e. return the name of an existing local or
-remote-tracking branch. The returned string is colorized
-according to the branch type."
- (magit--with-refresh-cache (list 'magit-get-upstream-branch branch)
- (when-let ((branch (or branch (magit-get-current-branch)))
- (upstream (magit-ref-abbrev (concat branch "@{upstream}"))))
- (magit--propertize-face
- upstream (if (equal (magit-get "branch" branch "remote") ".")
- 'magit-branch-local
- 'magit-branch-remote)))))
-
-(defun magit-get-indirect-upstream-branch (branch &optional force)
- (let ((remote (magit-get "branch" branch "remote")))
- (and remote (not (equal remote "."))
- ;; The user has opted in...
- (or force
- (--some (if (magit-git-success "check-ref-format" "--branch" it)
- (equal it branch)
- (string-match-p it branch))
- magit-branch-prefer-remote-upstream))
- ;; and local BRANCH tracks a remote branch...
- (let ((upstream (magit-get-upstream-branch branch)))
- ;; whose upstream...
- (and upstream
- ;; has the same name as BRANCH...
- (equal (substring upstream (1+ (length remote))) branch)
- ;; and can be fast-forwarded to BRANCH.
- (magit-rev-ancestor-p upstream branch)
- upstream)))))
-
-(defun magit-get-upstream-remote (&optional branch allow-unnamed)
- (when-let ((branch (or branch (magit-get-current-branch)))
- (remote (magit-get "branch" branch "remote")))
- (and (not (equal remote "."))
- (cond ((member remote (magit-list-remotes))
- (magit--propertize-face remote 'magit-branch-remote))
- ((and allow-unnamed
- (string-match-p "\\(\\`.\\{0,2\\}/\\|[:@]\\)" remote))
- (magit--propertize-face remote 'bold))))))
-
-(defun magit-get-unnamed-upstream (&optional branch)
- (when-let ((branch (or branch (magit-get-current-branch)))
- (remote (magit-get "branch" branch "remote"))
- (merge (magit-get "branch" branch "merge")))
- (and (magit--unnamed-upstream-p remote merge)
- (list (magit--propertize-face remote 'bold)
- (magit--propertize-face merge 'magit-branch-remote)))))
-
-(defun magit--unnamed-upstream-p (remote merge)
- (and remote (string-match-p "\\(\\`\\.\\{0,2\\}/\\|[:@]\\)" remote)
- merge (string-prefix-p "refs/" merge)))
-
-(defun magit--valid-upstream-p (remote merge)
- (and (or (equal remote ".")
- (member remote (magit-list-remotes)))
- (string-prefix-p "refs/" merge)))
-
-(defun magit-get-current-remote (&optional allow-unnamed)
- (or (magit-get-upstream-remote nil allow-unnamed)
- (when-let ((remotes (magit-list-remotes))
- (remote (if (= (length remotes) 1)
- (car remotes)
- (car (member "origin" remotes)))))
- (magit--propertize-face remote 'magit-branch-remote))))
-
-(defun magit-get-push-remote (&optional branch)
- (when-let ((remote
- (or (and (or branch (setq branch (magit-get-current-branch)))
- (magit-get "branch" branch "pushRemote"))
- (magit-get "remote.pushDefault"))))
- (magit--propertize-face remote 'magit-branch-remote)))
-
-(defun magit-get-push-branch (&optional branch verify)
- (magit--with-refresh-cache (list 'magit-get-push-branch branch verify)
- (when-let ((branch (or branch (setq branch (magit-get-current-branch))))
- (remote (magit-get-push-remote branch))
- (target (concat remote "/" branch)))
- (and (or (not verify)
- (magit-rev-verify target))
- (magit--propertize-face target 'magit-branch-remote)))))
-
-(defun magit-get-@{push}-branch (&optional branch)
- (let ((ref (magit-rev-parse "--symbolic-full-name"
- (concat branch "@{push}"))))
- (when (and ref (string-prefix-p "refs/remotes/" ref))
- (substring ref 13))))
-
-(defun magit-get-remote (&optional branch)
- (when (or branch (setq branch (magit-get-current-branch)))
- (let ((remote (magit-get "branch" branch "remote")))
- (unless (equal remote ".")
- remote))))
-
-(defun magit-get-some-remote (&optional branch)
- (or (magit-get-remote branch)
- (and (magit-branch-p "master")
- (magit-get-remote "master"))
- (let ((remotes (magit-list-remotes)))
- (or (car (member "origin" remotes))
- (car remotes)))))
-
-(defun magit-branch-merged-p (branch &optional target)
- "Return non-nil if BRANCH is merged into its upstream and TARGET.
-
-TARGET defaults to the current branch. If `HEAD' is detached and
-TARGET is nil, then always return nil. As a special case, if
-TARGET is t, then return non-nil if BRANCH is merged into any one
-of the other local branches.
-
-If, and only if, BRANCH has an upstream, then only return non-nil
-if BRANCH is merged into both TARGET (as described above) as well
-as into its upstream."
- (and (--if-let (and (magit-branch-p branch)
- (magit-get-upstream-branch branch))
- (magit-git-success "merge-base" "--is-ancestor" branch it)
- t)
- (if (eq target t)
- (delete (magit-name-local-branch branch)
- (magit-list-containing-branches branch))
- (--when-let (or target (magit-get-current-branch))
- (magit-git-success "merge-base" "--is-ancestor" branch it)))))
-
-(defun magit-get-tracked (refname)
- "Return the remote branch tracked by the remote-tracking branch REFNAME.
-The returned value has the form (REMOTE . REF), where REMOTE is
-the name of a remote and REF is the ref local to the remote."
- (when-let ((ref (magit-ref-fullname refname)))
- (save-match-data
- (seq-some (lambda (line)
- (and (string-match "\
-\\`remote\\.\\([^.]+\\)\\.fetch=\\+?\\([^:]+\\):\\(.+\\)" line)
- (let ((rmt (match-string 1 line))
- (src (match-string 2 line))
- (dst (match-string 3 line)))
- (and (string-match (format "\\`%s\\'"
- (replace-regexp-in-string
- "*" "\\(.+\\)" dst t t))
- ref)
- (cons rmt (replace-regexp-in-string
- "*" (match-string 1 ref) src))))))
- (magit-git-lines "config" "--local" "--list")))))
-
-(defun magit-split-branch-name (branch)
- (cond ((member branch (magit-list-local-branch-names))
- (cons "." branch))
- ((string-match "/" branch)
- (or (seq-some (lambda (remote)
- (and (string-match
- (format "\\`\\(%s\\)/\\(.+\\)\\'" remote)
- branch)
- (cons (match-string 1 branch)
- (match-string 2 branch))))
- (magit-list-remotes))
- (error "Invalid branch name %s" branch)))))
-
-(defun magit-get-current-tag (&optional rev with-distance)
- "Return the closest tag reachable from REV.
-
-If optional REV is nil, then default to `HEAD'.
-If optional WITH-DISTANCE is non-nil then return (TAG COMMITS),
-if it is `dirty' return (TAG COMMIT DIRTY). COMMITS is the number
-of commits in `HEAD' but not in TAG and DIRTY is t if there are
-uncommitted changes, nil otherwise."
- (--when-let (magit-git-str "describe" "--long" "--tags"
- (and (eq with-distance 'dirty) "--dirty") rev)
- (save-match-data
- (string-match
- "\\(.+\\)-\\(?:0[0-9]*\\|\\([0-9]+\\)\\)-g[0-9a-z]+\\(-dirty\\)?$" it)
- (if with-distance
- `(,(match-string 1 it)
- ,(string-to-number (or (match-string 2 it) "0"))
- ,@(and (match-string 3 it) (list t)))
- (match-string 1 it)))))
-
-(defun magit-get-next-tag (&optional rev with-distance)
- "Return the closest tag from which REV is reachable.
-
-If optional REV is nil, then default to `HEAD'.
-If no such tag can be found or if the distance is 0 (in which
-case it is the current tag, not the next), return nil instead.
-If optional WITH-DISTANCE is non-nil, then return (TAG COMMITS)
-where COMMITS is the number of commits in TAG but not in REV."
- (--when-let (magit-git-str "describe" "--contains" (or rev "HEAD"))
- (save-match-data
- (when (string-match "^[^^~]+" it)
- (setq it (match-string 0 it))
- (unless (equal it (magit-get-current-tag rev))
- (if with-distance
- (list it (car (magit-rev-diff-count it rev)))
- it))))))
-
-(defvar magit-list-refs-namespaces
- '("refs/heads" "refs/remotes" "refs/tags" "refs/pull"))
-
-(defun magit-list-refs (&optional namespaces format sortby)
- "Return list of references.
-
-When NAMESPACES is non-nil, list refs from these namespaces
-rather than those from `magit-list-refs-namespaces'.
-
-FORMAT is passed to the `--format' flag of `git for-each-ref'
-and defaults to \"%(refname)\". If the format is \"%(refname)\"
-or \"%(refname:short)\", then drop the symbolic-ref \"HEAD\".
-
-SORTBY is a key or list of keys to pass to the `--sort' flag of
-`git for-each-ref'. When nil, use `magit-list-refs-sortby'"
- (unless format
- (setq format "%(refname)"))
- (let ((refs (magit-git-lines "for-each-ref"
- (concat "--format=" format)
- (--map (concat "--sort=" it)
- (pcase (or sortby magit-list-refs-sortby)
- ((and val (pred stringp)) (list val))
- ((and val (pred listp)) val)))
- (or namespaces magit-list-refs-namespaces))))
- (if (member format '("%(refname)" "%(refname:short)"))
- (--remove (string-match-p "\\(\\`\\|/\\)HEAD\\'" it) refs)
- refs)))
-
-(defun magit-list-branches ()
- (magit-list-refs (list "refs/heads" "refs/remotes")))
-
-(defun magit-list-local-branches ()
- (magit-list-refs "refs/heads"))
-
-(defun magit-list-remote-branches (&optional remote)
- (magit-list-refs (concat "refs/remotes/" remote)))
-
-(defun magit-list-related-branches (relation &optional commit &rest args)
- (--remove (string-match-p "\\(\\`(HEAD\\|HEAD -> \\)" it)
- (--map (substring it 2)
- (magit-git-lines "branch" args relation commit))))
-
-(defun magit-list-containing-branches (&optional commit &rest args)
- (magit-list-related-branches "--contains" commit args))
-
-(defun magit-list-publishing-branches (&optional commit)
- (--filter (magit-rev-ancestor-p (or commit "HEAD") it)
- magit-published-branches))
-
-(defun magit-list-merged-branches (&optional commit &rest args)
- (magit-list-related-branches "--merged" commit args))
-
-(defun magit-list-unmerged-branches (&optional commit &rest args)
- (magit-list-related-branches "--no-merged" commit args))
-
-(defun magit-list-unmerged-to-upstream-branches ()
- (--filter (when-let ((upstream (magit-get-upstream-branch it)))
- (member it (magit-list-unmerged-branches upstream)))
- (magit-list-local-branch-names)))
-
-(defun magit-list-branches-pointing-at (commit)
- (let ((re (format "\\`%s refs/\\(heads\\|remotes\\)/\\(.*\\)\\'"
- (magit-rev-verify commit))))
- (--keep (and (string-match re it)
- (let ((name (match-string 2 it)))
- (and (not (string-suffix-p "HEAD" name))
- name)))
- (magit-git-lines "show-ref"))))
-
-(defun magit-list-refnames (&optional namespaces include-special)
- (nconc (magit-list-refs namespaces "%(refname:short)")
- (and include-special
- (magit-list-special-refnames))))
-
-(defvar magit-special-refnames
- '("HEAD" "ORIG_HEAD" "FETCH_HEAD" "MERGE_HEAD" "CHERRY_PICK_HEAD"))
-
-(defun magit-list-special-refnames ()
- (let ((gitdir (magit-gitdir)))
- (cl-mapcan (lambda (name)
- (and (file-exists-p (expand-file-name name gitdir))
- (list name)))
- magit-special-refnames)))
-
-(defun magit-list-branch-names ()
- (magit-list-refnames (list "refs/heads" "refs/remotes")))
-
-(defun magit-list-local-branch-names ()
- (magit-list-refnames "refs/heads"))
-
-(defun magit-list-remote-branch-names (&optional remote relative)
- (if (and remote relative)
- (let ((regexp (format "^refs/remotes/%s/\\(.+\\)" remote)))
- (--mapcat (when (string-match regexp it)
- (list (match-string 1 it)))
- (magit-list-remote-branches remote)))
- (magit-list-refnames (concat "refs/remotes/" remote))))
-
-(defun magit-format-refs (format &rest args)
- (let ((lines (magit-git-lines
- "for-each-ref" (concat "--format=" format)
- (or args (list "refs/heads" "refs/remotes" "refs/tags")))))
- (if (string-match-p "\f" format)
- (--map (split-string it "\f") lines)
- lines)))
-
-(defun magit-list-remotes ()
- (magit-git-lines "remote"))
-
-(defun magit-list-tags ()
- (magit-git-lines "tag"))
-
-(defun magit-list-stashes (&optional format)
- (magit-git-lines "stash" "list" (concat "--format=" (or format "%gd"))))
-
-(defun magit-list-active-notes-refs ()
- "Return notes refs according to `core.notesRef' and `notes.displayRef'."
- (magit-git-lines "for-each-ref" "--format=%(refname)"
- (or (magit-get "core.notesRef") "refs/notes/commits")
- (magit-get-all "notes.displayRef")))
-
-(defun magit-list-notes-refnames ()
- (--map (substring it 6) (magit-list-refnames "refs/notes")))
-
-(defun magit-remote-list-tags (remote)
- (--keep (and (not (string-match-p "\\^{}$" it))
- (substring it 51))
- (magit-git-lines "ls-remote" "--tags" remote)))
-
-(defun magit-remote-list-branches (remote)
- (--keep (and (not (string-match-p "\\^{}$" it))
- (substring it 52))
- (magit-git-lines "ls-remote" "--heads" remote)))
-
-(defun magit-remote-list-refs (remote)
- (--keep (and (not (string-match-p "\\^{}$" it))
- (substring it 41))
- (magit-git-lines "ls-remote" remote)))
-
-(defun magit-list-modified-modules ()
- (--keep (and (string-match "\\`\\+\\([^ ]+\\) \\(.+\\) (.+)\\'" it)
- (match-string 2 it))
- (magit-git-lines "submodule" "status")))
-
-(defun magit-list-module-paths ()
- (--mapcat (and (string-match "^160000 [0-9a-z]\\{40\\} 0\t\\(.+\\)$" it)
- (list (match-string 1 it)))
- (magit-git-items "ls-files" "-z" "--stage")))
-
-(defun magit-list-module-names ()
- (mapcar #'magit-get-submodule-name (magit-list-module-paths)))
-
-(defun magit-get-submodule-name (path)
- "Return the name of the submodule at PATH.
-PATH has to be relative to the super-repository."
- (magit-git-string "submodule--helper" "name" path))
-
-(defun magit-list-worktrees ()
- (let (worktrees worktree)
- (dolist (line (let ((magit-git-global-arguments
- ;; KLUDGE At least in v2.8.3 this triggers a segfault.
- (remove "--no-pager" magit-git-global-arguments)))
- (magit-git-lines "worktree" "list" "--porcelain")))
- (cond ((string-prefix-p "worktree" line)
- (push (setq worktree (list (substring line 9) nil nil nil))
- worktrees))
- ((string-equal line "bare")
- (let* ((default-directory (car worktree))
- (wt (and (not (magit-get-boolean "core.bare"))
- (magit-get "core.worktree"))))
- (if (and wt (file-exists-p (expand-file-name wt)))
- (progn (setf (nth 0 worktree) (expand-file-name wt))
- (setf (nth 2 worktree) (magit-rev-parse "HEAD"))
- (setf (nth 3 worktree) (magit-get-current-branch)))
- (setf (nth 1 worktree) t))))
- ((string-prefix-p "HEAD" line)
- (setf (nth 2 worktree) (substring line 5)))
- ((string-prefix-p "branch" line)
- (setf (nth 3 worktree) (substring line 18)))
- ((string-equal line "detached"))))
- (nreverse worktrees)))
-
-(defun magit-symbolic-ref-p (name)
- (magit-git-success "symbolic-ref" "--quiet" name))
-
-(defun magit-ref-p (rev)
- (or (car (member rev (magit-list-refs "refs/")))
- (car (member rev (magit-list-refnames "refs/")))))
-
-(defun magit-branch-p (rev)
- (or (car (member rev (magit-list-branches)))
- (car (member rev (magit-list-branch-names)))))
-
-(defun magit-local-branch-p (rev)
- (or (car (member rev (magit-list-local-branches)))
- (car (member rev (magit-list-local-branch-names)))))
-
-(defun magit-remote-branch-p (rev)
- (or (car (member rev (magit-list-remote-branches)))
- (car (member rev (magit-list-remote-branch-names)))))
-
-(defun magit-branch-set-face (branch)
- (magit--propertize-face branch (if (magit-local-branch-p branch)
- 'magit-branch-local
- 'magit-branch-remote)))
-
-(defun magit-tag-p (rev)
- (car (member rev (magit-list-tags))))
-
-(defun magit-remote-p (string)
- (car (member string (magit-list-remotes))))
-
-(defun magit-rev-diff-count (a b)
- "Return the commits in A but not B and vice versa.
-Return a list of two integers: (A>B B>A)."
- (mapcar 'string-to-number
- (split-string (magit-git-string "rev-list"
- "--count" "--left-right"
- (concat a "..." b))
- "\t")))
-
-(defun magit-abbrev-length ()
- (let ((abbrev (magit-get "core.abbrev")))
- (if (and abbrev (not (equal abbrev "auto")))
- (string-to-number abbrev)
- ;; Guess the length git will be using based on an example
- ;; abbreviation. Actually HEAD's abbreviation might be an
- ;; outlier, so use the shorter of the abbreviations for two
- ;; commits. See #3034.
- (if-let ((head (magit-rev-parse "--short" "HEAD"))
- (head-len (length head)))
- (min head-len
- (--if-let (magit-rev-parse "--short" "HEAD~")
- (length it)
- head-len))
- ;; We're on an unborn branch, but perhaps the repository has
- ;; other commits. See #4123.
- (if-let ((commits (magit-git-lines "rev-list" "-n2" "--all"
- "--abbrev-commit")))
- (apply #'min (mapcar #'length commits))
- ;; A commit does not exist. Fall back to the default of 7.
- 7)))))
-
-(defun magit-abbrev-arg (&optional arg)
- (format "--%s=%d" (or arg "abbrev") (magit-abbrev-length)))
-
-(defun magit-rev-abbrev (rev)
- (magit-rev-parse (magit-abbrev-arg "short") rev))
-
-(defun magit-commit-children (commit &optional args)
- (mapcar #'car
- (--filter (member commit (cdr it))
- (--map (split-string it " ")
- (magit-git-lines
- "log" "--format=%H %P"
- (or args (list "--branches" "--tags" "--remotes"))
- "--not" commit)))))
-
-(defun magit-commit-parents (commit)
- (--when-let (magit-git-string "rev-list" "-1" "--parents" commit)
- (cdr (split-string it))))
-
-(defun magit-patch-id (rev)
- (magit--with-temp-process-buffer
- (magit-process-file
- shell-file-name nil '(t nil) nil shell-command-switch
- (let ((exec (shell-quote-argument magit-git-executable)))
- (format "%s diff-tree -u %s | %s patch-id" exec rev exec)))
- (car (split-string (buffer-string)))))
-
-(defun magit-rev-format (format &optional rev args)
- (let ((str (magit-git-string "show" "--no-patch"
- (concat "--format=" format) args
- (if rev (concat rev "^{commit}") "HEAD") "--")))
- (unless (string-equal str "")
- str)))
-
-(defun magit-rev-insert-format (format &optional rev args)
- (magit-git-insert "show" "--no-patch"
- (concat "--format=" format) args
- (if rev (concat rev "^{commit}") "HEAD") "--"))
-
-(defun magit-format-rev-summary (rev)
- (--when-let (magit-rev-format "%h %s" rev)
- (string-match " " it)
- (magit--put-face 0 (match-beginning 0) 'magit-hash it)
- it))
-
-(defvar magit-ref-namespaces
- '(("\\`HEAD\\'" . magit-head)
- ("\\`refs/tags/\\(.+\\)" . magit-tag)
- ("\\`refs/heads/\\(.+\\)" . magit-branch-local)
- ("\\`refs/remotes/\\(.+\\)" . magit-branch-remote)
- ("\\`refs/bisect/\\(bad\\)" . magit-bisect-bad)
- ("\\`refs/bisect/\\(skip.*\\)" . magit-bisect-skip)
- ("\\`refs/bisect/\\(good.*\\)" . magit-bisect-good)
- ("\\`refs/stash$" . magit-refname-stash)
- ("\\`refs/wip/\\(.+\\)" . magit-refname-wip)
- ("\\`refs/pullreqs/\\(.+\\)" . magit-refname-pullreq)
- ("\\`\\(bad\\):" . magit-bisect-bad)
- ("\\`\\(skip\\):" . magit-bisect-skip)
- ("\\`\\(good\\):" . magit-bisect-good)
- ("\\`\\(.+\\)" . magit-refname))
- "How refs are formatted for display.
-
-Each entry controls how a certain type of ref is displayed, and
-has the form (REGEXP . FACE). REGEXP is a regular expression
-used to match full refs. The first entry whose REGEXP matches
-the reference is used.
-
-In log and revision buffers the first regexp submatch becomes the
-\"label\" that represents the ref and is propertized with FONT.
-In refs buffers the displayed text is controlled by other means
-and this option only controls what face is used.")
-
-(defun magit-format-ref-labels (string)
- (save-match-data
- (let ((regexp "\\(, \\|tag: \\|HEAD -> \\)")
- names)
- (if (and (derived-mode-p 'magit-log-mode)
- (member "--simplify-by-decoration" magit-buffer-log-args))
- (let ((branches (magit-list-local-branch-names))
- (re (format "^%s/.+" (regexp-opt (magit-list-remotes)))))
- (setq names
- (--map (cond ((string-equal it "HEAD") it)
- ((string-prefix-p "refs/" it) it)
- ((member it branches) (concat "refs/heads/" it))
- ((string-match re it) (concat "refs/remotes/" it))
- (t (concat "refs/" it)))
- (split-string
- (replace-regexp-in-string "tag: " "refs/tags/" string)
- regexp t))))
- (setq names (split-string string regexp t)))
- (let (state head upstream tags branches remotes other combined)
- (dolist (ref names)
- (let* ((face (cdr (--first (string-match (car it) ref)
- magit-ref-namespaces)))
- (name (magit--propertize-face
- (or (match-string 1 ref) ref) face)))
- (cl-case face
- ((magit-bisect-bad magit-bisect-skip magit-bisect-good)
- (setq state name))
- (magit-head
- (setq head (magit--propertize-face "@" 'magit-head)))
- (magit-tag (push name tags))
- (magit-branch-local (push name branches))
- (magit-branch-remote (push name remotes))
- (t (push name other)))))
- (setq remotes
- (-keep
- (lambda (name)
- (if (string-match "\\`\\([^/]*\\)/\\(.*\\)\\'" name)
- (let ((r (match-string 1 name))
- (b (match-string 2 name)))
- (and (not (equal b "HEAD"))
- (if (equal (concat "refs/remotes/" name)
- (magit-git-string
- "symbolic-ref"
- (format "refs/remotes/%s/HEAD" r)))
- (magit--propertize-face
- name 'magit-branch-remote-head)
- name)))
- name))
- remotes))
- (let* ((current (magit-get-current-branch))
- (target (magit-get-upstream-branch current)))
- (dolist (name branches)
- (let ((push (car (member (magit-get-push-branch name) remotes))))
- (when push
- (setq remotes (delete push remotes))
- (string-match "^[^/]*/" push)
- (setq push (substring push 0 (match-end 0))))
- (cond
- ((equal name current)
- (setq head
- (concat push
- (magit--propertize-face
- name 'magit-branch-current))))
- ((equal name target)
- (setq upstream
- (concat push
- (magit--propertize-face
- name '(magit-branch-upstream
- magit-branch-local)))))
- (t
- (push (concat push name) combined)))))
- (when (and target (not upstream))
- (if (member target remotes)
- (progn
- (magit--add-face-text-property
- 0 (length target) 'magit-branch-upstream nil target)
- (setq upstream target)
- (setq remotes (delete target remotes)))
- (when-let ((target (car (member target combined))))
- (magit--add-face-text-property
- 0 (length target) 'magit-branch-upstream nil target)
- (setq upstream target)
- (setq combined (delete target combined))))))
- (mapconcat #'identity
- (-flatten `(,state
- ,head
- ,upstream
- ,@(nreverse tags)
- ,@(nreverse combined)
- ,@(nreverse remotes)
- ,@other))
- " ")))))
-
-(defun magit-object-type (object)
- (magit-git-string "cat-file" "-t" object))
-
-(defmacro magit-with-blob (commit file &rest body)
- (declare (indent 2)
- (debug (form form body)))
- `(magit--with-temp-process-buffer
- (let ((buffer-file-name ,file))
- (save-excursion
- (magit-git-insert "cat-file" "-p"
- (concat ,commit ":" buffer-file-name)))
- (decode-coding-inserted-region
- (point-min) (point-max) buffer-file-name t nil nil t)
- ,@body)))
-
-(defmacro magit-with-temp-index (tree arg &rest body)
- (declare (indent 2) (debug (form form body)))
- (let ((file (cl-gensym "file")))
- `(let ((magit--refresh-cache nil)
- (,file (magit-convert-filename-for-git
- (make-temp-name (magit-git-dir "index.magit.")))))
- (unwind-protect
- (magit-with-toplevel
- (--when-let ,tree
- (or (magit-git-success "read-tree" ,arg it
- (concat "--index-output=" ,file))
- (error "Cannot read tree %s" it)))
- (if (file-remote-p default-directory)
- (let ((magit-tramp-process-environment
- (cons (concat "GIT_INDEX_FILE=" ,file)
- magit-tramp-process-environment)))
- ,@body)
- (let ((process-environment
- (cons (concat "GIT_INDEX_FILE=" ,file)
- process-environment)))
- ,@body)))
- (ignore-errors
- (delete-file (concat (file-remote-p default-directory) ,file)))))))
-
-(defun magit-commit-tree (message &optional tree &rest parents)
- (magit-git-string "commit-tree" "--no-gpg-sign" "-m" message
- (--mapcat (list "-p" it) (delq nil parents))
- (or tree
- (magit-git-string "write-tree")
- (error "Cannot write tree"))))
-
-(defun magit-commit-worktree (message &optional arg &rest other-parents)
- (magit-with-temp-index "HEAD" arg
- (and (magit-update-files (magit-unstaged-files))
- (apply #'magit-commit-tree message nil "HEAD" other-parents))))
-
-(defun magit-update-files (files)
- (magit-git-success "update-index" "--add" "--remove" "--" files))
-
-(defun magit-update-ref (ref message rev &optional stashish)
- (let ((magit--refresh-cache nil))
- (or (if (not (version< (magit-git-version) "2.6.0"))
- (zerop (magit-call-git "update-ref" "--create-reflog"
- "-m" message ref rev
- (or (magit-rev-verify ref) "")))
- ;; `--create-reflog' didn't exist before v2.6.0
- (let ((oldrev (magit-rev-verify ref))
- (logfile (magit-git-dir (concat "logs/" ref))))
- (unless (file-exists-p logfile)
- (when oldrev
- (magit-git-success "update-ref" "-d" ref oldrev))
- (make-directory (file-name-directory logfile) t)
- (with-temp-file logfile)
- (when (and oldrev (not stashish))
- (magit-git-success "update-ref" "-m" "enable reflog"
- ref oldrev ""))))
- (magit-git-success "update-ref" "-m" message ref rev
- (or (magit-rev-verify ref) "")))
- (error "Cannot update %s with %s" ref rev))))
-
-(defconst magit-range-re
- (concat "\\`\\([^ \t]*[^.]\\)?" ; revA
- "\\(\\.\\.\\.?\\)" ; range marker
- "\\([^.][^ \t]*\\)?\\'")) ; revB
-
-(defun magit-split-range (range)
- (and (string-match magit-range-re range)
- (let ((beg (or (match-string 1 range) "HEAD"))
- (end (or (match-string 3 range) "HEAD")))
- (cons (if (string-equal (match-string 2 range) "...")
- (magit-git-string "merge-base" beg end)
- beg)
- end))))
-
-(defun magit-hash-range (range)
- (if (string-match magit-range-re range)
- (concat (magit-rev-hash (match-string 1 range))
- (match-string 2 range)
- (magit-rev-hash (match-string 3 range)))
- (magit-rev-hash range)))
-
-(put 'git-revision 'thing-at-point 'magit-thingatpt--git-revision)
-(defun magit-thingatpt--git-revision ()
- (--when-let
- (let ((c "\s\n\t~^:?*[\\"))
- (cl-letf (((get 'git-revision 'beginning-op)
- (lambda ()
- (if (re-search-backward (format "[%s]" c) nil t)
- (forward-char)
- (goto-char (point-min)))))
- ((get 'git-revision 'end-op)
- (lambda ()
- (re-search-forward (format "\\=[^%s]*" c) nil t))))
- (bounds-of-thing-at-point 'git-revision)))
- (let ((text (buffer-substring-no-properties (car it) (cdr it))))
- (and (magit-commit-p text) text))))
-
-;;; Completion
-
-(defvar magit-revision-history nil)
-
-(defun magit-read-branch (prompt &optional secondary-default)
- (magit-completing-read prompt (magit-list-branch-names)
- nil t nil 'magit-revision-history
- (or (magit-branch-at-point)
- secondary-default
- (magit-get-current-branch))))
-
-(defun magit-read-branch-or-commit (prompt &optional secondary-default)
- (or (magit-completing-read prompt (magit-list-refnames nil t)
- nil nil nil 'magit-revision-history
- (or (magit-branch-or-commit-at-point)
- secondary-default
- (magit-get-current-branch)))
- (user-error "Nothing selected")))
-
-(defun magit-read-range-or-commit (prompt &optional secondary-default)
- (magit-read-range
- prompt
- (or (--when-let (magit-region-values '(commit branch) t)
- (deactivate-mark)
- (concat (car (last it)) ".." (car it)))
- (magit-branch-or-commit-at-point)
- secondary-default
- (magit-get-current-branch))))
-
-(defun magit-read-range (prompt &optional default)
- (magit-completing-read-multiple prompt
- (magit-list-refnames)
- "\\.\\.\\.?"
- default 'magit-revision-history))
-
-(defun magit-read-remote-branch
- (prompt &optional remote default local-branch require-match)
- (let ((choice (magit-completing-read
- prompt
- (-union (and local-branch
- (if remote
- (concat remote "/" local-branch)
- (--map (concat it "/" local-branch)
- (magit-list-remotes))))
- (magit-list-remote-branch-names remote t))
- nil require-match nil 'magit-revision-history default)))
- (if (or remote (string-match "\\`\\([^/]+\\)/\\(.+\\)" choice))
- choice
- (user-error "`%s' doesn't have the form REMOTE/BRANCH" choice))))
-
-(defun magit-read-refspec (prompt remote)
- (magit-completing-read prompt
- (prog2 (message "Determining available refs...")
- (magit-remote-list-refs remote)
- (message "Determining available refs...done"))))
-
-(defun magit-read-local-branch (prompt &optional secondary-default)
- (magit-completing-read prompt (magit-list-local-branch-names)
- nil t nil 'magit-revision-history
- (or (magit-local-branch-at-point)
- secondary-default
- (magit-get-current-branch))))
-
-(defun magit-read-local-branch-or-commit (prompt)
- (let ((choices (nconc (magit-list-local-branch-names)
- (magit-list-special-refnames)))
- (commit (magit-commit-at-point)))
- (when commit
- (push commit choices))
- (or (magit-completing-read prompt choices
- nil nil nil 'magit-revision-history
- (or (magit-local-branch-at-point) commit))
- (user-error "Nothing selected"))))
-
-(defun magit-read-local-branch-or-ref (prompt &optional secondary-default)
- (magit-completing-read prompt (nconc (magit-list-local-branch-names)
- (magit-list-refs "refs/"))
- nil t nil 'magit-revision-history
- (or (magit-local-branch-at-point)
- secondary-default
- (magit-get-current-branch))))
-
-(defun magit-read-other-branch
- (prompt &optional exclude secondary-default no-require-match)
- (let* ((current (magit-get-current-branch))
- (atpoint (magit-branch-at-point))
- (exclude (or exclude current))
- (default (or (and (not (equal atpoint exclude)) atpoint)
- (and (not (equal current exclude)) current)
- secondary-default
- (magit-get-previous-branch))))
- (magit-completing-read prompt (delete exclude (magit-list-branch-names))
- nil (not no-require-match)
- nil 'magit-revision-history default)))
-
-(defun magit-read-other-branch-or-commit
- (prompt &optional exclude secondary-default)
- (let* ((current (magit-get-current-branch))
- (atpoint (magit-branch-or-commit-at-point))
- (exclude (or exclude current))
- (default (or (and (not (equal atpoint exclude))
- (not (and (not current)
- (magit-rev-equal atpoint "HEAD")))
- atpoint)
- (and (not (equal current exclude)) current)
- secondary-default
- (magit-get-previous-branch))))
- (or (magit-completing-read prompt (delete exclude (magit-list-refnames))
- nil nil nil 'magit-revision-history default)
- (user-error "Nothing selected"))))
-
-(defun magit-read-other-local-branch
- (prompt &optional exclude secondary-default no-require-match)
- (let* ((current (magit-get-current-branch))
- (atpoint (magit-local-branch-at-point))
- (exclude (or exclude current))
- (default (or (and (not (equal atpoint exclude)) atpoint)
- (and (not (equal current exclude)) current)
- secondary-default
- (magit-get-previous-branch))))
- (magit-completing-read prompt
- (delete exclude (magit-list-local-branch-names))
- nil (not no-require-match)
- nil 'magit-revision-history default)))
-
-(defun magit-read-branch-prefer-other (prompt)
- (let* ((current (magit-get-current-branch))
- (commit (magit-commit-at-point))
- (atrev (and commit (magit-list-branches-pointing-at commit)))
- (atpoint (magit--painted-branch-at-point)))
- (magit-completing-read prompt (magit-list-branch-names)
- nil t nil 'magit-revision-history
- (or (magit-section-value-if 'branch)
- atpoint
- (and (not (cdr atrev)) (car atrev))
- (--first (not (equal it current)) atrev)
- (magit-get-previous-branch)
- (car atrev)))))
-
-(defun magit-read-upstream-branch (&optional branch prompt)
- "Read the upstream for BRANCH using PROMPT.
-If optional BRANCH is nil, then read the upstream for the
-current branch, or raise an error if no branch is checked
-out. Only existing branches can be selected."
- (unless branch
- (setq branch (or (magit-get-current-branch)
- (error "Need a branch to set its upstream"))))
- (let ((branches (delete branch (magit-list-branch-names))))
- (magit-completing-read
- (or prompt (format "Change upstream of %s to" branch))
- branches nil t nil 'magit-revision-history
- (or (let ((r (car (member (magit-remote-branch-at-point) branches)))
- (l (car (member (magit-local-branch-at-point) branches))))
- (if magit-prefer-remote-upstream (or r l) (or l r)))
- (let ((r (car (member "origin/master" branches)))
- (l (car (member "master" branches))))
- (if magit-prefer-remote-upstream (or r l) (or l r)))
- (car (member (magit-get-previous-branch) branches))))))
-
-(defun magit-read-starting-point (prompt &optional branch default)
- (or (magit-completing-read
- (concat prompt
- (and branch
- (if (bound-and-true-p ivy-mode)
- ;; Ivy-mode strips faces from prompt.
- (format " `%s'" branch)
- (concat " " (magit--propertize-face
- branch 'magit-branch-local))))
- " starting at")
- (nconc (list "HEAD")
- (magit-list-refnames)
- (directory-files (magit-git-dir) nil "_HEAD\\'"))
- nil nil nil 'magit-revision-history
- (or default (magit--default-starting-point)))
- (user-error "Nothing selected")))
-
-(defun magit--default-starting-point ()
- (or (let ((r (magit-remote-branch-at-point))
- (l (magit-local-branch-at-point)))
- (if magit-prefer-remote-upstream (or r l) (or l r)))
- (magit-commit-at-point)
- (magit-stash-at-point)
- (magit-get-current-branch)))
-
-(defun magit-read-tag (prompt &optional require-match)
- (magit-completing-read prompt (magit-list-tags) nil
- require-match nil 'magit-revision-history
- (magit-tag-at-point)))
-
-(defun magit-read-stash (prompt)
- (let* ((atpoint (magit-stash-at-point))
- (default (and atpoint
- (concat atpoint (magit-rev-format " %s" atpoint))))
- (choices (mapcar (lambda (c)
- (pcase-let ((`(,rev ,msg) (split-string c "\0")))
- (concat (propertize rev 'face 'magit-hash)
- " " msg)))
- (magit-list-stashes "%gd%x00%s")))
- (choice (magit-completing-read prompt choices
- nil t nil nil
- default
- (car choices))))
- (and choice
- (string-match "^\\([^ ]+\\) \\(.+\\)" choice)
- (substring-no-properties (match-string 1 choice)))))
-
-(defun magit-read-remote (prompt &optional default use-only)
- (let ((remotes (magit-list-remotes)))
- (if (and use-only (= (length remotes) 1))
- (car remotes)
- (magit-completing-read prompt remotes
- nil t nil nil
- (or default
- (magit-remote-at-point)
- (magit-get-remote))))))
-
-(defun magit-read-remote-or-url (prompt &optional default)
- (magit-completing-read prompt
- (nconc (magit-list-remotes)
- (list "https://" "git://" "git@"))
- nil nil nil nil
- (or default
- (magit-remote-at-point)
- (magit-get-remote))))
-
-(defun magit-read-module-path (prompt &optional predicate)
- (magit-completing-read prompt (magit-list-module-paths)
- predicate t nil nil
- (magit-module-at-point predicate)))
-
-(defun magit-module-confirm (verb &optional predicate)
- (let (modules)
- (if current-prefix-arg
- (progn
- (setq modules (magit-list-module-paths))
- (when predicate
- (setq modules (-filter predicate modules)))
- (unless modules
- (if predicate
- (user-error "No modules satisfying %s available" predicate)
- (user-error "No modules available"))))
- (setq modules (magit-region-values 'magit-module-section))
- (when modules
- (when predicate
- (setq modules (-filter predicate modules)))
- (unless modules
- (user-error "No modules satisfying %s selected" predicate))))
- (if (> (length modules) 1)
- (magit-confirm t nil (format "%s %%i modules" verb) nil modules)
- (list (magit-read-module-path (format "%s module" verb) predicate)))))
-
-;;; _
-(provide 'magit-git)
-;;; magit-git.el ends here
+++ /dev/null
-;;; magit-gitignore.el --- intentionally untracked files -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements gitignore commands.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit)
-
-;;; Transient
-
-;;;###autoload (autoload 'magit-gitignore "magit-gitignore" nil t)
-(transient-define-prefix magit-gitignore ()
- "Instruct Git to ignore a file or pattern."
- :man-page "gitignore"
- ["Gitignore"
- ("t" "shared at toplevel (.gitignore)"
- magit-gitignore-in-topdir)
- ("s" "shared in subdirectory (path/to/.gitignore)"
- magit-gitignore-in-subdir)
- ("p" "privately (.git/info/exclude)"
- magit-gitignore-in-gitdir)
- ("g" magit-gitignore-on-system
- :if (lambda () (magit-get "core.excludesfile"))
- :description (lambda ()
- (format "privately for all repositories (%s)"
- (magit-get "core.excludesfile"))))]
- ["Skip worktree"
- (7 "w" "do skip worktree" magit-skip-worktree)
- (7 "W" "do not skip worktree" magit-no-skip-worktree)]
- ["Assume unchanged"
- (7 "u" "do assume unchanged" magit-assume-unchanged)
- (7 "U" "do not assume unchanged" magit-no-assume-unchanged)])
-
-;;; Gitignore Commands
-
-;;;###autoload
-(defun magit-gitignore-in-topdir (rule)
- "Add the Git ignore RULE to the top-level \".gitignore\" file.
-Since this file is tracked, it is shared with other clones of the
-repository. Also stage the file."
- (interactive (list (magit-gitignore-read-pattern)))
- (magit-with-toplevel
- (magit--gitignore rule ".gitignore")
- (magit-run-git "add" ".gitignore")))
-
-;;;###autoload
-(defun magit-gitignore-in-subdir (rule directory)
- "Add the Git ignore RULE to a \".gitignore\" file.
-Prompted 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" file))))
-
-;;;###autoload
-(defun magit-gitignore-in-gitdir (rule)
- "Add the Git ignore RULE to \"$GIT_DIR/info/exclude\".
-Rules in that file only affects this clone of the repository."
- (interactive (list (magit-gitignore-read-pattern)))
- (magit--gitignore rule (magit-git-dir "info/exclude"))
- (magit-refresh))
-
-;;;###autoload
-(defun magit-gitignore-on-system (rule)
- "Add the Git ignore RULE to the file specified by `core.excludesFile'.
-Rules that are defined in that file affect all local repositories."
- (interactive (list (magit-gitignore-read-pattern)))
- (magit--gitignore rule
- (or (magit-get "core.excludesFile")
- (error "Variable `core.excludesFile' isn't set")))
- (magit-refresh))
-
-(defun magit--gitignore (rule file)
- (when-let ((directory (file-name-directory file)))
- (make-directory directory t))
- (with-temp-buffer
- (when (file-exists-p file)
- (insert-file-contents file))
- (goto-char (point-max))
- (unless (bolp)
- (insert "\n"))
- (insert (replace-regexp-in-string "\\(\\\\*\\)" "\\1\\1" rule))
- (insert "\n")
- (write-region nil nil file)))
-
-(defun magit-gitignore-read-pattern ()
- (let* ((default (magit-current-file))
- (base (car magit-buffer-diff-files))
- (base (and base (file-directory-p base) base))
- (choices
- (delete-dups
- (--mapcat
- (cons (concat "/" it)
- (when-let ((ext (file-name-extension it)))
- (list (concat "/" (file-name-directory it) "*." ext)
- (concat "*." ext))))
- (sort (nconc
- (magit-untracked-files nil base)
- ;; The untracked section of the status buffer lists
- ;; directories containing only untracked files.
- ;; Add those as candidates.
- (-filter #'directory-name-p
- (magit-list-files
- "--other" "--exclude-standard" "--directory"
- "--no-empty-directory" "--" base)))
- #'string-lessp)))))
- (when default
- (setq default (concat "/" default))
- (unless (member default choices)
- (setq default (concat "*." (file-name-extension default)))
- (unless (member default choices)
- (setq default nil))))
- (magit-completing-read "File or pattern to ignore"
- choices nil nil nil nil default)))
-
-;;; Skip Worktree Commands
-
-;;;###autoload
-(defun magit-skip-worktree (file)
- "Call \"git update-index --skip-worktree -- FILE\"."
- (interactive
- (list (magit-read-file-choice "Skip worktree for"
- (magit-with-toplevel
- (cl-set-difference
- (magit-list-files)
- (magit-skip-worktree-files))))))
- (magit-with-toplevel
- (magit-run-git "update-index" "--skip-worktree" "--" file)))
-
-;;;###autoload
-(defun magit-no-skip-worktree (file)
- "Call \"git update-index --no-skip-worktree -- FILE\"."
- (interactive
- (list (magit-read-file-choice "Do not skip worktree for"
- (magit-with-toplevel
- (magit-skip-worktree-files)))))
- (magit-with-toplevel
- (magit-run-git "update-index" "--no-skip-worktree" "--" file)))
-
-;;; Assume Unchanged Commands
-
-;;;###autoload
-(defun magit-assume-unchanged (file)
- "Call \"git update-index --assume-unchanged -- FILE\"."
- (interactive
- (list (magit-read-file-choice "Assume file to be unchanged"
- (magit-with-toplevel
- (cl-set-difference
- (magit-list-files)
- (magit-assume-unchanged-files))))))
- (magit-with-toplevel
- (magit-run-git "update-index" "--assume-unchanged" "--" file)))
-
-;;;###autoload
-(defun magit-no-assume-unchanged (file)
- "Call \"git update-index --no-assume-unchanged -- FILE\"."
- (interactive
- (list (magit-read-file-choice "Do not assume file to be unchanged"
- (magit-with-toplevel
- (magit-assume-unchanged-files)))))
- (magit-with-toplevel
- (magit-run-git "update-index" "--no-assume-unchanged" "--" file)))
-
-;;; _
-(provide 'magit-gitignore)
-;;; magit-gitignore.el ends here
+++ /dev/null
-;;; magit-imenu.el --- Integrate Imenu in magit major modes -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Damien Cassou <damienNOSPAMcassou.me>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Emacs' major modes can facilitate navigation in their buffers by
-;; supporting Imenu. In such major modes, launching Imenu (M-x imenu)
-;; makes Emacs display a list of items (e.g., function definitions in
-;; a programming major mode). Selecting an item from this list moves
-;; point to this item.
-
-;; magit-imenu.el adds Imenu support to every major mode in Magit.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit)
-(require 'git-rebase)
-
-;;; Core
-
-(defun magit-imenu--index-function (entry-types menu-types)
- "Return an alist of imenu entries in current buffer.
-
-ENTRY-TYPES is a list of section types to be selected through
-`imenu'.
-
-MENU-TYPES is a list of section types containing elements of
-ENTRY-TYPES. Elements of MENU-TYPES are are used to categories
-elements of ENTRY-TYPES.
-
-This function is used as a helper for functions set as
-`imenu-create-index-function'."
- (let ((entries (make-hash-table :test 'equal)))
- (goto-char (point-max))
- (while (magit-section--backward-find
- (lambda ()
- (let* ((section (magit-current-section))
- (type (oref section type))
- (parent (oref section parent))
- (parent-type (oref parent type)))
- (and (-contains-p entry-types type)
- (-contains-p menu-types parent-type)))))
- (let* ((section (magit-current-section))
- (name (buffer-substring-no-properties
- (line-beginning-position)
- (line-end-position)))
- (parent (oref section parent))
- (parent-title (buffer-substring-no-properties
- (oref parent start)
- (1- (oref parent content)))))
- (puthash parent-title
- (cons (cons name (point))
- (gethash parent-title entries (list)))
- entries)))
- (mapcar (lambda (menu-title)
- (cons menu-title (gethash menu-title entries)))
- (hash-table-keys entries))))
-
-;;; Log mode
-
-;;;###autoload
-(defun magit-imenu--log-prev-index-position-function ()
- "Move point to previous line in current buffer.
-This function is used as a value for
-`imenu-prev-index-position-function'."
- (magit-section--backward-find
- (lambda ()
- (-contains-p '(commit stash)
- (oref (magit-current-section) type)))))
-
-;;;###autoload
-(defun magit-imenu--log-extract-index-name-function ()
- "Return imenu name for line at point.
-This function is used as a value for
-`imenu-extract-index-name-function'. Point should be at the
-beginning of the line."
- (save-match-data
- (looking-at "\\([^ ]+\\)[ *|]+\\(.+\\)$")
- (format "%s: %s"
- (match-string-no-properties 1)
- (match-string-no-properties 2))))
-
-;;; Diff mode
-
-;;;###autoload
-(defun magit-imenu--diff-prev-index-position-function ()
- "Move point to previous file line in current buffer.
-This function is used as a value for
-`imenu-prev-index-position-function'."
- (magit-section--backward-find
- (lambda ()
- (let ((section (magit-current-section)))
- (and (magit-file-section-p section)
- (not (equal (oref (oref section parent) type)
- 'diffstat)))))))
-
-;;;###autoload
-(defun magit-imenu--diff-extract-index-name-function ()
- "Return imenu name for line at point.
-This function is used as a value for
-`imenu-extract-index-name-function'. Point should be at the
-beginning of the line."
- (buffer-substring-no-properties (line-beginning-position)
- (line-end-position)))
-
-;;; Status mode
-
-;;;###autoload
-(defun magit-imenu--status-create-index-function ()
- "Return an alist of all imenu entries in current buffer.
-This function is used as a value for
-`imenu-create-index-function'."
- (magit-imenu--index-function
- '(file commit stash)
- '(unpushed unstaged unpulled untracked staged stashes)))
-
-;;;; Refs mode
-
-;;;###autoload
-(defun magit-imenu--refs-create-index-function ()
- "Return an alist of all imenu entries in current buffer.
-This function is used as a value for
-`imenu-create-index-function'."
- (magit-imenu--index-function
- '(branch commit tag)
- '(local remote tags)))
-
-;;;; Cherry mode
-
-;;;###autoload
-(defun magit-imenu--cherry-create-index-function ()
- "Return an alist of all imenu entries in current buffer.
-This function is used as a value for
-`imenu-create-index-function'."
- (magit-imenu--index-function
- '(commit)
- '(cherries)))
-
-;;;; Submodule list mode
-
-;;;###autoload
-(defun magit-imenu--submodule-prev-index-position-function ()
- "Move point to previous line in magit-submodule-list buffer.
-This function is used as a value for
-`imenu-prev-index-position-function'."
- (unless (bobp)
- (forward-line -1)))
-
-;;;###autoload
-(defun magit-imenu--submodule-extract-index-name-function ()
- "Return imenu name for line at point.
-This function is used as a value for
-`imenu-extract-index-name-function'. Point should be at the
-beginning of the line."
- (elt (tabulated-list-get-entry) 0))
-
-;;;; Repolist mode
-
-;;;###autoload
-(defun magit-imenu--repolist-prev-index-position-function ()
- "Move point to previous line in magit-repolist buffer.
-This function is used as a value for
-`imenu-prev-index-position-function'."
- (unless (bobp)
- (forward-line -1)))
-
-;;;###autoload
-(defun magit-imenu--repolist-extract-index-name-function ()
- "Return imenu name for line at point.
-This function is used as a value for
-`imenu-extract-index-name-function'. Point should be at the
-beginning of the line."
- (let ((entry (tabulated-list-get-entry)))
- (format "%s (%s)"
- (elt entry 0)
- (elt entry (1- (length entry))))))
-
-;;;; Process mode
-
-;;;###autoload
-(defun magit-imenu--process-prev-index-position-function ()
- "Move point to previous process in magit-process buffer.
-This function is used as a value for
-`imenu-prev-index-position-function'."
- (magit-section--backward-find
- (lambda ()
- (eq (oref (magit-current-section) type) 'process))))
-
-;;;###autoload
-(defun magit-imenu--process-extract-index-name-function ()
- "Return imenu name for line at point.
-This function is used as a value for
-`imenu-extract-index-name-function'. Point should be at the
-beginning of the line."
- (buffer-substring-no-properties (line-beginning-position)
- (line-end-position)))
-
-;;;; Rebase mode
-
-;;;###autoload
-(defun magit-imenu--rebase-prev-index-position-function ()
- "Move point to previous commit in git-rebase buffer.
-This function is used as a value for
-`imenu-prev-index-position-function'."
- (catch 'found
- (while (not (bobp))
- (git-rebase-backward-line)
- (when (git-rebase-line-p)
- (throw 'found t)))))
-
-;;;###autoload
-(defun magit-imenu--rebase-extract-index-name-function ()
- "Return imenu name for line at point.
-This function is used as a value for
-`imenu-extract-index-name-function'. Point should be at the
-beginning of the line."
- (buffer-substring-no-properties (line-beginning-position)
- (line-end-position)))
-
-;;; _
-(provide 'magit-imenu)
-;;; magit-imenu.el ends here
+++ /dev/null
-;;; magit-log.el --- inspect Git history -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for looking at Git logs, including
-;; special logs like cherry-logs, as well as for selecting a commit
-;; from a log.
-
-;;; Code:
-
-(require 'magit-core)
-(require 'magit-diff)
-
-(declare-function magit-blob-visit "magit-files" (blob-or-file line))
-(declare-function magit-insert-head-branch-header "magit-status"
- (&optional branch))
-(declare-function magit-insert-upstream-branch-header "magit-status"
- (&optional branch pull keyword))
-(declare-function magit-read-file-from-rev "magit-files"
- (rev prompt &optional default))
-(declare-function magit-show-commit "magit-diff"
- (arg1 &optional arg2 arg3 arg4))
-(declare-function magit-reflog-format-subject "magit-reflog" (subject))
-(defvar magit-refs-focus-column-width)
-(defvar magit-refs-margin)
-(defvar magit-refs-show-commit-count)
-(defvar magit-buffer-margin)
-(defvar magit-status-margin)
-(defvar magit-status-sections-hook)
-
-(require 'ansi-color)
-(require 'crm)
-(require 'which-func)
-
-(eval-when-compile
- (require 'subr-x))
-
-;;; Options
-;;;; Log Mode
-
-(defgroup magit-log nil
- "Inspect and manipulate Git history."
- :link '(info-link "(magit)Logging")
- :group 'magit-commands
- :group 'magit-modes)
-
-(defcustom magit-log-mode-hook nil
- "Hook run after entering Magit-Log mode."
- :group 'magit-log
- :type 'hook)
-
-(defcustom magit-log-remove-graph-args '("--follow" "--grep" "-G" "-S" "-L")
- "The log arguments that cause the `--graph' argument to be dropped."
- :package-version '(magit . "2.3.0")
- :group 'magit-log
- :type '(repeat (string :tag "Argument"))
- :options '("--follow" "--grep" "-G" "-S" "-L"))
-
-(defcustom magit-log-revision-headers-format "\
-%+b
-Author: %aN <%aE>
-Committer: %cN <%cE>"
- "Additional format string used with the `++header' argument."
- :package-version '(magit . "2.3.0")
- :group 'magit-log
- :type 'string)
-
-(defcustom magit-log-auto-more nil
- "Insert more log entries automatically when moving past the last entry.
-Only considered when moving past the last entry with
-`magit-goto-*-section' commands."
- :group 'magit-log
- :type 'boolean)
-
-(defcustom magit-log-margin '(t age magit-log-margin-width t 18)
- "Format of the margin in `magit-log-mode' buffers.
-
-The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
-
-If INIT is non-nil, then the margin is shown initially.
-STYLE controls how to format the author or committer date.
- It can be one of `age' (to show the age of the commit),
- `age-abbreviated' (to abbreviate the time unit to a character),
- or a string (suitable for `format-time-string') to show the
- actual date. Option `magit-log-margin-show-committer-date'
- controls which date is being displayed.
-WIDTH controls the width of the margin. This exists for forward
- compatibility and currently the value should not be changed.
-AUTHOR controls whether the name of the author is also shown by
- default.
-AUTHOR-WIDTH has to be an integer. When the name of the author
- is shown, then this specifies how much space is used to do so."
- :package-version '(magit . "2.9.0")
- :group 'magit-log
- :group 'magit-margin
- :type magit-log-margin--custom-type
- :initialize 'magit-custom-initialize-reset
- :set (apply-partially #'magit-margin-set-variable 'magit-log-mode))
-
-(defcustom magit-log-margin-show-committer-date nil
- "Whether to show the committer date in the margin.
-
-This option only controls whether the committer date is displayed
-instead of the author date. Whether some date is displayed in
-the margin and whether the margin is displayed at all is
-controlled by other options."
- :package-version '(magit . "3.0.0")
- :group 'magit-log
- :group 'magit-margin
- :type 'boolean)
-
-(defcustom magit-log-show-refname-after-summary nil
- "Whether to show refnames after commit summaries.
-This is useful if you use really long branch names."
- :package-version '(magit . "2.2.0")
- :group 'magit-log
- :type 'boolean)
-
-(defcustom magit-log-highlight-keywords t
- "Whether to highlight bracketed keywords in commit summaries."
- :package-version '(magit . "2.12.0")
- :group 'magit-log
- :type 'boolean)
-
-(defcustom magit-log-header-line-function 'magit-log-header-line-sentence
- "Function used to generate text shown in header line of log buffers."
- :package-version '(magit . "2.12.0")
- :group 'magit-log
- :type '(choice (function-item magit-log-header-line-arguments)
- (function-item magit-log-header-line-sentence)
- function))
-
-(defcustom magit-log-trace-definition-function 'magit-which-function
- "Function used to determine the function at point.
-This is used by the command `magit-log-trace-definition'.
-You should prefer `magit-which-function' over `which-function'
-because the latter may make use of Imenu's outdated cache."
- :package-version '(magit . "3.0.0")
- :group 'magit-log
- :type '(choice (function-item magit-which-function)
- (function-item which-function)
- (function-item add-log-current-defun)
- function))
-
-(defface magit-log-graph
- '((((class color) (background light)) :foreground "grey30")
- (((class color) (background dark)) :foreground "grey80"))
- "Face for the graph part of the log output."
- :group 'magit-faces)
-
-(defface magit-log-author
- '((((class color) (background light))
- :foreground "firebrick"
- :slant normal
- :weight normal)
- (((class color) (background dark))
- :foreground "tomato"
- :slant normal
- :weight normal))
- "Face for the author part of the log output."
- :group 'magit-faces)
-
-(defface magit-log-date
- '((((class color) (background light))
- :foreground "grey30"
- :slant normal
- :weight normal)
- (((class color) (background dark))
- :foreground "grey80"
- :slant normal
- :weight normal))
- "Face for the date part of the log output."
- :group 'magit-faces)
-
-(defface magit-header-line-log-select
- '((t :inherit bold))
- "Face for the `header-line' in `magit-log-select-mode'."
- :group 'magit-faces)
-
-;;;; File Log
-
-(defcustom magit-log-buffer-file-locked t
- "Whether `magit-log-buffer-file-quick' uses a dedicated buffer."
- :package-version '(magit . "2.7.0")
- :group 'magit-commands
- :group 'magit-log
- :type 'boolean)
-
-;;;; Select Mode
-
-(defcustom magit-log-select-show-usage 'both
- "Whether to show usage information when selecting a commit from a log.
-The message can be shown in the `echo-area' or the `header-line', or in
-`both' places. If the value isn't one of these symbols, then it should
-be nil, in which case no usage information is shown."
- :package-version '(magit . "2.1.0")
- :group 'magit-log
- :type '(choice (const :tag "in echo-area" echo-area)
- (const :tag "in header-line" header-line)
- (const :tag "in both places" both)
- (const :tag "nowhere")))
-
-(defcustom magit-log-select-margin
- (list (nth 0 magit-log-margin)
- (nth 1 magit-log-margin)
- 'magit-log-margin-width t
- (nth 4 magit-log-margin))
- "Format of the margin in `magit-log-select-mode' buffers.
-
-The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
-
-If INIT is non-nil, then the margin is shown initially.
-STYLE controls how to format the author or committer date.
- It can be one of `age' (to show the age of the commit),
- `age-abbreviated' (to abbreviate the time unit to a character),
- or a string (suitable for `format-time-string') to show the
- actual date. Option `magit-log-margin-show-committer-date'
- controls which date is being displayed.
-WIDTH controls the width of the margin. This exists for forward
- compatibility and currently the value should not be changed.
-AUTHOR controls whether the name of the author is also shown by
- default.
-AUTHOR-WIDTH has to be an integer. When the name of the author
- is shown, then this specifies how much space is used to do so."
- :package-version '(magit . "2.9.0")
- :group 'magit-log
- :group 'magit-margin
- :type magit-log-margin--custom-type
- :initialize 'magit-custom-initialize-reset
- :set-after '(magit-log-margin)
- :set (apply-partially #'magit-margin-set-variable 'magit-log-select-mode))
-
-;;;; Cherry Mode
-
-(defcustom magit-cherry-sections-hook
- '(magit-insert-cherry-headers
- magit-insert-cherry-commits)
- "Hook run to insert sections into the cherry buffer."
- :package-version '(magit . "2.1.0")
- :group 'magit-log
- :type 'hook)
-
-(defcustom magit-cherry-margin
- (list (nth 0 magit-log-margin)
- (nth 1 magit-log-margin)
- 'magit-log-margin-width t
- (nth 4 magit-log-margin))
- "Format of the margin in `magit-cherry-mode' buffers.
-
-The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
-
-If INIT is non-nil, then the margin is shown initially.
-STYLE controls how to format the author or committer date.
- It can be one of `age' (to show the age of the commit),
- `age-abbreviated' (to abbreviate the time unit to a character),
- or a string (suitable for `format-time-string') to show the
- actual date. Option `magit-log-margin-show-committer-date'
- controls which date is being displayed.
-WIDTH controls the width of the margin. This exists for forward
- compatibility and currently the value should not be changed.
-AUTHOR controls whether the name of the author is also shown by
- default.
-AUTHOR-WIDTH has to be an integer. When the name of the author
- is shown, then this specifies how much space is used to do so."
- :package-version '(magit . "2.9.0")
- :group 'magit-log
- :group 'magit-margin
- :type magit-log-margin--custom-type
- :initialize 'magit-custom-initialize-reset
- :set-after '(magit-log-margin)
- :set (apply-partially #'magit-margin-set-variable 'magit-cherry-mode))
-
-;;;; Log Sections
-
-(defcustom magit-log-section-commit-count 10
- "How many recent commits to show in certain log sections.
-How many recent commits `magit-insert-recent-commits' and
-`magit-insert-unpulled-from-upstream-or-recent' (provided
-the upstream isn't ahead of the current branch) show."
- :package-version '(magit . "2.1.0")
- :group 'magit-status
- :type 'number)
-
-;;; Arguments
-;;;; Prefix Classes
-
-(defclass magit-log-prefix (transient-prefix)
- ((history-key :initform 'magit-log)
- (major-mode :initform 'magit-log-mode)))
-
-(defclass magit-log-refresh-prefix (magit-log-prefix)
- ((history-key :initform 'magit-log)
- (major-mode :initform nil)))
-
-;;;; Prefix Methods
-
-(cl-defmethod transient-init-value ((obj magit-log-prefix))
- (pcase-let ((`(,args ,files)
- (magit-log--get-value 'magit-log-mode
- magit-prefix-use-buffer-arguments)))
- (unless (eq transient-current-command 'magit-dispatch)
- (when-let ((file (magit-file-relative-name)))
- (setq files (list file))))
- (oset obj value (if files `(("--" ,@files) ,args) args))))
-
-(cl-defmethod transient-init-value ((obj magit-log-refresh-prefix))
- (oset obj value (if magit-buffer-log-files
- `(("--" ,@magit-buffer-log-files)
- ,magit-buffer-log-args)
- magit-buffer-log-args)))
-
-(cl-defmethod transient-set-value ((obj magit-log-prefix))
- (magit-log--set-value obj))
-
-(cl-defmethod transient-save-value ((obj magit-log-prefix))
- (magit-log--set-value obj 'save))
-
-;;;; Argument Access
-
-(defun magit-log-arguments (&optional mode)
- "Return the current log arguments."
- (if (memq transient-current-command '(magit-log magit-log-refresh))
- (pcase-let ((`(,args ,alist)
- (-separate #'atom (transient-get-value))))
- (list args (cdr (assoc "--" alist))))
- (magit-log--get-value (or mode 'magit-log-mode))))
-
-(defun magit-log--get-value (mode &optional use-buffer-args)
- (unless use-buffer-args
- (setq use-buffer-args magit-direct-use-buffer-arguments))
- (let (args files)
- (cond
- ((and (memq use-buffer-args '(always selected current))
- (eq major-mode mode))
- (setq args magit-buffer-log-args)
- (setq files magit-buffer-log-files))
- ((and (memq use-buffer-args '(always selected))
- (when-let ((buffer (magit-get-mode-buffer
- mode nil
- (eq use-buffer-args 'selected))))
- (setq args (buffer-local-value 'magit-buffer-log-args buffer))
- (setq files (buffer-local-value 'magit-buffer-log-files buffer))
- t)))
- ((plist-member (symbol-plist mode) 'magit-log-current-arguments)
- (setq args (get mode 'magit-log-current-arguments)))
- ((when-let ((elt (assq (intern (format "magit-log:%s" mode))
- transient-values)))
- (setq args (cdr elt))
- t))
- (t
- (setq args (get mode 'magit-log-default-arguments))))
- (list args files)))
-
-(defun magit-log--set-value (obj &optional save)
- (pcase-let* ((obj (oref obj prototype))
- (mode (or (oref obj major-mode) major-mode))
- (key (intern (format "magit-log:%s" mode)))
- (`(,args ,alist)
- (-separate #'atom (transient-get-value)))
- (files (cdr (assoc "--" alist))))
- (put mode 'magit-log-current-arguments args)
- (when save
- (setf (alist-get key transient-values) args)
- (transient-save-values))
- (transient--history-push obj)
- (setq magit-buffer-log-args args)
- (unless (derived-mode-p 'magit-log-select-mode)
- (setq magit-buffer-log-files files))
- (magit-refresh)))
-
-;;; Commands
-;;;; Prefix Commands
-
-;;;###autoload (autoload 'magit-log "magit-log" nil t)
-(transient-define-prefix magit-log ()
- "Show a commit or reference log."
- :man-page "git-log"
- :class 'magit-log-prefix
- ;; The grouping in git-log(1) appears to be guided by implementation
- ;; details, so our logical grouping only follows it to an extend.
- ;; Arguments that are "misplaced" here:
- ;; 1. From "Commit Formatting".
- ;; 2. From "Common Diff Options".
- ;; 3. From unnamed first group.
- ;; 4. Implemented by Magit.
- ["Commit limiting"
- (magit-log:-n)
- (magit:--author)
- (7 "=s" "Limit to commits since" "--since=" transient-read-date)
- (7 "=u" "Limit to commits until" "--until=" transient-read-date)
- (magit-log:--grep)
- (7 "-I" "Invert search pattern" "--invert-grep")
- (magit-log:-G) ;2
- (magit-log:-S) ;2
- (magit-log:-L) ;2
- (7 "=m" "Omit merges" "--no-merges")
- (7 "=p" "First parent" "--first-parent")]
- ["History simplification"
- ( "-D" "Simplify by decoration" "--simplify-by-decoration")
- (magit:--)
- ( "-f" "Follow renames when showing single-file log" "--follow") ;3
- (6 "/s" "Only commits changing given paths" "--sparse")
- (7 "/d" "Only selected commits plus meaningful history" "--dense")
- (7 "/a" "Only commits existing directly on ancestry path" "--ancestry-path")
- (6 "/f" "Do not prune history" "--full-history")
- (7 "/m" "Prune some history" "--simplify-merges")]
- ["Commit ordering"
- (magit-log:--*-order)
- ("-r" "Reverse order" "--reverse")]
- ["Formatting"
- ("-g" "Show graph" "--graph") ;1
- ("-c" "Show graph in color" "--color") ;2
- ("-d" "Show refnames" "--decorate") ;3
- ("=S" "Show signatures" "--show-signature") ;1
- ("-h" "Show header" "++header") ;4
- ("-p" "Show diffs" ("-p" "--patch")) ;2
- ("-s" "Show diffstats" "--stat")] ;2
- [["Log"
- ("l" "current" magit-log-current)
- ("o" "other" magit-log-other)
- ("h" "HEAD" magit-log-head)]
- [""
- ("L" "local branches" magit-log-branches)
- (7 "B" "matching branches" magit-log-matching-branches)
- (7 "T" "matching tags" magit-log-matching-tags)
- ("b" "all branches" magit-log-all-branches)
- ("a" "all references" magit-log-all)
- (7 "m" "merged" magit-log-merged)]
- ["Reflog"
- ("r" "current" magit-reflog-current)
- ("O" "other" magit-reflog-other)
- ("H" "HEAD" magit-reflog-head)]
- [:if (lambda ()
- (require 'magit-wip)
- (magit--any-wip-mode-enabled-p))
- :description "Wiplog"
- ("i" "index" magit-wip-log-index)
- ("w" "worktree" magit-wip-log-worktree)]
- ["Other"
- (5 "s" "shortlog" magit-shortlog)]])
-
-;;;###autoload (autoload 'magit-log-refresh "magit-log" nil t)
-(transient-define-prefix magit-log-refresh ()
- "Change the arguments used for the log(s) in the current buffer."
- :man-page "git-log"
- :class 'magit-log-refresh-prefix
- [:if-mode magit-log-mode
- :class transient-subgroups
- ["Commit limiting"
- (magit-log:-n)
- (magit:--author)
- (magit-log:--grep)
- (7 "-I" "Invert search pattern" "--invert-grep")
- (magit-log:-G)
- (magit-log:-S)
- (magit-log:-L)]
- ["History simplification"
- ( "-D" "Simplify by decoration" "--simplify-by-decoration")
- (magit:--)
- ( "-f" "Follow renames when showing single-file log" "--follow") ;3
- (6 "/s" "Only commits changing given paths" "--sparse")
- (7 "/d" "Only selected commits plus meaningful history" "--dense")
- (7 "/a" "Only commits existing directly on ancestry path" "--ancestry-path")
- (6 "/f" "Do not prune history" "--full-history")
- (7 "/m" "Prune some history" "--simplify-merges")]
- ["Commit ordering"
- (magit-log:--*-order)
- ("-r" "Reverse order" "--reverse")]
- ["Formatting"
- ("-g" "Show graph" "--graph")
- ("-c" "Show graph in color" "--color")
- ("-d" "Show refnames" "--decorate")
- ("=S" "Show signatures" "--show-signature")
- ("-h" "Show header" "++header")
- ("-p" "Show diffs" ("-p" "--patch"))
- ("-s" "Show diffstats" "--stat")]]
- [:if-not-mode magit-log-mode
- :description "Arguments"
- (magit-log:-n)
- (magit-log:--*-order)
- ("-g" "Show graph" "--graph")
- ("-c" "Show graph in color" "--color")
- ("-d" "Show refnames" "--decorate")]
- [["Refresh"
- ("g" "buffer" magit-log-refresh)
- ("s" "buffer and set defaults" transient-set :transient nil)
- ("w" "buffer and save defaults" transient-save :transient nil)]
- ["Margin"
- ("L" "toggle visibility" magit-toggle-margin)
- ("l" "cycle style" magit-cycle-margin-style)
- ("d" "toggle details" magit-toggle-margin-details)
- ("x" "toggle shortstat" magit-toggle-log-margin-style)]
- [:if-mode magit-log-mode
- :description "Toggle"
- ("b" "buffer lock" magit-toggle-buffer-lock)]]
- (interactive)
- (cond
- ((not (eq transient-current-command 'magit-log-refresh))
- (pcase major-mode
- (`magit-reflog-mode
- (user-error "Cannot change log arguments in reflog buffers"))
- (`magit-cherry-mode
- (user-error "Cannot change log arguments in cherry buffers")))
- (transient-setup 'magit-log-refresh))
- (t
- (pcase-let ((`(,args ,files) (magit-log-arguments)))
- (setq magit-buffer-log-args args)
- (unless (derived-mode-p 'magit-log-select-mode)
- (setq magit-buffer-log-files files)))
- (magit-refresh))))
-
-;;;; Infix Commands
-
-(transient-define-argument magit-log:-n ()
- :description "Limit number of commits"
- :class 'transient-option
- ;; For historic reasons (and because it easy to guess what "-n"
- ;; stands for) this is the only argument where we do not use the
- ;; long argument ("--max-count").
- :shortarg "-n"
- :argument "-n"
- :reader 'transient-read-number-N+)
-
-(transient-define-argument magit:--author ()
- :description "Limit to author"
- :class 'transient-option
- :key "-A"
- :argument "--author="
- :reader 'magit-transient-read-person)
-
-(transient-define-argument magit-log:--*-order ()
- :description "Order commits by"
- :class 'transient-switches
- :key "-o"
- :argument-format "--%s-order"
- :argument-regexp "\\(--\\(topo\\|author-date\\|date\\)-order\\)"
- :choices '("topo" "author-date" "date"))
-
-(transient-define-argument magit-log:--grep ()
- :description "Search messages"
- :class 'transient-option
- :key "-F"
- :argument "--grep=")
-
-(transient-define-argument magit-log:-G ()
- :description "Search changes"
- :class 'transient-option
- :argument "-G")
-
-(transient-define-argument magit-log:-S ()
- :description "Search occurrences"
- :class 'transient-option
- :argument "-S")
-
-(transient-define-argument magit-log:-L ()
- :description "Trace line evolution"
- :class 'transient-option
- :argument "-L"
- :reader 'magit-read-file-trace)
-
-(defun magit-read-file-trace (&rest _ignored)
- (let ((file (magit-read-file-from-rev "HEAD" "File"))
- (trace (magit-read-string "Trace")))
- (concat trace ":" file)))
-
-;;;; Setup Commands
-
-(defvar magit-log-read-revs-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map crm-local-completion-map)
- (define-key map "\s" 'self-insert-command)
- map))
-
-(defun magit-log-read-revs (&optional use-current)
- (or (and use-current (--when-let (magit-get-current-branch) (list it)))
- (let ((collection (magit-list-refnames nil t)))
- (split-string
- (magit-completing-read-multiple "Log rev,s" collection
- "\\(\\.\\.\\.?\\|[, ]\\)"
- (or (magit-branch-or-commit-at-point)
- (unless use-current
- (magit-get-previous-branch)))
- 'magit-revision-history
- magit-log-read-revs-map)
- "[, ]" t))))
-
-(defun magit-log-read-pattern (option)
- "Read a string from the user to pass as parameter to OPTION."
- (magit-read-string (format "Type a pattern to pass to %s" option)))
-
-;;;###autoload
-(defun magit-log-current (revs &optional args files)
- "Show log for the current branch.
-When `HEAD' is detached or with a prefix argument show log for
-one or more revs read from the minibuffer."
- (interactive (cons (magit-log-read-revs t)
- (magit-log-arguments)))
- (magit-log-setup-buffer revs args files))
-
-;;;###autoload
-(defun magit-log-other (revs &optional args files)
- "Show log for one or more revs read from the minibuffer.
-The user can input any revision or revisions separated by a
-space, or even ranges, but only branches and tags, and a
-representation of the commit at point, are available as
-completion candidates."
- (interactive (cons (magit-log-read-revs)
- (magit-log-arguments)))
- (magit-log-setup-buffer revs args files))
-
-;;;###autoload
-(defun magit-log-head (&optional args files)
- "Show log for `HEAD'."
- (interactive (magit-log-arguments))
- (magit-log-setup-buffer (list "HEAD") args files))
-
-;;;###autoload
-(defun magit-log-branches (&optional args files)
- "Show log for all local branches and `HEAD'."
- (interactive (magit-log-arguments))
- (magit-log-setup-buffer (if (magit-get-current-branch)
- (list "--branches")
- (list "HEAD" "--branches"))
- args files))
-
-;;;###autoload
-(defun magit-log-matching-branches (pattern &optional args files)
- "Show log for all branches matching PATTERN and `HEAD'."
- (interactive (cons (magit-log-read-pattern "--branches") (magit-log-arguments)))
- (magit-log-setup-buffer
- (list "HEAD" (format "--branches=%s" pattern))
- args files))
-
-;;;###autoload
-(defun magit-log-matching-tags (pattern &optional args files)
- "Show log for all tags matching PATTERN and `HEAD'."
- (interactive (cons (magit-log-read-pattern "--tags") (magit-log-arguments)))
- (magit-log-setup-buffer
- (list "HEAD" (format "--tags=%s" pattern))
- args files))
-
-;;;###autoload
-(defun magit-log-all-branches (&optional args files)
- "Show log for all local and remote branches and `HEAD'."
- (interactive (magit-log-arguments))
- (magit-log-setup-buffer (if (magit-get-current-branch)
- (list "--branches" "--remotes")
- (list "HEAD" "--branches" "--remotes"))
- args files))
-
-;;;###autoload
-(defun magit-log-all (&optional args files)
- "Show log for all references and `HEAD'."
- (interactive (magit-log-arguments))
- (magit-log-setup-buffer (if (magit-get-current-branch)
- (list "--all")
- (list "HEAD" "--all"))
- args files))
-
-;;;###autoload
-(defun magit-log-buffer-file (&optional follow beg end)
- "Show log for the blob or file visited in the current buffer.
-With a prefix argument or when `--follow' is an active log
-argument, then follow renames. When the region is active,
-restrict the log to the lines that the region touches."
- (interactive
- (cons current-prefix-arg
- (and (region-active-p)
- (magit-file-relative-name)
- (save-restriction
- (widen)
- (list (line-number-at-pos (region-beginning))
- (line-number-at-pos
- (let ((end (region-end)))
- (if (char-after end)
- end
- ;; Ensure that we don't get the line number
- ;; of a trailing newline.
- (1- end)))))))))
- (require 'magit)
- (if-let ((file (magit-file-relative-name)))
- (magit-log-setup-buffer
- (list (or magit-buffer-refname
- (magit-get-current-branch)
- "HEAD"))
- (let ((args (car (magit-log-arguments))))
- (when (and follow (not (member "--follow" args)))
- (push "--follow" args))
- (when (and (file-regular-p
- (expand-file-name file (magit-toplevel)))
- beg end)
- (setq args (cons (format "-L%s,%s:%s" beg end file)
- (cl-delete "-L" args :test
- 'string-prefix-p)))
- (setq file nil))
- args)
- (and file (list file))
- magit-log-buffer-file-locked)
- (user-error "Buffer isn't visiting a file")))
-
-;;;###autoload
-(defun magit-log-trace-definition (file fn rev)
- "Show log for the definition at point."
- (interactive (list (or (magit-file-relative-name)
- (user-error "Buffer isn't visiting a file"))
- (or (funcall magit-log-trace-definition-function)
- (user-error "No function at point found"))
- (or magit-buffer-refname
- (magit-get-current-branch)
- "HEAD")))
- (require 'magit)
- (magit-log-setup-buffer
- (list rev)
- (cons (format "-L:%s%s:%s"
- (replace-regexp-in-string ":" "\\:" (regexp-quote fn) nil t)
- (if (derived-mode-p 'lisp-mode 'emacs-lisp-mode)
- ;; Git doesn't treat "-" the same way as
- ;; "_", leading to false-positives such as
- ;; "foo-suffix" being considered a match
- ;; for "foo". Wing it.
- "\\( \\|$\\)"
- ;; We could use "\\b" here, but since Git
- ;; already does something equivalent, that
- ;; isn't necessary.
- "")
- file)
- (cl-delete "-L" (car (magit-log-arguments))
- :test 'string-prefix-p))
- nil magit-log-buffer-file-locked))
-
-(defun magit-diff-trace-definition ()
- "Show log for the definition at point in a diff."
- (interactive)
- (pcase-let ((`(,buf ,pos) (magit-diff-visit-file--noselect)))
- (magit--with-temp-position buf pos
- (call-interactively #'magit-log-trace-definition))))
-
-;;;###autoload
-(defun magit-log-merged (commit branch &optional args files)
- "Show log for the merge of COMMIT into BRANCH.
-
-More precisely, find merge commit M that brought COMMIT into
-BRANCH, and show the log of the range \"M^1..M\". If COMMIT is
-directly on BRANCH, then show approximately twenty surrounding
-commits instead.
-
-This command requires git-when-merged, which is available from
-https://github.com/mhagger/git-when-merged."
- (interactive
- (append (let ((commit (magit-read-branch-or-commit "Commit")))
- (list commit
- (magit-read-other-branch "Merged into" commit)))
- (magit-log-arguments)))
- (unless (executable-find "git-when-merged")
- (user-error "This command requires git-when-merged (%s)"
- "https://github.com/mhagger/git-when-merged"))
- (let (exit m)
- (with-temp-buffer
- (save-excursion
- (setq exit (magit-process-file
- magit-git-executable nil t nil
- "when-merged" "-c"
- "--abbrev" (number-to-string (magit-abbrev-length))
- commit branch)))
- (setq m (buffer-substring-no-properties (point) (line-end-position))))
- (if (zerop exit)
- (magit-log-setup-buffer (list (format "%s^1..%s" m m))
- args files nil commit)
- (setq m (string-trim-left (substring m (string-match " " m))))
- (if (equal m "Commit is directly on this branch.")
- (let* ((from (concat commit "~10"))
- (to (- (car (magit-rev-diff-count branch commit)) 10))
- (to (if (<= to 0)
- branch
- (format "%s~%s" branch to))))
- (unless (magit-rev-verify-commit from)
- (setq from (magit-git-string "rev-list" "--max-parents=0"
- commit)))
- (magit-log-setup-buffer (list (concat from ".." to))
- (cons "--first-parent" args)
- files nil commit))
- (user-error "Could not find when %s was merged into %s: %s"
- commit branch m)))))
-
-;;;; Limit Commands
-
-(defun magit-log-toggle-commit-limit ()
- "Toggle the number of commits the current log buffer is limited to.
-If the number of commits is currently limited, then remove that
-limit. Otherwise set it to 256."
- (interactive)
- (magit-log-set-commit-limit (lambda (&rest _) nil)))
-
-(defun magit-log-double-commit-limit ()
- "Double the number of commits the current log buffer is limited to."
- (interactive)
- (magit-log-set-commit-limit '*))
-
-(defun magit-log-half-commit-limit ()
- "Half the number of commits the current log buffer is limited to."
- (interactive)
- (magit-log-set-commit-limit '/))
-
-(defun magit-log-set-commit-limit (fn)
- (let* ((val magit-buffer-log-args)
- (arg (--first (string-match "^-n\\([0-9]+\\)?$" it) val))
- (num (and arg (string-to-number (match-string 1 arg))))
- (num (if num (funcall fn num 2) 256)))
- (setq val (delete arg val))
- (setq magit-buffer-log-args
- (if (and num (> num 0))
- (cons (format "-n%i" num) val)
- val)))
- (magit-refresh))
-
-(defun magit-log-get-commit-limit ()
- (--when-let (--first (string-match "^-n\\([0-9]+\\)?$" it)
- magit-buffer-log-args)
- (string-to-number (match-string 1 it))))
-
-;;;; Mode Commands
-
-(defun magit-log-bury-buffer (&optional arg)
- "Bury the current buffer or the revision buffer in the same frame.
-Like `magit-mode-bury-buffer' (which see) but with a negative
-prefix argument instead bury the revision buffer, provided it
-is displayed in the current frame."
- (interactive "p")
- (if (< arg 0)
- (let* ((buf (magit-get-mode-buffer 'magit-revision-mode))
- (win (and buf (get-buffer-window buf (selected-frame)))))
- (if win
- (with-selected-window win
- (with-current-buffer buf
- (magit-mode-bury-buffer (> (abs arg) 1))))
- (user-error "No revision buffer in this frame")))
- (magit-mode-bury-buffer (> arg 1))))
-
-;;;###autoload
-(defun magit-log-move-to-parent (&optional n)
- "Move to the Nth parent of the current commit."
- (interactive "p")
- (when (derived-mode-p 'magit-log-mode)
- (when (magit-section-match 'commit)
- (let* ((section (magit-current-section))
- (parent-rev (format "%s^%s" (oref section value) (or n 1))))
- (if-let ((parent-hash (magit-rev-parse "--short" parent-rev)))
- (if-let ((parent (--first (equal (oref it value)
- parent-hash)
- (magit-section-siblings section 'next))))
- (magit-section-goto parent)
- (user-error
- (substitute-command-keys
- (concat "Parent " parent-hash " not found. Try typing "
- "\\[magit-log-double-commit-limit] first"))))
- (user-error "Parent %s does not exist" parent-rev))))))
-
-;;;; 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)
- (with-current-buffer (get-buffer-create "*magit-shortlog*")
- (erase-buffer)
- (save-excursion
- (magit-git-insert "shortlog" args rev))
- (switch-to-buffer-other-window (current-buffer))))
-
-;;;###autoload
-(defun magit-shortlog-since (rev args)
- "Show a history summary for commits since REV."
- (interactive
- (list (magit-read-branch-or-commit "Shortlog since" (magit-get-current-tag))
- (transient-args 'magit-shortlog)))
- (magit-git-shortlog (concat rev "..") args))
-
-;;;###autoload
-(defun magit-shortlog-range (rev-or-range args)
- "Show a history summary for commit or range REV-OR-RANGE."
- (interactive
- (list (magit-read-range-or-commit "Shortlog for revision or range")
- (transient-args 'magit-shortlog)))
- (magit-git-shortlog rev-or-range args))
-
-;;; Log Mode
-
-(defvar magit-log-disable-graph-hack-args
- '("-G" "--grep" "--author")
- "Arguments which disable the graph speedup hack.")
-
-(defvar magit-log-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map "\C-c\C-b" 'magit-go-backward)
- (define-key map "\C-c\C-f" 'magit-go-forward)
- (define-key map "\C-c\C-n" 'magit-log-move-to-parent)
- (define-key map "=" 'magit-log-toggle-commit-limit)
- (define-key map "+" 'magit-log-double-commit-limit)
- (define-key map "-" 'magit-log-half-commit-limit)
- (define-key map "q" 'magit-log-bury-buffer)
- map)
- "Keymap for `magit-log-mode'.")
-
-(define-derived-mode magit-log-mode magit-mode "Magit Log"
- "Mode for looking at Git log.
-
-This mode is documented in info node `(magit)Log Buffer'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
-to visit the commit at point.
-
-Type \\[magit-branch] to see available branch commands.
-Type \\[magit-merge] to merge the branch or commit at point.
-Type \\[magit-cherry-pick] to apply the commit at point.
-Type \\[magit-reset] to reset `HEAD' to the commit at point.
-
-\\{magit-log-mode-map}"
- :group 'magit-log
- (hack-dir-local-variables-non-file-buffer)
- (setq imenu-prev-index-position-function
- 'magit-imenu--log-prev-index-position-function)
- (setq imenu-extract-index-name-function
- 'magit-imenu--log-extract-index-name-function))
-
-(put 'magit-log-mode 'magit-log-default-arguments
- '("--graph" "-n256" "--decorate"))
-
-(defun magit-log-setup-buffer (revs args files &optional locked focus)
- (require 'magit)
- (with-current-buffer
- (magit-setup-buffer #'magit-log-mode locked
- (magit-buffer-revisions revs)
- (magit-buffer-log-args args)
- (magit-buffer-log-files files))
- (when (if focus
- (magit-log-goto-commit-section focus)
- (magit-log-goto-same-commit))
- (magit-section-update-highlight))
- (current-buffer)))
-
-(defun magit-log-refresh-buffer ()
- (let ((revs magit-buffer-revisions)
- (args magit-buffer-log-args)
- (files magit-buffer-log-files))
- (magit-set-header-line-format
- (funcall magit-log-header-line-function revs args files))
- (if (= (length files) 1)
- (unless (magit-file-tracked-p (car files))
- (setq args (cons "--full-history" args)))
- (setq args (remove "--follow" args)))
- (when (and (car magit-log-remove-graph-args)
- (--any-p (string-match-p
- (concat "^" (regexp-opt magit-log-remove-graph-args)) it)
- args))
- (setq args (remove "--graph" args)))
- (unless (member "--graph" args)
- (setq args (remove "--color" args)))
- (when-let ((limit (magit-log-get-commit-limit))
- (limit (* 2 limit)) ; increase odds for complete graph
- (count (and (= (length revs) 1)
- (> limit 1024) ; otherwise it's fast enough
- (setq revs (car revs))
- (not (string-match-p "\\.\\." revs))
- (not (member revs '("--all" "--branches")))
- (-none-p (lambda (arg)
- (--any-p (string-prefix-p it arg)
- magit-log-disable-graph-hack-args))
- args)
- (magit-git-string "rev-list" "--count"
- "--first-parent" args revs))))
- (setq revs (if (< (string-to-number count) limit)
- revs
- (format "%s~%s..%s" revs limit revs))))
- (magit-insert-section (logbuf)
- (magit-insert-log revs args files))))
-
-(cl-defmethod magit-buffer-value (&context (major-mode magit-log-mode))
- (append magit-buffer-revisions
- (if (and magit-buffer-revisions magit-buffer-log-files)
- (cons "--" magit-buffer-log-files)
- magit-buffer-log-files)))
-
-(defun magit-log-header-line-arguments (revs args files)
- "Return string describing some of the used arguments."
- (mapconcat (lambda (arg)
- (if (string-match-p " " arg)
- (prin1 arg)
- arg))
- `("git" "log" ,@args ,@revs "--" ,@files)
- " "))
-
-(defun magit-log-header-line-sentence (revs args files)
- "Return string containing all arguments."
- (concat "Commits in "
- (mapconcat #'identity revs " ")
- (and (member "--reverse" args)
- " in reverse")
- (and files (concat " touching "
- (mapconcat 'identity files " ")))
- (--some (and (string-prefix-p "-L" it)
- (concat " " it))
- args)))
-
-(defun magit-insert-log (revs &optional args files)
- "Insert a log section.
-Do not add this to a hook variable."
- (let ((magit-git-global-arguments
- (remove "--literal-pathspecs" magit-git-global-arguments)))
- (magit-git-wash (apply-partially #'magit-log-wash-log 'log)
- "log"
- (format "--format=%s%%h%%x0c%s%%x0c%s%%x0c%%aN%%x0c%s%%x0c%%s%s"
- (if (and (member "--left-right" args)
- (not (member "--graph" args)))
- "%m "
- "")
- (if (member "--decorate" args) "%D" "")
- (if (member "--show-signature" args)
- (progn (setq args (remove "--show-signature" args)) "%G?")
- "")
- (if magit-log-margin-show-committer-date "%ct" "%at")
- (if (member "++header" args)
- (if (member "--graph" (setq args (remove "++header" args)))
- (concat "\n" magit-log-revision-headers-format "\n")
- (concat "\n\1e" magit-log-revision-headers-format "\1e\n"))
- ""))
- (progn
- (--when-let (--first (string-match "^\\+\\+order=\\(.+\\)$" it) args)
- (setq args (cons (format "--%s-order" (match-string 1 it))
- (remove it args))))
- (when (member "--decorate" args)
- (setq args (cons "--decorate=full" (remove "--decorate" args))))
- (when (member "--reverse" args)
- (setq args (remove "--graph" args)))
- args)
- "--use-mailmap" "--no-prefix" revs "--" files)))
-
-(defvar magit-commit-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-show-commit)
- (define-key map "a" 'magit-cherry-apply)
- map)
- "Keymap for `commit' sections.")
-
-(defvar magit-module-commit-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-show-commit)
- map)
- "Keymap for `module-commit' sections.")
-
-(defconst magit-log-heading-re
- ;; Note: A form feed instead of a null byte is used as the delimiter
- ;; because using the latter interferes with the graph prefix when
- ;; ++header is used.
- (concat "^"
- "\\(?4:[-_/|\\*o<>. ]*\\)" ; graph
- "\\(?1:[0-9a-fA-F]+\\)?\f" ; sha1
- "\\(?3:[^\f\n]+\\)?\f" ; refs
- "\\(?7:[BGUXYREN]\\)?\f" ; gpg
- "\\(?5:[^\f\n]*\\)\f" ; author
- ;; Note: Date is optional because, prior to Git v2.19.0,
- ;; `git rebase -i --root` corrupts the root's author date.
- "\\(?6:[^\f\n]*\\)\f" ; date
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-cherry-re
- (concat "^"
- "\\(?8:[-+]\\) " ; cherry
- "\\(?1:[0-9a-fA-F]+\\) " ; sha1
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-module-re
- (concat "^"
- "\\(?:\\(?11:[<>]\\) \\)?" ; side
- "\\(?1:[0-9a-fA-F]+\\) " ; sha1
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-bisect-vis-re
- (concat "^"
- "\\(?4:[-_/|\\*o<>. ]*\\)" ; graph
- "\\(?1:[0-9a-fA-F]+\\)?\0" ; sha1
- "\\(?3:[^\0\n]+\\)?\0" ; refs
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-bisect-log-re
- (concat "^# "
- "\\(?3:bad:\\|skip:\\|good:\\) " ; "refs"
- "\\[\\(?1:[^]\n]+\\)\\] " ; sha1
- "\\(?2:.*\\)$")) ; msg
-
-(defconst magit-log-reflog-re
- (concat "^"
- "\\(?1:[^\0\n]+\\)\0" ; sha1
- "\\(?5:[^\0\n]*\\)\0" ; author
- "\\(?:\\(?:[^@\n]+@{\\(?6:[^}\n]+\\)}\0" ; date
- "\\(?10:merge \\|autosave \\|restart \\|[^:\n]+: \\)?" ; refsub
- "\\(?2:.*\\)?\\)\\|\0\\)$")) ; msg
-
-(defconst magit-reflog-subject-re
- (concat "\\(?1:[^ ]+\\) ?" ; command
- "\\(?2:\\(?: ?-[^ ]+\\)+\\)?" ; option
- "\\(?: ?(\\(?3:[^)]+\\))\\)?")) ; type
-
-(defconst magit-log-stash-re
- (concat "^"
- "\\(?1:[^\0\n]+\\)\0" ; "sha1"
- "\\(?5:[^\0\n]*\\)\0" ; author
- "\\(?6:[^\0\n]+\\)\0" ; date
- "\\(?2:.*\\)$")) ; msg
-
-(defvar magit-log-count nil)
-
-(defvar magit-log-format-message-function 'magit-log-propertize-keywords)
-
-(defun magit-log-wash-log (style args)
- (setq args (-flatten args))
- (when (and (member "--graph" args)
- (member "--color" args))
- (let ((ansi-color-apply-face-function
- (lambda (beg end face)
- (put-text-property beg end 'font-lock-face
- (or face 'magit-log-graph)))))
- (ansi-color-apply-on-region (point-min) (point-max))))
- (when (eq style 'cherry)
- (reverse-region (point-min) (point-max)))
- (let ((magit-log-count 0))
- (when (looking-at "^\\.\\.\\.")
- (magit-delete-line))
- (magit-wash-sequence (apply-partially 'magit-log-wash-rev style
- (magit-abbrev-length)))
- (if (derived-mode-p 'magit-log-mode 'magit-reflog-mode)
- (when (eq magit-log-count (magit-log-get-commit-limit))
- (magit-insert-section (longer)
- (insert-text-button
- (substitute-command-keys
- (format "Type \\<%s>\\[%s] to show more history"
- 'magit-log-mode-map
- 'magit-log-double-commit-limit))
- 'action (lambda (_button)
- (magit-log-double-commit-limit))
- 'follow-link t
- 'mouse-face 'magit-section-highlight)))
- (insert ?\n))))
-
-(cl-defun magit-log-wash-rev (style abbrev)
- (when (derived-mode-p 'magit-log-mode 'magit-reflog-mode)
- (cl-incf magit-log-count))
- (looking-at (pcase style
- (`log magit-log-heading-re)
- (`cherry magit-log-cherry-re)
- (`module magit-log-module-re)
- (`reflog magit-log-reflog-re)
- (`stash magit-log-stash-re)
- (`bisect-vis magit-log-bisect-vis-re)
- (`bisect-log magit-log-bisect-log-re)))
- (magit-bind-match-strings
- (hash msg refs graph author date gpg cherry _ refsub side) nil
- (setq msg (substring-no-properties msg))
- (when refs
- (setq refs (substring-no-properties refs)))
- (let ((align (or (eq style 'cherry)
- (not (member "--stat" magit-buffer-log-args))))
- (non-graph-re (if (eq style 'bisect-vis)
- magit-log-bisect-vis-re
- magit-log-heading-re)))
- (magit-delete-line)
- ;; If the reflog entries have been pruned, the output of `git
- ;; reflog show' includes a partial line that refers to the hash
- ;; of the youngest expired reflog entry.
- (when (and (eq style 'reflog) (not date))
- (cl-return-from magit-log-wash-rev t))
- (magit-insert-section section (commit hash)
- (pcase style
- (`stash (oset section type 'stash))
- (`module (oset section type 'module-commit))
- (`bisect-log (setq hash (magit-rev-parse "--short" hash))))
- (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 (propertize hash 'font-lock-face 'magit-hash) ?\s))
- (when graph
- (insert graph))
- (unless align
- (insert (propertize hash 'font-lock-face 'magit-hash) ?\s))
- (when (and refs (not magit-log-show-refname-after-summary))
- (insert (magit-format-ref-labels refs) ?\s))
- (when (eq style 'reflog)
- (insert (format "%-2s " (1- magit-log-count)))
- (when refsub
- (insert (magit-reflog-format-subject
- (substring refsub 0 (if (string-match-p ":" refsub) -2 -1))))))
- (when msg
- (when gpg
- (setq msg (propertize msg 'font-lock-face
- (pcase (aref gpg 0)
- (?G 'magit-signature-good)
- (?B 'magit-signature-bad)
- (?U 'magit-signature-untrusted)
- (?X 'magit-signature-expired)
- (?Y 'magit-signature-expired-key)
- (?R 'magit-signature-revoked)
- (?E 'magit-signature-error)))))
- (insert (funcall magit-log-format-message-function hash msg)))
- (when (and refs magit-log-show-refname-after-summary)
- (insert ?\s)
- (insert (magit-format-ref-labels refs)))
- (insert ?\n)
- (when (memq style '(log reflog stash))
- (goto-char (line-beginning-position))
- (when (and refsub
- (string-match "\\`\\([^ ]\\) \\+\\(..\\)\\(..\\)" date))
- (setq date (+ (string-to-number (match-string 1 date))
- (* (string-to-number (match-string 2 date)) 60 60)
- (* (string-to-number (match-string 3 date)) 60))))
- (save-excursion
- (backward-char)
- (magit-log-format-margin hash author date)))
- (when (and (eq style 'cherry)
- (magit-buffer-margin-p))
- (save-excursion
- (backward-char)
- (apply #'magit-log-format-margin hash
- (split-string (magit-rev-format "%aN%x00%ct" hash) "\0"))))
- (when (and graph
- (not (eobp))
- (not (looking-at non-graph-re)))
- (when (looking-at "\1e")
- (magit-insert-heading)
- (delete-char 1)
- (magit-insert-section (commit-header)
- (forward-line)
- (magit-insert-heading)
- (re-search-forward "\1e")
- (backward-delete-char 1)
- (forward-char)
- (insert ?\n))
- (delete-char 1))
- (if (looking-at "^\\(---\\|\n\s\\|\ndiff\\)")
- (let ((limit (save-excursion
- (and (re-search-forward non-graph-re nil t)
- (match-beginning 0)))))
- (unless (oref magit-insert-section--current content)
- (magit-insert-heading))
- (delete-char (if (looking-at "\n") 1 4))
- (magit-diff-wash-diffs (list "--stat") limit))
- (when align
- (setq align (make-string (1+ abbrev) ? )))
- (when (and (not (eobp)) (not (looking-at non-graph-re)))
- (when align
- (setq align (make-string (1+ abbrev) ? )))
- (while (and (not (eobp)) (not (looking-at non-graph-re)))
- (when align
- (save-excursion (insert align)))
- (magit-make-margin-overlay)
- (forward-line))
- ;; When `--format' is used and its value isn't one of the
- ;; predefined formats, then `git-log' does not insert a
- ;; separator line.
- (save-excursion
- (forward-line -1)
- (looking-at "[-_/|\\*o<>. ]*"))
- (setq graph (match-string 0))
- (unless (string-match-p "[/\\.]" graph)
- (insert graph ?\n))))))))
- t)
-
-(defun magit-log-propertize-keywords (_rev msg)
- (let ((boundary 0))
- (when (string-match "^\\(?:squash\\|fixup\\)! " msg boundary)
- (setq boundary (match-end 0))
- (magit--put-face (match-beginning 0) (1- boundary)
- 'magit-keyword-squash msg))
- (when magit-log-highlight-keywords
- (while (string-match "\\[[^[]*?]" msg boundary)
- (setq boundary (match-end 0))
- (magit--put-face (match-beginning 0) boundary
- 'magit-keyword msg))))
- msg)
-
-(defun magit-log-maybe-show-more-commits (section)
- "When point is at the end of a log buffer, insert more commits.
-
-Log buffers end with a button \"Type + to show more history\".
-When the use of a section movement command puts point on that
-button, then automatically show more commits, without the user
-having to press \"+\".
-
-This function is called by `magit-section-movement-hook' and
-exists mostly for backward compatibility reasons."
- (when (and (eq (oref section type) 'longer)
- magit-log-auto-more)
- (magit-log-double-commit-limit)
- (forward-line -1)
- (magit-section-forward)))
-
-(add-hook 'magit-section-movement-hook #'magit-log-maybe-show-more-commits)
-
-(defvar magit--update-revision-buffer nil)
-
-(defun magit-log-maybe-update-revision-buffer (&optional _)
- "When moving in a log or cherry buffer, update the revision buffer.
-If there is no revision buffer in the same frame, then do nothing."
- (when (derived-mode-p 'magit-log-mode 'magit-cherry-mode 'magit-reflog-mode)
- (magit--maybe-update-revision-buffer)))
-
-(add-hook 'magit-section-movement-hook #'magit-log-maybe-update-revision-buffer)
-
-(defun magit--maybe-update-revision-buffer ()
- (when-let ((commit (magit-section-value-if 'commit))
- (buffer (magit-get-mode-buffer 'magit-revision-mode nil t)))
- (if magit--update-revision-buffer
- (setq magit--update-revision-buffer (list commit buffer))
- (setq magit--update-revision-buffer (list commit buffer))
- (run-with-idle-timer
- magit-update-other-window-delay nil
- (let ((args (with-current-buffer buffer
- (let ((magit-direct-use-buffer-arguments 'selected))
- (magit-show-commit--arguments)))))
- (lambda ()
- (pcase-let ((`(,rev ,buf) magit--update-revision-buffer))
- (setq magit--update-revision-buffer nil)
- (when (buffer-live-p buf)
- (let ((magit-display-buffer-noselect t))
- (apply #'magit-show-commit rev args))))
- (setq magit--update-revision-buffer nil)))))))
-
-(defvar magit--update-blob-buffer nil)
-
-(defun magit-log-maybe-update-blob-buffer (&optional _)
- "When moving in a log or cherry buffer, update the blob buffer.
-If there is no blob buffer in the same frame, then do nothing."
- (when (derived-mode-p 'magit-log-mode 'magit-cherry-mode 'magit-reflog-mode)
- (magit--maybe-update-blob-buffer)))
-
-(defun magit--maybe-update-blob-buffer ()
- (when-let ((commit (magit-section-value-if 'commit))
- (buffer (--first (with-current-buffer it
- (eq revert-buffer-function
- 'magit-revert-rev-file-buffer))
- (mapcar #'window-buffer (window-list)))))
- (if magit--update-blob-buffer
- (setq magit--update-blob-buffer (list commit buffer))
- (setq magit--update-blob-buffer (list commit buffer))
- (run-with-idle-timer
- magit-update-other-window-delay nil
- (lambda ()
- (pcase-let ((`(,rev ,buf) magit--update-blob-buffer))
- (setq magit--update-blob-buffer nil)
- (when (buffer-live-p buf)
- (with-selected-window (get-buffer-window buf)
- (with-current-buffer buf
- (save-excursion
- (magit-blob-visit (list (magit-rev-parse rev)
- (magit-file-relative-name
- magit-buffer-file-name))
- (line-number-at-pos))))))))))))
-
-(defun magit-log-goto-commit-section (rev)
- (let ((abbrev (magit-rev-format "%h" rev)))
- (when-let ((section (--first (equal (oref it value) abbrev)
- (oref magit-root-section children))))
- (goto-char (oref section start)))))
-
-(defun magit-log-goto-same-commit ()
- (when (and magit-previous-section
- (magit-section-match '(commit branch)
- magit-previous-section))
- (magit-log-goto-commit-section (oref magit-previous-section value))))
-
-;;; Log Margin
-
-(defvar-local magit-log-margin-show-shortstat nil)
-
-(defun magit-toggle-log-margin-style ()
- "Toggle between the regular and the shortstat margin style.
-The shortstat style is experimental and rather slow."
- (interactive)
- (setq magit-log-margin-show-shortstat
- (not magit-log-margin-show-shortstat))
- (magit-set-buffer-margin nil t))
-
-(defun magit-log-format-margin (rev author date)
- (when (magit-margin-option)
- (if magit-log-margin-show-shortstat
- (magit-log-format-shortstat-margin rev)
- (magit-log-format-author-margin author date))))
-
-(defun magit-log-format-author-margin (author date &optional previous-line)
- (pcase-let ((`(,_ ,style ,width ,details ,details-width)
- (or magit-buffer-margin
- (symbol-value (magit-margin-option)))))
- (magit-make-margin-overlay
- (concat (and details
- (concat (magit--propertize-face
- (truncate-string-to-width
- (or author "")
- details-width
- nil ?\s (make-string 1 magit-ellipsis))
- 'magit-log-author)
- " "))
- (magit--propertize-face
- (if (stringp style)
- (format-time-string
- style
- (seconds-to-time (string-to-number date)))
- (pcase-let* ((abbr (eq style 'age-abbreviated))
- (`(,cnt ,unit) (magit--age date abbr)))
- (format (format (if abbr "%%2i%%-%ic" "%%2i %%-%is")
- (- width (if details (1+ details-width) 0)))
- cnt unit)))
- 'magit-log-date))
- previous-line)))
-
-(defun magit-log-format-shortstat-margin (rev)
- (magit-make-margin-overlay
- (if-let ((line (and rev (magit-git-string
- "show" "--format=" "--shortstat" rev))))
- (if (string-match "\
-\\([0-9]+\\) files? changed, \
-\\(?:\\([0-9]+\\) insertions?(\\+)\\)?\
-\\(?:\\(?:, \\)?\\([0-9]+\\) deletions?(-)\\)?\\'" line)
- (magit-bind-match-strings (files add del) line
- (format
- "%5s %5s%4s"
- (if add
- (magit--propertize-face (format "%s+" add)
- 'magit-diffstat-added)
- "")
- (if del
- (magit--propertize-face (format "%s-" del)
- 'magit-diffstat-removed)
- "")
- files))
- "")
- "")))
-
-(defun magit-log-margin-width (style details details-width)
- (if magit-log-margin-show-shortstat
- 16
- (+ (if details (1+ details-width) 0)
- (if (stringp style)
- (length (format-time-string style))
- (+ 2 ; two digits
- 1 ; trailing space
- (if (eq style 'age-abbreviated)
- 1 ; single character
- (+ 1 ; gap after digits
- (apply #'max (--map (max (length (nth 1 it))
- (length (nth 2 it)))
- magit--age-spec)))))))))
-
-;;; Select Mode
-
-(defvar magit-log-select-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-log-mode-map)
- (define-key map "\C-c\C-b" 'undefined)
- (define-key map "\C-c\C-f" 'undefined)
- (define-key map "." 'magit-log-select-pick)
- (define-key map "e" 'magit-log-select-pick)
- (define-key map "\C-c\C-c" 'magit-log-select-pick)
- (define-key map "q" 'magit-log-select-quit)
- (define-key map "\C-c\C-k" 'magit-log-select-quit)
- map)
- "Keymap for `magit-log-select-mode'.")
-
-(put 'magit-log-select-pick :advertised-binding [?\C-c ?\C-c])
-(put 'magit-log-select-quit :advertised-binding [?\C-c ?\C-k])
-
-(define-derived-mode magit-log-select-mode magit-log-mode "Magit Select"
- "Mode for selecting a commit from history.
-
-This mode is documented in info node `(magit)Select from Log'.
-
-\\<magit-mode-map>\
-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.
-
-\\<magit-log-select-mode-map>\
-Type \\[magit-log-select-pick] to select the commit at point.
-Type \\[magit-log-select-quit] to abort without selecting a commit."
- :group 'magit-log
- (hack-dir-local-variables-non-file-buffer))
-
-(put 'magit-log-select-mode 'magit-log-default-arguments
- '("--graph" "-n256" "--decorate"))
-
-(defun magit-log-select-setup-buffer (revs args)
- (magit-setup-buffer #'magit-log-select-mode nil
- (magit-buffer-revisions revs)
- (magit-buffer-log-args args)))
-
-(defun magit-log-select-refresh-buffer ()
- (magit-insert-section (logbuf)
- (magit-insert-log magit-buffer-revisions
- magit-buffer-log-args)))
-
-(cl-defmethod magit-buffer-value (&context (major-mode magit-log-select-mode))
- magit-buffer-revisions)
-
-(defvar-local magit-log-select-pick-function nil)
-(defvar-local magit-log-select-quit-function nil)
-
-(defun magit-log-select (pick &optional msg quit branch args initial)
- (declare (indent defun))
- (unless initial
- (setq initial (magit-commit-at-point)))
- (magit-log-select-setup-buffer
- (or branch (magit-get-current-branch) "HEAD")
- (append args
- (car (magit-log--get-value 'magit-log-select-mode
- magit-direct-use-buffer-arguments))))
- (when initial
- (magit-log-goto-commit-section initial))
- (setq magit-log-select-pick-function pick)
- (setq magit-log-select-quit-function quit)
- (when magit-log-select-show-usage
- (let ((pick (propertize (substitute-command-keys
- "\\[magit-log-select-pick]")
- 'font-lock-face
- 'magit-header-line-key))
- (quit (propertize (substitute-command-keys
- "\\[magit-log-select-quit]")
- 'font-lock-face
- 'magit-header-line-key)))
- (setq msg (format-spec
- (if msg
- (if (string-suffix-p "," msg)
- (concat msg " or %q to abort")
- msg)
- "Type %p to select commit at point, or %q to abort")
- `((?p . ,pick)
- (?q . ,quit)))))
- (magit--add-face-text-property
- 0 (length msg) 'magit-header-line-log-select t msg)
- (when (memq magit-log-select-show-usage '(both header-line))
- (magit-set-header-line-format msg))
- (when (memq magit-log-select-show-usage '(both echo-area))
- (message "%s" (substring-no-properties msg)))))
-
-(defun magit-log-select-pick ()
- "Select the commit at point and act on it.
-Call `magit-log-select-pick-function' with the selected
-commit as argument."
- (interactive)
- (let ((fun magit-log-select-pick-function)
- (rev (magit-commit-at-point)))
- (magit-mode-bury-buffer 'kill)
- (funcall fun rev)))
-
-(defun magit-log-select-quit ()
- "Abort selecting a commit, don't act on any commit."
- (interactive)
- (magit-mode-bury-buffer 'kill)
- (when magit-log-select-quit-function
- (funcall magit-log-select-quit-function)))
-
-;;; Cherry Mode
-
-(defvar magit-cherry-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map "q" 'magit-log-bury-buffer)
- (define-key map "L" 'magit-margin-settings)
- map)
- "Keymap for `magit-cherry-mode'.")
-
-(define-derived-mode magit-cherry-mode magit-mode "Magit Cherry"
- "Mode for looking at commits not merged upstream.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
-to visit the commit at point.
-
-Type \\[magit-cherry-pick] to apply the commit at point.
-
-\\{magit-cherry-mode-map}"
- :group 'magit-log
- (hack-dir-local-variables-non-file-buffer)
- (setq imenu-create-index-function
- 'magit-imenu--cherry-create-index-function))
-
-(defun magit-cherry-setup-buffer (head upstream)
- (magit-setup-buffer #'magit-cherry-mode nil
- (magit-buffer-refname head)
- (magit-buffer-upstream upstream)
- (magit-buffer-range (concat upstream ".." head))))
-
-(defun magit-cherry-refresh-buffer ()
- (magit-insert-section (cherry)
- (magit-run-section-hook 'magit-cherry-sections-hook)))
-
-(cl-defmethod magit-buffer-value (&context (major-mode magit-cherry-mode))
- magit-buffer-range)
-
-;;;###autoload
-(defun magit-cherry (head upstream)
- "Show commits in a branch that are not merged in the upstream branch."
- (interactive
- (let ((head (magit-read-branch "Cherry head")))
- (list head (magit-read-other-branch "Cherry upstream" head
- (magit-get-upstream-branch head)))))
- (require 'magit)
- (magit-cherry-setup-buffer head upstream))
-
-(defun magit-insert-cherry-headers ()
- "Insert headers appropriate for `magit-cherry-mode' buffers."
- (let ((branch (propertize magit-buffer-refname
- 'font-lock-face 'magit-branch-local))
- (upstream (propertize magit-buffer-upstream 'font-lock-face
- (if (magit-local-branch-p magit-buffer-upstream)
- 'magit-branch-local
- 'magit-branch-remote))))
- (magit-insert-head-branch-header branch)
- (magit-insert-upstream-branch-header branch upstream "Upstream: ")
- (insert ?\n)))
-
-(defun magit-insert-cherry-commits ()
- "Insert commit sections into a `magit-cherry-mode' buffer."
- (magit-insert-section (cherries)
- (magit-insert-heading "Cherry commits:")
- (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry)
- "cherry" "-v" "--abbrev"
- magit-buffer-upstream
- magit-buffer-refname)))
-
-;;; Log Sections
-;;;; Standard Log Sections
-
-(defvar magit-unpulled-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-diff-dwim)
- map)
- "Keymap for `unpulled' sections.")
-
-(magit-define-section-jumper magit-jump-to-unpulled-from-upstream
- "Unpulled from @{upstream}" unpulled "..@{upstream}")
-
-(defun magit-insert-unpulled-from-upstream ()
- "Insert commits that haven't been pulled from the upstream yet."
- (when-let ((upstream (magit-get-upstream-branch)))
- (magit-insert-section (unpulled "..@{upstream}" t)
- (magit-insert-heading
- (format (propertize "Unpulled from %s."
- 'font-lock-face 'magit-section-heading)
- upstream))
- (magit-insert-log "..@{upstream}" magit-buffer-log-args)
- (magit-log-insert-child-count))))
-
-(magit-define-section-jumper magit-jump-to-unpulled-from-pushremote
- "Unpulled from <push-remote>" unpulled
- (concat ".." (magit-get-push-branch)))
-
-(defun magit-insert-unpulled-from-pushremote ()
- "Insert commits that haven't been pulled from the push-remote yet."
- (--when-let (magit-get-push-branch)
- (when (magit--insert-pushremote-log-p)
- (magit-insert-section (unpulled (concat ".." it) t)
- (magit-insert-heading
- (format (propertize "Unpulled from %s."
- 'font-lock-face 'magit-section-heading)
- (propertize it 'font-lock-face 'magit-branch-remote)))
- (magit-insert-log (concat ".." it) magit-buffer-log-args)
- (magit-log-insert-child-count)))))
-
-(defvar magit-unpushed-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-diff-dwim)
- map)
- "Keymap for `unpushed' sections.")
-
-(magit-define-section-jumper magit-jump-to-unpushed-to-upstream
- "Unpushed to @{upstream}" unpushed "@{upstream}..")
-
-(defun magit-insert-unpushed-to-upstream-or-recent ()
- "Insert section showing unpushed or other recent commits.
-If an upstream is configured for the current branch and it is
-behind of the current branch, then show the commits that have
-not yet been pushed into the upstream branch. If no upstream is
-configured or if the upstream is not behind of the current branch,
-then show the last `magit-log-section-commit-count' commits."
- (let ((upstream (magit-get-upstream-branch)))
- (if (or (not upstream)
- (magit-rev-ancestor-p "HEAD" upstream))
- (magit-insert-recent-commits 'unpushed "@{upstream}..")
- (magit-insert-unpushed-to-upstream))))
-
-(defun magit-insert-unpushed-to-upstream ()
- "Insert commits that haven't been pushed to the upstream yet."
- (when (magit-git-success "rev-parse" "@{upstream}")
- (magit-insert-section (unpushed "@{upstream}..")
- (magit-insert-heading
- (format (propertize "Unmerged into %s."
- 'font-lock-face 'magit-section-heading)
- (magit-get-upstream-branch)))
- (magit-insert-log "@{upstream}.." magit-buffer-log-args)
- (magit-log-insert-child-count))))
-
-(defun magit-insert-recent-commits (&optional type value)
- "Insert section showing recent commits.
-Show the last `magit-log-section-commit-count' commits."
- (let* ((start (format "HEAD~%s" magit-log-section-commit-count))
- (range (and (magit-rev-verify start)
- (concat start "..HEAD"))))
- (magit-insert-section ((eval (or type 'recent))
- (or value range)
- t)
- (magit-insert-heading "Recent commits")
- (magit-insert-log range
- (cons (format "-n%d" magit-log-section-commit-count)
- (--remove (string-prefix-p "-n" it)
- magit-buffer-log-args))))))
-
-(magit-define-section-jumper magit-jump-to-unpushed-to-pushremote
- "Unpushed to <push-remote>" unpushed
- (concat (magit-get-push-branch) ".."))
-
-(defun magit-insert-unpushed-to-pushremote ()
- "Insert commits that haven't been pushed to the push-remote yet."
- (--when-let (magit-get-push-branch)
- (when (magit--insert-pushremote-log-p)
- (magit-insert-section (unpushed (concat it "..") t)
- (magit-insert-heading
- (format (propertize "Unpushed to %s."
- 'font-lock-face 'magit-section-heading)
- (propertize it 'font-lock-face 'magit-branch-remote)))
- (magit-insert-log (concat it "..") magit-buffer-log-args)
- (magit-log-insert-child-count)))))
-
-(defun magit--insert-pushremote-log-p ()
- (magit--with-refresh-cache 'magit--insert-pushremote-log-p
- (not (and (equal (magit-get-push-branch)
- (magit-get-upstream-branch))
- (or (memq 'magit-insert-unpulled-from-upstream
- magit-status-sections-hook)
- (memq 'magit-insert-unpulled-from-upstream-or-recent
- magit-status-sections-hook))))))
-
-(defun magit-log-insert-child-count ()
- (when magit-section-show-child-count
- (let ((count (length (oref magit-insert-section--current children))))
- (when (> count 0)
- (when (= count (magit-log-get-commit-limit))
- (setq count (format "%s+" count)))
- (save-excursion
- (goto-char (- (oref magit-insert-section--current content) 2))
- (insert (format " (%s)" count))
- (delete-char 1))))))
-
-;;;; Auxiliary Log Sections
-
-(defun magit-insert-unpulled-cherries ()
- "Insert section showing unpulled commits.
-Like `magit-insert-unpulled-from-upstream' but prefix each commit
-which has not been applied yet (i.e. a commit with a patch-id
-not shared with any local commit) with \"+\", and all others with
-\"-\"."
- (when (magit-git-success "rev-parse" "@{upstream}")
- (magit-insert-section (unpulled "..@{upstream}")
- (magit-insert-heading "Unpulled commits:")
- (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry)
- "cherry" "-v" (magit-abbrev-arg)
- (magit-get-current-branch) "@{upstream}"))))
-
-(defun magit-insert-unpushed-cherries ()
- "Insert section showing unpushed commits.
-Like `magit-insert-unpushed-to-upstream' but prefix each commit
-which has not been applied to upstream yet (i.e. a commit with
-a patch-id not shared with any upstream commit) with \"+\", and
-all others with \"-\"."
- (when (magit-git-success "rev-parse" "@{upstream}")
- (magit-insert-section (unpushed "@{upstream}..")
- (magit-insert-heading "Unpushed commits:")
- (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry)
- "cherry" "-v" (magit-abbrev-arg) "@{upstream}"))))
-
-;;; _
-(provide 'magit-log)
-;;; magit-log.el ends here
+++ /dev/null
-;;; magit-margin.el --- margins in Magit buffers -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for showing additional information
-;; in the margins of Magit buffers. Currently this is only used for
-;; commits, for which the committer date or age, and optionally the
-;; author name are shown.
-
-;;; Code:
-
-(require 'dash)
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit-section)
-(require 'magit-transient)
-(require 'magit-mode)
-
-(defgroup magit-margin nil
- "Information Magit displays in the margin.
-
-You can change the STYLE and AUTHOR-WIDTH of all `magit-*-margin'
-options to the same values by customizing `magit-log-margin'
-*before* `magit' is loaded. If you do that, then the respective
-values for the other options will default to what you have set
-for that variable. Likewise if you set `magit-log-margin's INIT
-to nil, then that is used in the default of all other options. But
-setting it to t, i.e. re-enforcing the default for that option,
-does not carry to other options."
- :link '(info-link "(magit)Log Margin")
- :group 'magit-log)
-
-(defvar-local magit-buffer-margin nil)
-(put 'magit-buffer-margin 'permanent-local t)
-
-(defvar-local magit-set-buffer-margin-refresh nil)
-
-(defvar magit--age-spec)
-
-;;; Commands
-
-(transient-define-prefix magit-margin-settings ()
- "Change what information is displayed in the margin."
- :info-manual "(magit) Log Margin"
- ["Margin"
- ("L" "Toggle visibility" magit-toggle-margin)
- ("l" "Cycle style" magit-cycle-margin-style)
- ("d" "Toggle details" magit-toggle-margin-details)
- ("v" "Change verbosity" magit-refs-set-show-commit-count
- :if-derived magit-refs-mode)])
-
-(defun magit-toggle-margin ()
- "Show or hide the Magit margin."
- (interactive)
- (unless (magit-margin-option)
- (user-error "Magit margin isn't supported in this buffer"))
- (setcar magit-buffer-margin (not (magit-buffer-margin-p)))
- (magit-set-buffer-margin))
-
-(defun magit-cycle-margin-style ()
- "Cycle style used for the Magit margin."
- (interactive)
- (unless (magit-margin-option)
- (user-error "Magit margin isn't supported in this buffer"))
- ;; This is only suitable for commit margins (there are not others).
- (setf (cadr magit-buffer-margin)
- (pcase (cadr magit-buffer-margin)
- (`age 'age-abbreviated)
- (`age-abbreviated
- (let ((default (cadr (symbol-value (magit-margin-option)))))
- (if (stringp default) default "%Y-%m-%d %H:%M ")))
- (_ 'age)))
- (magit-set-buffer-margin nil t))
-
-(defun magit-toggle-margin-details ()
- "Show or hide details in the Magit margin."
- (interactive)
- (unless (magit-margin-option)
- (user-error "Magit margin isn't supported in this buffer"))
- (setf (nth 3 magit-buffer-margin)
- (not (nth 3 magit-buffer-margin)))
- (magit-set-buffer-margin nil t))
-
-;;; Core
-
-(defun magit-buffer-margin-p ()
- (car magit-buffer-margin))
-
-(defun magit-margin-option ()
- (pcase major-mode
- (`magit-cherry-mode 'magit-cherry-margin)
- (`magit-log-mode 'magit-log-margin)
- (`magit-log-select-mode 'magit-log-select-margin)
- (`magit-reflog-mode 'magit-reflog-margin)
- (`magit-refs-mode 'magit-refs-margin)
- (`magit-stashes-mode 'magit-stashes-margin)
- (`magit-status-mode 'magit-status-margin)
- (`forge-notifications-mode 'magit-status-margin)))
-
-(defun magit-set-buffer-margin (&optional reset refresh)
- (when-let ((option (magit-margin-option)))
- (let* ((default (symbol-value option))
- (default-width (nth 2 default)))
- (when (or reset (not magit-buffer-margin))
- (setq magit-buffer-margin (copy-sequence default)))
- (pcase-let ((`(,enable ,style ,_width ,details ,details-width)
- magit-buffer-margin))
- (when (functionp default-width)
- (setf (nth 2 magit-buffer-margin)
- (funcall default-width style details details-width)))
- (dolist (window (get-buffer-window-list nil nil 0))
- (with-selected-window window
- (magit-set-window-margin window)
- (if enable
- (add-hook 'window-configuration-change-hook
- 'magit-set-window-margin nil t)
- (remove-hook 'window-configuration-change-hook
- 'magit-set-window-margin t))))
- (when (and enable (or refresh magit-set-buffer-margin-refresh))
- (magit-refresh-buffer))))))
-
-(defun magit-set-window-margin (&optional window)
- (when (or window (setq window (get-buffer-window)))
- (with-selected-window window
- (set-window-margins
- nil (car (window-margins))
- (and (magit-buffer-margin-p)
- (nth 2 magit-buffer-margin))))))
-
-(defun magit-make-margin-overlay (&optional string previous-line)
- (if previous-line
- (save-excursion
- (forward-line -1)
- (magit-make-margin-overlay string))
- ;; Don't put the overlay on the complete line to work around #1880.
- (let ((o (make-overlay (1+ (line-beginning-position))
- (line-end-position)
- nil t)))
- (overlay-put o 'evaporate t)
- (overlay-put o 'before-string
- (propertize "o" 'display
- (list (list 'margin 'right-margin)
- (or string " ")))))))
-
-(defun magit-maybe-make-margin-overlay ()
- (when (or (magit-section-match
- '(unpulled unpushed recent stashes local cherries)
- magit-insert-section--current)
- (and (eq major-mode 'magit-refs-mode)
- (magit-section-match
- '(remote commit tags)
- magit-insert-section--current)))
- (magit-make-margin-overlay nil t)))
-
-;;; Custom Support
-
-(defun magit-margin-set-variable (mode symbol value)
- (set-default symbol value)
- (message "Updating margins in %s buffers..." mode)
- (dolist (buffer (buffer-list))
- (with-current-buffer buffer
- (when (eq major-mode mode)
- (magit-set-buffer-margin t)
- (magit-refresh))))
- (message "Updating margins in %s buffers...done" mode))
-
-(defconst magit-log-margin--custom-type
- '(list (boolean :tag "Show margin initially")
- (choice :tag "Show committer"
- (string :tag "date using time-format" "%Y-%m-%d %H:%M ")
- (const :tag "date's age" age)
- (const :tag "date's age (abbreviated)" age-abbreviated))
- (const :tag "Calculate width using magit-log-margin-width"
- magit-log-margin-width)
- (boolean :tag "Show author name by default")
- (integer :tag "Show author name using width")))
-
-;;; Time Utilities
-
-(defvar magit--age-spec
- `((?Y "year" "years" ,(round (* 60 60 24 365.2425)))
- (?M "month" "months" ,(round (* 60 60 24 30.436875)))
- (?w "week" "weeks" ,(* 60 60 24 7))
- (?d "day" "days" ,(* 60 60 24))
- (?h "hour" "hours" ,(* 60 60))
- (?m "minute" "minutes" 60)
- (?s "second" "seconds" 1))
- "Time units used when formatting relative commit ages.
-
-The value is a list of time units, beginning with the longest.
-Each element has the form (CHAR UNIT UNITS SECONDS). UNIT is the
-time unit, UNITS is the plural of that unit. CHAR is a character
-abbreviation. And SECONDS is the number of seconds in one UNIT.
-
-This is defined as a variable to make it possible to use time
-units for a language other than English. It is not defined
-as an option, because most other parts of Magit are always in
-English.")
-
-(defun magit--age (date &optional abbreviate)
- (cl-labels ((fn (age spec)
- (pcase-let ((`(,char ,unit ,units ,weight) (car spec)))
- (let ((cnt (round (/ age weight 1.0))))
- (if (or (not (cdr spec))
- (>= (/ age weight) 1))
- (list cnt (cond (abbreviate char)
- ((= cnt 1) unit)
- (t units)))
- (fn age (cdr spec)))))))
- (fn (abs (- (float-time)
- (if (stringp date)
- (string-to-number date)
- date)))
- magit--age-spec)))
-
-;;; _
-(provide 'magit-margin)
-;;; magit-margin.el ends here
+++ /dev/null
-;;; magit-merge.el --- merge functionality -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements merge commands.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit)
-(require 'magit-diff)
-
-(declare-function magit-git-push "magit-push" (branch target args))
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-merge "magit" nil t)
-(transient-define-prefix magit-merge ()
- "Merge branches."
- :man-page "git-merge"
- :incompatible '(("--ff-only" "--no-ff"))
- ["Arguments"
- :if-not magit-merge-in-progress-p
- ("-f" "Fast-forward only" "--ff-only")
- ("-n" "No fast-forward" "--no-ff")
- (magit-merge:--strategy)
- (5 magit-merge:--strategy-option)
- (5 magit-diff:--diff-algorithm :argument "-Xdiff-algorithm=")
- (5 magit:--gpg-sign)]
- ["Actions"
- :if-not magit-merge-in-progress-p
- [("m" "Merge" magit-merge-plain)
- ("e" "Merge and edit message" magit-merge-editmsg)
- ("n" "Merge but don't commit" magit-merge-nocommit)
- ("a" "Absorb" magit-merge-absorb)]
- [("p" "Preview merge" magit-merge-preview)
- ""
- ("s" "Squash merge" magit-merge-squash)
- ("i" "Merge into" magit-merge-into)]]
- ["Actions"
- :if magit-merge-in-progress-p
- ("m" "Commit merge" magit-commit-create)
- ("a" "Abort merge" magit-merge-abort)])
-
-(defun magit-merge-arguments ()
- (transient-args 'magit-merge))
-
-(transient-define-argument magit-merge:--strategy ()
- :description "Strategy"
- :class 'transient-option
- ;; key for merge and rebase: "-s"
- ;; key for cherry-pick and revert: "=s"
- ;; shortarg for merge and rebase: "-s"
- ;; shortarg for cherry-pick and revert: none
- :key "-s"
- :argument "--strategy="
- :choices '("resolve" "recursive" "octopus" "ours" "subtree"))
-
-(transient-define-argument magit-merge:--strategy-option ()
- :description "Strategy Option"
- :class 'transient-option
- :key "-X"
- :argument "--strategy-option="
- :choices '("ours" "theirs" "patience"))
-
-;;;###autoload
-(defun magit-merge-plain (rev &optional args nocommit)
- "Merge commit REV into the current branch; using default message.
-
-Unless there are conflicts or a prefix argument is used create a
-merge commit using a generic commit message and without letting
-the user inspect the result. With a prefix argument pretend the
-merge failed to give the user the opportunity to inspect the
-merge.
-
-\(git merge --no-edit|--no-commit [ARGS] REV)"
- (interactive (list (magit-read-other-branch-or-commit "Merge")
- (magit-merge-arguments)
- current-prefix-arg))
- (magit-merge-assert)
- (magit-run-git-async "merge" (if nocommit "--no-commit" "--no-edit") args rev))
-
-;;;###autoload
-(defun magit-merge-editmsg (rev &optional args)
- "Merge commit REV into the current branch; and edit message.
-Perform the merge and prepare a commit message but let the user
-edit it.
-\n(git merge --edit --no-ff [ARGS] REV)"
- (interactive (list (magit-read-other-branch-or-commit "Merge")
- (magit-merge-arguments)))
- (magit-merge-assert)
- (cl-pushnew "--no-ff" args :test #'equal)
- (apply #'magit-run-git-with-editor "merge" "--edit"
- (append (delete "--ff-only" args)
- (list rev))))
-
-;;;###autoload
-(defun magit-merge-nocommit (rev &optional args)
- "Merge commit REV into the current branch; pretending it failed.
-Pretend the merge failed to give the user the opportunity to
-inspect the merge and change the commit message.
-\n(git merge --no-commit --no-ff [ARGS] REV)"
- (interactive (list (magit-read-other-branch-or-commit "Merge")
- (magit-merge-arguments)))
- (magit-merge-assert)
- (cl-pushnew "--no-ff" args :test #'equal)
- (magit-run-git-async "merge" "--no-commit" args rev))
-
-;;;###autoload
-(defun magit-merge-into (branch &optional args)
- "Merge the current branch into BRANCH and remove the former.
-
-Before merging, force push the source branch to its push-remote,
-provided the respective remote branch already exists, ensuring
-that the respective pull-request (if any) won't get stuck on some
-obsolete version of the commits that are being merged. Finally
-if `forge-branch-pullreq' was used to create the merged branch,
-branch, then also remove the respective remote branch."
- (interactive
- (list (magit-read-other-local-branch
- (format "Merge `%s' into"
- (or (magit-get-current-branch)
- (magit-rev-parse "HEAD")))
- nil
- (when-let ((upstream (magit-get-upstream-branch))
- (upstream (cdr (magit-split-branch-name upstream))))
- (and (magit-branch-p upstream) upstream)))
- (magit-merge-arguments)))
- (let ((current (magit-get-current-branch))
- (head (magit-rev-parse "HEAD")))
- (when (zerop (magit-call-git "checkout" branch))
- (if current
- (magit--merge-absorb current args)
- (magit-run-git-with-editor "merge" args head)))))
-
-;;;###autoload
-(defun magit-merge-absorb (branch &optional args)
- "Merge BRANCH into the current branch and remove the former.
-
-Before merging, force push the source branch to its push-remote,
-provided the respective remote branch already exists, ensuring
-that the respective pull-request (if any) won't get stuck on some
-obsolete version of the commits that are being merged. Finally
-if `forge-branch-pullreq' was used to create the merged branch,
-then also remove the respective remote branch."
- (interactive (list (magit-read-other-local-branch "Absorb branch")
- (magit-merge-arguments)))
- (magit--merge-absorb branch args))
-
-(defun magit--merge-absorb (branch args)
- (when (equal branch "master")
- (unless (yes-or-no-p
- "Do you really want to merge `master' into another branch? ")
- (user-error "Abort")))
- (if-let ((target (magit-get-push-branch branch t)))
- (progn
- (magit-git-push branch target (list "--force-with-lease"))
- (set-process-sentinel
- magit-this-process
- (lambda (process event)
- (when (memq (process-status process) '(exit signal))
- (if (not (zerop (process-exit-status process)))
- (magit-process-sentinel process event)
- (process-put process 'inhibit-refresh t)
- (magit-process-sentinel process event)
- (magit--merge-absorb-1 branch args))))))
- (magit--merge-absorb-1 branch args)))
-
-(defun magit--merge-absorb-1 (branch args)
- (if-let ((pr (magit-get "branch" branch "pullRequest")))
- (magit-run-git-async
- "merge" args "-m"
- (format "Merge branch '%s'%s [#%s]"
- branch
- (let ((current (magit-get-current-branch)))
- (if (equal current "master") "" (format " into %s" current)))
- pr)
- branch)
- (magit-run-git-async "merge" args "--no-edit" branch))
- (set-process-sentinel
- magit-this-process
- (lambda (process event)
- (when (memq (process-status process) '(exit signal))
- (if (> (process-exit-status process) 0)
- (magit-process-sentinel process event)
- (process-put process 'inhibit-refresh t)
- (magit-process-sentinel process event)
- (magit-branch-maybe-delete-pr-remote branch)
- (magit-branch-unset-pushRemote branch)
- (magit-run-git "branch" "-D" branch))))))
-
-;;;###autoload
-(defun magit-merge-squash (rev)
- "Squash commit REV into the current branch; don't create a commit.
-\n(git merge --squash REV)"
- (interactive (list (magit-read-other-branch-or-commit "Squash")))
- (magit-merge-assert)
- (magit-run-git-async "merge" "--squash" rev))
-
-;;;###autoload
-(defun magit-merge-preview (rev)
- "Preview result of merging REV into the current branch."
- (interactive (list (magit-read-other-branch-or-commit "Preview merge")))
- (magit-merge-preview-setup-buffer rev))
-
-;;;###autoload
-(defun magit-merge-abort ()
- "Abort the current merge operation.
-\n(git merge --abort)"
- (interactive)
- (unless (file-exists-p (magit-git-dir "MERGE_HEAD"))
- (user-error "No merge in progress"))
- (magit-confirm 'abort-merge)
- (magit-run-git-async "merge" "--abort"))
-
-(defun magit-checkout-stage (file arg)
- "During a conflict checkout and stage side, or restore conflict."
- (interactive
- (let ((file (magit-completing-read "Checkout file"
- (magit-tracked-files) nil nil nil
- 'magit-read-file-hist
- (magit-current-file))))
- (cond ((member file (magit-unmerged-files))
- (list file (magit-checkout-read-stage file)))
- ((yes-or-no-p (format "Restore conflicts in %s? " file))
- (list file "--merge"))
- (t
- (user-error "Quit")))))
- (pcase (cons arg (cddr (car (magit-file-status file))))
- ((or `("--ours" ?D ,_)
- `("--theirs" ,_ ?D))
- (magit-run-git "rm" "--" file))
- (_ (if (equal arg "--merge")
- ;; This fails if the file was deleted on one
- ;; side. And we cannot do anything about it.
- (magit-run-git "checkout" "--merge" "--" file)
- (magit-call-git "checkout" arg "--" file)
- (magit-run-git "add" "-u" "--" file)))))
-
-;;; Utilities
-
-(defun magit-merge-in-progress-p ()
- (file-exists-p (magit-git-dir "MERGE_HEAD")))
-
-(defun magit--merge-range (&optional head)
- (unless head
- (setq head (magit-get-shortname
- (car (magit-file-lines (magit-git-dir "MERGE_HEAD"))))))
- (and head
- (concat (magit-git-string "merge-base" "--octopus" "HEAD" head)
- ".." head)))
-
-(defun magit-merge-assert ()
- (or (not (magit-anything-modified-p t))
- (magit-confirm 'merge-dirty
- "Merging with dirty worktree is risky. Continue")))
-
-(defun magit-checkout-read-stage (file)
- (magit-read-char-case (format "For %s checkout: " file) t
- (?o "[o]ur stage" "--ours")
- (?t "[t]heir stage" "--theirs")
- (?c "[c]onflict" "--merge")))
-
-;;; Sections
-
-(defvar magit-unmerged-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-diff-dwim)
- map)
- "Keymap for `unmerged' sections.")
-
-(defun magit-insert-merge-log ()
- "Insert section for the on-going merge.
-Display the heads that are being merged.
-If no merge is in progress, do nothing."
- (when (magit-merge-in-progress-p)
- (let* ((heads (mapcar #'magit-get-shortname
- (magit-file-lines (magit-git-dir "MERGE_HEAD"))))
- (range (magit--merge-range (car heads))))
- (magit-insert-section (unmerged range)
- (magit-insert-heading
- (format "Merging %s:" (mapconcat #'identity heads ", ")))
- (magit-insert-log
- range
- (let ((args magit-buffer-log-args))
- (unless (member "--decorate=full" magit-buffer-log-args)
- (push "--decorate=full" args))
- args))))))
-
-;;; _
-(provide 'magit-merge)
-;;; magit-merge.el ends here
+++ /dev/null
-;;; magit-mode.el --- create and refresh Magit buffers -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements the abstract major-mode `magit-mode' from
-;; which almost all other Magit major-modes derive. The code in here
-;; is mostly concerned with creating and refreshing Magit buffers.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'transient)
-
-(require 'magit-section)
-(require 'magit-git)
-
-;; For `magit-display-buffer-fullcolumn-most-v1' from `git-commit'
-(defvar git-commit-mode)
-;; For `magit-refresh'
-(defvar magit-post-commit-hook-commands)
-(defvar magit-post-stage-hook-commands)
-(defvar magit-post-unstage-hook-commands)
-;; For `magit-refresh' and `magit-refresh-all'
-(declare-function magit-auto-revert-buffers "magit-autorevert" ())
-;; For `magit-refresh-buffer'
-(declare-function magit-process-unset-mode-line-error-status "magit-process" ())
-;; For `magit-refresh-get-relative-position'
-(declare-function magit-hunk-section-p "magit-diff" (obj))
-;; For `magit-mode-setup-internal'
-(declare-function magit-status-goto-initial-section "magit-status" ())
-;; For `magit-mode' from `bookmark'
-(defvar bookmark-make-record-function)
-
-(require 'format-spec)
-(require 'help-mode)
-
-;;; Options
-
-(defcustom magit-mode-hook
- '(magit-load-config-extensions)
- "Hook run when entering a mode derived from Magit mode."
- :package-version '(magit . "3.0.0")
- :group 'magit-modes
- :type 'hook
- :options '(magit-load-config-extensions
- bug-reference-mode))
-
-(defcustom magit-setup-buffer-hook
- '(magit-maybe-save-repository-buffers
- magit-set-buffer-margin)
- "Hook run by `magit-setup-buffer'.
-
-This is run right after displaying the buffer and right before
-generating or updating its content. `magit-mode-hook' and other,
-more specific, `magit-mode-*-hook's on the other hand are run
-right before displaying the buffer. Usually one of these hooks
-should be used instead of this one."
- :package-version '(magit . "2.3.0")
- :group 'magit-modes
- :type 'hook
- :options '(magit-maybe-save-repository-buffers
- magit-set-buffer-margin))
-
-(defcustom magit-pre-refresh-hook '(magit-maybe-save-repository-buffers)
- "Hook run before refreshing in `magit-refresh'.
-
-This hook, or `magit-post-refresh-hook', should be used
-for functions that are not tied to a particular buffer.
-
-To run a function with a particular buffer current, use
-`magit-refresh-buffer-hook' and use `derived-mode-p'
-inside your function."
- :package-version '(magit . "2.4.0")
- :group 'magit-refresh
- :type 'hook
- :options '(magit-maybe-save-repository-buffers))
-
-(defcustom magit-post-refresh-hook nil
- "Hook run after refreshing in `magit-refresh'.
-
-This hook, or `magit-pre-refresh-hook', should be used
-for functions that are not tied to a particular buffer.
-
-To run a function with a particular buffer current, use
-`magit-refresh-buffer-hook' and use `derived-mode-p'
-inside your function."
- :package-version '(magit . "2.4.0")
- :group 'magit-refresh
- :type 'hook)
-
-(defcustom magit-display-buffer-function 'magit-display-buffer-traditional
- "The function used display a Magit buffer.
-
-All Magit buffers (buffers whose major-modes derive from
-`magit-mode') are displayed using `magit-display-buffer',
-which in turn uses the function specified here."
- :package-version '(magit . "2.3.0")
- :group 'magit-buffers
- :type '(radio (function-item magit-display-buffer-traditional)
- (function-item magit-display-buffer-same-window-except-diff-v1)
- (function-item magit-display-buffer-fullframe-status-v1)
- (function-item magit-display-buffer-fullframe-status-topleft-v1)
- (function-item magit-display-buffer-fullcolumn-most-v1)
- (function-item display-buffer)
- (function :tag "Function")))
-
-(defcustom magit-pre-display-buffer-hook '(magit-save-window-configuration)
- "Hook run by `magit-display-buffer' before displaying the buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-buffers
- :type 'hook
- :get 'magit-hook-custom-get
- :options '(magit-save-window-configuration))
-
-(defcustom magit-post-display-buffer-hook '(magit-maybe-set-dedicated)
- "Hook run by `magit-display-buffer' after displaying the buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-buffers
- :type 'hook
- :get 'magit-hook-custom-get
- :options '(magit-maybe-set-dedicated))
-
-(defcustom magit-generate-buffer-name-function
- 'magit-generate-buffer-name-default-function
- "The function used to generate the name for a Magit buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-buffers
- :type '(radio (function-item magit-generate-buffer-name-default-function)
- (function :tag "Function")))
-
-(defcustom magit-buffer-name-format "%x%M%v: %t%x"
- "The format string used to name Magit buffers.
-
-The following %-sequences are supported:
-
-`%m' The name of the major-mode, but with the `-mode' suffix
- removed.
-
-`%M' Like \"%m\" but abbreviate `magit-status-mode' as `magit'.
-
-`%v' The value the buffer is locked to, in parentheses, or an
- empty string if the buffer is not locked to a value.
-
-`%V' Like \"%v\", but the string is prefixed with a space, unless
- it is an empty string.
-
-`%t' The top-level directory of the working tree of the
- repository, or if `magit-uniquify-buffer-names' is non-nil
- an abbreviation of that.
-
-`%x' If `magit-uniquify-buffer-names' is nil \"*\", otherwise the
- empty string. Due to limitations of the `uniquify' package,
- buffer names must end with the path.
-
-`%T' Obsolete, use \"%t%x\" instead. Like \"%t\", but append an
- asterisk if and only if `magit-uniquify-buffer-names' is nil.
-
-The value should always contain \"%m\" or \"%M\", \"%v\" or
-\"%V\", and \"%t\" (or the obsolete \"%T\").
-
-If `magit-uniquify-buffer-names' is non-nil, then the value must
-end with \"%t\" or \"%t%x\" (or the obsolete \"%T\"). See issue
-#2841.
-
-This is used by `magit-generate-buffer-name-default-function'.
-If another `magit-generate-buffer-name-function' is used, then
-it may not respect this option, or on the contrary it may
-support additional %-sequences."
- :package-version '(magit . "2.12.0")
- :group 'magit-buffers
- :type 'string)
-
-(defcustom magit-uniquify-buffer-names t
- "Whether to uniquify the names of Magit buffers."
- :package-version '(magit . "2.3.0")
- :group 'magit-buffers
- :type 'boolean)
-
-(defcustom magit-bury-buffer-function 'magit-restore-window-configuration
- "The function used to bury or kill the current Magit buffer."
- :package-version '(magit . "2.3.0")
- :group 'magit-buffers
- :type '(radio (function-item quit-window)
- (function-item magit-mode-quit-window)
- (function-item magit-restore-window-configuration)
- (function :tag "Function")))
-
-(defcustom magit-prefix-use-buffer-arguments 'selected
- "Whether certain prefix commands reuse arguments active in relevant buffer.
-
-This affects the transient prefix commands `magit-diff',
-`magit-log' and `magit-show-refs'.
-
-Valid values are:
-
-`always': Always use the set of arguments that is currently
- active in the respective buffer, provided that buffer exists
- of course.
-`selected': Use the set of arguments from the respective
- buffer, but only if it is displayed in a window of the current
- frame. This is the default.
-`current': Use the set of arguments from the respective buffer,
- but only if it is the current buffer.
-`never': Never use the set of arguments from the respective
- buffer.
-
-For more information see info node `(magit)Transient Arguments
-and Buffer Arguments'."
- :package-version '(magit . "3.0.0")
- :group 'magit-buffers
- :group 'magit-commands
- :group 'magit-diff
- :group 'magit-log
- :type '(choice
- (const :tag "always use args from buffer" always)
- (const :tag "use args from buffer if displayed in frame" selected)
- (const :tag "use args from buffer if it is current" current)
- (const :tag "never use args from buffer" never)))
-
-(defcustom magit-direct-use-buffer-arguments 'selected
- "Whether certain commands reuse arguments active in relevant buffer.
-
-This affects certain commands such as `magit-show-commit' that
-are suffixes of the diff or log transient prefix commands, but
-only if they are invoked directly, i.e. *not* as a suffix.
-
-Valid values are:
-
-`always': Always use the set of arguments that is currently
- active in the respective buffer, provided that buffer exists
- of course.
-`selected': Use the set of arguments from the respective
- buffer, but only if it is displayed in a window of the current
- frame. This is the default.
-`current': Use the set of arguments from the respective buffer,
- but only if it is the current buffer.
-`never': Never use the set of arguments from the respective
- buffer.
-
-For more information see info node `(magit)Transient Arguments
-and Buffer Arguments'."
- :package-version '(magit . "3.0.0")
- :group 'magit-buffers
- :group 'magit-commands
- :group 'magit-diff
- :group 'magit-log
- :type '(choice
- (const :tag "always use args from buffer" always)
- (const :tag "use args from buffer if displayed in frame" selected)
- (const :tag "use args from buffer if it is current" current)
- (const :tag "never use args from buffer" never)))
-
-(defcustom magit-region-highlight-hook '(magit-diff-update-hunk-region)
- "Functions used to highlight the region.
-
-Each function is run with the current section as only argument
-until one of them returns non-nil. If all functions return nil,
-then fall back to regular region highlighting."
- :package-version '(magit . "2.1.0")
- :group 'magit-refresh
- :type 'hook
- :options '(magit-diff-update-hunk-region))
-
-(defcustom magit-create-buffer-hook nil
- "Normal hook run after creating a new `magit-mode' buffer."
- :package-version '(magit . "2.90.0")
- :group 'magit-refresh
- :type 'hook)
-
-(defcustom magit-refresh-buffer-hook nil
- "Normal hook for `magit-refresh-buffer' to run after refreshing."
- :package-version '(magit . "2.1.0")
- :group 'magit-refresh
- :type 'hook)
-
-(defcustom magit-refresh-status-buffer t
- "Whether the status buffer is refreshed after running git.
-
-When this is non-nil, then the status buffer is automatically
-refreshed after running git for side-effects, in addition to the
-current Magit buffer, which is always refreshed automatically.
-
-Only set this to nil after exhausting all other options to
-improve performance."
- :package-version '(magit . "2.4.0")
- :group 'magit-refresh
- :group 'magit-status
- :type 'boolean)
-
-(defcustom magit-refresh-verbose nil
- "Whether to revert Magit buffers verbosely."
- :package-version '(magit . "2.1.0")
- :group 'magit-refresh
- :type 'boolean)
-
-(defcustom magit-save-repository-buffers t
- "Whether to save file-visiting buffers when appropriate.
-
-If non-nil, then all modified file-visiting buffers belonging
-to the current repository may be saved before running Magit
-commands and before creating or refreshing Magit buffers.
-If `dontask', then this is done without user intervention, for
-any other non-nil value the user has to confirm each save.
-
-The default is t to avoid surprises, but `dontask' is the
-recommended value."
- :group 'magit-essentials
- :group 'magit-buffers
- :type '(choice (const :tag "Never" nil)
- (const :tag "Ask" t)
- (const :tag "Save without asking" dontask)))
-
-;;; Key Bindings
-
-(defvar magit-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-section-mode-map)
- (define-key map [C-return] 'magit-visit-thing)
- (define-key map (kbd "C-m") 'magit-visit-thing)
- (define-key map (kbd "C-M-i") 'magit-dired-jump)
- (define-key map [M-tab] 'magit-section-cycle-diffs)
- (define-key map (kbd "P") 'magit-push)
- (define-key map (kbd "k") 'magit-delete-thing)
- (define-key map (kbd "K") 'magit-file-untrack)
- (define-key map (kbd "i") 'magit-gitignore)
- (define-key map (kbd "I") 'magit-gitignore)
- (define-key map (kbd "SPC") 'magit-diff-show-or-scroll-up)
- (define-key map (kbd "S-SPC") 'magit-diff-show-or-scroll-down)
- (define-key map (kbd "DEL") 'magit-diff-show-or-scroll-down)
- (define-key map "+" 'magit-diff-more-context)
- (define-key map "-" 'magit-diff-less-context)
- (define-key map "0" 'magit-diff-default-context)
- (define-key map "$" 'magit-process-buffer)
- (define-key map "%" 'magit-worktree)
- (define-key map "a" 'magit-cherry-apply)
- (define-key map "A" 'magit-cherry-pick)
- (define-key map "b" 'magit-branch)
- (define-key map "B" 'magit-bisect)
- (define-key map "c" 'magit-commit)
- (define-key map "C" 'magit-clone)
- (define-key map "d" 'magit-diff)
- (define-key map "D" 'magit-diff-refresh)
- (define-key map "e" 'magit-ediff-dwim)
- (define-key map "E" 'magit-ediff)
- (define-key map "f" 'magit-fetch)
- (define-key map "F" 'magit-pull)
- (define-key map "g" 'magit-refresh)
- (define-key map "G" 'magit-refresh-all)
- (define-key map "h" 'magit-dispatch)
- (define-key map "?" 'magit-dispatch)
- (define-key map "l" 'magit-log)
- (define-key map "L" 'magit-log-refresh)
- (define-key map "m" 'magit-merge)
- (define-key map "M" 'magit-remote)
- (define-key map "o" 'magit-submodule)
- (define-key map "O" 'magit-subtree)
- (define-key map "q" 'magit-mode-bury-buffer)
- (define-key map "r" 'magit-rebase)
- (define-key map "R" 'magit-file-rename)
- (define-key map "s" 'magit-stage-file)
- (define-key map "S" 'magit-stage-modified)
- (define-key map "t" 'magit-tag)
- (define-key map "T" 'magit-notes)
- (define-key map "u" 'magit-unstage-file)
- (define-key map "U" 'magit-unstage-all)
- (define-key map "v" 'magit-revert-no-commit)
- (define-key map "V" 'magit-revert)
- (define-key map "w" 'magit-am)
- (define-key map "W" 'magit-patch)
- (define-key map "x" 'magit-reset-quickly)
- (define-key map "X" 'magit-reset)
- (define-key map "y" 'magit-show-refs)
- (define-key map "Y" 'magit-cherry)
- (define-key map "z" 'magit-stash)
- (define-key map "Z" 'magit-stash)
- (define-key map ":" 'magit-git-command)
- (define-key map "!" 'magit-run)
- (define-key map (kbd "C-c C-c") 'magit-dispatch)
- (define-key map (kbd "C-c C-e") 'magit-edit-thing)
- (define-key map (kbd "C-c C-o") 'magit-browse-thing)
- (define-key map (kbd "C-c C-w") 'magit-browse-thing)
- (define-key map (kbd "C-w") 'magit-copy-section-value)
- (define-key map (kbd "M-w") 'magit-copy-buffer-revision)
- (define-key map [remap previous-line] 'magit-previous-line)
- (define-key map [remap next-line] 'magit-next-line)
- (define-key map [remap evil-previous-line] 'evil-previous-visual-line)
- (define-key map [remap evil-next-line] 'evil-next-visual-line)
- map)
- "Parent keymap for all keymaps of modes derived from `magit-mode'.")
-
-(defun magit-delete-thing ()
- "This is a placeholder command.
-Where applicable, section-specific keymaps bind another command
-which deletes the thing at point."
- (interactive)
- (user-error "There is no thing at point that could be deleted"))
-
-(defun magit-visit-thing ()
- "This is a placeholder command.
-Where applicable, section-specific keymaps bind another command
-which visits the thing at point."
- (interactive)
- (if (eq transient-current-command 'magit-dispatch)
- (call-interactively (key-binding (this-command-keys)))
- (user-error "There is no thing at point that could be visited")))
-
-(defun magit-edit-thing ()
- "This is a placeholder command.
-Where applicable, section-specific keymaps bind another command
-which lets you edit the thing at point, likely in another buffer."
- (interactive)
- (if (eq transient-current-command 'magit-dispatch)
- (call-interactively (key-binding (this-command-keys)))
- (user-error "There is no thing at point that could be edited")))
-
-(defun magit-browse-thing ()
- "This is a placeholder command.
-Where applicable, section-specific keymaps bind another command
-which visits the thing at point using `browse-url'."
- (interactive)
- (user-error "There is no thing at point that could be browsed"))
-
-(defvar bug-reference-map)
-(with-eval-after-load 'bug-reference
- (define-key bug-reference-map [remap magit-visit-thing]
- 'bug-reference-push-button))
-
-(easy-menu-define magit-mode-menu magit-mode-map
- "Magit menu"
- '("Magit"
- ["Refresh" magit-refresh t]
- ["Refresh all" magit-refresh-all t]
- "---"
- ["Stage" magit-stage t]
- ["Stage modified" magit-stage-modified t]
- ["Unstage" magit-unstage t]
- ["Reset index" magit-reset-index t]
- ["Commit" magit-commit t]
- ["Add log entry" magit-commit-add-log t]
- ["Tag" magit-tag-create t]
- "---"
- ["Diff working tree" magit-diff-working-tree t]
- ["Diff" magit-diff t]
- ("Log"
- ["Log" magit-log-other t]
- ["Reflog" magit-reflog-other t]
- ["Extended..." magit-log t])
- "---"
- ["Cherry pick" magit-cherry-pick t]
- ["Revert commit" magit-revert t]
- "---"
- ["Ignore globally" magit-gitignore-globally t]
- ["Ignore locally" magit-gitignore-locally t]
- ["Discard" magit-discard t]
- ["Reset head and index" magit-reset-mixed t]
- ["Stash" magit-stash-both t]
- ["Snapshot" magit-snapshot-both t]
- "---"
- ["Branch..." magit-checkout t]
- ["Merge" magit-merge t]
- ["Ediff resolve" magit-ediff-resolve t]
- ["Rebase..." magit-rebase t]
- "---"
- ["Push" magit-push t]
- ["Pull" magit-pull-branch t]
- ["Remote update" magit-fetch-all t]
- ("Submodule"
- ["Submodule update" magit-submodule-update t]
- ["Submodule update and init" magit-submodule-setup t]
- ["Submodule init" magit-submodule-init t]
- ["Submodule sync" magit-submodule-sync t])
- "---"
- ("Extensions")
- "---"
- ["Display Git output" magit-process-buffer t]
- ["Quit Magit" magit-mode-bury-buffer t]))
-
-;;; Mode
-
-(defun magit-load-config-extensions ()
- "Load Magit extensions that are defined at the Git config layer."
- (dolist (ext (magit-get-all "magit.extension"))
- (let ((sym (intern (format "magit-%s-mode" ext))))
- (when (fboundp sym)
- (funcall sym 1)))))
-
-(define-derived-mode magit-mode magit-section-mode "Magit"
- "Parent major mode from which Magit major modes inherit.
-
-Magit is documented in info node `(magit)'."
- :group 'magit
- (hack-dir-local-variables-non-file-buffer)
- (face-remap-add-relative 'header-line 'magit-header-line)
- (setq mode-line-process (magit-repository-local-get 'mode-line-process))
- (setq-local bookmark-make-record-function 'magit--make-bookmark)
- (setq-local isearch-filter-predicate 'magit-section--open-temporarily))
-
-;;; Local Variables
-
-(defvar-local magit-buffer-arguments nil)
-(defvar-local magit-buffer-diff-args nil)
-(defvar-local magit-buffer-diff-files nil)
-(defvar-local magit-buffer-diff-files-suspended nil)
-(defvar-local magit-buffer-file-name nil)
-(defvar-local magit-buffer-files nil)
-(defvar-local magit-buffer-log-args nil)
-(defvar-local magit-buffer-log-files nil)
-(defvar-local magit-buffer-range nil)
-(defvar-local magit-buffer-range-hashed nil)
-(defvar-local magit-buffer-refname nil)
-(defvar-local magit-buffer-revision nil)
-(defvar-local magit-buffer-revision-hash nil)
-(defvar-local magit-buffer-revisions nil)
-(defvar-local magit-buffer-typearg nil)
-(defvar-local magit-buffer-upstream nil)
-
-;; These variables are also used in file-visiting buffers.
-;; Because the user may change the major-mode, they have
-;; to be permanent buffer-local.
-(put 'magit-buffer-file-name 'permanent-local t)
-(put 'magit-buffer-refname 'permanent-local t)
-(put 'magit-buffer-revision 'permanent-local t)
-(put 'magit-buffer-revision-hash 'permanent-local t)
-
-;; `magit-status' re-enables mode function but its refresher
-;; function does not reinstate this.
-(put 'magit-buffer-diff-files-suspended 'permanent-local t)
-
-(defvar-local magit-refresh-args nil
- "Obsolete. Possibly the arguments used to refresh the current buffer.
-Some third-party packages might still use this, but Magit does not.")
-(put 'magit-refresh-args 'permanent-local t)
-(make-obsolete-variable 'magit-refresh-args nil "Magit 3.0.0")
-
-(defvar magit-buffer-lock-functions nil
- "Obsolete buffer-locking support for third-party modes.
-Implement the generic function `magit-buffer-value' for
-your mode instead of adding an entry to this variable.")
-(make-obsolete-variable 'magit-buffer-lock-functions nil "Magit 3.0.0")
-
-(cl-defgeneric magit-buffer-value ()
- (when-let ((fn (cdr (assq major-mode magit-buffer-lock-functions))))
- (funcall fn (with-no-warnings magit-refresh-args))))
-
-(defvar-local magit-previous-section nil)
-(put 'magit-previous-section 'permanent-local t)
-
-;;; Setup Buffer
-
-(defmacro magit-setup-buffer (mode &optional locked &rest bindings)
- (declare (indent 2))
- `(magit-setup-buffer-internal
- ,mode ,locked
- ,(cons 'list (mapcar (pcase-lambda (`(,var ,form))
- `(list ',var ,form))
- bindings))))
-
-(defun magit-setup-buffer-internal (mode locked bindings)
- (let* ((value (and locked
- (with-temp-buffer
- (pcase-dolist (`(,var ,val) bindings)
- (set (make-local-variable var) val))
- (let ((major-mode mode))
- (magit-buffer-value)))))
- (buffer (magit-get-mode-buffer mode value))
- (section (and buffer (magit-current-section)))
- (created (not buffer)))
- (unless buffer
- (setq buffer (magit-with-toplevel
- (magit-generate-new-buffer mode value))))
- (with-current-buffer buffer
- (setq magit-previous-section section)
- (funcall mode)
- (magit-xref-setup 'magit-setup-buffer-internal bindings)
- (pcase-dolist (`(,var ,val) bindings)
- (set (make-local-variable var) val))
- (when created
- (magit-status-goto-initial-section)
- (run-hooks 'magit-create-buffer-hook)))
- (magit-display-buffer buffer)
- (with-current-buffer buffer
- (run-hooks 'magit-setup-buffer-hook)
- (magit-refresh-buffer))
- buffer))
-
-(defun magit-mode-setup (mode &rest args)
- "Setup up a MODE buffer using ARGS to generate its content."
- (declare (obsolete magit-setup-buffer "Magit 3.0.0"))
- (with-no-warnings
- (magit-mode-setup-internal mode args)))
-
-(defun magit-mode-setup-internal (mode args &optional locked)
- "Setup up a MODE buffer using ARGS to generate its content.
-When optional LOCKED is non-nil, then create a buffer that is
-locked to its value, which is derived from MODE and ARGS."
- (declare (obsolete magit-setup-buffer "Magit 3.0.0"))
- (let* ((value (and locked
- (with-temp-buffer
- (with-no-warnings
- (setq magit-refresh-args args))
- (let ((major-mode mode))
- (magit-buffer-value)))))
- (buffer (magit-get-mode-buffer mode value))
- (section (and buffer (magit-current-section)))
- (created (not buffer)))
- (unless buffer
- (setq buffer (magit-with-toplevel
- (magit-generate-new-buffer mode value))))
- (with-current-buffer buffer
- (setq magit-previous-section section)
- (with-no-warnings
- (setq magit-refresh-args args))
- (funcall mode)
- (magit-xref-setup 'magit-mode-setup-internal args)
- (when created
- (magit-status-goto-initial-section)
- (run-hooks 'magit-create-buffer-hook)))
- (magit-display-buffer buffer)
- (with-current-buffer buffer
- (run-hooks 'magit-mode-setup-hook)
- (magit-refresh-buffer))))
-
-;;; Display Buffer
-
-(defvar magit-display-buffer-noselect nil
- "If non-nil, then `magit-display-buffer' doesn't call `select-window'.")
-
-(defun magit-display-buffer (buffer &optional display-function)
- "Display BUFFER in some window and maybe select it.
-
-If optional DISPLAY-FUNCTION is non-nil, then use that to display
-the buffer. Otherwise use `magit-display-buffer-function', which
-is the normal case.
-
-Then, unless `magit-display-buffer-noselect' is non-nil, select
-the window which was used to display the buffer.
-
-Also run the hooks `magit-pre-display-buffer-hook'
-and `magit-post-display-buffer-hook'."
- (with-current-buffer buffer
- (run-hooks 'magit-pre-display-buffer-hook))
- (let ((window (funcall (or display-function magit-display-buffer-function)
- buffer)))
- (unless magit-display-buffer-noselect
- (let* ((old-frame (selected-frame))
- (new-frame (window-frame window)))
- (select-window window)
- (unless (eq old-frame new-frame)
- (select-frame-set-input-focus new-frame)))))
- (with-current-buffer buffer
- (run-hooks 'magit-post-display-buffer-hook)))
-
-(defun magit-display-buffer-traditional (buffer)
- "Display BUFFER the way this has traditionally been done."
- (display-buffer
- buffer (if (and (derived-mode-p 'magit-mode)
- (not (memq (with-current-buffer buffer major-mode)
- '(magit-process-mode
- magit-revision-mode
- magit-diff-mode
- magit-stash-mode
- magit-status-mode))))
- '(display-buffer-same-window)
- nil))) ; display in another window
-
-(defun magit-display-buffer-same-window-except-diff-v1 (buffer)
- "Display BUFFER in the selected window except for some modes.
-If a buffer's `major-mode' derives from `magit-diff-mode' or
-`magit-process-mode', display it in another window. Display all
-other buffers in the selected window."
- (display-buffer
- buffer (if (with-current-buffer buffer
- (derived-mode-p 'magit-diff-mode 'magit-process-mode))
- '(nil (inhibit-same-window . t))
- '(display-buffer-same-window))))
-
-(defun magit--display-buffer-fullframe (buffer alist)
- (when-let ((window (or (display-buffer-reuse-window buffer alist)
- (display-buffer-same-window buffer alist)
- (display-buffer-pop-up-window buffer alist)
- (display-buffer-use-some-window buffer alist))))
- (delete-other-windows window)
- window))
-
-(defun magit-display-buffer-fullframe-status-v1 (buffer)
- "Display BUFFER, filling entire frame if BUFFER is a status buffer.
-Otherwise, behave like `magit-display-buffer-traditional'."
- (if (eq (with-current-buffer buffer major-mode)
- 'magit-status-mode)
- (display-buffer buffer '(magit--display-buffer-fullframe))
- (magit-display-buffer-traditional buffer)))
-
-(defun magit--display-buffer-topleft (buffer alist)
- (or (display-buffer-reuse-window buffer alist)
- (when-let ((window2 (display-buffer-pop-up-window buffer alist)))
- (let ((window1 (get-buffer-window))
- (buffer1 (current-buffer))
- (buffer2 (window-buffer window2))
- (w2-quit-restore (window-parameter window2 'quit-restore)))
- (set-window-buffer window1 buffer2)
- (set-window-buffer window2 buffer1)
- (select-window window2)
- ;; Swap some window state that `magit-mode-quit-window' and
- ;; `quit-restore-window' inspect.
- (set-window-prev-buffers window2 (cdr (window-prev-buffers window1)))
- (set-window-prev-buffers window1 nil)
- (set-window-parameter window2 'magit-dedicated
- (window-parameter window1 'magit-dedicated))
- (set-window-parameter window1 'magit-dedicated t)
- (set-window-parameter window1 'quit-restore
- (list 'window 'window
- (nth 2 w2-quit-restore)
- (nth 3 w2-quit-restore)))
- (set-window-parameter window2 'quit-restore nil)
- window1))))
-
-(defun magit-display-buffer-fullframe-status-topleft-v1 (buffer)
- "Display BUFFER, filling entire frame if BUFFER is a status buffer.
-When BUFFER derives from `magit-diff-mode' or
-`magit-process-mode', try to display BUFFER to the top or left of
-the current buffer rather than to the bottom or right, as
-`magit-display-buffer-fullframe-status-v1' would. Whether the
-split is made vertically or horizontally is determined by
-`split-window-preferred-function'."
- (display-buffer
- buffer
- (cond ((eq (with-current-buffer buffer major-mode)
- 'magit-status-mode)
- '(magit--display-buffer-fullframe))
- ((with-current-buffer buffer
- (derived-mode-p 'magit-diff-mode 'magit-process-mode))
- '(magit--display-buffer-topleft))
- (t
- '(display-buffer-same-window)))))
-
-(defun magit--display-buffer-fullcolumn (buffer alist)
- (when-let ((window (or (display-buffer-reuse-window buffer alist)
- (display-buffer-same-window buffer alist)
- (display-buffer-below-selected buffer alist))))
- (delete-other-windows-vertically window)
- window))
-
-(defun magit-display-buffer-fullcolumn-most-v1 (buffer)
- "Display BUFFER using the full column except in some cases.
-For most cases where BUFFER's `major-mode' derives from
-`magit-mode', display it in the selected window and grow that
-window to the full height of the frame, deleting other windows in
-that column as necessary. However, display BUFFER in another
-window if 1) BUFFER's mode derives from `magit-process-mode', or
-2) BUFFER's mode derives from `magit-diff-mode', provided that
-the mode of the current buffer derives from `magit-log-mode' or
-`magit-cherry-mode'."
- (display-buffer
- buffer
- (cond ((and (or git-commit-mode
- (derived-mode-p 'magit-log-mode
- 'magit-cherry-mode
- 'magit-reflog-mode))
- (with-current-buffer buffer
- (derived-mode-p 'magit-diff-mode)))
- nil)
- ((with-current-buffer buffer
- (derived-mode-p 'magit-process-mode))
- nil)
- (t
- '(magit--display-buffer-fullcolumn)))))
-
-(defun magit-maybe-set-dedicated ()
- "Mark the selected window as dedicated if appropriate.
-
-If a new window was created to display the buffer, then remember
-that fact. That information is used by `magit-mode-quit-window',
-to determine whether the window should be deleted when its last
-Magit buffer is buried."
- (let ((window (get-buffer-window (current-buffer))))
- (when (and (window-live-p window)
- (not (window-prev-buffers window)))
- (set-window-parameter window 'magit-dedicated t))))
-
-;;; Get Buffer
-
-(defvar-local magit--default-directory nil
- "Value of `default-directory' when buffer is generated.
-This exists to prevent a let-bound `default-directory' from
-tricking `magit-get-mode-buffer' or `magit-mode-get-buffers'
-into thinking a buffer belongs to a repo that it doesn't.")
-(put 'magit--default-directory 'permanent-local t)
-
-(defun magit-mode-get-buffers ()
- (let ((topdir (magit-toplevel)))
- (--filter (with-current-buffer it
- (and (derived-mode-p 'magit-mode)
- (equal magit--default-directory topdir)))
- (buffer-list))))
-
-(defvar-local magit-buffer-locked-p nil)
-(put 'magit-buffer-locked-p 'permanent-local t)
-
-(defun magit-get-mode-buffer (mode &optional value frame)
- "Return buffer belonging to the current repository whose major-mode is MODE.
-
-If no such buffer exists then return nil. Multiple buffers with
-the same major-mode may exist for a repository but only one can
-exist that hasn't been looked to its value. Return that buffer
-\(or nil if there is no such buffer) unless VALUE is non-nil, in
-which case return the buffer that has been looked to that value.
-
-If FRAME nil or omitted, then consider all buffers. Otherwise
- only consider buffers that are displayed in some live window
- on some frame.
-If `all', then consider all buffers on all frames.
-If `visible', then only consider buffers on all visible frames.
-If `selected' or t, then only consider buffers on the selected
- frame.
-If a frame, then only consider buffers on that frame."
- (if-let ((topdir (magit-toplevel)))
- (cl-flet* ((b (buffer)
- (with-current-buffer buffer
- (and (eq major-mode mode)
- (equal magit--default-directory topdir)
- (if value
- (and magit-buffer-locked-p
- (equal (magit-buffer-value) value))
- (not magit-buffer-locked-p))
- buffer)))
- (w (window)
- (b (window-buffer window)))
- (f (frame)
- (seq-some #'w (window-list frame 'no-minibuf))))
- (pcase-exhaustive frame
- (`nil (seq-some #'b (buffer-list)))
- (`all (seq-some #'f (frame-list)))
- (`visible (seq-some #'f (visible-frame-list)))
- ((or `selected `t) (seq-some #'w (window-list (selected-frame))))
- ((guard (framep frame)) (seq-some #'w (window-list frame)))))
- (magit--not-inside-repository-error)))
-
-(defun magit-mode-get-buffer (mode &optional create frame value)
- (declare (obsolete magit-get-mode-buffer "Magit 3.0.0"))
- (when create
- (error "`magit-mode-get-buffer's CREATE argument is obsolete"))
- (if-let ((topdir (magit-toplevel)))
- (--first (with-current-buffer it
- (and (eq major-mode mode)
- (equal magit--default-directory topdir)
- (if value
- (and magit-buffer-locked-p
- (equal (magit-buffer-value) value))
- (not magit-buffer-locked-p))))
- (if frame
- (mapcar #'window-buffer
- (window-list (unless (eq frame t) frame)))
- (buffer-list)))
- (magit--not-inside-repository-error)))
-
-(defun magit-generate-new-buffer (mode &optional value)
- (let* ((name (funcall magit-generate-buffer-name-function mode value))
- (buffer (generate-new-buffer name)))
- (with-current-buffer buffer
- (setq magit--default-directory default-directory)
- (setq magit-buffer-locked-p (and value t))
- (magit-restore-section-visibility-cache mode))
- (when magit-uniquify-buffer-names
- (add-to-list 'uniquify-list-buffers-directory-modes mode)
- (with-current-buffer buffer
- (setq list-buffers-directory (abbreviate-file-name default-directory)))
- (let ((uniquify-buffer-name-style
- (if (memq uniquify-buffer-name-style '(nil forward))
- 'post-forward-angle-brackets
- uniquify-buffer-name-style)))
- (uniquify-rationalize-file-buffer-names
- name (file-name-directory (directory-file-name default-directory))
- buffer)))
- buffer))
-
-(defun magit-generate-buffer-name-default-function (mode &optional value)
- "Generate buffer name for a MODE buffer in the current repository.
-The returned name is based on `magit-buffer-name-format' and
-takes `magit-uniquify-buffer-names' and VALUE, if non-nil, into
-account."
- (let ((m (substring (symbol-name mode) 0 -5))
- (v (and value (format "%s" (if (listp value) value (list value)))))
- (n (if magit-uniquify-buffer-names
- (file-name-nondirectory
- (directory-file-name default-directory))
- (abbreviate-file-name default-directory))))
- (format-spec
- magit-buffer-name-format
- `((?m . ,m)
- (?M . ,(if (eq mode 'magit-status-mode) "magit" m))
- (?v . ,(or v ""))
- (?V . ,(if v (concat " " v) ""))
- (?t . ,n)
- (?x . ,(if magit-uniquify-buffer-names "" "*"))
- (?T . ,(if magit-uniquify-buffer-names n (concat n "*")))))))
-
-;;; Buffer Lock
-
-(defun magit-toggle-buffer-lock ()
- "Lock the current buffer to its value or unlock it.
-
-Locking a buffer to its value prevents it from being reused to
-display another value. The name of a locked buffer contains its
-value, which allows telling it apart from other locked buffers
-and the unlocked buffer.
-
-Not all Magit buffers can be locked to their values, for example
-it wouldn't make sense to lock a status buffer.
-
-There can only be a single unlocked buffer using a certain
-major-mode per repository. So when a buffer is being unlocked
-and another unlocked buffer already exists for that mode and
-repository, then the former buffer is instead deleted and the
-latter is displayed in its place."
- (interactive)
- (if magit-buffer-locked-p
- (if-let ((unlocked (magit-get-mode-buffer major-mode)))
- (let ((locked (current-buffer)))
- (switch-to-buffer unlocked nil t)
- (kill-buffer locked))
- (setq magit-buffer-locked-p nil)
- (rename-buffer (funcall magit-generate-buffer-name-function
- major-mode)))
- (if-let ((value (magit-buffer-value)))
- (if-let ((locked (magit-get-mode-buffer major-mode value)))
- (let ((unlocked (current-buffer)))
- (switch-to-buffer locked nil t)
- (kill-buffer unlocked))
- (setq magit-buffer-locked-p t)
- (rename-buffer (funcall magit-generate-buffer-name-function
- major-mode value)))
- (user-error "Buffer has no value it could be locked to"))))
-
-;;; Bury Buffer
-
-(defun magit-mode-bury-buffer (&optional kill-buffer)
- "Bury the current buffer.
-With a prefix argument, kill the buffer instead.
-With two prefix arguments, also kill all Magit buffers associated
-with this repository.
-This is done using `magit-bury-buffer-function'."
- (interactive "P")
- ;; Kill all associated Magit buffers when a double prefix arg is given.
- (when (>= (prefix-numeric-value kill-buffer) 16)
- (let ((current (current-buffer)))
- (dolist (buf (magit-mode-get-buffers))
- (unless (eq buf current)
- (kill-buffer buf)))))
- (funcall magit-bury-buffer-function kill-buffer))
-
-(defun magit-mode-quit-window (kill-buffer)
- "Quit the selected window and bury its buffer.
-
-This behaves similar to `quit-window', but when the window
-was originally created to display a Magit buffer and the
-current buffer is the last remaining Magit buffer that was
-ever displayed in the selected window, then delete that
-window."
- (if (or (one-window-p)
- (--first (let ((buffer (car it)))
- (and (not (eq buffer (current-buffer)))
- (buffer-live-p buffer)
- (or (not (window-parameter nil 'magit-dedicated))
- (with-current-buffer buffer
- (derived-mode-p 'magit-mode
- 'magit-process-mode)))))
- (window-prev-buffers)))
- (quit-window kill-buffer)
- (let ((window (selected-window)))
- (quit-window kill-buffer)
- (when (window-live-p window)
- (delete-window window)))))
-
-;;; Refresh Buffers
-
-(defvar inhibit-magit-refresh nil)
-
-(defun magit-refresh ()
- "Refresh some buffers belonging to the current repository.
-
-Refresh the current buffer if its major mode derives from
-`magit-mode', and refresh the corresponding status buffer.
-
-Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
- (interactive)
- (unless inhibit-magit-refresh
- (unwind-protect
- (let ((start (current-time))
- (magit--refresh-cache (or magit--refresh-cache
- (list (cons 0 0)))))
- (when magit-refresh-verbose
- (message "Refreshing magit..."))
- (magit-run-hook-with-benchmark 'magit-pre-refresh-hook)
- (cond ((derived-mode-p 'magit-mode)
- (magit-refresh-buffer))
- ((derived-mode-p 'tabulated-list-mode)
- (revert-buffer)))
- (--when-let (and magit-refresh-status-buffer
- (not (derived-mode-p 'magit-status-mode))
- (magit-get-mode-buffer 'magit-status-mode))
- (with-current-buffer it
- (magit-refresh-buffer)))
- (magit-auto-revert-buffers)
- (cond
- ((and (not this-command)
- (memq last-command magit-post-commit-hook-commands))
- (magit-run-hook-with-benchmark 'magit-post-commit-hook))
- ((memq this-command magit-post-stage-hook-commands)
- (magit-run-hook-with-benchmark 'magit-post-stage-hook))
- ((memq this-command magit-post-unstage-hook-commands)
- (magit-run-hook-with-benchmark 'magit-post-unstage-hook)))
- (magit-run-hook-with-benchmark 'magit-post-refresh-hook)
- (when magit-refresh-verbose
- (let* ((c (caar magit--refresh-cache))
- (a (+ c (cdar magit--refresh-cache))))
- (message "Refreshing magit...done (%.3fs, cached %s/%s (%.0f%%))"
- (float-time (time-subtract (current-time) start))
- c a (* (/ c (* a 1.0)) 100)))))
- (run-hooks 'magit-unwind-refresh-hook))))
-
-(defun magit-refresh-all ()
- "Refresh all buffers belonging to the current repository.
-
-Refresh all Magit buffers belonging to the current repository,
-and revert buffers that visit files located inside the current
-repository.
-
-Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
- (interactive)
- (magit-run-hook-with-benchmark 'magit-pre-refresh-hook)
- (dolist (buffer (magit-mode-get-buffers))
- (with-current-buffer buffer (magit-refresh-buffer)))
- (magit-auto-revert-buffers)
- (magit-run-hook-with-benchmark 'magit-post-refresh-hook))
-
-(defvar-local magit-refresh-start-time nil)
-
-(defun magit-refresh-buffer ()
- "Refresh the current Magit buffer."
- (setq magit-refresh-start-time (current-time))
- (let ((refresh (intern (format "%s-refresh-buffer"
- (substring (symbol-name major-mode) 0 -5))))
- (magit--refresh-cache (or magit--refresh-cache (list (cons 0 0)))))
- (when (functionp refresh)
- (when magit-refresh-verbose
- (message "Refreshing buffer `%s'..." (buffer-name)))
- (let* ((buffer (current-buffer))
- (windows
- (--mapcat (with-selected-window it
- (with-current-buffer buffer
- (when-let ((section (magit-current-section)))
- (list
- (nconc (list it section)
- (magit-refresh-get-relative-position))))))
- (or (get-buffer-window-list buffer nil t)
- (list (selected-window))))))
- (deactivate-mark)
- (setq magit-section-highlight-overlays nil)
- (setq magit-section-highlighted-section nil)
- (setq magit-section-highlighted-sections nil)
- (setq magit-section-unhighlight-sections nil)
- (magit-process-unset-mode-line-error-status)
- (let ((inhibit-read-only t))
- (erase-buffer)
- (save-excursion
- (apply refresh (with-no-warnings magit-refresh-args))))
- (pcase-dolist (`(,window . ,args) windows)
- (with-selected-window window
- (with-current-buffer buffer
- (apply #'magit-section-goto-successor args))))
- (run-hooks 'magit-refresh-buffer-hook)
- (magit-section-update-highlight)
- (set-buffer-modified-p nil))
- (when magit-refresh-verbose
- (message "Refreshing buffer `%s'...done (%.3fs)" (buffer-name)
- (float-time (time-subtract (current-time)
- magit-refresh-start-time)))))))
-
-(defun magit-refresh-get-relative-position ()
- (when-let ((section (magit-current-section)))
- (let ((start (oref section start)))
- (list (count-lines start (point))
- (- (point) (line-beginning-position))
- (and (magit-hunk-section-p section)
- (region-active-p)
- (progn (goto-char (line-beginning-position))
- (when (looking-at "^[-+]") (forward-line))
- (while (looking-at "^[ @]") (forward-line))
- (let ((beg (point)))
- (cond ((looking-at "^[-+]")
- (forward-line)
- (while (looking-at "^[-+]") (forward-line))
- (while (looking-at "^ ") (forward-line))
- (forward-line -1)
- (regexp-quote (buffer-substring-no-properties
- beg (line-end-position))))
- (t t)))))))))
-
-;;; Save File-Visiting Buffers
-
-(defvar disable-magit-save-buffers nil)
-
-(defun magit-pre-command-hook ()
- (setq disable-magit-save-buffers nil))
-(add-hook 'pre-command-hook #'magit-pre-command-hook)
-
-(defvar magit-after-save-refresh-buffers nil)
-
-(defun magit-after-save-refresh-buffers ()
- (dolist (buffer magit-after-save-refresh-buffers)
- (when (buffer-live-p buffer)
- (with-current-buffer buffer
- (magit-refresh-buffer))))
- (setq magit-after-save-refresh-buffers nil)
- (remove-hook 'post-command-hook 'magit-after-save-refresh-buffers))
-
-(defun magit-after-save-refresh-status ()
- "Refresh the status buffer of the current repository.
-
-This function is intended to be added to `after-save-hook'.
-
-If the status buffer does not exist or the file being visited in
-the current buffer isn't inside the working tree of a repository,
-then do nothing.
-
-Note that refreshing a Magit buffer is done by re-creating its
-contents from scratch, which can be slow in large repositories.
-If you are not satisfied with Magit's performance, then you
-should obviously not add this function to that hook."
- (when (and (not disable-magit-save-buffers)
- (magit-inside-worktree-p t))
- (--when-let (ignore-errors (magit-get-mode-buffer 'magit-status-mode))
- (add-to-list 'magit-after-save-refresh-buffers it)
- (add-hook 'post-command-hook 'magit-after-save-refresh-buffers))))
-
-(defun magit-maybe-save-repository-buffers ()
- "Maybe save file-visiting buffers belonging to the current repository.
-Do so if `magit-save-repository-buffers' is non-nil. You should
-not remove this from any hooks, instead set that variable to nil
-if you so desire."
- (when (and magit-save-repository-buffers
- (not disable-magit-save-buffers))
- (setq disable-magit-save-buffers t)
- (let ((msg (current-message)))
- (magit-save-repository-buffers
- (eq magit-save-repository-buffers 'dontask))
- (when (and msg
- (current-message)
- (not (equal msg (current-message))))
- (message "%s" msg)))))
-
-(add-hook 'magit-pre-refresh-hook #'magit-maybe-save-repository-buffers)
-(add-hook 'magit-pre-call-git-hook #'magit-maybe-save-repository-buffers)
-(add-hook 'magit-pre-start-git-hook #'magit-maybe-save-repository-buffers)
-
-(defvar-local magit-inhibit-refresh-save nil)
-
-(defun magit-save-repository-buffers (&optional arg)
- "Save file-visiting buffers belonging to the current repository.
-After any buffer where `buffer-save-without-query' is non-nil
-is saved without asking, the user is asked about each modified
-buffer which visits a file in the current repository. Optional
-argument (the prefix) non-nil means save all with no questions."
- (interactive "P")
- (when-let ((topdir (magit-rev-parse-safe "--show-toplevel")))
- (let ((remote (file-remote-p topdir))
- (save-some-buffers-action-alist
- `((?Y (lambda (buffer)
- (with-current-buffer buffer
- (setq buffer-save-without-query t)
- (save-buffer)))
- "to save the current buffer and remember choice")
- (?N (lambda (buffer)
- (with-current-buffer buffer
- (setq magit-inhibit-refresh-save t)))
- "to skip the current buffer and remember choice")
- ,@save-some-buffers-action-alist)))
- (save-some-buffers
- arg (lambda ()
- (and (not magit-inhibit-refresh-save)
- buffer-file-name
- ;; Avoid needlessly connecting to unrelated remotes.
- (equal (file-remote-p buffer-file-name)
- remote)
- ;; For remote files this makes network requests and
- ;; therefore has to come after the above to avoid
- ;; unnecessarily waiting for unrelated hosts.
- (file-exists-p (file-name-directory buffer-file-name))
- (string-prefix-p topdir (file-truename buffer-file-name))
- (equal (magit-rev-parse-safe "--show-toplevel")
- topdir)))))))
-
-;;; Restore Window Configuration
-
-(defvar magit-inhibit-save-previous-winconf nil)
-
-(defvar-local magit-previous-window-configuration nil)
-(put 'magit-previous-window-configuration 'permanent-local t)
-
-(defun magit-save-window-configuration ()
- "Save the current window configuration.
-
-Later, when the buffer is buried, it may be restored by
-`magit-restore-window-configuration'."
- (if magit-inhibit-save-previous-winconf
- (when (eq magit-inhibit-save-previous-winconf 'unset)
- (setq magit-previous-window-configuration nil))
- (unless (get-buffer-window (current-buffer) (selected-frame))
- (setq magit-previous-window-configuration
- (current-window-configuration)))))
-
-(defun magit-restore-window-configuration (&optional kill-buffer)
- "Bury or kill the current buffer and restore previous window configuration."
- (let ((winconf magit-previous-window-configuration)
- (buffer (current-buffer))
- (frame (selected-frame)))
- (quit-window kill-buffer (selected-window))
- (when (and winconf (equal frame (window-configuration-frame winconf)))
- (set-window-configuration winconf)
- (when (buffer-live-p buffer)
- (with-current-buffer buffer
- (setq magit-previous-window-configuration nil))))))
-
-;;; Buffer History
-
-(defun magit-go-backward ()
- "Move backward in current buffer's history."
- (interactive)
- (if help-xref-stack
- (help-xref-go-back (current-buffer))
- (user-error "No previous entry in buffer's history")))
-
-(defun magit-go-forward ()
- "Move forward in current buffer's history."
- (interactive)
- (if help-xref-forward-stack
- (help-xref-go-forward (current-buffer))
- (user-error "No next entry in buffer's history")))
-
-(defun magit-insert-xref-buttons ()
- "Insert xref buttons."
- (when (and (not magit-buffer-locked-p)
- (or help-xref-stack help-xref-forward-stack))
- (when help-xref-stack
- (magit-xref-insert-button help-back-label 'magit-xref-backward))
- (when help-xref-forward-stack
- (when help-xref-stack
- (insert " "))
- (magit-xref-insert-button help-forward-label 'magit-xref-forward))))
-
-(defun magit-xref-insert-button (label type)
- (magit-insert-section (button label)
- (insert-text-button label 'type type
- 'help-args (list (current-buffer)))))
-
-(define-button-type 'magit-xref-backward
- :supertype 'help-back
- 'mouse-face 'magit-section-highlight
- 'help-echo (purecopy "mouse-2, RET: go back to previous history entry"))
-
-(define-button-type 'magit-xref-forward
- :supertype 'help-forward
- 'mouse-face 'magit-section-highlight
- 'help-echo (purecopy "mouse-2, RET: go back to next history entry"))
-
-(defvar magit-xref-modes
- '(magit-log-mode
- magit-reflog-mode
- magit-diff-mode
- magit-revision-mode)
- "List of modes for which to insert navigation buttons.")
-
-(defun magit-xref-setup (fn args)
- (when (memq major-mode magit-xref-modes)
- (when help-xref-stack-item
- (push (cons (point) help-xref-stack-item) help-xref-stack)
- (setq help-xref-forward-stack nil))
- (when (called-interactively-p 'interactive)
- (--when-let (nthcdr 10 help-xref-stack)
- (setcdr it nil)))
- (setq help-xref-stack-item
- (list 'magit-xref-restore fn default-directory args))))
-
-(defun magit-xref-restore (fn dir args)
- (setq default-directory dir)
- (funcall fn major-mode nil args)
- (magit-refresh-buffer))
-
-;;; Repository-Local Cache
-
-(defvar magit-repository-local-cache nil
- "Alist mapping `magit-toplevel' paths to alists of key/value pairs.")
-
-(defun magit-repository-local-repository ()
- "Return the key for the current repository."
- (or (bound-and-true-p magit--default-directory)
- (magit-toplevel)))
-
-(defun magit-repository-local-set (key value &optional repository)
- "Set the repository-local VALUE for KEY.
-
-Unless specified, REPOSITORY is the current buffer's repository.
-
-If REPOSITORY is nil (meaning there is no current repository),
-then the value is not cached, and we return nil."
- (let* ((repokey (or repository (magit-repository-local-repository)))
- (cache (assoc repokey magit-repository-local-cache)))
- ;; Don't cache values for a nil REPOSITORY, as the 'set' and 'get'
- ;; calls for some KEY may happen in unrelated contexts.
- (when repokey
- (if cache
- (let ((keyvalue (assoc key (cdr cache))))
- (if keyvalue
- ;; Update pre-existing value for key.
- (setcdr keyvalue value)
- ;; No such key in repository-local cache.
- (push (cons key value) (cdr cache))))
- ;; No cache for this repository.
- (push (cons repokey (list (cons key value)))
- magit-repository-local-cache)))))
-
-(defun magit-repository-local-exists-p (key &optional repository)
- "Non-nil when a repository-local value exists for KEY.
-
-Return a (KEY . VALUE) cons cell.
-
-The KEY is matched using `equal'.
-
-Unless specified, REPOSITORY is the current buffer's repository."
- (when-let ((cache (assoc (or repository
- (magit-repository-local-repository))
- magit-repository-local-cache)))
- (assoc key (cdr cache))))
-
-(defun magit-repository-local-get (key &optional default repository)
- "Return the repository-local value for KEY.
-
-Return DEFAULT if no value for KEY exists.
-
-The KEY is matched using `equal'.
-
-Unless specified, REPOSITORY is the current buffer's repository."
- (if-let ((keyvalue (magit-repository-local-exists-p key repository)))
- (cdr keyvalue)
- default))
-
-(defun magit-repository-local-delete (key &optional repository)
- "Delete the repository-local value for KEY.
-
-Unless specified, REPOSITORY is the current buffer's repository."
- (when-let ((cache (assoc (or repository
- (magit-repository-local-repository))
- magit-repository-local-cache)))
- ;; There is no `assoc-delete-all'.
- (setf (cdr cache)
- (cl-delete key (cdr cache) :key #'car :test #'equal))))
-
-(defmacro magit--with-repository-local-cache (key &rest body)
- (declare (indent 1) (debug (form body)))
- (let ((k (cl-gensym)))
- `(let ((,k ,key))
- (if-let ((kv (magit-repository-local-exists-p ,k)))
- (cdr kv)
- (let ((v ,(macroexp-progn body)))
- (magit-repository-local-set ,k v)
- v)))))
-
-(defun magit-preserve-section-visibility-cache ()
- (when (derived-mode-p 'magit-status-mode 'magit-refs-mode)
- (magit-repository-local-set
- (cons major-mode 'magit-section-visibility-cache)
- magit-section-visibility-cache)))
-
-(defun magit-restore-section-visibility-cache (mode)
- (setq magit-section-visibility-cache
- (magit-repository-local-get
- (cons mode 'magit-section-visibility-cache))))
-
-(defun magit-zap-caches ()
- "Zap caches for the current repository.
-Remove the repository's entry from `magit-repository-local-cache'
-and set `magit-section-visibility-cache' to nil in all of the
-repository's Magit buffers."
- (interactive)
- (magit-with-toplevel
- (setq magit-repository-local-cache
- (cl-delete default-directory
- magit-repository-local-cache
- :key #'car :test #'equal)))
- (dolist (buffer (magit-mode-get-buffers))
- (with-current-buffer buffer
- (setq magit-section-visibility-cache nil)))
- (setq magit--libgit-available-p eieio-unbound))
-
-;;; Utilities
-
-(defun magit-toggle-verbose-refresh ()
- "Toggle whether Magit refreshes buffers verbosely.
-Enabling this helps figuring out which sections are bottlenecks.
-The additional output can be found in the *Messages* buffer."
- (interactive)
- (setq magit-refresh-verbose (not magit-refresh-verbose))
- (message "%s verbose refreshing"
- (if magit-refresh-verbose "Enabled" "Disabled")))
-
-(defun magit-run-hook-with-benchmark (hook)
- (when hook
- (if magit-refresh-verbose
- (let ((start (current-time)))
- (message "Running %s..." hook)
- (run-hooks hook)
- (message "Running %s...done (%.3fs)" hook
- (float-time (time-subtract (current-time) start))))
- (run-hooks hook))))
-
-;;; _
-(provide 'magit-mode)
-;;; magit-mode.el ends here
+++ /dev/null
-;;; magit-notes.el --- notes support -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for `git-notes'.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-notes "magit" nil t)
-(transient-define-prefix magit-notes ()
- "Edit notes attached to commits."
- :man-page "git-notes"
- ["Configure local settings"
- ("c" magit-core.notesRef)
- ("d" magit-notes.displayRef)]
- ["Configure global settings"
- ("C" magit-global-core.notesRef)
- ("D" magit-global-notes.displayRef)]
- ["Arguments for prune"
- :if-not magit-notes-merging-p
- ("-n" "Dry run" ("-n" "--dry-run"))]
- ["Arguments for edit and remove"
- :if-not magit-notes-merging-p
- (magit-notes:--ref)]
- ["Arguments for merge"
- :if-not magit-notes-merging-p
- (magit-notes:--strategy)]
- ["Actions"
- :if-not magit-notes-merging-p
- ("T" "Edit" magit-notes-edit)
- ("r" "Remove" magit-notes-remove)
- ("m" "Merge" magit-notes-merge)
- ("p" "Prune" magit-notes-prune)]
- ["Actions"
- :if magit-notes-merging-p
- ("c" "Commit merge" magit-notes-merge-commit)
- ("a" "Abort merge" magit-notes-merge-abort)])
-
-(defun magit-notes-merging-p ()
- (let ((dir (magit-git-dir "NOTES_MERGE_WORKTREE")))
- (and (file-directory-p dir)
- (directory-files dir nil "^[^.]"))))
-
-(transient-define-infix magit-core.notesRef ()
- :class 'magit--git-variable
- :variable "core.notesRef"
- :reader 'magit-notes-read-ref
- :prompt "Set local core.notesRef")
-
-(transient-define-infix magit-notes.displayRef ()
- :class 'magit--git-variable
- :variable "notes.displayRef"
- :multi-value t
- :reader 'magit-notes-read-refs
- :prompt "Set local notes.displayRef")
-
-(transient-define-infix magit-global-core.notesRef ()
- :class 'magit--git-variable
- :variable "core.notesRef"
- :reader 'magit-notes-read-ref
- :prompt "Set global core.notesRef")
-
-(transient-define-infix magit-global-notes.displayRef ()
- :class 'magit--git-variable
- :variable "notes.displayRef"
- :multi-value t
- :reader 'magit-notes-read-refs
- :prompt "Set global notes.displayRef")
-
-(transient-define-argument magit-notes:--ref ()
- :description "Merge strategy"
- :class 'transient-option
- :key "-r"
- :argument "--ref="
- :reader 'magit-notes-read-ref)
-
-(transient-define-argument magit-notes:--strategy ()
- :description "Merge strategy"
- :class 'transient-option
- :shortarg "-s"
- :argument "--strategy="
- :choices '("manual" "ours" "theirs" "union" "cat_sort_uniq"))
-
-(defun magit-notes-edit (commit &optional ref)
- "Edit the note attached to COMMIT.
-REF is the notes ref used to store the notes.
-
-Interactively or when optional REF is nil use the value of Git
-variable `core.notesRef' or \"refs/notes/commits\" if that is
-undefined."
- (interactive (magit-notes-read-args "Edit notes"))
- (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref))
- "edit" commit))
-
-(defun magit-notes-remove (commit &optional ref)
- "Remove the note attached to COMMIT.
-REF is the notes ref from which the note is removed.
-
-Interactively or when optional REF is nil use the value of Git
-variable `core.notesRef' or \"refs/notes/commits\" if that is
-undefined."
- (interactive (magit-notes-read-args "Remove notes"))
- (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref))
- "remove" commit))
-
-(defun magit-notes-merge (ref)
- "Merge the notes ref REF into the current notes ref.
-
-The current notes ref is the value of Git variable
-`core.notesRef' or \"refs/notes/commits\" if that is undefined.
-
-When there are conflicts, then they have to be resolved in the
-temporary worktree \".git/NOTES_MERGE_WORKTREE\". When
-done use `magit-notes-merge-commit' to finish. To abort
-use `magit-notes-merge-abort'."
- (interactive (list (magit-read-string-ns "Merge reference")))
- (magit-run-git-with-editor "notes" "merge" ref))
-
-(defun magit-notes-merge-commit ()
- "Commit the current notes ref merge.
-Also see `magit-notes-merge'."
- (interactive)
- (magit-run-git-with-editor "notes" "merge" "--commit"))
-
-(defun magit-notes-merge-abort ()
- "Abort the current notes ref merge.
-Also see `magit-notes-merge'."
- (interactive)
- (magit-run-git-with-editor "notes" "merge" "--abort"))
-
-(defun magit-notes-prune (&optional dry-run)
- "Remove notes about unreachable commits."
- (interactive (list (and (member "--dry-run" (transient-args 'magit-notes)) t)))
- (when dry-run
- (magit-process-buffer))
- (magit-run-git-with-editor "notes" "prune" (and dry-run "--dry-run")))
-
-;;; Readers
-
-(defun magit-notes-read-ref (prompt _initial-input history)
- (--when-let (magit-completing-read
- prompt (magit-list-notes-refnames) nil nil
- (--when-let (magit-get "core.notesRef")
- (if (string-prefix-p "refs/notes/" it)
- (substring it 11)
- it))
- history)
- (if (string-prefix-p "refs/" it)
- it
- (concat "refs/notes/" it))))
-
-(defun magit-notes-read-refs (prompt)
- (mapcar (lambda (ref)
- (if (string-prefix-p "refs/" ref)
- ref
- (concat "refs/notes/" ref)))
- (completing-read-multiple
- (concat prompt ": ")
- (magit-list-notes-refnames) nil nil
- (mapconcat (lambda (ref)
- (if (string-prefix-p "refs/notes/" ref)
- (substring ref 11)
- ref))
- (magit-get-all "notes.displayRef")
- ","))))
-
-(defun magit-notes-read-args (prompt)
- (list (magit-read-branch-or-commit prompt (magit-stash-at-point))
- (--when-let (--first (string-match "^--ref=\\(.+\\)" it)
- (transient-args 'magit-notes))
- (match-string 1 it))))
-
-;;; _
-(provide 'magit-notes)
-;;; magit-notes.el ends here
+++ /dev/null
-;;; magit-obsolete.el --- obsolete definitions -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library defines aliases for obsolete variables and functions.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Obsolete since v3.0.0
-
-(define-obsolete-function-alias 'magit-diff-visit-file-worktree
- 'magit-diff-visit-worktree-file "Magit 3.0.0")
-
-(define-obsolete-function-alias 'magit-status-internal
- 'magit-status-setup-buffer "Magit 3.0.0")
-
-(define-obsolete-variable-alias 'magit-mode-setup-hook
- 'magit-setup-buffer-hook "Magit 3.0.0")
-
-(define-obsolete-variable-alias 'magit-branch-popup-show-variables
- 'magit-branch-direct-configure "Magit 3.0.0")
-
-(define-obsolete-function-alias 'magit-dispatch-popup
- 'magit-dispatch "Magit 3.0.0")
-
-(define-obsolete-function-alias 'magit-repolist-column-dirty
- 'magit-repolist-column-flag "Magit 3.0.0")
-
-(define-obsolete-variable-alias 'magit-disable-line-numbers
- 'magit-section-disable-line-numbers "Magit 3.0.0")
-
-(defun magit--magit-popup-warning ()
- (display-warning 'magit "\
-Magit no longer uses Magit-Popup.
-It now uses Transient.
-See https://emacsair.me/2019/02/14/transient-0.1.
-
-However your configuration and/or some third-party package that
-you use still depends on the `magit-popup' package. But because
-`magit' no longer depends on that, `package' has removed it from
-your system.
-
-If some package that you use still depends on `magit-popup' but
-does not declare it as a dependency, then please contact its
-maintainer about that and install `magit-popup' explicitly.
-
-If you yourself use functions that are defined in `magit-popup'
-in your configuration, then the next step depends on what you use
-that for.
-
-* If you use `magit-popup' to define your own popups but do not
- modify any of Magit's old popups, then you have to install
- `magit-popup' explicitly. (You can also migrate to Transient,
- but there is no need to rush that.)
-
-* If you add additional arguments and/or actions to Magit's popups,
- then you have to port that to modify the new \"transients\" instead.
- See https://github.com/magit/magit/wiki/\
-Converting-popup-modifications-to-transient-modifications
-
-To find installed packages that still use `magit-popup' you can
-use e.g. \"M-x rgrep RET magit-popup RET RET ~/.emacs.d/ RET\"."))
-(cl-eval-when (eval load)
- (unless (require (quote magit-popup) nil t)
- (defun magit-define-popup-switch (&rest _)
- (magit--magit-popup-warning))
- (defun magit-define-popup-option (&rest _)
- (magit--magit-popup-warning))
- (defun magit-define-popup-variable (&rest _)
- (magit--magit-popup-warning))
- (defun magit-define-popup-action (&rest _)
- (magit--magit-popup-warning))
- (defun magit-define-popup-sequence-action (&rest _)
- (magit--magit-popup-warning))
- (defun magit-define-popup-key (&rest _)
- (magit--magit-popup-warning))
- (defun magit-define-popup-keys-deferred (&rest _)
- (magit--magit-popup-warning))
- (defun magit-change-popup-key (&rest _)
- (magit--magit-popup-warning))
- (defun magit-remove-popup-key (&rest _)
- (magit--magit-popup-warning))))
-
-;;; _
-(provide 'magit-obsolete)
-;;; magit-obsolete.el ends here
+++ /dev/null
-;;; magit-patch.el --- creating and applying patches -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements patch commands.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit)
-
-;;; Options
-
-(defcustom magit-patch-save-arguments '(exclude "--stat")
- "Control arguments used by the command `magit-patch-save'.
-
-`magit-patch-save' (which see) saves a diff for the changes
-shown in the current buffer in a patch file. It may use the
-same arguments as used in the buffer or a subset thereof, or
-a constant list of arguments, depending on this option and
-the prefix argument."
- :package-version '(magit . "2.12.0")
- :group 'magit-diff
- :type '(choice (const :tag "use buffer arguments" buffer)
- (cons :tag "use buffer arguments except"
- (const :format "" exclude)
- (repeat :format "%v%i\n"
- (string :tag "Argument")))
- (repeat :tag "use constant arguments"
- (string :tag "Argument"))))
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-patch "magit-patch" nil t)
-(transient-define-prefix magit-patch ()
- "Create or apply patches."
- ["Actions"
- ("c" "Create patches" magit-patch-create)
- ("a" "Apply patch" magit-patch-apply)
- ("s" "Save diff as patch" magit-patch-save)
- ("r" "Request pull" magit-request-pull)])
-
-;;;###autoload (autoload 'magit-patch-create "magit-patch" nil t)
-(transient-define-prefix magit-patch-create (range args files)
- "Create patches for the commits in RANGE.
-When a single commit is given for RANGE, create a patch for the
-changes introduced by that commit (unlike 'git format-patch'
-which creates patches for all commits that are reachable from
-`HEAD' but not from the specified commit)."
- :man-page "git-format-patch"
- :incompatible '(("--subject-prefix=" "--rfc"))
- ["Mail arguments"
- (6 magit-format-patch:--in-reply-to)
- (6 magit-format-patch:--thread)
- (6 magit-format-patch:--from)
- (6 magit-format-patch:--to)
- (6 magit-format-patch:--cc)]
- ["Patch arguments"
- (magit-format-patch:--base)
- (magit-format-patch:--reroll-count)
- (5 magit-format-patch:--interdiff)
- (magit-format-patch:--range-diff)
- (magit-format-patch:--subject-prefix)
- ("C-m r " "RFC subject prefix" "--rfc")
- ("C-m l " "Add cover letter" "--cover-letter")
- (5 magit-format-patch:--cover-from-description)
- (5 magit-format-patch:--notes)
- (magit-format-patch:--output-directory)]
- ["Diff arguments"
- (magit-diff:-U)
- (magit-diff:-M)
- (magit-diff:-C)
- (magit-diff:--diff-algorithm)
- (magit:--)
- (7 "-b" "Ignore whitespace changes" ("-b" "--ignore-space-change"))
- (7 "-w" "Ignore all whitespace" ("-w" "--ignore-all-space"))]
- ["Actions"
- ("c" "Create patches" magit-patch-create)]
- (interactive
- (if (not (eq transient-current-command 'magit-patch-create))
- (list nil nil nil)
- (cons (if-let ((revs (magit-region-values 'commit t)))
- (concat (car (last revs)) "^.." (car revs))
- (let ((range (magit-read-range-or-commit
- "Format range or commit")))
- (if (string-match-p "\\.\\." range)
- range
- (format "%s~..%s" range range))))
- (let ((args (transient-args 'magit-patch-create)))
- (list (-filter #'stringp args)
- (cdr (assoc "--" args)))))))
- (if (not range)
- (transient-setup 'magit-patch-create)
- (magit-run-git "format-patch" range args "--" files)
- (when (member "--cover-letter" args)
- (save-match-data
- (find-file
- (expand-file-name
- (concat (when-let ((v (transient-arg-value "--reroll-count=" args)))
- (format "v%s-" v))
- "0000-cover-letter.patch")
- (let ((topdir (magit-toplevel)))
- (if-let ((dir (transient-arg-value "--output-directory=" args)))
- (expand-file-name dir topdir)
- topdir))))))))
-
-(transient-define-argument magit-format-patch:--in-reply-to ()
- :description "In reply to"
- :class 'transient-option
- :key "C-m C-r"
- :argument "--in-reply-to=")
-
-(transient-define-argument magit-format-patch:--thread ()
- :description "Thread style"
- :class 'transient-option
- :key "C-m s "
- :argument "--thread="
- :reader #'magit-format-patch-select-thread-style)
-
-(defun magit-format-patch-select-thread-style (&rest _ignore)
- (magit-read-char-case "Thread style " t
- (?d "[d]eep" "deep")
- (?s "[s]hallow" "shallow")))
-
-(transient-define-argument magit-format-patch:--base ()
- :description "Insert base commit"
- :class 'transient-option
- :key "C-m b "
- :argument "--base="
- :reader #'magit-format-patch-select-base)
-
-(defun magit-format-patch-select-base (prompt initial-input history)
- (or (magit-completing-read prompt (cons "auto" (magit-list-refnames))
- nil nil initial-input history "auto")
- (user-error "Nothing selected")))
-
-(transient-define-argument magit-format-patch:--reroll-count ()
- :description "Reroll count"
- :class 'transient-option
- :key "C-m v "
- :shortarg "-v"
- :argument "--reroll-count="
- :reader 'transient-read-number-N+)
-
-(transient-define-argument magit-format-patch:--interdiff ()
- :description "Insert interdiff"
- :class 'transient-option
- :key "C-m d i"
- :argument "--interdiff="
- :reader #'magit-transient-read-revision)
-
-(transient-define-argument magit-format-patch:--range-diff ()
- :description "Insert range-diff"
- :class 'transient-option
- :key "C-m d r"
- :argument "--range-diff="
- :reader #'magit-format-patch-select-range-diff)
-
-(defun magit-format-patch-select-range-diff (prompt _initial-input _history)
- (magit-read-range-or-commit prompt))
-
-(transient-define-argument magit-format-patch:--subject-prefix ()
- :description "Subject Prefix"
- :class 'transient-option
- :key "C-m p "
- :argument "--subject-prefix=")
-
-(transient-define-argument magit-format-patch:--cover-from-description ()
- :description "Use branch description"
- :class 'transient-option
- :key "C-m D "
- :argument "--cover-from-description="
- :reader #'magit-format-patch-select-description-mode)
-
-(defun magit-format-patch-select-description-mode (&rest _ignore)
- (magit-read-char-case "Use description as " t
- (?m "[m]essage" "message")
- (?s "[s]ubject" "subject")
- (?a "[a]uto" "auto")
- (?n "[n]othing" "none")))
-
-(transient-define-argument magit-format-patch:--notes ()
- :description "Insert commentary from notes"
- :class 'transient-option
- :key "C-m n "
- :argument "--notes="
- :reader #'magit-notes-read-ref)
-
-(transient-define-argument magit-format-patch:--from ()
- :description "From"
- :class 'transient-option
- :key "C-m C-f"
- :argument "--from="
- :reader 'magit-transient-read-person)
-
-(transient-define-argument magit-format-patch:--to ()
- :description "To"
- :class 'transient-option
- :key "C-m C-t"
- :argument "--to="
- :reader 'magit-transient-read-person)
-
-(transient-define-argument magit-format-patch:--cc ()
- :description "CC"
- :class 'transient-option
- :key "C-m C-c"
- :argument "--cc="
- :reader 'magit-transient-read-person)
-
-(transient-define-argument magit-format-patch:--output-directory ()
- :description "Output directory"
- :class 'transient-option
- :key "C-m o "
- :shortarg "-o"
- :argument "--output-directory="
- :reader 'transient-read-existing-directory)
-
-;;;###autoload (autoload 'magit-patch-apply "magit-patch" nil t)
-(transient-define-prefix magit-patch-apply (file &rest args)
- "Apply the patch file FILE."
- :man-page "git-apply"
- ["Arguments"
- ("-i" "Also apply to index" "--index")
- ("-c" "Only apply to index" "--cached")
- ("-3" "Fall back on 3way merge" ("-3" "--3way"))]
- ["Actions"
- ("a" "Apply patch" magit-patch-apply)]
- (interactive
- (if (not (eq transient-current-command 'magit-patch-apply))
- (list nil)
- (list (expand-file-name
- (read-file-name "Apply patch: "
- default-directory nil nil
- (when-let ((file (magit-file-at-point)))
- (file-relative-name file))))
- (transient-args 'magit-patch-apply))))
- (if (not file)
- (transient-setup 'magit-patch-apply)
- (magit-run-git "apply" args "--" (magit-convert-filename-for-git file))))
-
-;;;###autoload
-(defun magit-patch-save (file &optional arg)
- "Write current diff into patch FILE.
-
-What arguments are used to create the patch depends on the value
-of `magit-patch-save-arguments' and whether a prefix argument is
-used.
-
-If the value is the symbol `buffer', then use the same arguments
-as the buffer. With a prefix argument use no arguments.
-
-If the value is a list beginning with the symbol `exclude', then
-use the same arguments as the buffer except for those matched by
-entries in the cdr of the list. The comparison is done using
-`string-prefix-p'. With a prefix argument use the same arguments
-as the buffer.
-
-If the value is a list of strings (including the empty list),
-then use those arguments. With a prefix argument use the same
-arguments as the buffer.
-
-Of course the arguments that are required to actually show the
-same differences as those shown in the buffer are always used."
- (interactive (list (read-file-name "Write patch file: " default-directory)
- current-prefix-arg))
- (unless (derived-mode-p 'magit-diff-mode)
- (user-error "Only diff buffers can be saved as patches"))
- (let ((rev magit-buffer-range)
- (typearg magit-buffer-typearg)
- (args magit-buffer-diff-args)
- (files magit-buffer-diff-files))
- (cond ((eq magit-patch-save-arguments 'buffer)
- (when arg
- (setq args nil)))
- ((eq (car-safe magit-patch-save-arguments) 'exclude)
- (unless arg
- (setq args (-difference args (cdr magit-patch-save-arguments)))))
- ((not arg)
- (setq args magit-patch-save-arguments)))
- (with-temp-file file
- (magit-git-insert "diff" rev "-p" typearg args "--" files)))
- (magit-refresh))
-
-;;;###autoload
-(defun magit-request-pull (url start end)
- "Request upstream to pull from your public repository.
-
-URL is the url of your publicly accessible repository.
-START is a commit that already is in the upstream repository.
-END is the last commit, usually a branch name, which upstream
-is asked to pull. START has to be reachable from that commit."
- (interactive
- (list (magit-get "remote" (magit-read-remote "Remote") "url")
- (magit-read-branch-or-commit "Start" (magit-get-upstream-branch))
- (magit-read-branch-or-commit "End")))
- (let ((dir default-directory))
- ;; mu4e changes default-directory
- (compose-mail)
- (setq default-directory dir))
- (message-goto-body)
- (magit-git-insert "request-pull" start url end)
- (set-buffer-modified-p nil))
-
-;;; _
-(provide 'magit-patch)
-;;; magit-patch.el ends here
+++ /dev/null
-(define-package "magit" "20210102.1019" "A Git porcelain inside Emacs."
- '((emacs "25.1")
- (async "20200113")
- (dash "20200524")
- (git-commit "20200516")
- (transient "20200601")
- (with-editor "20200522"))
- :commit "f3602d5f98ffdb548a629e171095cbc835faba73" :authors
- (("Marius Vollmer" . "marius.vollmerNOSPAMgmail.com"))
- :maintainer
- ("Jonas Bernoulli" . "jonasNOSPAMbernoul.li")
- :keywords
- ("git" "tools" "vc")
- :url "https://github.com/magit/magit")
-;; Local Variables:
-;; no-byte-compile: t
-;; End:
+++ /dev/null
-;;; magit-process.el --- process functionality -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements the tools used to run Git for side-effects.
-
-;; Note that the functions used to run Git and then consume its
-;; output, are defined in `magit-git.el'. There's a bit of overlap
-;; though.
-
-;;; Code:
-
-(require 'ansi-color)
-(require 'cl-lib)
-(require 'dash)
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'with-editor)
-(require 'magit-utils)
-(require 'magit-section)
-(require 'magit-git)
-(require 'magit-mode)
-
-(declare-function auth-source-search "auth-source"
- (&rest spec &key max require create delete &allow-other-keys))
-
-;;; Options
-
-(defcustom magit-process-connection-type (not (eq system-type 'cygwin))
- "Connection type used for the Git process.
-
-If nil, use pipes: this is usually more efficient, and works on Cygwin.
-If t, use ptys: this enables Magit to prompt for passphrases when needed."
- :group 'magit-process
- :type '(choice (const :tag "pipe" nil)
- (const :tag "pty" t)))
-
-(defcustom magit-need-cygwin-noglob
- (and (eq system-type 'windows-nt)
- (with-temp-buffer
- (let ((process-environment
- (append magit-git-environment process-environment)))
- (condition-case e
- (process-file magit-git-executable
- nil (current-buffer) nil
- "-c" "alias.echo=!echo" "echo" "x{0}")
- (file-error
- (lwarn 'magit-process :warning
- "Could not run Git: %S" e))))
- (equal "x0\n" (buffer-string))))
- "Whether to use a workaround for Cygwin's globbing behavior.
-
-If non-nil, add environment variables to `process-environment' to
-prevent the git.exe distributed by Cygwin and MSYS2 from
-attempting to perform glob expansion when called from a native
-Windows build of Emacs. See #2246."
- :package-version '(magit . "2.3.0")
- :group 'magit-process
- :type '(choice (const :tag "Yes" t)
- (const :tag "No" nil)))
-
-(defcustom magit-process-popup-time -1
- "Popup the process buffer if a command takes longer than this many seconds."
- :group 'magit-process
- :type '(choice (const :tag "Never" -1)
- (const :tag "Immediately" 0)
- (integer :tag "After this many seconds")))
-
-(defcustom magit-process-log-max 32
- "Maximum number of sections to keep in a process log buffer.
-When adding a new section would go beyond the limit set here,
-then the older half of the sections are remove. Sections that
-belong to processes that are still running are never removed.
-When this is nil, no sections are ever removed."
- :package-version '(magit . "2.1.0")
- :group 'magit-process
- :type '(choice (const :tag "Never remove old sections" nil) integer))
-
-(defvar magit-process-extreme-logging nil
- "Whether `magit-process-file' logs to *Messages* buffer.
-Only intended for temporary use when you try to figure out how
-Magit uses Git behind the scene. Output that normally goes to
-the magit-process buffer continues to go there. Not all output
-goes to either of these two buffers.")
-
-(defcustom magit-process-error-tooltip-max-lines 20
- "The number of lines for `magit-process-error-lines' to return.
-
-These are displayed in a tooltip for `mode-line-process' errors.
-
-If `magit-process-error-tooltip-max-lines' is nil, the tooltip
-displays the text of `magit-process-error-summary' instead."
- :package-version '(magit . "2.12.0")
- :group 'magit-process
- :type '(choice (const :tag "Use summary line" nil)
- integer))
-
-(defcustom magit-credential-cache-daemon-socket
- (--some (pcase-let ((`(,prog . ,args) (split-string it)))
- (if (and prog
- (string-match-p
- "\\`\\(?:\\(?:/.*/\\)?git-credential-\\)?cache\\'" prog))
- (or (cl-loop for (opt val) on args
- if (string= opt "--socket")
- return val)
- (expand-file-name "~/.git-credential-cache/socket"))))
- ;; Note: `magit-process-file' is not yet defined when
- ;; evaluating this form, so we use `process-lines'.
- (ignore-errors
- (let ((process-environment
- (append magit-git-environment process-environment)))
- (process-lines magit-git-executable
- "config" "--get-all" "credential.helper"))))
- "If non-nil, start a credential cache daemon using this socket.
-
-When using Git's cache credential helper in the normal way, Emacs
-sends a SIGHUP to the credential daemon after the git subprocess
-has exited, causing the daemon to also quit. This can be avoided
-by starting the `git-credential-cache--daemon' process directly
-from Emacs.
-
-The function `magit-maybe-start-credential-cache-daemon' takes
-care of starting the daemon if necessary, using the value of this
-option as the socket. If this option is nil, then it does not
-start any daemon. Likewise if another daemon is already running,
-then it starts no new daemon. This function has to be a member
-of the hook variable `magit-credential-hook' for this to work.
-If an error occurs while starting the daemon, most likely because
-the necessary executable is missing, then the function removes
-itself from the hook, to avoid further futile attempts."
- :package-version '(magit . "2.3.0")
- :group 'magit-process
- :type '(choice (file :tag "Socket")
- (const :tag "Don't start a cache daemon" nil)))
-
-(defcustom magit-process-yes-or-no-prompt-regexp
- (concat " [\[(]"
- "\\([Yy]\\(?:es\\)?\\)"
- "[/|]"
- "\\([Nn]o?\\)"
- ;; OpenSSH v8 prints this. See #3969.
- "\\(?:/\\[fingerprint\\]\\)?"
- "[\])] ?[?:]? ?$")
- "Regexp matching Yes-or-No prompts of Git and its subprocesses."
- :package-version '(magit . "2.1.0")
- :group 'magit-process
- :type 'regexp)
-
-(defcustom magit-process-password-prompt-regexps
- '("^\\(Enter \\)?[Pp]assphrase\\( for \\(RSA \\)?key '.*'\\)?: ?$"
- ;; Match-group 99 is used to identify the "user@host" part.
- "^\\(Enter \\)?[Pp]assword\\( for '?\\(https?://\\)?\\(?99:[^']*\\)'?\\)?: ?$"
- "Please enter the passphrase for the ssh key"
- "Please enter the passphrase to unlock the OpenPGP secret key"
- "^.*'s password: ?$"
- "^Yubikey for .*: ?$"
- "^Enter PIN for .*: ?$")
- "List of regexps matching password prompts of Git and its subprocesses.
-Also see `magit-process-find-password-functions'."
- :package-version '(magit . "2.8.0")
- :group 'magit-process
- :type '(repeat (regexp)))
-
-(defcustom magit-process-find-password-functions nil
- "List of functions to try in sequence to get a password.
-
-These functions may be called when git asks for a password, which
-is detected using `magit-process-password-prompt-regexps'. They
-are called if and only if matching the prompt resulted in the
-value of the 99th submatch to be non-nil. Therefore users can
-control for which prompts these functions should be called by
-putting the host name in the 99th submatch, or not.
-
-If the functions are called, then they are called in the order
-given, with the host name as only argument, until one of them
-returns non-nil. If they are not called or none of them returns
-non-nil, then the password is read from the user instead."
- :package-version '(magit . "2.3.0")
- :group 'magit-process
- :type 'hook
- :options '(magit-process-password-auth-source))
-
-(defcustom magit-process-username-prompt-regexps
- '("^Username for '.*': ?$")
- "List of regexps matching username prompts of Git and its subprocesses."
- :package-version '(magit . "2.1.0")
- :group 'magit-process
- :type '(repeat (regexp)))
-
-(defcustom magit-process-prompt-functions nil
- "List of functions used to forward arbitrary questions to the user.
-
-Magit has dedicated support for forwarding username and password
-prompts and Yes-or-No questions asked by Git and its subprocesses
-to the user. This can be customized using other options in the
-`magit-process' customization group.
-
-If you encounter a new question that isn't handled by default,
-then those options should be used instead of this hook.
-
-However subprocesses may also ask questions that differ too much
-from what the code related to the above options assume, and this
-hook allows users to deal with such questions explicitly.
-
-Each function is called with the process and the output string
-as arguments until one of the functions returns non-nil. The
-function is responsible for asking the user the appropriate
-question using e.g. `read-char-choice' and then forwarding the
-answer to the process using `process-send-string'.
-
-While functions such as `magit-process-yes-or-no-prompt' may not
-be sufficient to handle some prompt, it may still be of benefit
-to look at the implementations to gain some insights on how to
-implement such functions."
- :package-version '(magit . "3.0.0")
- :group 'magit-process
- :type 'hook)
-
-(defcustom magit-process-ensure-unix-line-ending t
- "Whether Magit should ensure a unix coding system when talking to Git."
- :package-version '(magit . "2.6.0")
- :group 'magit-process
- :type 'boolean)
-
-(defcustom magit-process-display-mode-line-error t
- "Whether Magit should retain and highlight process errors in the mode line."
- :package-version '(magit . "2.12.0")
- :group 'magit-process
- :type 'boolean)
-
-(defface magit-process-ok
- '((t :inherit magit-section-heading :foreground "green"))
- "Face for zero exit-status."
- :group 'magit-faces)
-
-(defface magit-process-ng
- '((t :inherit magit-section-heading :foreground "red"))
- "Face for non-zero exit-status."
- :group 'magit-faces)
-
-(defface magit-mode-line-process
- '((t :inherit mode-line-emphasis))
- "Face for `mode-line-process' status when Git is running for side-effects."
- :group 'magit-faces)
-
-(defface magit-mode-line-process-error
- '((t :inherit error))
- "Face for `mode-line-process' error status.
-
-Used when `magit-process-display-mode-line-error' is non-nil."
- :group 'magit-faces)
-
-;;; Process Mode
-
-(defvar magit-process-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- map)
- "Keymap for `magit-process-mode'.")
-
-(define-derived-mode magit-process-mode magit-mode "Magit Process"
- "Mode for looking at Git process output."
- :group 'magit-process
- (hack-dir-local-variables-non-file-buffer)
- (setq imenu-prev-index-position-function
- 'magit-imenu--process-prev-index-position-function)
- (setq imenu-extract-index-name-function
- 'magit-imenu--process-extract-index-name-function))
-
-(defun magit-process-buffer (&optional nodisplay)
- "Display the current repository's process buffer.
-
-If that buffer doesn't exist yet, then create it.
-Non-interactively return the buffer and unless
-optional NODISPLAY is non-nil also display it."
- (interactive)
- (let ((topdir (magit-toplevel)))
- (unless topdir
- (magit--with-safe-default-directory nil
- (setq topdir default-directory)
- (let (prev)
- (while (not (equal topdir prev))
- (setq prev topdir)
- (setq topdir (file-name-directory (directory-file-name topdir)))))))
- (let ((buffer (or (--first (with-current-buffer it
- (and (eq major-mode 'magit-process-mode)
- (equal default-directory topdir)))
- (buffer-list))
- (let ((default-directory topdir))
- (magit-generate-new-buffer 'magit-process-mode)))))
- (with-current-buffer buffer
- (if magit-root-section
- (when magit-process-log-max
- (magit-process-truncate-log))
- (magit-process-mode)
- (let ((inhibit-read-only t)
- (magit-insert-section--parent nil)
- (magit-insert-section--oldroot nil))
- (make-local-variable 'text-property-default-nonsticky)
- (magit-insert-section (processbuf)
- (insert "\n")))))
- (unless nodisplay
- (magit-display-buffer buffer))
- buffer)))
-
-(defun magit-process-kill ()
- "Kill the process at point."
- (interactive)
- (when-let ((process (magit-section-value-if 'process)))
- (unless (eq (process-status process) 'run)
- (user-error "Process isn't running"))
- (magit-confirm 'kill-process)
- (kill-process process)))
-
-;;; Synchronous Processes
-
-(defvar magit-process-raise-error nil)
-
-(defun magit-git (&rest args)
- "Call Git synchronously in a separate process, for side-effects.
-
-Option `magit-git-executable' specifies the Git executable.
-The arguments ARGS specify arguments to Git, they are flattened
-before use.
-
-Process output goes into a new section in the buffer returned by
-`magit-process-buffer'. If Git exits with a non-zero status,
-then raise an error."
- (let ((magit-process-raise-error t))
- (magit-call-git args)))
-
-(defun magit-run-git (&rest args)
- "Call Git synchronously in a separate process, and refresh.
-
-Option `magit-git-executable' specifies the Git executable and
-option `magit-git-global-arguments' specifies constant arguments.
-The arguments ARGS specify arguments to Git, they are flattened
-before use.
-
-After Git returns, the current buffer (if it is a Magit buffer)
-as well as the current repository's status buffer are refreshed.
-
-Process output goes into a new section in the buffer returned by
-`magit-process-buffer'."
- (let ((magit--refresh-cache (list (cons 0 0))))
- (magit-call-git args)
- (when (member (car args) '("init" "clone"))
- ;; Creating a new repository invalidates the cache.
- (setq magit--refresh-cache nil))
- (magit-refresh)))
-
-(defvar magit-pre-call-git-hook nil)
-
-(defun magit-call-git (&rest args)
- "Call Git synchronously in a separate process.
-
-Option `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-file (process &optional infile buffer display &rest args)
- "Process files synchronously in a separate process.
-Identical to `process-file' but temporarily enable Cygwin's
-\"noglob\" option during the call and ensure unix eol
-conversion."
- (when magit-process-extreme-logging
- (let ((inhibit-message t))
- (message "$ %s" (magit-process--format-arguments process args))))
- (let ((process-environment (magit-process-environment))
- (default-process-coding-system (magit--process-coding-system)))
- (apply #'process-file process infile buffer display args)))
-
-(defun magit-process-environment ()
- ;; The various w32 hacks are only applicable when running on the
- ;; local machine. As of Emacs 25.1, a local binding of
- ;; process-environment different from the top-level value affects
- ;; the environment used in
- ;; tramp-sh-handle-{start-file-process,process-file}.
- (let ((local (not (file-remote-p default-directory))))
- (append magit-git-environment
- (and local
- (cdr (assoc magit-git-executable magit-git-w32-path-hack)))
- (and local magit-need-cygwin-noglob
- (mapcar (lambda (var)
- (concat var "=" (--if-let (getenv var)
- (concat it " noglob")
- "noglob")))
- '("CYGWIN" "MSYS")))
- process-environment)))
-
-(defvar magit-this-process nil)
-
-(defun magit-run-git-with-input (&rest args)
- "Call Git in a separate process.
-ARGS is flattened and then used as arguments to Git.
-
-The current buffer's content is used as the process's standard
-input.
-
-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."
- (when (eq system-type 'windows-nt)
- ;; On w32, git expects UTF-8 encoded input, ignore any user
- ;; configuration telling us otherwise (see #3250).
- (encode-coding-region (point-min) (point-max) 'utf-8-unix))
- (if (file-remote-p default-directory)
- ;; We lack `process-file-region', so fall back to asynch +
- ;; waiting in remote case.
- (progn
- (magit-start-git (current-buffer) args)
- (while (and magit-this-process
- (eq (process-status magit-this-process) 'run))
- (sleep-for 0.005)))
- (run-hooks 'magit-pre-call-git-hook)
- (pcase-let* ((process-environment (magit-process-environment))
- (default-process-coding-system (magit--process-coding-system))
- (flat-args (magit-process-git-arguments args))
- (`(,process-buf . ,section)
- (magit-process-setup magit-git-executable flat-args))
- (inhibit-read-only t))
- (magit-process-finish
- (apply #'call-process-region (point-min) (point-max)
- magit-git-executable nil process-buf nil flat-args)
- process-buf nil default-directory section))))
-
-;;; Asynchronous Processes
-
-(defun magit-run-git-async (&rest args)
- "Start Git, prepare for refresh, and return the process object.
-ARGS is flattened and then used as arguments to Git.
-
-Display the command line arguments in the echo area.
-
-After Git returns some buffers are refreshed: the buffer that was
-current when this function was called (if it is a Magit buffer
-and still alive), as well as the respective Magit status buffer.
-
-See `magit-start-process' for more information."
- (message "Running %s %s" magit-git-executable
- (let ((m (mapconcat #'identity (-flatten args) " ")))
- (remove-list-of-text-properties 0 (length m) '(face) m)
- m))
- (magit-start-git nil args))
-
-(defun magit-run-git-with-editor (&rest args)
- "Export GIT_EDITOR and start Git.
-Also prepare for refresh and return the process object.
-ARGS is flattened and then used as arguments to Git.
-
-Display the command line arguments in the echo area.
-
-After Git returns some buffers are refreshed: the buffer that was
-current when this function was called (if it is a Magit buffer
-and still alive), as well as the respective Magit status buffer.
-
-See `magit-start-process' and `with-editor' for more information."
- (magit--record-separated-gitdir)
- (magit-with-editor (magit-run-git-async args)))
-
-(defun magit-run-git-sequencer (&rest args)
- "Export GIT_EDITOR and start Git.
-Also prepare for refresh and return the process object.
-ARGS is flattened and then used as arguments to Git.
-
-Display the command line arguments in the echo area.
-
-After Git returns some buffers are refreshed: the buffer that was
-current when this function was called (if it is a Magit buffer
-and still alive), as well as the respective Magit status buffer.
-If the sequence stops at a commit, make the section representing
-that commit the current section by moving `point' there.
-
-See `magit-start-process' and `with-editor' for more information."
- (apply #'magit-run-git-with-editor args)
- (set-process-sentinel magit-this-process #'magit-sequencer-process-sentinel)
- magit-this-process)
-
-(defvar magit-pre-start-git-hook nil)
-
-(defun magit-start-git (input &rest args)
- "Start Git, prepare for refresh, and return the process object.
-
-If INPUT is non-nil, it has to be a buffer or the name of an
-existing buffer. The buffer content becomes the processes
-standard input.
-
-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.
-
-See `magit-start-process' for more information."
- (run-hooks 'magit-pre-start-git-hook)
- (let ((default-process-coding-system (magit--process-coding-system)))
- (apply #'magit-start-process magit-git-executable input
- (magit-process-git-arguments args))))
-
-(defun magit-start-process (program &optional input &rest args)
- "Start PROGRAM, prepare for refresh, and return the process object.
-
-If optional argument INPUT is non-nil, it has to be a buffer or
-the name of an existing buffer. The buffer content becomes the
-processes standard input.
-
-The process is started using `start-file-process' and then setup
-to use the sentinel `magit-process-sentinel' and the filter
-`magit-process-filter'. Information required by these functions
-is stored in the process object. When this function returns the
-process has not started to run yet so it is possible to override
-the sentinel and filter.
-
-After the process returns, `magit-process-sentinel' refreshes the
-buffer that was current when `magit-start-process' was called (if
-it is a Magit buffer and still alive), as well as the respective
-Magit status buffer."
- (pcase-let*
- ((`(,process-buf . ,section)
- (magit-process-setup program args))
- (process
- (let ((process-connection-type
- ;; Don't use a pty, because it would set icrnl
- ;; which would modify the input (issue #20).
- (and (not input) magit-process-connection-type))
- (process-environment (magit-process-environment))
- (default-process-coding-system (magit--process-coding-system)))
- (apply #'start-file-process
- (file-name-nondirectory program)
- process-buf program args))))
- (with-editor-set-process-filter process #'magit-process-filter)
- (set-process-sentinel process #'magit-process-sentinel)
- (set-process-buffer process process-buf)
- (when (eq system-type 'windows-nt)
- ;; On w32, git expects UTF-8 encoded input, ignore any user
- ;; configuration telling us otherwise.
- (set-process-coding-system process 'utf-8-unix))
- (process-put process 'section section)
- (process-put process 'command-buf (current-buffer))
- (process-put process 'default-dir default-directory)
- (when inhibit-magit-refresh
- (process-put process 'inhibit-refresh t))
- (oset section process process)
- (with-current-buffer process-buf
- (set-marker (process-mark process) (point)))
- (when input
- (with-current-buffer input
- (process-send-region process (point-min) (point-max))
- (process-send-eof process)))
- (setq magit-this-process process)
- (oset section value process)
- (magit-process-display-buffer process)
- process))
-
-(defun magit-parse-git-async (&rest args)
- (setq args (magit-process-git-arguments args))
- (let ((command-buf (current-buffer))
- (process-buf (generate-new-buffer " *temp*"))
- (toplevel (magit-toplevel)))
- (with-current-buffer process-buf
- (setq default-directory toplevel)
- (let ((process
- (let ((process-connection-type nil)
- (process-environment (magit-process-environment))
- (default-process-coding-system
- (magit--process-coding-system)))
- (apply #'start-file-process "git" process-buf
- magit-git-executable args))))
- (process-put process 'command-buf command-buf)
- (process-put process 'parsed (point))
- (setq magit-this-process process)
- process))))
-
-;;; Process Internals
-
-(defun magit-process-setup (program args)
- (magit-process-set-mode-line program args)
- (let ((pwd default-directory)
- (buf (magit-process-buffer t)))
- (cons buf (with-current-buffer buf
- (prog1 (magit-process-insert-section pwd program args nil nil)
- (backward-char 1))))))
-
-(defun magit-process-insert-section (pwd program args &optional errcode errlog)
- (let ((inhibit-read-only t)
- (magit-insert-section--parent magit-root-section)
- (magit-insert-section--oldroot nil))
- (goto-char (1- (point-max)))
- (magit-insert-section (process)
- (insert (if errcode
- (format "%3s " (propertize (number-to-string errcode)
- 'font-lock-face 'magit-process-ng))
- "run "))
- (unless (equal (expand-file-name pwd)
- (expand-file-name default-directory))
- (insert (file-relative-name pwd default-directory) ?\s))
- (insert (magit-process--format-arguments program args))
- (magit-insert-heading)
- (when errlog
- (if (bufferp errlog)
- (insert (with-current-buffer errlog
- (buffer-substring-no-properties (point-min) (point-max))))
- (insert-file-contents errlog)
- (goto-char (1- (point-max)))))
- (insert "\n"))))
-
-(defun magit-process--format-arguments (program args)
- (cond
- ((and args (equal program magit-git-executable))
- (setq args (-split-at (length magit-git-global-arguments) args))
- (concat (propertize (file-name-nondirectory program)
- 'font-lock-face 'magit-section-heading)
- " "
- (propertize (char-to-string magit-ellipsis)
- 'font-lock-face 'magit-section-heading
- 'help-echo (mapconcat #'identity (car args) " "))
- " "
- (propertize (mapconcat #'shell-quote-argument (cadr args) " ")
- 'font-lock-face 'magit-section-heading)))
- ((and args (equal program shell-file-name))
- (propertize (cadr args)
- 'font-lock-face 'magit-section-heading))
- (t
- (concat (propertize (file-name-nondirectory program)
- 'font-lock-face 'magit-section-heading)
- " "
- (propertize (mapconcat #'shell-quote-argument args " ")
- 'font-lock-face 'magit-section-heading)))))
-
-(defun magit-process-truncate-log ()
- (let* ((head nil)
- (tail (oref magit-root-section children))
- (count (length tail)))
- (when (> (1+ count) magit-process-log-max)
- (while (and (cdr tail)
- (> count (/ magit-process-log-max 2)))
- (let* ((inhibit-read-only t)
- (section (car tail))
- (process (oref section process)))
- (cond ((not process))
- ((memq (process-status process) '(exit signal))
- (delete-region (oref section start)
- (1+ (oref section end)))
- (cl-decf count))
- (t
- (push section head))))
- (pop tail))
- (oset magit-root-section children
- (nconc (reverse head) tail)))))
-
-(defun magit-process-sentinel (process event)
- "Default sentinel used by `magit-start-process'."
- (when (memq (process-status process) '(exit signal))
- (setq event (substring event 0 -1))
- (when (string-match "^finished" event)
- (message (concat (capitalize (process-name process)) " finished")))
- (magit-process-finish process)
- (when (eq process magit-this-process)
- (setq magit-this-process nil))
- (unless (process-get process 'inhibit-refresh)
- (let ((command-buf (process-get process 'command-buf)))
- (if (buffer-live-p command-buf)
- (with-current-buffer command-buf
- (magit-refresh))
- (with-temp-buffer
- (setq default-directory (process-get process 'default-dir))
- (magit-refresh)))))))
-
-(defun magit-sequencer-process-sentinel (process event)
- "Special sentinel used by `magit-run-git-sequencer'."
- (when (memq (process-status process) '(exit signal))
- (magit-process-sentinel process event)
- (when-let ((process-buf (process-buffer process)))
- (when (buffer-live-p process-buf)
- (when-let ((status-buf (with-current-buffer process-buf
- (magit-get-mode-buffer 'magit-status-mode))))
- (with-current-buffer status-buf
- (--when-let
- (magit-get-section
- `((commit . ,(magit-rev-parse "HEAD"))
- (,(pcase (car (cadr (-split-at
- (1+ (length magit-git-global-arguments))
- (process-command process))))
- ((or "rebase" "am") 'rebase-sequence)
- ((or "cherry-pick" "revert") 'sequence)))
- (status)))
- (goto-char (oref it start))
- (magit-section-update-highlight))))))))
-
-(defun magit-process-filter (proc string)
- "Default filter used by `magit-start-process'."
- (with-current-buffer (process-buffer proc)
- (let ((inhibit-read-only t))
- (goto-char (process-mark proc))
- ;; Find last ^M in string. If one was found, ignore
- ;; everything before it and delete the current line.
- (when-let ((ret-pos (cl-position ?\r string :from-end t)))
- (cl-callf substring string (1+ ret-pos))
- (delete-region (line-beginning-position) (point)))
- (insert (propertize string 'magit-section
- (process-get proc 'section)))
- (set-marker (process-mark proc) (point))
- ;; Make sure prompts are matched after removing ^M.
- (magit-process-yes-or-no-prompt proc string)
- (magit-process-username-prompt proc string)
- (magit-process-password-prompt proc string)
- (run-hook-with-args-until-success 'magit-process-prompt-functions
- proc string))))
-
-(defmacro magit-process-kill-on-abort (proc &rest body)
- (declare (indent 1) (debug (form body)))
- (let ((map (cl-gensym)))
- `(let ((,map (make-sparse-keymap)))
- (set-keymap-parent ,map minibuffer-local-map)
- (define-key ,map "\C-g"
- (lambda ()
- (interactive)
- (ignore-errors (kill-process ,proc))
- (abort-recursive-edit)))
- (let ((minibuffer-local-map ,map))
- ,@body))))
-
-(defun magit-process-yes-or-no-prompt (process string)
- "Forward Yes-or-No prompts to the user."
- (when-let ((beg (string-match magit-process-yes-or-no-prompt-regexp string)))
- (let ((max-mini-window-height 30))
- (process-send-string
- process
- (downcase
- (concat
- (match-string
- (if (save-match-data
- (magit-process-kill-on-abort process
- (yes-or-no-p (substring string 0 beg)))) 1 2)
- string)
- "\n"))))))
-
-(defun magit-process-password-auth-source (key)
- "Use `auth-source-search' to get a password.
-If found, return the password. Otherwise, return nil.
-
-To use this function add it to the appropriate hook
- (add-hook 'magit-process-find-password-functions
- 'magit-process-password-auth-source)
-
-KEY typically derives from a prompt such as:
- Password for 'https://tarsiusNOSPAMbitbucket.org'
-in which case it would be the string
- tarsiusNOSPAMbitbucket.org
-which matches the ~/.authinfo.gpg entry
- machine bitbucket.org login tarsius password 12345
-or iff that is undefined, for backward compatibility
- machine tarsiusNOSPAMbitbucket.org password 12345"
- (require 'auth-source)
- (and (string-match "\\`\\(.+\\)@\\([^@]+\\)\\'" key)
- (let* ((user (match-string 1 key))
- (host (match-string 2 key))
- (secret
- (plist-get
- (car (or (auth-source-search :max 1 :host host :user user)
- (auth-source-search :max 1 :host key)))
- :secret)))
- (if (functionp secret)
- (funcall secret)
- secret))))
-
-(defun magit-process-password-prompt (process string)
- "Find a password based on prompt STRING and send it to git.
-Use `magit-process-password-prompt-regexps' to find a known
-prompt. If and only if one is found, then call functions in
-`magit-process-find-password-functions' until one of them returns
-the password. If all function return nil, then read the password
-from the user."
- (when-let ((prompt (magit-process-match-prompt
- magit-process-password-prompt-regexps string)))
- (process-send-string
- process (magit-process-kill-on-abort process
- (concat (or (when-let ((key (match-string 99 string)))
- (run-hook-with-args-until-success
- 'magit-process-find-password-functions key))
- (read-passwd prompt))
- "\n")))))
-
-(defun magit-process-username-prompt (process string)
- "Forward username prompts to the user."
- (--when-let (magit-process-match-prompt
- magit-process-username-prompt-regexps string)
- (process-send-string
- process (magit-process-kill-on-abort process
- (concat (read-string it nil nil (user-login-name)) "\n")))))
-
-(defun magit-process-match-prompt (prompts string)
- "Match STRING against PROMPTS and set match data.
-Return the matched string suffixed with \": \", if needed."
- (when (--any-p (string-match it string) prompts)
- (let ((prompt (match-string 0 string)))
- (cond ((string-suffix-p ": " prompt) prompt)
- ((string-suffix-p ":" prompt) (concat prompt " "))
- (t (concat prompt ": "))))))
-
-(defun magit--process-coding-system ()
- (let ((fro (or magit-git-output-coding-system
- (car default-process-coding-system)))
- (to (cdr default-process-coding-system)))
- (if magit-process-ensure-unix-line-ending
- (cons (coding-system-change-eol-conversion fro 'unix)
- (coding-system-change-eol-conversion to 'unix))
- (cons fro to))))
-
-(defvar magit-credential-hook nil
- "Hook run before Git needs credentials.")
-
-(defvar magit-credential-cache-daemon-process nil)
-
-(defun magit-maybe-start-credential-cache-daemon ()
- "Maybe start a `git-credential-cache--daemon' process.
-
-If such a process is already running or if the value of option
-`magit-credential-cache-daemon-socket' is nil, then do nothing.
-Otherwise start the process passing the value of that options
-as argument."
- (unless (or (not magit-credential-cache-daemon-socket)
- (process-live-p magit-credential-cache-daemon-process)
- (memq magit-credential-cache-daemon-process
- (list-system-processes)))
- (setq magit-credential-cache-daemon-process
- (or (--first (let* ((attr (process-attributes it))
- (comm (cdr (assq 'comm attr)))
- (user (cdr (assq 'user attr))))
- (and (string= comm "git-credential-cache--daemon")
- (string= user user-login-name)))
- (list-system-processes))
- (condition-case nil
- (start-process "git-credential-cache--daemon"
- " *git-credential-cache--daemon*"
- magit-git-executable
- "credential-cache--daemon"
- magit-credential-cache-daemon-socket)
- ;; Some Git implementations (e.g. Windows) won't have
- ;; this program; if we fail the first time, stop trying.
- ((debug error)
- (remove-hook 'magit-credential-hook
- #'magit-maybe-start-credential-cache-daemon)))))))
-
-(add-hook 'magit-credential-hook #'magit-maybe-start-credential-cache-daemon)
-
-(defun tramp-sh-handle-start-file-process--magit-tramp-process-environment
- (fn name buffer program &rest args)
- (if magit-tramp-process-environment
- (apply fn name buffer
- (car magit-tramp-process-environment)
- (append (cdr magit-tramp-process-environment)
- (cons program args)))
- (apply fn name buffer program args)))
-
-(advice-add 'tramp-sh-handle-start-file-process :around
- 'tramp-sh-handle-start-file-process--magit-tramp-process-environment)
-
-(defun tramp-sh-handle-process-file--magit-tramp-process-environment
- (fn program &optional infile destination display &rest args)
- (if magit-tramp-process-environment
- (apply fn "env" infile destination display
- (append magit-tramp-process-environment
- (cons program args)))
- (apply fn program infile destination display args)))
-
-(advice-add 'tramp-sh-handle-process-file :around
- 'tramp-sh-handle-process-file--magit-tramp-process-environment)
-
-(defvar magit-mode-line-process-map
- (let ((map (make-sparse-keymap)))
- (define-key map (kbd "<mode-line> <mouse-1>")
- 'magit-process-buffer)
- map)
- "Keymap for `mode-line-process'.")
-
-(defun magit-process-set-mode-line (program args)
- "Display the git command (sans arguments) in the mode line."
- (when (equal program magit-git-executable)
- (setq args (nthcdr (length magit-git-global-arguments) args)))
- (let ((str (concat " " (propertize
- (concat (file-name-nondirectory program)
- (and args (concat " " (car args))))
- 'mouse-face 'highlight
- 'keymap magit-mode-line-process-map
- 'help-echo "mouse-1: Show process buffer"
- 'font-lock-face 'magit-mode-line-process))))
- (magit-repository-local-set 'mode-line-process str)
- (dolist (buf (magit-mode-get-buffers))
- (with-current-buffer buf
- (setq mode-line-process str)))
- (force-mode-line-update t)))
-
-(defun magit-process-set-mode-line-error-status (&optional error str)
- "Apply an error face to the string set by `magit-process-set-mode-line'.
-
-If ERROR is supplied, include it in the `mode-line-process' tooltip.
-
-If STR is supplied, it replaces the `mode-line-process' text."
- (setq str (or str (magit-repository-local-get 'mode-line-process)))
- (when str
- (setq error (format "%smouse-1: Show process buffer"
- (if (stringp error)
- (concat error "\n\n")
- "")))
- (setq str (concat " " (propertize
- (substring-no-properties str 1)
- 'mouse-face 'highlight
- 'keymap magit-mode-line-process-map
- 'help-echo error
- 'font-lock-face 'magit-mode-line-process-error)))
- (magit-repository-local-set 'mode-line-process str)
- (dolist (buf (magit-mode-get-buffers))
- (with-current-buffer buf
- (setq mode-line-process str)))
- (force-mode-line-update t)
- ;; We remove any error status from the mode line when a magit
- ;; buffer is refreshed (see `magit-refresh-buffer'), but we must
- ;; ensure that we ignore any refreshes during the remainder of the
- ;; current command -- otherwise a newly-set error status would be
- ;; removed before it was seen. We set a flag which prevents the
- ;; status from being removed prior to the next command, so that
- ;; the error status is guaranteed to remain visible until then.
- (let ((repokey (magit-repository-local-repository)))
- ;; The following closure captures the repokey value, and is
- ;; added to `pre-command-hook'.
- (cl-labels ((enable-magit-process-unset-mode-line
- () ;; Remove ourself from the hook variable, so
- ;; that we only run once.
- (remove-hook 'pre-command-hook
- #'enable-magit-process-unset-mode-line)
- ;; Clear the inhibit flag for the repository in
- ;; which we set it.
- (magit-repository-local-set
- 'inhibit-magit-process-unset-mode-line nil repokey)))
- ;; Set the inhibit flag until the next command is invoked.
- (magit-repository-local-set
- 'inhibit-magit-process-unset-mode-line t repokey)
- (add-hook 'pre-command-hook
- #'enable-magit-process-unset-mode-line)))))
-
-(defun magit-process-unset-mode-line-error-status ()
- "Remove any current error status from the mode line."
- (let ((status (or mode-line-process
- (magit-repository-local-get 'mode-line-process))))
- (when (and status
- (eq (get-text-property 1 'font-lock-face status)
- 'magit-mode-line-process-error))
- (magit-process-unset-mode-line))))
-
-(defun magit-process-unset-mode-line (&optional directory)
- "Remove the git command from the mode line."
- (let ((default-directory (or directory default-directory)))
- (unless (magit-repository-local-get 'inhibit-magit-process-unset-mode-line)
- (magit-repository-local-set 'mode-line-process nil)
- (dolist (buf (magit-mode-get-buffers))
- (with-current-buffer buf (setq mode-line-process nil)))
- (force-mode-line-update t))))
-
-(defvar magit-process-error-message-regexps
- (list "^\\*ERROR\\*: Canceled by user$"
- "^\\(?:error\\|fatal\\|git\\): \\(.*\\)$"
- "^\\(Cannot rebase:.*\\)$"))
-
-(define-error 'magit-git-error "Git error")
-
-(defun magit-process-error-summary (process-buf section)
- "A one-line error summary from the given SECTION."
- (or (and (buffer-live-p process-buf)
- (with-current-buffer process-buf
- (and (oref section content)
- (save-excursion
- (goto-char (oref section end))
- (run-hook-wrapped
- 'magit-process-error-message-regexps
- (lambda (re)
- (save-excursion
- (and (re-search-backward
- re (oref section start) t)
- (or (match-string-no-properties 1)
- (and (not magit-process-raise-error)
- 'suppressed))))))))))
- "Git failed"))
-
-(defun magit-process-error-tooltip (process-buf section)
- "Returns the text from SECTION of the PROCESS-BUF buffer.
-
-Limited by `magit-process-error-tooltip-max-lines'."
- (and (integerp magit-process-error-tooltip-max-lines)
- (> magit-process-error-tooltip-max-lines 0)
- (buffer-live-p process-buf)
- (with-current-buffer process-buf
- (save-excursion
- (goto-char (or (oref section content)
- (oref section start)))
- (buffer-substring-no-properties
- (point)
- (save-excursion
- (forward-line magit-process-error-tooltip-max-lines)
- (goto-char
- (if (> (point) (oref section end))
- (oref section end)
- (point)))
- ;; Remove any trailing whitespace.
- (when (re-search-backward "[^[:space:]\n]"
- (oref section start) t)
- (forward-char 1))
- (point)))))))
-
-(defvar-local magit-this-error nil)
-
-(defvar magit-process-finish-apply-ansi-colors nil)
-
-(defun magit-process-finish (arg &optional process-buf command-buf
- default-dir section)
- (unless (integerp arg)
- (setq process-buf (process-buffer arg))
- (setq command-buf (process-get arg 'command-buf))
- (setq default-dir (process-get arg 'default-dir))
- (setq section (process-get arg 'section))
- (setq arg (process-exit-status arg)))
- (when (fboundp 'dired-uncache)
- (dired-uncache default-dir))
- (when (buffer-live-p process-buf)
- (with-current-buffer process-buf
- (let ((inhibit-read-only t)
- (marker (oref section start)))
- (goto-char marker)
- (save-excursion
- (delete-char 3)
- (set-marker-insertion-type marker nil)
- (insert (propertize (format "%3s" arg)
- 'magit-section section
- 'font-lock-face (if (= arg 0)
- 'magit-process-ok
- 'magit-process-ng)))
- (set-marker-insertion-type marker t))
- (when magit-process-finish-apply-ansi-colors
- (ansi-color-apply-on-region (oref section content)
- (oref section end)))
- (if (= (oref section end)
- (+ (line-end-position) 2))
- (save-excursion
- (goto-char (1+ (line-end-position)))
- (delete-char -1)
- (oset section content nil))
- (let ((buf (magit-process-buffer t)))
- (when (and (= arg 0)
- (not (--any-p (eq (window-buffer it) buf)
- (window-list))))
- (magit-section-hide section)))))))
- (if (= arg 0)
- ;; Unset the `mode-line-process' value upon success.
- (magit-process-unset-mode-line default-dir)
- ;; Otherwise process the error.
- (let ((msg (magit-process-error-summary process-buf section)))
- ;; Change `mode-line-process' to an error face upon failure.
- (if magit-process-display-mode-line-error
- (magit-process-set-mode-line-error-status
- (or (magit-process-error-tooltip process-buf section)
- msg))
- (magit-process-unset-mode-line default-dir))
- ;; Either signal the error, or else display the error summary in
- ;; the status buffer and with a message in the echo area.
- (cond
- (magit-process-raise-error
- (signal 'magit-git-error (list (format "%s (in %s)" msg default-dir))))
- ((not (eq msg 'suppressed))
- (when (buffer-live-p process-buf)
- (with-current-buffer process-buf
- (when-let ((status-buf (magit-get-mode-buffer 'magit-status-mode)))
- (with-current-buffer status-buf
- (setq magit-this-error msg)))))
- (message "%s ... [%s buffer %s for details]" msg
- (if-let ((key (and (buffer-live-p command-buf)
- (with-current-buffer command-buf
- (car (where-is-internal
- 'magit-process-buffer))))))
- (format "Hit %s to see" (key-description key))
- "See")
- (buffer-name process-buf))))))
- arg)
-
-(defun magit-process-display-buffer (process)
- (when (process-live-p process)
- (let ((buf (process-buffer process)))
- (cond ((not (buffer-live-p buf)))
- ((= magit-process-popup-time 0)
- (if (minibufferp)
- (switch-to-buffer-other-window buf)
- (pop-to-buffer buf)))
- ((> magit-process-popup-time 0)
- (run-with-timer magit-process-popup-time nil
- (lambda (p)
- (when (eq (process-status p) 'run)
- (let ((buf (process-buffer p)))
- (when (buffer-live-p buf)
- (if (minibufferp)
- (switch-to-buffer-other-window buf)
- (pop-to-buffer buf))))))
- process))))))
-
-(defun magit--log-action (summary line list)
- (let (heading lines)
- (if (cdr list)
- (progn (setq heading (funcall summary list))
- (setq lines (mapcar line list)))
- (setq heading (funcall line (car list))))
- (with-current-buffer (magit-process-buffer t)
- (goto-char (1- (point-max)))
- (let ((inhibit-read-only t))
- (magit-insert-section (message)
- (magit-insert-heading (concat " * " heading))
- (when lines
- (dolist (line lines)
- (insert line "\n"))
- (insert "\n"))))
- (let ((inhibit-message t))
- (when heading
- (setq lines (cons heading lines)))
- (message (mapconcat #'identity lines "\n"))))))
-
-;;; _
-(provide 'magit-process)
-;;; magit-process.el ends here
+++ /dev/null
-;;; magit-pull.el --- update local objects and refs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements pull commands.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Options
-
-(defcustom magit-pull-or-fetch nil
- "Whether `magit-pull' also offers some fetch suffixes."
- :package-version '(magit . "3.0.0")
- :group 'magit-commands
- :type 'boolean)
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-pull "magit-pull" nil t)
-(transient-define-prefix magit-pull ()
- "Pull from another repository."
- :man-page "git-pull"
- [:description
- (lambda () (if magit-pull-or-fetch "Pull arguments" "Arguments"))
- ("-r" "Rebase local commits" ("-r" "--rebase"))
- ("-A" "Autostash" "--autostash" :level 7)]
- [:description
- (lambda ()
- (if-let ((branch (magit-get-current-branch)))
- (concat
- (propertize "Pull into " 'face 'transient-heading)
- (propertize branch 'face 'magit-branch-local)
- (propertize " from" 'face 'transient-heading))
- (propertize "Pull from" 'face 'transient-heading)))
- ("p" magit-pull-from-pushremote)
- ("u" magit-pull-from-upstream)
- ("e" "elsewhere" magit-pull-branch)]
- ["Fetch from"
- :if-non-nil magit-pull-or-fetch
- ("f" "remotes" magit-fetch-all-no-prune)
- ("F" "remotes and prune" magit-fetch-all-prune)]
- ["Fetch"
- :if-non-nil magit-pull-or-fetch
- ("o" "another branch" magit-fetch-branch)
- ("s" "explicit refspec" magit-fetch-refspec)
- ("m" "submodules" magit-fetch-modules)]
- ["Configure"
- ("r" magit-branch.<branch>.rebase :if magit-get-current-branch)
- ("C" "variables..." magit-branch-configure)]
- (interactive)
- (transient-setup 'magit-pull nil nil :scope (magit-get-current-branch)))
-
-(defun magit-pull-arguments ()
- (transient-args 'magit-pull))
-
-;;;###autoload (autoload 'magit-pull-from-pushremote "magit-pull" nil t)
-(transient-define-suffix magit-pull-from-pushremote (args)
- "Pull from the push-remote of the current branch.
-
-With a prefix argument or when the push-remote is either not
-configured or unusable, then let the user first configure the
-push-remote."
- :if 'magit-get-current-branch
- :description 'magit-pull--pushbranch-description
- (interactive (list (magit-pull-arguments)))
- (pcase-let ((`(,branch ,remote)
- (magit--select-push-remote "pull from there")))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "pull" args remote branch)))
-
-(defun magit-pull--pushbranch-description ()
- ;; Also used by `magit-rebase-onto-pushremote'.
- (let* ((branch (magit-get-current-branch))
- (target (magit-get-push-branch branch t))
- (remote (magit-get-push-remote branch))
- (v (magit--push-remote-variable branch t)))
- (cond
- (target)
- ((member remote (magit-list-remotes))
- (format "%s, replacing non-existent" v))
- (remote
- (format "%s, replacing invalid" v))
- (t
- (format "%s, setting that" v)))))
-
-;;;###autoload (autoload 'magit-pull-from-upstream "magit-pull" nil t)
-(transient-define-suffix magit-pull-from-upstream (args)
- "Pull from the upstream of the current branch.
-
-With a prefix argument or when the upstream is either not
-configured or unusable, then let the user first configure
-the upstream."
- :if 'magit-get-current-branch
- :description 'magit-pull--upstream-description
- (interactive (list (magit-pull-arguments)))
- (let* ((branch (or (magit-get-current-branch)
- (user-error "No branch is checked out")))
- (remote (magit-get "branch" branch "remote"))
- (merge (magit-get "branch" branch "merge")))
- (when (or current-prefix-arg
- (not (or (magit-get-upstream-branch branch)
- (magit--unnamed-upstream-p remote merge))))
- (magit-set-upstream-branch
- branch (magit-read-upstream-branch
- branch (format "Set upstream of %s and pull from there" branch)))
- (setq remote (magit-get "branch" branch "remote"))
- (setq merge (magit-get "branch" branch "merge")))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-with-editor "pull" args remote merge)))
-
-(defun magit-pull--upstream-description ()
- (when-let ((branch (magit-get-current-branch)))
- (or (magit-get-upstream-branch branch)
- (let ((remote (magit-get "branch" branch "remote"))
- (merge (magit-get "branch" branch "merge"))
- (u (magit--propertize-face "@{upstream}" 'bold)))
- (cond
- ((magit--unnamed-upstream-p remote merge)
- (format "%s of %s"
- (magit--propertize-face merge 'magit-branch-remote)
- (magit--propertize-face remote 'bold)))
- ((magit--valid-upstream-p remote merge)
- (concat u ", replacing non-existent"))
- ((or remote merge)
- (concat u ", replacing invalid"))
- (t
- (concat u ", setting that")))))))
-
-;;;###autoload
-(defun magit-pull-branch (source args)
- "Pull from a branch read in the minibuffer."
- (interactive (list (magit-read-remote-branch "Pull" nil nil nil t)
- (magit-pull-arguments)))
- (run-hooks 'magit-credential-hook)
- (pcase-let ((`(,remote . ,branch)
- (magit-get-tracked source)))
- (magit-run-git-with-editor "pull" args remote branch)))
-
-;;; _
-(provide 'magit-pull)
-;;; magit-pull.el ends here
+++ /dev/null
-;;; magit-push.el --- update remote objects and refs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements push commands.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit)
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-push "magit-push" nil t)
-(transient-define-prefix magit-push ()
- "Push to another repository."
- :man-page "git-push"
- ["Arguments"
- ("-f" "Force with lease" (nil "--force-with-lease"))
- ("-F" "Force" ("-f" "--force"))
- ("-h" "Disable hooks" "--no-verify")
- ("-n" "Dry run" ("-n" "--dry-run"))
- (5 "-u" "Set upstream" "--set-upstream")
- (7 "-t" "Follow tags" "--follow-tags")]
- [:if magit-get-current-branch
- :description (lambda ()
- (format (propertize "Push %s to" 'face 'transient-heading)
- (propertize (magit-get-current-branch)
- 'face 'magit-branch-local)))
- ("p" magit-push-current-to-pushremote)
- ("u" magit-push-current-to-upstream)
- ("e" "elsewhere" magit-push-current)]
- ["Push"
- [("o" "another branch" magit-push-other)
- ("r" "explicit refspecs" magit-push-refspecs)
- ("m" "matching branches" magit-push-matching)]
- [("T" "a tag" magit-push-tag)
- ("t" "all tags" magit-push-tags)
- (6 "n" "a note ref" magit-push-notes-ref)]]
- ["Configure"
- ("C" "Set variables..." magit-branch-configure)])
-
-(defun magit-push-arguments ()
- (transient-args 'magit-push))
-
-(defun magit-git-push (branch target args)
- (run-hooks 'magit-credential-hook)
- ;; If the remote branch already exists, then we do not have to
- ;; qualify the target, which we prefer to avoid doing because
- ;; using the default namespace is wrong in obscure cases.
- (pcase-let ((namespace (if (magit-get-tracked target) "" "refs/heads/"))
- (`(,remote . ,target)
- (magit-split-branch-name target)))
- (magit-run-git-async "push" "-v" args remote
- (format "%s:%s%s" branch namespace target))))
-
-;;;###autoload (autoload 'magit-push-current-to-pushremote "magit-push" nil t)
-(transient-define-suffix magit-push-current-to-pushremote (args)
- "Push the current branch to its push-remote.
-
-When the push-remote is not configured, then read the push-remote
-from the user, set it, and then push to it. With a prefix
-argument the push-remote can be changed before pushed to it."
- :if 'magit-get-current-branch
- :description 'magit-push--pushbranch-description
- (interactive (list (magit-push-arguments)))
- (pcase-let ((`(,branch ,remote ,changed)
- (magit--select-push-remote "push there")))
- (when changed
- (magit-confirm 'set-and-push
- (format "Really use \"%s\" as push-remote and push \"%s\" there"
- remote branch)))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" "-v" args remote
- (format "refs/heads/%s:refs/heads/%s"
- branch branch)))) ; see #3847 and #3872
-
-(defun magit-push--pushbranch-description ()
- (let* ((branch (magit-get-current-branch))
- (target (magit-get-push-branch branch t))
- (remote (magit-get-push-remote branch))
- (v (magit--push-remote-variable branch t)))
- (cond
- (target)
- ((member remote (magit-list-remotes))
- (format "%s, creating it"
- (magit--propertize-face (concat remote "/" branch)
- 'magit-branch-remote)))
- (remote
- (format "%s, replacing invalid" v))
- (t
- (format "%s, setting that" v)))))
-
-;;;###autoload (autoload 'magit-push-current-to-upstream "magit-push" nil t)
-(transient-define-suffix magit-push-current-to-upstream (args)
- "Push the current branch to its upstream branch.
-
-With a prefix argument or when the upstream is either not
-configured or unusable, then let the user first configure
-the upstream."
- :if 'magit-get-current-branch
- :description 'magit-push--upstream-description
- (interactive (list (magit-push-arguments)))
- (let* ((branch (or (magit-get-current-branch)
- (user-error "No branch is checked out")))
- (remote (magit-get "branch" branch "remote"))
- (merge (magit-get "branch" branch "merge")))
- (when (or current-prefix-arg
- (not (or (magit-get-upstream-branch branch)
- (magit--unnamed-upstream-p remote merge)
- (magit--valid-upstream-p remote merge))))
- (let* ((branches (-union (--map (concat it "/" branch)
- (magit-list-remotes))
- (magit-list-remote-branch-names)))
- (upstream (magit-completing-read
- (format "Set upstream of %s and push there" branch)
- branches nil nil nil 'magit-revision-history
- (or (car (member (magit-remote-branch-at-point) branches))
- (car (member "origin/master" branches)))))
- (upstream* (or (magit-get-tracked upstream)
- (magit-split-branch-name upstream))))
- (setq remote (car upstream*))
- (setq merge (cdr upstream*))
- (unless (string-prefix-p "refs/" merge)
- ;; User selected a non-existent remote-tracking branch.
- ;; It is very likely, but not certain, that this is the
- ;; correct thing to do. It is even more likely that it
- ;; is what the user wants to happen.
- (setq merge (concat "refs/heads/" merge)))
- (magit-confirm 'set-and-push
- (format "Really use \"%s\" as upstream and push \"%s\" there"
- upstream branch)))
- (cl-pushnew "--set-upstream" args :test #'equal))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" "-v" args remote (concat branch ":" merge))))
-
-(defun magit-push--upstream-description ()
- (when-let ((branch (magit-get-current-branch)))
- (or (magit-get-upstream-branch branch)
- (let ((remote (magit-get "branch" branch "remote"))
- (merge (magit-get "branch" branch "merge"))
- (u (magit--propertize-face "@{upstream}" 'bold)))
- (cond
- ((magit--unnamed-upstream-p remote merge)
- (format "%s as %s"
- (magit--propertize-face remote 'bold)
- (magit--propertize-face merge 'magit-branch-remote)))
- ((magit--valid-upstream-p remote merge)
- (format "%s creating %s"
- (magit--propertize-face remote 'magit-branch-remote)
- (magit--propertize-face merge 'magit-branch-remote)))
- ((or remote merge)
- (concat u ", creating it and replacing invalid"))
- (t
- (concat u ", creating it")))))))
-
-;;;###autoload
-(defun magit-push-current (target args)
- "Push the current branch to a branch read in the minibuffer."
- (interactive
- (--if-let (magit-get-current-branch)
- (list (magit-read-remote-branch (format "Push %s to" it)
- nil nil it 'confirm)
- (magit-push-arguments))
- (user-error "No branch is checked out")))
- (magit-git-push (magit-get-current-branch) target args))
-
-;;;###autoload
-(defun magit-push-other (source target args)
- "Push an arbitrary branch or commit somewhere.
-Both the source and the target are read in the minibuffer."
- (interactive
- (let ((source (magit-read-local-branch-or-commit "Push")))
- (list source
- (magit-read-remote-branch
- (format "Push %s to" source) nil
- (if (magit-local-branch-p source)
- (or (magit-get-push-branch source)
- (magit-get-upstream-branch source))
- (and (magit-rev-ancestor-p source "HEAD")
- (or (magit-get-push-branch)
- (magit-get-upstream-branch))))
- source 'confirm)
- (magit-push-arguments))))
- (magit-git-push source target args))
-
-(defvar magit-push-refspecs-history nil)
-
-;;;###autoload
-(defun magit-push-refspecs (remote refspecs args)
- "Push one or multiple REFSPECS to a REMOTE.
-Both the REMOTE and the REFSPECS are read in the minibuffer. To
-use multiple REFSPECS, separate them with commas. Completion is
-only available for the part before the colon, or when no colon
-is used."
- (interactive
- (list (magit-read-remote "Push to remote")
- (split-string (magit-completing-read-multiple
- "Push refspec,s"
- (cons "HEAD" (magit-list-local-branch-names))
- nil nil 'magit-push-refspecs-history)
- crm-default-separator t)
- (magit-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.<branch>.pushRemote', `branch.<branch>.remote',
-`branch.<branch>.merge', and `remote.<remote>.push'.
-
-If you add this suffix to a transient prefix without explicitly
-specifying the description, then an attempt is made to predict
-what this command will do. For example:
-
- (transient-insert-suffix 'magit-push \"p\"
- '(\"i\" magit-push-implicitly))"
- :description 'magit-push-implicitly--desc
- (interactive (list (magit-push-arguments)))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" "-v" args))
-
-(defun magit-push-implicitly--desc ()
- (let ((default (magit-get "push.default")))
- (unless (equal default "nothing")
- (or (when-let ((remote (or (magit-get-remote)
- (magit-remote-p "origin")))
- (refspec (magit-get "remote" remote "push")))
- (format "%s using %s"
- (magit--propertize-face remote 'magit-branch-remote)
- (magit--propertize-face refspec 'bold)))
- (--when-let (and (not (magit-get-push-branch))
- (magit-get-upstream-branch))
- (format "%s aka %s\n"
- (magit-branch-set-face it)
- (magit--propertize-face "@{upstream}" 'bold)))
- (--when-let (magit-get-push-branch)
- (format "%s aka %s\n"
- (magit-branch-set-face it)
- (magit--propertize-face "pushRemote" 'bold)))
- (--when-let (magit-get-@{push}-branch)
- (format "%s aka %s\n"
- (magit-branch-set-face it)
- (magit--propertize-face "@{push}" 'bold)))
- (format "using %s (%s is %s)\n"
- (magit--propertize-face "git push" 'bold)
- (magit--propertize-face "push.default" 'bold)
- (magit--propertize-face default 'bold))))))
-
-;;;###autoload
-(defun magit-push-to-remote (remote args)
- "Push to REMOTE without using an explicit refspec.
-The REMOTE is read in the minibuffer.
-
-This command simply runs \"git push -v [ARGS] REMOTE\". ARGS
-are the arguments specified in the popup buffer. No refspec
-arguments are used. Instead the behavior depends on at least
-these Git variables: `push.default', `remote.pushDefault',
-`branch.<branch>.pushRemote', `branch.<branch>.remote',
-`branch.<branch>.merge', and `remote.<remote>.push'."
- (interactive (list (magit-read-remote "Push to remote")
- (magit-push-arguments)))
- (run-hooks 'magit-credential-hook)
- (magit-run-git-async "push" "-v" args remote))
-
-(defun magit-push-to-remote--desc ()
- (format "using %s\n" (magit--propertize-face "git push <remote>" 'bold)))
-
-;;; _
-(provide 'magit-push)
-;;; magit-push.el ends here
+++ /dev/null
-;;; magit-reflog.el --- inspect ref history -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for looking at Git reflogs.
-
-;;; Code:
-
-(require 'magit-core)
-(require 'magit-log)
-
-(eval-when-compile
- (require 'subr-x))
-
-;;; Options
-
-(defcustom magit-reflog-limit 256
- "Maximal number of entries initially shown in reflog buffers.
-The limit in the current buffer can be changed using \"+\"
-and \"-\"."
- :package-version '(magit . "3.0.0")
- :group 'magit-commands
- :type 'number)
-
-(defcustom magit-reflog-margin
- (list (nth 0 magit-log-margin)
- (nth 1 magit-log-margin)
- 'magit-log-margin-width nil
- (nth 4 magit-log-margin))
- "Format of the margin in `magit-reflog-mode' buffers.
-
-The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
-
-If INIT is non-nil, then the margin is shown initially.
-STYLE controls how to format the author or committer date.
- It can be one of `age' (to show the age of the commit),
- `age-abbreviated' (to abbreviate the time unit to a character),
- or a string (suitable for `format-time-string') to show the
- actual date. Option `magit-log-margin-show-committer-date'
- controls which date is being displayed.
-WIDTH controls the width of the margin. This exists for forward
- compatibility and currently the value should not be changed.
-AUTHOR controls whether the name of the author is also shown by
- default.
-AUTHOR-WIDTH has to be an integer. When the name of the author
- is shown, then this specifies how much space is used to do so."
- :package-version '(magit . "2.9.0")
- :group 'magit-log
- :group 'magit-margin
- :type magit-log-margin--custom-type
- :initialize 'magit-custom-initialize-reset
- :set-after '(magit-log-margin)
- :set (apply-partially #'magit-margin-set-variable 'magit-reflog-mode))
-
-;;; Faces
-
-(defface magit-reflog-commit '((t :foreground "green"))
- "Face for commit commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-amend '((t :foreground "magenta"))
- "Face for amend commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-merge '((t :foreground "green"))
- "Face for merge, checkout and branch commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-checkout '((t :foreground "blue"))
- "Face for checkout commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-reset '((t :foreground "red"))
- "Face for reset commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-rebase '((t :foreground "magenta"))
- "Face for rebase commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-cherry-pick '((t :foreground "green"))
- "Face for cherry-pick commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-remote '((t :foreground "cyan"))
- "Face for pull and clone commands in reflogs."
- :group 'magit-faces)
-
-(defface magit-reflog-other '((t :foreground "cyan"))
- "Face for other commands in reflogs."
- :group 'magit-faces)
-
-;;; Commands
-
-;;;###autoload
-(defun magit-reflog-current ()
- "Display the reflog of the current branch.
-If `HEAD' is detached, then show the reflog for that instead."
- (interactive)
- (magit-reflog-setup-buffer (or (magit-get-current-branch) "HEAD")))
-
-;;;###autoload
-(defun magit-reflog-other (ref)
- "Display the reflog of a branch or another ref."
- (interactive (list (magit-read-local-branch-or-ref "Show reflog for")))
- (magit-reflog-setup-buffer ref))
-
-;;;###autoload
-(defun magit-reflog-head ()
- "Display the `HEAD' reflog."
- (interactive)
- (magit-reflog-setup-buffer "HEAD"))
-
-;;; Mode
-
-(defvar magit-reflog-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-log-mode-map)
- (define-key map "\C-c\C-n" 'undefined)
- (define-key map "L" 'magit-margin-settings)
- map)
- "Keymap for `magit-reflog-mode'.")
-
-(define-derived-mode magit-reflog-mode magit-mode "Magit Reflog"
- "Mode for looking at Git reflog.
-
-This mode is documented in info node `(magit)Reflog'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
-to visit the commit at point.
-
-Type \\[magit-cherry-pick] to apply the commit at point.
-Type \\[magit-reset] to reset `HEAD' to the commit at point.
-
-\\{magit-reflog-mode-map}"
- :group 'magit-log
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-reflog-setup-buffer (ref)
- (require 'magit)
- (magit-setup-buffer #'magit-reflog-mode nil
- (magit-buffer-refname ref)
- (magit-buffer-log-args (list (format "-n%s" magit-reflog-limit)))))
-
-(defun magit-reflog-refresh-buffer ()
- (magit-set-header-line-format (concat "Reflog for " magit-buffer-refname))
- (magit-insert-section (reflogbuf)
- (magit-git-wash (apply-partially 'magit-log-wash-log 'reflog)
- "reflog" "show" "--format=%h%x00%aN%x00%gd%x00%gs" "--date=raw"
- magit-buffer-log-args magit-buffer-refname "--")))
-
-(cl-defmethod magit-buffer-value (&context (major-mode magit-reflog-mode))
- magit-buffer-refname)
-
-(defvar magit-reflog-labels
- '(("commit" . magit-reflog-commit)
- ("amend" . magit-reflog-amend)
- ("merge" . magit-reflog-merge)
- ("checkout" . magit-reflog-checkout)
- ("branch" . magit-reflog-checkout)
- ("reset" . magit-reflog-reset)
- ("rebase" . magit-reflog-rebase)
- ("cherry-pick" . magit-reflog-cherry-pick)
- ("initial" . magit-reflog-commit)
- ("pull" . magit-reflog-remote)
- ("clone" . magit-reflog-remote)
- ("autosave" . magit-reflog-commit)
- ("restart" . magit-reflog-reset)))
-
-(defun magit-reflog-format-subject (subject)
- (let* ((match (string-match magit-reflog-subject-re subject))
- (command (and match (match-string 1 subject)))
- (option (and match (match-string 2 subject)))
- (type (and match (match-string 3 subject)))
- (label (if (string= command "commit")
- (or type command)
- command))
- (text (if (string= command "commit")
- label
- (mapconcat #'identity
- (delq nil (list command option type))
- " "))))
- (format "%-16s "
- (magit--propertize-face
- text (or (cdr (assoc label magit-reflog-labels))
- 'magit-reflog-other)))))
-
-;;; _
-(provide 'magit-reflog)
-;;; magit-reflog.el ends here
+++ /dev/null
-;;; magit-refs.el --- listing references -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for listing references in a buffer.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit)
-
-;;; Options
-
-(defgroup magit-refs nil
- "Inspect and manipulate Git branches and tags."
- :link '(info-link "(magit)References Buffer")
- :group 'magit-modes)
-
-(defcustom magit-refs-mode-hook nil
- "Hook run after entering Magit-Refs mode."
- :package-version '(magit . "2.1.0")
- :group 'magit-refs
- :type 'hook)
-
-(defcustom magit-refs-sections-hook
- '(magit-insert-error-header
- magit-insert-branch-description
- magit-insert-local-branches
- magit-insert-remote-branches
- magit-insert-tags)
- "Hook run to insert sections into a references buffer."
- :package-version '(magit . "2.1.0")
- :group 'magit-refs
- :type 'hook)
-
-(defcustom magit-refs-show-commit-count nil
- "Whether to show commit counts in Magit-Refs mode buffers.
-
-all Show counts for branches and tags.
-branch Show counts for branches only.
-nil Never show counts.
-
-To change the value in an existing buffer use the command
-`magit-refs-show-commit-count'"
- :package-version '(magit . "2.1.0")
- :group 'magit-refs
- :safe (lambda (val) (memq val '(all branch nil)))
- :type '(choice (const all :tag "For branches and tags")
- (const branch :tag "For branches only")
- (const nil :tag "Never")))
-(put 'magit-refs-show-commit-count 'safe-local-variable 'symbolp)
-(put 'magit-refs-show-commit-count 'permanent-local t)
-
-(defcustom magit-refs-pad-commit-counts nil
- "Whether to pad all counts on all sides in `magit-refs-mode' buffers.
-
-If this is nil, then some commit counts are displayed right next
-to one of the branches that appear next to the count, without any
-space in between. This might look bad if the branch name faces
-look too similar to `magit-dimmed'.
-
-If this is non-nil, then spaces are placed on both sides of all
-commit counts."
- :package-version '(magit . "2.12.0")
- :group 'magit-refs
- :type 'boolean)
-
-(defvar magit-refs-show-push-remote nil
- "Whether to show the push-remotes of local branches.
-Also show the commits that the local branch is ahead and behind
-the push-target. Unfortunately there is a bug in Git that makes
-this useless (the commits ahead and behind the upstream are
-shown), so this isn't enabled yet.")
-
-(defcustom magit-refs-show-remote-prefix nil
- "Whether to show the remote prefix in lists of remote branches.
-
-This is redundant because the name of the remote is already shown
-in the heading preceding the list of its branches."
- :package-version '(magit . "2.12.0")
- :group 'magit-refs
- :type 'boolean)
-
-(defcustom magit-refs-margin
- (list nil
- (nth 1 magit-log-margin)
- 'magit-log-margin-width nil
- (nth 4 magit-log-margin))
- "Format of the margin in `magit-refs-mode' buffers.
-
-The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
-
-If INIT is non-nil, then the margin is shown initially.
-STYLE controls how to format the author or committer date.
- It can be one of `age' (to show the age of the commit),
- `age-abbreviated' (to abbreviate the time unit to a character),
- or a string (suitable for `format-time-string') to show the
- actual date. Option `magit-log-margin-show-committer-date'
- controls which date is being displayed.
-WIDTH controls the width of the margin. This exists for forward
- compatibility and currently the value should not be changed.
-AUTHOR controls whether the name of the author is also shown by
- default.
-AUTHOR-WIDTH has to be an integer. When the name of the author
- is shown, then this specifies how much space is used to do so."
- :package-version '(magit . "2.9.0")
- :group 'magit-refs
- :group 'magit-margin
- :safe (lambda (val) (memq val '(all branch nil)))
- :type magit-log-margin--custom-type
- :initialize 'magit-custom-initialize-reset
- :set-after '(magit-log-margin)
- :set (apply-partially #'magit-margin-set-variable 'magit-refs-mode))
-
-(defcustom magit-refs-margin-for-tags nil
- "Whether to show information about tags in the margin.
-
-This is disabled by default because it is slow if there are many
-tags."
- :package-version '(magit . "2.9.0")
- :group 'magit-refs
- :group 'magit-margin
- :type 'boolean)
-
-(defcustom magit-refs-primary-column-width (cons 16 32)
- "Width of the focus column in `magit-refs-mode' buffers.
-
-The primary column is the column that contains the name of the
-branch that the current row is about.
-
-If this is an integer, then the column is that many columns wide.
-Otherwise it has to be a cons-cell of two integers. The first
-specifies the minimal width, the second the maximal width. In that
-case the actual width is determined using the length of the names
-of the shown local branches. (Remote branches and tags are not
-taken into account when calculating to optimal width.)"
- :package-version '(magit . "2.12.0")
- :group 'magit-refs
- :type '(choice (integer :tag "Constant wide")
- (cons :tag "Wide constrains"
- (integer :tag "Minimum")
- (integer :tag "Maximum"))))
-
-(defcustom magit-refs-focus-column-width 5
- "Width of the focus column in `magit-refs-mode' buffers.
-
-The focus column is the first column, which marks one
-branch (usually the current branch) as the focused branch using
-\"*\" or \"@\". For each other reference, this column optionally
-shows how many commits it is ahead of the focused branch and \"<\", or
-if it isn't ahead then the commits it is behind and \">\", or if it
-isn't behind either, then a \"=\".
-
-This column may also display only \"*\" or \"@\" for the focused
-branch, in which case this option is ignored. Use \"L v\" to
-change the verbosity of this column."
- :package-version '(magit . "2.12.0")
- :group 'magit-refs
- :type 'integer)
-
-(defcustom magit-refs-filter-alist nil
- "Alist controlling which refs are omitted from `magit-refs-mode' buffers.
-
-The purpose of this option is to forgo displaying certain refs
-based on their name. If you want to not display any refs of a
-certain type, then you should remove the appropriate function
-from `magit-refs-sections-hook' instead.
-
-All keys are tried in order until one matches. Then its value
-is used and subsequent elements are ignored. If the value is
-non-nil, then the reference is displayed, otherwise it is not.
-If no element matches, then the reference is displayed.
-
-A key can either be a regular expression that the refname has to
-match, or a function that takes the refname as only argument and
-returns a boolean. A remote branch such as \"origin/master\" is
-displayed as just \"master\", however for this comparison the
-former is used."
- :package-version '(magit . "2.12.0")
- :group 'magit-refs
- :type '(alist :key-type (choice :tag "Key" regexp function)
- :value-type (boolean :tag "Value"
- :on "show (non-nil)"
- :off "omit (nil)")))
-
-(defcustom magit-visit-ref-behavior nil
- "Control how `magit-visit-ref' behaves in `magit-refs-mode' buffers.
-
-By default `magit-visit-ref' behaves like `magit-show-commit',
-in all buffers, including `magit-refs-mode' buffers. When the
-type of the section at point is `commit' then \"RET\" is bound to
-`magit-show-commit', and when the type is either `branch' or
-`tag' then it is bound to `magit-visit-ref'.
-
-\"RET\" is one of Magit's most essential keys and at least by
-default it should behave consistently across all of Magit,
-especially because users quickly learn that it does something
-very harmless; it shows more information about the thing at point
-in another buffer.
-
-However \"RET\" used to behave differently in `magit-refs-mode'
-buffers, doing surprising things, some of which cannot really be
-described as \"visit this thing\". If you have grown accustomed
-to such inconsistent, but to you useful, behavior, then you can
-restore that by adding one or more of the below symbols to the
-value of this option. But keep in mind that by doing so you
-don't only introduce inconsistencies, you also lose some
-functionality and might have to resort to `M-x magit-show-commit'
-to get it back.
-
-`magit-visit-ref' looks for these symbols in the order in which
-they are described here. If the presence of a symbol applies to
-the current situation, then the symbols that follow do not affect
-the outcome.
-
-`focus-on-ref'
-
- With a prefix argument update the buffer to show commit counts
- and lists of cherry commits relative to the reference at point
- instead of relative to the current buffer or `HEAD'.
-
- Instead of adding this symbol, consider pressing \"C-u y o RET\".
-
-`create-branch'
-
- If point is on a remote branch, then create a new local branch
- with the same name, use the remote branch as its upstream, and
- then check out the local branch.
-
- Instead of adding this symbol, consider pressing \"b c RET RET\",
- like you would do in other buffers.
-
-`checkout-any'
-
- Check out the reference at point. If that reference is a tag
- or a remote branch, then this results in a detached `HEAD'.
-
- Instead of adding this symbol, consider pressing \"b b RET\",
- like you would do in other buffers.
-
-`checkout-branch'
-
- Check out the local branch at point.
-
- Instead of adding this symbol, consider pressing \"b b RET\",
- like you would do in other buffers."
- :package-version '(magit . "2.9.0")
- :group 'magit-refs
- :group 'magit-commands
- :options '(focus-on-ref create-branch checkout-any checkout-branch)
- :type '(list :convert-widget custom-hook-convert-widget))
-
-;;; Mode
-
-(defvar magit-refs-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map "\C-y" 'magit-refs-set-show-commit-count)
- (define-key map "L" 'magit-margin-settings)
- map)
- "Keymap for `magit-refs-mode'.")
-
-(define-derived-mode magit-refs-mode magit-mode "Magit Refs"
- "Mode which lists and compares references.
-
-This mode is documented in info node `(magit)References Buffer'.
-
-\\<magit-mode-map>\
-Type \\[magit-refresh] to refresh the current buffer.
-Type \\[magit-section-toggle] to expand or hide the section at point.
-Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
-to visit the commit or branch at point.
-
-Type \\[magit-branch] to see available branch commands.
-Type \\[magit-merge] to merge the branch or commit at point.
-Type \\[magit-cherry-pick] to apply the commit at point.
-Type \\[magit-reset] to reset `HEAD' to the commit at point.
-
-\\{magit-refs-mode-map}"
- :group 'magit-refs
- (hack-dir-local-variables-non-file-buffer)
- (setq imenu-create-index-function
- #'magit-imenu--refs-create-index-function))
-
-(defun magit-refs-setup-buffer (ref args)
- (magit-setup-buffer #'magit-refs-mode nil
- (magit-buffer-upstream ref)
- (magit-buffer-arguments args)))
-
-(defun magit-refs-refresh-buffer ()
- (setq magit-set-buffer-margin-refresh (not (magit-buffer-margin-p)))
- (unless (magit-rev-verify magit-buffer-upstream)
- (setq magit-refs-show-commit-count nil))
- (magit-set-header-line-format
- (format "%s %s" magit-buffer-upstream
- (mapconcat #'identity magit-buffer-arguments " ")))
- (magit-insert-section (branchbuf)
- (magit-run-section-hook 'magit-refs-sections-hook))
- (add-hook 'kill-buffer-hook 'magit-preserve-section-visibility-cache))
-
-(cl-defmethod magit-buffer-value (&context (major-mode magit-refs-mode))
- (cons magit-buffer-upstream magit-buffer-arguments))
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-show-refs "magit-refs" nil t)
-(transient-define-prefix magit-show-refs (&optional transient)
- "List and compare references in a dedicated buffer."
- :man-page "git-branch"
- :value (lambda ()
- (magit-show-refs-arguments magit-prefix-use-buffer-arguments))
- ["Arguments"
- (magit-for-each-ref:--contains)
- ("-M" "Merged" "--merged=" magit-transient-read-revision)
- ("-m" "Merged to HEAD" "--merged")
- ("-N" "Not merged" "--no-merged=" magit-transient-read-revision)
- ("-n" "Not merged to HEAD" "--no-merged")
- (magit-for-each-ref:--sort)]
- ["Actions"
- ("y" "Show refs, comparing them with HEAD" magit-show-refs-head)
- ("c" "Show refs, comparing them with current branch" magit-show-refs-current)
- ("o" "Show refs, comparing them with other branch" magit-show-refs-other)]
- (interactive (list (or (derived-mode-p 'magit-refs-mode)
- current-prefix-arg)))
- (if transient
- (transient-setup 'magit-show-refs)
- (magit-refs-setup-buffer "HEAD" (magit-show-refs-arguments))))
-
-(defun magit-show-refs-arguments (&optional use-buffer-args)
- (unless use-buffer-args
- (setq use-buffer-args magit-direct-use-buffer-arguments))
- (let (args)
- (cond
- ((eq transient-current-command 'magit-show-refs)
- (setq args (transient-args 'magit-show-refs)))
- ((eq major-mode 'magit-refs-mode)
- (setq args magit-buffer-arguments))
- ((and (memq use-buffer-args '(always selected))
- (when-let ((buffer (magit-get-mode-buffer
- 'magit-refs-mode nil
- (eq use-buffer-args 'selected))))
- (setq args (buffer-local-value 'magit-buffer-arguments buffer))
- t)))
- (t
- (setq args (alist-get 'magit-show-refs transient-values))))
- args))
-
-(transient-define-argument magit-for-each-ref:--contains ()
- :description "Contains"
- :class 'transient-option
- :key "-c"
- :argument "--contains="
- :reader 'magit-transient-read-revision)
-
-(transient-define-argument magit-for-each-ref:--sort ()
- :description "Sort"
- :class 'transient-option
- :key "-s"
- :argument "--sort="
- :reader 'magit-read-ref-sort)
-
-(defun magit-read-ref-sort (prompt initial-input _history)
- (magit-completing-read prompt
- '("-committerdate" "-authordate"
- "committerdate" "authordate")
- nil nil initial-input))
-
-;;;###autoload
-(defun magit-show-refs-head (&optional args)
- "List and compare references in a dedicated buffer.
-Compared with `HEAD'."
- (interactive (list (magit-show-refs-arguments)))
- (magit-refs-setup-buffer "HEAD" args))
-
-;;;###autoload
-(defun magit-show-refs-current (&optional args)
- "List and compare references in a dedicated buffer.
-Compare with the current branch or `HEAD' if it is detached."
- (interactive (list (magit-show-refs-arguments)))
- (magit-refs-setup-buffer (magit-get-current-branch) args))
-
-;;;###autoload
-(defun magit-show-refs-other (&optional ref args)
- "List and compare references in a dedicated buffer.
-Compared with a branch read from the user."
- (interactive (list (magit-read-other-branch "Compare with")
- (magit-show-refs-arguments)))
- (magit-refs-setup-buffer ref args))
-
-(defun magit-refs-set-show-commit-count ()
- "Change for which refs the commit count is shown."
- (interactive)
- (setq-local magit-refs-show-commit-count
- (magit-read-char-case "Show commit counts for " nil
- (?a "[a]ll refs" 'all)
- (?b "[b]ranches only" t)
- (?n "[n]othing" nil)))
- (magit-refresh))
-
-(defun magit-visit-ref ()
- "Visit the reference or revision at point in another buffer.
-If there is no revision at point or with a prefix argument prompt
-for a revision.
-
-This command behaves just like `magit-show-commit', except if
-point is on a reference in a `magit-refs-mode' buffer (a buffer
-listing branches and tags), in which case the behavior may be
-different, but only if you have customized the option
-`magit-visit-ref-behavior' (which see)."
- (interactive)
- (if (and (derived-mode-p 'magit-refs-mode)
- (magit-section-match '(branch tag)))
- (let ((ref (oref (magit-current-section) value)))
- (cond (current-prefix-arg
- (cond ((memq 'focus-on-ref magit-visit-ref-behavior)
- (magit-refs-setup-buffer ref (magit-show-refs-arguments)))
- (magit-visit-ref-behavior
- ;; Don't prompt for commit to visit.
- (let ((current-prefix-arg nil))
- (call-interactively #'magit-show-commit)))))
- ((and (memq 'create-branch magit-visit-ref-behavior)
- (magit-section-match [branch remote]))
- (let ((branch (cdr (magit-split-branch-name ref))))
- (if (magit-branch-p branch)
- (if (magit-rev-eq branch ref)
- (magit-call-git "checkout" branch)
- (setq branch (propertize branch 'face 'magit-branch-local))
- (setq ref (propertize ref 'face 'magit-branch-remote))
- (pcase (prog1 (read-char-choice (format (propertize "\
-Branch %s already exists.
- [c]heckout %s as-is
- [r]reset %s to %s and checkout %s
- [a]bort " 'face 'minibuffer-prompt) branch branch branch ref branch)
- '(?c ?r ?a))
- (message "")) ; otherwise prompt sticks
- (?c (magit-call-git "checkout" branch))
- (?r (magit-call-git "checkout" "-B" branch ref))
- (?a (user-error "Abort"))))
- (magit-call-git "checkout" "-b" branch ref))
- (setq magit-buffer-upstream branch)
- (magit-refresh)))
- ((or (memq 'checkout-any magit-visit-ref-behavior)
- (and (memq 'checkout-branch magit-visit-ref-behavior)
- (magit-section-match [branch local])))
- (magit-call-git "checkout" ref)
- (setq magit-buffer-upstream ref)
- (magit-refresh))
- (t
- (call-interactively #'magit-show-commit))))
- (call-interactively #'magit-show-commit)))
-
-;;; Sections
-
-(defvar magit-remote-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-delete-thing] 'magit-remote-remove)
- (define-key map "R" 'magit-remote-rename)
- map)
- "Keymap for `remote' sections.")
-
-(defvar magit-branch-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-visit-ref)
- (define-key map [remap magit-delete-thing] 'magit-branch-delete)
- (define-key map "R" 'magit-branch-rename)
- map)
- "Keymap for `branch' sections.")
-
-(defvar magit-tag-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-visit-ref)
- (define-key map [remap magit-delete-thing] 'magit-tag-delete)
- map)
- "Keymap for `tag' sections.")
-
-(defun magit-insert-branch-description ()
- "Insert header containing the description of the current branch.
-Insert a header line with the name and description of the
-current branch. The description is taken from the Git variable
-`branch.<NAME>.description'; if that is undefined then no header
-line is inserted at all."
- (when-let ((branch (magit-get-current-branch))
- (desc (magit-get "branch" branch "description"))
- (desc (split-string desc "\n")))
- (when (equal (car (last desc)) "")
- (setq desc (butlast desc)))
- (magit-insert-section (branchdesc branch t)
- (magit-insert-heading branch ": " (car desc))
- (when (cdr desc)
- (insert (mapconcat 'identity (cdr desc) "\n"))
- (insert "\n\n")))))
-
-(defun magit-insert-tags ()
- "Insert sections showing all tags."
- (when-let ((tags (magit-git-lines "tag" "--list" "-n" magit-buffer-arguments)))
- (let ((_head (magit-rev-parse "HEAD")))
- (magit-insert-section (tags)
- (magit-insert-heading "Tags:")
- (dolist (tag tags)
- (string-match "^\\([^ \t]+\\)[ \t]+\\([^ \t\n].*\\)?" tag)
- (let ((tag (match-string 1 tag))
- (msg (match-string 2 tag)))
- (when (magit-refs--insert-refname-p tag)
- (magit-insert-section (tag tag t)
- (magit-insert-heading
- (magit-refs--format-focus-column tag 'tag)
- (propertize tag 'font-lock-face 'magit-tag)
- (make-string (max 1 (- magit-refs-primary-column-width
- (length tag)))
- ?\s)
- (and msg (magit-log-propertize-keywords nil msg)))
- (when (and magit-refs-margin-for-tags (magit-buffer-margin-p))
- (magit-refs--format-margin tag))
- (magit-refs--insert-cherry-commits tag)))))
- (insert ?\n)
- (magit-make-margin-overlay nil t)))))
-
-(defun magit-insert-remote-branches ()
- "Insert sections showing all remote-tracking branches."
- (dolist (remote (magit-list-remotes))
- (magit-insert-section (remote remote)
- (magit-insert-heading
- (let ((pull (magit-get "remote" remote "url"))
- (push (magit-get "remote" remote "pushurl")))
- (format (propertize "Remote %s (%s):"
- 'font-lock-face 'magit-section-heading)
- (propertize remote 'font-lock-face 'magit-branch-remote)
- (concat pull (and pull push ", ") push))))
- (let (head)
- (dolist (line (magit-git-lines "for-each-ref" "--format=\
-%(symref:short)%00%(refname:short)%00%(refname)%00%(subject)"
- (concat "refs/remotes/" remote)
- magit-buffer-arguments))
- (pcase-let ((`(,head-branch ,branch ,ref ,msg)
- (-replace "" nil (split-string line "\0"))))
- (if head-branch
- (progn (cl-assert (equal branch (concat remote "/HEAD")))
- (setq head head-branch))
- (when (magit-refs--insert-refname-p branch)
- (magit-insert-section (branch branch t)
- (let ((headp (equal branch head))
- (abbrev (if magit-refs-show-remote-prefix
- branch
- (substring branch (1+ (length remote))))))
- (magit-insert-heading
- (magit-refs--format-focus-column branch)
- (magit-refs--propertize-branch
- abbrev ref (and headp 'magit-branch-remote-head))
- (make-string (max 1 (- magit-refs-primary-column-width
- (length abbrev)))
- ?\s)
- (and msg (magit-log-propertize-keywords nil msg))))
- (when (magit-buffer-margin-p)
- (magit-refs--format-margin branch))
- (magit-refs--insert-cherry-commits branch)))))))
- (insert ?\n)
- (magit-make-margin-overlay nil t))))
-
-(defun magit-insert-local-branches ()
- "Insert sections showing all local branches."
- (magit-insert-section (local nil)
- (magit-insert-heading "Branches:")
- (dolist (line (magit-refs--format-local-branches))
- (pcase-let ((`(,branch . ,strings) line))
- (magit-insert-section
- ((eval (if branch 'branch 'commit))
- (or branch (magit-rev-parse "HEAD"))
- t)
- (apply #'magit-insert-heading strings)
- (when (magit-buffer-margin-p)
- (magit-refs--format-margin branch))
- (magit-refs--insert-cherry-commits branch))))
- (insert ?\n)
- (magit-make-margin-overlay nil t)))
-
-(defun magit-refs--format-local-branches ()
- (let ((lines (-keep 'magit-refs--format-local-branch
- (magit-git-lines
- "for-each-ref"
- (concat "--format=\
-%(HEAD)%00%(refname:short)%00%(refname)%00\
-%(upstream:short)%00%(upstream)%00%(upstream:track)%00"
- (if magit-refs-show-push-remote "\
-%(push:remotename)%00%(push)%00%(push:track)%00%(subject)"
- "%00%00%00%(subject)"))
- "refs/heads"
- magit-buffer-arguments))))
- (unless (magit-get-current-branch)
- (push (magit-refs--format-local-branch
- (concat "*\0\0\0\0\0\0\0\0" (magit-rev-format "%s")))
- lines))
- (setq-local magit-refs-primary-column-width
- (let ((def (default-value 'magit-refs-primary-column-width)))
- (if (atom def)
- def
- (pcase-let ((`(,min . ,max) def))
- (min max (apply #'max min (mapcar #'car lines)))))))
- (mapcar (pcase-lambda (`(,_ ,branch ,focus ,branch-desc ,u:ahead ,p:ahead
- ,u:behind ,upstream ,p:behind ,push ,msg))
- (list branch focus branch-desc u:ahead p:ahead
- (make-string (max 1 (- magit-refs-primary-column-width
- (length (concat branch-desc
- u:ahead
- p:ahead
- u:behind))))
- ?\s)
- u:behind upstream p:behind push
- msg))
- lines)))
-
-(defun magit-refs--format-local-branch (line)
- (pcase-let ((`(,head ,branch ,ref ,upstream ,u:ref ,u:track
- ,push ,p:ref ,p:track ,msg)
- (-replace "" nil (split-string line "\0"))))
- (when (or (not branch)
- (magit-refs--insert-refname-p branch))
- (let* ((headp (equal head "*"))
- (pushp (and push
- magit-refs-show-push-remote
- (magit-rev-verify p:ref)
- (not (equal p:ref u:ref))))
- (branch-desc
- (if branch
- (magit-refs--propertize-branch
- branch ref (and headp 'magit-branch-current))
- (magit--propertize-face "(detached)"
- 'font-lock-warning-face)))
- (u:ahead (and u:track
- (string-match "ahead \\([0-9]+\\)" u:track)
- (magit--propertize-face
- (concat (and magit-refs-pad-commit-counts " ")
- (match-string 1 u:track)
- ">")
- 'magit-dimmed)))
- (u:behind (and u:track
- (string-match "behind \\([0-9]+\\)" u:track)
- (magit--propertize-face
- (concat "<"
- (match-string 1 u:track)
- (and magit-refs-pad-commit-counts " "))
- 'magit-dimmed)))
- (p:ahead (and pushp p:track
- (string-match "ahead \\([0-9]+\\)" p:track)
- (magit--propertize-face
- (concat (match-string 1 p:track)
- ">"
- (and magit-refs-pad-commit-counts " "))
- 'magit-branch-remote)))
- (p:behind (and pushp p:track
- (string-match "behind \\([0-9]+\\)" p:track)
- (magit--propertize-face
- (concat "<"
- (match-string 1 p:track)
- (and magit-refs-pad-commit-counts " "))
- 'magit-dimmed))))
- (list (1+ (length (concat branch-desc u:ahead p:ahead u:behind)))
- branch
- (magit-refs--format-focus-column branch headp)
- branch-desc u:ahead p:ahead u:behind
- (and upstream
- (concat (if (equal u:track "[gone]")
- (magit--propertize-face upstream 'error)
- (magit-refs--propertize-branch upstream u:ref))
- " "))
- (and pushp
- (concat p:behind
- (magit--propertize-face
- push 'magit-branch-remote)
- " "))
- (and msg (magit-log-propertize-keywords nil msg)))))))
-
-(defun magit-refs--format-focus-column (ref &optional type)
- (let ((focus magit-buffer-upstream)
- (width (if magit-refs-show-commit-count
- magit-refs-focus-column-width
- 1)))
- (format
- (format "%%%ss " width)
- (cond ((or (equal ref focus)
- (and (eq type t)
- (equal focus "HEAD")))
- (magit--propertize-face (concat (if (equal focus "HEAD") "@" "*")
- (make-string (1- width) ?\s))
- 'magit-section-heading))
- ((if (eq type 'tag)
- (eq magit-refs-show-commit-count 'all)
- magit-refs-show-commit-count)
- (pcase-let ((`(,behind ,ahead)
- (magit-rev-diff-count magit-buffer-upstream ref)))
- (magit--propertize-face
- (cond ((> ahead 0) (concat "<" (number-to-string ahead)))
- ((> behind 0) (concat (number-to-string behind) ">"))
- (t "="))
- 'magit-dimmed)))
- (t "")))))
-
-(defun magit-refs--propertize-branch (branch ref &optional head-face)
- (let ((face (cdr (cl-find-if (pcase-lambda (`(,re . ,_))
- (string-match-p re ref))
- magit-ref-namespaces))))
- (magit--propertize-face
- branch (if head-face (list face head-face) face))))
-
-(defun magit-refs--insert-refname-p (refname)
- (--if-let (-first (pcase-lambda (`(,key . ,_))
- (if (functionp key)
- (funcall key refname)
- (string-match-p key refname)))
- magit-refs-filter-alist)
- (cdr it)
- t))
-
-(defun magit-refs--insert-cherry-commits (ref)
- (magit-insert-section-body
- (let ((start (point))
- (magit-insert-section--current nil))
- (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry)
- "cherry" "-v" (magit-abbrev-arg) magit-buffer-upstream ref)
- (if (= (point) start)
- (message "No cherries for %s" ref)
- (magit-make-margin-overlay nil t)))))
-
-(defun magit-refs--format-margin (commit)
- (save-excursion
- (goto-char (line-beginning-position 0))
- (let ((line (magit-rev-format "%ct%cN" commit)))
- (magit-log-format-margin commit
- (substring line 10)
- (substring line 0 10)))))
-
-;;; _
-(provide 'magit-refs)
-;;; magit-refs.el ends here
+++ /dev/null
-;;; magit-remote.el --- transfer Git commits -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements remote commands.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Options
-
-(defcustom magit-remote-add-set-remote.pushDefault 'ask-if-unset
- "Whether to set the value of `remote.pushDefault' after adding a remote.
-
-If `ask', then always ask. If `ask-if-unset', then ask, but only
-if the variable isn't set already. If nil, then don't ever set.
-If the value is a string, then set without asking, provided that
-the name of the added remote is equal to that string and the
-variable isn't already set."
- :package-version '(magit . "2.4.0")
- :group 'magit-commands
- :type '(choice (const :tag "ask if unset" ask-if-unset)
- (const :tag "always ask" ask)
- (string :tag "set if named")
- (const :tag "don't set")))
-
-(defcustom magit-remote-direct-configure t
- "Whether the command `magit-remote' shows Git variables.
-When set to nil, no variables are displayed by this transient
-command, instead the sub-transient `magit-remote-configure'
-has to be used to view and change remote related variables."
- :package-version '(magit . "2.12.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defcustom magit-prefer-push-default nil
- "Whether to prefer `remote.pushDefault' over per-branch variables."
- :package-version '(magit . "3.0.0")
- :group 'magit-commands
- :type 'boolean)
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-remote "magit-remote" nil t)
-(transient-define-prefix magit-remote (remote)
- "Add, configure or remove a remote."
- :man-page "git-remote"
- :value '("-f")
- ["Variables"
- :if (lambda ()
- (and magit-remote-direct-configure
- (oref transient--prefix scope)))
- ("u" magit-remote.<remote>.url)
- ("U" magit-remote.<remote>.fetch)
- ("s" magit-remote.<remote>.pushurl)
- ("S" magit-remote.<remote>.push)
- ("O" magit-remote.<remote>.tagopt)]
- ["Arguments for add"
- ("-f" "Fetch after add" "-f")]
- ["Actions"
- [("a" "Add" magit-remote-add)
- ("r" "Rename" magit-remote-rename)
- ("k" "Remove" magit-remote-remove)]
- [("C" "Configure..." magit-remote-configure)
- ("p" "Prune stale branches" magit-remote-prune)
- ("P" "Prune stale refspecs" magit-remote-prune-refspecs)]]
- (interactive (list (magit-get-current-remote)))
- (transient-setup 'magit-remote nil nil :scope remote))
-
-(defun magit-read-url (prompt &optional initial-input)
- (let ((url (magit-read-string-ns prompt initial-input)))
- (if (string-prefix-p "~" url)
- (expand-file-name url)
- url)))
-
-;;;###autoload
-(defun magit-remote-add (remote url &optional args)
- "Add a remote named REMOTE and fetch it."
- (interactive
- (let ((origin (magit-get "remote.origin.url"))
- (remote (magit-read-string-ns "Remote name")))
- (list remote
- (magit-read-url
- "Remote url"
- (and origin
- (string-match "\\([^:/]+\\)/[^/]+\\(\\.git\\)?\\'" origin)
- (replace-match remote t t origin 1)))
- (transient-args 'magit-remote))))
- (if (pcase (list magit-remote-add-set-remote.pushDefault
- (magit-get "remote.pushDefault"))
- (`(,(pred stringp) ,_) t)
- ((or `(ask ,_) `(ask-if-unset nil))
- (y-or-n-p (format "Set `remote.pushDefault' to \"%s\"? " remote))))
- (progn (magit-call-git "remote" "add" args remote url)
- (setf (magit-get "remote.pushDefault") remote)
- (magit-refresh))
- (magit-run-git-async "remote" "add" args remote url)))
-
-;;;###autoload
-(defun magit-remote-rename (old new)
- "Rename the remote named OLD to NEW."
- (interactive
- (let ((remote (magit-read-remote "Rename remote")))
- (list remote (magit-read-string-ns (format "Rename %s to" remote)))))
- (unless (string= old new)
- (magit-call-git "remote" "rename" old new)
- (magit-remote--cleanup-push-variables old new)
- (magit-refresh)))
-
-;;;###autoload
-(defun magit-remote-remove (remote)
- "Delete the remote named REMOTE."
- (interactive (list (magit-read-remote "Delete remote")))
- (magit-call-git "remote" "rm" remote)
- (magit-remote--cleanup-push-variables remote)
- (magit-refresh))
-
-(defun magit-remote--cleanup-push-variables (remote &optional new-name)
- (magit-with-toplevel
- (when (equal (magit-get "remote.pushDefault") remote)
- (magit-set new-name "remote.pushDefault"))
- (dolist (var (magit-git-lines "config" "--name-only"
- "--get-regexp" "^branch\.[^.]*\.pushRemote"
- (format "^%s$" remote)))
- (magit-call-git "config" (and (not new-name) "--unset") var new-name))))
-
-(defconst magit--refspec-re "\\`\\(\\+\\)?\\([^:]+\\):\\(.*\\)\\'")
-
-;;;###autoload
-(defun magit-remote-prune (remote)
- "Remove stale remote-tracking branches for REMOTE."
- (interactive (list (magit-read-remote "Prune stale branches of remote")))
- (magit-run-git-async "remote" "prune" remote))
-
-;;;###autoload
-(defun magit-remote-prune-refspecs (remote)
- "Remove stale refspecs for REMOTE.
-
-A refspec is stale if there no longer exists at least one branch
-on the remote that would be fetched due to that refspec. A stale
-refspec is problematic because its existence causes Git to refuse
-to fetch according to the remaining non-stale refspecs.
-
-If only stale refspecs remain, then offer to either delete the
-remote or to replace the stale refspecs with the default refspec.
-
-Also remove the remote-tracking branches that were created due to
-the now stale refspecs. Other stale branches are not removed."
- (interactive (list (magit-read-remote "Prune refspecs of remote")))
- (let* ((tracking-refs (magit-list-remote-branches remote))
- (remote-refs (magit-remote-list-refs remote))
- (variable (format "remote.%s.fetch" remote))
- (refspecs (magit-get-all variable))
- stale)
- (dolist (refspec refspecs)
- (when (string-match magit--refspec-re refspec)
- (let ((theirs (match-string 2 refspec))
- (ours (match-string 3 refspec)))
- (unless (if (string-match "\\*" theirs)
- (let ((re (replace-match ".*" t t theirs)))
- (--some (string-match-p re it) remote-refs))
- (member theirs remote-refs))
- (push (cons refspec
- (if (string-match "\\*" ours)
- (let ((re (replace-match ".*" t t ours)))
- (--filter (string-match-p re it) tracking-refs))
- (list (car (member ours tracking-refs)))))
- stale)))))
- (if (not stale)
- (message "No stale refspecs for remote %S" remote)
- (if (= (length stale)
- (length refspecs))
- (magit-read-char-case
- (format "All of %s's refspecs are stale. " remote) nil
- (?s "replace with [d]efault refspec"
- (magit-set-all
- (list (format "+refs/heads/*:refs/remotes/%s/*" remote))
- variable))
- (?r "[r]emove remote"
- (magit-call-git "remote" "rm" remote))
- (?a "or [a]abort"
- (user-error "Abort")))
- (if (if (= (length stale) 1)
- (pcase-let ((`(,refspec . ,refs) (car stale)))
- (magit-confirm 'prune-stale-refspecs
- (format "Prune stale refspec %s and branch %%s" refspec)
- (format "Prune stale refspec %s and %%i branches" refspec)
- nil refs))
- (magit-confirm 'prune-stale-refspecs nil
- (format "Prune %%i stale refspecs and %i branches"
- (length (cl-mapcan (lambda (s) (copy-sequence (cdr s)))
- stale)))
- nil
- (mapcar (pcase-lambda (`(,refspec . ,refs))
- (concat refspec "\n"
- (mapconcat (lambda (b) (concat " " b))
- refs "\n")))
- stale)))
- (pcase-dolist (`(,refspec . ,refs) stale)
- (magit-call-git "config" "--unset" variable
- (regexp-quote refspec))
- (magit--log-action
- (lambda (refs)
- (format "Deleting %i branches" (length refs)))
- (lambda (ref)
- (format "Deleting branch %s (was %s)" ref
- (magit-rev-parse "--short" ref)))
- refs)
- (dolist (ref refs)
- (magit-call-git "update-ref" "-d" ref)))
- (user-error "Abort")))
- (magit-refresh))))
-
-;;;###autoload
-(defun magit-remote-set-head (remote &optional branch)
- "Set the local representation of REMOTE's default branch.
-Query REMOTE and set the symbolic-ref refs/remotes/<remote>/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/<remote>/HEAD\"."
- (interactive (list (magit-read-remote "Unset HEAD for remote")))
- (magit-run-git "remote" "set-head" remote "--delete"))
-
-;;; Configure
-
-;;;###autoload (autoload 'magit-remote-configure "magit-remote" nil t)
-(transient-define-prefix magit-remote-configure (remote)
- "Configure a remote."
- :man-page "git-remote"
- [:description
- (lambda ()
- (concat
- (propertize "Configure " 'face 'transient-heading)
- (propertize (oref transient--prefix scope) 'face 'magit-branch-remote)))
- ("u" magit-remote.<remote>.url)
- ("U" magit-remote.<remote>.fetch)
- ("s" magit-remote.<remote>.pushurl)
- ("S" magit-remote.<remote>.push)
- ("O" magit-remote.<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) "<name>"))
- "Configure remote")))
-
-(transient-define-infix magit-remote.<remote>.url ()
- :class 'magit--git-variable:urls
- :scope 'magit--read-remote-scope
- :variable "remote.%s.url"
- :multi-value t
- :history-key 'magit-remote.<remote>.*url)
-
-(transient-define-infix magit-remote.<remote>.fetch ()
- :class 'magit--git-variable
- :scope 'magit--read-remote-scope
- :variable "remote.%s.fetch"
- :multi-value t)
-
-(transient-define-infix magit-remote.<remote>.pushurl ()
- :class 'magit--git-variable:urls
- :scope 'magit--read-remote-scope
- :variable "remote.%s.pushurl"
- :multi-value t
- :history-key 'magit-remote.<remote>.*url
- :seturl-arg "--push")
-
-(transient-define-infix magit-remote.<remote>.push ()
- :class 'magit--git-variable
- :scope 'magit--read-remote-scope
- :variable "remote.%s.push")
-
-(transient-define-infix magit-remote.<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
+++ /dev/null
-;;; magit-repos.el --- listing repositories -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for listing repositories. This
-;; includes getting a Lisp list of known repositories as well as a
-;; mode for listing repositories in a buffer.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit-core)
-
-(declare-function magit-status-setup-buffer "magit-status" (directory))
-
-(defvar x-stretch-cursor)
-
-;;; Options
-
-(defcustom magit-repository-directories nil
- "List of directories that are or contain Git repositories.
-
-Each element has the form (DIRECTORY . DEPTH). DIRECTORY has
-to be a directory or a directory file-name, a string. DEPTH,
-an integer, specifies the maximum depth to look for Git
-repositories. If it is 0, then only add DIRECTORY itself.
-
-This option controls which repositories are being listed by
-`magit-list-repositories'. It also affects `magit-status'
-\(which see) in potentially surprising ways."
- :package-version '(magit . "3.0.0")
- :group 'magit-essentials
- :type '(repeat (cons directory (integer :tag "Depth"))))
-
-(defgroup magit-repolist nil
- "List repositories in a buffer."
- :link '(info-link "(magit)Repository List")
- :group 'magit-modes)
-
-(defcustom magit-repolist-mode-hook '(hl-line-mode)
- "Hook run after entering Magit-Repolist mode."
- :package-version '(magit . "2.9.0")
- :group 'magit-repolist
- :type 'hook
- :get 'magit-hook-custom-get
- :options '(hl-line-mode))
-
-(defcustom magit-repolist-columns
- '(("Name" 25 magit-repolist-column-ident nil)
- ("Version" 25 magit-repolist-column-version nil)
- ("B<U" 3 magit-repolist-column-unpulled-from-upstream
- ((:right-align t)
- (:help-echo "Upstream changes not in branch")))
- ("B>U" 3 magit-repolist-column-unpushed-to-upstream
- ((:right-align t)
- (:help-echo "Local changes not in upstream")))
- ("Path" 99 magit-repolist-column-path nil))
- "List of columns displayed by `magit-list-repositories'.
-
-Each element has the form (HEADER WIDTH FORMAT PROPS).
-
-HEADER is the string displayed in the header. WIDTH is the width
-of the column. FORMAT is a function that is called with one
-argument, the repository identification (usually its basename),
-and with `default-directory' bound to the toplevel of its working
-tree. It has to return a string to be inserted or nil. PROPS is
-an alist that supports the keys `:right-align' and `:pad-right'.
-Some entries also use `:help-echo', but `tabulated-list' does not
-actually support that yet."
- :package-version '(magit . "2.12.0")
- :group 'magit-repolist
- :type `(repeat (list :tag "Column"
- (string :tag "Header Label")
- (integer :tag "Column Width")
- (function :tag "Inserter Function")
- (repeat :tag "Properties"
- (list (choice :tag "Property"
- (const :right-align)
- (const :pad-right)
- (symbol))
- (sexp :tag "Value"))))))
-
-(defcustom magit-repolist-column-flag-alist
- '((magit-untracked-files . "N")
- (magit-unstaged-files . "U")
- (magit-staged-files . "S"))
- "Association list of predicates and flags for `magit-repolist-column-flag'.
-
-Each element is of the form (FUNCTION . FLAG). Each FUNCTION is
-called with no arguments, with `default-directory' bound to the
-top level of a repository working tree, until one of them returns
-a non-nil value. FLAG corresponding to that function is returned
-as the value of `magit-repolist-column-flag'."
- :package-version '(magit . "3.0.0")
- :group 'magit-repolist
- :type '(alist :key-type (function :tag "Predicate Function")
- :value-type (string :tag "Flag")))
-
-;;; List Repositories
-;;;; Command
-;;;###autoload
-(defun magit-list-repositories ()
- "Display a list of repositories.
-
-Use the options `magit-repository-directories' to control which
-repositories are displayed."
- (interactive)
- (if magit-repository-directories
- (with-current-buffer (get-buffer-create "*Magit Repositories*")
- (magit-repolist-mode)
- (magit-repolist-refresh)
- (tabulated-list-print)
- (switch-to-buffer (current-buffer)))
- (message "You need to customize `magit-repository-directories' %s"
- "before you can list repositories")))
-
-;;;; Mode
-
-(defvar magit-repolist-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map tabulated-list-mode-map)
- (define-key map (kbd "C-m") 'magit-repolist-status)
- map)
- "Local keymap for Magit-Repolist mode buffers.")
-
-(defun magit-repolist-status (&optional _button)
- "Show the status for the repository at point."
- (interactive)
- (--if-let (tabulated-list-get-id)
- (magit-status-setup-buffer (expand-file-name it))
- (user-error "There is no repository at point")))
-
-(define-derived-mode magit-repolist-mode tabulated-list-mode "Repos"
- "Major mode for browsing a list of Git repositories."
- (setq-local x-stretch-cursor nil)
- (setq tabulated-list-padding 0)
- (setq tabulated-list-sort-key (cons "Path" nil))
- (setq tabulated-list-format
- (vconcat (mapcar (pcase-lambda (`(,title ,width ,_fn ,props))
- (nconc (list title width t)
- (-flatten props)))
- magit-repolist-columns)))
- (tabulated-list-init-header)
- (add-hook 'tabulated-list-revert-hook 'magit-repolist-refresh nil t)
- (setq imenu-prev-index-position-function
- 'magit-imenu--repolist-prev-index-position-function)
- (setq imenu-extract-index-name-function
- 'magit-imenu--repolist-extract-index-name-function))
-
-(defun magit-repolist-refresh ()
- (setq tabulated-list-entries
- (mapcar (pcase-lambda (`(,id . ,path))
- (let ((default-directory path))
- (list path
- (vconcat (--map (or (funcall (nth 2 it) id) "")
- magit-repolist-columns)))))
- (magit-list-repos-uniquify
- (--map (cons (file-name-nondirectory (directory-file-name it))
- it)
- (magit-list-repos))))))
-
-;;;; Columns
-
-(defun magit-repolist-column-ident (id)
- "Insert the identification of the repository.
-Usually this is just its basename."
- id)
-
-(defun magit-repolist-column-path (_id)
- "Insert the absolute path of the repository."
- (abbreviate-file-name default-directory))
-
-(defun magit-repolist-column-version (_id)
- "Insert a description of the repository's `HEAD' revision."
- (when-let ((v (or (magit-git-string "describe" "--tags" "--dirty")
- ;; If there are no tags, use the date in MELPA format.
- (magit-git-string "show" "--no-patch" "--format=%cd-g%h"
- "--date=format:%Y%m%d.%H%M"))))
- (save-match-data
- (when (string-match "-dirty\\'" v)
- (magit--put-face (1+ (match-beginning 0)) (length v) 'error v))
- (if (and v (string-match "\\`[0-9]" v))
- (concat " " v)
- v))))
-
-(defun magit-repolist-column-branch (_id)
- "Insert the current branch."
- (magit-get-current-branch))
-
-(defun magit-repolist-column-upstream (_id)
- "Insert the upstream branch of the current branch."
- (magit-get-upstream-branch))
-
-(defun magit-repolist-column-flag (_id)
- "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-unpulled-from-upstream (_id)
- "Insert number of upstream commits not in the current branch."
- (--when-let (magit-get-upstream-branch)
- (let ((n (cadr (magit-rev-diff-count "HEAD" it))))
- (magit--propertize-face
- (number-to-string n) (if (> n 0) 'bold 'shadow)))))
-
-(defun magit-repolist-column-unpulled-from-pushremote (_id)
- "Insert number of commits in the push branch but not the current branch."
- (--when-let (magit-get-push-branch nil t)
- (let ((n (cadr (magit-rev-diff-count "HEAD" it))))
- (magit--propertize-face
- (number-to-string n) (if (> n 0) 'bold 'shadow)))))
-
-(defun magit-repolist-column-unpushed-to-upstream (_id)
- "Insert number of commits in the current branch but not its upstream."
- (--when-let (magit-get-upstream-branch)
- (let ((n (car (magit-rev-diff-count "HEAD" it))))
- (magit--propertize-face
- (number-to-string n) (if (> n 0) 'bold 'shadow)))))
-
-(defun magit-repolist-column-unpushed-to-pushremote (_id)
- "Insert number of commits in the current branch but not its push branch."
- (--when-let (magit-get-push-branch nil t)
- (let ((n (car (magit-rev-diff-count "HEAD" it))))
- (magit--propertize-face
- (number-to-string n) (if (> n 0) 'bold 'shadow)))))
-
-(defun magit-repolist-column-branches (_id)
- "Insert number of branches."
- (let ((n (length (magit-list-local-branches))))
- (magit--propertize-face (number-to-string n) (if (> n 1) 'bold 'shadow))))
-
-(defun magit-repolist-column-stashes (_id)
- "Insert number of stashes."
- (let ((n (length (magit-list-stashes))))
- (magit--propertize-face (number-to-string n) (if (> n 0) 'bold 'shadow))))
-
-;;; Read Repository
-
-(defun magit-read-repository (&optional read-directory-name)
- "Read a Git repository in the minibuffer, with completion.
-
-The completion choices are the basenames of top-levels of
-repositories found in the directories specified by option
-`magit-repository-directories'. In case of name conflicts
-the basenames are prefixed with the name of the respective
-parent directories. The returned value is the actual path
-to the selected repository.
-
-If READ-DIRECTORY-NAME is non-nil or no repositories can be
-found based on the value of `magit-repository-directories',
-then read an arbitrary directory using `read-directory-name'
-instead."
- (if-let ((repos (and (not read-directory-name)
- magit-repository-directories
- (magit-repos-alist))))
- (let ((reply (magit-completing-read "Git repository" repos)))
- (file-name-as-directory
- (or (cdr (assoc reply repos))
- (if (file-directory-p reply)
- (expand-file-name reply)
- (user-error "Not a repository or a directory: %s" reply)))))
- (file-name-as-directory
- (read-directory-name "Git repository: "
- (or (magit-toplevel) default-directory)))))
-
-(defun magit-list-repos ()
- (cl-mapcan (pcase-lambda (`(,dir . ,depth))
- (magit-list-repos-1 dir depth))
- magit-repository-directories))
-
-(defun magit-list-repos-1 (directory depth)
- (cond ((file-readable-p (expand-file-name ".git" directory))
- (list (file-name-as-directory directory)))
- ((and (> depth 0) (magit-file-accessible-directory-p directory))
- (--mapcat (and (file-directory-p it)
- (magit-list-repos-1 it (1- depth)))
- (directory-files directory t
- directory-files-no-dot-files-regexp t)))))
-
-(defun magit-list-repos-uniquify (alist)
- (let (result (dict (make-hash-table :test 'equal)))
- (dolist (a (delete-dups alist))
- (puthash (car a) (cons (cdr a) (gethash (car a) dict)) dict))
- (maphash
- (lambda (key value)
- (if (= (length value) 1)
- (push (cons key (car value)) result)
- (setq result
- (append result
- (magit-list-repos-uniquify
- (--map (cons (concat
- key "\\"
- (file-name-nondirectory
- (directory-file-name
- (substring it 0 (- (1+ (length key)))))))
- it)
- value))))))
- dict)
- result))
-
-(defun magit-repos-alist ()
- (magit-list-repos-uniquify
- (--map (cons (file-name-nondirectory (directory-file-name it)) it)
- (magit-list-repos))))
-
-;;; _
-(provide 'magit-repos)
-;;; magit-repos.el ends here
+++ /dev/null
-;;; magit-reset.el --- reset fuctionality -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements reset commands.
-
-;;; Code:
-
-(require 'magit)
-
-;;;###autoload (autoload 'magit-reset "magit" nil t)
-(transient-define-prefix magit-reset ()
- "Reset the `HEAD', index and/or worktree to a previous state."
- :man-page "git-reset"
- ["Reset"
- ("m" "mixed (HEAD and index)" magit-reset-mixed)
- ("s" "soft (HEAD only)" magit-reset-soft)
- ("h" "hard (HEAD, index and files)" magit-reset-hard)
- ("k" "keep (HEAD and index, keeping uncommitted)" magit-reset-keep)
- ("i" "index (only)" magit-reset-index)
- ("w" "worktree (only)" magit-reset-worktree)
- ""
- ("f" "a file" magit-file-checkout)])
-
-;;;###autoload
-(defun magit-reset-mixed (commit)
- "Reset the `HEAD' and index to COMMIT, but not the working tree.
-\n(git reset --mixed COMMIT)"
- (interactive (list (magit-reset-read-branch-or-commit "Reset %s to")))
- (magit-reset-internal "--mixed" commit))
-
-;;;###autoload
-(defun magit-reset-soft (commit)
- "Reset the `HEAD' to COMMIT, but not the index and working tree.
-\n(git reset --soft REVISION)"
- (interactive (list (magit-reset-read-branch-or-commit "Soft reset %s to")))
- (magit-reset-internal "--soft" commit))
-
-;;;###autoload
-(defun magit-reset-hard (commit)
- "Reset the `HEAD', index, and working tree to COMMIT.
-\n(git reset --hard REVISION)"
- (interactive (list (magit-reset-read-branch-or-commit
- (concat (magit--propertize-face "Hard" 'bold)
- " reset %s to"))))
- (magit-reset-internal "--hard" commit))
-
-;;;###autoload
-(defun magit-reset-keep (commit)
- "Reset the `HEAD' and index to COMMIT, while keeping uncommitted changes.
-\n(git reset --keep REVISION)"
- (interactive (list (magit-reset-read-branch-or-commit "Reset %s to")))
- (magit-reset-internal "--keep" commit))
-
-;;;###autoload
-(defun magit-reset-index (commit)
- "Reset the index to COMMIT.
-Keep the `HEAD' and working tree as-is, so if COMMIT refers to the
-head this effectively unstages all changes.
-\n(git reset COMMIT .)"
- (interactive (list (magit-read-branch-or-commit "Reset index to")))
- (magit-reset-internal nil commit "."))
-
-;;;###autoload
-(defun magit-reset-worktree (commit)
- "Reset the worktree to COMMIT.
-Keep the `HEAD' and index as-is."
- (interactive (list (magit-read-branch-or-commit "Reset worktree to")))
- (magit-wip-commit-before-change nil " before reset")
- (magit-with-temp-index commit nil
- (magit-call-git "checkout-index" "--all" "--force"))
- (magit-wip-commit-after-apply nil " after reset")
- (magit-refresh))
-
-;;;###autoload
-(defun magit-reset-quickly (commit &optional hard)
- "Reset the `HEAD' and index to COMMIT, and possibly the working tree.
-With a prefix argument reset the working tree otherwise don't.
-\n(git reset --mixed|--hard COMMIT)"
- (interactive (list (magit-reset-read-branch-or-commit
- (if current-prefix-arg
- (concat (magit--propertize-face "Hard" 'bold)
- " reset %s to")
- "Reset %s to"))
- current-prefix-arg))
- (magit-reset-internal (if hard "--hard" "--mixed") commit))
-
-(defun magit-reset-read-branch-or-commit (prompt)
- "Prompt for and return a ref to reset HEAD to.
-
-PROMPT is a format string, where either the current branch name
-or \"detached head\" will be substituted for %s."
- (magit-read-branch-or-commit
- (format prompt (or (magit-get-current-branch) "detached head"))))
-
-(defun magit-reset-internal (arg commit &optional path)
- (when (and (not (member arg '("--hard" nil)))
- (equal (magit-rev-parse commit)
- (magit-rev-parse "HEAD~")))
- (with-temp-buffer
- (magit-git-insert "show" "-s" "--format=%B" "HEAD")
- (when git-commit-major-mode
- (funcall git-commit-major-mode))
- (git-commit-setup-font-lock)
- (git-commit-save-message)))
- (let ((cmd (if (and (equal commit "HEAD") (not arg)) "unstage" "reset")))
- (magit-wip-commit-before-change nil (concat " before " cmd))
- (magit-run-git "reset" arg commit "--" path)
- (when (equal cmd "unstage")
- (magit-wip-commit-after-apply nil " after unstage"))))
-
-;;; _
-(provide 'magit-reset)
-;;; magit-reset.el ends here
+++ /dev/null
-;;; magit-section.el --- Sections for read-only buffers -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Package-Requires: ((emacs "25.1") (dash "20200524"))
-;; Keywords: tools
-;; Homepage: https://github.com/magit/magit
-
-;; Magit-Section is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit-Section is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This package implements the main user interface of Magit — the
-;; collapsible sections that make up its buffers. This package used
-;; to be distributed as part of Magit but now it can also be used by
-;; other packages that have nothing to do with Magit or Git.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-(require 'eieio)
-
-(eval-when-compile
- (require 'benchmark)
- (require 'subr-x))
-
-;;; Hooks
-
-(defvar magit-section-movement-hook nil
- "Hook run by `magit-section-goto'.
-That function in turn is used by all section movement commands.")
-
-(defvar magit-section-highlight-hook
- '(magit-section-highlight
- magit-section-highlight-selection)
- "Functions used to highlight the current section.
-Each function is run with the current section as only argument
-until one of them returns non-nil.")
-
-(defvar magit-section-unhighlight-hook nil
- "Functions used to unhighlight the previously current section.
-Each function is run with the current section as only argument
-until one of them returns non-nil. Most sections are properly
-unhighlighted without requiring a specialized unhighlighter,
-diff-related sections being the only exception.")
-
-(defvar magit-section-set-visibility-hook
- '(magit-section-cached-visibility)
- "Hook used to set the initial visibility of a section.
-Stop at the first function that returns non-nil. The returned
-value should be `show', `hide' or nil. If no function returns
-non-nil, determine the visibility as usual, i.e. use the
-hardcoded section specific default (see `magit-insert-section').")
-
-(defvar magit-section-goto-successor-hook nil
- "Hook used to go to the same section as was current before a refresh.
-This is only used if the standard mechanism for doing so did not
-succeed.")
-
-;;; Options
-
-(defgroup magit-section nil
- "Expandable sections."
- :link '(info-link "(magit)Sections")
- :group 'extensions)
-
-(defcustom magit-section-show-child-count t
- "Whether to append the number of children to section headings.
-This only applies to sections for which doing so makes sense."
- :package-version '(magit . "2.1.0")
- :group 'magit-section
- :type 'boolean)
-
-(defcustom magit-section-cache-visibility t
- "Whether to cache visibility of sections.
-
-Sections always retain their visibility state when they are being
-recreated during a refresh. But if a section disappears and then
-later reappears again, then this option controls whether this is
-the case.
-
-If t, then cache the visibility of all sections. If a list of
-section types, then only do so for matching sections. If nil,
-then don't do so for any sections."
- :package-version '(magit . "2.12.0")
- :group 'magit-section
- :type '(choice (const :tag "Don't cache visibility" nil)
- (const :tag "Cache visibility of all sections" t)
- (repeat :tag "Cache visibility for section types" symbol)))
-
-(defcustom magit-section-initial-visibility-alist
- '((stashes . hide))
- "Alist controlling the initial visibility of sections.
-
-Each element maps a section type or lineage to the initial
-visibility state for such sections. The state has to be one of
-`show' or `hide', or a function that returns one of these symbols.
-A function is called with the section as the only argument.
-
-Use the command `magit-describe-section' to determine a section's
-lineage or type. The vector in the output is the section lineage
-and the type is the first element of that vector. Wildcards can
-be used, see `magit-section-match'.
-
-Currently this option is only used to override hardcoded defaults,
-but in the future it will also be used set the defaults.
-
-An entry whose key is `magit-status-initial-section' specifies
-the visibility of the section `magit-status-goto-initial-section'
-jumps to. This does not only override defaults, but also other
-entries of this alist."
- :package-version '(magit . "2.12.0")
- :group 'magit-section
- :type '(alist :key-type (sexp :tag "Section type/lineage")
- :value-type (choice (const hide)
- (const show)
- function)))
-
-(defcustom magit-section-visibility-indicator
- (if (window-system)
- '(magit-fringe-bitmap> . magit-fringe-bitmapv)
- '("…" . t))
- "Whether and how to indicate that a section can be expanded/collapsed.
-
-If nil, then don't show any indicators.
-Otherwise the value has to have one of these two forms:
-
-\(EXPANDABLE-BITMAP . COLLAPSIBLE-BITMAP)
-
- Both values have to be variables whose values are fringe
- bitmaps. In this case every section that can be expanded or
- collapsed gets an indicator in the left fringe.
-
- To provide extra padding around the indicator, set
- `left-fringe-width' in `magit-mode-hook'.
-
-\(STRING . BOOLEAN)
-
- In this case STRING (usually an ellipsis) is shown at the end
- of the heading of every collapsed section. Expanded sections
- get no indicator. The cdr controls whether the appearance of
- these ellipsis take section highlighting into account. Doing
- so might potentially have an impact on performance, while not
- doing so is kinda ugly."
- :package-version '(magit . "3.0.0")
- :group 'magit-section
- :type '(choice (const :tag "No indicators" nil)
- (cons :tag "Use +- fringe indicators"
- (const magit-fringe-bitmap+)
- (const magit-fringe-bitmap-))
- (cons :tag "Use >v fringe indicators"
- (const magit-fringe-bitmap>)
- (const magit-fringe-bitmapv))
- (cons :tag "Use bold >v fringe indicators)"
- (const magit-fringe-bitmap-bold>)
- (const magit-fringe-bitmap-boldv))
- (cons :tag "Use custom fringe indicators"
- (variable :tag "Expandable bitmap variable")
- (variable :tag "Collapsible bitmap variable"))
- (cons :tag "Use ellipses at end of headings"
- (string :tag "Ellipsis" "…")
- (choice :tag "Use face kludge"
- (const :tag "Yes (potentially slow)" t)
- (const :tag "No (kinda ugly)" nil)))))
-
-(defcustom magit-keep-region-overlay nil
- "Whether to keep the region overlay when there is a valid selection.
-
-By default Magit removes the regular region overlay if, and only
-if, that region constitutes a valid selection as understood by
-Magit commands. Otherwise it does not remove that overlay, and
-the region looks like it would in other buffers.
-
-There are two types of such valid selections: hunk-internal
-regions and regions that select two or more sibling sections.
-In such cases Magit removes the region overlay and instead
-highlights a slightly larger range. All text (for hunk-internal
-regions) or the headings of all sections (for sibling selections)
-that are inside that range (not just inside the region) are acted
-on by commands such as the staging command. This buffer range
-begins at the beginning of the line on which the region begins
-and ends at the end of the line on which the region ends.
-
-Because Magit acts on this larger range and not the region, it is
-actually quite important to visualize that larger range. If we
-don't do that, then one might think that these commands act on
-the region instead. If you want to *also* visualize the region,
-then set this option to t. But please note that when the region
-does *not* constitute a valid selection, then the region is
-*always* visualized as usual, and that it is usually under such
-circumstances that you want to use a non-magit command to act on
-the region.
-
-Besides keeping the region overlay, setting this option to t also
-causes all face properties, except for `:foreground', to be
-ignored for the faces used to highlight headings of selected
-sections. This avoids the worst conflicts that result from
-displaying the region and the selection overlays at the same
-time. We are not interested in dealing with other conflicts.
-In fact we *already* provide a way to avoid all of these
-conflicts: *not* changing the value of this option.
-
-It should be clear by now that we consider it a mistake to set
-this to display the region when the Magit selection is also
-visualized, but since it has been requested a few times and
-because it doesn't cost much to offer this option we do so.
-However that might change. If the existence of this option
-starts complicating other things, then it will be removed."
- :package-version '(magit . "2.3.0")
- :group 'magit-section
- :type 'boolean)
-
-(defcustom magit-section-disable-line-numbers t
- "In Magit buffers, whether to disable modes that display line numbers.
-
-Some users who turn on `global-display-line-numbers-mode' (or
-`global-nlinum-mode' or `global-linum-mode') expect line numbers
-to be displayed everywhere except in Magit buffers. Other users
-do not expect Magit buffers to be treated differently. At least
-in theory users in the first group should not use the global mode,
-but that ship has sailed, thus this option."
- :package-version '(magit . "3.0.0")
- :group 'magit-section
- :type 'boolean)
-
-;;; Faces
-
-(defgroup magit-section-faces nil
- "Faces used by Magit-Section."
- :group 'magit-section
- :group 'faces)
-
-(defface magit-section-highlight
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "grey95")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :background "grey20"))
- "Face for highlighting the current section."
- :group 'magit-section-faces)
-
-(defface magit-section-heading
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :foreground "DarkGoldenrod4"
- :weight bold)
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :foreground "LightGoldenrod2"
- :weight bold))
- "Face for section headings."
- :group 'magit-section-faces)
-
-(defface magit-section-secondary-heading
- `((t ,@(and (>= emacs-major-version 27) '(:extend t))
- :weight bold))
- "Face for section headings of some secondary headings."
- :group 'magit-section-faces)
-
-(defface magit-section-heading-selection
- `((((class color) (background light))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :foreground "salmon4")
- (((class color) (background dark))
- ,@(and (>= emacs-major-version 27) '(:extend t))
- :foreground "LightSalmon3"))
- "Face for selected section headings."
- :group 'magit-section-faces)
-
-;;; Classes
-
-(defvar magit--current-section-hook nil
- "Internal variable used for `magit-describe-section'.")
-
-(defvar magit--section-type-alist nil)
-
-(defclass magit-section ()
- ((keymap :initform nil :allocation :class)
- (type :initform nil :initarg :type)
- (value :initform nil :initarg :value)
- (start :initform nil :initarg :start)
- (content :initform nil)
- (end :initform nil)
- (hidden :initform nil)
- (washer :initform nil)
- (process :initform nil)
- (heading-highlight-face :initform nil)
- (inserter :initform (symbol-value 'magit--current-section-hook))
- (parent :initform nil :initarg :parent)
- (children :initform nil)))
-
-;;; Mode
-
-(defvar symbol-overlay-inhibit-map)
-
-(defvar magit-section-mode-map
- (let ((map (make-keymap)))
- (suppress-keymap map t)
- (define-key map (kbd "C-i") 'magit-section-toggle)
- (define-key map [C-tab] 'magit-section-cycle)
- (define-key map [M-tab] 'magit-section-cycle)
- ;; [backtab] is the most portable binding for Shift+Tab.
- (define-key map [backtab] 'magit-section-cycle-global)
- (define-key map (kbd "^") 'magit-section-up)
- (define-key map (kbd "p") 'magit-section-backward)
- (define-key map (kbd "n") 'magit-section-forward)
- (define-key map (kbd "M-p") 'magit-section-backward-sibling)
- (define-key map (kbd "M-n") 'magit-section-forward-sibling)
- (define-key map "1" 'magit-section-show-level-1)
- (define-key map "2" 'magit-section-show-level-2)
- (define-key map "3" 'magit-section-show-level-3)
- (define-key map "4" 'magit-section-show-level-4)
- (define-key map (kbd "M-1") 'magit-section-show-level-1-all)
- (define-key map (kbd "M-2") 'magit-section-show-level-2-all)
- (define-key map (kbd "M-3") 'magit-section-show-level-3-all)
- (define-key map (kbd "M-4") 'magit-section-show-level-4-all)
- map))
-
-(define-derived-mode magit-section-mode special-mode "Magit-Sections"
- "Parent major mode from which major modes with Magit-like sections inherit.
-
-Magit-Section is documented in info node `(magit-section)'."
- :group 'magit-section
- (buffer-disable-undo)
- (setq truncate-lines t)
- (setq buffer-read-only t)
- (setq-local line-move-visual t) ; see #1771
- ;; Turn off syntactic font locking, but not by setting
- ;; `font-lock-defaults' because that would enable font locking, and
- ;; not all magit plugins may be ready for that (see #3950).
- (setq-local font-lock-syntactic-face-function #'ignore)
- (setq show-trailing-whitespace nil)
- (setq-local symbol-overlay-inhibit-map t)
- (setq list-buffers-directory (abbreviate-file-name default-directory))
- ;; (hack-dir-local-variables-non-file-buffer)
- (make-local-variable 'text-property-default-nonsticky)
- (push (cons 'keymap t) text-property-default-nonsticky)
- (add-hook 'post-command-hook #'magit-section-update-highlight t t)
- (add-hook 'deactivate-mark-hook #'magit-section-update-highlight t t)
- (setq-local redisplay-highlight-region-function
- 'magit-section--highlight-region)
- (setq-local redisplay-unhighlight-region-function
- 'magit-section--unhighlight-region)
- (when magit-section-disable-line-numbers
- (when (bound-and-true-p global-linum-mode)
- (linum-mode -1))
- (when (and (fboundp 'nlinum-mode)
- (bound-and-true-p global-nlinum-mode))
- (nlinum-mode -1))
- (when (and (fboundp 'display-line-numbers-mode)
- (bound-and-true-p global-display-line-numbers-mode))
- (display-line-numbers-mode -1)))
- (when (fboundp 'magit-preserve-section-visibility-cache)
- (add-hook 'kill-buffer-hook #'magit-preserve-section-visibility-cache)))
-
-;;; Core
-
-(defvar-local magit-root-section nil
- "The root section in the current buffer.
-All other sections are descendants of this section. The value
-of this variable is set by `magit-insert-section' and you should
-never modify it.")
-(put 'magit-root-section 'permanent-local t)
-
-(defun magit-current-section ()
- "Return the section at point."
- (or (get-text-property (point) 'magit-section) magit-root-section))
-
-(defun magit-section-ident (section)
- "Return an unique identifier for SECTION.
-The return value has the form ((TYPE . VALUE)...)."
- (with-slots (type value parent) section
- (cons (cons type
- (cond ((eieio-object-p value)
- (magit-section-ident-value value))
- ((not (memq type '(unpulled unpushed))) value)
- ((string-match-p "@{upstream}" value) value)
- ;; Unfortunately Git chokes on "@{push}" when
- ;; the value of `push.default' does not allow a
- ;; 1:1 mapping. Arbitrary commands may consult
- ;; the section value so we cannot use "@{push}".
- ;; But `unpushed' and `unpulled' sections should
- ;; keep their identity when switching branches
- ;; so we have to use another value here.
- ((string-match-p "\\`\\.\\." value) "..@{push}")
- (t "@{push}..")))
- (and parent
- (magit-section-ident parent)))))
-
-(cl-defgeneric magit-section-ident-value (value)
- "Return a constant representation of VALUE.
-VALUE is the value of a `magit-section' object. If that is an
-object itself, then that is not suitable to be used to identify
-the section because two objects may represent the same thing but
-not be equal. If possible a method should be added for such
-objects, which returns a value that is equal. Otherwise the
-catch-all method is used, which just returns the argument
-itself.")
-
-(cl-defmethod magit-section-ident-value (arg) arg)
-
-(defun magit-get-section (ident &optional root)
- "Return the section identified by IDENT.
-IDENT has to be a list as returned by `magit-section-ident'.
-If optional ROOT is non-nil, then search in that section tree
-instead of in the one whose root `magit-root-section' is."
- (setq ident (reverse ident))
- (let ((section (or root magit-root-section)))
- (when (eq (car (pop ident))
- (oref section type))
- (while (and ident
- (pcase-let* ((`(,type . ,value) (car ident))
- (value (magit-section-ident-value value)))
- (setq section
- (cl-find-if (lambda (section)
- (and (eq (oref section type) type)
- (equal (magit-section-ident-value
- (oref section value))
- value)))
- (oref section children)))))
- (pop ident))
- section)))
-
-(defun magit-section-lineage (section)
- "Return the lineage of SECTION.
-The return value has the form (TYPE...)."
- (cons (oref section type)
- (when-let ((parent (oref section parent)))
- (magit-section-lineage parent))))
-
-(defvar magit-insert-section--current nil "For internal use only.")
-(defvar magit-insert-section--parent nil "For internal use only.")
-(defvar magit-insert-section--oldroot nil "For internal use only.")
-
-;;; Commands
-;;;; Movement
-
-(defun magit-section-forward ()
- "Move to the beginning of the next visible section."
- (interactive)
- (if (eobp)
- (user-error "No next section")
- (let ((section (magit-current-section)))
- (if (oref section parent)
- (let ((next (and (not (oref section hidden))
- (not (= (oref section end)
- (1+ (point))))
- (car (oref section children)))))
- (while (and section (not next))
- (unless (setq next (car (magit-section-siblings section 'next)))
- (setq section (oref section parent))))
- (if next
- (magit-section-goto next)
- (user-error "No next section")))
- (magit-section-goto 1)))))
-
-(defun magit-section-backward ()
- "Move to the beginning of the current or the previous visible section.
-When point is at the beginning of a section then move to the
-beginning of the previous visible section. Otherwise move to
-the beginning of the current section."
- (interactive)
- (if (bobp)
- (user-error "No previous section")
- (let ((section (magit-current-section)) children)
- (cond
- ((and (= (point)
- (1- (oref section end)))
- (setq children (oref section children)))
- (magit-section-goto (car (last children))))
- ((and (oref section parent)
- (not (= (point)
- (oref section start))))
- (magit-section-goto section))
- (t
- (let ((prev (car (magit-section-siblings section 'prev))))
- (if prev
- (while (and (not (oref prev hidden))
- (setq children (oref prev children)))
- (setq prev (car (last children))))
- (setq prev (oref section parent)))
- (cond (prev
- (magit-section-goto prev))
- ((oref section parent)
- (user-error "No previous section"))
- ;; Eob special cases.
- ((not (get-text-property (1- (point)) 'invisible))
- (magit-section-goto -1))
- (t
- (goto-char (previous-single-property-change
- (1- (point)) 'invisible))
- (forward-line -1)
- (magit-section-goto (magit-current-section))))))))))
-
-(defun magit-section-up ()
- "Move to the beginning of the parent section."
- (interactive)
- (--if-let (oref (magit-current-section) parent)
- (magit-section-goto it)
- (user-error "No parent section")))
-
-(defun magit-section-forward-sibling ()
- "Move to the beginning of the next sibling section.
-If there is no next sibling section, then move to the parent."
- (interactive)
- (let ((current (magit-current-section)))
- (if (oref current parent)
- (--if-let (car (magit-section-siblings current 'next))
- (magit-section-goto it)
- (magit-section-forward))
- (magit-section-goto 1))))
-
-(defun magit-section-backward-sibling ()
- "Move to the beginning of the previous sibling section.
-If there is no previous sibling section, then move to the parent."
- (interactive)
- (let ((current (magit-current-section)))
- (if (oref current parent)
- (--if-let (car (magit-section-siblings current 'prev))
- (magit-section-goto it)
- (magit-section-backward))
- (magit-section-goto -1))))
-
-(defun magit-section-goto (arg)
- (if (integerp arg)
- (progn (forward-line arg)
- (setq arg (magit-current-section)))
- (goto-char (oref arg start)))
- (run-hook-with-args 'magit-section-movement-hook arg))
-
-(defun magit-section-set-window-start (section)
- "Ensure the beginning of SECTION is visible."
- (unless (pos-visible-in-window-p (oref section end))
- (set-window-start (selected-window) (oref section start))))
-
-(defmacro magit-define-section-jumper (name heading type &optional value)
- "Define an interactive function to go some section.
-Together TYPE and VALUE identify the section.
-HEADING is the displayed heading of the section."
- (declare (indent defun))
- `(defun ,name (&optional expand) ,(format "\
-Jump to the section \"%s\".
-With a prefix argument also expand it." heading)
- (interactive "P")
- (--if-let (magit-get-section
- (cons (cons ',type ,value)
- (magit-section-ident magit-root-section)))
- (progn (goto-char (oref it start))
- (when expand
- (with-local-quit (magit-section-show it))
- (recenter 0)))
- (message ,(format "Section \"%s\" wasn't found" heading)))))
-
-;;;; Visibility
-
-(defun magit-section-show (section)
- "Show the body of the current section."
- (interactive (list (magit-current-section)))
- (oset section hidden nil)
- (magit-section--maybe-wash section)
- (when-let ((beg (oref section content)))
- (remove-overlays beg (oref section end) 'invisible t))
- (magit-section-maybe-update-visibility-indicator section)
- (magit-section-maybe-cache-visibility section)
- (dolist (child (oref section children))
- (if (oref child hidden)
- (magit-section-hide child)
- (magit-section-show child))))
-
-(defun magit-section--maybe-wash (section)
- (when-let ((washer (oref section washer)))
- (oset section washer nil)
- (let ((inhibit-read-only t)
- (magit-insert-section--parent section)
- (content (oref section content)))
- (save-excursion
- (if (and content (< content (oref section end)))
- (funcall washer section) ; already partially washed (hunk)
- (goto-char (oref section end))
- (oset section content (point-marker))
- (funcall washer)
- (oset section end (point-marker)))))
- (magit-section-update-highlight)))
-
-(defun magit-section-hide (section)
- "Hide the body of the current section."
- (interactive (list (magit-current-section)))
- (if (eq section magit-root-section)
- (user-error "Cannot hide root section")
- (oset section hidden t)
- (when-let ((beg (oref section content)))
- (let ((end (oref section end)))
- (remove-overlays beg end 'invisible t)
- (let ((o (make-overlay beg end)))
- (overlay-put o 'evaporate t)
- (overlay-put o 'invisible t))))
- (magit-section-maybe-update-visibility-indicator section)
- (magit-section-maybe-cache-visibility section)))
-
-(defun magit-section-toggle (section)
- "Toggle visibility of the body of the current section."
- (interactive (list (magit-current-section)))
- (if (eq section magit-root-section)
- (user-error "Cannot hide root section")
- (goto-char (oref section start))
- (if (oref section hidden)
- (magit-section-show section)
- (magit-section-hide section))))
-
-(defun magit-section-toggle-children (section)
- "Toggle visibility of bodies of children of the current section."
- (interactive (list (magit-current-section)))
- (goto-char (oref section start))
- (let* ((children (oref section children))
- (show (--any-p (oref it hidden) children)))
- (dolist (c children)
- (oset c hidden show)))
- (magit-section-show section))
-
-(defun magit-section-show-children (section &optional depth)
- "Recursively show the bodies of children of the current section.
-With a prefix argument show children that deep and hide deeper
-children."
- (interactive (list (magit-current-section)))
- (magit-section-show-children-1 section depth)
- (magit-section-show section))
-
-(defun magit-section-show-children-1 (section &optional depth)
- (dolist (child (oref section children))
- (oset child hidden nil)
- (if depth
- (if (> depth 0)
- (magit-section-show-children-1 child (1- depth))
- (magit-section-hide child))
- (magit-section-show-children-1 child))))
-
-(defun magit-section-hide-children (section)
- "Recursively hide the bodies of children of the current section."
- (interactive (list (magit-current-section)))
- (mapc 'magit-section-hide (oref section children)))
-
-(defun magit-section-show-headings (section)
- "Recursively show headings of children of the current section.
-Only show the headings, previously shown text-only bodies are
-hidden."
- (interactive (list (magit-current-section)))
- (magit-section-show-headings-1 section)
- (magit-section-show section))
-
-(defun magit-section-show-headings-1 (section)
- (dolist (child (oref section children))
- (oset child hidden nil)
- (when (or (oref child children)
- (not (oref child content)))
- (magit-section-show-headings-1 child))))
-
-(defun magit-section-cycle (section)
- "Cycle visibility of current section and its children."
- (interactive (list (magit-current-section)))
- (goto-char (oref section start))
- (if (oref section hidden)
- (progn (magit-section-show section)
- (magit-section-hide-children section))
- (let ((children (oref section children)))
- (cond ((and (--any-p (oref it hidden) children)
- (--any-p (oref it children) children))
- (magit-section-show-headings section))
- ((seq-some 'magit-section-hidden-body children)
- (magit-section-show-children section))
- (t
- (magit-section-hide section))))))
-
-(defun magit-section-cycle-global ()
- "Cycle visibility of all sections in the current buffer."
- (interactive)
- (let ((children (oref magit-root-section children)))
- (cond ((and (--any-p (oref it hidden) children)
- (--any-p (oref it children) children))
- (magit-section-show-headings magit-root-section))
- ((seq-some 'magit-section-hidden-body children)
- (magit-section-show-children magit-root-section))
- (t
- (mapc 'magit-section-hide children)))))
-
-(defun magit-section-hidden-body (section &optional pred)
- (--if-let (oref section children)
- (funcall (or pred '-any-p) 'magit-section-hidden-body it)
- (and (oref section content)
- (oref section hidden))))
-
-(defun magit-section-invisible-p (section)
- "Return t if the SECTION's body is invisible.
-When the body of an ancestor of SECTION is collapsed then
-SECTION's body (and heading) obviously cannot be visible."
- (or (oref section hidden)
- (--when-let (oref section parent)
- (magit-section-invisible-p it))))
-
-(defun magit-section-show-level (level)
- "Show surrounding sections up to LEVEL.
-If LEVEL is negative, show up to the absolute value.
-Sections at higher levels are hidden."
- (if (< level 0)
- (let ((s (magit-current-section)))
- (setq level (- level))
- (while (> (1- (length (magit-section-ident s))) level)
- (setq s (oref s parent))
- (goto-char (oref s start)))
- (magit-section-show-children magit-root-section (1- level)))
- (cl-do* ((s (magit-current-section)
- (oref s parent))
- (i (1- (length (magit-section-ident s)))
- (cl-decf i)))
- ((cond ((< i level) (magit-section-show-children s (- level i 1)) t)
- ((= i level) (magit-section-hide s) t))
- (magit-section-goto s)))))
-
-(defun magit-section-show-level-1 ()
- "Show surrounding sections on first level."
- (interactive)
- (magit-section-show-level 1))
-
-(defun magit-section-show-level-1-all ()
- "Show all sections on first level."
- (interactive)
- (magit-section-show-level -1))
-
-(defun magit-section-show-level-2 ()
- "Show surrounding sections up to second level."
- (interactive)
- (magit-section-show-level 2))
-
-(defun magit-section-show-level-2-all ()
- "Show all sections up to second level."
- (interactive)
- (magit-section-show-level -2))
-
-(defun magit-section-show-level-3 ()
- "Show surrounding sections up to third level."
- (interactive)
- (magit-section-show-level 3))
-
-(defun magit-section-show-level-3-all ()
- "Show all sections up to third level."
- (interactive)
- (magit-section-show-level -3))
-
-(defun magit-section-show-level-4 ()
- "Show surrounding sections up to fourth level."
- (interactive)
- (magit-section-show-level 4))
-
-(defun magit-section-show-level-4-all ()
- "Show all sections up to fourth level."
- (interactive)
- (magit-section-show-level -4))
-
-;;;; Auxiliary
-
-(defun magit-describe-section-briefly (section &optional ident)
- "Show information about the section at point.
-With a prefix argument show the section identity instead of the
-section lineage. This command is intended for debugging purposes."
- (interactive (list (magit-current-section) current-prefix-arg))
- (let ((str (format "#<%s %S %S %s-%s>"
- (eieio-object-class section)
- (let ((val (oref section value)))
- (cond ((stringp val)
- (substring-no-properties val))
- ((and (eieio-object-p val)
- (fboundp 'cl-prin1-to-string))
- (cl-prin1-to-string val))
- (t
- val)))
- (if ident
- (magit-section-ident section)
- (apply #'vector (magit-section-lineage section)))
- (when-let ((m (oref section start)))
- (marker-position m))
- (when-let ((m (oref section end)))
- (marker-position m)))))
- (if (called-interactively-p 'any)
- (message "%s" str)
- str)))
-
-(cl-defmethod cl-print-object ((section magit-section) stream)
- "Print `magit-describe-section' result of SECTION."
- ;; Used by debug and edebug as of Emacs 26.
- (princ (magit-describe-section-briefly section) stream))
-
-(defun magit-describe-section (section &optional interactive-p)
- "Show information about the section at point."
- (interactive (list (magit-current-section) t))
- (let ((inserter-section section))
- (while (and inserter-section (not (oref inserter-section inserter)))
- (setq inserter-section (oref inserter-section parent)))
- (when (and inserter-section (oref inserter-section inserter))
- (setq section inserter-section)))
- (pcase (oref section inserter)
- (`((,hook ,fun) . ,src-src)
- (help-setup-xref `(magit-describe-section ,section) interactive-p)
- (with-help-window (help-buffer)
- (with-current-buffer standard-output
- (insert (format-message
- "%s\n is inserted by `%s'\n from `%s'"
- (magit-describe-section-briefly section)
- (make-text-button (symbol-name fun) nil
- :type 'help-function
- 'help-args (list fun))
- (make-text-button (symbol-name hook) nil
- :type 'help-variable
- 'help-args (list hook))))
- (pcase-dolist (`(,hook ,fun) src-src)
- (insert (format-message
- ",\n called by `%s'\n from `%s'"
- (make-text-button (symbol-name fun) nil
- :type 'help-function
- 'help-args (list fun))
- (make-text-button (symbol-name hook) nil
- :type 'help-variable
- 'help-args (list hook)))))
- (insert ".\n\n")
- (insert
- (format-message
- "`%s' is "
- (make-text-button (symbol-name fun) nil
- :type 'help-function 'help-args (list fun))))
- (describe-function-1 fun))))
- (_ (message "%s, inserter unknown"
- (magit-describe-section-briefly section)))))
-
-;;; Match
-
-(cl-defun magit-section-match
- (condition &optional (section (magit-current-section)))
- "Return t if SECTION matches CONDITION.
-
-SECTION defaults to the section at point. If SECTION is not
-specified and there also is no section at point, then return
-nil.
-
-CONDITION can take the following forms:
- (CONDITION...) matches if any of the CONDITIONs matches.
- [CLASS...] matches if the section's class is the same
- as the first CLASS or a subclass of that;
- the section's parent class matches the
- second CLASS; and so on.
- [* CLASS...] matches sections that match [CLASS...] and
- also recursively all their child sections.
- CLASS matches if the section's class is the same
- as CLASS or a subclass of that; regardless
- of the classes of the parent sections.
-
-Each CLASS should be a class symbol, identifying a class that
-derives from `magit-section'. For backward compatibility CLASS
-can also be a \"type symbol\". A section matches such a symbol
-if the value of its `type' slot is `eq'. If a type symbol has
-an entry in `magit--section-type-alist', then a section also
-matches that type if its class is a subclass of the class that
-corresponds to the type as per that alist.
-
-Note that it is not necessary to specify the complete section
-lineage as printed by `magit-describe-section-briefly', unless
-of course you want to be that precise."
- (and section (magit-section-match-1 condition section)))
-
-(defun magit-section-match-1 (condition section)
- (cl-assert condition)
- (and section
- (if (listp condition)
- (--first (magit-section-match-1 it section) condition)
- (magit-section-match-2 (if (symbolp condition)
- (list condition)
- (cl-coerce condition 'list))
- section))))
-
-(defun magit-section-match-2 (condition section)
- (if (eq (car condition) '*)
- (or (magit-section-match-2 (cdr condition) section)
- (when-let ((parent (oref section parent)))
- (magit-section-match-2 condition parent)))
- (and (let ((c (car condition)))
- (if (class-p c)
- (cl-typep section c)
- (if-let ((class (cdr (assq c magit--section-type-alist))))
- (cl-typep section class)
- (eq (oref section type) c))))
- (or (not (setq condition (cdr condition)))
- (when-let ((parent (oref section parent)))
- (magit-section-match-2 condition parent))))))
-
-(defun magit-section-value-if (condition &optional section)
- "If the section at point matches CONDITION, then return its value.
-
-If optional SECTION is non-nil then test whether that matches
-instead. If there is no section at point and SECTION is nil,
-then return nil. If the section does not match, then return
-nil.
-
-See `magit-section-match' for the forms CONDITION can take."
- (when-let ((section (or section (magit-current-section))))
- (and (magit-section-match condition section)
- (oref section value))))
-
-(defmacro magit-section-when (condition &rest body)
- "If the section at point matches CONDITION, evaluate BODY.
-
-If the section matches, then evaluate BODY forms sequentially
-with `it' bound to the section and return the value of the last
-form. If there are no BODY forms, then return the value of the
-section. If the section does not match or if there is no section
-at point, then return nil.
-
-See `magit-section-match' for the forms CONDITION can take."
- (declare (obsolete
- "instead use `magit-section-match' or `magit-section-value-if'."
- "Magit 2.90.0")
- (indent 1)
- (debug (sexp body)))
- `(--when-let (magit-current-section)
- ;; Quoting CONDITION here often leads to double-quotes, which
- ;; isn't an issue because `magit-section-match-1' implicitly
- ;; deals with that. We shouldn't force users of this function
- ;; to not quote CONDITION because that would needlessly break
- ;; backward compatibility.
- (when (magit-section-match ',condition it)
- ,@(or body '((oref it value))))))
-
-(defmacro magit-section-case (&rest clauses)
- "Choose among clauses on the type of the section at point.
-
-Each clause looks like (CONDITION BODY...). The type of the
-section is compared against each CONDITION; the BODY forms of the
-first match are evaluated sequentially and the value of the last
-form is returned. Inside BODY the symbol `it' is bound to the
-section at point. If no clause succeeds or if there is no
-section at point, return nil.
-
-See `magit-section-match' for the forms CONDITION can take.
-Additionally a CONDITION of t is allowed in the final clause, and
-matches if no other CONDITION match, even if there is no section
-at point."
- (declare (indent 0)
- (debug (&rest (sexp body))))
- `(let* ((it (magit-current-section)))
- (cond ,@(mapcar (lambda (clause)
- `(,(or (eq (car clause) t)
- `(and it
- (magit-section-match-1 ',(car clause) it)))
- ,@(cdr clause)))
- clauses))))
-
-(defun magit-section-match-assoc (section alist)
- "Return the value associated with SECTION's type or lineage in ALIST."
- (seq-some (pcase-lambda (`(,key . ,val))
- (and (magit-section-match-1 key section) val))
- alist))
-
-;;; Create
-
-(defvar magit-insert-section-hook nil
- "Hook run after `magit-insert-section's BODY.
-Avoid using this hook and only ever do so if you know
-what you are doing and are sure there is no other way.")
-
-(defmacro magit-insert-section (&rest args)
- "Insert a section at point.
-
-Create a section object of type CLASS, storing VALUE in its
-`value' slot, and insert the section at point. CLASS is a
-subclass of `magit-section' or has the form `(eval FORM)', in
-which case FORM is evaluated at runtime and should return a
-subclass. In other places a sections class is oftern referred
-to as its \"type\".
-
-Many commands behave differently depending on the class of the
-current section and sections of a certain class can have their
-own keymap, which is specified using the `keymap' class slot.
-The value of that slot should be a variable whose value is a
-keymap.
-
-For historic reasons Magit and Forge in most cases use symbols
-as CLASS that don't actually identify a class and that lack the
-appropriate package prefix. This works due to some undocumented
-kludges, which are not available to other packages.
-
-When optional HIDE is non-nil collapse the section body by
-default, i.e. when first creating the section, but not when
-refreshing the buffer. Else expand it by default. This can be
-overwritten using `magit-section-set-visibility-hook'. When a
-section is recreated during a refresh, then the visibility of
-predecessor is inherited and HIDE is ignored (but the hook is
-still honored).
-
-BODY is any number of forms that actually insert the section's
-heading and body. Optional NAME, if specified, has to be a
-symbol, which is then bound to the object of the section being
-inserted.
-
-Before BODY is evaluated the `start' of the section object is set
-to the value of `point' and after BODY was evaluated its `end' is
-set to the new value of `point'; BODY is responsible for moving
-`point' forward.
-
-If it turns out inside BODY that the section is empty, then
-`magit-cancel-section' can be used to abort and remove all traces
-of the partially inserted section. This can happen when creating
-a section by washing Git's output and Git didn't actually output
-anything this time around.
-
-\(fn [NAME] (CLASS &optional VALUE HIDE) &rest BODY)"
- (declare (indent defun)
- (debug ([&optional symbolp]
- (&or [("eval" form) &optional form form]
- [symbolp &optional form form])
- body)))
- (let ((tp (cl-gensym "type"))
- (s* (and (symbolp (car args))
- (pop args)))
- (s (cl-gensym "section")))
- `(let* ((,tp ,(let ((type (nth 0 (car args))))
- (if (eq (car-safe type) 'eval)
- (cadr type)
- `',type)))
- (,s (funcall (if (class-p ,tp)
- ,tp
- (or (cdr (assq ,tp magit--section-type-alist))
- 'magit-section))
- :type
- (or (and (class-p ,tp)
- (car (rassq ,tp magit--section-type-alist)))
- ,tp)
- :value ,(nth 1 (car args))
- :start (point-marker)
- :parent magit-insert-section--parent)))
- (oset ,s hidden
- (let ((value (run-hook-with-args-until-success
- 'magit-section-set-visibility-hook ,s)))
- (if value
- (eq value 'hide)
- (let ((incarnation (and magit-insert-section--oldroot
- (magit-get-section
- (magit-section-ident ,s)
- magit-insert-section--oldroot))))
- (if incarnation
- (oref incarnation hidden)
- (let ((value (magit-section-match-assoc
- ,s magit-section-initial-visibility-alist)))
- (if value
- (progn
- (when (functionp value)
- (setq value (funcall value ,s)))
- (eq value 'hide))
- ,(nth 2 (car args)))))))))
- (let ((magit-insert-section--current ,s)
- (magit-insert-section--parent ,s)
- (magit-insert-section--oldroot
- (or magit-insert-section--oldroot
- (unless magit-insert-section--parent
- (prog1 magit-root-section
- (setq magit-root-section ,s))))))
- (catch 'cancel-section
- ,@(if s*
- `((let ((,s* ,s))
- ,@(cdr args)))
- (cdr args))
- ;; `magit-insert-section-hook' should *not* be run with
- ;; `magit-run-section-hook' because it's a hook that runs
- ;; on section insertion, not a section inserting hook.
- (run-hooks 'magit-insert-section-hook)
- (magit-insert-child-count ,s)
- (set-marker-insertion-type (oref ,s start) t)
- (let* ((end (oset ,s end (point-marker)))
- (class-map (oref-default ,s keymap))
- (magit-map (intern (format "magit-%s-section-map"
- (oref ,s type))))
- (forge-map (intern (format "forge-%s-section-map"
- (oref ,s type))))
- (map (or (and class-map (symbol-value class-map))
- (and (boundp magit-map) (symbol-value magit-map))
- (and (boundp forge-map) (symbol-value forge-map)))))
- (save-excursion
- (goto-char (oref ,s start))
- (while (< (point) end)
- (let ((next (or (next-single-property-change
- (point) 'magit-section)
- end)))
- (unless (get-text-property (point) 'magit-section)
- (put-text-property (point) next 'magit-section ,s)
- (when map
- (put-text-property (point) next 'keymap map)))
- (goto-char next)))))
- (if (eq ,s magit-root-section)
- (let ((magit-section-cache-visibility nil))
- (magit-section-show ,s))
- (oset (oref ,s parent) children
- (nconc (oref (oref ,s parent) children)
- (list ,s)))))
- ,s))))
-
-(defun magit-cancel-section ()
- "Cancel inserting the section that is currently being inserted.
-Remove all traces of that section."
- (when magit-insert-section--current
- (if (not (oref magit-insert-section--current parent))
- (insert "(empty)\n")
- (delete-region (oref magit-insert-section--current start)
- (point))
- (setq magit-insert-section--current nil)
- (throw 'cancel-section nil))))
-
-(defun magit-insert-heading (&rest args)
- "Insert the heading for the section currently being inserted.
-
-This function should only be used inside `magit-insert-section'.
-
-When called without any arguments, then just set the `content'
-slot of the object representing the section being inserted to
-a marker at `point'. The section should only contain a single
-line when this function is used like this.
-
-When called with arguments ARGS, which have to be strings, or
-nil, then insert those strings at point. The section should not
-contain any text before this happens and afterwards it should
-again only contain a single line. If the `face' property is set
-anywhere inside any of these strings, then insert all of them
-unchanged. Otherwise use the `magit-section-heading' face for
-all inserted text.
-
-The `content' property of the section object is the end of the
-heading (which lasts from `start' to `content') and the beginning
-of the the body (which lasts from `content' to `end'). If the
-value of `content' is nil, then the section has no heading and
-its body cannot be collapsed. If a section does have a heading,
-then its height must be exactly one line, including a trailing
-newline character. This isn't enforced, you are responsible for
-getting it right. The only exception is that this function does
-insert a newline character if necessary."
- (declare (indent defun))
- (when args
- (let ((heading (apply #'concat args)))
- (insert (if (or (text-property-not-all 0 (length heading)
- 'font-lock-face nil heading)
- (text-property-not-all 0 (length heading)
- 'face nil heading))
- heading
- (propertize heading 'font-lock-face 'magit-section-heading)))))
- (unless (bolp)
- (insert ?\n))
- (when (fboundp 'magit-maybe-make-margin-overlay)
- (magit-maybe-make-margin-overlay))
- (oset magit-insert-section--current content (point-marker)))
-
-(defmacro magit-insert-section-body (&rest body)
- "Use BODY to insert the section body, once the section is expanded.
-If the section is expanded when it is created, then this is
-like `progn'. Otherwise BODY isn't evaluated until the section
-is explicitly expanded."
- (declare (indent 0))
- (let ((f (cl-gensym))
- (s (cl-gensym)))
- `(let ((,f (lambda () ,@body))
- (,s magit-insert-section--current))
- (if (oref ,s hidden)
- (oset ,s washer
- (lambda ()
- (funcall ,f)
- (magit-section-maybe-remove-visibility-indicator ,s)))
- (funcall ,f)))))
-
-(defun magit-insert-headers (hook)
- (let* ((header-sections nil)
- (magit-insert-section-hook
- (cons (lambda ()
- (push magit-insert-section--current
- header-sections))
- (if (listp magit-insert-section-hook)
- magit-insert-section-hook
- (list magit-insert-section-hook)))))
- (magit-run-section-hook hook)
- (when header-sections
- (insert "\n")
- ;; Make the first header into the parent of the rest.
- (when (cdr header-sections)
- (cl-callf nreverse header-sections)
- (let* ((1st-header (pop header-sections))
- (header-parent (oref 1st-header parent)))
- (oset header-parent children (list 1st-header))
- (oset 1st-header children header-sections)
- (oset 1st-header content (oref (car header-sections) start))
- (oset 1st-header end (oref (car (last header-sections)) end))
- (dolist (sub-header header-sections)
- (oset sub-header parent 1st-header)))))))
-
-(defun magit-insert-child-count (section)
- "Modify SECTION's heading to contain number of child sections.
-
-If `magit-section-show-child-count' is non-nil and the SECTION
-has children and its heading ends with \":\", then replace that
-with \" (N)\", where N is the number of child sections.
-
-This function is called by `magit-insert-section' after that has
-evaluated its BODY. Admittedly that's a bit of a hack."
- ;; This has to be fast, not pretty!
- (let (content count)
- (when (and magit-section-show-child-count
- (setq count (length (oref section children)))
- (> count 0)
- (setq content (oref section content))
- (eq (char-before (1- content)) ?:))
- (save-excursion
- (goto-char (- content 2))
- (insert (format " (%s)" count))
- (delete-char 1)))))
-
-;;; Highlight
-
-(defvar-local magit-section-highlight-overlays nil)
-(defvar-local magit-section-highlighted-section nil)
-(defvar-local magit-section-highlighted-sections nil)
-(defvar-local magit-section-unhighlight-sections nil)
-(defun magit-section-update-highlight ()
- (let ((section (magit-current-section)))
- (unless (eq section magit-section-highlighted-section)
- (let ((inhibit-read-only t)
- (deactivate-mark nil)
- (selection (magit-region-sections)))
- (mapc #'delete-overlay magit-section-highlight-overlays)
- (setq magit-section-highlight-overlays nil)
- (setq magit-section-unhighlight-sections
- magit-section-highlighted-sections)
- (setq magit-section-highlighted-sections nil)
- (unless (eq section magit-root-section)
- (run-hook-with-args-until-success
- 'magit-section-highlight-hook section selection))
- (dolist (s magit-section-unhighlight-sections)
- (run-hook-with-args-until-success
- 'magit-section-unhighlight-hook s selection))
- (restore-buffer-modified-p nil)
- (unless (eq magit-section-highlighted-section section)
- (setq magit-section-highlighted-section
- (and (not (oref section hidden))
- section)))))
- (magit-section-maybe-paint-visibility-ellipses)))
-
-(defun magit-section-highlight (section selection)
- "Highlight SECTION and if non-nil all sections in SELECTION.
-This function works for any section but produces undesirable
-effects for diff related sections, which by default are
-highlighted using `magit-diff-highlight'. Return t."
- (when-let ((face (oref section heading-highlight-face)))
- (dolist (section (or selection (list section)))
- (magit-section-make-overlay
- (oref section start)
- (or (oref section content)
- (oref section end))
- face)))
- (cond (selection
- (magit-section-make-overlay (oref (car selection) start)
- (oref (car (last selection)) end)
- 'magit-section-highlight)
- (magit-section-highlight-selection nil selection))
- (t
- (magit-section-make-overlay (oref section start)
- (oref section end)
- 'magit-section-highlight)))
- t)
-
-(defun magit-section-highlight-selection (_ selection)
- "Highlight the section-selection region.
-If SELECTION is non-nil, then it is a list of sections selected by
-the region. The headings of these sections are then highlighted.
-
-This is a fallback for people who don't want to highlight the
-current section and therefore removed `magit-section-highlight'
-from `magit-section-highlight-hook'.
-
-This function is necessary to ensure that a representation of
-such a region is visible. If neither of these functions were
-part of the hook variable, then such a region would be
-invisible."
- (when (and selection
- (not (and (eq this-command 'mouse-drag-region))))
- (dolist (section selection)
- (magit-section-make-overlay (oref section start)
- (or (oref section content)
- (oref section end))
- 'magit-section-heading-selection))
- t))
-
-(defun magit-section-make-overlay (start end face)
- ;; Yes, this doesn't belong here. But the alternative of
- ;; spreading this hack across the code base is even worse.
- (when (and magit-keep-region-overlay
- (memq face '(magit-section-heading-selection
- magit-diff-file-heading-selection
- magit-diff-hunk-heading-selection)))
- (setq face (list :foreground (face-foreground face))))
- (let ((ov (make-overlay start end nil t)))
- (overlay-put ov 'font-lock-face face)
- (overlay-put ov 'evaporate t)
- (push ov magit-section-highlight-overlays)
- ov))
-
-(defun magit-section-goto-successor (section line char arg)
- (let ((ident (magit-section-ident section)))
- (--if-let (magit-get-section ident)
- (let ((start (oref it start)))
- (goto-char start)
- (unless (eq it magit-root-section)
- (ignore-errors
- (forward-line line)
- (forward-char char))
- (unless (eq (magit-current-section) it)
- (goto-char start))))
- (or (run-hook-with-args-until-success
- 'magit-section-goto-successor-hook section arg)
- (goto-char (--if-let (magit-section-goto-successor-1 section)
- (if (eq (oref it type) 'button)
- (point-min)
- (oref it start))
- (point-min)))))))
-
-(defun magit-section-goto-successor-1 (section)
- (or (--when-let (pcase (oref section type)
- (`staged 'unstaged)
- (`unstaged 'staged)
- (`unpushed 'unpulled)
- (`unpulled 'unpushed))
- (magit-get-section `((,it) (status))))
- (--when-let (car (magit-section-siblings section 'next))
- (magit-get-section (magit-section-ident it)))
- (--when-let (car (magit-section-siblings section 'prev))
- (magit-get-section (magit-section-ident it)))
- (--when-let (oref section parent)
- (or (magit-get-section (magit-section-ident it))
- (magit-section-goto-successor-1 it)))))
-
-;;; Region
-
-(defvar-local magit-section--region-overlays nil)
-
-(defun magit-section--delete-region-overlays ()
- (mapc #'delete-overlay magit-section--region-overlays)
- (setq magit-section--region-overlays nil))
-
-(defun magit-section--highlight-region (start end window rol)
- (magit-section--delete-region-overlays)
- (if (and (not magit-keep-region-overlay)
- (or (magit-region-sections)
- (run-hook-with-args-until-success 'magit-region-highlight-hook
- (magit-current-section)))
- (not (= (line-number-at-pos start)
- (line-number-at-pos end)))
- ;; (not (eq (car-safe last-command-event) 'mouse-movement))
- )
- (funcall (default-value 'redisplay-unhighlight-region-function) rol)
- (funcall (default-value 'redisplay-highlight-region-function)
- start end window rol)))
-
-(defun magit-section--unhighlight-region (rol)
- (setq magit-section-highlighted-section nil)
- (magit-section--delete-region-overlays)
- (funcall (default-value 'redisplay-unhighlight-region-function) rol))
-
-;;; Visibility
-
-(defvar-local magit-section-visibility-cache nil)
-(put 'magit-section-visibility-cache 'permanent-local t)
-
-(defun magit-section-cached-visibility (section)
- "Set SECTION's visibility to the cached value."
- (cdr (assoc (magit-section-ident section)
- magit-section-visibility-cache)))
-
-(cl-defun magit-section-cache-visibility
- (&optional (section magit-insert-section--current))
- ;; Emacs 25's `alist-get' lacks TESTFN.
- (let* ((id (magit-section-ident section))
- (elt (assoc id magit-section-visibility-cache))
- (val (if (oref section hidden) 'hide 'show)))
- (if elt
- (setcdr elt val)
- (push (cons id val) magit-section-visibility-cache))))
-
-(cl-defun magit-section-maybe-cache-visibility
- (&optional (section magit-insert-section--current))
- (when (or (eq magit-section-cache-visibility t)
- (memq (oref section type)
- magit-section-cache-visibility))
- (magit-section-cache-visibility section)))
-
-(defun magit-section-maybe-update-visibility-indicator (section)
- (when magit-section-visibility-indicator
- (let ((beg (oref section start))
- (cnt (oref section content))
- (end (oref section end)))
- (when (and cnt (or (not (= cnt end)) (oref section washer)))
- (let ((eoh (save-excursion
- (goto-char beg)
- (line-end-position))))
- (cond
- ((symbolp (car-safe magit-section-visibility-indicator))
- ;; It would make more sense to put the overlay only on the
- ;; location we actually don't put it on, but then inserting
- ;; before that location (while taking care not to mess with
- ;; the overlay) would cause the fringe bitmap to disappear
- ;; (but not other effects of the overlay).
- (let ((ov (magit--overlay-at (1+ beg) 'magit-vis-indicator 'fringe)))
- (unless ov
- (setq ov (make-overlay (1+ beg) eoh))
- (overlay-put ov 'evaporate t)
- (overlay-put ov 'magit-vis-indicator 'fringe))
- (overlay-put
- ov 'before-string
- (propertize "fringe" 'display
- (list 'left-fringe
- (if (oref section hidden)
- (car magit-section-visibility-indicator)
- (cdr magit-section-visibility-indicator))
- 'fringe)))))
- ((stringp (car-safe magit-section-visibility-indicator))
- (let ((ov (magit--overlay-at (1- eoh) 'magit-vis-indicator 'eoh)))
- (cond ((oref section hidden)
- (unless ov
- (setq ov (make-overlay (1- eoh) eoh))
- (overlay-put ov 'evaporate t)
- (overlay-put ov 'magit-vis-indicator 'eoh))
- (overlay-put ov 'after-string
- (car magit-section-visibility-indicator)))
- (ov
- (delete-overlay ov)))))))))))
-
-(defvar-local magit--ellipses-sections nil)
-
-(defun magit-section-maybe-paint-visibility-ellipses ()
- ;; This is needed because we hide the body instead of "the body
- ;; except the final newline and additionally the newline before
- ;; the body"; otherwise we could use `buffer-invisibility-spec'.
- (when (stringp (car-safe magit-section-visibility-indicator))
- (let* ((sections (append magit--ellipses-sections
- (setq magit--ellipses-sections
- (or (magit-region-sections)
- (list (magit-current-section))))))
- (beg (--map (oref it start) sections))
- (end (--map (oref it end) sections)))
- (when (region-active-p)
- ;; This ensures that the region face is removed from ellipses
- ;; when the region becomes inactive, but fails to ensure that
- ;; all ellipses within the active region use the region face,
- ;; because the respective overlay has not yet been updated at
- ;; this time. The magit-selection face is always applied.
- (push (region-beginning) beg)
- (push (region-end) end))
- (setq beg (apply #'min beg))
- (setq end (apply #'max end))
- (dolist (ov (overlays-in beg end))
- (when (eq (overlay-get ov 'magit-vis-indicator) 'eoh)
- (overlay-put
- ov 'after-string
- (propertize
- (car magit-section-visibility-indicator) 'font-lock-face
- (let ((pos (overlay-start ov)))
- (delq nil (nconc (--map (overlay-get it 'font-lock-face)
- (overlays-at pos))
- (list (get-char-property
- pos 'font-lock-face))))))))))))
-
-(defun magit-section-maybe-remove-visibility-indicator (section)
- (when (and magit-section-visibility-indicator
- (= (oref section content)
- (oref section end)))
- (dolist (o (overlays-in (oref section start)
- (save-excursion
- (goto-char (oref section start))
- (1+ (line-end-position)))))
- (when (overlay-get o 'magit-vis-indicator)
- (delete-overlay o)))))
-
-(defvar-local magit-section--opened-sections nil)
-
-(defun magit-section--open-temporarily (beg end)
- (save-excursion
- (goto-char beg)
- (let ((section (magit-current-section)))
- (while section
- (let ((content (oref section content)))
- (if (and (magit-section-invisible-p section)
- (<= (or content (oref section start))
- beg
- (oref section end)))
- (progn
- (when content
- (magit-section-show section)
- (push section magit-section--opened-sections))
- (setq section (oref section parent)))
- (setq section nil))))))
- (or (eq search-invisible t)
- (not (isearch-range-invisible beg end))))
-
-(defun isearch-clean-overlays@magit-mode (fn)
- (if (derived-mode-p 'magit-mode)
- (let ((pos (point)))
- (dolist (section magit-section--opened-sections)
- (unless (<= (oref section content) pos (oref section end))
- (magit-section-hide section)))
- (setq magit-section--opened-sections nil))
- (funcall fn)))
-
-(advice-add 'isearch-clean-overlays :around
- 'isearch-clean-overlays@magit-mode)
-
-;;; Utilities
-
-(cl-defun magit-section-selected-p (section &optional (selection nil sselection))
- (and (not (eq section magit-root-section))
- (or (eq section (magit-current-section))
- (memq section (if sselection
- selection
- (setq selection (magit-region-sections))))
- (--when-let (oref section parent)
- (magit-section-selected-p it selection)))))
-
-(defun magit-section-parent-value (section)
- (when-let ((parent (oref section parent)))
- (oref parent value)))
-
-(defun magit-section-siblings (section &optional direction)
- "Return a list of the sibling sections of SECTION.
-
-If optional DIRECTION is `prev', then return siblings that come
-before SECTION. If it is `next', then return siblings that come
-after SECTION. For all other values, return all siblings
-excluding SECTION itself."
- (when-let ((parent (oref section parent)))
- (let ((siblings (oref parent children)))
- (pcase direction
- (`prev (cdr (member section (reverse siblings))))
- (`next (cdr (member section siblings)))
- (_ (remq section siblings))))))
-
-(defun magit-region-values (&optional condition multiple)
- "Return a list of the values of the selected sections.
-
-Return the values that themselves would be returned by
-`magit-region-sections' (which see)."
- (--map (oref it value)
- (magit-region-sections condition multiple)))
-
-(defun magit-region-sections (&optional condition multiple)
- "Return a list of the selected sections.
-
-When the region is active and constitutes a valid section
-selection, then return a list of all selected sections. This is
-the case when the region begins in the heading of a section and
-ends in the heading of the same section or in that of a sibling
-section. If optional MULTIPLE is non-nil, then the region cannot
-begin and end in the same section.
-
-When the selection is not valid, then return nil. In this case,
-most commands that can act on the selected sections will instead
-act on the section at point.
-
-When the region looks like it would in any other buffer then
-the selection is invalid. When the selection is valid then the
-region uses the `magit-section-highlight' face. This does not
-apply to diffs where things get a bit more complicated, but even
-here if the region looks like it usually does, then that's not
-a valid selection as far as this function is concerned.
-
-If optional CONDITION is non-nil, then the selection not only
-has to be valid; all selected sections additionally have to match
-CONDITION, or nil is returned. See `magit-section-match' for the
-forms CONDITION can take."
- (when (region-active-p)
- (let* ((rbeg (region-beginning))
- (rend (region-end))
- (sbeg (get-text-property rbeg 'magit-section))
- (send (get-text-property rend 'magit-section)))
- (when (and send
- (not (eq send magit-root-section))
- (not (and multiple (eq send sbeg))))
- (let ((siblings (cons sbeg (magit-section-siblings sbeg 'next)))
- sections)
- (when (and (memq send siblings)
- (magit-section-position-in-heading-p sbeg rbeg)
- (magit-section-position-in-heading-p send rend))
- (while siblings
- (push (car siblings) sections)
- (when (eq (pop siblings) send)
- (setq siblings nil)))
- (setq sections (nreverse sections))
- (when (or (not condition)
- (--all-p (magit-section-match condition it) sections))
- sections)))))))
-
-(defun magit-section-position-in-heading-p (&optional section pos)
- "Return t if POSITION is inside the heading of SECTION.
-POSITION defaults to point and SECTION defaults to the
-current section."
- (unless section
- (setq section (magit-current-section)))
- (unless pos
- (setq pos (point)))
- (and section
- (>= pos (oref section start))
- (< pos (or (oref section content)
- (oref section end)))
- t))
-
-(defun magit-section-internal-region-p (&optional section)
- "Return t if the region is active and inside SECTION's body.
-If optional SECTION is nil, use the current section."
- (and (region-active-p)
- (or section (setq section (magit-current-section)))
- (let ((beg (get-text-property (region-beginning) 'magit-section)))
- (and (eq beg (get-text-property (region-end) 'magit-section))
- (eq beg section)))
- (not (or (magit-section-position-in-heading-p section (region-beginning))
- (magit-section-position-in-heading-p section (region-end))))
- t))
-
-(defun magit-section--backward-protected ()
- "Move to the beginning of the current or the previous visible section.
-Same as `magit-section-backward' but for non-interactive use.
-Suppress `magit-section-movement-hook', and return a boolean to
-indicate whether a section was found, instead of raising an error
-if not."
- (condition-case nil
- (let ((magit-section-movement-hook nil))
- (magit-section-backward)
- t)
- (user-error nil)))
-
-(defun magit-section--backward-find (predicate)
- "Move to the first previous section satisfying PREDICATE.
-PREDICATE does not take any parameter and should not move
-point."
- (let (found)
- (while (and (setq found (magit-section--backward-protected))
- (not (funcall predicate))))
- found))
-
-(defun magit-wash-sequence (function)
- "Repeatedly call FUNCTION until it returns nil or eob is reached.
-FUNCTION has to move point forward or return nil."
- (while (and (not (eobp)) (funcall function))))
-
-(defun magit-add-section-hook (hook function &optional at append local)
- "Add to the value of section hook HOOK the function FUNCTION.
-
-Add FUNCTION at the beginning of the hook list unless optional
-APPEND is non-nil, in which case FUNCTION is added at the end.
-If FUNCTION already is a member, then move it to the new location.
-
-If optional AT is non-nil and a member of the hook list, then
-add FUNCTION next to that instead. Add before or after AT, or
-replace AT with FUNCTION depending on APPEND. If APPEND is the
-symbol `replace', then replace AT with FUNCTION. For any other
-non-nil value place FUNCTION right after AT. If nil, then place
-FUNCTION right before AT. If FUNCTION already is a member of the
-list but AT is not, then leave FUNCTION where ever it already is.
-
-If optional LOCAL is non-nil, then modify the hook's buffer-local
-value rather than its global value. This makes the hook local by
-copying the default value. That copy is then modified.
-
-HOOK should be a symbol. If HOOK is void, it is first set to nil.
-HOOK's value must not be a single hook function. FUNCTION should
-be a function that takes no arguments and inserts one or multiple
-sections at point, moving point forward. FUNCTION may choose not
-to insert its section(s), when doing so would not make sense. It
-should not be abused for other side-effects. To remove FUNCTION
-again use `remove-hook'."
- (unless (boundp hook)
- (error "Cannot add function to undefined hook variable %s" hook))
- (unless (default-boundp hook)
- (set-default hook nil))
- (let ((value (if local
- (if (local-variable-p hook)
- (symbol-value hook)
- (unless (local-variable-if-set-p hook)
- (make-local-variable hook))
- (copy-sequence (default-value hook)))
- (default-value hook))))
- (if at
- (when (setq at (member at value))
- (setq value (delq function value))
- (cond ((eq append 'replace)
- (setcar at function))
- (append
- (push function (cdr at)))
- (t
- (push (car at) (cdr at))
- (setcar at function))))
- (setq value (delq function value)))
- (unless (member function value)
- (setq value (if append
- (append value (list function))
- (cons function value))))
- (when (eq append 'replace)
- (setq value (delq at value)))
- (if local
- (set hook value)
- (set-default hook value))))
-
-(defvar-local magit-disabled-section-inserters nil)
-
-(defun magit-disable-section-inserter (fn)
- "Disable the section inserter FN in the current repository.
-It is only intended for use in \".dir-locals.el\" and
-\".dir-locals-2.el\". Also see info node `(magit)Per-Repository
-Configuration'."
- (cl-pushnew fn magit-disabled-section-inserters))
-
-(put 'magit-disable-section-inserter 'safe-local-eval-function t)
-
-(defun magit-run-section-hook (hook &rest args)
- "Run HOOK with ARGS, warning about invalid entries."
- (let ((entries (symbol-value hook)))
- (unless (listp entries)
- (setq entries (list entries)))
- (--when-let (-remove #'functionp entries)
- (message "`%s' contains entries that are no longer valid.
-%s\nUsing standard value instead. Please re-configure hook variable."
- hook
- (mapconcat (lambda (sym) (format " `%s'" sym)) it "\n"))
- (sit-for 5)
- (setq entries (eval (car (get hook 'standard-value)))))
- (dolist (entry entries)
- (let ((magit--current-section-hook (cons (list hook entry)
- magit--current-section-hook)))
- (unless (memq entry magit-disabled-section-inserters)
- (if (bound-and-true-p magit-refresh-verbose)
- (let ((time (benchmark-elapse (apply entry args))))
- (message " %-50s %s %s" entry time
- (cond ((> time 0.03) "!!")
- ((> time 0.01) "!")
- (t ""))))
- (apply entry args)))))))
-
-(cl-defun magit--overlay-at (pos prop &optional (val nil sval) testfn)
- (cl-find-if (lambda (o)
- (let ((p (overlay-properties o)))
- (and (plist-member p prop)
- (or (not sval)
- (funcall (or testfn #'eql)
- (plist-get p prop)
- val)))))
- (overlays-at pos t)))
-
-;;; _
-(provide 'magit-section)
-;;; magit-section.el ends here
+++ /dev/null
-;;; magit-sequence.el --- history manipulation in Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2011-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Support for Git commands that replay commits and help the user make
-;; changes along the way. Supports `cherry-pick', `revert', `rebase',
-;; `rebase--interactive' and `am'.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit)
-
-;; For `magit-rebase--todo'.
-(declare-function git-rebase-current-line "git-rebase" ())
-(eval-when-compile
- (cl-pushnew 'action-type eieio--known-slot-names)
- (cl-pushnew 'action eieio--known-slot-names)
- (cl-pushnew 'action-options eieio--known-slot-names)
- (cl-pushnew 'target eieio--known-slot-names))
-
-;;; Options
-;;;; Faces
-
-(defface magit-sequence-pick
- '((t :inherit default))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-stop
- '((((class color) (background light)) :foreground "DarkOliveGreen4")
- (((class color) (background dark)) :foreground "DarkSeaGreen2"))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-part
- '((((class color) (background light)) :foreground "Goldenrod4")
- (((class color) (background dark)) :foreground "LightGoldenrod2"))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-head
- '((((class color) (background light)) :foreground "SkyBlue4")
- (((class color) (background dark)) :foreground "LightSkyBlue1"))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-drop
- '((((class color) (background light)) :foreground "IndianRed")
- (((class color) (background dark)) :foreground "IndianRed"))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-done
- '((t :inherit magit-hash))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-onto
- '((t :inherit magit-sequence-done))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-(defface magit-sequence-exec
- '((t :inherit magit-hash))
- "Face used in sequence sections."
- :group 'magit-faces)
-
-;;; Common
-
-;;;###autoload
-(defun magit-sequencer-continue ()
- "Resume the current cherry-pick or revert sequence."
- (interactive)
- (if (magit-sequencer-in-progress-p)
- (if (magit-anything-unstaged-p t)
- (user-error "Cannot continue due to unstaged changes")
- (magit-run-git-sequencer
- (if (magit-revert-in-progress-p) "revert" "cherry-pick") "--continue"))
- (user-error "No cherry-pick or revert in progress")))
-
-;;;###autoload
-(defun magit-sequencer-skip ()
- "Skip the stopped at commit during a cherry-pick or revert sequence."
- (interactive)
- (if (magit-sequencer-in-progress-p)
- (progn (magit-call-git "reset" "--hard")
- (magit-sequencer-continue))
- (user-error "No cherry-pick or revert in progress")))
-
-;;;###autoload
-(defun magit-sequencer-abort ()
- "Abort the current cherry-pick or revert sequence.
-This discards all changes made since the sequence started."
- (interactive)
- (if (magit-sequencer-in-progress-p)
- (magit-run-git-sequencer
- (if (magit-revert-in-progress-p) "revert" "cherry-pick") "--abort")
- (user-error "No cherry-pick or revert in progress")))
-
-(defun magit-sequencer-in-progress-p ()
- (or (magit-cherry-pick-in-progress-p)
- (magit-revert-in-progress-p)))
-
-;;; Cherry-Pick
-
-(defvar magit-perl-executable "perl"
- "The Perl executable.")
-
-;;;###autoload (autoload 'magit-cherry-pick "magit-sequence" nil t)
-(transient-define-prefix magit-cherry-pick ()
- "Apply or transplant commits."
- :man-page "git-cherry-pick"
- :value '("--ff")
- :incompatible '(("--ff" "-x"))
- ["Arguments"
- :if-not magit-sequencer-in-progress-p
- (magit-cherry-pick:--mainline)
- ("=s" magit-merge:--strategy)
- ("-F" "Attempt fast-forward" "--ff")
- ("-x" "Reference cherry in commit message" "-x")
- ("-e" "Edit commit messages" ("-e" "--edit"))
- ("-s" "Add Signed-off-by lines" ("-s" "--signoff"))
- (5 magit:--gpg-sign)]
- [:if-not magit-sequencer-in-progress-p
- ["Apply here"
- ("A" "Pick" magit-cherry-copy)
- ("a" "Apply" magit-cherry-apply)
- ("h" "Harvest" magit-cherry-harvest)]
- ["Apply elsewhere"
- ("d" "Donate" magit-cherry-donate)
- ("n" "Spinout" magit-cherry-spinout)
- ("s" "Spinoff" magit-cherry-spinoff)]]
- ["Actions"
- :if magit-sequencer-in-progress-p
- ("A" "Continue" magit-sequencer-continue)
- ("s" "Skip" magit-sequencer-skip)
- ("a" "Abort" magit-sequencer-abort)])
-
-(transient-define-argument magit-cherry-pick:--mainline ()
- :description "Replay merge relative to parent"
- :class 'transient-option
- :shortarg "-m"
- :argument "--mainline="
- :reader 'transient-read-number-N+)
-
-(defun magit-cherry-pick-read-args (prompt)
- (list (or (nreverse (magit-region-values 'commit))
- (magit-read-other-branch-or-commit prompt))
- (transient-args 'magit-cherry-pick)))
-
-(defun magit--cherry-move-read-args (verb away fn)
- (declare (indent defun))
- (let ((commits (or (nreverse (magit-region-values 'commit))
- (list (funcall (if away
- 'magit-read-branch-or-commit
- 'magit-read-other-branch-or-commit)
- (format "%s cherry" (capitalize verb))))))
- (current (magit-get-current-branch)))
- (unless current
- (user-error "Cannot %s cherries while HEAD is detached" verb))
- (let ((reachable (magit-rev-ancestor-p (car commits) current))
- (msg "Cannot %s cherries that %s reachable from HEAD"))
- (pcase (list away reachable)
- (`(nil t) (user-error msg verb "are"))
- (`(t nil) (user-error msg verb "are not"))))
- `(,commits
- ,@(funcall fn commits)
- ,(transient-args 'magit-cherry-pick))))
-
-(defun magit--cherry-spinoff-read-args (verb)
- (magit--cherry-move-read-args verb t
- (lambda (commits)
- (magit-branch-read-args
- (format "Create branch from %s cherries" (length commits))
- (magit-get-upstream-branch)))))
-
-;;;###autoload
-(defun magit-cherry-copy (commits &optional args)
- "Copy COMMITS from another branch onto the current branch.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then pick all of them,
-without prompting."
- (interactive (magit-cherry-pick-read-args "Cherry-pick"))
- (magit--cherry-pick commits args))
-
-;;;###autoload
-(defun magit-cherry-apply (commits &optional args)
- "Apply the changes in COMMITS but do not commit them.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then apply all of them,
-without prompting."
- (interactive (magit-cherry-pick-read-args "Apply changes from commit"))
- (magit--cherry-pick commits (cons "--no-commit" (remove "--ff" args))))
-
-;;;###autoload
-(defun magit-cherry-harvest (commits branch &optional args)
- "Move COMMITS from another BRANCH onto the current branch.
-Remove the COMMITS from BRANCH and stay on the current branch.
-If a conflict occurs, then you have to fix that and finish the
-process manually."
- (interactive
- (magit--cherry-move-read-args "harvest" nil
- (lambda (commits)
- (list (let ((branches (magit-list-containing-branches (car commits))))
- (pcase (length branches)
- (0 nil)
- (1 (car branches))
- (_ (magit-completing-read
- (format "Remove %s cherries from branch" (length commits))
- branches nil t))))))))
- (magit--cherry-move commits branch (magit-get-current-branch) args nil t))
-
-;;;###autoload
-(defun magit-cherry-donate (commits branch &optional args)
- "Move COMMITS from the current branch onto another existing BRANCH.
-Remove COMMITS from the current branch and stay on that branch.
-If a conflict occurs, then you have to fix that and finish the
-process manually."
- (interactive
- (magit--cherry-move-read-args "donate" t
- (lambda (commits)
- (list (magit-read-other-branch (format "Move %s cherries to branch"
- (length commits)))))))
- (magit--cherry-move commits (magit-get-current-branch) branch args))
-
-;;;###autoload
-(defun magit-cherry-spinout (commits branch start-point &optional args)
- "Move COMMITS from the current branch onto a new BRANCH.
-Remove COMMITS from the current branch and stay on that branch.
-If a conflict occurs, then you have to fix that and finish the
-process manually."
- (interactive (magit--cherry-spinoff-read-args "spinout"))
- (magit--cherry-move commits (magit-get-current-branch) branch args
- start-point))
-
-;;;###autoload
-(defun magit-cherry-spinoff (commits branch start-point &optional args)
- "Move COMMITS from the current branch onto a new BRANCH.
-Remove COMMITS from the current branch and checkout BRANCH.
-If a conflict occurs, then you have to fix that and finish
-the process manually."
- (interactive (magit--cherry-spinoff-read-args "spinoff"))
- (magit--cherry-move commits (magit-get-current-branch) branch args
- start-point t))
-
-(defun magit--cherry-move (commits src dst args
- &optional start-point checkout-dst)
- (let ((current (magit-get-current-branch)))
- (unless (magit-branch-p dst)
- (let ((magit-process-raise-error t))
- (magit-call-git "branch" dst start-point))
- (--when-let (magit-get-indirect-upstream-branch start-point)
- (magit-call-git "branch" "--set-upstream-to" it dst)))
- (unless (equal dst current)
- (let ((magit-process-raise-error t))
- (magit-call-git "checkout" dst)))
- (if (not src) ; harvest only
- (magit--cherry-pick commits args)
- (let ((tip (car (last commits)))
- (keep (concat (car commits) "^")))
- (magit--cherry-pick commits args)
- (set-process-sentinel
- magit-this-process
- (lambda (process event)
- (when (memq (process-status process) '(exit signal))
- (if (> (process-exit-status process) 0)
- (magit-process-sentinel process event)
- (process-put process 'inhibit-refresh t)
- (magit-process-sentinel process event)
- (cond
- ((magit-rev-equal tip src)
- (magit-call-git "update-ref"
- "-m" (format "reset: moving to %s" keep)
- (magit-ref-fullname src)
- keep tip)
- (if (not checkout-dst)
- (magit-run-git "checkout" src)
- (magit-refresh)))
- (t
- (magit-git "checkout" src)
- (let ((process-environment process-environment))
- (push (format "%s=%s -i -ne '/^pick (%s)/ or print'"
- "GIT_SEQUENCE_EDITOR"
- magit-perl-executable
- (mapconcat #'magit-rev-abbrev commits "|"))
- process-environment)
- (magit-run-git-sequencer "rebase" "-i" keep))
- (when checkout-dst
- (set-process-sentinel
- magit-this-process
- (lambda (process event)
- (when (memq (process-status process) '(exit signal))
- (if (> (process-exit-status process) 0)
- (magit-process-sentinel process event)
- (process-put process 'inhibit-refresh t)
- (magit-process-sentinel process event)
- (magit-run-git "checkout" dst))))))))))))))))
-
-(defun magit--cherry-pick (commits args &optional revert)
- (let ((command (if revert "revert" "cherry-pick")))
- (when (stringp commits)
- (setq commits (if (string-match-p "\\.\\." commits)
- (split-string commits "\\.\\.")
- (list commits))))
- (magit-run-git-sequencer
- (if revert "revert" "cherry-pick")
- (pcase-let ((`(,merge ,non-merge)
- (-separate 'magit-merge-commit-p commits)))
- (cond
- ((not merge)
- (--remove (string-prefix-p "--mainline=" it) args))
- (non-merge
- (user-error "Cannot %s merge and non-merge commits at once"
- command))
- ((--first (string-prefix-p "--mainline=" it) args)
- args)
- (t
- (cons (format "--mainline=%s"
- (read-number "Replay merges relative to parent: "))
- args))))
- commits)))
-
-(defun magit-cherry-pick-in-progress-p ()
- ;; .git/sequencer/todo does not exist when there is only one commit left.
- (file-exists-p (magit-git-dir "CHERRY_PICK_HEAD")))
-
-;;; Revert
-
-;;;###autoload (autoload 'magit-revert "magit-sequence" nil t)
-(transient-define-prefix magit-revert ()
- "Revert existing commits, with or without creating new commits."
- :man-page "git-revert"
- :value '("--edit")
- ["Arguments"
- :if-not magit-sequencer-in-progress-p
- (magit-cherry-pick:--mainline)
- ("-e" "Edit commit message" ("-e" "--edit"))
- ("-E" "Don't edit commit message" "--no-edit")
- ("=s" magit-merge:--strategy)
- ("-s" "Add Signed-off-by lines" ("-s" "--signoff"))
- (5 magit:--gpg-sign)]
- ["Actions"
- :if-not magit-sequencer-in-progress-p
- ("V" "Revert commit(s)" magit-revert-and-commit)
- ("v" "Revert changes" magit-revert-no-commit)]
- ["Actions"
- :if magit-sequencer-in-progress-p
- ("V" "Continue" magit-sequencer-continue)
- ("s" "Skip" magit-sequencer-skip)
- ("a" "Abort" magit-sequencer-abort)])
-
-(defun magit-revert-read-args (prompt)
- (list (or (magit-region-values 'commit)
- (magit-read-branch-or-commit prompt))
- (transient-args 'magit-revert)))
-
-;;;###autoload
-(defun magit-revert-and-commit (commit &optional args)
- "Revert COMMIT by creating a new commit.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then revert all of them,
-without prompting."
- (interactive (magit-revert-read-args "Revert commit"))
- (magit--cherry-pick commit args t))
-
-;;;###autoload
-(defun magit-revert-no-commit (commit &optional args)
- "Revert COMMIT by applying it in reverse to the worktree.
-Prompt for a commit, defaulting to the commit at point. If
-the region selects multiple commits, then revert all of them,
-without prompting."
- (interactive (magit-revert-read-args "Revert changes"))
- (magit--cherry-pick commit (cons "--no-commit" args) t))
-
-(defun magit-revert-in-progress-p ()
- ;; .git/sequencer/todo does not exist when there is only one commit left.
- (file-exists-p (magit-git-dir "REVERT_HEAD")))
-
-;;; Patch
-
-;;;###autoload (autoload 'magit-am "magit-sequence" nil t)
-(transient-define-prefix magit-am ()
- "Apply patches received by email."
- :man-page "git-am"
- :value '("--3way")
- ["Arguments"
- :if-not magit-am-in-progress-p
- ("-3" "Fall back on 3way merge" ("-3" "--3way"))
- (magit-apply:-p)
- ("-c" "Remove text before scissors line" ("-c" "--scissors"))
- ("-k" "Inhibit removal of email cruft" ("-k" "--keep"))
- ("-b" "Limit removal of email cruft" "--keep-non-patch")
- ("-d" "Use author date as committer date" "--committer-date-is-author-date")
- ("-D" "Use committer date as author date" "--ignore-date")
- ("-s" "Add Signed-off-by lines" ("-s" "--signoff"))
- (5 magit:--gpg-sign)]
- ["Apply"
- :if-not magit-am-in-progress-p
- ("m" "maildir" magit-am-apply-maildir)
- ("w" "patches" magit-am-apply-patches)
- ("a" "plain patch" magit-patch-apply)]
- ["Actions"
- :if magit-am-in-progress-p
- ("w" "Continue" magit-am-continue)
- ("s" "Skip" magit-am-skip)
- ("a" "Abort" magit-am-abort)])
-
-(defun magit-am-arguments ()
- (transient-args 'magit-am))
-
-(transient-define-argument magit-apply:-p ()
- :description "Remove leading slashes from paths"
- :class 'transient-option
- :argument "-p"
- :reader 'transient-read-number-N+)
-
-;;;###autoload
-(defun magit-am-apply-patches (&optional files args)
- "Apply the patches FILES."
- (interactive (list (or (magit-region-values 'file)
- (list (let ((default (magit-file-at-point)))
- (read-file-name
- (if default
- (format "Apply patch (%s): " default)
- "Apply patch: ")
- nil default))))
- (magit-am-arguments)))
- (magit-run-git-sequencer "am" args "--"
- (--map (magit-convert-filename-for-git
- (expand-file-name it))
- files)))
-
-;;;###autoload
-(defun magit-am-apply-maildir (&optional maildir args)
- "Apply the patches from MAILDIR."
- (interactive (list (read-file-name "Apply mbox or Maildir: ")
- (magit-am-arguments)))
- (magit-run-git-sequencer "am" args (magit-convert-filename-for-git
- (expand-file-name maildir))))
-
-;;;###autoload
-(defun magit-am-continue ()
- "Resume the current patch applying sequence."
- (interactive)
- (if (magit-am-in-progress-p)
- (if (magit-anything-unstaged-p t)
- (error "Cannot continue due to unstaged changes")
- (magit-run-git-sequencer "am" "--continue"))
- (user-error "Not applying any patches")))
-
-;;;###autoload
-(defun magit-am-skip ()
- "Skip the stopped at patch during a patch applying sequence."
- (interactive)
- (if (magit-am-in-progress-p)
- (magit-run-git-sequencer "am" "--skip")
- (user-error "Not applying any patches")))
-
-;;;###autoload
-(defun magit-am-abort ()
- "Abort the current patch applying sequence.
-This discards all changes made since the sequence started."
- (interactive)
- (if (magit-am-in-progress-p)
- (magit-run-git "am" "--abort")
- (user-error "Not applying any patches")))
-
-(defun magit-am-in-progress-p ()
- (file-exists-p (magit-git-dir "rebase-apply/applying")))
-
-;;; Rebase
-
-;;;###autoload (autoload 'magit-rebase "magit-sequence" nil t)
-(transient-define-prefix magit-rebase ()
- "Transplant commits and/or modify existing commits."
- :man-page "git-rebase"
- ["Arguments"
- :if-not magit-rebase-in-progress-p
- ("-k" "Keep empty commits" "--keep-empty")
- ("-p" "Preserve merges" ("-p" "--preserve-merges"))
- (7 magit-merge:--strategy)
- (7 magit-merge:--strategy-option)
- (7 "=X" magit-diff:--diff-algorithm :argument "-Xdiff-algorithm=")
- ("-d" "Lie about committer date" "--committer-date-is-author-date")
- ("-a" "Autosquash" "--autosquash")
- ("-A" "Autostash" "--autostash")
- ("-i" "Interactive" ("-i" "--interactive"))
- ("-h" "Disable hooks" "--no-verify")
- (7 magit-rebase:--exec)
- (5 magit:--gpg-sign)
- (5 "-r" "Rebase merges" "--rebase-merges=" magit-rebase-merges-select-mode)]
- [:if-not magit-rebase-in-progress-p
- :description (lambda ()
- (format (propertize "Rebase %s onto" 'face 'transient-heading)
- (propertize (or (magit-get-current-branch) "HEAD")
- 'face 'magit-branch-local)))
- ("p" magit-rebase-onto-pushremote)
- ("u" magit-rebase-onto-upstream)
- ("e" "elsewhere" magit-rebase-branch)]
- ["Rebase"
- :if-not magit-rebase-in-progress-p
- [("i" "interactively" magit-rebase-interactive)
- ("s" "a subset" magit-rebase-subset)]
- [("m" "to modify a commit" magit-rebase-edit-commit)
- ("w" "to reword a commit" magit-rebase-reword-commit)
- ("k" "to remove a commit" magit-rebase-remove-commit)
- ("f" "to autosquash" magit-rebase-autosquash)
- (6 "t" "to change dates" magit-reshelve-since)]]
- ["Actions"
- :if magit-rebase-in-progress-p
- ("r" "Continue" magit-rebase-continue)
- ("s" "Skip" magit-rebase-skip)
- ("e" "Edit" magit-rebase-edit)
- ("a" "Abort" magit-rebase-abort)])
-
-(transient-define-argument magit-rebase:--exec ()
- :description "Run command after commits"
- :class 'transient-option
- :shortarg "-x"
- :argument "--exec="
- :reader #'read-shell-command)
-
-(defun magit-rebase-merges-select-mode (&rest _ignore)
- (magit-read-char-case nil t
- (?n "[n]o-rebase-cousins" "no-rebase-cousins")
- (?r "[r]ebase-cousins" "rebase-cousins")))
-
-(defun magit-rebase-arguments ()
- (transient-args 'magit-rebase))
-
-(defun magit-git-rebase (target args)
- (magit-run-git-sequencer "rebase" args target))
-
-;;;###autoload (autoload 'magit-rebase-onto-pushremote "magit-sequence" nil t)
-(transient-define-suffix magit-rebase-onto-pushremote (args)
- "Rebase the current branch onto its push-remote branch.
-
-With a prefix argument or when the push-remote is either not
-configured or unusable, then let the user first configure the
-push-remote."
- :if 'magit-get-current-branch
- :description 'magit-pull--pushbranch-description
- (interactive (list (magit-rebase-arguments)))
- (pcase-let ((`(,branch ,remote)
- (magit--select-push-remote "rebase onto that")))
- (magit-git-rebase (concat remote "/" branch) args)))
-
-;;;###autoload (autoload 'magit-rebase-onto-upstream "magit-sequence" nil t)
-(transient-define-suffix magit-rebase-onto-upstream (args)
- "Rebase the current branch onto its upstream branch.
-
-With a prefix argument or when the upstream is either not
-configured or unusable, then let the user first configure
-the upstream."
- :if 'magit-get-current-branch
- :description 'magit-rebase--upstream-description
- (interactive (list (magit-rebase-arguments)))
- (let* ((branch (or (magit-get-current-branch)
- (user-error "No branch is checked out")))
- (upstream (magit-get-upstream-branch branch)))
- (when (or current-prefix-arg (not upstream))
- (setq upstream
- (magit-read-upstream-branch
- branch (format "Set upstream of %s and rebase onto that" branch)))
- (magit-set-upstream-branch branch upstream))
- (magit-git-rebase upstream args)))
-
-(defun magit-rebase--upstream-description ()
- (when-let ((branch (magit-get-current-branch)))
- (or (magit-get-upstream-branch branch)
- (let ((remote (magit-get "branch" branch "remote"))
- (merge (magit-get "branch" branch "merge"))
- (u (magit--propertize-face "@{upstream}" 'bold)))
- (cond
- ((magit--unnamed-upstream-p remote merge)
- (concat u ", replacing unnamed"))
- ((magit--valid-upstream-p remote merge)
- (concat u ", replacing non-existent"))
- ((or remote merge)
- (concat u ", replacing invalid"))
- (t
- (concat u ", setting that")))))))
-
-;;;###autoload
-(defun magit-rebase-branch (target args)
- "Rebase the current branch onto a branch read in the minibuffer.
-All commits that are reachable from `HEAD' but not from the
-selected branch TARGET are being rebased."
- (interactive (list (magit-read-other-branch-or-commit "Rebase onto")
- (magit-rebase-arguments)))
- (message "Rebasing...")
- (magit-git-rebase target args)
- (message "Rebasing...done"))
-
-;;;###autoload
-(defun magit-rebase-subset (newbase start args)
- "Rebase a subset of the current branch's history onto a new base.
-Rebase commits from START to `HEAD' onto NEWBASE.
-START has to be selected from a list of recent commits."
- (interactive (list (magit-read-other-branch-or-commit
- "Rebase subset onto" nil
- (magit-get-upstream-branch))
- nil
- (magit-rebase-arguments)))
- (if start
- (progn (message "Rebasing...")
- (magit-run-git-sequencer "rebase" "--onto" newbase start args)
- (message "Rebasing...done"))
- (magit-log-select
- `(lambda (commit)
- (magit-rebase-subset ,newbase (concat commit "^") (list ,@args)))
- (concat "Type %p on a commit to rebase it "
- "and commits above it onto " newbase ","))))
-
-(defvar magit-rebase-interactive-include-selected t)
-
-(defun magit-rebase-interactive-1
- (commit args message &optional editor delay-edit-confirm noassert confirm)
- (declare (indent 2))
- (when commit
- (if (eq commit :merge-base)
- (setq commit (--if-let (magit-get-upstream-branch)
- (magit-git-string "merge-base" it "HEAD")
- nil))
- (unless (magit-rev-ancestor-p commit "HEAD")
- (user-error "%s isn't an ancestor of HEAD" commit))
- (if (magit-commit-parents commit)
- (when (or (not (eq this-command 'magit-rebase-interactive))
- magit-rebase-interactive-include-selected)
- (setq commit (concat commit "^")))
- (setq args (cons "--root" args)))))
- (when (and commit (not noassert))
- (setq commit (magit-rebase-interactive-assert
- commit delay-edit-confirm
- (--some (string-prefix-p "--rebase-merges" it) args))))
- (if (and commit (not confirm))
- (let ((process-environment process-environment))
- (when editor
- (push (concat "GIT_SEQUENCE_EDITOR="
- (if (functionp editor)
- (funcall editor commit)
- editor))
- process-environment))
- (magit-run-git-sequencer "rebase" "-i" args
- (unless (member "--root" args) commit)))
- (magit-log-select
- `(lambda (commit)
- (magit-rebase-interactive-1 commit (list ,@args)
- ,message ,editor ,delay-edit-confirm ,noassert))
- message)))
-
-(defvar magit--rebase-published-symbol nil)
-(defvar magit--rebase-public-edit-confirmed nil)
-
-(defun magit-rebase-interactive-assert
- (since &optional delay-edit-confirm rebase-merges)
- (let* ((commit (magit-rebase--target-commit since))
- (branches (magit-list-publishing-branches commit)))
- (setq magit--rebase-public-edit-confirmed
- (delete (magit-toplevel) magit--rebase-public-edit-confirmed))
- (when (and branches
- (or (not delay-edit-confirm)
- ;; The user might have stopped at a published commit
- ;; merely to add new commits *after* it. Try not to
- ;; ask users whether they really want to edit public
- ;; commits, when they don't actually intend to do so.
- (not (--all-p (magit-rev-equal it commit) branches))))
- (let ((m1 "Some of these commits have already been published to ")
- (m2 ".\nDo you really want to modify them"))
- (magit-confirm (or magit--rebase-published-symbol 'rebase-published)
- (concat m1 "%s" m2)
- (concat m1 "%i public branches" m2)
- nil branches))
- (push (magit-toplevel) magit--rebase-public-edit-confirmed)))
- (if (and (magit-git-lines "rev-list" "--merges" (concat since "..HEAD"))
- (not rebase-merges))
- (magit-read-char-case "Proceed despite merge in rebase range? " nil
- (?c "[c]ontinue" since)
- (?s "[s]elect other" nil)
- (?a "[a]bort" (user-error "Quit")))
- since))
-
-(defun magit-rebase--target-commit (since)
- (if (string-suffix-p "^" since)
- ;; If SINCE is "REV^", then the user selected
- ;; "REV", which is the first commit that will
- ;; be replaced. (from^..to] <=> [from..to]
- (substring since 0 -1)
- ;; The "--root" argument is being used.
- since))
-
-;;;###autoload
-(defun magit-rebase-interactive (commit args)
- "Start an interactive rebase sequence."
- (interactive (list (magit-commit-at-point)
- (magit-rebase-arguments)))
- (magit-rebase-interactive-1 commit args
- "Type %p on a commit to rebase it and all commits above it,"
- nil t))
-
-;;;###autoload
-(defun magit-rebase-autosquash (args)
- "Combine squash and fixup commits with their intended targets."
- (interactive (list (magit-rebase-arguments)))
- (magit-rebase-interactive-1 :merge-base
- (nconc (list "--autosquash" "--keep-empty") args)
- "Type %p on a commit to squash into it and then rebase as necessary,"
- "true" nil t))
-
-;;;###autoload
-(defun magit-rebase-edit-commit (commit args)
- "Edit a single older commit using rebase."
- (interactive (list (magit-commit-at-point)
- (magit-rebase-arguments)))
- (magit-rebase-interactive-1 commit args
- "Type %p on a commit to edit it,"
- (apply-partially #'magit-rebase--perl-editor 'edit)
- t))
-
-;;;###autoload
-(defun magit-rebase-reword-commit (commit args)
- "Reword a single older commit using rebase."
- (interactive (list (magit-commit-at-point)
- (magit-rebase-arguments)))
- (magit-rebase-interactive-1 commit args
- "Type %p on a commit to reword its message,"
- (apply-partially #'magit-rebase--perl-editor 'reword)))
-
-;;;###autoload
-(defun magit-rebase-remove-commit (commit args)
- "Remove a single older commit using rebase."
- (interactive (list (magit-commit-at-point)
- (magit-rebase-arguments)))
- (magit-rebase-interactive-1 commit args
- "Type %p on a commit to remove it,"
- (apply-partially #'magit-rebase--perl-editor 'remove)
- nil nil t))
-
-(defun magit-rebase--perl-editor (action since)
- (let ((commit (magit-rev-abbrev (magit-rebase--target-commit since))))
- (format "%s -i -p -e '++$x if not $x and s/^pick %s/%s %s/'"
- magit-perl-executable
- commit
- (cl-case action
- (edit "edit")
- (remove "noop\n# pick")
- (reword "reword")
- (t (error "unknown action: %s" action)))
- commit)))
-
-;;;###autoload
-(defun magit-rebase-continue (&optional noedit)
- "Restart the current rebasing operation.
-In some cases this pops up a commit message buffer for you do
-edit. With a prefix argument the old message is reused as-is."
- (interactive "P")
- (if (magit-rebase-in-progress-p)
- (if (magit-anything-unstaged-p t)
- (user-error "Cannot continue rebase with unstaged changes")
- (when (and (magit-anything-staged-p)
- (file-exists-p (magit-git-dir "rebase-merge"))
- (not (member (magit-toplevel)
- magit--rebase-public-edit-confirmed)))
- (magit-commit-amend-assert
- (magit-file-line (magit-git-dir "rebase-merge/orig-head"))))
- (if noedit
- (let ((process-environment process-environment))
- (push "GIT_EDITOR=true" process-environment)
- (magit-run-git-async (magit--rebase-resume-command) "--continue")
- (set-process-sentinel magit-this-process
- #'magit-sequencer-process-sentinel)
- magit-this-process)
- (magit-run-git-sequencer (magit--rebase-resume-command) "--continue")))
- (user-error "No rebase in progress")))
-
-;;;###autoload
-(defun magit-rebase-skip ()
- "Skip the current commit and restart the current rebase operation."
- (interactive)
- (unless (magit-rebase-in-progress-p)
- (user-error "No rebase in progress"))
- (magit-run-git-sequencer (magit--rebase-resume-command) "--skip"))
-
-;;;###autoload
-(defun magit-rebase-edit ()
- "Edit the todo list of the current rebase operation."
- (interactive)
- (unless (magit-rebase-in-progress-p)
- (user-error "No rebase in progress"))
- (magit-run-git-sequencer "rebase" "--edit-todo"))
-
-;;;###autoload
-(defun magit-rebase-abort ()
- "Abort the current rebase operation, restoring the original branch."
- (interactive)
- (unless (magit-rebase-in-progress-p)
- (user-error "No rebase in progress"))
- (magit-confirm 'abort-rebase "Abort this rebase")
- (magit-run-git (magit--rebase-resume-command) "--abort"))
-
-(defun magit-rebase-in-progress-p ()
- "Return t if a rebase is in progress."
- (or (file-exists-p (magit-git-dir "rebase-merge"))
- (file-exists-p (magit-git-dir "rebase-apply/onto"))))
-
-(defun magit--rebase-resume-command ()
- (if (file-exists-p (magit-git-dir "rebase-recursive")) "rbr" "rebase"))
-
-;;; Sections
-
-(defun magit-insert-sequencer-sequence ()
- "Insert section for the on-going cherry-pick or revert sequence.
-If no such sequence is in progress, do nothing."
- (let ((picking (magit-cherry-pick-in-progress-p)))
- (when (or picking (magit-revert-in-progress-p))
- (magit-insert-section (sequence)
- (magit-insert-heading (if picking "Cherry Picking" "Reverting"))
- (when-let ((lines
- (cdr (magit-file-lines (magit-git-dir "sequencer/todo")))))
- (dolist (line (nreverse lines))
- (when (string-match
- "^\\(pick\\|revert\\) \\([^ ]+\\) \\(.*\\)$" line)
- (magit-bind-match-strings (cmd hash msg) line
- (magit-insert-section (commit hash)
- (insert (propertize cmd 'font-lock-face 'magit-sequence-pick)
- " " (propertize hash 'font-lock-face 'magit-hash)
- " " msg "\n"))))))
- (magit-sequence-insert-sequence
- (magit-file-line (magit-git-dir (if picking
- "CHERRY_PICK_HEAD"
- "REVERT_HEAD")))
- (magit-file-line (magit-git-dir "sequencer/head")))
- (insert "\n")))))
-
-(defun magit-insert-am-sequence ()
- "Insert section for the on-going patch applying sequence.
-If no such sequence is in progress, do nothing."
- (when (magit-am-in-progress-p)
- (magit-insert-section (rebase-sequence)
- (magit-insert-heading "Applying patches")
- (let ((patches (nreverse (magit-rebase-patches)))
- patch commit)
- (while patches
- (setq patch (pop patches))
- (setq commit (magit-commit-p
- (cadr (split-string (magit-file-line patch)))))
- (cond ((and commit patches)
- (magit-sequence-insert-commit
- "pick" commit 'magit-sequence-pick))
- (patches
- (magit-sequence-insert-am-patch
- "pick" patch 'magit-sequence-pick))
- (commit
- (magit-sequence-insert-sequence commit "ORIG_HEAD"))
- (t
- (magit-sequence-insert-am-patch
- "stop" patch 'magit-sequence-stop)
- (magit-sequence-insert-sequence nil "ORIG_HEAD")))))
- (insert ?\n))))
-
-(defun magit-sequence-insert-am-patch (type patch face)
- (magit-insert-section (file patch)
- (let ((title
- (with-temp-buffer
- (insert-file-contents patch nil nil 4096)
- (unless (re-search-forward "^Subject: " nil t)
- (goto-char (point-min)))
- (buffer-substring (point) (line-end-position)))))
- (insert (propertize type 'font-lock-face face)
- ?\s (propertize (file-name-nondirectory patch)
- 'font-lock-face 'magit-hash)
- ?\s title
- ?\n))))
-
-(defun magit-insert-rebase-sequence ()
- "Insert section for the on-going rebase sequence.
-If no such sequence is in progress, do nothing."
- (when (magit-rebase-in-progress-p)
- (let* ((interactive (file-directory-p (magit-git-dir "rebase-merge")))
- (dir (if interactive "rebase-merge/" "rebase-apply/"))
- (name (thread-first (concat dir "head-name")
- magit-git-dir
- magit-file-line))
- (onto (thread-first (concat dir "onto")
- magit-git-dir
- magit-file-line))
- (onto (or (magit-rev-name onto name)
- (magit-rev-name onto "refs/heads/*") onto))
- (name (or (magit-rev-name name "refs/heads/*") name)))
- (magit-insert-section (rebase-sequence)
- (magit-insert-heading (format "Rebasing %s onto %s" name onto))
- (if interactive
- (magit-rebase-insert-merge-sequence onto)
- (magit-rebase-insert-apply-sequence onto))
- (insert ?\n)))))
-
-(defun magit-rebase--todo ()
- "Return `git-rebase-action' instances for remaining rebase actions.
-These are ordered in that the same way they'll be sorted in the
-status buffer (i.e. the reverse of how they will be applied)."
- (let ((comment-start (or (magit-get "core.commentChar") "#"))
- lines)
- (with-temp-buffer
- (insert-file-contents (magit-git-dir "rebase-merge/git-rebase-todo"))
- (while (not (eobp))
- (let ((ln (git-rebase-current-line)))
- (when (oref ln action-type)
- (push ln lines)))
- (forward-line)))
- lines))
-
-(defun magit-rebase-insert-merge-sequence (onto)
- (dolist (line (magit-rebase--todo))
- (with-slots (action-type action action-options target) line
- (pcase action-type
- (`commit
- (magit-sequence-insert-commit action target 'magit-sequence-pick))
- ((or (or `exec `label)
- (and `merge (guard (not action-options))))
- (insert (propertize action 'font-lock-face 'magit-sequence-onto) "\s"
- (propertize target 'font-lock-face 'git-rebase-label) "\n"))
- (`merge
- (if-let ((hash (and (string-match "-[cC] \\([^ ]+\\)" action-options)
- (match-string 1 action-options))))
- (magit-insert-section (commit hash)
- (magit-insert-heading
- (propertize "merge" 'font-lock-face 'magit-sequence-pick)
- "\s"
- (magit-format-rev-summary hash) "\n"))
- (error "failed to parse merge message hash"))))))
- (magit-sequence-insert-sequence
- (magit-file-line (magit-git-dir "rebase-merge/stopped-sha"))
- onto
- (--when-let (magit-file-lines (magit-git-dir "rebase-merge/done"))
- (cadr (split-string (car (last it)))))))
-
-(defun magit-rebase-insert-apply-sequence (onto)
- (let ((rewritten
- (--map (car (split-string it))
- (magit-file-lines (magit-git-dir "rebase-apply/rewritten"))))
- (stop (magit-file-line (magit-git-dir "rebase-apply/original-commit"))))
- (dolist (patch (nreverse (cdr (magit-rebase-patches))))
- (let ((hash (cadr (split-string (magit-file-line patch)))))
- (unless (or (member hash rewritten)
- (equal hash stop))
- (magit-sequence-insert-commit "pick" hash 'magit-sequence-pick)))))
- (magit-sequence-insert-sequence
- (magit-file-line (magit-git-dir "rebase-apply/original-commit"))
- onto))
-
-(defun magit-rebase-patches ()
- (directory-files (magit-git-dir "rebase-apply") t "^[0-9]\\{4\\}$"))
-
-(defun magit-sequence-insert-sequence (stop onto &optional orig)
- (let ((head (magit-rev-parse "HEAD")) done)
- (setq onto (if onto (magit-rev-parse onto) head))
- (setq done (magit-git-lines "log" "--format=%H" (concat onto "..HEAD")))
- (when (and stop (not (member (magit-rev-parse stop) done)))
- (let ((id (magit-patch-id stop)))
- (--if-let (--first (equal (magit-patch-id it) id) done)
- (setq stop it)
- (cond
- ((--first (magit-rev-equal it stop) done)
- ;; The commit's testament has been executed.
- (magit-sequence-insert-commit "void" stop 'magit-sequence-drop))
- ;; The faith of the commit is still undecided...
- ((magit-anything-unmerged-p)
- ;; ...and time travel isn't for the faint of heart.
- (magit-sequence-insert-commit "join" stop 'magit-sequence-part))
- ((magit-anything-modified-p t)
- ;; ...and the dust hasn't settled yet...
- (magit-sequence-insert-commit
- (let* ((magit--refresh-cache nil)
- (staged (magit-commit-tree "oO" nil "HEAD"))
- (unstaged (magit-commit-worktree "oO" "--reset")))
- (cond
- ;; ...but we could end up at the same tree just by committing.
- ((or (magit-rev-equal staged stop)
- (magit-rev-equal unstaged stop)) "goal")
- ;; ...but the changes are still there, untainted.
- ((or (equal (magit-patch-id staged) id)
- (equal (magit-patch-id unstaged) id)) "same")
- ;; ...and some changes are gone and/or others were added.
- (t "work")))
- stop 'magit-sequence-part))
- ;; The commit is definitely gone...
- ((--first (magit-rev-equal it stop) done)
- ;; ...but all of its changes are still in effect.
- (magit-sequence-insert-commit "poof" stop 'magit-sequence-drop))
- (t
- ;; ...and some changes are gone and/or other changes were added.
- (magit-sequence-insert-commit "gone" stop 'magit-sequence-drop)))
- (setq stop nil))))
- (dolist (rev done)
- (apply 'magit-sequence-insert-commit
- (cond ((equal rev stop)
- ;; ...but its reincarnation lives on.
- ;; Or it didn't die in the first place.
- (list (if (and (equal rev head)
- (equal (magit-patch-id rev)
- (magit-patch-id orig)))
- "stop" ; We haven't done anything yet.
- "like") ; There are new commits.
- rev (if (equal rev head)
- 'magit-sequence-head
- 'magit-sequence-stop)))
- ((equal rev head)
- (list "done" rev 'magit-sequence-head))
- (t
- (list "done" rev 'magit-sequence-done)))))
- (magit-sequence-insert-commit "onto" onto
- (if (equal onto head)
- 'magit-sequence-head
- 'magit-sequence-onto))))
-
-(defun magit-sequence-insert-commit (type hash face)
- (magit-insert-section (commit hash)
- (magit-insert-heading
- (propertize type 'font-lock-face face) "\s"
- (magit-format-rev-summary hash) "\n")))
-
-;;; _
-(provide 'magit-sequence)
-;;; magit-sequence.el ends here
+++ /dev/null
-;;; magit-stash.el --- stash support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; Support for Git stashes.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit)
-(require 'magit-reflog)
-
-;; For `magit-stash-drop'.
-(defvar helm-comp-read-use-marked)
-
-;;; Options
-
-(defgroup magit-stash nil
- "List stashes and show stash diffs."
- :group 'magit-modes)
-
-;;;; Diff options
-
-(defcustom magit-stash-sections-hook
- '(magit-insert-stash-notes
- magit-insert-stash-worktree
- magit-insert-stash-index
- magit-insert-stash-untracked)
- "Hook run to insert sections into stash diff buffers."
- :package-version '(magit . "2.1.0")
- :group 'magit-stash
- :type 'hook)
-
-;;;; Log options
-
-(defcustom magit-stashes-margin
- (list (nth 0 magit-log-margin)
- (nth 1 magit-log-margin)
- 'magit-log-margin-width nil
- (nth 4 magit-log-margin))
- "Format of the margin in `magit-stashes-mode' buffers.
-
-The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
-
-If INIT is non-nil, then the margin is shown initially.
-STYLE controls how to format the author or committer date.
- It can be one of `age' (to show the age of the commit),
- `age-abbreviated' (to abbreviate the time unit to a character),
- or a string (suitable for `format-time-string') to show the
- actual date. Option `magit-log-margin-show-committer-date'
- controls which date is being displayed.
-WIDTH controls the width of the margin. This exists for forward
- compatibility and currently the value should not be changed.
-AUTHOR controls whether the name of the author is also shown by
- default.
-AUTHOR-WIDTH has to be an integer. When the name of the author
- is shown, then this specifies how much space is used to do so."
- :package-version '(magit . "2.9.0")
- :group 'magit-stash
- :group 'magit-margin
- :type magit-log-margin--custom-type
- :initialize 'magit-custom-initialize-reset
- :set-after '(magit-log-margin)
- :set (apply-partially #'magit-margin-set-variable 'magit-stashes-mode))
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-stash "magit-stash" nil t)
-(transient-define-prefix magit-stash ()
- "Stash uncommitted changes."
- :man-page "git-stash"
- ["Arguments"
- ("-u" "Also save untracked files" ("-u" "--include-untracked"))
- ("-a" "Also save untracked and ignored files" ("-a" "--all"))]
- [["Stash"
- ("z" "both" magit-stash-both)
- ("i" "index" magit-stash-index)
- ("w" "worktree" magit-stash-worktree)
- ("x" "keeping index" magit-stash-keep-index)]
- ["Snapshot"
- ("Z" "both" magit-snapshot-both)
- ("I" "index" magit-snapshot-index)
- ("W" "worktree" magit-snapshot-worktree)
- ("r" "to wip ref" magit-wip-commit)]
- ["Use"
- ("a" "Apply" magit-stash-apply)
- ("p" "Pop" magit-stash-pop)
- ("k" "Drop" magit-stash-drop)]
- ["Inspect"
- ("l" "List" magit-stash-list)
- ("v" "Show" magit-stash-show)]
- ["Transform"
- ("b" "Branch" magit-stash-branch)
- ("B" "Branch here" magit-stash-branch-here)
- ("f" "Format patch" magit-stash-format-patch)]])
-
-(defun magit-stash-arguments ()
- (transient-args 'magit-stash))
-
-;;;###autoload
-(defun magit-stash-both (message &optional include-untracked)
- "Create a stash of the index and working tree.
-Untracked files are included according to infix arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-stash-read-args))
- (magit-stash-save message t t include-untracked t))
-
-;;;###autoload
-(defun magit-stash-index (message)
- "Create a stash of the index only.
-Unstaged and untracked changes are not stashed. The stashed
-changes are applied in reverse to both the index and the
-worktree. This command can fail when the worktree is not clean.
-Applying the resulting stash has the inverse effect."
- (interactive (list (magit-stash-read-message)))
- (magit-stash-save message t nil nil t 'worktree))
-
-;;;###autoload
-(defun magit-stash-worktree (message &optional include-untracked)
- "Create a stash of unstaged changes in the working tree.
-Untracked files are included according to infix arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-stash-read-args))
- (magit-stash-save message nil t include-untracked t 'index))
-
-;;;###autoload
-(defun magit-stash-keep-index (message &optional include-untracked)
- "Create a stash of the index and working tree, keeping index intact.
-Untracked files are included according to infix arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-stash-read-args))
- (magit-stash-save message t t include-untracked t 'index))
-
-(defun magit-stash-read-args ()
- (list (magit-stash-read-message)
- (magit-stash-read-untracked)))
-
-(defun magit-stash-read-untracked ()
- (let ((prefix (prefix-numeric-value current-prefix-arg))
- (args (magit-stash-arguments)))
- (cond ((or (= prefix 16) (member "--all" args)) 'all)
- ((or (= prefix 4) (member "--include-untracked" args)) t))))
-
-(defun magit-stash-read-message ()
- (let* ((default (format "On %s: "
- (or (magit-get-current-branch) "(no branch)")))
- (input (magit-read-string "Stash message" default)))
- (if (equal input default)
- (concat default (magit-rev-format "%h %s"))
- input)))
-
-;;;###autoload
-(defun magit-snapshot-both (&optional include-untracked)
- "Create a snapshot of the index and working tree.
-Untracked files are included according to infix arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-snapshot-read-args))
- (magit-snapshot-save t t include-untracked t))
-
-;;;###autoload
-(defun magit-snapshot-index ()
- "Create a snapshot of the index only.
-Unstaged and untracked changes are not stashed."
- (interactive)
- (magit-snapshot-save t nil nil t))
-
-;;;###autoload
-(defun magit-snapshot-worktree (&optional include-untracked)
- "Create a snapshot of unstaged changes in the working tree.
-Untracked files are included according to infix arguments.
-One prefix argument is equivalent to `--include-untracked'
-while two prefix arguments are equivalent to `--all'."
- (interactive (magit-snapshot-read-args))
- (magit-snapshot-save nil t include-untracked t))
-
-(defun magit-snapshot-read-args ()
- (list (magit-stash-read-untracked)))
-
-(defun magit-snapshot-save (index worktree untracked &optional refresh)
- (magit-stash-save (concat "WIP on " (magit-stash-summary))
- index worktree untracked refresh t))
-
-;;;###autoload
-(defun magit-stash-apply (stash)
- "Apply a stash to the working tree.
-Try to preserve the stash index. If that fails because there
-are staged changes, apply without preserving the stash index."
- (interactive (list (magit-read-stash "Apply stash")))
- (if (= (magit-call-git "stash" "apply" "--index" stash) 0)
- (magit-refresh)
- (magit-run-git "stash" "apply" stash)))
-
-(defun magit-stash-pop (stash)
- "Apply a stash to the working tree and remove it from stash list.
-Try to preserve the stash index. If that fails because there
-are staged changes, apply without preserving the stash index
-and forgo removing the stash."
- (interactive (list (magit-read-stash "Pop stash")))
- (if (= (magit-call-git "stash" "apply" "--index" stash) 0)
- (magit-stash-drop stash)
- (magit-run-git "stash" "apply" stash)))
-
-;;;###autoload
-(defun magit-stash-drop (stash)
- "Remove a stash from the stash list.
-When the region is active offer to drop all contained stashes."
- (interactive
- (list (--if-let (magit-region-values 'stash)
- (magit-confirm 'drop-stashes nil "Drop %i stashes" nil it)
- (let ((helm-comp-read-use-marked t))
- (magit-read-stash "Drop stash")))))
- (dolist (stash (if (listp stash)
- (nreverse (prog1 stash (setq stash (car stash))))
- (list stash)))
- (message "Deleted refs/%s (was %s)" stash
- (magit-rev-parse "--short" stash))
- (magit-call-git "rev-parse" stash)
- (magit-call-git "reflog" "delete" "--updateref" "--rewrite" stash))
- (when-let ((ref (and (string-match "\\(.+\\)@{[0-9]+}$" stash)
- (match-string 1 stash))))
- (unless (string-match "^refs/" ref)
- (setq ref (concat "refs/" ref)))
- (unless (magit-rev-verify (concat ref "@{0}"))
- (magit-run-git "update-ref" "-d" ref)))
- (magit-refresh))
-
-;;;###autoload
-(defun magit-stash-clear (ref)
- "Remove all stashes saved in REF's reflog by deleting REF."
- (interactive (let ((ref (or (magit-section-value-if 'stashes) "refs/stash")))
- (magit-confirm t (format "Drop all stashes in %s" ref))
- (list ref)))
- (magit-run-git "update-ref" "-d" ref))
-
-;;;###autoload
-(defun magit-stash-branch (stash branch)
- "Create and checkout a new BRANCH from STASH."
- (interactive (list (magit-read-stash "Branch stash")
- (magit-read-string-ns "Branch name")))
- (magit-run-git "stash" "branch" branch stash))
-
-;;;###autoload
-(defun magit-stash-branch-here (stash branch)
- "Create and checkout a new BRANCH and apply STASH.
-The branch is created using `magit-branch-and-checkout', using the
-current branch or `HEAD' as the start-point."
- (interactive (list (magit-read-stash "Branch stash")
- (magit-read-string-ns "Branch name")))
- (let ((inhibit-magit-refresh t))
- (magit-branch-and-checkout branch (or (magit-get-current-branch) "HEAD")))
- (magit-stash-apply stash))
-
-;;;###autoload
-(defun magit-stash-format-patch (stash)
- "Create a patch from STASH"
- (interactive (list (magit-read-stash "Create patch from stash")))
- (with-temp-file (magit-rev-format "0001-%f.patch" stash)
- (magit-git-insert "stash" "show" "-p" stash))
- (magit-refresh))
-
-;;; Plumbing
-
-(defun magit-stash-save (message index worktree untracked
- &optional refresh keep noerror ref)
- (if (or (and index (magit-staged-files t))
- (and worktree (magit-unstaged-files t))
- (and untracked (magit-untracked-files (eq untracked 'all))))
- (magit-with-toplevel
- (magit-stash-store message (or ref "refs/stash")
- (magit-stash-create message index worktree untracked))
- (if (eq keep 'worktree)
- (with-temp-buffer
- (magit-git-insert "diff" "--cached")
- (magit-run-git-with-input
- "apply" "--reverse" "--cached" "--ignore-space-change" "-")
- (magit-run-git-with-input
- "apply" "--reverse" "--ignore-space-change" "-"))
- (unless (eq keep t)
- (if (eq keep 'index)
- (magit-call-git "checkout" "--" ".")
- (magit-call-git "reset" "--hard" "HEAD" "--"))
- (when untracked
- (magit-call-git "clean" "--force" "-d"
- (and (eq untracked 'all) "-x")))))
- (when refresh
- (magit-refresh)))
- (unless noerror
- (user-error "No %s changes to save" (cond ((not index) "unstaged")
- ((not worktree) "staged")
- (t "local"))))))
-
-(defun magit-stash-store (message ref commit)
- (magit-update-ref ref message commit t))
-
-(defun magit-stash-create (message index worktree untracked)
- (unless (magit-rev-parse "--verify" "HEAD")
- (error "You do not have the initial commit yet"))
- (let ((magit-git-global-arguments (nconc (list "-c" "commit.gpgsign=false")
- magit-git-global-arguments))
- (default-directory (magit-toplevel))
- (summary (magit-stash-summary))
- (head "HEAD"))
- (when (and worktree (not index))
- (setq head (or (magit-commit-tree "pre-stash index" nil "HEAD")
- (error "Cannot save the current index state"))))
- (or (setq index (magit-commit-tree (concat "index on " summary) nil head))
- (error "Cannot save the current index state"))
- (and untracked
- (setq untracked (magit-untracked-files (eq untracked 'all)))
- (setq untracked (magit-with-temp-index nil nil
- (or (and (magit-update-files untracked)
- (magit-commit-tree
- (concat "untracked files on " summary)))
- (error "Cannot save the untracked files")))))
- (magit-with-temp-index index "-m"
- (when worktree
- (or (magit-update-files (magit-git-items "diff" "-z" "--name-only" head))
- (error "Cannot save the current worktree state")))
- (or (magit-commit-tree message nil head index untracked)
- (error "Cannot save the current worktree state")))))
-
-(defun magit-stash-summary ()
- (concat (or (magit-get-current-branch) "(no branch)")
- ": " (magit-rev-format "%h %s")))
-
-;;; Sections
-
-(defvar magit-stashes-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-delete-thing] 'magit-stash-clear)
- map)
- "Keymap for `stashes' section.")
-
-(defvar magit-stash-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-stash-show)
- (define-key map [remap magit-delete-thing] 'magit-stash-drop)
- (define-key map "a" 'magit-stash-apply)
- (define-key map "A" 'magit-stash-pop)
- map)
- "Keymap for `stash' sections.")
-
-(magit-define-section-jumper magit-jump-to-stashes
- "Stashes" stashes "refs/stash")
-
-(cl-defun magit-insert-stashes (&optional (ref "refs/stash")
- (heading "Stashes:"))
- "Insert `stashes' section showing reflog for \"refs/stash\".
-If optional REF is non-nil, show reflog for that instead.
-If optional HEADING is non-nil, use that as section heading
-instead of \"Stashes:\"."
- (let ((verified (magit-rev-verify ref))
- (autostash
- (and (magit-rebase-in-progress-p)
- (thread-first
- (if (file-directory-p (magit-git-dir "rebase-merge"))
- "rebase-merge/autostash"
- "rebase-apply/autostash")
- magit-git-dir
- magit-file-line))))
- (when (or autostash verified)
- (magit-insert-section (stashes ref)
- (magit-insert-heading heading)
- (when autostash
- (pcase-let ((`(,author ,date ,msg)
- (split-string
- (car (magit-git-lines
- "show" "-q" "--format=%aN%x00%at%x00%s"
- autostash))
- "\0")))
- (magit-insert-section (stash autostash)
- (insert (propertize "AUTOSTASH" 'font-lock-face 'magit-hash))
- (insert " " msg "\n")
- (save-excursion
- (backward-char)
- (magit-log-format-margin autostash author date)))))
- (if verified
- (magit-git-wash (apply-partially 'magit-log-wash-log 'stash)
- "reflog" "--format=%gd%x00%aN%x00%at%x00%gs" ref)
- (insert ?\n)
- (save-excursion
- (backward-char)
- (magit-make-margin-overlay)))))))
-
-;;; List Stashes
-
-;;;###autoload
-(defun magit-stash-list ()
- "List all stashes in a buffer."
- (interactive)
- (magit-stashes-setup-buffer))
-
-(define-derived-mode magit-stashes-mode magit-reflog-mode "Magit Stashes"
- "Mode for looking at lists of stashes."
- :group 'magit-log
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-stashes-setup-buffer ()
- (magit-setup-buffer #'magit-stashes-mode nil
- (magit-buffer-refname "refs/stash")))
-
-(defun magit-stashes-refresh-buffer ()
- (magit-insert-section (stashesbuf)
- (magit-insert-heading (if (equal magit-buffer-refname "refs/stash")
- "Stashes:"
- (format "Stashes [%s]:" magit-buffer-refname)))
- (magit-git-wash (apply-partially 'magit-log-wash-log 'stash)
- "reflog" "--format=%gd%x00%aN%x00%at%x00%gs" magit-buffer-refname)))
-
-(cl-defmethod magit-buffer-value (&context (major-mode magit-stashes-mode))
- magit-buffer-refname)
-
-(defvar magit--update-stash-buffer nil)
-
-(defun magit-stashes-maybe-update-stash-buffer (&optional _)
- "When moving in the stashes buffer, update the stash buffer.
-If there is no stash buffer in the same frame, then do nothing."
- (when (derived-mode-p 'magit-stashes-mode)
- (magit--maybe-update-stash-buffer)))
-
-(defun magit--maybe-update-stash-buffer ()
- (when-let ((stash (magit-section-value-if 'stash))
- (buffer (magit-get-mode-buffer 'magit-stash-mode nil t)))
- (if magit--update-stash-buffer
- (setq magit--update-stash-buffer (list stash buffer))
- (setq magit--update-stash-buffer (list stash buffer))
- (run-with-idle-timer
- magit-update-other-window-delay nil
- (let ((args (with-current-buffer buffer
- (let ((magit-direct-use-buffer-arguments 'selected))
- (magit-show-commit--arguments)))))
- (lambda ()
- (pcase-let ((`(,stash ,buf) magit--update-stash-buffer))
- (setq magit--update-stash-buffer nil)
- (when (buffer-live-p buf)
- (let ((magit-display-buffer-noselect t))
- (apply #'magit-stash-show stash args))))
- (setq magit--update-stash-buffer nil)))))))
-
-;;; Show Stash
-
-;;;###autoload
-(defun magit-stash-show (stash &optional args files)
- "Show all diffs of a stash in a buffer."
- (interactive (cons (or (and (not current-prefix-arg)
- (magit-stash-at-point))
- (magit-read-stash "Show stash"))
- (pcase-let ((`(,args ,files)
- (magit-diff-arguments 'magit-stash-mode)))
- (list (delete "--stat" args) files))))
- (magit-stash-setup-buffer stash args files))
-
-(define-derived-mode magit-stash-mode magit-diff-mode "Magit Stash"
- "Mode for looking at individual stashes."
- :group 'magit-diff
- (hack-dir-local-variables-non-file-buffer))
-
-(defun magit-stash-setup-buffer (stash args files)
- (magit-setup-buffer #'magit-stash-mode nil
- (magit-buffer-revision stash)
- (magit-buffer-range (format "%s^..%s" stash stash))
- (magit-buffer-diff-args args)
- (magit-buffer-diff-files files)))
-
-(defun magit-stash-refresh-buffer ()
- (magit-set-header-line-format
- (concat (capitalize magit-buffer-revision) " "
- (propertize (magit-rev-format "%s" magit-buffer-revision)
- 'font-lock-face
- (list :weight 'normal :foreground
- (face-attribute 'default :foreground)))))
- (setq magit-buffer-revision-hash (magit-rev-parse magit-buffer-revision))
- (magit-insert-section (stash)
- (magit-run-section-hook 'magit-stash-sections-hook)))
-
-(cl-defmethod magit-buffer-value (&context (major-mode magit-stash-mode))
- magit-buffer-revision)
-
-(defun magit-stash-insert-section (commit range message &optional files)
- (magit-insert-section (commit commit)
- (magit-insert-heading message)
- (magit--insert-diff "diff" range "-p" "--no-prefix" magit-buffer-diff-args
- "--" (or files magit-buffer-diff-files))))
-
-(defun magit-insert-stash-notes ()
- "Insert section showing notes for a stash.
-This shows the notes for stash@{N} but not for the other commits
-that make up the stash."
- (magit-insert-section section (note)
- (magit-insert-heading "Notes")
- (magit-git-insert "notes" "show" magit-buffer-revision)
- (if (= (point)
- (oref section content))
- (magit-cancel-section)
- (insert "\n"))))
-
-(defun magit-insert-stash-index ()
- "Insert section showing staged changes of the stash."
- (magit-stash-insert-section
- (format "%s^2" magit-buffer-revision)
- (format "%s^..%s^2" magit-buffer-revision magit-buffer-revision)
- "Staged"))
-
-(defun magit-insert-stash-worktree ()
- "Insert section showing unstaged changes of the stash."
- (magit-stash-insert-section
- magit-buffer-revision
- (format "%s^2..%s" magit-buffer-revision magit-buffer-revision)
- "Unstaged"))
-
-(defun magit-insert-stash-untracked ()
- "Insert section showing the untracked files commit of the stash."
- (let ((stash magit-buffer-revision)
- (rev (concat magit-buffer-revision "^3")))
- (when (magit-rev-verify rev)
- (magit-stash-insert-section (format "%s^3" stash)
- (format "%s^..%s^3" stash stash)
- "Untracked files"
- (magit-git-items "ls-tree" "-z" "--name-only"
- "-r" "--full-tree" rev)))))
-
-;;; _
-(provide 'magit-stash)
-;;; magit-stash.el ends here
+++ /dev/null
-;;; magit-status.el --- the grand overview -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements the status buffer.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit)
-
-;;; Options
-
-(defgroup magit-status nil
- "Inspect and manipulate Git repositories."
- :link '(info-link "(magit)Status Buffer")
- :group 'magit-modes)
-
-(defcustom magit-status-mode-hook nil
- "Hook run after entering Magit-Status mode."
- :group 'magit-status
- :type 'hook)
-
-(defcustom magit-status-headers-hook
- '(magit-insert-error-header
- magit-insert-diff-filter-header
- magit-insert-head-branch-header
- magit-insert-upstream-branch-header
- magit-insert-push-branch-header
- magit-insert-tags-header)
- "Hook run to insert headers into the status buffer.
-
-This hook is run by `magit-insert-status-headers', which in turn
-has to be a member of `magit-status-sections-hook' to be used at
-all."
- :package-version '(magit . "2.1.0")
- :group 'magit-status
- :type 'hook
- :options '(magit-insert-error-header
- magit-insert-diff-filter-header
- magit-insert-repo-header
- magit-insert-remote-header
- magit-insert-head-branch-header
- magit-insert-upstream-branch-header
- magit-insert-push-branch-header
- magit-insert-tags-header))
-
-(defcustom magit-status-sections-hook
- '(magit-insert-status-headers
- magit-insert-merge-log
- magit-insert-rebase-sequence
- magit-insert-am-sequence
- magit-insert-sequencer-sequence
- magit-insert-bisect-output
- magit-insert-bisect-rest
- magit-insert-bisect-log
- magit-insert-untracked-files
- magit-insert-unstaged-changes
- magit-insert-staged-changes
- magit-insert-stashes
- magit-insert-unpushed-to-pushremote
- magit-insert-unpushed-to-upstream-or-recent
- magit-insert-unpulled-from-pushremote
- magit-insert-unpulled-from-upstream)
- "Hook run to insert sections into a status buffer."
- :package-version '(magit . "2.12.0")
- :group 'magit-status
- :type 'hook)
-
-(defcustom magit-status-initial-section '(1)
- "The section point is placed on when a status buffer is created.
-
-When such a buffer is merely being refreshed or being shown again
-after it was merely buried, then this option has no effect.
-
-If this is nil, then point remains on the very first section as
-usual. Otherwise it has to be a list of integers and section
-identity lists. The members of that list are tried in order
-until a matching section is found.
-
-An integer means to jump to the nth section, 1 for example
-jumps over the headings. To get a section's \"identity list\"
-use \\[universal-argument] \\[magit-describe-section-briefly].
-
-If, for example, you want to jump to the commits that haven't
-been pulled from the upstream, or else the second section, then
-use: (((unpulled . \"..@{upstream}\") (status)) 1).
-
-See option `magit-section-initial-visibility-alist' for how to
-control the initial visibility of the jumped to section."
- :package-version '(magit . "2.90.0")
- :group 'magit-status
- :type '(choice (const :tag "as usual" nil)
- (repeat (choice (number :tag "nth top-level section")
- (sexp :tag "section identity")))))
-
-(defcustom magit-status-goto-file-position nil
- "Whether to go to position corresponding to file position.
-
-If this is non-nil and the current buffer is visiting a file,
-then `magit-status' tries to go to the position in the status
-buffer that corresponds to the position in the file-visiting
-buffer. This jumps into either the diff of unstaged changes
-or the diff of staged changes.
-
-If the previously current buffer does not visit a file, or if
-the file has neither unstaged nor staged changes then this has
-no effect.
-
-The command `magit-status-here' tries to go to that position,
-regardless of the value of this option."
- :package-version '(magit . "3.0.0")
- :group 'magit-status
- :type 'boolean)
-
-(defcustom magit-status-show-hashes-in-headers nil
- "Whether headers in the status buffer show hashes.
-The functions which respect this option are
-`magit-insert-head-branch-header',
-`magit-insert-upstream-branch-header', and
-`magit-insert-push-branch-header'."
- :package-version '(magit . "2.4.0")
- :group 'magit-status
- :type 'boolean)
-
-(defcustom magit-status-margin
- (list nil
- (nth 1 magit-log-margin)
- 'magit-log-margin-width nil
- (nth 4 magit-log-margin))
- "Format of the margin in `magit-status-mode' buffers.
-
-The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
-
-If INIT is non-nil, then the margin is shown initially.
-STYLE controls how to format the author or committer date.
- It can be one of `age' (to show the age of the commit),
- `age-abbreviated' (to abbreviate the time unit to a character),
- or a string (suitable for `format-time-string') to show the
- actual date. Option `magit-log-margin-show-committer-date'
- controls which date is being displayed.
-WIDTH controls the width of the margin. This exists for forward
- compatibility and currently the value should not be changed.
-AUTHOR controls whether the name of the author is also shown by
- default.
-AUTHOR-WIDTH has to be an integer. When the name of the author
- is shown, then this specifies how much space is used to do so."
- :package-version '(magit . "2.9.0")
- :group 'magit-status
- :group 'magit-margin
- :type magit-log-margin--custom-type
- :initialize 'magit-custom-initialize-reset
- :set-after '(magit-log-margin)
- :set (apply-partially #'magit-margin-set-variable 'magit-status-mode))
-
-(defcustom magit-status-use-buffer-arguments 'selected
- "Whether `magit-status' reuses arguments when the buffer already exists.
-
-This option has no effect when merely refreshing the status
-buffer using `magit-refresh'.
-
-Valid values are:
-
-`always': Always use the set of arguments that is currently
- active in the status buffer, provided that buffer exists
- of course.
-`selected': Use the set of arguments from the status
- buffer, but only if it is displayed in a window of the
- current frame. This is the default.
-`current': Use the set of arguments from the status buffer,
- but only if it is the current buffer.
-`never': Never use the set of arguments from the status
- buffer."
- :package-version '(magit . "3.0.0")
- :group 'magit-buffers
- :group 'magit-commands
- :type '(choice
- (const :tag "always use args from buffer" always)
- (const :tag "use args from buffer if displayed in frame" selected)
- (const :tag "use args from buffer if it is current" current)
- (const :tag "never use args from buffer" never)))
-
-;;; Commands
-
-;;;###autoload
-(defun magit-init (directory)
- "Initialize a Git repository, then show its status.
-
-If the directory is below an existing repository, then the user
-has to confirm that a new one should be created inside. If the
-directory is the root of the existing repository, then the user
-has to confirm that it should be reinitialized.
-
-Non-interactively DIRECTORY is (re-)initialized unconditionally."
- (interactive
- (let ((directory (file-name-as-directory
- (expand-file-name
- (read-directory-name "Create repository in: ")))))
- (when-let ((toplevel (magit-toplevel directory)))
- (setq toplevel (expand-file-name toplevel))
- (unless (y-or-n-p (if (file-equal-p toplevel directory)
- (format "Reinitialize existing repository %s? "
- directory)
- (format "%s is a repository. Create another in %s? "
- toplevel directory)))
- (user-error "Abort")))
- (list directory)))
- ;; `git init' does not understand the meaning of "~"!
- (magit-call-git "init" (magit-convert-filename-for-git
- (expand-file-name directory)))
- (magit-status-setup-buffer directory))
-
-;;;###autoload
-(defun magit-status (&optional directory cache)
- "Show the status of the current Git repository in a buffer.
-
-If the current directory isn't located within a Git repository,
-then prompt for an existing repository or an arbitrary directory,
-depending on option `magit-repository-directories', and show the
-status of the selected repository instead.
-
-* If that option specifies any existing repositories, then offer
- those for completion and show the status buffer for the
- selected one.
-
-* Otherwise read an arbitrary directory using regular file-name
- completion. If the selected directory is the top-level of an
- existing working tree, then show the status buffer for that.
-
-* Otherwise offer to initialize the selected directory as a new
- repository. After creating the repository show its status
- buffer.
-
-These fallback behaviors can also be forced using one or more
-prefix arguments:
-
-* With two prefix arguments (or more precisely a numeric prefix
- value of 16 or greater) read an arbitrary directory and act on
- it as described above. The same could be accomplished using
- the command `magit-init'.
-
-* With a single prefix argument read an existing repository, or
- if none can be found based on `magit-repository-directories',
- then fall back to the same behavior as with two prefix
- arguments."
- (interactive
- (let ((magit--refresh-cache (list (cons 0 0))))
- (list (and (or current-prefix-arg (not (magit-toplevel)))
- (magit-read-repository
- (>= (prefix-numeric-value current-prefix-arg) 16)))
- magit--refresh-cache)))
- (let ((magit--refresh-cache (or cache (list (cons 0 0)))))
- (if directory
- (let ((toplevel (magit-toplevel directory)))
- (setq directory (file-name-as-directory
- (expand-file-name directory)))
- (if (and toplevel (file-equal-p directory toplevel))
- (magit-status-setup-buffer directory)
- (when (y-or-n-p
- (if toplevel
- (format "%s is a repository. Create another in %s? "
- toplevel directory)
- (format "Create repository in %s? " directory)))
- ;; Creating a new repository invalidates cached values.
- (setq magit--refresh-cache nil)
- (magit-init directory))))
- (magit-status-setup-buffer default-directory))))
-
-(put 'magit-status 'interactive-only 'magit-status-setup-buffer)
-
-;;;###autoload
-(defalias 'magit 'magit-status
- "An alias for `magit-status' for better discoverability.
-
-Instead of invoking this alias for `magit-status' using
-\"M-x magit RET\", you should bind a key to `magit-status'
-and read the info node `(magit)Getting Started', which
-also contains other useful hints.")
-
-;;;###autoload
-(defun magit-status-here ()
- "Like `magit-status' but with non-nil `magit-status-goto-file-position'."
- (interactive)
- (let ((magit-status-goto-file-position t))
- (call-interactively #'magit-status)))
-
-(put 'magit-status-here 'interactive-only 'magit-status-setup-buffer)
-
-(defvar magit--remotes-using-recent-git nil)
-
-(defun magit--tramp-asserts (directory)
- (when-let ((remote (file-remote-p directory)))
- (unless (member remote magit--remotes-using-recent-git)
- (if-let ((version (let ((default-directory directory))
- (magit-git-version))))
- (if (version<= magit--minimal-git version)
- (push remote magit--remotes-using-recent-git)
- (display-warning 'magit (format "\
-Magit requires Git >= %s, but on %s the version is %s.
-
-If multiple Git versions are installed on the host, then the
-problem might be that TRAMP uses the wrong executable.
-
-First check the value of `magit-git-executable'. Its value is
-used when running git locally as well as when running it on a
-remote host. The default value is \"git\", except on Windows
-where an absolute path is used for performance reasons.
-
-If the value already is just \"git\" but TRAMP never-the-less
-doesn't use the correct executable, then consult the info node
-`(tramp)Remote programs'.\n" magit--minimal-git remote version) :error))
- (display-warning 'magit (format "\
-Magit cannot find Git on %s.
-
-First check the value of `magit-git-executable'. Its value is
-used when running git locally as well as when running it on a
-remote host. The default value is \"git\", except on Windows
-where an absolute path is used for performance reasons.
-
-If the value already is just \"git\" but TRAMP never-the-less
-doesn't find the executable, then consult the info node
-`(tramp)Remote programs'.\n" remote) :error)))))
-
-;;; Mode
-
-(defvar magit-status-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-mode-map)
- (define-key map "j" 'magit-status-jump)
- (define-key map [remap dired-jump] 'magit-dired-jump)
- map)
- "Keymap for `magit-status-mode'.")
-
-(transient-define-prefix magit-status-jump ()
- "In a Magit-Status buffer, jump to a section."
- ["Jump to"
- [("z " "Stashes" magit-jump-to-stashes
- :if (lambda () (memq 'magit-insert-stashes magit-status-sections-hook)))
- ("t " "Tracked" magit-jump-to-tracked
- :if (lambda () (memq 'magit-insert-tracked-files magit-status-sections-hook)))
- ("n " "Untracked" magit-jump-to-untracked
- :if (lambda () (memq 'magit-insert-untracked-files magit-status-sections-hook)))
- ("u " "Unstaged" magit-jump-to-unstaged
- :if (lambda () (memq 'magit-insert-unstaged-changes magit-status-sections-hook)))
- ("s " "Staged" magit-jump-to-staged
- :if (lambda () (memq 'magit-insert-staged-changes magit-status-sections-hook)))]
- [("fu" "Unpulled from upstream" magit-jump-to-unpulled-from-upstream
- :if (lambda () (memq 'magit-insert-unpulled-from-upstream magit-status-sections-hook)))
- ("fp" "Unpulled from pushremote" magit-jump-to-unpulled-from-pushremote
- :if (lambda () (memq 'magit-insert-unpulled-from-pushremote magit-status-sections-hook)))
- ("pu" magit-jump-to-unpushed-to-upstream
- :if (lambda ()
- (or (memq 'magit-insert-unpushed-to-upstream-or-recent magit-status-sections-hook)
- (memq 'magit-insert-unpushed-to-upstream magit-status-sections-hook)))
- :description (lambda ()
- (let ((upstream (magit-get-upstream-branch)))
- (if (or (not upstream)
- (magit-rev-ancestor-p "HEAD" upstream))
- "Recent commits"
- "Unmerged into upstream"))))
- ("pp" "Unpushed to pushremote" magit-jump-to-unpushed-to-pushremote
- :if (lambda () (memq 'magit-insert-unpushed-to-pushremote magit-status-sections-hook)))
- ("a " "Assumed unstaged" magit-jump-to-assume-unchanged
- :if (lambda () (memq 'magit-insert-assume-unchanged-files magit-status-sections-hook)))
- ("w " "Skip worktree" magit-jump-to-skip-worktree
- :if (lambda () (memq 'magit-insert-skip-worktree-files magit-status-sections-hook)))]])
-
-(define-derived-mode magit-status-mode magit-mode "Magit"
- "Mode for looking at Git status.
-
-This mode is documented in info node `(magit)Status Buffer'.
-
-\\<magit-mode-map>\
-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'.
-
-\\<magit-hunk-section-map>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-status-mode-map>\
-Type \\[magit-commit] to create a commit.
-
-\\{magit-status-mode-map}"
- :group 'magit-status
- (hack-dir-local-variables-non-file-buffer)
- (setq imenu-create-index-function
- 'magit-imenu--status-create-index-function))
-
-(put 'magit-status-mode 'magit-diff-default-arguments
- '("--no-ext-diff"))
-(put 'magit-status-mode 'magit-log-default-arguments
- '("-n256" "--decorate"))
-
-;;;###autoload
-(defun magit-status-setup-buffer (&optional directory)
- (unless directory
- (setq directory default-directory))
- (magit--tramp-asserts directory)
- (let* ((default-directory directory)
- (d (magit-diff--get-value 'magit-status-mode
- magit-status-use-buffer-arguments))
- (l (magit-log--get-value 'magit-status-mode
- magit-status-use-buffer-arguments))
- (file (and magit-status-goto-file-position
- (magit-file-relative-name)))
- (line (and file (line-number-at-pos)))
- (col (and file (current-column)))
- (buf (magit-setup-buffer #'magit-status-mode nil
- (magit-buffer-diff-args (nth 0 d))
- (magit-buffer-diff-files (nth 1 d))
- (magit-buffer-log-args (nth 0 l))
- (magit-buffer-log-files (nth 1 l)))))
- (when file
- (with-current-buffer buf
- (let ((staged (magit-get-section '((staged) (status)))))
- (if (and staged
- (cadr (magit-diff--locate-hunk file line staged)))
- (magit-diff--goto-position file line col staged)
- (let ((unstaged (magit-get-section '((unstaged) (status)))))
- (unless (and unstaged
- (magit-diff--goto-position file line col unstaged))
- (when staged
- (magit-diff--goto-position file line col staged))))))))
- buf))
-
-(defun magit-status-refresh-buffer ()
- (magit-git-exit-code "update-index" "--refresh")
- (magit-insert-section (status)
- (magit-run-section-hook 'magit-status-sections-hook)))
-
-(defun magit-status-goto-initial-section ()
- "In a `magit-status-mode' buffer, jump `magit-status-initial-section'.
-Actually doing so is deferred until `magit-refresh-buffer-hook'
-runs `magit-status-goto-initial-section-1'. That function then
-removes itself from the hook, so that this only happens when the
-status buffer is first created."
- (when (and magit-status-initial-section
- (derived-mode-p 'magit-status-mode))
- (add-hook 'magit-refresh-buffer-hook
- 'magit-status-goto-initial-section-1 nil t)))
-
-(defun magit-status-goto-initial-section-1 ()
- "In a `magit-status-mode' buffer, jump `magit-status-initial-section'.
-This function removes itself from `magit-refresh-buffer-hook'."
- (when-let ((section
- (--some (if (integerp it)
- (nth (1- it)
- (magit-section-siblings (magit-current-section)
- 'next))
- (magit-get-section it))
- magit-status-initial-section)))
- (goto-char (oref section start))
- (when-let ((vis (cdr (assq 'magit-status-initial-section
- magit-section-initial-visibility-alist))))
- (if (eq vis 'hide)
- (magit-section-hide section)
- (magit-section-show section))))
- (remove-hook 'magit-refresh-buffer-hook
- 'magit-status-goto-initial-section-1 t))
-
-(defun magit-status-maybe-update-revision-buffer (&optional _)
- "When moving in the status buffer, update the revision buffer.
-If there is no revision buffer in the same frame, then do nothing."
- (when (derived-mode-p 'magit-status-mode)
- (magit--maybe-update-revision-buffer)))
-
-(defun magit-status-maybe-update-stash-buffer (&optional _)
- "When moving in the status buffer, update the stash buffer.
-If there is no stash buffer in the same frame, then do nothing."
- (when (derived-mode-p 'magit-status-mode)
- (magit--maybe-update-stash-buffer)))
-
-(defun magit-status-maybe-update-blob-buffer (&optional _)
- "When moving in the status buffer, update the blob buffer.
-If there is no blob buffer in the same frame, then do nothing."
- (when (derived-mode-p 'magit-status-mode)
- (magit--maybe-update-blob-buffer)))
-
-;;; Sections
-;;;; Special Headers
-
-(defun magit-insert-status-headers ()
- "Insert header sections appropriate for `magit-status-mode' buffers.
-The sections are inserted by running the functions on the hook
-`magit-status-headers-hook'."
- (if (magit-rev-verify "HEAD")
- (magit-insert-headers 'magit-status-headers-hook)
- (insert "In the beginning there was darkness\n\n")))
-
-(defvar magit-error-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-process-buffer)
- map)
- "Keymap for `error' sections.")
-
-(defun magit-insert-error-header ()
- "Insert the message about the Git error that just occurred.
-
-This function is only aware of the last error that occur when Git
-was run for side-effects. If, for example, an error occurs while
-generating a diff, then that error won't be inserted. Refreshing
-the status buffer causes this section to disappear again."
- (when magit-this-error
- (magit-insert-section (error 'git)
- (insert (propertize (format "%-10s" "GitError! ")
- 'font-lock-face 'magit-section-heading))
- (insert (propertize magit-this-error
- 'font-lock-face 'font-lock-warning-face))
- (when-let ((key (car (where-is-internal 'magit-process-buffer))))
- (insert (format " [Type `%s' for details]" (key-description key))))
- (insert ?\n))
- (setq magit-this-error nil)))
-
-(defun magit-insert-diff-filter-header ()
- "Insert a header line showing the effective diff filters."
- (let ((ignore-modules (magit-ignore-submodules-p)))
- (when (or ignore-modules
- magit-buffer-diff-files)
- (insert (propertize (format "%-10s" "Filter! ")
- 'font-lock-face 'magit-section-heading))
- (when ignore-modules
- (insert ignore-modules)
- (when magit-buffer-diff-files
- (insert " -- ")))
- (when magit-buffer-diff-files
- (insert (mapconcat #'identity magit-buffer-diff-files " ")))
- (insert ?\n))))
-
-;;;; Reference Headers
-
-(defun magit-insert-head-branch-header (&optional branch)
- "Insert a header line about the current branch.
-If `HEAD' is detached, then insert information about that commit
-instead. The optional BRANCH argument is for internal use only."
- (let ((branch (or branch (magit-get-current-branch)))
- (output (magit-rev-format "%h %s" (or branch "HEAD"))))
- (string-match "^\\([^ ]+\\) \\(.*\\)" output)
- (magit-bind-match-strings (commit summary) output
- (when (equal summary "")
- (setq summary "(no commit message)"))
- (if branch
- (magit-insert-section (branch branch)
- (insert (format "%-10s" "Head: "))
- (when magit-status-show-hashes-in-headers
- (insert (propertize commit 'font-lock-face 'magit-hash) ?\s))
- (insert (propertize branch 'font-lock-face 'magit-branch-local))
- (insert ?\s)
- (insert (funcall magit-log-format-message-function branch summary))
- (insert ?\n))
- (magit-insert-section (commit commit)
- (insert (format "%-10s" "Head: "))
- (insert (propertize commit 'font-lock-face 'magit-hash))
- (insert ?\s)
- (insert (funcall magit-log-format-message-function nil summary))
- (insert ?\n))))))
-
-(defun magit-insert-upstream-branch-header (&optional branch upstream keyword)
- "Insert a header line about the upstream of the current branch.
-If no branch is checked out, then insert nothing. The optional
-arguments are for internal use only."
- (when-let ((branch (or branch (magit-get-current-branch))))
- (let ((remote (magit-get "branch" branch "remote"))
- (merge (magit-get "branch" branch "merge"))
- (rebase (magit-get "branch" branch "rebase")))
- (when (or remote merge)
- (unless upstream
- (setq upstream (magit-get-upstream-branch branch)))
- (magit-insert-section (branch upstream)
- (pcase rebase
- ("true")
- ("false" (setq rebase nil))
- (_ (setq rebase (magit-get-boolean "pull.rebase"))))
- (insert (format "%-10s" (or keyword (if rebase "Rebase: " "Merge: "))))
- (insert
- (if upstream
- (concat (and magit-status-show-hashes-in-headers
- (concat (propertize (magit-rev-format "%h" upstream)
- 'font-lock-face 'magit-hash)
- " "))
- upstream " "
- (funcall magit-log-format-message-function upstream
- (funcall magit-log-format-message-function nil
- (or (magit-rev-format "%s" upstream)
- "(no commit message)"))))
- (cond
- ((magit--unnamed-upstream-p remote merge)
- (concat (propertize merge 'font-lock-face 'magit-branch-remote)
- " from "
- (propertize remote 'font-lock-face 'bold)))
- ((magit--valid-upstream-p remote merge)
- (if (equal remote ".")
- (concat
- (propertize merge 'font-lock-face 'magit-branch-local)
- (propertize " does not exist"
- 'font-lock-face 'font-lock-warning-face))
- (concat
- (propertize merge 'font-lock-face 'magit-branch-remote)
- (propertize " does not exist on "
- 'font-lock-face 'font-lock-warning-face)
- (propertize remote 'font-lock-face 'magit-branch-remote))))
- (t
- (propertize "invalid upstream configuration"
- 'font-lock-face 'font-lock-warning-face)))))
- (insert ?\n))))))
-
-(defun magit-insert-push-branch-header ()
- "Insert a header line about the branch the current branch is pushed to."
- (when-let ((branch (magit-get-current-branch))
- (target (magit-get-push-branch branch)))
- (magit-insert-section (branch target)
- (insert (format "%-10s" "Push: "))
- (insert
- (if (magit-rev-verify target)
- (concat target " "
- (and magit-status-show-hashes-in-headers
- (concat (propertize (magit-rev-format "%h" target)
- 'font-lock-face 'magit-hash)
- " "))
- (funcall magit-log-format-message-function target
- (funcall magit-log-format-message-function nil
- (or (magit-rev-format "%s" target)
- "(no commit message)"))))
- (let ((remote (magit-get-push-remote branch)))
- (if (magit-remote-p remote)
- (concat target
- (propertize " does not exist"
- 'font-lock-face 'font-lock-warning-face))
- (concat remote
- (propertize " remote does not exist"
- 'font-lock-face 'font-lock-warning-face))))))
- (insert ?\n))))
-
-(defun magit-insert-tags-header ()
- "Insert a header line about the current and/or next tag."
- (let* ((this-tag (magit-get-current-tag nil t))
- (next-tag (magit-get-next-tag nil t))
- (this-cnt (cadr this-tag))
- (next-cnt (cadr next-tag))
- (this-tag (car this-tag))
- (next-tag (car next-tag))
- (both-tags (and this-tag next-tag t)))
- (when (or this-tag next-tag)
- (magit-insert-section (tag (or this-tag next-tag))
- (insert (format "%-10s" (if both-tags "Tags: " "Tag: ")))
- (cl-flet ((insert-count
- (tag count face)
- (insert (concat (propertize tag 'font-lock-face 'magit-tag)
- (and (> count 0)
- (format " (%s)"
- (propertize
- (format "%s" count)
- 'font-lock-face face)))))))
- (when this-tag (insert-count this-tag this-cnt 'magit-branch-local))
- (when both-tags (insert ", "))
- (when next-tag (insert-count next-tag next-cnt 'magit-tag)))
- (insert ?\n)))))
-
-;;;; Auxiliary Headers
-
-(defun magit-insert-user-header ()
- "Insert a header line about the current user."
- (let ((name (magit-get "user.name"))
- (email (magit-get "user.email")))
- (when (and name email)
- (magit-insert-section (user name)
- (insert (format "%-10s" "User: "))
- (insert (propertize name 'font-lock-face 'magit-log-author))
- (insert " <" email ">\n")))))
-
-(defun magit-insert-repo-header ()
- "Insert a header line showing the path to the repository top-level."
- (let ((topdir (magit-toplevel)))
- (magit-insert-section (repo topdir)
- (insert (format "%-10s%s\n" "Repo: " (abbreviate-file-name topdir))))))
-
-(defun magit-insert-remote-header ()
- "Insert a header line about the remote of the current branch.
-
-If no remote is configured for the current branch, then fall back
-showing the \"origin\" remote, or if that does not exist the first
-remote in alphabetic order."
- (when-let ((name (magit-get-some-remote))
- ;; Under certain configurations it's possible for url
- ;; to be nil, when name is not, see #2858.
- (url (magit-get "remote" name "url")))
- (magit-insert-section (remote name)
- (insert (format "%-10s" "Remote: "))
- (insert (propertize name 'font-lock-face 'magit-branch-remote) ?\s)
- (insert url ?\n))))
-
-;;;; File Sections
-
-(defvar magit-untracked-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-delete-thing] 'magit-discard)
- (define-key map "s" 'magit-stage)
- map)
- "Keymap for the `untracked' section.")
-
-(magit-define-section-jumper magit-jump-to-untracked "Untracked files" untracked)
-
-(defun magit-insert-untracked-files ()
- "Maybe insert a list or tree of untracked files.
-
-Do so depending on the value of `status.showUntrackedFiles'.
-Note that even if the value is `all', Magit still initially
-only shows directories. But the directory sections can then
-be expanded using \"TAB\".
-
-If the first element of `magit-buffer-diff-files' is a
-directory, then limit the list to files below that. The value
-value of that variable can be set using \"D -- DIRECTORY RET g\"."
- (let* ((show (or (magit-get "status.showUntrackedFiles") "normal"))
- (base (car magit-buffer-diff-files))
- (base (and base (file-directory-p base) base)))
- (unless (equal show "no")
- (if (equal show "all")
- (when-let ((files (magit-untracked-files nil base)))
- (magit-insert-section (untracked)
- (magit-insert-heading "Untracked files:")
- (magit-insert-files files base)
- (insert ?\n)))
- (when-let ((files
- (--mapcat (and (eq (aref it 0) ??)
- (list (substring it 3)))
- (magit-git-items "status" "-z" "--porcelain"
- (magit-ignore-submodules-p t)
- "--" base))))
- (magit-insert-section (untracked)
- (magit-insert-heading "Untracked files:")
- (dolist (file files)
- (magit-insert-section (file file)
- (insert (propertize file 'font-lock-face 'magit-filename) ?\n)))
- (insert ?\n)))))))
-
-(magit-define-section-jumper magit-jump-to-tracked "Tracked files" tracked)
-
-(defun magit-insert-tracked-files ()
- "Insert a tree of tracked files.
-
-If the first element of `magit-buffer-diff-files' is a
-directory, then limit the list to files below that. The value
-value of that variable can be set using \"D -- DIRECTORY RET g\"."
- (when-let ((files (magit-list-files)))
- (let* ((base (car magit-buffer-diff-files))
- (base (and base (file-directory-p base) base)))
- (magit-insert-section (tracked nil t)
- (magit-insert-heading "Tracked files:")
- (magit-insert-files files base)
- (insert ?\n)))))
-
-(defun magit-insert-ignored-files ()
- "Insert a tree of ignored files.
-
-If the first element of `magit-buffer-diff-files' is a
-directory, then limit the list to files below that. The value
-of that variable can be set using \"D -- DIRECTORY RET g\"."
- (when-let ((files (magit-ignored-files)))
- (let* ((base (car magit-buffer-diff-files))
- (base (and base (file-directory-p base) base)))
- (magit-insert-section (tracked nil t)
- (magit-insert-heading "Ignored files:")
- (magit-insert-files files base)
- (insert ?\n)))))
-
-(magit-define-section-jumper magit-jump-to-skip-worktree "Skip-worktree files" skip-worktree)
-
-(defun magit-insert-skip-worktree-files ()
- "Insert a tree of skip-worktree files.
-
-If the first element of `magit-buffer-diff-files' is a
-directory, then limit the list to files below that. The value
-of that variable can be set using \"D -- DIRECTORY RET g\"."
- (when-let ((files (magit-skip-worktree-files)))
- (let* ((base (car magit-buffer-diff-files))
- (base (and base (file-directory-p base) base)))
- (magit-insert-section (skip-worktree nil t)
- (magit-insert-heading "Skip-worktree files:")
- (magit-insert-files files base)
- (insert ?\n)))))
-
-(magit-define-section-jumper magit-jump-to-assume-unchanged "Assume-unchanged files" assume-unchanged)
-
-(defun magit-insert-assume-unchanged-files ()
- "Insert a tree of files that are assumed to be unchanged.
-
-If the first element of `magit-buffer-diff-files' is a
-directory, then limit the list to files below that. The value
-of that variable can be set using \"D -- DIRECTORY RET g\"."
- (when-let ((files (magit-assume-unchanged-files)))
- (let* ((base (car magit-buffer-diff-files))
- (base (and base (file-directory-p base) base)))
- (magit-insert-section (assume-unchanged nil t)
- (magit-insert-heading "Assume-unchanged files:")
- (magit-insert-files files base)
- (insert ?\n)))))
-
-(defun magit-insert-files (files directory)
- (while (and files (string-prefix-p (or directory "") (car files)))
- (let ((dir (file-name-directory (car files))))
- (if (equal dir directory)
- (let ((file (pop files)))
- (magit-insert-section (file file)
- (insert (propertize file 'font-lock-face 'magit-filename) ?\n)))
- (magit-insert-section (file dir t)
- (insert (propertize dir 'file 'magit-filename) ?\n)
- (magit-insert-heading)
- (setq files (magit-insert-files files dir))))))
- files)
-
-;;; _
-(provide 'magit-status)
-;;; magit-status.el ends here
+++ /dev/null
-;;; magit-submodule.el --- submodule support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2011-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit)
-
-(defvar x-stretch-cursor)
-;;; Options
-
-(defcustom magit-module-sections-hook
- '(magit-insert-modules-overview
- magit-insert-modules-unpulled-from-upstream
- magit-insert-modules-unpulled-from-pushremote
- magit-insert-modules-unpushed-to-upstream
- magit-insert-modules-unpushed-to-pushremote)
- "Hook run by `magit-insert-modules'.
-
-That function isn't part of `magit-status-sections-hook's default
-value, so you have to add it yourself for this hook to have any
-effect."
- :package-version '(magit . "2.11.0")
- :group 'magit-status
- :type 'hook)
-
-(defcustom magit-module-sections-nested t
- "Whether `magit-insert-modules' wraps inserted sections.
-
-If this is non-nil, then only a single top-level section
-is inserted. If it is nil, then all sections listed in
-`magit-module-sections-hook' become top-level sections."
- :package-version '(magit . "2.11.0")
- :group 'magit-status
- :type 'boolean)
-
-(defcustom magit-submodule-list-mode-hook '(hl-line-mode)
- "Hook run after entering Magit-Submodule-List mode."
- :package-version '(magit . "2.9.0")
- :group 'magit-repolist
- :type 'hook
- :get 'magit-hook-custom-get
- :options '(hl-line-mode))
-
-(defcustom magit-submodule-list-columns
- '(("Path" 25 magit-modulelist-column-path nil)
- ("Version" 25 magit-repolist-column-version nil)
- ("Branch" 20 magit-repolist-column-branch nil)
- ("B<U" 3 magit-repolist-column-unpulled-from-upstream ((:right-align t)))
- ("B>U" 3 magit-repolist-column-unpushed-to-upstream ((:right-align t)))
- ("B<P" 3 magit-repolist-column-unpulled-from-pushremote ((:right-align t)))
- ("B>P" 3 magit-repolist-column-unpushed-to-pushremote ((:right-align t)))
- ("B" 3 magit-repolist-column-branches ((:right-align t)))
- ("S" 3 magit-repolist-column-stashes ((:right-align t))))
- "List of columns displayed by `magit-list-submodules'.
-
-Each element has the form (HEADER WIDTH FORMAT PROPS).
-
-HEADER is the string displayed in the header. WIDTH is the width
-of the column. FORMAT is a function that is called with one
-argument, the repository identification (usually its basename),
-and with `default-directory' bound to the toplevel of its working
-tree. It has to return a string to be inserted or nil. PROPS is
-an alist that supports the keys `:right-align' and `:pad-right'."
- :package-version '(magit . "2.8.0")
- :group 'magit-repolist-mode
- :type `(repeat (list :tag "Column"
- (string :tag "Header Label")
- (integer :tag "Column Width")
- (function :tag "Inserter Function")
- (repeat :tag "Properties"
- (list (choice :tag "Property"
- (const :right-align)
- (const :pad-right)
- (symbol))
- (sexp :tag "Value"))))))
-
-(defcustom magit-submodule-remove-trash-gitdirs nil
- "Whether `magit-submodule-remove' offers to trash module gitdirs.
-
-If this is nil, then that command does not offer to do so unless
-a prefix argument is used. When this is t, then it does offer to
-do so even without a prefix argument.
-
-In both cases the action still has to be confirmed unless that is
-disabled using the option `magit-no-confirm'. Doing the latter
-and also setting this variable to t will lead to tears."
- :package-version '(magit . "2.90.0")
- :group 'magit-commands
- :type 'boolean)
-
-;;; Popup
-
-;;;###autoload (autoload 'magit-submodule "magit-submodule" nil t)
-(transient-define-prefix magit-submodule ()
- "Act on a submodule."
- :man-page "git-submodule"
- ["Arguments"
- ("-f" "Force" ("-f" "--force"))
- ("-r" "Recursive" "--recursive")
- ("-N" "Do not fetch" ("-N" "--no-fetch"))
- ("-C" "Checkout tip" "--checkout")
- ("-R" "Rebase onto tip" "--rebase")
- ("-M" "Merge tip" "--merge")
- ("-U" "Use upstream tip" "--remote")]
- ["One module actions"
- ("a" magit-submodule-add)
- ("r" magit-submodule-register)
- ("p" magit-submodule-populate)
- ("u" magit-submodule-update)
- ("s" magit-submodule-synchronize)
- ("d" magit-submodule-unpopulate)
- ("k" "Remove" magit-submodule-remove)]
- ["All modules actions"
- ("l" "List all modules" magit-list-submodules)
- ("f" "Fetch all modules" magit-fetch-modules)])
-
-(defun magit-submodule-arguments (&rest filters)
- (--filter (and (member it filters) it)
- (transient-args 'magit-submodule)))
-
-(defclass magit--git-submodule-suffix (transient-suffix)
- ())
-
-(cl-defmethod transient-format-description ((obj magit--git-submodule-suffix))
- (let ((value (delq nil (mapcar 'transient-infix-value transient--suffixes))))
- (replace-regexp-in-string
- "\\[--[^]]+\\]"
- (lambda (match)
- (format (propertize "[%s]" 'face 'transient-inactive-argument)
- (mapconcat (lambda (arg)
- (propertize arg 'face
- (if (member arg value)
- 'transient-argument
- 'transient-inactive-argument)))
- (save-match-data
- (split-string (substring match 1 -1) "|"))
- (propertize "|" 'face 'transient-inactive-argument))))
- (cl-call-next-method obj))))
-
-;;;###autoload (autoload 'magit-submodule-add "magit-submodule" nil t)
-(transient-define-suffix magit-submodule-add (url &optional path name args)
- "Add the repository at URL as a module.
-
-Optional PATH is the path to the module relative to the root of
-the superproject. If it is nil, then the path is determined
-based on the URL. Optional NAME is the name of the module. If
-it is nil, then PATH also becomes the name."
- :class 'magit--git-submodule-suffix
- :description "Add git submodule add [--force]"
- (interactive
- (magit-with-toplevel
- (let* ((url (magit-read-string-ns "Add submodule (remote url)"))
- (path (let ((read-file-name-function
- (if (or (eq read-file-name-function 'ido-read-file-name)
- (advice-function-member-p
- 'ido-read-file-name
- read-file-name-function))
- ;; The Ido variant doesn't work properly here.
- #'read-file-name-default
- read-file-name-function)))
- (directory-file-name
- (file-relative-name
- (read-directory-name
- "Add submodules at path: " nil nil nil
- (and (string-match "\\([^./]+\\)\\(\\.git\\)?$" url)
- (match-string 1 url))))))))
- (list url
- (directory-file-name path)
- (magit-submodule-read-name-for-path path)
- (magit-submodule-arguments "--force")))))
- (magit-submodule-add-1 url path name args))
-
-(defun magit-submodule-add-1 (url &optional path name args)
- (magit-with-toplevel
- (magit-submodule--maybe-reuse-gitdir name path)
- (magit-run-git-async "submodule" "add"
- (and name (list "--name" name))
- args "--" url path)
- (set-process-sentinel
- magit-this-process
- (lambda (process event)
- (when (memq (process-status process) '(exit signal))
- (if (> (process-exit-status process) 0)
- (magit-process-sentinel process event)
- (process-put process 'inhibit-refresh t)
- (magit-process-sentinel process event)
- (unless (version< (magit-git-version) "2.12.0")
- (magit-call-git "submodule" "absorbgitdirs" path))
- (magit-refresh)))))))
-
-;;;###autoload
-(defun magit-submodule-read-name-for-path (path &optional prefer-short)
- (let* ((path (directory-file-name (file-relative-name path)))
- (name (file-name-nondirectory path)))
- (push (if prefer-short path name) minibuffer-history)
- (magit-read-string-ns
- "Submodule name" nil (cons 'minibuffer-history 2)
- (or (--keep (pcase-let ((`(,var ,val) (split-string it "=")))
- (and (equal val path)
- (cadr (split-string var "\\."))))
- (magit-git-lines "config" "--list" "-f" ".gitmodules"))
- (if prefer-short name path)))))
-
-;;;###autoload (autoload 'magit-submodule-register "magit-submodule" nil t)
-(transient-define-suffix magit-submodule-register (modules)
- "Register MODULES.
-
-With a prefix argument act on all suitable modules. Otherwise,
-if the region selects modules, then act on those. Otherwise, if
-there is a module at point, then act on that. Otherwise read a
-single module from the user."
- ;; This command and the underlying "git submodule init" do NOT
- ;; "initialize" modules. They merely "register" modules in the
- ;; super-projects $GIT_DIR/config file, the purpose of which is to
- ;; allow users to change such values before actually initializing
- ;; the modules.
- :description "Register git submodule init"
- (interactive
- (list (magit-module-confirm "Register" 'magit-module-no-worktree-p)))
- (magit-with-toplevel
- (magit-run-git-async "submodule" "init" "--" modules)))
-
-;;;###autoload (autoload 'magit-submodule-populate "magit-submodule" nil t)
-(transient-define-suffix magit-submodule-populate (modules)
- "Create MODULES working directories, checking out the recorded commits.
-
-With a prefix argument act on all suitable modules. Otherwise,
-if the region selects modules, then act on those. Otherwise, if
-there is a module at point, then act on that. Otherwise read a
-single module from the user."
- ;; This is the command that actually "initializes" modules.
- ;; A module is initialized when it has a working directory,
- ;; a gitlink, and a .gitmodules entry.
- :description "Populate git submodule update --init"
- (interactive
- (list (magit-module-confirm "Populate" 'magit-module-no-worktree-p)))
- (magit-with-toplevel
- (magit-run-git-async "submodule" "update" "--init" "--" modules)))
-
-;;;###autoload (autoload 'magit-submodule-update "magit-submodule" nil t)
-(transient-define-suffix magit-submodule-update (modules args)
- "Update MODULES by checking out the recorded commits.
-
-With a prefix argument act on all suitable modules. Otherwise,
-if the region selects modules, then act on those. Otherwise, if
-there is a module at point, then act on that. Otherwise read a
-single module from the user."
- ;; Unlike `git-submodule's `update' command ours can only update
- ;; "initialized" modules by checking out other commits but not
- ;; "initialize" modules by creating the working directories.
- ;; To do the latter we provide the "setup" command.
- :class 'magit--git-submodule-suffix
- :description "Update git submodule update [--force] [--no-fetch]
- [--remote] [--recursive] [--checkout|--rebase|--merge]"
- (interactive
- (list (magit-module-confirm "Update" 'magit-module-worktree-p)
- (magit-submodule-arguments
- "--force" "--remote" "--recursive" "--checkout" "--rebase" "--merge"
- "--no-fetch")))
- (magit-with-toplevel
- (magit-run-git-async "submodule" "update" args "--" modules)))
-
-;;;###autoload (autoload 'magit-submodule-synchronize "magit-submodule" nil t)
-(transient-define-suffix magit-submodule-synchronize (modules args)
- "Synchronize url configuration of MODULES.
-
-With a prefix argument act on all suitable modules. Otherwise,
-if the region selects modules, then act on those. Otherwise, if
-there is a module at point, then act on that. Otherwise read a
-single module from the user."
- :class 'magit--git-submodule-suffix
- :description "Synchronize git submodule sync [--recursive]"
- (interactive
- (list (magit-module-confirm "Synchronize" 'magit-module-worktree-p)
- (magit-submodule-arguments "--recursive")))
- (magit-with-toplevel
- (magit-run-git-async "submodule" "sync" args "--" modules)))
-
-;;;###autoload (autoload 'magit-submodule-unpopulate "magit-submodule" nil t)
-(transient-define-suffix magit-submodule-unpopulate (modules args)
- "Remove working directories of MODULES.
-
-With a prefix argument act on all suitable modules. Otherwise,
-if the region selects modules, then act on those. Otherwise, if
-there is a module at point, then act on that. Otherwise read a
-single module from the user."
- ;; Even though a package is "uninitialized" (it has no worktree)
- ;; the super-projects $GIT_DIR/config may never-the-less set the
- ;; module's url. This may happen if you `deinit' and then `init'
- ;; to register (NOT initialize). Because the purpose of `deinit'
- ;; is to remove the working directory AND to remove the url, this
- ;; command does not limit itself to modules that have no working
- ;; directory.
- :class 'magit--git-submodule-suffix
- :description "Unpopulate git submodule deinit [--force]"
- (interactive
- (list (magit-module-confirm "Unpopulate")
- (magit-submodule-arguments "--force")))
- (magit-with-toplevel
- (magit-run-git-async "submodule" "deinit" args "--" modules)))
-
-;;;###autoload
-(defun magit-submodule-remove (modules args trash-gitdirs)
- "Unregister MODULES and remove their working directories.
-
-For safety reasons, do not remove the gitdirs and if a module has
-uncommitted changes, then do not remove it at all. If a module's
-gitdir is located inside the working directory, then move it into
-the gitdir of the superproject first.
-
-With the \"--force\" argument offer to remove dirty working
-directories and with a prefix argument offer to delete gitdirs.
-Both actions are very dangerous and have to be confirmed. There
-are additional safety precautions in place, so you might be able
-to recover from making a mistake here, but don't count on it."
- (interactive
- (list (if-let ((modules (magit-region-values 'magit-module-section t)))
- (magit-confirm 'remove-modules nil "Remove %i modules" nil modules)
- (list (magit-read-module-path "Remove module")))
- (magit-submodule-arguments "--force")
- current-prefix-arg))
- (when (version< (magit-git-version) "2.12.0")
- (error "This command requires Git v2.12.0"))
- (when magit-submodule-remove-trash-gitdirs
- (setq trash-gitdirs t))
- (magit-with-toplevel
- (when-let
- ((modified
- (-filter (lambda (module)
- (let ((default-directory (file-name-as-directory
- (expand-file-name module))))
- (and (cddr (directory-files default-directory))
- (magit-anything-modified-p))))
- modules)))
- (if (member "--force" args)
- (if (magit-confirm 'remove-dirty-modules
- "Remove dirty module %s"
- "Remove %i dirty modules"
- t modified)
- (dolist (module modified)
- (let ((default-directory (file-name-as-directory
- (expand-file-name module))))
- (magit-git "stash" "push"
- "-m" "backup before removal of this module")))
- (setq modules (cl-set-difference modules modified)))
- (if (cdr modified)
- (message "Omitting %s modules with uncommitted changes: %s"
- (length modified)
- (mapconcat #'identity modified ", "))
- (message "Omitting module %s, it has uncommitted changes"
- (car modified)))
- (setq modules (cl-set-difference modules modified))))
- (when modules
- (let ((alist
- (and trash-gitdirs
- (--map (split-string it "\0")
- (magit-git-lines "submodule" "foreach" "-q"
- "printf \"$sm_path\\0$name\n\"")))))
- (magit-git "submodule" "absorbgitdirs" "--" modules)
- (magit-git "submodule" "deinit" args "--" modules)
- (magit-git "rm" args "--" modules)
- (when (and trash-gitdirs
- (magit-confirm 'trash-module-gitdirs
- "Trash gitdir of module %s"
- "Trash gitdirs of %i modules"
- t modules))
- (dolist (module modules)
- (if-let ((name (cadr (assoc module alist))))
- ;; Disregard if `magit-delete-by-moving-to-trash'
- ;; is nil. Not doing so would be too dangerous.
- (delete-directory (magit-git-dir
- (convert-standard-filename
- (concat "modules/" name)))
- t t)
- (error "BUG: Weird module name and/or path for %s" module)))))
- (magit-refresh))))
-
-;;; Sections
-
-;;;###autoload
-(defun magit-insert-modules ()
- "Insert submodule sections.
-Hook `magit-module-sections-hook' controls which module sections
-are inserted, and option `magit-module-sections-nested' controls
-whether they are wrapped in an additional section."
- (when-let ((modules (magit-list-module-paths)))
- (if magit-module-sections-nested
- (magit-insert-section (modules nil t)
- (magit-insert-heading
- (format "%s (%s)"
- (propertize "Modules"
- 'font-lock-face 'magit-section-heading)
- (length modules)))
- (magit-insert-section-body
- (magit--insert-modules)))
- (magit--insert-modules))))
-
-(defun magit--insert-modules (&optional _section)
- (magit-run-section-hook 'magit-module-sections-hook))
-
-;;;###autoload
-(defun magit-insert-modules-overview ()
- "Insert sections for all modules.
-For each section insert the path and the output of `git describe --tags',
-or, failing that, the abbreviated HEAD commit hash."
- (when-let ((modules (magit-list-module-paths)))
- (magit-insert-section (modules nil t)
- (magit-insert-heading
- (format "%s (%s)"
- (propertize "Modules overview"
- 'font-lock-face 'magit-section-heading)
- (length modules)))
- (magit-insert-section-body
- (magit--insert-modules-overview)))))
-
-(defvar magit-modules-overview-align-numbers t)
-
-(defun magit--insert-modules-overview (&optional _section)
- (magit-with-toplevel
- (let* ((modules (magit-list-module-paths))
- (path-format (format "%%-%is "
- (min (apply 'max (mapcar 'length modules))
- (/ (window-width) 2))))
- (branch-format (format "%%-%is " (min 25 (/ (window-width) 3)))))
- (dolist (module modules)
- (let ((default-directory
- (expand-file-name (file-name-as-directory module))))
- (magit-insert-section (magit-module-section module t)
- (insert (propertize (format path-format module)
- 'font-lock-face 'magit-diff-file-heading))
- (if (not (file-exists-p ".git"))
- (insert "(unpopulated)")
- (insert (format
- branch-format
- (--if-let (magit-get-current-branch)
- (propertize it 'font-lock-face 'magit-branch-local)
- (propertize "(detached)" 'font-lock-face 'warning))))
- (--if-let (magit-git-string "describe" "--tags")
- (progn (when (and magit-modules-overview-align-numbers
- (string-match-p "\\`[0-9]" it))
- (insert ?\s))
- (insert (propertize it 'font-lock-face 'magit-tag)))
- (--when-let (magit-rev-format "%h")
- (insert (propertize it 'font-lock-face 'magit-hash)))))
- (insert ?\n))))))
- (insert ?\n))
-
-(defvar magit-modules-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-list-submodules)
- map)
- "Keymap for `modules' sections.")
-
-(defvar magit-module-section-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-file-section-map)
- (define-key map (kbd "C-j") 'magit-submodule-visit)
- (define-key map [C-return] 'magit-submodule-visit)
- (define-key map [remap magit-visit-thing] 'magit-submodule-visit)
- (define-key map [remap magit-delete-thing] 'magit-submodule-unpopulate)
- (define-key map "K" 'magit-file-untrack)
- (define-key map "R" 'magit-file-rename)
- map)
- "Keymap for `module' sections.")
-
-(defun magit-submodule-visit (module &optional other-window)
- "Visit MODULE by calling `magit-status' on it.
-Offer to initialize MODULE if it's not checked out yet.
-With a prefix argument, visit in another window."
- (interactive (list (or (magit-section-value-if 'module)
- (magit-read-module-path "Visit module"))
- current-prefix-arg))
- (magit-with-toplevel
- (let ((path (expand-file-name module)))
- (cond
- ((file-exists-p (expand-file-name ".git" module))
- (magit-diff-visit-directory path other-window))
- ((y-or-n-p (format "Initialize submodule '%s' first?" module))
- (magit-run-git-async "submodule" "update" "--init" "--" module)
- (set-process-sentinel
- magit-this-process
- (lambda (process event)
- (let ((magit-process-raise-error t))
- (magit-process-sentinel process event))
- (when (and (eq (process-status process) 'exit)
- (= (process-exit-status process) 0))
- (magit-diff-visit-directory path other-window)))))
- ((file-exists-p path)
- (dired-jump other-window (concat path "/.")))))))
-
-;;;###autoload
-(defun magit-insert-modules-unpulled-from-upstream ()
- "Insert sections for modules that haven't been pulled from the upstream.
-These sections can be expanded to show the respective commits."
- (magit--insert-modules-logs "Modules unpulled from @{upstream}"
- 'modules-unpulled-from-upstream
- "HEAD..@{upstream}"))
-
-;;;###autoload
-(defun magit-insert-modules-unpulled-from-pushremote ()
- "Insert sections for modules that haven't been pulled from the push-remote.
-These sections can be expanded to show the respective commits."
- (magit--insert-modules-logs "Modules unpulled from @{push}"
- 'modules-unpulled-from-pushremote
- "HEAD..@{push}"))
-
-;;;###autoload
-(defun magit-insert-modules-unpushed-to-upstream ()
- "Insert sections for modules that haven't been pushed to the upstream.
-These sections can be expanded to show the respective commits."
- (magit--insert-modules-logs "Modules unmerged into @{upstream}"
- 'modules-unpushed-to-upstream
- "@{upstream}..HEAD"))
-
-;;;###autoload
-(defun magit-insert-modules-unpushed-to-pushremote ()
- "Insert sections for modules that haven't been pushed to the push-remote.
-These sections can be expanded to show the respective commits."
- (magit--insert-modules-logs "Modules unpushed to @{push}"
- 'modules-unpushed-to-pushremote
- "@{push}..HEAD"))
-
-(defun magit--insert-modules-logs (heading type range)
- "For internal use, don't add to a hook."
- (unless (magit-ignore-submodules-p)
- (when-let ((modules (magit-list-module-paths)))
- (magit-insert-section section ((eval type) nil t)
- (string-match "\\`\\(.+\\) \\([^ ]+\\)\\'" heading)
- (magit-insert-heading
- (propertize (match-string 1 heading)
- 'font-lock-face 'magit-section-heading)
- " "
- (propertize (match-string 2 heading)
- 'font-lock-face 'magit-branch-remote)
- ":")
- (magit-with-toplevel
- (dolist (module modules)
- (when (magit-module-worktree-p module)
- (let ((default-directory
- (expand-file-name (file-name-as-directory module))))
- (when (magit-file-accessible-directory-p default-directory)
- (magit-insert-section sec (magit-module-section module t)
- (magit-insert-heading
- (propertize module
- 'font-lock-face 'magit-diff-file-heading)
- ":")
- (magit-git-wash
- (apply-partially 'magit-log-wash-log 'module)
- "-c" "push.default=current" "log" "--oneline" range)
- (when (> (point)
- (oref sec content))
- (delete-char -1))))))))
- (if (> (point)
- (oref section content))
- (insert ?\n)
- (magit-cancel-section))))))
-
-;;; List
-
-;;;###autoload
-(defun magit-list-submodules ()
- "Display a list of the current repository's submodules."
- (interactive)
- (magit-display-buffer
- (or (magit-get-mode-buffer 'magit-submodule-list-mode)
- (magit-with-toplevel
- (magit-generate-new-buffer 'magit-submodule-list-mode))))
- (magit-submodule-list-mode)
- (magit-submodule-list-refresh)
- (tabulated-list-print))
-
-(defvar magit-submodule-list-mode-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map magit-repolist-mode-map)
- map)
- "Local keymap for Magit-Submodule-List mode buffers.")
-
-(define-derived-mode magit-submodule-list-mode tabulated-list-mode "Modules"
- "Major mode for browsing a list of Git submodules."
- :group 'magit-repolist-mode
- (setq-local x-stretch-cursor nil)
- (setq tabulated-list-padding 0)
- (setq tabulated-list-sort-key (cons "Path" nil))
- (setq tabulated-list-format
- (vconcat (mapcar (pcase-lambda (`(,title ,width ,_fn ,props))
- (nconc (list title width t)
- (-flatten props)))
- magit-submodule-list-columns)))
- (tabulated-list-init-header)
- (add-hook 'tabulated-list-revert-hook 'magit-submodule-list-refresh nil t)
- (setq imenu-prev-index-position-function
- #'magit-imenu--submodule-prev-index-position-function)
- (setq imenu-extract-index-name-function
- #'magit-imenu--submodule-extract-index-name-function))
-
-(defun magit-submodule-list-refresh ()
- (setq tabulated-list-entries
- (-keep (lambda (module)
- (let ((default-directory
- (expand-file-name (file-name-as-directory module))))
- (and (file-exists-p ".git")
- (list module
- (vconcat
- (--map (or (funcall (nth 2 it) module) "")
- magit-submodule-list-columns))))))
- (magit-list-module-paths))))
-
-(defun magit-modulelist-column-path (path)
- "Insert the relative path of the submodule."
- path)
-
-;;; Utilities
-
-(defun magit-submodule--maybe-reuse-gitdir (name path)
- (let ((gitdir
- (magit-git-dir (convert-standard-filename (concat "modules/" name)))))
- (when (and (file-exists-p gitdir)
- (not (file-exists-p path)))
- (pcase (read-char-choice
- (concat
- gitdir " already exists.\n"
- "Type [u] to use the existing gitdir and create the working tree\n"
- " [r] to rename the existing gitdir and clone again\n"
- " [t] to trash the existing gitdir and clone again\n"
- " [C-g] to abort ")
- '(?u ?r ?t))
- (?u (magit-submodule--restore-worktree (expand-file-name path) gitdir))
- (?r (rename-file gitdir (concat gitdir "-"
- (format-time-string "%F-%T"))))
- (?t (delete-directory gitdir t t))))))
-
-(defun magit-submodule--restore-worktree (worktree gitdir)
- (make-directory worktree t)
- (with-temp-file (expand-file-name ".git" worktree)
- (insert "gitdir: " (file-relative-name gitdir worktree) "\n"))
- (let ((default-directory worktree))
- (magit-call-git "reset" "--hard" "HEAD" "--")))
-
-;;; _
-(provide 'magit-submodule)
-;;; magit-submodule.el ends here
+++ /dev/null
-;;; magit-subtree.el --- subtree support for Magit -*- lexical-binding: t -*-
-
-;; Copyright (C) 2011-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-subtree "magit-subtree" nil t)
-(transient-define-prefix magit-subtree ()
- "Import or export subtrees."
- :man-page "git-subtree"
- ["Actions"
- ("i" "Import" magit-subtree-import)
- ("e" "Export" magit-subtree-export)])
-
-;;;###autoload (autoload 'magit-subtree-import "magit-subtree" nil t)
-(transient-define-prefix magit-subtree-import ()
- "Import subtrees."
- :man-page "git-subtree"
- ["Arguments"
- (magit-subtree:--prefix)
- (magit-subtree:--message)
- ("-s" "Squash" "--squash")]
- ["Actions"
- [("a" "Add" magit-subtree-add)
- ("c" "Add commit" magit-subtree-add-commit)]
- [("m" "Merge" magit-subtree-merge)
- ("f" "Pull" magit-subtree-pull)]])
-
-;;;###autoload (autoload 'magit-subtree-export "magit-subtree" nil t)
-(transient-define-prefix magit-subtree-export ()
- "Export subtrees."
- :man-page "git-subtree"
- ["Arguments"
- (magit-subtree:--prefix)
- (magit-subtree:--annotate)
- (magit-subtree:--branch)
- (magit-subtree:--onto)
- ("-i" "Ignore joins" "--ignore-joins")
- ("-j" "Rejoin" "--rejoin")]
- ["Actions"
- ("p" "Push" magit-subtree-push)
- ("s" "Split" magit-subtree-split)])
-
-(transient-define-argument magit-subtree:--prefix ()
- :description "Prefix"
- :class 'transient-option
- :shortarg "-P"
- :argument "--prefix="
- :reader 'magit-subtree-read-prefix)
-
-(defun magit-subtree-read-prefix (prompt &optional default _history)
- (let* ((insert-default-directory nil)
- (topdir (magit-toplevel))
- (prefix (read-directory-name (concat prompt ": ") topdir default)))
- (if (file-name-absolute-p prefix)
- ;; At least `ido-mode's variant is not compatible.
- (if (string-prefix-p topdir prefix)
- (file-relative-name prefix topdir)
- (user-error "%s isn't inside the repository at %s" prefix topdir))
- prefix)))
-
-(transient-define-argument magit-subtree:--message ()
- :description "Message"
- :class 'transient-option
- :shortarg "-m"
- :argument "--message=")
-
-(transient-define-argument magit-subtree:--annotate ()
- :description "Annotate"
- :class 'transient-option
- :key "-a"
- :argument "--annotate=")
-
-(transient-define-argument magit-subtree:--branch ()
- :description "Branch"
- :class 'transient-option
- :shortarg "-b"
- :argument "--branch=")
-
-(transient-define-argument magit-subtree:--onto ()
- :description "Onto"
- :class 'transient-option
- :key "-o"
- :argument "--onto="
- :reader 'magit-transient-read-revision)
-
-(defun magit-subtree-prefix (transient prompt)
- (--if-let (--first (string-prefix-p "--prefix=" it)
- (transient-args transient))
- (substring it 9)
- (magit-subtree-read-prefix prompt)))
-
-(defun magit-subtree-arguments (transient)
- (--remove (string-prefix-p "--prefix=" it)
- (transient-args transient)))
-
-(defun magit-git-subtree (subcmd prefix &rest args)
- (magit-run-git-async "subtree" subcmd (concat "--prefix=" prefix) args))
-
-;;;###autoload
-(defun magit-subtree-add (prefix repository ref args)
- "Add REF from REPOSITORY as a new subtree at PREFIX."
- (interactive
- (cons (magit-subtree-prefix 'magit-subtree-import "Add subtree")
- (let ((remote (magit-read-remote-or-url "From repository")))
- (list remote
- (magit-read-refspec "Ref" remote)
- (magit-subtree-arguments 'magit-subtree-import)))))
- (magit-git-subtree "add" prefix args repository ref))
-
-;;;###autoload
-(defun magit-subtree-add-commit (prefix commit args)
- "Add COMMIT as a new subtree at PREFIX."
- (interactive
- (list (magit-subtree-prefix 'magit-subtree-import "Add subtree")
- (magit-read-string-ns "Commit")
- (magit-subtree-arguments 'magit-subtree-import)))
- (magit-git-subtree "add" prefix args commit))
-
-;;;###autoload
-(defun magit-subtree-merge (prefix commit args)
- "Merge COMMIT into the PREFIX subtree."
- (interactive
- (list (magit-subtree-prefix 'magit-subtree-import "Merge into subtree")
- (magit-read-string-ns "Commit")
- (magit-subtree-arguments 'magit-subtree-import)))
- (magit-git-subtree "merge" prefix args commit))
-
-;;;###autoload
-(defun magit-subtree-pull (prefix repository ref args)
- "Pull REF from REPOSITORY into the PREFIX subtree."
- (interactive
- (cons (magit-subtree-prefix 'magit-subtree-import "Pull into subtree")
- (let ((remote (magit-read-remote-or-url "From repository")))
- (list remote
- (magit-read-refspec "Ref" remote)
- (magit-subtree-arguments 'magit-subtree-import)))))
- (magit-git-subtree "pull" prefix args repository ref))
-
-;;;###autoload
-(defun magit-subtree-push (prefix repository ref args)
- "Extract the history of the subtree PREFIX and push it to REF on REPOSITORY."
- (interactive (list (magit-subtree-prefix 'magit-subtree-export "Push subtree")
- (magit-read-remote-or-url "To repository")
- (magit-read-string-ns "To reference")
- (magit-subtree-arguments 'magit-subtree-export)))
- (magit-git-subtree "push" prefix args repository ref))
-
-;;;###autoload
-(defun magit-subtree-split (prefix commit args)
- "Extract the history of the subtree PREFIX."
- (interactive (list (magit-subtree-prefix 'magit-subtree-export "Split subtree")
- (magit-read-string-ns "Commit")
- (magit-subtree-arguments 'magit-subtree-export)))
- (magit-git-subtree "split" prefix args commit))
-
-;;; _
-(provide 'magit-subtree)
-;;; magit-subtree.el ends here
+++ /dev/null
-;;; magit-tag.el --- tag functionality -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements tag commands.
-
-;;; Code:
-
-(require 'magit)
-
-;; For `magit-tag-delete'.
-(defvar helm-comp-read-use-marked)
-
-;;;###autoload (autoload 'magit-tag "magit" nil t)
-(transient-define-prefix magit-tag ()
- "Create or delete a tag."
- :man-page "git-tag"
- ["Arguments"
- ("-f" "Force" ("-f" "--force"))
- ("-a" "Annotate" ("-a" "--annotate"))
- ("-s" "Sign" ("-s" "--sign"))
- (magit-tag:--local-user)]
- [["Create"
- ("t" "tag" magit-tag-create)
- ("r" "release" magit-tag-release)]
- ["Do"
- ("k" "delete" magit-tag-delete)
- ("p" "prune" magit-tag-prune)]])
-
-(defun magit-tag-arguments ()
- (transient-args 'magit-tag))
-
-(transient-define-argument magit-tag:--local-user ()
- :description "Sign as"
- :class 'transient-option
- :shortarg "-u"
- :argument "--local-user="
- :reader 'magit-read-gpg-secret-key
- :history-key 'magit:--gpg-sign)
-
-;;;###autoload
-(defun magit-tag-create (name rev &optional args)
- "Create a new tag with the given NAME at REV.
-With a prefix argument annotate the tag.
-\n(git tag [--annotate] NAME REV)"
- (interactive (list (magit-read-tag "Tag name")
- (magit-read-branch-or-commit "Place tag on")
- (let ((args (magit-tag-arguments)))
- (when current-prefix-arg
- (cl-pushnew "--annotate" args))
- args)))
- (magit-run-git-with-editor "tag" args name rev))
-
-;;;###autoload
-(defun magit-tag-delete (tags)
- "Delete one or more tags.
-If the region marks multiple tags (and nothing else), then offer
-to delete those, otherwise prompt for a single tag to be deleted,
-defaulting to the tag at point.
-\n(git tag -d TAGS)"
- (interactive (list (--if-let (magit-region-values 'tag)
- (magit-confirm t nil "Delete %i tags" nil it)
- (let ((helm-comp-read-use-marked t))
- (magit-read-tag "Delete tag" t)))))
- (magit-run-git "tag" "-d" tags))
-
-;;;###autoload
-(defun magit-tag-prune (tags remote-tags remote)
- "Offer to delete tags missing locally from REMOTE, and vice versa."
- (interactive
- (let* ((remote (magit-read-remote "Prune tags using remote"))
- (tags (magit-list-tags))
- (rtags (prog2 (message "Determining remote tags...")
- (magit-remote-list-tags remote)
- (message "Determining remote tags...done")))
- (ltags (-difference tags rtags))
- (rtags (-difference rtags tags)))
- (unless (or ltags rtags)
- (message "Same tags exist locally and remotely"))
- (unless (magit-confirm t
- "Delete %s locally"
- "Delete %i tags locally"
- 'noabort ltags)
- (setq ltags nil))
- (unless (magit-confirm t
- "Delete %s from remote"
- "Delete %i tags from remote"
- 'noabort rtags)
- (setq rtags nil))
- (list ltags rtags remote)))
- (when tags
- (magit-call-git "tag" "-d" tags))
- (when remote-tags
- (magit-run-git-async "push" remote (--map (concat ":" it) remote-tags))))
-
-(defvar magit-tag-version-regexp-alist
- '(("^[-._+ ]?snapshot\\.?$" . -4)
- ("^[-._+]$" . -4)
- ("^[-._+ ]?\\(cvs\\|git\\|bzr\\|svn\\|hg\\|darcs\\)\\.?$" . -4)
- ("^[-._+ ]?unknown\\.?$" . -4)
- ("^[-._+ ]?alpha\\.?$" . -3)
- ("^[-._+ ]?beta\\.?$" . -2)
- ("^[-._+ ]?\\(pre\\|rc\\)\\.?$" . -1))
- "Overrides `version-regexp-alist' for `magit-tag-release'.
-See also `magit-release-tag-regexp'.")
-
-(defvar magit-release-tag-regexp "\\`\
-\\(?1:\\(?:v\\(?:ersion\\)?\\|r\\(?:elease\\)?\\)?[-_]?\\)?\
-\\(?2:[0-9]+\\(?:\\.[0-9]+\\)*\
-\\(?:-[a-zA-Z0-9-]+\\(?:\\.[a-zA-Z0-9-]+\\)*\\)?\\)\\'"
- "Regexp used by `magit-tag-release' to parse release tags.
-
-The first submatch must match the prefix, if any. The second
-submatch must match the version string.
-
-If this matches versions that are not dot separated numbers,
-then `magit-tag-version-regexp-alist' has to contain entries
-for the separators allowed here.")
-
-;;;###autoload
-(defun magit-tag-release (tag msg &optional args)
- "Create a release tag.
-
-Assume that release tags match `magit-release-tag-regexp'.
-
-First prompt for the name of the new tag using the highest
-existing tag as initial input and leaving it to the user to
-increment the desired part of the version string.
-
-If `--annotate' is enabled, then prompt for the message of the
-new tag. Base the proposed tag message on the message of the
-highest tag, provided that that contains the corresponding
-version string and substituting the new version string for that.
-Otherwise propose something like \"Foo-Bar 1.2.3\", given, for
-example, a TAG \"v1.2.3\" and a repository located at something
-like \"/path/to/foo-bar\"."
- (interactive
- (save-match-data
- (pcase-let*
- ((`(,pver ,ptag ,pmsg) (car (magit--list-releases)))
- (tag (read-string "Create release tag: " ptag))
- (ver (and (string-match magit-release-tag-regexp tag)
- (match-string 2 tag)))
- (args (magit-tag-arguments)))
- (list tag
- (and (member "--annotate" args)
- (read-string
- (format "Message for %S: " tag)
- (cond ((and pver (string-match (regexp-quote pver) pmsg))
- (replace-match ver t t pmsg))
- ((and ptag (string-match (regexp-quote ptag) pmsg))
- (replace-match tag t t pmsg))
- (t (format "%s %s"
- (capitalize
- (file-name-nondirectory
- (directory-file-name (magit-toplevel))))
- ver)))))
- args))))
- (magit-run-git-async "tag" args (and msg (list "-m" msg)) tag)
- (set-process-sentinel
- magit-this-process
- (lambda (process event)
- (when (memq (process-status process) '(exit signal))
- (magit-process-sentinel process event)
- (magit-refs-setup-buffer "HEAD" (magit-show-refs-arguments))))))
-
-(defun magit--list-releases ()
- "Return a list of releases.
-The list is ordered, beginning with the highest release.
-Each release element has the form (VERSION TAG MESSAGE).
-`magit-release-tag-regexp' is used to determine whether
-a tag qualifies as a release tag."
- (save-match-data
- (mapcar
- #'cdr
- (nreverse
- (cl-sort (cl-mapcan
- (lambda (line)
- (and (string-match " +" line)
- (let ((tag (substring line 0 (match-beginning 0)))
- (msg (substring line (match-end 0))))
- (and (string-match magit-release-tag-regexp tag)
- (let ((ver (match-string 2 tag))
- (version-regexp-alist
- magit-tag-version-regexp-alist))
- (list (list (version-to-list ver)
- ver tag msg)))))))
- ;; Cannot rely on "--sort=-version:refname" because
- ;; that gets confused if the version prefix has changed.
- (magit-git-lines "tag" "-n"))
- ;; The inverse of this function does not exist.
- #'version-list-< :key #'car)))))
-
-;;; _
-(provide 'magit-tag)
-;;; magit-tag.el ends here
+++ /dev/null
-;;; magit-transient.el --- support for transients -*- lexical-binding: t -*-
-
-;; Copyright (C) 2008-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements Magit-specific prefix and suffix classes,
-;; and their methods.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'transient)
-
-(require 'magit-git)
-(require 'magit-mode)
-(require 'magit-process)
-
-;;; Classes
-
-(defclass magit--git-variable (transient-variable)
- ((scope :initarg :scope)))
-
-(defclass magit--git-variable:choices (magit--git-variable)
- ((choices :initarg :choices)
- (fallback :initarg :fallback :initform nil)
- (default :initarg :default :initform nil)))
-
-(defclass magit--git-variable:urls (magit--git-variable)
- ((seturl-arg :initarg :seturl-arg :initform nil)))
-
-;;; Methods
-;;;; Init
-
-(cl-defmethod transient-init-scope ((obj magit--git-variable))
- (oset obj scope
- (cond (transient--prefix
- (oref transient--prefix scope))
- ((slot-boundp obj 'scope)
- (funcall (oref obj scope) obj)))))
-
-(cl-defmethod transient-init-value ((obj magit--git-variable))
- (let ((variable (format (oref obj variable)
- (oref obj scope))))
- (oset obj variable variable)
- (oset obj value
- (cond ((oref obj multi-value)
- (magit-get-all variable))
- (t
- (magit-git-string "config" "--local" variable))))))
-
-;;;; Read
-
-(cl-defmethod transient-infix-read :around ((obj magit--git-variable:urls))
- (mapcar (lambda (url)
- (if (string-prefix-p "~" url)
- (expand-file-name url)
- url))
- (cl-call-next-method obj)))
-
-(cl-defmethod transient-infix-read ((obj magit--git-variable:choices))
- (let ((choices (oref obj choices)))
- (when (functionp choices)
- (setq choices (funcall choices)))
- (if-let ((value (oref obj value)))
- (cadr (member value choices))
- (car choices))))
-
-;;;; Readers
-
-(defun magit-transient-read-person (prompt initial-input history)
- (magit-completing-read
- prompt
- (mapcar (lambda (line)
- (save-excursion
- (and (string-match "\\`[\s\t]+[0-9]+\t" line)
- (list (substring line (match-end 0))))))
- (magit-git-lines "shortlog" "-n" "-s" "-e" "HEAD"))
- nil nil initial-input history))
-
-(defun magit-transient-read-revision (prompt initial-input history)
- (or (magit-completing-read prompt (cons "HEAD" (magit-list-refnames))
- nil nil initial-input history
- (or (magit-branch-or-commit-at-point)
- (magit-get-current-branch)))
- (user-error "Nothing selected")))
-
-;;;; Set
-
-(cl-defmethod transient-infix-set ((obj magit--git-variable) value)
- (let ((variable (oref obj variable)))
- (oset obj value value)
- (if (oref obj multi-value)
- (magit-set-all value variable)
- (magit-set value variable))
- (magit-refresh)
- (unless (or value transient--prefix)
- (message "Unset %s" variable))))
-
-(cl-defmethod transient-infix-set ((obj magit--git-variable:urls) values)
- (let ((previous (oref obj value))
- (seturl (oref obj seturl-arg))
- (remote (oref transient--prefix scope)))
- (oset obj value values)
- (dolist (v (-difference values previous))
- (magit-call-git "remote" "set-url" seturl "--add" remote v))
- (dolist (v (-difference previous values))
- (magit-call-git "remote" "set-url" seturl "--delete" remote
- (concat "^" (regexp-quote v) "$")))
- (magit-refresh)))
-
-;;;; Draw
-
-(cl-defmethod transient-format-description ((obj magit--git-variable))
- (or (oref obj description)
- (oref obj variable)))
-
-(cl-defmethod transient-format-value ((obj magit--git-variable))
- (if-let ((value (oref obj value)))
- (if (oref obj multi-value)
- (if (cdr value)
- (mapconcat (lambda (v)
- (concat "\n "
- (propertize v 'face 'transient-value)))
- value "")
- (propertize (car value) 'face 'transient-value))
- (propertize (car (split-string value "\n"))
- 'face 'transient-value))
- (propertize "unset" 'face 'transient-inactive-value)))
-
-(cl-defmethod transient-format-value ((obj magit--git-variable:choices))
- (let* ((variable (oref obj variable))
- (choices (oref obj choices))
- (local (magit-git-string "config" "--local" variable))
- (global (magit-git-string "config" "--global" variable))
- (default (oref obj default))
- (fallback (oref obj fallback))
- (fallback (and fallback
- (when-let ((val (magit-get fallback)))
- (concat fallback ":" val)))))
- (when (functionp choices)
- (setq choices (funcall choices)))
- (concat
- (propertize "[" 'face 'transient-inactive-value)
- (mapconcat (lambda (choice)
- (propertize choice 'face (if (equal choice local)
- (if (member choice choices)
- 'transient-value
- 'font-lock-warning-face)
- 'transient-inactive-value)))
- (if (and local (not (member local choices)))
- (cons local choices)
- choices)
- (propertize "|" 'face 'transient-inactive-value))
- (and (or global fallback default)
- (concat
- (propertize "|" 'face 'transient-inactive-value)
- (cond (global
- (propertize (concat "global:" global)
- 'face (cond (local
- 'transient-inactive-value)
- ((member global choices)
- 'transient-value)
- (t
- 'font-lock-warning-face))))
- (fallback
- (propertize fallback
- 'face (if local
- 'transient-inactive-value
- 'transient-value)))
- (default
- (propertize (concat "default:" default)
- 'face (if local
- 'transient-inactive-value
- 'transient-value))))))
- (propertize "]" 'face 'transient-inactive-value))))
-
-;;; _
-(provide 'magit-transient)
-;;; magit-transient.el ends here
-
+++ /dev/null
-;;; magit-utils.el --- various utilities -*- lexical-binding: t; coding: utf-8 -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Contains code from GNU Emacs https://www.gnu.org/software/emacs,
-;; released under the GNU General Public License version 3 or later.
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library defines several utility functions used by several
-;; other libraries which cannot depend on one another (because
-;; circular dependencies are not good). Luckily most (all) of these
-;; functions have very little (nothing) to do with Git, so we not only
-;; have to do this, it even makes sense.
-
-;; Unfortunately there are also some options which are used by several
-;; libraries which cannot depend on one another, they are defined here
-;; too.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'crm)
-
-(eval-when-compile (require 'ido))
-(declare-function ido-completing-read+ "ido-completing-read+"
- (prompt collection &optional predicate
- require-match initial-input
- hist def inherit-input-method))
-(declare-function Info-get-token "info" (pos start all &optional errorstring))
-
-(eval-when-compile (require 'vc-git))
-(declare-function vc-git--run-command-string "vc-git" (file &rest args))
-
-(eval-when-compile (require 'which-func))
-(declare-function which-function "which-func" ())
-
-(defvar magit-wip-before-change-mode)
-
-;;; Options
-
-(defcustom magit-completing-read-function 'magit-builtin-completing-read
- "Function to be called when requesting input from the user.
-
-If you have enabled `ivy-mode' or `helm-mode', then you don't
-have to customize this option; `magit-builtin-completing-read'
-will work just fine. However, if you use Ido completion, then
-you do have to use `magit-ido-completing-read', because Ido is
-less well behaved than the former, more modern alternatives.
-
-If you would like to use Ivy or Helm completion with Magit but
-not enable the respective modes globally, then customize this
-option to use `ivy-completing-read' or
-`helm--completing-read-default'. If you choose to use
-`ivy-completing-read', note that the items may always be shown in
-alphabetical order, depending on your version of Ivy."
- :group 'magit-essentials
- :type '(radio (function-item magit-builtin-completing-read)
- (function-item magit-ido-completing-read)
- (function-item ivy-completing-read)
- (function-item helm--completing-read-default)
- (function :tag "Other function")))
-
-(defcustom magit-dwim-selection
- '((magit-stash-apply nil t)
- (magit-stash-branch nil t)
- (magit-stash-branch-here nil t)
- (magit-stash-format-patch nil t)
- (magit-stash-drop nil ask)
- (magit-stash-pop nil ask)
- (forge-browse-dwim nil t)
- (forge-browse-commit nil t)
- (forge-browse-branch nil t)
- (forge-browse-remote nil t)
- (forge-browse-issue nil t)
- (forge-browse-pullreq nil t)
- (forge-edit-topic-title nil t)
- (forge-edit-topic-state nil t)
- (forge-edit-topic-milestone nil t)
- (forge-edit-topic-labels nil t)
- (forge-edit-topic-marks nil t)
- (forge-edit-topic-assignees nil t)
- (forge-edit-topic-review-requests nil t)
- (forge-edit-topic-note nil t)
- (forge-pull-pullreq nil t)
- (forge-visit-issue nil t)
- (forge-visit-pullreq nil t))
- "When not to offer alternatives and ask for confirmation.
-
-Many commands by default ask the user to select from a list of
-possible candidates. They do so even when there is a thing at
-point that they can act on, which is then offered as the default.
-
-This option can be used to tell certain commands to use the thing
-at point instead of asking the user to select a candidate to act
-on, with or without confirmation.
-
-The value has the form ((COMMAND nil|PROMPT DEFAULT)...).
-
-- COMMAND is the command that should not prompt for a choice.
- To have an effect, the command has to use the function
- `magit-completing-read' or a utility function which in turn uses
- that function.
-
-- If the command uses `magit-completing-read' multiple times, then
- PROMPT can be used to only affect one of these uses. PROMPT, if
- non-nil, is a regular expression that is used to match against
- the PROMPT argument passed to `magit-completing-read'.
-
-- DEFAULT specifies how to use the default. If it is t, then
- the DEFAULT argument passed to `magit-completing-read' is used
- without confirmation. If it is `ask', then the user is given
- a chance to abort. DEFAULT can also be nil, in which case the
- entry has no effect."
- :package-version '(magit . "2.12.0")
- :group 'magit-commands
- :type '(repeat
- (list (symbol :tag "Command") ; It might not be fboundp yet.
- (choice (const :tag "for all prompts" nil)
- (regexp :tag "for prompts matching regexp"))
- (choice (const :tag "offer other choices" nil)
- (const :tag "require confirmation" ask)
- (const :tag "use default without confirmation" t)))))
-
-(defconst magit--confirm-actions
- '((const discard)
- (const reverse)
- (const stage-all-changes)
- (const unstage-all-changes)
- (const delete)
- (const trash)
- (const resurrect)
- (const untrack)
- (const rename)
- (const reset-bisect)
- (const abort-rebase)
- (const abort-merge)
- (const merge-dirty)
- (const delete-unmerged-branch)
- (const delete-pr-remote)
- (const drop-stashes)
- (const set-and-push)
- (const amend-published)
- (const rebase-published)
- (const edit-published)
- (const remove-modules)
- (const remove-dirty-modules)
- (const trash-module-gitdirs)
- (const kill-process)
- (const safe-with-wip)))
-
-(defcustom magit-no-confirm '(set-and-push)
- "A list of symbols for actions Magit should not confirm, or t.
-
-Many potentially dangerous commands by default ask the user for
-confirmation. Each of the below symbols stands for an action
-which, when invoked unintentionally or without being fully aware
-of the consequences, could lead to tears. In many cases there
-are several commands that perform variations of a certain action,
-so we don't use the command names but more generic symbols.
-
-Applying changes:
-
- `discard' Discarding one or more changes (i.e. hunks or the
- complete diff for a file) loses that change, obviously.
-
- `reverse' Reverting one or more changes can usually be undone
- by reverting the reversion.
-
- `stage-all-changes', `unstage-all-changes' When there are both
- staged and unstaged changes, then un-/staging everything would
- destroy that distinction. Of course that also applies when
- un-/staging a single change, but then less is lost and one does
- that so often that having to confirm every time would be
- unacceptable.
-
-Files:
-
- `delete' When a file that isn't yet tracked by Git is deleted
- then it is completely lost, not just the last changes. Very
- dangerous.
-
- `trash' Instead of deleting a file it can also be move to the
- system trash. Obviously much less dangerous than deleting it.
-
- Also see option `magit-delete-by-moving-to-trash'.
-
- `resurrect' A deleted file can easily be resurrected by
- \"deleting\" the deletion, which is done using the same command
- that was used to delete the same file in the first place.
-
- `untrack' Untracking a file can be undone by tracking it again.
-
- `rename' Renaming a file can easily be undone.
-
-Sequences:
-
- `reset-bisect' Aborting (known to Git as \"resetting\") a
- bisect operation loses all information collected so far.
-
- `abort-rebase' Aborting a rebase throws away all already
- modified commits, but it's possible to restore those from the
- reflog.
-
- `abort-merge' Aborting a merge throws away all conflict
- resolutions which has already been carried out by the user.
-
- `merge-dirty' Merging with a dirty worktree can make it hard to
- go back to the state before the merge was initiated.
-
-References:
-
- `delete-unmerged-branch' Once a branch has been deleted it can
- only be restored using low-level recovery tools provided by
- Git. And even then the reflog is gone. The user always has
- to confirm the deletion of a branch by accepting the default
- choice (or selecting another branch), but when a branch has
- not been merged yet, also make sure the user is aware of that.
-
- `delete-pr-remote' When deleting a branch that was created from
- a pull-request and if no other branches still exist on that
- remote, then `magit-branch-delete' offers to delete the remote
- as well. This should be safe because it only happens if no
- other refs exist in the remotes namespace, and you can recreate
- the remote if necessary.
-
- `drop-stashes' Dropping a stash is dangerous because Git stores
- stashes in the reflog. Once a stash is removed, there is no
- going back without using low-level recovery tools provided by
- Git. When a single stash is dropped, then the user always has
- to confirm by accepting the default (or selecting another).
- This action only concerns the deletion of multiple stashes at
- once.
-
-Publishing:
-
- `set-and-push' When pushing to the upstream or the push-remote
- and that isn't actually configured yet, then the user can first
- set the target. If s/he confirms the default too quickly, then
- s/he might end up pushing to the wrong branch and if the remote
- repository is configured to disallow fixing such mistakes, then
- that can be quite embarrassing and annoying.
-
-Edit published history:
-
- Without adding these symbols here, you will be warned before
- editing commits that have already been pushed to one of the
- branches listed in `magit-published-branches'.
-
- `amend-published' Affects most commands that amend to \"HEAD\".
-
- `rebase-published' Affects commands that perform interactive
- rebases. This includes commands from the commit popup that
- modify a commit other than \"HEAD\", namely the various fixup
- and squash variants.
-
- `edit-published' Affects the commands `magit-edit-line-commit'
- and `magit-diff-edit-hunk-commit'. These two commands make
- it quite easy to accidentally edit a published commit, so you
- should think twice before configuring them not to ask for
- confirmation.
-
- To disable confirmation completely, add all three symbols here
- or set `magit-published-branches' to nil.
-
-Removing modules:
-
- `remove-modules' When you remove the working directory of a
- module that does not contain uncommitted changes, then that is
- safer than doing so when there are uncommitted changes and/or
- when you also remove the gitdir. Still, you don't want to do
- that by accident.
-
- `remove-dirty-modules' When you remove the working directory of
- a module that contains uncommitted changes, then those changes
- are gone for good. It is better to go to the module, inspect
- these changes and only if appropriate discard them manually.
-
- `trash-module-gitdirs' When you remove the gitdir of a module,
- then all unpushed changes are gone for good. It is very easy
- to forget that you have some unfinished work on an unpublished
- feature branch or even in a stash.
-
- Actually there are some safety precautions in place, that might
- help you out if you make an unwise choice here, but don't count
- on it. In case of emergency, stay calm and check the stash and
- the `trash-directory' for traces of lost work.
-
-Various:
-
- `kill-process' There seldom is a reason to kill a process.
-
-Global settings:
-
- Instead of adding all of the above symbols to the value of this
- option you can also set it to the atom `t', which has the same
- effect as adding all of the above symbols. Doing that most
- certainly is a bad idea, especially because other symbols might
- be added in the future. So even if you don't want to be asked
- for confirmation for any of these actions, you are still better
- of adding all of the respective symbols individually.
-
- When `magit-wip-before-change-mode' is enabled then these actions
- can fairly easily be undone: `discard', `reverse',
- `stage-all-changes', and `unstage-all-changes'. If and only if
- this mode is enabled, then `safe-with-wip' has the same effect
- as adding all of these symbols individually."
- :package-version '(magit . "2.1.0")
- :group 'magit-essentials
- :group 'magit-commands
- :type `(choice (const :tag "Always require confirmation" nil)
- (const :tag "Never require confirmation" t)
- (set :tag "Require confirmation except for"
- ;; `remove-dirty-modules' and
- ;; `trash-module-gitdirs' intentionally
- ;; omitted.
- ,@magit--confirm-actions)))
-
-(defcustom magit-slow-confirm '(drop-stashes)
- "Whether to ask user \"y or n\" or \"yes or no\" questions.
-
-When this is nil, then `y-or-n-p' is used when the user has to
-confirm a potentially destructive action. When this is t, then
-`yes-or-no-p' is used instead. If this is a list of symbols
-identifying actions, then `yes-or-no-p' is used for those,
-`y-or-no-p' for all others. The list of actions is the same as
-for `magit-no-confirm' (which see)."
- :package-version '(magit . "2.9.0")
- :group 'magit-miscellaneous
- :type `(choice (const :tag "Always ask \"yes or no\" questions" t)
- (const :tag "Always ask \"y or n\" questions" nil)
- (set :tag "Ask \"yes or no\" questions only for"
- ,@magit--confirm-actions)))
-
-(defcustom magit-no-message nil
- "A list of messages Magit should not display.
-
-Magit displays most echo area messages using `message', but a few
-are displayed using `magit-message' instead, which takes the same
-arguments as the former, FORMAT-STRING and ARGS. `magit-message'
-forgoes printing a message if any member of this list is a prefix
-of the respective FORMAT-STRING.
-
-If Magit prints a message which causes you grief, then please
-first investigate whether there is another option which can be
-used to suppress it. If that is not the case, then ask the Magit
-maintainers to start using `magit-message' instead of `message'
-in that case. We are not proactively replacing all uses of
-`message' with `magit-message', just in case someone *might* find
-some of these messages useless.
-
-Messages which can currently be suppressed using this option are:
-* \"Turning on magit-auto-revert-mode...\""
- :package-version '(magit . "2.8.0")
- :group 'magit-miscellaneous
- :type '(repeat string))
-
-(defcustom magit-ellipsis ?…
- "Character used to abbreviate text.
-
-Currently this is used to abbreviate author names in the margin
-and in process buffers to elide `magit-git-global-arguments'."
- :package-version '(magit . "2.1.0")
- :group 'magit-miscellaneous
- :type 'character)
-
-(defcustom magit-update-other-window-delay 0.2
- "Delay before automatically updating the other window.
-
-When moving around in certain buffers, then certain other
-buffers, which are being displayed in another window, may
-optionally be updated to display information about the
-section at point.
-
-When holding down a key to move by more than just one section,
-then that would update that buffer for each section on the way.
-To prevent that, updating the revision buffer is delayed, and
-this option controls for how long. For optimal experience you
-might have to adjust this delay and/or the keyboard repeat rate
-and delay of your graphical environment or operating system."
- :package-version '(magit . "2.3.0")
- :group 'magit-miscellaneous
- :type 'number)
-
-(defcustom magit-view-git-manual-method 'info
- "How links to Git documentation are followed from Magit's Info manuals.
-
-`info' Follow the link to the node in the `gitman' Info manual
- as usual. Unfortunately that manual is not installed by
- default on some platforms, and when it is then the nodes
- look worse than the actual manpages.
-
-`man' View the respective man-page using the `man' package.
-
-`woman' View the respective man-page using the `woman' package."
- :package-version '(magit . "2.9.0")
- :group 'magit-miscellaneous
- :type '(choice (const :tag "view info manual" info)
- (const :tag "view manpage using `man'" man)
- (const :tag "view manpage using `woman'" woman)))
-
-;;; User Input
-
-(defvar helm-completion-in-region-default-sort-fn)
-(defvar helm-crm-default-separator)
-(defvar ivy-sort-functions-alist)
-(defvar ivy-sort-matches-functions-alist)
-
-(defvar magit-completing-read--silent-default nil)
-
-(defun magit-completing-read (prompt collection &optional
- predicate require-match initial-input
- hist def fallback)
- "Read a choice in the minibuffer, or use the default choice.
-
-This is the function that Magit commands use when they need the
-user to select a single thing to act on. The arguments have the
-same meaning as for `completing-read', except for FALLBACK, which
-is unique to this function and is described below.
-
-Instead of asking the user to choose from a list of possible
-candidates, this function may instead just return the default
-specified by DEF, with or without requiring user confirmation.
-Whether that is the case depends on PROMPT, `this-command' and
-`magit-dwim-selection'. See the documentation of the latter for
-more information.
-
-If it does use the default without the user even having to
-confirm that, then `magit-completing-read--silent-default' is set
-to t, otherwise nil.
-
-If it does read a value in the minibuffer, then this function
-acts similarly to `completing-read', except for the following:
-
-- COLLECTION must be a list of choices. A function is not
- supported.
-
-- If REQUIRE-MATCH is nil and the user exits without a choice,
- then nil is returned instead of an empty string.
-
-- If REQUIRE-MATCH is non-nil and the user exits without a
- choice, `user-error' is raised.
-
-- FALLBACK specifies a secondary default that is only used if
- the primary default DEF is nil. The secondary default is not
- subject to `magit-dwim-selection' — if DEF is nil but FALLBACK
- is not, then this function always asks the user to choose a
- candidate, just as if both defaults were nil.
-
-- \": \" is appended to PROMPT.
-
-- PROMPT is modified to end with \" (default DEF|FALLBACK): \"
- provided that DEF or FALLBACK is non-nil, that neither
- `ivy-mode' nor `helm-mode' is enabled, and that
- `magit-completing-read-function' is set to its default value of
- `magit-builtin-completing-read'."
- (setq magit-completing-read--silent-default nil)
- (if-let ((dwim (and def
- (nth 2 (-first (pcase-lambda (`(,cmd ,re ,_))
- (and (eq this-command cmd)
- (or (not re)
- (string-match-p re prompt))))
- magit-dwim-selection)))))
- (if (eq dwim 'ask)
- (if (y-or-n-p (format "%s %s? " prompt def))
- def
- (user-error "Abort"))
- (setq magit-completing-read--silent-default t)
- def)
- (unless def
- (setq def fallback))
- (let ((command this-command)
- (reply (funcall magit-completing-read-function
- (concat prompt ": ")
- (if (and def (not (member def collection)))
- (cons def collection)
- collection)
- predicate
- require-match initial-input hist def)))
- (setq this-command command)
- ;; Note: Avoid `string=' to support `helm-comp-read-use-marked'.
- (if (equal reply "")
- (if require-match
- (user-error "Nothing selected")
- nil)
- reply))))
-
-(defun magit--completion-table (collection)
- (lambda (string pred action)
- (if (eq action 'metadata)
- '(metadata (display-sort-function . identity))
- (complete-with-action action collection string pred))))
-
-(defun magit-builtin-completing-read
- (prompt choices &optional predicate require-match initial-input hist def)
- "Magit wrapper for standard `completing-read' function."
- (unless (or (bound-and-true-p helm-mode)
- (bound-and-true-p ivy-mode))
- (setq prompt (magit-prompt-with-default prompt def))
- (setq choices (magit--completion-table choices)))
- (cl-letf (((symbol-function 'completion-pcm--all-completions)
- #'magit-completion-pcm--all-completions))
- (let ((ivy-sort-functions-alist nil))
- (completing-read prompt choices
- predicate require-match
- initial-input hist def))))
-
-(defun magit-completing-read-multiple
- (prompt choices &optional sep default hist keymap)
- "Read multiple items from CHOICES, separated by SEP.
-
-Set up the `crm' variables needed to read multiple values with
-`read-from-minibuffer'.
-
-SEP is a regexp matching characters that can separate choices.
-When SEP is nil, it defaults to `crm-default-separator'.
-DEFAULT, HIST, and KEYMAP are passed to `read-from-minibuffer'.
-When KEYMAP is nil, it defaults to `crm-local-completion-map'.
-
-Unlike `completing-read-multiple', the return value is not split
-into a list."
- (let* ((crm-separator (or sep crm-default-separator))
- (crm-completion-table (magit--completion-table choices))
- (choose-completion-string-functions
- '(crm--choose-completion-string))
- (minibuffer-completion-table #'crm--collection-fn)
- (minibuffer-completion-confirm t)
- (helm-completion-in-region-default-sort-fn nil)
- (helm-crm-default-separator nil)
- (ivy-sort-matches-functions-alist nil)
- (input
- (cl-letf (((symbol-function 'completion-pcm--all-completions)
- #'magit-completion-pcm--all-completions))
- (read-from-minibuffer
- (concat prompt (and default (format " (%s)" default)) ": ")
- nil (or keymap crm-local-completion-map)
- nil hist default))))
- (when (string-equal input "")
- (or (setq input default)
- (user-error "Nothing selected")))
- input))
-
-(defun magit-completing-read-multiple*
- (prompt table &optional predicate require-match initial-input
- hist def inherit-input-method)
- "Read multiple strings in the minibuffer, with completion.
-Like `completing-read-multiple' but don't mess with order of
-TABLE. Also bind `helm-completion-in-region-default-sort-fn'
-to nil."
- (unwind-protect
- (cl-letf (((symbol-function 'completion-pcm--all-completions)
- #'magit-completion-pcm--all-completions))
- (add-hook 'choose-completion-string-functions
- 'crm--choose-completion-string)
- (let* ((minibuffer-completion-table #'crm--collection-fn)
- (minibuffer-completion-predicate predicate)
- ;; see completing_read in src/minibuf.c
- (minibuffer-completion-confirm
- (unless (eq require-match t) require-match))
- (crm-completion-table (magit--completion-table table))
- (map (if require-match
- crm-local-must-match-map
- crm-local-completion-map))
- (helm-completion-in-region-default-sort-fn nil)
- (ivy-sort-matches-functions-alist nil)
- ;; If the user enters empty input, `read-from-minibuffer'
- ;; returns the empty string, not DEF.
- (input (read-from-minibuffer
- prompt initial-input map
- nil hist def inherit-input-method)))
- (and def (string-equal input "") (setq input def))
- ;; Remove empty strings in the list of read strings.
- (split-string input crm-separator t)))
- (remove-hook 'choose-completion-string-functions
- 'crm--choose-completion-string)))
-
-(defun magit-ido-completing-read
- (prompt choices &optional predicate require-match initial-input hist def)
- "Ido-based `completing-read' almost-replacement.
-
-Unfortunately `ido-completing-read' is not suitable as a
-drop-in replacement for `completing-read', instead we use
-`ido-completing-read+' from the third-party package by the
-same name."
- (if (require 'ido-completing-read+ nil t)
- (ido-completing-read+ prompt choices predicate require-match
- initial-input hist
- (or def (and require-match (car choices))))
- (display-warning 'magit "ido-completing-read+ is not installed
-
-To use Ido completion with Magit you need to install the
-third-party `ido-completing-read+' packages. Falling
-back to built-in `completing-read' for now." :error)
- (magit-builtin-completing-read prompt choices predicate require-match
- initial-input hist def)))
-
-(defun magit-prompt-with-default (prompt def)
- (if (and def (> (length prompt) 2)
- (string-equal ": " (substring prompt -2)))
- (format "%s (default %s): " (substring prompt 0 -2) def)
- prompt))
-
-(defvar magit-minibuffer-local-ns-map
- (let ((map (make-sparse-keymap)))
- (set-keymap-parent map minibuffer-local-map)
- (define-key map "\s" 'magit-whitespace-disallowed)
- (define-key map "\t" 'magit-whitespace-disallowed)
- map))
-
-(defun magit-whitespace-disallowed ()
- "Beep to tell the user that whitespace is not allowed."
- (interactive)
- (ding)
- (message "Whitespace isn't allowed here")
- (setq defining-kbd-macro nil)
- (force-mode-line-update))
-
-(defun magit-read-string (prompt &optional initial-input history default-value
- inherit-input-method no-whitespace)
- "Read a string from the minibuffer, prompting with string PROMPT.
-
-This is similar to `read-string', but
-* empty input is only allowed if DEFAULT-VALUE is non-nil in
- which case that is returned,
-* whitespace is not allowed and leading and trailing whitespace is
- removed automatically if NO-WHITESPACE is non-nil,
-* \": \" is appended to PROMPT, and
-* an invalid DEFAULT-VALUE is silently ignored."
- (when default-value
- (when (consp default-value)
- (setq default-value (car default-value)))
- (unless (stringp default-value)
- (setq default-value nil)))
- (let* ((minibuffer-completion-table nil)
- (val (read-from-minibuffer
- (magit-prompt-with-default (concat prompt ": ") default-value)
- initial-input (and no-whitespace magit-minibuffer-local-ns-map)
- nil history default-value inherit-input-method))
- (trim (lambda (regexp string)
- (save-match-data
- (if (string-match regexp string)
- (replace-match "" t t string)
- string)))))
- (when (and (string= val "") default-value)
- (setq val default-value))
- (when no-whitespace
- (setq val (funcall trim "\\`\\(?:[ \t\n\r]+\\)"
- (funcall trim "\\(?:[ \t\n\r]+\\)\\'" val))))
- (cond ((string= val "")
- (user-error "Need non-empty input"))
- ((and no-whitespace (string-match-p "[\s\t\n]" val))
- (user-error "Input contains whitespace"))
- (t val))))
-
-(defun magit-read-string-ns (prompt &optional initial-input history
- default-value inherit-input-method)
- "Call `magit-read-string' with non-nil NO-WHITESPACE."
- (magit-read-string prompt initial-input history default-value
- inherit-input-method t))
-
-(defmacro magit-read-char-case (prompt verbose &rest clauses)
- (declare (indent 2)
- (debug (form form &rest (characterp form body))))
- `(prog1 (pcase (read-char-choice
- (concat ,prompt
- ,(concat (mapconcat 'cadr clauses ", ")
- (and verbose ", or [C-g] to abort") " "))
- ',(mapcar 'car clauses))
- ,@(--map `(,(car it) ,@(cddr it)) clauses))
- (message "")))
-
-(defun magit-y-or-n-p (prompt &optional action)
- "Ask user a \"y or n\" or a \"yes or no\" question using PROMPT.
-Which kind of question is used depends on whether
-ACTION is a member of option `magit-slow-confirm'."
- (if (or (eq magit-slow-confirm t)
- (and action (member action magit-slow-confirm)))
- (yes-or-no-p prompt)
- (y-or-n-p prompt)))
-
-(defvar magit--no-confirm-alist
- '((safe-with-wip magit-wip-before-change-mode
- discard reverse stage-all-changes unstage-all-changes)))
-
-(cl-defun magit-confirm (action &optional prompt prompt-n noabort
- (items nil sitems))
- (declare (indent defun))
- (setq prompt-n (format (concat (or prompt-n prompt) "? ") (length items)))
- (setq prompt (format (concat (or prompt (magit-confirm-make-prompt action))
- "? ")
- (car items)))
- (or (cond ((and (not (eq action t))
- (or (eq magit-no-confirm t)
- (memq action magit-no-confirm)
- (cl-member-if (pcase-lambda (`(,key ,var . ,sub))
- (and (memq key magit-no-confirm)
- (memq action sub)
- (or (not var)
- (and (boundp var)
- (symbol-value var)))))
- magit--no-confirm-alist)))
- (or (not sitems) items))
- ((not sitems)
- (magit-y-or-n-p prompt action))
- ((= (length items) 1)
- (and (magit-y-or-n-p prompt action) items))
- ((> (length items) 1)
- (and (magit-y-or-n-p (concat (mapconcat #'identity items "\n")
- "\n\n" prompt-n)
- action)
- items)))
- (if noabort nil (user-error "Abort"))))
-
-(defun magit-confirm-files (action files &optional prompt)
- (when files
- (unless prompt
- (setq prompt (magit-confirm-make-prompt action)))
- (magit-confirm action
- (concat prompt " %s")
- (concat prompt " %i files")
- nil files)))
-
-(defun magit-confirm-make-prompt (action)
- (let ((prompt (symbol-name action)))
- (replace-regexp-in-string
- "-" " " (concat (upcase (substring prompt 0 1)) (substring prompt 1)))))
-
-(defun magit-read-number-string (prompt &optional default _history)
- "Like `read-number' but return value is a string.
-DEFAULT may be a number or a numeric string."
- (number-to-string
- (read-number prompt (if (stringp default)
- (string-to-number default)
- default))))
-
-;;; Debug Utilities
-
-;;;###autoload
-(defun magit-emacs-Q-command ()
- "Show a shell command that runs an uncustomized Emacs with only Magit loaded.
-See info node `(magit)Debugging Tools' for more information."
- (interactive)
- (let ((cmd (mapconcat
- #'shell-quote-argument
- `(,(concat invocation-directory invocation-name)
- "-Q" "--eval" "(setq debug-on-error t)"
- ,@(cl-mapcan
- (lambda (dir) (list "-L" dir))
- (delete-dups
- (cl-mapcan
- (lambda (lib)
- (let ((path (locate-library lib)))
- (cond
- (path
- (list (file-name-directory path)))
- ((not (equal lib "libgit"))
- (error "Cannot find mandatory dependency %s" lib)))))
- '(;; Like `LOAD_PATH' in `default.mk'.
- "dash"
- "libgit"
- "transient"
- "with-editor"
- ;; Obviously `magit' itself is needed too.
- "magit"
- ;; While this is part of the Magit repository,
- ;; it is distributed as a separate package.
- "git-commit"
- ;; Even though `async' is a dependency of the
- ;; `magit' package, it is not required here.
- ))))
- ;; Avoid Emacs bug#16406 by using full path.
- "-l" ,(file-name-sans-extension (locate-library "magit")))
- " ")))
- (message "Uncustomized Magit command saved to kill-ring, %s"
- "please run it in a terminal.")
- (kill-new cmd)))
-
-;;; Text Utilities
-
-(defmacro magit-bind-match-strings (varlist string &rest body)
- "Bind variables to submatches according to VARLIST then evaluate BODY.
-Bind the symbols in VARLIST to submatches of the current match
-data, starting with 1 and incrementing by 1 for each symbol. If
-the last match was against a string, then that has to be provided
-as STRING."
- (declare (indent 2) (debug (listp form body)))
- (let ((s (cl-gensym "string"))
- (i 0))
- `(let ((,s ,string))
- (let ,(save-match-data
- (--map (list it (list 'match-string (cl-incf i) s)) varlist))
- ,@body))))
-
-(defun magit-delete-line ()
- "Delete the rest of the current line."
- (delete-region (point) (1+ (line-end-position))))
-
-(defun magit-delete-match (&optional num)
- "Delete text matched by last search.
-If optional NUM is specified, only delete that subexpression."
- (delete-region (match-beginning (or num 0))
- (match-end (or num 0))))
-
-(defun magit-file-line (file)
- "Return the first line of FILE as a string."
- (when (file-regular-p file)
- (with-temp-buffer
- (insert-file-contents file)
- (buffer-substring-no-properties (point-min)
- (line-end-position)))))
-
-(defun magit-file-lines (file &optional keep-empty-lines)
- "Return a list of strings containing one element per line in FILE.
-Unless optional argument KEEP-EMPTY-LINES is t, trim all empty lines."
- (when (file-regular-p file)
- (with-temp-buffer
- (insert-file-contents file)
- (split-string (buffer-string) "\n" (not keep-empty-lines)))))
-
-(defun magit-set-header-line-format (string)
- "Set the header-line using STRING.
-Propertize STRING with the `magit-header-line'. If the `face'
-property of any part of STRING is already set, then that takes
-precedence. Also pad the left side of STRING so that it aligns
-with the text area."
- (setq header-line-format
- (concat (propertize " " 'display '(space :align-to 0))
- string)))
-
-(defun magit-face-property-all (face string)
- "Return non-nil if FACE is present in all of STRING."
- (catch 'missing
- (let ((pos 0))
- (while (setq pos (next-single-property-change pos 'font-lock-face string))
- (let ((val (get-text-property pos 'font-lock-face string)))
- (unless (if (consp val)
- (memq face val)
- (eq face val))
- (throw 'missing nil))))
- (not pos))))
-
-(defun magit--add-face-text-property (beg end face &optional append object)
- "Like `add-face-text-property' but for `font-lock-face'."
- (while (< beg end)
- (let* ((pos (next-single-property-change beg 'font-lock-face object end))
- (val (get-text-property beg 'font-lock-face object))
- (val (if (listp val) val (list val))))
- (put-text-property beg pos 'font-lock-face
- (if append
- (append val (list face))
- (cons face val))
- object)
- (setq beg pos))))
-
-(defun magit--propertize-face (string face)
- (propertize string 'face face 'font-lock-face face))
-
-(defun magit--put-face (beg end face string)
- (put-text-property beg end 'face face string)
- (put-text-property beg end 'font-lock-face face string))
-
-(defun magit--format-spec (format specification)
- "Like `format-spec' but preserve text properties in SPECIFICATION."
- (with-temp-buffer
- (insert format)
- (goto-char (point-min))
- (while (search-forward "%" nil t)
- (cond
- ;; Quoted percent sign.
- ((eq (char-after) ?%)
- (delete-char 1))
- ;; Valid format spec.
- ((looking-at "\\([-0-9.]*\\)\\([a-zA-Z]\\)")
- (let* ((num (match-string 1))
- (spec (string-to-char (match-string 2)))
- (val (assq spec specification)))
- (unless val
- (error "Invalid format character: `%%%c'" spec))
- (setq val (cdr val))
- ;; Pad result to desired length.
- (let ((text (format (concat "%" num "s") val)))
- ;; Insert first, to preserve text properties.
- (if (next-property-change 0 (concat " " text))
- ;; If the inserted text has properties, then preserve those.
- (insert text)
- ;; Otherwise preserve FORMAT's properties, like `format-spec'.
- (insert-and-inherit text))
- ;; Delete the specifier body.
- (delete-region (+ (match-beginning 0) (length text))
- (+ (match-end 0) (length text)))
- ;; Delete the percent sign.
- (delete-region (1- (match-beginning 0)) (match-beginning 0)))))
- ;; Signal an error on bogus format strings.
- (t
- (error "Invalid format string"))))
- (buffer-string)))
-
-;;; Missing from Emacs
-
-(defun magit-kill-this-buffer ()
- "Kill the current buffer."
- (interactive)
- (kill-buffer (current-buffer)))
-
-(defun magit--buffer-string (&optional min max trim)
- "Like `buffer-substring-no-properties' but the arguments are optional.
-
-This combines the benefits of `buffer-string', `buffer-substring'
-and `buffer-substring-no-properties' into one function that is
-not as painful to use as the latter. I.e. you can write
- (magit--buffer-string)
-instead of
- (buffer-substring-no-properties (point-min)
- (point-max))
-
-Optional MIN defaults to the value of `point-min'.
-Optional MAX defaults to the value of `point-max'.
-
-If optional TRIM is non-nil, then all leading and trailing
-whitespace is remove. If it is the newline character, then
-one trailing newline is added."
- ;; Lets write that one last time and be done with it:
- (let ((str (buffer-substring-no-properties (or min (point-min))
- (or max (point-max)))))
- (if trim
- (concat (string-trim str)
- (and (eq trim ?\n) "\n"))
- str)))
-
-;;; Kludges for Emacs Bugs
-
-(defun magit-file-accessible-directory-p (filename)
- "Like `file-accessible-directory-p' but work around an Apple bug.
-See http://debbugs.gnu.org/cgi/bugreport.cgi?bug=21573#17
-and https://github.com/magit/magit/issues/2295."
- (and (file-directory-p filename)
- (file-accessible-directory-p filename)))
-
-(when (version<= "25.1" emacs-version)
- (with-eval-after-load 'vc-git
- (defun vc-git-conflicted-files (directory)
- "Return the list of files with conflicts in DIRECTORY."
- (let* ((status
- (vc-git--run-command-string directory "diff-files"
- "--name-status"))
- (lines (when status (split-string status "\n" 'omit-nulls)))
- files)
- (dolist (line lines files)
- (when (string-match "\\([ MADRCU?!]\\)[ \t]+\\(.+\\)" line)
- (let ((state (match-string 1 line))
- (file (match-string 2 line)))
- (when (equal state "U")
- (push (expand-file-name file directory) files)))))))))
-
-(when (< emacs-major-version 27)
- (defun vc-git--call@bug21559 (fn buffer command &rest args)
- "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559."
- (let ((process-environment process-environment))
- (when revert-buffer-in-progress-p
- (push "GIT_OPTIONAL_LOCKS=0" process-environment))
- (apply fn buffer command args)))
- (advice-add 'vc-git--call :around 'vc-git--call@bug21559)
-
- (defun vc-git-command@bug21559
- (fn buffer okstatus file-or-list &rest flags)
- "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559."
- (let ((process-environment process-environment))
- (when revert-buffer-in-progress-p
- (push "GIT_OPTIONAL_LOCKS=0" process-environment))
- (apply fn buffer okstatus file-or-list flags)))
- (advice-add 'vc-git-command :around 'vc-git-command@bug21559)
-
- (defun auto-revert-handler@bug21559 (fn)
- "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559."
- (let ((revert-buffer-in-progress-p t))
- (funcall fn)))
- (advice-add 'auto-revert-handler :around 'auto-revert-handler@bug21559)
- )
-
-;; `completion-pcm--all-completions' reverses the completion list. To
-;; preserve the order of our pre-sorted completions, we'll temporarily
-;; override it with the function below. bug#24676
-(defun magit-completion-pcm--all-completions (prefix pattern table pred)
- (if (completion-pcm--pattern-trivial-p pattern)
- (all-completions (concat prefix (car pattern)) table pred)
- (let* ((regex (completion-pcm--pattern->regex pattern))
- (case-fold-search completion-ignore-case)
- (completion-regexp-list (cons regex completion-regexp-list))
- (compl (all-completions
- (concat prefix
- (if (stringp (car pattern)) (car pattern) ""))
- table pred)))
- (if (not (functionp table))
- compl
- (let ((poss ()))
- (dolist (c compl)
- (when (string-match-p regex c) (push c poss)))
- ;; This `nreverse' call is the only code change made to the
- ;; `completion-pcm--all-completions' that shipped with Emacs 25.1.
- (nreverse poss))))))
-
-(defun magit-which-function ()
- "Return current function name based on point.
-
-This is a simple wrapper around `which-function', that resets
-Imenu's potentially outdated and therefore unreliable cache by
-setting `imenu--index-alist' to nil before calling that function."
- (setq imenu--index-alist nil)
- (which-function))
-
-;;; Kludges for Custom
-
-(defun magit-custom-initialize-reset (symbol exp)
- "Initialize SYMBOL based on EXP.
-Set the symbol, using `set-default' (unlike
-`custom-initialize-reset' which uses the `:set' function if any.)
-The value is either the symbol's current value
- (as obtained using the `:get' function), if any,
-or the value in the symbol's `saved-value' property if any,
-or (last of all) the value of EXP."
- (set-default-toplevel-value
- symbol
- (condition-case nil
- (let ((def (default-toplevel-value symbol))
- (getter (get symbol 'custom-get)))
- (if getter (funcall getter symbol) def))
- (error
- (eval (let ((sv (get symbol 'saved-value)))
- (if sv (car sv) exp)))))))
-
-(defun magit-hook-custom-get (symbol)
- (if (symbol-file symbol 'defvar)
- (default-toplevel-value symbol)
- ;;
- ;; Called by `custom-initialize-reset' on behalf of `symbol's
- ;; `defcustom', which is being evaluated for the first time to
- ;; set the initial value, but there's already a default value,
- ;; which most likely was established by one or more `add-hook'
- ;; calls.
- ;;
- ;; We combine the `standard-value' and the current value, while
- ;; preserving the order established by `:options', and return
- ;; the result of that to be used as the "initial" default value.
- ;;
- (let ((standard (eval (car (get symbol 'standard-value))))
- (current (default-toplevel-value symbol))
- (value nil))
- (dolist (fn (get symbol 'custom-options))
- (when (or (memq fn standard)
- (memq fn current))
- (push fn value)))
- (dolist (fn current)
- (unless (memq fn value)
- (push fn value)))
- (nreverse value))))
-
-;;; Kludges for Info Manuals
-
-;;;###autoload
-(defun Info-follow-nearest-node--magit-gitman (fn &optional fork)
- (let ((node (Info-get-token
- (point) "\\*note[ \n\t]+"
- "\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?")))
- (if (and node (string-match "^(gitman)\\(.+\\)" node))
- (pcase magit-view-git-manual-method
- (`info (funcall fn fork))
- (`man (require 'man)
- (man (match-string 1 node)))
- (`woman (require 'woman)
- (woman (match-string 1 node)))
- (_
- (user-error "Invalid value for `magit-view-git-manual-method'")))
- (funcall fn fork))))
-
-;;;###autoload
-(advice-add 'Info-follow-nearest-node :around
- 'Info-follow-nearest-node--magit-gitman)
-
-;;;###autoload
-(defun org-man-export--magit-gitman (fn link description format)
- (if (and (eq format 'texinfo)
- (string-match-p "\\`git" link))
- (replace-regexp-in-string "%s" link "
-@ifinfo
-@ref{%s,,,gitman,}.
-@end ifinfo
-@ifhtml
-@html
-the <a href=\"http://git-scm.com/docs/%s\">%s(1)</a> manpage.
-@end html
-@end ifhtml
-@iftex
-the %s(1) manpage.
-@end iftex
-")
- (funcall fn link description format)))
-
-;;;###autoload
-(advice-add 'org-man-export :around
- 'org-man-export--magit-gitman)
-
-;;; Kludges for Package Managers
-
-(defun magit--straight-chase-links (filename)
- "Chase links in FILENAME until a name that is not a link.
-
-This is the same as `file-chase-links', except that it also
-handles fake symlinks that are created by the package manager
-straight.el on Windows.
-
-See <https://github.com/raxod502/straight.el/issues/520>."
- (when (and (bound-and-true-p straight-symlink-emulation-mode)
- (fboundp 'straight-chase-emulated-symlink))
- (when-let ((target (straight-chase-emulated-symlink filename)))
- (unless (eq target 'broken)
- (setq filename target))))
- (file-chase-links filename))
-
-;;; Bitmaps
-
-(when (fboundp 'define-fringe-bitmap)
- (define-fringe-bitmap 'magit-fringe-bitmap+
- [#b00000000
- #b00011000
- #b00011000
- #b01111110
- #b01111110
- #b00011000
- #b00011000
- #b00000000])
- (define-fringe-bitmap 'magit-fringe-bitmap-
- [#b00000000
- #b00000000
- #b00000000
- #b01111110
- #b01111110
- #b00000000
- #b00000000
- #b00000000])
-
- (define-fringe-bitmap 'magit-fringe-bitmap>
- [#b01100000
- #b00110000
- #b00011000
- #b00001100
- #b00011000
- #b00110000
- #b01100000
- #b00000000])
- (define-fringe-bitmap 'magit-fringe-bitmapv
- [#b00000000
- #b10000010
- #b11000110
- #b01101100
- #b00111000
- #b00010000
- #b00000000
- #b00000000])
-
- (define-fringe-bitmap 'magit-fringe-bitmap-bold>
- [#b11100000
- #b01110000
- #b00111000
- #b00011100
- #b00011100
- #b00111000
- #b01110000
- #b11100000])
- (define-fringe-bitmap 'magit-fringe-bitmap-boldv
- [#b10000001
- #b11000011
- #b11100111
- #b01111110
- #b00111100
- #b00011000
- #b00000000
- #b00000000])
- )
-
-;;; Miscellaneous
-
-(defun magit-message (format-string &rest args)
- "Display a message at the bottom of the screen, or not.
-Like `message', except that if the users configured option
-`magit-no-message' to prevent the message corresponding to
-FORMAT-STRING to be displayed, then don't."
- (unless (--first (string-prefix-p it format-string) magit-no-message)
- (apply #'message format-string args)))
-
-(defun magit-msg (format-string &rest args)
- "Display a message at the bottom of the screen, but don't log it.
-Like `message', except that `message-log-max' is bound to nil."
- (let ((message-log-max nil))
- (apply #'message format-string args)))
-
-(defmacro magit--with-temp-position (buf pos &rest body)
- (declare (indent 2))
- `(with-current-buffer ,buf
- (save-excursion
- (save-restriction
- (widen)
- (goto-char (or ,pos 1))
- ,@body))))
-
-;;; _
-(provide 'magit-utils)
-;;; magit-utils.el ends here
+++ /dev/null
-;;; magit-wip.el --- commit snapshots to work-in-progress refs -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library defines tree global modes which automatically commit
-;; snapshots to branch-specific work-in-progress refs before and after
-;; making changes, and two commands which can be used to do so on
-;; demand.
-
-;;; Code:
-
-(eval-when-compile
- (require 'subr-x))
-
-(require 'magit-core)
-(require 'magit-log)
-
-;;; Options
-
-(defgroup magit-wip nil
- "Automatically commit to work-in-progress refs."
- :link '(info-link "(magit)Wip Modes")
- :group 'magit-modes
- :group 'magit-essentials)
-
-(defgroup magit-wip-legacy nil
- "It is better to not use these modes individually."
- :link '(info-link "(magit)Legacy Wip Modes")
- :group 'magit-wip)
-
-(defcustom magit-wip-mode-lighter " Wip"
- "Lighter for Magit-Wip mode."
- :package-version '(magit . "2.90.0")
- :group 'magit-wip
- :type 'string)
-
-(defcustom magit-wip-after-save-local-mode-lighter ""
- "Lighter for Magit-Wip-After-Save-Local mode."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip-legacy
- :type 'string)
-
-(defcustom magit-wip-after-apply-mode-lighter ""
- "Lighter for Magit-Wip-After-Apply mode."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip-legacy
- :type 'string)
-
-(defcustom magit-wip-before-change-mode-lighter ""
- "Lighter for Magit-Wip-Before-Change mode."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip-legacy
- :type 'string)
-
-(defcustom magit-wip-initial-backup-mode-lighter ""
- "Lighter for Magit-Wip-Initial Backup mode."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip-legacy
- :type 'string)
-
-(defcustom magit-wip-merge-branch nil
- "Whether to merge the current branch into its wip ref.
-
-If non-nil and the current branch has new commits, then it is
-merged into the wip ref before creating a new wip commit. This
-makes it easier to inspect wip history and the wip commits are
-never garbage collected.
-
-If nil and the current branch has new commits, then the wip ref
-is reset to the tip of the branch before creating a new wip
-commit. With this setting wip commits are eventually garbage
-collected. This is currently the default."
- :package-version '(magit . "2.90.0")
- :group 'magit-wip
- :type 'boolean)
-
-(defcustom magit-wip-namespace "refs/wip/"
- "Namespace used for work-in-progress refs.
-The wip refs are named \"<namespace/>index/<branchref>\"
-and \"<namespace/>wtree/<branchref>\". When snapshots
-are created while the `HEAD' is detached then \"HEAD\"
-is used as `branch-ref'."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :type 'string)
-
-;;; Modes
-
-;;;###autoload
-(define-minor-mode magit-wip-mode
- "Save uncommitted changes to work-in-progress refs.
-
-Whenever appropriate (i.e. when dataloss would be a possibility
-otherwise) this mode causes uncommitted changes to be committed
-to dedicated work-in-progress refs.
-
-For historic reasons this mode is implemented on top of four
-other `magit-wip-*' modes, which can also be used individually,
-if you want finer control over when the wip refs are updated;
-but that is discouraged."
- :package-version '(magit . "2.90.0")
- :lighter magit-wip-mode-lighter
- :global t
- (let ((arg (if magit-wip-mode 1 -1)))
- (magit-wip-after-save-mode arg)
- (magit-wip-after-apply-mode arg)
- (magit-wip-before-change-mode arg)
- (magit-wip-initial-backup-mode arg)))
-
-(define-minor-mode magit-wip-after-save-local-mode
- "After saving, also commit to a worktree work-in-progress ref.
-
-After saving the current file-visiting buffer this mode also
-commits the changes to the worktree work-in-progress ref for
-the current branch.
-
-This mode should be enabled globally by turning on the globalized
-variant `magit-wip-after-save-mode'."
- :package-version '(magit . "2.1.0")
- :lighter magit-wip-after-save-local-mode-lighter
- (if magit-wip-after-save-local-mode
- (if (and buffer-file-name (magit-inside-worktree-p t))
- (add-hook 'after-save-hook 'magit-wip-commit-buffer-file t t)
- (setq magit-wip-after-save-local-mode nil)
- (user-error "Need a worktree and a file"))
- (remove-hook 'after-save-hook 'magit-wip-commit-buffer-file t)))
-
-(defun magit-wip-after-save-local-mode-turn-on ()
- (and buffer-file-name
- (magit-inside-worktree-p t)
- (magit-file-tracked-p buffer-file-name)
- (magit-wip-after-save-local-mode)))
-
-;;;###autoload
-(define-globalized-minor-mode magit-wip-after-save-mode
- magit-wip-after-save-local-mode magit-wip-after-save-local-mode-turn-on
- :package-version '(magit . "2.1.0")
- :group 'magit-wip)
-
-(defun magit-wip-commit-buffer-file (&optional msg)
- "Commit visited file to a worktree work-in-progress ref.
-
-Also see `magit-wip-after-save-mode' which calls this function
-automatically whenever a buffer visiting a tracked file is saved."
- (interactive)
- (--when-let (magit-wip-get-ref)
- (magit-with-toplevel
- (let ((file (file-relative-name buffer-file-name)))
- (magit-wip-commit-worktree
- it (list file)
- (format (cond (msg)
- ((called-interactively-p 'any)
- "wip-save %s after save")
- (t
- "autosave %s after save"))
- file))))))
-
-;;;###autoload
-(define-minor-mode magit-wip-after-apply-mode
- "Commit to work-in-progress refs.
-
-After applying a change using any \"apply variant\"
-command (apply, stage, unstage, discard, and reverse) commit the
-affected files to the current wip refs. For each branch there
-may be two wip refs; one contains snapshots of the files as found
-in the worktree and the other contains snapshots of the entries
-in the index."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :lighter magit-wip-after-apply-mode-lighter
- :global t)
-
-(defun magit-wip-commit-after-apply (&optional files msg)
- (when magit-wip-after-apply-mode
- (magit-wip-commit files msg)))
-
-;;;###autoload
-(define-minor-mode magit-wip-before-change-mode
- "Commit to work-in-progress refs before certain destructive changes.
-
-Before invoking a revert command or an \"apply variant\"
-command (apply, stage, unstage, discard, and reverse) commit the
-affected tracked files to the current wip refs. For each branch
-there may be two wip refs; one contains snapshots of the files
-as found in the worktree and the other contains snapshots of the
-entries in the index.
-
-Only changes to files which could potentially be affected by the
-command which is about to be called are committed."
- :package-version '(magit . "2.1.0")
- :group 'magit-wip
- :lighter magit-wip-before-change-mode-lighter
- :global t)
-
-(defun magit-wip-commit-before-change (&optional files msg)
- (when magit-wip-before-change-mode
- (magit-with-toplevel
- (magit-wip-commit files msg))))
-
-(define-minor-mode magit-wip-initial-backup-mode
- "Before saving a buffer for the first time, commit to a wip ref."
- :package-version '(magit . "2.90.0")
- :group 'magit-wip
- :lighter magit-wip-initial-backup-mode-lighter
- :global t
- (if magit-wip-initial-backup-mode
- (add-hook 'before-save-hook 'magit-wip-commit-initial-backup)
- (remove-hook 'before-save-hook 'magit-wip-commit-initial-backup)))
-
-(defun magit--any-wip-mode-enabled-p ()
- "Return non-nil if any global wip mode is enabled."
- (or magit-wip-mode
- magit-wip-after-save-mode
- magit-wip-after-apply-mode
- magit-wip-before-change-mode
- magit-wip-initial-backup-mode))
-
-(defvar-local magit-wip-buffer-backed-up nil)
-(put 'magit-wip-buffer-backed-up 'permanent-local t)
-
-;;;###autoload
-(defun magit-wip-commit-initial-backup ()
- "Before saving, commit current file to a worktree wip ref.
-
-The user has to add this function to `before-save-hook'.
-
-Commit the current state of the visited file before saving the
-current buffer to that file. This backs up the same version of
-the file as `backup-buffer' would, but stores the backup in the
-worktree wip ref, which is also used by the various Magit Wip
-modes, instead of in a backup file as `backup-buffer' would.
-
-This function ignores the variables that affect `backup-buffer'
-and can be used along-side that function, which is recommended
-because this function only backs up files that are tracked in
-a Git repository."
- (when (and (not magit-wip-buffer-backed-up)
- buffer-file-name
- (magit-inside-worktree-p t)
- (magit-file-tracked-p buffer-file-name))
- (let ((magit-save-repository-buffers nil))
- (magit-wip-commit-buffer-file "autosave %s before save"))
- (setq magit-wip-buffer-backed-up t)))
-
-;;; Core
-
-(defun magit-wip-commit (&optional files msg)
- "Commit all tracked files to the work-in-progress refs.
-
-Interactively, commit all changes to all tracked files using
-a generic commit message. With a prefix-argument the commit
-message is read in the minibuffer.
-
-Non-interactively, only commit changes to FILES using MSG as
-commit message."
- (interactive (list nil (if current-prefix-arg
- (magit-read-string "Wip commit message")
- "wip-save tracked files")))
- (--when-let (magit-wip-get-ref)
- (magit-wip-commit-index it files msg)
- (magit-wip-commit-worktree it files msg)))
-
-(defun magit-wip-commit-index (ref files msg)
- (let* ((wipref (magit--wip-index-ref ref))
- (parent (magit-wip-get-parent ref wipref))
- (tree (magit-git-string "write-tree")))
- (magit-wip-update-wipref ref wipref tree parent files msg "index")))
-
-(defun magit-wip-commit-worktree (ref files msg)
- (let* ((wipref (magit--wip-wtree-ref ref))
- (parent (magit-wip-get-parent ref wipref))
- (tree (magit-with-temp-index parent (list "--reset" "-i")
- (if files
- ;; Note: `update-index' is used instead of `add'
- ;; because `add' will fail if a file is already
- ;; deleted in the temporary index.
- (magit-call-git
- "update-index" "--add" "--remove"
- (and (pcase (magit-repository-local-get
- 'update-index-has-ignore-sw-p 'unset)
- (`unset
- (let ((val (version<= "2.25.0"
- (magit-git-version))))
- (magit-repository-local-set
- 'update-index-has-ignore-sw-p val)
- val))
- (val val))
- "--ignore-skip-worktree-entries")
- "--" files)
- (magit-with-toplevel
- (magit-call-git "add" "-u" ".")))
- (magit-git-string "write-tree"))))
- (magit-wip-update-wipref ref wipref tree parent files msg "worktree")))
-
-(defun magit-wip-update-wipref (ref wipref tree parent files msg start-msg)
- (cond
- ((and (not (equal parent wipref))
- (or (not magit-wip-merge-branch)
- (not (magit-rev-verify wipref))))
- (setq start-msg (concat "start autosaving " start-msg))
- (magit-update-ref wipref start-msg
- (magit-git-string "commit-tree" "--no-gpg-sign"
- "-p" parent "-m" start-msg
- (concat parent "^{tree}")))
- (setq parent wipref))
- ((and magit-wip-merge-branch
- (or (not (magit-rev-ancestor-p ref wipref))
- (not (magit-rev-ancestor-p
- (concat (magit-git-string "log" "--format=%H"
- "-1" "--merges" wipref)
- "^2")
- ref))))
- (setq start-msg (format "merge %s into %s" ref start-msg))
- (magit-update-ref wipref start-msg
- (magit-git-string "commit-tree" "--no-gpg-sign"
- "-p" wipref "-p" ref
- "-m" start-msg
- (concat ref "^{tree}")))
- (setq parent wipref)))
- (when (magit-git-failure "diff-tree" "--quiet" parent tree "--" files)
- (unless (and msg (not (= (aref msg 0) ?\s)))
- (let ((len (length files)))
- (setq msg (concat
- (cond ((= len 0) "autosave tracked files")
- ((> len 1) (format "autosave %s files" len))
- (t (concat "autosave "
- (file-relative-name (car files)
- (magit-toplevel)))))
- msg))))
- (magit-update-ref wipref msg
- (magit-git-string "commit-tree" "--no-gpg-sign"
- "-p" parent "-m" msg tree))))
-
-(defun magit-wip-get-ref ()
- (let ((ref (or (magit-git-string "symbolic-ref" "HEAD") "HEAD")))
- (and (magit-rev-verify ref)
- ref)))
-
-(defun magit-wip-get-parent (ref wipref)
- (if (and (magit-rev-verify wipref)
- (equal (magit-git-string "merge-base" wipref ref)
- (magit-rev-verify ref)))
- wipref
- ref))
-
-(defun magit--wip-index-ref (&optional ref)
- (magit--wip-ref "index/" ref))
-
-(defun magit--wip-wtree-ref (&optional ref)
- (magit--wip-ref "wtree/" ref))
-
-(defun magit--wip-ref (namespace &optional ref)
- (concat magit-wip-namespace namespace
- (or (and ref (string-prefix-p "refs/" ref) ref)
- (when-let ((branch (and (not (equal ref "HEAD"))
- (or ref (magit-get-current-branch)))))
- (concat "refs/heads/" branch))
- "HEAD")))
-
-(defun magit-wip-maybe-add-commit-hook ()
- (when (and magit-wip-merge-branch
- (magit-wip-any-enabled-p))
- (add-hook 'git-commit-post-finish-hook 'magit-wip-commit nil t)))
-
-(defun magit-wip-any-enabled-p ()
- (or magit-wip-mode
- magit-wip-after-save-local-mode
- magit-wip-after-save-mode
- magit-wip-after-apply-mode
- magit-wip-before-change-mode
- magit-wip-initial-backup-mode))
-
-;;; Log
-
-(defun magit-wip-log-index (args files)
- "Show log for the index wip ref of the current branch."
- (interactive (magit-log-arguments))
- (magit-log-setup-buffer (list (magit--wip-index-ref)) args files))
-
-(defun magit-wip-log-worktree (args files)
- "Show log for the worktree wip ref of the current branch."
- (interactive (magit-log-arguments))
- (magit-log-setup-buffer (list (magit--wip-wtree-ref)) args files))
-
-(defun magit-wip-log-current (branch args files count)
- "Show log for the current branch and its wip refs.
-With a negative prefix argument only show the worktree wip ref.
-The absolute numeric value of the prefix argument controls how
-many \"branches\" of each wip ref are shown."
- (interactive
- (nconc (list (or (magit-get-current-branch) "HEAD"))
- (magit-log-arguments)
- (list (prefix-numeric-value current-prefix-arg))))
- (magit-wip-log branch args files count))
-
-(defun magit-wip-log (branch args files count)
- "Show log for a branch and its wip refs.
-With a negative prefix argument only show the worktree wip ref.
-The absolute numeric value of the prefix argument controls how
-many \"branches\" of each wip ref are shown."
- (interactive
- (nconc (list (magit-completing-read
- "Log branch and its wip refs"
- (-snoc (magit-list-local-branch-names) "HEAD")
- nil t nil 'magit-revision-history
- (or (magit-branch-at-point)
- (magit-get-current-branch)
- "HEAD")))
- (magit-log-arguments)
- (list (prefix-numeric-value current-prefix-arg))))
- (magit-log-setup-buffer (nconc (list branch)
- (magit-wip-log-get-tips
- (magit--wip-wtree-ref branch)
- (abs count))
- (and (>= count 0)
- (magit-wip-log-get-tips
- (magit--wip-index-ref branch)
- (abs count))))
- args files))
-
-(defun magit-wip-log-get-tips (wipref count)
- (when-let ((reflog (magit-git-lines "reflog" wipref)))
- (let (tips)
- (while (and reflog (> count 1))
- (setq reflog (cl-member "^[^ ]+ [^:]+: restart autosaving"
- reflog :test #'string-match-p))
- (when (and (cadr reflog)
- (string-match "^[^ ]+ \\([^:]+\\)" (cadr reflog)))
- (push (match-string 1 (cadr reflog)) tips))
- (setq reflog (cddr reflog))
- (cl-decf count))
- (cons wipref (nreverse tips)))))
-
-;;; _
-(provide 'magit-wip)
-;;; magit-wip.el ends here
+++ /dev/null
-;;; magit-worktree.el --- worktree support -*- lexical-binding: t -*-
-
-;; Copyright (C) 2010-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; This library implements support for `git-worktree'.
-
-;;; Code:
-
-(require 'magit)
-
-;;; Options
-
-(defcustom magit-worktree-read-directory-name-function 'read-directory-name
- "Function used to read a directory for worktree commands.
-This is called with one argument, the prompt, and can be used
-to e.g. use a base directory other than `default-directory'.
-Used by `magit-worktree-checkout' and `magit-worktree-branch'."
- :package-version '(magit . "3.0.0")
- :group 'magit-commands
- :type 'function)
-
-;;; Commands
-
-;;;###autoload (autoload 'magit-worktree "magit-worktree" nil t)
-(transient-define-prefix magit-worktree ()
- "Act on a worktree."
- :man-page "git-worktree"
- [["Create new"
- ("b" "worktree" magit-worktree-checkout)
- ("c" "branch and worktree" magit-worktree-branch)]
- ["Commands"
- ("m" "Move worktree" magit-worktree-move)
- ("k" "Delete worktree" magit-worktree-delete)
- ("g" "Visit worktree" magit-worktree-status)]])
-
-;;;###autoload
-(defun magit-worktree-checkout (path branch)
- "Checkout BRANCH in a new worktree at PATH."
- (interactive
- (let ((branch (magit-read-branch-or-commit "Checkout")))
- (list (funcall magit-worktree-read-directory-name-function
- (format "Checkout %s in new worktree: " branch))
- branch)))
- (magit-run-git "worktree" "add" (expand-file-name path) branch)
- (magit-diff-visit-directory path))
-
-;;;###autoload
-(defun magit-worktree-branch (path branch start-point &optional force)
- "Create a new BRANCH and check it out in a new worktree at PATH."
- (interactive
- `(,(funcall magit-worktree-read-directory-name-function
- "Create worktree: ")
- ,@(magit-branch-read-args "Create and checkout branch")
- ,current-prefix-arg))
- (magit-run-git "worktree" "add" (if force "-B" "-b")
- branch (expand-file-name path) start-point)
- (magit-diff-visit-directory path))
-
-;;;###autoload
-(defun magit-worktree-move (worktree path)
- "Move WORKTREE to PATH."
- (interactive
- (list (magit-completing-read "Move worktree"
- (cdr (magit-list-worktrees))
- nil t nil nil
- (magit-section-value-if 'worktree))
- (funcall magit-worktree-read-directory-name-function
- "Move worktree to: ")))
- (if (file-directory-p (expand-file-name ".git" worktree))
- (user-error "You may not move the main working tree")
- (let ((preexisting-directory (file-directory-p path)))
- (when (and (zerop (magit-call-git "worktree" "move" worktree
- (expand-file-name path)))
- (not (file-exists-p default-directory))
- (derived-mode-p 'magit-status-mode))
- (kill-buffer)
- (magit-diff-visit-directory
- (if preexisting-directory
- (concat (file-name-as-directory path)
- (file-name-nondirectory worktree))
- path)))
- (magit-refresh))))
-
-(defun magit-worktree-delete (worktree)
- "Delete a worktree, defaulting to the worktree at point.
-The primary worktree cannot be deleted."
- (interactive
- (list (magit-completing-read "Delete worktree"
- (cdr (magit-list-worktrees))
- nil t nil nil
- (magit-section-value-if 'worktree))))
- (if (file-directory-p (expand-file-name ".git" worktree))
- (user-error "Deleting %s would delete the shared .git directory" worktree)
- (let ((primary (file-name-as-directory (caar (magit-list-worktrees)))))
- (magit-confirm-files (if magit-delete-by-moving-to-trash 'trash 'delete)
- (list "worktree"))
- (when (file-exists-p worktree)
- (let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash))
- (delete-directory worktree t magit-delete-by-moving-to-trash)))
- (if (file-exists-p default-directory)
- (magit-run-git "worktree" "prune")
- (let ((default-directory primary))
- (magit-run-git "worktree" "prune"))
- (when (derived-mode-p 'magit-status-mode)
- (kill-buffer)
- (magit-status-setup-buffer primary))))))
-
-(defun magit-worktree-status (worktree)
- "Show the status for the worktree at point.
-If there is no worktree at point, then read one in the
-minibuffer. If the worktree at point is the one whose
-status is already being displayed in the current buffer,
-then show it in Dired instead."
- (interactive
- (list (or (magit-section-value-if 'worktree)
- (magit-completing-read
- "Show status for worktree"
- (cl-delete (directory-file-name (magit-toplevel))
- (magit-list-worktrees)
- :test #'equal :key #'car)))))
- (magit-diff-visit-directory worktree))
-
-;;; Sections
-
-(defvar magit-worktree-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map [remap magit-visit-thing] 'magit-worktree-status)
- (define-key map [remap magit-delete-thing] 'magit-worktree-delete)
- map)
- "Keymap for `worktree' sections.")
-
-(defun magit-insert-worktrees ()
- "Insert sections for all worktrees.
-If there is only one worktree, then insert nothing."
- (let ((worktrees (magit-list-worktrees)))
- (when (> (length worktrees) 1)
- (magit-insert-section (worktrees)
- (magit-insert-heading "Worktrees:")
- (let* ((cols
- (mapcar
- (pcase-lambda (`(,path ,barep ,commit ,branch))
- (cons (cond
- (branch (propertize
- branch 'font-lock-face
- (if (equal branch (magit-get-current-branch))
- 'magit-branch-current
- 'magit-branch-local)))
- (commit (propertize (magit-rev-abbrev commit)
- 'font-lock-face 'magit-hash))
- (barep "(bare)"))
- path))
- worktrees))
- (align (1+ (-max (--map (string-width (car it)) cols)))))
- (pcase-dolist (`(,head . ,path) cols)
- (magit-insert-section (worktree path)
- (insert head)
- (insert (make-string (- align (length head)) ?\s))
- (insert (let ((r (file-relative-name path))
- (a (abbreviate-file-name path)))
- (if (< (string-width r) (string-width a)) r a)))
- (insert ?\n))))
- (insert ?\n)))))
-
-;;; _
-(provide 'magit-worktree)
-;;; magit-worktree.el ends here
+++ /dev/null
-;;; magit.el --- A Git porcelain inside Emacs -*- lexical-binding: t; coding: utf-8 -*-
-
-;; Copyright (C) 2008-2020 The Magit Project Contributors
-;;
-;; You should have received a copy of the AUTHORS.md file which
-;; lists all contributors. If not, see http://magit.vc/authors.
-
-;; Author: Marius Vollmer <marius.vollmerNOSPAMgmail.com>
-;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
-;; Kyle Meyer <kyleNOSPAMkyleam.com>
-;; Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
-;; Former-Maintainers:
-;; Nicolas Dudebout <nicolas.dudeboutNOSPAMgatech.edu>
-;; Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
-;; Phil Jackson <phil@shellarchive.co.uk>
-;; Rémi Vanicat <vanicatNOSPAMdebian.org>
-;; Yann Hodique <yann.hodiqueNOSPAMgmail.com>
-
-;; Keywords: git tools vc
-;; Homepage: https://github.com/magit/magit
-
-;; Magit requires at least GNU Emacs 25.1 and Git 2.2.0.
-
-;; Magit is free software; you can redistribute it and/or modify it
-;; under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 3, or (at your option)
-;; any later version.
-;;
-;; Magit is distributed in the hope that it will be useful, but WITHOUT
-;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
-;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
-;; License for more details.
-;;
-;; You should have received a copy of the GNU General Public License
-;; along with Magit. If not, see http://www.gnu.org/licenses.
-
-;;; Commentary:
-
-;; 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.
-
-;;; Code:
-
-(require 'cl-lib)
-(require 'dash)
-
-(require 'subr-x)
-
-(require 'with-editor)
-(require 'git-commit)
-(require 'magit-core)
-(require 'magit-diff)
-(require 'magit-log)
-(require 'magit-wip)
-(require 'magit-apply)
-(require 'magit-repos)
-
-(require 'format-spec)
-(require 'package nil t) ; used in `magit-version'
-
-(defconst magit--minimal-git "2.2.0")
-(defconst magit--minimal-emacs "25.1")
-
-;;; Faces
-
-(defface magit-header-line
- '((t :inherit magit-section-heading))
- "Face for the `header-line' in some Magit modes.
-Note that some modes, such as `magit-log-select-mode', have their
-own faces for the `header-line', or for parts of the
-`header-line'."
- :group 'magit-faces)
-
-(defface magit-header-line-key
- '((t :inherit font-lock-builtin-face))
- "Face for keys in the `header-line'."
- :group 'magit-faces)
-
-(defface magit-dimmed
- '((((class color) (background light)) :foreground "grey50")
- (((class color) (background dark)) :foreground "grey50"))
- "Face for text that shouldn't stand out."
- :group 'magit-faces)
-
-(defface magit-hash
- '((((class color) (background light)) :foreground "grey60")
- (((class color) (background dark)) :foreground "grey40"))
- "Face for the sha1 part of the log output."
- :group 'magit-faces)
-
-(defface magit-tag
- '((((class color) (background light)) :foreground "Goldenrod4")
- (((class color) (background dark)) :foreground "LightGoldenrod2"))
- "Face for tag labels shown in log buffer."
- :group 'magit-faces)
-
-(defface magit-branch-remote
- '((((class color) (background light)) :foreground "DarkOliveGreen4")
- (((class color) (background dark)) :foreground "DarkSeaGreen2"))
- "Face for remote branch head labels shown in log buffer."
- :group 'magit-faces)
-
-(defface magit-branch-remote-head
- '((((class color) (background light)) :inherit magit-branch-remote :box t)
- (((class color) (background dark)) :inherit magit-branch-remote :box t))
- "Face for current branch."
- :group 'magit-faces)
-
-(defface magit-branch-local
- '((((class color) (background light)) :foreground "SkyBlue4")
- (((class color) (background dark)) :foreground "LightSkyBlue1"))
- "Face for local branches."
- :group 'magit-faces)
-
-(defface magit-branch-current
- '((((class color) (background light)) :inherit magit-branch-local :box t)
- (((class color) (background dark)) :inherit magit-branch-local :box t))
- "Face for current branch."
- :group 'magit-faces)
-
-(defface magit-branch-upstream
- '((t :slant italic))
- "Face for upstream branch.
-This face is only used in logs and it gets combined
- with `magit-branch-local', `magit-branch-remote'
-and/or `magit-branch-remote-head'."
- :group 'magit-faces)
-
-(defface magit-head
- '((((class color) (background light)) :inherit magit-branch-local)
- (((class color) (background dark)) :inherit magit-branch-local))
- "Face for the symbolic ref `HEAD'."
- :group 'magit-faces)
-
-(defface magit-refname
- '((((class color) (background light)) :foreground "grey30")
- (((class color) (background dark)) :foreground "grey80"))
- "Face for refnames without a dedicated face."
- :group 'magit-faces)
-
-(defface magit-refname-stash
- '((t :inherit magit-refname))
- "Face for stash refnames."
- :group 'magit-faces)
-
-(defface magit-refname-wip
- '((t :inherit magit-refname))
- "Face for wip refnames."
- :group 'magit-faces)
-
-(defface magit-refname-pullreq
- '((t :inherit magit-refname))
- "Face for pullreq refnames."
- :group 'magit-faces)
-
-(defface magit-keyword
- '((t :inherit font-lock-string-face))
- "Face for parts of commit messages inside brackets."
- :group 'magit-faces)
-
-(defface magit-keyword-squash
- '((t :inherit font-lock-warning-face))
- "Face for squash! and fixup! keywords in commit messages."
- :group 'magit-faces)
-
-(defface magit-signature-good
- '((t :foreground "green"))
- "Face for good signatures."
- :group 'magit-faces)
-
-(defface magit-signature-bad
- '((t :foreground "red" :weight bold))
- "Face for bad signatures."
- :group 'magit-faces)
-
-(defface magit-signature-untrusted
- '((t :foreground "cyan"))
- "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 "firebrick3"))
- "Face for signatures that cannot be checked (e.g. missing key)."
- :group 'magit-faces)
-
-(defface magit-cherry-unmatched
- '((t :foreground "cyan"))
- "Face for unmatched cherry commits."
- :group 'magit-faces)
-
-(defface magit-cherry-equivalent
- '((t :foreground "magenta"))
- "Face for equivalent cherry commits."
- :group 'magit-faces)
-
-(defface magit-filename
- '((t :weight normal))
- "Face for filenames."
- :group 'magit-faces)
-
-;;; Global Bindings
-
-;;;###autoload
-(define-obsolete-variable-alias 'global-magit-file-mode
- 'magit-define-global-key-bindings "Magit 3.0.0")
-
-;;;###autoload
-(defcustom magit-define-global-key-bindings t
- "Whether to bind some Magit commands in the global keymap.
-
-If this variable is non-nil, then the following bindings may
-be added to the global keymap. The default is t.
-
-key binding
---- -------
-C-x g magit-status
-C-x M-g magit-dispatch
-C-c M-g magit-file-dispatch
-
-These bindings may be added when `after-init-hook' is called.
-Each binding is added if and only if at that time no other key
-is bound to the same command and no other command is bound to
-the same key. In other words we try to avoid adding bindings
-that are unnecessary, as well as bindings that conflict with
-other bindings.
-
-Adding the above bindings is delayed until `after-init-hook'
-is called to allow users to set the variable anywhere in their
-init file (without having to make sure to do so before `magit'
-is loaded or autoloaded) and to increase the likelihood that
-all the potentially conflicting user bindings have already
-been added.
-
-Setting this variable after the hook has already been called
-has no effect.
-
-We recommend that you bind \"C-c g\" instead of \"C-c M-g\" to
-`magit-file-dispatch'. The former is a much better binding
-but the \"C-c <letter>\" namespace is strictly reserved for
-users; preventing Magit from using it by default.
-
-Also see info node `(magit)Commands for Buffers Visiting Files'."
- :package-version '(magit . "3.0.0")
- :group 'magit-essentials
- :type 'boolean)
-
-;;;###autoload
-(progn
- (defun magit-maybe-define-global-key-bindings ()
- (when magit-define-global-key-bindings
- (let ((map (current-global-map)))
- (dolist (elt '(("C-x g" . magit-status)
- ("C-x M-g" . magit-dispatch)
- ("C-c M-g" . magit-file-dispatch)))
- (let ((key (kbd (car elt)))
- (def (cdr elt)))
- (unless (or (lookup-key map key)
- (where-is-internal def (make-sparse-keymap) t))
- (define-key map key def)))))))
- (if after-init-time
- (magit-maybe-define-global-key-bindings)
- (add-hook 'after-init-hook 'magit-maybe-define-global-key-bindings t)))
-
-;;; Dispatch Popup
-
-;;;###autoload (autoload 'magit-dispatch "magit" nil t)
-(transient-define-prefix magit-dispatch ()
- "Invoke a Magit command from a list of available commands."
- :info-manual "(magit)Top"
- ["Transient and dwim commands"
- [("A" "Apply" magit-cherry-pick)
- ("b" "Branch" magit-branch)
- ("B" "Bisect" magit-bisect)
- ("c" "Commit" magit-commit)
- ("C" "Clone" magit-clone)
- ("d" "Diff" magit-diff)
- ("D" "Diff (change)" magit-diff-refresh)
- ("e" "Ediff (dwim)" magit-ediff-dwim)
- ("E" "Ediff" magit-ediff)]
- [("f" "Fetch" magit-fetch)
- ("F" "Pull" magit-pull)
- ("l" "Log" magit-log)
- ("L" "Log (change)" magit-log-refresh)
- ("m" "Merge" magit-merge)
- ("M" "Remote" magit-remote)
- ("o" "Submodule" magit-submodule)
- ("O" "Subtree" magit-subtree)]
- [("P" "Push" magit-push)
- ("r" "Rebase" magit-rebase)
- ("t" "Tag" magit-tag)
- ("T" "Note" magit-notes)
- ("V" "Revert" magit-revert)
- ("w" "Apply patches" magit-am)
- ("W" "Format patches" magit-patch)
- ("X" "Reset" magit-reset)]
- [("y" "Show Refs" magit-show-refs)
- ("Y" "Cherries" magit-cherry)
- ("z" "Stash" magit-stash)
- ("!" "Run" magit-run)
- ("%" "Worktree" magit-worktree)]]
- ["Applying changes"
- :if-derived magit-mode
- [("a" "Apply" magit-apply)
- ("v" "Reverse" magit-reverse)
- ("k" "Discard" magit-discard)]
- [("s" "Stage" magit-stage)
- ("u" "Unstage" magit-unstage)]
- [("S" "Stage all" magit-stage-modified)
- ("U" "Unstage all" magit-unstage-all)]]
- ["Essential commands"
- :if-derived magit-mode
- ("g" " refresh current buffer" magit-refresh)
- ("<tab>" " toggle section at point" magit-section-toggle)
- ("<return>" "visit thing at point" magit-visit-thing)
- ("C-h m" " show all key bindings" describe-mode)])
-
-;;; Git Popup
-
-(defcustom magit-shell-command-verbose-prompt t
- "Whether to show the working directory when reading a command.
-This affects `magit-git-command', `magit-git-command-topdir',
-`magit-shell-command', and `magit-shell-command-topdir'."
- :package-version '(magit . "2.11.0")
- :group 'magit-commands
- :type 'boolean)
-
-(defvar magit-git-command-history nil)
-
-;;;###autoload (autoload 'magit-run "magit" nil t)
-(transient-define-prefix magit-run ()
- "Run git or another command, or launch a graphical utility."
-
-
- [["Run git subcommand"
- ("!" "in repository root" magit-git-command-topdir)
- ("p" "in working directory" magit-git-command)]
- ["Run shell command"
- ("s" "in repository root" magit-shell-command-topdir)
- ("S" "in working directory" magit-shell-command)]
- ["Launch"
- ("k" "gitk" magit-run-gitk)
- ("a" "gitk --all" magit-run-gitk-all)
- ("b" "gitk --branches" magit-run-gitk-branches)
- ("g" "git gui" magit-run-git-gui)]])
-
-;;;###autoload
-(defun magit-git-command (command)
- "Execute COMMAND asynchronously; display output.
-
-Interactively, prompt for COMMAND in the minibuffer. \"git \" is
-used as initial input, but can be deleted to run another command.
-
-With a prefix argument COMMAND is run in the top-level directory
-of the current working tree, otherwise in `default-directory'."
- (interactive (list (magit-read-shell-command nil "git ")))
- (magit--shell-command command))
-
-;;;###autoload
-(defun magit-git-command-topdir (command)
- "Execute COMMAND asynchronously; display output.
-
-Interactively, prompt for COMMAND in the minibuffer. \"git \" is
-used as initial input, but can be deleted to run another command.
-
-COMMAND is run in the top-level directory of the current
-working tree."
- (interactive (list (magit-read-shell-command t "git ")))
- (magit--shell-command command (magit-toplevel)))
-
-;;;###autoload
-(defun magit-shell-command (command)
- "Execute COMMAND asynchronously; display output.
-
-Interactively, prompt for COMMAND in the minibuffer. With a
-prefix argument COMMAND is run in the top-level directory of
-the current working tree, otherwise in `default-directory'."
- (interactive (list (magit-read-shell-command)))
- (magit--shell-command command))
-
-;;;###autoload
-(defun magit-shell-command-topdir (command)
- "Execute COMMAND asynchronously; display output.
-
-Interactively, prompt for COMMAND in the minibuffer. COMMAND
-is run in the top-level directory of the current working tree."
- (interactive (list (magit-read-shell-command t)))
- (magit--shell-command command (magit-toplevel)))
-
-(defun magit--shell-command (command &optional directory)
- (let ((default-directory (or directory default-directory))
- (process-environment process-environment))
- (push "GIT_PAGER=cat" process-environment)
- (magit-start-process shell-file-name nil
- shell-command-switch command))
- (magit-process-buffer))
-
-(defun magit-read-shell-command (&optional toplevel initial-input)
- (let ((default-directory
- (if (or toplevel current-prefix-arg)
- (or (magit-toplevel)
- (magit--not-inside-repository-error))
- default-directory)))
- (read-shell-command (if magit-shell-command-verbose-prompt
- (format "Async shell command in %s: "
- (abbreviate-file-name default-directory))
- "Async shell command: ")
- initial-input 'magit-git-command-history)))
-
-;;; Font-Lock Keywords
-
-(defconst magit-font-lock-keywords
- (eval-when-compile
- `((,(concat "(\\(magit-define-section-jumper\\)\\_>"
- "[ \t'\(]*"
- "\\(\\(?:\\sw\\|\\s_\\)+\\)?")
- (1 'font-lock-keyword-face)
- (2 'font-lock-function-name-face nil t))
- (,(concat "(" (regexp-opt '("magit-insert-section"
- "magit-section-case"
- "magit-bind-match-strings"
- "magit-with-temp-index"
- "magit-with-blob"
- "magit-with-toplevel") t)
- "\\_>")
- . 1))))
-
-(font-lock-add-keywords 'emacs-lisp-mode magit-font-lock-keywords)
-
-;;; Version
-
-(defvar magit-version 'undefined
- "The version of Magit that you're using.
-Use the function by the same name instead of this variable.")
-
-;;;###autoload
-(defun magit-version (&optional print-dest)
- "Return the version of Magit currently in use.
-If optional argument PRINT-DEST is non-nil, output
-stream (interactively, the echo area, or the current buffer with
-a prefix argument), also print the used versions of Magit, Git,
-and Emacs to it."
- (interactive (list (if current-prefix-arg (current-buffer) t)))
- (let ((magit-git-global-arguments nil)
- (toplib (or load-file-name buffer-file-name))
- debug)
- (unless (and toplib
- (equal (file-name-nondirectory toplib) "magit.el"))
- (setq toplib (locate-library "magit.el")))
- (setq toplib (and toplib (magit--straight-chase-links toplib)))
- (push toplib debug)
- (when toplib
- (let* ((topdir (file-name-directory toplib))
- (gitdir (expand-file-name
- ".git" (file-name-directory
- (directory-file-name topdir))))
- (static (locate-library "magit-version.el" nil (list topdir)))
- (static (and static (magit--straight-chase-links static))))
- (or (progn
- (push 'repo debug)
- (when (and (file-exists-p gitdir)
- ;; It is a repo, but is it the Magit repo?
- (file-exists-p
- (expand-file-name "../lisp/magit.el" gitdir)))
- (push t debug)
- ;; Inside the repo the version file should only exist
- ;; while running make.
- (when (and static (not noninteractive))
- (ignore-errors (delete-file static)))
- (setq magit-version
- (let ((default-directory topdir))
- (magit-git-string "describe"
- "--tags" "--dirty" "--always")))))
- (progn
- (push 'static debug)
- (when (and static (file-exists-p static))
- (push t debug)
- (load-file static)
- magit-version))
- (when (featurep 'package)
- (push 'elpa debug)
- (ignore-errors
- (--when-let (assq 'magit package-alist)
- (push t debug)
- (setq magit-version
- (and (fboundp 'package-desc-version)
- (package-version-join
- (package-desc-version (cadr it))))))))
- (progn
- (push 'dirname debug)
- (let ((dirname (file-name-nondirectory
- (directory-file-name topdir))))
- (when (string-match "\\`magit-\\([0-9].*\\)" dirname)
- (setq magit-version (match-string 1 dirname)))))
- ;; If all else fails, just report the commit hash. It's
- ;; better than nothing and we cannot do better in the case
- ;; of e.g. a shallow clone.
- (progn
- (push 'hash debug)
- ;; Same check as above to see if it's really the Magit repo.
- (when (and (file-exists-p gitdir)
- (file-exists-p
- (expand-file-name "../lisp/magit.el" gitdir)))
- (setq magit-version
- (let ((default-directory topdir))
- (magit-git-string "rev-parse" "HEAD"))))))))
- (if (stringp magit-version)
- (when print-dest
- (princ (format "Magit %s, Git %s, Emacs %s, %s"
- (or magit-version "(unknown)")
- (or (let ((magit-git-debug
- (lambda (err)
- (display-warning '(magit git)
- err :error))))
- (magit-git-version t))
- "(unknown)")
- emacs-version
- system-type)
- print-dest))
- (setq debug (reverse debug))
- (setq magit-version 'error)
- (when magit-version
- (push magit-version debug))
- (unless (equal (getenv "TRAVIS") "true")
- ;; The repository is a sparse clone.
- (message "Cannot determine Magit's version %S" debug)))
- magit-version))
-
-;;; Debugging Tools
-
-(defun magit-debug-git-executable ()
- "Display a buffer with information about `magit-git-executable'.
-See info node `(magit)Debugging Tools' for more information."
- (interactive)
- (with-current-buffer (get-buffer-create "*magit-git-debug*")
- (pop-to-buffer (current-buffer))
- (erase-buffer)
- (insert (concat
- (format "magit-git-executable: %S" magit-git-executable)
- (and (not (file-name-absolute-p magit-git-executable))
- (format " [%S]" (executable-find magit-git-executable)))
- (format " (%s)\n"
- (let* ((errmsg nil)
- (magit-git-debug (lambda (err) (setq errmsg err))))
- (or (magit-git-version t) errmsg)))))
- (insert (format "exec-path: %S\n" exec-path))
- (--when-let (cl-set-difference
- (-filter #'file-exists-p (remq nil (parse-colon-path
- (getenv "PATH"))))
- (-filter #'file-exists-p (remq nil exec-path))
- :test #'file-equal-p)
- (insert (format " entries in PATH, but not in exec-path: %S\n" it)))
- (dolist (execdir exec-path)
- (insert (format " %s (%s)\n" execdir (car (file-attributes execdir))))
- (when (file-directory-p execdir)
- (dolist (exec (directory-files
- execdir t (concat
- "\\`git" (regexp-opt exec-suffixes) "\\'")))
- (insert (format " %s (%s)\n" exec
- (let* ((magit-git-executable exec)
- (errmsg nil)
- (magit-git-debug (lambda (err) (setq errmsg err))))
- (or (magit-git-version t) errmsg)))))))))
-
-;;; Startup Asserts
-
-(defun magit-startup-asserts ()
- (when-let ((val (getenv "GIT_DIR")))
- (setenv "GIT_DIR")
- (message "Magit unset $GIT_DIR (was %S). See \
-https://github.com/magit/magit/wiki/Don't-set-$GIT_DIR-and-alike" val))
- (when-let ((val (getenv "GIT_WORK_TREE")))
- (setenv "GIT_WORK_TREE")
- (message "Magit unset $GIT_WORK_TREE (was %S). See \
-https://github.com/magit/magit/wiki/Don't-set-$GIT_DIR-and-alike" val))
- (let ((version (magit-git-version)))
- (when (and version
- (version< version magit--minimal-git)
- (not (equal (getenv "TRAVIS") "true")))
- (display-warning 'magit (format "\
-Magit requires Git >= %s, you are using %s.
-
-If this comes as a surprise to you, because you do actually have
-a newer version installed, then that probably means that the
-older version happens to appear earlier on the `$PATH'. If you
-always start Emacs from a shell, then that can be fixed in the
-shell's init file. If you start Emacs by clicking on an icon,
-or using some sort of application launcher, then you probably
-have to adjust the environment as seen by graphical interface.
-For X11 something like ~/.xinitrc should work.
-
-If you use Tramp to work inside remote Git repositories, then you
-have to make sure a suitable Git is used on the remote machines
-too.\n" magit--minimal-git version) :error)))
- (when (version< emacs-version magit--minimal-emacs)
- (display-warning 'magit (format "\
-Magit requires Emacs >= %s, you are using %s.
-
-If this comes as a surprise to you, because you do actually have
-a newer version installed, then that probably means that the
-older version happens to appear earlier on the `$PATH'. If you
-always start Emacs from a shell, then that can be fixed in the
-shell's init file. If you start Emacs by clicking on an icon,
-or using some sort of application launcher, then you probably
-have to adjust the environment as seen by graphical interface.
-For X11 something like ~/.xinitrc should work.\n"
- magit--minimal-emacs emacs-version)
- :error)))
-
-;;; Loading Libraries
-
-(provide 'magit)
-
-(cl-eval-when (load eval)
- (require 'magit-status)
- (require 'magit-refs)
- (require 'magit-files)
- (require 'magit-reset)
- (require 'magit-branch)
- (require 'magit-merge)
- (require 'magit-tag)
- (require 'magit-worktree)
- (require 'magit-notes)
- (require 'magit-sequence)
- (require 'magit-commit)
- (require 'magit-remote)
- (require 'magit-clone)
- (require 'magit-fetch)
- (require 'magit-pull)
- (require 'magit-push)
- (require 'magit-bisect)
- (require 'magit-stash)
- (require 'magit-blame)
- (require 'magit-obsolete)
- (require 'magit-submodule)
- (unless (load "magit-autoloads" t t)
- (require 'magit-patch)
- (require 'magit-subtree)
- (require 'magit-ediff)
- (require 'magit-gitignore)
- (require 'magit-extras)
- (require 'git-rebase)
- (require 'magit-imenu)
- (require 'magit-bookmark)))
-
-(eval-after-load 'bookmark
- '(require 'magit-bookmark))
-
-(if after-init-time
- (progn (magit-startup-asserts)
- (magit-version))
- (add-hook 'after-init-hook #'magit-startup-asserts t)
- (add-hook 'after-init-hook #'magit-version t))
-
-;;; magit.el ends here
+++ /dev/null
-This is magit.info, produced by makeinfo version 6.5 from magit.texi.
-
- Copyright (C) 2015-2021 Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
- 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
-
-\1f
-Indirect:
-magit.info-1: 754
-magit.info-2: 301254
-\1f
-Tag Table:
-(Indirect)
-Node: Top\7f754
-Node: Introduction\7f6512
-Node: Installation\7f11235
-Node: Installing from Melpa\7f11565
-Node: Installing from the Git Repository\7f12638
-Node: Post-Installation Tasks\7f15370
-Node: Getting Started\7f16655
-Node: Interface Concepts\7f21895
-Node: Modes and Buffers\7f22256
-Node: Switching Buffers\7f24005
-Node: Naming Buffers\7f28756
-Node: Quitting Windows\7f32063
-Node: Automatic Refreshing of Magit Buffers\7f33809
-Node: Automatic Saving of File-Visiting Buffers\7f36661
-Node: Automatic Reverting of File-Visiting Buffers\7f37846
-Node: Risk of Reverting Automatically\7f42841
-Node: Sections\7f45223
-Node: Section Movement\7f46149
-Node: Section Visibility\7f51059
-Node: Section Hooks\7f57136
-Node: Section Types and Values\7f59543
-Node: Section Options\7f60846
-Node: Transient Commands\7f61318
-Node: Transient Arguments and Buffer Variables\7f62555
-Node: Completion Confirmation and the Selection\7f69573
-Node: Action Confirmation\7f70017
-Node: Completion and Confirmation\7f77833
-Node: The Selection\7f81019
-Node: The hunk-internal region\7f83918
-Node: Support for Completion Frameworks\7f85007
-Node: Additional Completion Options\7f89914
-Node: Running Git\7f90513
-Node: Viewing Git Output\7f90786
-Node: Git Process Status\7f91919
-Node: Running Git Manually\7f92884
-Node: Git Executable\7f95354
-Node: Global Git Arguments\7f97636
-Node: Inspecting\7f98442
-Node: Status Buffer\7f99599
-Node: Status Sections\7f103589
-Node: Status Header Sections\7f109141
-Node: Status Module Sections\7f111771
-Node: Status Options\7f114276
-Node: Repository List\7f115745
-Node: Logging\7f118783
-Node: Refreshing Logs\7f121344
-Node: Log Buffer\7f122790
-Node: Log Margin\7f126646
-Node: Select from Log\7f129825
-Node: Reflog\7f132050
-Node: Cherries\7f133707
-Node: Diffing\7f135555
-Node: Refreshing Diffs\7f138634
-Node: Commands Available in Diffs\7f142213
-Node: Diff Options\7f144749
-Node: Revision Buffer\7f149787
-Node: Ediffing\7f153117
-Node: References Buffer\7f156765
-Node: References Sections\7f167285
-Node: Bisecting\7f168146
-Node: Visiting Files and Blobs\7f169959
-Node: General-Purpose Visit Commands\7f170429
-Node: Visiting Files and Blobs from a Diff\7f171385
-Node: Blaming\7f174844
-Node: Manipulating\7f181185
-Node: Creating Repository\7f181527
-Node: Cloning Repository\7f182082
-Node: Staging and Unstaging\7f187487
-Node: Staging from File-Visiting Buffers\7f191570
-Node: Applying\7f192738
-Node: Committing\7f194631
-Node: Initiating a Commit\7f195214
-Node: Editing Commit Messages\7f198599
-Node: Using the Revision Stack\7f201402
-Node: Commit Pseudo Headers\7f204453
-Node: Commit Mode and Hooks\7f205789
-Node: Commit Message Conventions\7f208727
-Node: Branching\7f210855
-Node: The Two Remotes\7f211081
-Node: Branch Commands\7f213734
-Node: Branch Git Variables\7f226115
-Node: Auxiliary Branch Commands\7f231506
-Node: Merging\7f232624
-Node: Resolving Conflicts\7f236632
-Node: Rebasing\7f241633
-Node: Editing Rebase Sequences\7f246492
-Node: Information About In-Progress Rebase\7f250820
-Ref: Information About In-Progress Rebase-Footnote-1\7f259702
-Node: Cherry Picking\7f260298
-Node: Reverting\7f264629
-Node: Resetting\7f266078
-Node: Stashing\7f267944
-Node: Transferring\7f272645
-Node: Remotes\7f272867
-Node: Remote Commands\7f273019
-Node: Remote Git Variables\7f277100
-Node: Fetching\7f278379
-Node: Pulling\7f280866
-Node: Pushing\7f281912
-Node: Plain Patches\7f285665
-Node: Maildir Patches\7f287156
-Node: Miscellaneous\7f288670
-Node: Tagging\7f288984
-Node: Notes\7f290901
-Node: Submodules\7f293273
-Node: Listing Submodules\7f293491
-Node: Submodule Transient\7f294897
-Node: Subtree\7f297419
-Node: Worktree\7f299395
-Node: Common Commands\7f301254
-Node: Wip Modes\7f303377
-Node: Wip Graph\7f308308
-Node: Legacy Wip Modes\7f310622
-Node: Commands for Buffers Visiting Files\7f313517
-Node: Minor Mode for Buffers Visiting Blobs\7f319139
-Node: Customizing\7f319950
-Node: Per-Repository Configuration\7f321546
-Node: Essential Settings\7f323801
-Node: Safety\7f324146
-Node: Performance\7f325907
-Node: Microsoft Windows Performance\7f333075
-Node: MacOS Performance\7f334266
-Ref: MacOS Performance-Footnote-1\7f335443
-Node: Default Bindings\7f335525
-Node: Plumbing\7f337380
-Node: Calling Git\7f338209
-Node: Getting a Value from Git\7f339734
-Node: Calling Git for Effect\7f342820
-Node: Section Plumbing\7f349342
-Node: Creating Sections\7f349570
-Node: Section Selection\7f353470
-Node: Matching Sections\7f355269
-Node: Refreshing Buffers\7f361242
-Node: Conventions\7f364390
-Node: Theming Faces\7f364582
-Node: FAQ\7f372697
-Node: FAQ - How to ...?\7f373139
-Node: How to pronounce Magit?\7f373552
-Node: How to show git's output?\7f374354
-Node: How to install the gitman info manual?\7f375140
-Node: How to show diffs for gpg-encrypted files?\7f376110
-Node: How does branching and pushing work?\7f376706
-Node: Can Magit be used as ediff-version-control-package?\7f377069
-Node: Should I disable VC?\7f379087
-Node: FAQ - Issues and Errors\7f379705
-Node: Magit is slow\7f380601
-Node: I changed several thousand files at once and now Magit is unusable\7f380815
-Node: I am having problems committing\7f381544
-Node: I am using MS Windows and cannot push with Magit\7f382025
-Node: I am using OS X and SOMETHING works in shell but not in Magit\7f382642
-Node: Expanding a file to show the diff causes it to disappear\7f383473
-Node: Point is wrong in the COMMIT_EDITMSG buffer\7f384054
-Node: The mode-line information isn't always up-to-date\7f385100
-Node: A branch and tag sharing the same name breaks SOMETHING\7f386163
-Node: My Git hooks work on the command-line but not inside Magit\7f387049
-Node: git-commit-mode isn't used when committing from the command-line\7f387895
-Node: Point ends up inside invisible text when jumping to a file-visiting buffer\7f390166
-Node: Debugging Tools\7f390964
-Node: Keystroke Index\7f393143
-Node: Command Index\7f427176
-Node: Function Index\7f464242
-Node: Variable Index\7f480513
-\1f
-End Tag Table
-
-\1f
-Local Variables:
-coding: utf-8
-End:
+++ /dev/null
-This is magit.info, produced by makeinfo version 6.5 from magit.texi.
-
- Copyright (C) 2015-2021 Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
- 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
-
-\1f
-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 2.90.1 (v2.90.1-1133-g2fb44690b+1).
-
- Copyright (C) 2015-2021 Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
- You can redistribute this document and/or modify it under the terms
- of the GNU General Public License as published by the Free Software
- Foundation, either version 3 of the License, or (at your option)
- any later version.
-
- This document is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
-* Menu:
-
-* Introduction::
-* Installation::
-* Getting Started::
-* Interface Concepts::
-* Inspecting::
-* Manipulating::
-* Transferring::
-* Miscellaneous::
-* Customizing::
-* Plumbing::
-* FAQ::
-* Debugging Tools::
-* Keystroke Index::
-* Command Index::
-* Function Index::
-* Variable Index::
-
-— The Detailed Node Listing —
-
-Installation
-
-* Installing from Melpa::
-* Installing from the Git Repository::
-* Post-Installation Tasks::
-
-Interface Concepts
-
-* Modes and Buffers::
-* Sections::
-* Transient Commands::
-* Transient Arguments and Buffer Variables::
-* Completion, Confirmation and the Selection: Completion Confirmation and the Selection.
-* Running Git::
-
-Modes and Buffers
-
-* Switching Buffers::
-* Naming Buffers::
-* Quitting Windows::
-* Automatic Refreshing of Magit Buffers::
-* Automatic Saving of File-Visiting Buffers::
-* Automatic Reverting of File-Visiting Buffers::
-
-
-Sections
-
-* Section Movement::
-* Section Visibility::
-* Section Hooks::
-* Section Types and Values::
-* Section Options::
-
-
-Completion, Confirmation and the Selection
-
-* Action Confirmation::
-* Completion and Confirmation::
-* The Selection::
-* The hunk-internal region::
-* Support for Completion Frameworks::
-* Additional Completion Options::
-
-
-Running Git
-
-* Viewing Git Output::
-* Git Process Status::
-* Running Git Manually::
-* Git Executable::
-* Global Git Arguments::
-
-
-Inspecting
-
-* Status Buffer::
-* Repository List::
-* Logging::
-* Diffing::
-* Ediffing::
-* References Buffer::
-* Bisecting::
-* Visiting Files and Blobs::
-* Blaming::
-
-Status Buffer
-
-* Status Sections::
-* Status Header Sections::
-* Status Module Sections::
-* Status Options::
-
-
-Logging
-
-* Refreshing Logs::
-* Log Buffer::
-* Log Margin::
-* Select from Log::
-* Reflog::
-* Cherries::
-
-
-Diffing
-
-* Refreshing Diffs::
-* Commands Available in Diffs::
-* Diff Options::
-* Revision Buffer::
-
-
-References Buffer
-
-* References Sections::
-
-
-Visiting Files and Blobs
-
-* General-Purpose Visit Commands::
-* Visiting Files and Blobs from a Diff::
-
-
-Manipulating
-
-* Creating Repository::
-* Cloning Repository::
-* Staging and Unstaging::
-* Applying::
-* Committing::
-* Branching::
-* Merging::
-* Resolving Conflicts::
-* Rebasing::
-* Cherry Picking::
-* Resetting::
-* Stashing::
-
-Staging and Unstaging
-
-* Staging from File-Visiting Buffers::
-
-
-Committing
-
-* Initiating a Commit::
-* Editing Commit Messages::
-
-
-Branching
-
-* The Two Remotes::
-* Branch Commands::
-* Branch Git Variables::
-* Auxiliary Branch Commands::
-
-
-Rebasing
-
-* Editing Rebase Sequences::
-* Information About In-Progress Rebase::
-
-
-Cherry Picking
-
-* Reverting::
-
-
-Transferring
-
-* Remotes::
-* Fetching::
-* Pulling::
-* Pushing::
-* Plain Patches::
-* Maildir Patches::
-
-Remotes
-
-* Remote Commands::
-* Remote Git Variables::
-
-
-Miscellaneous
-
-* Tagging::
-* Notes::
-* Submodules::
-* Subtree::
-* Worktree::
-* Common Commands::
-* Wip Modes::
-* Commands for Buffers Visiting Files::
-* Minor Mode for Buffers Visiting Blobs::
-
-Submodules
-
-* Listing Submodules::
-* Submodule Transient::
-
-
-Wip Modes
-
-* Wip Graph::
-* Legacy Wip Modes::
-
-
-Customizing
-
-* Per-Repository Configuration::
-* Essential Settings::
-
-Essential Settings
-
-* Safety::
-* Performance::
-* Default Bindings::
-
-
-Plumbing
-
-* Calling Git::
-* Section Plumbing::
-* Refreshing Buffers::
-* Conventions::
-
-Calling Git
-
-* Getting a Value from Git::
-* Calling Git for Effect::
-
-
-Section Plumbing
-
-* Creating Sections::
-* Section Selection::
-* Matching Sections::
-
-
-Conventions
-
-* Theming Faces::
-
-
-FAQ
-
-* FAQ - How to ...?::
-* FAQ - Issues and Errors::
-
-FAQ - How to ...?
-
-* How to pronounce Magit?::
-* How to show git's output?::
-* How to install the gitman info manual?::
-* How to show diffs for gpg-encrypted files?::
-* How does branching and pushing work?::
-* Can Magit be used as ediff-version-control-package?::
-* Should I disable VC?::
-
-
-FAQ - Issues and Errors
-
-* Magit is slow::
-* I changed several thousand files at once and now Magit is unusable::
-* I am having problems committing::
-* I am using MS Windows and cannot push with Magit::
-* I am using OS X and SOMETHING works in shell, but not in Magit: I am using OS X and SOMETHING works in shell but not in Magit.
-* Expanding a file to show the diff causes it to disappear::
-* Point is wrong in the COMMIT_EDITMSG buffer::
-* The mode-line information isn't always up-to-date::
-* A branch and tag sharing the same name breaks SOMETHING::
-* My Git hooks work on the command-line but not inside Magit::
-* git-commit-mode isn't used when committing from the command-line::
-* Point ends up inside invisible text when jumping to a file-visiting buffer::
-
-
-
-\1f
-File: magit.info, Node: Introduction, Next: Installation, Prev: Top, Up: Top
-
-1 Introduction
-**************
-
-Magit is an interface to the version control system Git, implemented as
-an Emacs package. Magit aspires to be a complete Git porcelain. While
-we cannot (yet) claim that Magit wraps and improves upon each and every
-Git command, it is complete enough to allow even experienced Git users
-to perform almost all of their daily version control tasks directly from
-within Emacs. While many fine Git clients exist, only Magit and Git
-itself deserve to be called porcelains.
-
- Staging and otherwise applying changes is one of the most important
-features in a Git porcelain and here Magit outshines anything else,
-including Git itself. Git’s own staging interface (‘git add --patch’)
-is so cumbersome that many users only use it in exceptional cases. In
-Magit staging a hunk or even just part of a hunk is as trivial as
-staging all changes made to a file.
-
- The most visible part of Magit’s interface is the status buffer,
-which displays information about the current repository. Its content is
-created by running several Git commands and making their output
-actionable. Among other things, it displays information about the
-current branch, lists unpulled and unpushed changes and contains
-sections displaying the staged and unstaged changes. That might sound
-noisy, but, since sections are collapsible, it’s not.
-
- To stage or unstage a change one places the cursor on the change and
-then types ‘s’ or ‘u’. The change can be a file or a hunk, or when the
-region is active (i.e. when there is a selection) several files or
-hunks, or even just part of a hunk. The change or changes that these
-commands - and many others - would act on are highlighted.
-
- Magit also implements several other "apply variants" in addition to
-staging and unstaging. One can discard or reverse a change, or apply it
-to the working tree. Git’s own porcelain only supports this for staging
-and unstaging and you would have to do something like ‘git diff ... |
-??? | git apply ...’ to discard, revert, or apply a single hunk on the
-command line. In fact that’s exactly what Magit does internally (which
-is what lead to the term "apply variants").
-
- Magit isn’t just for Git experts, but it does assume some prior
-experience with Git as well as Emacs. That being said, many users have
-reported that using Magit was what finally taught them what Git is
-capable of and how to use it to its fullest. Other users wished they
-had switched to Emacs sooner so that they would have gotten their hands
-on Magit earlier.
-
- While one has to know the basic features of Emacs to be able to make
-full use of Magit, acquiring just enough Emacs skills doesn’t take long
-and is worth it, even for users who prefer other editors. Vim users are
-advised to give Evil (https://bitbucket.org/lyro/evil/wiki/Home), the
-"Extensible VI Layer for Emacs", and Spacemacs
-(https://github.com/syl20bnr/spacemacs), an "Emacs starter-kit focused
-on Evil" a try.
-
- Magit provides a consistent and efficient Git porcelain. After a
-short learning period, you will be able to perform most of your daily
-version control tasks faster than you would on the command line. You
-will likely also start using features that seemed too daunting in the
-past.
-
- Magit fully embraces Git. It exposes many advanced features using a
-simple but flexible interface instead of only wrapping the trivial ones
-like many GUI clients do. Of course Magit supports logging, cloning,
-pushing, and other commands that usually don’t fail in spectacular ways;
-but it also supports tasks that often cannot be completed in a single
-step. Magit fully supports tasks such as merging, rebasing,
-cherry-picking, reverting, and blaming by not only providing a command
-to initiate these tasks but also by displaying context sensitive
-information along the way and providing commands that are useful for
-resolving conflicts and resuming the sequence after doing so.
-
- Magit wraps and in many cases improves upon at least the following
-Git porcelain commands: ‘add’, ‘am’, ‘bisect’, ‘blame’, ‘branch’,
-‘checkout’, ‘cherry’, ‘cherry-pick’, ‘clean’, ‘clone’, ‘commit’,
-‘config’, ‘describe’, ‘diff’, ‘fetch’, ‘format-patch’, ‘init’, ‘log’,
-‘merge’, ‘merge-tree’, ‘mv’, ‘notes’, ‘pull’, ‘rebase’, ‘reflog’,
-‘remote’, ‘request-pull’, ‘reset’, ‘revert’, ‘rm’, ‘show’, ‘stash’,
-‘submodule’, ‘subtree’, ‘tag’, and ‘worktree.’ Many more Magit porcelain
-commands are implemented on top of Git plumbing commands.
-
-\1f
-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::
-
-\1f
-File: magit.info, Node: Installing from Melpa, Next: Installing from the Git Repository, Up: Installation
-
-2.1 Installing from Melpa
-=========================
-
-Magit is available from Melpa and Melpa-Stable. If you haven’t used
-Emacs’ package manager before, then it is high time you familiarize
-yourself with it by reading the documentation in the Emacs manual, see
-*note (emacs)Packages::. Then add one of the archives to
-‘package-archives’:
-
- • To use Melpa:
-
- (require 'package)
- (add-to-list 'package-archives
- '("melpa" . "http://melpa.org/packages/") t)
-
- • To use Melpa-Stable:
-
- (require 'package)
- (add-to-list 'package-archives
- '("melpa-stable" . "http://stable.melpa.org/packages/") t)
-
- Once you have added your preferred archive, you need to update the
-local package list using:
-
- M-x package-refresh-contents RET
-
- Once you have done that, you can install Magit and its dependencies
-using:
-
- M-x package-install RET magit RET
-
- Now see *note Post-Installation Tasks::.
-
-\1f
-File: magit.info, Node: Installing from the Git Repository, Next: Post-Installation Tasks, Prev: Installing from Melpa, Up: Installation
-
-2.2 Installing from the Git Repository
-======================================
-
-Magit depends on the ‘dash’, ‘transient’ and ‘with-editor’ libraries
-which are available from Melpa and Melpa-Stable. Install them using
-‘M-x package-install RET <package> RET’. Of course you may also install
-them manually from their repository.
-
- Then clone the Magit repository:
-
- $ git clone https://github.com/magit/magit.git ~/.emacs.d/site-lisp/magit
- $ cd ~/.emacs.d/site-lisp/magit
-
- Then compile the libraries and generate the info manuals:
-
- $ make
-
- If you haven’t installed ‘dash’, ‘transient’ and ‘with-editor’ from
-Melpa or at ‘/path/to/magit/../<package>’, then you have to tell ‘make’
-where to find them. To do so create the file ‘/path/to/magit/config.mk’
-with the following content before running ‘make’:
-
- LOAD_PATH = -L ~/.emacs.d/site-lisp/magit/lisp
- LOAD_PATH += -L ~/.emacs.d/site-lisp/dash
- LOAD_PATH += -L ~/.emacs.d/site-lisp/transient/lisp
- LOAD_PATH += -L ~/.emacs.d/site-lisp/with-editor
-
- Finally add this to your init file:
-
- (add-to-list 'load-path "~/.emacs.d/site-lisp/magit/lisp")
- (require 'magit)
-
- (with-eval-after-load 'info
- (info-initialize)
- (add-to-list 'Info-directory-list
- "~/.emacs.d/site-lisp/magit/Documentation/"))
-
- Of course if you installed the dependencies manually as well, then
-you have to tell Emacs about them too, by prefixing the above with:
-
- (add-to-list 'load-path "~/.emacs.d/site-lisp/dash")
- (add-to-list 'load-path "~/.emacs.d/site-lisp/transient/lisp")
- (add-to-list 'load-path "~/.emacs.d/site-lisp/with-editor")
-
- Note that you have to add the ‘lisp’ subdirectory to the ‘load-path’,
-not the top-level of the repository, and that elements of ‘load-path’
-should not end with a slash, while those of ‘Info-directory-list’
-should.
-
- Instead of requiring the feature ‘magit’, you could load just the
-autoload definitions, by loading the file ‘magit-autoloads.el’.
-
- (load "/path/to/magit/lisp/magit-autoloads")
-
- Instead of running Magit directly from the repository by adding that
-to the ‘load-path’, you might want to instead install it in some other
-directory using ‘sudo make install’ and setting ‘load-path’ accordingly.
-
- To update Magit use:
-
- $ git pull
- $ make
-
- At times it might be necessary to run ‘make clean all’ instead.
-
- To view all available targets use ‘make help’.
-
- Now see *note Post-Installation Tasks::.
-
-\1f
-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 <https://magit.vc/donations>.
-for various donation options.
-
-\1f
-File: magit.info, Node: Getting Started, Next: Interface Concepts, Prev: Installation, Up: Top
-
-3 Getting Started
-*****************
-
-This short tutorial describes the most essential features that many
-Magitians use on a daily basis. It only scratches the surface but
-should be enough to get you started.
-
- IMPORTANT: It is safest if you clone some repository just for this
-tutorial. Alternatively you can use an existing local repository, but
-if you do that, then you should commit all uncommitted changes before
-proceeding.
-
- Type ‘C-x g’ to display information about the current Git repository
-in a dedicated buffer, called the status buffer.
-
- Most Magit commands are commonly invoked from the status buffer. It
-can be considered the primary interface for interacting with Git using
-Magit. Many other Magit buffers may exist at a given time, but they are
-often created from this buffer.
-
- Depending on what state your repository is in, this buffer may
-contain sections titled "Staged changes", "Unstaged changes", "Unmerged
-into origin/master", "Unpushed to origin/master", and many others.
-
- Since we are starting from a safe state, which you can easily return
-to (by doing a ‘git reset --hard PRE-MAGIT-STATE’), there currently are
-no staged or unstaged changes. Edit some files and save the changes.
-Then go back to the status buffer, while at the same time refreshing it,
-by typing ‘C-x g’. (When the status buffer, or any Magit buffer for
-that matter, is the current buffer, then you can also use just ‘g’ to
-refresh it).
-
- Move between sections using ‘p’ and ‘n’. Note that the bodies of
-some sections are hidden. Type ‘TAB’ to expand or collapse the section
-at point. You can also use ‘C-tab’ to cycle the visibility of the
-current section and its children. Move to a file section inside the
-section named "Unstaged changes" and type ‘s’ to stage the changes you
-have made to that file. That file now appears under "Staged changes".
-
- Magit can stage and unstage individual hunks, not just complete
-files. Move to the file you have just staged, expand it using ‘TAB’,
-move to one of the hunks using ‘n’, and unstage just that by typing ‘u’.
-Note how the staging (‘s’) and unstaging (‘u’) commands operate on the
-change at point. Many other commands behave the same way.
-
- You can also un-/stage just part of a hunk. Inside the body of a
-hunk section (move there using ‘C-n’), set the mark using ‘C-SPC’ and
-move down until some added and/or removed lines fall inside the region
-but not all of them. Again type ‘s’ to stage.
-
- It is also possible to un-/stage multiple files at once. Move to a
-file section, type ‘C-SPC’, move to the next file using ‘n’, and then
-‘s’ to stage both files. Note that both the mark and point have to be
-on the headings of sibling sections for this to work. If the region
-looks like it does in other buffers, then it doesn’t select Magit
-sections that can be acted on as a unit.
-
- And then of course you want to commit your changes. Type ‘c’. This
-shows the available commit commands and arguments in a buffer at the
-bottom of the frame. Each command and argument is prefixed with the key
-that invokes/sets it. Do not worry about this for now. We want to
-create a "normal" commit, which is done by typing ‘c’ again.
-
- Now two new buffers appear. One is for writing the commit message,
-the other shows a diff with the changes that you are about to commit.
-Write a message and then type ‘C-c C-c’ to actually create the commit.
-
- You probably don’t want to push the commit you just created because
-you just committed some random changes, but if that is not the case you
-could push it by typing ‘P’ to show all the available push commands and
-arguments and then ‘p’ to push to a branch with the same name as the
-local branch onto the remote configured as the push-remote. (If the
-push-remote is not configured yet, then you would first be prompted for
-the remote to push to.)
-
- So far we have mentioned the commit, push, and log menu commands.
-These are probably among the menus you will be using the most, but many
-others exist. To show a menu that lists all other menus (as well as the
-various apply commands and some other essential commands), type ‘h’.
-Try a few. (Such menus are also called "transient prefix commands" or
-just "transients".)
-
- The key bindings in that menu correspond to the bindings in Magit
-buffers, including but not limited to the status buffer. So you could
-type ‘h d’ to bring up the diff menu, but once you remember that "d"
-stands for "diff", you would usually do so by just typing ‘d’. But this
-"prefix of prefixes" is useful even once you have memorized all the
-bindings, as it can provide easy access to Magit commands from non-Magit
-buffers. The global binding is ‘C-x M-g’.
-
- In file visiting buffers ‘C-c M-g’ brings up a similar menu featuring
-commands that act on just the visited file, see *note Commands for
-Buffers Visiting Files::.
-
- It is not necessary that you do so now, but if you stick with Magit,
-then it is highly recommended that you read the next section too.
-
-\1f
-File: magit.info, Node: Interface Concepts, Next: Inspecting, Prev: Getting Started, Up: Top
-
-4 Interface Concepts
-********************
-
-* Menu:
-
-* Modes and Buffers::
-* Sections::
-* Transient Commands::
-* Transient Arguments and Buffer Variables::
-* Completion, Confirmation and the Selection: Completion Confirmation and the Selection.
-* Running Git::
-
-\1f
-File: magit.info, Node: Modes and Buffers, Next: Sections, Up: Interface Concepts
-
-4.1 Modes and Buffers
-=====================
-
-Magit provides several major-modes. For each of these modes there
-usually exists only one buffer per repository. Separate modes and thus
-buffers exist for commits, diffs, logs, and some other things.
-
- Besides these special purpose buffers, there also exists an overview
-buffer, called the *status buffer*. It’s usually from this buffer that
-the user invokes Git commands, or creates or visits other buffers.
-
- In this manual we often speak about "Magit buffers". By that we mean
-buffers whose major-modes derive from ‘magit-mode’.
-
-‘M-x magit-toggle-buffer-lock’ (‘magit-toggle-buffer-lock’)
-
- This command locks the current buffer to its value or if the buffer
- is already locked, then it unlocks it.
-
- Locking a buffer to its value prevents it from being reused to
- display another value. The name of a locked buffer contains its
- value, which allows telling it apart from other locked buffers and
- the unlocked buffer.
-
- Not all Magit buffers can be locked to their values; for example,
- it wouldn’t make sense to lock a status buffer.
-
- There can only be a single unlocked buffer using a certain
- major-mode per repository. So when a buffer is being unlocked and
- another unlocked buffer already exists for that mode and
- repository, then the former buffer is instead deleted and the
- latter is displayed in its place.
-
-* Menu:
-
-* Switching Buffers::
-* Naming Buffers::
-* Quitting Windows::
-* Automatic Refreshing of Magit Buffers::
-* Automatic Saving of File-Visiting Buffers::
-* Automatic Reverting of File-Visiting Buffers::
-
-\1f
-File: magit.info, Node: Switching Buffers, Next: Naming Buffers, Up: Modes and Buffers
-
-4.1.1 Switching Buffers
------------------------
-
- -- Function: magit-display-buffer buffer &optional display-function
-
- This function is a wrapper around ‘display-buffer’ and is used to
- display any Magit buffer. It displays BUFFER in some window and,
- unlike ‘display-buffer’, also selects that window, provided
- ‘magit-display-buffer-noselect’ is ‘nil’. It also runs the hooks
- mentioned below.
-
- If optional DISPLAY-FUNCTION is non-nil, then that is used to
- display the buffer. Usually that is ‘nil’ and the function
- specified by ‘magit-display-buffer-function’ is used.
-
- -- Variable: magit-display-buffer-noselect
-
- When this is non-nil, then ‘magit-display-buffer’ only displays the
- buffer but forgoes also selecting the window. This variable should
- not be set globally, it is only intended to be let-bound, by code
- that automatically updates "the other window". This is used for
- example when the revision buffer is updated when you move inside
- the log buffer.
-
- -- User Option: magit-display-buffer-function
-
- The function specified here is called by ‘magit-display-buffer’
- with one argument, a buffer, to actually display that buffer. This
- function should call ‘display-buffer’ with that buffer as first and
- a list of display actions as second argument.
-
- Magit provides several functions, listed below, that are suitable
- values for this option. If you want to use different rules, then a
- good way of doing that is to start with a copy of one of these
- functions and then adjust it to your needs.
-
- Instead of using a wrapper around ‘display-buffer’, that function
- itself can be used here, in which case the display actions have to
- be specified by adding them to ‘display-buffer-alist’ instead.
-
- To learn about display actions, see *note (elisp)Choosing Window::.
-
- -- Function: magit-display-buffer-traditional buffer
-
- This function is the current default value of the option
- ‘magit-display-buffer-function’. Before that option and this
- function were added, the behavior was hard-coded in many places all
- over the code base but now all the rules are contained in this one
- function (except for the "noselect" special case mentioned above).
-
- -- Function: magit-display-buffer-same-window-except-diff-v1
-
- This function displays most buffers in the currently selected
- window. If a buffer’s mode derives from ‘magit-diff-mode’ or
- ‘magit-process-mode’, it is displayed in another window.
-
- -- Function: magit-display-buffer-fullframe-status-v1
-
- This function fills the entire frame when displaying a status
- buffer. Otherwise, it behaves like
- ‘magit-display-buffer-traditional’.
-
- -- Function: magit-display-buffer-fullframe-status-topleft-v1
-
- This function fills the entire frame when displaying a status
- buffer. It behaves like ‘magit-display-buffer-fullframe-status-v1’
- except that it displays buffers that derive from ‘magit-diff-mode’
- or ‘magit-process-mode’ to the top or left of the current buffer
- rather than to the bottom or right. As a result, Magit buffers
- tend to pop up on the same side as they would if
- ‘magit-display-buffer-traditional’ were in use.
-
- -- Function: magit-display-buffer-fullcolumn-most-v1
-
- This function displays most buffers so that they fill the entire
- height of the frame. However, the buffer is displayed in another
- window if (1) the buffer’s mode derives from ‘magit-process-mode’,
- or (2) the buffer’s mode derives from ‘magit-diff-mode’, provided
- that the mode of the current buffer derives from ‘magit-log-mode’
- or ‘magit-cherry-mode’.
-
- -- User Option: magit-pre-display-buffer-hook
-
- This hook is run by ‘magit-display-buffer’ before displaying the
- buffer.
-
- -- Function: magit-save-window-configuration
-
- This function saves the current window configuration. Later when
- the buffer is buried, it may be restored by
- ‘magit-restore-window-configuration’.
-
- -- User Option: magit-post-display-buffer-hook
-
- This hook is run by ‘magit-display-buffer’ after displaying the
- buffer.
-
- -- Function: magit-maybe-set-dedicated
-
- This function remembers if a new window had to be created to
- display the buffer, or whether an existing window was reused. This
- information is later used by ‘magit-mode-quit-window’, to determine
- whether the window should be deleted when its last Magit buffer is
- buried.
-
-\1f
-File: magit.info, Node: Naming Buffers, Next: Quitting Windows, Prev: Switching Buffers, Up: Modes and Buffers
-
-4.1.2 Naming Buffers
---------------------
-
- -- User Option: magit-generate-buffer-name-function
-
- The function used to generate the names of Magit buffers.
-
- Such a function should take the options
- ‘magit-uniquify-buffer-names’ as well as ‘magit-buffer-name-format’
- into account. If it doesn’t, then should be clearly stated in the
- doc-string. And if it supports %-sequences beyond those mentioned
- in the doc-string of the option ‘magit-buffer-name-format’, then
- its own doc-string should describe the additions.
-
- -- Function: magit-generate-buffer-name-default-function mode
-
- This function returns a buffer name suitable for a buffer whose
- major-mode is MODE and which shows information about the repository
- in which ‘default-directory’ is located.
-
- This function uses ‘magit-buffer-name-format’ and supporting all of
- the %-sequences mentioned the documentation of that option. It
- also respects the option ‘magit-uniquify-buffer-names’.
-
- -- User Option: magit-buffer-name-format
-
- The format string used to name Magit buffers.
-
- At least the following %-sequences are supported:
-
- • ‘%m’
-
- The name of the major-mode, but with the ‘-mode’ suffix
- removed.
-
- • ‘%M’
-
- Like ‘%m’ but abbreviate ‘magit-status-mode’ as ‘magit’.
-
- • ‘%v’
-
- The value the buffer is locked to, in parentheses, or an empty
- string if the buffer is not locked to a value.
-
- • ‘%V’
-
- Like ‘%v’, but the string is prefixed with a space, unless it
- is an empty string.
-
- • ‘%t’
-
- The top-level directory of the working tree of the repository,
- or if ‘magit-uniquify-buffer-names’ is non-nil an abbreviation
- of that.
-
- • ‘%x’
-
- If ‘magit-uniquify-buffer-names’ is nil "*", otherwise the
- empty string. Due to limitations of the ‘uniquify’ package,
- buffer names must end with the path.
-
- • ‘%T’
-
- Obsolete, use "%t%x" instead. Like ‘%t’, but append an
- asterisk if and only if ‘magit-uniquify-buffer-names’ is nil.
-
- The value should always contain ‘%m’ or ‘%M’, ‘%v’ or ‘%V’, and
- ‘%t’ (or the obsolete ‘%T’). If ‘magit-uniquify-buffer-names’ is
- non-nil, then the value must end with ‘%t’ or ‘%t%x’ (or the
- obsolete ‘%T’). See issue #2841.
-
- -- User Option: magit-uniquify-buffer-names
-
- This option controls whether the names of Magit buffers are
- uniquified. If the names are not being uniquified, then they
- contain the full path of the top-level of the working tree of the
- corresponding repository. If they are being uniquified, then they
- end with the basename of the top-level, or if that would conflict
- with the name used for other buffers, then the names of all these
- buffers are adjusted until they no longer conflict.
-
- This is done using the ‘uniquify’ package; customize its options to
- control how buffer names are uniquified.
-
-\1f
-File: magit.info, Node: Quitting Windows, Next: Automatic Refreshing of Magit Buffers, Prev: Naming Buffers, Up: Modes and Buffers
-
-4.1.3 Quitting Windows
-----------------------
-
-‘q’ (‘magit-mode-bury-buffer’)
-
- This command buries the current Magit buffer.
-
- With a prefix argument, it instead kills the buffer. With a double
- prefix argument, also kills all other Magit buffers associated with
- the current project.
-
- -- User Option: magit-bury-buffer-function
-
- The function used to actually bury or kill the current buffer.
-
- ‘magit-mode-bury-buffer’ calls this function with one argument. If
- the argument is non-nil, then the function has to kill the current
- buffer. Otherwise it has to bury it alive. The default value
- currently is ‘magit-restore-window-configuration’.
-
- -- Function: magit-restore-window-configuration kill-buffer
-
- Bury or kill the current buffer using ‘quit-window’, which is
- called with KILL-BUFFER as first and the selected window as second
- argument.
-
- Then restore the window configuration that existed right before the
- current buffer was displayed in the selected frame. Unfortunately
- that also means that point gets adjusted in all the buffers, which
- are being displayed in the selected frame.
-
- -- Function: magit-mode-quit-window kill-buffer
-
- Bury or kill the current buffer using ‘quit-window’, which is
- called with KILL-BUFFER as first and the selected window as second
- argument.
-
- Then, if the window was originally created to display a Magit
- buffer and the buried buffer was the last remaining Magit buffer
- that was ever displayed in the window, then that is deleted.
-
-\1f
-File: magit.info, Node: Automatic Refreshing of Magit Buffers, Next: Automatic Saving of File-Visiting Buffers, Prev: Quitting Windows, Up: Modes and Buffers
-
-4.1.4 Automatic Refreshing of Magit Buffers
--------------------------------------------
-
-After running a command which may change the state of the current
-repository, the current Magit buffer and the corresponding status buffer
-are refreshed. The status buffer can be automatically refreshed
-whenever a buffer is saved to a file inside the respective repository by
-adding a hook, like so:
-
- (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.
-
-\1f
-File: magit.info, Node: Automatic Saving of File-Visiting Buffers, Next: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Refreshing of Magit Buffers, Up: Modes and Buffers
-
-4.1.5 Automatic Saving of File-Visiting Buffers
------------------------------------------------
-
-File-visiting buffers are by default saved at certain points in time.
-This doesn’t guarantee that Magit buffers are always up-to-date, but,
-provided one only edits files by editing them in Emacs and uses only
-Magit to interact with Git, one can be fairly confident. When in doubt
-or after outside changes, type ‘g’ (‘magit-refresh’) to save and refresh
-explicitly.
-
- -- User Option: magit-save-repository-buffers
-
- This option controls whether file-visiting buffers are saved before
- certain events.
-
- If this is non-nil then all modified file-visiting buffers
- belonging to the current repository may be saved before running
- commands, before creating new Magit buffers, and before explicitly
- refreshing such buffers. If this is ‘dontask’ then this is done
- without user intervention. If it is ‘t’ then the user has to
- confirm each save.
-
-\1f
-File: magit.info, Node: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Saving of File-Visiting Buffers, Up: Modes and Buffers
-
-4.1.6 Automatic Reverting of File-Visiting Buffers
---------------------------------------------------
-
-By default Magit automatically reverts buffers that are visiting files
-that are being tracked in a Git repository, after they have changed on
-disk. When using Magit one often changes files on disk by running Git,
-i.e. "outside Emacs", making this a rather important feature.
-
- For example, if you discard a change in the status buffer, then that
-is done by running ‘git apply --reverse ...’, and Emacs considers the
-file to have "changed on disk". If Magit did not automatically revert
-the buffer, then you would have to type ‘M-x revert-buffer RET RET’ in
-the visiting buffer before you could continue making changes.
-
- -- User Option: magit-auto-revert-mode
-
- When this mode is enabled, then buffers that visit tracked files
- are automatically reverted after the visited files change on disk.
-
- -- User Option: global-auto-revert-mode
-
- When this mode is enabled, then any file-visiting buffer is
- automatically reverted after the visited file changes on disk.
-
- If you like buffers that visit tracked files to be automatically
- reverted, then you might also like any buffer to be reverted, not
- just those visiting tracked files. If that is the case, then
- enable this mode _instead of_ ‘magit-auto-revert-mode’.
-
- -- User Option: magit-auto-revert-immediately
-
- This option controls whether Magit reverts buffers immediately.
-
- If this is non-nil and either ‘global-auto-revert-mode’ or
- ‘magit-auto-revert-mode’ is enabled, then Magit immediately reverts
- buffers by explicitly calling ‘auto-revert-buffers’ after running
- Git for side-effects.
-
- If ‘auto-revert-use-notify’ is non-nil (and file notifications are
- actually supported), then ‘magit-auto-revert-immediately’ does not
- have to be non-nil, because the reverts happen immediately anyway.
-
- If ‘magit-auto-revert-immediately’ and ‘auto-revert-use-notify’ are
- both ‘nil’, then reverts happen after ‘auto-revert-interval’
- seconds of user inactivity. That is not desirable.
-
- -- User Option: auto-revert-use-notify
-
- This option controls whether file notification functions should be
- used. Note that this variable unfortunately defaults to ‘t’ even
- on systems on which file notifications cannot be used.
-
- -- User Option: magit-auto-revert-tracked-only
-
- This option controls whether ‘magit-auto-revert-mode’ only reverts
- tracked files or all files that are located inside Git
- repositories, including untracked files and files located inside
- Git’s control directory.
-
- -- User Option: auto-revert-mode
-
- The global mode ‘magit-auto-revert-mode’ works by turning on this
- local mode in the appropriate buffers (but
- ‘global-auto-revert-mode’ is implemented differently). You can
- also turn it on or off manually, which might be necessary if Magit
- does not notice that a previously untracked file now is being
- tracked or vice-versa.
-
- -- User Option: auto-revert-stop-on-user-input
-
- This option controls whether the arrival of user input suspends the
- automatic reverts for ‘auto-revert-interval’ seconds.
-
- -- User Option: auto-revert-interval
-
- This option controls how many seconds Emacs waits for before
- resuming suspended reverts.
-
- -- User Option: auto-revert-buffer-list-filter
-
- This option specifies an additional filter used by
- ‘auto-revert-buffers’ to determine whether a buffer should be
- reverted or not.
-
- This option is provided by Magit, which also advises
- ‘auto-revert-buffers’ to respect it. Magit users who do not turn
- on the local mode ‘auto-revert-mode’ themselves, are best served by
- setting the value to ‘magit-auto-revert-repository-buffer-p’.
-
- However the default is nil, so as not to disturb users who do use
- the local mode directly. If you experience delays when running
- Magit commands, then you should consider using one of the
- predicates provided by Magit - especially if you also use Tramp.
-
- Users who do turn on ‘auto-revert-mode’ in buffers in which Magit
- doesn’t do that for them, should likely not use any filter. Users
- who turn on ‘global-auto-revert-mode’, do not have to worry about
- this option, because it is disregarded if the global mode is
- enabled.
-
- -- User Option: auto-revert-verbose
-
- This option controls whether Emacs reports when a buffer has been
- reverted.
-
- The options with the ‘auto-revert-’ prefix are located in the Custom
-group named ‘auto-revert’. The other, Magit-specific, options are
-located in the ‘magit’ group.
-
-* Menu:
-
-* Risk of Reverting Automatically::
-
-\1f
-File: magit.info, Node: Risk of Reverting Automatically, Up: Automatic Reverting of File-Visiting Buffers
-
-Risk of Reverting Automatically
-...............................
-
-For the vast majority of users, automatically reverting file-visiting
-buffers after they have changed on disk is harmless.
-
- If a buffer is modified (i.e. it contains changes that haven’t been
-saved yet), then Emacs will refuse to automatically revert it. If you
-save a previously modified buffer, then that results in what is seen by
-Git as an uncommitted change. Git will then refuse to carry out any
-commands that would cause these changes to be lost. In other words, if
-there is anything that could be lost, then either Git or Emacs will
-refuse to discard the changes.
-
- However, if you use file-visiting buffers as a sort of ad hoc
-"staging area", then the automatic reverts could potentially cause data
-loss. So far I have heard from only one user who uses such a workflow.
-
- An example: You visit some file in a buffer, edit it, and save the
-changes. Then, outside of Emacs (or at least not using Magit or by
-saving the buffer) you change the file on disk again. At this point the
-buffer is the only place where the intermediate version still exists.
-You have saved the changes to disk, but that has since been overwritten.
-Meanwhile Emacs considers the buffer to be unmodified (because you have
-not made any changes to it since you last saved it to the visited file)
-and therefore would not object to it being automatically reverted. At
-this point an Auto-Revert mode would kick in. It would check whether
-the buffer is modified and since that is not the case it would revert
-it. The intermediate version would be lost. (Actually you could still
-get it back using the ‘undo’ command.)
-
- If your workflow depends on Emacs preserving the intermediate version
-in the buffer, then you have to disable all Auto-Revert modes. But
-please consider that such a workflow would be dangerous even without
-using an Auto-Revert mode, and should therefore be avoided. If Emacs
-crashes or if you quit Emacs by mistake, then you would also lose the
-buffer content. There would be no autosave file still containing the
-intermediate version (because that was deleted when you saved the
-buffer) and you would not be asked whether you want to save the buffer
-(because it isn’t modified).
-
-\1f
-File: magit.info, Node: Sections, Next: Transient Commands, Prev: Modes and Buffers, Up: Interface Concepts
-
-4.2 Sections
-============
-
-Magit buffers are organized into nested sections, which can be collapsed
-and expanded, similar to how sections are handled in Org mode. Each
-section also has a type, and some sections also have a value. For each
-section type there can also be a local keymap, shared by all sections of
-that type.
-
- Taking advantage of the section value and type, many commands operate
-on the current section, or when the region is active and selects
-sections of the same type, all of the selected sections. Commands that
-only make sense for a particular section type (as opposed to just
-behaving differently depending on the type) are usually bound in section
-type keymaps.
-
-* Menu:
-
-* Section Movement::
-* Section Visibility::
-* Section Hooks::
-* Section Types and Values::
-* Section Options::
-
-\1f
-File: magit.info, Node: Section Movement, Next: Section Visibility, Up: Sections
-
-4.2.1 Section Movement
-----------------------
-
-To move within a section use the usual keys (‘C-p’, ‘C-n’, ‘C-b’, ‘C-f’
-etc), whose global bindings are not shadowed. To move to another
-section use the following commands.
-
-‘p’ (‘magit-section-backward’)
-
- When not at the beginning of a section, then move to the beginning
- of the current section. At the beginning of a section, instead
- move to the beginning of the previous visible section.
-
-‘n’ (‘magit-section-forward’)
-
- Move to the beginning of the next visible section.
-
-‘M-p’ (‘magit-section-backward-siblings’)
-
- Move to the beginning of the previous sibling section. If there is
- no previous sibling section, then move to the parent section
- instead.
-
-‘M-n’ (‘magit-section-forward-siblings’)
-
- Move to the beginning of the next sibling section. If there is no
- next sibling section, then move to the parent section instead.
-
-‘^’ (‘magit-section-up’)
-
- Move to the beginning of the parent of the current section.
-
- The above commands all call the hook ‘magit-section-movement-hook’.
-Any of the functions listed below can be used as members of this hook.
-
- You might want to remove some of the functions that Magit adds using
-‘add-hook’. In doing so you have to make sure you do not attempt to
-remove function that haven’t even been added yet, for example:
-
- (with-eval-after-load 'magit-diff
- (remove-hook 'magit-section-movement-hook
- 'magit-hunk-set-window-start))
-
- -- Variable: magit-section-movement-hook
-
- This hook is run by all of the above movement commands, after
- arriving at the destination.
-
- -- Function: magit-hunk-set-window-start
-
- This hook function ensures that the beginning of the current
- section is visible, provided it is a ‘hunk’ section. Otherwise, it
- does nothing.
-
- Loading ‘magit-diff’ adds this function to the hook.
-
- -- Function: magit-section-set-window-start
-
- This hook function ensures that the beginning of the current
- section is visible, regardless of the section’s type. If you add
- this to ‘magit-section-movement-hook’, then you must remove the
- hunk-only variant in turn.
-
- -- Function: magit-log-maybe-show-more-commits
-
- This hook function only has an effect in log buffers, and ‘point’
- is on the "show more" section. If that is the case, then it
- doubles the number of commits that are being shown.
-
- Loading ‘magit-log’ adds this function to the hook.
-
- -- Function: magit-log-maybe-update-revision-buffer
-
- When moving inside a log buffer, then this function updates the
- revision buffer, provided it is already being displayed in another
- window of the same frame.
-
- Loading ‘magit-log’ adds this function to the hook.
-
- -- Function: magit-log-maybe-update-blob-buffer
-
- When moving inside a log buffer and another window of the same
- frame displays a blob buffer, then this function instead displays
- the blob buffer for the commit at point in that window.
-
- -- Function: magit-status-maybe-update-revision-buffer
-
- When moving inside a status buffer, then this function updates the
- revision buffer, provided it is already being displayed in another
- window of the same frame.
-
- -- Function: magit-status-maybe-update-stash-buffer
-
- When moving inside a status buffer, then this function updates the
- stash buffer, provided it is already being displayed in another
- window of the same frame.
-
- -- Function: magit-status-maybe-update-blob-buffer
-
- When moving inside a status buffer and another window of the same
- frame displays a blob buffer, then this function instead displays
- the blob buffer for the commit at point in that window.
-
- -- Function: magit-stashes-maybe-update-stash-buffer
-
- When moving inside a buffer listing stashes, then this function
- updates the stash buffer, provided it is already being displayed in
- another window of the same frame.
-
- -- User Option: magit-update-other-window-delay
-
- Delay before automatically updating the other window.
-
- When moving around in certain buffers, then certain other buffers,
- which are being displayed in another window, may optionally be
- updated to display information about the section at point.
-
- When holding down a key to move by more than just one section, then
- that would update that buffer for each section on the way. To
- prevent that, updating the revision buffer is delayed, and this
- option controls for how long. For optimal experience you might
- have to adjust this delay and/or the keyboard repeat rate and delay
- of your graphical environment or operating system.
-
-\1f
-File: magit.info, Node: Section Visibility, Next: Section Hooks, Prev: Section Movement, Up: Sections
-
-4.2.2 Section Visibility
-------------------------
-
-Magit provides many commands for changing the visibility of sections,
-but all you need to get started are the next two.
-
-‘TAB’ (‘magit-section-toggle’)
-
- Toggle the visibility of the body of the current section.
-
-‘C-<tab>’ (‘magit-section-cycle’)
-
- Cycle the visibility of current section and its children.
-
-‘M-<tab>’ (‘magit-section-cycle-diffs’)
-
- Cycle the visibility of diff-related sections in the current
- buffer.
-
-‘S-<tab>’ (‘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.
-
-\1f
-File: magit.info, Node: Section Hooks, Next: Section Types and Values, Prev: Section Visibility, Up: Sections
-
-4.2.3 Section Hooks
--------------------
-
-Which sections are inserted into certain buffers is controlled with
-hooks. This includes the status and the refs buffers. For other
-buffers, e.g. log and diff buffers, this is not possible. The command
-‘magit-describe-section’ can be used to see which hook (if any) was
-responsible for inserting the section at point.
-
- For buffers whose sections can be customized by the user, a hook
-variable called ‘magit-TYPE-sections-hook’ exists. This hook should be
-changed using ‘magit-add-section-hook’. Avoid using ‘add-hooks’ or the
-Custom interface.
-
- The various available section hook variables are described later in
-this manual along with the appropriate "section inserter functions".
-
- -- Function: magit-add-section-hook hook function &optional at append
- local
-
- Add the function FUNCTION to the value of section hook HOOK.
-
- Add FUNCTION at the beginning of the hook list unless optional
- APPEND is non-nil, in which case FUNCTION is added at the end. If
- FUNCTION already is a member then move it to the new location.
-
- If optional AT is non-nil and a member of the hook list, then add
- FUNCTION next to that instead. Add before or after AT, or replace
- AT with FUNCTION depending on APPEND. If APPEND is the symbol
- ‘replace’, then replace AT with FUNCTION. For any other non-nil
- value place FUNCTION right after AT. If nil, then place FUNCTION
- right before AT. If FUNCTION already is a member of the list but
- AT is not, then leave FUNCTION where ever it already is.
-
- If optional LOCAL is non-nil, then modify the hook’s buffer-local
- value rather than its global value. This makes the hook local by
- copying the default value. That copy is then modified.
-
- HOOK should be a symbol. If HOOK is void, it is first set to nil.
- HOOK’s value must not be a single hook function. FUNCTION should
- be a function that takes no arguments and inserts one or multiple
- sections at point, moving point forward. FUNCTION may choose not
- to insert its section(s), when doing so would not make sense. It
- should not be abused for other side-effects.
-
- To remove a function from a section hook, use ‘remove-hook’.
-
-\1f
-File: magit.info, Node: Section Types and Values, Next: Section Options, Prev: Section Hooks, Up: Sections
-
-4.2.4 Section Types and Values
-------------------------------
-
-Each section has a type, for example ‘hunk’, ‘file’, and ‘commit’.
-Instances of certain section types also have a value. The value of a
-section of type ‘file’, for example, is a file name.
-
- Users usually do not have to worry about a section’s type and value,
-but knowing them can be handy at times.
-
-‘M-x magit-describe-section-briefly’ (‘magit-describe-section-briefly’)
-
- Show information about the section at point in the echo area, as
- "#<magit-section VALUE [TYPE PARENT-TYPE...] BEGINNING-END>".
-
- 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.
-
-\1f
-File: magit.info, Node: Section Options, Prev: Section Types and Values, Up: Sections
-
-4.2.5 Section Options
----------------------
-
-This section describes options that have an effect on more than just a
-certain type of sections. As you can see there are not many of those.
-
- -- User Option: magit-section-show-child-count
-
- Whether to append the number of children to section headings. This
- only affects sections that could benefit from this information.
-
-\1f
-File: magit.info, Node: Transient Commands, Next: Transient Arguments and Buffer Variables, Prev: Sections, Up: Interface Concepts
-
-4.3 Transient Commands
-======================
-
-Many Magit commands are implemented as *transient* commands. First the
-user invokes a *prefix* command, which causes its *infix* arguments and
-*suffix* commands to be displayed in the echo area. The user then
-optionally sets some infix arguments and finally invokes one of the
-suffix commands.
-
- This is implemented in the library ‘transient’. Earlier Magit
-releases used the package ‘magit-popup’ and even earlier versions
-library ‘magit-key-mode’.
-
- Transient is documented in *note (transient)Top::.
-
-‘C-c C-c’ (‘magit-dispatch’)
-
- This transient prefix command binds most of Magit’s other prefix
- commands as suffix commands and displays them in a temporary buffer
- until one of them is invoked. Invoking such a sub-prefix causes
- the suffixes of that command to be bound and displayed instead of
- those of ‘magit-dispatch’.
-
- This command is also, or especially, useful outside Magit buffers, so
-you should setup a global binding:
-
- (global-set-key (kbd "C-x M-g") 'magit-dispatch)
-
-\1f
-File: magit.info, Node: Transient Arguments and Buffer Variables, Next: Completion Confirmation and the Selection, Prev: Transient Commands, Up: Interface Concepts
-
-4.4 Transient Arguments and Buffer Variables
-============================================
-
-The infix arguments of many of Magit’s transient prefix commands cease
-to have an effect once the ‘git’ command that is called with those
-arguments has returned. Commands that create a commit are a good
-example for this. If the user changes the arguments, then that only
-affects the next invocation of a suffix command. If the same transient
-prefix command is later invoked again, then the arguments are initially
-reset to the default value. This default value can be set for the
-current Emacs session or saved permanently, see *note (transient)Saving
-Values::. It is also possible to cycle through previously used sets of
-arguments using ‘M-p’ and ‘M-n’, see *note (transient)Using History::.
-
- However the infix arguments of many other transient commands continue
-to have an effect even after the ‘git’ command that was called with
-those arguments has returned. The most important commands like this are
-those that display a diff or log in a dedicated buffer. Their arguments
-obviously continue to have an effect for as long as the respective diff
-or log is being displayed. Furthermore the used arguments are stored in
-buffer-local variables for future reference.
-
- For commands in the second group it isn’t always desirable to reset
-their arguments to the global value when the transient prefix command is
-invoked again.
-
- As mentioned above, it is possible to cycle through previously used
-sets of arguments while a transient popup is visible. That means that
-we could always reset the infix arguments to the default because the set
-of arguments that is active in the existing buffer is only a few ‘M-p’
-away. Magit can be configured to behave like that, but because I expect
-that most users would not find that very convenient, it is not the
-default.
-
- Also note that it is possible to change the diff and log arguments
-used in the current buffer (including the status buffer, which contains
-both diff and log sections) using the respective "refresh" transient
-prefix commands on ‘D’ and ‘L’. (‘d’ and ‘l’ on the other hand are
-intended to change *what* diff or log is being displayed. It is
-possible to also change *how* the diff or log is being displayed at the
-same time, but if you only want to do the latter, then you should use
-the refresh variants.) Because these secondary diff and log transient
-prefixes are about *changing* the arguments used in the current buffer,
-they *always* start out with the set of arguments that are currently in
-effect in that buffer.
-
- Some commands are usually invoked directly even though they can also
-be invoked as the suffix of a transient prefix command. Most
-prominently ‘magit-show-commit’ is usually invoked by typing ‘RET’ while
-point is on a commit in a log, but it can also be invoked from the
-‘magit-diff’ transient prefix.
-
- When such a command is invoked directly, then it is important to
-reuse the arguments as specified by the respective buffer-local values,
-instead of using the default arguments. Imagine you press ‘RET’ in a
-log to display the commit at point in a different buffer and then use
-‘D’ to change how the diff is displayed in that buffer. And then you
-press ‘RET’ on another commit to show that instead and the diff
-arguments are reset to the default. Not cool; so Magit does not do that
-by default.
-
- -- User Option: magit-prefix-use-buffer-arguments
-
- This option controls whether the infix arguments initially shown in
- certain transient prefix commands are based on the arguments that
- are currently in effect in the buffer that their suffixes update.
-
- The ‘magit-diff’ and ‘magit-log’ transient prefix commands are
- affected by this option.
-
- -- User Option: magit-direct-use-buffer-arguments
-
- This option controls whether certain commands, when invoked
- directly (i.e. not as the suffix of a transient prefix command),
- use the arguments that are currently active in the buffer that they
- are about to update. The alternative is to use the default value
- for these arguments, which might change the arguments that are used
- in the buffer.
-
-Valid values for both of the above options are:
-
- • ‘always’: Always use the set of arguments that is currently active
- in the respective buffer, provided that buffer exists of course.
-
- • ‘selected’ or ‘t’: Use the set of arguments from the respective
- buffer, but only if it is displayed in a window of the current
- frame. This is the default for both variables.
-
- • ‘current’: Use the set of arguments from the respective buffer, but
- only if it is the current buffer.
-
- • ‘never’: Never use the set of arguments from the respective buffer.
-
-I am afraid it gets more complicated still:
-
- • The global diff and log arguments are set for each support mode
- individually. The diff arguments for example have different values
- in ‘magit-diff-mode’, ‘magit-revision-mode’,
- ‘magit-merge-preview-mode’ and ‘magit-status-mode’ buffers.
- Setting or saving the value for one mode does not change the value
- for other modes. The history however is shared.
-
- • When ‘magit-show-commit’ is invoked directly from a log buffer,
- then the file filter is picked up from that buffer, not from the
- revision buffer and or the mode’s global diff arguments.
-
- • Even though they are suffixes of the diff prefix
- ‘magit-show-commit’ and ‘magit-stash-show’ do not use the diff
- buffer used by the diff commands, instead they use the dedicated
- revision and stash buffers.
-
- At the time you invoke the diff prefix it is unknown to Magit which
- of the suffix commands you are going to invoke. While not certain,
- more often than not users invoke one of the commands that use the
- diff buffer, so the initial infix arguments are those used in that
- buffer. However if you invoke one of these commands directly, then
- Magit knows that it should use the arguments from the revision
- resp. stash buffer.
-
- • The log prefix also features reflog commands, but these commands do
- not use the log arguments.
-
- • If ‘magit-show-refs’ is invoked from a ‘magit-refs-mode’ buffer,
- then it acts as a refresh prefix and therefore unconditionally uses
- the buffer’s arguments as initial arguments. If it is invoked
- elsewhere with a prefix argument, then it acts as regular prefix
- and therefore respects ‘magit-prefix-use-buffer-arguments’. If it
- is invoked elsewhere without a prefix argument, then it acts as a
- direct command and therefore respects
- ‘magit-direct-use-buffer-arguments’.
-
-\1f
-File: magit.info, Node: Completion Confirmation and the Selection, Next: Running Git, Prev: Transient Arguments and Buffer Variables, Up: Interface Concepts
-
-4.5 Completion, Confirmation and the Selection
-==============================================
-
-* Menu:
-
-* Action Confirmation::
-* Completion and Confirmation::
-* The Selection::
-* The hunk-internal region::
-* Support for Completion Frameworks::
-* Additional Completion Options::
-
-\1f
-File: magit.info, Node: Action Confirmation, Next: Completion and Confirmation, Up: Completion Confirmation and the Selection
-
-4.5.1 Action Confirmation
--------------------------
-
-By default many actions that could potentially lead to data loss have to
-be confirmed. This includes many very common actions, so this can
-quickly become annoying. Many of these actions can be undone and if you
-have thought about how to undo certain mistakes, then it should be safe
-to disable confirmation for the respective actions.
-
- The option ‘magit-no-confirm’ can be used to tell Magit to perform
-certain actions without the user having to confirm them. Note that
-while this option can only be used to disable confirmation for a
-specific set of actions, the next section explains another way of
-telling Magit to ask fewer questions.
-
- -- User Option: magit-no-confirm
-
- The value of this option is a list of symbols, representing actions
- that do not have to be confirmed by the user before being carried
- out.
-
- By default many potentially dangerous commands ask the user for
- confirmation. Each of the below symbols stands for an action
- which, when invoked unintentionally or without being fully aware of
- the consequences, could lead to tears. In many cases there are
- several commands that perform variations of a certain action, so we
- don’t use the command names but more generic symbols.
-
- • Applying changes:
-
- • ‘discard’ Discarding one or more changes (i.e. hunks or
- the complete diff for a file) loses that change,
- obviously.
-
- • ‘reverse’ Reverting one or more changes can usually be
- undone by reverting the reversion.
-
- • ‘stage-all-changes’, ‘unstage-all-changes’ When there are
- both staged and unstaged changes, then un-/staging
- everything would destroy that distinction. Of course
- that also applies when un-/staging a single change, but
- then less is lost and one does that so often that having
- to confirm every time would be unacceptable.
-
- • Files:
-
- • ‘delete’ When a file that isn’t yet tracked by Git is
- deleted, then it is completely lost, not just the last
- changes. Very dangerous.
-
- • ‘trash’ Instead of deleting a file it can also be move to
- the system trash. Obviously much less dangerous than
- deleting it.
-
- Also see option ‘magit-delete-by-moving-to-trash’.
-
- • ‘resurrect’ A deleted file can easily be resurrected by
- "deleting" the deletion, which is done using the same
- command that was used to delete the same file in the
- first place.
-
- • ‘untrack’ Untracking a file can be undone by tracking it
- again.
-
- • ‘rename’ Renaming a file can easily be undone.
-
- • Sequences:
-
- • ‘reset-bisect’ Aborting (known to Git as "resetting") a
- bisect operation loses all information collected so far.
-
- • ‘abort-rebase’ Aborting a rebase throws away all already
- modified commits, but it’s possible to restore those from
- the reflog.
-
- • ‘abort-merge’ Aborting a merge throws away all conflict
- resolutions which have already been carried out by the
- user.
-
- • ‘merge-dirty’ Merging with a dirty worktree can make it
- hard to go back to the state before the merge was
- initiated.
-
- • References:
-
- • ‘delete-unmerged-branch’ Once a branch has been deleted,
- it can only be restored using low-level recovery tools
- provided by Git. And even then the reflog is gone. The
- user always has to confirm the deletion of a branch by
- accepting the default choice (or selecting another
- branch), but when a branch has not been merged yet, also
- make sure the user is aware of that.
-
- • ‘delete-pr-remote’ When deleting a branch that was
- created from a pull-request and if no other branches
- still exist on that remote, then ‘magit-branch-delete’
- offers to delete the remote as well. This should be safe
- because it only happens if no other refs exist in the
- remotes namespace, and you can recreate the remote if
- necessary.
-
- • ‘drop-stashes’ Dropping a stash is dangerous because Git
- stores stashes in the reflog. Once a stash is removed,
- there is no going back without using low-level recovery
- tools provided by Git. When a single stash is dropped,
- then the user always has to confirm by accepting the
- default (or selecting another). This action only
- concerns the deletion of multiple stashes at once.
-
- • Publishing:
-
- ‘set-and-push’ When pushing to the upstream or the push-remote
- and that isn’t actually configured yet, then the user can
- first set the target. If s/he confirms the default too
- quickly, then s/he might end up pushing to the wrong branch
- and if the remote repository is configured to disallow fixing
- such mistakes, then that can be quite embarrassing and
- annoying.
-
- • Edit published history:
-
- Without adding these symbols here, you will be warned before
- editing commits that have already been pushed to one of the
- branches listed in ‘magit-published-branches’.
-
- • ‘amend-published’ Affects most commands that amend to
- "HEAD".
-
- • ‘rebase-published’ Affects commands that perform
- interactive rebases. This includes commands from the
- commit transient that modify a commit other than "HEAD",
- namely the various fixup and squash variants.
-
- • ‘edit-published’ Affects the commands
- ‘magit-edit-line-commit’ and
- ‘magit-diff-edit-hunk-commit’. These two commands make
- it quite easy to accidentally edit a published commit, so
- you should think twice before configuring them not to ask
- for confirmation.
-
- To disable confirmation completely, add all three symbols here
- or set ‘magit-published-branches’ to ‘nil’.
-
- • Various:
-
- • ‘kill-process’ There seldom is a reason to kill a
- process.
-
- • Global settings:
-
- Instead of adding all of the above symbols to the value of
- this option, you can also set it to the atom ‘t’, which has
- the same effect as adding all of the above symbols. Doing
- that most certainly is a bad idea, especially because other
- symbols might be added in the future. So even if you don’t
- want to be asked for confirmation for any of these actions,
- you are still better of adding all of the respective symbols
- individually.
-
- When ‘magit-wip-before-change-mode’ is enabled, then the
- following actions can be undone fairly easily: ‘discard’,
- ‘reverse’, ‘stage-all-changes’, and ‘unstage-all-changes’. If
- and only if this mode is enabled, then ‘safe-with-wip’ has the
- same effect as adding all of these symbols individually.
-
-\1f
-File: magit.info, Node: Completion and Confirmation, Next: The Selection, Prev: Action Confirmation, Up: Completion Confirmation and the Selection
-
-4.5.2 Completion and Confirmation
----------------------------------
-
-Many Magit commands ask the user to select from a list of possible
-things to act on, while offering the most likely choice as the default.
-For many of these commands the default is the thing at point, provided
-that it actually is a valid thing to act on. For many commands that act
-on a branch, the current branch serves as the default if there is no
-branch at point.
-
- These commands combine asking for confirmation and asking for a
-target to act on into a single action. The user can confirm the default
-target using ‘RET’ or abort using ‘C-g’. This is similar to a
-‘y-or-n-p’ prompt, but the keys to confirm or abort differ.
-
- At the same time the user is also given the opportunity to select
-another target, which is useful because for some commands and/or in some
-situations you might want to select the action before selecting the
-target by moving to it.
-
- However you might find that for some commands you always want to use
-the default target, if any, or even that you want the command to act on
-the default without requiring any confirmation at all. The option
-‘magit-dwim-selection’ can be used to configure certain commands to that
-effect.
-
- Note that when the region is active then many commands act on the
-things that are selected using a mechanism based on the region, in many
-cases after asking for confirmation. This region-based mechanism is
-called the "selection" and is described in detail in the next section.
-When a selection exists that is valid for the invoked command, then that
-command never offers to act on something else, and whether it asks for
-confirmation is not controlled by this option.
-
- Also note that Magit asks for confirmation of certain actions that
-are not coupled with completion (or the selection). Such dialogs are
-also not affected by this option and are described in the previous
-section.
-
- -- User Option: magit-dwim-selection
-
- This option can be used to tell certain commands to use the thing at
-point instead of asking the user to select a candidate to act on, with
-or without confirmation.
-
- The value has the form ‘((COMMAND nil|PROMPT DEFAULT)...)’.
-
- • COMMAND is the command that should not prompt for a choice. To
- have an effect, the command has to use the function
- ‘magit-completing-read’ or a utility function which in turn uses
- that function.
-
- • If the command uses ‘magit-completing-read’ multiple times, then
- PROMPT can be used to only affect one of these uses. PROMPT, if
- non-nil, is a regular expression that is used to match against the
- PROMPT argument passed to ‘magit-completing-read’.
-
- • DEFAULT specifies how to use the default. If it is ‘t’, then the
- DEFAULT argument passed to ‘magit-completing-read’ is used without
- confirmation. If it is ‘ask’, then the user is given a chance to
- abort. DEFAULT can also be ‘nil’, in which case the entry has no
- effect.
-
-\1f
-File: magit.info, Node: The Selection, Next: The hunk-internal region, Prev: Completion and Confirmation, Up: Completion Confirmation and the Selection
-
-4.5.3 The Selection
--------------------
-
-If the region is active, then many Magit commands act on the things that
-are selected using a mechanism based on the region instead of one single
-thing. When the region is not active, then these commands act on the
-thing at point or read a single thing to act on. This is described in
-the previous section — this section only covers how multiple things are
-selected, how that is visualized, and how certain commands behave when
-that is the case.
-
- Magit’s mechanism for selecting multiple things, or rather sections
-that represent these things, is based on the Emacs region, but the area
-that Magit considers to be selected is typically larger than the region
-and additional restrictions apply.
-
- Magit makes a distinction between a region that qualifies as forming
-a valid Magit selection and a region that does not. If the region does
-not qualify, then it is displayed as it is in other Emacs buffers. If
-the region does qualify as a Magit selection, then the selection is
-always visualized, while the region itself is only visualized if it
-begins and ends on the same line.
-
- For a region to qualify as a Magit selection, it must begin in the
-heading of one section and end in the heading of a sibling section.
-Note that if the end of the region is at the very beginning of section
-heading (i.e. at the very beginning of a line) then that section is
-considered to be *inside* the selection.
-
- This is not consistent with how the region is normally treated in
-Emacs — if the region ends at the beginning of a line, then that line is
-outside the region. Due to how Magit visualizes the selection, it
-should be obvious that this difference exists.
-
- Not every command acts on every valid selection. Some commands do
-not even consider the location of point, others may act on the section
-at point but not support acting on the selection, and even commands that
-do support the selection of course only do so if it selects things that
-they can act on.
-
- This is the main reason why the selection must include the section at
-point. Even if a selection exists, the invoked command may disregard
-it, in which case it may act on the current section only. It is much
-safer to only act on the current section but not the other selected
-sections than it is to act on the current section *instead* of the
-selected sections. The latter would be much more surprising and if the
-current section always is part of the selection, then that cannot
-happen.
-
- -- Variable: magit-keep-region-overlay
-
- This variable controls whether the region is visualized as usual
- even when a valid Magit selection or a hunk-internal region exists.
- See the doc-string for more information.
-
-\1f
-File: magit.info, Node: The hunk-internal region, Next: Support for Completion Frameworks, Prev: The Selection, Up: Completion Confirmation and the Selection
-
-4.5.4 The hunk-internal region
-------------------------------
-
-Somewhat related to the Magit selection described in the previous
-section is the hunk-internal region.
-
- Like the selection, the hunk-internal region is based on the Emacs
-region but causes that region to not be visualized as it would in other
-Emacs buffers, and includes the line on which the region ends even if it
-ends at the very beginning of that line.
-
- Unlike the selection, which is based on a region that must begin in
-the heading of one section and ends in the section of a sibling section,
-the hunk-internal region must begin inside the *body* of a hunk section
-and end in the body of the *same* section.
-
- The hunk-internal region is honored by "apply" commands, which can,
-among other targets, act on a hunk. If the hunk-internal region is
-active, then such commands act only on the marked part of the hunk
-instead of on the complete hunk.
-
-\1f
-File: magit.info, Node: Support for Completion Frameworks, Next: Additional Completion Options, Prev: The hunk-internal region, Up: Completion Confirmation and the Selection
-
-4.5.5 Support for Completion Frameworks
----------------------------------------
-
-The built-in option ‘completing-read-function’ specifies the low-level
-function used by ‘completing-read’ to ask a user to select from a list
-of choices. Its default value is ‘completing-read-default’.
-Alternative completion frameworks typically activate themselves by
-substituting their own implementation.
-
- Mostly for historic reasons Magit provides a similar option named
-‘magit-completing-read-function’, which only controls the low-level
-function used by ‘magit-completing-read’. This option also makes it
-possible to use a different completing mechanism for Magit than for the
-rest of Emacs, but doing that is not recommend.
-
- You most likely don’t have to customize the magit-specific option to
-use an alternative completion framework. For example, if you enable
-‘ivy-mode’, then Magit will respect that, and if you enable ‘helm-mode’,
-then you are done too.
-
- However if you want to use Ido, then ‘ido-mode’ won’t do the trick.
-You will also have to install the ‘ido-completing-read+’ package and use
-‘magit-ido-completing-read’ as ‘magit-completing-read-function’.
-
- -- User Option: magit-completing-read-function
-
- The value of this variable is the low-level function used to
- perform completion by code that uses ‘magit-completing-read’ (as
- opposed to the built-in ‘completing-read’).
-
- The default value, ‘magit-builtin-completing-read’, is suitable for
- the standard completion mechanism, ‘ivy-mode’, and ‘helm-mode’ at
- least.
-
- The built-in ‘completing-read’ and ‘completing-read-default’ are
- *not* suitable to be used here. ‘magit-builtin-completing-read’
- performs some additional work, and any function used in its place
- has to do the same.
-
- -- Function: magit-builtin-completing-read prompt choices &optional
- predicate require-match initial-input hist def
-
- This function performs completion using the built-in
- ‘completing-read’ and does some additional magit-specific work.
-
- -- Function: magit-ido-completing-read prompt choices &optional
- predicate require-match initial-input hist def
-
- This function performs completion using ‘ido-completing-read+’ from
- the package by the same name (which you have to explicitly install)
- and does some additional magit-specific work.
-
- We have to use ‘ido-completing-read+’ instead of the
- ‘ido-completing-read’ that comes with Ido itself, because the
- latter, while intended as a drop-in replacement, cannot serve that
- purpose because it violates too many of the implicit conventions.
-
- -- Function: magit-completing-read prompt choices &optional predicate
- require-match initial-input hist def fallback
-
- This is the function that Magit commands use when they need the
- user to select a single thing to act on. The arguments have the
- same meaning as for ‘completing-read’, except for FALLBACK, which
- is unique to this function and is described below.
-
- Instead of asking the user to choose from a list of possible
- candidates, this function may just return the default specified by
- DEF, with or without requiring user confirmation. Whether that is
- the case depends on PROMPT, ‘this-command’ and
- ‘magit-dwim-selection’. See the documentation of the latter for
- more information.
-
- If it does read a value in the minibuffer, then this function acts
- similar to ‘completing-read’, except for the following:
-
- • COLLECTION must be a list of choices. A function is not
- supported.
-
- • If REQUIRE-MATCH is ‘nil’ and the user exits without a choice,
- then ‘nil’ is returned instead of an empty string.
-
- • If REQUIRE-MATCH is non-nil and the users exits without a
- choice, an user-error is raised.
-
- • FALLBACK specifies a secondary default that is only used if
- the primary default DEF is ‘nil’. The secondary default is
- not subject to ‘magit-dwim-selection’ — if DEF is ‘nil’ but
- FALLBACK is not, then this function always asks the user to
- choose a candidate, just as if both defaults were ‘nil’.
-
- • ": " is appended to PROMPT.
-
- • PROMPT is modified to end with \" (default DEF|FALLBACK): \"
- provided that DEF or FALLBACK is non-nil, that neither
- ‘ivy-mode’ nor ‘helm-mode’ is enabled, and that
- ‘magit-completing-read-function’ is set to its default value
- of ‘magit-builtin-completing-read’.
-
-\1f
-File: magit.info, Node: Additional Completion Options, Prev: Support for Completion Frameworks, Up: Completion Confirmation and the Selection
-
-4.5.6 Additional Completion Options
------------------------------------
-
- -- User Option: magit-list-refs-sortby
-
- For many commands that read a ref or refs from the user, the value
- of this option can be used to control the order of the refs. Valid
- values include any key accepted by the ‘--sort’ flag of ‘git
- for-each-ref’. By default, refs are sorted alphabetically by their
- full name (e.g., "refs/heads/master").
-
-\1f
-File: magit.info, Node: Running Git, Prev: Completion Confirmation and the Selection, Up: Interface Concepts
-
-4.6 Running Git
-===============
-
-* Menu:
-
-* Viewing Git Output::
-* Git Process Status::
-* Running Git Manually::
-* Git Executable::
-* Global Git Arguments::
-
-\1f
-File: magit.info, Node: Viewing Git Output, Next: Git Process Status, Up: Running Git
-
-4.6.1 Viewing Git Output
-------------------------
-
-Magit runs Git either for side-effects (e.g. when pushing) or to get
-some value (e.g. the name of the current branch).
-
- When Git is run for side-effects, the process output is logged in a
-per-repository log buffer, which can be consulted using the
-‘magit-process’ command when things don’t go as expected.
-
- The output/errors for up to ‘magit-process-log-max’ Git commands are
-retained.
-
-‘$’ (‘magit-process’)
-
- This commands displays the process buffer for the current
- repository.
-
- Inside that buffer, the usual key bindings for navigating and showing
-sections are available. There is one additional command.
-
-‘k’ (‘magit-process-kill’)
-
- This command kills the process represented by the section at point.
-
- -- User Option: magit-git-debug
-
- When this is non-nil then the output of all calls to git are logged
- in the process buffer. This is useful when debugging, otherwise it
- just negatively affects performance.
-
-\1f
-File: magit.info, Node: Git Process Status, Next: Running Git Manually, Prev: Viewing Git Output, Up: Running Git
-
-4.6.2 Git Process Status
-------------------------
-
-When a Git process is running for side-effects, Magit displays an
-indicator in the mode line, using the ‘magit-mode-line-process’ face.
-
- If the Git process exits successfully, the process indicator is
-removed from the mode line immediately.
-
- In the case of a Git error, the process indicator is not removed, but
-is instead highlighted with the ‘magit-mode-line-process-error’ face,
-and the error details from the process buffer are provided as a tooltip
-for mouse users. This error indicator persists in the mode line until
-the next magit buffer refresh.
-
- If you do not wish process errors to be indicated in the mode line,
-customize the ‘magit-process-display-mode-line-error’ user option.
-
- Process errors are additionally indicated at the top of the status
-buffer.
-
-\1f
-File: magit.info, Node: Running Git Manually, Next: Git Executable, Prev: Git Process Status, Up: Running Git
-
-4.6.3 Running Git Manually
---------------------------
-
-While Magit provides many Emacs commands to interact with Git, it does
-not cover everything. In those cases your existing Git knowledge will
-come in handy. Magit provides some commands for running arbitrary Git
-commands by typing them into the minibuffer, instead of having to switch
-to a shell.
-
-‘!’ (‘magit-run’)
-
- This transient prefix command binds the following suffix commands
- and displays them in a temporary buffer until a suffix is invoked.
-
-‘! !’ (‘magit-git-command-topdir’)
-
- This command reads a command from the user and executes it in the
- top-level directory of the current working tree.
-
- The string "git " is used as initial input when prompting the user
- for the command. It can be removed to run another command.
-
-‘! p’ (‘magit-git-command’)
-
- This command reads a command from the user and executes it in
- ‘default-directory’. With a prefix argument the command is
- executed in the top-level directory of the current working tree
- instead.
-
- The string "git " is used as initial input when prompting the user
- for the command. It can be removed to run another command.
-
-‘! s’ (‘magit-shell-command-topdir’)
-
- This command reads a command from the user and executes it in the
- top-level directory of the current working tree.
-
-‘! S’ (‘magit-shell-command’)
-
- This command reads a command from the user and executes it in
- ‘default-directory’. With a prefix argument the command is
- executed in the top-level directory of the current working tree
- instead.
-
- -- User Option: magit-shell-command-verbose-prompt
-
- Whether the prompt, used by the above commands when reading a shell
- command, shows the directory in which it will be run.
-
- These suffix commands start external gui tools.
-
-‘! k’ (‘magit-run-gitk’)
-
- This command runs ‘gitk’ in the current repository.
-
-‘! a’ (‘magit-run-gitk-all’)
-
- This command runs ‘gitk --all’ in the current repository.
-
-‘! b’ (‘magit-run-gitk-branches’)
-
- This command runs ‘gitk --branches’ in the current repository.
-
-‘! g’ (‘magit-run-git-gui’)
-
- This command runs ‘git gui’ in the current repository.
-
-\1f
-File: magit.info, Node: Git Executable, Next: Global Git Arguments, Prev: Running Git Manually, Up: Running Git
-
-4.6.4 Git Executable
---------------------
-
-Except on MS Windows, Magit defaults to running Git without specifying
-the path to the git executable. Instead the first executable found by
-Emacs on ‘exec-path’ is used (whose value in turn is set based on the
-value of the environment variable ‘$PATH’ when Emacs was started).
-
- This has the advantage that it continues to work even when using
-Tramp to connect to a remote machine on which the executable is found in
-a different place. The downside is that if you have multiple versions
-of Git installed, then you might end up using another version than the
-one you think you are using.
-
-‘M-x magit-version’ (‘magit-version’)
-
- This command shows the currently used versions of Magit, Git, and
- Emacs in the echo area. Non-interactively this just returns the
- Magit version.
-
- When the ‘system-type’ is ‘windows-nt’, then ‘magit-git-executable’
-is set to an absolute path when Magit is first loaded. This is
-necessary because Git on that platform comes with several wrapper
-scripts for the actual git binary, which are also placed on ‘$PATH’, and
-using one of these wrappers instead of the binary would degrade
-performance horribly.
-
- If Magit doesn’t find the correct executable then you *can* work
-around that by setting ‘magit-git-executable’ to an absolute path. But
-note that doing so is a kludge. It is better to make sure the order in
-the environment variable ‘$PATH’ is correct, and that Emacs is started
-with that environment in effect. The command
-‘magit-debug-git-executable’ can be useful to find out where Emacs is
-searching for git. If you have to connect from Windows to a non-Windows
-machine, then you must change the value to "git".
-
- -- User Option: magit-git-executable
-
- The git executable used by Magit, either the full path to the
- executable or the string "git" to let Emacs find the executable
- itself, using the standard mechanism for doing such things.
-
-‘M-x magit-debug-git-executable’ (‘magit-debug-git-executable’)
-
- Display a buffer with information about ‘magit-git-executable’.
-
-\1f
-File: magit.info, Node: Global Git Arguments, Prev: Git Executable, Up: Running Git
-
-4.6.5 Global Git Arguments
---------------------------
-
- -- User Option: magit-git-global-arguments
-
- The arguments set here are used every time the git executable is
- run as a subprocess. They are placed right after the executable
- itself and before the git command - as in ‘git HERE... COMMAND
- REST’. For valid arguments see *note (gitman)git::.
-
- Be careful what you add here, especially if you are using Tramp to
- connect to servers with ancient Git versions. Never remove
- anything that is part of the default value, unless you really know
- what you are doing. And think very hard before adding something;
- it will be used every time Magit runs Git for any purpose.
-
-\1f
-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::
-
-\1f
-File: magit.info, Node: Status Buffer, Next: Repository List, Up: Inspecting
-
-5.1 Status Buffer
-=================
-
-While other Magit buffers contain e.g. one particular diff or one
-particular log, the status buffer contains the diffs for staged and
-unstaged changes, logs for unpushed and unpulled commits, lists of
-stashes and untracked files, and information related to the current
-branch.
-
- During certain incomplete operations – for example when a merge
-resulted in a conflict – additional information is displayed that helps
-proceeding with or aborting the operation.
-
- The command ‘magit-status’ displays the status buffer belonging to
-the current repository in another window. This command is used so often
-that it should be bound globally. We recommend using ‘C-x g’:
-
- (global-set-key (kbd "C-x g") 'magit-status)
-
-‘C-x g’ (‘magit-status’)
-
- When invoked from within an existing Git repository, then this
- command shows the status of that repository in a buffer.
-
- If the current directory isn’t located within a Git repository,
- then this command prompts for an existing repository or an
- arbitrary directory, depending on the option
- ‘magit-repository-directories’, and the status for the selected
- repository is shown instead.
-
- • If that option specifies any existing repositories, then the
- user is asked to select one of them.
-
- • Otherwise the user is asked to select an arbitrary directory
- using regular file-name completion. If the selected directory
- is the top-level directory of an existing working tree, then
- the status buffer for that is shown.
-
- • Otherwise the user is offered to initialize the selected
- directory as a new repository. After creating the repository
- its status buffer is shown.
-
- These fallback behaviors can also be forced using one or more
- prefix arguments:
-
- • With two prefix arguments (or more precisely a numeric prefix
- value of 16 or greater) an arbitrary directory is read, which
- is then acted on as described above. The same could be
- accomplished using the command ‘magit-init’.
-
- • With a single prefix argument an existing repository is read
- from the user, or if no repository can be found based on the
- value of ‘magit-repository-directories’, then the behavior is
- the same as with two prefix arguments.
-
- -- User Option: magit-repository-directories
-
- List of directories that are Git repositories or contain Git
- repositories.
-
- Each element has the form ‘(DIRECTORY . DEPTH)’. DIRECTORY has to
- be a directory or a directory file-name, a string. DEPTH, an
- integer, specifies the maximum depth to look for Git repositories.
- If it is 0, then only add DIRECTORY itself.
-
- This option controls which repositories are being listed by
- ‘magit-list-repositories’. It also affects ‘magit-status’ (which
- see) in potentially surprising ways (see above).
-
- -- Command: ido-enter-magit-status
-
- From an Ido prompt used to open a file, instead drop into
- ‘magit-status’. This is similar to ‘ido-magic-delete-char’, which,
- despite its name, usually causes a Dired buffer to be created.
-
- To make this command available, use something like:
-
- (add-hook 'ido-setup-hook
- (lambda ()
- (define-key ido-completion-map
- (kbd \"C-x g\") 'ido-enter-magit-status)))
-
- Starting with Emacs 25.1 the Ido keymaps are defined just once
- instead of every time Ido is invoked, so now you can modify it like
- pretty much every other keymap:
-
- (define-key ido-common-completion-map
- (kbd \"C-x g\") 'ido-enter-magit-status)
-
-* Menu:
-
-* Status Sections::
-* Status Header Sections::
-* Status Module Sections::
-* Status Options::
-
-\1f
-File: magit.info, Node: Status Sections, Next: Status Header Sections, Up: Status Buffer
-
-5.1.1 Status Sections
----------------------
-
-The contents of status buffers is controlled using the hook
-‘magit-status-sections-hook’. See *note Section Hooks:: to learn about
-such hooks and how to customize them.
-
- -- User Option: magit-status-sections-hook
-
- Hook run to insert sections into a status buffer.
-
- The first function on that hook by default is
-‘magit-insert-status-headers’; it is described in the next section. By
-default the following functions are also members of that hook:
-
- -- Function: magit-insert-merge-log
-
- Insert section for the on-going merge. Display the heads that are
- being merged. If no merge is in progress, do nothing.
-
- -- Function: magit-insert-rebase-sequence
-
- Insert section for the on-going rebase sequence. If no such
- sequence is in progress, do nothing.
-
- -- Function: magit-insert-am-sequence
-
- Insert section for the on-going patch applying sequence. If no
- such sequence is in progress, do nothing.
-
- -- Function: magit-insert-sequencer-sequence
-
- Insert section for the on-going cherry-pick or revert sequence. If
- no such sequence is in progress, do nothing.
-
- -- Function: magit-insert-bisect-output
-
- While bisecting, insert section with output from ‘git bisect’.
-
- -- Function: magit-insert-bisect-rest
-
- While bisecting, insert section visualizing the bisect state.
-
- -- Function: magit-insert-bisect-log
-
- While bisecting, insert section logging bisect progress.
-
- -- Function: magit-insert-untracked-files
-
- Maybe insert a list or tree of untracked files.
-
- Do so depending on the value of ‘status.showUntrackedFiles’. Note
- that even if the value is ‘all’, Magit still initially only shows
- directories. But the directory sections can then be expanded using
- ‘TAB’.
-
- -- Function: magit-insert-unstaged-changes
-
- Insert section showing unstaged changes.
-
- -- Function: magit-insert-staged-changes
-
- Insert section showing staged changes.
-
- -- Function: magit-insert-stashes &optional ref heading
-
- Insert the ‘stashes’ section showing reflog for "refs/stash". If
- optional REF is non-nil show reflog for that instead. If optional
- HEADING is non-nil use that as section heading instead of
- "Stashes:".
-
- -- Function: magit-insert-unpulled-from-upstream
-
- Insert section showing commits that haven’t been pulled from the
- upstream branch yet.
-
- -- Function: magit-insert-unpulled-from-pushremote
-
- Insert section showing commits that haven’t been pulled from the
- push-remote branch yet.
-
- -- Function: magit-insert-unpushed-to-upstream
-
- Insert section showing commits that haven’t been pushed to the
- upstream yet.
-
- -- Function: magit-insert-unpushed-to-pushremote
-
- Insert section showing commits that haven’t been pushed to the
- push-remote yet.
-
- The following functions can also be added to the above hook:
-
- -- Function: magit-insert-tracked-files
-
- Insert a tree of tracked files.
-
- -- Function: magit-insert-ignored-files
-
- Insert a tree of ignored files. Its possible to limit the logs in
- the current buffer to a certain directory using ‘D = f <DIRECTORY>
- RET g’. If you do that, then that that also affects this command.
-
- The log filter can be used to limit to multiple files. In that
- case this function only respects the first of the files and only if
- it is a directory.
-
- -- Function: magit-insert-skip-worktree-files
-
- Insert a tree of skip-worktree files. If the first element of
- ‘magit-buffer-diff-files’ is a directory, then limit the list to
- files below that. The value of that variable can be set using ‘D
- -- DIRECTORY RET g’.
-
- -- Function: magit-insert-assumed-unchanged-files
-
- Insert a tree of files that are assumed to be unchanged. If the
- first element of ‘magit-buffer-diff-files’ is a directory, then
- limit the list to files below that. The value of that variable can
- be set using ‘D -- DIRECTORY RET g’.
-
- -- Function: magit-insert-unpulled-or-recent-commits
-
- Insert section showing unpulled or recent commits. If an upstream
- is configured for the current branch and it is ahead of the current
- branch, then show the missing commits. Otherwise, show the last
- ‘magit-log-section-commit-count’ commits.
-
- -- Function: magit-insert-recent-commits
-
- Insert section showing the last ‘magit-log-section-commit-count’
- commits.
-
- -- User Option: magit-log-section-commit-count
-
- How many recent commits ‘magit-insert-recent-commits’ and
- ‘magit-insert-unpulled-or-recent-commits’ (provided there are no
- unpulled commits) show.
-
- -- Function: magit-insert-unpulled-cherries
-
- Insert section showing unpulled commits. Like
- ‘magit-insert-unpulled-commits’ but prefix each commit that has not
- been applied yet (i.e. a commit with a patch-id not shared with
- any local commit) with "+", and all others with "-".
-
- -- Function: magit-insert-unpushed-cherries
-
- Insert section showing unpushed commits. Like
- ‘magit-insert-unpushed-commits’ but prefix each commit which has
- not been applied to upstream yet (i.e. a commit with a patch-id
- not shared with any upstream commit) with "+" and all others with
- "-".
-
- See *note References Buffer:: for some more section inserters, which
-could be used here.
-
-\1f
-File: magit.info, Node: Status Header Sections, Next: Status Module Sections, Prev: Status Sections, Up: Status Buffer
-
-5.1.2 Status Header Sections
-----------------------------
-
-The contents of status buffers is controlled using the hook
-‘magit-status-sections-hook’ (see *note Status Sections::).
-
- By default ‘magit-insert-status-headers’ is the first member of that
-hook variable.
-
- -- Function: magit-insert-status-headers
-
- Insert headers sections appropriate for ‘magit-status-mode’
- buffers. The sections are inserted by running the functions on the
- hook ‘magit-status-headers-hook’.
-
- -- User Option: magit-status-headers-hook
-
- Hook run to insert headers sections into the status buffer.
-
- This hook is run by ‘magit-insert-status-headers’, which in turn
- has to be a member of ‘magit-status-sections-hook’ to be used at
- all.
-
- By default the following functions are members of the above hook:
-
- -- Function: magit-insert-error-header
-
- Insert a header line showing the message about the Git error that
- just occurred.
-
- This function is only aware of the last error that occur when Git
- was run for side-effects. If, for example, an error occurs while
- generating a diff, then that error won’t be inserted. Refreshing
- the status buffer causes this section to disappear again.
-
- -- Function: magit-insert-diff-filter-header
-
- Insert a header line showing the effective diff filters.
-
- -- Function: magit-insert-head-branch-header
-
- Insert a header line about the current branch or detached ‘HEAD’.
-
- -- Function: magit-insert-upstream-branch-header
-
- Insert a header line about the branch that is usually pulled into
- the current branch.
-
- -- Function: magit-insert-push-branch-header
-
- Insert a header line about the branch that the current branch is
- usually pushed to.
-
- -- Function: magit-insert-tags-header
-
- Insert a header line about the current and/or next tag, along with
- the number of commits between the tag and ‘HEAD’.
-
- The following functions can also be added to the above hook:
-
- -- Function: magit-insert-repo-header
-
- Insert a header line showing the path to the repository top-level.
-
- -- Function: magit-insert-remote-header
-
- Insert a header line about the remote of the current branch.
-
- If no remote is configured for the current branch, then fall back
- showing the "origin" remote, or if that does not exist the first
- remote in alphabetic order.
-
- -- Function: magit-insert-user-header
-
- Insert a header line about the current user.
-
-\1f
-File: magit.info, Node: Status Module Sections, Next: Status Options, Prev: Status Header Sections, Up: Status Buffer
-
-5.1.3 Status Module Sections
-----------------------------
-
-The contents of status buffers is controlled using the hook
-‘magit-status-sections-hook’ (see *note Status Sections::).
-
- By default ‘magit-insert-modules’ is _not_ a member of that hook
-variable.
-
- -- Function: magit-insert-modules
-
- Insert submodule sections.
-
- Hook ‘magit-module-sections-hook’ controls which module sections
- are inserted, and option ‘magit-module-sections-nested’ controls
- whether they are wrapped in an additional section.
-
- -- User Option: magit-module-sections-hook
-
- Hook run by ‘magit-insert-modules’.
-
- -- User Option: magit-module-sections-nested
-
- This option controls whether ‘magit-insert-modules’ wraps inserted
- sections in an additional section.
-
- If this is non-nil, then only a single top-level section is
- inserted. If it is nil, then all sections listed in
- ‘magit-module-sections-hook’ become top-level sections.
-
- -- Function: magit-insert-modules-overview
-
- Insert sections for all submodules. For each section insert the
- path, the branch, and the output of ‘git describe --tags’, or,
- failing that, the abbreviated HEAD commit hash.
-
- Press ‘RET’ on such a submodule section to show its own status
- buffer. Press ‘RET’ on the "Modules" section to display a list of
- submodules in a separate buffer. This shows additional information
- not displayed in the super-repository’s status buffer.
-
- -- Function: magit-insert-modules-unpulled-from-upstream
-
- Insert sections for modules that haven’t been pulled from the
- upstream yet. These sections can be expanded to show the
- respective commits.
-
- -- Function: magit-insert-modules-unpulled-from-pushremote
-
- Insert sections for modules that haven’t been pulled from the
- push-remote yet. These sections can be expanded to show the
- respective commits.
-
- -- Function: magit-insert-modules-unpushed-to-upstream
-
- Insert sections for modules that haven’t been pushed to the
- upstream yet. These sections can be expanded to show the
- respective commits.
-
- -- Function: magit-insert-modules-unpushed-to-pushremote
-
- Insert sections for modules that haven’t been pushed to the
- push-remote yet. These sections can be expanded to show the
- respective commits.
-
-\1f
-File: magit.info, Node: Status Options, Prev: Status Module Sections, Up: Status Buffer
-
-5.1.4 Status Options
---------------------
-
- -- User Option: magit-status-refresh-hook
-
- Hook run after a status buffer has been refreshed.
-
- -- User Option: magit-status-margin
-
- This option specifies whether the margin is initially shown in
- Magit-Status mode buffers and how it is formatted.
-
- The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’.
-
- • If INIT is non-nil, then the margin is shown initially.
-
- • STYLE controls how to format the author or committer date. It
- can be one of ‘age’ (to show the age of the commit),
- ‘age-abbreviated’ (to abbreviate the time unit to a
- character), or a string (suitable for ‘format-time-string’) to
- show the actual date. Option
- ‘magit-log-margin-show-committer-date’ controls which date is
- being displayed.
-
- • WIDTH controls the width of the margin. This exists for
- forward compatibility and currently the value should not be
- changed.
-
- • AUTHOR controls whether the name of the author is also shown
- by default.
-
- • AUTHOR-WIDTH has to be an integer. When the name of the
- author is shown, then this specifies how much space is used to
- do so.
-
- Also see the proceeding section for more options concerning status
-buffers.
-
-\1f
-File: magit.info, Node: Repository List, Next: Logging, Prev: Status Buffer, Up: Inspecting
-
-5.2 Repository List
-===================
-
- -- Command: magit-list-repositories
-
- This command displays a list of repositories in a separate buffer.
-
- The options ‘magit-repository-directories’ and
- ‘magit-repository-directories-depth’ control which repositories are
- displayed.
-
- -- User Option: magit-repolist-columns
-
- This option controls what columns are displayed by the command
- ‘magit-list-repositories’ and how they are displayed.
-
- Each element has the form ‘(HEADER WIDTH FORMAT PROPS)’.
-
- HEADER is the string displayed in the header. WIDTH is the width
- of the column. FORMAT is a function that is called with one
- argument, the repository identification (usually its basename), and
- with ‘default-directory’ bound to the toplevel of its working tree.
- It has to return a string to be inserted or nil. PROPS is an alist
- that supports the keys ‘:right-align’ and ‘:pad-right’.
-
- The following functions can be added to the above option:
-
- -- Function: magit-repolist-column-ident
-
- This function inserts the identification of the repository.
- Usually this is just its basename.
-
- -- Function: magit-repolist-column-path
-
- This function inserts the absolute path of the repository.
-
- -- Function: magit-repolist-column-version
-
- This function inserts a description of the repository’s ‘HEAD’
- revision.
-
- -- Function: magit-repolist-column-branch
-
- This function inserts the name of the current branch.
-
- -- Function: magit-repolist-column-upstream
-
- This function inserts the name of the upstream branch of the
- current branch.
-
- -- Function: magit-repolist-column-branches
-
- This function inserts the number of branches.
-
- -- Function: magit-repolist-column-stashes
-
- This function inserts the number of stashes.
-
- -- Function: magit-repolist-column-flag
-
- This function inserts a flag as specified by
- ‘magit-repolist-column-flag-alist’.
-
- By default this indicates whether there are uncommitted changes.
-
- • ‘N’ if there is at least one untracked file.
-
- • ‘U’ if there is at least one unstaged file.
-
- • ‘S’ if there is at least one staged file.
-
- Only the first one of these that applies is shown.
-
- -- Function: magit-repolist-column-unpulled-from-upstream
-
- This function inserts the number of upstream commits not in the
- current branch.
-
- -- Function: magit-repolist-column-unpulled-from-pushremote
-
- This function inserts the number of commits in the push branch but
- not the current branch.
-
- -- Function: magit-repolist-column-unpushed-to-upstream
-
- This function inserts the number of commits in the current branch
- but not its upstream.
-
- -- Function: magit-repolist-column-unpushed-to-pushremote
-
- This function inserts the number of commits in the current branch
- but not its push branch.
-
-\1f
-File: magit.info, Node: Logging, Next: Diffing, Prev: Repository List, Up: Inspecting
-
-5.3 Logging
-===========
-
-The status buffer contains logs for the unpushed and unpulled commits,
-but that obviously isn’t enough. The transient prefix command
-‘magit-log’, on ‘l’, features several suffix commands, which show a
-specific log in a separate log buffer.
-
- Like other transient prefix commands, ‘magit-log’ also features
-several infix arguments that can be changed before invoking one of the
-suffix commands. However, in the case of the log transient, these
-arguments may be taken from those currently in use in the current
-repository’s log buffer, depending on the value of
-‘magit-prefix-use-buffer-arguments’ (see *note Transient Arguments and
-Buffer Variables::).
-
- For information about the various arguments, see *note
-(gitman)git-log::.
-
- The switch ‘++order=VALUE’ is converted to one of
-‘--author-date-order’, ‘--date-order’, or ‘--topo-order’ before being
-passed to ‘git log’.
-
- The log transient also features several reflog commands. See *note
-Reflog::.
-
-‘l’ (‘magit-log’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
-‘l l’ (‘magit-log-current’)
-
- Show log for the current branch. When ‘HEAD’ is detached or with a
- prefix argument, show log for one or more revs read from the
- minibuffer.
-
-‘l o’ (‘magit-log-other’)
-
- Show log for one or more revs read from the minibuffer. The user
- can input any revision or revisions separated by a space, or even
- ranges, but only branches, tags, and a representation of the commit
- at point are available as completion candidates.
-
-‘l h’ (‘magit-log-head’)
-
- Show log for ‘HEAD’.
-
-‘l L’ (‘magit-log-branches’)
-
- Show log for all local branches and ‘HEAD’.
-
-‘l b’ (‘magit-log-all-branches’)
-
- Show log for all local and remote branches and ‘HEAD’.
-
-‘l a’ (‘magit-log-all’)
-
- Show log for all references and ‘HEAD’.
-
- Two additional commands that show the log for the file or blob that
-is being visited in the current buffer exists, see *note Commands for
-Buffers Visiting Files::. The command ‘magit-cherry’ also shows a log,
-see *note Cherries::.
-
-* Menu:
-
-* Refreshing Logs::
-* Log Buffer::
-* Log Margin::
-* Select from Log::
-* Reflog::
-* Cherries::
-
-\1f
-File: magit.info, Node: Refreshing Logs, Next: Log Buffer, Up: Logging
-
-5.3.1 Refreshing Logs
----------------------
-
-The transient prefix command ‘magit-log-refresh’, on ‘L’, can be used to
-change the log arguments used in the current buffer, without changing
-which log is shown. This works in dedicated log buffers, but also in
-the status buffer.
-
-‘L’ (‘magit-log-refresh’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
-‘L g’ (‘magit-log-refresh’)
-
- This suffix command sets the local log arguments for the current
- buffer.
-
-‘L s’ (‘magit-log-set-default-arguments’)
-
- This suffix command sets the default log arguments for buffers of
- the same type as that of the current buffer. Other existing
- buffers of the same type are not affected because their local
- values have already been initialized.
-
-‘L w’ (‘magit-log-save-default-arguments’)
-
- This suffix command sets the default log arguments for buffers of
- the same type as that of the current buffer, and saves the value
- for future sessions. Other existing buffers of the same type are
- not affected because their local values have already been
- initialized.
-
-‘L t’ (‘magit-toggle-margin’)
-
- Show or hide the margin.
-
-\1f
-File: magit.info, Node: Log Buffer, Next: Log Margin, Prev: Refreshing Logs, Up: Logging
-
-5.3.2 Log Buffer
-----------------
-
-‘L’ (‘magit-log-refresh’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
- See *note Refreshing Logs::.
-
-‘q’ (‘magit-log-bury-buffer’)
-
- Bury the current buffer or the revision buffer in the same frame.
- Like ‘magit-mode-bury-buffer’ (which see) but with a negative
- prefix argument instead bury the revision buffer, provided it is
- displayed in the current frame.
-
-‘C-c C-b’ (‘magit-go-backward’)
-
- Move backward in current buffer’s history.
-
-‘C-c C-f’ (‘magit-go-forward’)
-
- Move forward in current buffer’s history.
-
-‘C-c C-n’ (‘magit-log-move-to-parent’)
-
- Move to a parent of the current commit. By default, this is the
- first parent, but a numeric prefix can be used to specify another
- parent.
-
-‘SPC’ (‘magit-diff-show-or-scroll-up’)
-
- Update the commit or diff buffer for the thing at point.
-
- Either show the commit or stash at point in the appropriate buffer,
- or if that buffer is already being displayed in the current frame
- and contains information about that commit or stash, then instead
- scroll the buffer up. If there is no commit or stash at point,
- then prompt for a commit.
-
-‘DEL’ (‘magit-diff-show-or-scroll-down’)
-
- Update the commit or diff buffer for the thing at point.
-
- Either show the commit or stash at point in the appropriate buffer,
- or if that buffer is already being displayed in the current frame
- and contains information about that commit or stash, then instead
- scroll the buffer down. If there is no commit or stash at point,
- then prompt for a commit.
-
-‘=’ (‘magit-log-toggle-commit-limit’)
-
- Toggle the number of commits the current log buffer is limited to.
- If the number of commits is currently limited, then remove that
- limit. Otherwise set it to 256.
-
-‘+’ (‘magit-log-double-commit-limit’)
-
- Double the number of commits the current log buffer is limited to.
-
-‘-’ (‘magit-log-half-commit-limit’)
-
- Half the number of commits the current log buffer is limited to.
-
- -- User Option: magit-log-auto-more
-
- Insert more log entries automatically when moving past the last
- entry. Only considered when moving past the last entry with
- ‘magit-goto-*-section’ commands.
-
- -- User Option: magit-log-show-refname-after-summary
-
- Whether to show the refnames after the commit summaries. This is
- useful if you use really long branch names.
-
- Magit displays references in logs a bit differently from how Git does
-it.
-
- Local branches are blue and remote branches are green. Of course
-that depends on the used theme, as do the colors used for other types of
-references. The current branch has a box around it, as do remote
-branches that are their respective remote’s ‘HEAD’ branch.
-
- If a local branch and its push-target point at the same commit, then
-their names are combined to preserve space and to make that relationship
-visible. For example:
-
- origin/feature
- [green][blue-]
-
- instead of
-
- feature origin/feature
- [blue-] [green-------]
-
- Also note that while the transient features the ‘--show-signature’
-argument, that won’t actually be used when enabled, because Magit
-defaults to use just one line per commit. Instead the commit colorized
-to indicate the validity of the signed commit object, using the faces
-named ‘magit-signature-*’ (which see).
-
- For a description of ‘magit-log-margin’ see *note Log Margin::.
-
-\1f
-File: magit.info, Node: Log Margin, Next: Select from Log, Prev: Log Buffer, Up: Logging
-
-5.3.3 Log Margin
-----------------
-
-In buffers which show one or more logs, it is possible to show
-additional information about each commit in the margin. The options
-used to configure the margin are named ‘magit-INFIX-margin’, where INFIX
-is the same as in the respective major-mode ‘magit-INFIX-mode’. In
-regular log buffers that would be ‘magit-log-margin’.
-
- -- User Option: magit-log-margin
-
- This option specifies whether the margin is initially shown in
- Magit-Log mode buffers and how it is formatted.
-
- The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’.
-
- • If INIT is non-nil, then the margin is shown initially.
-
- • STYLE controls how to format the author or committer date. It
- can be one of ‘age’ (to show the age of the commit),
- ‘age-abbreviated’ (to abbreviate the time unit to a
- character), or a string (suitable for ‘format-time-string’) to
- show the actual date. Option
- ‘magit-log-margin-show-committer-date’ controls which date is
- being displayed.
-
- • WIDTH controls the width of the margin. This exists for
- forward compatibility and currently the value should not be
- changed.
-
- • AUTHOR controls whether the name of the author is also shown
- by default.
-
- • AUTHOR-WIDTH has to be an integer. When the name of the
- author is shown, then this specifies how much space is used to
- do so.
-
- You can change the STYLE and AUTHOR-WIDTH of all ‘magit-INFIX-margin’
-options to the same values by customizing ‘magit-log-margin’ *before*
-‘magit’ is loaded. If you do that, then the respective values for the
-other options will default to what you have set for that variable.
-Likewise if you set INIT in ‘magit-log-margin’ to ‘nil’, then that is
-used in the default of all other options. But setting it to ‘t’, i.e.
-re-enforcing the default for that option, does not carry to other
-options.
-
- -- User Option: magit-log-margin-show-committer-date
-
- This option specifies whether to show the committer date in the
- margin. This option only controls whether the committer date is
- displayed instead of the author date. Whether some date is
- displayed in the margin and whether the margin is displayed at all
- is controlled by other options.
-
-‘L’ (‘magit-margin-settings’)
-
- This transient prefix command binds the following suffix commands,
- each of which changes the appearance of the margin in some way.
-
- In some buffers that support the margin, ‘L’ is instead bound to
-‘magit-log-refresh’, but that transient features the same commands, and
-then some other unrelated commands.
-
-‘L L’ (‘magit-toggle-margin’)
-
- This command shows or hides the margin.
-
-‘L l’ (‘magit-cycle-margin-style’)
-
- This command cycles the style used for the margin.
-
-‘L d’ (‘magit-toggle-margin-details’)
-
- This command shows or hides details in the margin.
-
-\1f
-File: magit.info, Node: Select from Log, Next: Reflog, Prev: Log Margin, Up: Logging
-
-5.3.4 Select from Log
----------------------
-
-When the user has to select a recent commit that is reachable from
-‘HEAD’, using regular completion would be inconvenient (because most
-humans cannot remember hashes or "HEAD~5", at least not without double
-checking). Instead a log buffer is used to select the commit, which has
-the advantage that commits are presented in order and with the commit
-message.
-
- Such selection logs are used when selecting the beginning of a rebase
-and when selecting the commit to be squashed into.
-
- In addition to the key bindings available in all log buffers, the
-following additional key bindings are available in selection log
-buffers:
-
-‘C-c C-c’ (‘magit-log-select-pick’)
-
- Select the commit at point and act on it. Call
- ‘magit-log-select-pick-function’ with the selected commit as
- argument.
-
-‘C-c C-k’ (‘magit-log-select-quit’)
-
- Abort selecting a commit, don’t act on any commit.
-
- -- User Option: magit-log-select-margin
-
- This option specifies whether the margin is initially shown in
- Magit-Log-Select mode buffers and how it is formatted.
-
- The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’.
-
- • If INIT is non-nil, then the margin is shown initially.
-
- • STYLE controls how to format the author or committer date. It
- can be one of ‘age’ (to show the age of the commit),
- ‘age-abbreviated’ (to abbreviate the time unit to a
- character), or a string (suitable for ‘format-time-string’) to
- show the actual date. Option
- ‘magit-log-margin-show-committer-date’ controls which date is
- being displayed.
-
- • WIDTH controls the width of the margin. This exists for
- forward compatibility and currently the value should not be
- changed.
-
- • AUTHOR controls whether the name of the author is also shown
- by default.
-
- • AUTHOR-WIDTH has to be an integer. When the name of the
- author is shown, then this specifies how much space is used to
- do so.
-
-\1f
-File: magit.info, Node: Reflog, Next: Cherries, Prev: Select from Log, Up: Logging
-
-5.3.5 Reflog
-------------
-
-Also see *note (gitman)git-reflog::.
-
- These reflog commands are available from the log transient. See
-*note Logging::.
-
-‘l r’ (‘magit-reflog-current’)
-
- Display the reflog of the current branch.
-
-‘l O’ (‘magit-reflog-other’)
-
- Display the reflog of a branch or another ref.
-
-‘l H’ (‘magit-reflog-head’)
-
- Display the ‘HEAD’ reflog.
-
- -- User Option: magit-reflog-margin
-
- This option specifies whether the margin is initially shown in
- Magit-Reflog mode buffers and how it is formatted.
-
- The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’.
-
- • If INIT is non-nil, then the margin is shown initially.
-
- • STYLE controls how to format the author or committer date. It
- can be one of ‘age’ (to show the age of the commit),
- ‘age-abbreviated’ (to abbreviate the time unit to a
- character), or a string (suitable for ‘format-time-string’) to
- show the actual date. Option
- ‘magit-log-margin-show-committer-date’ controls which date is
- being displayed.
-
- • WIDTH controls the width of the margin. This exists for
- forward compatibility and currently the value should not be
- changed.
-
- • AUTHOR controls whether the name of the author is also shown
- by default.
-
- • AUTHOR-WIDTH has to be an integer. When the name of the
- author is shown, then this specifies how much space is used to
- do so.
-
-\1f
-File: magit.info, Node: Cherries, Prev: Reflog, Up: Logging
-
-5.3.6 Cherries
---------------
-
-Cherries are commits that haven’t been applied upstream (yet), and are
-usually visualized using a log. Each commit is prefixed with ‘-’ if it
-has an equivalent in the upstream and ‘+’ if it does not, i.e. if it is
-a cherry.
-
- The command ‘magit-cherry’ shows cherries for a single branch, but
-the references buffer (see *note References Buffer::) can show cherries
-for multiple "upstreams" at once.
-
- Also see *note (gitman)git-reflog::.
-
-‘Y’ (‘magit-cherry’)
-
- Show commits that are in a certain branch but that have not been
- merged in the upstream branch.
-
- -- User Option: magit-cherry-margin
-
- This option specifies whether the margin is initially shown in
- Magit-Cherry mode buffers and how it is formatted.
-
- The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’.
-
- • If INIT is non-nil, then the margin is shown initially.
-
- • STYLE controls how to format the author or committer date. It
- can be one of ‘age’ (to show the age of the commit),
- ‘age-abbreviated’ (to abbreviate the time unit to a
- character), or a string (suitable for ‘format-time-string’) to
- show the actual date. Option
- ‘magit-log-margin-show-committer-date’ controls which date is
- being displayed.
-
- • WIDTH controls the width of the margin. This exists for
- forward compatibility and currently the value should not be
- changed.
-
- • AUTHOR controls whether the name of the author is also shown
- by default.
-
- • AUTHOR-WIDTH has to be an integer. When the name of the
- author is shown, then this specifies how much space is used to
- do so.
-
-\1f
-File: magit.info, Node: Diffing, Next: Ediffing, Prev: Logging, Up: Inspecting
-
-5.4 Diffing
-===========
-
-The status buffer contains diffs for the staged and unstaged commits,
-but that obviously isn’t enough. The transient prefix command
-‘magit-diff’, on ‘d’, features several suffix commands, which show a
-specific diff in a separate diff buffer.
-
- Like other transient prefix commands, ‘magit-diff’ also features
-several infix arguments that can be changed before invoking one of the
-suffix commands. However, in the case of the diff transient, these
-arguments may be taken from those currently in use in the current
-repository’s diff buffer, depending on the value of
-‘magit-prefix-use-buffer-arguments’ (see *note Transient Arguments and
-Buffer Variables::).
-
- Also see *note (gitman)git-diff::.
-
-‘d’ (‘magit-diff’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
-‘d d’ (‘magit-diff-dwim’)
-
- Show changes for the thing at point.
-
-‘d r’ (‘magit-diff-range’)
-
- Show differences between two commits.
-
- RANGE should be a range (A..B or A...B) but can also be a single
- commit. If one side of the range is omitted, then it defaults to
- ‘HEAD’. If just a commit is given, then changes in the working
- tree relative to that commit are shown.
-
- If the region is active, use the revisions on the first and last
- line of the region. With a prefix argument, instead of diffing the
- revisions, choose a revision to view changes along, starting at the
- common ancestor of both revisions (i.e., use a "..." range).
-
-‘d w’ (‘magit-diff-working-tree’)
-
- Show changes between the current working tree and the ‘HEAD’
- commit. With a prefix argument show changes between the working
- tree and a commit read from the minibuffer.
-
-‘d s’ (‘magit-diff-staged’)
-
- Show changes between the index and the ‘HEAD’ commit. With a
- prefix argument show changes between the index and a commit read
- from the minibuffer.
-
-‘d u’ (‘magit-diff-unstaged’)
-
- Show changes between the working tree and the index.
-
-‘d p’ (‘magit-diff-paths’)
-
- Show changes between any two files on disk.
-
- All of the above suffix commands update the repository’s diff buffer.
-The diff transient also features two commands which show differences in
-another buffer:
-
-‘d c’ (‘magit-show-commit’)
-
- Show the commit at point. If there is no commit at point or with a
- prefix argument, prompt for a commit.
-
-‘d t’ (‘magit-stash-show’)
-
- Show all diffs of a stash in a buffer.
-
- Two additional commands that show the diff for the file or blob that
-is being visited in the current buffer exists, see *note Commands for
-Buffers Visiting Files::.
-
-* Menu:
-
-* Refreshing Diffs::
-* Commands Available in Diffs::
-* Diff Options::
-* Revision Buffer::
-
-\1f
-File: magit.info, Node: Refreshing Diffs, Next: Commands Available in Diffs, Up: Diffing
-
-5.4.1 Refreshing Diffs
-----------------------
-
-The transient prefix command ‘magit-diff-refresh’, on ‘D’, can be used
-to change the diff arguments used in the current buffer, without
-changing which diff is shown. This works in dedicated diff buffers, but
-also in the status buffer.
-
-‘D’ (‘magit-diff-refresh’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
-‘D g’ (‘magit-diff-refresh’)
-
- This suffix command sets the local diff arguments for the current
- buffer.
-
-‘D s’ (‘magit-diff-set-default-arguments’)
-
- This suffix command sets the default diff arguments for buffers of
- the same type as that of the current buffer. Other existing
- buffers of the same type are not affected because their local
- values have already been initialized.
-
-‘D w’ (‘magit-diff-save-default-arguments’)
-
- This suffix command sets the default diff arguments for buffers of
- the same type as that of the current buffer, and saves the value
- for future sessions. Other existing buffers of the same type are
- not affected because their local values have already been
- initialized.
-
-‘D t’ (‘magit-diff-toggle-refine-hunk’)
-
- This command toggles hunk refinement on or off.
-
-‘D r’ (‘magit-diff-switch-range-type’)
-
- This command converts the diff range type from "revA..revB" to
- "revB...revA", or vice versa.
-
-‘D f’ (‘magit-diff-flip-revs’)
-
- This command swaps revisions in the diff range from "revA..revB" to
- "revB..revA", or vice versa.
-
-‘D F’ (‘magit-diff-toggle-file-filter’)
-
- This command toggles the file restriction of the diffs in the
- current buffer, allowing you to quickly switch between viewing all
- the changes in the commit and the restricted subset. As a special
- case, when this command is called from a log buffer, it toggles the
- file restriction in the repository’s revision buffer, which is
- useful when you display a revision from a log buffer that is
- restricted to a file or files.
-
- In addition to the above transient, which allows changing any of the
-supported arguments, there also exist some commands that change only a
-particular argument.
-
-‘-’ (‘magit-diff-less-context’)
-
- This command decreases the context for diff hunks by COUNT lines.
-
-‘+’ (‘magit-diff-more-context’)
-
- This command increases the context for diff hunks by COUNT lines.
-
-‘0’ (‘magit-diff-default-context’)
-
- This command resets the context for diff hunks to the default
- height.
-
- The following commands quickly change what diff is being displayed
-without having to using one of the diff transient.
-
-‘C-c C-d’ (‘magit-diff-while-committing’)
-
- While committing, this command shows the changes that are about to
- be committed. While amending, invoking the command again toggles
- between showing just the new changes or all the changes that will
- be committed.
-
- This binding is available in the diff buffer as well as the commit
- message buffer.
-
-‘C-c C-b’ (‘magit-go-backward’)
-
- This command moves backward in current buffer’s history.
-
-‘C-c C-f’ (‘magit-go-forward’)
-
- This command moves forward in current buffer’s history.
-
-\1f
-File: magit.info, Node: Commands Available in Diffs, Next: Diff Options, Prev: Refreshing Diffs, Up: Diffing
-
-5.4.2 Commands Available in Diffs
----------------------------------
-
-Some commands are only available if point is inside a diff.
-
- ‘magit-diff-visit-file’ and related commands visit the appropriate
-version of the file that the diff at point is about. Likewise
-‘magit-diff-visit-worktree-file’ and related commands visit the worktree
-version of the file that the diff at point is about. See *note Visiting
-Files and Blobs from a Diff:: for more information and the key bindings.
-
-‘C-c C-t’ (‘magit-diff-trace-definition’)
-
- This command shows a log for the definition at point.
-
- -- User Option: magit-log-trace-definition-function
-
- The function specified by this option is used by
- ‘magit-log-trace-definition’ to determine the function at point.
- For major-modes that have special needs, you could set the local
- value using the mode’s hook.
-
-‘C-c C-e’ (‘magit-diff-edit-hunk-commit’)
-
- From a hunk, this command edits the respective commit and visits
- the file.
-
- First it visits the file being modified by the hunk at the correct
- location using ‘magit-diff-visit-file’. This actually visits a
- blob. When point is on a diff header, not within an individual
- hunk, then this visits the blob the first hunk is about.
-
- Then it invokes ‘magit-edit-line-commit’, which uses an interactive
- rebase to make the commit editable, or if that is not possible
- because the commit is not reachable from ‘HEAD’ by checking out
- that commit directly. This also causes the actual worktree file to
- be visited.
-
- Neither the blob nor the file buffer are killed when finishing the
- rebase. If that is undesirable, then it might be better to use
- ‘magit-rebase-edit-command’ instead of this command.
-
-‘j’ (‘magit-jump-to-diffstat-or-diff’)
-
- This command jumps to the diffstat or diff. When point is on a
- file inside the diffstat section, then jump to the respective diff
- section. Otherwise, jump to the diffstat section or a child
- thereof.
-
- The next two commands are not specific to Magit-Diff mode (or and
-Magit buffer for that matter), but it might be worth pointing out that
-they are available here too.
-
-‘SPC’ (‘scroll-up’)
-
- This command scrolls text upward.
-
-‘DEL’ (‘scroll-down’)
-
- This command scrolls text downward.
-
-\1f
-File: magit.info, Node: Diff Options, Next: Revision Buffer, Prev: Commands Available in Diffs, Up: Diffing
-
-5.4.3 Diff Options
-------------------
-
- -- User Option: magit-diff-refine-hunk
-
- Whether to show word-granularity differences within diff hunks.
-
- • ‘nil’ Never show fine differences.
-
- • ‘t’ Show fine differences for the current diff hunk only.
-
- • ‘all’ Show fine differences for all displayed diff hunks.
-
- -- User Option: magit-diff-refine-ignore-whitespace
-
- Whether to ignore whitespace changes in word-granularity
- differences.
-
- -- User Option: magit-diff-adjust-tab-width
-
- Whether to adjust the width of tabs in diffs.
-
- Determining the correct width can be expensive if it requires
- opening large and/or many files, so the widths are cached in the
- variable ‘magit-diff--tab-width-cache’. Set that to nil to
- invalidate the cache.
-
- • ‘nil’ Never adjust tab width. Use ‘tab-width’s value from the
- Magit buffer itself instead.
-
- • ‘t’ If the corresponding file-visiting buffer exits, then use
- ‘tab-width’’s value from that buffer. Doing this is cheap, so
- this value is used even if a corresponding cache entry exists.
-
- • ‘always’ If there is no such buffer, then temporarily visit
- the file to determine the value.
-
- • NUMBER Like ‘always’, but don’t visit files larger than NUMBER
- bytes.
-
- -- User Option: magit-diff-paint-whitespace
-
- Specify where to highlight whitespace errors.
-
- See ‘magit-diff-highlight-trailing’,
- ‘magit-diff-highlight-indentation’. The symbol ‘t’ means in all
- diffs, ‘status’ means only in the status buffer, and nil means
- nowhere.
-
- • ‘nil’ Never highlight whitespace errors.
-
- • ‘t’ Highlight whitespace errors everywhere.
-
- • ‘uncommitted’ Only highlight whitespace errors in diffs
- showing uncommitted changes. For backward compatibility
- ‘status’ is treated as a synonym.
-
- -- User Option: magit-diff-paint-whitespace-lines
-
- Specify in what kind of lines to highlight whitespace errors.
-
- • ‘t’ Highlight only in added lines.
-
- • ‘both’ Highlight in added and removed lines.
-
- • ‘all’ Highlight in added, removed and context lines.
-
- -- User Option: magit-diff-highlight-trailing
-
- Whether to highlight whitespace at the end of a line in diffs.
- Used only when ‘magit-diff-paint-whitespace’ is non-nil.
-
- -- User Option: magit-diff-highlight-indentation
-
- This option controls whether to highlight the indentation in case
- it used the "wrong" indentation style. Indentation is only
- highlighted if ‘magit-diff-paint-whitespace’ is also non-nil.
-
- The value is an alist of the form ‘((REGEXP . INDENT)...)’. The
- path to the current repository is matched against each element in
- reverse order. Therefore if a REGEXP matches, then earlier
- elements are not tried.
-
- If the used INDENT is ‘tabs’, highlight indentation with tabs. If
- INDENT is an integer, highlight indentation with at least that many
- spaces. Otherwise, highlight neither.
-
- -- User Option: magit-diff-hide-trailing-cr-characters
-
- Whether to hide ^M characters at the end of a line in diffs.
-
- -- User Option: magit-diff-highlight-hunk-region-functions
-
- This option specifies the functions used to highlight the
- hunk-internal region.
-
- ‘magit-diff-highlight-hunk-region-dim-outside’ overlays the outside
- of the hunk internal selection with a face that causes the added
- and removed lines to have the same background color as context
- lines. This function should not be removed from the value of this
- option.
-
- ‘magit-diff-highlight-hunk-region-using-overlays’ and
- ‘magit-diff-highlight-hunk-region-using-underline’ emphasize the
- region by placing delimiting horizontal lines before and after it.
- Both of these functions have glitches which cannot be fixed due to
- limitations of Emacs’ display engine. For more information see
- <https://github.com/magit/magit/issues/2758> ff.
-
- Instead of, or in addition to, using delimiting horizontal lines,
- to emphasize the boundaries, you may which to emphasize the text
- itself, using ‘magit-diff-highlight-hunk-region-using-face’.
-
- In terminal frames it’s not possible to draw lines as the overlay
- and underline variants normally do, so there they fall back to
- calling the face function instead.
-
- -- User Option: magit-diff-unmarked-lines-keep-foreground
-
- This option controls whether added and removed lines outside the
- hunk-internal region only lose their distinct background color or
- also the foreground color. Whether the outside of the region is
- dimmed at all depends on
- ‘magit-diff-highlight-hunk-region-functions’.
-
-\1f
-File: magit.info, Node: Revision Buffer, Prev: Diff Options, Up: Diffing
-
-5.4.4 Revision Buffer
----------------------
-
- -- User Option: magit-revision-insert-related-refs
-
- Whether to show related branches in revision buffers.
-
- • ‘nil’ Don’t show any related branches.
-
- • ‘t’ Show related local branches.
-
- • ‘all’ Show related local and remote branches.
-
- • ‘mixed’ Show all containing branches and local merged
- branches.
-
- -- User Option: magit-revision-show-gravatars
-
- Whether to show gravatar images in revision buffers.
-
- If ‘nil’, then don’t insert any gravatar images. If ‘t’, then
- insert both images. If ‘author’ or ‘committer’, then insert only
- the respective image.
-
- If you have customized the option ‘magit-revision-headers-format’
- and want to insert the images then you might also have to specify
- where to do so. In that case the value has to be a cons-cell of
- two regular expressions. The car specifies where to insert the
- author’s image. The top half of the image is inserted right after
- the matched text, the bottom half on the next line in the same
- column. The cdr specifies where to insert the committer’s image,
- accordingly. Either the car or the cdr may be nil."
-
- -- User Option: magit-revision-use-hash-sections
-
- Whether to turn hashes inside the commit message into sections.
-
- If non-nil, then hashes inside the commit message are turned into
- ‘commit’ sections. There is a trade off to be made between
- performance and reliability:
-
- • ‘slow’ calls git for every word to be absolutely sure.
-
- • ‘quick’ skips words less than seven characters long.
-
- • ‘quicker’ additionally skips words that don’t contain a
- number.
-
- • ‘quickest’ uses all words that are at least seven characters
- long and which contain at least one number as well as at least
- one letter.
-
- If nil, then no hashes are turned into sections, but you can still
- visit the commit at point using "RET".
-
- The diffs shown in the revision buffer may be automatically
-restricted to a subset of the changed files. If the revision buffer is
-displayed from a log buffer, the revision buffer will share the same
-file restriction as that log buffer (also see the command
-‘magit-diff-toggle-file-filter’).
-
- -- User Option: magit-revision-filter-files-on-follow
-
- Whether showing a commit from a log buffer honors the log’s file
- filter when the log arguments include ‘--follow’.
-
- When this option is nil, displaying a commit from a log ignores the
- log’s file filter if the log arguments include ‘--follow’. Doing
- so avoids showing an empty diff in revision buffers for commits
- before a rename event. In such cases, the ‘--patch’ argument of
- the log transient can be used to show the file-restricted diffs
- inline.
-
- Set this option to non-nil to keep the log’s file restriction even
- if ‘--follow’ is present in the log arguments.
-
- If the revision buffer is not displayed from a log buffer, the file
-restriction is determined as usual (see *note Transient Arguments and
-Buffer Variables::).
-
-\1f
-File: magit.info, Node: Ediffing, Next: References Buffer, Prev: Diffing, Up: Inspecting
-
-5.5 Ediffing
-============
-
-This section describes how to enter Ediff from Magit buffers. For
-information on how to use Ediff itself, see *note (ediff)Top::.
-
-‘e’ (‘magit-ediff-dwim’)
-
- Compare, stage, or resolve using Ediff.
-
- This command tries to guess what file, and what commit or range the
- user wants to compare, stage, or resolve using Ediff. It might
- only be able to guess either the file, or range/commit, in which
- case the user is asked about the other. It might not always guess
- right, in which case the appropriate ‘magit-ediff-*’ command has to
- be used explicitly. If it cannot read the user’s mind at all, then
- it asks the user for a command to run.
-
-‘E’ (‘magit-ediff’)
-
- This transient prefix command binds the following suffix commands
- and displays them in a temporary buffer until a suffix is invoked.
-
-‘E r’ (‘magit-ediff-compare’)
-
- Compare two revisions of a file using Ediff.
-
- If the region is active, use the revisions on the first and last
- line of the region. With a prefix argument, instead of diffing the
- revisions, choose a revision to view changes along, starting at the
- common ancestor of both revisions (i.e., use a "..." range).
-
-‘E m’ (‘magit-ediff-resolve’)
-
- Resolve outstanding conflicts in a file using Ediff, defaulting to
- the file at point.
-
- Provided that the value of ‘merge.conflictstyle’ is ‘diff3’, you
- can view the file’s merge-base revision using ‘/’ in the Ediff
- control buffer.
-
- In the rare event that you want to manually resolve all conflicts,
- including those already resolved by Git, use
- ‘ediff-merge-revisions-with-ancestor’.
-
-‘E s’ (‘magit-ediff-stage’)
-
- Stage and unstage changes to a file using Ediff, defaulting to the
- file at point.
-
-‘E u’ (‘magit-ediff-show-unstaged’)
-
- Show unstaged changes to a file using Ediff.
-
-‘E i’ (‘magit-ediff-show-staged’)
-
- Show staged changes to a file using Ediff.
-
-‘E w’ (‘magit-ediff-show-working-tree’)
-
- Show changes in a file between ‘HEAD’ and working tree using Ediff.
-
-‘E c’ (‘magit-ediff-show-commit’)
-
- Show changes to a file introduced by a commit using Ediff.
-
-‘E z’ (‘magit-ediff-show-stash’)
-
- Show changes to a file introduced by a stash using Ediff.
-
- -- User Option: magit-ediff-dwim-show-on-hunks
-
- This option controls what command ‘magit-ediff-dwim’ calls when
- point is on uncommitted hunks. When nil, always run
- ‘magit-ediff-stage’. Otherwise, use ‘magit-ediff-show-staged’ and
- ‘magit-ediff-show-unstaged’ to show staged and unstaged changes,
- respectively.
-
- -- User Option: magit-ediff-show-stash-with-index
-
- This option controls whether ‘magit-ediff-show-stash’ includes a
- buffer containing the file’s state in the index at the time the
- stash was created. This makes it possible to tell which changes in
- the stash were staged.
-
- -- User Option: magit-ediff-quit-hook
-
- This hook is run after quitting an Ediff session that was created
- using a Magit command. The hook functions are run inside the Ediff
- control buffer, and should not change the current buffer.
-
- This is similar to ‘ediff-quit-hook’ but takes the needs of Magit
- into account. The regular ‘ediff-quit-hook’ is ignored by Ediff
- sessions that were created using a Magit command.
-
-\1f
-File: magit.info, Node: References Buffer, Next: Bisecting, Prev: Ediffing, Up: Inspecting
-
-5.6 References Buffer
-=====================
-
-‘y’ (‘magit-show-refs’)
-
- This command lists branches and tags in a dedicated buffer.
-
- However if this command is invoked again from this buffer or if it
- is invoked with a prefix argument, then it acts as a transient
- prefix command, which binds the following suffix commands and some
- infix arguments.
-
- All of the following suffix commands list exactly the same branches
-and tags. The only difference the optional feature that can be enabled
-by changing the value of ‘magit-refs-show-commit-count’ (see below).
-These commands specify a different branch or commit against which all
-the other references are compared.
-
-‘y y’ (‘magit-show-refs-head’)
-
- This command lists branches and tags in a dedicated buffer. Each
- reference is being compared with ‘HEAD’.
-
-‘y c’ (‘magit-show-refs-current’)
-
- This command lists branches and tags in a dedicated buffer. Each
- reference is being compared with the current branch or ‘HEAD’ if it
- is detached.
-
-‘y o’ (‘magit-show-refs-other’)
-
- This command lists branches and tags in a dedicated buffer. Each
- reference is being compared with a branch read from the user.
-
- -- User Option: magit-refs-show-commit-count
-
- Whether to show commit counts in Magit-Refs mode buffers.
-
- • ‘all’ Show counts for branches and tags.
-
- • ‘branch’ Show counts for branches only.
-
- • ‘nil’ Never show counts.
-
- The default is ‘nil’ because anything else can be very expensive.
-
- -- User Option: magit-refs-pad-commit-counts
-
- Whether to pad all commit counts on all sides in Magit-Refs mode
- buffers.
-
- If this is nil, then some commit counts are displayed right next to
- one of the branches that appear next to the count, without any
- space in between. This might look bad if the branch name faces
- look too similar to ‘magit-dimmed’.
-
- If this is non-nil, then spaces are placed on both sides of all
- commit counts.
-
- -- User Option: magit-refs-show-remote-prefix
-
- Whether to show the remote prefix in lists of remote branches.
-
- Showing the prefix is redundant because the name of the remote is
- already shown in the heading preceding the list of its branches.
-
- -- User Option: magit-refs-primary-column-width
-
- Width of the primary column in ‘magit-refs-mode’ buffers. The
- primary column is the column that contains the name of the branch
- that the current row is about.
-
- If this is an integer, then the column is that many columns wide.
- Otherwise it has to be a cons-cell of two integers. The first
- specifies the minimal width, the second the maximal width. In that
- case the actual width is determined using the length of the names
- of the shown local branches. (Remote branches and tags are not
- taken into account when calculating to optimal width.)
-
- -- User Option: magit-refs-focus-column-width
-
- Width of the focus column in ‘magit-refs-mode’ buffers.
-
- The focus column is the first column, which marks one branch
- (usually the current branch) as the focused branch using ‘*’ or
- ‘@’. For each other reference, this column optionally shows how
- many commits it is ahead of the focused branch and ‘<’, or if it
- isn’t ahead then the commits it is behind and ‘>’, or if it isn’t
- behind either, then a ‘=’.
-
- This column may also display only ‘*’ or ‘@’ for the focused
- branch, in which case this option is ignored. Use ‘L v’ to change
- the verbosity of this column.
-
- -- User Option: magit-refs-margin
-
- This option specifies whether the margin is initially shown in
- Magit-Refs mode buffers and how it is formatted.
-
- The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’.
-
- • If INIT is non-nil, then the margin is shown initially.
-
- • STYLE controls how to format the author or committer date. It
- can be one of ‘age’ (to show the age of the commit),
- ‘age-abbreviated’ (to abbreviate the time unit to a
- character), or a string (suitable for ‘format-time-string’) to
- show the actual date. Option
- ‘magit-log-margin-show-committer-date’ controls which date is
- being displayed.
-
- • WIDTH controls the width of the margin. This exists for
- forward compatibility and currently the value should not be
- changed.
-
- • AUTHOR controls whether the name of the author is also shown
- by default.
-
- • AUTHOR-WIDTH has to be an integer. When the name of the
- author is shown, then this specifies how much space is used to
- do so.
-
- -- User Option: magit-refs-margin-for-tags
-
- This option specifies whether to show information about tags in the
- margin. This is disabled by default because it is slow if there
- are many tags.
-
- The following variables control how individual refs are displayed.
-If you change one of these variables (especially the "%c" part), then
-you should also change the others to keep things aligned. The following
-%-sequences are supported:
-
- • ‘%a’ Number of commits this ref has over the one we compare to.
-
- • ‘%b’ Number of commits the ref we compare to has over this one.
-
- • ‘%c’ Number of commits this ref has over the one we compare to.
- For the ref which all other refs are compared this is instead "@",
- if it is the current branch, or "#" otherwise.
-
- • ‘%C’ For the ref which all other refs are compared this is "@", if
- it is the current branch, or "#" otherwise. For all other refs "
- ".
-
- • ‘%h’ Hash of this ref’s tip.
-
- • ‘%m’ Commit summary of the tip of this ref.
-
- • ‘%n’ Name of this ref.
-
- • ‘%u’ Upstream of this local branch.
-
- • ‘%U’ Upstream of this local branch and additional local vs.
- upstream information.
-
- -- User Option: magit-refs-filter-alist
-
- The purpose of this option is to forgo displaying certain refs
- based on their name. If you want to not display any refs of a
- certain type, then you should remove the appropriate function from
- ‘magit-refs-sections-hook’ instead.
-
- This alist controls which tags and branches are omitted from being
- displayed in ‘magit-refs-mode’ buffers. If it is ‘nil’, then all
- refs are displayed (subject to ‘magit-refs-sections-hook’).
-
- All keys are tried in order until one matches. Then its value is
- used and subsequent elements are ignored. If the value is non-nil,
- then the reference is displayed, otherwise it is not. If no
- element matches, then the reference is displayed.
-
- A key can either be a regular expression that the refname has to
- match, or a function that takes the refname as only argument and
- returns a boolean. A remote branch such as "origin/master" is
- displayed as just "master", however for this comparison the former
- is used.
-
-‘RET’ (‘magit-visit-ref’)
-
- This command visits the reference or revision at point in another
- buffer. If there is no revision at point or with a prefix argument
- then it prompts for a revision.
-
- This command behaves just like ‘magit-show-commit’ as described
- above, except if point is on a reference in a ‘magit-refs-mode’
- buffer, in which case the behavior may be different, but only if
- you have customized the option ‘magit-visit-ref-behavior’.
-
- -- User Option: magit-visit-ref-behavior
-
- This option controls how ‘magit-visit-ref’ behaves in
- ‘magit-refs-mode’ buffers.
-
- By default ‘magit-visit-ref’ behaves like ‘magit-show-commit’, in
- all buffers, including ‘magit-refs-mode’ buffers. When the type of
- the section at point is ‘commit’ then "RET" is bound to
- ‘magit-show-commit’, and when the type is either ‘branch’ or ‘tag’
- then it is bound to ‘magit-visit-ref’.
-
- "RET" is one of Magit’s most essential keys and at least by default
- it should behave consistently across all of Magit, especially
- because users quickly learn that it does something very harmless;
- it shows more information about the thing at point in another
- buffer.
-
- However "RET" used to behave differently in ‘magit-refs-mode’
- buffers, doing surprising things, some of which cannot really be
- described as "visit this thing". If you’ve grown accustomed this
- behavior, you can restore it by adding one or more of the below
- symbols to the value of this option. But keep in mind that by
- doing so you don’t only introduce inconsistencies, you also lose
- some functionality and might have to resort to ‘M-x
- magit-show-commit’ to get it back.
-
- ‘magit-visit-ref’ looks for these symbols in the order in which
- they are described here. If the presence of a symbol applies to
- the current situation, then the symbols that follow do not affect
- the outcome.
-
- • ‘focus-on-ref’
-
- With a prefix argument update the buffer to show commit counts
- and lists of cherry commits relative to the reference at point
- instead of relative to the current buffer or ‘HEAD’.
-
- Instead of adding this symbol, consider pressing "C-u y o
- RET".
-
- • ‘create-branch’
-
- If point is on a remote branch, then create a new local branch
- with the same name, use the remote branch as its upstream, and
- then check out the local branch.
-
- Instead of adding this symbol, consider pressing "b c RET
- RET", like you would do in other buffers.
-
- • ‘checkout-any’
-
- Check out the reference at point. If that reference is a tag
- or a remote branch, then this results in a detached ‘HEAD’.
-
- Instead of adding this symbol, consider pressing "b b RET",
- like you would do in other buffers.
-
- • ‘checkout-branch’
-
- Check out the local branch at point.
-
- Instead of adding this symbol, consider pressing "b b RET",
- like you would do in other buffers.
-
-* Menu:
-
-* References Sections::
-
-\1f
-File: magit.info, Node: References Sections, Up: References Buffer
-
-5.6.1 References Sections
--------------------------
-
-The contents of references buffers is controlled using the hook
-‘magit-refs-sections-hook’. See *note Section Hooks:: to learn about
-such hooks and how to customize them. All of the below functions are
-members of the default value. Note that it makes much less sense to
-customize this hook than it does for the respective hook used for the
-status buffer.
-
- -- User Option: magit-refs-sections-hook
-
- Hook run to insert sections into a references buffer.
-
- -- Function: magit-insert-local-branches
-
- Insert sections showing all local branches.
-
- -- Function: magit-insert-remote-branches
-
- Insert sections showing all remote-tracking branches.
-
- -- Function: magit-insert-tags
-
- Insert sections showing all tags.
-
-\1f
-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 and
- a bad commit.
-
-‘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 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.
-
-\1f
-File: magit.info, Node: Visiting Files and Blobs, Next: Blaming, Prev: Bisecting, Up: Inspecting
-
-5.8 Visiting Files and Blobs
-============================
-
-Magit provides several commands that visit a file or blob (the version
-of a file that is stored in a certain commit). Actually it provides
-several *groups* of such commands and the several *variants* within each
-group.
-
-* Menu:
-
-* General-Purpose Visit Commands::
-* Visiting Files and Blobs from a Diff::
-
-\1f
-File: magit.info, Node: General-Purpose Visit Commands, Next: Visiting Files and Blobs from a Diff, Up: Visiting Files and Blobs
-
-5.8.1 General-Purpose Visit Commands
-------------------------------------
-
-These commands can be used anywhere to open any blob. Currently no keys
-are bound to these commands by default, but that is likely to change.
-
- -- Command: magit-find-file
-
- This command reads a filename and revision from the user and visits
- the respective blob in a buffer. The buffer is displayed in the
- selected window.
-
- -- Command: magit-find-file-other-window
-
- This command reads a filename and revision from the user and visits
- the respective blob in a buffer. The buffer is displayed in
- another window.
-
- -- Command: magit-find-file-other-frame
-
- This command reads a filename and revision from the user and visits
- the respective blob in a buffer. The buffer is displayed in
- another frame.
-
-\1f
-File: magit.info, Node: Visiting Files and Blobs from a Diff, Prev: General-Purpose Visit Commands, Up: Visiting Files and Blobs
-
-5.8.2 Visiting Files and Blobs from a Diff
-------------------------------------------
-
-These commands can only be used when point is inside a diff.
-
-‘RET’ (‘magit-diff-visit-file’)
-
- This command visits the appropriate version of the file that the
- diff at point is about.
-
- This commands visits the worktree version of the appropriate file.
- The location of point inside the diff determines which file is
- being visited. The visited version depends on what changes the
- diff is about.
-
- • If the diff shows uncommitted changes (i.e. staged or
- unstaged changes), then visit the file in the working tree
- (i.e. the same "real" file that ‘find-file’ would visit. In
- all other cases visit a "blob" (i.e. the version of a file as
- stored in some commit).
-
- • If point is on a removed line, then visit the blob for the
- first parent of the commit that removed that line, i.e. the
- last commit where that line still exists.
-
- • If point is on an added or context line, then visit the blob
- that adds that line, or if the diff shows from more than a
- single commit, then visit the blob from the last of these
- commits.
-
- In the file-visiting buffer this command goes to the line that
- corresponds to the line that point is on in the diff.
-
- The buffer is displayed in the selected window. With a prefix
- argument the buffer is displayed in another window instead.
-
- -- User Option: magit-diff-visit-previous-blob
-
- This option controls whether ‘magit-diff-visit-file’ may visit the
- previous blob. When this is ‘t’ (the default) and point is on a
- removed line in a diff for a committed change, then
- ‘magit-diff-visit-file’ visits the blob from the last revision
- which still had that line.
-
- Currently this is only supported for committed changes, for staged
- and unstaged changes ‘magit-diff-visit-file’ always visits the file
- in the working tree.
-
-‘C-<return>’ (‘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
-
-\1f
-File: magit.info, Node: Blaming, Prev: Visiting Files and Blobs, Up: Inspecting
-
-5.9 Blaming
-===========
-
-Also see *note (gitman)git-blame::.
-
- To start blaming invoke the ‘magit-file-dispatch’ transient prefix
-command by pressing ‘C-c M-g’.
-
- The blaming suffix commands can be invoked from the dispatch
-transient. However if you want to set an infix argument, then you have
-to enter the blaming sub-transient first.
-
- The key bindings shown below assume that you enter the dispatch
-transient using the default binding.
-
-‘C-c M-g B’ (‘magit-blame’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
- Note that not all of the following suffixes are available at all
-times. For example if ‘magit-blame-mode’ is not enabled, then the
-command whose purpose is to turn off that mode would not be of any use
-and therefore isn’t available.
-
-‘C-c M-g b’ (‘magit-blame-addition’)
-‘C-c M-g B b’ (‘magit-blame-addition’)
-
- This command augments each line or chunk of lines in the current
- file-visiting or blob-visiting buffer with information about what
- commits last touched these lines.
-
- If the buffer visits a revision of that file, then history up to
- that revision is considered. Otherwise, the file’s full history is
- considered, including uncommitted changes.
-
- If Magit-Blame mode is already turned on in the current buffer then
- blaming is done recursively, by visiting REVISION:FILE (using
- ‘magit-find-file’), where REVISION is a parent of the revision that
- added the current line or chunk of lines.
-
-‘C-c M-g r’ (‘magit-blame-removal’)
-‘C-c M-g B r’ (‘magit-blame-removal’)
-
- This command augments each line or chunk of lines in the current
- blob-visiting buffer with information about the revision that
- removes it. It cannot be used in file-visiting buffers.
-
- Like ‘magit-blame-addition’, this command can be used recursively.
-
-‘C-c M-g f’ (‘magit-blame-reverse’)
-‘C-c M-g B f’ (‘magit-blame-reverse’)
-
- This command augments each line or chunk of lines in the current
- file-visiting or blob-visiting buffer with information about the
- last revision in which a line still existed.
-
- Like ‘magit-blame-addition’, this command can be used recursively.
-
-‘C-c M-g e’ (‘magit-blame-echo’)
-‘C-c M-g B e’ (‘magit-blame-echo’)
-
- This command is like ‘magit-blame-addition’ except that it doesn’t
- turn on ‘read-only-mode’ and that it initially uses the
- visualization style specified by option ‘magit-blame-echo-style’.
-
- The following key bindings are available when Magit-Blame mode is
-enabled and Read-Only mode is not enabled. These commands are also
-available in other buffers; here only the behavior is described that is
-relevant in file-visiting buffers that are being blamed.
-
-‘RET’ (‘magit-show-commit’)
-
- This command shows the commit that last touched the line at point.
-
-‘SPC’ (‘magit-diff-show-or-scroll-up’)
-
- This command updates the commit buffer.
-
- This either shows the commit that last touched the line at point in
- the appropriate buffer, or if that buffer is already being
- displayed in the current frame and if that buffer contains
- information about that commit, then the buffer is scrolled up
- instead.
-
-‘DEL’ (‘magit-diff-show-or-scroll-down’)
-
- This command updates the commit buffer.
-
- This either shows the commit that last touched the line at point in
- the appropriate buffer, or if that buffer is already being
- displayed in the current frame and if that buffer contains
- information about that commit, then the buffer is scrolled down
- instead.
-
- The following key bindings are available when both Magit-Blame mode
-and Read-Only mode are enabled.
-
-‘b’ (‘magit-blame’)
-
- See above.
-
-‘n’ (‘magit-blame-next-chunk’)
-
- This command moves to the next chunk.
-
-‘N’ (‘magit-blame-next-chunk-same-commit’)
-
- This command moves to the next chunk from the same commit.
-
-‘p’ (‘magit-blame-previous-chunk’)
-
- This command moves to the previous chunk.
-
-‘P’ (‘magit-blame-previous-chunk-same-commit’)
-
- This command moves to the previous chunk from the same commit.
-
-‘q’ (‘magit-blame-quit’)
-
- This command turns off Magit-Blame mode. If the buffer was created
- during a recursive blame, then it also kills the buffer.
-
-‘M-w’ (‘magit-blame-copy-hash’)
-
- This command saves the hash of the current chunk’s commit to the
- kill ring.
-
- When the region is active, the command saves the region’s content
- instead of the hash, like ‘kill-ring-save’ would.
-
-‘c’ (‘magit-blame-cycle-style’)
-
- This command changes how blame information is visualized in the
- current buffer by cycling through the styles specified using the
- option ‘magit-blame-styles’.
-
- Blaming is also controlled using the following options.
-
- -- User Option: magit-blame-styles
-
- This option defines a list of styles used to visualize blame
- information. For now see its doc-string to learn more.
-
- -- User Option: magit-blame-echo-style
-
- This option specifies the blame visualization style used by the
- command ‘magit-blame-echo’. This must be a symbol that is used as
- the identifier for one of the styles defined in
- ‘magit-blame-styles’.
-
- -- User Option: magit-blame-time-format
-
- This option specifies the format string used to display times when
- showing blame information.
-
- -- User Option: magit-blame-read-only
-
- This option controls whether blaming a buffer also makes
- temporarily read-only.
-
- -- User Option: magit-blame-disable-modes
-
- This option lists incompatible minor-modes that should be disabled
- temporarily when a buffer contains blame information. They are
- enabled again when the buffer no longer shows blame information.
-
- -- User Option: magit-blame-goto-chunk-hook
-
- This hook is run when moving between chunks.
-
-\1f
-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::
-
-\1f
-File: magit.info, Node: Creating Repository, Next: Cloning Repository, Up: Manipulating
-
-6.1 Creating Repository
-=======================
-
-‘M-x magit-init’ (‘magit-init’)
-
- This command initializes a repository and then shows the status
- buffer for the new repository.
-
- If the directory is below an existing repository, then the user has
- to confirm that a new one should be created inside. If the
- directory is the root of the existing repository, then the user has
- to confirm that it should be reinitialized.
-
-\1f
-File: magit.info, Node: Cloning Repository, Next: Staging and Unstaging, Prev: Creating Repository, Up: Manipulating
-
-6.2 Cloning Repository
-======================
-
-To clone a remote or local repository use ‘C’, which is bound to the
-command ‘magit-clone’. This command either act as a transient prefix
-command, which binds several infix arguments and suffix commands, or it
-can invoke ‘git clone’ directly, depending on whether a prefix argument
-is used and on the value of ‘magit-clone-always-transient’.
-
- -- User Option: magit-clone-always-transient
-
- This option controls whether the command ‘magit-clone’ always acts
- as a transient prefix command, regardless of whether a prefix
- argument is used or not. If ‘t’, then that command always acts as
- a transient prefix. If ‘nil’, then a prefix argument has to be
- used for it to act as a transient.
-
-‘C’ (‘magit-clone’)
-
- This command either acts as a transient prefix command as described
- above or does the same thing as ‘transient-clone-regular’ as
- described below.
-
- If it acts as a transient prefix, then it binds the following
- suffix commands and several infix arguments.
-
-‘C C’ (‘magit-clone-regular’)
-
- This command creates a regular clone of an existing repository.
- The repository and the target directory are read from the user.
-
-‘C s’ (‘magit-clone-shallow’)
-
- This command creates a shallow clone of an existing repository.
- The repository and the target directory are read from the user. By
- default the depth of the cloned history is a single commit, but
- with a prefix argument the depth is read from the user.
-
-‘C b’ (‘magit-clone-bare’)
-
- This command creates a bare clone of an existing repository. The
- repository and the target directory are read from the user.
-
-‘C m’ (‘magit-clone-mirror’)
-
- This command creates a mirror of an existing repository. The
- repository and the target directory are read from the user.
-
- The following suffixes are disabled by default. See *note
-(transient)Enabling and Disabling Suffixes:: for how to enable them.
-
-‘C d’ (‘magit-clone-shallow-since’)
-
- This command creates a shallow clone of an existing repository.
- Only commits that were committed after a date are cloned, which is
- read from the user. The repository and the target directory are
- also read from the user.
-
-‘C e’ (‘magit-clone-shallow-exclude’)
-
- This command creates a shallow clone of an existing repository.
- This reads a branch or tag from the user. Commits that are
- reachable from that are not cloned. The repository and the target
- directory are also read from the user.
-
- -- User Option: magit-clone-set-remote-head
-
- This option controls whether cloning causes the reference
- ‘refs/remotes/<remote>/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.
-
-\1f
-File: magit.info, Node: Staging and Unstaging, Next: Applying, Prev: Cloning Repository, Up: Manipulating
-
-6.3 Staging and Unstaging
-=========================
-
-Like Git, Magit can of course stage and unstage complete files. Unlike
-Git, it also allows users to gracefully un-/stage individual hunks and
-even just part of a hunk. To stage individual hunks and parts of hunks
-using Git directly, one has to use the very modal and rather clumsy
-interface of a ‘git add --interactive’ session.
-
- With Magit, on the other hand, one can un-/stage individual hunks by
-just moving point into the respective section inside a diff displayed in
-the status buffer or a separate diff buffer and typing ‘s’ or ‘u’. To
-operate on just parts of a hunk, mark the changes that should be
-un-/staged using the region and then press the same key that would be
-used to un-/stage. To stage multiple files or hunks at once use a
-region that starts inside the heading of such a section and ends inside
-the heading of a sibling section of the same type.
-
- Besides staging and unstaging, Magit also provides several other
-"apply variants" that can also operate on a file, multiple files at
-once, a hunk, multiple hunks at once, and on parts of a hunk. These
-apply variants are described in the next section.
-
- You can also use Ediff to stage and unstage. See *note Ediffing::.
-
-‘s’ (‘magit-stage’)
-
- Add the change at point to the staging area.
-
- With a prefix argument and an untracked file (or files) at point,
- stage the file but not its content. This makes it possible to
- stage only a subset of the new file’s changes.
-
-‘S’ (‘magit-stage-modified’)
-
- Stage all changes to files modified in the worktree. Stage all new
- content of tracked files and remove tracked files that no longer
- exist in the working tree from the index also. With a prefix
- argument also stage previously untracked (but not ignored) files.
-
-‘u’ (‘magit-unstage’)
-
- Remove the change at point from the staging area.
-
- Only staged changes can be unstaged. But by default this command
- performs an action that is somewhat similar to unstaging, when it
- is called on a committed change: it reverses the change in the
- index but not in the working tree.
-
-‘U’ (‘magit-unstage-all’)
-
- Remove all changes from the staging area.
-
- -- User Option: magit-unstage-committed
-
- This option controls whether ‘magit-unstage’ "unstages" committed
- changes by reversing them in the index but not the working tree.
- The alternative is to raise an error.
-
-‘M-x magit-reverse-in-index’ (‘magit-reverse-in-index’)
-
- This command reverses the committed change at point in the index
- but not the working tree. By default no key is bound directly to
- this command, but it is indirectly called when ‘u’
- (‘magit-unstage’) is pressed on a committed change.
-
- This allows extracting a change from ‘HEAD’, while leaving it in
- the working tree, so that it can later be committed using a
- separate commit. A typical workflow would be:
-
- • Optionally make sure that there are no uncommitted changes.
-
- • Visit the ‘HEAD’ commit and navigate to the change that should
- not have been included in that commit.
-
- • Type ‘u’ (‘magit-unstage’) to reverse it in the index. This
- assumes that ‘magit-unstage-committed-changes’ is non-nil.
-
- • Type ‘c e’ to extend ‘HEAD’ with the staged changes, including
- those that were already staged before.
-
- • Optionally stage the remaining changes using ‘s’ or ‘S’ and
- then type ‘c c’ to create a new commit.
-
-‘M-x magit-reset-index’ (‘magit-reset-index’)
-
- Reset the index to some commit. The commit is read from the user
- and defaults to the commit at point. If there is no commit at
- point, then it defaults to ‘HEAD’.
-
-* Menu:
-
-* Staging from File-Visiting Buffers::
-
-\1f
-File: magit.info, Node: Staging from File-Visiting Buffers, Up: Staging and Unstaging
-
-6.3.1 Staging from File-Visiting Buffers
-----------------------------------------
-
-Fine-grained un-/staging has to be done from the status or a diff
-buffer, but it’s also possible to un-/stage all changes made to the file
-visited in the current buffer right from inside that buffer.
-
-‘M-x magit-stage-file’ (‘magit-stage-file’)
-
- When invoked inside a file-visiting buffer, then stage all changes
- to that file. In a Magit buffer, stage the file at point if any.
- Otherwise prompt for a file to be staged. With a prefix argument
- always prompt the user for a file, even in a file-visiting buffer
- or when there is a file section at point.
-
-‘M-x magit-unstage-file’ (‘magit-unstage-file’)
-
- When invoked inside a file-visiting buffer, then unstage all
- changes to that file. In a Magit buffer, unstage the file at point
- if any. Otherwise prompt for a file to be unstaged. With a prefix
- argument always prompt the user for a file, even in a file-visiting
- buffer or when there is a file section at point.
-
-\1f
-File: magit.info, Node: Applying, Next: Committing, Prev: Staging and Unstaging, Up: Manipulating
-
-6.4 Applying
-============
-
-Magit provides several "apply variants": stage, unstage, discard,
-reverse, and "regular apply". At least when operating on a hunk they
-are all implemented using ‘git apply’, which is why they are called
-"apply variants".
-
- • Stage. Apply a change from the working tree to the index. The
- change also remains in the working tree.
-
- • Unstage. Remove a change from the index. The change remains in
- the working tree.
-
- • Discard. On a staged change, remove it from the working tree and
- the index. On an unstaged change, remove it from the working tree
- only.
-
- • Reverse. Reverse a change in the working tree. Both committed and
- staged changes can be reversed. Unstaged changes cannot be
- reversed. Discard them instead.
-
- • Apply. Apply a change to the working tree. Both committed and
- staged changes can be applied. Unstaged changes cannot be applied
- - as they already have been applied.
-
- The previous section described the staging and unstaging commands.
-What follows are the commands which implement the remaining apply
-variants.
-
-‘a’ (‘magit-apply’)
-
- Apply the change at point to the working tree.
-
- With a prefix argument fallback to a 3-way merge. Doing so causes
- the change to be applied to the index as well.
-
-‘k’ (‘magit-discard’)
-
- Remove the change at point from the working tree.
-
-‘v’ (‘magit-reverse’)
-
- Reverse the change at point in the working tree.
-
- With a prefix argument fallback to a 3-way merge. Doing so causes
- the change to be applied to the index as well.
-
- With a prefix argument all apply variants attempt a 3-way merge when
-appropriate (i.e. when ‘git apply’ is used internally).
-
-\1f
-File: magit.info, Node: Committing, Next: Branching, Prev: Applying, Up: Manipulating
-
-6.5 Committing
-==============
-
-When the user initiates a commit, Magit calls ‘git commit’ without any
-arguments, so Git has to get it from the user. It creates the file
-‘.git/COMMIT_EDITMSG’ and then opens that file in an editor. Magit
-arranges for that editor to be the Emacsclient. Once the user finishes
-the editing session, the Emacsclient exits and Git creates the commit
-using the file’s content as message.
-
-* Menu:
-
-* Initiating a Commit::
-* Editing Commit Messages::
-
-\1f
-File: magit.info, Node: Initiating a Commit, Next: Editing Commit Messages, Up: Committing
-
-6.5.1 Initiating a Commit
--------------------------
-
-Also see *note (gitman)git-commit::.
-
-‘c’ (‘magit-commit’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
-‘c c’ (‘magit-commit-create’)
-
- Create a new commit on ‘HEAD’. With a prefix argument amend to the
- commit at ‘HEAD’ instead.
-
-‘c a’ (‘magit-commit-amend’)
-
- Amend the last commit.
-
-‘c e’ (‘magit-commit-extend’)
-
- Amend the last commit, without editing the message. With a prefix
- argument keep the committer date, otherwise change it. The option
- ‘magit-commit-extend-override-date’ can be used to inverse the
- meaning of the prefix argument.
-
- Non-interactively respect the optional OVERRIDE-DATE argument and
- ignore the option.
-
-‘c w’ (‘magit-commit-reword’)
-
- Reword the last commit, ignoring staged changes. With a prefix
- argument keep the committer date, otherwise change it. The option
- ‘magit-commit-reword-override-date’ can be used to inverse the
- meaning of the prefix argument.
-
- Non-interactively respect the optional OVERRIDE-DATE argument and
- ignore the option.
-
-‘c f’ (‘magit-commit-fixup’)
-
- Create a fixup commit.
-
- With a prefix argument the target commit has to be confirmed.
- Otherwise the commit at point may be used without confirmation
- depending on the value of option ‘magit-commit-squash-confirm’.
-
-‘c F’ (‘magit-commit-instant-fixup’)
-
- Create a fixup commit and instantly rebase.
-
-‘c s’ (‘magit-commit-squash’)
-
- Create a squash commit, without editing the squash message.
-
- With a prefix argument the target commit has to be confirmed.
- Otherwise the commit at point may be used without confirmation
- depending on the value of option ‘magit-commit-squash-confirm’.
-
-‘c S’ (‘magit-commit-instant-squash’)
-
- Create a squash commit and instantly rebase.
-
-‘c A’ (‘magit-commit-augment’)
-
- Create a squash commit, editing the squash message.
-
- With a prefix argument the target commit has to be confirmed.
- Otherwise the commit at point may be used without confirmation
- depending on the value of option ‘magit-commit-squash-confirm’.
-
- -- User Option: magit-commit-ask-to-stage
-
- Whether to ask to stage all unstaged changes when committing and
- nothing is staged.
-
- -- User Option: magit-commit-extend-override-date
-
- Whether using ‘magit-commit-extend’ changes the committer date.
-
- -- User Option: magit-commit-reword-override-date
-
- Whether using ‘magit-commit-reword’ changes the committer date.
-
- -- User Option: magit-commit-squash-confirm
-
- Whether the commit targeted by squash and fixup has to be
- confirmed. When non-nil then the commit at point (if any) is used
- as default choice. Otherwise it has to be confirmed. This option
- only affects ‘magit-commit-squash’ and ‘magit-commit-fixup’. The
- "instant" variants always require confirmation because making an
- error while using those is harder to recover from.
-
-\1f
-File: magit.info, Node: Editing Commit Messages, Prev: Initiating a Commit, Up: Committing
-
-6.5.2 Editing Commit Messages
------------------------------
-
-After initiating a commit as described in the previous section, two new
-buffers appear. One shows the changes that are about to be committed,
-while the other is used to write the message.
-
- Commit messages are edited in an edit session - in the background
-‘git’ is waiting for the editor, in our case ‘emacsclient’, to save the
-commit message in a file (in most cases ‘.git/COMMIT_EDITMSG’) and then
-return. If the editor returns with a non-zero exit status then ‘git’
-does not create the commit. So the most important commands are those
-for finishing and aborting the commit.
-
-‘C-c C-c’ (‘with-editor-finish’)
-
- Finish the current editing session by returning with exit code 0.
- Git then creates the commit using the message it finds in the file.
-
-‘C-c C-k’ (‘with-editor-cancel’)
-
- Cancel the current editing session by returning with exit code 1.
- Git then cancels the commit, but leaves the file untouched.
-
- In addition to being used by ‘git commit’, messages may also be
-stored in a ring that persists until Emacs is closed. By default the
-message is stored at the beginning and the end of an edit session
-(regardless of whether the session is finished successfully or was
-canceled). It is sometimes useful to bring back messages from that
-ring.
-
-‘C-c M-s’ (‘git-commit-save-message’)
-
- Save the current buffer content to the commit message ring.
-
-‘M-p’ (‘git-commit-prev-message’)
-
- Cycle backward through the commit message ring, after saving the
- current message to the ring. With a numeric prefix ARG, go back
- ARG comments.
-
-‘M-n’ (‘git-commit-next-message’)
-
- Cycle forward through the commit message ring, after saving the
- current message to the ring. With a numeric prefix ARG, go back
- ARG comments.
-
- By default the diff for the changes that are about to be committed
-are automatically shown when invoking the commit. To prevent that,
-remove ‘magit-commit-diff’ from ‘server-switch-hook’.
-
- When amending to an existing commit it may be useful to show either
-the changes that are about to be added to that commit or to show those
-changes alongside those that have already been committed.
-
-‘C-c C-d’ (‘magit-diff-while-committing’)
-
- While committing, show the changes that are about to be committed.
- While amending, invoking the command again toggles between showing
- just the new changes or all the changes that will be committed.
-
-* Menu:
-
-* Using the Revision Stack::
-* Commit Pseudo Headers::
-* Commit Mode and Hooks::
-* Commit Message Conventions::
-
-\1f
-File: magit.info, Node: Using the Revision Stack, Next: Commit Pseudo Headers, Up: Editing Commit Messages
-
-Using the Revision Stack
-........................
-
-‘C-c C-w’ (‘magit-pop-revision-stack’)
-
- This command inserts a representation of a revision into the
- current buffer. It can be used inside buffers used to write commit
- messages but also in other buffers such as buffers used to edit
- emails or ChangeLog files.
-
- By default this command pops the revision which was last added to
- the ‘magit-revision-stack’ and inserts it into the current buffer
- according to ‘magit-pop-revision-stack-format’. Revisions can be
- put on the stack using ‘magit-copy-section-value’ and
- ‘magit-copy-buffer-revision’.
-
- If the stack is empty or with a prefix argument it instead reads a
- revision in the minibuffer. By using the minibuffer history this
- allows selecting an item which was popped earlier or to insert an
- arbitrary reference or revision without first pushing it onto the
- stack.
-
- When reading the revision from the minibuffer, then it might not be
- possible to guess the correct repository. When this command is
- called inside a repository (e.g. while composing a commit
- message), then that repository is used. Otherwise (e.g. while
- composing an email) then the repository recorded for the top
- element of the stack is used (even though we insert another
- revision). If not called inside a repository and with an empty
- stack, or with two prefix arguments, then read the repository in
- the minibuffer too.
-
- -- User Option: magit-pop-revision-stack-format
-
- This option controls how the command ‘magit-pop-revision-stack’
- inserts a revision into the current buffer.
-
- The entries on the stack have the format ‘(HASH TOPLEVEL)’ and this
- option has the format ‘(POINT-FORMAT EOB-FORMAT INDEX-REGEXP)’, all
- of which may be nil or a string (though either one of EOB-FORMAT or
- POINT-FORMAT should be a string, and if INDEX-REGEXP is non-nil,
- then the two formats should be too).
-
- First INDEX-REGEXP is used to find the previously inserted entry,
- by searching backward from point. The first submatch must match
- the index number. That number is incremented by one, and becomes
- the index number of the entry to be inserted. If you don’t want to
- number the inserted revisions, then use nil for INDEX-REGEXP.
-
- If INDEX-REGEXP is non-nil then both POINT-FORMAT and EOB-FORMAT
- should contain \"%N\", which is replaced with the number that was
- determined in the previous step.
-
- Both formats, if non-nil and after removing %N, are then expanded
- using ‘git show --format=FORMAT ...’ inside TOPLEVEL.
-
- The expansion of POINT-FORMAT is inserted at point, and the
- expansion of EOB-FORMAT is inserted at the end of the buffer (if
- the buffer ends with a comment, then it is inserted right before
- that).
-
-\1f
-File: magit.info, Node: Commit Pseudo Headers, Next: Commit Mode and Hooks, Prev: Using the Revision Stack, Up: Editing Commit Messages
-
-Commit Pseudo Headers
-.....................
-
-Some projects use pseudo headers in commit messages. Magit colorizes
-such headers and provides some commands to insert such headers.
-
- -- User Option: git-commit-known-pseudo-headers
-
- A list of Git pseudo headers to be highlighted.
-
-‘C-c C-i’ (‘git-commit-insert-pseudo-header’)
-
- Insert a commit message pseudo header.
-
-‘C-c C-a’ (‘git-commit-ack’)
-
- Insert a header acknowledging that you have looked at the commit.
-
-‘C-c C-r’ (‘git-commit-review’)
-
- Insert a header acknowledging that you have reviewed the commit.
-
-‘C-c C-s’ (‘git-commit-signoff’)
-
- Insert a header to sign off the commit.
-
-‘C-c C-t’ (‘git-commit-test’)
-
- Insert a header acknowledging that you have tested the commit.
-
-‘C-c C-o’ (‘git-commit-cc’)
-
- Insert a header mentioning someone who might be interested.
-
-‘C-c C-p’ (‘git-commit-reported’)
-
- Insert a header mentioning the person who reported the issue being
- fixed by the commit.
-
-‘C-c M-i’ (‘git-commit-suggested’)
-
- Insert a header mentioning the person who suggested the change.
-
-\1f
-File: magit.info, Node: Commit Mode and Hooks, Next: Commit Message Conventions, Prev: Commit Pseudo Headers, Up: Editing Commit Messages
-
-Commit Mode and Hooks
-.....................
-
-‘git-commit-mode’ is a minor mode that is only used to establish certain
-key bindings. This makes it possible to use an arbitrary major mode in
-buffers used to edit commit messages. It is even possible to use
-different major modes in different repositories, which is useful when
-different projects impose different commit message conventions.
-
- -- User Option: git-commit-major-mode
-
- The value of this option is the major mode used to edit Git commit
- messages.
-
- Because ‘git-commit-mode’ is a minor mode, we don’t use its mode hook
-to setup the buffer, except for the key bindings. All other setup
-happens in the function ‘git-commit-setup’, which among other things
-runs the hook ‘git-commit-setup-hook’.
-
- -- User Option: git-commit-setup-hook
-
- Hook run at the end of ‘git-commit-setup’.
-
-The following functions are suitable for this hook:
-
- -- Function: git-commit-save-message
-
- Save the current buffer content to the commit message ring.
-
- -- Function: git-commit-setup-changelog-support
-
- After this function is called, ChangeLog entries are treated as
- paragraphs.
-
- -- Function: git-commit-turn-on-auto-fill
-
- Turn on ‘auto-fill-mode’ and set ‘fill-column’ to the value of
- ‘git-commit-fill-column’.
-
- -- Function: git-commit-turn-on-flyspell
-
- Turn on Flyspell mode. Also prevent comments from being checked
- and finally check current non-comment text.
-
- -- Function: git-commit-propertize-diff
-
- Propertize the diff shown inside the commit message buffer. Git
- inserts such diffs into the commit message template when the
- ‘--verbose’ argument is used. ‘magit-commit’ by default does not
- offer that argument because the diff that is shown in a separate
- buffer is more useful. But some users disagree, which is why this
- function exists.
-
- -- Function: bug-reference-mode
-
- Hyperlink bug references in the buffer.
-
- -- Function: with-editor-usage-message
-
- Show usage information in the echo area.
-
- -- User Option: git-commit-setup-hook
-
- Hook run after the user finished writing a commit message.
-
- This hook is only run after pressing ‘C-c C-c’ in a buffer used to
- edit a commit message. If a commit is created without the user
- typing a message into a buffer, then this hook is not run.
-
- This hook is not run until the new commit has been created. If
- doing so takes Git longer than one second, then this hook isn’t run
- at all. For certain commands such as ‘magit-rebase-continue’ this
- hook is never run because doing so would lead to a race condition.
-
- This hook is only run if ‘magit’ is available.
-
- Also see ‘magit-post-commit-hook’.
-
-\1f
-File: magit.info, Node: Commit Message Conventions, Prev: Commit Mode and Hooks, Up: Editing Commit Messages
-
-Commit Message Conventions
-..........................
-
-Git-Commit highlights certain violations of commonly accepted commit
-message conventions. Certain violations even cause Git-Commit to ask
-you to confirm that you really want to do that. This nagging can of
-course be turned off, but the result of doing that usually is that
-instead of some code it’s now the human who is reviewing your commits
-who has to waste some time telling you to fix your commits.
-
- -- User Option: git-commit-summary-max-length
-
- The intended maximal length of the summary line of commit messages.
- Characters beyond this column are colorized to indicate that this
- preference has been violated.
-
- -- User Option: git-commit-fill-column
-
- Column beyond which automatic line-wrapping should happen in commit
- message buffers.
-
- -- User Option: git-commit-finish-query-functions
-
- List of functions called to query before performing commit.
-
- The commit message buffer is current while the functions are
- called. If any of them returns nil, then the commit is not
- performed and the buffer is not killed. The user should then fix
- the issue and try again.
-
- The functions are called with one argument. If it is non-nil then
- that indicates that the user used a prefix argument to force
- finishing the session despite issues. Functions should usually
- honor this wish and return non-nil.
-
- By default the only member is ‘git-commit-check-style-conventions’.
-
- -- Function: git-commit-check-style-conventions
-
- This function checks for violations of certain basic style
- conventions. For each violation it asks users if they want to
- proceed anyway.
-
- -- User Option: git-commit-style-convention-checks
-
- This option controls what conventions the function by the same name
- tries to enforce. The value is a list of self-explanatory symbols
- identifying certain conventions; ‘non-empty-second-line’ and
- ‘overlong-summary-line’.
-
-\1f
-File: magit.info, Node: Branching, Next: Merging, Prev: Committing, Up: Manipulating
-
-6.6 Branching
-=============
-
-* Menu:
-
-* The Two Remotes::
-* Branch Commands::
-* Branch Git Variables::
-* Auxiliary Branch Commands::
-
-\1f
-File: magit.info, Node: The Two Remotes, Next: Branch Commands, Up: Branching
-
-6.6.1 The Two Remotes
----------------------
-
-The upstream branch of some local branch is the branch into which the
-commits on that local branch should eventually be merged, usually
-something like ‘origin/master’. For the ‘master’ branch itself the
-upstream branch and the branch it is being pushed to, are usually the
-same remote branch. But for a feature branch the upstream branch and
-the branch it is being pushed to should differ.
-
- The commits on feature branches too should _eventually_ end up in a
-remote branch such as ‘origin/master’ or ‘origin/maint’. Such a branch
-should therefore be used as the upstream. But feature branches
-shouldn’t be pushed directly to such branches. Instead a feature branch
-‘my-feature’ is usually pushed to ‘my-fork/my-feature’ or if you are a
-contributor ‘origin/my-feature’. After the new feature has been
-reviewed, the maintainer merges the feature into ‘master’. And finally
-‘master’ (not ‘my-feature’ itself) is pushed to ‘origin/master’.
-
- But new features seldom are perfect on the first try, and so feature
-branches usually have to be reviewed, improved, and re-pushed several
-times. Pushing should therefore be easy to do, and for that reason many
-Git users have concluded that it is best to use the remote branch to
-which the local feature branch is being pushed as its upstream.
-
- But luckily Git has long ago gained support for a push-remote which
-can be configured separately from the upstream branch, using the
-variables ‘branch.<name>.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::).
-
-\1f
-File: magit.info, Node: Branch Commands, Next: Branch Git Variables, Prev: The Two Remotes, Up: Branching
-
-6.6.2 Branch Commands
----------------------
-
-The transient prefix command ‘magit-branch’ is used to create and
-checkout branches, and to make changes to existing branches. It is not
-used to fetch, pull, merge, rebase, or push branches, i.e. this command
-deals with branches themselves, not with the commits reachable from
-them. Those features are available from separate transient command.
-
-‘b’ (‘magit-branch’)
-
- This transient prefix command binds the following suffix commands
- and displays them in a temporary buffer until a suffix is invoked.
-
- By default it also binds and displays the values of some
- branch-related Git variables and allows changing their values.
-
- -- User Option: magit-branch-direct-configure
-
- This option controls whether the transient command ‘magit-branch’
- can be used directly change the values Git variables. This
- defaults to ‘t’ (to avoid changing key bindings). When set to
- ‘nil’, then no variables are displayed by that transient command,
- and its suffix command ‘magit-branch-configure’ has to be used
- instead to view and change branch related variables.
-
-‘b C’ (‘magit-branch-configure’)
-‘f C’ (‘magit-branch-configure’)
-‘F C’ (‘magit-branch-configure’)
-‘P C’ (‘magit-branch-configure’)
-
- This transient prefix command binds commands that set the value of
- branch-related variables and displays them in a temporary buffer
- until the transient is exited.
-
- With a prefix argument, this command always prompts for a branch.
-
- Without a prefix argument this depends on whether it was invoked as
- a suffix of ‘magit-branch’ and on the
- ‘magit-branch-direct-configure’ option. If ‘magit-branch’ already
- displays the variables for the current branch, then it isn’t useful
- to invoke another transient that displays them for the same branch.
- In that case this command prompts for a branch.
-
- The variables are described in *note Branch Git Variables::.
-
-‘b b’ (‘magit-checkout’)
-
- Checkout a revision read in the minibuffer and defaulting to the
- branch or arbitrary revision at point. If the revision is a local
- branch then that becomes the current branch. If it is something
- else then ‘HEAD’ becomes detached. Checkout fails if the working
- tree or the staging area contain changes.
-
-‘b n’ (‘magit-branch-create’)
-
- Create a new branch. The user is asked for a branch or arbitrary
- revision to use as the starting point of the new branch. When a
- branch name is provided, then that becomes the upstream branch of
- the new branch. The name of the new branch is also read in the
- minibuffer.
-
- Also see option ‘magit-branch-prefer-remote-upstream’.
-
-‘b c’ (‘magit-branch-and-checkout’)
-
- This command creates a new branch like ‘magit-branch’, but then
- also checks it out.
-
- Also see option ‘magit-branch-prefer-remote-upstream’.
-
-‘b l’ (‘magit-branch-checkout’)
-
- This command checks out an existing or new local branch. It reads
- a branch name from the user offering all local branches and a
- subset of remote branches as candidates. Remote branches for which
- a local branch by the same name exists are omitted from the list of
- candidates. The user can also enter a completely new branch name.
-
- • If the user selects an existing local branch, then that is
- checked out.
-
- • If the user selects a remote branch, then it creates and
- checks out a new local branch with the same name, and
- configures the selected remote branch as the push target.
-
- • If the user enters a new branch name, then it creates and
- checks that out, after also reading the starting-point from
- the user.
-
- In the latter two cases the upstream is also set. Whether it is
- set to the chosen starting point or something else depends on the
- value of ‘magit-branch-adjust-remote-upstream-alist’.
-
-‘b s’ (‘magit-branch-spinoff’)
-
- This command creates and checks out a new branch starting at and
- tracking the current branch. That branch in turn is reset to the
- last commit it shares with its upstream. If the current branch has
- no upstream or no unpushed commits, then the new branch is created
- anyway and the previously current branch is not touched.
-
- This is useful to create a feature branch after work has already
- began on the old branch (likely but not necessarily "master").
-
- If the current branch is a member of the value of option
- ‘magit-branch-prefer-remote-upstream’ (which see), then the current
- branch will be used as the starting point as usual, but the
- upstream of the starting-point may be used as the upstream of the
- new branch, instead of the starting-point itself.
-
- If optional FROM is non-nil, then the source branch is reset to
- ‘FROM~’, instead of to the last commit it shares with its upstream.
- Interactively, FROM is only ever non-nil, if the region selects
- some commits, and among those commits, FROM is the commit that is
- the fewest commits ahead of the source branch.
-
- The commit at the other end of the selection actually does not
- matter, all commits between FROM and ‘HEAD’ are moved to the new
- branch. If FROM is not reachable from ‘HEAD’ or is reachable from
- the source branch’s upstream, then an error is raised.
-
-‘b S’ (‘magit-branch-spinout’)
-
- This command behaves like ‘magit-branch-spinoff’, except that it
- does not change the current branch. If there are any uncommitted
- changes, then it behaves exactly like ‘magit-branch-spinoff’.
-
-‘b x’ (‘magit-branch-reset’)
-
- This command resets a branch, defaulting to the branch at point, to
- the tip of another branch or any other commit.
-
- When the branch being reset is the current branch, then a hard
- reset is performed. If there are any uncommitted changes, then the
- user has to confirm the reset because those changes would be lost.
-
- This is useful when you have started work on a feature branch but
- realize it’s all crap and want to start over.
-
- When resetting to another branch and a prefix argument is used,
- then the target branch is set as the upstream of the branch that is
- being reset.
-
-‘b k’ (‘magit-branch-delete’)
-
- Delete one or multiple branches. If the region marks multiple
- branches, then offer to delete those. Otherwise, prompt for a
- single branch to be deleted, defaulting to the branch at point.
-
-‘b r’ (‘magit-branch-rename’)
-
- Rename a branch. The branch and the new name are read in the
- minibuffer. With prefix argument the branch is renamed even if
- that name conflicts with an existing branch.
-
- -- User Option: magit-branch-read-upstream-first
-
- When creating a branch, whether to read the upstream branch before
- the name of the branch that is to be created. The default is ‘t’,
- and I recommend you leave it at that.
-
- -- User Option: magit-branch-prefer-remote-upstream
-
- This option specifies whether remote upstreams are favored over
- local upstreams when creating new branches.
-
- When a new branch is created, then the branch, commit, or stash at
- point is suggested as the starting point of the new branch, or if
- there is no such revision at point the current branch. In either
- case the user may choose another starting point.
-
- If the chosen starting point is a branch, then it may also be set
- as the upstream of the new branch, depending on the value of the
- Git variable ‘branch.autoSetupMerge’. By default this is done for
- remote branches, but not for local branches.
-
- You might prefer to always use some remote branch as upstream. If
- the chosen starting point is (1) a local branch, (2) whose name
- matches a member of the value of this option, (3) the upstream of
- that local branch is a remote branch with the same name, and (4)
- that remote branch can be fast-forwarded to the local branch, then
- the chosen branch is used as starting point, but its own upstream
- is used as the upstream of the new branch.
-
- Members of this option’s value are treated as branch names that
- have to match exactly unless they contain a character that makes
- them invalid as a branch name. Recommended characters to use to
- trigger interpretation as a regexp are "*" and "^". Some other
- characters which you might expect to be invalid, actually are not,
- e.g. ".+$" are all perfectly valid. More precisely, if ‘git
- check-ref-format --branch STRING’ exits with a non-zero status,
- then treat STRING as a regexp.
-
- Assuming the chosen branch matches these conditions you would end
- up with with e.g.:
-
- feature --upstream--> origin/master
-
- instead of
-
- feature --upstream--> master --upstream--> origin/master
-
- Which you prefer is a matter of personal preference. If you do
- prefer the former, then you should add branches such as ‘master’,
- ‘next’, and ‘maint’ to the value of this options.
-
- -- User Option: magit-branch-adjust-remote-upstream-alist
-
- The value of this option is an alist of branches to be used as the
- upstream when branching a remote branch.
-
- When creating a local branch from an ephemeral branch located on a
- remote, e.g. a feature or hotfix branch, then that remote branch
- should usually not be used as the upstream branch, since the
- push-remote already allows accessing it and having both the
- upstream and the push-remote reference the same related branch
- would be wasteful. Instead a branch like "maint" or "master"
- should be used as the upstream.
-
- This option allows specifying the branch that should be used as the
- upstream when branching certain remote branches. The value is an
- alist of the form ‘((UPSTREAM . RULE)...)’. The first matching
- element is used, the following elements are ignored.
-
- UPSTREAM is the branch to be used as the upstream for branches
- specified by RULE. It can be a local or a remote branch.
-
- RULE can either be a regular expression, matching branches whose
- upstream should be the one specified by UPSTREAM. Or it can be a
- list of the only branches that should *not* use UPSTREAM; all other
- branches will. Matching is done after stripping the remote part of
- the name of the branch that is being branched from.
-
- If you use a finite set of non-ephemeral branches across all your
- repositories, then you might use something like:
-
- (("origin/master" "master" "next" "maint"))
-
- Or if the names of all your ephemeral branches contain a slash, at
- least in some repositories, then a good value could be:
-
- (("origin/master" . "/"))
-
- Of course you can also fine-tune:
-
- (("origin/maint" . "\\`hotfix/")
- ("origin/master" . "\\`feature/"))
-
- -- 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))
-
-\1f
-File: magit.info, Node: Branch Git Variables, Next: Auxiliary Branch Commands, Prev: Branch Commands, Up: Branching
-
-6.6.3 Branch Git Variables
---------------------------
-
-These variables can be set from the transient prefix command
-‘magit-branch-configure’. By default they can also be set from
-‘magit-branch’. See *note Branch Commands::.
-
- -- Variable: branch.NAME.merge
-
- Together with ‘branch.NAME.remote’ this variable defines the
- upstream branch of the local branch named NAME. The value of this
- variable is the full reference of the upstream _branch_.
-
- -- Variable: branch.NAME.remote
-
- Together with ‘branch.NAME.merge’ this variable defines the
- upstream branch of the local branch named NAME. The value of this
- variable is the name of the upstream _remote_.
-
- -- Variable: branch.NAME.rebase
-
- This variable controls whether pulling into the branch named NAME
- is done by rebasing or by merging the fetched branch.
-
- • When ‘true’ then pulling is done by rebasing.
-
- • When ‘false’ then pulling is done by merging.
-
- • When undefined then the value of ‘pull.rebase’ is used. The
- default of that variable is ‘false’.
-
- -- Variable: branch.NAME.pushRemote
-
- This variable specifies the remote that the branch named NAME is
- usually pushed to. The value has to be the name of an existing
- remote.
-
- It is not possible to specify the name of _branch_ to push the
- local branch to. The name of the remote branch is always the same
- as the name of the local branch.
-
- If this variable is undefined but ‘remote.pushDefault’ is defined,
- then the value of the latter is used. By default
- ‘remote.pushDefault’ is undefined.
-
- -- Variable: branch.NAME.description
-
- This variable can be used to describe the branch named NAME. That
- description is used e.g. when turning the branch into a series of
- patches.
-
- The following variables specify defaults which are used if the above
-branch-specific variables are not set.
-
- -- Variable: pull.rebase
-
- This variable specifies whether pulling is done by rebasing or by
- merging. It can be overwritten using ‘branch.NAME.rebase’.
-
- • When ‘true’ then pulling is done by rebasing.
-
- • When ‘false’ (the default) then pulling is done by merging.
-
- Since it is never a good idea to merge the upstream branch into a
- feature or hotfix branch and most branches are such branches, you
- should consider setting this to ‘true’, and ‘branch.master.rebase’
- to ‘false’.
-
- -- Variable: remote.pushDefault
-
- This variable specifies what remote the local branches are usually
- pushed to. This can be overwritten per branch using
- ‘branch.NAME.pushRemote’.
-
- The following variables are used during the creation of a branch and
-control whether the various branch-specific variables are automatically
-set at this time.
-
- -- Variable: branch.autoSetupMerge
-
- This variable specifies under what circumstances creating a branch
- NAME should result in the variables ‘branch.NAME.merge’ and
- ‘branch.NAME.remote’ being set according to the starting point used
- to create the branch. If the starting point isn’t a branch, then
- these variables are never set.
-
- • When ‘always’ then the variables are set regardless of whether
- the starting point is a local or a remote branch.
-
- • When ‘true’ (the default) then the variables are set when the
- starting point is a remote branch, but not when it is a local
- branch.
-
- • When ‘false’ then the variables are never set.
-
- -- Variable: branch.autoSetupRebase
-
- This variable specifies whether creating a branch NAME should
- result in the variable ‘branch.NAME.rebase’ being set to ‘true’.
-
- • When ‘always’ then the variable is set regardless of whether
- the starting point is a local or a remote branch.
-
- • When ‘local’ then the variable are set when the starting point
- is a local branch, but not when it is a remote branch.
-
- • When ‘remote’ then the variable are set when the starting
- point is a remote branch, but not when it is a local branch.
-
- • When ‘never’ (the default) then the variable is never set.
-
- Note that the respective commands always change the repository-local
-values. If you want to change the global value, which is used when the
-local value is undefined, then you have to do so on the command line,
-e.g.:
-
- git config --global remote.autoSetupMerge always
-
- For more information about these variables you should also see
-
- *note (gitman)git-config::. Also see *note (gitman)git-branch::. ,
-*note (gitman)git-checkout::. and *note Pushing::.
-
- -- User Option: magit-prefer-remote-upstream
-
- This option controls whether commands that read a branch from the
- user and then set it as the upstream branch, offer a local or a
- remote branch as default completion candidate, when they have the
- choice.
-
- This affects all commands that use ‘magit-read-upstream-branch’ or
- ‘magit-read-starting-point’, which includes all commands that
- change the upstream and many which create new branches.
-
-\1f
-File: magit.info, Node: Auxiliary Branch Commands, Prev: Branch Git Variables, Up: Branching
-
-6.6.4 Auxiliary Branch Commands
--------------------------------
-
-These commands are not available from the transient ‘magit-branch’ by
-default.
-
- -- Command: magit-branch-shelve
-
- This command shelves a branch. This is done by deleting the
- branch, and creating a new reference "refs/shelved/BRANCH-NAME"
- pointing at the same commit as the branch pointed at. If the
- deleted branch had a reflog, then that is preserved as the reflog
- of the new reference.
-
- This is useful if you want to move a branch out of sight, but are
- not ready to completely discard it yet.
-
- -- Command: magit-branch-unshelve
-
- This command unshelves a branch that was previously shelved using
- ‘magit-branch-shelve’. This is done by deleting the reference
- "refs/shelved/BRANCH-NAME" and creating a branch "BRANCH-NAME"
- pointing at the same commit as the deleted reference pointed at.
- If the deleted reference had a reflog, then that is restored as the
- reflog of the branch.
-
-\1f
-File: magit.info, Node: Merging, Next: Resolving Conflicts, Prev: Branching, Up: Manipulating
-
-6.7 Merging
-===========
-
-Also see *note (gitman)git-merge::. For information on how to resolve
-merge conflicts see the next section.
-
-‘m’ (‘magit-merge’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
- When no merge is in progress, then the transient features the
-following suffix commands.
-
-‘m m’ (‘magit-merge-plain’)
-
- This command merges another branch or an arbitrary revision into
- the current branch. The branch or revision to be merged is read in
- the minibuffer and defaults to the branch at point.
-
- Unless there are conflicts or a prefix argument is used, then the
- resulting merge commit uses a generic commit message, and the user
- does not get a chance to inspect or change it before the commit is
- created. With a prefix argument this does not actually create the
- merge commit, which makes it possible to inspect how conflicts were
- resolved and to adjust the commit message.
-
-‘m e’ (‘magit-merge-editmsg’)
-
- This command merges another branch or an arbitrary revision into
- the current branch and opens a commit message buffer, so that the
- user can make adjustments. The commit is not actually created
- until the user finishes with ‘C-c C-c’.
-
-‘m n’ (‘magit-merge-nocommit’)
-
- This command merges another branch or an arbitrary revision into
- the current branch, but does not actually create the merge commit.
- The user can then further adjust the merge, even when automatic
- conflict resolution succeeded and/or adjust the commit message.
-
-‘m a’ (‘magit-merge-absorb’)
-
- This command merges another local branch into the current branch
- and then removes the former.
-
- Before the source branch is merged, it is first force pushed to its
- push-remote, provided the respective remote branch already exists.
- This ensures that the respective pull-request (if any) won’t get
- stuck on some obsolete version of the commits that are being
- merged. Finally, if ‘magit-branch-pull-request’ was used to create
- the merged branch, then the respective remote branch is also
- removed.
-
-‘m i’ (‘magit-merge-into’)
-
- This command merges the current branch into another local branch
- and then removes the former. The latter becomes the new current
- branch.
-
- Before the source branch is merged, it is first force pushed to its
- push-remote, provided the respective remote branch already exists.
- This ensures that the respective pull-request (if any) won’t get
- stuck on some obsolete version of the commits that are being
- merged. Finally, if ‘magit-branch-pull-request’ was used to create
- the merged branch, then the respective remote branch is also
- removed.
-
-‘m s’ (‘magit-merge-squash’)
-
- This command squashes the changes introduced by another branch or
- an arbitrary revision into the current branch. This only applies
- the changes made by the squashed commits. No information is
- preserved that would allow creating an actual merge commit.
- Instead of this command you should probably use a command from the
- apply transient.
-
-‘m p’ (‘magit-merge-preview’)
-
- This command shows a preview of merging another branch or an
- arbitrary revision into the current branch.
-
- When a merge is in progress, then the transient instead features the
-following suffix commands.
-
-‘m m’ (‘magit-merge’)
-
- After the user resolved conflicts, this command proceeds with the
- merge. If some conflicts weren’t resolved, then this command
- fails.
-
-‘m a’ (‘magit-merge-abort’)
-
- This command aborts the current merge operation.
-
-\1f
-File: magit.info, Node: Resolving Conflicts, Next: Rebasing, Prev: Merging, Up: Manipulating
-
-6.8 Resolving Conflicts
-=======================
-
-When merging branches (or otherwise combining or changing history)
-conflicts can occur. If you edited two completely different parts of
-the same file in two branches and then merge one of these branches into
-the other, then Git can resolve that on its own, but if you edit the
-same area of a file, then a human is required to decide how the two
-versions, or "sides of the conflict", are to be combined into one.
-
- Here we can only provide a brief introduction to the subject and
-point you toward some tools that can help. If you are new to this, then
-please also consult Git’s own documentation as well as other resources.
-
- If a file has conflicts and Git cannot resolve them by itself, then
-it puts both versions into the affected file along with special markers
-whose purpose is to denote the boundaries of the unresolved part of the
-file and between the different versions. These boundary lines begin
-with the strings consisting of six times the same character, one of ‘<’,
-‘|’, ‘=’ and ‘>’ and are followed by information about the source of the
-respective versions, e.g.:
-
- <<<<<<< HEAD
- Take the blue pill.
- =======
- Take the red pill.
- >>>>>>> feature
-
- In this case you have chosen to take the red pill on one branch and
-on another you picked the blue pill. Now that you are merging these two
-diverging branches, Git cannot possibly know which pill you want to
-take.
-
- To resolve that conflict you have to create a version of the affected
-area of the file by keeping only one of the sides, possibly by editing
-it in order to bring in the changes from the other side, remove the
-other versions as well as the markers, and then stage the result. A
-possible resolution might be:
-
- Take both pills.
-
- Often it is useful to see not only the two sides of the conflict but
-also the "original" version from before the same area of the file was
-modified twice on different branches. Instruct Git to insert that
-version as well by running this command once:
-
- git config --global merge.conflictStyle diff3
-
- The above conflict might then have looked like this:
-
- <<<<<<< HEAD
- Take the blue pill.
- ||||||| merged common ancestors
- Take either the blue or the red pill, but not both.
- =======
- Take the red pill.
- >>>>>>> feature
-
- If that were the case, then the above conflict resolution would not
-have been correct, which demonstrates why seeing the original version
-alongside the conflicting versions can be useful.
-
- You can perform the conflict resolution completely by hand, but Emacs
-also provides some packages that help in the process: Smerge, Ediff
-(*note (ediff)Top::), and Emerge (*note (emacs)Emerge::). Magit does
-not provide its own tools for conflict resolution, but it does make
-using Smerge and Ediff more convenient. (Ediff supersedes Emerge, so
-you probably don’t want to use the latter anyway.)
-
- In the Magit status buffer, files with unresolved conflicts are
-listed in the "Unstaged changes" and/or "Staged changes" sections. They
-are prefixed with the word "unmerged", which in this context essentially
-is a synonym for "unresolved".
-
- Pressing ‘RET’ while point is on such a file section shows a buffer
-visiting that file, turns on ‘smerge-mode’ in that buffer, and places
-point inside the first area with conflicts. You should then resolve
-that conflict using regular edit commands and/or Smerge commands.
-
- Unfortunately Smerge does not have a manual, but you can get a list
-of commands and binding ‘C-c ^ C-h’ and press ‘RET’ while point is on a
-command name to read its documentation.
-
- Normally you would edit one version and then tell Smerge to keep only
-that version. Use ‘C-c ^ m’ (‘smerge-keep-mine’) to keep the ‘HEAD’
-version or ‘C-c ^ o’ (‘smerge-keep-other’) to keep the version that
-follows "|||||||". Then use ‘C-c ^ n’ to move to the next conflicting
-area in the same file. Once you are done resolving conflicts, return to
-the Magit status buffer. The file should now be shown as "modified", no
-longer as "unmerged", because Smerge automatically stages the file when
-you save the buffer after resolving the last conflict.
-
- Alternatively you could use Ediff, which uses separate buffers for
-the different versions of the file. To resolve conflicts in a file
-using Ediff press ‘e’ while point is on such a file in the status
-buffer.
-
- Ediff can be used for other purposes as well. For more information
-on how to enter Ediff from Magit, see *note Ediffing::. Explaining how
-to use Ediff is beyond the scope of this manual, instead see *note
-(ediff)Top::.
-
- If you are unsure whether you should Smerge or Ediff, then use the
-former. It is much easier to understand and use, and except for truly
-complex conflicts, the latter is usually overkill.
-
-\1f
-File: magit.info, Node: Rebasing, Next: Cherry Picking, Prev: Resolving Conflicts, Up: Manipulating
-
-6.9 Rebasing
-============
-
-Also see *note (gitman)git-rebase::. For information on how to resolve
-conflicts that occur during rebases see the preceding section.
-
-‘r’ (‘magit-rebase’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
- When no rebase is in progress, then the transient features the
-following suffix commands.
-
- Using one of these commands _starts_ a rebase sequence. Git might
-then stop somewhere along the way, either because you told it to do so,
-or because applying a commit failed due to a conflict. When that
-happens, then the status buffer shows information about the rebase
-sequence which is in progress in a section similar to a log section.
-See *note Information About In-Progress Rebase::.
-
- For information about the upstream and the push-remote, see *note The
-Two Remotes::.
-
-‘r p’ (‘magit-rebase-onto-pushremote’)
-
- This command rebases the current branch onto its push-remote.
-
- With a prefix argument or when the push-remote is either not
- configured or unusable, then let the user first configure the
- push-remote.
-
-‘r u’ (‘magit-rebase-onto-upstream’)
-
- This command rebases the current branch onto its upstream branch.
-
- With a prefix argument or when the upstream is either not
- configured or unusable, then let the user first configure the
- upstream.
-
-‘r e’ (‘magit-rebase-branch’)
-
- This command rebases the current branch onto a branch read in the
- minibuffer. All commits that are reachable from head but not from
- the selected branch TARGET are being rebased.
-
-‘r s’ (‘magit-rebase-subset’)
-
- This command starts a non-interactive rebase sequence to transfer
- commits from START to ‘HEAD’ onto NEWBASE. START has to be
- selected from a list of recent commits.
-
- By default Magit uses the ‘--autostash’ argument, which causes
-uncommitted changes to be stored in a stash before the rebase begins.
-These changes are restored after the rebase completes and if possible
-the stash is removed. If the stash does not apply cleanly, then the
-stash is not removed. In case something goes wrong when resolving the
-conflicts, this allows you to start over.
-
- Even though one of the actions is dedicated to interactive rebases,
-the transient also features the infix argument ‘--interactive’. This
-can be used to turn one of the other, non-interactive rebase variants
-into an interactive rebase.
-
- For example if you want to clean up a feature branch and at the same
-time rebase it onto ‘master’, then you could use ‘r-iu’. But we
-recommend that you instead do that in two steps. First use ‘ri’ to
-cleanup the feature branch, and then in a second step ‘ru’ to rebase it
-onto ‘master’. That way if things turn out to be more complicated than
-you thought and/or you make a mistake and have to start over, then you
-only have to redo half the work.
-
- Explicitly enabling ‘--interactive’ won’t have an effect on the
-following commands as they always use that argument anyway, even if it
-is not enabled in the transient.
-
-‘r i’ (‘magit-rebase-interactive’)
-
- This command starts an interactive rebase sequence.
-
-‘r f’ (‘magit-rebase-autosquash’)
-
- This command combines squash and fixup commits with their intended
- targets.
-
-‘r m’ (‘magit-rebase-edit-commit’)
-
- This command starts an interactive rebase sequence that lets the
- user edit a single older commit.
-
-‘r w’ (‘magit-rebase-reword-commit’)
-
- This command starts an interactive rebase sequence that lets the
- user reword a single older commit.
-
-‘r k’ (‘magit-rebase-remove-commit’)
-
- This command removes a single older commit using rebase.
-
- When a rebase is in progress, then the transient instead features the
-following suffix commands.
-
-‘r r’ (‘magit-rebase-continue’)
-
- This command restart the current rebasing operation.
-
- In some cases this pops up a commit message buffer for you do edit.
- With a prefix argument the old message is reused as-is.
-
-‘r s’ (‘magit-rebase-skip’)
-
- This command skips the current commit and restarts the current
- rebase operation.
-
-‘r e’ (‘magit-rebase-edit’)
-
- This command lets the user edit the todo list of the current rebase
- operation.
-
-‘r a’ (‘magit-rebase-abort’)
-
- This command aborts the current rebase operation, restoring the
- original branch.
-
-* Menu:
-
-* Editing Rebase Sequences::
-* Information About In-Progress Rebase::
-
-\1f
-File: magit.info, Node: Editing Rebase Sequences, Next: Information About In-Progress Rebase, Up: Rebasing
-
-6.9.1 Editing Rebase Sequences
-------------------------------
-
-‘C-c C-c’ (‘with-editor-finish’)
-
- Finish the current editing session by returning with exit code 0.
- Git then uses the rebase instructions it finds in the file.
-
-‘C-c C-k’ (‘with-editor-cancel’)
-
- Cancel the current editing session by returning with exit code 1.
- Git then forgoes starting the rebase sequence.
-
-‘RET’ (‘git-rebase-show-commit’)
-
- Show the commit on the current line in another buffer and select
- that buffer.
-
-‘SPC’ (‘git-rebase-show-or-scroll-up’)
-
- Show the commit on the current line in another buffer without
- selecting that buffer. If the revision buffer is already visible
- in another window of the current frame, then instead scroll that
- window up.
-
-‘DEL’ (‘git-rebase-show-or-scroll-down’)
-
- Show the commit on the current line in another buffer without
- selecting that buffer. If the revision buffer is already visible
- in another window of the current frame, then instead scroll that
- window down.
-
-‘p’ (‘git-rebase-backward-line’)
-
- Move to previous line.
-
-‘n’ (‘forward-line’)
-
- Move to next line.
-
-‘M-p’ (‘git-rebase-move-line-up’)
-
- Move the current commit (or command) up.
-
-‘M-n’ (‘git-rebase-move-line-down’)
-
- Move the current commit (or command) down.
-
-‘r’ (‘git-rebase-reword’)
-
- Edit message of commit on current line.
-
-‘e’ (‘git-rebase-edit’)
-
- Stop at the commit on the current line.
-
-‘s’ (‘git-rebase-squash’)
-
- Meld commit on current line into previous commit, and edit message.
-
-‘f’ (‘git-rebase-fixup’)
-
- Meld commit on current line into previous commit, discarding the
- current commit’s message.
-
-‘k’ (‘git-rebase-kill-line’)
-
- Kill the current action line.
-
-‘c’ (‘git-rebase-pick’)
-
- Use commit on current line.
-
-‘x’ (‘git-rebase-exec’)
-
- Insert a shell command to be run after the proceeding commit.
-
- If there already is such a command on the current line, then edit
- that instead. With a prefix argument insert a new command even
- when there already is one on the current line. With empty input
- remove the command on the current line, if any.
-
-‘b’ (‘git-rebase-break’)
-
- Insert a break action before the current line, instructing Git to
- return control to the user.
-
-‘y’ (‘git-rebase-insert’)
-
- Read an arbitrary commit and insert it below current line.
-
-‘C-x u’ (‘git-rebase-undo’)
-
- Undo some previous changes. Like ‘undo’ but works in read-only
- buffers.
-
- -- User Option: git-rebase-auto-advance
-
- Whether to move to next line after changing a line.
-
- -- User Option: git-rebase-show-instructions
-
- Whether to show usage instructions inside the rebase buffer.
-
- -- User Option: git-rebase-confirm-cancel
-
- Whether confirmation is required to cancel.
-
- When a rebase is performed with the ‘--rebase-merges’ option, the
-sequence will include a few other types of actions and the following
-commands become relevant.
-
-‘l’ (‘git-rebase-label’)
-
- This commands inserts a label action or edits the one at point.
-
-‘t’ (‘git-rebase-reset’)
-
- This command inserts a reset action or edits the one at point. The
- prompt will offer the labels that are currently present in the
- buffer.
-
-‘MM’ (‘git-rebase-merge’)
-
- The command inserts a merge action or edits the one at point. The
- prompt will offer the labels that are currently present in the
- buffer. Specifying a message to reuse via ‘-c’ or ‘-C’ is not
- supported; an editor will always be invoked for the merge.
-
-‘Mt’ (‘git-rebase-merge-toggle-editmsg’)
-
- This command toggles between the ‘-C’ and ‘-c’ options of the merge
- action at point. These options both specify a commit whose message
- should be reused. The lower-case variant instructs Git to invoke
- the editor when creating the merge, allowing the user to edit the
- message.
-
-\1f
-File: magit.info, Node: Information About In-Progress Rebase, Prev: Editing Rebase Sequences, Up: Rebasing
-
-6.9.2 Information About In-Progress Rebase
-------------------------------------------
-
-While a rebase sequence is in progress, the status buffer features a
-section that lists the commits that have already been applied as well as
-the commits that still have to be applied.
-
- The commits are split in two halves. When rebase stops at a commit,
-either because the user has to deal with a conflict or because s/he
-explicitly requested that rebase stops at that commit, then point is
-placed on the commit that separates the two groups, i.e. on ‘HEAD’.
-The commits above it have not been applied yet, while the ‘HEAD’ and the
-commits below it have already been applied. In between these two groups
-of applied and yet-to-be applied commits, there sometimes is a commit
-which has been dropped.
-
- Each commit is prefixed with a word and these words are additionally
-shown in different colors to indicate the status of the commits.
-
- The following colors are used:
-
- • Yellow commits have not been applied yet.
-
- • Gray commits have already been applied.
-
- • The blue commit is the ‘HEAD’ commit.
-
- • The green commit is the commit the rebase sequence stopped at. If
- this is the same commit as ‘HEAD’ (e.g. because you haven’t done
- anything yet after rebase stopped at the commit, then this commit
- is shown in blue, not green). There can only be a green *and* a
- blue commit at the same time, if you create one or more new commits
- after rebase stops at a commit.
-
- • Red commits have been dropped. They are shown for reference only,
- e.g. to make it easier to diff.
-
- Of course these colors are subject to the color-theme in use.
-
- The following words are used:
-
- • Commits prefixed with ‘pick’, ‘reword’, ‘edit’, ‘squash’, and
- ‘fixup’ have not been applied yet. These words have the same
- meaning here as they do in the buffer used to edit the rebase
- sequence. See *note Editing Rebase Sequences::. When the
- ‘--rebase-merges’ option was specified, ‘reset’, ‘label’, and
- ‘merge’ lines may also be present.
-
- • Commits prefixed with ‘done’ and ‘onto’ have already been applied.
- It is possible for such a commit to be the ‘HEAD’, in which case it
- is blue. Otherwise it is grey.
-
- • The commit prefixed with ‘onto’ is the commit on top of which
- all the other commits are being re-applied. This commit
- itself did not have to be re-applied, it is the commit rebase
- did rewind to before starting to re-apply other commits.
-
- • Commits prefixed with ‘done’ have already been re-applied.
- This includes commits that have been re-applied but also new
- commits that you have created during the rebase.
-
- • All other commits, those not prefixed with any of the above words,
- are in some way related to the commit at which rebase stopped.
-
- To determine whether a commit is related to the stopped-at commit
- their hashes, trees and patch-ids (1) are being compared. The
- commit message is not used for this purpose.
-
- Generally speaking commits that are related to the stopped-at
- commit can have any of the used colors, though not all color/word
- combinations are possible.
-
- Words used for stopped-at commits are:
-
- • When a commit is prefixed with ‘void’, then that indicates
- that Magit knows for sure that all the changes in that commit
- have been applied using several new commits. This commit is
- no longer reachable from ‘HEAD’, and it also isn’t one of the
- commits that will be applied when resuming the session.
-
- • When a commit is prefixed with ‘join’, then that indicates
- that the rebase sequence stopped at that commit due to a
- conflict - you now have to join (merge) the changes with what
- has already been applied. In a sense this is the commit
- rebase stopped at, but while its effect is already in the
- index and in the worktree (with conflict markers), the commit
- itself has not actually been applied yet (it isn’t the
- ‘HEAD’). So it is shown in yellow, like the other commits
- that still have to be applied.
-
- • When a commit is prefixed with ‘stop’ or a _blue_ or _green_
- ‘same’, then that indicates that rebase stopped at this
- commit, that it is still applied or has been applied again,
- and that at least its patch-id is unchanged.
-
- • When a commit is prefixed with ‘stop’, then that
- indicates that rebase stopped at that commit because you
- requested that earlier, and its patch-id is unchanged.
- It might even still be the exact same commit.
-
- • When a commit is prefixed with a _blue_ or _green_
- ‘same’, then that indicates that while its tree or hash
- changed, its patch-id did not. If it is blue, then it is
- the ‘HEAD’ commit (as always for blue). When it is
- green, then it no longer is ‘HEAD’ because other commit
- have been created since (but before continuing the
- rebase).
-
- • When a commit is prefixed with ‘goal’, a _yellow_ ‘same,’ or
- ‘work’, then that indicates that rebase applied that commit
- but that you then reset ‘HEAD’ to an earlier commit (likely to
- split it up into multiple commits), and that there are some
- uncommitted changes remaining which likely (but not
- necessarily) originate from that commit.
-
- • When a commit is prefixed with ‘goal’, then that
- indicates that it is still possible to create a new
- commit with the exact same tree (the "goal") without
- manually editing any files, by committing the index, or
- by staging all changes and then committing that. This is
- the case when the original tree still exists in the index
- or worktree in untainted form.
-
- • When a commit is prefixed with a yellow ‘same’, then that
- indicates that it is no longer possible to create a
- commit with the exact same tree, but that it is still
- possible to create a commit with the same patch-id. This
- would be the case if you created a new commit with other
- changes, but the changes from the original commit still
- exist in the index or working tree in untainted form.
-
- • When a commit is prefixed with ‘work’, then that
- indicates that you reset ‘HEAD’ to an earlier commit, and
- that there are some staged and/or unstaged changes
- (likely, but not necessarily) originating from that
- commit. However it is no longer possible to create a new
- commit with the same tree or at least the same patch-id
- because you have already made other changes.
-
- • When a commit is prefixed with ‘poof’ or ‘gone’, then that
- indicates that rebase applied that commit but that you then
- reset ‘HEAD’ to an earlier commit (likely to split it up into
- multiple commits), and that there are no uncommitted changes.
-
- • When a commit is prefixed with ‘poof’, then that
- indicates that it is no longer reachable from ‘HEAD’, but
- that it has been replaced with one or more commits, which
- together have the exact same effect.
-
- • When a commit is prefixed with ‘gone’, then that
- indicates that it is no longer reachable from ‘HEAD’ and
- that we also cannot determine whether its changes are
- still in effect in one or more new commits. They might
- be, but if so, then there must also be other changes
- which makes it impossible to know for sure.
-
- Do not worry if you do not fully understand the above. That’s okay,
-you will acquire a good enough understanding through practice.
-
- For other sequence operations such as cherry-picking, a similar
-section is displayed, but they lack some of the features described
-above, due to limitations in the git commands used to implement them.
-Most importantly these sequences only support "picking" a commit but not
-other actions such as "rewording", and they do not keep track of the
-commits which have already been applied.
-
- ---------- Footnotes ----------
-
- (1) The patch-id is a hash of the _changes_ introduced by a commit.
-It differs from the hash of the commit itself, which is a hash of the
-result of applying that change (i.e. the resulting trees and blobs) as
-well as author and committer information, the commit message, and the
-hashes of the parents of the commit. The patch-id hash on the other
-hand is created only from the added and removed lines, even line numbers
-and whitespace changes are ignored when calculating this hash. The
-patch-ids of two commits can be used to answer the question "Do these
-commits make the same change?".
-
-\1f
-File: magit.info, Node: Cherry Picking, Next: Resetting, Prev: Rebasing, Up: Manipulating
-
-6.10 Cherry Picking
-===================
-
-Also see *note (gitman)git-cherry-pick::.
-
-‘A’ (‘magit-cherry-pick’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
- When no cherry-pick or revert is in progress, then the transient
-features the following suffix commands.
-
-‘A A’ (‘magit-cherry-copy’)
-
- This command copies COMMITS from another branch onto the current
- branch. If the region selects multiple commits, then those are
- copied, without prompting. Otherwise the user is prompted for a
- commit or range, defaulting to the commit at point.
-
-‘A a’ (‘magit-cherry-apply’)
-
- This command applies the changes in COMMITS from another branch
- onto the current branch. If the region selects multiple commits,
- then those are used, without prompting. Otherwise the user is
- prompted for a commit or range, defaulting to the commit at point.
-
- This command also has a top-level binding, which can be invoked
- without using the transient by typing ‘a’ at the top-level.
-
- The following commands not only apply some commits to some branch,
-but also remove them from some other branch. The removal is performed
-using either ‘git-update-ref’ or if necessary ‘git-rebase’. Both
-applying commits as well as removing them using ‘git-rebase’ can lead to
-conflicts. If that happens, then these commands abort and you not only
-have to resolve the conflicts but also finish the process the same way
-you would have to if these commands didn’t exist at all.
-
-‘A h’ (‘magit-cherry-harvest’)
-
- This command moves the selected COMMITS that must be located on
- another BRANCH onto the current branch instead, removing them from
- the former. When this command succeeds, then the same branch is
- current as before.
-
- Applying the commits on the current branch or removing them from
- the other branch can lead to conflicts. When that happens, then
- this command stops and you have to resolve the conflicts and then
- finish the process manually.
-
-‘A d’ (‘magit-cherry-donate’)
-
- This command moves the selected COMMITS from the current branch
- onto another existing BRANCH, removing them from the former. When
- this command succeeds, then the same branch is current as before.
-
- Applying the commits on the other branch or removing them from the
- current branch can lead to conflicts. When that happens, then this
- command stops and you have to resolve the conflicts and then finish
- the process manually.
-
-‘A n’ (‘magit-cherry-spinout’)
-
- This command moves the selected COMMITS from the current branch
- onto a new branch BRANCH, removing them from the former. When this
- command succeeds, then the same branch is current as before.
-
- Applying the commits on the other branch or removing them from the
- current branch can lead to conflicts. When that happens, then this
- command stops and you have to resolve the conflicts and then finish
- the process manually.
-
-‘A s’ (‘magit-cherry-spinoff’)
-
- This command moves the selected COMMITS from the current branch
- onto a new branch BRANCH, removing them from the former. When this
- command succeeds, then the new branch is checked out.
-
- Applying the commits on the other branch or removing them from the
- current branch can lead to conflicts. When that happens, then this
- command stops and you have to resolve the conflicts and then finish
- the process manually.
-
- When a cherry-pick or revert is in progress, then the transient
-instead features the following suffix commands.
-
-‘A A’ (‘magit-sequence-continue’)
-
- Resume the current cherry-pick or revert sequence.
-
-‘A s’ (‘magit-sequence-skip’)
-
- Skip the stopped at commit during a cherry-pick or revert sequence.
-
-‘A a’ (‘magit-sequence-abort’)
-
- Abort the current cherry-pick or revert sequence. This discards
- all changes made since the sequence started.
-
-* Menu:
-
-* Reverting::
-
-\1f
-File: magit.info, Node: Reverting, Up: Cherry Picking
-
-6.10.1 Reverting
-----------------
-
-‘V’ (‘magit-revert’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
- When no cherry-pick or revert is in progress, then the transient
-features the following suffix commands.
-
-‘V V’ (‘magit-revert-and-commit’)
-
- Revert a commit by creating a new commit. Prompt for a commit,
- defaulting to the commit at point. If the region selects multiple
- commits, then revert all of them, without prompting.
-
-‘V v’ (‘magit-revert-no-commit’)
-
- Revert a commit by applying it in reverse to the working tree.
- Prompt for a commit, defaulting to the commit at point. If the
- region selects multiple commits, then revert all of them, without
- prompting.
-
- When a cherry-pick or revert is in progress, then the transient
-instead features the following suffix commands.
-
-‘V A’ (‘magit-sequence-continue’)
-
- Resume the current cherry-pick or revert sequence.
-
-‘V s’ (‘magit-sequence-skip’)
-
- Skip the stopped at commit during a cherry-pick or revert sequence.
-
-‘V a’ (‘magit-sequence-abort’)
-
- Abort the current cherry-pick or revert sequence. This discards
- all changes made since the sequence started.
-
-\1f
-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.
-
-\1f
-File: magit.info, Node: Stashing, Prev: Resetting, Up: Manipulating
-
-6.12 Stashing
-=============
-
-Also see *note (gitman)git-stash::.
-
-‘z’ (‘magit-stash’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
-‘z z’ (‘magit-stash-both’)
-
- Create a stash of the index and working tree. Untracked files are
- included according to infix arguments. One prefix argument is
- equivalent to ‘--include-untracked’ while two prefix arguments are
- equivalent to ‘--all’.
-
-‘z i’ (‘magit-stash-index’)
-
- Create a stash of the index only. Unstaged and untracked changes
- are not stashed.
-
-‘z w’ (‘magit-stash-worktree’)
-
- Create a stash of unstaged changes in the working tree. Untracked
- files are included according to infix arguments. One prefix
- argument is equivalent to ‘--include-untracked’ while two prefix
- arguments are equivalent to ‘--all’.
-
-‘z x’ (‘magit-stash-keep-index’)
-
- Create a stash of the index and working tree, keeping index intact.
- Untracked files are included according to infix arguments. One
- prefix argument is equivalent to ‘--include-untracked’ while two
- prefix arguments are equivalent to ‘--all’.
-
-‘z Z’ (‘magit-snapshot-both’)
-
- Create a snapshot of the index and working tree. Untracked files
- are included according to infix arguments. One prefix argument is
- equivalent to ‘--include-untracked’ while two prefix arguments are
- equivalent to ‘--all’.
-
-‘z I’ (‘magit-snapshot-index’)
-
- Create a snapshot of the index only. Unstaged and untracked
- changes are not stashed.
-
-‘z W’ (‘magit-snapshot-worktree’)
-
- Create a snapshot of unstaged changes in the working tree.
- Untracked files are included according to infix arguments. One
- prefix argument is equivalent to ‘--include-untracked’ while two
- prefix arguments are equivalent to ‘--all’-.
-
-‘z a’ (‘magit-stash-apply’)
-
- Apply a stash to the working tree. Try to preserve the stash
- index. If that fails because there are staged changes, apply
- without preserving the stash index.
-
-‘z p’ (‘magit-stash-pop’)
-
- Apply a stash to the working tree and remove it from stash list.
- Try to preserve the stash index. If that fails because there are
- staged changes, apply without preserving the stash index and forgo
- removing the stash.
-
-‘z k’ (‘magit-stash-drop’)
-
- Remove a stash from the stash list. When the region is active,
- offer to drop all contained stashes.
-
-‘z v’ (‘magit-stash-show’)
-
- Show all diffs of a stash in a buffer.
-
-‘z b’ (‘magit-stash-branch’)
-
- Create and checkout a new BRANCH from STASH. The branch starts at
- the commit that was current when the stash was created.
-
-‘z B’ (‘magit-stash-branch-here’)
-
- Create and checkout a new BRANCH using ‘magit-branch’ with the
- current branch or ‘HEAD’ as the starting-point. Then apply STASH,
- dropping it if it applies cleanly.
-
-‘z f’ (‘magit-stash-format-patch’)
-
- Create a patch from STASH.
-
-‘k’ (‘magit-stash-clear’)
-
- Remove all stashes saved in REF’s reflog by deleting REF.
-
-‘z l’ (‘magit-stash-list’)
-
- List all stashes in a buffer.
-
- -- User Option: magit-stashes-margin
-
- This option specifies whether the margin is initially shown in
- stashes buffers and how it is formatted.
-
- The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’.
-
- • If INIT is non-nil, then the margin is shown initially.
-
- • STYLE controls how to format the author or committer date. It
- can be one of ‘age’ (to show the age of the commit),
- ‘age-abbreviated’ (to abbreviate the time unit to a
- character), or a string (suitable for ‘format-time-string’) to
- show the actual date. Option
- ‘magit-log-margin-show-committer-date’ controls which date is
- being displayed.
-
- • WIDTH controls the width of the margin. This exists for
- forward compatibility and currently the value should not be
- changed.
-
- • AUTHOR controls whether the name of the author is also shown
- by default.
-
- • AUTHOR-WIDTH has to be an integer. When the name of the
- author is shown, then this specifies how much space is used to
- do so.
-
-\1f
-File: magit.info, Node: Transferring, Next: Miscellaneous, Prev: Manipulating, Up: Top
-
-7 Transferring
-**************
-
-* Menu:
-
-* Remotes::
-* Fetching::
-* Pulling::
-* Pushing::
-* Plain Patches::
-* Maildir Patches::
-
-\1f
-File: magit.info, Node: Remotes, Next: Fetching, Up: Transferring
-
-7.1 Remotes
-===========
-
-* Menu:
-
-* Remote Commands::
-* Remote Git Variables::
-
-\1f
-File: magit.info, Node: Remote Commands, Next: Remote Git Variables, Up: Remotes
-
-7.1.1 Remote Commands
----------------------
-
-The transient prefix command ‘magit-remote’ is used to add remotes and
-to make changes to existing remotes. This command only deals with
-remotes themselves, not with branches or the transfer of commits. Those
-features are available from separate transient commands.
-
- Also see *note (gitman)git-remote::.
-
-‘M’ (‘magit-remote’)
-
- This transient prefix command binds the following suffix commands
- and displays them in a temporary buffer until a suffix is invoked.
-
- By default it also binds and displays the values of some
- remote-related Git variables and allows changing their values.
-
- -- User Option: magit-remote-direct-configure
-
- This option controls whether remote-related Git variables are
- accessible directly from the transient ‘magit-remote’.
-
- If ‘t’ (the default) and a local branch is checked out, then
- ‘magit-remote’ features the variables for the upstream remote of
- that branch, or if ‘HEAD’ is detached, for ‘origin’, provided that
- exists.
-
- If ‘nil’, then ‘magit-remote-configure’ has to be used to do so.
-
-‘M C’ (‘magit-remote-configure’)
-
- This transient prefix command binds commands that set the value of
- remote-related variables and displays them in a temporary buffer
- until the transient is exited.
-
- With a prefix argument, this command always prompts for a remote.
-
- Without a prefix argument this depends on whether it was invoked as
- a suffix of ‘magit-remote’ and on the
- ‘magit-remote-direct-configure’ option. If ‘magit-remote’ already
- displays the variables for the upstream, then it does not make
- sense to invoke another transient that displays them for the same
- remote. In that case this command prompts for a remote.
-
- The variables are described in *note Remote Git Variables::.
-
-‘M a’ (‘magit-remote-add’)
-
- This command add a remote and fetches it. The remote name and url
- are read in the minibuffer.
-
-‘M r’ (‘magit-remote-rename’)
-
- This command renames a remote. Both the old and the new names are
- read in the minibuffer.
-
-‘M u’ (‘magit-remote-set-url’)
-
- This command changes the url of a remote. Both the remote and the
- new url are read in the minibuffer.
-
-‘M k’ (‘magit-remote-remove’)
-
- This command deletes a remote, read in the minibuffer.
-
-‘M p’ (‘magit-remote-prune’)
-
- This command removes stale remote-tracking branches for a remote
- read in the minibuffer.
-
-‘M P’ (‘magit-remote-prune-refspecs’)
-
- This command removes stale refspecs for a remote read in the
- minibuffer.
-
- A refspec is stale if there no longer exists at least one branch on
- the remote that would be fetched due to that refspec. A stale
- refspec is problematic because its existence causes Git to refuse
- to fetch according to the remaining non-stale refspecs.
-
- If only stale refspecs remain, then this command offers to either
- delete the remote or to replace the stale refspecs with the default
- refspec ("+refs/heads/*:refs/remotes/REMOTE/*").
-
- This command also removes the remote-tracking branches that were
- created due to the now stale refspecs. Other stale branches are
- not removed.
-
- -- User Option: magit-remote-add-set-remote.pushDefault
-
- This option controls whether the user is asked whether they want to
- set ‘remote.pushDefault’ after adding a remote.
-
- If ‘ask’, then users is always ask. If ‘ask-if-unset’, then the
- user is only if the variable isn’t set already. If ‘nil’, then the
- user isn’t asked and the variable isn’t set. If the value is a
- string, then the variable is set without the user being asked,
- provided that the name of the added remote is equal to that string
- and the variable isn’t already set.
-
-\1f
-File: magit.info, Node: Remote Git Variables, Prev: Remote Commands, Up: Remotes
-
-7.1.2 Remote Git Variables
---------------------------
-
-These variables can be set from the transient prefix command
-‘magit-remote-configure’. By default they can also be set from
-‘magit-remote’. See *note Remote Commands::.
-
- -- Variable: remote.NAME.url
-
- This variable specifies the url of the remote named NAME. It can
- have multiple values.
-
- -- Variable: remote.NAME.fetch
-
- The refspec used when fetching from the remote named NAME. It can
- have multiple values.
-
- -- Variable: remote.NAME.pushurl
-
- This variable specifies the url used for fetching from the remote
- named NAME. If it is not specified, then ‘remote.NAME.url’ is used
- instead. It can have multiple values.
-
- -- Variable: remote.NAME.push
-
- The refspec used when pushing to the remote named NAME. It can
- have multiple values.
-
- -- Variable: remote.NAME.tagOpts
-
- This variable specifies what tags are fetched by default. If the
- value is ‘--no-tags’ then no tags are fetched. If the value is
- ‘--tags’, then all tags are fetched. If this variable has no
- value, then only tags are fetched that are reachable from fetched
- branches.
-
-\1f
-File: magit.info, Node: Fetching, Next: Pulling, Prev: Remotes, Up: Transferring
-
-7.2 Fetching
-============
-
-Also see *note (gitman)git-fetch::. For information about the upstream
-and the push-remote, see *note The Two Remotes::.
-
-‘f’ (‘magit-fetch’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
-‘f p’ (‘magit-fetch-from-pushremote’)
-
- This command fetches from the current push-remote.
-
- With a prefix argument or when the push-remote is either not
- configured or unusable, then let the user first configure the
- push-remote.
-
-‘f u’ (‘magit-fetch-from-upstream’)
-
- This command fetch from the upstream of the current branch.
-
- If the upstream is configured for the current branch and names an
- existing remote, then use that. Otherwise try to use another
- remote: If only a single remote is configured, then use that.
- Otherwise if a remote named "origin" exists, then use that.
-
- If no remote can be determined, then this command is not available
- from the ‘magit-fetch’ transient prefix and invoking it directly
- results in an error.
-
-‘f e’ (‘magit-fetch-other’)
-
- This command fetch from a repository read from the minibuffer.
-
-‘f o’ (‘magit-fetch-branch’)
-
- This command fetches a branch from a remote, both of which are read
- from the minibuffer.
-
-‘f r’ (‘magit-fetch-refspec’)
-
- This command fetches from a remote using an explicit refspec, both
- of which are read from the minibuffer.
-
-‘f a’ (‘magit-fetch-all’)
-
- This command fetches from all remotes.
-
-‘f m’ (‘magit-submodule-fetch’)
-
- This command fetches all submodules. With a prefix argument it
- fetches all remotes of all submodules.
-
- -- User Option: magit-pull-or-fetch
-
- By default fetch and pull commands are available from separate
- transient prefix command. Setting this to ‘t’ adds some (but not
- all) of the above suffix commands to the ‘magit-pull’ transient.
-
- If you do that, then you might also want to change the key binding
- for these prefix commands, e.g.:
-
- (setq magit-pull-or-fetch t)
- (define-key magit-mode-map "f" 'magit-pull) ; was magit-fetch
- (define-key magit-mode-map "F" nil) ; was magit-pull
-
-\1f
-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.
-
-\1f
-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.
-
- 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.<branch>.pushRemote’,
- ‘branch.<branch>.remote’, ‘branch.<branch>.merge’, and
- ‘remote.<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.<branch>.pushRemote’,
- ‘branch.<branch>.remote’, ‘branch.<branch>.merge’, and
- ‘remote.<remote>.push’.
-
-\1f
-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.
-
-\1f
-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.
-
-\1f
-File: magit.info, Node: Miscellaneous, Next: Customizing, Prev: Transferring, Up: Top
-
-8 Miscellaneous
-***************
-
-* Menu:
-
-* Tagging::
-* Notes::
-* Submodules::
-* Subtree::
-* Worktree::
-* Common Commands::
-* Wip Modes::
-* Commands for Buffers Visiting Files::
-* Minor Mode for Buffers Visiting Blobs::
-
-\1f
-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 annotate 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.
-
-\1f
-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).
-
-\1f
-File: magit.info, Node: Submodules, Next: Subtree, Prev: Notes, Up: Miscellaneous
-
-8.3 Submodules
-==============
-
-Also see *note (gitman)git-submodule::.
-
-* Menu:
-
-* Listing Submodules::
-* Submodule Transient::
-
-\1f
-File: magit.info, Node: Listing Submodules, Next: Submodule Transient, Up: Submodules
-
-8.3.1 Listing Submodules
-------------------------
-
-The command ‘magit-list-submodules’ displays a list of the current
-repository’s submodules in a separate buffer. It’s also possible to
-display information about submodules directly in the status buffer of
-the super-repository by adding ‘magit-insert-modules’ to the hook
-‘magit-status-sections-hook’ as described in *note Status Module
-Sections::.
-
- -- Command: magit-list-submodules
-
- This command displays a list of the current repository’s submodules
- in a separate buffer.
-
- It can be invoked by pressing ‘RET’ on the section titled
- "Modules".
-
- -- User Option: magit-submodule-list-columns
-
- This option controls what columns are displayed by the command
- ‘magit-list-submodules’ and how they are displayed.
-
- Each element has the form ‘(HEADER WIDTH FORMAT PROPS)’.
-
- HEADER is the string displayed in the header. WIDTH is the width
- of the column. FORMAT is a function that is called with one
- argument, the repository identification (usually its basename), and
- with ‘default-directory’ bound to the toplevel of its working tree.
- It has to return a string to be inserted or nil. PROPS is an alist
- that supports the keys ‘:right-align’ and ‘:pad-right’.
-
-\1f
-File: magit.info, Node: Submodule Transient, Prev: Listing Submodules, Up: Submodules
-
-8.3.2 Submodule Transient
--------------------------
-
-‘o’ (‘magit-submodule’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
- Some of the below commands default to act on the modules that are
-selected using the region. For brevity their description talk about
-"the selected modules", but if no modules are selected, then they act on
-the current module instead, or if point isn’t on a module, then the read
-a single module to act on. With a prefix argument these commands ignore
-the selection and the current module and instead act on all suitable
-modules.
-
-‘o a’ (‘magit-submodule-add’)
-
- This commands adds the repository at URL as a module. Optional
- PATH is the path to the module relative to the root of the
- super-project. If it is nil then the path is determined based on
- URL.
-
-‘o r’ (‘magit-submodule-register’)
-
- This command registers the selected modules by copying their urls
- from ".gitmodules" to "$GIT_DIR/config". These values can then be
- edited before running ‘magit-submodule-populate’. If you don’t
- need to edit any urls, then use the latter directly.
-
-‘o p’ (‘magit-submodule-populate’)
-
- This command creates the working directory or directories of the
- selected modules, checking out the recorded commits.
-
-‘o u’ (‘magit-submodule-update’)
-
- This command updates the selected modules checking out the recorded
- commits.
-
-‘o s’ (‘magit-submodule-synchronize’)
-
- This command synchronizes the urls of the selected modules, copying
- the values from ".gitmodules" to the ".git/config" of the
- super-project as well those of the modules.
-
-‘o d’ (‘magit-submodule-unpopulate’)
-
- This command removes the working directory of the selected modules.
-
-‘o l’ (‘magit-list-submodules’)
-
- This command displays a list of the current repository’s modules.
-
-‘o f’ (‘magit-fetch-modules’)
-
- This command fetches all modules.
-
- Option ‘magit-fetch-modules-jobs’ controls how many submodules are
- being fetched in parallel. Also fetch the super-repository,
- because ‘git fetch’ does not support not doing that. With a prefix
- argument fetch all remotes.
-
-\1f
-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.
-
-\1f
-File: magit.info, Node: Worktree, Next: Common Commands, Prev: Subtree, Up: Miscellaneous
-
-8.5 Worktree
-============
-
-Also see *note (gitman)git-worktree::.
-
-‘%’ (‘magit-worktree’)
-
- This transient prefix command binds the following suffix commands
- and displays them in a temporary buffer until a suffix is invoked.
-
-‘% b’ (‘magit-worktree-checkout’)
-
- Checkout BRANCH in a new worktree at PATH.
-
-‘% c’ (‘magit-worktree-branch’)
-
- Create a new BRANCH and check it out in a new worktree at PATH.
-
-‘% m’ (‘magit-worktree-move’)
-
- Move an existing worktree to a new PATH.
-
-‘% k’ (‘magit-worktree-delete’)
-
- Delete a worktree, defaulting to the worktree at point. The
- primary worktree cannot be deleted.
-
-‘% g’ (‘magit-worktree-status’)
-
- Show the status for the worktree at point.
-
- If there is no worktree at point, then read one in the minibuffer.
- If the worktree at point is the one whose status is already being
- displayed in the current buffer, then show it in Dired instead.
-
+++ /dev/null
-This is magit.info, produced by makeinfo version 6.5 from magit.texi.
-
- Copyright (C) 2015-2021 Jonas Bernoulli <jonasNOSPAMbernoul.li>
-
- 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
-
-\1f
-File: magit.info, Node: Common Commands, Next: Wip Modes, Prev: Worktree, Up: Miscellaneous
-
-8.6 Common Commands
-===================
-
-These are some of the commands that can be used in all buffers whose
-major-modes derive from ‘magit-mode’. There are other common commands
-beside the ones below, but these didn’t fit well anywhere else.
-
-‘C-w’ (‘magit-copy-section-value’)
-
- This command saves the value of the current section to the
- ‘kill-ring’, and, provided that the current section is a commit,
- branch, or tag section, it also pushes the (referenced) revision to
- the ‘magit-revision-stack’.
-
- When the current section is a branch or a tag, and a prefix
- argument is used, then it saves the revision at its tip to the
- ‘kill-ring’ instead of the reference name.
-
- When the region is active, this command saves that to the
- ‘kill-ring’, like ‘kill-ring-save’ would, instead of behaving as
- described above. If a prefix argument is used and the region is
- within a hunk, then it strips the diff marker column and keeps only
- either the added or removed lines, depending on the sign of the
- prefix argument.
-
-‘M-w’ (‘magit-copy-buffer-revision’)
-
- This command saves the revision being displayed in the current
- buffer to the ‘kill-ring’ and also pushes it to the
- ‘magit-revision-stack’. It is mainly intended for use in
- ‘magit-revision-mode’ buffers, the only buffers where it is always
- unambiguous exactly which revision should be saved.
-
- Most other Magit buffers usually show more than one revision, in
- some way or another, so this command has to select one of them, and
- that choice might not always be the one you think would have been
- the best pick.
-
- Outside of Magit ‘M-w’ and ‘C-w’ are usually bound to
-‘kill-ring-save’ and ‘kill-region’, and these commands would also be
-useful in Magit buffers. Therefore when the region is active, then both
-of these commands behave like ‘kill-ring-save’ instead of as described
-above.
-
-\1f
-File: magit.info, Node: Wip Modes, Next: Commands for Buffers Visiting Files, Prev: Common Commands, Up: Miscellaneous
-
-8.7 Wip Modes
-=============
-
-Git keeps *committed* changes around long enough for users to recover
-changes they have accidentally deleted. It does so by not garbage
-collecting any committed but no longer referenced objects for a certain
-period of time, by default 30 days.
-
- But Git does *not* keep track of *uncommitted* changes in the working
-tree and not even the index (the staging area). Because Magit makes it
-so convenient to modify uncommitted changes, it also makes it easy to
-shoot yourself in the foot in the process.
-
- For that reason Magit provides a global mode that saves *tracked*
-files to work-in-progress references after or before certain actions.
-(At present untracked files are never saved and for technical reasons
-nothing is saved before the first commit has been created).
-
- Two separate work-in-progress references are used to track the state
-of the index and of the working tree: ‘refs/wip/index/<branchref>’ and
-‘refs/wip/wtree/<branchref>’, where ‘<branchref>’ 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 ‘<branchref>’.
-
- Checking out another branch (or detaching ‘HEAD’) causes the use of
-different wip refs for subsequent changes.
-
- -- User Option: magit-wip-mode
-
- When this mode is enabled, then uncommitted changes are committed
- to dedicated work-in-progress refs whenever appropriate (i.e. when
- dataloss would be a possibility otherwise).
-
- Setting this variable directly does not take effect; either use the
- Custom interface to do so or call the respective mode function.
-
- For historic reasons this mode is implemented on top of four other
- ‘magit-wip-*’ modes, which can also be used individually, if you
- want finer control over when the wip refs are updated; but that is
- discouraged. See *note Legacy Wip Modes::.
-
- To view the log for a branch and its wip refs use the commands
-‘magit-wip-log’ and ‘magit-wip-log-current’. You should use ‘--graph’
-when using these commands.
-
- -- Command: magit-wip-log
-
- This command shows the log for a branch and its wip refs. With a
- negative prefix argument only the worktree wip ref is shown.
-
- The absolute numeric value of the prefix argument controls how many
- "branches" of each wip ref are shown. This is only relevant if the
- value of ‘magit-wip-merge-branch’ is ‘nil’.
-
- -- Command: magit-wip-log-current
-
- This command shows the log for the current branch and its wip refs.
- With a negative prefix argument only the worktree wip ref is shown.
-
- The absolute numeric value of the prefix argument controls how many
- "branches" of each wip ref are shown. This is only relevant if the
- value of ‘magit-wip-merge-branch’ is ‘nil’.
-
-‘X w’ (‘magit-reset-worktree’)
-
- This command resets the working tree to some commit read from the
- user and defaulting to the commit at point, while keeping the
- ‘HEAD’ and index as-is.
-
- This can be used to restore files to the state committed to a wip
- ref. Note that this will discard any unstaged changes that might
- have existed before invoking this command (but of course only after
- committing that to the working tree wip ref).
-
- Note that even if you enable ‘magit-wip-mode’ this won’t give you
-perfect protection. The most likely scenario for losing changes despite
-the use of ‘magit-wip-mode’ is making a change outside Emacs and then
-destroying it also outside Emacs. In some such a scenario, Magit, being
-an Emacs package, didn’t get the opportunity to keep you from shooting
-yourself in the foot.
-
- When you are unsure whether Magit did commit a change to the wip
-refs, then you can explicitly request that all changes to all tracked
-files are being committed.
-
-‘M-x magit-wip-commit’ (‘magit-wip-commit’)
-
- This command commits all changes to all tracked files to the index
- and working tree work-in-progress refs. Like the modes described
- above, it does not commit untracked files, but it does check all
- tracked files for changes. Use this command when you suspect that
- the modes might have overlooked a change made outside Emacs/Magit.
-
- -- User Option: magit-wip-namespace
-
- The namespace used for work-in-progress refs. It has to end with a
- slash. The wip refs are named ‘<namespace>index/<branchref>’ and
- ‘<namespace>wtree/<branchref>’. When snapshots are created while
- the ‘HEAD’ is detached then ‘HEAD’ is used in place of
- ‘<branchref>’.
-
- -- User Option: magit-wip-mode-lighter
-
- Mode-line lighter for ‘magit-wip--mode’.
-
-* Menu:
-
-* Wip Graph::
-* Legacy Wip Modes::
-
-\1f
-File: magit.info, Node: Wip Graph, Next: Legacy Wip Modes, Up: Wip Modes
-
-8.7.1 Wip Graph
----------------
-
- -- User Option: magit-wip-merge-branch
-
- This option controls whether the current branch is merged into the
- wip refs after a new commit was created on the branch.
-
- If non-nil and the current branch has new commits, then it is
- merged into the wip ref before creating a new wip commit. This
- makes it easier to inspect wip history and the wip commits are
- never garbage collected.
-
- If nil and the current branch has new commits, then the wip ref is
- reset to the tip of the branch before creating a new wip commit.
- With this setting wip commits are eventually garbage collected.
-
- When ‘magit-wip-merge-branch’ is ‘t’, then the history looks like
-this:
-
- *--*--*--*--*--* refs/wip/index/refs/heads/master
- / / /
- A-----B-----C refs/heads/master
-
- When ‘magit-wip-merge-branch’ is ‘nil’, then creating a commit on the
-real branch and then making a change causes the wip refs to be recreated
-to fork from the new commit. But the old commits on the wip refs are
-not lost. They are still available from the reflog. To make it easier
-to see when the fork point of a wip ref was changed, an additional
-commit with the message "restart autosaving" is created on it (‘xxO’
-commits below are such boundary commits).
-
- Starting with
-
- BI0---BI1 refs/wip/index/refs/heads/master
- /
- A---B refs/heads/master
- \
- BW0---BW1 refs/wip/wtree/refs/heads/master
-
- and committing the staged changes and editing and saving a file would
-result in
-
- BI0---BI1 refs/wip/index/refs/heads/master
- /
- A---B---C refs/heads/master
- \ \
- \ CW0---CW1 refs/wip/wtree/refs/heads/master
- \
- BW0---BW1 refs/wip/wtree/refs/heads/master@{2}
-
- The fork-point of the index wip ref is not changed until some change
-is being staged. Likewise just checking out a branch or creating a
-commit does not change the fork-point of the working tree wip ref. The
-fork-points are not adjusted until there actually is a change that
-should be committed to the respective wip ref.
-
-\1f
-File: magit.info, Node: Legacy Wip Modes, Prev: Wip Graph, Up: Wip Modes
-
-8.7.2 Legacy Wip Modes
-----------------------
-
-It is recommended that you use the mode ‘magit-wip-mode’ (which see) and
-ignore the existence of the following modes, which are preserved for
-historic reasons.
-
- Setting the following variables directly does not take effect; either
-use the Custom interface to do so or call the respective mode functions.
-
- -- User Option: magit-wip-after-save-mode
-
- When this mode is enabled, then saving a buffer that visits a file
- tracked in a Git repository causes its current state to be
- committed to the working tree wip ref for the current branch.
-
- -- User Option: magit-wip-after-apply-mode
-
- When this mode is enabled, then applying (i.e. staging, unstaging,
- discarding, reversing, and regularly applying) a change to a file
- tracked in a Git repository causes its current state to be
- committed to the index and/or working tree wip refs for the current
- branch.
-
- If you only ever edit files using Emacs and only ever interact with
-Git using Magit, then the above two modes should be enough to protect
-each and every change from accidental loss. In practice nobody does
-that. Two additional modes exists that do commit to the wip refs before
-making changes that could cause the loss of earlier changes.
-
- -- User Option: magit-wip-before-change-mode
-
- When this mode is enabled, then certain commands commit the
- existing changes to the files they are about to make changes to.
-
- -- User Option: magit-wip-initial-backup-mode
-
- When this mode is enabled, then the current version of a file is
- committed to the worktree wip ref before the buffer visiting that
- file is saved for the first time since the buffer was created.
-
- This backs up the same version of the file that ‘backup-buffer’
- would save. While ‘backup-buffer’ uses a backup file, this mode
- uses the same worktree wip ref as used by the other Magit Wip
- modes. Like ‘backup-buffer’, it only does this once; unless you
- kill the buffer and visit the file again only one backup will be
- created per Emacs session.
-
- This mode ignores the variables that affect ‘backup-buffer’ and can
- be used along-side that function, which is recommended because it
- only backs up files that are tracked in a Git repository.
-
- -- User Option: magit-wip-after-save-local-mode-lighter
-
- Mode-line lighter for ‘magit-wip-after-save-local-mode’.
-
- -- User Option: magit-wip-after-apply-mode-lighter
-
- Mode-line lighter for ‘magit-wip-after-apply-mode’.
-
- -- User Option: magit-wip-before-change-mode-lighter
-
- Mode-line lighter for ‘magit-wip-before-change-mode’.
-
- -- User Option: magit-wip-initial-backup-mode-lighter
-
- Mode-line lighter for ‘magit-wip-initial-backup-mode’.
-
-\1f
-File: magit.info, Node: Commands for Buffers Visiting Files, Next: Minor Mode for Buffers Visiting Blobs, Prev: Wip Modes, Up: Miscellaneous
-
-8.8 Commands for Buffers Visiting Files
-=======================================
-
-Magit defines a few global key bindings unless the user sets
-‘magit-define-global-key-bindings’ to ‘nil’. This includes binding ‘C-c
-M-g’ to ‘magit-file-dispatch’. ‘C-c g’ would be a much better binding
-but the ‘C-c <letter>’ namespace is reserved for users, meaning that
-packages are not allowed to use it. If you want to use ‘C-c g’, then
-you have to add that binding yourself. Also see *note Default
-Bindings:: and *note (elisp)Key Binding Conventions::.
-
- If you want a better binding, you have to add it yourself:
-
- (global-set-key (kbd "C-c g") 'magit-file-dispatch)
-
- The key bindings shown below assume that you have not improved the
-binding for ‘magit-file-dispatch’.
-
-‘C-c M-g’ (‘magit-file-dispatch’)
-
- This transient prefix command binds the following suffix commands
- and displays them in a temporary buffer until a suffix is invoked.
-
- When invoked in a buffer that does not visit a file, then it falls
- back to regular ‘magit-dispatch’.
-
-‘C-c M-g s’ (‘magit-stage-file’)
-
- Stage all changes to the file being visited in the current buffer.
-
-‘C-c M-g u’ (‘magit-unstage-file’)
-
- Unstage all changes to the file being visited in the current
- buffer.
-
-‘C-c M-g c’ (‘magit-commit’)
-
- This transient prefix command binds the following suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked. See *note Initiating a
- Commit::.
-
-‘C-c M-g D’ (‘magit-diff’)
-
- This transient prefix command binds several diff suffix commands
- and infix arguments and displays them in a temporary buffer until a
- suffix is invoked. See *note Diffing::.
-
- This is the same command that ‘d’ is bound to in Magit buffers. If
- this command is invoked from a file-visiting buffer, then the
- initial value of the option (‘--’) that limits the diff to certain
- file(s) is set to the visited file.
-
-‘C-c M-g d’ (‘magit-diff-buffer-file’)
-
- This command shows the diff for the file of blob that the current
- buffer visits.
-
- -- User Option: magit-diff-buffer-file-locked
-
- This option controls whether ‘magit-diff-buffer-file’ uses a
- dedicated buffer. See *note Modes and Buffers::.
-
-‘C-c M-g L’ (‘magit-log’)
-
- This transient prefix command binds several log suffix commands and
- infix arguments and displays them in a temporary buffer until a
- suffix is invoked. See *note Logging::.
-
- This is the same command that ‘l’ is bound to in Magit buffers. If
- this command is invoked from a file-visiting buffer, then the
- initial value of the option (‘--’) that limits the log to certain
- file(s) is set to the visited file.
-
-‘C-c M-g l’ (‘magit-log-buffer-file’)
-
- This command shows the log for the file of blob that the current
- buffer visits. Renames are followed when a prefix argument is used
- or when ‘--follow’ is an active log argument. When the region is
- active, the log is restricted to the selected line range.
-
-‘C-c M-g t’ (‘magit-log-trace-definition’)
-
- This command shows the log for the definition at point.
-
- -- User Option: magit-log-buffer-file-locked
-
- This option controls whether ‘magit-log-buffer-file’ uses a
- dedicated buffer. See *note Modes and Buffers::.
-
-‘C-c M-g B’ (‘magit-blame’)
-
- This transient prefix command binds all blaming suffix commands
- along with the appropriate infix arguments and displays them in a
- temporary buffer until a suffix is invoked.
-
- For more information about this and the following commands also see
- *note Blaming::.
-
- In addition to the ‘magit-blame’ sub-transient, the dispatch
-transient also binds several blaming suffix commands directly. See
-*note Blaming:: for information about those commands and bindings.
-
-‘C-c M-g e’ (‘magit-edit-line-commit’)
-
- This command makes the commit editable that added the current line.
-
- With a prefix argument it makes the commit editable that removes
- the line, if any. The commit is determined using ‘git blame’ and
- made editable using ‘git rebase --interactive’ if it is reachable
- from ‘HEAD’, or by checking out the commit (or a branch that points
- at it) otherwise.
-
-‘C-c M-g p’ (‘magit-blob-previous’)
-
- Visit the previous blob which modified the current file.
-
- There are a few additional commands that operate on a single file but
-are not enabled in the file transient command by default:
-
- -- Command: magit-file-rename
-
- This command renames a file read from the user.
-
- -- Command: magit-file-delete
-
- This command deletes a file read from the user.
-
- -- Command: magit-file-untrack
-
- This command untracks a file read from the user.
-
- -- Command: magit-file-checkout
-
- This command updates a file in the working tree and index to the
- contents from a revision. Both the revision and file are read from
- the user.
-
- To enable them invoke the transient (‘C-c M-g’), enter "edit mode"
-(‘C-x l’), set the "transient level" (‘C-x l’ again), enter ‘5’, and
-leave edit mode (‘C-g’). Also see *note (transient)Enabling and
-Disabling Suffixes::.
-
-\1f
-File: magit.info, Node: Minor Mode for Buffers Visiting Blobs, Prev: Commands for Buffers Visiting Files, Up: Miscellaneous
-
-8.9 Minor Mode for Buffers Visiting Blobs
-=========================================
-
-The ‘magit-blob-mode’ enables certain Magit features in blob-visiting
-buffers. Such buffers can be created using ‘magit-find-file’ and some
-of the commands mentioned below, which also take care of turning on this
-minor mode. Currently this mode only establishes a few key bindings,
-but this might be extended.
-
-‘p’ (‘magit-blob-previous’)
-
- Visit the previous blob which modified the current file.
-
-‘n’ (‘magit-blob-next’)
-
- Visit the next blob which modified the current file.
-
-‘q’ (‘magit-kill-this-buffer’)
-
- Kill the current buffer.
-
-\1f
-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::
-
-\1f
-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)
-
-\1f
-File: magit.info, Node: Essential Settings, Prev: Per-Repository Configuration, Up: Customizing
-
-9.2 Essential Settings
-======================
-
-The next two sections list and discuss several variables that many users
-might want to customize, for safety and/or performance reasons.
-
-* Menu:
-
-* Safety::
-* Performance::
-* Default Bindings::
-
-\1f
-File: magit.info, Node: Safety, Next: Performance, Up: Essential Settings
-
-9.2.1 Safety
-------------
-
-This section discusses various variables that you might want to change
-(or *not* change) for safety reasons.
-
- Git keeps *committed* changes around long enough for users to recover
-changes they have accidentally been deleted. It does not do the same
-for *uncommitted* changes in the working tree and not even the index
-(the staging area). Because Magit makes it so easy to modify
-uncommitted changes, it also makes it easy to shoot yourself in the foot
-in the process. For that reason Magit provides three global modes that
-save *tracked* files to work-in-progress references after or before
-certain actions. See *note Wip Modes::.
-
- These modes are not enabled by default because of performance
-concerns. Instead a lot of potentially destructive commands require
-confirmation every time they are used. In many cases this can be
-disabled by adding a symbol to ‘magit-no-confirm’ (see *note Completion
-and Confirmation::). If you enable the various wip modes then you
-should add ‘safe-with-wip’ to this list.
-
- Similarly it isn’t necessary to require confirmation before moving a
-file to the system trash - if you trashed a file by mistake then you can
-recover it from there. Option ‘magit-delete-by-moving-to-trash’
-controls whether the system trash is used, which is the case by default.
-Nevertheless, ‘trash’ isn’t a member of ‘magit-no-confirm’ - you might
-want to change that.
-
- By default buffers visiting files are automatically reverted when the
-visited file changes on disk. This isn’t as risky as it might seem, but
-to make an informed decision you should see *note Risk of Reverting
-Automatically::.
-
-\1f
-File: magit.info, Node: Performance, Next: Default Bindings, Prev: Safety, Up: Essential Settings
-
-9.2.2 Performance
------------------
-
-After Magit has run ‘git’ for side-effects, it also refreshes the
-current Magit buffer and the respective status buffer. This is
-necessary because otherwise outdated information might be displayed
-without the user noticing. Magit buffers are updated by recreating
-their content from scratch, which makes updating simpler and less
-error-prone, but also more costly. Keeping it simple and just
-re-creating everything from scratch is an old design decision and
-departing from that will require major refactoring.
-
- I plan to do that in time for the next major release. I also intend
-to create logs and diffs asynchronously, which should also help a lot
-but also requires major refactoring.
-
- Meanwhile you can tell Magit to only automatically refresh the
-current Magit buffer, but not the status buffer. If you do that, then
-the status buffer is only refreshed automatically if it is the current
-buffer.
-
- (setq magit-refresh-status-buffer nil)
-
- You should also check whether any third-party packages have added
-anything to ‘magit-refresh-buffer-hook’, ‘magit-status-refresh-hook’,
-‘magit-pre-refresh-hook’, and ‘magit-post-refresh-hook’. If so, then
-check whether those additions impact performance significantly.
-
- Magit can be told to refresh buffers verbosely using ‘M-x
-magit-toggle-verbose-refresh’. Enabling this helps figuring out which
-sections are bottlenecks. The additional output can be found in the
-‘*Messages*’ buffer.
-
- Magit also reverts buffers for visited files located inside the
-current repository when the visited file changes on disk. That is
-implemented on top of ‘auto-revert-mode’ from the built-in library
-‘autorevert’. To figure out whether that impacts performance, check
-whether performance is significantly worse, when many buffers exist
-and/or when some buffers visit files using TRAMP. If so, then this
-should help.
-
- (setq auto-revert-buffer-list-filter
- 'magit-auto-revert-repository-buffer-p)
-
- For alternative approaches see *note Automatic Reverting of
-File-Visiting Buffers::.
-
- If you have enabled any features that are disabled by default, then
-you should check whether they impact performance significantly. It’s
-likely that they were not enabled by default because it is known that
-they reduce performance at least in large repositories.
-
- If performance is only slow inside certain unusually large
-repositories, then you might want to disable certain features on a
-per-repository or per-repository-class basis only. See *note
-Per-Repository Configuration::. For example it takes a long time to
-determine the next and current tag in repository with exceptional
-numbers of tags. It would therefore be a good idea to disable
-‘magit-insert-tags-headers’, as explained at the mentioned node.
-
-* Menu:
-
-* Microsoft Windows Performance::
-* MacOS Performance::
-
-Log Performance
-...............
-
-When showing logs, Magit limits the number of commits initially shown in
-the hope that this avoids unnecessary work. When using ‘--graph’ is
-used, then this unfortunately does not have the desired effect for large
-histories. Junio, Git’s maintainer, said on the git mailing list
-(<http://www.spinics.net/lists/git/msg232230.html>): "‘--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 ‘-<N>’ but by also using a range. But unfortunately
-that’s not always possible.
-
- When more than a few thousand commits are shown, then the use of
-‘--graph’ can slow things down.
-
- Using ‘--color --graph’ is even slower. Magit uses code that is part
-of Emacs to turn control characters into faces. That code is pretty
-slow and this is quite noticeable when showing a log with many branches
-and merges. For that reason ‘--color’ is not enabled by default
-anymore. Consider leaving it at that.
-
-Diff Performance
-................
-
-If diffs are slow, then consider turning off some optional diff features
-by setting all or some of the following variables to ‘nil’:
-‘magit-diff-highlight-indentation’, ‘magit-diff-highlight-trailing’,
-‘magit-diff-paint-whitespace’, ‘magit-diff-highlight-hunk-body’, and
-‘magit-diff-refine-hunk’.
-
- When showing a commit instead of some arbitrary diff, then some
-additional information is displayed. Calculating this information can
-be quite expensive given certain circumstances. If looking at a commit
-using ‘magit-revision-mode’ takes considerably more time than looking at
-the same commit in ‘magit-diff-mode’, then consider setting
-‘magit-revision-insert-related-refs’ to ‘nil’.
-
- When you are often confronted with diffs that contain deleted files,
-then you might want to enable the ‘--irreversible-delete’ argument. If
-you do that then diffs still show that a file was deleted but without
-also showing the complete deleted content of the file. This argument is
-not available by default, see *note (transient)Enabling and Disabling
-Suffixes::. Once you have done that you should enable it and save that
-setting, see *note (transient)Saving Values::. You should do this in
-both the diff (‘d’) and the diff refresh (‘D’) transient popups.
-
-Refs Buffer Performance
-.......................
-
-When refreshing the "references buffer" is slow, then that’s usually
-because several hundred refs are being displayed. The best way to
-address that is to display fewer refs, obviously.
-
- If you are not, or only mildly, interested in seeing the list of
-tags, then start by not displaying them:
-
- (remove-hook 'magit-refs-sections-hook 'magit-insert-tags)
-
- Then you should also make sure that the listed remote branches
-actually all exist. You can do so by pruning branches which no longer
-exist using ‘f-pa’.
-
-Committing Performance
-......................
-
-When you initiate a commit, then Magit by default automatically shows a
-diff of the changes you are about to commit. For large commits this can
-take a long time, which is especially distracting when you are
-committing large amounts of generated data which you don’t actually
-intend to inspect before committing. This behavior can be turned off
-using:
-
- (remove-hook 'server-switch-hook 'magit-commit-diff)
-
- Then you can type ‘C-c C-d’ to show the diff when you actually want
-to see it, but only then. Alternatively you can leave the hook alone
-and just type ‘C-g’ in those cases when it takes too long to generate
-the diff. If you do that, then you will end up with a broken diff
-buffer, but doing it this way has the advantage that you usually get to
-see the diff, which is useful because it increases the odds that you
-spot potential issues.
-
-\1f
-File: magit.info, Node: Microsoft Windows Performance, Next: MacOS Performance, Up: Performance
-
-Microsoft Windows Performance
-.............................
-
-In order to update the status buffer, ‘git’ has to be run a few dozen
-times. That is problematic on Microsoft Windows, because that operating
-system is exceptionally slow at starting processes. Sadly this is an
-issue that can only be fixed by Microsoft itself, and they don’t appear
-to be particularly interested in doing so.
-
- Beside the subprocess issue, there are also other Windows-specific
-performance issues. Some of these have workarounds. The maintainers of
-"Git for Windows" try to improve performance on Windows. Always use the
-latest release in order to benefit from the latest performance tweaks.
-Magit too tries to work around some Windows-specific issues.
-
- According to some sources, setting the following Git variables can
-also help.
-
- git config --global core.preloadindex true # default since v2.1
- git config --global core.fscache true # default since v2.8
- git config --global gc.auto 256
-
- You should also check whether an anti-virus program is affecting
-performance.
-
-\1f
-File: magit.info, Node: MacOS Performance, Prev: Microsoft Windows Performance, Up: Performance
-
-MacOS Performance
-.................
-
-Before Emacs 26.1 child processes were created using ‘fork’ on macOS.
-That needlessly copied GUI resources, which is expensive. The result
-was that forking took about 30 times as long on Darwin than on Linux,
-and because Magit starts many ‘git’ processes that made quite a
-difference.
-
- So make sure that you are using at least Emacs 26.1, in which case
-the faster ‘vfork’ will be used. (The creation of child processes still
-takes about twice as long on Darwin compared to Linux.) See (1) for
-more information.
-
- On Catalina, and potentially other macOS releases, there may be a
-performance problem where any action takes 20 times longer on Darwin
-than on Linux. This can be worked around by setting
-‘magit-git-executable’ to the absolute path of the ‘git’ executable,
-instead of relying on resolving the ‘$PATH’. You should not do that if
-you want to use Magit on remote machines using Tramp and if ‘git’ is not
-installed in the same location on those machines.
-
- ---------- Footnotes ----------
-
- (1)
-<https://lists.gnu.org/archive/html/bug-gnu-emacs/2017-04/msg00201.html>
-
-\1f
-File: magit.info, Node: Default Bindings, Prev: Performance, Up: Essential Settings
-
-9.2.3 Default Bindings
-----------------------
-
- -- User Option: magit-define-global-key-bindings
-
- This option controls whether some Magit commands are automatically
- bound in the global keymap even before Magit is used for the first
- time in the current session.
-
- If this variable is non-nil, which it is by default, then the
- following bindings may be added to the global keymap.
-
- ‘C-x g’ ‘magit-status’
- ‘C-x M-g’ ‘magit-dispatch’
- ‘C-c M-g’ ‘magit-file-dispatch’
-
- These bindings may be added when ‘after-init-hook’ is called. Each
- binding is added if and only if at that time no other key is bound
- to the same command and no other command is bound to the same key.
- In other words we try to avoid adding bindings that are
- unnecessary, as well as bindings that conflict with other bindings.
-
- Adding the above bindings is delayed until ‘after-init-hook’ is
- called to allow users to set the variable anywhere in their init
- file (without having to make sure to do so before ‘magit’ is loaded
- or autoloaded) and to increase the likelihood that all the
- potentially conflicting user bindings have already been added.
-
- Setting this variable after the hook has already been called has no
- effect.
-
- We recommend that you bind ‘C-c g’ instead of ‘C-c M-g’ to
- ‘magit-file-dispatch’. The former is a much better binding but the
- ‘C-c <letter>’ namespace is strictly reserved for users; preventing
- Magit from using it by default.
-
- (global-set-key (kbd "C-c g") 'magit-file-dispatch)
-
- Also see *note Commands for Buffers Visiting Files:: and *note
- (elisp)Key Binding Conventions::.
-
-\1f
-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
-<https://github.com/magit/magit/wiki/Plugin-Dispatch-Key-Registry>.
-
-* Menu:
-
-* Calling Git::
-* Section Plumbing::
-* Refreshing Buffers::
-* Conventions::
-
-\1f
-File: magit.info, Node: Calling Git, Next: Section Plumbing, Up: Plumbing
-
-10.1 Calling Git
-================
-
-Magit provides many specialized functions for calling Git. All of these
-functions are defined in either ‘magit-git.el’ or ‘magit-process.el’ and
-have one of the prefixes ‘magit-run-’, ‘magit-call-’, ‘magit-start-’, or
-‘magit-git-’ (which is also used for other things).
-
- All of these functions accept an indefinite number of arguments,
-which are strings that specify command line arguments for Git (or in
-some cases an arbitrary executable). These arguments are flattened
-before being passed on to the executable; so instead of strings they can
-also be lists of strings and arguments that are ‘nil’ are silently
-dropped. Some of these functions also require a single mandatory
-argument before these command line arguments.
-
- Roughly speaking, these functions run Git either to get some value or
-for side-effects. The functions that return a value are useful to
-collect the information necessary to populate a Magit buffer, while the
-others are used to implement Magit commands.
-
- The functions in the value-only group always run synchronously, and
-they never trigger a refresh. The function in the side-effect group can
-be further divided into subgroups depending on whether they run Git
-synchronously or asynchronously, and depending on whether they trigger a
-refresh when the executable has finished.
-
-* Menu:
-
-* Getting a Value from Git::
-* Calling Git for Effect::
-
-\1f
-File: magit.info, Node: Getting a Value from Git, Next: Calling Git for Effect, Up: Calling Git
-
-10.1.1 Getting a Value from Git
--------------------------------
-
-These functions run Git in order to get a value, an exit status, or
-output. Of course you could also use them to run Git commands that have
-side-effects, but that should be avoided.
-
- -- Function: magit-git-exit-code &rest args
-
- Executes git with ARGS and returns its exit code.
-
- -- Function: magit-git-success &rest args
-
- Executes git with ARGS and returns ‘t’ if the exit code is ‘0’,
- ‘nil’ otherwise.
-
- -- Function: magit-git-failure &rest args
-
- Executes git with ARGS and returns ‘t’ if the exit code is ‘1’,
- ‘nil’ otherwise.
-
- -- Function: magit-git-true &rest args
-
- Executes git with ARGS and returns ‘t’ if the first line printed by
- git is the string "true", ‘nil’ otherwise.
-
- -- Function: magit-git-false &rest args
-
- Executes git with ARGS and returns ‘t’ if the first line printed by
- git is the string "false", ‘nil’ otherwise.
-
- -- Function: magit-git-insert &rest args
-
- Executes git with ARGS and inserts its output at point.
-
- -- Function: magit-git-string &rest args
-
- Executes git with ARGS and returns the first line of its output.
- If there is no output or if it begins with a newline character,
- then this returns ‘nil’.
-
- -- Function: magit-git-lines &rest args
-
- Executes git with ARGS and returns its output as a list of lines.
- Empty lines anywhere in the output are omitted.
-
- -- Function: magit-git-items &rest args
-
- Executes git with ARGS and returns its null-separated output as a
- list. Empty items anywhere in the output are omitted.
-
- If the value of option ‘magit-git-debug’ is non-nil and git exits
- with a non-zero exit status, then warn about that in the echo area
- and add a section containing git’s standard error in the current
- repository’s process buffer.
-
- 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.
-
-\1f
-File: magit.info, Node: Calling Git for Effect, Prev: Getting a Value from Git, Up: Calling Git
-
-10.1.2 Calling Git for Effect
------------------------------
-
-These functions are used to run git to produce some effect. Most Magit
-commands that actually run git do so by using such a function.
-
- Because we do not need to consume git’s output when using these
-functions, their output is instead logged into a per-repository buffer,
-which can be shown using ‘$’ from a Magit buffer or ‘M-x magit-process’
-elsewhere.
-
- These functions can have an effect in two distinct ways. Firstly,
-running git may change something, i.e. create or push a new commit.
-Secondly, that change may require that Magit buffers are refreshed to
-reflect the changed state of the repository. But refreshing isn’t
-always desirable, so only some of these functions do perform such a
-refresh after git has returned.
-
- Sometimes it is useful to run git asynchronously. For example, when
-the user has just initiated a push, then there is no reason to make her
-wait until that has completed. In other cases it makes sense to wait
-for git to complete before letting the user do something else. For
-example after staging a change it is useful to wait until after the
-refresh because that also automatically moves to the next change.
-
- -- Function: magit-call-git &rest args
-
- Calls git synchronously with ARGS.
-
- -- Function: magit-call-process program &rest args
-
- Calls PROGRAM synchronously with ARGS.
-
- -- Function: magit-run-git &rest args
-
- Calls git synchronously with ARGS and then refreshes.
-
- -- Function: magit-run-git-with-input input &rest args
-
- Calls git synchronously with ARGS and sends it INPUT on standard
- input.
-
- INPUT should be a buffer or the name of an existing buffer. The
- content of that buffer is used as the process’s standard input.
- After the process returns a refresh is performed.
-
- As a special case, INPUT may also be nil. In that case the content
- of the current buffer is used as standard input and *no* refresh is
- performed.
-
- This function actually runs git asynchronously. But then it waits
- for the process to return, so the function itself is synchronous.
-
- -- Function: magit-run-git-with-logfile file &rest args
-
- Calls git synchronously with ARGS. The process’s output is saved
- in FILE. This is rarely useful and so this function might be
- removed in the future.
-
- This function actually runs git asynchronously. But then it waits
- for the process to return, so the function itself is synchronous.
-
- -- 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 &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.
-
-\1f
-File: magit.info, Node: Section Plumbing, Next: Refreshing Buffers, Prev: Calling Git, Up: Plumbing
-
-10.2 Section Plumbing
-=====================
-
-* Menu:
-
-* Creating Sections::
-* Section Selection::
-* Matching Sections::
-
-\1f
-File: magit.info, Node: Creating Sections, Next: Section Selection, Up: Section Plumbing
-
-10.2.1 Creating Sections
-------------------------
-
- -- Macro: magit-insert-section &rest args
-
- Insert a section at point.
-
- TYPE is the section type, a symbol. Many commands that act on the
- current section behave differently depending on that type. Also if
- a variable ‘magit-TYPE-section-map’ exists, then use that as the
- text-property ‘keymap’ of all text belonging to the section (but
- this may be overwritten in subsections). TYPE can also have the
- form ‘(eval FORM)’ in which case FORM is evaluated at runtime.
-
- Optional VALUE is the value of the section, usually a string that
- is required when acting on the section.
-
- When optional HIDE is non-nil collapse the section body by default,
- i.e. when first creating the section, but not when refreshing the
- buffer. Otherwise, expand it by default. This can be overwritten
- using ‘magit-section-set-visibility-hook’. When a section is
- recreated during a refresh, then the visibility of predecessor is
- inherited and HIDE is ignored (but the hook is still honored).
-
- BODY is any number of forms that actually insert the section’s
- heading and body. Optional NAME, if specified, has to be a symbol,
- which is then bound to the struct of the section being inserted.
-
- Before BODY is evaluated the ‘start’ of the section object is set
- to the value of ‘point’ and after BODY was evaluated its ‘end’ is
- set to the new value of ‘point’; BODY is responsible for moving
- ‘point’ forward.
-
- If it turns out inside BODY that the section is empty, then
- ‘magit-cancel-section’ can be used to abort and remove all traces
- of the partially inserted section. This can happen when creating a
- section by washing Git’s output and Git didn’t actually output
- anything this time around.
-
- -- Function: magit-insert-heading &rest args
-
- Insert the heading for the section currently being inserted.
-
- This function should only be used inside ‘magit-insert-section’.
-
- When called without any arguments, then just set the ‘content’ slot
- of the object representing the section being inserted to a marker
- at ‘point’. The section should only contain a single line when
- this function is used like this.
-
- When called with arguments ARGS, which have to be strings, then
- insert those strings at point. The section should not contain any
- text before this happens and afterwards it should again only
- contain a single line. If the ‘face’ property is set anywhere
- inside any of these strings, then insert all of them unchanged.
- Otherwise use the ‘magit-section-heading’ face for all inserted
- text.
-
- The ‘content’ property of the section struct is the end of the
- heading (which lasts from ‘start’ to ‘content’) and the beginning
- of the body (which lasts from ‘content’ to ‘end’). If the value of
- ‘content’ is nil, then the section has no heading and its body
- cannot be collapsed. If a section does have a heading then its
- height must be exactly one line, including a trailing newline
- character. This isn’t enforced; you are responsible for getting it
- right. The only exception is that this function does insert a
- newline character if necessary.
-
- -- Function: magit-cancel-section
-
- Cancel the section currently being inserted. This exits the
- innermost call to ‘magit-insert-section’ and removes all traces of
- what has already happened inside that call.
-
- -- Function: magit-define-section-jumper sym title &optional value
-
- Define an interactive function to go to section SYM. TITLE is the
- displayed title of the section.
-
-\1f
-File: magit.info, Node: Section Selection, Next: Matching Sections, Prev: Creating Sections, Up: Section Plumbing
-
-10.2.2 Section Selection
-------------------------
-
- -- Function: magit-current-section
-
- Return the section at point.
-
- -- Function: magit-region-sections &optional condition multiple
-
- Return a list of the selected sections.
-
- When the region is active and constitutes a valid section
- selection, then return a list of all selected sections. This is
- the case when the region begins in the heading of a section and
- ends in the heading of the same section or in that of a sibling
- section. If optional MULTIPLE is non-nil, then the region cannot
- begin and end in the same section.
-
- When the selection is not valid, then return nil. In this case,
- most commands that can act on the selected sections will instead
- act on the section at point.
-
- When the region looks like it would in any other buffer then the
- selection is invalid. When the selection is valid then the region
- uses the ‘magit-section-highlight’ face. This does not apply to
- diffs where things get a bit more complicated, but even here if the
- region looks like it usually does, then that’s not a valid
- selection as far as this function is concerned.
-
- If optional CONDITION is non-nil, then the selection not only has
- to be valid; all selected sections additionally have to match
- CONDITION, or nil is returned. See ‘magit-section-match’ for the
- forms CONDITION can take.
-
- -- Function: magit-region-values &optional condition multiple
-
- Return a list of the values of the selected sections.
-
- Return the values that themselves would be returned by
- ‘magit-region-sections’ (which see).
-
-\1f
-File: magit.info, Node: Matching Sections, Prev: Section Selection, Up: Section Plumbing
-
-10.2.3 Matching Sections
-------------------------
-
-‘M-x magit-describe-section-briefly’ (‘magit-describe-section-briefly’)
-
- Show information about the section at point. This command is
- intended for debugging purposes.
-
- -- Function: magit-section-ident section
-
- Return an unique identifier for SECTION. The return value has the
- form ‘((TYPE . VALUE)...)’.
-
- -- Function: magit-get-section ident &optional root
-
- Return the section identified by IDENT. IDENT has to be a list as
- returned by ‘magit-section-ident’.
-
- -- Function: magit-section-match condition &optional section
-
- Return ‘t’ if SECTION matches CONDITION. SECTION defaults to the
- section at point. If SECTION is not specified and there also is no
- section at point, then return ‘nil’.
-
- CONDITION can take the following forms:
- • ‘(CONDITION...)’
-
- matches if any of the CONDITIONs matches.
-
- • ‘[CLASS...]’
-
- matches if the section’s class is the same as the first CLASS
- or a subclass of that; the section’s parent class matches the
- second CLASS; and so on.
-
- • ‘[* CLASS...]’
-
- matches sections that match ‘[CLASS...]’ and also recursively
- all their child sections.
-
- • ‘CLASS’
-
- matches if the section’s class is the same as CLASS or a
- subclass of that; regardless of the classes of the parent
- sections.
-
- Each CLASS should be a class symbol, identifying a class that
- derives from ‘magit-section’. For backward compatibility CLASS can
- also be a "type symbol". A section matches such a symbol if the
- value of its ‘type’ slot is ‘eq’. If a type symbol has an entry in
- ‘magit--section-type-alist’, then a section also matches that type
- if its class is a subclass of the class that corresponds to the
- type as per that alist.
-
- Note that it is not necessary to specify the complete section
- lineage as printed by ‘magit-describe-section-briefly’, unless of
- course you want to be that precise.
-
- -- Function: magit-section-value-if condition &optional section
-
- If the section at point matches CONDITION, then return its value.
-
- If optional SECTION is non-nil then test whether that matches
- instead. If there is no section at point and SECTION is nil, then
- return nil. If the section does not match, then return nil.
-
- See ‘magit-section-match’ for the forms CONDITION can take.
-
- -- Function: magit-section-case &rest clauses
-
- Choose among clauses on the type of the section at point.
-
- Each clause looks like (CONDITION BODY...). The type of the
- section is compared against each CONDITION; the BODY forms of the
- first match are evaluated sequentially and the value of the last
- form is returned. Inside BODY the symbol ‘it’ is bound to the
- section at point. If no clause succeeds or if there is no section
- at point return nil.
-
- See ‘magit-section-match’ for the forms CONDITION can take.
- Additionally a CONDITION of t is allowed in the final clause and
- matches if no other CONDITION match, even if there is no section at
- point.
-
- -- Variable: magit-root-section
-
- The root section in the current buffer. All other sections are
- descendants of this section. The value of this variable is set by
- ‘magit-insert-section’ and you should never modify it.
-
- For diff related sections a few additional tools exist.
-
- -- Function: magit-diff-type &optional section
-
- Return the diff type of SECTION.
-
- The returned type is one of the symbols ‘staged’, ‘unstaged’,
- ‘committed’, or ‘undefined’. This type serves a similar purpose as
- the general type common to all sections (which is stored in the
- ‘type’ slot of the corresponding ‘magit-section’ struct) but takes
- additional information into account. When the SECTION isn’t
- related to diffs and the buffer containing it also isn’t a
- diff-only buffer, then return nil.
-
- Currently the type can also be one of ‘tracked’ and ‘untracked’,
- but these values are not handled explicitly in every place they
- should be. A possible fix could be to just return nil here.
-
- The section has to be a ‘diff’ or ‘hunk’ section, or a section
- whose children are of type ‘diff’. If optional SECTION is nil,
- return the diff type for the current section. In buffers whose
- major mode is ‘magit-diff-mode’ SECTION is ignored and the type is
- determined using other means. In ‘magit-revision-mode’ buffers the
- type is always ‘committed’.
-
- -- Function: magit-diff-scope &optional section strict
-
- Return the diff scope of SECTION or the selected section(s).
-
- A diff’s "scope" describes what part of a diff is selected, it is a
- symbol, one of ‘region’, ‘hunk’, ‘hunks’, ‘file’, ‘files’, or
- ‘list’. Do not confuse this with the diff "type", as returned by
- ‘magit-diff-type’.
-
- If optional SECTION is non-nil, then return the scope of that,
- ignoring the sections selected by the region. Otherwise return the
- scope of the current section, or if the region is active and
- selects a valid group of diff related sections, the type of these
- sections, i.e. ‘hunks’ or ‘files’. If SECTION (or if the current
- section that is nil) is a ‘hunk’ section and the region starts and
- ends inside the body of a that section, then the type is ‘region’.
-
- If optional STRICT is non-nil then return nil if the diff type of
- the section at point is ‘untracked’ or the section at point is not
- actually a ‘diff’ but a ‘diffstat’ section.
-
-\1f
-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<N>’ argument. In
- both case this is done by changing the value of this variable and
- then calling this ‘magit-refresh-function’.
-
-\1f
-File: magit.info, Node: Conventions, Prev: Refreshing Buffers, Up: Plumbing
-
-10.4 Conventions
-================
-
-Also see *note Completion and Confirmation::.
-
-* Menu:
-
-* Theming Faces::
-
-\1f
-File: magit.info, Node: Theming Faces, Up: Conventions
-
-10.4.1 Theming Faces
---------------------
-
-The default theme uses blue for local branches, green for remote
-branches, and goldenrod (brownish yellow) for tags. When creating a new
-theme, you should probably follow that example. If your theme already
-uses other colors, then stick to that.
-
- In older releases these reference faces used to have a background
-color and a box around them. The basic default faces no longer do so,
-to make Magit buffers much less noisy, and you should follow that
-example at least with regards to boxes. (Boxes were used in the past to
-work around a conflict between the highlighting overlay and text
-property backgrounds. That’s no longer necessary because highlighting
-no longer causes other background colors to disappear.) Alternatively
-you can keep the background color and/or box, but then have to take
-special care to adjust ‘magit-branch-current’ accordingly. By default
-it looks mostly like ‘magit-branch-local’, but with a box (by default
-the former is the only face that uses a box, exactly so that it sticks
-out). If the former also uses a box, then you have to make sure that it
-differs in some other way from the latter.
-
- The most difficult faces to theme are those related to diffs,
-headings, highlighting, and the region. There are faces that fall into
-all four groups - expect to spend some time getting this right.
-
- The ‘region’ face in the default theme, in both the light and dark
-variants, as well as in many other themes, distributed with Emacs or by
-third-parties, is very ugly. It is common to use a background color
-that really sticks out, which is ugly but if that were the only problem
-then it would be acceptable. Unfortunately many themes also set the
-foreground color, which ensures that all text within the region is
-readable. Without doing that there might be cases where some foreground
-color is too close to the region background color to still be readable.
-But it also means that text within the region loses all syntax
-highlighting.
-
- I consider the work that went into getting the ‘region’ face right to
-be a good indicator for the general quality of a theme. My
-recommendation for the ‘region’ face is this: use a background color
-slightly different from the background color of the ‘default’ face, and
-do not set the foreground color at all. So for a light theme you might
-use a light (possibly tinted) gray as the background color of ‘default’
-and a somewhat darker gray for the background of ‘region’. That should
-usually be enough to not collide with the foreground color of any other
-face. But if some other faces also set a light gray as background
-color, then you should also make sure it doesn’t collide with those (in
-some cases it might be acceptable though).
-
- Magit only uses the ‘region’ face when the region is "invalid" by its
-own definition. In a Magit buffer the region is used to either select
-multiple sibling sections, so that commands which support it act on all
-of these sections instead of just the current section, or to select
-lines within a single hunk section. In all other cases, the section is
-considered invalid and Magit won’t act on it. But such invalid sections
-happen, either because the user has not moved point enough yet to make
-it valid or because she wants to use a non-magit command to act on the
-region, e.g. ‘kill-region’.
-
- So using the regular ‘region’ face for invalid sections is a feature.
-It tells the user that Magit won’t be able to act on it. It’s
-acceptable if that face looks a bit odd and even (but less so) if it
-collides with the background colors of section headings and other things
-that have a background color.
-
- Magit highlights the current section. If a section has subsections,
-then all of them are highlighted. This is done using faces that have
-"highlight" in their names. For most sections,
-‘magit-section-highlight’ is used for both the body and the heading.
-Like the ‘region’ face, it should only set the background color to
-something similar to that of ‘default’. The highlight background color
-must be different from both the ‘region’ background color and the
-‘default’ background color.
-
- For diff related sections Magit uses various faces to highlight
-different parts of the selected section(s). Note that hunk headings,
-unlike all other section headings, by default have a background color,
-because it is useful to have very visible separators between hunks.
-That face ‘magit-diff-hunk-heading’, should be different from both
-‘magit-diff-hunk-heading-highlight’ and ‘magit-section-highlight’, as
-well as from ‘magit-diff-context’ and ‘magit-diff-context-highlight’.
-By default we do that by changing the foreground color. Changing the
-background color would lead to complications, and there are already
-enough we cannot get around. (Also note that it is generally a good
-idea for section headings to always be bold, but only for sections that
-have subsections).
-
- When there is a valid region selecting diff-related sibling sections,
-i.e. multiple files or hunks, then the bodies of all these sections use
-the respective highlight faces, but additionally the headings instead
-use one of the faces ‘magit-diff-file-heading-selection’ or
-‘magit-diff-hunk-heading-selection’. These faces have to be different
-from the regular highlight variants to provide explicit visual
-indication that the region is active.
-
- When theming diff related faces, start by setting the option
-‘magit-diff-refine-hunk’ to ‘all’. You might personally prefer to only
-refine the current hunk or not use hunk refinement at all, but some of
-the users of your theme want all hunks to be refined, so you have to
-cater to that.
-
- (Also turn on ‘magit-diff-highlight-indentation’,
-‘magit-diff-highlight-trailing’, and ‘magit-diff-paint-whitespace’; and
-insert some whitespace errors into the code you use for testing.)
-
- For e.g. "added lines" you have to adjust three faces:
-‘magit-diff-added’, ‘magit-diff-added-highlight’, and
-‘smerge-refined-added’. Make sure that the latter works well with both
-of the former, as well as ‘smerge-other’ and ‘diff-added’. Then do the
-same for the removed lines, context lines, lines added by us, and lines
-added by them. Also make sure the respective added, removed, and
-context faces use approximately the same saturation for both the
-highlighted and unhighlighted variants. Also make sure the file and
-diff headings work nicely with context lines (e.g. make them look
-different). Line faces should set both the foreground and the
-background color. For example, for added lines use two different
-greens.
-
- It’s best if the foreground color of both the highlighted and the
-unhighlighted variants are the same, so you will need to have to find a
-color that works well on the highlight and unhighlighted background, the
-refine background, and the highlight context background. When there is
-an hunk internal region, then the added- and removed-lines background
-color is used only within that region. Outside the region the
-highlighted context background color is used. This makes it easier to
-see what is being staged. With an hunk internal region the hunk heading
-is shown using ‘magit-diff-hunk-heading-selection’, and so are the thin
-lines that are added around the lines that fall within the region. The
-background color of that has to be distinct enough from the various
-other involved background colors.
-
- Nobody said this would be easy. If your theme restricts itself to a
-certain set of colors, then you should make an exception here.
-Otherwise it would be impossible to make the diffs look good in each and
-every variation. Actually you might want to just stick to the default
-definitions for these faces. You have been warned. Also please note
-that if you do not get this right, this will in some cases look to users
-like bugs in Magit - so please do it right or not at all.
-
-\1f
-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
-<https://github.com/magit/magit/wiki/FAQ>.
-
- Please also use the *note Debugging Tools::.
-
-* Menu:
-
-* FAQ - How to ...?::
-* FAQ - Issues and Errors::
-
-\1f
-File: magit.info, Node: FAQ - How to ...?, Next: FAQ - Issues and Errors, Up: FAQ
-
-A.1 FAQ - How to ...?
-=====================
-
-* Menu:
-
-* How to pronounce Magit?::
-* How to show git's output?::
-* How to install the gitman info manual?::
-* How to show diffs for gpg-encrypted files?::
-* How does branching and pushing work?::
-* Can Magit be used as ediff-version-control-package?::
-* Should I disable VC?::
-
-\1f
-File: magit.info, Node: How to pronounce Magit?, Next: How to show git's output?, Up: FAQ - How to ...?
-
-A.1.1 How to pronounce Magit?
------------------------------
-
-Either ‘mu[m's] git’ or ‘magi{c => t}’ is fine.
-
- The slogan is "It’s Magit! The magical Git client", so it makes
-sense to pronounce Magit like magic, while taking into account that C
-and T do not sound the same.
-
- The German "Magie" is not pronounced the same as the English "magic",
-so if you speak German then you can use the above rational to justify
-using the former pronunciation; ‘Mag{ie => it}’.
-
- You can also choose to use the former pronunciation just because you
-like it better.
-
- Also see <https://magit.vc/assets/videos/magic.mp4>. Also see
-<https://emacs.stackexchange.com/questions/13696>.
-
-\1f
-File: magit.info, Node: How to show git's output?, Next: How to install the gitman info manual?, Prev: How to pronounce Magit?, Up: FAQ - How to ...?
-
-A.1.2 How to show git’s output?
--------------------------------
-
-To show the output of recently run git commands, press ‘$’ (or, if that
-isn’t available, ‘M-x magit-process-buffer’). This will show a buffer
-containing a section per git invocation; as always press ‘TAB’ to expand
-or collapse them.
-
- By default, git’s output is only inserted into the process buffer if
-it is run for side-effects. When the output is consumed in some way,
-also inserting it into the process buffer would be too expensive. For
-debugging purposes, it’s possible to do so anyway by setting
-‘magit-git-debug’ to ‘t’.
-
-\1f
-File: magit.info, Node: How to install the gitman info manual?, Next: How to show diffs for gpg-encrypted files?, Prev: How to show git's output?, Up: FAQ - How to ...?
-
-A.1.3 How to install the gitman info manual?
---------------------------------------------
-
-Git’s manpages can be exported as an info manual called ‘gitman’.
-Magit’s own info manual links to nodes in that manual instead of the
-actual manpages because Info doesn’t support linking to manpages.
-
- Unfortunately some distributions do not install the ‘gitman’ manual
-by default and you will have to install a separate documentation package
-to get it.
-
- Magit patches Info adding the ability to visit links to the ‘gitman’
-Info manual by instead viewing the respective manpage. If you prefer
-that approach, then set the value of ‘magit-view-git-manual-method’ to
-one of the supported packages ‘man’ or ‘woman’, e.g.:
-
- (setq magit-view-git-manual-method 'man)
-
-\1f
-File: magit.info, Node: How to show diffs for gpg-encrypted files?, Next: How does branching and pushing work?, Prev: How to install the gitman info manual?, Up: FAQ - How to ...?
-
-A.1.4 How to show diffs for gpg-encrypted files?
-------------------------------------------------
-
-Git supports showing diffs for encrypted files, but has to be told to do
-so. Since Magit just uses Git to get the diffs, configuring Git also
-affects the diffs displayed inside Magit.
-
- git config --global diff.gpg.textconv "gpg --no-tty --decrypt"
- echo "*.gpg filter=gpg diff=gpg" > .gitattributes
-
-\1f
-File: magit.info, Node: How does branching and pushing work?, Next: Can Magit be used as ediff-version-control-package?, Prev: How to show diffs for gpg-encrypted files?, Up: FAQ - How to ...?
-
-A.1.5 How does branching and pushing work?
-------------------------------------------
-
-Please see *note Branching:: and
-<http://emacsair.me/2016/01/18/magit-2.4>
-
-\1f
-File: magit.info, Node: Can Magit be used as ediff-version-control-package?, Next: Should I disable VC?, Prev: How does branching and pushing work?, Up: FAQ - How to ...?
-
-A.1.6 Can Magit be used as ‘ediff-version-control-package’?
------------------------------------------------------------
-
-No, it cannot. For that to work the functions ‘ediff-magit-internal’
-and ‘ediff-magit-merge-internal’ would have to be implemented, and they
-are not. These two functions are only used by the three commands
-‘ediff-revision’, ‘ediff-merge-revisions-with-ancestor’, and
-‘ediff-merge-revisions’.
-
- These commands only delegate the task of populating buffers with
-certain revisions to the "internal" functions. The equally important
-task of determining which revisions are to be compared/merged is not
-delegated. Instead this is done without any support whatsoever from the
-version control package/system - meaning that the user has to enter the
-revisions explicitly. Instead of implementing ‘ediff-magit-internal’ we
-provide ‘magit-ediff-compare’, which handles both tasks like it is 2005.
-
- The other commands ‘ediff-merge-revisions’ and
-‘ediff-merge-revisions-with-ancestor’ are normally not what you want
-when using a modern version control system like Git. Instead of letting
-the user resolve only those conflicts which Git could not resolve on its
-own, they throw away all work done by Git and then expect the user to
-manually merge all conflicts, including those that had already been
-resolved. That made sense back in the days when version control systems
-couldn’t merge (or so I have been told), but not anymore. Once in a
-blue moon you might actually want to see all conflicts, in which case
-you *can* use these commands, which then use ‘ediff-vc-merge-internal’.
-So we don’t actually have to implement ‘ediff-magit-merge-internal’.
-Instead we provide the more useful command ‘magit-ediff-resolve’ which
-only shows yet-to-be resolved conflicts.
-
-\1f
-File: magit.info, Node: Should I disable VC?, Prev: Can Magit be used as ediff-version-control-package?, Up: FAQ - How to ...?
-
-A.1.7 Should I disable VC?
---------------------------
-
-If you don’t use VC (the built-in version control interface) then you
-might be tempted to disable it, not least because we used to recommend
-that you do that.
-
- We no longer recommend that you disable VC. Doing so would break
-useful third-party packages (such as ‘diff-hl’), which depend on VC
-being enabled.
-
- If you choose to disable VC anyway, then you can do so by changing
-the value of ‘vc-handled-backends’.
-
-\1f
-File: magit.info, Node: FAQ - Issues and Errors, Prev: FAQ - How to ...?, Up: FAQ
-
-A.2 FAQ - Issues and Errors
-===========================
-
-* Menu:
-
-* Magit is slow::
-* I changed several thousand files at once and now Magit is unusable::
-* I am having problems committing::
-* I am using MS Windows and cannot push with Magit::
-* I am using OS X and SOMETHING works in shell, but not in Magit: I am using OS X and SOMETHING works in shell but not in Magit.
-* Expanding a file to show the diff causes it to disappear::
-* Point is wrong in the COMMIT_EDITMSG buffer::
-* The mode-line information isn't always up-to-date::
-* A branch and tag sharing the same name breaks SOMETHING::
-* My Git hooks work on the command-line but not inside Magit::
-* git-commit-mode isn't used when committing from the command-line::
-* Point ends up inside invisible text when jumping to a file-visiting buffer::
-
-\1f
-File: magit.info, Node: Magit is slow, Next: I changed several thousand files at once and now Magit is unusable, Up: FAQ - Issues and Errors
-
-A.2.1 Magit is slow
--------------------
-
-See *note Performance::.
-
-\1f
-File: magit.info, Node: I changed several thousand files at once and now Magit is unusable, Next: I am having problems committing, Prev: Magit is slow, Up: FAQ - Issues and Errors
-
-A.2.2 I changed several thousand files at once and now Magit is unusable
-------------------------------------------------------------------------
-
-Magit is *currently* not expected to work under such conditions. It
-sure would be nice if it did, and v2.5 will hopefully be a big step into
-that direction. But it might take until v3.1 to accomplish fully
-satisfactory performance, because that requires some heavy refactoring.
-
- But for now we recommend you use the command line to complete this
-one commit. Also see *note Performance::.
-
-\1f
-File: magit.info, Node: I am having problems committing, Next: I am using MS Windows and cannot push with Magit, Prev: I changed several thousand files at once and now Magit is unusable, Up: FAQ - Issues and Errors
-
-A.2.3 I am having problems committing
--------------------------------------
-
-That likely means that Magit is having problems finding an appropriate
-emacsclient executable. See *note (with-editor)Configuring
-With-Editor:: and *note (with-editor)Debugging::.
-
-\1f
-File: magit.info, Node: I am using MS Windows and cannot push with Magit, Next: I am using OS X and SOMETHING works in shell but not in Magit, Prev: I am having problems committing, Up: FAQ - Issues and Errors
-
-A.2.4 I am using MS Windows and cannot push with Magit
-------------------------------------------------------
-
-It’s almost certain that Magit is only incidental to this issue. It is
-much more likely that this is a configuration issue, even if you can
-push on the command line.
-
- Detailed setup instructions can be found at
-<https://github.com/magit/magit/wiki/Pushing-with-Magit-from-Windows>.
-
-\1f
-File: magit.info, Node: I am using OS X and SOMETHING works in shell but not in Magit, Next: Expanding a file to show the diff causes it to disappear, Prev: I am using MS Windows and cannot push with Magit, Up: FAQ - Issues and Errors
-
-A.2.5 I am using OS X and SOMETHING works in shell, but not in Magit
---------------------------------------------------------------------
-
-This usually occurs because Emacs doesn’t have the same environment
-variables as your shell. Try installing and configuring
-<https://github.com/purcell/exec-path-from-shell>. 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’.
-
-\1f
-File: magit.info, Node: Expanding a file to show the diff causes it to disappear, Next: Point is wrong in the COMMIT_EDITMSG buffer, Prev: I am using OS X and SOMETHING works in shell but not in Magit, Up: FAQ - Issues and Errors
-
-A.2.6 Expanding a file to show the diff causes it to disappear
---------------------------------------------------------------
-
-This is probably caused by a change of a ‘diff.*’ Git variable. You
-probably set that variable for a reason, and should therefore only undo
-that setting in Magit by customizing ‘magit-git-global-arguments’.
-
-\1f
-File: magit.info, Node: Point is wrong in the COMMIT_EDITMSG buffer, Next: The mode-line information isn't always up-to-date, Prev: Expanding a file to show the diff causes it to disappear, Up: FAQ - Issues and Errors
-
-A.2.7 Point is wrong in the ‘COMMIT_EDITMSG’ buffer
----------------------------------------------------
-
-Neither Magit nor ‘git-commit‘ fiddle with point in the buffer used to
-write commit messages, so something else must be doing it.
-
- You have probably globally enabled a mode which does restore point in
-file-visiting buffers. It might be a bit surprising, but when you write
-a commit message, then you are actually editing a file.
-
- So you have to figure out which package is doing. ‘saveplace’,
-‘pointback’, and ‘session’ are likely candidates. These snippets might
-help:
-
- (setq session-name-disable-regexp "\\(?:\\`'\\.git/[A-Z_]+\\'\\)")
-
- (with-eval-after-load 'pointback
- (lambda ()
- (when (or git-commit-mode git-rebase-mode)
- (pointback-mode -1))))
-
-\1f
-File: magit.info, Node: The mode-line information isn't always up-to-date, Next: A branch and tag sharing the same name breaks SOMETHING, Prev: Point is wrong in the COMMIT_EDITMSG buffer, Up: FAQ - Issues and Errors
-
-A.2.8 The mode-line information isn’t always up-to-date
--------------------------------------------------------
-
-Magit is not responsible for the version control information that is
-being displayed in the mode-line and looks something like ‘Git-master’.
-The built-in "Version Control" package, also known as "VC", updates that
-information, and can be told to do so more often:
-
- (setq auto-revert-check-vc-info t)
-
- But doing so isn’t good for performance. For more (overly
-optimistic) information see *note (emacs)VC Mode Line::.
-
- If you don’t really care about seeing this information in the
-mode-line, but just don’t want to see _incorrect_ information, then
-consider simply not displaying it in the mode-line:
-
- (setq-default mode-line-format
- (delete '(vc-mode vc-mode) mode-line-format))
-
-\1f
-File: magit.info, Node: A branch and tag sharing the same name breaks SOMETHING, Next: My Git hooks work on the command-line but not inside Magit, Prev: The mode-line information isn't always up-to-date, Up: FAQ - Issues and Errors
-
-A.2.9 A branch and tag sharing the same name breaks SOMETHING
--------------------------------------------------------------
-
-Or more generally, ambiguous refnames break SOMETHING.
-
- Magit assumes that refs are named non-ambiguously across the
-"refs/heads/", "refs/tags/", and "refs/remotes/" namespaces (i.e., all
-the names remain unique when those prefixes are stripped). We consider
-ambiguous refnames unsupported and recommend that you use a
-non-ambiguous naming scheme. However, if you do work with a repository
-that has ambiguous refnames, please report any issues you encounter so
-that we can investigate whether there is a simple fix.
-
-\1f
-File: magit.info, Node: My Git hooks work on the command-line but not inside Magit, Next: git-commit-mode isn't used when committing from the command-line, Prev: A branch and tag sharing the same name breaks SOMETHING, Up: FAQ - Issues and Errors
-
-A.2.10 My Git hooks work on the command-line but not inside Magit
------------------------------------------------------------------
-
-When Magit calls ‘git’ it adds a few global arguments including
-‘--literal-pathspecs’ and the ‘git’ process started by Magit then passes
-that setting on to other ‘git’ process it starts itself. It does so by
-setting the environment variable ‘GIT_LITERAL_PATHSPECS’, not by calling
-subprocesses with the ‘--literal-pathspecs’ argument. You can therefore
-override this setting in hook scripts using ‘unset
-GIT_LITERAL_PATHSPECS’.
-
-\1f
-File: magit.info, Node: git-commit-mode isn't used when committing from the command-line, Next: Point ends up inside invisible text when jumping to a file-visiting buffer, Prev: My Git hooks work on the command-line but not inside Magit, Up: FAQ - Issues and Errors
-
-A.2.11 ‘git-commit-mode’ isn’t used when committing from the command-line
--------------------------------------------------------------------------
-
-The reason for this is that ‘git-commit.el’ has not been loaded yet
-and/or that the server has not been started yet. These things have
-always already been taken care of when you commit from Magit because in
-order to do so, Magit has to be loaded and doing that involves loading
-‘git-commit’ and starting the server.
-
- If you want to commit from the command-line, then you have to take
-care of these things yourself. Your ‘init.el’ file should contain:
-
- (require 'git-commit)
- (server-mode)
-
- Instead of ‘(require ’git-commit)‘ you may also use:
-
- (load "/path/to/magit-autoloads.el")
-
- You might want to do that because loading ‘git-commit’ causes large
-parts of Magit to be loaded.
-
- There are also some variations of ‘(server-mode)’ that you might want
-to try. Personally I use:
-
- (use-package server
- :config (or (server-running-p) (server-mode)))
-
- Now you can use:
-
- $ emacs&
- $ EDITOR=emacsclient git commit
-
- However you cannot use:
-
- $ killall emacs
- $ EDITOR="emacsclient --alternate-editor emacs" git commit
-
- This will actually end up using ‘emacs’, not ‘emacsclient’. If you
-do this, then you can still edit the commit message but
-‘git-commit-mode’ won’t be used and you have to exit ‘emacs’ to finish
-the process.
-
- Tautology ahead. If you want to be able to use ‘emacsclient’ to
-connect to a running ‘emacs’ instance, even though no ‘emacs’ instance
-is running, then you cannot use ‘emacsclient’ directly.
-
- Instead you have to create a script that does something like this:
-
- Try to use ‘emacsclient’ (without using ‘--alternate-editor’). If
-that succeeds, do nothing else. Otherwise start ‘emacs &’ (and
-‘init.el’ must call ‘server-start’) and try to use ‘emacsclient’ again.
-
-\1f
-File: magit.info, Node: Point ends up inside invisible text when jumping to a file-visiting buffer, Prev: git-commit-mode isn't used when committing from the command-line, Up: FAQ - Issues and Errors
-
-A.2.12 Point ends up inside invisible text when jumping to a file-visiting buffer
----------------------------------------------------------------------------------
-
-This can happen when you type ‘RET’ on a hunk to visit the respective
-file at the respective position. One solution to this problem is to use
-‘global-reveal-mode’. It makes sure that text around point is always
-visible. If that is too drastic for your taste, then you may instead
-use ‘magit-diff-visit-file-hook’ to reveal the text, possibly using
-‘reveal-post-command’ or for Org buffers ‘org-reveal’.
-
-\1f
-File: magit.info, Node: Debugging Tools, Next: Keystroke Index, Prev: FAQ, Up: Top
-
-B Debugging Tools
-*****************
-
-Magit and its dependencies provide a few debugging tools, and we
-appreciate it very much if you use those tools before reporting an
-issue. Please include all relevant output when reporting an issue.
-
-‘M-x magit-version’ (‘magit-version’)
-
- This command shows the currently used versions of Magit, Git, and
- Emacs in the echo area. Non-interactively this just returns the
- Magit version.
-
-‘M-x magit-emacs-Q-command’ (‘magit-emacs-Q-command’)
-
- This command shows a debugging shell command in the echo area and
- adds it to the kill ring. Paste that command into a shell and run
- it.
-
- This shell command starts ‘emacs’ with only ‘magit’ and its
- dependencies loaded. Neither your configuration nor other
- installed packages are loaded. This makes it easier to determine
- whether some issue lays with Magit or something else.
-
- If you run Magit from its Git repository, then you should be able
- to use ‘make emacs-Q’ instead of the output of this command.
-
-‘M-x magit-toggle-verbose-refresh’ (‘magit-toggle-verbose-refresh’)
-
- This command toggles whether Magit refreshes buffers verbosely.
- Enabling this helps figuring out which sections are bottlenecks.
- The additional output can be found in the ‘*Messages*’ buffer.
-
-‘M-x magit-debug-git-executable’ (‘magit-debug-git-executable’)
-
- This command displays a buffer containing information about the
- available and used ‘git’ executable(s), and can be useful when
- investigating ‘exec-path’ issues.
-
- Also see *note Git Executable::.
-
-‘M-x with-editor-debug’ (‘with-editor-debug’)
-
- This command displays a buffer containing information about the
- available and used ‘emacsclient’ executable(s), and can be useful
- when investigating why Magit (or rather ‘with-editor’) cannot find
- an appropriate ‘emacsclient’ executable.
-
- Also see *note (with-editor)Debugging::.
-
- Please also see the *note FAQ::.
-
-\1f
-File: magit.info, Node: Keystroke Index, Next: Command Index, Prev: Debugging Tools, Up: Top
-
-Appendix C Keystroke Index
-**************************
-
-\0\b[index\0\b]
-* Menu:
-
-* !: Running Git Manually.
- (line 12)
-* ! !: Running Git Manually.
- (line 17)
-* ! a: Running Git Manually.
- (line 58)
-* ! b: Running Git Manually.
- (line 62)
-* ! g: Running Git Manually.
- (line 66)
-* ! k: Running Git Manually.
- (line 54)
-* ! p: Running Git Manually.
- (line 25)
-* ! s: Running Git Manually.
- (line 35)
-* ! S: Running Git Manually.
- (line 40)
-* $: Viewing Git Output. (line 16)
-* %: Worktree. (line 8)
-* % b: Worktree. (line 13)
-* % c: Worktree. (line 17)
-* % g: Worktree. (line 30)
-* % k: Worktree. (line 25)
-* % m: Worktree. (line 21)
-* +: Log Buffer. (line 61)
-* + <1>: Refreshing Diffs. (line 69)
-* -: Log Buffer. (line 65)
-* - <1>: Refreshing Diffs. (line 65)
-* 0: Refreshing Diffs. (line 73)
-* 1: Section Visibility. (line 26)
-* 2: Section Visibility. (line 27)
-* 3: Section Visibility. (line 28)
-* 4: Section Visibility. (line 29)
-* =: Log Buffer. (line 55)
-* ^: Section Movement. (line 31)
-* a: Applying. (line 33)
-* A: Cherry Picking. (line 8)
-* A A: Cherry Picking. (line 17)
-* A a: Cherry Picking. (line 24)
-* A A <1>: Cherry Picking. (line 90)
-* A a <1>: Cherry Picking. (line 98)
-* A d: Cherry Picking. (line 54)
-* A h: Cherry Picking. (line 42)
-* A n: Cherry Picking. (line 65)
-* A s: Cherry Picking. (line 76)
-* A s <1>: Cherry Picking. (line 94)
-* B: Bisecting. (line 8)
-* b: Blaming. (line 102)
-* b <1>: Branch Commands. (line 12)
-* b <2>: Editing Rebase Sequences.
- (line 85)
-* B B: Bisecting. (line 16)
-* B b: Bisecting. (line 31)
-* b b: Branch Commands. (line 49)
-* b C: Branch Commands. (line 29)
-* b c: Branch Commands. (line 67)
-* B g: Bisecting. (line 36)
-* B k: Bisecting. (line 41)
-* b k: Branch Commands. (line 147)
-* b l: Branch Commands. (line 74)
-* b n: Branch Commands. (line 57)
-* B r: Bisecting. (line 47)
-* b r: Branch Commands. (line 153)
-* B s: Bisecting. (line 24)
-* b s: Branch Commands. (line 97)
-* b S: Branch Commands. (line 125)
-* b x: Branch Commands. (line 131)
-* c: Blaming. (line 135)
-* C: Cloning Repository. (line 20)
-* c <1>: Initiating a Commit. (line 8)
-* c <2>: Editing Rebase Sequences.
- (line 72)
-* c a: Initiating a Commit. (line 19)
-* c A: Initiating a Commit. (line 67)
-* C b: Cloning Repository. (line 41)
-* C C: Cloning Repository. (line 29)
-* c c: Initiating a Commit. (line 14)
-* C d: Cloning Repository. (line 54)
-* C e: Cloning Repository. (line 61)
-* c e: Initiating a Commit. (line 23)
-* c f: Initiating a Commit. (line 43)
-* c F: Initiating a Commit. (line 51)
-* C m: Cloning Repository. (line 46)
-* C s: Cloning Repository. (line 34)
-* c s: Initiating a Commit. (line 55)
-* c S: Initiating a Commit. (line 63)
-* c w: Initiating a Commit. (line 33)
-* C-<return>: Visiting Files and Blobs from a Diff.
- (line 51)
-* C-<tab>: Section Visibility. (line 13)
-* C-c C-a: Commit Pseudo Headers.
- (line 17)
-* C-c C-b: Log Buffer. (line 21)
-* C-c C-b <1>: Refreshing Diffs. (line 91)
-* C-c C-c: Transient Commands. (line 18)
-* C-c C-c <1>: Select from Log. (line 20)
-* C-c C-c <2>: Editing Commit Messages.
- (line 17)
-* C-c C-c <3>: Editing Rebase Sequences.
- (line 6)
-* C-c C-d: Refreshing Diffs. (line 81)
-* C-c C-d <1>: Editing Commit Messages.
- (line 58)
-* C-c C-e: Commands Available in Diffs.
- (line 25)
-* C-c C-f: Log Buffer. (line 25)
-* C-c C-f <1>: Refreshing Diffs. (line 95)
-* C-c C-i: Commit Pseudo Headers.
- (line 13)
-* C-c C-k: Select from Log. (line 26)
-* C-c C-k <1>: Editing Commit Messages.
- (line 22)
-* C-c C-k <2>: Editing Rebase Sequences.
- (line 11)
-* C-c C-n: Log Buffer. (line 29)
-* C-c C-o: Commit Pseudo Headers.
- (line 33)
-* C-c C-p: Commit Pseudo Headers.
- (line 37)
-* C-c C-r: Commit Pseudo Headers.
- (line 21)
-* C-c C-s: Commit Pseudo Headers.
- (line 25)
-* C-c C-t: Commands Available in Diffs.
- (line 14)
-* C-c C-t <1>: Commit Pseudo Headers.
- (line 29)
-* C-c C-w: Using the Revision Stack.
- (line 6)
-* C-c M-g: Commands for Buffers Visiting Files.
- (line 21)
-* C-c M-g B: Blaming. (line 18)
-* C-c M-g b: Blaming. (line 29)
-* C-c M-g B <1>: Commands for Buffers Visiting Files.
- (line 93)
-* C-c M-g B b: Blaming. (line 30)
-* C-c M-g B e: Blaming. (line 64)
-* C-c M-g B f: Blaming. (line 55)
-* C-c M-g B r: Blaming. (line 46)
-* C-c M-g c: Commands for Buffers Visiting Files.
- (line 38)
-* C-c M-g D: Commands for Buffers Visiting Files.
- (line 45)
-* C-c M-g d: Commands for Buffers Visiting Files.
- (line 56)
-* C-c M-g e: Blaming. (line 63)
-* C-c M-g e <1>: Commands for Buffers Visiting Files.
- (line 106)
-* C-c M-g f: Blaming. (line 54)
-* C-c M-g L: Commands for Buffers Visiting Files.
- (line 66)
-* C-c M-g l: Commands for Buffers Visiting Files.
- (line 77)
-* C-c M-g p: Commands for Buffers Visiting Files.
- (line 116)
-* C-c M-g r: Blaming. (line 45)
-* C-c M-g s: Commands for Buffers Visiting Files.
- (line 29)
-* C-c M-g t: Commands for Buffers Visiting Files.
- (line 84)
-* C-c M-g u: Commands for Buffers Visiting Files.
- (line 33)
-* C-c M-i: Commit Pseudo Headers.
- (line 42)
-* C-c M-s: Editing Commit Messages.
- (line 34)
-* C-w: Common Commands. (line 10)
-* C-x g: Status Buffer. (line 22)
-* C-x u: Editing Rebase Sequences.
- (line 94)
-* d: Diffing. (line 21)
-* D: Refreshing Diffs. (line 11)
-* d c: Diffing. (line 69)
-* d d: Diffing. (line 27)
-* D f: Refreshing Diffs. (line 46)
-* D F: Refreshing Diffs. (line 51)
-* D g: Refreshing Diffs. (line 17)
-* d p: Diffing. (line 61)
-* d r: Diffing. (line 31)
-* D r: Refreshing Diffs. (line 41)
-* d s: Diffing. (line 51)
-* D s: Refreshing Diffs. (line 22)
-* d t: Diffing. (line 74)
-* D t: Refreshing Diffs. (line 37)
-* d u: Diffing. (line 57)
-* d w: Diffing. (line 45)
-* D w: Refreshing Diffs. (line 29)
-* DEL: Log Buffer. (line 45)
-* DEL <1>: Commands Available in Diffs.
- (line 60)
-* DEL <2>: Blaming. (line 89)
-* DEL <3>: Editing Rebase Sequences.
- (line 28)
-* e: Ediffing. (line 9)
-* E: Ediffing. (line 21)
-* e <1>: Editing Rebase Sequences.
- (line 55)
-* E c: Ediffing. (line 65)
-* E i: Ediffing. (line 57)
-* E m: Ediffing. (line 35)
-* E r: Ediffing. (line 26)
-* E s: Ediffing. (line 48)
-* E u: Ediffing. (line 53)
-* E w: Ediffing. (line 61)
-* E z: Ediffing. (line 69)
-* f: Editing Rebase Sequences.
- (line 63)
-* f <1>: Fetching. (line 9)
-* F: Pulling. (line 9)
-* f a: Fetching. (line 50)
-* f C: Branch Commands. (line 30)
-* F C: Branch Commands. (line 31)
-* f e: Fetching. (line 36)
-* F e: Pulling. (line 30)
-* f m: Fetching. (line 54)
-* f o: Fetching. (line 40)
-* f p: Fetching. (line 15)
-* F p: Pulling. (line 14)
-* f r: Fetching. (line 45)
-* f u: Fetching. (line 23)
-* F u: Pulling. (line 22)
-* g: Automatic Refreshing of Magit Buffers.
- (line 24)
-* G: Automatic Refreshing of Magit Buffers.
- (line 33)
-* j: Commands Available in Diffs.
- (line 45)
-* k: Viewing Git Output. (line 24)
-* k <1>: Applying. (line 40)
-* k <2>: Editing Rebase Sequences.
- (line 68)
-* k <3>: Stashing. (line 96)
-* l: Logging. (line 29)
-* L: Refreshing Logs. (line 11)
-* L <1>: Log Buffer. (line 6)
-* L <2>: Log Margin. (line 57)
-* l <1>: Editing Rebase Sequences.
- (line 115)
-* l a: Logging. (line 60)
-* l b: Logging. (line 56)
-* L d: Log Margin. (line 74)
-* L g: Refreshing Logs. (line 17)
-* l h: Logging. (line 48)
-* l H: Reflog. (line 19)
-* l l: Logging. (line 35)
-* l L: Logging. (line 52)
-* L L: Log Margin. (line 66)
-* L l: Log Margin. (line 70)
-* l o: Logging. (line 41)
-* l O: Reflog. (line 15)
-* l r: Reflog. (line 11)
-* L s: Refreshing Logs. (line 22)
-* L t: Refreshing Logs. (line 37)
-* L w: Refreshing Logs. (line 29)
-* m: Merging. (line 9)
-* M: Remote Commands. (line 13)
-* m a: Merging. (line 45)
-* m a <1>: Merging. (line 95)
-* M a: Remote Commands. (line 50)
-* M C: Remote Commands. (line 33)
-* m e: Merging. (line 31)
-* m i: Merging. (line 58)
-* M k: Remote Commands. (line 65)
-* m m: Merging. (line 18)
-* m m <1>: Merging. (line 89)
-* m n: Merging. (line 38)
-* m p: Merging. (line 81)
-* M p: Remote Commands. (line 69)
-* M P: Remote Commands. (line 74)
-* M r: Remote Commands. (line 55)
-* m s: Merging. (line 72)
-* M u: Remote Commands. (line 60)
-* M-1: Section Visibility. (line 33)
-* M-2: Section Visibility. (line 34)
-* M-3: Section Visibility. (line 35)
-* M-4: Section Visibility. (line 36)
-* M-<tab>: Section Visibility. (line 17)
-* M-n: Section Movement. (line 26)
-* M-n <1>: Editing Commit Messages.
- (line 44)
-* M-n <2>: Editing Rebase Sequences.
- (line 47)
-* M-p: Section Movement. (line 20)
-* M-p <1>: Editing Commit Messages.
- (line 38)
-* M-p <2>: Editing Rebase Sequences.
- (line 43)
-* M-w: Blaming. (line 127)
-* M-w <1>: Common Commands. (line 28)
-* M-x magit-debug-git-executable: Git Executable. (line 45)
-* M-x magit-debug-git-executable <1>: Debugging Tools. (line 36)
-* M-x magit-describe-section-briefly: Section Types and Values.
- (line 13)
-* M-x magit-describe-section-briefly <1>: Matching Sections. (line 6)
-* M-x magit-emacs-Q-command: Debugging Tools. (line 16)
-* M-x magit-init: Creating Repository. (line 6)
-* M-x magit-reset-index: Staging and Unstaging.
- (line 87)
-* M-x magit-reverse-in-index: Staging and Unstaging.
- (line 62)
-* M-x magit-stage-file: Staging from File-Visiting Buffers.
- (line 10)
-* M-x magit-toggle-buffer-lock: Modes and Buffers. (line 17)
-* M-x magit-toggle-verbose-refresh: Debugging Tools. (line 30)
-* M-x magit-unstage-file: Staging from File-Visiting Buffers.
- (line 18)
-* M-x magit-version: Git Executable. (line 17)
-* M-x magit-version <1>: Debugging Tools. (line 10)
-* M-x magit-wip-commit: Wip Modes. (line 88)
-* M-x with-editor-debug: Debugging Tools. (line 44)
-* MM: Editing Rebase Sequences.
- (line 125)
-* Mt: Editing Rebase Sequences.
- (line 132)
-* n: Section Movement. (line 16)
-* n <1>: Blaming. (line 106)
-* N: Blaming. (line 110)
-* n <2>: Editing Rebase Sequences.
- (line 39)
-* n <3>: Minor Mode for Buffers Visiting Blobs.
- (line 16)
-* o: Submodule Transient. (line 6)
-* O: Subtree. (line 8)
-* o a: Submodule Transient. (line 20)
-* o d: Submodule Transient. (line 50)
-* O e: Subtree. (line 42)
-* O e p: Subtree. (line 54)
-* O e s: Subtree. (line 59)
-* o f: Submodule Transient. (line 58)
-* O i: Subtree. (line 13)
-* O i a: Subtree. (line 25)
-* O i c: Subtree. (line 30)
-* O i f: Subtree. (line 38)
-* O i m: Subtree. (line 34)
-* o l: Submodule Transient. (line 54)
-* o p: Submodule Transient. (line 34)
-* o r: Submodule Transient. (line 27)
-* o s: Submodule Transient. (line 44)
-* o u: Submodule Transient. (line 39)
-* p: Section Movement. (line 10)
-* p <1>: Blaming. (line 114)
-* P: Blaming. (line 118)
-* p <2>: Editing Rebase Sequences.
- (line 35)
-* P <1>: Pushing. (line 9)
-* p <3>: Minor Mode for Buffers Visiting Blobs.
- (line 12)
-* P C: Branch Commands. (line 32)
-* P e: Pushing. (line 31)
-* P m: Pushing. (line 50)
-* P o: Pushing. (line 36)
-* P p: Pushing. (line 15)
-* P r: Pushing. (line 41)
-* P t: Pushing. (line 58)
-* P T: Pushing. (line 66)
-* P u: Pushing. (line 23)
-* q: Quitting Windows. (line 6)
-* q <1>: Log Buffer. (line 14)
-* q <2>: Blaming. (line 122)
-* q <3>: Minor Mode for Buffers Visiting Blobs.
- (line 20)
-* r: Rebasing. (line 9)
-* r <1>: Editing Rebase Sequences.
- (line 51)
-* r a: Rebasing. (line 123)
-* r e: Rebasing. (line 44)
-* r e <1>: Rebasing. (line 118)
-* r f: Rebasing. (line 84)
-* r i: Rebasing. (line 80)
-* r k: Rebasing. (line 99)
-* r m: Rebasing. (line 89)
-* r p: Rebasing. (line 28)
-* r r: Rebasing. (line 106)
-* r s: Rebasing. (line 50)
-* r s <1>: Rebasing. (line 113)
-* r u: Rebasing. (line 36)
-* r w: Rebasing. (line 94)
-* RET: References Buffer. (line 181)
-* RET <1>: Visiting Files and Blobs from a Diff.
- (line 8)
-* RET <2>: Blaming. (line 75)
-* RET <3>: Editing Rebase Sequences.
- (line 16)
-* s: Staging and Unstaging.
- (line 28)
-* S: Staging and Unstaging.
- (line 36)
-* s <1>: Editing Rebase Sequences.
- (line 59)
-* S-<tab>: Section Visibility. (line 22)
-* SPC: Log Buffer. (line 35)
-* SPC <1>: Commands Available in Diffs.
- (line 56)
-* SPC <2>: Blaming. (line 79)
-* SPC <3>: Editing Rebase Sequences.
- (line 21)
-* t: Editing Rebase Sequences.
- (line 119)
-* t <1>: Tagging. (line 8)
-* T: Notes. (line 8)
-* T a: Notes. (line 52)
-* T c: Notes. (line 47)
-* t k: Tagging. (line 39)
-* T m: Notes. (line 38)
-* t p: Tagging. (line 46)
-* T p: Notes. (line 30)
-* t r: Tagging. (line 19)
-* T r: Notes. (line 22)
-* t t: Tagging. (line 14)
-* T T: Notes. (line 14)
-* TAB: Section Visibility. (line 9)
-* u: Staging and Unstaging.
- (line 43)
-* U: Staging and Unstaging.
- (line 52)
-* v: Applying. (line 44)
-* V: Reverting. (line 6)
-* V A: Reverting. (line 31)
-* V a: Reverting. (line 39)
-* V s: Reverting. (line 35)
-* V V: Reverting. (line 15)
-* V v: Reverting. (line 21)
-* W: Plain Patches. (line 6)
-* w: Maildir Patches. (line 8)
-* w a: Plain Patches. (line 21)
-* w a <1>: Maildir Patches. (line 25)
-* w a <2>: Maildir Patches. (line 43)
-* W c: Plain Patches. (line 12)
-* w m: Maildir Patches. (line 21)
-* W s: Plain Patches. (line 28)
-* w s: Maildir Patches. (line 38)
-* w w: Maildir Patches. (line 14)
-* w w <1>: Maildir Patches. (line 34)
-* x: Editing Rebase Sequences.
- (line 76)
-* x <1>: Resetting. (line 8)
-* X f: Resetting. (line 50)
-* X h: Resetting. (line 26)
-* X i: Resetting. (line 37)
-* X k: Resetting. (line 31)
-* X m: Resetting. (line 15)
-* X s: Resetting. (line 20)
-* X w: Resetting. (line 44)
-* X w <1>: Wip Modes. (line 66)
-* Y: Cherries. (line 17)
-* y: References Buffer. (line 6)
-* y <1>: Editing Rebase Sequences.
- (line 90)
-* y c: References Buffer. (line 26)
-* y o: References Buffer. (line 32)
-* y y: References Buffer. (line 21)
-* z: Stashing. (line 8)
-* z a: Stashing. (line 59)
-* z b: Stashing. (line 81)
-* z B: Stashing. (line 86)
-* z f: Stashing. (line 92)
-* z i: Stashing. (line 21)
-* z I: Stashing. (line 47)
-* z k: Stashing. (line 72)
-* z l: Stashing. (line 100)
-* z p: Stashing. (line 65)
-* z v: Stashing. (line 77)
-* z w: Stashing. (line 26)
-* z W: Stashing. (line 52)
-* z x: Stashing. (line 33)
-* z z: Stashing. (line 14)
-* z Z: Stashing. (line 40)
-
-\1f
-File: magit.info, Node: Command Index, Next: Function Index, Prev: Keystroke Index, Up: Top
-
-Appendix D Command Index
-************************
-
-\0\b[index\0\b]
-* Menu:
-
-* forward-line: Editing Rebase Sequences.
- (line 39)
-* git-commit-ack: Commit Pseudo Headers.
- (line 17)
-* git-commit-cc: Commit Pseudo Headers.
- (line 33)
-* git-commit-insert-pseudo-header: Commit Pseudo Headers.
- (line 13)
-* git-commit-next-message: Editing Commit Messages.
- (line 44)
-* git-commit-prev-message: Editing Commit Messages.
- (line 38)
-* git-commit-reported: Commit Pseudo Headers.
- (line 37)
-* git-commit-review: Commit Pseudo Headers.
- (line 21)
-* git-commit-save-message: Editing Commit Messages.
- (line 34)
-* git-commit-signoff: Commit Pseudo Headers.
- (line 25)
-* git-commit-suggested: Commit Pseudo Headers.
- (line 42)
-* git-commit-test: Commit Pseudo Headers.
- (line 29)
-* git-rebase-backward-line: Editing Rebase Sequences.
- (line 35)
-* git-rebase-break: Editing Rebase Sequences.
- (line 85)
-* git-rebase-edit: Editing Rebase Sequences.
- (line 55)
-* git-rebase-exec: Editing Rebase Sequences.
- (line 76)
-* git-rebase-fixup: Editing Rebase Sequences.
- (line 63)
-* git-rebase-insert: Editing Rebase Sequences.
- (line 90)
-* git-rebase-kill-line: Editing Rebase Sequences.
- (line 68)
-* git-rebase-label: Editing Rebase Sequences.
- (line 115)
-* git-rebase-merge: Editing Rebase Sequences.
- (line 125)
-* git-rebase-merge-toggle-editmsg: Editing Rebase Sequences.
- (line 132)
-* git-rebase-move-line-down: Editing Rebase Sequences.
- (line 47)
-* git-rebase-move-line-up: Editing Rebase Sequences.
- (line 43)
-* git-rebase-pick: Editing Rebase Sequences.
- (line 72)
-* git-rebase-reset: Editing Rebase Sequences.
- (line 119)
-* git-rebase-reword: Editing Rebase Sequences.
- (line 51)
-* git-rebase-show-commit: Editing Rebase Sequences.
- (line 16)
-* git-rebase-show-or-scroll-down: Editing Rebase Sequences.
- (line 28)
-* git-rebase-show-or-scroll-up: Editing Rebase Sequences.
- (line 21)
-* git-rebase-squash: Editing Rebase Sequences.
- (line 59)
-* git-rebase-undo: Editing Rebase Sequences.
- (line 94)
-* ido-enter-magit-status: Status Buffer. (line 72)
-* magit-am: Maildir Patches. (line 8)
-* magit-am-abort: Maildir Patches. (line 43)
-* magit-am-apply-maildir: Maildir Patches. (line 21)
-* magit-am-apply-patches: Maildir Patches. (line 14)
-* magit-am-continue: Maildir Patches. (line 34)
-* magit-am-skip: Maildir Patches. (line 38)
-* magit-apply: Applying. (line 33)
-* magit-bisect: Bisecting. (line 8)
-* magit-bisect-bad: Bisecting. (line 31)
-* magit-bisect-good: Bisecting. (line 36)
-* magit-bisect-reset: Bisecting. (line 47)
-* magit-bisect-run: Bisecting. (line 24)
-* magit-bisect-skip: Bisecting. (line 41)
-* magit-bisect-start: Bisecting. (line 16)
-* magit-blame: Blaming. (line 18)
-* magit-blame <1>: Blaming. (line 102)
-* magit-blame <2>: Commands for Buffers Visiting Files.
- (line 93)
-* magit-blame-addition: Blaming. (line 29)
-* magit-blame-addition <1>: Blaming. (line 30)
-* magit-blame-copy-hash: Blaming. (line 127)
-* magit-blame-cycle-style: Blaming. (line 135)
-* magit-blame-echo: Blaming. (line 63)
-* magit-blame-echo <1>: Blaming. (line 64)
-* magit-blame-next-chunk: Blaming. (line 106)
-* magit-blame-next-chunk-same-commit: Blaming. (line 110)
-* magit-blame-previous-chunk: Blaming. (line 114)
-* magit-blame-previous-chunk-same-commit: Blaming. (line 118)
-* magit-blame-quit: Blaming. (line 122)
-* magit-blame-removal: Blaming. (line 45)
-* magit-blame-removal <1>: Blaming. (line 46)
-* magit-blame-reverse: Blaming. (line 54)
-* magit-blame-reverse <1>: Blaming. (line 55)
-* magit-blob-next: Minor Mode for Buffers Visiting Blobs.
- (line 16)
-* magit-blob-previous: Commands for Buffers Visiting Files.
- (line 116)
-* magit-blob-previous <1>: Minor Mode for Buffers Visiting Blobs.
- (line 12)
-* magit-branch: Branch Commands. (line 12)
-* magit-branch-and-checkout: Branch Commands. (line 67)
-* magit-branch-checkout: Branch Commands. (line 74)
-* magit-branch-configure: Branch Commands. (line 29)
-* magit-branch-configure <1>: Branch Commands. (line 30)
-* magit-branch-configure <2>: Branch Commands. (line 31)
-* magit-branch-configure <3>: Branch Commands. (line 32)
-* magit-branch-create: Branch Commands. (line 57)
-* magit-branch-delete: Branch Commands. (line 147)
-* magit-branch-or-checkout: Branch Commands. (line 257)
-* magit-branch-orphan: Branch Commands. (line 252)
-* magit-branch-rename: Branch Commands. (line 153)
-* magit-branch-reset: Branch Commands. (line 131)
-* magit-branch-shelve: Auxiliary Branch Commands.
- (line 9)
-* magit-branch-spinoff: Branch Commands. (line 97)
-* magit-branch-spinout: Branch Commands. (line 125)
-* magit-branch-unshelve: Auxiliary Branch Commands.
- (line 20)
-* magit-checkout: Branch Commands. (line 49)
-* magit-cherry: Cherries. (line 17)
-* magit-cherry-apply: Cherry Picking. (line 24)
-* magit-cherry-copy: Cherry Picking. (line 17)
-* magit-cherry-donate: Cherry Picking. (line 54)
-* magit-cherry-harvest: Cherry Picking. (line 42)
-* magit-cherry-pick: Cherry Picking. (line 8)
-* magit-cherry-spinoff: Cherry Picking. (line 76)
-* magit-cherry-spinout: Cherry Picking. (line 65)
-* magit-clone: Cloning Repository. (line 20)
-* magit-clone-bare: Cloning Repository. (line 41)
-* magit-clone-mirror: Cloning Repository. (line 46)
-* magit-clone-regular: Cloning Repository. (line 29)
-* magit-clone-shallow: Cloning Repository. (line 34)
-* magit-clone-shallow-exclude: Cloning Repository. (line 61)
-* magit-clone-shallow-since: Cloning Repository. (line 54)
-* magit-commit: Initiating a Commit. (line 8)
-* magit-commit <1>: Commands for Buffers Visiting Files.
- (line 38)
-* magit-commit-amend: Initiating a Commit. (line 19)
-* magit-commit-augment: Initiating a Commit. (line 67)
-* magit-commit-create: Initiating a Commit. (line 14)
-* magit-commit-extend: Initiating a Commit. (line 23)
-* magit-commit-fixup: Initiating a Commit. (line 43)
-* magit-commit-instant-fixup: Initiating a Commit. (line 51)
-* magit-commit-instant-squash: Initiating a Commit. (line 63)
-* magit-commit-reword: Initiating a Commit. (line 33)
-* magit-commit-squash: Initiating a Commit. (line 55)
-* magit-copy-buffer-revision: Common Commands. (line 28)
-* magit-copy-section-value: Common Commands. (line 10)
-* magit-cycle-margin-style: Log Margin. (line 70)
-* magit-debug-git-executable: Git Executable. (line 45)
-* magit-debug-git-executable <1>: Debugging Tools. (line 36)
-* magit-describe-section-briefly: Section Types and Values.
- (line 13)
-* magit-describe-section-briefly <1>: Matching Sections. (line 6)
-* magit-diff: Diffing. (line 21)
-* magit-diff <1>: Commands for Buffers Visiting Files.
- (line 45)
-* magit-diff-buffer-file: Commands for Buffers Visiting Files.
- (line 56)
-* magit-diff-default-context: Refreshing Diffs. (line 73)
-* magit-diff-dwim: Diffing. (line 27)
-* magit-diff-edit-hunk-commit: Commands Available in Diffs.
- (line 25)
-* magit-diff-flip-revs: Refreshing Diffs. (line 46)
-* magit-diff-less-context: Refreshing Diffs. (line 65)
-* magit-diff-more-context: Refreshing Diffs. (line 69)
-* magit-diff-paths: Diffing. (line 61)
-* magit-diff-range: Diffing. (line 31)
-* magit-diff-refresh: Refreshing Diffs. (line 11)
-* magit-diff-refresh <1>: Refreshing Diffs. (line 17)
-* magit-diff-save-default-arguments: Refreshing Diffs. (line 29)
-* magit-diff-set-default-arguments: Refreshing Diffs. (line 22)
-* magit-diff-show-or-scroll-down: Log Buffer. (line 45)
-* magit-diff-show-or-scroll-down <1>: Blaming. (line 89)
-* magit-diff-show-or-scroll-up: Log Buffer. (line 35)
-* magit-diff-show-or-scroll-up <1>: Blaming. (line 79)
-* magit-diff-staged: Diffing. (line 51)
-* magit-diff-switch-range-type: Refreshing Diffs. (line 41)
-* magit-diff-toggle-file-filter: Refreshing Diffs. (line 51)
-* magit-diff-toggle-refine-hunk: Refreshing Diffs. (line 37)
-* magit-diff-trace-definition: Commands Available in Diffs.
- (line 14)
-* magit-diff-unstaged: Diffing. (line 57)
-* magit-diff-visit-file: Visiting Files and Blobs from a Diff.
- (line 8)
-* magit-diff-visit-file-other-frame: Visiting Files and Blobs from a Diff.
- (line 74)
-* magit-diff-visit-file-other-window: Visiting Files and Blobs from a Diff.
- (line 73)
-* magit-diff-visit-file-worktree: Visiting Files and Blobs from a Diff.
- (line 51)
-* magit-diff-visit-worktree-file-other-frame: Visiting Files and Blobs from a Diff.
- (line 76)
-* magit-diff-visit-worktree-file-other-window: Visiting Files and Blobs from a Diff.
- (line 75)
-* magit-diff-while-committing: Refreshing Diffs. (line 81)
-* magit-diff-while-committing <1>: Editing Commit Messages.
- (line 58)
-* magit-diff-working-tree: Diffing. (line 45)
-* magit-discard: Applying. (line 40)
-* magit-dispatch: Transient Commands. (line 18)
-* magit-ediff: Ediffing. (line 21)
-* magit-ediff-compare: Ediffing. (line 26)
-* magit-ediff-dwim: Ediffing. (line 9)
-* magit-ediff-resolve: Ediffing. (line 35)
-* magit-ediff-show-commit: Ediffing. (line 65)
-* magit-ediff-show-staged: Ediffing. (line 57)
-* magit-ediff-show-stash: Ediffing. (line 69)
-* magit-ediff-show-unstaged: Ediffing. (line 53)
-* magit-ediff-show-working-tree: Ediffing. (line 61)
-* magit-ediff-stage: Ediffing. (line 48)
-* magit-edit-line-commit: Commands for Buffers Visiting Files.
- (line 106)
-* magit-emacs-Q-command: Debugging Tools. (line 16)
-* magit-fetch: Fetching. (line 9)
-* magit-fetch-all: Fetching. (line 50)
-* magit-fetch-branch: Fetching. (line 40)
-* magit-fetch-from-pushremote: Fetching. (line 15)
-* magit-fetch-from-upstream: Fetching. (line 23)
-* magit-fetch-modules: Submodule Transient. (line 58)
-* magit-fetch-other: Fetching. (line 36)
-* magit-fetch-refspec: Fetching. (line 45)
-* magit-file-checkout: Resetting. (line 50)
-* magit-file-checkout <1>: Commands for Buffers Visiting Files.
- (line 135)
-* magit-file-delete: Commands for Buffers Visiting Files.
- (line 127)
-* magit-file-dispatch: Commands for Buffers Visiting Files.
- (line 21)
-* magit-file-rename: Commands for Buffers Visiting Files.
- (line 123)
-* magit-file-untrack: Commands for Buffers Visiting Files.
- (line 131)
-* magit-find-file: General-Purpose Visit Commands.
- (line 9)
-* magit-find-file-other-frame: General-Purpose Visit Commands.
- (line 21)
-* magit-find-file-other-window: General-Purpose Visit Commands.
- (line 15)
-* magit-git-command: Running Git Manually.
- (line 25)
-* magit-git-command-topdir: Running Git Manually.
- (line 17)
-* magit-go-backward: Log Buffer. (line 21)
-* magit-go-backward <1>: Refreshing Diffs. (line 91)
-* magit-go-forward: Log Buffer. (line 25)
-* magit-go-forward <1>: Refreshing Diffs. (line 95)
-* magit-init: Creating Repository. (line 6)
-* magit-jump-to-diffstat-or-diff: Commands Available in Diffs.
- (line 45)
-* magit-kill-this-buffer: Minor Mode for Buffers Visiting Blobs.
- (line 20)
-* magit-list-repositories: Repository List. (line 6)
-* magit-list-submodules: Listing Submodules. (line 13)
-* magit-list-submodules <1>: Submodule Transient. (line 54)
-* magit-log: Logging. (line 29)
-* magit-log <1>: Commands for Buffers Visiting Files.
- (line 66)
-* magit-log-all: Logging. (line 60)
-* magit-log-all-branches: Logging. (line 56)
-* magit-log-branches: Logging. (line 52)
-* magit-log-buffer-file: Commands for Buffers Visiting Files.
- (line 77)
-* magit-log-bury-buffer: Log Buffer. (line 14)
-* magit-log-current: Logging. (line 35)
-* magit-log-double-commit-limit: Log Buffer. (line 61)
-* magit-log-half-commit-limit: Log Buffer. (line 65)
-* magit-log-head: Logging. (line 48)
-* magit-log-move-to-parent: Log Buffer. (line 29)
-* magit-log-other: Logging. (line 41)
-* magit-log-refresh: Refreshing Logs. (line 11)
-* magit-log-refresh <1>: Refreshing Logs. (line 17)
-* magit-log-refresh <2>: Log Buffer. (line 6)
-* magit-log-save-default-arguments: Refreshing Logs. (line 29)
-* magit-log-select-pick: Select from Log. (line 20)
-* magit-log-select-quit: Select from Log. (line 26)
-* magit-log-set-default-arguments: Refreshing Logs. (line 22)
-* magit-log-toggle-commit-limit: Log Buffer. (line 55)
-* magit-log-trace-definition: Commands for Buffers Visiting Files.
- (line 84)
-* magit-margin-settings: Log Margin. (line 57)
-* magit-merge: Merging. (line 9)
-* magit-merge <1>: Merging. (line 89)
-* magit-merge-abort: Merging. (line 95)
-* magit-merge-absorb: Merging. (line 45)
-* magit-merge-editmsg: Merging. (line 31)
-* magit-merge-into: Merging. (line 58)
-* magit-merge-nocommit: Merging. (line 38)
-* magit-merge-plain: Merging. (line 18)
-* magit-merge-preview: Merging. (line 81)
-* magit-merge-squash: Merging. (line 72)
-* magit-mode-bury-buffer: Quitting Windows. (line 6)
-* magit-notes: Notes. (line 8)
-* magit-notes-edit: Notes. (line 14)
-* magit-notes-merge: Notes. (line 38)
-* magit-notes-merge-abort: Notes. (line 52)
-* magit-notes-merge-commit: Notes. (line 47)
-* magit-notes-prune: Notes. (line 30)
-* magit-notes-remove: Notes. (line 22)
-* magit-patch: Plain Patches. (line 6)
-* magit-patch-apply: Plain Patches. (line 21)
-* magit-patch-apply <1>: Maildir Patches. (line 25)
-* magit-patch-create: Plain Patches. (line 12)
-* magit-patch-save: Plain Patches. (line 28)
-* magit-pop-revision-stack: Using the Revision Stack.
- (line 6)
-* magit-process: Viewing Git Output. (line 16)
-* magit-process-kill: Viewing Git Output. (line 24)
-* magit-pull: Pulling. (line 9)
-* magit-pull-branch: Pulling. (line 30)
-* magit-pull-from-pushremote: Pulling. (line 14)
-* magit-pull-from-upstream: Pulling. (line 22)
-* magit-push: Pushing. (line 9)
-* magit-push-current: Pushing. (line 31)
-* magit-push-current-to-pushremote: Pushing. (line 15)
-* magit-push-current-to-upstream: Pushing. (line 23)
-* magit-push-implicitly args: Pushing. (line 74)
-* magit-push-matching: Pushing. (line 50)
-* magit-push-other: Pushing. (line 36)
-* magit-push-refspecs: Pushing. (line 41)
-* magit-push-tag: Pushing. (line 66)
-* magit-push-tags: Pushing. (line 58)
-* magit-push-to-remote remote args: Pushing. (line 92)
-* magit-rebase: Rebasing. (line 9)
-* magit-rebase-abort: Rebasing. (line 123)
-* magit-rebase-autosquash: Rebasing. (line 84)
-* magit-rebase-branch: Rebasing. (line 44)
-* magit-rebase-continue: Rebasing. (line 106)
-* magit-rebase-edit: Rebasing. (line 118)
-* magit-rebase-edit-commit: Rebasing. (line 89)
-* magit-rebase-interactive: Rebasing. (line 80)
-* magit-rebase-onto-pushremote: Rebasing. (line 28)
-* magit-rebase-onto-upstream: Rebasing. (line 36)
-* magit-rebase-remove-commit: Rebasing. (line 99)
-* magit-rebase-reword-commit: Rebasing. (line 94)
-* magit-rebase-skip: Rebasing. (line 113)
-* magit-rebase-subset: Rebasing. (line 50)
-* magit-reflog-current: Reflog. (line 11)
-* magit-reflog-head: Reflog. (line 19)
-* magit-reflog-other: Reflog. (line 15)
-* magit-refresh: Automatic Refreshing of Magit Buffers.
- (line 24)
-* magit-refresh-all: Automatic Refreshing of Magit Buffers.
- (line 33)
-* magit-remote: Remote Commands. (line 13)
-* magit-remote-add: Remote Commands. (line 50)
-* magit-remote-configure: Remote Commands. (line 33)
-* magit-remote-prune: Remote Commands. (line 69)
-* magit-remote-prune-refspecs: Remote Commands. (line 74)
-* magit-remote-remove: Remote Commands. (line 65)
-* magit-remote-rename: Remote Commands. (line 55)
-* magit-remote-set-url: Remote Commands. (line 60)
-* magit-reset-hard: Resetting. (line 26)
-* magit-reset-index: Staging and Unstaging.
- (line 87)
-* magit-reset-index <1>: Resetting. (line 37)
-* magit-reset-keep: Resetting. (line 31)
-* magit-reset-mixed: Resetting. (line 15)
-* magit-reset-quickly: Resetting. (line 8)
-* magit-reset-soft: Resetting. (line 20)
-* magit-reset-worktree: Resetting. (line 44)
-* magit-reset-worktree <1>: Wip Modes. (line 66)
-* magit-reverse: Applying. (line 44)
-* magit-reverse-in-index: Staging and Unstaging.
- (line 62)
-* magit-revert: Reverting. (line 6)
-* magit-revert-and-commit: Reverting. (line 15)
-* magit-revert-no-commit: Reverting. (line 21)
-* magit-run: Running Git Manually.
- (line 12)
-* magit-run-git-gui: Running Git Manually.
- (line 66)
-* magit-run-gitk: Running Git Manually.
- (line 54)
-* magit-run-gitk-all: Running Git Manually.
- (line 58)
-* magit-run-gitk-branches: Running Git Manually.
- (line 62)
-* magit-section-backward: Section Movement. (line 10)
-* magit-section-backward-siblings: Section Movement. (line 20)
-* magit-section-cycle: Section Visibility. (line 13)
-* magit-section-cycle-diffs: Section Visibility. (line 17)
-* magit-section-cycle-global: Section Visibility. (line 22)
-* magit-section-forward: Section Movement. (line 16)
-* magit-section-forward-siblings: Section Movement. (line 26)
-* magit-section-hide: Section Visibility. (line 49)
-* magit-section-hide-children: Section Visibility. (line 64)
-* magit-section-show: Section Visibility. (line 45)
-* magit-section-show-children: Section Visibility. (line 58)
-* magit-section-show-headings: Section Visibility. (line 53)
-* magit-section-show-level-1: Section Visibility. (line 26)
-* magit-section-show-level-1-all: Section Visibility. (line 33)
-* magit-section-show-level-2: Section Visibility. (line 27)
-* magit-section-show-level-2-all: Section Visibility. (line 34)
-* magit-section-show-level-3: Section Visibility. (line 28)
-* magit-section-show-level-3-all: Section Visibility. (line 35)
-* magit-section-show-level-4: Section Visibility. (line 29)
-* magit-section-show-level-4-all: Section Visibility. (line 36)
-* magit-section-toggle: Section Visibility. (line 9)
-* magit-section-toggle-children: Section Visibility. (line 68)
-* magit-section-up: Section Movement. (line 31)
-* magit-sequence-abort: Cherry Picking. (line 98)
-* magit-sequence-abort <1>: Reverting. (line 39)
-* magit-sequence-continue: Cherry Picking. (line 90)
-* magit-sequence-continue <1>: Reverting. (line 31)
-* magit-sequence-skip: Cherry Picking. (line 94)
-* magit-sequence-skip <1>: Reverting. (line 35)
-* magit-shell-command: Running Git Manually.
- (line 40)
-* magit-shell-command-topdir: Running Git Manually.
- (line 35)
-* magit-show-commit: Diffing. (line 69)
-* magit-show-commit <1>: Blaming. (line 75)
-* magit-show-refs: References Buffer. (line 6)
-* magit-show-refs-current: References Buffer. (line 26)
-* magit-show-refs-head: References Buffer. (line 21)
-* magit-show-refs-other: References Buffer. (line 32)
-* magit-snapshot-both: Stashing. (line 40)
-* magit-snapshot-index: Stashing. (line 47)
-* magit-snapshot-worktree: Stashing. (line 52)
-* magit-stage: Staging and Unstaging.
- (line 28)
-* magit-stage-file: Staging from File-Visiting Buffers.
- (line 10)
-* magit-stage-file <1>: Commands for Buffers Visiting Files.
- (line 29)
-* magit-stage-modified: Staging and Unstaging.
- (line 36)
-* magit-stash: Stashing. (line 8)
-* magit-stash-apply: Stashing. (line 59)
-* magit-stash-both: Stashing. (line 14)
-* magit-stash-branch: Stashing. (line 81)
-* magit-stash-branch-here: Stashing. (line 86)
-* magit-stash-clear: Stashing. (line 96)
-* magit-stash-drop: Stashing. (line 72)
-* magit-stash-format-patch: Stashing. (line 92)
-* magit-stash-index: Stashing. (line 21)
-* magit-stash-keep-index: Stashing. (line 33)
-* magit-stash-list: Stashing. (line 100)
-* magit-stash-pop: Stashing. (line 65)
-* magit-stash-show: Diffing. (line 74)
-* magit-stash-show <1>: Stashing. (line 77)
-* magit-stash-worktree: Stashing. (line 26)
-* magit-status: Status Buffer. (line 22)
-* magit-submodule: Submodule Transient. (line 6)
-* magit-submodule-add: Submodule Transient. (line 20)
-* magit-submodule-fetch: Fetching. (line 54)
-* magit-submodule-populate: Submodule Transient. (line 34)
-* magit-submodule-register: Submodule Transient. (line 27)
-* magit-submodule-synchronize: Submodule Transient. (line 44)
-* magit-submodule-unpopulate: Submodule Transient. (line 50)
-* magit-submodule-update: Submodule Transient. (line 39)
-* magit-subtree: Subtree. (line 8)
-* magit-subtree-add: Subtree. (line 25)
-* magit-subtree-add-commit: Subtree. (line 30)
-* magit-subtree-export: Subtree. (line 42)
-* magit-subtree-import: Subtree. (line 13)
-* magit-subtree-merge: Subtree. (line 34)
-* magit-subtree-pull: Subtree. (line 38)
-* magit-subtree-push: Subtree. (line 54)
-* magit-subtree-split: Subtree. (line 59)
-* magit-tag: Tagging. (line 8)
-* magit-tag-create: Tagging. (line 14)
-* magit-tag-delete: Tagging. (line 39)
-* magit-tag-prune: Tagging. (line 46)
-* magit-tag-release: Tagging. (line 19)
-* magit-toggle-buffer-lock: Modes and Buffers. (line 17)
-* magit-toggle-margin: Refreshing Logs. (line 37)
-* magit-toggle-margin <1>: Log Margin. (line 66)
-* magit-toggle-margin-details: Log Margin. (line 74)
-* magit-toggle-verbose-refresh: Debugging Tools. (line 30)
-* magit-unstage: Staging and Unstaging.
- (line 43)
-* magit-unstage-all: Staging and Unstaging.
- (line 52)
-* magit-unstage-file: Staging from File-Visiting Buffers.
- (line 18)
-* magit-unstage-file <1>: Commands for Buffers Visiting Files.
- (line 33)
-* magit-version: Git Executable. (line 17)
-* magit-version <1>: Debugging Tools. (line 10)
-* magit-visit-ref: References Buffer. (line 181)
-* magit-wip-commit: Wip Modes. (line 88)
-* magit-wip-log: Wip Modes. (line 48)
-* magit-wip-log-current: Wip Modes. (line 57)
-* magit-worktree: Worktree. (line 8)
-* magit-worktree-branch: Worktree. (line 17)
-* magit-worktree-checkout: Worktree. (line 13)
-* magit-worktree-delete: Worktree. (line 25)
-* magit-worktree-move: Worktree. (line 21)
-* magit-worktree-status: Worktree. (line 30)
-* scroll-down: Commands Available in Diffs.
- (line 60)
-* scroll-up: Commands Available in Diffs.
- (line 56)
-* with-editor-cancel: Editing Commit Messages.
- (line 22)
-* with-editor-cancel <1>: Editing Rebase Sequences.
- (line 11)
-* with-editor-debug: Debugging Tools. (line 44)
-* with-editor-finish: Editing Commit Messages.
- (line 17)
-* with-editor-finish <1>: Editing Rebase Sequences.
- (line 6)
-
-\1f
-File: magit.info, Node: Function Index, Next: Variable Index, Prev: Command Index, Up: Top
-
-Appendix E Function Index
-*************************
-
-\0\b[index\0\b]
-* Menu:
-
-* bug-reference-mode: Commit Mode and Hooks.
- (line 56)
-* git-commit-check-style-conventions: Commit Message Conventions.
- (line 40)
-* git-commit-propertize-diff: Commit Mode and Hooks.
- (line 47)
-* git-commit-save-message: Commit Mode and Hooks.
- (line 28)
-* git-commit-setup-changelog-support: Commit Mode and Hooks.
- (line 32)
-* git-commit-turn-on-auto-fill: Commit Mode and Hooks.
- (line 37)
-* git-commit-turn-on-flyspell: Commit Mode and Hooks.
- (line 42)
-* ido-enter-magit-status: Status Buffer. (line 72)
-* magit-add-section-hook: Section Hooks. (line 20)
-* magit-after-save-refresh-status: Automatic Refreshing of Magit Buffers.
- (line 58)
-* magit-branch-or-checkout: Branch Commands. (line 257)
-* magit-branch-orphan: Branch Commands. (line 252)
-* magit-branch-shelve: Auxiliary Branch Commands.
- (line 9)
-* magit-branch-unshelve: Auxiliary Branch Commands.
- (line 20)
-* magit-builtin-completing-read: Support for Completion Frameworks.
- (line 42)
-* magit-call-git: Calling Git for Effect.
- (line 28)
-* magit-call-process: Calling Git for Effect.
- (line 32)
-* magit-cancel-section: Creating Sections. (line 71)
-* magit-completing-read: Support for Completion Frameworks.
- (line 60)
-* magit-current-section: Section Selection. (line 6)
-* magit-define-section-jumper: Creating Sections. (line 77)
-* magit-diff-scope: Matching Sections. (line 118)
-* magit-diff-type: Matching Sections. (line 95)
-* magit-diff-visit-file-other-frame: Visiting Files and Blobs from a Diff.
- (line 74)
-* magit-diff-visit-file-other-window: Visiting Files and Blobs from a Diff.
- (line 73)
-* magit-diff-visit-worktree-file-other-frame: Visiting Files and Blobs from a Diff.
- (line 76)
-* magit-diff-visit-worktree-file-other-window: Visiting Files and Blobs from a Diff.
- (line 75)
-* magit-disable-section-inserter: Per-Repository Configuration.
- (line 31)
-* magit-display-buffer: Switching Buffers. (line 6)
-* magit-display-buffer-fullcolumn-most-v1: Switching Buffers. (line 75)
-* magit-display-buffer-fullframe-status-topleft-v1: Switching Buffers.
- (line 65)
-* magit-display-buffer-fullframe-status-v1: Switching Buffers.
- (line 59)
-* magit-display-buffer-same-window-except-diff-v1: Switching Buffers.
- (line 53)
-* magit-display-buffer-traditional: Switching Buffers. (line 45)
-* magit-file-checkout: Commands for Buffers Visiting Files.
- (line 135)
-* magit-file-delete: Commands for Buffers Visiting Files.
- (line 127)
-* magit-file-rename: Commands for Buffers Visiting Files.
- (line 123)
-* magit-file-untrack: Commands for Buffers Visiting Files.
- (line 131)
-* magit-find-file: General-Purpose Visit Commands.
- (line 9)
-* magit-find-file-other-frame: General-Purpose Visit Commands.
- (line 21)
-* magit-find-file-other-window: General-Purpose Visit Commands.
- (line 15)
-* magit-generate-buffer-name-default-function: Naming Buffers.
- (line 17)
-* magit-get-section: Matching Sections. (line 16)
-* magit-git: Calling Git for Effect.
- (line 65)
-* magit-git-exit-code: Getting a Value from Git.
- (line 10)
-* magit-git-failure: Getting a Value from Git.
- (line 19)
-* magit-git-false: Getting a Value from Git.
- (line 29)
-* magit-git-insert: Getting a Value from Git.
- (line 34)
-* magit-git-items: Getting a Value from Git.
- (line 49)
-* magit-git-lines: Getting a Value from Git.
- (line 44)
-* magit-git-str: Getting a Value from Git.
- (line 72)
-* magit-git-string: Getting a Value from Git.
- (line 38)
-* magit-git-success: Getting a Value from Git.
- (line 14)
-* magit-git-true: Getting a Value from Git.
- (line 24)
-* magit-git-wash: Calling Git for Effect.
- (line 70)
-* magit-hunk-set-window-start: Section Movement. (line 51)
-* magit-ido-completing-read: Support for Completion Frameworks.
- (line 48)
-* magit-insert-am-sequence: Status Sections. (line 28)
-* magit-insert-assumed-unchanged-files: Status Sections. (line 117)
-* magit-insert-bisect-log: Status Sections. (line 46)
-* magit-insert-bisect-output: Status Sections. (line 38)
-* magit-insert-bisect-rest: Status Sections. (line 42)
-* magit-insert-diff-filter-header: Status Header Sections.
- (line 38)
-* magit-insert-error-header: Status Header Sections.
- (line 28)
-* magit-insert-head-branch-header: Status Header Sections.
- (line 42)
-* magit-insert-heading: Creating Sections. (line 42)
-* magit-insert-ignored-files: Status Sections. (line 100)
-* magit-insert-local-branches: References Sections. (line 17)
-* magit-insert-merge-log: Status Sections. (line 18)
-* magit-insert-modules: Status Module Sections.
- (line 12)
-* magit-insert-modules-overview: Status Module Sections.
- (line 33)
-* magit-insert-modules-unpulled-from-pushremote: Status Module Sections.
- (line 50)
-* magit-insert-modules-unpulled-from-upstream: Status Module Sections.
- (line 44)
-* magit-insert-modules-unpushed-to-pushremote: Status Module Sections.
- (line 62)
-* magit-insert-modules-unpushed-to-upstream: Status Module Sections.
- (line 56)
-* magit-insert-push-branch-header: Status Header Sections.
- (line 51)
-* magit-insert-rebase-sequence: Status Sections. (line 23)
-* magit-insert-recent-commits: Status Sections. (line 131)
-* magit-insert-remote-branches: References Sections. (line 21)
-* magit-insert-remote-header: Status Header Sections.
- (line 67)
-* magit-insert-repo-header: Status Header Sections.
- (line 63)
-* magit-insert-section: Creating Sections. (line 6)
-* magit-insert-sequencer-sequence: Status Sections. (line 33)
-* magit-insert-skip-worktree-files: Status Sections. (line 110)
-* magit-insert-staged-changes: Status Sections. (line 63)
-* magit-insert-stashes: Status Sections. (line 67)
-* magit-insert-status-headers: Status Header Sections.
- (line 12)
-* magit-insert-tags: References Sections. (line 25)
-* magit-insert-tags-header: Status Header Sections.
- (line 56)
-* magit-insert-tracked-files: Status Sections. (line 96)
-* magit-insert-unpulled-cherries: Status Sections. (line 142)
-* magit-insert-unpulled-from-pushremote: Status Sections. (line 79)
-* magit-insert-unpulled-from-upstream: Status Sections. (line 74)
-* magit-insert-unpulled-or-recent-commits: Status Sections. (line 124)
-* magit-insert-unpushed-cherries: Status Sections. (line 149)
-* magit-insert-unpushed-to-pushremote: Status Sections. (line 89)
-* magit-insert-unpushed-to-upstream: Status Sections. (line 84)
-* magit-insert-unstaged-changes: Status Sections. (line 59)
-* magit-insert-untracked-files: Status Sections. (line 50)
-* magit-insert-upstream-branch-header: Status Header Sections.
- (line 46)
-* magit-insert-user-header: Status Header Sections.
- (line 75)
-* magit-list-repositories: Repository List. (line 6)
-* magit-list-submodules: Listing Submodules. (line 13)
-* magit-log-maybe-show-more-commits: Section Movement. (line 66)
-* magit-log-maybe-update-blob-buffer: Section Movement. (line 82)
-* magit-log-maybe-update-revision-buffer: Section Movement. (line 74)
-* magit-maybe-set-dedicated: Switching Buffers. (line 100)
-* magit-mode-display-buffer: Refreshing Buffers. (line 33)
-* magit-mode-quit-window: Quitting Windows. (line 34)
-* magit-mode-setup: Refreshing Buffers. (line 17)
-* magit-push-implicitly: Pushing. (line 74)
-* magit-push-to-remote: Pushing. (line 92)
-* magit-region-sections: Section Selection. (line 10)
-* magit-region-values: Section Selection. (line 37)
-* magit-repolist-column-branch: Repository List. (line 44)
-* magit-repolist-column-branches: Repository List. (line 53)
-* magit-repolist-column-flag: Repository List. (line 61)
-* magit-repolist-column-ident: Repository List. (line 30)
-* magit-repolist-column-path: Repository List. (line 35)
-* magit-repolist-column-stashes: Repository List. (line 57)
-* magit-repolist-column-unpulled-from-pushremote: Repository List.
- (line 81)
-* magit-repolist-column-unpulled-from-upstream: Repository List.
- (line 76)
-* magit-repolist-column-unpushed-to-pushremote: Repository List.
- (line 91)
-* magit-repolist-column-unpushed-to-upstream: Repository List.
- (line 86)
-* magit-repolist-column-upstream: Repository List. (line 48)
-* magit-repolist-column-version: Repository List. (line 39)
-* magit-restore-window-configuration: Quitting Windows. (line 23)
-* magit-run-git: Calling Git for Effect.
- (line 36)
-* magit-run-git-async: Calling Git for Effect.
- (line 80)
-* magit-run-git-with-editor: Calling Git for Effect.
- (line 93)
-* magit-run-git-with-input: Calling Git for Effect.
- (line 40)
-* magit-run-git-with-logfile: Calling Git for Effect.
- (line 56)
-* magit-save-window-configuration: Switching Buffers. (line 89)
-* magit-section-case: Matching Sections. (line 71)
-* magit-section-hide: Section Visibility. (line 49)
-* magit-section-hide-children: Section Visibility. (line 64)
-* magit-section-ident: Matching Sections. (line 11)
-* magit-section-match: Matching Sections. (line 21)
-* magit-section-set-window-start: Section Movement. (line 59)
-* magit-section-show: Section Visibility. (line 45)
-* magit-section-show-children: Section Visibility. (line 58)
-* magit-section-show-headings: Section Visibility. (line 53)
-* magit-section-toggle-children: Section Visibility. (line 68)
-* magit-section-value-if: Matching Sections. (line 61)
-* magit-start-git: Calling Git for Effect.
- (line 105)
-* magit-start-process: Calling Git for Effect.
- (line 124)
-* magit-stashes-maybe-update-stash-buffer: Section Movement. (line 106)
-* magit-status-maybe-update-blob-buffer: Section Movement. (line 100)
-* magit-status-maybe-update-revision-buffer: Section Movement.
- (line 88)
-* magit-status-maybe-update-stash-buffer: Section Movement. (line 94)
-* magit-wip-log: Wip Modes. (line 48)
-* magit-wip-log-current: Wip Modes. (line 57)
-* with-editor-usage-message: Commit Mode and Hooks.
- (line 60)
-
-\1f
-File: magit.info, Node: Variable Index, Prev: Function Index, Up: Top
-
-Appendix F Variable Index
-*************************
-
-\0\b[index\0\b]
-* Menu:
-
-* auto-revert-buffer-list-filter: Automatic Reverting of File-Visiting Buffers.
- (line 81)
-* auto-revert-interval: Automatic Reverting of File-Visiting Buffers.
- (line 76)
-* auto-revert-mode: Automatic Reverting of File-Visiting Buffers.
- (line 62)
-* auto-revert-stop-on-user-input: Automatic Reverting of File-Visiting Buffers.
- (line 71)
-* auto-revert-use-notify: Automatic Reverting of File-Visiting Buffers.
- (line 49)
-* auto-revert-verbose: Automatic Reverting of File-Visiting Buffers.
- (line 103)
-* branch.autoSetupMerge: Branch Git Variables.
- (line 81)
-* branch.autoSetupRebase: Branch Git Variables.
- (line 98)
-* branch.NAME.description: Branch Git Variables.
- (line 48)
-* branch.NAME.merge: Branch Git Variables.
- (line 10)
-* branch.NAME.pushRemote: Branch Git Variables.
- (line 34)
-* branch.NAME.rebase: Branch Git Variables.
- (line 22)
-* branch.NAME.remote: Branch Git Variables.
- (line 16)
-* core.notesRef: Notes. (line 60)
-* git-commit-fill-column: Commit Message Conventions.
- (line 19)
-* git-commit-finish-query-functions: Commit Message Conventions.
- (line 24)
-* git-commit-known-pseudo-headers: Commit Pseudo Headers.
- (line 9)
-* git-commit-major-mode: Commit Mode and Hooks.
- (line 12)
-* git-commit-setup-hook: Commit Mode and Hooks.
- (line 22)
-* git-commit-setup-hook <1>: Commit Mode and Hooks.
- (line 64)
-* git-commit-style-convention-checks: Commit Message Conventions.
- (line 46)
-* git-commit-summary-max-length: Commit Message Conventions.
- (line 13)
-* git-rebase-auto-advance: Editing Rebase Sequences.
- (line 99)
-* git-rebase-confirm-cancel: Editing Rebase Sequences.
- (line 107)
-* git-rebase-show-instructions: Editing Rebase Sequences.
- (line 103)
-* global-auto-revert-mode: Automatic Reverting of File-Visiting Buffers.
- (line 22)
-* magit-auto-revert-immediately: Automatic Reverting of File-Visiting Buffers.
- (line 32)
-* magit-auto-revert-mode: Automatic Reverting of File-Visiting Buffers.
- (line 17)
-* magit-auto-revert-tracked-only: Automatic Reverting of File-Visiting Buffers.
- (line 55)
-* magit-bisect-show-graph: Bisecting. (line 55)
-* magit-blame-disable-modes: Blaming. (line 165)
-* magit-blame-echo-style: Blaming. (line 148)
-* magit-blame-goto-chunk-hook: Blaming. (line 171)
-* magit-blame-read-only: Blaming. (line 160)
-* magit-blame-styles: Blaming. (line 143)
-* magit-blame-time-format: Blaming. (line 155)
-* magit-branch-adjust-remote-upstream-alist: Branch Commands. (line 210)
-* magit-branch-direct-configure: Branch Commands. (line 20)
-* magit-branch-prefer-remote-upstream: Branch Commands. (line 165)
-* magit-branch-read-upstream-first: Branch Commands. (line 159)
-* magit-buffer-name-format: Naming Buffers. (line 27)
-* magit-bury-buffer-function: Quitting Windows. (line 14)
-* magit-cherry-margin: Cherries. (line 22)
-* magit-clone-always-transient: Cloning Repository. (line 12)
-* magit-clone-default-directory: Cloning Repository. (line 90)
-* magit-clone-name-alist: Cloning Repository. (line 103)
-* magit-clone-set-remote-head: Cloning Repository. (line 68)
-* magit-clone-set-remote.pushDefault: Cloning Repository. (line 78)
-* magit-clone-url-format: Cloning Repository. (line 124)
-* magit-commit-ask-to-stage: Initiating a Commit. (line 75)
-* magit-commit-extend-override-date: Initiating a Commit. (line 80)
-* magit-commit-reword-override-date: Initiating a Commit. (line 84)
-* magit-commit-squash-confirm: Initiating a Commit. (line 88)
-* magit-completing-read-function: Support for Completion Frameworks.
- (line 27)
-* magit-define-global-key-bindings: Default Bindings. (line 6)
-* magit-diff-adjust-tab-width: Diff Options. (line 21)
-* magit-diff-buffer-file-locked: Commands for Buffers Visiting Files.
- (line 61)
-* magit-diff-hide-trailing-cr-characters: Diff Options. (line 90)
-* magit-diff-highlight-hunk-region-functions: Diff Options. (line 94)
-* magit-diff-highlight-indentation: Diff Options. (line 75)
-* magit-diff-highlight-trailing: Diff Options. (line 70)
-* magit-diff-paint-whitespace: Diff Options. (line 43)
-* magit-diff-paint-whitespace-lines: Diff Options. (line 60)
-* magit-diff-refine-hunk: Diff Options. (line 6)
-* magit-diff-refine-ignore-whitespace: Diff Options. (line 16)
-* magit-diff-unmarked-lines-keep-foreground: Diff Options. (line 120)
-* magit-diff-visit-previous-blob: Visiting Files and Blobs from a Diff.
- (line 39)
-* magit-direct-use-buffer-arguments: Transient Arguments and Buffer Variables.
- (line 73)
-* magit-display-buffer-function: Switching Buffers. (line 27)
-* magit-display-buffer-noselect: Switching Buffers. (line 18)
-* magit-dwim-selection: Completion and Confirmation.
- (line 42)
-* magit-ediff-dwim-show-on-hunks: Ediffing. (line 73)
-* magit-ediff-quit-hook: Ediffing. (line 88)
-* magit-ediff-show-stash-with-index: Ediffing. (line 81)
-* magit-generate-buffer-name-function: Naming Buffers. (line 6)
-* magit-git-debug: Viewing Git Output. (line 28)
-* magit-git-debug <1>: Getting a Value from Git.
- (line 64)
-* magit-git-executable: Git Executable. (line 39)
-* magit-git-global-arguments: Global Git Arguments.
- (line 6)
-* magit-keep-region-overlay: The Selection. (line 52)
-* magit-list-refs-sortby: Additional Completion Options.
- (line 6)
-* magit-log-auto-more: Log Buffer. (line 69)
-* magit-log-buffer-file-locked: Commands for Buffers Visiting Files.
- (line 88)
-* magit-log-margin: Log Margin. (line 12)
-* magit-log-margin-show-committer-date: Log Margin. (line 49)
-* magit-log-section-commit-count: Status Sections. (line 136)
-* magit-log-select-margin: Select from Log. (line 30)
-* magit-log-show-refname-after-summary: Log Buffer. (line 75)
-* magit-log-trace-definition-function: Commands Available in Diffs.
- (line 18)
-* magit-module-sections-hook: Status Module Sections.
- (line 20)
-* magit-module-sections-nested: Status Module Sections.
- (line 24)
-* magit-no-confirm: Action Confirmation. (line 18)
-* magit-pop-revision-stack-format: Using the Revision Stack.
- (line 35)
-* magit-post-display-buffer-hook: Switching Buffers. (line 95)
-* magit-pre-display-buffer-hook: Switching Buffers. (line 84)
-* magit-prefer-remote-upstream: Branch Git Variables.
- (line 126)
-* magit-prefix-use-buffer-arguments: Transient Arguments and Buffer Variables.
- (line 64)
-* magit-process-raise-error: Calling Git for Effect.
- (line 151)
-* magit-pull-or-fetch: Fetching. (line 59)
-* magit-reflog-margin: Reflog. (line 23)
-* magit-refresh-args: Refreshing Buffers. (line 55)
-* magit-refresh-buffer-hook: Automatic Refreshing of Magit Buffers.
- (line 42)
-* magit-refresh-function: Refreshing Buffers. (line 49)
-* magit-refresh-status-buffer: Automatic Refreshing of Magit Buffers.
- (line 48)
-* magit-refs-filter-alist: References Buffer. (line 159)
-* magit-refs-focus-column-width: References Buffer. (line 82)
-* magit-refs-margin: References Buffer. (line 97)
-* magit-refs-margin-for-tags: References Buffer. (line 125)
-* magit-refs-pad-commit-counts: References Buffer. (line 49)
-* magit-refs-primary-column-width: References Buffer. (line 69)
-* magit-refs-sections-hook: References Sections. (line 13)
-* magit-refs-show-commit-count: References Buffer. (line 37)
-* magit-refs-show-remote-prefix: References Buffer. (line 62)
-* magit-remote-add-set-remote.pushDefault: Remote Commands. (line 92)
-* magit-remote-direct-configure: Remote Commands. (line 21)
-* magit-repolist-columns: Repository List. (line 14)
-* magit-repository-directories: Status Buffer. (line 58)
-* magit-revision-filter-files-on-follow: Revision Buffer. (line 64)
-* magit-revision-insert-related-refs: Revision Buffer. (line 6)
-* magit-revision-show-gravatars: Revision Buffer. (line 19)
-* magit-revision-use-hash-sections: Revision Buffer. (line 36)
-* magit-root-section: Matching Sections. (line 87)
-* magit-save-repository-buffers: Automatic Saving of File-Visiting Buffers.
- (line 13)
-* magit-section-cache-visibility: Section Visibility. (line 95)
-* magit-section-initial-visibility-alist: Section Visibility. (line 78)
-* magit-section-movement-hook: Section Movement. (line 46)
-* magit-section-set-visibility-hook: Section Visibility. (line 106)
-* magit-section-show-child-count: Section Options. (line 9)
-* magit-section-visibility-indicator: Section Visibility. (line 124)
-* magit-shell-command-verbose-prompt: Running Git Manually.
- (line 47)
-* magit-stashes-margin: Stashing. (line 104)
-* magit-status-headers-hook: Status Header Sections.
- (line 18)
-* magit-status-margin: Status Options. (line 10)
-* magit-status-refresh-hook: Status Options. (line 6)
-* magit-status-sections-hook: Status Sections. (line 10)
-* magit-submodule-list-columns: Listing Submodules. (line 21)
-* magit-this-process: Calling Git for Effect.
- (line 146)
-* magit-uniquify-buffer-names: Naming Buffers. (line 74)
-* magit-unstage-committed: Staging and Unstaging.
- (line 56)
-* magit-update-other-window-delay: Section Movement. (line 112)
-* magit-visit-ref-behavior: References Buffer. (line 192)
-* magit-wip-after-apply-mode: Legacy Wip Modes. (line 19)
-* magit-wip-after-apply-mode-lighter: Legacy Wip Modes. (line 59)
-* magit-wip-after-save-local-mode-lighter: Legacy Wip Modes. (line 55)
-* magit-wip-after-save-mode: Legacy Wip Modes. (line 13)
-* magit-wip-before-change-mode: Legacy Wip Modes. (line 33)
-* magit-wip-before-change-mode-lighter: Legacy Wip Modes. (line 63)
-* magit-wip-initial-backup-mode: Legacy Wip Modes. (line 38)
-* magit-wip-initial-backup-mode-lighter: Legacy Wip Modes. (line 67)
-* magit-wip-merge-branch: Wip Graph. (line 6)
-* magit-wip-mode: Wip Modes. (line 30)
-* magit-wip-mode-lighter: Wip Modes. (line 104)
-* magit-wip-namespace: Wip Modes. (line 96)
-* notes.displayRef: Notes. (line 65)
-* pull.rebase: Branch Git Variables.
- (line 57)
-* remote.NAME.fetch: Remote Git Variables.
- (line 15)
-* remote.NAME.push: Remote Git Variables.
- (line 26)
-* remote.NAME.pushurl: Remote Git Variables.
- (line 20)
-* remote.NAME.tagOpts: Remote Git Variables.
- (line 31)
-* remote.NAME.url: Remote Git Variables.
- (line 10)
-* remote.pushDefault: Branch Git Variables.
- (line 71)
-
--- /dev/null
+Authors
+=======
+
+The following people have contributed to Magit, including the
+libraries `git-commit.el`, `magit-popup.el`, and `with-editor.el`
+which are distributed as separate Elpa packages.
+
+For statistics see https://magit.vc/stats/authors.html.
+
+Names below are sorted alphabetically.
+
+Author
+------
+
+- Marius Vollmer <marius.vollmerNOSPAMgmail.com>
+
+Maintainer
+----------
+
+- Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+Developers
+----------
+
+- Kyle Meyer <kyleNOSPAMkyleam.com>
+- Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
+
+Retired Maintainers and Developers
+----------------------------------
+
+- Nicolas Dudebout <nicolas.dudeboutNOSPAMgatech.edu>
+- Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
+- Pieter Praet <pieterNOSPAMpraet.org>
+- Phil Jackson <philNOSPAMshellarchive.co.uk>
+- Rémi Vanicat <vanicatNOSPAMdebian.org>
+- Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+
+Contributors
+------------
+
+- Aaron Culich <aculichNOSPAMgmail.com>
+- Aaron Madlon-Kay <aaronNOSPAMmadlon-kay.com>
+- Abdo Roig-Maranges <abdo.roigNOSPAMgmail.com>
+- Adam Benanti <0entropyNOSPAMprotonmail.com>
+- Adam Kruszewski <adamNOSPAMkruszewski.name>
+- Adam Porter <adamNOSPAMalphapapa.net>
+- Adam Spiers <emacsNOSPAMadamspiers.org>
+- Adeodato Simó <datoNOSPAMnet.com.org.es>
+- Ævar Arnfjörð Bjarmason <avarabNOSPAMgmail.com>
+- Alan Falloon <alan.falloonNOSPAMgmail.com>
+- Alban Gruin <albanNOSPAMpa1ch.fr>
+- Aleksey Uimanov <s9gf4ultNOSPAMgmail.com>
+- Alexander Gramiak <fice-tNOSPAMprotonmail.com>
+- Alexander Miller <alexandermNOSPAMweb.de>
+- Alex Branham <alex.branhamNOSPAMgmail.com>
+- Alex Dunn <adunnNOSPAMucsb.edu>
+- Alexey Voinov <alexey.v.voinovNOSPAMgmail.com>
+- Alex Kost <alezostNOSPAMgmail.com>
+- Alex Ott <alexott@gmail.com>
+- Allen <darkfelineNOSPAMfelesatra.moe>
+- Allen Li <darkfelineNOSPAMfelesatra.moe>
+- Andreas Fuchs <asfNOSPAMboinkor.net>
+- Andreas Liljeqvist <andreas.liljeqvistNOSPAMrobacks.se>
+- Andreas Rottmann <a.rottmannNOSPAMgmx.at>
+- Andrei Chițu <andrei.chitu1NOSPAMgmail.com>
+- Andrew Eggenberger <andrew.eggenbergerNOSPAMgmail.com>
+- Andrew Kirkpatrick <andrew.kirkpatrickNOSPAMadelaide.edu.au>
+- Andrew Schwartzmeyer <andrewNOSPAMschwartzmeyer.com>
+- Andrey Smirnov <andrew.smirnovNOSPAMgmail.com>
+- Andriy Kmit' <dev@madand.net>
+- Andy Sawyer <gitNOSPAMpureabstract.org>
+- Aria Edmonds <ariaNOSPAMar1as.space>
+- Arialdo Martini <arialdomartiniNOSPAMgmail.com>
+- Arnau Roig Ninerola <arnau.ninerolaNOSPAMoutlook.com>
+- Barak A. Pearlmutter <barak+gitNOSPAMpearlmutter.net>
+- Bar Magal <bmagambNOSPAMgmail.com>
+- Bart Bakker <bartNOSPAMthesoftwarecraft.com>
+- Basil L. Contovounesios <contovobNOSPAMtcd.ie>
+- Bastian Beischer <beischerNOSPAMphysik.rwth-aachen.de>
+- Benjamin Motz <benjamin.motzNOSPAMmailbox.org>
+- Ben North <ben@redfrontdoor.org>
+- Ben Walton <bwaltonNOSPAMartsci.utoronto.ca>
+- Bob Uhl <buhlNOSPAMzvelo.com>
+- Bradley Wright <bradNOSPAMintranation.com>
+- Brandon W Maister <quodlibetorNOSPAMgmail.com>
+- Brian Leung <leungbkNOSPAMmailfence.com>
+- Brian Warner <warnerNOSPAMlothar.com>
+- Bryan Shell <bryan.shellNOSPAMorbitz.com>
+- Buster Copley <busterNOSPAMbuster.me.uk>
+- Carl Lieberman <liebermancarlNOSPAMgmail.com>
+- Chillar Anand <anand21nandaNOSPAMgmail.com>
+- Chris Bernard <cebernardNOSPAMgmail.com>
+- Chris Done <chrisdoneNOSPAMgmail.com>
+- Chris LaRose <cjlaroseNOSPAMgmail.com>
+- Chris Moore <dooglusNOSPAMgmail.com>
+- Chris Ring <chrisNOSPAMringthis.com>
+- Chris Shoemaker <chrisNOSPAMmojotech.com>
+- Christian Dietrich <christian.dietrichNOSPAMinformatik.uni-erlangen.de>
+- Christian Kluge <ckfrakturfreakNOSPAMweb.de>
+- Christophe Junke <junke.christopheNOSPAMgmail.com>
+- Christopher Monsanto <chrisNOSPAMmonsan.to>
+- Clément Pit-Claudel <clement.pitclaudelNOSPAMlive.com>
+- Cornelius Mika <cornelius.mikaNOSPAMgmail.com>
+- Craig Andera <canderaNOSPAMwangdera.com>
+- Dale Hagglund <dale.hagglundNOSPAMgmail.com>
+- Damien Cassou <damienNOSPAMcassou.me>
+- Dan Davison <dandavison7NOSPAMgmail.com>
+- Dan Erikson <derikson3NOSPAMgmail.com>
+- Daniel Brockman <danielNOSPAMgointeractive.se>
+- Daniel Farina <drfarinaNOSPAMacm.org>
+- Daniel Gröber <danielNOSPAMdps.uibk.ac.at>
+- Daniel Hackney <danNOSPAMhaxney.org>
+- Daniel Kraus <danielNOSPAMkraus.my>
+- Daniel Mai <danielNOSPAMdanielmai.net>
+- Daniel MartÃn <mardani29NOSPAMyahoo.es>
+- Dan LaManna <dan.lamannaNOSPAMgmail.com>
+- Danny Zhu <dzhuNOSPAMdzhu.us>
+- Dato Simó <datoNOSPAMnet.com.org.es>
+- David Abrahams <daveNOSPAMboostpro.com>
+- David Ellison <davidehellisonNOSPAMgmail.com>
+- David Ellison <davideNOSPAMvoicebox.com>
+- David Hull <david.hullNOSPAMopenx.com>
+- David L. Rager <ragerdlNOSPAMgmail.com>
+- David Wallin <david.wallinNOSPAMgmail.com>
+- Dean Kariniemi <8913263+d3k4rNOSPAMusers.noreply.github.com>
+- Dennis Paskorz <dennisNOSPAMwalltowall.com>
+- Divye Kapoor <divyeNOSPAMgoogle.com>
+- Dominique Quatravaux <dominique.quatravauxNOSPAMepfl.ch>
+- Dominique Quatravaux <domqNOSPAMgoogle.com>
+- Duianto Vebotci <vebotciNOSPAMopenmailbox.org>
+- Eli Barzilay <eliNOSPAMbarzilay.org>
+- Eric Davis <edNOSPAMnpri.org>
+- Eric <e.a.gebhartNOSPAMgmail.com>
+- Eric Prud'hommeaux <ericNOSPAMw3.org>
+- Eric Schulte <schulte.ericNOSPAMgmail.com>
+- Erik Anderson <erikbpandersonNOSPAMgmail.com>
+- Evan Torrie <etorrieNOSPAMgmail.com>
+- Evgkeni Sampelnikof <esabofNOSPAMgmail.com>
+- Eyal Lotem <eyal.lotemNOSPAMgmail.com>
+- Fabian Wiget <fabacinoNOSPAMgmail.com>
+- Felix Geller <fgellerNOSPAMgmail.com>
+- Felix Yan <felixonmarsNOSPAMarchlinux.org>
+- Feng Li <fengliNOSPAMblackmagicdesign.com>
+- Florian Ragwitz <raflNOSPAMdebian.org>
+- Fritz Grabo <fritz.graboNOSPAMgmail.com>
+- Fritz Stelzer <brotzeitmacherNOSPAMgmail.com>
+- Geoff Shannon <geoffpshannonNOSPAMgmail.com>
+- George Kadianakis <desnackedNOSPAMgmail.com>
+- Graham Clark <grclarkNOSPAMgmail.com>
+- Graham Dobbins <gdobbinsNOSPAMprotonmail.com>
+- Greg A. Woods <woodsNOSPAMplanix.com>
+- Greg Lucas <gregNOSPAMglucas.net>
+- Gregory Heytings <gheNOSPAMsdf.org>
+- Greg Sexton <gregsextonNOSPAMgmail.com>
+- Guillaume Martres <smarterNOSPAMubuntu.com>
+- Hannu Koivisto <azureNOSPAMiki.fi>
+- Hans-Peter Deifel <hpdeifelNOSPAMgmx.de>
+- Hussein Ait-Lahcen <hussein.ait-lahcenNOSPAMfretlink.com>
+- Ian Eure <ian.eureNOSPAMgmail.com>
+- Ian Milligan <ianmllgnNOSPAMgmail.com>
+- Ingo Lohmar <i.lohmarNOSPAMgmail.com>
+- Ioan-Adrian Ratiu <adiNOSPAMadirat.com>
+- Ivan Brennan <ivan.brennanNOSPAMgmail.com>
+- Jan Tatarik <jan.tatarikNOSPAMxing.com>
+- Jasper St. Pierre <jstpierreNOSPAMmecheye.net>
+- Jeff Bellegarde <jbellegardeNOSPAMwhitepages.com>
+- Jeff Dairiki <dairikiNOSPAMdairiki.org>
+- Jeremy Meng <yumengNOSPAMmicrosoft.com>
+- Jesse Alama <jesse.alamaNOSPAMgmail.com>
+- Jim Blandy <jimbNOSPAMred-bean.com>
+- Joakim Jalap <JOJANOSPAMstoneridge.com>
+- Johannes Altmanninger <aclopteNOSPAMgmail.com>
+- Johann Klähn <johannNOSPAMjklaehn.de>
+- John Mastro <john.b.mastroNOSPAMgmail.com>
+- John Morris <johnNOSPAMzultron.com>
+- John Wiegley <johnwNOSPAMnewartisans.com>
+- Jonas Bernoulli <jonasNOSPAMbernoul.li>
+- Jonas Galvão Xavier <jonas.agxNOSPAMgmail.com>
+- Jonathan Arnett <jonathanNOSPAMscriptdrop.co>
+- Jonathan del Strother <meNOSPAMdelstrother.com>
+- Jonathan Leech-Pepin <jonathan.leechpepinNOSPAMgmail.com>
+- Jonathan Roes <jroesNOSPAMjroes.net>
+- Jon Vanderwijk <jonathnNOSPAMgithub.com>
+- Jordan Galby <gravemind2a@gmail.com>
+- Jordan Greenberg <jordanNOSPAMsoftwareslave.com>
+- Josh Elsasser <jelsasserNOSPAMappneta.com>
+- Josiah Schwab <jschwabNOSPAMgmail.com>
+- Julien Danjou <julienNOSPAMdanjou.info>
+- Justin Burkett <justinNOSPAMburkett.cc>
+- Justin Caratzas <justin.caratzasNOSPAMgmail.com>
+- Justin Guenther <jguentherNOSPAMgmail.com>
+- Justin Thomas <justin.thomas1NOSPAMgmail.com>
+- Kan-Ru Chen <kanruNOSPAMkanru.info>
+- Kenny Ballou <kballouNOSPAMdevnulllabs.io>
+- Keshav Kini <keshav.kiniNOSPAMgmail.com>
+- Kevin Brubeck Unhammer <unhammerNOSPAMfsfe.org>
+- Kevin J. Foley <kfoley15NOSPAMgmail.com>
+- Kévin Le Gouguec <kevin.legouguecNOSPAMgmail.com>
+- Kimberly Wolk <kimwolkNOSPAMhotmail.com>
+- Knut Olav Bøhmer <bohmerNOSPAMgmail.com>
+- Kyle Meyer <kyleNOSPAMkyleam.com>
+- Laurent Laffont <laurent.laffontNOSPAMgmail.com>
+- Laverne Schrock <laverneNOSPAMschrock.email>
+- Leandro Facchinetti <meNOSPAMleafac.com>
+- Lele Gaifax <leleNOSPAMmetapensiero.it>
+- Leo Liu <sdl.webNOSPAMgmail.com>
+- Leonardo Etcheverry <leoNOSPAMkalio.net>
+- Leo Vivier <leo.vivier+devNOSPAMgmail.com>
+- Lingchao Xin <douglarekNOSPAMusers.noreply.github.com>
+- Li-Yun Chang <michael142536NOSPAMgmail.com>
+- LluÃs Vilanova <vilanovaNOSPAMac.upc.edu>
+- Loic Dachary <loicNOSPAMdachary.org>
+- Louis Roché <louisNOSPAMlouisroche.net>
+- LuÃs Oliveira <luismboNOSPAMgmail.com>
+- Luke Amdor <luke.amdorNOSPAMgmail.com>
+- Magnus Malm <magnusmalmNOSPAMgmail.com>
+- Mak Kolybabi <makNOSPAMkolybabi.com>
+- Manuel Vázquez Acosta <mva.ledNOSPAMgmail.com>
+- Marcel Wolf <mwolfNOSPAMml1.net>
+- Marc Herbert <marc.herbertNOSPAMgmail.com>
+- Marcin Bachry <hegel666NOSPAMgmail.com>
+- Marco Craveiro <marco.craveiroNOSPAMgmail.com>
+- Marco Wahl <marcowahlsoftNOSPAMgmail.com>
+- Marc Sherry <msherryNOSPAMgmail.com>
+- Marian Schubert <marian.schubertNOSPAMgmail.com>
+- Mario Rodas <marsamNOSPAMusers.noreply.github.com>
+- Marius Vollmer <marius.vollmerNOSPAMgmail.com>
+- Mark Hepburn <Mark.HepburnNOSPAMcsiro.au>
+- Mark Karpov <markkarpovNOSPAMopmbx.org>
+- Mark Oteiza <mvoteizaNOSPAMudel.edu>
+- Matthew Fluet <matthew.fluetNOSPAMgmail.com>
+- Matthew Kraai <kraaiNOSPAMftbfs.org>
+- Matthieu Hauglustaine <matt.hauglustaineNOSPAMgmail.com>
+- Matus Goljer <dota.keysNOSPAMgmail.com>
+- Maxim Cournoyer <maxim.cournoyerNOSPAMgmail.com>
+- Michael Fogleman <michaelwfoglemanNOSPAMgmail.com>
+- Michael Griffiths <mikeyNOSPAMcich.li>
+- Michael Heerdegen <michael_heerdegenNOSPAMweb.de>
+- Michal Sojka <sojkam1NOSPAMfel.cvut.cz>
+- Miciah Masters <miciah.mastersNOSPAMgmail.com>
+- Miles Bader <milesNOSPAMgnu.org>
+- Miloš Mošić <mosic.milosNOSPAMgmail.com>
+- Mitchel Humpherys <mitch.specialNOSPAMgmail.com>
+- Moritz Bunkus <moritzNOSPAMbunkus.org>
+- Naoya Yamashita <conao3NOSPAMgmail.com>
+- Natalie Weizenbaum <nex342NOSPAMgmail.com>
+- Nguyễn Tuấn Anh <ubolontonNOSPAMgmail.com>
+- Nic Ferier <nicNOSPAMferrier.me.uk>
+- Nick Alcock <nick.alcockNOSPAMoracle.com>
+- Nick Alexander <nalexanderNOSPAMmozilla.com>
+- Nick Dimiduk <ndimidukNOSPAMgmail.com>
+- Nicklas Lindgren <niliNOSPAMgulmohar.se>
+- Nicolas Dudebout <nicolas.dudeboutNOSPAMgatech.edu>
+- Nicolas Petton <nicolasNOSPAMpetton.fr>
+- Nicolas Richard <theonewiththeevillookNOSPAMyahoo.fr>
+- Nikolay Martynov <mar.kolyaNOSPAMgmail.com>
+- Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
+- N. Troy de Freitas <meNOSPAMntdef.com>
+- Ole Arndt <oliver.arndtNOSPAMcegedim.com>
+- Oleh Krehel <ohwoeowhoNOSPAMgmail.com>
+- Orivej Desh <orivejNOSPAMgmx.fr>
+- Óscar Fuentes <ofvNOSPAMwanadoo.es>
+- Paul Stadig <paulNOSPAMstadig.name>
+- Pavel Holejsovsky <pavel.holejsovskyNOSPAMupek.com>
+- Pekka Pessi <nospamNOSPAMpessi.fi>
+- Peter Eisentraut <peterNOSPAMeisentraut.org>
+- Peter Jaros <peter.a.jarosNOSPAMgmail.com>
+- Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
+- Peter Vasil <mailNOSPAMpetervasil.net>
+- Philippe Vaucher <philippe.vaucherNOSPAMgmail.com>
+- Philipp Fehre <pfehreNOSPAMtwitter.com>
+- Philipp Haselwarter <philippNOSPAMhaselwarter.org>
+- Philipp Stephani <phstNOSPAMgoogle.com>
+- Philip Weaver <philip.weaverNOSPAMgmail.com>
+- Phil Jackson <philNOSPAMshellarchive.co.uk>
+- Phil Sainty <philNOSPAMcatalyst.net.nz>
+- Pierre Neidhardt <ambrevarNOSPAMgmail.com>
+- Pieter Praet <pieterNOSPAMpraet.org>
+- Prathamesh Sonpatki <csonpatkiNOSPAMgmail.com>
+- rabio <rabiodevNOSPAMo2.pl>
+- Radon Rosborough <radon.neonNOSPAMgmail.com>
+- Rafael Laboissiere <rafaelNOSPAMlaboissiere.net>
+- Raimon Grau <raimonNOSPAM3scale.net>
+- Ramkumar Ramachandra <artagnonNOSPAMgmail.com>
+- Remco van 't Veer <rwvtveerNOSPAMxs4all.nl>
+- Rémi Vanicat <vanicat@debian.org>
+- René Stadler <mailNOSPAMrenestadler.de>
+- Richard Kim <emacs18NOSPAMgmail.com>
+- Robert Boone <robo4288NOSPAMgmail.com>
+- Robin Green <greenrdNOSPAMgreenrd.org>
+- Roey Darwish Dror <roey.ghostNOSPAMgmail.com>
+- Roger Crew <crewNOSPAMcs.stanford.edu>
+- Romain Francoise <romainNOSPAMorebokech.com>
+- Ron Parker <rparkerNOSPAMa123systems.com>
+- Roy Crihfield <rscrihfNOSPAMgmail.com>
+- Rüdiger Sonderfeld <ruedigerNOSPAMc-plusplus.net>
+- Russell Black <black.russellNOSPAMgmail.com>
+- Ryan C. Thompson <rctNOSPAMthompsonclan.org>
+- Samuel Bronson <naestenNOSPAMgmail.com>
+- Samuel W. Flint <swflintNOSPAMflintfam.org>
+- Sanjoy Das <sanjoyNOSPAMplayingwithpointers.com>
+- Sean Allred <codeNOSPAMseanallred.com>
+- Sean Bryant <sbryantNOSPAMhackinggibsons.com>
+- Sean Whitton <spwhittonNOSPAMspwhitton.name>
+- Sebastian Wiesner <lunaryornNOSPAMgmail.com>
+- Sébastien Gross <sebNOSPAMchezwam.org>
+- Seong-Kook Shin <cinskyNOSPAMgmail.com>
+- Sergey Pashinin <sergeyNOSPAMpashinin.com>
+- Sergey Vinokurov <serg.fooNOSPAMgmail.com>
+- Servilio Afre Puentes <afrepuesNOSPAMmcmaster.ca>
+- Silent Sphere <silentsphere110NOSPAMgmail.com>
+- Simon Pintarelli <simon.pintarelliNOSPAMcscs.ch>
+- Štěpán Němec <stepnemNOSPAMgmail.com>
+- Steven Chow <steveNOSPAMmyfreestuffapp.com>
+- Steven E. Harris <sehNOSPAMpanix.com>
+- Steven Thomas <sthomas314NOSPAMgmail.com>
+- Steven Vancoillie <steven.vancoillieNOSPAMrunbox.com>
+- Steve Purcell <steveNOSPAMsanityinc.com>
+- Suhail Shergill <suhailshergillNOSPAMgmail.com>
+- Sylvain Rousseau <thisirsNOSPAMgmail.com>
+- Syohei Yoshida <syohexNOSPAMgmail.com>
+- Szunti <SzuntiNOSPAMusers.noreply.github.com>
+- Takafumi Arakaki <aka.tkfNOSPAMgmail.com>
+- Tassilo Horn <tsdhNOSPAMgnu.org>
+- Teemu Likonen <tlikonenNOSPAMiki.fi>
+- Teruki Shigitani <teruki.shigitaniNOSPAMgmail.com>
+- Thierry Volpiatto <thievolNOSPAMposteo.net>
+- Thomas A Caswell <tcaswellNOSPAMgmail.com>
+- Thomas Fini Hansen <xenNOSPAMxen.dk>
+- Thomas Frössman <thomasfNOSPAMjossystem.se>
+- Thomas Jost <thomas.jostNOSPAMgmail.com>
+- Thomas Riccardi <riccardi.thomasNOSPAMgmail.com>
+- Tibor Simko <tibor.simkoNOSPAMcern.ch>
+- Timo Juhani Lindfors <timo.lindforsNOSPAMiki.fi>
+- Tim Perkins <tprk77NOSPAMgmail.com>
+- Tim Wraight <timNOSPAMwraight.net>
+- Ting-Yu Lin <aethanycNOSPAMgmail.com>
+- Tom Feist <shabbleNOSPAMmetavore.org>
+- Topi Miettinen <toiwotonNOSPAMgmail.com>
+- Troy Hinckley <t.macmanNOSPAMgmail.com>
+- Tsuyoshi Kitamoto <tsuyoshi.kitamotoNOSPAMgmail.com>
+- Tunc Uzlu <bb2020NOSPAMusers.noreply.github.com>
+- Vineet Naik <vineetNOSPAMhelpshift.com>
+- Vitaly Ostashov <hotoshoNOSPAMyandex-team.ru>
+- Vladimir Panteleev <gitNOSPAMthecybershadow.net>
+- Vladimir Sedach <vasNOSPAMoneofus.la>
+- Wei Huang <weihNOSPAMopera.com>
+- Wilfred Hughes <meNOSPAMwilfred.me.uk>
+- Win Treese <treeseNOSPAMacm.org>
+- Wojciech Siewierski <wojciechNOSPAMsiewierski.eu>
+- Wouter Bolsterlee <wouterNOSPAMbolsterl.ee>
+- Xavier Noria <fxnNOSPAMhashref.com>
+- Xu Chunyang <mailNOSPAMxuchunyang.me>
+- Yann Herklotz <gitNOSPAMyannherklotz.com>
+- Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+- Ynilu <ynilu.changNOSPAMgmail.com>
+- York Zhao <gtdplatformNOSPAMgmail.com>
+- Yuichi Higashi <aaa707bNOSPAMgmail.com>
+- Yuri Khan <yurivkhanNOSPAMgmail.com>
+- Zach Latta <zachNOSPAMzachlatta.com>
+- zakora <zakoraNOSPAMusers.noreply.github.com>
+- Zhu Zihao <all_but_lastNOSPAM163.com>
+- zilongshanren <guanghui8827NOSPAM126.com>
--- /dev/null
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ 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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 <http://www.gnu.org/licenses/>.
+
+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:
+
+ <program> Copyright (C) <year> <name of author>
+ 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
+<http://www.gnu.org/licenses/>.
+
+ 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
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
+
--- /dev/null
+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.
+\1f
+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<Return>" 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.
--- /dev/null
+;;; git-rebase.el --- Edit Git rebase files -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Phil Jackson <philNOSPAMshellarchive.co.uk>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; This file is not part of GNU Emacs.
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this file. If not, see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+
+;; This package assists the user in editing the list of commits to be
+;; rewritten during an interactive rebase.
+
+;; When the user initiates an interactive rebase, e.g. using "r e" in
+;; a Magit buffer or on the command line using "git rebase -i REV",
+;; Git invokes the `$GIT_SEQUENCE_EDITOR' (or if that is undefined
+;; `$GIT_EDITOR' or even `$EDITOR') letting the user rearrange, drop,
+;; reword, edit, and squash commits.
+
+;; This package provides the major-mode `git-rebase-mode' which makes
+;; doing so much more fun, by making the buffer more colorful and
+;; providing the following commands:
+;;
+;; C-c C-c Tell Git to make it happen.
+;; C-c C-k Tell Git that you changed your mind, i.e. abort.
+;;
+;; p Move point to previous line.
+;; n Move point to next line.
+;;
+;; M-p Move the commit at point up.
+;; M-n Move the commit at point down.
+;;
+;; k Drop the commit at point.
+;; c Don't drop the commit at point.
+;; r Change the message of the commit at point.
+;; e Edit the commit at point.
+;; s Squash the commit at point, into the one above.
+;; f Like "s" but don't also edit the commit message.
+;; b Break for editing at this point in the sequence.
+;; x Add a script to be run with the commit at point
+;; being checked out.
+;; z Add noop action at point.
+;;
+;; SPC Show the commit at point in another buffer.
+;; RET Show the commit at point in another buffer and
+;; select its window.
+;; C-/ Undo last change.
+;;
+;; Commands for --rebase-merges:
+;; l Associate label with current HEAD in sequence.
+;; MM Merge specified revisions into HEAD.
+;; Mt Toggle whether the merge will invoke an editor
+;; before committing.
+;; t Reset HEAD to the specified label.
+
+;; You should probably also read the `git-rebase' manpage.
+
+;;; Code:
+
+(require 'magit)
+
+(require 'easymenu)
+(require 'server)
+(require 'with-editor)
+
+(defvar recentf-exclude)
+
+;;; Options
+;;;; Variables
+
+(defgroup git-rebase nil
+ "Edit Git rebase sequences."
+ :link '(info-link "(magit)Editing Rebase Sequences")
+ :group 'tools)
+
+(defcustom git-rebase-auto-advance t
+ "Whether to move to next line after changing a line."
+ :group 'git-rebase
+ :type 'boolean)
+
+(defcustom git-rebase-show-instructions t
+ "Whether to show usage instructions inside the rebase buffer."
+ :group 'git-rebase
+ :type 'boolean)
+
+(defcustom git-rebase-confirm-cancel t
+ "Whether confirmation is required to cancel."
+ :group 'git-rebase
+ :type 'boolean)
+
+;;;; Faces
+
+(defgroup git-rebase-faces nil
+ "Faces used by Git-Rebase mode."
+ :group 'faces
+ :group 'git-rebase)
+
+(defface git-rebase-hash '((t (:inherit magit-hash)))
+ "Face for commit hashes."
+ :group 'git-rebase-faces)
+
+(defface git-rebase-label '((t (:inherit magit-refname)))
+ "Face for labels in label, merge, and reset lines."
+ :group 'git-rebase-faces)
+
+(defface git-rebase-description nil
+ "Face for commit descriptions."
+ :group 'git-rebase-faces)
+
+(defface git-rebase-killed-action
+ '((t (:inherit font-lock-comment-face :strike-through t)))
+ "Face for commented commit action lines."
+ :group 'git-rebase-faces)
+
+(defface git-rebase-comment-hash
+ '((t (:inherit git-rebase-hash :weight bold)))
+ "Face for commit hashes in commit message comments."
+ :group 'git-rebase-faces)
+
+(defface git-rebase-comment-heading
+ '((t :inherit font-lock-keyword-face))
+ "Face for headings in rebase message comments."
+ :group 'git-commit-faces)
+
+;;; Keymaps
+
+(defvar git-rebase-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map special-mode-map)
+ (define-key map (kbd "C-m") 'git-rebase-show-commit)
+ (define-key map (kbd "p") 'git-rebase-backward-line)
+ (define-key map (kbd "n") 'forward-line)
+ (define-key map (kbd "M-p") 'git-rebase-move-line-up)
+ (define-key map (kbd "M-n") 'git-rebase-move-line-down)
+ (define-key map (kbd "c") 'git-rebase-pick)
+ (define-key map (kbd "k") 'git-rebase-kill-line)
+ (define-key map (kbd "C-k") 'git-rebase-kill-line)
+ (define-key map (kbd "b") 'git-rebase-break)
+ (define-key map (kbd "e") 'git-rebase-edit)
+ (define-key map (kbd "l") 'git-rebase-label)
+ (define-key map (kbd "MM") 'git-rebase-merge)
+ (define-key map (kbd "Mt") 'git-rebase-merge-toggle-editmsg)
+ (define-key map (kbd "m") 'git-rebase-edit)
+ (define-key map (kbd "f") 'git-rebase-fixup)
+ (define-key map (kbd "q") 'undefined)
+ (define-key map (kbd "r") 'git-rebase-reword)
+ (define-key map (kbd "w") 'git-rebase-reword)
+ (define-key map (kbd "s") 'git-rebase-squash)
+ (define-key map (kbd "t") 'git-rebase-reset)
+ (define-key map (kbd "x") 'git-rebase-exec)
+ (define-key map (kbd "y") 'git-rebase-insert)
+ (define-key map (kbd "z") 'git-rebase-noop)
+ (define-key map (kbd "SPC") 'git-rebase-show-or-scroll-up)
+ (define-key map (kbd "DEL") 'git-rebase-show-or-scroll-down)
+ (define-key map (kbd "C-x C-t") 'git-rebase-move-line-up)
+ (define-key map [M-up] 'git-rebase-move-line-up)
+ (define-key map [M-down] 'git-rebase-move-line-down)
+ (define-key map [remap undo] 'git-rebase-undo)
+ map)
+ "Keymap for Git-Rebase mode.")
+
+(put 'git-rebase-reword :advertised-binding (kbd "r"))
+(put 'git-rebase-move-line-up :advertised-binding (kbd "M-p"))
+(put 'git-rebase-kill-line :advertised-binding (kbd "k"))
+
+(easy-menu-define git-rebase-mode-menu git-rebase-mode-map
+ "Git-Rebase mode menu"
+ '("Rebase"
+ ["Pick" git-rebase-pick t]
+ ["Reword" git-rebase-reword t]
+ ["Edit" git-rebase-edit t]
+ ["Squash" git-rebase-squash t]
+ ["Fixup" git-rebase-fixup t]
+ ["Kill" git-rebase-kill-line t]
+ ["Noop" git-rebase-noop t]
+ ["Execute" git-rebase-exec t]
+ ["Move Down" git-rebase-move-line-down t]
+ ["Move Up" git-rebase-move-line-up t]
+ "---"
+ ["Cancel" with-editor-cancel t]
+ ["Finish" with-editor-finish t]))
+
+(defvar git-rebase-command-descriptions
+ '((with-editor-finish . "tell Git to make it happen")
+ (with-editor-cancel . "tell Git that you changed your mind, i.e. abort")
+ (git-rebase-backward-line . "move point to previous line")
+ (forward-line . "move point to next line")
+ (git-rebase-move-line-up . "move the commit at point up")
+ (git-rebase-move-line-down . "move the commit at point down")
+ (git-rebase-show-or-scroll-up . "show the commit at point in another buffer")
+ (git-rebase-show-commit
+ . "show the commit at point in another buffer and select its window")
+ (undo . "undo last change")
+ (git-rebase-kill-line . "drop the commit at point")
+ (git-rebase-insert . "insert a line for an arbitrary commit")
+ (git-rebase-noop . "add noop action at point")))
+
+;;; Commands
+
+(defun git-rebase-pick ()
+ "Use commit on current line.
+If the region is active, act on all lines touched by the region."
+ (interactive)
+ (git-rebase-set-action "pick"))
+
+(defun git-rebase-reword ()
+ "Edit message of commit on current line.
+If the region is active, act on all lines touched by the region."
+ (interactive)
+ (git-rebase-set-action "reword"))
+
+(defun git-rebase-edit ()
+ "Stop at the commit on the current line.
+If the region is active, act on all lines touched by the region."
+ (interactive)
+ (git-rebase-set-action "edit"))
+
+(defun git-rebase-squash ()
+ "Meld commit on current line into previous commit, edit message.
+If the region is active, act on all lines touched by the region."
+ (interactive)
+ (git-rebase-set-action "squash"))
+
+(defun git-rebase-fixup ()
+ "Meld commit on current line into previous commit, discard its message.
+If the region is active, act on all lines touched by the region."
+ (interactive)
+ (git-rebase-set-action "fixup"))
+
+(defvar-local git-rebase-comment-re nil)
+
+(defvar git-rebase-short-options
+ '((?b . "break")
+ (?e . "edit")
+ (?f . "fixup")
+ (?l . "label")
+ (?m . "merge")
+ (?p . "pick")
+ (?r . "reword")
+ (?s . "squash")
+ (?t . "reset")
+ (?x . "exec"))
+ "Alist mapping single key of an action to the full name.")
+
+(defclass git-rebase-action ()
+ (;; action-type: commit, exec, bare, label, merge
+ (action-type :initarg :action-type :initform nil)
+ ;; Examples for each action type:
+ ;; | action | action options | target | trailer |
+ ;; |--------+----------------+---------+---------|
+ ;; | pick | | hash | subject |
+ ;; | exec | | command | |
+ ;; | noop | | | |
+ ;; | reset | | name | subject |
+ ;; | merge | -C hash | name | subject |
+ (action :initarg :action :initform nil)
+ (action-options :initarg :action-options :initform nil)
+ (target :initarg :target :initform nil)
+ (trailer :initarg :trailer :initform nil)
+ (comment-p :initarg :comment-p :initform nil)))
+
+(defvar git-rebase-line-regexps
+ `((commit . ,(concat
+ (regexp-opt '("e" "edit"
+ "f" "fixup"
+ "p" "pick"
+ "r" "reword"
+ "s" "squash")
+ "\\(?1:")
+ " \\(?3:[^ \n]+\\) ?\\(?4:.*\\)"))
+ (exec . "\\(?1:x\\|exec\\) \\(?3:.*\\)")
+ (bare . ,(concat (regexp-opt '("b" "break" "noop") "\\(?1:")
+ " *$"))
+ (label . ,(concat (regexp-opt '("l" "label"
+ "t" "reset")
+ "\\(?1:")
+ " \\(?3:[^ \n]+\\) ?\\(?4:.*\\)"))
+ (merge . ,(concat "\\(?1:m\\|merge\\) "
+ "\\(?:\\(?2:-[cC] [^ \n]+\\) \\)?"
+ "\\(?3:[^ \n]+\\)"
+ " ?\\(?4:.*\\)"))))
+
+;;;###autoload
+(defun git-rebase-current-line ()
+ "Parse current line into a `git-rebase-action' instance.
+If the current line isn't recognized as a rebase line, an
+instance with all nil values is returned."
+ (save-excursion
+ (goto-char (line-beginning-position))
+ (if-let ((re-start (concat "^\\(?5:" (regexp-quote comment-start)
+ "\\)? *"))
+ (type (seq-some (lambda (arg)
+ (let ((case-fold-search nil))
+ (and (looking-at (concat re-start (cdr arg)))
+ (car arg))))
+ git-rebase-line-regexps)))
+ (git-rebase-action
+ :action-type type
+ :action (when-let ((action (match-string-no-properties 1)))
+ (or (cdr (assoc action git-rebase-short-options))
+ action))
+ :action-options (match-string-no-properties 2)
+ :target (match-string-no-properties 3)
+ :trailer (match-string-no-properties 4)
+ :comment-p (and (match-string 5) t))
+ ;; Use default empty class rather than nil to ease handling.
+ (git-rebase-action))))
+
+(defun git-rebase-set-action (action)
+ "Set action of commit line to ACTION.
+If the region is active, operate on all lines that it touches.
+Otherwise, operate on the current line. As a special case, an
+ACTION of nil comments the rebase line, regardless of its action
+type."
+ (pcase (git-rebase-region-bounds t)
+ (`(,beg ,end)
+ (let ((end-marker (copy-marker end))
+ (pt-below-p (and mark-active (< (mark) (point)))))
+ (set-marker-insertion-type end-marker t)
+ (goto-char beg)
+ (while (< (point) end-marker)
+ (with-slots (action-type target trailer comment-p)
+ (git-rebase-current-line)
+ (cond
+ ((and action (eq action-type 'commit))
+ (let ((inhibit-read-only t))
+ (magit-delete-line)
+ (insert (concat action " " target " " trailer "\n"))))
+ ((and action-type (not (or action comment-p)))
+ (let ((inhibit-read-only t))
+ (insert comment-start " "))
+ (forward-line))
+ (t
+ ;; In the case of --rebase-merges, commit lines may have
+ ;; other lines with other action types, empty lines, and
+ ;; "Branch" comments interspersed. Move along.
+ (forward-line)))))
+ (goto-char
+ (if git-rebase-auto-advance
+ end-marker
+ (if pt-below-p (1- end-marker) beg)))
+ (goto-char (line-beginning-position))))
+ (_ (ding))))
+
+(defun git-rebase-line-p (&optional pos)
+ (save-excursion
+ (when pos (goto-char pos))
+ (and (oref (git-rebase-current-line) action-type)
+ t)))
+
+(defun git-rebase-region-bounds (&optional fallback)
+ "Return region bounds if both ends touch rebase lines.
+Each bound is extended to include the entire line touched by the
+point or mark. If the region isn't active and FALLBACK is
+non-nil, return the beginning and end of the current rebase line,
+if any."
+ (cond
+ ((use-region-p)
+ (let ((beg (save-excursion (goto-char (region-beginning))
+ (line-beginning-position)))
+ (end (save-excursion (goto-char (region-end))
+ (line-end-position))))
+ (when (and (git-rebase-line-p beg)
+ (git-rebase-line-p end))
+ (list beg (1+ end)))))
+ ((and fallback (git-rebase-line-p))
+ (list (line-beginning-position)
+ (1+ (line-end-position))))))
+
+(defun git-rebase-move-line-down (n)
+ "Move the current commit (or command) N lines down.
+If N is negative, move the commit up instead. With an active
+region, move all the lines that the region touches, not just the
+current line."
+ (interactive "p")
+ (pcase-let* ((`(,beg ,end)
+ (or (git-rebase-region-bounds)
+ (list (line-beginning-position)
+ (1+ (line-end-position)))))
+ (pt-offset (- (point) beg))
+ (mark-offset (and mark-active (- (mark) beg))))
+ (save-restriction
+ (narrow-to-region
+ (point-min)
+ (1-
+ (if git-rebase-show-instructions
+ (save-excursion
+ (goto-char (point-min))
+ (while (or (git-rebase-line-p)
+ ;; The output for --rebase-merges has empty
+ ;; lines and "Branch" comments interspersed.
+ (looking-at-p "^$")
+ (looking-at-p (concat git-rebase-comment-re
+ " Branch")))
+ (forward-line))
+ (line-beginning-position))
+ (point-max))))
+ (if (or (and (< n 0) (= beg (point-min)))
+ (and (> n 0) (= end (point-max)))
+ (> end (point-max)))
+ (ding)
+ (goto-char (if (< n 0) beg end))
+ (forward-line n)
+ (atomic-change-group
+ (let ((inhibit-read-only t))
+ (insert (delete-and-extract-region beg end)))
+ (let ((new-beg (- (point) (- end beg))))
+ (when (use-region-p)
+ (setq deactivate-mark nil)
+ (set-mark (+ new-beg mark-offset)))
+ (goto-char (+ new-beg pt-offset))))))))
+
+(defun git-rebase-move-line-up (n)
+ "Move the current commit (or command) N lines up.
+If N is negative, move the commit down instead. With an active
+region, move all the lines that the region touches, not just the
+current line."
+ (interactive "p")
+ (git-rebase-move-line-down (- n)))
+
+(defun git-rebase-highlight-region (start end window rol)
+ (let ((inhibit-read-only t)
+ (deactivate-mark nil)
+ (bounds (git-rebase-region-bounds)))
+ (mapc #'delete-overlay magit-section-highlight-overlays)
+ (when bounds
+ (magit-section-make-overlay (car bounds) (cadr bounds)
+ 'magit-section-heading-selection))
+ (if (and bounds (not magit-keep-region-overlay))
+ (funcall (default-value 'redisplay-unhighlight-region-function) rol)
+ (funcall (default-value 'redisplay-highlight-region-function)
+ start end window rol))))
+
+(defun git-rebase-unhighlight-region (rol)
+ (mapc #'delete-overlay magit-section-highlight-overlays)
+ (funcall (default-value 'redisplay-unhighlight-region-function) rol))
+
+(defun git-rebase-kill-line ()
+ "Kill the current action line.
+If the region is active, act on all lines touched by the region."
+ (interactive)
+ (git-rebase-set-action nil))
+
+(defun git-rebase-insert (rev)
+ "Read an arbitrary commit and insert it below current line."
+ (interactive (list (magit-read-branch-or-commit "Insert revision")))
+ (forward-line)
+ (--if-let (magit-rev-format "%h %s" rev)
+ (let ((inhibit-read-only t))
+ (insert "pick " it ?\n))
+ (user-error "Unknown revision")))
+
+(defun git-rebase-set-noncommit-action (action value-fn arg)
+ (goto-char (line-beginning-position))
+ (pcase-let* ((inhibit-read-only t)
+ (`(,initial ,trailer ,comment-p)
+ (and (not arg)
+ (with-slots ((ln-action action)
+ target trailer comment-p)
+ (git-rebase-current-line)
+ (and (equal ln-action action)
+ (list target trailer comment-p)))))
+ (value (funcall value-fn initial)))
+ (pcase (list value initial comment-p)
+ (`("" nil ,_)
+ (ding))
+ (`("" ,_ ,_)
+ (magit-delete-line))
+ (_
+ (if initial
+ (magit-delete-line)
+ (forward-line))
+ (insert (concat action " " value
+ (and (equal value initial)
+ trailer
+ (concat " " trailer))
+ "\n"))
+ (unless git-rebase-auto-advance
+ (forward-line -1))))))
+
+(defun git-rebase-exec (arg)
+ "Insert a shell command to be run after the current commit.
+
+If there already is such a command on the current line, then edit
+that instead. With a prefix argument insert a new command even
+when there already is one on the current line. With empty input
+remove the command on the current line, if any."
+ (interactive "P")
+ (git-rebase-set-noncommit-action
+ "exec"
+ (lambda (initial) (read-shell-command "Execute: " initial))
+ arg))
+
+(defun git-rebase-label (arg)
+ "Add a label after the current commit.
+If there already is a label on the current line, then edit that
+instead. With a prefix argument, insert a new label even when
+there is already a label on the current line. With empty input,
+remove the label on the current line, if any."
+ (interactive "P")
+ (git-rebase-set-noncommit-action
+ "label"
+ (lambda (initial)
+ (read-from-minibuffer
+ "Label: " initial magit-minibuffer-local-ns-map))
+ arg))
+
+(defun git-rebase-buffer-labels ()
+ (let (labels)
+ (save-excursion
+ (goto-char (point-min))
+ (while (re-search-forward "^\\(?:l\\|label\\) \\([^ \n]+\\)" nil t)
+ (push (match-string-no-properties 1) labels)))
+ (nreverse labels)))
+
+(defun git-rebase-reset (arg)
+ "Reset the current HEAD to a label.
+If there already is a reset command on the current line, then
+edit that instead. With a prefix argument, insert a new reset
+line even when point is already on a reset line. With empty
+input, remove the reset command on the current line, if any."
+ (interactive "P")
+ (git-rebase-set-noncommit-action
+ "reset"
+ (lambda (initial)
+ (or (magit-completing-read "Label" (git-rebase-buffer-labels)
+ nil t initial)
+ ""))
+ arg))
+
+(defun git-rebase-merge (arg)
+ "Add a merge command after the current commit.
+If there is already a merge command on the current line, then
+replace that command instead. With a prefix argument, insert a
+new merge command even when there is already one on the current
+line. With empty input, remove the merge command on the current
+line, if any."
+ (interactive "P")
+ (git-rebase-set-noncommit-action
+ "merge"
+ (lambda (_)
+ (or (magit-completing-read "Merge" (git-rebase-buffer-labels))
+ ""))
+ arg))
+
+(defun git-rebase-merge-toggle-editmsg ()
+ "Toggle whether an editor is invoked when performing the merge at point.
+When a merge command uses a lower-case -c, the message for the
+specified commit will be opened in an editor before creating the
+commit. For an upper-case -C, the message will be used as is."
+ (interactive)
+ (with-slots (action-type target action-options trailer)
+ (git-rebase-current-line)
+ (if (eq action-type 'merge)
+ (let ((inhibit-read-only t))
+ (magit-delete-line)
+ (insert
+ (format "merge %s %s %s\n"
+ (replace-regexp-in-string
+ "-[cC]" (lambda (c)
+ (if (equal c "-c") "-C" "-c"))
+ action-options t t)
+ target
+ trailer)))
+ (ding))))
+
+(defun git-rebase-set-bare-action (action arg)
+ (goto-char (line-beginning-position))
+ (with-slots ((ln-action action) comment-p)
+ (git-rebase-current-line)
+ (let ((same-action-p (equal action ln-action))
+ (inhibit-read-only t))
+ (when (or arg
+ (not ln-action)
+ (not same-action-p)
+ (and same-action-p comment-p))
+ (unless (or arg (not same-action-p))
+ (magit-delete-line))
+ (insert action ?\n)
+ (unless git-rebase-auto-advance
+ (forward-line -1))))))
+
+(defun git-rebase-noop (&optional arg)
+ "Add noop action at point.
+
+If the current line already contains a noop action, leave it
+unchanged. If there is a commented noop action present, remove
+the comment. Otherwise add a new noop action. With a prefix
+argument insert a new noop action regardless of what is already
+present on the current line.
+
+A noop action can be used to make git perform a rebase even if
+no commits are selected. Without the noop action present, git
+would see an empty file and therefore do nothing."
+ (interactive "P")
+ (git-rebase-set-bare-action "noop" arg))
+
+(defun git-rebase-break (&optional arg)
+ "Add break action at point.
+
+If there is a commented break action present, remove the comment.
+If the current line already contains a break action, add another
+break action only if a prefix argument is given.
+
+A break action can be used to interrupt the rebase at the
+specified point. It is particularly useful for pausing before
+the first commit in the sequence. For other cases, the
+equivalent behavior can be achieved with `git-rebase-edit'."
+ (interactive "P")
+ (git-rebase-set-bare-action "break" arg))
+
+(defun git-rebase-undo (&optional arg)
+ "Undo some previous changes.
+Like `undo' but works in read-only buffers."
+ (interactive "P")
+ (let ((inhibit-read-only t))
+ (undo arg)))
+
+(defun git-rebase--show-commit (&optional scroll)
+ (let ((disable-magit-save-buffers t))
+ (save-excursion
+ (goto-char (line-beginning-position))
+ (--if-let (with-slots (action-type target) (git-rebase-current-line)
+ (and (eq action-type 'commit)
+ target))
+ (pcase scroll
+ (`up (magit-diff-show-or-scroll-up))
+ (`down (magit-diff-show-or-scroll-down))
+ (_ (apply #'magit-show-commit it
+ (magit-diff-arguments 'magit-revision-mode))))
+ (ding)))))
+
+(defun git-rebase-show-commit ()
+ "Show the commit on the current line if any."
+ (interactive)
+ (git-rebase--show-commit))
+
+(defun git-rebase-show-or-scroll-up ()
+ "Update the commit buffer for commit on current line.
+
+Either show the commit at point in the appropriate buffer, or if
+that buffer is already being displayed in the current frame and
+contains information about that commit, then instead scroll the
+buffer up."
+ (interactive)
+ (git-rebase--show-commit 'up))
+
+(defun git-rebase-show-or-scroll-down ()
+ "Update the commit buffer for commit on current line.
+
+Either show the commit at point in the appropriate buffer, or if
+that buffer is already being displayed in the current frame and
+contains information about that commit, then instead scroll the
+buffer down."
+ (interactive)
+ (git-rebase--show-commit 'down))
+
+(defun git-rebase-backward-line (&optional n)
+ "Move N lines backward (forward if N is negative).
+Like `forward-line' but go into the opposite direction."
+ (interactive "p")
+ (forward-line (- (or n 1))))
+
+;;; Mode
+
+;;;###autoload
+(define-derived-mode git-rebase-mode special-mode "Git Rebase"
+ "Major mode for editing of a Git rebase file.
+
+Rebase files are generated when you run 'git rebase -i' or run
+`magit-interactive-rebase'. They describe how Git should perform
+the rebase. See the documentation for git-rebase (e.g., by
+running 'man git-rebase' at the command line) for details."
+ :group 'git-rebase
+ (setq comment-start (or (magit-get "core.commentChar") "#"))
+ (setq git-rebase-comment-re (concat "^" (regexp-quote comment-start)))
+ (setq font-lock-defaults (list (git-rebase-mode-font-lock-keywords) t t))
+ (unless git-rebase-show-instructions
+ (let ((inhibit-read-only t))
+ (flush-lines git-rebase-comment-re)))
+ (unless with-editor-mode
+ ;; Maybe already enabled when using `shell-command' or an Emacs shell.
+ (with-editor-mode 1))
+ (when git-rebase-confirm-cancel
+ (add-hook 'with-editor-cancel-query-functions
+ 'git-rebase-cancel-confirm nil t))
+ (setq-local redisplay-highlight-region-function 'git-rebase-highlight-region)
+ (setq-local redisplay-unhighlight-region-function 'git-rebase-unhighlight-region)
+ (add-hook 'with-editor-pre-cancel-hook 'git-rebase-autostash-save nil t)
+ (add-hook 'with-editor-post-cancel-hook 'git-rebase-autostash-apply nil t)
+ (setq imenu-prev-index-position-function
+ #'magit-imenu--rebase-prev-index-position-function)
+ (setq imenu-extract-index-name-function
+ #'magit-imenu--rebase-extract-index-name-function)
+ (when (boundp 'save-place)
+ (setq save-place nil)))
+
+(defun git-rebase-cancel-confirm (force)
+ (or (not (buffer-modified-p))
+ force
+ (magit-confirm 'abort-rebase "Abort this rebase" nil 'noabort)))
+
+(defun git-rebase-autostash-save ()
+ (--when-let (magit-file-line (magit-git-dir "rebase-merge/autostash"))
+ (push (cons 'stash it) with-editor-cancel-alist)))
+
+(defun git-rebase-autostash-apply ()
+ (--when-let (cdr (assq 'stash with-editor-cancel-alist))
+ (magit-stash-apply it)))
+
+(defun git-rebase-match-comment-line (limit)
+ (re-search-forward (concat git-rebase-comment-re ".*") limit t))
+
+(defun git-rebase-mode-font-lock-keywords ()
+ "Font lock keywords for Git-Rebase mode."
+ `((,(concat "^" (cdr (assq 'commit git-rebase-line-regexps)))
+ (1 'font-lock-keyword-face)
+ (3 'git-rebase-hash)
+ (4 'git-rebase-description))
+ (,(concat "^" (cdr (assq 'exec git-rebase-line-regexps)))
+ (1 'font-lock-keyword-face)
+ (3 'git-rebase-description))
+ (,(concat "^" (cdr (assq 'bare git-rebase-line-regexps)))
+ (1 'font-lock-keyword-face))
+ (,(concat "^" (cdr (assq 'label git-rebase-line-regexps)))
+ (1 'font-lock-keyword-face)
+ (3 'git-rebase-label)
+ (4 'font-lock-comment-face))
+ ("^\\(m\\(?:erge\\)?\\) -[Cc] \\([^ \n]+\\) \\([^ \n]+\\)\\( #.*\\)?"
+ (1 'font-lock-keyword-face)
+ (2 'git-rebase-hash)
+ (3 'git-rebase-label)
+ (4 'font-lock-comment-face))
+ ("^\\(m\\(?:erge\\)?\\) \\([^ \n]+\\)"
+ (1 'font-lock-keyword-face)
+ (2 'git-rebase-label))
+ (,(concat git-rebase-comment-re " *"
+ (cdr (assq 'commit git-rebase-line-regexps)))
+ 0 'git-rebase-killed-action t)
+ (git-rebase-match-comment-line 0 'font-lock-comment-face)
+ ("\\[[^[]*\\]"
+ 0 'magit-keyword t)
+ ("\\(?:fixup!\\|squash!\\)"
+ 0 'magit-keyword-squash t)
+ (,(format "^%s Rebase \\([^ ]*\\) onto \\([^ ]*\\)" comment-start)
+ (1 'git-rebase-comment-hash t)
+ (2 'git-rebase-comment-hash t))
+ (,(format "^%s \\(Commands:\\)" comment-start)
+ (1 'git-rebase-comment-heading t))
+ (,(format "^%s Branch \\(.*\\)" comment-start)
+ (1 'git-rebase-label t))))
+
+(defun git-rebase-mode-show-keybindings ()
+ "Modify the \"Commands:\" section of the comment Git generates
+at the bottom of the file so that in place of the one-letter
+abbreviation for the command, it shows the command's keybinding.
+By default, this is the same except for the \"pick\" command."
+ (let ((inhibit-read-only t))
+ (save-excursion
+ (goto-char (point-min))
+ (when (and git-rebase-show-instructions
+ (re-search-forward
+ (concat git-rebase-comment-re "\\s-+p, pick")
+ nil t))
+ (goto-char (line-beginning-position))
+ (pcase-dolist (`(,cmd . ,desc) git-rebase-command-descriptions)
+ (insert (format "%s %-8s %s\n"
+ comment-start
+ (substitute-command-keys (format "\\[%s]" cmd))
+ desc)))
+ (while (re-search-forward (concat git-rebase-comment-re
+ "\\( ?\\)\\([^\n,],\\) "
+ "\\([^\n ]+\\) ")
+ nil t)
+ (let ((cmd (intern (concat "git-rebase-" (match-string 3)))))
+ (if (not (fboundp cmd))
+ (delete-region (line-beginning-position) (1+ (line-end-position)))
+ (replace-match " " t t nil 1)
+ (replace-match
+ (format "%-8s"
+ (mapconcat #'key-description
+ (--remove (eq (elt it 0) 'menu-bar)
+ (reverse (where-is-internal
+ cmd git-rebase-mode-map)))
+ ", "))
+ t t nil 2))))))))
+
+(add-hook 'git-rebase-mode-hook 'git-rebase-mode-show-keybindings t)
+
+(defun git-rebase-mode-disable-before-save-hook ()
+ (set (make-local-variable 'before-save-hook) nil))
+
+(add-hook 'git-rebase-mode-hook 'git-rebase-mode-disable-before-save-hook)
+
+;;;###autoload
+(defconst git-rebase-filename-regexp "/git-rebase-todo\\'")
+;;;###autoload
+(add-to-list 'auto-mode-alist
+ (cons git-rebase-filename-regexp 'git-rebase-mode))
+
+(add-to-list 'with-editor-server-window-alist
+ (cons git-rebase-filename-regexp 'switch-to-buffer))
+
+(eval-after-load 'recentf
+ '(add-to-list 'recentf-exclude git-rebase-filename-regexp))
+
+(add-to-list 'with-editor-file-name-history-exclude git-rebase-filename-regexp)
+
+;;; _
+(provide 'git-rebase)
+;;; git-rebase.el ends here
--- /dev/null
+;;; magit-apply.el --- apply Git diffs -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements commands for applying Git diffs or parts
+;; of such a diff. The supported "apply variants" are apply, stage,
+;; unstage, discard, and reverse - more than Git itself knows about,
+;; at least at the porcelain level.
+
+;;; Code:
+
+(require 'magit-core)
+(require 'magit-diff)
+(require 'magit-wip)
+
+(require 'transient) ; See #3732.
+
+;; For `magit-apply'
+(declare-function magit-am "magit-sequence" ())
+(declare-function magit-patch-apply "magit-files" ())
+;; For `magit-discard-files'
+(declare-function magit-checkout-stage "magit-merge" (file arg))
+(declare-function magit-checkout-read-stage "magit-merge" (file))
+(defvar auto-revert-verbose)
+;; For `magit-stage-untracked'
+(declare-function magit-submodule-add-1 "magit-submodule"
+ (url &optional path name args))
+(declare-function magit-submodule-read-name-for-path "magit-submodule"
+ (path &optional prefer-short))
+(declare-function borg--maybe-absorb-gitdir "borg" (pkg))
+(declare-function borg--sort-submodule-sections "borg" (file))
+(declare-function borg-assimilate "borg" (package url &optional partially))
+(defvar borg-user-emacs-directory)
+
+;;; Options
+
+(defcustom magit-delete-by-moving-to-trash t
+ "Whether Magit uses the system's trash can.
+
+You should absolutely not disable this and also remove `discard'
+from `magit-no-confirm'. You shouldn't do that even if you have
+all of the Magit-Wip modes enabled, because those modes do not
+track any files that are not tracked in the proper branch."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-essentials
+ :type 'boolean)
+
+(defcustom magit-unstage-committed t
+ "Whether unstaging a committed change reverts it instead.
+
+A committed change cannot be unstaged, because staging and
+unstaging are actions that are concerned with the differences
+between the index and the working tree, not with committed
+changes.
+
+If this option is non-nil (the default), then typing \"u\"
+\(`magit-unstage') on a committed change, causes it to be
+reversed in the index but not the working tree. For more
+information see command `magit-reverse-in-index'."
+ :package-version '(magit . "2.4.1")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-reverse-atomically nil
+ "Whether to reverse changes atomically.
+
+If some changes can be reversed while others cannot, then nothing
+is reversed if the value of this option is non-nil. But when it
+is nil, then the changes that can be reversed are reversed and
+for the other changes diff files are created that contain the
+rejected reversals."
+ :package-version '(magit . "2.7.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-post-stage-hook nil
+ "Hook run after staging changes.
+This hook is run by `magit-refresh' if `this-command'
+is a member of `magit-post-stage-hook-commands'."
+ :package-version '(magit . "2.90.0")
+ :group 'magit-commands
+ :type 'hook)
+
+(defvar magit-post-stage-hook-commands
+ '(magit-stage magit-stage-file magit-stage-modified))
+
+(defcustom magit-post-unstage-hook nil
+ "Hook run after unstaging changes.
+This hook is run by `magit-refresh' if `this-command'
+is a member of `magit-post-unstage-hook-commands'."
+ :package-version '(magit . "2.90.0")
+ :group 'magit-commands
+ :type 'hook)
+
+(defvar magit-post-unstage-hook-commands
+ '(magit-unstage magit-unstage-file magit-unstage-all))
+
+;;; Commands
+;;;; Apply
+
+(defun magit-apply (&rest args)
+ "Apply the change at point to the working tree.
+With a prefix argument fallback to a 3-way merge. Doing
+so causes the change to be applied to the index as well."
+ (interactive (and current-prefix-arg (list "--3way")))
+ (--when-let (magit-apply--get-selection)
+ (pcase (list (magit-diff-type) (magit-diff-scope))
+ (`(,(or `unstaged `staged) ,_)
+ (user-error "Change is already in the working tree"))
+ (`(untracked ,(or `file `files))
+ (call-interactively 'magit-am))
+ (`(,_ region) (magit-apply-region it args))
+ (`(,_ hunk) (magit-apply-hunk it args))
+ (`(,_ hunks) (magit-apply-hunks it args))
+ (`(rebase-sequence file)
+ (call-interactively 'magit-patch-apply))
+ (`(,_ file) (magit-apply-diff it args))
+ (`(,_ files) (magit-apply-diffs it args)))))
+
+(defun magit-apply--section-content (section)
+ (buffer-substring-no-properties (if (magit-hunk-section-p section)
+ (oref section start)
+ (oref section content))
+ (oref section end)))
+
+(defun magit-apply-diffs (sections &rest args)
+ (setq sections (magit-apply--get-diffs sections))
+ (magit-apply-patch sections args
+ (mapconcat
+ (lambda (s)
+ (concat (magit-diff-file-header s)
+ (magit-apply--section-content s)))
+ sections "")))
+
+(defun magit-apply-diff (section &rest args)
+ (setq section (car (magit-apply--get-diffs (list section))))
+ (magit-apply-patch section args
+ (concat (magit-diff-file-header section)
+ (magit-apply--section-content section))))
+
+(defun magit-apply--adjust-hunk-new-starts (hunks)
+ "Adjust new line numbers in headers of HUNKS for partial application.
+HUNKS should be a list of ordered, contiguous hunks to be applied
+from a file. For example, if there is a sequence of hunks with
+the headers
+
+ @@ -2,6 +2,7 @@
+ @@ -10,6 +11,7 @@
+ @@ -18,6 +20,7 @@
+
+and only the second and third are to be applied, they would be
+adjusted as \"@@ -10,6 +10,7 @@\" and \"@@ -18,6 +19,7 @@\"."
+ (let* ((first-hunk (car hunks))
+ (offset (if (string-match diff-hunk-header-re-unified first-hunk)
+ (- (string-to-number (match-string 3 first-hunk))
+ (string-to-number (match-string 1 first-hunk)))
+ (error "Hunk does not have expected header"))))
+ (if (= offset 0)
+ hunks
+ (mapcar (lambda (hunk)
+ (if (string-match diff-hunk-header-re-unified hunk)
+ (replace-match (number-to-string
+ (- (string-to-number (match-string 3 hunk))
+ offset))
+ t t hunk 3)
+ (error "Hunk does not have expected header")))
+ hunks))))
+
+(defun magit-apply--adjust-hunk-new-start (hunk)
+ (car (magit-apply--adjust-hunk-new-starts (list hunk))))
+
+(defun magit-apply-hunks (sections &rest args)
+ (let ((section (oref (car sections) parent)))
+ (when (string-match "^diff --cc" (oref section value))
+ (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
+ (magit-apply-patch
+ section args
+ (concat (oref section header)
+ (mapconcat #'identity
+ (magit-apply--adjust-hunk-new-starts
+ (mapcar #'magit-apply--section-content sections))
+ "")))))
+
+(defun magit-apply-hunk (section &rest args)
+ (when (string-match "^diff --cc" (magit-section-parent-value section))
+ (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
+ (magit-apply-patch (oref section parent) args
+ (concat (magit-diff-file-header section)
+ (magit-apply--adjust-hunk-new-start
+ (magit-apply--section-content section)))))
+
+(defun magit-apply-region (section &rest args)
+ (when (string-match "^diff --cc" (magit-section-parent-value section))
+ (user-error "Cannot un-/stage resolution hunks. Stage the whole file"))
+ (magit-apply-patch (oref section parent) args
+ (concat (magit-diff-file-header section)
+ (magit-apply--adjust-hunk-new-start
+ (magit-diff-hunk-region-patch section args)))))
+
+(defun magit-apply-patch (section:s args patch)
+ (let* ((files (if (atom section:s)
+ (list (oref section:s value))
+ (--map (oref it value) section:s)))
+ (command (symbol-name this-command))
+ (command (if (and command (string-match "^magit-\\([^-]+\\)" command))
+ (match-string 1 command)
+ "apply"))
+ (ignore-context (magit-diff-ignore-any-space-p)))
+ (unless (magit-diff-context-p)
+ (user-error "Not enough context to apply patch. Increase the context"))
+ (when (and magit-wip-before-change-mode (not inhibit-magit-refresh))
+ (magit-wip-commit-before-change files (concat " before " command)))
+ (with-temp-buffer
+ (insert patch)
+ (magit-run-git-with-input
+ "apply" args "-p0"
+ (and ignore-context "-C0")
+ "--ignore-space-change" "-"))
+ (unless inhibit-magit-refresh
+ (when magit-wip-after-apply-mode
+ (magit-wip-commit-after-apply files (concat " after " command)))
+ (magit-refresh))))
+
+(defun magit-apply--get-selection ()
+ (or (magit-region-sections '(hunk file module) t)
+ (let ((section (magit-current-section)))
+ (pcase (oref section type)
+ ((or `hunk `file `module) section)
+ ((or `staged `unstaged `untracked
+ `stashed-index `stashed-worktree `stashed-untracked)
+ (oref section children))
+ (_ (user-error "Cannot apply this, it's not a change"))))))
+
+(defun magit-apply--get-diffs (sections)
+ (magit-section-case
+ ([file diffstat]
+ (--map (or (magit-get-section
+ (append `((file . ,(oref it value)))
+ (magit-section-ident magit-root-section)))
+ (error "Cannot get required diff headers"))
+ sections))
+ (t sections)))
+
+(defun magit-apply--diff-ignores-whitespace-p ()
+ (and (cl-intersection magit-buffer-diff-args
+ '("--ignore-space-at-eol"
+ "--ignore-space-change"
+ "--ignore-all-space"
+ "--ignore-blank-lines")
+ :test #'equal)
+ t))
+
+;;;; Stage
+
+(defun magit-stage (&optional intent)
+ "Add the change at point to the staging area.
+With a prefix argument, INTENT, and an untracked file (or files)
+at point, stage the file but not its content."
+ (interactive "P")
+ (--if-let (and (derived-mode-p 'magit-mode) (magit-apply--get-selection))
+ (pcase (list (magit-diff-type)
+ (magit-diff-scope)
+ (magit-apply--diff-ignores-whitespace-p))
+ (`(untracked ,_ ,_) (magit-stage-untracked intent))
+ (`(unstaged region ,_) (magit-apply-region it "--cached"))
+ (`(unstaged hunk ,_) (magit-apply-hunk it "--cached"))
+ (`(unstaged hunks ,_) (magit-apply-hunks it "--cached"))
+ (`(unstaged file t) (magit-apply-diff it "--cached"))
+ (`(unstaged files t) (magit-apply-diffs it "--cached"))
+ (`(unstaged list t) (magit-apply-diffs it "--cached"))
+ (`(unstaged file nil) (magit-stage-1 "-u" (list (oref it value))))
+ (`(unstaged files nil) (magit-stage-1 "-u" (magit-region-values nil t)))
+ (`(unstaged list nil) (magit-stage-modified))
+ (`(staged ,_ ,_) (user-error "Already staged"))
+ (`(committed ,_ ,_) (user-error "Cannot stage committed changes"))
+ (`(undefined ,_ ,_) (user-error "Cannot stage this change")))
+ (call-interactively 'magit-stage-file)))
+
+;;;###autoload
+(defun magit-stage-file (file)
+ "Stage all changes to FILE.
+With a prefix argument or when there is no file at point ask for
+the file to be staged. Otherwise stage the file at point without
+requiring confirmation."
+ (interactive
+ (let* ((atpoint (magit-section-value-if 'file))
+ (current (magit-file-relative-name))
+ (choices (nconc (magit-unstaged-files)
+ (magit-untracked-files)))
+ (default (car (member (or atpoint current) choices))))
+ (list (if (or current-prefix-arg (not default))
+ (magit-completing-read "Stage file" choices
+ nil t nil nil default)
+ default))))
+ (magit-with-toplevel
+ (magit-stage-1 nil (list file))))
+
+;;;###autoload
+(defun magit-stage-modified (&optional all)
+ "Stage all changes to files modified in the worktree.
+Stage all new content of tracked files and remove tracked files
+that no longer exist in the working tree from the index also.
+With a prefix argument also stage previously untracked (but not
+ignored) files."
+ (interactive "P")
+ (when (magit-anything-staged-p)
+ (magit-confirm 'stage-all-changes))
+ (magit-with-toplevel
+ (magit-stage-1 (if all "--all" "-u") magit-buffer-diff-files)))
+
+(defun magit-stage-1 (arg &optional files)
+ (magit-wip-commit-before-change files " before stage")
+ (magit-run-git "add" arg (if files (cons "--" files) "."))
+ (when magit-auto-revert-mode
+ (mapc #'magit-turn-on-auto-revert-mode-if-desired files))
+ (magit-wip-commit-after-apply files " after stage"))
+
+(defun magit-stage-untracked (&optional intent)
+ (let* ((section (magit-current-section))
+ (files (pcase (magit-diff-scope)
+ (`file (list (oref section value)))
+ (`files (magit-region-values nil t))
+ (`list (magit-untracked-files))))
+ plain repos)
+ (dolist (file files)
+ (if (and (not (file-symlink-p file))
+ (magit-git-repo-p file t))
+ (push file repos)
+ (push file plain)))
+ (magit-wip-commit-before-change files " before stage")
+ (when plain
+ (magit-run-git "add" (and intent "--intent-to-add")
+ "--" plain)
+ (when magit-auto-revert-mode
+ (mapc #'magit-turn-on-auto-revert-mode-if-desired plain)))
+ (dolist (repo repos)
+ (save-excursion
+ (goto-char (oref (magit-get-section
+ `((file . ,repo) (untracked) (status)))
+ start))
+ (let* ((topdir (magit-toplevel))
+ (url (let ((default-directory
+ (file-name-as-directory (expand-file-name repo))))
+ (or (magit-get "remote" (magit-get-some-remote) "url")
+ (concat (file-name-as-directory ".") repo))))
+ (package
+ (and (equal (bound-and-true-p borg-user-emacs-directory)
+ topdir)
+ (file-name-nondirectory (directory-file-name repo)))))
+ (if (and package
+ (y-or-n-p (format "Also assimilate `%s' drone?" package)))
+ (borg-assimilate package url)
+ (magit-submodule-add-1
+ url repo (magit-submodule-read-name-for-path repo package))
+ (when package
+ (borg--sort-submodule-sections
+ (expand-file-name ".gitmodules" topdir))
+ (let ((default-directory borg-user-emacs-directory))
+ (borg--maybe-absorb-gitdir package)))))))
+ (magit-wip-commit-after-apply files " after stage")))
+
+;;;; Unstage
+
+(defun magit-unstage ()
+ "Remove the change at point from the staging area."
+ (interactive)
+ (--when-let (magit-apply--get-selection)
+ (pcase (list (magit-diff-type)
+ (magit-diff-scope)
+ (magit-apply--diff-ignores-whitespace-p))
+ (`(untracked ,_ ,_) (user-error "Cannot unstage untracked changes"))
+ (`(unstaged file ,_) (magit-unstage-intent (list (oref it value))))
+ (`(unstaged files ,_) (magit-unstage-intent (magit-region-values nil t)))
+ (`(unstaged ,_ ,_) (user-error "Already unstaged"))
+ (`(staged region ,_) (magit-apply-region it "--reverse" "--cached"))
+ (`(staged hunk ,_) (magit-apply-hunk it "--reverse" "--cached"))
+ (`(staged hunks ,_) (magit-apply-hunks it "--reverse" "--cached"))
+ (`(staged file t) (magit-apply-diff it "--reverse" "--cached"))
+ (`(staged files t) (magit-apply-diffs it "--reverse" "--cached"))
+ (`(staged list t) (magit-apply-diffs it "--reverse" "--cached"))
+ (`(staged file nil) (magit-unstage-1 (list (oref it value))))
+ (`(staged files nil) (magit-unstage-1 (magit-region-values nil t)))
+ (`(staged list nil) (magit-unstage-all))
+ (`(committed ,_ ,_) (if magit-unstage-committed
+ (magit-reverse-in-index)
+ (user-error "Cannot unstage committed changes")))
+ (`(undefined ,_ ,_) (user-error "Cannot unstage this change")))))
+
+;;;###autoload
+(defun magit-unstage-file (file)
+ "Unstage all changes to FILE.
+With a prefix argument or when there is no file at point ask for
+the file to be unstaged. Otherwise unstage the file at point
+without requiring confirmation."
+ (interactive
+ (let* ((atpoint (magit-section-value-if 'file))
+ (current (magit-file-relative-name))
+ (choices (magit-staged-files))
+ (default (car (member (or atpoint current) choices))))
+ (list (if (or current-prefix-arg (not default))
+ (magit-completing-read "Unstage file" choices
+ nil t nil nil default)
+ default))))
+ (magit-with-toplevel
+ (magit-unstage-1 (list file))))
+
+(defun magit-unstage-1 (files)
+ (magit-wip-commit-before-change files " before unstage")
+ (if (magit-no-commit-p)
+ (magit-run-git "rm" "--cached" "--" files)
+ (magit-run-git "reset" "HEAD" "--" files))
+ (magit-wip-commit-after-apply files " after unstage"))
+
+(defun magit-unstage-intent (files)
+ (if-let ((staged (magit-staged-files))
+ (intent (--filter (member it staged) files)))
+ (magit-unstage-1 intent)
+ (user-error "Already unstaged")))
+
+;;;###autoload
+(defun magit-unstage-all ()
+ "Remove all changes from the staging area."
+ (interactive)
+ (when (or (magit-anything-unstaged-p)
+ (magit-untracked-files))
+ (magit-confirm 'unstage-all-changes))
+ (magit-wip-commit-before-change nil " before unstage")
+ (magit-run-git "reset" "HEAD" "--" magit-buffer-diff-files)
+ (magit-wip-commit-after-apply nil " after unstage"))
+
+;;;; Discard
+
+(defun magit-discard ()
+ "Remove the change at point."
+ (interactive)
+ (--when-let (magit-apply--get-selection)
+ (pcase (list (magit-diff-type) (magit-diff-scope))
+ (`(committed ,_) (user-error "Cannot discard committed changes"))
+ (`(undefined ,_) (user-error "Cannot discard this change"))
+ (`(,_ region) (magit-discard-region it))
+ (`(,_ hunk) (magit-discard-hunk it))
+ (`(,_ hunks) (magit-discard-hunks it))
+ (`(,_ file) (magit-discard-file it))
+ (`(,_ files) (magit-discard-files it))
+ (`(,_ list) (magit-discard-files it)))))
+
+(defun magit-discard-region (section)
+ (magit-confirm 'discard "Discard region")
+ (magit-discard-apply section 'magit-apply-region))
+
+(defun magit-discard-hunk (section)
+ (magit-confirm 'discard "Discard hunk")
+ (magit-discard-apply section 'magit-apply-hunk))
+
+(defun magit-discard-apply (section apply)
+ (if (eq (magit-diff-type section) 'unstaged)
+ (funcall apply section "--reverse")
+ (if (magit-anything-unstaged-p
+ nil (if (magit-file-section-p section)
+ (oref section value)
+ (magit-section-parent-value section)))
+ (progn (let ((inhibit-magit-refresh t))
+ (funcall apply section "--reverse" "--cached")
+ (funcall apply section "--reverse" "--reject"))
+ (magit-refresh))
+ (funcall apply section "--reverse" "--index"))))
+
+(defun magit-discard-hunks (sections)
+ (magit-confirm 'discard (format "Discard %s hunks from %s"
+ (length sections)
+ (magit-section-parent-value (car sections))))
+ (magit-discard-apply-n sections 'magit-apply-hunks))
+
+(defun magit-discard-apply-n (sections apply)
+ (let ((section (car sections)))
+ (if (eq (magit-diff-type section) 'unstaged)
+ (funcall apply sections "--reverse")
+ (if (magit-anything-unstaged-p
+ nil (if (magit-file-section-p section)
+ (oref section value)
+ (magit-section-parent-value section)))
+ (progn (let ((inhibit-magit-refresh t))
+ (funcall apply sections "--reverse" "--cached")
+ (funcall apply sections "--reverse" "--reject"))
+ (magit-refresh))
+ (funcall apply sections "--reverse" "--index")))))
+
+(defun magit-discard-file (section)
+ (magit-discard-files (list section)))
+
+(defun magit-discard-files (sections)
+ (let ((auto-revert-verbose nil)
+ (type (magit-diff-type (car sections)))
+ (status (magit-file-status))
+ files delete resurrect rename discard discard-new resolve)
+ (dolist (section sections)
+ (let ((file (oref section value)))
+ (push file files)
+ (pcase (cons (pcase type
+ (`staged ?X)
+ (`unstaged ?Y)
+ (`untracked ?Z))
+ (cddr (assoc file status)))
+ (`(?Z) (dolist (f (magit-untracked-files nil file))
+ (push f delete)))
+ ((or `(?Z ?? ??) `(?Z ?! ?!)) (push file delete))
+ ((or `(?Z ?D ? ) `(,_ ?D ?D)) (push file delete))
+ ((or `(,_ ?U ,_) `(,_ ,_ ?U)) (push file resolve))
+ (`(,_ ?A ?A) (push file resolve))
+ (`(?X ?M ,(or ? ?M ?D)) (push section discard))
+ (`(?Y ,_ ?M ) (push section discard))
+ (`(?X ?A ?M ) (push file discard-new))
+ (`(?X ?C ?M ) (push file discard-new))
+ (`(?X ?A ,(or ? ?D)) (push file delete))
+ (`(?X ?C ,(or ? ?D)) (push file delete))
+ (`(?X ?D ,(or ? ?M )) (push file resurrect))
+ (`(?Y ,_ ?D ) (push file resurrect))
+ (`(?X ?R ,(or ? ?M ?D)) (push file rename)))))
+ (unwind-protect
+ (let ((inhibit-magit-refresh t))
+ (magit-wip-commit-before-change files " before discard")
+ (when resolve
+ (magit-discard-files--resolve (nreverse resolve)))
+ (when resurrect
+ (magit-discard-files--resurrect (nreverse resurrect)))
+ (when delete
+ (magit-discard-files--delete (nreverse delete) status))
+ (when rename
+ (magit-discard-files--rename (nreverse rename) status))
+ (when (or discard discard-new)
+ (magit-discard-files--discard (nreverse discard)
+ (nreverse discard-new)))
+ (magit-wip-commit-after-apply files " after discard"))
+ (magit-refresh))))
+
+(defun magit-discard-files--resolve (files)
+ (if-let ((arg (and (cdr files)
+ (magit-read-char-case
+ (format "For these %i files\n%s\ncheckout:\n"
+ (length files)
+ (mapconcat (lambda (file)
+ (concat " " file))
+ files "\n"))
+ t
+ (?o "[o]ur stage" "--ours")
+ (?t "[t]heir stage" "--theirs")
+ (?c "[c]onflict" "--merge")
+ (?i "decide [i]ndividually" nil)))))
+ (dolist (file files)
+ (magit-checkout-stage file arg))
+ (dolist (file files)
+ (magit-checkout-stage file (magit-checkout-read-stage file)))))
+
+(defun magit-discard-files--resurrect (files)
+ (magit-confirm-files 'resurrect files)
+ (if (eq (magit-diff-type) 'staged)
+ (magit-call-git "reset" "--" files)
+ (magit-call-git "checkout" "--" files)))
+
+(defun magit-discard-files--delete (files status)
+ (magit-confirm-files (if magit-delete-by-moving-to-trash 'trash 'delete)
+ files)
+ (let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash))
+ (dolist (file files)
+ (when (string-match-p "\\`\\\\?~" file)
+ (error "Refusing to delete %S, too dangerous" file))
+ (pcase (nth 3 (assoc file status))
+ ((guard (memq (magit-diff-type) '(unstaged untracked)))
+ (dired-delete-file file dired-recursive-deletes
+ magit-delete-by-moving-to-trash)
+ (dired-clean-up-after-deletion file))
+ (?\s (delete-file file t)
+ (magit-call-git "rm" "--cached" "--" file))
+ (?M (let ((temp (magit-git-string "checkout-index" "--temp" file)))
+ (string-match
+ (format "\\(.+?\\)\t%s" (regexp-quote file)) temp)
+ (rename-file (match-string 1 temp)
+ (setq temp (concat file ".~{index}~")))
+ (delete-file temp t))
+ (magit-call-git "rm" "--cached" "--force" "--" file))
+ (?D (magit-call-git "checkout" "--" file)
+ (delete-file file t)
+ (magit-call-git "rm" "--cached" "--force" "--" file))))))
+
+(defun magit-discard-files--rename (files status)
+ (magit-confirm 'rename "Undo rename %s" "Undo %i renames" nil
+ (mapcar (lambda (file)
+ (setq file (assoc file status))
+ (format "%s -> %s" (cadr file) (car file)))
+ files))
+ (dolist (file files)
+ (let ((orig (cadr (assoc file status))))
+ (if (file-exists-p file)
+ (progn
+ (--when-let (file-name-directory orig)
+ (make-directory it t))
+ (magit-call-git "mv" file orig))
+ (magit-call-git "rm" "--cached" "--" file)
+ (magit-call-git "reset" "--" orig)))))
+
+(defun magit-discard-files--discard (sections new-files)
+ (let ((files (--map (oref it value) sections)))
+ (magit-confirm-files 'discard (append files new-files)
+ (format "Discard %s changes in" (magit-diff-type)))
+ (if (eq (magit-diff-type (car sections)) 'unstaged)
+ (magit-call-git "checkout" "--" files)
+ (when new-files
+ (magit-call-git "add" "--" new-files)
+ (magit-call-git "reset" "--" new-files))
+ (let ((binaries (magit-binary-files "--cached")))
+ (when binaries
+ (setq sections
+ (--remove (member (oref it value) binaries)
+ sections)))
+ (cond ((= (length sections) 1)
+ (magit-discard-apply (car sections) 'magit-apply-diff))
+ (sections
+ (magit-discard-apply-n sections 'magit-apply-diffs)))
+ (when binaries
+ (let ((modified (magit-unstaged-files t)))
+ (setq binaries (--separate (member it modified) binaries)))
+ (when (cadr binaries)
+ (magit-call-git "reset" "--" (cadr binaries)))
+ (when (car binaries)
+ (user-error
+ (concat
+ "Cannot discard staged changes to binary files, "
+ "which also have unstaged changes. Unstage instead."))))))))
+
+;;;; Reverse
+
+(defun magit-reverse (&rest args)
+ "Reverse the change at point in the working tree.
+With a prefix argument fallback to a 3-way merge. Doing
+so causes the change to be applied to the index as well."
+ (interactive (and current-prefix-arg (list "--3way")))
+ (--when-let (magit-apply--get-selection)
+ (pcase (list (magit-diff-type) (magit-diff-scope))
+ (`(untracked ,_) (user-error "Cannot reverse untracked changes"))
+ (`(unstaged ,_) (user-error "Cannot reverse unstaged changes"))
+ (`(,_ region) (magit-reverse-region it args))
+ (`(,_ hunk) (magit-reverse-hunk it args))
+ (`(,_ hunks) (magit-reverse-hunks it args))
+ (`(,_ file) (magit-reverse-file it args))
+ (`(,_ files) (magit-reverse-files it args))
+ (`(,_ list) (magit-reverse-files it args)))))
+
+(defun magit-reverse-region (section args)
+ (magit-confirm 'reverse "Reverse region")
+ (magit-reverse-apply section 'magit-apply-region args))
+
+(defun magit-reverse-hunk (section args)
+ (magit-confirm 'reverse "Reverse hunk")
+ (magit-reverse-apply section 'magit-apply-hunk args))
+
+(defun magit-reverse-hunks (sections args)
+ (magit-confirm 'reverse
+ (format "Reverse %s hunks from %s"
+ (length sections)
+ (magit-section-parent-value (car sections))))
+ (magit-reverse-apply sections 'magit-apply-hunks args))
+
+(defun magit-reverse-file (section args)
+ (magit-reverse-files (list section) args))
+
+(defun magit-reverse-files (sections args)
+ (pcase-let ((`(,binaries ,sections)
+ (let ((bs (magit-binary-files
+ (cond ((derived-mode-p 'magit-revision-mode)
+ magit-buffer-range)
+ ((derived-mode-p 'magit-diff-mode)
+ magit-buffer-range)
+ (t
+ "--cached")))))
+ (--separate (member (oref it value) bs)
+ sections))))
+ (magit-confirm-files 'reverse (--map (oref it value) sections))
+ (cond ((= (length sections) 1)
+ (magit-reverse-apply (car sections) 'magit-apply-diff args))
+ (sections
+ (magit-reverse-apply sections 'magit-apply-diffs args)))
+ (when binaries
+ (user-error "Cannot reverse binary files"))))
+
+(defun magit-reverse-apply (section:s apply args)
+ (funcall apply section:s "--reverse" args
+ (and (not magit-reverse-atomically)
+ (not (member "--3way" args))
+ "--reject")))
+
+(defun magit-reverse-in-index (&rest args)
+ "Reverse the change at point in the index but not the working tree.
+
+Use this command to extract a change from `HEAD', while leaving
+it in the working tree, so that it can later be committed using
+a separate commit. A typical workflow would be:
+
+0. Optionally make sure that there are no uncommitted changes.
+1. Visit the `HEAD' commit and navigate to the change that should
+ not have been included in that commit.
+2. Type \"u\" (`magit-unstage') to reverse it in the index.
+ This assumes that `magit-unstage-committed-changes' is non-nil.
+3. Type \"c e\" to extend `HEAD' with the staged changes,
+ including those that were already staged before.
+4. Optionally stage the remaining changes using \"s\" or \"S\"
+ and then type \"c c\" to create a new commit."
+ (interactive)
+ (magit-reverse (cons "--cached" args)))
+
+;;; _
+(provide 'magit-apply)
+;;; magit-apply.el ends here
--- /dev/null
+;;; magit-autoloads.el --- automatically extracted autoloads
+;;
+;;; Code:
+
+(add-to-list 'load-path (directory-file-name
+ (or (file-name-directory #$) (car load-path))))
+
+\f
+;;;### (autoloads nil "git-rebase" "git-rebase.el" (0 0 0 0))
+;;; Generated autoloads from git-rebase.el
+
+(autoload 'git-rebase-current-line "git-rebase" "\
+Parse current line into a `git-rebase-action' instance.
+If the current line isn't recognized as a rebase line, an
+instance with all nil values is returned." nil nil)
+
+(autoload 'git-rebase-mode "git-rebase" "\
+Major mode for editing of a Git rebase file.
+
+Rebase files are generated when you run 'git rebase -i' or run
+`magit-interactive-rebase'. They describe how Git should perform
+the rebase. See the documentation for git-rebase (e.g., by
+running 'man git-rebase' at the command line) for details.
+
+\(fn)" t nil)
+
+(defconst git-rebase-filename-regexp "/git-rebase-todo\\'")
+
+(add-to-list 'auto-mode-alist (cons git-rebase-filename-regexp 'git-rebase-mode))
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "git-rebase" '("git-rebase-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit" "magit.el" (0 0 0 0))
+;;; Generated autoloads from magit.el
+
+(define-obsolete-variable-alias 'global-magit-file-mode 'magit-define-global-key-bindings "Magit 3.0.0")
+
+(defvar magit-define-global-key-bindings t "\
+Whether to bind some Magit commands in the global keymap.
+
+If this variable is non-nil, then the following bindings may
+be added to the global keymap. The default is t.
+
+key binding
+--- -------
+C-x g magit-status
+C-x M-g magit-dispatch
+C-c M-g magit-file-dispatch
+
+These bindings may be added when `after-init-hook' is called.
+Each binding is added if and only if at that time no other key
+is bound to the same command and no other command is bound to
+the same key. In other words we try to avoid adding bindings
+that are unnecessary, as well as bindings that conflict with
+other bindings.
+
+Adding the above bindings is delayed until `after-init-hook'
+is called to allow users to set the variable anywhere in their
+init file (without having to make sure to do so before `magit'
+is loaded or autoloaded) and to increase the likelihood that
+all the potentially conflicting user bindings have already
+been added.
+
+Setting this variable after the hook has already been called
+has no effect.
+
+We recommend that you bind \"C-c g\" instead of \"C-c M-g\" to
+`magit-file-dispatch'. The former is a much better binding
+but the \"C-c <letter>\" namespace is strictly reserved for
+users; preventing Magit from using it by default.
+
+Also see info node `(magit)Commands for Buffers Visiting Files'.")
+
+(custom-autoload 'magit-define-global-key-bindings "magit" t)
+
+(defun magit-maybe-define-global-key-bindings nil (when magit-define-global-key-bindings (let ((map (current-global-map))) (dolist (elt '(("C-x g" . magit-status) ("C-x M-g" . magit-dispatch) ("C-c M-g" . magit-file-dispatch))) (let ((key (kbd (car elt))) (def (cdr elt))) (unless (or (lookup-key map key) (where-is-internal def (make-sparse-keymap) t)) (define-key map key def)))))))
+
+(if after-init-time (magit-maybe-define-global-key-bindings) (add-hook 'after-init-hook 'magit-maybe-define-global-key-bindings t))
+ (autoload 'magit-dispatch "magit" nil t)
+ (autoload 'magit-run "magit" nil t)
+
+(autoload 'magit-git-command "magit" "\
+Execute COMMAND asynchronously; display output.
+
+Interactively, prompt for COMMAND in the minibuffer. \"git \" is
+used as initial input, but can be deleted to run another command.
+
+With a prefix argument COMMAND is run in the top-level directory
+of the current working tree, otherwise in `default-directory'.
+
+\(fn COMMAND)" t nil)
+
+(autoload 'magit-git-command-topdir "magit" "\
+Execute COMMAND asynchronously; display output.
+
+Interactively, prompt for COMMAND in the minibuffer. \"git \" is
+used as initial input, but can be deleted to run another command.
+
+COMMAND is run in the top-level directory of the current
+working tree.
+
+\(fn COMMAND)" t nil)
+
+(autoload 'magit-shell-command "magit" "\
+Execute COMMAND asynchronously; display output.
+
+Interactively, prompt for COMMAND in the minibuffer. With a
+prefix argument COMMAND is run in the top-level directory of
+the current working tree, otherwise in `default-directory'.
+
+\(fn COMMAND)" t nil)
+
+(autoload 'magit-shell-command-topdir "magit" "\
+Execute COMMAND asynchronously; display output.
+
+Interactively, prompt for COMMAND in the minibuffer. COMMAND
+is run in the top-level directory of the current working tree.
+
+\(fn COMMAND)" t nil)
+
+(autoload 'magit-version "magit" "\
+Return the version of Magit currently in use.
+If optional argument PRINT-DEST is non-nil, output
+stream (interactively, the echo area, or the current buffer with
+a prefix argument), also print the used versions of Magit, Git,
+and Emacs to it.
+
+\(fn &optional PRINT-DEST)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-apply" "magit-apply.el" (0 0 0 0))
+;;; Generated autoloads from magit-apply.el
+
+(autoload 'magit-stage-file "magit-apply" "\
+Stage all changes to FILE.
+With a prefix argument or when there is no file at point ask for
+the file to be staged. Otherwise stage the file at point without
+requiring confirmation.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-stage-modified "magit-apply" "\
+Stage all changes to files modified in the worktree.
+Stage all new content of tracked files and remove tracked files
+that no longer exist in the working tree from the index also.
+With a prefix argument also stage previously untracked (but not
+ignored) files.
+
+\(fn &optional ALL)" t nil)
+
+(autoload 'magit-unstage-file "magit-apply" "\
+Unstage all changes to FILE.
+With a prefix argument or when there is no file at point ask for
+the file to be unstaged. Otherwise unstage the file at point
+without requiring confirmation.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-unstage-all "magit-apply" "\
+Remove all changes from the staging area." t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-apply" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-autorevert" "magit-autorevert.el" (0
+;;;;;; 0 0 0))
+;;; Generated autoloads from magit-autorevert.el
+
+(put 'magit-auto-revert-mode 'globalized-minor-mode t)
+
+(defvar magit-auto-revert-mode (not (or global-auto-revert-mode noninteractive)) "\
+Non-nil if Magit-Auto-Revert mode is enabled.
+See the `magit-auto-revert-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `magit-auto-revert-mode'.")
+
+(custom-autoload 'magit-auto-revert-mode "magit-autorevert" nil)
+
+(autoload 'magit-auto-revert-mode "magit-autorevert" "\
+Toggle Auto-Revert mode in all buffers.
+With prefix ARG, enable Magit-Auto-Revert mode if ARG is positive;
+otherwise, disable it. If called from Lisp, enable the mode if
+ARG is omitted or nil.
+
+Auto-Revert mode is enabled in all buffers where
+`magit-turn-on-auto-revert-mode-if-desired' would do it.
+See `auto-revert-mode' for more information on Auto-Revert mode.
+
+\(fn &optional ARG)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-autorevert" '("auto-revert-buffer" "magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-bisect" "magit-bisect.el" (0 0 0 0))
+;;; Generated autoloads from magit-bisect.el
+ (autoload 'magit-bisect "magit-bisect" nil t)
+
+(autoload 'magit-bisect-start "magit-bisect" "\
+Start a bisect session.
+
+Bisecting a bug means to find the commit that introduced it.
+This command starts such a bisect session by asking for a known
+good and a known bad commit. To move the session forward use the
+other actions from the bisect transient command (\\<magit-status-mode-map>\\[magit-bisect]).
+
+\(fn BAD GOOD ARGS)" t nil)
+
+(autoload 'magit-bisect-reset "magit-bisect" "\
+After bisecting, cleanup bisection state and return to original `HEAD'." t nil)
+
+(autoload 'magit-bisect-good "magit-bisect" "\
+While bisecting, mark the current commit as good.
+Use this after you have asserted that the commit does not contain
+the bug in question." t nil)
+
+(autoload 'magit-bisect-bad "magit-bisect" "\
+While bisecting, mark the current commit as bad.
+Use this after you have asserted that the commit does contain the
+bug in question." t nil)
+
+(autoload 'magit-bisect-mark "magit-bisect" "\
+While bisecting, mark the current commit with a bisect term.
+During a bisect using alternate terms, commits can still be
+marked with `magit-bisect-good' and `magit-bisect-bad', as those
+commands map to the correct term (\"good\" to --term-old's value
+and \"bad\" to --term-new's). However, in some cases, it can be
+difficult to keep that mapping straight in your head; this
+command provides an interface that exposes the underlying terms." t nil)
+
+(autoload 'magit-bisect-skip "magit-bisect" "\
+While bisecting, skip the current commit.
+Use this if for some reason the current commit is not a good one
+to test. This command lets Git choose a different one." t nil)
+
+(autoload 'magit-bisect-run "magit-bisect" "\
+Bisect automatically by running commands after each step.
+
+Unlike `git bisect run' this can be used before bisecting has
+begun. In that case it behaves like `git bisect start; git
+bisect run'.
+
+\(fn CMDLINE &optional BAD GOOD ARGS)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-bisect" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-blame" "magit-blame.el" (0 0 0 0))
+;;; Generated autoloads from magit-blame.el
+ (autoload 'magit-blame-echo "magit-blame" nil t)
+ (autoload 'magit-blame-addition "magit-blame" nil t)
+ (autoload 'magit-blame-removal "magit-blame" nil t)
+ (autoload 'magit-blame-reverse "magit-blame" nil t)
+ (autoload 'magit-blame "magit-blame" nil t)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-blame" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-bookmark" "magit-bookmark.el" (0 0 0
+;;;;;; 0))
+;;; Generated autoloads from magit-bookmark.el
+
+(autoload 'magit--handle-bookmark "magit-bookmark" "\
+Open a bookmark created by `magit--make-bookmark'.
+Call the `magit-*-setup-buffer' function of the the major-mode
+with the variables' values as arguments, which were recorded by
+`magit--make-bookmark'. Ignore `magit-display-buffer-function'.
+
+\(fn BOOKMARK)" nil nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-bookmark" '("magit--make-bookmark")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-branch" "magit-branch.el" (0 0 0 0))
+;;; Generated autoloads from magit-branch.el
+ (autoload 'magit-branch "magit" nil t)
+
+(autoload 'magit-checkout "magit-branch" "\
+Checkout REVISION, updating the index and the working tree.
+If REVISION is a local branch, then that becomes the current
+branch. If it is something else, then `HEAD' becomes detached.
+Checkout fails if the working tree or the staging area contain
+changes.
+
+\(git checkout REVISION).
+
+\(fn REVISION)" t nil)
+
+(autoload 'magit-branch-create "magit-branch" "\
+Create BRANCH at branch or revision START-POINT.
+
+\(fn BRANCH START-POINT)" t nil)
+
+(autoload 'magit-branch-and-checkout "magit-branch" "\
+Create and checkout BRANCH at branch or revision START-POINT.
+
+\(fn BRANCH START-POINT)" t nil)
+
+(autoload 'magit-branch-or-checkout "magit-branch" "\
+Hybrid between `magit-checkout' and `magit-branch-and-checkout'.
+
+Ask the user for an existing branch or revision. If the user
+input actually can be resolved as a branch or revision, then
+check that out, just like `magit-checkout' would.
+
+Otherwise create and checkout a new branch using the input as
+its name. Before doing so read the starting-point for the new
+branch. This is similar to what `magit-branch-and-checkout'
+does.
+
+\(fn ARG &optional START-POINT)" t nil)
+
+(autoload 'magit-branch-checkout "magit-branch" "\
+Checkout an existing or new local branch.
+
+Read a branch name from the user offering all local branches and
+a subset of remote branches as candidates. Omit remote branches
+for which a local branch by the same name exists from the list
+of candidates. The user can also enter a completely new branch
+name.
+
+- If the user selects an existing local branch, then check that
+ out.
+
+- If the user selects a remote branch, then create and checkout
+ a new local branch with the same name. Configure the selected
+ remote branch as push target.
+
+- If the user enters a new branch name, then create and check
+ that out, after also reading the starting-point from the user.
+
+In the latter two cases the upstream is also set. Whether it is
+set to the chosen START-POINT or something else depends on the
+value of `magit-branch-adjust-remote-upstream-alist', just like
+when using `magit-branch-and-checkout'.
+
+\(fn BRANCH &optional START-POINT)" t nil)
+
+(autoload 'magit-branch-orphan "magit-branch" "\
+Create and checkout an orphan BRANCH with contents from revision START-POINT.
+
+\(fn BRANCH START-POINT)" t nil)
+
+(autoload 'magit-branch-spinout "magit-branch" "\
+Create new branch from the unpushed commits.
+Like `magit-branch-spinoff' but remain on the current branch.
+If there are any uncommitted changes, then behave exactly like
+`magit-branch-spinoff'.
+
+\(fn BRANCH &optional FROM)" t nil)
+
+(autoload 'magit-branch-spinoff "magit-branch" "\
+Create new branch from the unpushed commits.
+
+Create and checkout a new branch starting at and tracking the
+current branch. That branch in turn is reset to the last commit
+it shares with its upstream. If the current branch has no
+upstream or no unpushed commits, then the new branch is created
+anyway and the previously current branch is not touched.
+
+This is useful to create a feature branch after work has already
+began on the old branch (likely but not necessarily \"master\").
+
+If the current branch is a member of the value of option
+`magit-branch-prefer-remote-upstream' (which see), then the
+current branch will be used as the starting point as usual, but
+the upstream of the starting-point may be used as the upstream
+of the new branch, instead of the starting-point itself.
+
+If optional FROM is non-nil, then the source branch is reset
+to `FROM~', instead of to the last commit it shares with its
+upstream. Interactively, FROM is only ever non-nil, if the
+region selects some commits, and among those commits, FROM is
+the commit that is the fewest commits ahead of the source
+branch.
+
+The commit at the other end of the selection actually does not
+matter, all commits between FROM and `HEAD' are moved to the new
+branch. If FROM is not reachable from `HEAD' or is reachable
+from the source branch's upstream, then an error is raised.
+
+\(fn BRANCH &optional FROM)" t nil)
+
+(autoload 'magit-branch-reset "magit-branch" "\
+Reset a branch to the tip of another branch or any other commit.
+
+When the branch being reset is the current branch, then do a
+hard reset. If there are any uncommitted changes, then the user
+has to confirm the reset because those changes would be lost.
+
+This is useful when you have started work on a feature branch but
+realize it's all crap and want to start over.
+
+When resetting to another branch and a prefix argument is used,
+then also set the target branch as the upstream of the branch
+that is being reset.
+
+\(fn BRANCH TO &optional SET-UPSTREAM)" t nil)
+
+(autoload 'magit-branch-delete "magit-branch" "\
+Delete one or multiple branches.
+If the region marks multiple branches, then offer to delete
+those, otherwise prompt for a single branch to be deleted,
+defaulting to the branch at point.
+
+\(fn BRANCHES &optional FORCE)" t nil)
+
+(autoload 'magit-branch-rename "magit-branch" "\
+Rename the branch named OLD to NEW.
+
+With a prefix argument FORCE, rename even if a branch named NEW
+already exists.
+
+If `branch.OLD.pushRemote' is set, then unset it. Depending on
+the value of `magit-branch-rename-push-target' (which see) maybe
+set `branch.NEW.pushRemote' and maybe rename the push-target on
+the remote.
+
+\(fn OLD NEW &optional FORCE)" t nil)
+
+(autoload 'magit-branch-shelve "magit-branch" "\
+Shelve a BRANCH.
+Rename \"refs/heads/BRANCH\" to \"refs/shelved/BRANCH\",
+and also rename the respective reflog file.
+
+\(fn BRANCH)" t nil)
+
+(autoload 'magit-branch-unshelve "magit-branch" "\
+Unshelve a BRANCH
+Rename \"refs/shelved/BRANCH\" to \"refs/heads/BRANCH\",
+and also rename the respective reflog file.
+
+\(fn BRANCH)" t nil)
+ (autoload 'magit-branch-configure "magit-branch" nil t)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-branch" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-clone" "magit-clone.el" (0 0 0 0))
+;;; Generated autoloads from magit-clone.el
+ (autoload 'magit-clone "magit-clone" nil t)
+
+(autoload 'magit-clone-regular "magit-clone" "\
+Create a clone of REPOSITORY in DIRECTORY.
+Then show the status buffer for the new repository.
+
+\(fn REPOSITORY DIRECTORY ARGS)" t nil)
+
+(autoload 'magit-clone-shallow "magit-clone" "\
+Create a shallow clone of REPOSITORY in DIRECTORY.
+Then show the status buffer for the new repository.
+With a prefix argument read the DEPTH of the clone;
+otherwise use 1.
+
+\(fn REPOSITORY DIRECTORY ARGS DEPTH)" t nil)
+
+(autoload 'magit-clone-shallow-since "magit-clone" "\
+Create a shallow clone of REPOSITORY in DIRECTORY.
+Then show the status buffer for the new repository.
+Exclude commits before DATE, which is read from the
+user.
+
+\(fn REPOSITORY DIRECTORY ARGS DATE)" t nil)
+
+(autoload 'magit-clone-shallow-exclude "magit-clone" "\
+Create a shallow clone of REPOSITORY in DIRECTORY.
+Then show the status buffer for the new repository.
+Exclude commits reachable from EXCLUDE, which is a
+branch or tag read from the user.
+
+\(fn REPOSITORY DIRECTORY ARGS EXCLUDE)" t nil)
+
+(autoload 'magit-clone-bare "magit-clone" "\
+Create a bare clone of REPOSITORY in DIRECTORY.
+Then show the status buffer for the new repository.
+
+\(fn REPOSITORY DIRECTORY ARGS)" t nil)
+
+(autoload 'magit-clone-mirror "magit-clone" "\
+Create a mirror of REPOSITORY in DIRECTORY.
+Then show the status buffer for the new repository.
+
+\(fn REPOSITORY DIRECTORY ARGS)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-clone" '("magit-clone-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-commit" "magit-commit.el" (0 0 0 0))
+;;; Generated autoloads from magit-commit.el
+ (autoload 'magit-commit "magit-commit" nil t)
+
+(autoload 'magit-commit-create "magit-commit" "\
+Create a new commit on `HEAD'.
+With a prefix argument, amend to the commit at `HEAD' instead.
+
+\(git commit [--amend] ARGS)
+
+\(fn &optional ARGS)" t nil)
+
+(autoload 'magit-commit-amend "magit-commit" "\
+Amend the last commit.
+
+\(git commit --amend ARGS)
+
+\(fn &optional ARGS)" t nil)
+
+(autoload 'magit-commit-extend "magit-commit" "\
+Amend the last commit, without editing the message.
+
+With a prefix argument keep the committer date, otherwise change
+it. The option `magit-commit-extend-override-date' can be used
+to inverse the meaning of the prefix argument.
+\(git commit
+--amend --no-edit)
+
+\(fn &optional ARGS OVERRIDE-DATE)" t nil)
+
+(autoload 'magit-commit-reword "magit-commit" "\
+Reword the last commit, ignoring staged changes.
+
+With a prefix argument keep the committer date, otherwise change
+it. The option `magit-commit-reword-override-date' can be used
+to inverse the meaning of the prefix argument.
+
+Non-interactively respect the optional OVERRIDE-DATE argument
+and ignore the option.
+
+\(git commit --amend --only)
+
+\(fn &optional ARGS OVERRIDE-DATE)" t nil)
+
+(autoload 'magit-commit-fixup "magit-commit" "\
+Create a fixup commit.
+
+With a prefix argument the target COMMIT has to be confirmed.
+Otherwise the commit at point may be used without confirmation
+depending on the value of option `magit-commit-squash-confirm'.
+
+\(fn &optional COMMIT ARGS)" t nil)
+
+(autoload 'magit-commit-squash "magit-commit" "\
+Create a squash commit, without editing the squash message.
+
+With a prefix argument the target COMMIT has to be confirmed.
+Otherwise the commit at point may be used without confirmation
+depending on the value of option `magit-commit-squash-confirm'.
+
+\(fn &optional COMMIT ARGS)" t nil)
+
+(autoload 'magit-commit-augment "magit-commit" "\
+Create a squash commit, editing the squash message.
+
+With a prefix argument the target COMMIT has to be confirmed.
+Otherwise the commit at point may be used without confirmation
+depending on the value of option `magit-commit-squash-confirm'.
+
+\(fn &optional COMMIT ARGS)" t nil)
+
+(autoload 'magit-commit-instant-fixup "magit-commit" "\
+Create a fixup commit targeting COMMIT and instantly rebase.
+
+\(fn &optional COMMIT ARGS)" t nil)
+
+(autoload 'magit-commit-instant-squash "magit-commit" "\
+Create a squash commit targeting COMMIT and instantly rebase.
+
+\(fn &optional COMMIT ARGS)" t nil)
+
+(autoload 'magit-commit-reshelve "magit-commit" "\
+Change the committer date and possibly the author date of `HEAD'.
+
+If you are the author of `HEAD', then both dates are changed,
+otherwise only the committer date. The current time is used
+as the initial minibuffer input and the original author (if
+that is you) or committer date is available as the previous
+history element.
+
+\(fn DATE)" t nil)
+
+(autoload 'magit-commit-absorb-modules "magit-commit" "\
+Spread modified modules across recent commits.
+
+\(fn PHASE COMMIT)" t nil)
+ (autoload 'magit-commit-absorb "magit-commit" nil t)
+ (autoload 'magit-commit-autofixup "magit-commit" nil t)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-commit" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-diff" "magit-diff.el" (0 0 0 0))
+;;; Generated autoloads from magit-diff.el
+ (autoload 'magit-diff "magit-diff" nil t)
+ (autoload 'magit-diff-refresh "magit-diff" nil t)
+
+(autoload 'magit-diff-dwim "magit-diff" "\
+Show changes for the thing at point.
+
+\(fn &optional ARGS FILES)" t nil)
+
+(autoload 'magit-diff-range "magit-diff" "\
+Show differences between two commits.
+
+REV-OR-RANGE should be a range or a single revision. If it is a
+revision, then show changes in the working tree relative to that
+revision. If it is a range, but one side is omitted, then show
+changes relative to `HEAD'.
+
+If the region is active, use the revisions on the first and last
+line of the region as the two sides of the range. With a prefix
+argument, instead of diffing the revisions, choose a revision to
+view changes along, starting at the common ancestor of both
+revisions (i.e., use a \"...\" range).
+
+\(fn REV-OR-RANGE &optional ARGS FILES)" t nil)
+
+(autoload 'magit-diff-working-tree "magit-diff" "\
+Show changes between the current working tree and the `HEAD' commit.
+With a prefix argument show changes between the working tree and
+a commit read from the minibuffer.
+
+\(fn &optional REV ARGS FILES)" t nil)
+
+(autoload 'magit-diff-staged "magit-diff" "\
+Show changes between the index and the `HEAD' commit.
+With a prefix argument show changes between the index and
+a commit read from the minibuffer.
+
+\(fn &optional REV ARGS FILES)" t nil)
+
+(autoload 'magit-diff-unstaged "magit-diff" "\
+Show changes between the working tree and the index.
+
+\(fn &optional ARGS FILES)" t nil)
+
+(autoload 'magit-diff-unmerged "magit-diff" "\
+Show changes that are being merged.
+
+\(fn &optional ARGS FILES)" t nil)
+
+(autoload 'magit-diff-while-committing "magit-diff" "\
+While committing, show the changes that are about to be committed.
+While amending, invoking the command again toggles between
+showing just the new changes or all the changes that will
+be committed.
+
+\(fn &optional ARGS)" t nil)
+
+(autoload 'magit-diff-buffer-file "magit-diff" "\
+Show diff for the blob or file visited in the current buffer.
+
+When the buffer visits a blob, then show the respective commit.
+When the buffer visits a file, then show the differenced between
+`HEAD' and the working tree. In both cases limit the diff to
+the file or blob." t nil)
+
+(autoload 'magit-diff-paths "magit-diff" "\
+Show changes between any two files on disk.
+
+\(fn A B)" t nil)
+
+(autoload 'magit-show-commit "magit-diff" "\
+Visit the revision at point in another buffer.
+If there is no revision at point or with a prefix argument prompt
+for a revision.
+
+\(fn REV &optional ARGS FILES MODULE)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-diff" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-ediff" "magit-ediff.el" (0 0 0 0))
+;;; Generated autoloads from magit-ediff.el
+ (autoload 'magit-ediff "magit-ediff" nil)
+
+(autoload 'magit-ediff-resolve "magit-ediff" "\
+Resolve outstanding conflicts in FILE using Ediff.
+FILE has to be relative to the top directory of the repository.
+
+In the rare event that you want to manually resolve all
+conflicts, including those already resolved by Git, use
+`ediff-merge-revisions-with-ancestor'.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-ediff-stage "magit-ediff" "\
+Stage and unstage changes to FILE using Ediff.
+FILE has to be relative to the top directory of the repository.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-ediff-compare "magit-ediff" "\
+Compare REVA:FILEA with REVB:FILEB using Ediff.
+
+FILEA and FILEB have to be relative to the top directory of the
+repository. If REVA or REVB is nil, then this stands for the
+working tree state.
+
+If the region is active, use the revisions on the first and last
+line of the region. With a prefix argument, instead of diffing
+the revisions, choose a revision to view changes along, starting
+at the common ancestor of both revisions (i.e., use a \"...\"
+range).
+
+\(fn REVA REVB FILEA FILEB)" t nil)
+
+(autoload 'magit-ediff-dwim "magit-ediff" "\
+Compare, stage, or resolve using Ediff.
+This command tries to guess what file, and what commit or range
+the user wants to compare, stage, or resolve using Ediff. It
+might only be able to guess either the file, or range or commit,
+in which case the user is asked about the other. It might not
+always guess right, in which case the appropriate `magit-ediff-*'
+command has to be used explicitly. If it cannot read the user's
+mind at all, then it asks the user for a command to run." t nil)
+
+(autoload 'magit-ediff-show-staged "magit-ediff" "\
+Show staged changes using Ediff.
+
+This only allows looking at the changes; to stage, unstage,
+and discard changes using Ediff, use `magit-ediff-stage'.
+
+FILE must be relative to the top directory of the repository.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-ediff-show-unstaged "magit-ediff" "\
+Show unstaged changes using Ediff.
+
+This only allows looking at the changes; to stage, unstage,
+and discard changes using Ediff, use `magit-ediff-stage'.
+
+FILE must be relative to the top directory of the repository.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-ediff-show-working-tree "magit-ediff" "\
+Show changes between `HEAD' and working tree using Ediff.
+FILE must be relative to the top directory of the repository.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-ediff-show-commit "magit-ediff" "\
+Show changes introduced by COMMIT using Ediff.
+
+\(fn COMMIT)" t nil)
+
+(autoload 'magit-ediff-show-stash "magit-ediff" "\
+Show changes introduced by STASH using Ediff.
+`magit-ediff-show-stash-with-index' controls whether a
+three-buffer Ediff is used in order to distinguish changes in the
+stash that were staged.
+
+\(fn STASH)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-ediff" '("magit-ediff-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-extras" "magit-extras.el" (0 0 0 0))
+;;; Generated autoloads from magit-extras.el
+
+(autoload 'magit-run-git-gui "magit-extras" "\
+Run `git gui' for the current git repository." t nil)
+
+(autoload 'magit-run-git-gui-blame "magit-extras" "\
+Run `git gui blame' on the given FILENAME and COMMIT.
+Interactively run it for the current file and the `HEAD', with a
+prefix or when the current file cannot be determined let the user
+choose. When the current buffer is visiting FILENAME instruct
+blame to center around the line point is on.
+
+\(fn COMMIT FILENAME &optional LINENUM)" t nil)
+
+(autoload 'magit-run-gitk "magit-extras" "\
+Run `gitk' in the current repository." t nil)
+
+(autoload 'magit-run-gitk-branches "magit-extras" "\
+Run `gitk --branches' in the current repository." t nil)
+
+(autoload 'magit-run-gitk-all "magit-extras" "\
+Run `gitk --all' in the current repository." t nil)
+
+(autoload 'ido-enter-magit-status "magit-extras" "\
+Drop into `magit-status' from file switching.
+
+This command does not work in Emacs 26.1.
+See https://github.com/magit/magit/issues/3634
+and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31707.
+
+To make this command available use something like:
+
+ (add-hook \\='ido-setup-hook
+ (lambda ()
+ (define-key ido-completion-map
+ (kbd \"C-x g\") \\='ido-enter-magit-status)))
+
+Starting with Emacs 25.1 the Ido keymaps are defined just once
+instead of every time Ido is invoked, so now you can modify it
+like pretty much every other keymap:
+
+ (define-key ido-common-completion-map
+ (kbd \"C-x g\") \\='ido-enter-magit-status)" t nil)
+
+(autoload 'magit-project-status "magit-extras" "\
+Run `magit-status' in the current project's root." t nil)
+
+(autoload 'magit-dired-jump "magit-extras" "\
+Visit file at point using Dired.
+With a prefix argument, visit in another window. If there
+is no file at point, then instead visit `default-directory'.
+
+\(fn &optional OTHER-WINDOW)" t nil)
+
+(autoload 'magit-dired-log "magit-extras" "\
+Show log for all marked files, or the current file.
+
+\(fn &optional FOLLOW)" t nil)
+
+(autoload 'magit-do-async-shell-command "magit-extras" "\
+Open FILE with `dired-do-async-shell-command'.
+Interactively, open the file at point.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-previous-line "magit-extras" "\
+Like `previous-line' but with Magit-specific shift-selection.
+
+Magit's selection mechanism is based on the region but selects an
+area that is larger than the region. This causes `previous-line'
+when invoked while holding the shift key to move up one line and
+thereby select two lines. When invoked inside a hunk body this
+command does not move point on the first invocation and thereby
+it only selects a single line. Which inconsistency you prefer
+is a matter of preference.
+
+\(fn &optional ARG TRY-VSCROLL)" t nil)
+
+(function-put 'magit-previous-line 'interactive-only '"use `forward-line' with negative argument instead.")
+
+(autoload 'magit-next-line "magit-extras" "\
+Like `next-line' but with Magit-specific shift-selection.
+
+Magit's selection mechanism is based on the region but selects
+an area that is larger than the region. This causes `next-line'
+when invoked while holding the shift key to move down one line
+and thereby select two lines. When invoked inside a hunk body
+this command does not move point on the first invocation and
+thereby it only selects a single line. Which inconsistency you
+prefer is a matter of preference.
+
+\(fn &optional ARG TRY-VSCROLL)" t nil)
+
+(function-put 'magit-next-line 'interactive-only 'forward-line)
+
+(autoload 'magit-clean "magit-extras" "\
+Remove untracked files from the working tree.
+With a prefix argument also remove ignored files,
+with two prefix arguments remove ignored files only.
+
+\(git clean -f -d [-x|-X])
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'magit-add-change-log-entry "magit-extras" "\
+Find change log file and add date entry and item for current change.
+This differs from `add-change-log-entry' (which see) in that
+it acts on the current hunk in a Magit buffer instead of on
+a position in a file-visiting buffer.
+
+\(fn &optional WHOAMI FILE-NAME OTHER-WINDOW)" t nil)
+
+(autoload 'magit-add-change-log-entry-other-window "magit-extras" "\
+Find change log file in other window and add entry and item.
+This differs from `add-change-log-entry-other-window' (which see)
+in that it acts on the current hunk in a Magit buffer instead of
+on a position in a file-visiting buffer.
+
+\(fn &optional WHOAMI FILE-NAME)" t nil)
+
+(autoload 'magit-edit-line-commit "magit-extras" "\
+Edit the commit that added the current line.
+
+With a prefix argument edit the commit that removes the line,
+if any. The commit is determined using `git blame' and made
+editable using `git rebase --interactive' if it is reachable
+from `HEAD', or by checking out the commit (or a branch that
+points at it) otherwise.
+
+\(fn &optional TYPE)" t nil)
+
+(autoload 'magit-diff-edit-hunk-commit "magit-extras" "\
+From a hunk, edit the respective commit and visit the file.
+
+First visit the file being modified by the hunk at the correct
+location using `magit-diff-visit-file'. This actually visits a
+blob. When point is on a diff header, not within an individual
+hunk, then this visits the blob the first hunk is about.
+
+Then invoke `magit-edit-line-commit', which uses an interactive
+rebase to make the commit editable, or if that is not possible
+because the commit is not reachable from `HEAD' by checking out
+that commit directly. This also causes the actual worktree file
+to be visited.
+
+Neither the blob nor the file buffer are killed when finishing
+the rebase. If that is undesirable, then it might be better to
+use `magit-rebase-edit-command' instead of this command.
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-reshelve-since "magit-extras" "\
+Change the author and committer dates of the commits since REV.
+
+Ask the user for the first reachable commit whose dates should
+be changed. Then read the new date for that commit. The initial
+minibuffer input and the previous history element offer good
+values. The next commit will be created one minute later and so
+on.
+
+This command is only intended for interactive use and should only
+be used on highly rearranged and unpublished history.
+
+\(fn REV)" t nil)
+
+(autoload 'magit-pop-revision-stack "magit-extras" "\
+Insert a representation of a revision into the current buffer.
+
+Pop a revision from the `magit-revision-stack' and insert it into
+the current buffer according to `magit-pop-revision-stack-format'.
+Revisions can be put on the stack using `magit-copy-section-value'
+and `magit-copy-buffer-revision'.
+
+If the stack is empty or with a prefix argument, instead read a
+revision in the minibuffer. By using the minibuffer history this
+allows selecting an item which was popped earlier or to insert an
+arbitrary reference or revision without first pushing it onto the
+stack.
+
+When reading the revision from the minibuffer, then it might not
+be possible to guess the correct repository. When this command
+is called inside a repository (e.g. while composing a commit
+message), then that repository is used. Otherwise (e.g. while
+composing an email) then the repository recorded for the top
+element of the stack is used (even though we insert another
+revision). If not called inside a repository and with an empty
+stack, or with two prefix arguments, then read the repository in
+the minibuffer too.
+
+\(fn REV TOPLEVEL)" t nil)
+
+(autoload 'magit-copy-section-value "magit-extras" "\
+Save the value of the current section for later use.
+
+Save the section value to the `kill-ring', and, provided that
+the current section is a commit, branch, or tag section, push
+the (referenced) revision to the `magit-revision-stack' for use
+with `magit-pop-revision-stack'.
+
+When `magit-copy-revision-abbreviated' is non-nil, save the
+abbreviated revision to the `kill-ring' and the
+`magit-revision-stack'.
+
+When the current section is a branch or a tag, and a prefix
+argument is used, then save the revision at its tip to the
+`kill-ring' instead of the reference name.
+
+When the region is active, then save that to the `kill-ring',
+like `kill-ring-save' would, instead of behaving as described
+above. If a prefix argument is used and the region is within
+a hunk, then strip the diff marker column and keep only either
+the added or removed lines, depending on the sign of the prefix
+argument.
+
+\(fn ARG)" t nil)
+
+(autoload 'magit-copy-buffer-revision "magit-extras" "\
+Save the revision of the current buffer for later use.
+
+Save the revision shown in the current buffer to the `kill-ring'
+and push it to the `magit-revision-stack'.
+
+This command is mainly intended for use in `magit-revision-mode'
+buffers, the only buffers where it is always unambiguous exactly
+which revision should be saved.
+
+Most other Magit buffers usually show more than one revision, in
+some way or another, so this command has to select one of them,
+and that choice might not always be the one you think would have
+been the best pick.
+
+In such buffers it is often more useful to save the value of
+the current section instead, using `magit-copy-section-value'.
+
+When the region is active, then save that to the `kill-ring',
+like `kill-ring-save' would, instead of behaving as described
+above.
+
+When `magit-copy-revision-abbreviated' is non-nil, save the
+abbreviated revision to the `kill-ring' and the
+`magit-revision-stack'." t nil)
+
+(autoload 'magit-abort-dwim "magit-extras" "\
+Abort current operation.
+Depending on the context, this will abort a merge, a rebase, a
+patch application, a cherry-pick, a revert, or a bisect." t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-extras" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-fetch" "magit-fetch.el" (0 0 0 0))
+;;; Generated autoloads from magit-fetch.el
+ (autoload 'magit-fetch "magit-fetch" nil t)
+ (autoload 'magit-fetch-from-pushremote "magit-fetch" nil t)
+ (autoload 'magit-fetch-from-upstream "magit-fetch" nil t)
+
+(autoload 'magit-fetch-other "magit-fetch" "\
+Fetch from another repository.
+
+\(fn REMOTE ARGS)" t nil)
+
+(autoload 'magit-fetch-branch "magit-fetch" "\
+Fetch a BRANCH from a REMOTE.
+
+\(fn REMOTE BRANCH ARGS)" t nil)
+
+(autoload 'magit-fetch-refspec "magit-fetch" "\
+Fetch a REFSPEC from a REMOTE.
+
+\(fn REMOTE REFSPEC ARGS)" t nil)
+
+(autoload 'magit-fetch-all "magit-fetch" "\
+Fetch from all remotes.
+
+\(fn ARGS)" t nil)
+
+(autoload 'magit-fetch-all-prune "magit-fetch" "\
+Fetch from all remotes, and prune.
+Prune remote tracking branches for branches that have been
+removed on the respective remote." t nil)
+
+(autoload 'magit-fetch-all-no-prune "magit-fetch" "\
+Fetch from all remotes." t nil)
+
+(autoload 'magit-fetch-modules "magit-fetch" "\
+Fetch all submodules.
+
+Option `magit-fetch-modules-jobs' controls how many submodules
+are being fetched in parallel. Also fetch the super-repository,
+because `git-fetch' does not support not doing that. With a
+prefix argument fetch all remotes.
+
+\(fn &optional ALL)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-fetch" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-files" "magit-files.el" (0 0 0 0))
+;;; Generated autoloads from magit-files.el
+
+(autoload 'magit-find-file "magit-files" "\
+View FILE from REV.
+Switch to a buffer visiting blob REV:FILE, creating one if none
+already exists. If prior to calling this command the current
+buffer and/or cursor position is about the same file, then go
+to the line and column corresponding to that location.
+
+\(fn REV FILE)" t nil)
+
+(autoload 'magit-find-file-other-window "magit-files" "\
+View FILE from REV, in another window.
+Switch to a buffer visiting blob REV:FILE, creating one if none
+already exists. If prior to calling this command the current
+buffer and/or cursor position is about the same file, then go to
+the line and column corresponding to that location.
+
+\(fn REV FILE)" t nil)
+
+(autoload 'magit-find-file-other-frame "magit-files" "\
+View FILE from REV, in another frame.
+Switch to a buffer visiting blob REV:FILE, creating one if none
+already exists. If prior to calling this command the current
+buffer and/or cursor position is about the same file, then go to
+the line and column corresponding to that location.
+
+\(fn REV FILE)" t nil)
+ (autoload 'magit-file-dispatch "magit" nil t)
+
+(autoload 'magit-blob-visit-file "magit-files" "\
+View the file from the worktree corresponding to the current blob.
+When visiting a blob or the version from the index, then go to
+the same location in the respective file in the working tree." t nil)
+
+(autoload 'magit-file-checkout "magit-files" "\
+Checkout FILE from REV.
+
+\(fn REV FILE)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-files" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-git" "magit-git.el" (0 0 0 0))
+;;; Generated autoloads from magit-git.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-git" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-gitignore" "magit-gitignore.el" (0 0
+;;;;;; 0 0))
+;;; Generated autoloads from magit-gitignore.el
+ (autoload 'magit-gitignore "magit-gitignore" nil t)
+
+(autoload 'magit-gitignore-in-topdir "magit-gitignore" "\
+Add the Git ignore RULE to the top-level \".gitignore\" file.
+Since this file is tracked, it is shared with other clones of the
+repository. Also stage the file.
+
+\(fn RULE)" t nil)
+
+(autoload 'magit-gitignore-in-subdir "magit-gitignore" "\
+Add the Git ignore RULE to a \".gitignore\" file.
+Prompted the user for a directory and add the rule to the
+\".gitignore\" file in that directory. Since such files are
+tracked, they are shared with other clones of the repository.
+Also stage the file.
+
+\(fn RULE DIRECTORY)" t nil)
+
+(autoload 'magit-gitignore-in-gitdir "magit-gitignore" "\
+Add the Git ignore RULE to \"$GIT_DIR/info/exclude\".
+Rules in that file only affects this clone of the repository.
+
+\(fn RULE)" t nil)
+
+(autoload 'magit-gitignore-on-system "magit-gitignore" "\
+Add the Git ignore RULE to the file specified by `core.excludesFile'.
+Rules that are defined in that file affect all local repositories.
+
+\(fn RULE)" t nil)
+
+(autoload 'magit-skip-worktree "magit-gitignore" "\
+Call \"git update-index --skip-worktree -- FILE\".
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-no-skip-worktree "magit-gitignore" "\
+Call \"git update-index --no-skip-worktree -- FILE\".
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-assume-unchanged "magit-gitignore" "\
+Call \"git update-index --assume-unchanged -- FILE\".
+
+\(fn FILE)" t nil)
+
+(autoload 'magit-no-assume-unchanged "magit-gitignore" "\
+Call \"git update-index --no-assume-unchanged -- FILE\".
+
+\(fn FILE)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-gitignore" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-imenu" "magit-imenu.el" (0 0 0 0))
+;;; Generated autoloads from magit-imenu.el
+
+(autoload 'magit-imenu--log-prev-index-position-function "magit-imenu" "\
+Move point to previous line in current buffer.
+This function is used as a value for
+`imenu-prev-index-position-function'." nil nil)
+
+(autoload 'magit-imenu--log-extract-index-name-function "magit-imenu" "\
+Return imenu name for line at point.
+This function is used as a value for
+`imenu-extract-index-name-function'. Point should be at the
+beginning of the line." nil nil)
+
+(autoload 'magit-imenu--diff-prev-index-position-function "magit-imenu" "\
+Move point to previous file line in current buffer.
+This function is used as a value for
+`imenu-prev-index-position-function'." nil nil)
+
+(autoload 'magit-imenu--diff-extract-index-name-function "magit-imenu" "\
+Return imenu name for line at point.
+This function is used as a value for
+`imenu-extract-index-name-function'. Point should be at the
+beginning of the line." nil nil)
+
+(autoload 'magit-imenu--status-create-index-function "magit-imenu" "\
+Return an alist of all imenu entries in current buffer.
+This function is used as a value for
+`imenu-create-index-function'." nil nil)
+
+(autoload 'magit-imenu--refs-create-index-function "magit-imenu" "\
+Return an alist of all imenu entries in current buffer.
+This function is used as a value for
+`imenu-create-index-function'." nil nil)
+
+(autoload 'magit-imenu--cherry-create-index-function "magit-imenu" "\
+Return an alist of all imenu entries in current buffer.
+This function is used as a value for
+`imenu-create-index-function'." nil nil)
+
+(autoload 'magit-imenu--submodule-prev-index-position-function "magit-imenu" "\
+Move point to previous line in magit-submodule-list buffer.
+This function is used as a value for
+`imenu-prev-index-position-function'." nil nil)
+
+(autoload 'magit-imenu--submodule-extract-index-name-function "magit-imenu" "\
+Return imenu name for line at point.
+This function is used as a value for
+`imenu-extract-index-name-function'. Point should be at the
+beginning of the line." nil nil)
+
+(autoload 'magit-imenu--repolist-prev-index-position-function "magit-imenu" "\
+Move point to previous line in magit-repolist buffer.
+This function is used as a value for
+`imenu-prev-index-position-function'." nil nil)
+
+(autoload 'magit-imenu--repolist-extract-index-name-function "magit-imenu" "\
+Return imenu name for line at point.
+This function is used as a value for
+`imenu-extract-index-name-function'. Point should be at the
+beginning of the line." nil nil)
+
+(autoload 'magit-imenu--process-prev-index-position-function "magit-imenu" "\
+Move point to previous process in magit-process buffer.
+This function is used as a value for
+`imenu-prev-index-position-function'." nil nil)
+
+(autoload 'magit-imenu--process-extract-index-name-function "magit-imenu" "\
+Return imenu name for line at point.
+This function is used as a value for
+`imenu-extract-index-name-function'. Point should be at the
+beginning of the line." nil nil)
+
+(autoload 'magit-imenu--rebase-prev-index-position-function "magit-imenu" "\
+Move point to previous commit in git-rebase buffer.
+This function is used as a value for
+`imenu-prev-index-position-function'." nil nil)
+
+(autoload 'magit-imenu--rebase-extract-index-name-function "magit-imenu" "\
+Return imenu name for line at point.
+This function is used as a value for
+`imenu-extract-index-name-function'. Point should be at the
+beginning of the line." nil nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-imenu" '("magit-imenu--index-function")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-log" "magit-log.el" (0 0 0 0))
+;;; Generated autoloads from magit-log.el
+ (autoload 'magit-log "magit-log" nil t)
+ (autoload 'magit-log-refresh "magit-log" nil t)
+
+(autoload 'magit-log-current "magit-log" "\
+Show log for the current branch.
+When `HEAD' is detached or with a prefix argument show log for
+one or more revs read from the minibuffer.
+
+\(fn REVS &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log-other "magit-log" "\
+Show log for one or more revs read from the minibuffer.
+The user can input any revision or revisions separated by a
+space, or even ranges, but only branches and tags, and a
+representation of the commit at point, are available as
+completion candidates.
+
+\(fn REVS &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log-head "magit-log" "\
+Show log for `HEAD'.
+
+\(fn &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log-branches "magit-log" "\
+Show log for all local branches and `HEAD'.
+
+\(fn &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log-matching-branches "magit-log" "\
+Show log for all branches matching PATTERN and `HEAD'.
+
+\(fn PATTERN &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log-matching-tags "magit-log" "\
+Show log for all tags matching PATTERN and `HEAD'.
+
+\(fn PATTERN &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log-all-branches "magit-log" "\
+Show log for all local and remote branches and `HEAD'.
+
+\(fn &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log-all "magit-log" "\
+Show log for all references and `HEAD'.
+
+\(fn &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log-buffer-file "magit-log" "\
+Show log for the blob or file visited in the current buffer.
+With a prefix argument or when `--follow' is an active log
+argument, then follow renames. When the region is active,
+restrict the log to the lines that the region touches.
+
+\(fn &optional FOLLOW BEG END)" t nil)
+
+(autoload 'magit-log-trace-definition "magit-log" "\
+Show log for the definition at point.
+
+\(fn FILE FN REV)" t nil)
+
+(autoload 'magit-log-merged "magit-log" "\
+Show log for the merge of COMMIT into BRANCH.
+
+More precisely, find merge commit M that brought COMMIT into
+BRANCH, and show the log of the range \"M^1..M\". If COMMIT is
+directly on BRANCH, then show approximately twenty surrounding
+commits instead.
+
+This command requires git-when-merged, which is available from
+https://github.com/mhagger/git-when-merged.
+
+\(fn COMMIT BRANCH &optional ARGS FILES)" t nil)
+
+(autoload 'magit-log-move-to-parent "magit-log" "\
+Move to the Nth parent of the current commit.
+
+\(fn &optional N)" t nil)
+ (autoload 'magit-shortlog "magit-log" nil t)
+
+(autoload 'magit-shortlog-since "magit-log" "\
+Show a history summary for commits since REV.
+
+\(fn REV ARGS)" t nil)
+
+(autoload 'magit-shortlog-range "magit-log" "\
+Show a history summary for commit or range REV-OR-RANGE.
+
+\(fn REV-OR-RANGE ARGS)" t nil)
+
+(autoload 'magit-cherry "magit-log" "\
+Show commits in a branch that are not merged in the upstream branch.
+
+\(fn HEAD UPSTREAM)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-log" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-margin" "magit-margin.el" (0 0 0 0))
+;;; Generated autoloads from magit-margin.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-margin" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-merge" "magit-merge.el" (0 0 0 0))
+;;; Generated autoloads from magit-merge.el
+ (autoload 'magit-merge "magit" nil t)
+
+(autoload 'magit-merge-plain "magit-merge" "\
+Merge commit REV into the current branch; using default message.
+
+Unless there are conflicts or a prefix argument is used create a
+merge commit using a generic commit message and without letting
+the user inspect the result. With a prefix argument pretend the
+merge failed to give the user the opportunity to inspect the
+merge.
+
+\(git merge --no-edit|--no-commit [ARGS] REV)
+
+\(fn REV &optional ARGS NOCOMMIT)" t nil)
+
+(autoload 'magit-merge-editmsg "magit-merge" "\
+Merge commit REV into the current branch; and edit message.
+Perform the merge and prepare a commit message but let the user
+edit it.
+
+\(git merge --edit --no-ff [ARGS] REV)
+
+\(fn REV &optional ARGS)" t nil)
+
+(autoload 'magit-merge-nocommit "magit-merge" "\
+Merge commit REV into the current branch; pretending it failed.
+Pretend the merge failed to give the user the opportunity to
+inspect the merge and change the commit message.
+
+\(git merge --no-commit --no-ff [ARGS] REV)
+
+\(fn REV &optional ARGS)" t nil)
+
+(autoload 'magit-merge-into "magit-merge" "\
+Merge the current branch into BRANCH and remove the former.
+
+Before merging, force push the source branch to its push-remote,
+provided the respective remote branch already exists, ensuring
+that the respective pull-request (if any) won't get stuck on some
+obsolete version of the commits that are being merged. Finally
+if `forge-branch-pullreq' was used to create the merged branch,
+branch, then also remove the respective remote branch.
+
+\(fn BRANCH &optional ARGS)" t nil)
+
+(autoload 'magit-merge-absorb "magit-merge" "\
+Merge BRANCH into the current branch and remove the former.
+
+Before merging, force push the source branch to its push-remote,
+provided the respective remote branch already exists, ensuring
+that the respective pull-request (if any) won't get stuck on some
+obsolete version of the commits that are being merged. Finally
+if `forge-branch-pullreq' was used to create the merged branch,
+then also remove the respective remote branch.
+
+\(fn BRANCH &optional ARGS)" t nil)
+
+(autoload 'magit-merge-squash "magit-merge" "\
+Squash commit REV into the current branch; don't create a commit.
+
+\(git merge --squash REV)
+
+\(fn REV)" t nil)
+
+(autoload 'magit-merge-preview "magit-merge" "\
+Preview result of merging REV into the current branch.
+
+\(fn REV)" t nil)
+
+(autoload 'magit-merge-abort "magit-merge" "\
+Abort the current merge operation.
+
+\(git merge --abort)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-merge" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-mode" "magit-mode.el" (0 0 0 0))
+;;; Generated autoloads from magit-mode.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-mode" '("disable-magit-save-buffers" "inhibit-magit-refresh" "magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-notes" "magit-notes.el" (0 0 0 0))
+;;; Generated autoloads from magit-notes.el
+ (autoload 'magit-notes "magit" nil t)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-notes" '("magit-notes-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-obsolete" "magit-obsolete.el" (0 0 0
+;;;;;; 0))
+;;; Generated autoloads from magit-obsolete.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-obsolete" '("magit--magit-popup-warning")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-patch" "magit-patch.el" (0 0 0 0))
+;;; Generated autoloads from magit-patch.el
+ (autoload 'magit-patch "magit-patch" nil t)
+ (autoload 'magit-patch-create "magit-patch" nil t)
+ (autoload 'magit-patch-apply "magit-patch" nil t)
+
+(autoload 'magit-patch-save "magit-patch" "\
+Write current diff into patch FILE.
+
+What arguments are used to create the patch depends on the value
+of `magit-patch-save-arguments' and whether a prefix argument is
+used.
+
+If the value is the symbol `buffer', then use the same arguments
+as the buffer. With a prefix argument use no arguments.
+
+If the value is a list beginning with the symbol `exclude', then
+use the same arguments as the buffer except for those matched by
+entries in the cdr of the list. The comparison is done using
+`string-prefix-p'. With a prefix argument use the same arguments
+as the buffer.
+
+If the value is a list of strings (including the empty list),
+then use those arguments. With a prefix argument use the same
+arguments as the buffer.
+
+Of course the arguments that are required to actually show the
+same differences as those shown in the buffer are always used.
+
+\(fn FILE &optional ARG)" t nil)
+
+(autoload 'magit-request-pull "magit-patch" "\
+Request upstream to pull from your public repository.
+
+URL is the url of your publicly accessible repository.
+START is a commit that already is in the upstream repository.
+END is the last commit, usually a branch name, which upstream
+is asked to pull. START has to be reachable from that commit.
+
+\(fn URL START END)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-patch" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-process" "magit-process.el" (0 0 0 0))
+;;; Generated autoloads from magit-process.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-process" '("magit-" "tramp-sh-handle-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-pull" "magit-pull.el" (0 0 0 0))
+;;; Generated autoloads from magit-pull.el
+ (autoload 'magit-pull "magit-pull" nil t)
+ (autoload 'magit-pull-from-pushremote "magit-pull" nil t)
+ (autoload 'magit-pull-from-upstream "magit-pull" nil t)
+
+(autoload 'magit-pull-branch "magit-pull" "\
+Pull from a branch read in the minibuffer.
+
+\(fn SOURCE ARGS)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-pull" '("magit-pull-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-push" "magit-push.el" (0 0 0 0))
+;;; Generated autoloads from magit-push.el
+ (autoload 'magit-push "magit-push" nil t)
+ (autoload 'magit-push-current-to-pushremote "magit-push" nil t)
+ (autoload 'magit-push-current-to-upstream "magit-push" nil t)
+
+(autoload 'magit-push-current "magit-push" "\
+Push the current branch to a branch read in the minibuffer.
+
+\(fn TARGET ARGS)" t nil)
+
+(autoload 'magit-push-other "magit-push" "\
+Push an arbitrary branch or commit somewhere.
+Both the source and the target are read in the minibuffer.
+
+\(fn SOURCE TARGET ARGS)" t nil)
+
+(autoload 'magit-push-refspecs "magit-push" "\
+Push one or multiple REFSPECS to a REMOTE.
+Both the REMOTE and the REFSPECS are read in the minibuffer. To
+use multiple REFSPECS, separate them with commas. Completion is
+only available for the part before the colon, or when no colon
+is used.
+
+\(fn REMOTE REFSPECS ARGS)" t nil)
+
+(autoload 'magit-push-matching "magit-push" "\
+Push all matching branches to another repository.
+If multiple remotes exist, then read one from the user.
+If just one exists, use that without requiring confirmation.
+
+\(fn REMOTE &optional ARGS)" t nil)
+
+(autoload 'magit-push-tags "magit-push" "\
+Push all tags to another repository.
+If only one remote exists, then push to that. Otherwise prompt
+for a remote, offering the remote configured for the current
+branch as default.
+
+\(fn REMOTE &optional ARGS)" t nil)
+
+(autoload 'magit-push-tag "magit-push" "\
+Push a tag to another repository.
+
+\(fn TAG REMOTE &optional ARGS)" t nil)
+
+(autoload 'magit-push-notes-ref "magit-push" "\
+Push a notes ref to another repository.
+
+\(fn REF REMOTE &optional ARGS)" t nil)
+ (autoload 'magit-push-implicitly "magit-push" nil t)
+
+(autoload 'magit-push-to-remote "magit-push" "\
+Push to REMOTE without using an explicit refspec.
+The REMOTE is read in the minibuffer.
+
+This command simply runs \"git push -v [ARGS] REMOTE\". ARGS
+are the arguments specified in the popup buffer. No refspec
+arguments are used. Instead the behavior depends on at least
+these Git variables: `push.default', `remote.pushDefault',
+`branch.<branch>.pushRemote', `branch.<branch>.remote',
+`branch.<branch>.merge', and `remote.<remote>.push'.
+
+\(fn REMOTE ARGS)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-push" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-reflog" "magit-reflog.el" (0 0 0 0))
+;;; Generated autoloads from magit-reflog.el
+
+(autoload 'magit-reflog-current "magit-reflog" "\
+Display the reflog of the current branch.
+If `HEAD' is detached, then show the reflog for that instead." t nil)
+
+(autoload 'magit-reflog-other "magit-reflog" "\
+Display the reflog of a branch or another ref.
+
+\(fn REF)" t nil)
+
+(autoload 'magit-reflog-head "magit-reflog" "\
+Display the `HEAD' reflog." t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-reflog" '("magit-reflog-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-refs" "magit-refs.el" (0 0 0 0))
+;;; Generated autoloads from magit-refs.el
+ (autoload 'magit-show-refs "magit-refs" nil t)
+
+(autoload 'magit-show-refs-head "magit-refs" "\
+List and compare references in a dedicated buffer.
+Compared with `HEAD'.
+
+\(fn &optional ARGS)" t nil)
+
+(autoload 'magit-show-refs-current "magit-refs" "\
+List and compare references in a dedicated buffer.
+Compare with the current branch or `HEAD' if it is detached.
+
+\(fn &optional ARGS)" t nil)
+
+(autoload 'magit-show-refs-other "magit-refs" "\
+List and compare references in a dedicated buffer.
+Compared with a branch read from the user.
+
+\(fn &optional REF ARGS)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-refs" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-remote" "magit-remote.el" (0 0 0 0))
+;;; Generated autoloads from magit-remote.el
+ (autoload 'magit-remote "magit-remote" nil t)
+
+(autoload 'magit-remote-add "magit-remote" "\
+Add a remote named REMOTE and fetch it.
+
+\(fn REMOTE URL &optional ARGS)" t nil)
+
+(autoload 'magit-remote-rename "magit-remote" "\
+Rename the remote named OLD to NEW.
+
+\(fn OLD NEW)" t nil)
+
+(autoload 'magit-remote-remove "magit-remote" "\
+Delete the remote named REMOTE.
+
+\(fn REMOTE)" t nil)
+
+(autoload 'magit-remote-prune "magit-remote" "\
+Remove stale remote-tracking branches for REMOTE.
+
+\(fn REMOTE)" t nil)
+
+(autoload 'magit-remote-prune-refspecs "magit-remote" "\
+Remove stale refspecs for REMOTE.
+
+A refspec is stale if there no longer exists at least one branch
+on the remote that would be fetched due to that refspec. A stale
+refspec is problematic because its existence causes Git to refuse
+to fetch according to the remaining non-stale refspecs.
+
+If only stale refspecs remain, then offer to either delete the
+remote or to replace the stale refspecs with the default refspec.
+
+Also remove the remote-tracking branches that were created due to
+the now stale refspecs. Other stale branches are not removed.
+
+\(fn REMOTE)" t nil)
+
+(autoload 'magit-remote-set-head "magit-remote" "\
+Set the local representation of REMOTE's default branch.
+Query REMOTE and set the symbolic-ref refs/remotes/<remote>/HEAD
+accordingly. With a prefix argument query for the branch to be
+used, which allows you to select an incorrect value if you fancy
+doing that.
+
+\(fn REMOTE &optional BRANCH)" t nil)
+
+(autoload 'magit-remote-unset-head "magit-remote" "\
+Unset the local representation of REMOTE's default branch.
+Delete the symbolic-ref \"refs/remotes/<remote>/HEAD\".
+
+\(fn REMOTE)" t nil)
+ (autoload 'magit-remote-configure "magit-remote" nil t)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-remote" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-repos" "magit-repos.el" (0 0 0 0))
+;;; Generated autoloads from magit-repos.el
+
+(autoload 'magit-list-repositories "magit-repos" "\
+Display a list of repositories.
+
+Use the options `magit-repository-directories' to control which
+repositories are displayed." t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-repos" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-reset" "magit-reset.el" (0 0 0 0))
+;;; Generated autoloads from magit-reset.el
+ (autoload 'magit-reset "magit" nil t)
+
+(autoload 'magit-reset-mixed "magit-reset" "\
+Reset the `HEAD' and index to COMMIT, but not the working tree.
+
+\(git reset --mixed COMMIT)
+
+\(fn COMMIT)" t nil)
+
+(autoload 'magit-reset-soft "magit-reset" "\
+Reset the `HEAD' to COMMIT, but not the index and working tree.
+
+\(git reset --soft REVISION)
+
+\(fn COMMIT)" t nil)
+
+(autoload 'magit-reset-hard "magit-reset" "\
+Reset the `HEAD', index, and working tree to COMMIT.
+
+\(git reset --hard REVISION)
+
+\(fn COMMIT)" t nil)
+
+(autoload 'magit-reset-keep "magit-reset" "\
+Reset the `HEAD' and index to COMMIT, while keeping uncommitted changes.
+
+\(git reset --keep REVISION)
+
+\(fn COMMIT)" t nil)
+
+(autoload 'magit-reset-index "magit-reset" "\
+Reset the index to COMMIT.
+Keep the `HEAD' and working tree as-is, so if COMMIT refers to the
+head this effectively unstages all changes.
+
+\(git reset COMMIT .)
+
+\(fn COMMIT)" t nil)
+
+(autoload 'magit-reset-worktree "magit-reset" "\
+Reset the worktree to COMMIT.
+Keep the `HEAD' and index as-is.
+
+\(fn COMMIT)" t nil)
+
+(autoload 'magit-reset-quickly "magit-reset" "\
+Reset the `HEAD' and index to COMMIT, and possibly the working tree.
+With a prefix argument reset the working tree otherwise don't.
+
+\(git reset --mixed|--hard COMMIT)
+
+\(fn COMMIT &optional HARD)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-reset" '("magit-reset-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-section" "magit-section.el" (0 0 0 0))
+;;; Generated autoloads from magit-section.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-section" '("isearch-clean-overlays@magit-mode" "magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-sequence" "magit-sequence.el" (0 0 0
+;;;;;; 0))
+;;; Generated autoloads from magit-sequence.el
+
+(autoload 'magit-sequencer-continue "magit-sequence" "\
+Resume the current cherry-pick or revert sequence." t nil)
+
+(autoload 'magit-sequencer-skip "magit-sequence" "\
+Skip the stopped at commit during a cherry-pick or revert sequence." t nil)
+
+(autoload 'magit-sequencer-abort "magit-sequence" "\
+Abort the current cherry-pick or revert sequence.
+This discards all changes made since the sequence started." t nil)
+ (autoload 'magit-cherry-pick "magit-sequence" nil t)
+
+(autoload 'magit-cherry-copy "magit-sequence" "\
+Copy COMMITS from another branch onto the current branch.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then pick all of them,
+without prompting.
+
+\(fn COMMITS &optional ARGS)" t nil)
+
+(autoload 'magit-cherry-apply "magit-sequence" "\
+Apply the changes in COMMITS but do not commit them.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then apply all of them,
+without prompting.
+
+\(fn COMMITS &optional ARGS)" t nil)
+
+(autoload 'magit-cherry-harvest "magit-sequence" "\
+Move COMMITS from another BRANCH onto the current branch.
+Remove the COMMITS from BRANCH and stay on the current branch.
+If a conflict occurs, then you have to fix that and finish the
+process manually.
+
+\(fn COMMITS BRANCH &optional ARGS)" t nil)
+
+(autoload 'magit-cherry-donate "magit-sequence" "\
+Move COMMITS from the current branch onto another existing BRANCH.
+Remove COMMITS from the current branch and stay on that branch.
+If a conflict occurs, then you have to fix that and finish the
+process manually.
+
+\(fn COMMITS BRANCH &optional ARGS)" t nil)
+
+(autoload 'magit-cherry-spinout "magit-sequence" "\
+Move COMMITS from the current branch onto a new BRANCH.
+Remove COMMITS from the current branch and stay on that branch.
+If a conflict occurs, then you have to fix that and finish the
+process manually.
+
+\(fn COMMITS BRANCH START-POINT &optional ARGS)" t nil)
+
+(autoload 'magit-cherry-spinoff "magit-sequence" "\
+Move COMMITS from the current branch onto a new BRANCH.
+Remove COMMITS from the current branch and checkout BRANCH.
+If a conflict occurs, then you have to fix that and finish
+the process manually.
+
+\(fn COMMITS BRANCH START-POINT &optional ARGS)" t nil)
+ (autoload 'magit-revert "magit-sequence" nil t)
+
+(autoload 'magit-revert-and-commit "magit-sequence" "\
+Revert COMMIT by creating a new commit.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then revert all of them,
+without prompting.
+
+\(fn COMMIT &optional ARGS)" t nil)
+
+(autoload 'magit-revert-no-commit "magit-sequence" "\
+Revert COMMIT by applying it in reverse to the worktree.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then revert all of them,
+without prompting.
+
+\(fn COMMIT &optional ARGS)" t nil)
+ (autoload 'magit-am "magit-sequence" nil t)
+
+(autoload 'magit-am-apply-patches "magit-sequence" "\
+Apply the patches FILES.
+
+\(fn &optional FILES ARGS)" t nil)
+
+(autoload 'magit-am-apply-maildir "magit-sequence" "\
+Apply the patches from MAILDIR.
+
+\(fn &optional MAILDIR ARGS)" t nil)
+
+(autoload 'magit-am-continue "magit-sequence" "\
+Resume the current patch applying sequence." t nil)
+
+(autoload 'magit-am-skip "magit-sequence" "\
+Skip the stopped at patch during a patch applying sequence." t nil)
+
+(autoload 'magit-am-abort "magit-sequence" "\
+Abort the current patch applying sequence.
+This discards all changes made since the sequence started." t nil)
+ (autoload 'magit-rebase "magit-sequence" nil t)
+ (autoload 'magit-rebase-onto-pushremote "magit-sequence" nil t)
+ (autoload 'magit-rebase-onto-upstream "magit-sequence" nil t)
+
+(autoload 'magit-rebase-branch "magit-sequence" "\
+Rebase the current branch onto a branch read in the minibuffer.
+All commits that are reachable from `HEAD' but not from the
+selected branch TARGET are being rebased.
+
+\(fn TARGET ARGS)" t nil)
+
+(autoload 'magit-rebase-subset "magit-sequence" "\
+Rebase a subset of the current branch's history onto a new base.
+Rebase commits from START to `HEAD' onto NEWBASE.
+START has to be selected from a list of recent commits.
+
+\(fn NEWBASE START ARGS)" t nil)
+
+(autoload 'magit-rebase-interactive "magit-sequence" "\
+Start an interactive rebase sequence.
+
+\(fn COMMIT ARGS)" t nil)
+
+(autoload 'magit-rebase-autosquash "magit-sequence" "\
+Combine squash and fixup commits with their intended targets.
+
+\(fn ARGS)" t nil)
+
+(autoload 'magit-rebase-edit-commit "magit-sequence" "\
+Edit a single older commit using rebase.
+
+\(fn COMMIT ARGS)" t nil)
+
+(autoload 'magit-rebase-reword-commit "magit-sequence" "\
+Reword a single older commit using rebase.
+
+\(fn COMMIT ARGS)" t nil)
+
+(autoload 'magit-rebase-remove-commit "magit-sequence" "\
+Remove a single older commit using rebase.
+
+\(fn COMMIT ARGS)" t nil)
+
+(autoload 'magit-rebase-continue "magit-sequence" "\
+Restart the current rebasing operation.
+In some cases this pops up a commit message buffer for you do
+edit. With a prefix argument the old message is reused as-is.
+
+\(fn &optional NOEDIT)" t nil)
+
+(autoload 'magit-rebase-skip "magit-sequence" "\
+Skip the current commit and restart the current rebase operation." t nil)
+
+(autoload 'magit-rebase-edit "magit-sequence" "\
+Edit the todo list of the current rebase operation." t nil)
+
+(autoload 'magit-rebase-abort "magit-sequence" "\
+Abort the current rebase operation, restoring the original branch." t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-sequence" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-stash" "magit-stash.el" (0 0 0 0))
+;;; Generated autoloads from magit-stash.el
+ (autoload 'magit-stash "magit-stash" nil t)
+
+(autoload 'magit-stash-both "magit-stash" "\
+Create a stash of the index and working tree.
+Untracked files are included according to infix arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'.
+
+\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
+
+(autoload 'magit-stash-index "magit-stash" "\
+Create a stash of the index only.
+Unstaged and untracked changes are not stashed. The stashed
+changes are applied in reverse to both the index and the
+worktree. This command can fail when the worktree is not clean.
+Applying the resulting stash has the inverse effect.
+
+\(fn MESSAGE)" t nil)
+
+(autoload 'magit-stash-worktree "magit-stash" "\
+Create a stash of unstaged changes in the working tree.
+Untracked files are included according to infix arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'.
+
+\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
+
+(autoload 'magit-stash-keep-index "magit-stash" "\
+Create a stash of the index and working tree, keeping index intact.
+Untracked files are included according to infix arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'.
+
+\(fn MESSAGE &optional INCLUDE-UNTRACKED)" t nil)
+
+(autoload 'magit-snapshot-both "magit-stash" "\
+Create a snapshot of the index and working tree.
+Untracked files are included according to infix arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'.
+
+\(fn &optional INCLUDE-UNTRACKED)" t nil)
+
+(autoload 'magit-snapshot-index "magit-stash" "\
+Create a snapshot of the index only.
+Unstaged and untracked changes are not stashed." t nil)
+
+(autoload 'magit-snapshot-worktree "magit-stash" "\
+Create a snapshot of unstaged changes in the working tree.
+Untracked files are included according to infix arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'.
+
+\(fn &optional INCLUDE-UNTRACKED)" t nil)
+
+(autoload 'magit-stash-apply "magit-stash" "\
+Apply a stash to the working tree.
+Try to preserve the stash index. If that fails because there
+are staged changes, apply without preserving the stash index.
+
+\(fn STASH)" t nil)
+
+(autoload 'magit-stash-drop "magit-stash" "\
+Remove a stash from the stash list.
+When the region is active offer to drop all contained stashes.
+
+\(fn STASH)" t nil)
+
+(autoload 'magit-stash-clear "magit-stash" "\
+Remove all stashes saved in REF's reflog by deleting REF.
+
+\(fn REF)" t nil)
+
+(autoload 'magit-stash-branch "magit-stash" "\
+Create and checkout a new BRANCH from STASH.
+
+\(fn STASH BRANCH)" t nil)
+
+(autoload 'magit-stash-branch-here "magit-stash" "\
+Create and checkout a new BRANCH and apply STASH.
+The branch is created using `magit-branch-and-checkout', using the
+current branch or `HEAD' as the start-point.
+
+\(fn STASH BRANCH)" t nil)
+
+(autoload 'magit-stash-format-patch "magit-stash" "\
+Create a patch from STASH
+
+\(fn STASH)" t nil)
+
+(autoload 'magit-stash-list "magit-stash" "\
+List all stashes in a buffer." t nil)
+
+(autoload 'magit-stash-show "magit-stash" "\
+Show all diffs of a stash in a buffer.
+
+\(fn STASH &optional ARGS FILES)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-stash" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-status" "magit-status.el" (0 0 0 0))
+;;; Generated autoloads from magit-status.el
+
+(autoload 'magit-init "magit-status" "\
+Initialize a Git repository, then show its status.
+
+If the directory is below an existing repository, then the user
+has to confirm that a new one should be created inside. If the
+directory is the root of the existing repository, then the user
+has to confirm that it should be reinitialized.
+
+Non-interactively DIRECTORY is (re-)initialized unconditionally.
+
+\(fn DIRECTORY)" t nil)
+
+(autoload 'magit-status "magit-status" "\
+Show the status of the current Git repository in a buffer.
+
+If the current directory isn't located within a Git repository,
+then prompt for an existing repository or an arbitrary directory,
+depending on option `magit-repository-directories', and show the
+status of the selected repository instead.
+
+* If that option specifies any existing repositories, then offer
+ those for completion and show the status buffer for the
+ selected one.
+
+* Otherwise read an arbitrary directory using regular file-name
+ completion. If the selected directory is the top-level of an
+ existing working tree, then show the status buffer for that.
+
+* Otherwise offer to initialize the selected directory as a new
+ repository. After creating the repository show its status
+ buffer.
+
+These fallback behaviors can also be forced using one or more
+prefix arguments:
+
+* With two prefix arguments (or more precisely a numeric prefix
+ value of 16 or greater) read an arbitrary directory and act on
+ it as described above. The same could be accomplished using
+ the command `magit-init'.
+
+* With a single prefix argument read an existing repository, or
+ if none can be found based on `magit-repository-directories',
+ then fall back to the same behavior as with two prefix
+ arguments.
+
+\(fn &optional DIRECTORY CACHE)" t nil)
+
+(defalias 'magit 'magit-status "\
+An alias for `magit-status' for better discoverability.
+
+Instead of invoking this alias for `magit-status' using
+\"M-x magit RET\", you should bind a key to `magit-status'
+and read the info node `(magit)Getting Started', which
+also contains other useful hints.")
+
+(autoload 'magit-status-here "magit-status" "\
+Like `magit-status' but with non-nil `magit-status-goto-file-position'." t nil)
+
+(autoload 'magit-status-setup-buffer "magit-status" "\
+
+
+\(fn &optional DIRECTORY)" nil nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-status" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-submodule" "magit-submodule.el" (0 0
+;;;;;; 0 0))
+;;; Generated autoloads from magit-submodule.el
+ (autoload 'magit-submodule "magit-submodule" nil t)
+ (autoload 'magit-submodule-add "magit-submodule" nil t)
+
+(autoload 'magit-submodule-read-name-for-path "magit-submodule" "\
+
+
+\(fn PATH &optional PREFER-SHORT)" nil nil)
+ (autoload 'magit-submodule-register "magit-submodule" nil t)
+ (autoload 'magit-submodule-populate "magit-submodule" nil t)
+ (autoload 'magit-submodule-update "magit-submodule" nil t)
+ (autoload 'magit-submodule-synchronize "magit-submodule" nil t)
+ (autoload 'magit-submodule-unpopulate "magit-submodule" nil t)
+
+(autoload 'magit-submodule-remove "magit-submodule" "\
+Unregister MODULES and remove their working directories.
+
+For safety reasons, do not remove the gitdirs and if a module has
+uncommitted changes, then do not remove it at all. If a module's
+gitdir is located inside the working directory, then move it into
+the gitdir of the superproject first.
+
+With the \"--force\" argument offer to remove dirty working
+directories and with a prefix argument offer to delete gitdirs.
+Both actions are very dangerous and have to be confirmed. There
+are additional safety precautions in place, so you might be able
+to recover from making a mistake here, but don't count on it.
+
+\(fn MODULES ARGS TRASH-GITDIRS)" t nil)
+
+(autoload 'magit-insert-modules "magit-submodule" "\
+Insert submodule sections.
+Hook `magit-module-sections-hook' controls which module sections
+are inserted, and option `magit-module-sections-nested' controls
+whether they are wrapped in an additional section." nil nil)
+
+(autoload 'magit-insert-modules-overview "magit-submodule" "\
+Insert sections for all modules.
+For each section insert the path and the output of `git describe --tags',
+or, failing that, the abbreviated HEAD commit hash." nil nil)
+
+(autoload 'magit-insert-modules-unpulled-from-upstream "magit-submodule" "\
+Insert sections for modules that haven't been pulled from the upstream.
+These sections can be expanded to show the respective commits." nil nil)
+
+(autoload 'magit-insert-modules-unpulled-from-pushremote "magit-submodule" "\
+Insert sections for modules that haven't been pulled from the push-remote.
+These sections can be expanded to show the respective commits." nil nil)
+
+(autoload 'magit-insert-modules-unpushed-to-upstream "magit-submodule" "\
+Insert sections for modules that haven't been pushed to the upstream.
+These sections can be expanded to show the respective commits." nil nil)
+
+(autoload 'magit-insert-modules-unpushed-to-pushremote "magit-submodule" "\
+Insert sections for modules that haven't been pushed to the push-remote.
+These sections can be expanded to show the respective commits." nil nil)
+
+(autoload 'magit-list-submodules "magit-submodule" "\
+Display a list of the current repository's submodules." t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-submodule" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-subtree" "magit-subtree.el" (0 0 0 0))
+;;; Generated autoloads from magit-subtree.el
+ (autoload 'magit-subtree "magit-subtree" nil t)
+ (autoload 'magit-subtree-import "magit-subtree" nil t)
+ (autoload 'magit-subtree-export "magit-subtree" nil t)
+
+(autoload 'magit-subtree-add "magit-subtree" "\
+Add REF from REPOSITORY as a new subtree at PREFIX.
+
+\(fn PREFIX REPOSITORY REF ARGS)" t nil)
+
+(autoload 'magit-subtree-add-commit "magit-subtree" "\
+Add COMMIT as a new subtree at PREFIX.
+
+\(fn PREFIX COMMIT ARGS)" t nil)
+
+(autoload 'magit-subtree-merge "magit-subtree" "\
+Merge COMMIT into the PREFIX subtree.
+
+\(fn PREFIX COMMIT ARGS)" t nil)
+
+(autoload 'magit-subtree-pull "magit-subtree" "\
+Pull REF from REPOSITORY into the PREFIX subtree.
+
+\(fn PREFIX REPOSITORY REF ARGS)" t nil)
+
+(autoload 'magit-subtree-push "magit-subtree" "\
+Extract the history of the subtree PREFIX and push it to REF on REPOSITORY.
+
+\(fn PREFIX REPOSITORY REF ARGS)" t nil)
+
+(autoload 'magit-subtree-split "magit-subtree" "\
+Extract the history of the subtree PREFIX.
+
+\(fn PREFIX COMMIT ARGS)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-subtree" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-tag" "magit-tag.el" (0 0 0 0))
+;;; Generated autoloads from magit-tag.el
+ (autoload 'magit-tag "magit" nil t)
+
+(autoload 'magit-tag-create "magit-tag" "\
+Create a new tag with the given NAME at REV.
+With a prefix argument annotate the tag.
+
+\(git tag [--annotate] NAME REV)
+
+\(fn NAME REV &optional ARGS)" t nil)
+
+(autoload 'magit-tag-delete "magit-tag" "\
+Delete one or more tags.
+If the region marks multiple tags (and nothing else), then offer
+to delete those, otherwise prompt for a single tag to be deleted,
+defaulting to the tag at point.
+
+\(git tag -d TAGS)
+
+\(fn TAGS)" t nil)
+
+(autoload 'magit-tag-prune "magit-tag" "\
+Offer to delete tags missing locally from REMOTE, and vice versa.
+
+\(fn TAGS REMOTE-TAGS REMOTE)" t nil)
+
+(autoload 'magit-tag-release "magit-tag" "\
+Create a release tag.
+
+Assume that release tags match `magit-release-tag-regexp'.
+
+First prompt for the name of the new tag using the highest
+existing tag as initial input and leaving it to the user to
+increment the desired part of the version string.
+
+If `--annotate' is enabled, then prompt for the message of the
+new tag. Base the proposed tag message on the message of the
+highest tag, provided that that contains the corresponding
+version string and substituting the new version string for that.
+Otherwise propose something like \"Foo-Bar 1.2.3\", given, for
+example, a TAG \"v1.2.3\" and a repository located at something
+like \"/path/to/foo-bar\".
+
+\(fn TAG MSG &optional ARGS)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-tag" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-transient" "magit-transient.el" (0 0
+;;;;;; 0 0))
+;;; Generated autoloads from magit-transient.el
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-transient" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-utils" "magit-utils.el" (0 0 0 0))
+;;; Generated autoloads from magit-utils.el
+
+(autoload 'magit-emacs-Q-command "magit-utils" "\
+Show a shell command that runs an uncustomized Emacs with only Magit loaded.
+See info node `(magit)Debugging Tools' for more information." t nil)
+
+(autoload 'Info-follow-nearest-node--magit-gitman "magit-utils" "\
+
+
+\(fn FN &optional FORK)" nil nil)
+
+(advice-add 'Info-follow-nearest-node :around 'Info-follow-nearest-node--magit-gitman)
+
+(autoload 'org-man-export--magit-gitman "magit-utils" "\
+
+
+\(fn FN LINK DESCRIPTION FORMAT)" nil nil)
+
+(advice-add 'org-man-export :around 'org-man-export--magit-gitman)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-utils" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-wip" "magit-wip.el" (0 0 0 0))
+;;; Generated autoloads from magit-wip.el
+
+(defvar magit-wip-mode nil "\
+Non-nil if Magit-Wip mode is enabled.
+See the `magit-wip-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `magit-wip-mode'.")
+
+(custom-autoload 'magit-wip-mode "magit-wip" nil)
+
+(autoload 'magit-wip-mode "magit-wip" "\
+Save uncommitted changes to work-in-progress refs.
+
+If called interactively, enable Magit-Wip mode if ARG is
+positive, and disable it if ARG is zero or negative. If called
+from Lisp, also enable the mode if ARG is omitted or nil, and
+toggle it if ARG is `toggle'; disable the mode otherwise.
+
+Whenever appropriate (i.e. when dataloss would be a possibility
+otherwise) this mode causes uncommitted changes to be committed
+to dedicated work-in-progress refs.
+
+For historic reasons this mode is implemented on top of four
+other `magit-wip-*' modes, which can also be used individually,
+if you want finer control over when the wip refs are updated;
+but that is discouraged.
+
+\(fn &optional ARG)" t nil)
+
+(put 'magit-wip-after-save-mode 'globalized-minor-mode t)
+
+(defvar magit-wip-after-save-mode nil "\
+Non-nil if Magit-Wip-After-Save mode is enabled.
+See the `magit-wip-after-save-mode' command
+for a description of this minor mode.
+Setting this variable directly does not take effect;
+either customize it (see the info node `Easy Customization')
+or call the function `magit-wip-after-save-mode'.")
+
+(custom-autoload 'magit-wip-after-save-mode "magit-wip" nil)
+
+(autoload 'magit-wip-after-save-mode "magit-wip" "\
+Toggle Magit-Wip-After-Save-Local mode in all buffers.
+With prefix ARG, enable Magit-Wip-After-Save mode if ARG is positive;
+otherwise, disable it. If called from Lisp, enable the mode if
+ARG is omitted or nil.
+
+Magit-Wip-After-Save-Local mode is enabled in all buffers where
+`magit-wip-after-save-local-mode-turn-on' would do it.
+See `magit-wip-after-save-local-mode' for more information on Magit-Wip-After-Save-Local mode.
+
+\(fn &optional ARG)" t nil)
+
+(defvar magit-wip-after-apply-mode nil "\
+Non-nil if Magit-Wip-After-Apply mode is enabled.
+See the `magit-wip-after-apply-mode' command
+for a description of this minor mode.")
+
+(custom-autoload 'magit-wip-after-apply-mode "magit-wip" nil)
+
+(autoload 'magit-wip-after-apply-mode "magit-wip" "\
+Commit to work-in-progress refs.
+
+If called interactively, enable Magit-Wip-After-Apply mode if ARG
+is positive, and disable it if ARG is zero or negative. If
+called from Lisp, also enable the mode if ARG is omitted or nil,
+and toggle it if ARG is `toggle'; disable the mode otherwise.
+
+After applying a change using any \"apply variant\"
+command (apply, stage, unstage, discard, and reverse) commit the
+affected files to the current wip refs. For each branch there
+may be two wip refs; one contains snapshots of the files as found
+in the worktree and the other contains snapshots of the entries
+in the index.
+
+\(fn &optional ARG)" t nil)
+
+(defvar magit-wip-before-change-mode nil "\
+Non-nil if Magit-Wip-Before-Change mode is enabled.
+See the `magit-wip-before-change-mode' command
+for a description of this minor mode.")
+
+(custom-autoload 'magit-wip-before-change-mode "magit-wip" nil)
+
+(autoload 'magit-wip-before-change-mode "magit-wip" "\
+Commit to work-in-progress refs before certain destructive changes.
+
+If called interactively, enable Magit-Wip-Before-Change mode if
+ARG is positive, and disable it if ARG is zero or negative. If
+called from Lisp, also enable the mode if ARG is omitted or nil,
+and toggle it if ARG is `toggle'; disable the mode otherwise.
+
+Before invoking a revert command or an \"apply variant\"
+command (apply, stage, unstage, discard, and reverse) commit the
+affected tracked files to the current wip refs. For each branch
+there may be two wip refs; one contains snapshots of the files
+as found in the worktree and the other contains snapshots of the
+entries in the index.
+
+Only changes to files which could potentially be affected by the
+command which is about to be called are committed.
+
+\(fn &optional ARG)" t nil)
+
+(autoload 'magit-wip-commit-initial-backup "magit-wip" "\
+Before saving, commit current file to a worktree wip ref.
+
+The user has to add this function to `before-save-hook'.
+
+Commit the current state of the visited file before saving the
+current buffer to that file. This backs up the same version of
+the file as `backup-buffer' would, but stores the backup in the
+worktree wip ref, which is also used by the various Magit Wip
+modes, instead of in a backup file as `backup-buffer' would.
+
+This function ignores the variables that affect `backup-buffer'
+and can be used along-side that function, which is recommended
+because this function only backs up files that are tracked in
+a Git repository." nil nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-wip" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil "magit-worktree" "magit-worktree.el" (0 0 0
+;;;;;; 0))
+;;; Generated autoloads from magit-worktree.el
+ (autoload 'magit-worktree "magit-worktree" nil t)
+
+(autoload 'magit-worktree-checkout "magit-worktree" "\
+Checkout BRANCH in a new worktree at PATH.
+
+\(fn PATH BRANCH)" t nil)
+
+(autoload 'magit-worktree-branch "magit-worktree" "\
+Create a new BRANCH and check it out in a new worktree at PATH.
+
+\(fn PATH BRANCH START-POINT &optional FORCE)" t nil)
+
+(autoload 'magit-worktree-move "magit-worktree" "\
+Move WORKTREE to PATH.
+
+\(fn WORKTREE PATH)" t nil)
+
+(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-worktree" '("magit-")))
+
+;;;***
+\f
+;;;### (autoloads nil nil ("magit-core.el" "magit-pkg.el") (0 0 0
+;;;;;; 0))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; coding: utf-8
+;; End:
+;;; magit-autoloads.el ends here
--- /dev/null
+;;; magit-autorevert.el --- revert buffers when files in repository change -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Code:
+
+(require 'magit-git)
+
+(require 'autorevert)
+
+;;; Options
+
+(defgroup magit-auto-revert nil
+ "Revert buffers when files in repository change."
+ :link '(custom-group-link auto-revert)
+ :link '(info-link "(magit)Automatic Reverting of File-Visiting Buffers")
+ :group 'auto-revert
+ :group 'magit-essentials
+ :group 'magit-modes)
+
+(defcustom auto-revert-buffer-list-filter nil
+ "Filter that determines which buffers `auto-revert-buffers' reverts.
+
+This option is provided by Magit, which also advises
+`auto-revert-buffers' to respect it. Magit users who do not turn
+on the local mode `auto-revert-mode' themselves, are best served
+by setting the value to `magit-auto-revert-repository-buffer-p'.
+
+However the default is nil, so as not to disturb users who do use
+the local mode directly. If you experience delays when running
+Magit commands, then you should consider using one of the
+predicates provided by Magit - especially if you also use Tramp.
+
+Users who do turn on `auto-revert-mode' in buffers in which Magit
+doesn't do that for them, should likely not use any filter.
+Users who turn on `global-auto-revert-mode', do not have to worry
+about this option, because it is disregarded if the global mode
+is enabled."
+ :package-version '(magit . "2.4.2")
+ :group 'auto-revert
+ :group 'magit-auto-revert
+ :group 'magit-related
+ :type '(radio (const :tag "No filter" nil)
+ (function-item magit-auto-revert-buffer-p)
+ (function-item magit-auto-revert-repository-buffer-p)
+ function))
+
+(defcustom magit-auto-revert-tracked-only t
+ "Whether `magit-auto-revert-mode' only reverts tracked files."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-auto-revert
+ :type 'boolean
+ :set (lambda (var val)
+ (set var val)
+ (when (and (bound-and-true-p magit-auto-revert-mode)
+ (featurep 'magit-autorevert))
+ (magit-auto-revert-mode -1)
+ (magit-auto-revert-mode))))
+
+(defcustom magit-auto-revert-immediately t
+ "Whether Magit reverts buffers immediately.
+
+If this is non-nil and either `global-auto-revert-mode' or
+`magit-auto-revert-mode' is enabled, then Magit immediately
+reverts buffers by explicitly calling `auto-revert-buffers'
+after running Git for side-effects.
+
+If `auto-revert-use-notify' is non-nil (and file notifications
+are actually supported), then `magit-auto-revert-immediately'
+does not have to be non-nil, because the reverts happen
+immediately anyway.
+
+If `magit-auto-revert-immediately' and `auto-revert-use-notify'
+are both nil, then reverts happen after `auto-revert-interval'
+seconds of user inactivity. That is not desirable."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-auto-revert
+ :type 'boolean)
+
+;;; Mode
+
+(defun magit-turn-on-auto-revert-mode-if-desired (&optional file)
+ (if file
+ (--when-let (find-buffer-visiting file)
+ (with-current-buffer it
+ (magit-turn-on-auto-revert-mode-if-desired)))
+ (when (and buffer-file-name
+ (file-readable-p buffer-file-name)
+ (or (< emacs-major-version 27)
+ (with-no-warnings
+ (condition-case nil
+ (executable-find magit-git-executable t) ; see #3684
+ (wrong-number-of-arguments t)))) ; very old 27 built
+ (magit-toplevel)
+ (or (not magit-auto-revert-tracked-only)
+ (magit-file-tracked-p buffer-file-name))
+ (not auto-revert-mode) ; see #3014
+ (not global-auto-revert-mode)) ; see #3460
+ (auto-revert-mode 1))))
+
+;;;###autoload
+(define-globalized-minor-mode magit-auto-revert-mode auto-revert-mode
+ magit-turn-on-auto-revert-mode-if-desired
+ :package-version '(magit . "2.4.0")
+ :link '(info-link "(magit)Automatic Reverting of File-Visiting Buffers")
+ :group 'magit-auto-revert
+ :group 'magit-essentials
+ ;; - When `global-auto-revert-mode' is enabled, then this mode is
+ ;; redundant.
+ ;; - In all other cases enable the mode because if buffers are not
+ ;; automatically reverted that would make many very common tasks
+ ;; much more cumbersome.
+ :init-value (not (or global-auto-revert-mode
+ noninteractive)))
+;; - Unfortunately `:init-value t' only sets the value of the mode
+;; variable but does not cause the mode function to be called.
+;; - I don't think it works like this on purpose, but since one usually
+;; should not enable global modes by default, it is understandable.
+;; - If the user has set the variable `magit-auto-revert-mode' to nil
+;; after loading magit (instead of doing so before loading magit or
+;; by using the function), then we should still respect that setting.
+;; - If the user sets one of these variables after loading magit and
+;; after `after-init-hook' has run, then that won't have an effect
+;; and there is nothing we can do about it.
+(defun magit-auto-revert-mode--init-kludge ()
+ "This is an internal kludge to be used on `after-init-hook'.
+Do not use this function elsewhere, and don't remove it from
+the `after-init-hook'. For more information see the comments
+and code surrounding the definition of this function."
+ (if magit-auto-revert-mode
+ (let ((start (current-time)))
+ (magit-message "Turning on magit-auto-revert-mode...")
+ (magit-auto-revert-mode 1)
+ (magit-message
+ "Turning on magit-auto-revert-mode...done%s"
+ (let ((elapsed (float-time (time-subtract nil start))))
+ (if (> elapsed 0.2)
+ (format " (%.3fs, %s buffers checked)" elapsed
+ (length (buffer-list)))
+ ""))))
+ (magit-auto-revert-mode -1)))
+(if after-init-time
+ ;; Since `after-init-hook' has already been
+ ;; run, turn the mode on or off right now.
+ (magit-auto-revert-mode--init-kludge)
+ ;; By the time the init file has been fully loaded the
+ ;; values of the relevant variables might have changed.
+ (add-hook 'after-init-hook #'magit-auto-revert-mode--init-kludge t))
+
+(put 'magit-auto-revert-mode 'function-documentation
+ "Toggle Magit Auto Revert mode.
+If called interactively, enable Magit Auto Revert mode if ARG is
+positive, and disable it if ARG is zero or negative. If called
+from Lisp, also enable the mode if ARG is omitted or nil, and
+toggle it if ARG is `toggle'; disable the mode otherwise.
+
+Magit Auto Revert mode is a global minor mode that reverts
+buffers associated with a file that is located inside a Git
+repository when the file changes on disk. Use `auto-revert-mode'
+to revert a particular buffer. Or use `global-auto-revert-mode'
+to revert all file-visiting buffers, not just those that visit
+a file located inside a Git repository.
+
+This global mode works by turning on the buffer-local mode
+`auto-revert-mode' at the time a buffer is first created. The
+local mode is turned on if the visited file is being tracked in
+a Git repository at the time when the buffer is created.
+
+If `magit-auto-revert-tracked-only' is non-nil (the default),
+then only tracked files are reverted. But if you stage a
+previously untracked file using `magit-stage', then this mode
+notices that.
+
+Unlike `global-auto-revert-mode', this mode never reverts any
+buffers that are not visiting files.
+
+The behavior of this mode can be customized using the options
+in the `autorevert' and `magit-autorevert' groups.
+
+This function calls the hook `magit-auto-revert-mode-hook'.
+
+Like nearly every mode, this mode should be enabled or disabled
+by calling the respective mode function, the reason being that
+changing the state of a mode involves more than merely toggling
+a single switch, so setting the mode variable is not enough.
+Also, you should not use `after-init-hook' to disable this mode.")
+
+(defun magit-auto-revert-buffers ()
+ (when (and magit-auto-revert-immediately
+ (or global-auto-revert-mode
+ (and magit-auto-revert-mode auto-revert-buffer-list)))
+ (let ((auto-revert-buffer-list-filter
+ (or auto-revert-buffer-list-filter
+ #'magit-auto-revert-repository-buffer-p)))
+ (auto-revert-buffers))))
+
+(defvar magit-auto-revert-toplevel nil)
+
+(defvar magit-auto-revert-counter 1
+ "Incremented each time `auto-revert-buffers' is called.")
+
+(defun magit-auto-revert-buffer-p (buffer)
+ "Return non-nil if BUFFER visits a file inside the current repository.
+The current repository is the one containing `default-directory'.
+If there is no current repository, then return t for any BUFFER."
+ (magit-auto-revert-repository-buffer-p buffer t))
+
+(defun magit-auto-revert-repository-buffer-p (buffer &optional fallback)
+ "Return non-nil if BUFFER visits a file inside the current repository.
+The current repository is the one containing `default-directory'.
+If there is no current repository, then return FALLBACK (which
+defaults to nil) for any BUFFER."
+ ;; Call `magit-toplevel' just once per cycle.
+ (unless (and magit-auto-revert-toplevel
+ (= (cdr magit-auto-revert-toplevel)
+ magit-auto-revert-counter))
+ (setq magit-auto-revert-toplevel
+ (cons (or (magit-toplevel) 'no-repo)
+ magit-auto-revert-counter)))
+ (let ((top (car magit-auto-revert-toplevel)))
+ (if (eq top 'no-repo)
+ fallback
+ (let ((dir (buffer-local-value 'default-directory buffer)))
+ (and (equal (file-remote-p dir)
+ (file-remote-p top))
+ ;; ^ `tramp-handle-file-in-directory-p' lacks this optimization.
+ (file-in-directory-p dir top))))))
+
+(defun auto-revert-buffers--buffer-list-filter (fn)
+ (cl-incf magit-auto-revert-counter)
+ (if (or global-auto-revert-mode
+ (not auto-revert-buffer-list)
+ (not auto-revert-buffer-list-filter))
+ (funcall fn)
+ (let ((auto-revert-buffer-list
+ (-filter auto-revert-buffer-list-filter
+ auto-revert-buffer-list)))
+ (funcall fn))
+ (unless auto-revert-timer
+ (auto-revert-set-timer))))
+
+(advice-add 'auto-revert-buffers :around
+ 'auto-revert-buffers--buffer-list-filter)
+
+;;; _
+(provide 'magit-autorevert)
+;;; magit-autorevert.el ends here
--- /dev/null
+;;; magit-bisect.el --- bisect support for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2011-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; Use a binary search to find the commit that introduced a bug.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Options
+
+(defcustom magit-bisect-show-graph t
+ "Whether to use `--graph' in the log showing commits yet to be bisected."
+ :package-version '(magit . "2.8.0")
+ :group 'magit-status
+ :type 'boolean)
+
+(defface magit-bisect-good
+ '((t :foreground "DarkOliveGreen"))
+ "Face for good bisect revisions."
+ :group 'magit-faces)
+
+(defface magit-bisect-skip
+ '((t :foreground "DarkGoldenrod"))
+ "Face for skipped bisect revisions."
+ :group 'magit-faces)
+
+(defface magit-bisect-bad
+ '((t :foreground "IndianRed4"))
+ "Face for bad bisect revisions."
+ :group 'magit-faces)
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-bisect "magit-bisect" nil t)
+(transient-define-prefix magit-bisect ()
+ "Narrow in on the commit that introduced a bug."
+ :man-page "git-bisect"
+ [:class transient-subgroups
+ :if-not magit-bisect-in-progress-p
+ ["Arguments"
+ ("-n" "Don't checkout commits" "--no-checkout")
+ ("-p" "Follow only first parent of a merge" "--first-parent"
+ :if (lambda () (version<= "2.29" (magit-git-version))))
+ (6 magit-bisect:--term-old
+ :if (lambda () (version<= "2.7" (magit-git-version))))
+ (6 magit-bisect:--term-new
+ :if (lambda () (version<= "2.7" (magit-git-version))))]
+ ["Actions"
+ ("B" "Start" magit-bisect-start)
+ ("s" "Start script" magit-bisect-run)]]
+ ["Actions"
+ :if magit-bisect-in-progress-p
+ ("B" "Bad" magit-bisect-bad)
+ ("g" "Good" magit-bisect-good)
+ (6 "m" "Mark" magit-bisect-mark
+ :if (lambda () (version<= "2.7" (magit-git-version))))
+ ("k" "Skip" magit-bisect-skip)
+ ("r" "Reset" magit-bisect-reset)
+ ("s" "Run script" magit-bisect-run)])
+
+(transient-define-argument magit-bisect:--term-old ()
+ :description "Old/good term"
+ :class 'transient-option
+ :key "=o"
+ :argument "--term-old=")
+
+(transient-define-argument magit-bisect:--term-new ()
+ :description "New/bad term"
+ :class 'transient-option
+ :key "=n"
+ :argument "--term-new=")
+
+;;;###autoload
+(defun magit-bisect-start (bad good args)
+ "Start a bisect session.
+
+Bisecting a bug means to find the commit that introduced it.
+This command starts such a bisect session by asking for a known
+good and a known bad commit. To move the session forward use the
+other actions from the bisect transient command (\
+\\<magit-status-mode-map>\\[magit-bisect])."
+ (interactive (if (magit-bisect-in-progress-p)
+ (user-error "Already bisecting")
+ (magit-bisect-start-read-args)))
+ (unless (magit-rev-ancestor-p good bad)
+ (user-error
+ "The %s revision (%s) has to be an ancestor of the %s one (%s)"
+ (or (transient-arg-value "--term-old=" args) "good")
+ good
+ (or (transient-arg-value "--term-new=" args) "bad")
+ bad))
+ (when (magit-anything-modified-p)
+ (user-error "Cannot bisect with uncommitted changes"))
+ (magit-git-bisect "start" (list args bad good) t))
+
+(defun magit-bisect-start-read-args ()
+ (let* ((args (transient-args 'magit-bisect))
+ (bad (magit-read-branch-or-commit
+ (format "Start bisect with %s revision"
+ (or (transient-arg-value "--term-new=" args)
+ "bad")))))
+ (list bad
+ (magit-read-other-branch-or-commit
+ (format "%s revision" (or (transient-arg-value "--term-old=" args)
+ "Good"))
+ bad)
+ args)))
+
+;;;###autoload
+(defun magit-bisect-reset ()
+ "After bisecting, cleanup bisection state and return to original `HEAD'."
+ (interactive)
+ (magit-confirm 'reset-bisect)
+ (magit-run-git "bisect" "reset")
+ (ignore-errors (delete-file (magit-git-dir "BISECT_CMD_OUTPUT"))))
+
+;;;###autoload
+(defun magit-bisect-good ()
+ "While bisecting, mark the current commit as good.
+Use this after you have asserted that the commit does not contain
+the bug in question."
+ (interactive)
+ (magit-git-bisect (or (cadr (magit-bisect-terms))
+ (user-error "Not bisecting"))))
+
+;;;###autoload
+(defun magit-bisect-bad ()
+ "While bisecting, mark the current commit as bad.
+Use this after you have asserted that the commit does contain the
+bug in question."
+ (interactive)
+ (magit-git-bisect (or (car (magit-bisect-terms))
+ (user-error "Not bisecting"))))
+
+;;;###autoload
+(defun magit-bisect-mark ()
+ "While bisecting, mark the current commit with a bisect term.
+During a bisect using alternate terms, commits can still be
+marked with `magit-bisect-good' and `magit-bisect-bad', as those
+commands map to the correct term (\"good\" to --term-old's value
+and \"bad\" to --term-new's). However, in some cases, it can be
+difficult to keep that mapping straight in your head; this
+command provides an interface that exposes the underlying terms."
+ (interactive)
+ (magit-git-bisect
+ (pcase-let ((`(,term-new ,term-old) (or (magit-bisect-terms)
+ (user-error "Not bisecting"))))
+ (pcase (read-char-choice
+ (format "Mark HEAD as %s ([n]ew) or %s ([o]ld)"
+ term-new term-old)
+ (list ?n ?o))
+ (?n term-new)
+ (?o term-old)))))
+
+;;;###autoload
+(defun magit-bisect-skip ()
+ "While bisecting, skip the current commit.
+Use this if for some reason the current commit is not a good one
+to test. This command lets Git choose a different one."
+ (interactive)
+ (magit-git-bisect "skip"))
+
+;;;###autoload
+(defun magit-bisect-run (cmdline &optional bad good args)
+ "Bisect automatically by running commands after each step.
+
+Unlike `git bisect run' this can be used before bisecting has
+begun. In that case it behaves like `git bisect start; git
+bisect run'."
+ (interactive (let ((args (and (not (magit-bisect-in-progress-p))
+ (magit-bisect-start-read-args))))
+ (cons (read-shell-command "Bisect shell command: ") args)))
+ (when (and bad good)
+ (magit-bisect-start bad good args))
+ (magit-git-bisect "run" (list shell-file-name shell-command-switch cmdline)))
+
+(defun magit-git-bisect (subcommand &optional args no-assert)
+ (unless (or no-assert (magit-bisect-in-progress-p))
+ (user-error "Not bisecting"))
+ (message "Bisecting...")
+ (magit-with-toplevel
+ (magit-run-git-async "bisect" subcommand args))
+ (set-process-sentinel
+ magit-this-process
+ (lambda (process event)
+ (when (memq (process-status process) '(exit signal))
+ (if (> (process-exit-status process) 0)
+ (magit-process-sentinel process event)
+ (process-put process 'inhibit-refresh t)
+ (magit-process-sentinel process event)
+ (when (buffer-live-p (process-buffer process))
+ (with-current-buffer (process-buffer process)
+ (when-let ((section (get-text-property (point) 'magit-section))
+ (output (buffer-substring-no-properties
+ (oref section content)
+ (oref section end))))
+ (with-temp-file (magit-git-dir "BISECT_CMD_OUTPUT")
+ (insert output)))))
+ (magit-refresh))
+ (message "Bisecting...done")))))
+
+;;; Sections
+
+(defun magit-bisect-in-progress-p ()
+ (file-exists-p (magit-git-dir "BISECT_LOG")))
+
+(defun magit-bisect-terms ()
+ (magit-file-lines (magit-git-dir "BISECT_TERMS")))
+
+(defun magit-insert-bisect-output ()
+ "While bisecting, insert section with output from `git bisect'."
+ (when (magit-bisect-in-progress-p)
+ (let* ((lines
+ (or (magit-file-lines (magit-git-dir "BISECT_CMD_OUTPUT"))
+ (list "Bisecting: (no saved bisect output)"
+ "It appears you have invoked `git bisect' from a shell."
+ "There is nothing wrong with that, we just cannot display"
+ "anything useful here. Consult the shell output instead.")))
+ (done-re "^\\([a-z0-9]\\{40\\}\\) is the first bad commit$")
+ (bad-line (or (and (string-match done-re (car lines))
+ (pop lines))
+ (--first (string-match done-re it) lines))))
+ (magit-insert-section ((eval (if bad-line 'commit 'bisect-output))
+ (and bad-line (match-string 1 bad-line)))
+ (magit-insert-heading
+ (propertize (or bad-line (pop lines))
+ 'font-lock-face 'magit-section-heading))
+ (dolist (line lines)
+ (insert line "\n"))))
+ (insert "\n")))
+
+(defun magit-insert-bisect-rest ()
+ "While bisecting, insert section visualizing the bisect state."
+ (when (magit-bisect-in-progress-p)
+ (magit-insert-section (bisect-view)
+ (magit-insert-heading "Bisect Rest:")
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'bisect-vis)
+ "bisect" "visualize" "git" "log"
+ "--format=%h%x00%D%x00%s" "--decorate=full"
+ (and magit-bisect-show-graph "--graph")))))
+
+(defun magit-insert-bisect-log ()
+ "While bisecting, insert section logging bisect progress."
+ (when (magit-bisect-in-progress-p)
+ (magit-insert-section (bisect-log)
+ (magit-insert-heading "Bisect Log:")
+ (magit-git-wash #'magit-wash-bisect-log "bisect" "log")
+ (insert ?\n))))
+
+(defun magit-wash-bisect-log (_args)
+ (let (beg)
+ (while (progn (setq beg (point-marker))
+ (re-search-forward "^\\(git bisect [^\n]+\n\\)" nil t))
+ (magit-bind-match-strings (heading) nil
+ (magit-delete-match)
+ (save-restriction
+ (narrow-to-region beg (point))
+ (goto-char (point-min))
+ (magit-insert-section (bisect-item heading t)
+ (insert (propertize heading 'font-lock-face
+ 'magit-section-secondary-heading))
+ (magit-insert-heading)
+ (magit-wash-sequence
+ (apply-partially 'magit-log-wash-rev 'bisect-log
+ (magit-abbrev-length)))
+ (insert ?\n)))))
+ (when (re-search-forward
+ "# first bad commit: \\[\\([a-z0-9]\\{40\\}\\)\\] [^\n]+\n" nil t)
+ (magit-bind-match-strings (hash) nil
+ (magit-delete-match)
+ (magit-insert-section (bisect-item)
+ (insert hash " is the first bad commit\n"))))))
+
+;;; _
+(provide 'magit-bisect)
+;;; magit-bisect.el ends here
--- /dev/null
+;;; magit-blame.el --- blame support for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2012-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; Annotates each line in file-visiting buffer with information from
+;; the revision which last modified the line.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Options
+
+(defgroup magit-blame nil
+ "Blame support for Magit."
+ :link '(info-link "(magit)Blaming")
+ :group 'magit-modes)
+
+(defcustom magit-blame-styles
+ '((headings
+ (heading-format . "%-20a %C %s\n"))
+ (margin
+ (margin-format . (" %s%f" " %C %a" " %H"))
+ (margin-width . 42)
+ (margin-face . magit-blame-margin)
+ (margin-body-face . (magit-blame-dimmed)))
+ (highlight
+ (highlight-face . magit-blame-highlight))
+ (lines
+ (show-lines . t)
+ (show-message . t)))
+ "List of styles used to visualize blame information.
+
+Each entry has the form (IDENT (KEY . VALUE)...). IDENT has
+to be a symbol uniquely identifying the style. The following
+KEYs are recognized:
+
+ `show-lines'
+ Whether to prefix each chunk of lines with a thin line.
+ This has no effect if `heading-format' is non-nil.
+ `show-message'
+ Whether to display a commit's summary line in the echo area
+ when crossing chunks.
+ `highlight-face'
+ Face used to highlight the first line of each chunk.
+ If this is nil, then those lines are not highlighted.
+ `heading-format'
+ String specifying the information to be shown above each
+ chunk of lines. It must end with a newline character.
+ `margin-format'
+ String specifying the information to be shown in the left
+ buffer margin. It must NOT end with a newline character.
+ This can also be a list of formats used for the lines at
+ the same positions within the chunk. If the chunk has
+ more lines than formats are specified, then the last is
+ repeated.
+ `margin-width'
+ Width of the margin, provided `margin-format' is non-nil.
+ `margin-face'
+ Face used in the margin, provided `margin-format' is
+ non-nil. This face is used in combination with the faces
+ that are specific to the used %-specs. If this is nil,
+ then `magit-blame-margin' is used.
+ `margin-body-face'
+ Face used in the margin for all but first line of a chunk.
+ This face is used in combination with the faces that are
+ specific to the used %-specs. This can also be a list of
+ faces (usually one face), in which case only these faces
+ are used and the %-spec faces are ignored. A good value
+ might be `(magit-blame-dimmed)'. If this is nil, then
+ the same face as for the first line is used.
+
+The following %-specs can be used in `heading-format' and
+`margin-format':
+
+ %H hash using face `magit-blame-hash'
+ %s summary using face `magit-blame-summary'
+ %a author using face `magit-blame-name'
+ %A author time using face `magit-blame-date'
+ %c committer using face `magit-blame-name'
+ %C committer time using face `magit-blame-date'
+
+Additionally if `margin-format' ends with %f, then the string
+that is displayed in the margin is made at least `margin-width'
+characters wide, which may be desirable if the used face sets
+the background color.
+
+The style used in the current buffer can be cycled from the blame
+popup. Blame commands (except `magit-blame-echo') use the first
+style as the initial style when beginning to blame in a buffer."
+ :package-version '(magit . "2.13.0")
+ :group 'magit-blame
+ :type 'string)
+
+(defcustom magit-blame-echo-style 'lines
+ "The blame visualization style used by `magit-blame-echo'.
+A symbol that has to be used as the identifier for one of the
+styles defined in `magit-blame-styles'."
+ :package-version '(magit . "2.13.0")
+ :group 'magit-blame
+ :type 'symbol)
+
+(defcustom magit-blame-time-format "%F %H:%M"
+ "Format for time strings in blame headings."
+ :group 'magit-blame
+ :type 'string)
+
+(defcustom magit-blame-read-only t
+ "Whether to initially make the blamed buffer read-only."
+ :package-version '(magit . "2.13.0")
+ :group 'magit-blame
+ :type 'boolean)
+
+(defcustom magit-blame-disable-modes '(fci-mode yascroll-bar-mode)
+ "List of modes not compatible with Magit-Blame mode.
+This modes are turned off when Magit-Blame mode is turned on,
+and then turned on again when turning off the latter."
+ :group 'magit-blame
+ :type '(repeat (symbol :tag "Mode")))
+
+(defcustom magit-blame-mode-lighter " Blame"
+ "The mode-line lighter of the Magit-Blame mode."
+ :group 'magit-blame
+ :type '(choice (const :tag "No lighter" "") string))
+
+(defcustom magit-blame-goto-chunk-hook
+ '(magit-blame-maybe-update-revision-buffer
+ magit-blame-maybe-show-message)
+ "Hook run after point entered another chunk."
+ :package-version '(magit . "2.13.0")
+ :group 'magit-blame
+ :type 'hook
+ :get 'magit-hook-custom-get
+ :options '(magit-blame-maybe-update-revision-buffer
+ magit-blame-maybe-show-message))
+
+;;; Faces
+
+(defface magit-blame-highlight
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "grey80"
+ :foreground "black")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "grey25"
+ :foreground "white"))
+ "Face used for highlighting when blaming.
+Also see option `magit-blame-styles'."
+ :group 'magit-faces)
+
+(defface magit-blame-margin
+ '((t :inherit magit-blame-highlight
+ :weight normal
+ :slant normal))
+ "Face used for the blame margin by default when blaming.
+Also see option `magit-blame-styles'."
+ :group 'magit-faces)
+
+(defface magit-blame-dimmed
+ '((t :inherit magit-dimmed
+ :weight normal
+ :slant normal))
+ "Face used for the blame margin in some cases when blaming.
+Also see option `magit-blame-styles'."
+ :group 'magit-faces)
+
+(defface magit-blame-heading
+ `((t ,@(and (>= emacs-major-version 27) '(:extend t))
+ :inherit magit-blame-highlight
+ :weight normal
+ :slant normal))
+ "Face used for blame headings by default when blaming.
+Also see option `magit-blame-styles'."
+ :group 'magit-faces)
+
+(defface magit-blame-summary nil
+ "Face used for commit summaries when blaming."
+ :group 'magit-faces)
+
+(defface magit-blame-hash nil
+ "Face used for commit hashes when blaming."
+ :group 'magit-faces)
+
+(defface magit-blame-name nil
+ "Face used for author and committer names when blaming."
+ :group 'magit-faces)
+
+(defface magit-blame-date nil
+ "Face used for dates when blaming."
+ :group 'magit-faces)
+
+;;; Chunks
+
+(defclass magit-blame-chunk ()
+ (;; <orig-rev> <orig-line> <final-line> <num-lines>
+ (orig-rev :initarg :orig-rev)
+ (orig-line :initarg :orig-line)
+ (final-line :initarg :final-line)
+ (num-lines :initarg :num-lines)
+ ;; previous <prev-rev> <prev-file>
+ (prev-rev :initform nil)
+ (prev-file :initform nil)
+ ;; filename <orig-file>
+ (orig-file)))
+
+(defun magit-current-blame-chunk (&optional type)
+ (or (and (not (and type (not (eq type magit-blame-type))))
+ (magit-blame-chunk-at (point)))
+ (and type
+ (let ((rev (or magit-buffer-refname magit-buffer-revision))
+ (file (magit-file-relative-name nil (not magit-buffer-file-name)))
+ (line (format "%i,+1" (line-number-at-pos))))
+ (unless file
+ (error "Buffer does not visit a tracked file"))
+ (with-temp-buffer
+ (magit-with-toplevel
+ (magit-git-insert
+ "blame" "--porcelain"
+ (if (memq magit-blame-type '(final removal))
+ (cons "--reverse" (magit-blame-arguments))
+ (magit-blame-arguments))
+ "-L" line rev "--" file)
+ (goto-char (point-min))
+ (car (magit-blame--parse-chunk type))))))))
+
+(defun magit-blame-chunk-at (pos)
+ (--some (overlay-get it 'magit-blame-chunk)
+ (overlays-at pos)))
+
+(defun magit-blame--overlay-at (&optional pos key)
+ (unless pos
+ (setq pos (point)))
+ (--first (overlay-get it (or key 'magit-blame-chunk))
+ (nconc (overlays-at pos)
+ (overlays-in pos pos))))
+
+;;; Keymaps
+
+(defvar magit-blame-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "C-c C-q") 'magit-blame-quit)
+ map)
+ "Keymap for `magit-blame-mode'.
+Note that most blaming key bindings are defined
+in `magit-blame-read-only-mode-map' instead.")
+
+(defvar magit-blame-read-only-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "C-m") 'magit-show-commit)
+ (define-key map (kbd "p") 'magit-blame-previous-chunk)
+ (define-key map (kbd "P") 'magit-blame-previous-chunk-same-commit)
+ (define-key map (kbd "n") 'magit-blame-next-chunk)
+ (define-key map (kbd "N") 'magit-blame-next-chunk-same-commit)
+ (define-key map (kbd "b") 'magit-blame-addition)
+ (define-key map (kbd "r") 'magit-blame-removal)
+ (define-key map (kbd "f") 'magit-blame-reverse)
+ (define-key map (kbd "B") 'magit-blame)
+ (define-key map (kbd "c") 'magit-blame-cycle-style)
+ (define-key map (kbd "q") 'magit-blame-quit)
+ (define-key map (kbd "M-w") 'magit-blame-copy-hash)
+ (define-key map (kbd "SPC") 'magit-diff-show-or-scroll-up)
+ (define-key map (kbd "S-SPC") 'magit-diff-show-or-scroll-down)
+ (define-key map (kbd "DEL") 'magit-diff-show-or-scroll-down)
+ map)
+ "Keymap for `magit-blame-read-only-mode'.")
+
+;;; Modes
+;;;; Variables
+
+(defvar-local magit-blame-buffer-read-only nil)
+(defvar-local magit-blame-cache nil)
+(defvar-local magit-blame-disabled-modes nil)
+(defvar-local magit-blame-process nil)
+(defvar-local magit-blame-recursive-p nil)
+(defvar-local magit-blame-type nil)
+(defvar-local magit-blame-separator nil)
+(defvar-local magit-blame-previous-chunk nil)
+
+(defvar-local magit-blame--style nil)
+
+(defsubst magit-blame--style-get (key)
+ (cdr (assoc key (cdr magit-blame--style))))
+
+;;;; Base Mode
+
+(define-minor-mode magit-blame-mode
+ "Display blame information inline."
+ :lighter magit-blame-mode-lighter
+ (cond (magit-blame-mode
+ (when (called-interactively-p 'any)
+ (setq magit-blame-mode nil)
+ (user-error
+ (concat "Don't call `magit-blame-mode' directly; "
+ "instead use `magit-blame'")))
+ (add-hook 'after-save-hook 'magit-blame--refresh t t)
+ (add-hook 'post-command-hook 'magit-blame-goto-chunk-hook t t)
+ (add-hook 'before-revert-hook 'magit-blame--remove-overlays t t)
+ (add-hook 'after-revert-hook 'magit-blame--refresh t t)
+ (add-hook 'read-only-mode-hook 'magit-blame-toggle-read-only t t)
+ (setq magit-blame-buffer-read-only buffer-read-only)
+ (when (or magit-blame-read-only magit-buffer-file-name)
+ (read-only-mode 1))
+ (dolist (mode magit-blame-disable-modes)
+ (when (and (boundp mode) (symbol-value mode))
+ (funcall mode -1)
+ (push mode magit-blame-disabled-modes)))
+ (setq magit-blame-separator (magit-blame--format-separator))
+ (unless magit-blame--style
+ (setq magit-blame--style (car magit-blame-styles)))
+ (magit-blame--update-margin))
+ (t
+ (when (process-live-p magit-blame-process)
+ (kill-process magit-blame-process)
+ (while magit-blame-process
+ (sit-for 0.01))) ; avoid racing the sentinel
+ (remove-hook 'after-save-hook 'magit-blame--refresh t)
+ (remove-hook 'post-command-hook 'magit-blame-goto-chunk-hook t)
+ (remove-hook 'before-revert-hook 'magit-blame--remove-overlays t)
+ (remove-hook 'after-revert-hook 'magit-blame--refresh t)
+ (remove-hook 'read-only-mode-hook 'magit-blame-toggle-read-only t)
+ (unless magit-blame-buffer-read-only
+ (read-only-mode -1))
+ (magit-blame-read-only-mode -1)
+ (dolist (mode magit-blame-disabled-modes)
+ (funcall mode 1))
+ (kill-local-variable 'magit-blame-disabled-modes)
+ (kill-local-variable 'magit-blame-type)
+ (kill-local-variable 'magit-blame--style)
+ (magit-blame--update-margin)
+ (magit-blame--remove-overlays))))
+
+(defun magit-blame--refresh ()
+ (magit-blame--run (magit-blame-arguments)))
+
+(defun magit-blame-goto-chunk-hook ()
+ (let ((chunk (magit-blame-chunk-at (point))))
+ (when (cl-typep chunk 'magit-blame-chunk)
+ (unless (eq chunk magit-blame-previous-chunk)
+ (run-hooks 'magit-blame-goto-chunk-hook))
+ (setq magit-blame-previous-chunk chunk))))
+
+(defun magit-blame-toggle-read-only ()
+ (magit-blame-read-only-mode (if buffer-read-only 1 -1)))
+
+;;;; Read-Only Mode
+
+(define-minor-mode magit-blame-read-only-mode
+ "Provide keybindings for Magit-Blame mode.
+
+This minor-mode provides the key bindings for Magit-Blame mode,
+but only when Read-Only mode is also enabled because these key
+bindings would otherwise conflict badly with regular bindings.
+
+When both Magit-Blame mode and Read-Only mode are enabled, then
+this mode gets automatically enabled too and when one of these
+modes is toggled, then this mode also gets toggled automatically.
+
+\\{magit-blame-read-only-mode-map}")
+
+;;;; Kludges
+
+(defun magit-blame-put-keymap-before-view-mode ()
+ "Put `magit-blame-read-only-mode' ahead of `view-mode' in `minor-mode-map-alist'."
+ (--when-let (assq 'magit-blame-read-only-mode
+ (cl-member 'view-mode minor-mode-map-alist :key #'car))
+ (setq minor-mode-map-alist
+ (cons it (delq it minor-mode-map-alist))))
+ (remove-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode))
+
+(add-hook 'view-mode-hook #'magit-blame-put-keymap-before-view-mode)
+
+;;; Process
+
+(defun magit-blame--run (args)
+ (magit-with-toplevel
+ (unless magit-blame-mode
+ (magit-blame-mode 1))
+ (message "Blaming...")
+ (magit-blame-run-process
+ (or magit-buffer-refname magit-buffer-revision)
+ (magit-file-relative-name nil (not magit-buffer-file-name))
+ (if (memq magit-blame-type '(final removal))
+ (cons "--reverse" args)
+ args)
+ (list (line-number-at-pos (window-start))
+ (line-number-at-pos (1- (window-end nil t)))))
+ (set-process-sentinel magit-this-process
+ 'magit-blame-process-quickstart-sentinel)))
+
+(defun magit-blame-run-process (revision file args &optional lines)
+ (let ((process (magit-parse-git-async
+ "blame" "--incremental" args
+ (and lines (list "-L" (apply #'format "%s,%s" lines)))
+ revision "--" file)))
+ (set-process-filter process 'magit-blame-process-filter)
+ (set-process-sentinel process 'magit-blame-process-sentinel)
+ (process-put process 'arguments (list revision file args))
+ (setq magit-blame-cache (make-hash-table :test 'equal))
+ (setq magit-blame-process process)))
+
+(defun magit-blame-process-quickstart-sentinel (process event)
+ (when (memq (process-status process) '(exit signal))
+ (magit-blame-process-sentinel process event t)
+ (magit-blame-assert-buffer process)
+ (with-current-buffer (process-get process 'command-buf)
+ (when magit-blame-mode
+ (let ((default-directory (magit-toplevel)))
+ (apply #'magit-blame-run-process
+ (process-get process 'arguments)))))))
+
+(defun magit-blame-process-sentinel (process _event &optional quiet)
+ (let ((status (process-status process)))
+ (when (memq status '(exit signal))
+ (kill-buffer (process-buffer process))
+ (if (and (eq status 'exit)
+ (zerop (process-exit-status process)))
+ (unless quiet
+ (message "Blaming...done"))
+ (magit-blame-assert-buffer process)
+ (with-current-buffer (process-get process 'command-buf)
+ (if magit-blame-mode
+ (progn (magit-blame-mode -1)
+ (message "Blaming...failed"))
+ (message "Blaming...aborted"))))
+ (kill-local-variable 'magit-blame-process))))
+
+(defun magit-blame-process-filter (process string)
+ (internal-default-process-filter process string)
+ (let ((buf (process-get process 'command-buf))
+ (pos (process-get process 'parsed))
+ (mark (process-mark process))
+ type cache)
+ (with-current-buffer buf
+ (setq type magit-blame-type)
+ (setq cache magit-blame-cache))
+ (with-current-buffer (process-buffer process)
+ (goto-char pos)
+ (while (and (< (point) mark)
+ (save-excursion (re-search-forward "^filename .+\n" nil t)))
+ (pcase-let* ((`(,chunk ,revinfo)
+ (magit-blame--parse-chunk type))
+ (rev (oref chunk orig-rev)))
+ (if revinfo
+ (puthash rev revinfo cache)
+ (setq revinfo
+ (or (gethash rev cache)
+ (puthash rev (magit-blame--commit-alist rev) cache))))
+ (magit-blame--make-overlays buf chunk revinfo))
+ (process-put process 'parsed (point))))))
+
+(defun magit-blame--parse-chunk (type)
+ (let (chunk revinfo)
+ (unless (looking-at "^\\(.\\{40\\}\\) \\([0-9]+\\) \\([0-9]+\\) \\([0-9]+\\)")
+ (error "Blaming failed due to unexpected output: %s"
+ (buffer-substring-no-properties (point) (line-end-position))))
+ (with-slots (orig-rev orig-file prev-rev prev-file)
+ (setq chunk (magit-blame-chunk
+ :orig-rev (match-string 1)
+ :orig-line (string-to-number (match-string 2))
+ :final-line (string-to-number (match-string 3))
+ :num-lines (string-to-number (match-string 4))))
+ (forward-line)
+ (let (done)
+ (while (not done)
+ (cond ((looking-at "^filename \\(.+\\)")
+ (setq done t)
+ (setf orig-file (match-string 1)))
+ ((looking-at "^previous \\(.\\{40\\}\\) \\(.+\\)")
+ (setf prev-rev (match-string 1))
+ (setf prev-file (match-string 2)))
+ ((looking-at "^\\([^ ]+\\) \\(.+\\)")
+ (push (cons (match-string 1)
+ (match-string 2)) revinfo)))
+ (forward-line)))
+ (when (and (eq type 'removal) prev-rev)
+ (cl-rotatef orig-rev prev-rev)
+ (cl-rotatef orig-file prev-file)
+ (setq revinfo nil)))
+ (list chunk revinfo)))
+
+(defun magit-blame--commit-alist (rev)
+ (cl-mapcar 'cons
+ '("summary"
+ "author" "author-time" "author-tz"
+ "committer" "committer-time" "committer-tz")
+ (split-string (magit-rev-format "%s\v%an\v%ad\v%cn\v%cd" rev
+ "--date=format:%s\v%z")
+ "\v")))
+
+(defun magit-blame-assert-buffer (process)
+ (unless (buffer-live-p (process-get process 'command-buf))
+ (kill-process process)
+ (user-error "Buffer being blamed has been killed")))
+
+;;; Display
+
+(defun magit-blame--make-overlays (buf chunk revinfo)
+ (with-current-buffer buf
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (forward-line (1- (oref chunk final-line)))
+ (let ((beg (point))
+ (end (save-excursion
+ (forward-line (oref chunk num-lines))
+ (point))))
+ (magit-blame--remove-overlays beg end)
+ (magit-blame--make-margin-overlays chunk revinfo beg end)
+ (magit-blame--make-heading-overlay chunk revinfo beg end)
+ (magit-blame--make-highlight-overlay chunk beg))))))
+
+(defun magit-blame--make-margin-overlays (chunk revinfo _beg end)
+ (save-excursion
+ (let ((line 0))
+ (while (< (point) end)
+ (magit-blame--make-margin-overlay chunk revinfo line)
+ (forward-line)
+ (cl-incf line)))))
+
+(defun magit-blame--make-margin-overlay (chunk revinfo line)
+ (let* ((end (line-end-position))
+ ;; If possible avoid putting this on the first character
+ ;; of the line to avoid a conflict with the line overlay.
+ (beg (min (1+ (line-beginning-position)) end))
+ (ov (make-overlay beg end)))
+ (overlay-put ov 'magit-blame-chunk chunk)
+ (overlay-put ov 'magit-blame-revinfo revinfo)
+ (overlay-put ov 'magit-blame-margin line)
+ (magit-blame--update-margin-overlay ov)))
+
+(defun magit-blame--make-heading-overlay (chunk revinfo beg end)
+ (let ((ov (make-overlay beg end)))
+ (overlay-put ov 'magit-blame-chunk chunk)
+ (overlay-put ov 'magit-blame-revinfo revinfo)
+ (overlay-put ov 'magit-blame-heading t)
+ (magit-blame--update-heading-overlay ov)))
+
+(defun magit-blame--make-highlight-overlay (chunk beg)
+ (let ((ov (make-overlay beg (1+ (line-end-position)))))
+ (overlay-put ov 'magit-blame-chunk chunk)
+ (overlay-put ov 'magit-blame-highlight t)
+ (magit-blame--update-highlight-overlay ov)))
+
+(defun magit-blame--update-margin ()
+ (setq left-margin-width (or (magit-blame--style-get 'margin-width) 0))
+ (set-window-buffer (selected-window) (current-buffer)))
+
+(defun magit-blame--update-overlays ()
+ (save-restriction
+ (widen)
+ (dolist (ov (overlays-in (point-min) (point-max)))
+ (cond ((overlay-get ov 'magit-blame-heading)
+ (magit-blame--update-heading-overlay ov))
+ ((overlay-get ov 'magit-blame-margin)
+ (magit-blame--update-margin-overlay ov))
+ ((overlay-get ov 'magit-blame-highlight)
+ (magit-blame--update-highlight-overlay ov))))))
+
+(defun magit-blame--update-margin-overlay (ov)
+ (overlay-put
+ ov 'before-string
+ (and (magit-blame--style-get 'margin-width)
+ (propertize
+ "o" 'display
+ (list (list 'margin 'left-margin)
+ (let ((line (overlay-get ov 'magit-blame-margin))
+ (format (magit-blame--style-get 'margin-format))
+ (face (magit-blame--style-get 'margin-face)))
+ (magit-blame--format-string
+ ov
+ (or (and (atom format)
+ format)
+ (nth line format)
+ (car (last format)))
+ (or (and (not (zerop line))
+ (magit-blame--style-get 'margin-body-face))
+ face
+ 'magit-blame-margin))))))))
+
+(defun magit-blame--update-heading-overlay (ov)
+ (overlay-put
+ ov 'before-string
+ (--if-let (magit-blame--style-get 'heading-format)
+ (magit-blame--format-string ov it 'magit-blame-heading)
+ (and (magit-blame--style-get 'show-lines)
+ (or (not (magit-blame--style-get 'margin-format))
+ (save-excursion
+ (goto-char (overlay-start ov))
+ ;; Special case of the special case described in
+ ;; `magit-blame--make-margin-overlay'. For empty
+ ;; lines it is not possible to show both overlays
+ ;; without the line being to high.
+ (not (= (point) (line-end-position)))))
+ magit-blame-separator))))
+
+(defun magit-blame--update-highlight-overlay (ov)
+ (overlay-put ov 'font-lock-face (magit-blame--style-get 'highlight-face)))
+
+(defun magit-blame--format-string (ov format face)
+ (let* ((chunk (overlay-get ov 'magit-blame-chunk))
+ (revinfo (overlay-get ov 'magit-blame-revinfo))
+ (key (list format face))
+ (string (cdr (assoc key revinfo))))
+ (unless string
+ (setq string
+ (and format
+ (magit-blame--format-string-1 (oref chunk orig-rev)
+ revinfo format face)))
+ (nconc revinfo (list (cons key string))))
+ string))
+
+(defun magit-blame--format-string-1 (rev revinfo format face)
+ (let ((str
+ (if (equal rev "0000000000000000000000000000000000000000")
+ (propertize (concat (if (string-prefix-p "\s" format) "\s" "")
+ "Not Yet Committed"
+ (if (string-suffix-p "\n" format) "\n" ""))
+ 'font-lock-face face)
+ (magit--format-spec
+ (propertize format 'font-lock-face face)
+ (cl-flet* ((p0 (s f)
+ (propertize s 'font-lock-face
+ (if face
+ (if (listp face)
+ face
+ (list f face))
+ f)))
+ (p1 (k f)
+ (p0 (cdr (assoc k revinfo)) f))
+ (p2 (k1 k2 f)
+ (p0 (magit-blame--format-time-string
+ (cdr (assoc k1 revinfo))
+ (cdr (assoc k2 revinfo)))
+ f)))
+ `((?H . ,(p0 rev 'magit-blame-hash))
+ (?s . ,(p1 "summary" 'magit-blame-summary))
+ (?a . ,(p1 "author" 'magit-blame-name))
+ (?c . ,(p1 "committer" 'magit-blame-name))
+ (?A . ,(p2 "author-time" "author-tz" 'magit-blame-date))
+ (?C . ,(p2 "committer-time" "committer-tz" 'magit-blame-date))
+ (?f . "")))))))
+ (if-let ((width (and (string-suffix-p "%f" format)
+ (magit-blame--style-get 'margin-width))))
+ (concat str
+ (propertize (make-string (max 0 (- width (length str))) ?\s)
+ 'font-lock-face face))
+ str)))
+
+(defun magit-blame--format-separator ()
+ (propertize
+ (concat (propertize "\s" 'display '(space :height (2)))
+ (propertize "\n" 'line-height t))
+ 'font-lock-face `(:background
+ ,(face-attribute 'magit-blame-heading
+ :background nil t)
+ ,@(and (>= emacs-major-version 27) '(:extend t)))))
+
+(defun magit-blame--format-time-string (time tz)
+ (let* ((time-format (or (magit-blame--style-get 'time-format)
+ magit-blame-time-format))
+ (tz-in-second (and (string-match "%z" time-format)
+ (car (last (parse-time-string tz))))))
+ (format-time-string time-format
+ (seconds-to-time (string-to-number time))
+ tz-in-second)))
+
+(defun magit-blame--remove-overlays (&optional beg end)
+ (save-restriction
+ (widen)
+ (dolist (ov (overlays-in (or beg (point-min))
+ (or end (point-max))))
+ (when (overlay-get ov 'magit-blame-chunk)
+ (delete-overlay ov)))))
+
+(defun magit-blame-maybe-show-message ()
+ (when (magit-blame--style-get 'show-message)
+ (let ((message-log-max 0))
+ (if-let ((msg (cdr (assoc "summary"
+ (gethash (oref (magit-current-blame-chunk)
+ orig-rev)
+ magit-blame-cache)))))
+ (progn (set-text-properties 0 (length msg) nil msg)
+ (message msg))
+ (message "Commit data not available yet. Still blaming.")))))
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-blame-echo "magit-blame" nil t)
+(transient-define-suffix magit-blame-echo (args)
+ "For each line show the revision in which it was added.
+Show the information about the chunk at point in the echo area
+when moving between chunks. Unlike other blaming commands, do
+not turn on `read-only-mode'."
+ :if (lambda ()
+ (and buffer-file-name
+ (or (not magit-blame-mode)
+ buffer-read-only)))
+ (interactive (list (magit-blame-arguments)))
+ (when magit-buffer-file-name
+ (user-error "Blob buffers aren't supported"))
+ (setq-local magit-blame--style
+ (assq magit-blame-echo-style magit-blame-styles))
+ (setq-local magit-blame-disable-modes
+ (cons 'eldoc-mode magit-blame-disable-modes))
+ (if (not magit-blame-mode)
+ (let ((magit-blame-read-only nil))
+ (magit-blame--pre-blame-assert 'addition)
+ (magit-blame--pre-blame-setup 'addition)
+ (magit-blame--run args))
+ (read-only-mode -1)
+ (magit-blame--update-overlays)))
+
+;;;###autoload (autoload 'magit-blame-addition "magit-blame" nil t)
+(transient-define-suffix magit-blame-addition (args)
+ "For each line show the revision in which it was added."
+ (interactive (list (magit-blame-arguments)))
+ (magit-blame--pre-blame-assert 'addition)
+ (magit-blame--pre-blame-setup 'addition)
+ (magit-blame--run args))
+
+;;;###autoload (autoload 'magit-blame-removal "magit-blame" nil t)
+(transient-define-suffix magit-blame-removal (args)
+ "For each line show the revision in which it was removed."
+ :if-nil 'buffer-file-name
+ (interactive (list (magit-blame-arguments)))
+ (unless magit-buffer-file-name
+ (user-error "Only blob buffers can be blamed in reverse"))
+ (magit-blame--pre-blame-assert 'removal)
+ (magit-blame--pre-blame-setup 'removal)
+ (magit-blame--run args))
+
+;;;###autoload (autoload 'magit-blame-reverse "magit-blame" nil t)
+(transient-define-suffix magit-blame-reverse (args)
+ "For each line show the last revision in which it still exists."
+ :if-nil 'buffer-file-name
+ (interactive (list (magit-blame-arguments)))
+ (unless magit-buffer-file-name
+ (user-error "Only blob buffers can be blamed in reverse"))
+ (magit-blame--pre-blame-assert 'final)
+ (magit-blame--pre-blame-setup 'final)
+ (magit-blame--run args))
+
+(defun magit-blame--pre-blame-assert (type)
+ (unless (magit-toplevel)
+ (magit--not-inside-repository-error))
+ (if (and magit-blame-mode
+ (eq type magit-blame-type))
+ (if-let ((chunk (magit-current-blame-chunk)))
+ (unless (oref chunk prev-rev)
+ (user-error "Chunk has no further history"))
+ (user-error "Commit data not available yet. Still blaming."))
+ (unless (magit-file-relative-name nil (not magit-buffer-file-name))
+ (if buffer-file-name
+ (user-error "Buffer isn't visiting a tracked file")
+ (user-error "Buffer isn't visiting a file")))))
+
+(defun magit-blame--pre-blame-setup (type)
+ (when magit-blame-mode
+ (if (eq type magit-blame-type)
+ (let ((style magit-blame--style))
+ (magit-blame-visit-other-file)
+ (setq-local magit-blame--style style)
+ (setq-local magit-blame-recursive-p t)
+ ;; Set window-start for the benefit of quickstart.
+ (redisplay))
+ (magit-blame--remove-overlays)))
+ (setq magit-blame-type type))
+
+(defun magit-blame-visit-other-file ()
+ "Visit another blob related to the current chunk."
+ (interactive)
+ (with-slots (prev-rev prev-file orig-line)
+ (magit-current-blame-chunk)
+ (unless prev-rev
+ (user-error "Chunk has no further history"))
+ (magit-with-toplevel
+ (magit-find-file prev-rev prev-file))
+ ;; TODO Adjust line like magit-diff-visit-file.
+ (goto-char (point-min))
+ (forward-line (1- orig-line))))
+
+(defun magit-blame-visit-file ()
+ "Visit the blob related to the current chunk."
+ (interactive)
+ (with-slots (orig-rev orig-file orig-line)
+ (magit-current-blame-chunk)
+ (magit-with-toplevel
+ (magit-find-file orig-rev orig-file))
+ (goto-char (point-min))
+ (forward-line (1- orig-line))))
+
+(transient-define-suffix magit-blame-quit ()
+ "Turn off Magit-Blame mode.
+If the buffer was created during a recursive blame,
+then also kill the buffer."
+ :if-non-nil 'magit-blame-mode
+ (interactive)
+ (magit-blame-mode -1)
+ (when magit-blame-recursive-p
+ (kill-buffer)))
+
+(defun magit-blame-next-chunk ()
+ "Move to the next chunk."
+ (interactive)
+ (--if-let (next-single-char-property-change (point) 'magit-blame-chunk)
+ (goto-char it)
+ (user-error "No more chunks")))
+
+(defun magit-blame-previous-chunk ()
+ "Move to the previous chunk."
+ (interactive)
+ (--if-let (previous-single-char-property-change (point) 'magit-blame-chunk)
+ (goto-char it)
+ (user-error "No more chunks")))
+
+(defun magit-blame-next-chunk-same-commit (&optional previous)
+ "Move to the next chunk from the same commit.\n\n(fn)"
+ (interactive)
+ (if-let ((rev (oref (magit-current-blame-chunk) orig-rev)))
+ (let ((pos (point)) ov)
+ (save-excursion
+ (while (and (not ov)
+ (not (= pos (if previous (point-min) (point-max))))
+ (setq pos (funcall
+ (if previous
+ 'previous-single-char-property-change
+ 'next-single-char-property-change)
+ pos 'magit-blame-chunk)))
+ (--when-let (magit-blame--overlay-at pos)
+ (when (equal (oref (magit-blame-chunk-at pos) orig-rev) rev)
+ (setq ov it)))))
+ (if ov
+ (goto-char (overlay-start ov))
+ (user-error "No more chunks from same commit")))
+ (user-error "This chunk hasn't been blamed yet")))
+
+(defun magit-blame-previous-chunk-same-commit ()
+ "Move to the previous chunk from the same commit."
+ (interactive)
+ (magit-blame-next-chunk-same-commit 'previous-single-char-property-change))
+
+(defun magit-blame-cycle-style ()
+ "Change how blame information is visualized.
+Cycle through the elements of option `magit-blame-styles'."
+ (interactive)
+ (setq magit-blame--style
+ (or (cadr (cl-member (car magit-blame--style)
+ magit-blame-styles :key #'car))
+ (car magit-blame-styles)))
+ (magit-blame--update-margin)
+ (magit-blame--update-overlays))
+
+(defun magit-blame-copy-hash ()
+ "Save hash of the current chunk's commit to the kill ring.
+
+When the region is active, then save the region's content
+instead of the hash, like `kill-ring-save' would."
+ (interactive)
+ (if (use-region-p)
+ (call-interactively #'copy-region-as-kill)
+ (kill-new (message "%s" (oref (magit-current-blame-chunk) orig-rev)))))
+
+;;; Popup
+
+;;;###autoload (autoload 'magit-blame "magit-blame" nil t)
+(transient-define-prefix magit-blame ()
+ "Show the commits that added or removed lines in the visited file."
+ :man-page "git-blame"
+ :value '("-w")
+ ["Arguments"
+ ("-w" "Ignore whitespace" "-w")
+ ("-r" "Do not treat root commits as boundaries" "--root")
+ (magit-blame:-M)
+ (magit-blame:-C)]
+ ["Actions"
+ ("b" "Show commits adding lines" magit-blame-addition)
+ ("r" "Show commits removing lines" magit-blame-removal)
+ ("f" "Show last commits that still have lines" magit-blame-reverse)
+ ("m" "Blame echo" magit-blame-echo)
+ ("q" "Quit blaming" magit-blame-quit)]
+ ["Refresh"
+ :if-non-nil magit-blame-mode
+ ("c" "Cycle style" magit-blame-cycle-style :transient t)])
+
+(defun magit-blame-arguments ()
+ (transient-args 'magit-blame))
+
+(transient-define-argument magit-blame:-M ()
+ :description "Detect lines moved or copied within a file"
+ :class 'transient-option
+ :argument "-M"
+ :reader 'transient-read-number-N+)
+
+(transient-define-argument magit-blame:-C ()
+ :description "Detect lines moved or copied between files"
+ :class 'transient-option
+ :argument "-C"
+ :reader 'transient-read-number-N+)
+
+;;; Utilities
+
+(defun magit-blame-maybe-update-revision-buffer ()
+ (when-let ((chunk (magit-current-blame-chunk))
+ (commit (oref chunk orig-rev))
+ (buffer (magit-get-mode-buffer 'magit-revision-mode nil t)))
+ (if magit--update-revision-buffer
+ (setq magit--update-revision-buffer (list commit buffer))
+ (setq magit--update-revision-buffer (list commit buffer))
+ (run-with-idle-timer
+ magit-update-other-window-delay nil
+ (lambda ()
+ (pcase-let ((`(,rev ,buf) magit--update-revision-buffer))
+ (setq magit--update-revision-buffer nil)
+ (when (buffer-live-p buf)
+ (let ((magit-display-buffer-noselect t))
+ (apply #'magit-show-commit rev
+ (magit-diff-arguments 'magit-revision-mode))))))))))
+
+;;; _
+(provide 'magit-blame)
+;;; magit-blame.el ends here
--- /dev/null
+;;; magit-bookmark.el --- bookmark support for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Inspired by an earlier implementation by Yuri Khan.
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; Support for bookmarks for most Magit buffers.
+
+;;; Code:
+
+(require 'magit)
+(require 'bookmark)
+
+;;; Core
+
+(defun magit--make-bookmark ()
+ "Create a bookmark for the current Magit buffer.
+Input values are the major-mode's `magit-bookmark-name' method,
+and the buffer-local values of the variables referenced in its
+`magit-bookmark-variables' property."
+ (if (plist-member (symbol-plist major-mode) 'magit-bookmark-variables)
+ (let ((bookmark (bookmark-make-record-default 'no-file)))
+ (bookmark-prop-set bookmark 'handler 'magit--handle-bookmark)
+ (bookmark-prop-set bookmark 'mode major-mode)
+ (bookmark-prop-set bookmark 'filename (magit-toplevel))
+ (bookmark-prop-set bookmark 'defaults (list (magit-bookmark-name)))
+ (dolist (var (get major-mode 'magit-bookmark-variables))
+ (bookmark-prop-set bookmark var (symbol-value var)))
+ (bookmark-prop-set
+ bookmark 'magit-hidden-sections
+ (--keep (and (oref it hidden)
+ (cons (oref it type)
+ (if (derived-mode-p 'magit-stash-mode)
+ (replace-regexp-in-string
+ (regexp-quote magit-buffer-revision)
+ magit-buffer-revision-hash
+ (oref it value))
+ (oref it value))))
+ (oref magit-root-section children)))
+ bookmark)
+ (user-error "Bookmarking is not implemented for %s buffers" major-mode)))
+
+;;;###autoload
+(defun magit--handle-bookmark (bookmark)
+ "Open a bookmark created by `magit--make-bookmark'.
+Call the `magit-*-setup-buffer' function of the the major-mode
+with the variables' values as arguments, which were recorded by
+`magit--make-bookmark'. Ignore `magit-display-buffer-function'."
+ (let ((buffer (let ((default-directory (bookmark-get-filename bookmark))
+ (mode (bookmark-prop-get bookmark 'mode))
+ (magit-display-buffer-function #'identity)
+ (magit-display-buffer-noselect t))
+ (apply (intern (format "%s-setup-buffer"
+ (substring (symbol-name mode) 0 -5)))
+ (--map (bookmark-prop-get bookmark it)
+ (get mode 'magit-bookmark-variables))))))
+ (set-buffer buffer) ; That is the interface we have to adhere to.
+ (when-let ((hidden (bookmark-prop-get bookmark 'magit-hidden-sections)))
+ (with-current-buffer buffer
+ (dolist (child (oref magit-root-section children))
+ (if (member (cons (oref child type)
+ (oref child value))
+ hidden)
+ (magit-section-hide child)
+ (magit-section-show child)))))
+ nil))
+
+(cl-defgeneric magit-bookmark-name ()
+ "Return name for bookmark to current buffer."
+ (format "%s%s"
+ (substring (symbol-name major-mode) 0 -5)
+ (if-let ((vars (get major-mode 'magit-bookmark-variables)))
+ (cl-mapcan (lambda (var)
+ (let ((val (symbol-value var)))
+ (if (and val (atom val))
+ (list val)
+ val)))
+ vars)
+ "")))
+
+;;; Diff
+;;;; Diff
+
+(put 'magit-diff-mode 'magit-bookmark-variables
+ '(magit-buffer-range-hashed
+ magit-buffer-typearg
+ magit-buffer-diff-args
+ magit-buffer-diff-files))
+
+(cl-defmethod magit-bookmark-name (&context (major-mode magit-diff-mode))
+ (format "magit-diff(%s%s)"
+ (pcase (magit-diff-type)
+ (`staged "staged")
+ (`unstaged "unstaged")
+ (`committed magit-buffer-range)
+ (`undefined
+ (delq nil (list magit-buffer-typearg magit-buffer-range-hashed))))
+ (if magit-buffer-diff-files
+ (concat " -- " (mapconcat #'identity magit-buffer-diff-files " "))
+ "")))
+
+;;;; Revision
+
+(put 'magit-revision-mode 'magit-bookmark-variables
+ '(magit-buffer-revision-hash
+ magit-buffer-diff-args
+ magit-buffer-diff-files))
+
+(cl-defmethod magit-bookmark-name (&context (major-mode magit-revision-mode))
+ (format "magit-revision(%s %s)"
+ (magit-rev-abbrev magit-buffer-revision)
+ (if magit-buffer-diff-files
+ (mapconcat #'identity magit-buffer-diff-files " ")
+ (magit-rev-format "%s" magit-buffer-revision))))
+
+;;;; Stash
+
+(put 'magit-stash-mode 'magit-bookmark-variables
+ '(magit-buffer-revision-hash
+ magit-buffer-diff-args
+ magit-buffer-diff-files))
+
+(cl-defmethod magit-bookmark-name (&context (major-mode magit-stash-mode))
+ (format "magit-stash(%s %s)"
+ (magit-rev-abbrev magit-buffer-revision)
+ (if magit-buffer-diff-files
+ (mapconcat #'identity magit-buffer-diff-files " ")
+ (magit-rev-format "%s" magit-buffer-revision))))
+
+;;; Log
+;;;; Log
+
+(put 'magit-log-mode 'magit-bookmark-variables
+ '(magit-buffer-revisions
+ magit-buffer-log-args
+ magit-buffer-log-files))
+
+(cl-defmethod magit-bookmark-name (&context (major-mode magit-log-mode))
+ (format "magit-log(%s%s)"
+ (mapconcat #'identity magit-buffer-revisions " ")
+ (if magit-buffer-log-files
+ (concat " -- " (mapconcat #'identity magit-buffer-log-files " "))
+ "")))
+
+;;;; Cherry
+
+(put 'magit-cherry-mode 'magit-bookmark-variables
+ '(magit-buffer-refname
+ magit-buffer-upstream))
+
+(cl-defmethod magit-bookmark-name (&context (major-mode magit-cherry-mode))
+ (format "magit-cherry(%s > %s)"
+ magit-buffer-refname
+ magit-buffer-upstream))
+
+;;;; Reflog
+
+(put 'magit-reflog-mode 'magit-bookmark-variables
+ '(magit-buffer-refname))
+
+(cl-defmethod magit-bookmark-name (&context (major-mode magit-reflog-mode))
+ (format "magit-reflog(%s)" magit-buffer-refname))
+
+;;; Misc
+
+(put 'magit-status-mode 'magit-bookmark-variables nil)
+
+(put 'magit-refs-mode 'magit-bookmark-variables
+ '(magit-buffer-upstream
+ magit-buffer-arguments))
+
+(put 'magit-stashes-mode 'magit-bookmark-variables nil)
+
+(cl-defmethod magit-bookmark-name (&context (major-mode magit-stashes-mode))
+ (format "magit-states(%s)" magit-buffer-refname))
+
+;;; _
+(provide 'magit-bookmark)
+;;; magit-bookmark.el ends here
--- /dev/null
+;;; magit-branch.el --- branch support -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements support for branches. It defines commands
+;; for creating, checking out, manipulating, and configuring branches.
+;; Commands defined here are mainly concerned with branches as
+;; pointers, commands that deal with what a branch points at, are
+;; defined elsewhere.
+
+;;; Code:
+
+(require 'magit)
+(require 'magit-reset)
+
+;;; Options
+
+(defcustom magit-branch-read-upstream-first t
+ "Whether to read upstream before name of new branch when creating a branch.
+
+`nil' Read the branch name first.
+`t' Read the upstream first.
+`fallback' Read the upstream first, but if it turns out that the chosen
+ value is not a valid upstream (because it cannot be resolved
+ as an existing revision), then treat it as the name of the
+ new branch and continue by reading the upstream next."
+ :package-version '(magit . "2.2.0")
+ :group 'magit-commands
+ :type '(choice (const :tag "read branch name first" nil)
+ (const :tag "read upstream first" t)
+ (const :tag "read upstream first, with fallback" fallback)))
+
+(defcustom magit-branch-prefer-remote-upstream nil
+ "Whether to favor remote upstreams when creating new branches.
+
+When a new branch is created, then the branch, commit, or stash
+at point is suggested as the default starting point of the new
+branch, or if there is no such revision at point the current
+branch. In either case the user may choose another starting
+point.
+
+If the chosen starting point is a branch, then it may also be set
+as the upstream of the new branch, depending on the value of the
+Git variable `branch.autoSetupMerge'. By default this is done
+for remote branches, but not for local branches.
+
+You might prefer to always use some remote branch as upstream.
+If the chosen starting point is (1) a local branch, (2) whose
+name matches a member of the value of this option, (3) the
+upstream of that local branch is a remote branch with the same
+name, and (4) that remote branch can be fast-forwarded to the
+local branch, then the chosen branch is used as starting point,
+but its own upstream is used as the upstream of the new branch.
+
+Members of this option's value are treated as branch names that
+have to match exactly unless they contain a character that makes
+them invalid as a branch name. Recommended characters to use
+to trigger interpretation as a regexp are \"*\" and \"^\". Some
+other characters which you might expect to be invalid, actually
+are not, e.g. \".+$\" are all perfectly valid. More precisely,
+if `git check-ref-format --branch STRING' exits with a non-zero
+status, then treat STRING as a regexp.
+
+Assuming the chosen branch matches these conditions you would end
+up with with e.g.:
+
+ feature --upstream--> origin/master
+
+instead of
+
+ feature --upstream--> master --upstream--> origin/master
+
+Which you prefer is a matter of personal preference. If you do
+prefer the former, then you should add branches such as \"master\",
+\"next\", and \"maint\" to the value of this options."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-commands
+ :type '(repeat string))
+
+(defcustom magit-branch-adjust-remote-upstream-alist nil
+ "Alist of upstreams to be used when branching from remote branches.
+
+When creating a local branch from an ephemeral branch located
+on a remote, e.g. a feature or hotfix branch, then that remote
+branch should usually not be used as the upstream branch, since
+the push-remote already allows accessing it and having both the
+upstream and the push-remote reference the same related branch
+would be wasteful. Instead a branch like \"maint\" or \"master\"
+should be used as the upstream.
+
+This option allows specifying the branch that should be used as
+the upstream when branching certain remote branches. The value
+is an alist of the form ((UPSTREAM . RULE)...). The first
+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/\"))
+
+If you use remote branches as UPSTREAM, then you might also want
+to set `magit-branch-prefer-remote-upstream' to a non-nil value.
+However, I recommend that you use local branches as UPSTREAM."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-commands
+ :type '(repeat (cons (string :tag "Use upstream")
+ (choice :tag "for branches"
+ (regexp :tag "matching")
+ (repeat :tag "except"
+ (string :tag "branch"))))))
+
+(defcustom magit-branch-rename-push-target t
+ "Whether the push-remote setup is preserved when renaming a branch.
+
+The command `magit-branch-rename' renames a branch named OLD to
+NEW. This option controls how much of the push-remote setup is
+preserved when doing so.
+
+When nil, then preserve nothing and unset `branch.OLD.pushRemote'.
+
+When `local-only', then first set `branch.NEW.pushRemote' to the
+ same value as `branch.OLD.pushRemote', provided the latter is
+ actually set and unless the former already has another value.
+
+When t, then rename the branch named OLD on the remote specified
+ by `branch.OLD.pushRemote' to NEW, provided OLD exists on that
+ remote and unless NEW already exists on the remote.
+
+When `forge-only' and the `forge' package is available, then
+ behave like `t' if the remote points to a repository on a forge
+ (currently Github or Gitlab), otherwise like `local-only'.
+
+Another supported but obsolete value is `github-only'. It is a
+ misnomer because it now treated as an alias for `forge-only'."
+ :package-version '(magit . "2.90.0")
+ :group 'magit-commands
+ :type '(choice
+ (const :tag "Don't preserve push-remote setup" nil)
+ (const :tag "Preserve push-remote setup" local-only)
+ (const :tag "... and rename corresponding branch on remote" t)
+ (const :tag "... but only if remote is on a forge" forge-only)))
+
+(defcustom magit-branch-direct-configure t
+ "Whether the command `magit-branch' shows Git variables.
+When set to nil, no variables are displayed by this transient
+command, instead the sub-transient `magit-branch-configure'
+has to be used to view and change branch related variables."
+ :package-version '(magit . "2.7.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-published-branches '("origin/master")
+ "List of branches that are considered to be published."
+ :package-version '(magit . "2.13.0")
+ :group 'magit-commands
+ :type '(repeat string))
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-branch "magit" nil t)
+(transient-define-prefix magit-branch (branch)
+ "Add, configure or remove a branch."
+ :man-page "git-branch"
+ ["Variables"
+ :if (lambda ()
+ (and magit-branch-direct-configure
+ (oref transient--prefix scope)))
+ ("d" magit-branch.<branch>.description)
+ ("u" magit-branch.<branch>.merge/remote)
+ ("r" magit-branch.<branch>.rebase)
+ ("p" magit-branch.<branch>.pushRemote)]
+ [["Checkout"
+ ("b" "branch/revision" magit-checkout)
+ ("l" "local branch" magit-branch-checkout)
+ (6 "o" "new orphan" magit-branch-orphan)]
+ [""
+ ("c" "new branch" magit-branch-and-checkout)
+ ("s" "new spin-off" magit-branch-spinoff)
+ (5 "w" "new worktree" magit-worktree-checkout)]
+ ["Create"
+ ("n" "new branch" magit-branch-create)
+ ("S" "new spin-out" magit-branch-spinout)
+ (5 "W" "new worktree" magit-worktree-branch)]
+ ["Do"
+ ("C" "configure..." magit-branch-configure)
+ ("m" "rename" magit-branch-rename)
+ ("x" "reset" magit-branch-reset)
+ ("k" "delete" magit-branch-delete)]
+ [""
+ (7 "h" "shelve" magit-branch-shelve)
+ (7 "H" "unshelve" magit-branch-unshelve)]]
+ (interactive (list (magit-get-current-branch)))
+ (transient-setup 'magit-branch nil nil :scope branch))
+
+;;;###autoload
+(defun magit-checkout (revision)
+ "Checkout REVISION, updating the index and the working tree.
+If REVISION is a local branch, then that becomes the current
+branch. If it is something else, then `HEAD' becomes detached.
+Checkout fails if the working tree or the staging area contain
+changes.
+\n(git checkout REVISION)."
+ (interactive (list (magit-read-other-branch-or-commit "Checkout")))
+ (when (string-match "\\`heads/\\(.+\\)" revision)
+ (setq revision (match-string 1 revision)))
+ (magit-run-git "checkout" revision))
+
+;;;###autoload
+(defun magit-branch-create (branch start-point)
+ "Create BRANCH at branch or revision START-POINT."
+ (interactive (magit-branch-read-args "Create branch"))
+ (magit-call-git "branch" branch start-point)
+ (magit-branch-maybe-adjust-upstream branch start-point)
+ (magit-refresh))
+
+;;;###autoload
+(defun magit-branch-and-checkout (branch start-point)
+ "Create and checkout BRANCH at branch or revision START-POINT."
+ (interactive (magit-branch-read-args "Create and checkout branch"))
+ (if (string-match-p "^stash@{[0-9]+}$" start-point)
+ (magit-run-git "stash" "branch" branch start-point)
+ (magit-call-git "checkout" "-b" branch start-point)
+ (magit-branch-maybe-adjust-upstream branch start-point)
+ (magit-refresh)))
+
+;;;###autoload
+(defun magit-branch-or-checkout (arg &optional start-point)
+ "Hybrid between `magit-checkout' and `magit-branch-and-checkout'.
+
+Ask the user for an existing branch or revision. If the user
+input actually can be resolved as a branch or revision, then
+check that out, just like `magit-checkout' would.
+
+Otherwise create and checkout a new branch using the input as
+its name. Before doing so read the starting-point for the new
+branch. This is similar to what `magit-branch-and-checkout'
+does."
+ (interactive
+ (let ((arg (magit-read-other-branch-or-commit "Checkout")))
+ (list arg
+ (and (not (magit-commit-p arg))
+ (magit-read-starting-point "Create and checkout branch" arg)))))
+ (when (string-match "\\`heads/\\(.+\\)" arg)
+ (setq arg (match-string 1 arg)))
+ (if start-point
+ (magit-branch-and-checkout arg start-point)
+ (magit-checkout arg)))
+
+;;;###autoload
+(defun magit-branch-checkout (branch &optional start-point)
+ "Checkout an existing or new local branch.
+
+Read a branch name from the user offering all local branches and
+a subset of remote branches as candidates. Omit remote branches
+for which a local branch by the same name exists from the list
+of candidates. The user can also enter a completely new branch
+name.
+
+- If the user selects an existing local branch, then check that
+ out.
+
+- If the user selects a remote branch, then create and checkout
+ a new local branch with the same name. Configure the selected
+ remote branch as push target.
+
+- If the user enters a new branch name, then create and check
+ that out, after also reading the starting-point from the user.
+
+In the latter two cases the upstream is also set. Whether it is
+set to the chosen START-POINT or something else depends on the
+value of `magit-branch-adjust-remote-upstream-alist', just like
+when using `magit-branch-and-checkout'."
+ (interactive
+ (let* ((current (magit-get-current-branch))
+ (local (magit-list-local-branch-names))
+ (remote (--filter (and (string-match "[^/]+/" it)
+ (not (member (substring it (match-end 0))
+ (cons "HEAD" local))))
+ (magit-list-remote-branch-names)))
+ (choices (nconc (delete current local) remote))
+ (atpoint (magit-branch-at-point))
+ (choice (magit-completing-read
+ "Checkout branch" choices
+ nil nil nil 'magit-revision-history
+ (or (car (member atpoint choices))
+ (and atpoint
+ (car (member (and (string-match "[^/]+/" atpoint)
+ (substring atpoint (match-end 0)))
+ choices)))))))
+ (cond ((member choice remote)
+ (list (and (string-match "[^/]+/" choice)
+ (substring choice (match-end 0)))
+ choice))
+ ((member choice local)
+ (list choice))
+ (t
+ (list choice (magit-read-starting-point "Create" choice))))))
+ (if (not start-point)
+ (magit-checkout branch)
+ (when (magit-anything-modified-p t)
+ (user-error "Cannot checkout when there are uncommitted changes"))
+ (magit-branch-and-checkout branch start-point)
+ (when (magit-remote-branch-p start-point)
+ (pcase-let ((`(,remote . ,remote-branch)
+ (magit-split-branch-name start-point)))
+ (when (and (equal branch remote-branch)
+ (not (equal remote (magit-get "remote.pushDefault"))))
+ (magit-set remote "branch" branch "pushRemote"))))))
+
+(defun magit-branch-maybe-adjust-upstream (branch start-point)
+ (--when-let
+ (or (and (magit-get-upstream-branch branch)
+ (magit-get-indirect-upstream-branch start-point))
+ (and (magit-remote-branch-p start-point)
+ (let ((name (cdr (magit-split-branch-name start-point))))
+ (car (--first (if (listp (cdr it))
+ (not (member name (cdr it)))
+ (string-match-p (cdr it) name))
+ magit-branch-adjust-remote-upstream-alist)))))
+ (magit-call-git "branch" (concat "--set-upstream-to=" it) branch)))
+
+;;;###autoload
+(defun magit-branch-orphan (branch start-point)
+ "Create and checkout an orphan BRANCH with contents from revision START-POINT."
+ (interactive (magit-branch-read-args "Create and checkout orphan branch"))
+ (magit-run-git "checkout" "--orphan" branch start-point))
+
+(defun magit-branch-read-args (prompt &optional default-start)
+ (if magit-branch-read-upstream-first
+ (let ((choice (magit-read-starting-point prompt nil default-start)))
+ (if (magit-rev-verify choice)
+ (list (magit-read-string-ns
+ (if magit-completing-read--silent-default
+ (format "%s (starting at `%s')" prompt choice)
+ "Name for new branch")
+ (let ((def (mapconcat #'identity
+ (cdr (split-string choice "/"))
+ "/")))
+ (and (member choice (magit-list-remote-branch-names))
+ (not (member def (magit-list-local-branch-names)))
+ def)))
+ choice)
+ (if (eq magit-branch-read-upstream-first 'fallback)
+ (list choice
+ (magit-read-starting-point prompt choice default-start))
+ (user-error "Not a valid starting-point: %s" choice))))
+ (let ((branch (magit-read-string-ns (concat prompt " named"))))
+ (list branch (magit-read-starting-point prompt branch default-start)))))
+
+;;;###autoload
+(defun magit-branch-spinout (branch &optional from)
+ "Create new branch from the unpushed commits.
+Like `magit-branch-spinoff' but remain on the current branch.
+If there are any uncommitted changes, then behave exactly like
+`magit-branch-spinoff'."
+ (interactive (list (magit-read-string-ns "Spin out branch")
+ (car (last (magit-region-values 'commit)))))
+ (magit--branch-spinoff branch from nil))
+
+;;;###autoload
+(defun magit-branch-spinoff (branch &optional from)
+ "Create new branch from the unpushed commits.
+
+Create and checkout a new branch starting at and tracking the
+current branch. That branch in turn is reset to the last commit
+it shares with its upstream. If the current branch has no
+upstream or no unpushed commits, then the new branch is created
+anyway and the previously current branch is not touched.
+
+This is useful to create a feature branch after work has already
+began on the old branch (likely but not necessarily \"master\").
+
+If the current branch is a member of the value of option
+`magit-branch-prefer-remote-upstream' (which see), then the
+current branch will be used as the starting point as usual, but
+the upstream of the starting-point may be used as the upstream
+of the new branch, instead of the starting-point itself.
+
+If optional FROM is non-nil, then the source branch is reset
+to `FROM~', instead of to the last commit it shares with its
+upstream. Interactively, FROM is only ever non-nil, if the
+region selects some commits, and among those commits, FROM is
+the commit that is the fewest commits ahead of the source
+branch.
+
+The commit at the other end of the selection actually does not
+matter, all commits between FROM and `HEAD' are moved to the new
+branch. If FROM is not reachable from `HEAD' or is reachable
+from the source branch's upstream, then an error is raised."
+ (interactive (list (magit-read-string-ns "Spin off branch")
+ (car (last (magit-region-values 'commit)))))
+ (magit--branch-spinoff branch from t))
+
+(defun magit--branch-spinoff (branch from checkout)
+ (when (magit-branch-p branch)
+ (user-error "Cannot spin off %s. It already exists" branch))
+ (when (and (not checkout)
+ (magit-anything-modified-p))
+ (message "Staying on HEAD due to uncommitted changes")
+ (setq checkout t))
+ (if-let ((current (magit-get-current-branch)))
+ (let ((tracked (magit-get-upstream-branch current))
+ base)
+ (when from
+ (unless (magit-rev-ancestor-p from current)
+ (user-error "Cannot spin off %s. %s is not reachable from %s"
+ branch from current))
+ (when (and tracked
+ (magit-rev-ancestor-p from tracked))
+ (user-error "Cannot spin off %s. %s is ancestor of upstream %s"
+ branch from tracked)))
+ (let ((magit-process-raise-error t))
+ (if checkout
+ (magit-call-git "checkout" "-b" branch current)
+ (magit-call-git "branch" branch current)))
+ (--when-let (magit-get-indirect-upstream-branch current)
+ (magit-call-git "branch" "--set-upstream-to" it branch))
+ (when (and tracked
+ (setq base
+ (if from
+ (concat from "^")
+ (magit-git-string "merge-base" current tracked)))
+ (not (magit-rev-eq base current)))
+ (if checkout
+ (magit-call-git "update-ref" "-m"
+ (format "reset: moving to %s" base)
+ (concat "refs/heads/" current) base)
+ (magit-call-git "reset" "--hard" base))))
+ (if checkout
+ (magit-call-git "checkout" "-b" branch)
+ (magit-call-git "branch" branch)))
+ (magit-refresh))
+
+;;;###autoload
+(defun magit-branch-reset (branch to &optional set-upstream)
+ "Reset a branch to the tip of another branch or any other commit.
+
+When the branch being reset is the current branch, then do a
+hard reset. If there are any uncommitted changes, then the user
+has to confirm the reset because those changes would be lost.
+
+This is useful when you have started work on a feature branch but
+realize it's all crap and want to start over.
+
+When resetting to another branch and a prefix argument is used,
+then also set the target branch as the upstream of the branch
+that is being reset."
+ (interactive
+ (let* ((atpoint (magit-local-branch-at-point))
+ (branch (magit-read-local-branch "Reset branch" atpoint)))
+ (list branch
+ (magit-completing-read (format "Reset %s to" branch)
+ (delete branch (magit-list-branch-names))
+ nil nil nil 'magit-revision-history
+ (or (and (not (equal branch atpoint)) atpoint)
+ (magit-get-upstream-branch branch)))
+ current-prefix-arg)))
+ (let ((inhibit-magit-refresh t))
+ (if (equal branch (magit-get-current-branch))
+ (if (and (magit-anything-modified-p)
+ (not (yes-or-no-p
+ "Uncommitted changes will be lost. Proceed? ")))
+ (user-error "Abort")
+ (magit-reset-hard to))
+ (magit-call-git "update-ref"
+ "-m" (format "reset: moving to %s" to)
+ (magit-git-string "rev-parse" "--symbolic-full-name"
+ branch)
+ to))
+ (when (and set-upstream (magit-branch-p to))
+ (magit-set-upstream-branch branch to)
+ (magit-branch-maybe-adjust-upstream branch to)))
+ (magit-refresh))
+
+(defvar magit-branch-delete-never-verify nil
+ "Whether `magit-branch-delete' always pushes with \"--no-verify\".")
+
+;;;###autoload
+(defun magit-branch-delete (branches &optional force)
+ "Delete one or multiple branches.
+If the region marks multiple branches, then offer to delete
+those, otherwise prompt for a single branch to be deleted,
+defaulting to the branch at point."
+ ;; One would expect this to be a command as simple as, for example,
+ ;; `magit-branch-rename'; but it turns out everyone wants to squeeze
+ ;; a bit of extra functionality into this one, including myself.
+ (interactive
+ (let ((branches (magit-region-values 'branch t))
+ (force current-prefix-arg))
+ (if (> (length branches) 1)
+ (magit-confirm t nil "Delete %i branches" nil branches)
+ (setq branches
+ (list (magit-read-branch-prefer-other
+ (if force "Force delete branch" "Delete branch")))))
+ (unless force
+ (when-let ((unmerged (-remove #'magit-branch-merged-p branches)))
+ (if (magit-confirm 'delete-unmerged-branch
+ "Delete unmerged branch %s"
+ "Delete %i unmerged branches"
+ 'noabort unmerged)
+ (setq force branches)
+ (or (setq branches (-difference branches unmerged))
+ (user-error "Abort")))))
+ (list branches force)))
+ (let* ((refs (mapcar #'magit-ref-fullname branches))
+ (ambiguous (--remove it refs)))
+ (when ambiguous
+ (user-error
+ "%s ambiguous. Please cleanup using git directly."
+ (let ((len (length ambiguous)))
+ (cond
+ ((= len 1)
+ (format "%s is" (-first #'magit-ref-ambiguous-p branches)))
+ ((= len (length refs))
+ (format "These %s names are" len))
+ (t
+ (format "%s of these names are" len))))))
+ (cond
+ ((string-match "^refs/remotes/\\([^/]+\\)" (car refs))
+ (let* ((remote (match-string 1 (car refs)))
+ (offset (1+ (length remote))))
+ ;; Assume the branches actually still exists on the remote.
+ (magit-run-git-async
+ "push"
+ (and (or force magit-branch-delete-never-verify) "--no-verify")
+ remote
+ (--map (concat ":" (substring it offset)) branches))
+ ;; If that is not the case, then this deletes the tracking branches.
+ (set-process-sentinel
+ magit-this-process
+ (apply-partially 'magit-delete-remote-branch-sentinel remote refs))))
+ ((> (length branches) 1)
+ (setq branches (delete (magit-get-current-branch) branches))
+ (mapc 'magit-branch-maybe-delete-pr-remote branches)
+ (mapc 'magit-branch-unset-pushRemote branches)
+ (magit-run-git "branch" (if force "-D" "-d") branches))
+ (t ; And now for something completely different.
+ (let* ((branch (car branches))
+ (prompt (format "Branch %s is checked out. " branch))
+ (main (magit-main-branch)))
+ (when (equal branch (magit-get-current-branch))
+ (pcase (if (or (equal branch main)
+ (not main))
+ (magit-read-char-case prompt nil
+ (?d "[d]etach HEAD & delete" 'detach)
+ (?a "[a]bort" 'abort))
+ (magit-read-char-case prompt nil
+ (?d "[d]etach HEAD & delete" 'detach)
+ (?c (format "[c]heckout %s & delete" main) 'main)
+ (?a "[a]bort" 'abort)))
+ (`detach (unless (or (equal force '(4))
+ (member branch force)
+ (magit-branch-merged-p branch t))
+ (magit-confirm 'delete-unmerged-branch
+ "Delete unmerged branch %s" ""
+ nil (list branch)))
+ (magit-call-git "checkout" "--detach"))
+ (`main (unless (or (equal force '(4))
+ (member branch force)
+ (magit-branch-merged-p branch main))
+ (magit-confirm 'delete-unmerged-branch
+ "Delete unmerged branch %s" ""
+ nil (list branch)))
+ (magit-call-git "checkout" main))
+ (`abort (user-error "Abort")))
+ (setq force t))
+ (magit-branch-maybe-delete-pr-remote branch)
+ (magit-branch-unset-pushRemote branch)
+ (magit-run-git "branch" (if force "-D" "-d") branch))))))
+
+(put 'magit-branch-delete 'interactive-only t)
+
+(defun magit-branch-maybe-delete-pr-remote (branch)
+ (when-let ((remote (magit-get "branch" branch "pullRequestRemote")))
+ (let* ((variable (format "remote.%s.fetch" remote))
+ (refspecs (magit-get-all variable)))
+ (unless (member (format "+refs/heads/*:refs/remotes/%s/*" remote)
+ refspecs)
+ (let ((refspec
+ (if (equal (magit-get "branch" branch "pushRemote") remote)
+ (format "+refs/heads/%s:refs/remotes/%s/%s"
+ branch remote branch)
+ (let ((merge (magit-get "branch" branch "merge")))
+ (and merge
+ (string-prefix-p "refs/heads/" merge)
+ (setq merge (substring merge 11))
+ (format "+refs/heads/%s:refs/remotes/%s/%s"
+ merge remote merge))))))
+ (when (member refspec refspecs)
+ (if (and (= (length refspecs) 1)
+ (magit-confirm 'delete-pr-remote
+ (format "Also delete remote %s (%s)" remote
+ "no pull-request branch remains")
+ nil t))
+ (magit-call-git "remote" "rm" remote)
+ (magit-call-git "config" "--unset-all" variable
+ (format "^%s$" (regexp-quote refspec))))))))))
+
+(defun magit-branch-unset-pushRemote (branch)
+ (magit-set nil "branch" branch "pushRemote"))
+
+(defun magit-delete-remote-branch-sentinel (remote refs process event)
+ (when (memq (process-status process) '(exit signal))
+ (if (= (process-exit-status process) 1)
+ (if-let ((on-remote (--map (concat "refs/remotes/" remote "/" it)
+ (magit-remote-list-branches remote)))
+ (rest (--filter (and (not (member it on-remote))
+ (magit-ref-exists-p it))
+ refs)))
+ (progn
+ (process-put process 'inhibit-refresh t)
+ (magit-process-sentinel process event)
+ (setq magit-this-error nil)
+ (message "Some remote branches no longer exist. %s"
+ "Deleting just the local tracking refs instead...")
+ (dolist (ref rest)
+ (magit-call-git "update-ref" "-d" ref))
+ (magit-refresh)
+ (message "Deleting local remote-tracking refs...done"))
+ (magit-process-sentinel process event))
+ (magit-process-sentinel process event))))
+
+;;;###autoload
+(defun magit-branch-rename (old new &optional force)
+ "Rename the branch named OLD to NEW.
+
+With a prefix argument FORCE, rename even if a branch named NEW
+already exists.
+
+If `branch.OLD.pushRemote' is set, then unset it. Depending on
+the value of `magit-branch-rename-push-target' (which see) maybe
+set `branch.NEW.pushRemote' and maybe rename the push-target on
+the remote."
+ (interactive
+ (let ((branch (magit-read-local-branch "Rename branch")))
+ (list branch
+ (magit-read-string-ns (format "Rename branch '%s' to" branch)
+ nil 'magit-revision-history)
+ current-prefix-arg)))
+ (when (string-match "\\`heads/\\(.+\\)" old)
+ (setq old (match-string 1 old)))
+ (when (equal old new)
+ (user-error "Old and new branch names are the same"))
+ (magit-call-git "branch" (if force "-M" "-m") old new)
+ (when magit-branch-rename-push-target
+ (let ((remote (magit-get-push-remote old))
+ (old-specific (magit-get "branch" old "pushRemote"))
+ (new-specific (magit-get "branch" new "pushRemote")))
+ (when (and old-specific (or force (not new-specific)))
+ ;; Keep the target setting branch specific, even if that is
+ ;; redundant. But if a branch by the same name existed before
+ ;; and the rename isn't forced, then do not change a leftover
+ ;; setting. Such a leftover setting may or may not conform to
+ ;; what we expect here...
+ (magit-set old-specific "branch" new "pushRemote"))
+ (when (and (equal (magit-get-push-remote new) remote)
+ ;; ...and if it does not, then we must abort.
+ (not (eq magit-branch-rename-push-target 'local-only))
+ (or (not (memq magit-branch-rename-push-target
+ '(forge-only github-only)))
+ (and (require (quote forge) nil t)
+ (fboundp 'forge--forge-remote-p)
+ (forge--forge-remote-p remote))))
+ (let ((old-target (magit-get-push-branch old t))
+ (new-target (magit-get-push-branch new t))
+ (remote (magit-get-push-remote new)))
+ (when (and old-target
+ (not new-target)
+ (magit-y-or-n-p (format "Also rename %S to %S on \"%s\""
+ old new remote)))
+ ;; Rename on (i.e. within) the remote, but only if the
+ ;; destination ref doesn't exist yet. If that ref already
+ ;; exists, then it probably is of some value and we better
+ ;; not touch it. Ignore what the local ref points at,
+ ;; i.e. if the local and the remote ref didn't point at
+ ;; the same commit before the rename then keep it that way.
+ (magit-call-git "push" "-v" remote
+ (format "%s:refs/heads/%s" old-target new)
+ (format ":refs/heads/%s" old)))))))
+ (magit-branch-unset-pushRemote old)
+ (magit-refresh))
+
+;;;###autoload
+(defun magit-branch-shelve (branch)
+ "Shelve a BRANCH.
+Rename \"refs/heads/BRANCH\" to \"refs/shelved/BRANCH\",
+and also rename the respective reflog file."
+ (interactive (list (magit-read-other-local-branch "Shelve branch")))
+ (let ((old (concat "refs/heads/" branch))
+ (new (concat "refs/shelved/" branch)))
+ (magit-git "update-ref" new old "")
+ (magit--rename-reflog-file old new)
+ (magit-branch-unset-pushRemote branch)
+ (magit-run-git "branch" "-D" branch)))
+
+;;;###autoload
+(defun magit-branch-unshelve (branch)
+ "Unshelve a BRANCH
+Rename \"refs/shelved/BRANCH\" to \"refs/heads/BRANCH\",
+and also rename the respective reflog file."
+ (interactive
+ (list (magit-completing-read
+ "Unshelve branch"
+ (--map (substring it 8)
+ (magit-list-refnames "refs/shelved"))
+ nil t)))
+ (let ((old (concat "refs/shelved/" branch))
+ (new (concat "refs/heads/" branch)))
+ (magit-git "update-ref" new old "")
+ (magit--rename-reflog-file old new)
+ (magit-run-git "update-ref" "-d" old)))
+
+(defun magit--rename-reflog-file (old new)
+ (let ((old (magit-git-dir (concat "logs/" old)))
+ (new (magit-git-dir (concat "logs/" new))))
+ (when (file-exists-p old)
+ (make-directory (file-name-directory new) t)
+ (rename-file old new t))))
+
+;;; Configure
+
+;;;###autoload (autoload 'magit-branch-configure "magit-branch" nil t)
+(transient-define-prefix magit-branch-configure (branch)
+ "Configure a branch."
+ :man-page "git-branch"
+ [:description
+ (lambda ()
+ (concat
+ (propertize "Configure " 'face 'transient-heading)
+ (propertize (oref transient--prefix scope) 'face 'magit-branch-local)))
+ ("d" magit-branch.<branch>.description)
+ ("u" magit-branch.<branch>.merge/remote)
+ ("r" magit-branch.<branch>.rebase)
+ ("p" magit-branch.<branch>.pushRemote)]
+ ["Configure repository defaults"
+ ("R" magit-pull.rebase)
+ ("P" magit-remote.pushDefault)]
+ ["Configure branch creation"
+ ("a m" magit-branch.autoSetupMerge)
+ ("a r" magit-branch.autoSetupRebase)]
+ (interactive
+ (list (or (and (not current-prefix-arg)
+ (not (and magit-branch-direct-configure
+ (eq transient-current-command 'magit-branch)))
+ (magit-get-current-branch))
+ (magit--read-branch-scope))))
+ (transient-setup 'magit-branch-configure nil nil :scope branch))
+
+(defun magit--read-branch-scope (&optional obj)
+ (magit-read-local-branch
+ (if obj
+ (format "Set %s for branch"
+ (format (oref obj variable) "<name>"))
+ "Configure branch")))
+
+(transient-define-suffix magit-branch.<branch>.description (branch)
+ "Edit the description of BRANCH."
+ :class 'magit--git-variable
+ :transient nil
+ :variable "branch.%s.description"
+ (interactive (list (oref transient-current-prefix scope)))
+ (magit-run-git-with-editor "branch" "--edit-description" branch))
+
+(add-hook 'find-file-hook 'magit-branch-description-check-buffers)
+
+(defun magit-branch-description-check-buffers ()
+ (and buffer-file-name
+ (string-match-p "/\\(BRANCH\\|EDIT\\)_DESCRIPTION\\'" buffer-file-name)))
+
+(defclass magit--git-branch:upstream (magit--git-variable)
+ ((format :initform " %k %m %M\n %r %R")))
+
+(transient-define-infix magit-branch.<branch>.merge/remote ()
+ :class 'magit--git-branch:upstream)
+
+(cl-defmethod transient-init-value ((obj magit--git-branch:upstream))
+ (when-let ((branch (oref transient--prefix scope))
+ (remote (magit-get "branch" branch "remote"))
+ (merge (magit-get "branch" branch "merge")))
+ (oset obj value (list remote merge))))
+
+(cl-defmethod transient-infix-read ((obj magit--git-branch:upstream))
+ (if (oref obj value)
+ (oset obj value nil)
+ (magit-read-upstream-branch (oref transient--prefix scope) "Upstream")))
+
+(cl-defmethod transient-infix-set ((obj magit--git-branch:upstream) refname)
+ (magit-set-upstream-branch (oref transient--prefix scope) refname)
+ (oset obj value
+ (let ((branch (oref transient--prefix scope)))
+ (when-let ((r (magit-get "branch" branch "remote"))
+ (m (magit-get "branch" branch "merge")))
+ (list r m))))
+ (magit-refresh))
+
+(cl-defmethod transient-format ((obj magit--git-branch:upstream))
+ (let ((branch (oref transient--prefix scope)))
+ (format-spec
+ (oref obj format)
+ `((?k . ,(transient-format-key obj))
+ (?r . ,(format "branch.%s.remote" branch))
+ (?m . ,(format "branch.%s.merge" branch))
+ (?R . ,(transient-format-value obj #'car))
+ (?M . ,(transient-format-value obj #'cadr))))))
+
+(cl-defmethod transient-format-value ((obj magit--git-branch:upstream) key)
+ (if-let ((value (funcall key (oref obj value))))
+ (propertize value 'face 'transient-argument)
+ (propertize "unset" 'face 'transient-inactive-argument)))
+
+(transient-define-infix magit-branch.<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.<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
--- /dev/null
+;;; magit-clone.el --- clone a repository -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements clone commands.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Options
+
+(defcustom magit-clone-set-remote-head nil
+ "Whether cloning creates the symbolic-ref `<remote>/HEAD'."
+ :package-version '(magit . "2.4.2")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-clone-set-remote.pushDefault 'ask
+ "Whether to set the value of `remote.pushDefault' after cloning.
+
+If t, then set without asking. If nil, then don't set. If
+`ask', then ask."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-commands
+ :type '(choice (const :tag "set" t)
+ (const :tag "ask" ask)
+ (const :tag "don't set" nil)))
+
+(defcustom magit-clone-default-directory nil
+ "Default directory to use when `magit-clone' reads destination.
+If nil (the default), then use the value of `default-directory'.
+If a directory, then use that. If a function, then call that
+with the remote url as only argument and use the returned value."
+ :package-version '(magit . "2.90.0")
+ :group 'magit-commands
+ :type '(choice (const :tag "value of default-directory")
+ (directory :tag "constant directory")
+ (function :tag "function's value")))
+
+(defcustom magit-clone-always-transient nil
+ "Whether `magit-clone' always acts as a transient prefix command.
+If nil, then a prefix argument has to be used to show the transient
+popup instead of invoking the default suffix `magit-clone-regular'
+directly."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-clone-name-alist
+ '(("\\`\\(?:github:\\|gh:\\)?\\([^:]+\\)\\'" "github.com" "github.user")
+ ("\\`\\(?:gitlab:\\|gl:\\)\\([^:]+\\)\\'" "gitlab.com" "gitlab.user"))
+ "Alist mapping repository names to repository urls.
+
+Each element has the form (REGEXP HOSTNAME USER). When the user
+enters a name when a cloning command asks for a name or url, then
+that is looked up in this list. The first element whose REGEXP
+matches is used.
+
+The format specified by option `magit-clone-url-format' is used
+to turn the name into an url, using HOSTNAME and the repository
+name. If the provided name contains a slash, then that is used.
+Otherwise if the name omits the owner of the repository, then the
+default user specified in the matched entry is used.
+
+If USER contains a dot, then it is treated as a Git variable and
+the value of that is used as the username. Otherwise it is used
+as the username itself."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-commands
+ :type '(repeat (list regexp
+ (string :tag "hostname")
+ (string :tag "user name or git variable"))))
+
+(defcustom magit-clone-url-format "git@%h:%n.git"
+ "Format used when turning repository names into urls.
+%h is the hostname and %n is the repository name, including
+the name of the owner. Also see `magit-clone-name-alist'."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-commands
+ :type 'regexp)
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-clone "magit-clone" nil t)
+(transient-define-prefix magit-clone (&optional transient)
+ "Clone a repository."
+ :man-page "git-clone"
+ ["Fetch arguments"
+ ("-B" "Clone a single branch" "--single-branch")
+ ("-n" "Do not clone tags" "--no-tags")
+ ("-S" "Clones submodules" "--recurse-submodules" :level 6)
+ ("-l" "Do not optimize" "--no-local" :level 7)]
+ ["Setup arguments"
+ ("-o" "Set name of remote" ("-o" "--origin="))
+ ("-b" "Set HEAD branch" ("-b" "--branch="))
+ ("-g" "Separate git directory" "--separate-git-dir="
+ transient-read-directory :level 7)
+ ("-t" "Use template directory" "--template="
+ transient-read-existing-directory :level 6)]
+ ["Local sharing arguments"
+ ("-s" "Share objects" ("-s" "--shared" :level 7))
+ ("-h" "Do not use hardlinks" "--no-hardlinks")]
+ ["Clone"
+ ("C" "regular" magit-clone-regular)
+ ("s" "shallow" magit-clone-shallow)
+ ("d" "shallow since date" magit-clone-shallow-since :level 7)
+ ("e" "shallow excluding" magit-clone-shallow-exclude :level 7)
+ ("b" "bare" magit-clone-bare)
+ ("m" "mirror" magit-clone-mirror)]
+ (interactive (list (or magit-clone-always-transient current-prefix-arg)))
+ (if transient
+ (transient-setup #'magit-clone)
+ (call-interactively #'magit-clone-regular)))
+
+;;;###autoload
+(defun magit-clone-regular (repository directory args)
+ "Create a clone of REPOSITORY in DIRECTORY.
+Then show the status buffer for the new repository."
+ (interactive (magit-clone-read-args))
+ (magit-clone-internal repository directory args))
+
+;;;###autoload
+(defun magit-clone-shallow (repository directory args depth)
+ "Create a shallow clone of REPOSITORY in DIRECTORY.
+Then show the status buffer for the new repository.
+With a prefix argument read the DEPTH of the clone;
+otherwise use 1."
+ (interactive (append (magit-clone-read-args)
+ (list (if current-prefix-arg
+ (read-number "Depth: " 1)
+ 1))))
+ (magit-clone-internal repository directory
+ (cons (format "--depth=%s" depth) args)))
+
+;;;###autoload
+(defun magit-clone-shallow-since (repository directory args date)
+ "Create a shallow clone of REPOSITORY in DIRECTORY.
+Then show the status buffer for the new repository.
+Exclude commits before DATE, which is read from the
+user."
+ (interactive (append (magit-clone-read-args)
+ (list (transient-read-date "Exclude commits before: "
+ nil nil))))
+ (magit-clone-internal repository directory
+ (cons (format "--shallow-since=%s" date) args)))
+
+;;;###autoload
+(defun magit-clone-shallow-exclude (repository directory args exclude)
+ "Create a shallow clone of REPOSITORY in DIRECTORY.
+Then show the status buffer for the new repository.
+Exclude commits reachable from EXCLUDE, which is a
+branch or tag read from the user."
+ (interactive (append (magit-clone-read-args)
+ (list (read-string "Exclude commits reachable from: "))))
+ (magit-clone-internal repository directory
+ (cons (format "--shallow-exclude=%s" exclude) args)))
+
+;;;###autoload
+(defun magit-clone-bare (repository directory args)
+ "Create a bare clone of REPOSITORY in DIRECTORY.
+Then show the status buffer for the new repository."
+ (interactive (magit-clone-read-args))
+ (magit-clone-internal repository directory (cons "--bare" args)))
+
+;;;###autoload
+(defun magit-clone-mirror (repository directory args)
+ "Create a mirror of REPOSITORY in DIRECTORY.
+Then show the status buffer for the new repository."
+ (interactive (magit-clone-read-args))
+ (magit-clone-internal repository directory (cons "--mirror" args)))
+
+(defun magit-clone-internal (repository directory args)
+ (let* ((checkout (not (memq (car args) '("--bare" "--mirror"))))
+ (set-push-default
+ (and checkout
+ (or (eq magit-clone-set-remote.pushDefault t)
+ (and magit-clone-set-remote.pushDefault
+ (y-or-n-p "Set `remote.pushDefault' to \"origin\"? "))))))
+ (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") "origin"))
+ (unless magit-clone-set-remote-head
+ (magit-remote-unset-head "origin"))))
+ (with-current-buffer (process-get process 'command-buf)
+ (magit-status-setup-buffer directory)))))))
+
+(defun magit-clone-read-args ()
+ (let ((repo (magit-clone-read-repository)))
+ (list repo
+ (read-directory-name
+ "Clone to: "
+ (if (functionp magit-clone-default-directory)
+ (funcall magit-clone-default-directory repo)
+ magit-clone-default-directory)
+ nil nil
+ (magit-clone--url-to-name repo))
+ (transient-args 'magit-clone))))
+
+(defun magit-clone-read-repository ()
+ (magit-read-char-case "Clone from " nil
+ (?u "[u]rl or name"
+ (let ((str (magit-read-string-ns "Clone from url or name")))
+ (if (string-match-p "\\(://\\|@\\)" str)
+ str
+ (magit-clone--name-to-url str))))
+ (?p "[p]ath"
+ (read-directory-name "Clone repository: "))
+ (?l "or [l]ocal url"
+ (concat "file://" (read-directory-name "Clone repository: file://")))))
+
+(defun magit-clone--url-to-name (url)
+ (and (string-match "\\([^/:]+?\\)\\(/?\\.git\\)?$" url)
+ (match-string 1 url)))
+
+(defun magit-clone--name-to-url (name)
+ (or (seq-some
+ (pcase-lambda (`(,re ,host ,user))
+ (and (string-match re name)
+ (let ((repo (match-string 1 name)))
+ (magit-clone--format-url host user repo))))
+ magit-clone-name-alist)
+ (user-error "Not an url and no matching entry in `%s'"
+ 'magit-clone-name-alist)))
+
+(defun magit-clone--format-url (host user repo)
+ (format-spec
+ magit-clone-url-format
+ `((?h . ,host)
+ (?n . ,(if (string-match-p "/" repo)
+ repo
+ (if (string-match-p "\\." user)
+ (if-let ((user (magit-get user)))
+ (concat user "/" repo)
+ (user-error "Set %S or specify owner explicitly" user))
+ (concat user "/" repo)))))))
+
+;;; _
+(provide 'magit-clone)
+;;; magit-clone.el ends here
--- /dev/null
+;;; magit-commit.el --- create Git commits -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements commands for creating Git commits. These
+;; commands just initiate the commit, support for writing the commit
+;; messages is implemented in `git-commit.el'.
+
+;;; Code:
+
+(require 'magit)
+(require 'magit-sequence)
+
+(eval-when-compile (require 'epa)) ; for `epa-protocol'
+(eval-when-compile (require 'epg))
+
+;;; Options
+
+(defcustom magit-commit-ask-to-stage 'verbose
+ "Whether to ask to stage everything when committing and nothing is staged."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-commands
+ :type '(choice (const :tag "Ask" t)
+ (const :tag "Ask showing diff" verbose)
+ (const :tag "Stage without confirmation" stage)
+ (const :tag "Don't ask" nil)))
+
+(defcustom magit-commit-show-diff t
+ "Whether the relevant diff is automatically shown when committing."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-commit-extend-override-date t
+ "Whether using `magit-commit-extend' changes the committer date."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-commit-reword-override-date t
+ "Whether using `magit-commit-reword' changes the committer date."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-commit-squash-confirm t
+ "Whether the commit targeted by squash and fixup has to be confirmed.
+When non-nil then the commit at point (if any) is used as default
+choice, otherwise it has to be confirmed. This option only
+affects `magit-commit-squash' and `magit-commit-fixup'. The
+\"instant\" variants always require confirmation because making
+an error while using those is harder to recover from."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-post-commit-hook nil
+ "Hook run after creating a commit without the user editing a message.
+
+This hook is run by `magit-refresh' if `this-command' is a member
+of `magit-post-stage-hook-commands'. This only includes commands
+named `magit-commit-*' that do *not* require that the user edits
+the commit message in a buffer and then finishes by pressing
+\\<with-editor-mode-map>\\[with-editor-finish].
+
+Also see `git-commit-post-finish-hook'."
+ :package-version '(magit . "2.90.0")
+ :group 'magit-commands
+ :type 'hook)
+
+(defvar magit-post-commit-hook-commands
+ '(magit-commit-extend
+ magit-commit-fixup
+ magit-commit-augment
+ magit-commit-instant-fixup
+ magit-commit-instant-squash))
+
+;;; Popup
+
+;;;###autoload (autoload 'magit-commit "magit-commit" nil t)
+(transient-define-prefix magit-commit ()
+ "Create a new commit or replace an existing commit."
+ :info-manual "(magit)Initiating a Commit"
+ :man-page "git-commit"
+ ["Arguments"
+ ("-a" "Stage all modified and deleted files" ("-a" "--all"))
+ ("-e" "Allow empty commit" "--allow-empty")
+ ("-v" "Show diff of changes to be committed" ("-v" "--verbose"))
+ ("-n" "Disable hooks" ("-n" "--no-verify"))
+ ("-R" "Claim authorship and reset author date" "--reset-author")
+ (magit:--author :description "Override the author")
+ (7 "-D" "Override the author date" "--date=" transient-read-date)
+ ("-s" "Add Signed-off-by line" ("-s" "--signoff"))
+ (5 magit:--gpg-sign)
+ (magit-commit:--reuse-message)]
+ [["Create"
+ ("c" "Commit" magit-commit-create)]
+ ["Edit HEAD"
+ ("e" "Extend" magit-commit-extend)
+ ("w" "Reword" magit-commit-reword)
+ ("a" "Amend" magit-commit-amend)
+ (6 "n" "Reshelve" magit-commit-reshelve)]
+ ["Edit"
+ ("f" "Fixup" magit-commit-fixup)
+ ("s" "Squash" magit-commit-squash)
+ ("A" "Augment" magit-commit-augment)
+ (6 "x" "Absorb changes" magit-commit-autofixup)
+ (6 "X" "Absorb modules" magit-commit-absorb-modules)]
+ [""
+ ("F" "Instant fixup" magit-commit-instant-fixup)
+ ("S" "Instant squash" magit-commit-instant-squash)]]
+ (interactive)
+ (if-let ((buffer (magit-commit-message-buffer)))
+ (switch-to-buffer buffer)
+ (transient-setup 'magit-commit)))
+
+(defun magit-commit-arguments nil
+ (transient-args 'magit-commit))
+
+(transient-define-argument magit:--gpg-sign ()
+ :description "Sign using gpg"
+ :class 'transient-option
+ :shortarg "-S"
+ :argument "--gpg-sign="
+ :allow-empty t
+ :reader 'magit-read-gpg-secret-key)
+
+(defvar magit-gpg-secret-key-hist nil)
+
+(defun magit-read-gpg-secret-key (prompt &optional initial-input history)
+ (require 'epa)
+ (let* ((keys (mapcar
+ (lambda (obj)
+ (let ((key (epg-sub-key-id (car (epg-key-sub-key-list obj))))
+ (author
+ (when-let ((id-obj (car (epg-key-user-id-list obj))))
+ (let ((id-str (epg-user-id-string id-obj)))
+ (if (stringp id-str)
+ id-str
+ (epg-decode-dn id-obj))))))
+ (propertize key 'display (concat key " " author))))
+ (epg-list-keys (epg-make-context epa-protocol) nil t)))
+ (choice (completing-read prompt keys nil nil nil
+ history nil initial-input)))
+ (set-text-properties 0 (length choice) nil choice)
+ choice))
+
+(transient-define-argument magit-commit:--reuse-message ()
+ :description "Reuse commit message"
+ :class 'transient-option
+ :shortarg "-C"
+ :argument "--reuse-message="
+ :reader 'magit-read-reuse-message
+ :history-key 'magit-revision-history)
+
+(defun magit-read-reuse-message (prompt &optional default history)
+ (magit-completing-read prompt (magit-list-refnames)
+ nil nil nil history
+ (or default
+ (and (magit-rev-verify "ORIG_HEAD")
+ "ORIG_HEAD"))))
+
+;;; Commands
+
+;;;###autoload
+(defun magit-commit-create (&optional args)
+ "Create a new commit on `HEAD'.
+With a prefix argument, amend to the commit at `HEAD' instead.
+\n(git commit [--amend] ARGS)"
+ (interactive (if current-prefix-arg
+ (list (cons "--amend" (magit-commit-arguments)))
+ (list (magit-commit-arguments))))
+ (when (member "--all" args)
+ (setq this-command 'magit-commit-all))
+ (when (setq args (magit-commit-assert args))
+ (let ((default-directory (magit-toplevel)))
+ (magit-run-git-with-editor "commit" args))))
+
+;;;###autoload
+(defun magit-commit-amend (&optional args)
+ "Amend the last commit.
+\n(git commit --amend ARGS)"
+ (interactive (list (magit-commit-arguments)))
+ (magit-commit-amend-assert)
+ (magit-run-git-with-editor "commit" "--amend" args))
+
+;;;###autoload
+(defun magit-commit-extend (&optional args override-date)
+ "Amend the last commit, without editing the message.
+
+With a prefix argument keep the committer date, otherwise change
+it. The option `magit-commit-extend-override-date' can be used
+to inverse the meaning of the prefix argument. \n(git commit
+--amend --no-edit)"
+ (interactive (list (magit-commit-arguments)
+ (if current-prefix-arg
+ (not magit-commit-extend-override-date)
+ magit-commit-extend-override-date)))
+ (when (setq args (magit-commit-assert args))
+ (magit-commit-amend-assert)
+ (let ((process-environment process-environment))
+ (unless override-date
+ (push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment))
+ (magit-run-git-with-editor "commit" "--amend" "--no-edit" args))))
+
+;;;###autoload
+(defun magit-commit-reword (&optional args override-date)
+ "Reword the last commit, ignoring staged changes.
+
+With a prefix argument keep the committer date, otherwise change
+it. The option `magit-commit-reword-override-date' can be used
+to inverse the meaning of the prefix argument.
+
+Non-interactively respect the optional OVERRIDE-DATE argument
+and ignore the option.
+\n(git commit --amend --only)"
+ (interactive (list (magit-commit-arguments)
+ (if current-prefix-arg
+ (not magit-commit-reword-override-date)
+ magit-commit-reword-override-date)))
+ (magit-commit-amend-assert)
+ (let ((process-environment process-environment))
+ (unless override-date
+ (push (magit-rev-format "GIT_COMMITTER_DATE=%cD") process-environment))
+ (cl-pushnew "--allow-empty" args :test #'equal)
+ (magit-run-git-with-editor "commit" "--amend" "--only" args)))
+
+;;;###autoload
+(defun magit-commit-fixup (&optional commit args)
+ "Create a fixup commit.
+
+With a prefix argument the target COMMIT has to be confirmed.
+Otherwise the commit at point may be used without confirmation
+depending on the value of option `magit-commit-squash-confirm'."
+ (interactive (list (magit-commit-at-point)
+ (magit-commit-arguments)))
+ (magit-commit-squash-internal "--fixup" commit args))
+
+;;;###autoload
+(defun magit-commit-squash (&optional commit args)
+ "Create a squash commit, without editing the squash message.
+
+With a prefix argument the target COMMIT has to be confirmed.
+Otherwise the commit at point may be used without confirmation
+depending on the value of option `magit-commit-squash-confirm'."
+ (interactive (list (magit-commit-at-point)
+ (magit-commit-arguments)))
+ (magit-commit-squash-internal "--squash" commit args))
+
+;;;###autoload
+(defun magit-commit-augment (&optional commit args)
+ "Create a squash commit, editing the squash message.
+
+With a prefix argument the target COMMIT has to be confirmed.
+Otherwise the commit at point may be used without confirmation
+depending on the value of option `magit-commit-squash-confirm'."
+ (interactive (list (magit-commit-at-point)
+ (magit-commit-arguments)))
+ (magit-commit-squash-internal "--squash" commit args nil t))
+
+;;;###autoload
+(defun magit-commit-instant-fixup (&optional commit args)
+ "Create a fixup commit targeting COMMIT and instantly rebase."
+ (interactive (list (magit-commit-at-point)
+ (magit-commit-arguments)))
+ (magit-commit-squash-internal "--fixup" commit args t))
+
+;;;###autoload
+(defun magit-commit-instant-squash (&optional commit args)
+ "Create a squash commit targeting COMMIT and instantly rebase."
+ (interactive (list (magit-commit-at-point)
+ (magit-commit-arguments)))
+ (magit-commit-squash-internal "--squash" commit args t))
+
+(defun magit-commit-squash-internal
+ (option commit &optional args rebase edit confirmed)
+ (when-let ((args (magit-commit-assert args t)))
+ (when commit
+ (when (and rebase (not (magit-rev-ancestor-p commit "HEAD")))
+ (magit-read-char-case
+ (format "%s isn't an ancestor of HEAD. " commit) nil
+ (?c "[c]reate without rebasing" (setq rebase nil))
+ (?s "[s]elect other" (setq commit nil))
+ (?a "[a]bort" (user-error "Quit")))))
+ (when commit
+ (setq commit (magit-rebase-interactive-assert commit t)))
+ (if (and commit
+ (or confirmed
+ (not (or rebase
+ current-prefix-arg
+ magit-commit-squash-confirm))))
+ (let ((magit-commit-show-diff nil))
+ (push (concat option "=" commit) args)
+ (unless edit
+ (push "--no-edit" args))
+ (if rebase
+ (magit-with-editor
+ (magit-call-git
+ "commit" "--no-gpg-sign"
+ (-remove-first
+ (apply-partially #'string-match-p "\\`--gpg-sign=")
+ args)))
+ (magit-run-git-with-editor "commit" args))
+ t) ; The commit was created; used by below lambda.
+ (magit-log-select
+ (lambda (commit)
+ (when (and (magit-commit-squash-internal option commit args
+ rebase edit t)
+ rebase)
+ (magit-commit-amend-assert commit)
+ (magit-rebase-interactive-1 commit
+ (list "--autosquash" "--autostash" "--keep-empty")
+ "" "true" nil t)))
+ (format "Type %%p on a commit to %s into it,"
+ (substring option 2))
+ nil nil nil commit)
+ (when magit-commit-show-diff
+ (let ((magit-display-buffer-noselect t))
+ (apply #'magit-diff-staged nil (magit-diff-arguments)))))))
+
+(defun magit-commit-amend-assert (&optional commit)
+ (--when-let (magit-list-publishing-branches commit)
+ (let ((m1 "This commit has already been published to ")
+ (m2 ".\nDo you really want to modify it"))
+ (magit-confirm 'amend-published
+ (concat m1 "%s" m2)
+ (concat m1 "%i public branches" m2)
+ nil it))))
+
+(defun magit-commit-assert (args &optional strict)
+ (cond
+ ((or (magit-anything-staged-p)
+ (and (magit-anything-unstaged-p)
+ ;; ^ Everything of nothing is still nothing.
+ (member "--all" args))
+ (and (not strict)
+ ;; ^ For amend variants that don't make sense otherwise.
+ (or (member "--amend" args)
+ (member "--allow-empty" args)
+ (member "--reset-author" args)
+ (member "--author" args)
+ (member "--signoff" args)
+ (cl-find-if (lambda (a) (string-match-p "\\`--date=" a)) args))))
+ (or args (list "--")))
+ ((and (magit-rebase-in-progress-p)
+ (not (magit-anything-unstaged-p))
+ (y-or-n-p "Nothing staged. Continue in-progress rebase? "))
+ (setq this-command 'magit-rebase-continue)
+ (magit-run-git-sequencer "rebase" "--continue")
+ nil)
+ ((and (file-exists-p (magit-git-dir "MERGE_MSG"))
+ (not (magit-anything-unstaged-p)))
+ (or args (list "--")))
+ ((not (magit-anything-unstaged-p))
+ (user-error "Nothing staged (or unstaged)"))
+ (magit-commit-ask-to-stage
+ (when (eq magit-commit-ask-to-stage 'verbose)
+ (magit-diff-unstaged))
+ (prog1 (when (or (eq magit-commit-ask-to-stage 'stage)
+ (y-or-n-p "Nothing staged. Stage and commit all unstaged changes? "))
+ (magit-run-git "add" "-u" ".")
+ (or args (list "--")))
+ (when (and (eq magit-commit-ask-to-stage 'verbose)
+ (derived-mode-p 'magit-diff-mode))
+ (magit-mode-bury-buffer))))
+ (t
+ (user-error "Nothing staged"))))
+
+(defvar magit--reshelve-history nil)
+
+;;;###autoload
+(defun magit-commit-reshelve (date)
+ "Change the committer date and possibly the author date of `HEAD'.
+
+If you are the author of `HEAD', then both dates are changed,
+otherwise only the committer date. The current time is used
+as the initial minibuffer input and the original author (if
+that is you) or committer date is available as the previous
+history element."
+ (interactive
+ (let ((author-p (magit-rev-author-p "HEAD")))
+ (push (magit-rev-format (if author-p "%ad" "%cd") "HEAD"
+ (concat "--date=format:%F %T %z"))
+ magit--reshelve-history)
+ (list (read-string (if author-p
+ "Change author and committer dates to: "
+ "Change committer date to: ")
+ (cons (format-time-string "%F %T %z") 17)
+ 'magit--reshelve-history))))
+ (let ((process-environment process-environment))
+ (push (concat "GIT_COMMITTER_DATE=" date) process-environment)
+ (magit-run-git "commit" "--amend" "--no-edit"
+ (and (magit-rev-author-p "HEAD")
+ (concat "--date=" date)))))
+
+;;;###autoload
+(defun magit-commit-absorb-modules (phase commit)
+ "Spread modified modules across recent commits."
+ (interactive (list 'select (magit-get-upstream-branch)))
+ (let ((modules (magit-list-modified-modules)))
+ (unless modules
+ (user-error "There are no modified modules that could be absorbed"))
+ (when commit
+ (setq commit (magit-rebase-interactive-assert commit t)))
+ (if (and commit (eq phase 'run))
+ (progn
+ (dolist (module modules)
+ (when-let ((msg (magit-git-string
+ "log" "-1" "--format=%s"
+ (concat commit "..") "--" module)))
+ (magit-git "commit" "-m" (concat "fixup! " msg)
+ "--only" "--" module)))
+ (magit-refresh)
+ t)
+ (magit-log-select
+ (lambda (commit)
+ (magit-commit-absorb-modules 'run commit))
+ nil nil nil nil commit))))
+
+;;;###autoload (autoload 'magit-commit-absorb "magit-commit" nil t)
+(transient-define-prefix magit-commit-absorb (phase commit args)
+ "Spread staged changes across recent commits.
+With a prefix argument use a transient command to select infix
+arguments. This command requires git-absorb executable, which
+is available from https://github.com/tummychow/git-absorb.
+See `magit-commit-autofixup' for an alternative implementation."
+ ["Arguments"
+ ("-f" "Skip safety checks" ("-f" "--force"))
+ ("-v" "Display more output" ("-v" "--verbose"))]
+ ["Actions"
+ ("x" "Absorb" magit-commit-absorb)]
+ (interactive (if current-prefix-arg
+ (list 'transient nil nil)
+ (list 'select
+ (magit-get-upstream-branch)
+ (transient-args 'magit-commit-absorb))))
+ (if (eq phase 'transient)
+ (transient-setup 'magit-commit-absorb)
+ (unless (executable-find "git-absorb")
+ (user-error "This command requires the git-absorb executable, which %s"
+ "is available from https://github.com/tummychow/git-absorb"))
+ (unless (magit-anything-staged-p)
+ (if (magit-anything-unstaged-p)
+ (if (y-or-n-p "Nothing staged. Absorb all unstaged changes? ")
+ (magit-with-toplevel
+ (magit-run-git "add" "-u" "."))
+ (user-error "Abort"))
+ (user-error "There are no changes that could be absorbed")))
+ (when commit
+ (setq commit (magit-rebase-interactive-assert commit t)))
+ (if (and commit (eq phase 'run))
+ (progn (magit-run-git-async "absorb" "-v" args "-b" commit) t)
+ (magit-log-select
+ (lambda (commit)
+ (with-no-warnings ; about non-interactive use
+ (magit-commit-absorb 'run commit args)))
+ nil nil nil nil commit))))
+
+;;;###autoload (autoload 'magit-commit-autofixup "magit-commit" nil t)
+(transient-define-prefix magit-commit-autofixup (phase commit args)
+ "Spread staged or unstaged changes across recent commits.
+
+If there are any staged then spread only those, otherwise
+spread all unstaged changes. With a prefix argument use a
+transient command to select infix arguments.
+
+This command requires the git-autofixup script, which is
+available from https://github.com/torbiak/git-autofixup.
+See `magit-commit-absorb' for an alternative implementation."
+ ["Arguments"
+ (magit-autofixup:--context)
+ (magit-autofixup:--strict)]
+ ["Actions"
+ ("x" "Absorb" magit-commit-autofixup)]
+ (interactive (if current-prefix-arg
+ (list 'transient nil nil)
+ (list 'select
+ (magit-get-upstream-branch)
+ (transient-args 'magit-commit-autofixup))))
+ (if (eq phase 'transient)
+ (transient-setup 'magit-commit-autofixup)
+ (unless (executable-find "git-autofixup")
+ (user-error "This command requires the git-autofixup script, which %s"
+ "is available from https://github.com/torbiak/git-autofixup"))
+ (unless (magit-anything-modified-p)
+ (user-error "There are no changes that could be absorbed"))
+ (when commit
+ (setq commit (magit-rebase-interactive-assert commit t)))
+ (if (and commit (eq phase 'run))
+ (progn (magit-run-git-async "autofixup" "-vv" args commit) t)
+ (magit-log-select
+ (lambda (commit)
+ (with-no-warnings ; about non-interactive use
+ (magit-commit-autofixup 'run commit args)))
+ nil nil nil nil commit))))
+
+(transient-define-argument magit-autofixup:--context ()
+ :description "Diff context lines"
+ :class 'transient-option
+ :shortarg "-c"
+ :argument "--context="
+ :reader 'transient-read-number-N0)
+
+(transient-define-argument magit-autofixup:--strict ()
+ :description "Strictness"
+ :class 'transient-option
+ :shortarg "-s"
+ :argument "--strict="
+ :reader 'transient-read-number-N0)
+
+;;; Pending Diff
+
+(defun magit-commit-diff ()
+ (when (and git-commit-mode magit-commit-show-diff)
+ (when-let ((diff-buffer (magit-get-mode-buffer 'magit-diff-mode)))
+ ;; This window just started displaying the commit message
+ ;; buffer. Without this that buffer would immediately be
+ ;; replaced with the diff buffer. See #2632.
+ (unrecord-window-buffer nil diff-buffer))
+ (condition-case nil
+ (let ((args (car (magit-diff-arguments)))
+ (magit-inhibit-save-previous-winconf 'unset)
+ (magit-display-buffer-noselect t)
+ (inhibit-quit nil)
+ (display-buffer-overriding-action '(nil (inhibit-same-window t))))
+ (message "Diffing changes to be committed (C-g to abort diffing)")
+ (cl-case last-command
+ (magit-commit
+ (magit-diff-staged nil args))
+ (magit-commit-all
+ (magit-diff-working-tree nil args))
+ ((magit-commit-amend
+ magit-commit-reword
+ magit-rebase-reword-commit)
+ (magit-diff-while-amending args))
+ (t (if (magit-anything-staged-p)
+ (magit-diff-staged nil args)
+ (magit-diff-while-amending args)))))
+ (quit))))
+
+;; Mention `magit-diff-while-committing' because that's
+;; always what I search for when I try to find this line.
+(add-hook 'server-switch-hook 'magit-commit-diff)
+(add-hook 'with-editor-filter-visit-hook 'magit-commit-diff)
+
+(add-to-list 'with-editor-server-window-alist
+ (cons git-commit-filename-regexp 'switch-to-buffer))
+
+;;; Message Utilities
+
+(defun magit-commit-message-buffer ()
+ (let* ((find-file-visit-truename t) ; git uses truename of COMMIT_EDITMSG
+ (topdir (magit-toplevel)))
+ (--first (equal topdir (with-current-buffer it
+ (and git-commit-mode (magit-toplevel))))
+ (append (buffer-list (selected-frame))
+ (buffer-list)))))
+
+(defvar magit-commit-add-log-insert-function 'magit-commit-add-log-insert
+ "Used by `magit-commit-add-log' to insert a single entry.")
+
+(defun magit-commit-add-log ()
+ "Add a stub for the current change into the commit message buffer.
+If no commit is in progress, then initiate it. Use the function
+specified by variable `magit-commit-add-log-insert-function' to
+actually insert the entry."
+ (interactive)
+ (pcase-let* ((hunk (and (magit-section-match 'hunk)
+ (magit-current-section)))
+ (log (magit-commit-message-buffer))
+ (`(,buf ,pos) (magit-diff-visit-file--noselect)))
+ (unless log
+ (unless (magit-commit-assert nil)
+ (user-error "Abort"))
+ (magit-commit-create)
+ (while (not (setq log (magit-commit-message-buffer)))
+ (sit-for 0.01)))
+ (magit--with-temp-position buf pos
+ (funcall magit-commit-add-log-insert-function log
+ (magit-file-relative-name)
+ (and hunk (add-log-current-defun))))))
+
+(defun magit-commit-add-log-insert (buffer file defun)
+ (with-current-buffer buffer
+ (undo-boundary)
+ (goto-char (point-max))
+ (while (re-search-backward (concat "^" comment-start) nil t))
+ (save-restriction
+ (narrow-to-region (point-min) (point))
+ (cond ((re-search-backward (format "* %s\\(?: (\\([^)]+\\))\\)?: " file)
+ nil t)
+ (when (equal (match-string 1) defun)
+ (setq defun nil))
+ (re-search-forward ": "))
+ (t
+ (when (re-search-backward "^[\\*(].+\n" nil t)
+ (goto-char (match-end 0)))
+ (while (re-search-forward "^[^\\*\n].*\n" nil t))
+ (if defun
+ (progn (insert (format "* %s (%s): \n" file defun))
+ (setq defun nil))
+ (insert (format "* %s: \n" file)))
+ (backward-char)
+ (unless (looking-at "\n[\n\\']")
+ (insert ?\n)
+ (backward-char))))
+ (when defun
+ (forward-line)
+ (let ((limit (save-excursion
+ (and (re-search-forward "^\\*" nil t)
+ (point)))))
+ (unless (or (looking-back (format "(%s): " defun)
+ (line-beginning-position))
+ (re-search-forward (format "^(%s): " defun) limit t))
+ (while (re-search-forward "^[^\\*\n].*\n" limit t))
+ (insert (format "(%s): \n" defun))
+ (backward-char)))))))
+
+;;; _
+(provide 'magit-commit)
+;;; magit-commit.el ends here
--- /dev/null
+;;; magit-core.el --- core functionality -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library requires several other libraries, so that yet other
+;; libraries can just require this one, instead of having to require
+;; all the other ones. In other words this separates the low-level
+;; stuff from the rest. It also defines some Custom groups.
+
+;;; Code:
+
+(require 'magit-utils)
+(require 'magit-section)
+(require 'magit-git)
+(require 'magit-mode)
+(require 'magit-margin)
+(require 'magit-process)
+(require 'magit-transient)
+(require 'magit-autorevert)
+
+(when (magit--libgit-available-p)
+ (condition-case err
+ (require 'magit-libgit)
+ (error
+ (setq magit-inhibit-libgit 'error)
+ (message "Error while loading `magit-libgit': %S" err)
+ (message "That is not fatal. The `libegit2' module just won't be used."))))
+
+(defgroup magit nil
+ "Controlling Git from Emacs."
+ :link '(url-link "https://magit.vc")
+ :link '(info-link "(magit)FAQ")
+ :link '(info-link "(magit)")
+ :group 'tools)
+
+(defgroup magit-essentials nil
+ "Options that every Magit user should briefly think about.
+
+Each of these options falls into one or more of these categories:
+
+* Options that affect Magit's behavior in fundamental ways.
+* Options that affect safety.
+* Options that affect performance.
+* Options that are of a personal nature."
+ :link '(info-link "(magit)Essential Settings")
+ :group 'magit)
+
+(defgroup magit-miscellaneous nil
+ "Miscellaneous Magit options."
+ :group 'magit)
+
+(defgroup magit-commands nil
+ "Options controlling behavior of certain commands."
+ :group 'magit)
+
+(defgroup magit-modes nil
+ "Modes used or provided by Magit."
+ :group 'magit)
+
+(defgroup magit-buffers nil
+ "Options concerning Magit buffers."
+ :link '(info-link "(magit)Modes and Buffers")
+ :group 'magit)
+
+(defgroup magit-refresh nil
+ "Options controlling how Magit buffers are refreshed."
+ :link '(info-link "(magit)Automatic Refreshing of Magit Buffers")
+ :group 'magit
+ :group 'magit-buffers)
+
+(defgroup magit-faces nil
+ "Faces used by Magit."
+ :group 'magit
+ :group 'faces)
+
+(defgroup magit-extensions nil
+ "Extensions to Magit."
+ :group 'magit)
+
+(custom-add-to-group 'magit-modes 'git-commit 'custom-group)
+(custom-add-to-group 'magit-faces 'git-commit-faces 'custom-group)
+(custom-add-to-group 'magit-modes 'git-rebase 'custom-group)
+(custom-add-to-group 'magit-faces 'git-rebase-faces 'custom-group)
+(custom-add-to-group 'magit 'magit-section 'custom-group)
+(custom-add-to-group 'magit-faces 'magit-section-faces 'custom-group)
+(custom-add-to-group 'magit-process 'with-editor 'custom-group)
+
+(defgroup magit-related nil
+ "Options that are relevant to Magit but that are defined elsewhere."
+ :link '(custom-group-link vc)
+ :link '(custom-group-link smerge)
+ :link '(custom-group-link ediff)
+ :link '(custom-group-link auto-revert)
+ :group 'magit
+ :group 'magit-extensions
+ :group 'magit-essentials)
+
+(custom-add-to-group 'magit-related 'auto-revert-check-vc-info 'custom-variable)
+(custom-add-to-group 'magit-auto-revert 'auto-revert-check-vc-info 'custom-variable)
+
+(custom-add-to-group 'magit-related 'ediff-window-setup-function 'custom-variable)
+(custom-add-to-group 'magit-related 'smerge-refine-ignore-whitespace 'custom-variable)
+(custom-add-to-group 'magit-related 'vc-follow-symlinks 'custom-variable)
+
+;;; _
+(provide 'magit-core)
+;;; magit-core.el ends here
--- /dev/null
+;;; magit-diff.el --- inspect Git diffs -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements support for looking at Git diffs and
+;; commits.
+
+;;; Code:
+
+(require 'magit-core)
+(require 'git-commit)
+
+(eval-when-compile (require 'ansi-color))
+(require 'diff-mode)
+(require 'smerge-mode)
+
+;; For `magit-diff-popup'
+(declare-function magit-stash-show "magit-stash" (stash &optional args files))
+;; For `magit-diff-visit-file'
+(declare-function dired-jump "dired-x" (&optional other-window file-name))
+(declare-function magit-find-file-noselect "magit-files" (rev file))
+(declare-function magit-status-setup-buffer "magit-status" (directory))
+;; For `magit-diff-while-committing'
+(declare-function magit-commit-message-buffer "magit-commit" ())
+;; For `magit-insert-revision-gravatar'
+(defvar gravatar-size)
+;; For `magit-show-commit' and `magit-diff-show-or-scroll'
+(declare-function magit-current-blame-chunk "magit-blame" ())
+(declare-function magit-blame-mode "magit-blame" (&optional arg))
+(defvar magit-blame-mode)
+;; For `magit-diff-show-or-scroll'
+(declare-function git-rebase-current-line "git-rebase" ())
+;; For `magit-diff-unmerged'
+(declare-function magit-merge-in-progress-p "magit-merge" ())
+(declare-function magit--merge-range "magit-merge" (&optional head))
+;; For `magit-diff--dwim'
+(declare-function forge--pullreq-range "forge-pullreq"
+ (pullreq &optional endpoints))
+(declare-function forge--pullreq-ref "forge-pullreq" (pullreq))
+;; For `magit-diff-wash-diff'
+(declare-function ansi-color-apply-on-region "ansi-color" (begin end))
+
+(eval-when-compile
+ (cl-pushnew 'orig-rev eieio--known-slot-names)
+ (cl-pushnew 'action-type eieio--known-slot-names)
+ (cl-pushnew 'target eieio--known-slot-names))
+
+;;; Options
+;;;; Diff Mode
+
+(defgroup magit-diff nil
+ "Inspect and manipulate Git diffs."
+ :link '(info-link "(magit)Diffing")
+ :group 'magit-commands
+ :group 'magit-modes)
+
+(defcustom magit-diff-mode-hook nil
+ "Hook run after entering Magit-Diff mode."
+ :group 'magit-diff
+ :type 'hook)
+
+(defcustom magit-diff-sections-hook
+ '(magit-insert-diff
+ magit-insert-xref-buttons)
+ "Hook run to insert sections into a `magit-diff-mode' buffer."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-diff
+ :type 'hook)
+
+(defcustom magit-diff-expansion-threshold 60
+ "After how many seconds not to expand anymore diffs.
+
+Except in status buffers, diffs are usually start out fully
+expanded. Because that can take a long time, all diffs that
+haven't been fontified during a refresh before the threshold
+defined here are instead displayed with their bodies collapsed.
+
+Note that this can cause sections that were previously expanded
+to be collapsed. So you should not pick a very low value here.
+
+The hook function `magit-diff-expansion-threshold' has to be a
+member of `magit-section-set-visibility-hook' for this option
+to have any effect."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-diff
+ :type 'float)
+
+(defcustom magit-diff-highlight-hunk-body t
+ "Whether to highlight bodies of selected hunk sections.
+This only has an effect if `magit-diff-highlight' is a
+member of `magit-section-highlight-hook', which see."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-diff
+ :type 'boolean)
+
+(defcustom magit-diff-highlight-hunk-region-functions
+ '(magit-diff-highlight-hunk-region-dim-outside
+ magit-diff-highlight-hunk-region-using-overlays)
+ "The functions used to highlight the hunk-internal region.
+
+`magit-diff-highlight-hunk-region-dim-outside' overlays the outside
+of the hunk internal selection with a face that causes the added and
+removed lines to have the same background color as context lines.
+This function should not be removed from the value of this option.
+
+`magit-diff-highlight-hunk-region-using-overlays' and
+`magit-diff-highlight-hunk-region-using-underline' emphasize the
+region by placing delimiting horizontal lines before and after it.
+The underline variant was implemented because Eli said that is
+how we should do it. However the overlay variant actually works
+better. Also see https://github.com/magit/magit/issues/2758.
+
+Instead of, or in addition to, using delimiting horizontal lines,
+to emphasize the boundaries, you may which to emphasize the text
+itself, using `magit-diff-highlight-hunk-region-using-face'.
+
+In terminal frames it's not possible to draw lines as the overlay
+and underline variants normally do, so there they fall back to
+calling the face function instead."
+ :package-version '(magit . "2.9.0")
+ :set-after '(magit-diff-show-lines-boundaries)
+ :group 'magit-diff
+ :type 'hook
+ :options '(magit-diff-highlight-hunk-region-dim-outside
+ magit-diff-highlight-hunk-region-using-underline
+ magit-diff-highlight-hunk-region-using-overlays
+ magit-diff-highlight-hunk-region-using-face))
+
+(defcustom magit-diff-unmarked-lines-keep-foreground t
+ "Whether `magit-diff-highlight-hunk-region-dim-outside' preserves foreground.
+When this is set to nil, then that function only adjusts the
+foreground color but added and removed lines outside the region
+keep their distinct foreground colors."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-diff
+ :type 'boolean)
+
+(defcustom magit-diff-refine-hunk nil
+ "Whether to show word-granularity differences within diff hunks.
+
+nil Never show fine differences.
+t Show fine differences for the current diff hunk only.
+`all' Show fine differences for all displayed diff hunks."
+ :group 'magit-diff
+ :safe (lambda (val) (memq val '(nil t all)))
+ :type '(choice (const :tag "Never" nil)
+ (const :tag "Current" t)
+ (const :tag "All" all)))
+
+(defcustom magit-diff-refine-ignore-whitespace smerge-refine-ignore-whitespace
+ "Whether to ignore whitespace changes in word-granularity differences."
+ :package-version '(magit . "3.0.0")
+ :set-after '(smerge-refine-ignore-whitespace)
+ :group 'magit-diff
+ :safe 'booleanp
+ :type 'boolean)
+
+(put 'magit-diff-refine-hunk 'permanent-local t)
+
+(defcustom magit-diff-adjust-tab-width nil
+ "Whether to adjust the width of tabs in diffs.
+
+Determining the correct width can be expensive if it requires
+opening large and/or many files, so the widths are cached in
+the variable `magit-diff--tab-width-cache'. Set that to nil
+to invalidate the cache.
+
+nil Never adjust tab width. Use `tab-width's value from
+ the Magit buffer itself instead.
+
+t If the corresponding file-visiting buffer exits, then
+ use `tab-width's value from that buffer. Doing this is
+ cheap, so this value is used even if a corresponding
+ cache entry exists.
+
+`always' If there is no such buffer, then temporarily visit the
+ file to determine the value.
+
+NUMBER Like `always', but don't visit files larger than NUMBER
+ bytes."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-diff
+ :type '(choice (const :tag "Never" nil)
+ (const :tag "If file-visiting buffer exists" t)
+ (integer :tag "If file isn't larger than N bytes")
+ (const :tag "Always" always)))
+
+(defcustom magit-diff-paint-whitespace t
+ "Specify where to highlight whitespace errors.
+
+nil Never highlight whitespace errors.
+t Highlight whitespace errors everywhere.
+`uncommitted' Only highlight whitespace errors in diffs
+ showing uncommitted changes.
+
+For backward compatibility `status' is treated as a synonym
+for `uncommitted'.
+
+The option `magit-diff-paint-whitespace-lines' controls for
+what lines (added/remove/context) errors are highlighted.
+
+The options `magit-diff-highlight-trailing' and
+`magit-diff-highlight-indentation' control what kind of
+whitespace errors are highlighted."
+ :group 'magit-diff
+ :safe (lambda (val) (memq val '(t nil uncommitted status)))
+ :type '(choice (const :tag "In all diffs" t)
+ (const :tag "Only in uncommitted changes" uncommitted)
+ (const :tag "Never" nil)))
+
+(defcustom magit-diff-paint-whitespace-lines t
+ "Specify in what kind of lines to highlight whitespace errors.
+
+t Highlight only in added lines.
+`both' Highlight in added and removed lines.
+`all' Highlight in added, removed and context lines."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-diff
+ :safe (lambda (val) (memq val '(t both all)))
+ :type '(choice (const :tag "in added lines" t)
+ (const :tag "in added and removed lines" both)
+ (const :tag "in added, removed and context lines" all)))
+
+(defcustom magit-diff-highlight-trailing t
+ "Whether to highlight whitespace at the end of a line in diffs.
+Used only when `magit-diff-paint-whitespace' is non-nil."
+ :group 'magit-diff
+ :safe 'booleanp
+ :type 'boolean)
+
+(defcustom magit-diff-highlight-indentation nil
+ "Highlight the \"wrong\" indentation style.
+Used only when `magit-diff-paint-whitespace' is non-nil.
+
+The value is an alist of the form ((REGEXP . INDENT)...). The
+path to the current repository is matched against each element
+in reverse order. Therefore if a REGEXP matches, then earlier
+elements are not tried.
+
+If the used INDENT is `tabs', highlight indentation with tabs.
+If INDENT is an integer, highlight indentation with at least
+that many spaces. Otherwise, highlight neither."
+ :group 'magit-diff
+ :type `(repeat (cons (string :tag "Directory regexp")
+ (choice (const :tag "Tabs" tabs)
+ (integer :tag "Spaces" :value ,tab-width)
+ (const :tag "Neither" nil)))))
+
+(defcustom magit-diff-hide-trailing-cr-characters
+ (and (memq system-type '(ms-dos windows-nt)) t)
+ "Whether to hide ^M characters at the end of a line in diffs."
+ :package-version '(magit . "2.6.0")
+ :group 'magit-diff
+ :type 'boolean)
+
+(defcustom magit-diff-highlight-keywords t
+ "Whether to highlight bracketed keywords in commit messages."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-diff
+ :type 'boolean)
+
+(defcustom magit-diff-extra-stat-arguments nil
+ "Additional arguments to be used alongside `--stat'.
+
+A list of zero or more arguments or a function that takes no
+argument and returns such a list. These arguments are allowed
+here: `--stat-width', `--stat-name-width', `--stat-graph-width'
+and `--compact-summary'. See the git-diff(1) manpage."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-diff
+ :type '(radio (function-item magit-diff-use-window-width-as-stat-width)
+ function
+ (list string)
+ (const :tag "None" nil)))
+
+;;;; File Diff
+
+(defcustom magit-diff-buffer-file-locked t
+ "Whether `magit-diff-buffer-file' uses a dedicated buffer."
+ :package-version '(magit . "2.7.0")
+ :group 'magit-commands
+ :group 'magit-diff
+ :type 'boolean)
+
+;;;; Revision Mode
+
+(defgroup magit-revision nil
+ "Inspect and manipulate Git commits."
+ :link '(info-link "(magit)Revision Buffer")
+ :group 'magit-modes)
+
+(defcustom magit-revision-mode-hook
+ '(bug-reference-mode
+ goto-address-mode)
+ "Hook run after entering Magit-Revision mode."
+ :group 'magit-revision
+ :type 'hook
+ :options '(bug-reference-mode
+ goto-address-mode))
+
+(defcustom magit-revision-sections-hook
+ '(magit-insert-revision-tag
+ magit-insert-revision-headers
+ magit-insert-revision-message
+ magit-insert-revision-notes
+ magit-insert-revision-diff
+ magit-insert-xref-buttons)
+ "Hook run to insert sections into a `magit-revision-mode' buffer."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-revision
+ :type 'hook)
+
+(defcustom magit-revision-headers-format "\
+Author: %aN <%aE>
+AuthorDate: %ad
+Commit: %cN <%cE>
+CommitDate: %cd
+"
+ "Format string used to insert headers in revision buffers.
+
+All headers in revision buffers are inserted by the section
+inserter `magit-insert-revision-headers'. Some of the headers
+are created by calling `git show --format=FORMAT' where FORMAT
+is the format specified here. Other headers are hard coded or
+subject to option `magit-revision-insert-related-refs'."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-revision
+ :type 'string)
+
+(defcustom magit-revision-insert-related-refs t
+ "Whether to show related branches in revision buffers
+
+`nil' Don't show any related branches.
+`t' Show related local branches.
+`all' Show related local and remote branches.
+`mixed' Show all containing branches and local merged branches."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-revision
+ :type '(choice (const :tag "don't" nil)
+ (const :tag "local only" t)
+ (const :tag "all related" all)
+ (const :tag "all containing, local merged" mixed)))
+
+(defcustom magit-revision-use-hash-sections 'quicker
+ "Whether to turn hashes inside the commit message into sections.
+
+If non-nil, then hashes inside the commit message are turned into
+`commit' sections. There is a trade off to be made between
+performance and reliability:
+
+- `slow' calls git for every word to be absolutely sure.
+- `quick' skips words less than seven characters long.
+- `quicker' additionally skips words that don't contain a number.
+- `quickest' uses all words that are at least seven characters
+ long and which contain at least one number as well as at least
+ one letter.
+
+If nil, then no hashes are turned into sections, but you can
+still visit the commit at point using \"RET\"."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-revision
+ :type '(choice (const :tag "Use sections, quickest" quickest)
+ (const :tag "Use sections, quicker" quicker)
+ (const :tag "Use sections, quick" quick)
+ (const :tag "Use sections, slow" slow)
+ (const :tag "Don't use sections" nil)))
+
+(defcustom magit-revision-show-gravatars nil
+ "Whether to show gravatar images in revision buffers.
+
+If nil, then don't insert any gravatar images. If t, then insert
+both images. If `author' or `committer', then insert only the
+respective image.
+
+If you have customized the option `magit-revision-header-format'
+and want to insert the images then you might also have to specify
+where to do so. In that case the value has to be a cons-cell of
+two regular expressions. The car specifies where to insert the
+author's image. The top half of the image is inserted right
+after the matched text, the bottom half on the next line in the
+same column. The cdr specifies where to insert the committer's
+image, accordingly. Either the car or the cdr may be nil."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-revision
+ :type '(choice (const :tag "Don't show gravatars" nil)
+ (const :tag "Show gravatars" t)
+ (const :tag "Show author gravatar" author)
+ (const :tag "Show committer gravatar" committer)
+ (cons :tag "Show gravatars using custom pattern."
+ (regexp :tag "Author regexp" "^Author: ")
+ (regexp :tag "Committer regexp" "^Commit: "))))
+
+(defcustom magit-revision-use-gravatar-kludge nil
+ "Whether to work around a bug which affects display of gravatars.
+
+Gravatar images are spliced into two halves which are then
+displayed on separate lines. On OS X the splicing has a bug in
+some Emacs builds, which causes the top and bottom halves to be
+interchanged. Enabling this option works around this issue by
+interchanging the halves once more, which cancels out the effect
+of the bug.
+
+See https://github.com/magit/magit/issues/2265
+and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=7847.
+
+Starting with Emacs 26.1 this kludge should not be required for
+any build."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-revision
+ :type 'boolean)
+
+(defcustom magit-revision-fill-summary-line nil
+ "Whether to fill excessively long summary lines.
+
+If this is an integer, then the summary line is filled if it is
+longer than either the limit specified here or `window-width'.
+
+You may want to only set this locally in \".dir-locals-2.el\" for
+repositories known to contain bad commit messages.
+
+The body of the message is left alone because (a) most people who
+write excessively long summary lines usually don't add a body and
+(b) even people who have the decency to wrap their lines may have
+a good reason to include a long line in the body sometimes."
+ :package-version '(magit . "2.90.0")
+ :group 'magit-revision
+ :type '(choice (const :tag "Don't fill" nil)
+ (integer :tag "Fill if longer than")))
+
+(defcustom magit-revision-filter-files-on-follow nil
+ "Whether to honor file filter if log arguments include --follow.
+
+When a commit is displayed from a log buffer, the resulting
+revision buffer usually shares the log's file arguments,
+restricting the diff to those files. However, there's a
+complication when the log arguments include --follow: if the log
+follows a file across a rename event, keeping the file
+restriction would mean showing an empty diff in revision buffers
+for commits before the rename event.
+
+When this option is nil, the revision buffer ignores the log's
+filter if the log arguments include --follow. If non-nil, the
+log's file filter is always honored."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-revision
+ :type 'boolean)
+
+;;;; Visit Commands
+
+(defcustom magit-diff-visit-previous-blob t
+ "Whether `magit-diff-visit-file' may visit the previous blob.
+
+When this is t and point is on a removed line in a diff for a
+committed change, then `magit-diff-visit-file' visits the blob
+from the last revision which still had that line.
+
+Currently this is only supported for committed changes, for
+staged and unstaged changes `magit-diff-visit-file' always
+visits the file in the working tree."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-diff
+ :type 'boolean)
+
+(defcustom magit-diff-visit-avoid-head-blob nil
+ "Whether `magit-diff-visit-file' avoids visiting a blob from `HEAD'.
+
+By default `magit-diff-visit-file' always visits the blob that
+added the current line, while `magit-diff-visit-worktree-file'
+visits the respective file in the working tree. For the `HEAD'
+commit, the former command used to visit the worktree file too,
+but that made it impossible to visit a blob from `HEAD'.
+
+When point is on a removed line and that change has not been
+committed yet, then `magit-diff-visit-file' now visits the last
+blob that still had that line, which is a blob from `HEAD'.
+Previously this function used to visit the worktree file not
+only for added lines but also for such removed lines.
+
+If you prefer the old behaviors, then set this to t."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-diff
+ :type 'boolean)
+
+;;; Faces
+
+(defface magit-diff-file-heading
+ `((t ,@(and (>= emacs-major-version 27) '(:extend t))
+ :weight bold))
+ "Face for diff file headings."
+ :group 'magit-faces)
+
+(defface magit-diff-file-heading-highlight
+ `((t ,@(and (>= emacs-major-version 27) '(:extend t))
+ :inherit magit-section-highlight))
+ "Face for current diff file headings."
+ :group 'magit-faces)
+
+(defface magit-diff-file-heading-selection
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :inherit magit-diff-file-heading-highlight
+ :foreground "salmon4")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :inherit magit-diff-file-heading-highlight
+ :foreground "LightSalmon3"))
+ "Face for selected diff file headings."
+ :group 'magit-faces)
+
+(defface magit-diff-hunk-heading
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "grey80"
+ :foreground "grey30")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "grey25"
+ :foreground "grey70"))
+ "Face for diff hunk headings."
+ :group 'magit-faces)
+
+(defface magit-diff-hunk-heading-highlight
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "grey75"
+ :foreground "grey30")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "grey35"
+ :foreground "grey70"))
+ "Face for current diff hunk headings."
+ :group 'magit-faces)
+
+(defface magit-diff-hunk-heading-selection
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :inherit magit-diff-hunk-heading-highlight
+ :foreground "salmon4")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :inherit magit-diff-hunk-heading-highlight
+ :foreground "LightSalmon3"))
+ "Face for selected diff hunk headings."
+ :group 'magit-faces)
+
+(defface magit-diff-hunk-region
+ `((t :inherit bold
+ ,@(and (>= emacs-major-version 27)
+ (list :extend (ignore-errors (face-attribute 'region :extend))))))
+ "Face used by `magit-diff-highlight-hunk-region-using-face'.
+
+This face is overlaid over text that uses other hunk faces,
+and those normally set the foreground and background colors.
+The `:foreground' and especially the `:background' properties
+should be avoided here. Setting the latter would cause the
+loss of information. Good properties to set here are `:weight'
+and `:slant'."
+ :group 'magit-faces)
+
+(defface magit-diff-revision-summary
+ '((t :inherit magit-diff-hunk-heading))
+ "Face for commit message summaries."
+ :group 'magit-faces)
+
+(defface magit-diff-revision-summary-highlight
+ '((t :inherit magit-diff-hunk-heading-highlight))
+ "Face for highlighted commit message summaries."
+ :group 'magit-faces)
+
+(defface magit-diff-lines-heading
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :inherit magit-diff-hunk-heading-highlight
+ :background "LightSalmon3")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :inherit magit-diff-hunk-heading-highlight
+ :foreground "grey80"
+ :background "salmon4"))
+ "Face for diff hunk heading when lines are marked."
+ :group 'magit-faces)
+
+(defface magit-diff-lines-boundary
+ `((t ,@(and (>= emacs-major-version 27) '(:extend t)) ; !important
+ :inherit magit-diff-lines-heading))
+ "Face for boundary of marked lines in diff hunk."
+ :group 'magit-faces)
+
+(defface magit-diff-conflict-heading
+ '((t :inherit magit-diff-hunk-heading))
+ "Face for conflict markers."
+ :group 'magit-faces)
+
+(defface magit-diff-added
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "#ddffdd"
+ :foreground "#22aa22")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "#335533"
+ :foreground "#ddffdd"))
+ "Face for lines in a diff that have been added."
+ :group 'magit-faces)
+
+(defface magit-diff-removed
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "#ffdddd"
+ :foreground "#aa2222")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "#553333"
+ :foreground "#ffdddd"))
+ "Face for lines in a diff that have been removed."
+ :group 'magit-faces)
+
+(defface magit-diff-our
+ '((t :inherit magit-diff-removed))
+ "Face for lines in a diff for our side in a conflict."
+ :group 'magit-faces)
+
+(defface magit-diff-base
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "#ffffcc"
+ :foreground "#aaaa11")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "#555522"
+ :foreground "#ffffcc"))
+ "Face for lines in a diff for the base side in a conflict."
+ :group 'magit-faces)
+
+(defface magit-diff-their
+ '((t :inherit magit-diff-added))
+ "Face for lines in a diff for their side in a conflict."
+ :group 'magit-faces)
+
+(defface magit-diff-context
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :foreground "grey50")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :foreground "grey70"))
+ "Face for lines in a diff that are unchanged."
+ :group 'magit-faces)
+
+(defface magit-diff-added-highlight
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "#cceecc"
+ :foreground "#22aa22")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "#336633"
+ :foreground "#cceecc"))
+ "Face for lines in a diff that have been added."
+ :group 'magit-faces)
+
+(defface magit-diff-removed-highlight
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "#eecccc"
+ :foreground "#aa2222")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "#663333"
+ :foreground "#eecccc"))
+ "Face for lines in a diff that have been removed."
+ :group 'magit-faces)
+
+(defface magit-diff-our-highlight
+ '((t :inherit magit-diff-removed-highlight))
+ "Face for lines in a diff for our side in a conflict."
+ :group 'magit-faces)
+
+(defface magit-diff-base-highlight
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "#eeeebb"
+ :foreground "#aaaa11")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "#666622"
+ :foreground "#eeeebb"))
+ "Face for lines in a diff for the base side in a conflict."
+ :group 'magit-faces)
+
+(defface magit-diff-their-highlight
+ '((t :inherit magit-diff-added-highlight))
+ "Face for lines in a diff for their side in a conflict."
+ :group 'magit-faces)
+
+(defface magit-diff-context-highlight
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "grey95"
+ :foreground "grey50")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "grey20"
+ :foreground "grey70"))
+ "Face for lines in the current context in a diff."
+ :group 'magit-faces)
+
+(defface magit-diff-whitespace-warning
+ '((t :inherit trailing-whitespace))
+ "Face for highlighting whitespace errors added lines."
+ :group 'magit-faces)
+
+(defface magit-diffstat-added
+ '((((class color) (background light)) :foreground "#22aa22")
+ (((class color) (background dark)) :foreground "#448844"))
+ "Face for plus sign in diffstat."
+ :group 'magit-faces)
+
+(defface magit-diffstat-removed
+ '((((class color) (background light)) :foreground "#aa2222")
+ (((class color) (background dark)) :foreground "#aa4444"))
+ "Face for minus sign in diffstat."
+ :group 'magit-faces)
+
+;;; Arguments
+;;;; Prefix Classes
+
+(defclass magit-diff-prefix (transient-prefix)
+ ((history-key :initform 'magit-diff)
+ (major-mode :initform 'magit-diff-mode)))
+
+(defclass magit-diff-refresh-prefix (magit-diff-prefix)
+ ((history-key :initform 'magit-diff)
+ (major-mode :initform nil)))
+
+;;;; Prefix Methods
+
+(cl-defmethod transient-init-value ((obj magit-diff-prefix))
+ (pcase-let ((`(,args ,files)
+ (magit-diff--get-value 'magit-diff-mode
+ magit-prefix-use-buffer-arguments)))
+ (unless (eq transient-current-command 'magit-dispatch)
+ (when-let ((file (magit-file-relative-name)))
+ (setq files (list file))))
+ (oset obj value (if files `(("--" ,@files) ,args) args))))
+
+(cl-defmethod transient-init-value ((obj magit-diff-refresh-prefix))
+ (oset obj value (if magit-buffer-diff-files
+ `(("--" ,@magit-buffer-diff-files)
+ ,magit-buffer-diff-args)
+ magit-buffer-diff-args)))
+
+(cl-defmethod transient-set-value ((obj magit-diff-prefix))
+ (magit-diff--set-value obj))
+
+(cl-defmethod transient-save-value ((obj magit-diff-prefix))
+ (magit-diff--set-value obj 'save))
+
+;;;; Argument Access
+
+(defun magit-diff-arguments (&optional mode)
+ "Return the current diff arguments."
+ (if (memq transient-current-command '(magit-diff magit-diff-refresh))
+ (pcase-let ((`(,args ,alist)
+ (-separate #'atom (transient-get-value))))
+ (list args (cdr (assoc "--" alist))))
+ (magit-diff--get-value (or mode 'magit-diff-mode))))
+
+(defun magit-diff--get-value (mode &optional use-buffer-args)
+ (unless use-buffer-args
+ (setq use-buffer-args magit-direct-use-buffer-arguments))
+ (let (args files)
+ (cond
+ ((and (memq use-buffer-args '(always selected current))
+ (eq major-mode mode))
+ (setq args magit-buffer-diff-args)
+ (setq files magit-buffer-diff-files))
+ ((and (memq use-buffer-args '(always selected))
+ (when-let ((buffer (magit-get-mode-buffer
+ mode nil
+ (eq use-buffer-args 'selected))))
+ (setq args (buffer-local-value 'magit-buffer-diff-args buffer))
+ (setq files (buffer-local-value 'magit-buffer-diff-files buffer))
+ t)))
+ ((plist-member (symbol-plist mode) 'magit-diff-current-arguments)
+ (setq args (get mode 'magit-diff-current-arguments)))
+ ((when-let ((elt (assq (intern (format "magit-diff:%s" mode))
+ transient-values)))
+ (setq args (cdr elt))
+ t))
+ (t
+ (setq args (get mode 'magit-diff-default-arguments))))
+ (list args files)))
+
+(defun magit-diff--set-value (obj &optional save)
+ (pcase-let* ((obj (oref obj prototype))
+ (mode (or (oref obj major-mode) major-mode))
+ (key (intern (format "magit-diff:%s" mode)))
+ (`(,args ,alist)
+ (-separate #'atom (transient-get-value)))
+ (files (cdr (assoc "--" alist))))
+ (put mode 'magit-diff-current-arguments args)
+ (when save
+ (setf (alist-get key transient-values) args)
+ (transient-save-values))
+ (transient--history-push obj)
+ (setq magit-buffer-diff-args args)
+ (setq magit-buffer-diff-files files)
+ (magit-refresh)))
+
+;;; Section Classes
+
+(defclass magit-file-section (magit-section)
+ ((keymap :initform magit-file-section-map)
+ (source :initform nil)
+ (header :initform nil)))
+
+(defclass magit-module-section (magit-file-section)
+ ((keymap :initform magit-hunk-section-map)))
+
+(defclass magit-hunk-section (magit-section)
+ ((keymap :initform magit-hunk-section-map)
+ (refined :initform nil)
+ (combined :initform nil)
+ (from-range :initform nil)
+ (from-ranges :initform nil)
+ (to-range :initform nil)
+ (about :initform nil)))
+
+(setf (alist-get 'hunk magit--section-type-alist) 'magit-hunk-section)
+(setf (alist-get 'module magit--section-type-alist) 'magit-module-section)
+(setf (alist-get 'file magit--section-type-alist) 'magit-file-section)
+
+;;; Commands
+;;;; Prefix Commands
+
+;;;###autoload (autoload 'magit-diff "magit-diff" nil t)
+(transient-define-prefix magit-diff ()
+ "Show changes between different versions."
+ :man-page "git-diff"
+ :class 'magit-diff-prefix
+ ["Limit arguments"
+ (magit:--)
+ (magit-diff:--ignore-submodules)
+ ("-b" "Ignore whitespace changes" ("-b" "--ignore-space-change"))
+ ("-w" "Ignore all whitespace" ("-w" "--ignore-all-space"))
+ (5 "-D" "Omit preimage for deletes" ("-D" "--irreversible-delete"))]
+ ["Context arguments"
+ (magit-diff:-U)
+ ("-W" "Show surrounding functions" ("-W" "--function-context"))]
+ ["Tune arguments"
+ (magit-diff:--diff-algorithm)
+ (magit-diff:-M)
+ (magit-diff:-C)
+ ("-x" "Disallow external diff drivers" "--no-ext-diff")
+ ("-s" "Show stats" "--stat")
+ ("=g" "Show signature" "--show-signature")
+ (5 magit-diff:--color-moved)
+ (5 magit-diff:--color-moved-ws)]
+ ["Actions"
+ [("d" "Dwim" magit-diff-dwim)
+ ("r" "Diff range" magit-diff-range)
+ ("p" "Diff paths" magit-diff-paths)]
+ [("u" "Diff unstaged" magit-diff-unstaged)
+ ("s" "Diff staged" magit-diff-staged)
+ ("w" "Diff worktree" magit-diff-working-tree)]
+ [("c" "Show commit" magit-show-commit)
+ ("t" "Show stash" magit-stash-show)]])
+
+;;;###autoload (autoload 'magit-diff-refresh "magit-diff" nil t)
+(transient-define-prefix magit-diff-refresh ()
+ "Change the arguments used for the diff(s) in the current buffer."
+ :man-page "git-diff"
+ :class 'magit-diff-refresh-prefix
+ ["Limit arguments"
+ (magit:--)
+ (magit-diff:--ignore-submodules)
+ ("-b" "Ignore whitespace changes" ("-b" "--ignore-space-change"))
+ ("-w" "Ignore all whitespace" ("-w" "--ignore-all-space"))
+ (5 "-D" "Omit preimage for deletes" ("-D" "--irreversible-delete"))]
+ ["Context arguments"
+ (magit-diff:-U)
+ ("-W" "Show surrounding functions" ("-W" "--function-context"))]
+ ["Tune arguments"
+ (magit-diff:--diff-algorithm)
+ (magit-diff:-M)
+ (magit-diff:-C)
+ ("-x" "Disallow external diff drivers" "--no-ext-diff")
+ ("-s" "Show stats" "--stat"
+ :if-derived magit-diff-mode)
+ ("=g" "Show signature" "--show-signature"
+ :if-derived magit-diff-mode)
+ (5 magit-diff:--color-moved)
+ (5 magit-diff:--color-moved-ws)]
+ [["Refresh"
+ ("g" "buffer" magit-diff-refresh)
+ ("s" "buffer and set defaults" transient-set :transient nil)
+ ("w" "buffer and save defaults" transient-save :transient nil)]
+ ["Toggle"
+ ("t" "hunk refinement" magit-diff-toggle-refine-hunk)
+ ("F" "file filter" magit-diff-toggle-file-filter)
+ ("b" "buffer lock" magit-toggle-buffer-lock
+ :if-mode (magit-diff-mode magit-revision-mode magit-stash-mode))]
+ [:if-mode magit-diff-mode
+ :description "Do"
+ ("r" "switch range type" magit-diff-switch-range-type)
+ ("f" "flip revisions" magit-diff-flip-revs)]]
+ (interactive)
+ (if (not (eq transient-current-command 'magit-diff-refresh))
+ (transient-setup 'magit-diff-refresh)
+ (pcase-let ((`(,args ,files) (magit-diff-arguments)))
+ (setq magit-buffer-diff-args args)
+ (setq magit-buffer-diff-files files))
+ (magit-refresh)))
+
+;;;; Infix Commands
+
+(transient-define-argument magit:-- ()
+ :description "Limit to files"
+ :class 'transient-files
+ :key "--"
+ :argument "--"
+ :prompt "Limit to file(s): "
+ :reader 'magit-read-files
+ :multi-value t)
+
+(defun magit-read-files (prompt initial-input history)
+ (magit-completing-read-multiple* prompt
+ (magit-list-files)
+ nil nil
+ (or initial-input (magit-file-at-point))
+ history))
+
+(transient-define-argument magit-diff:-U ()
+ :description "Context lines"
+ :class 'transient-option
+ :argument "-U"
+ :reader 'transient-read-number-N0)
+
+(transient-define-argument magit-diff:-M ()
+ :description "Detect renames"
+ :class 'transient-option
+ :argument "-M"
+ :reader 'transient-read-number-N+)
+
+(transient-define-argument magit-diff:-C ()
+ :description "Detect copies"
+ :class 'transient-option
+ :argument "-C"
+ :reader 'transient-read-number-N+)
+
+(transient-define-argument magit-diff:--diff-algorithm ()
+ :description "Diff algorithm"
+ :class 'transient-option
+ :key "-A"
+ :argument "--diff-algorithm="
+ :reader 'magit-diff-select-algorithm)
+
+(defun magit-diff-select-algorithm (&rest _ignore)
+ (magit-read-char-case nil t
+ (?d "[d]efault" "default")
+ (?m "[m]inimal" "minimal")
+ (?p "[p]atience" "patience")
+ (?h "[h]istogram" "histogram")))
+
+(transient-define-argument magit-diff:--ignore-submodules ()
+ :description "Ignore submodules"
+ :class 'transient-option
+ :key "-i"
+ :argument "--ignore-submodules="
+ :reader 'magit-diff-select-ignore-submodules)
+
+(defun magit-diff-select-ignore-submodules (&rest _ignored)
+ (magit-read-char-case "Ignore submodules " t
+ (?u "[u]ntracked" "untracked")
+ (?d "[d]irty" "dirty")
+ (?a "[a]ll" "all")))
+
+(transient-define-argument magit-diff:--color-moved ()
+ :description "Color moved lines"
+ :class 'transient-option
+ :key "-m"
+ :argument "--color-moved="
+ :reader 'magit-diff-select-color-moved-mode)
+
+(defun magit-diff-select-color-moved-mode (&rest _ignore)
+ (magit-read-char-case "Color moved " t
+ (?d "[d]efault" "default")
+ (?p "[p]lain" "plain")
+ (?b "[b]locks" "blocks")
+ (?z "[z]ebra" "zebra")
+ (?Z "[Z] dimmed-zebra" "dimmed-zebra")))
+
+(transient-define-argument magit-diff:--color-moved-ws ()
+ :description "Whitespace treatment for --color-moved"
+ :class 'transient-option
+ :key "=w"
+ :argument "--color-moved-ws="
+ :reader 'magit-diff-select-color-moved-ws-mode)
+
+(defun magit-diff-select-color-moved-ws-mode (&rest _ignore)
+ (magit-read-char-case "Ignore whitespace " t
+ (?i "[i]ndentation" "allow-indentation-change")
+ (?e "[e]nd of line" "ignore-space-at-eol")
+ (?s "[s]pace change" "ignore-space-change")
+ (?a "[a]ll space" "ignore-all-space")
+ (?n "[n]o" "no")))
+
+;;;; Setup Commands
+
+;;;###autoload
+(defun magit-diff-dwim (&optional args files)
+ "Show changes for the thing at point."
+ (interactive (magit-diff-arguments))
+ (pcase (magit-diff--dwim)
+ (`unmerged (magit-diff-unmerged args files))
+ (`unstaged (magit-diff-unstaged args files))
+ (`staged
+ (let ((file (magit-file-at-point)))
+ (if (and file (equal (cddr (car (magit-file-status file))) '(?D ?U)))
+ ;; File was deleted by us and modified by them. Show the latter.
+ (magit-diff-unmerged args (list file))
+ (magit-diff-staged nil args files))))
+ (`(commit . ,value)
+ (magit-diff-range (format "%s^..%s" value value) args files))
+ (`(stash . ,value) (magit-stash-show value args))
+ ((and range (pred stringp))
+ (magit-diff-range range args files))
+ (_
+ (call-interactively #'magit-diff-range))))
+
+(defun magit-diff--dwim ()
+ "Return information for performing DWIM diff.
+
+The information can be in three forms:
+1. TYPE
+ A symbol describing a type of diff where no additional information
+ is needed to generate the diff. Currently, this includes `staged',
+ `unstaged' and `unmerged'.
+2. (TYPE . VALUE)
+ Like #1 but the diff requires additional information, which is
+ given by VALUE. Currently, this includes `commit' and `stash',
+ where VALUE is the given commit or stash, respectively.
+3. RANGE
+ A string indicating a diff range.
+
+If no DWIM context is found, nil is returned."
+ (cond
+ ((--when-let (magit-region-values '(commit branch) t)
+ (deactivate-mark)
+ (concat (car (last it)) ".." (car it))))
+ (magit-buffer-refname
+ (cons 'commit magit-buffer-refname))
+ ((derived-mode-p 'magit-stash-mode)
+ (cons 'commit
+ (magit-section-case
+ (commit (oref it value))
+ (file (thread-first it
+ (oref parent)
+ (oref value)))
+ (hunk (thread-first it
+ (oref parent)
+ (oref parent)
+ (oref value))))))
+ ((derived-mode-p 'magit-revision-mode)
+ (cons 'commit magit-buffer-revision))
+ ((derived-mode-p 'magit-diff-mode)
+ magit-buffer-range)
+ (t
+ (magit-section-case
+ ([* unstaged] 'unstaged)
+ ([* staged] 'staged)
+ (unmerged 'unmerged)
+ (unpushed (oref it value))
+ (unpulled (oref it value))
+ (branch (let ((current (magit-get-current-branch))
+ (atpoint (oref it value)))
+ (if (equal atpoint current)
+ (--if-let (magit-get-upstream-branch)
+ (format "%s...%s" it current)
+ (if (magit-anything-modified-p)
+ current
+ (cons 'commit current)))
+ (format "%s...%s"
+ (or current "HEAD")
+ atpoint))))
+ (commit (cons 'commit (oref it value)))
+ (stash (cons 'stash (oref it value)))
+ (pullreq (forge--pullreq-range (oref it value) t))))))
+
+(defun magit-diff-read-range-or-commit (prompt &optional secondary-default mbase)
+ "Read range or revision with special diff range treatment.
+If MBASE is non-nil, prompt for which rev to place at the end of
+a \"revA...revB\" range. Otherwise, always construct
+\"revA..revB\" range."
+ (--if-let (magit-region-values '(commit branch) t)
+ (let ((revA (car (last it)))
+ (revB (car it)))
+ (deactivate-mark)
+ (if mbase
+ (let ((base (magit-git-string "merge-base" revA revB)))
+ (cond
+ ((string= (magit-rev-parse revA) base)
+ (format "%s..%s" revA revB))
+ ((string= (magit-rev-parse revB) base)
+ (format "%s..%s" revB revA))
+ (t
+ (let ((main (magit-completing-read "View changes along"
+ (list revA revB)
+ nil t nil nil revB)))
+ (format "%s...%s"
+ (if (string= main revB) revA revB) main)))))
+ (format "%s..%s" revA revB)))
+ (magit-read-range prompt
+ (or (pcase (magit-diff--dwim)
+ (`(commit . ,value)
+ (format "%s^..%s" value value))
+ ((and range (pred stringp))
+ range))
+ secondary-default
+ (magit-get-current-branch)))))
+
+;;;###autoload
+(defun magit-diff-range (rev-or-range &optional args files)
+ "Show differences between two commits.
+
+REV-OR-RANGE should be a range or a single revision. If it is a
+revision, then show changes in the working tree relative to that
+revision. If it is a range, but one side is omitted, then show
+changes relative to `HEAD'.
+
+If the region is active, use the revisions on the first and last
+line of the region as the two sides of the range. With a prefix
+argument, instead of diffing the revisions, choose a revision to
+view changes along, starting at the common ancestor of both
+revisions (i.e., use a \"...\" range)."
+ (interactive (cons (magit-diff-read-range-or-commit "Diff for range"
+ nil current-prefix-arg)
+ (magit-diff-arguments)))
+ (magit-diff-setup-buffer rev-or-range nil args files))
+
+;;;###autoload
+(defun magit-diff-working-tree (&optional rev args files)
+ "Show changes between the current working tree and the `HEAD' commit.
+With a prefix argument show changes between the working tree and
+a commit read from the minibuffer."
+ (interactive
+ (cons (and current-prefix-arg
+ (magit-read-branch-or-commit "Diff working tree and commit"))
+ (magit-diff-arguments)))
+ (magit-diff-setup-buffer (or rev "HEAD") nil args files))
+
+;;;###autoload
+(defun magit-diff-staged (&optional rev args files)
+ "Show changes between the index and the `HEAD' commit.
+With a prefix argument show changes between the index and
+a commit read from the minibuffer."
+ (interactive
+ (cons (and current-prefix-arg
+ (magit-read-branch-or-commit "Diff index and commit"))
+ (magit-diff-arguments)))
+ (magit-diff-setup-buffer rev "--cached" args files))
+
+;;;###autoload
+(defun magit-diff-unstaged (&optional args files)
+ "Show changes between the working tree and the index."
+ (interactive (magit-diff-arguments))
+ (magit-diff-setup-buffer nil nil args files))
+
+;;;###autoload
+(defun magit-diff-unmerged (&optional args files)
+ "Show changes that are being merged."
+ (interactive (magit-diff-arguments))
+ (unless (magit-merge-in-progress-p)
+ (user-error "No merge is in progress"))
+ (magit-diff-setup-buffer (magit--merge-range) nil args files))
+
+;;;###autoload
+(defun magit-diff-while-committing (&optional args)
+ "While committing, show the changes that are about to be committed.
+While amending, invoking the command again toggles between
+showing just the new changes or all the changes that will
+be committed."
+ (interactive (list (car (magit-diff-arguments))))
+ (unless (magit-commit-message-buffer)
+ (user-error "No commit in progress"))
+ (let ((magit-display-buffer-noselect t))
+ (if-let ((diff-buf (magit-get-mode-buffer 'magit-diff-mode 'selected)))
+ (with-current-buffer diff-buf
+ (cond ((and (equal magit-buffer-range "HEAD^")
+ (equal magit-buffer-typearg "--cached"))
+ (magit-diff-staged nil args))
+ ((and (equal magit-buffer-range nil)
+ (equal magit-buffer-typearg "--cached"))
+ (magit-diff-while-amending args))
+ ((magit-anything-staged-p)
+ (magit-diff-staged nil args))
+ (t
+ (magit-diff-while-amending args))))
+ (if (magit-anything-staged-p)
+ (magit-diff-staged nil args)
+ (magit-diff-while-amending args)))))
+
+(define-key git-commit-mode-map
+ (kbd "C-c C-d") 'magit-diff-while-committing)
+
+(defun magit-diff-while-amending (&optional args)
+ (magit-diff-setup-buffer "HEAD^" "--cached" args nil))
+
+;;;###autoload
+(defun magit-diff-buffer-file ()
+ "Show diff for the blob or file visited in the current buffer.
+
+When the buffer visits a blob, then show the respective commit.
+When the buffer visits a file, then show the differenced between
+`HEAD' and the working tree. In both cases limit the diff to
+the file or blob."
+ (interactive)
+ (require 'magit)
+ (if-let ((file (magit-file-relative-name)))
+ (if magit-buffer-refname
+ (magit-show-commit magit-buffer-refname
+ (car (magit-show-commit--arguments))
+ (list file))
+ (save-buffer)
+ (let ((line (line-number-at-pos))
+ (col (current-column)))
+ (with-current-buffer
+ (magit-diff-setup-buffer (or (magit-get-current-branch) "HEAD")
+ nil
+ (car (magit-diff-arguments))
+ (list file)
+ magit-diff-buffer-file-locked)
+ (magit-diff--goto-position file line col))))
+ (user-error "Buffer isn't visiting a file")))
+
+;;;###autoload
+(defun magit-diff-paths (a b)
+ "Show changes between any two files on disk."
+ (interactive (list (read-file-name "First file: " nil nil t)
+ (read-file-name "Second file: " nil nil t)))
+ (magit-diff-setup-buffer nil "--no-index"
+ nil (list (magit-convert-filename-for-git
+ (expand-file-name a))
+ (magit-convert-filename-for-git
+ (expand-file-name b)))))
+
+(defun magit-show-commit--arguments ()
+ (pcase-let ((`(,args ,diff-files)
+ (magit-diff-arguments 'magit-revision-mode)))
+ (list args (if (derived-mode-p 'magit-log-mode)
+ (and (or magit-revision-filter-files-on-follow
+ (not (member "--follow" magit-buffer-log-args)))
+ magit-buffer-log-files)
+ diff-files))))
+
+;;;###autoload
+(defun magit-show-commit (rev &optional args files module)
+ "Visit the revision at point in another buffer.
+If there is no revision at point or with a prefix argument prompt
+for a revision."
+ (interactive
+ (pcase-let* ((mcommit (magit-section-value-if 'module-commit))
+ (atpoint (or (and (bound-and-true-p magit-blame-mode)
+ (oref (magit-current-blame-chunk) orig-rev))
+ mcommit
+ (thing-at-point 'git-revision t)
+ (magit-branch-or-commit-at-point)))
+ (`(,args ,files) (magit-show-commit--arguments)))
+ (list (or (and (not current-prefix-arg) atpoint)
+ (magit-read-branch-or-commit "Show commit" atpoint))
+ args
+ files
+ (and mcommit
+ (magit-section-parent-value (magit-current-section))))))
+ (require 'magit)
+ (let ((file (magit-file-relative-name)))
+ (magit-with-toplevel
+ (when module
+ (setq default-directory
+ (expand-file-name (file-name-as-directory module))))
+ (unless (magit-commit-p rev)
+ (user-error "%s is not a commit" rev))
+ (let ((buf (magit-revision-setup-buffer rev args files)))
+ (when file
+ (save-buffer)
+ (let ((line (magit-diff-visit--offset file (list "-R" rev)
+ (line-number-at-pos)))
+ (col (current-column)))
+ (with-current-buffer buf
+ (magit-diff--goto-position file line col))))))))
+
+(defun magit-diff--locate-hunk (file line &optional parent)
+ (when-let ((diff (cl-find-if (lambda (section)
+ (and (cl-typep section 'magit-file-section)
+ (equal (oref section value) file)))
+ (oref (or parent magit-root-section) children))))
+ (let (hunk (hunks (oref diff children)))
+ (cl-block nil
+ (while (setq hunk (pop hunks))
+ (pcase-let* ((`(,beg ,len) (oref hunk to-range))
+ (end (+ beg len)))
+ (cond ((> beg line) (cl-return (list diff nil)))
+ ((<= beg line end) (cl-return (list hunk t)))
+ ((null hunks) (cl-return (list hunk nil))))))))))
+
+(defun magit-diff--goto-position (file line column &optional parent)
+ (when-let ((pos (magit-diff--locate-hunk file line parent)))
+ (pcase-let ((`(,section ,exact) pos))
+ (cond ((cl-typep section 'magit-file-section)
+ (goto-char (oref section start)))
+ (exact
+ (goto-char (oref section content))
+ (let ((pos (car (oref section to-range))))
+ (while (or (< pos line)
+ (= (char-after) ?-))
+ (unless (= (char-after) ?-)
+ (cl-incf pos))
+ (forward-line)))
+ (forward-char (1+ column)))
+ (t
+ (goto-char (oref section start))
+ (setq section (oref section parent))))
+ (while section
+ (when (oref section hidden)
+ (magit-section-show section))
+ (setq section (oref section parent))))
+ (magit-section-update-highlight)
+ t))
+
+;;;; Setting Commands
+
+(defun magit-diff-switch-range-type ()
+ "Convert diff range type.
+Change \"revA..revB\" to \"revA...revB\", or vice versa."
+ (interactive)
+ (if (and magit-buffer-range
+ (derived-mode-p 'magit-diff-mode)
+ (string-match magit-range-re magit-buffer-range))
+ (setq magit-buffer-range
+ (replace-match (if (string= (match-string 2 magit-buffer-range) "..")
+ "..."
+ "..")
+ t t magit-buffer-range 2))
+ (user-error "No range to change"))
+ (magit-refresh))
+
+(defun magit-diff-flip-revs ()
+ "Swap revisions in diff range.
+Change \"revA..revB\" to \"revB..revA\"."
+ (interactive)
+ (if (and magit-buffer-range
+ (derived-mode-p 'magit-diff-mode)
+ (string-match magit-range-re magit-buffer-range))
+ (progn
+ (setq magit-buffer-range
+ (concat (match-string 3 magit-buffer-range)
+ (match-string 2 magit-buffer-range)
+ (match-string 1 magit-buffer-range)))
+ (magit-refresh))
+ (user-error "No range to swap")))
+
+(defun magit-diff-toggle-file-filter ()
+ "Toggle the file restriction of the current buffer's diffs.
+If the current buffer's mode is derived from `magit-log-mode',
+toggle the file restriction in the repository's revision buffer
+instead."
+ (interactive)
+ (cl-flet ((toggle ()
+ (if (or magit-buffer-diff-files
+ magit-buffer-diff-files-suspended)
+ (cl-rotatef magit-buffer-diff-files
+ magit-buffer-diff-files-suspended)
+ (setq magit-buffer-diff-files
+ (transient-infix-read 'magit:--)))
+ (magit-refresh)))
+ (cond
+ ((derived-mode-p 'magit-log-mode
+ 'magit-cherry-mode
+ 'magit-reflog-mode)
+ (if-let ((buffer (magit-get-mode-buffer 'magit-revision-mode)))
+ (with-current-buffer buffer (toggle))
+ (message "No revision buffer")))
+ ((local-variable-p 'magit-buffer-diff-files)
+ (toggle))
+ (t
+ (user-error "Cannot toggle file filter in this buffer")))))
+
+(defun magit-diff-less-context (&optional count)
+ "Decrease the context for diff hunks by COUNT lines."
+ (interactive "p")
+ (magit-diff-set-context (lambda (cur) (max 0 (- (or cur 0) count)))))
+
+(defun magit-diff-more-context (&optional count)
+ "Increase the context for diff hunks by COUNT lines."
+ (interactive "p")
+ (magit-diff-set-context (lambda (cur) (+ (or cur 0) count))))
+
+(defun magit-diff-default-context ()
+ "Reset context for diff hunks to the default height."
+ (interactive)
+ (magit-diff-set-context #'ignore))
+
+(defun magit-diff-set-context (fn)
+ (let* ((def (--if-let (magit-get "diff.context") (string-to-number it) 3))
+ (val magit-buffer-diff-args)
+ (arg (--first (string-match "^-U\\([0-9]+\\)?$" it) val))
+ (num (--if-let (and arg (match-string 1 arg)) (string-to-number it) def))
+ (val (delete arg val))
+ (num (funcall fn num))
+ (arg (and num (not (= num def)) (format "-U%i" num)))
+ (val (if arg (cons arg val) val)))
+ (setq magit-buffer-diff-args val))
+ (magit-refresh))
+
+(defun magit-diff-context-p ()
+ (if-let ((arg (--first (string-match "^-U\\([0-9]+\\)$" it)
+ magit-buffer-diff-args)))
+ (not (equal arg "-U0"))
+ t))
+
+(defun magit-diff-ignore-any-space-p ()
+ (--any-p (member it magit-buffer-diff-args)
+ '("--ignore-cr-at-eol"
+ "--ignore-space-at-eol"
+ "--ignore-space-change" "-b"
+ "--ignore-all-space" "-w"
+ "--ignore-blank-space")))
+
+(defun magit-diff-toggle-refine-hunk (&optional style)
+ "Turn diff-hunk refining on or off.
+
+If hunk refining is currently on, then hunk refining is turned off.
+If hunk refining is off, then hunk refining is turned on, in
+`selected' mode (only the currently selected hunk is refined).
+
+With a prefix argument, the \"third choice\" is used instead:
+If hunk refining is currently on, then refining is kept on, but
+the refining mode (`selected' or `all') is switched.
+If hunk refining is off, then hunk refining is turned on, in
+`all' mode (all hunks refined).
+
+Customize variable `magit-diff-refine-hunk' to change the default mode."
+ (interactive "P")
+ (setq-local magit-diff-refine-hunk
+ (if style
+ (if (eq magit-diff-refine-hunk 'all) t 'all)
+ (not magit-diff-refine-hunk)))
+ (magit-diff-update-hunk-refinement))
+
+;;;; Visit Commands
+;;;;; Dwim Variants
+
+(defun magit-diff-visit-file (file &optional other-window)
+ "From a diff visit the appropriate version of FILE.
+
+Display the buffer in the selected window. With a prefix
+argument OTHER-WINDOW display the buffer in another window
+instead.
+
+Visit the worktree version of the appropriate file. The location
+of point inside the diff determines which file is being visited.
+The visited version depends on what changes the diff is about.
+
+1. If the diff shows uncommitted changes (i.e. stage or unstaged
+ changes), then visit the file in the working tree (i.e. the
+ same \"real\" file that `find-file' would visit. In all other
+ cases visit a \"blob\" (i.e. the version of a file as stored
+ in some commit).
+
+2. If point is on a removed line, then visit the blob for the
+ first parent of the commit that removed that line, i.e. the
+ last commit where that line still exists.
+
+3. If point is on an added or context line, then visit the blob
+ that adds that line, or if the diff shows from more than a
+ single commit, then visit the blob from the last of these
+ commits.
+
+In the file-visiting buffer also go to the line that corresponds
+to the line that point is on in the diff.
+
+Note that this command only works if point is inside a diff. In
+other cases `magit-find-file' (which see) had to be used."
+ (interactive (list (magit-file-at-point t t) current-prefix-arg))
+ (magit-diff-visit-file--internal file nil
+ (if other-window
+ #'switch-to-buffer-other-window
+ #'pop-to-buffer-same-window)))
+
+(defun magit-diff-visit-file-other-window (file)
+ "From a diff visit the appropriate version of FILE in another window.
+Like `magit-diff-visit-file' but use
+`switch-to-buffer-other-window'."
+ (interactive (list (magit-file-at-point t t)))
+ (magit-diff-visit-file--internal file nil #'switch-to-buffer-other-window))
+
+(defun magit-diff-visit-file-other-frame (file)
+ "From a diff visit the appropriate version of FILE in another frame.
+Like `magit-diff-visit-file' but use
+`switch-to-buffer-other-frame'."
+ (interactive (list (magit-file-at-point t t)))
+ (magit-diff-visit-file--internal file nil #'switch-to-buffer-other-frame))
+
+;;;;; Worktree Variants
+
+(defun magit-diff-visit-worktree-file (file &optional other-window)
+ "From a diff visit the worktree version of FILE.
+
+Display the buffer in the selected window. With a prefix
+argument OTHER-WINDOW display the buffer in another window
+instead.
+
+Visit the worktree version of the appropriate file. The location
+of point inside the diff determines which file is being visited.
+
+Unlike `magit-diff-visit-file' always visits the \"real\" file in
+the working tree, i.e the \"current version\" of the file.
+
+In the file-visiting buffer also go to the line that corresponds
+to the line that point is on in the diff. Lines that were added
+or removed in the working tree, the index and other commits in
+between are automatically accounted for."
+ (interactive (list (magit-file-at-point t t) current-prefix-arg))
+ (magit-diff-visit-file--internal file t
+ (if other-window
+ #'switch-to-buffer-other-window
+ #'pop-to-buffer-same-window)))
+
+(defun magit-diff-visit-worktree-file-other-window (file)
+ "From a diff visit the worktree version of FILE in another window.
+Like `magit-diff-visit-worktree-file' but use
+`switch-to-buffer-other-window'."
+ (interactive (list (magit-file-at-point t t)))
+ (magit-diff-visit-file--internal file t #'switch-to-buffer-other-window))
+
+(defun magit-diff-visit-worktree-file-other-frame (file)
+ "From a diff visit the worktree version of FILE in another frame.
+Like `magit-diff-visit-worktree-file' but use
+`switch-to-buffer-other-frame'."
+ (interactive (list (magit-file-at-point t t)))
+ (magit-diff-visit-file--internal file t #'switch-to-buffer-other-frame))
+
+;;;;; Internal
+
+(defun magit-diff-visit-file--internal (file force-worktree fn)
+ "From a diff visit the appropriate version of FILE.
+If FORCE-WORKTREE is non-nil, then visit the worktree version of
+the file, even if the diff is about a committed change. Use FN
+to display the buffer in some window."
+ (if (magit-file-accessible-directory-p file)
+ (magit-diff-visit-directory file force-worktree)
+ (pcase-let ((`(,buf ,pos)
+ (magit-diff-visit-file--noselect file force-worktree)))
+ (funcall fn buf)
+ (magit-diff-visit-file--setup buf pos)
+ buf)))
+
+(defun magit-diff-visit-directory (directory &optional other-window)
+ "Visit DIRECTORY in some window.
+Display the buffer in the selected window unless OTHER-WINDOW is
+non-nil. If DIRECTORY is the top-level directory of the current
+repository, then visit the containing directory using Dired and
+in the Dired buffer put point on DIRECTORY. Otherwise display
+the Magit-Status buffer for DIRECTORY."
+ (if (equal (magit-toplevel directory)
+ (magit-toplevel))
+ (dired-jump other-window (concat directory "/."))
+ (let ((display-buffer-overriding-action
+ (if other-window
+ '(nil (inhibit-same-window t))
+ '(display-buffer-same-window))))
+ (magit-status-setup-buffer directory))))
+
+(defun magit-diff-visit-file--setup (buf pos)
+ (if-let ((win (get-buffer-window buf 'visible)))
+ (with-selected-window win
+ (when pos
+ (unless (<= (point-min) pos (point-max))
+ (widen))
+ (goto-char pos))
+ (when (and buffer-file-name
+ (magit-anything-unmerged-p buffer-file-name))
+ (smerge-start-session))
+ (run-hooks 'magit-diff-visit-file-hook))
+ (error "File buffer is not visible")))
+
+(defun magit-diff-visit-file--noselect (&optional file goto-worktree)
+ (unless file
+ (setq file (magit-file-at-point t t)))
+ (let* ((hunk (magit-diff-visit--hunk))
+ (goto-from (and hunk
+ (magit-diff-visit--goto-from-p hunk goto-worktree)))
+ (line (and hunk (magit-diff-hunk-line hunk goto-from)))
+ (col (and hunk (magit-diff-hunk-column hunk goto-from)))
+ (spec (magit-diff--dwim))
+ (rev (if goto-from
+ (magit-diff-visit--range-from spec)
+ (magit-diff-visit--range-to spec)))
+ (buf (if (or goto-worktree
+ (and (not (stringp rev))
+ (or magit-diff-visit-avoid-head-blob
+ (not goto-from))))
+ (or (get-file-buffer file)
+ (find-file-noselect file))
+ (magit-find-file-noselect (if (stringp rev) rev "HEAD")
+ file))))
+ (if line
+ (with-current-buffer buf
+ (cond ((eq rev 'staged)
+ (setq line (magit-diff-visit--offset file nil line)))
+ ((and goto-worktree
+ (stringp rev))
+ (setq line (magit-diff-visit--offset file rev line))))
+ (list buf (save-restriction
+ (widen)
+ (goto-char (point-min))
+ (forward-line (1- line))
+ (move-to-column col)
+ (point))))
+ (list buf nil))))
+
+(defun magit-diff-visit--hunk ()
+ (when-let ((scope (magit-diff-scope)))
+ (let ((section (magit-current-section)))
+ (cl-case scope
+ ((file files)
+ (setq section (car (oref section children))))
+ (list
+ (setq section (car (oref section children)))
+ (when section
+ (setq section (car (oref section children))))))
+ (and
+ ;; Unmerged files appear in the list of staged changes
+ ;; but unlike in the list of unstaged changes no diffs
+ ;; are shown here. In that case `section' is nil.
+ section
+ ;; Currently the `hunk' type is also abused for file
+ ;; mode changes, which we are not interested in here.
+ ;; Such sections have no value.
+ (oref section value)
+ section))))
+
+(defun magit-diff-visit--goto-from-p (section in-worktree)
+ (and magit-diff-visit-previous-blob
+ (not in-worktree)
+ (not (oref section combined))
+ (not (< (point) (oref section content)))
+ (= (char-after (line-beginning-position)) ?-)))
+
+(defun magit-diff-hunk-line (section goto-from)
+ (save-excursion
+ (goto-char (line-beginning-position))
+ (with-slots (content combined from-ranges from-range to-range) section
+ (when (< (point) content)
+ (goto-char content)
+ (re-search-forward "^[-+]"))
+ (+ (car (if goto-from from-range to-range))
+ (let ((prefix (if combined (length from-ranges) 1))
+ (target (point))
+ (offset 0))
+ (goto-char content)
+ (while (< (point) target)
+ (unless (string-match-p
+ (if goto-from "\\+" "-")
+ (buffer-substring (point) (+ (point) prefix)))
+ (cl-incf offset))
+ (forward-line))
+ offset)))))
+
+(defun magit-diff-hunk-column (section goto-from)
+ (if (or (< (point)
+ (oref section content))
+ (and (not goto-from)
+ (= (char-after (line-beginning-position)) ?-)))
+ 0
+ (max 0 (- (+ (current-column) 2)
+ (length (oref section value))))))
+
+(defun magit-diff-visit--range-from (spec)
+ (cond ((consp spec)
+ (concat (cdr spec) "^"))
+ ((stringp spec)
+ (car (magit-split-range spec)))
+ (t
+ spec)))
+
+(defun magit-diff-visit--range-to (spec)
+ (if (symbolp spec)
+ spec
+ (let ((rev (if (consp spec)
+ (cdr spec)
+ (cdr (magit-split-range spec)))))
+ (if (and magit-diff-visit-avoid-head-blob
+ (magit-rev-head-p rev))
+ 'unstaged
+ rev))))
+
+(defun magit-diff-visit--offset (file rev line)
+ (let ((offset 0))
+ (with-temp-buffer
+ (save-excursion
+ (magit-with-toplevel
+ (magit-git-insert "diff" rev "--" file)))
+ (catch 'found
+ (while (re-search-forward
+ "^@@ -\\([0-9]+\\),\\([0-9]+\\) \\+\\([0-9]+\\),\\([0-9]+\\) @@.*\n"
+ nil t)
+ (let ((from-beg (string-to-number (match-string 1)))
+ (from-len (string-to-number (match-string 2)))
+ ( to-len (string-to-number (match-string 4))))
+ (if (<= from-beg line)
+ (if (< (+ from-beg from-len) line)
+ (cl-incf offset (- to-len from-len))
+ (let ((rest (- line from-beg)))
+ (while (> rest 0)
+ (pcase (char-after)
+ (?\s (cl-decf rest))
+ (?- (cl-decf offset) (cl-decf rest))
+ (?+ (cl-incf offset)))
+ (forward-line))))
+ (throw 'found nil))))))
+ (+ line offset)))
+
+;;;; Scroll Commands
+
+(defun magit-diff-show-or-scroll-up ()
+ "Update the commit or diff buffer for the thing at point.
+
+Either show the commit or stash at point in the appropriate
+buffer, or if that buffer is already being displayed in the
+current frame and contains information about that commit or
+stash, then instead scroll the buffer up. If there is no
+commit or stash at point, then prompt for a commit."
+ (interactive)
+ (magit-diff-show-or-scroll 'scroll-up))
+
+(defun magit-diff-show-or-scroll-down ()
+ "Update the commit or diff buffer for the thing at point.
+
+Either show the commit or stash at point in the appropriate
+buffer, or if that buffer is already being displayed in the
+current frame and contains information about that commit or
+stash, then instead scroll the buffer down. If there is no
+commit or stash at point, then prompt for a commit."
+ (interactive)
+ (magit-diff-show-or-scroll 'scroll-down))
+
+(defun magit-diff-show-or-scroll (fn)
+ (let (rev cmd buf win)
+ (cond
+ (magit-blame-mode
+ (setq rev (oref (magit-current-blame-chunk) orig-rev))
+ (setq cmd 'magit-show-commit)
+ (setq buf (magit-get-mode-buffer 'magit-revision-mode)))
+ ((derived-mode-p 'git-rebase-mode)
+ (with-slots (action-type target)
+ (git-rebase-current-line)
+ (if (not (eq action-type 'commit))
+ (user-error "No commit on this line")
+ (setq rev target)
+ (setq cmd 'magit-show-commit)
+ (setq buf (magit-get-mode-buffer 'magit-revision-mode)))))
+ (t
+ (magit-section-case
+ (branch
+ (setq rev (magit-ref-maybe-qualify (oref it value)))
+ (setq cmd 'magit-show-commit)
+ (setq buf (magit-get-mode-buffer 'magit-revision-mode)))
+ (commit
+ (setq rev (oref it value))
+ (setq cmd 'magit-show-commit)
+ (setq buf (magit-get-mode-buffer 'magit-revision-mode)))
+ (stash
+ (setq rev (oref it value))
+ (setq cmd 'magit-stash-show)
+ (setq buf (magit-get-mode-buffer 'magit-stash-mode))))))
+ (if rev
+ (if (and buf
+ (setq win (get-buffer-window buf))
+ (with-current-buffer buf
+ (and (equal rev magit-buffer-revision)
+ (equal (magit-rev-parse rev)
+ magit-buffer-revision-hash))))
+ (with-selected-window win
+ (condition-case nil
+ (funcall fn)
+ (error
+ (goto-char (pcase fn
+ (`scroll-up (point-min))
+ (`scroll-down (point-max)))))))
+ (let ((magit-display-buffer-noselect t))
+ (if (eq cmd 'magit-show-commit)
+ (apply #'magit-show-commit rev (magit-show-commit--arguments))
+ (funcall cmd rev))))
+ (call-interactively #'magit-show-commit))))
+
+;;;; Section Commands
+
+(defun magit-section-cycle-diffs ()
+ "Cycle visibility of diff-related sections in the current buffer."
+ (interactive)
+ (when-let ((sections
+ (cond ((derived-mode-p 'magit-status-mode)
+ (--mapcat
+ (when it
+ (when (oref it hidden)
+ (magit-section-show it))
+ (oref it children))
+ (list (magit-get-section '((staged) (status)))
+ (magit-get-section '((unstaged) (status))))))
+ ((derived-mode-p 'magit-diff-mode)
+ (-filter #'magit-file-section-p
+ (oref magit-root-section children))))))
+ (if (--any-p (oref it hidden) sections)
+ (dolist (s sections)
+ (magit-section-show s)
+ (magit-section-hide-children s))
+ (let ((children (--mapcat (oref it children) sections)))
+ (cond ((and (--any-p (oref it hidden) children)
+ (--any-p (oref it children) children))
+ (mapc 'magit-section-show-headings sections))
+ ((seq-some 'magit-section-hidden-body children)
+ (mapc 'magit-section-show-children sections))
+ (t
+ (mapc 'magit-section-hide sections)))))))
+
+;;; Diff Mode
+
+(defvar magit-diff-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-mode-map)
+ (define-key map (kbd "C-c C-d") 'magit-diff-while-committing)
+ (define-key map (kbd "C-c C-b") 'magit-go-backward)
+ (define-key map (kbd "C-c C-f") 'magit-go-forward)
+ (define-key map (kbd "SPC") 'scroll-up)
+ (define-key map (kbd "DEL") 'scroll-down)
+ (define-key map (kbd "j") 'magit-jump-to-diffstat-or-diff)
+ (define-key map [remap write-file] 'magit-patch-save)
+ map)
+ "Keymap for `magit-diff-mode'.")
+
+(define-derived-mode magit-diff-mode magit-mode "Magit Diff"
+ "Mode for looking at a Git diff.
+
+This mode is documented in info node `(magit)Diff Buffer'.
+
+\\<magit-mode-map>\
+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'.
+
+\\<magit-hunk-section-map>Type \
+\\[magit-apply] to apply the change at point, \
+\\[magit-stage] to stage,
+\\[magit-unstage] to unstage, \
+\\[magit-discard] to discard, or \
+\\[magit-reverse] to reverse it.
+
+\\{magit-diff-mode-map}"
+ :group 'magit-diff
+ (hack-dir-local-variables-non-file-buffer)
+ (setq imenu-prev-index-position-function
+ 'magit-imenu--diff-prev-index-position-function)
+ (setq imenu-extract-index-name-function
+ 'magit-imenu--diff-extract-index-name-function))
+
+(put 'magit-diff-mode 'magit-diff-default-arguments
+ '("--stat" "--no-ext-diff"))
+
+(defun magit-diff-setup-buffer (range typearg args files &optional locked)
+ (require 'magit)
+ (magit-setup-buffer #'magit-diff-mode locked
+ (magit-buffer-range range)
+ (magit-buffer-typearg typearg)
+ (magit-buffer-diff-args args)
+ (magit-buffer-diff-files files)
+ (magit-buffer-diff-files-suspended nil)))
+
+(defun magit-diff-refresh-buffer ()
+ "Refresh the current `magit-diff-mode' buffer."
+ (magit-set-header-line-format
+ (if (equal magit-buffer-typearg "--no-index")
+ (apply #'format "Differences between %s and %s" magit-buffer-diff-files)
+ (concat (if magit-buffer-range
+ (if (string-match-p "\\(\\.\\.\\|\\^-\\)"
+ magit-buffer-range)
+ (format "Changes in %s" magit-buffer-range)
+ (format "Changes from %s to working tree" magit-buffer-range))
+ (if (equal magit-buffer-typearg "--cached")
+ "Staged changes"
+ "Unstaged changes"))
+ (pcase (length magit-buffer-diff-files)
+ (0)
+ (1 (concat " in file " (car magit-buffer-diff-files)))
+ (_ (concat " in files "
+ (mapconcat #'identity magit-buffer-diff-files ", ")))))))
+ (setq magit-buffer-range-hashed
+ (and magit-buffer-range (magit-hash-range magit-buffer-range)))
+ (magit-insert-section (diffbuf)
+ (magit-run-section-hook 'magit-diff-sections-hook)))
+
+(cl-defmethod magit-buffer-value (&context (major-mode magit-diff-mode))
+ (nconc (cond (magit-buffer-range
+ (delq nil (list magit-buffer-range magit-buffer-typearg)))
+ ((equal magit-buffer-typearg "--cached")
+ (list 'staged))
+ (t
+ (list 'unstaged magit-buffer-typearg)))
+ (and magit-buffer-diff-files (cons "--" magit-buffer-diff-files))))
+
+(defvar magit-diff-section-base-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "C-j") 'magit-diff-visit-worktree-file)
+ (define-key map (kbd "C-<return>") 'magit-diff-visit-worktree-file)
+ (define-key map (kbd "C-x 4 <return>") 'magit-diff-visit-file-other-window)
+ (define-key map (kbd "C-x 5 <return>") 'magit-diff-visit-file-other-frame)
+ (define-key map [remap magit-visit-thing] 'magit-diff-visit-file)
+ (define-key map [remap magit-delete-thing] 'magit-discard)
+ (define-key map [remap magit-revert-no-commit] 'magit-reverse)
+ (define-key map "a" 'magit-apply)
+ (define-key map "s" 'magit-stage)
+ (define-key map "u" 'magit-unstage)
+ (define-key map "&" 'magit-do-async-shell-command)
+ (define-key map "C" 'magit-commit-add-log)
+ (define-key map (kbd "C-x a") 'magit-add-change-log-entry)
+ (define-key map (kbd "C-x 4 a") 'magit-add-change-log-entry-other-window)
+ (define-key map (kbd "C-c C-t") 'magit-diff-trace-definition)
+ (define-key map (kbd "C-c C-e") 'magit-diff-edit-hunk-commit)
+ map)
+ "Parent of `magit-{hunk,file}-section-map'.")
+
+(defvar magit-file-section-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-diff-section-base-map)
+ map)
+ "Keymap for `file' sections.")
+
+(defvar magit-hunk-section-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-diff-section-base-map)
+ map)
+ "Keymap for `hunk' sections.")
+
+(defconst magit-diff-conflict-headline-re
+ (concat "^" (regexp-opt
+ ;; Defined in merge-tree.c in this order.
+ '("merged"
+ "added in remote"
+ "added in both"
+ "added in local"
+ "removed in both"
+ "changed in both"
+ "removed in local"
+ "removed in remote"))))
+
+(defconst magit-diff-headline-re
+ (concat "^\\(@@@?\\|diff\\|Submodule\\|"
+ "\\* Unmerged path\\|"
+ (substring magit-diff-conflict-headline-re 1)
+ "\\)"))
+
+(defconst magit-diff-statline-re
+ (concat "^ ?"
+ "\\(.*\\)" ; file
+ "\\( +| +\\)" ; separator
+ "\\([0-9]+\\|Bin\\(?: +[0-9]+ -> [0-9]+ bytes\\)?$\\) ?"
+ "\\(\\+*\\)" ; add
+ "\\(-*\\)$")) ; del
+
+(defvar magit-diff--reset-non-color-moved
+ (list
+ "-c" "color.diff.context=normal"
+ "-c" "color.diff.plain=normal" ; historical synonym for context
+ "-c" "color.diff.meta=normal"
+ "-c" "color.diff.frag=normal"
+ "-c" "color.diff.func=normal"
+ "-c" "color.diff.old=normal"
+ "-c" "color.diff.new=normal"
+ "-c" "color.diff.commit=normal"
+ "-c" "color.diff.whitespace=normal"
+ ;; "git-range-diff" does not support "--color-moved", so we don't
+ ;; need to reset contextDimmed, oldDimmed, newDimmed, contextBold,
+ ;; oldBold, and newBold.
+ ))
+
+(defun magit-insert-diff ()
+ "Insert the diff into this `magit-diff-mode' buffer."
+ (magit--insert-diff
+ "diff" magit-buffer-range "-p" "--no-prefix"
+ (and (member "--stat" magit-buffer-diff-args) "--numstat")
+ magit-buffer-typearg
+ magit-buffer-diff-args "--"
+ magit-buffer-diff-files))
+
+(defun magit--insert-diff (&rest args)
+ (declare (indent 0))
+ (pcase-let ((`(,cmd . ,args)
+ (-flatten args))
+ (magit-git-global-arguments
+ (remove "--literal-pathspecs" magit-git-global-arguments)))
+ ;; As of Git 2.19.0, we need to generate diffs with
+ ;; --ita-visible-in-index so that `magit-stage' can work with
+ ;; intent-to-add files (see #4026). Cache the result for each
+ ;; repo to avoid a `git version' call for every diff insertion.
+ (when (and (not (equal cmd "merge-tree"))
+ (pcase (magit-repository-local-get 'diff-ita-kludge-p 'unset)
+ (`unset
+ (let ((val (version<= "2.19.0" (magit-git-version))))
+ (magit-repository-local-set 'diff-ita-kludge-p val)
+ val))
+ (val val)))
+ (push "--ita-visible-in-index" args))
+ (setq args (magit-diff--maybe-add-stat-arguments args))
+ (when (cl-member-if (lambda (arg) (string-prefix-p "--color-moved" arg)) args)
+ (push "--color=always" args)
+ (setq magit-git-global-arguments
+ (append magit-diff--reset-non-color-moved
+ magit-git-global-arguments)))
+ (magit-git-wash #'magit-diff-wash-diffs cmd args)))
+
+(defun magit-diff--maybe-add-stat-arguments (args)
+ (if (member "--stat" args)
+ (append (if (functionp magit-diff-extra-stat-arguments)
+ (funcall magit-diff-extra-stat-arguments)
+ magit-diff-extra-stat-arguments)
+ args)
+ args))
+
+(defun magit-diff-use-window-width-as-stat-width ()
+ "Use the `window-width' as the value of `--stat-width'."
+ (when-let ((window (get-buffer-window (current-buffer) 'visible)))
+ (list (format "--stat-width=%d" (window-width window)))))
+
+(defun magit-diff-wash-diffs (args &optional limit)
+ (run-hooks 'magit-diff-wash-diffs-hook)
+ (when (member "--show-signature" args)
+ (magit-diff-wash-signature))
+ (when (member "--stat" args)
+ (magit-diff-wash-diffstat))
+ (when (re-search-forward magit-diff-headline-re limit t)
+ (goto-char (line-beginning-position))
+ (magit-wash-sequence (apply-partially 'magit-diff-wash-diff args))
+ (insert ?\n)))
+
+(defun magit-jump-to-diffstat-or-diff ()
+ "Jump to the diffstat or diff.
+When point is on a file inside the diffstat section, then jump
+to the respective diff section, otherwise jump to the diffstat
+section or a child thereof."
+ (interactive)
+ (--if-let (magit-get-section
+ (append (magit-section-case
+ ([file diffstat] `((file . ,(oref it value))))
+ (file `((file . ,(oref it value)) (diffstat)))
+ (t '((diffstat))))
+ (magit-section-ident magit-root-section)))
+ (magit-section-goto it)
+ (user-error "No diffstat in this buffer")))
+
+(defun magit-diff-wash-signature ()
+ (when (looking-at "^gpg: ")
+ (magit-insert-section (signature)
+ (while (looking-at "^gpg: ")
+ (forward-line))
+ (insert "\n"))))
+
+(defun magit-diff-wash-diffstat ()
+ (let (heading (beg (point)))
+ (when (re-search-forward "^ ?\\([0-9]+ +files? change[^\n]*\n\\)" nil t)
+ (setq heading (match-string 1))
+ (magit-delete-match)
+ (goto-char beg)
+ (magit-insert-section (diffstat)
+ (insert (propertize heading 'font-lock-face 'magit-diff-file-heading))
+ (magit-insert-heading)
+ (let (files)
+ (while (looking-at "^[-0-9]+\t[-0-9]+\t\\(.+\\)$")
+ (push (magit-decode-git-path
+ (let ((f (match-string 1)))
+ (cond
+ ((string-match "\\`\\([^{]+\\){\\(.+\\) => \\(.+\\)}\\'" f)
+ (concat (match-string 1 f)
+ (match-string 3 f)))
+ ((string-match " => " f)
+ (substring f (match-end 0)))
+ (t f))))
+ files)
+ (magit-delete-line))
+ (setq files (nreverse files))
+ (while (looking-at magit-diff-statline-re)
+ (magit-bind-match-strings (file sep cnt add del) nil
+ (magit-delete-line)
+ (when (string-match " +$" file)
+ (setq sep (concat (match-string 0 file) sep))
+ (setq file (substring file 0 (match-beginning 0))))
+ (let ((le (length file)) ld)
+ (setq file (magit-decode-git-path file))
+ (setq ld (length file))
+ (when (> le ld)
+ (setq sep (concat (make-string (- le ld) ?\s) sep))))
+ (magit-insert-section (file (pop files))
+ (insert (propertize file 'font-lock-face 'magit-filename)
+ sep cnt " ")
+ (when add
+ (insert (propertize add 'font-lock-face
+ 'magit-diffstat-added)))
+ (when del
+ (insert (propertize del 'font-lock-face
+ 'magit-diffstat-removed)))
+ (insert "\n")))))
+ (if (looking-at "^$") (forward-line) (insert "\n"))))))
+
+(defun magit-diff-wash-diff (args)
+ (when (cl-member-if (lambda (arg) (string-prefix-p "--color-moved" arg)) args)
+ (require 'ansi-color)
+ (ansi-color-apply-on-region (point-min) (point-max)))
+ (cond
+ ((looking-at "^Submodule")
+ (magit-diff-wash-submodule))
+ ((looking-at "^\\* Unmerged path \\(.*\\)")
+ (let ((file (magit-decode-git-path (match-string 1))))
+ (magit-delete-line)
+ (unless (and (derived-mode-p 'magit-status-mode)
+ (not (member "--cached" args)))
+ (magit-insert-section (file file)
+ (insert (propertize
+ (format "unmerged %s%s" file
+ (pcase (cddr (car (magit-file-status file)))
+ (`(?D ?D) " (both deleted)")
+ (`(?D ?U) " (deleted by us)")
+ (`(?U ?D) " (deleted by them)")
+ (`(?A ?A) " (both added)")
+ (`(?A ?U) " (added by us)")
+ (`(?U ?A) " (added by them)")
+ (`(?U ?U) "")))
+ 'font-lock-face 'magit-diff-file-heading))
+ (insert ?\n))))
+ t)
+ ((looking-at magit-diff-conflict-headline-re)
+ (let ((long-status (match-string 0))
+ (status "BUG")
+ file orig base modes)
+ (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 modes nil long-status)))
+ ((looking-at
+ "^diff --\\(?:\\(git\\) \\(?:\\(.+?\\) \\2\\)?\\|\\(cc\\|combined\\) \\(.+\\)\\)")
+ (let ((status (cond ((equal (match-string 1) "git") "modified")
+ ((derived-mode-p 'magit-revision-mode) "resolved")
+ (t "unmerged")))
+ (file (or (match-string 2) (match-string 4)))
+ (beg (point))
+ orig header modes)
+ (save-excursion
+ (forward-line 1)
+ (setq header (buffer-substring
+ beg (if (re-search-forward magit-diff-headline-re nil t)
+ (match-beginning 0)
+ (point-max)))))
+ (magit-delete-line)
+ (while (not (or (eobp) (looking-at magit-diff-headline-re)))
+ (if (looking-at "^old mode \\([^\n]+\\)\nnew mode \\([^\n]+\\)\n")
+ (progn (setq modes (match-string 0))
+ (magit-delete-match))
+ (cond
+ ((looking-at "^--- \\([^/].*?\\)\t?$") ; i.e. not /dev/null
+ (setq orig (match-string 1)))
+ ((looking-at "^\\+\\+\\+ \\([^/].*?\\)\t?$")
+ (setq file (match-string 1)))
+ ((looking-at "^\\(copy\\|rename\\) from \\(.+\\)$")
+ (setq orig (match-string 2)))
+ ((looking-at "^\\(copy\\|rename\\) to \\(.+\\)$")
+ (setq file (match-string 2))
+ (setq status (if (equal (match-string 1) "copy") "new file" "renamed")))
+ ((looking-at "^\\(new file\\|deleted\\)")
+ (setq status (match-string 1))))
+ (magit-delete-line)))
+ (when orig
+ (setq orig (magit-decode-git-path orig)))
+ (setq file (magit-decode-git-path file))
+ ;; KLUDGE `git-log' ignores `--no-prefix' when `-L' is used.
+ (when (and (derived-mode-p 'magit-log-mode)
+ (--first (string-match-p "\\`-L" it) magit-buffer-log-args))
+ (setq file (substring file 2))
+ (when orig
+ (setq orig (substring orig 2))))
+ (magit-diff-insert-file-section file orig status modes header)))))
+
+(defun magit-diff-insert-file-section
+ (file orig status modes header &optional long-status)
+ (magit-insert-section section
+ (file file (or (equal status "deleted")
+ (derived-mode-p 'magit-status-mode)))
+ (insert (propertize (format "%-10s %s" status
+ (if (or (not orig) (equal orig file))
+ file
+ (format "%s -> %s" orig file)))
+ 'font-lock-face 'magit-diff-file-heading))
+ (when long-status
+ (insert (format " (%s)" long-status)))
+ (magit-insert-heading)
+ (unless (equal orig file)
+ (oset section source orig))
+ (oset section header header)
+ (when modes
+ (magit-insert-section (hunk)
+ (insert modes)
+ (magit-insert-heading)))
+ (magit-wash-sequence #'magit-diff-wash-hunk)))
+
+(defun magit-diff-wash-submodule ()
+ ;; See `show_submodule_summary' in submodule.c and "this" commit.
+ (when (looking-at "^Submodule \\([^ ]+\\)")
+ (let ((module (match-string 1))
+ untracked modified)
+ (when (looking-at "^Submodule [^ ]+ contains untracked content$")
+ (magit-delete-line)
+ (setq untracked t))
+ (when (looking-at "^Submodule [^ ]+ contains modified content$")
+ (magit-delete-line)
+ (setq modified t))
+ (cond
+ ((and (looking-at "^Submodule \\([^ ]+\\) \\([^ :]+\\)\\( (rewind)\\)?:$")
+ (equal (match-string 1) module))
+ (magit-bind-match-strings (_module range rewind) nil
+ (magit-delete-line)
+ (while (looking-at "^ \\([<>]\\) \\(.+\\)$")
+ (magit-delete-line))
+ (when rewind
+ (setq range (replace-regexp-in-string "[^.]\\(\\.\\.\\)[^.]"
+ "..." range t t 1)))
+ (magit-insert-section (magit-module-section module t)
+ (magit-insert-heading
+ (propertize (concat "modified " module)
+ 'font-lock-face 'magit-diff-file-heading)
+ " ("
+ (cond (rewind "rewind")
+ ((string-match-p "\\.\\.\\." range) "non-ff")
+ (t "new commits"))
+ (and (or modified untracked)
+ (concat ", "
+ (and modified "modified")
+ (and modified untracked " and ")
+ (and untracked "untracked")
+ " content"))
+ ")")
+ (let ((default-directory
+ (file-name-as-directory
+ (expand-file-name module (magit-toplevel)))))
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'module)
+ "log" "--oneline" "--left-right" range)
+ (delete-char -1)))))
+ ((and (looking-at "^Submodule \\([^ ]+\\) \\([^ ]+\\) (\\([^)]+\\))$")
+ (equal (match-string 1) module))
+ (magit-bind-match-strings (_module _range msg) nil
+ (magit-delete-line)
+ (magit-insert-section (magit-module-section module)
+ (magit-insert-heading
+ (propertize (concat "submodule " module)
+ 'font-lock-face 'magit-diff-file-heading)
+ " (" msg ")"))))
+ (t
+ (magit-insert-section (magit-module-section module)
+ (magit-insert-heading
+ (propertize (concat "modified " module)
+ 'font-lock-face 'magit-diff-file-heading)
+ " ("
+ (and modified "modified")
+ (and modified untracked " and ")
+ (and untracked "untracked")
+ " content)")))))))
+
+(defun magit-diff-wash-hunk ()
+ (when (looking-at "^@\\{2,\\} \\(.+?\\) @\\{2,\\}\\(?: \\(.*\\)\\)?")
+ (let* ((heading (match-string 0))
+ (ranges (mapcar (lambda (str)
+ (mapcar #'string-to-number
+ (split-string (substring str 1) ",")))
+ (split-string (match-string 1))))
+ (about (match-string 2))
+ (combined (= (length ranges) 3))
+ (value (cons about ranges)))
+ (magit-delete-line)
+ (magit-insert-section section (hunk value)
+ (insert (propertize (concat heading "\n")
+ 'font-lock-face 'magit-diff-hunk-heading))
+ (magit-insert-heading)
+ (while (not (or (eobp) (looking-at "^[^-+\s\\]")))
+ (forward-line))
+ (oset section end (point))
+ (oset section washer 'magit-diff-paint-hunk)
+ (oset section combined combined)
+ (if combined
+ (oset section from-ranges (butlast ranges))
+ (oset section from-range (car ranges)))
+ (oset section to-range (car (last ranges)))
+ (oset section about about)))
+ t))
+
+(defun magit-diff-expansion-threshold (section)
+ "Keep new diff sections collapsed if washing takes too long."
+ (and (magit-file-section-p section)
+ (> (float-time (time-subtract (current-time) magit-refresh-start-time))
+ magit-diff-expansion-threshold)
+ 'hide))
+
+(add-hook 'magit-section-set-visibility-hook #'magit-diff-expansion-threshold)
+
+;;; Revision Mode
+
+(define-derived-mode magit-revision-mode magit-diff-mode "Magit Rev"
+ "Mode for looking at a Git commit.
+
+This mode is documented in info node `(magit)Revision Buffer'.
+
+\\<magit-mode-map>\
+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'.
+
+\\<magit-hunk-section-map>Type \
+\\[magit-apply] to apply the change at point, \
+\\[magit-stage] to stage,
+\\[magit-unstage] to unstage, \
+\\[magit-discard] to discard, or \
+\\[magit-reverse] to reverse it.
+
+\\{magit-revision-mode-map}"
+ :group 'magit-revision
+ (hack-dir-local-variables-non-file-buffer))
+
+(put 'magit-revision-mode 'magit-diff-default-arguments
+ '("--stat" "--no-ext-diff"))
+
+(defun magit-revision-setup-buffer (rev args files)
+ (magit-setup-buffer #'magit-revision-mode nil
+ (magit-buffer-revision rev)
+ (magit-buffer-range (format "%s^..%s" rev rev))
+ (magit-buffer-diff-args args)
+ (magit-buffer-diff-files files)
+ (magit-buffer-diff-files-suspended nil)))
+
+(defun magit-revision-refresh-buffer ()
+ (magit-set-header-line-format
+ (concat (capitalize (magit-object-type magit-buffer-revision))
+ " " magit-buffer-revision
+ (pcase (length magit-buffer-diff-files)
+ (0)
+ (1 (concat " limited to file " (car magit-buffer-diff-files)))
+ (_ (concat " limited to files "
+ (mapconcat #'identity magit-buffer-diff-files ", "))))))
+ (setq magit-buffer-revision-hash (magit-rev-parse magit-buffer-revision))
+ (magit-insert-section (commitbuf)
+ (magit-run-section-hook 'magit-revision-sections-hook)))
+
+(cl-defmethod magit-buffer-value (&context (major-mode magit-revision-mode))
+ (cons magit-buffer-revision magit-buffer-diff-files))
+
+(defun magit-insert-revision-diff ()
+ "Insert the diff into this `magit-revision-mode' buffer."
+ (magit--insert-diff
+ "show" "-p" "--cc" "--format=" "--no-prefix"
+ (and (member "--stat" magit-buffer-diff-args) "--numstat")
+ magit-buffer-diff-args
+ (concat magit-buffer-revision "^{commit}")
+ "--" magit-buffer-diff-files))
+
+(defun magit-insert-revision-tag ()
+ "Insert tag message and headers into a revision buffer.
+This function only inserts anything when `magit-show-commit' is
+called with a tag as argument, when that is called with a commit
+or a ref which is not a branch, then it inserts nothing."
+ (when (equal (magit-object-type magit-buffer-revision) "tag")
+ (magit-insert-section (taginfo)
+ (let ((beg (point)))
+ ;; "git verify-tag -v" would output what we need, but the gpg
+ ;; output is send to stderr and we have no control over the
+ ;; order in which stdout and stderr are inserted, which would
+ ;; make parsing hard. We are forced to use "git cat-file tag"
+ ;; instead, which inserts the signature instead of verifying
+ ;; it. We remove that later and then insert the verification
+ ;; output using "git verify-tag" (without the "-v").
+ (magit-git-insert "cat-file" "tag" magit-buffer-revision)
+ (goto-char beg)
+ (forward-line 3)
+ (delete-region beg (point)))
+ (looking-at "^tagger \\([^<]+\\) <\\([^>]+\\)")
+ (let ((heading (format "Tagger: %s <%s>"
+ (match-string 1)
+ (match-string 2))))
+ (magit-delete-line)
+ (insert (propertize heading 'font-lock-face
+ 'magit-section-secondary-heading)))
+ (magit-insert-heading)
+ (if (re-search-forward "-----BEGIN PGP SIGNATURE-----" nil t)
+ (progn
+ (let ((beg (match-beginning 0)))
+ (re-search-forward "-----END PGP SIGNATURE-----")
+ (delete-region beg (point)))
+ (insert ?\n)
+ (process-file magit-git-executable nil t nil
+ "verify-tag" magit-buffer-revision))
+ (goto-char (point-max)))
+ (insert ?\n))))
+
+(defvar magit-commit-message-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-show-commit)
+ map)
+ "Keymap for `commit-message' sections.")
+
+(defun magit-insert-revision-message ()
+ "Insert the commit message into a revision buffer."
+ (magit-insert-section section (commit-message)
+ (oset section heading-highlight-face 'magit-diff-revision-summary-highlight)
+ (let ((beg (point))
+ (rev magit-buffer-revision))
+ (insert (with-temp-buffer
+ (magit-rev-insert-format "%B" rev)
+ (magit-revision--wash-message)))
+ (if (= (point) (+ beg 2))
+ (progn (backward-delete-char 2)
+ (insert "(no message)\n"))
+ (goto-char beg)
+ (save-excursion
+ (while (search-forward "\r\n" nil t) ; Remove trailing CRs.
+ (delete-region (match-beginning 0) (1+ (match-beginning 0)))))
+ (when magit-revision-fill-summary-line
+ (let ((fill-column (min magit-revision-fill-summary-line
+ (window-width))))
+ (fill-region (point) (line-end-position))))
+ (when magit-revision-use-hash-sections
+ (save-excursion
+ (while (not (eobp))
+ (re-search-forward "\\_<" nil 'move)
+ (let ((beg (point)))
+ (re-search-forward "\\_>" nil t)
+ (when (> (point) beg)
+ (let ((text (buffer-substring-no-properties beg (point))))
+ (when (pcase magit-revision-use-hash-sections
+ (`quickest ; false negatives and positives
+ (and (>= (length text) 7)
+ (string-match-p "[0-9]" text)
+ (string-match-p "[a-z]" text)))
+ (`quicker ; false negatives (number-less hashes)
+ (and (>= (length text) 7)
+ (string-match-p "[0-9]" text)
+ (magit-commit-p text)))
+ (`quick ; false negatives (short hashes)
+ (and (>= (length text) 7)
+ (magit-commit-p text)))
+ (`slow
+ (magit-commit-p text)))
+ (put-text-property beg (point)
+ 'font-lock-face 'magit-hash)
+ (let ((end (point)))
+ (goto-char beg)
+ (magit-insert-section (commit text)
+ (goto-char end))))))))))
+ (save-excursion
+ (forward-line)
+ (magit--add-face-text-property
+ beg (point) 'magit-diff-revision-summary)
+ (magit-insert-heading))
+ (when magit-diff-highlight-keywords
+ (save-excursion
+ (while (re-search-forward "\\[[^[]*\\]" nil t)
+ (let ((beg (match-beginning 0))
+ (end (match-end 0)))
+ (put-text-property
+ beg end 'font-lock-face
+ (if-let ((face (get-text-property beg 'font-lock-face)))
+ (list face 'magit-keyword)
+ 'magit-keyword))))))
+ (goto-char (point-max))))))
+
+(defun magit-insert-revision-notes ()
+ "Insert commit notes into a revision buffer."
+ (let* ((var "core.notesRef")
+ (def (or (magit-get var) "refs/notes/commits")))
+ (dolist (ref (or (magit-list-active-notes-refs)))
+ (magit-insert-section section (notes ref (not (equal ref def)))
+ (oset section heading-highlight-face 'magit-diff-hunk-heading-highlight)
+ (let ((beg (point))
+ (rev magit-buffer-revision))
+ (insert (with-temp-buffer
+ (magit-git-insert "-c" (concat "core.notesRef=" ref)
+ "notes" "show" rev)
+ (magit-revision--wash-message)))
+ (if (= (point) beg)
+ (magit-cancel-section)
+ (goto-char beg)
+ (end-of-line)
+ (insert (format " (%s)"
+ (propertize (if (string-prefix-p "refs/notes/" ref)
+ (substring ref 11)
+ ref)
+ 'font-lock-face 'magit-refname)))
+ (forward-char)
+ (magit--add-face-text-property beg (point) 'magit-diff-hunk-heading)
+ (magit-insert-heading)
+ (goto-char (point-max))
+ (insert ?\n)))))))
+
+(defun magit-revision--wash-message ()
+ (let ((major-mode 'git-commit-mode))
+ (hack-dir-local-variables)
+ (hack-local-variables-apply))
+ (unless (memq git-commit-major-mode '(nil text-mode))
+ (funcall git-commit-major-mode)
+ (font-lock-ensure))
+ (buffer-string))
+
+(defun magit-insert-revision-headers ()
+ "Insert headers about the commit into a revision buffer."
+ (magit-insert-section (headers)
+ (--when-let (magit-rev-format "%D" magit-buffer-revision "--decorate=full")
+ (insert (magit-format-ref-labels it) ?\s))
+ (insert (propertize
+ (magit-rev-parse (concat magit-buffer-revision "^{commit}"))
+ 'font-lock-face 'magit-hash))
+ (magit-insert-heading)
+ (let ((beg (point)))
+ (magit-rev-insert-format magit-revision-headers-format
+ magit-buffer-revision)
+ (magit-insert-revision-gravatars magit-buffer-revision beg))
+ (when magit-revision-insert-related-refs
+ (dolist (parent (magit-commit-parents magit-buffer-revision))
+ (magit-insert-section (commit parent)
+ (let ((line (magit-rev-format "%h %s" parent)))
+ (string-match "^\\([^ ]+\\) \\(.*\\)" line)
+ (magit-bind-match-strings (hash msg) line
+ (insert "Parent: ")
+ (insert (propertize hash 'font-lock-face 'magit-hash))
+ (insert " " msg "\n")))))
+ (magit--insert-related-refs
+ magit-buffer-revision "--merged" "Merged"
+ (eq magit-revision-insert-related-refs 'all))
+ (magit--insert-related-refs
+ magit-buffer-revision "--contains" "Contained"
+ (memq magit-revision-insert-related-refs '(all mixed)))
+ (when-let ((follows (magit-get-current-tag magit-buffer-revision t)))
+ (let ((tag (car follows))
+ (cnt (cadr follows)))
+ (magit-insert-section (tag tag)
+ (insert
+ (format "Follows: %s (%s)\n"
+ (propertize tag 'font-lock-face 'magit-tag)
+ (propertize (number-to-string cnt)
+ 'font-lock-face 'magit-branch-local))))))
+ (when-let ((precedes (magit-get-next-tag magit-buffer-revision t)))
+ (let ((tag (car precedes))
+ (cnt (cadr precedes)))
+ (magit-insert-section (tag tag)
+ (insert (format "Precedes: %s (%s)\n"
+ (propertize tag 'font-lock-face 'magit-tag)
+ (propertize (number-to-string cnt)
+ 'font-lock-face 'magit-tag))))))
+ (insert ?\n))))
+
+(defun magit--insert-related-refs (rev arg title remote)
+ (when-let ((refs (magit-list-related-branches arg rev (and remote "-a"))))
+ (insert title ":" (make-string (- 10 (length title)) ?\s))
+ (dolist (branch refs)
+ (if (<= (+ (current-column) 1 (length branch))
+ (window-width))
+ (insert ?\s)
+ (insert ?\n (make-string 12 ?\s)))
+ (magit-insert-section (branch branch)
+ (insert (propertize branch 'font-lock-face
+ (if (string-prefix-p "remotes/" branch)
+ 'magit-branch-remote
+ 'magit-branch-local)))))
+ (insert ?\n)))
+
+(defun magit-insert-revision-gravatars (rev beg)
+ (when (and magit-revision-show-gravatars
+ (window-system))
+ (require 'gravatar)
+ (pcase-let ((`(,author . ,committer)
+ (pcase magit-revision-show-gravatars
+ (`t '("^Author: " . "^Commit: "))
+ (`author '("^Author: " . nil))
+ (`committer '(nil . "^Commit: "))
+ (_ magit-revision-show-gravatars))))
+ (--when-let (and author (magit-rev-format "%aE" rev))
+ (magit-insert-revision-gravatar beg rev it author))
+ (--when-let (and committer (magit-rev-format "%cE" rev))
+ (magit-insert-revision-gravatar beg rev it committer)))))
+
+(defun magit-insert-revision-gravatar (beg rev email regexp)
+ (save-excursion
+ (goto-char beg)
+ (when (re-search-forward regexp nil t)
+ (when-let ((window (get-buffer-window)))
+ (let* ((column (length (match-string 0)))
+ (font-obj (query-font (font-at (point) window)))
+ (size (* 2 (+ (aref font-obj 4)
+ (aref font-obj 5))))
+ (align-to (+ column
+ (ceiling (/ size (aref font-obj 7) 1.0))
+ 1))
+ (gravatar-size (- size 2)))
+ (ignore-errors ; service may be unreachable
+ (gravatar-retrieve email 'magit-insert-revision-gravatar-cb
+ (list rev (point-marker) align-to column))))))))
+
+(defun magit-insert-revision-gravatar-cb (image rev marker align-to column)
+ (unless (eq image 'error)
+ (when-let ((buffer (marker-buffer marker)))
+ (with-current-buffer buffer
+ (save-excursion
+ (goto-char marker)
+ ;; The buffer might display another revision by now or
+ ;; it might have been refreshed, in which case another
+ ;; process might already have inserted the image.
+ (when (and (equal rev magit-buffer-revision)
+ (not (eq (car-safe
+ (car-safe
+ (get-text-property (point) 'display)))
+ 'image)))
+ (let ((top `((,@image :ascent center :relief 1)
+ (slice 0.0 0.0 1.0 0.5)))
+ (bot `((,@image :ascent center :relief 1)
+ (slice 0.0 0.5 1.0 1.0)))
+ (align `((space :align-to ,align-to))))
+ (when magit-revision-use-gravatar-kludge
+ (cl-rotatef top bot))
+ (let ((inhibit-read-only t))
+ (insert (propertize " " 'display top))
+ (insert (propertize " " 'display align))
+ (forward-line)
+ (forward-char column)
+ (insert (propertize " " 'display bot))
+ (insert (propertize " " 'display align))))))))))
+
+;;; Merge-Preview Mode
+
+(define-derived-mode magit-merge-preview-mode magit-diff-mode "Magit Merge"
+ "Mode for previewing a merge."
+ :group 'magit-diff
+ (hack-dir-local-variables-non-file-buffer))
+
+(put 'magit-merge-preview-mode 'magit-diff-default-arguments
+ '("--no-ext-diff"))
+
+(defun magit-merge-preview-setup-buffer (rev)
+ (magit-setup-buffer #'magit-merge-preview-mode nil
+ (magit-buffer-revision rev)
+ (magit-buffer-range (format "%s^..%s" rev rev))))
+
+(defun magit-merge-preview-refresh-buffer ()
+ (let* ((branch (magit-get-current-branch))
+ (head (or branch (magit-rev-verify "HEAD"))))
+ (magit-set-header-line-format (format "Preview merge of %s into %s"
+ magit-buffer-revision
+ (or branch "HEAD")))
+ (magit-insert-section (diffbuf)
+ (magit--insert-diff
+ "merge-tree" (magit-git-string "merge-base" head magit-buffer-revision)
+ head magit-buffer-revision))))
+
+(cl-defmethod magit-buffer-value (&context (major-mode magit-merge-preview-mode))
+ magit-buffer-revision)
+
+;;; Diff Sections
+
+(defun magit-hunk-set-window-start (section)
+ "When SECTION is a `hunk', ensure that its beginning is visible.
+It the SECTION has a different type, then do nothing."
+ (when (magit-hunk-section-p section)
+ (magit-section-set-window-start section)))
+
+(add-hook 'magit-section-movement-hook #'magit-hunk-set-window-start)
+
+(defun magit-hunk-goto-successor (section arg)
+ (and (magit-hunk-section-p section)
+ (when-let ((parent (magit-get-section
+ (magit-section-ident
+ (oref section parent)))))
+ (let* ((children (oref parent children))
+ (siblings (magit-section-siblings section 'prev))
+ (previous (nth (length siblings) children)))
+ (if (not arg)
+ (--when-let (or previous (car (last children)))
+ (magit-section-goto it)
+ t)
+ (when previous
+ (magit-section-goto previous))
+ (if (and (stringp arg)
+ (re-search-forward arg (oref parent end) t))
+ (goto-char (match-beginning 0))
+ (goto-char (oref (car (last children)) end))
+ (forward-line -1)
+ (while (looking-at "^ ") (forward-line -1))
+ (while (looking-at "^[-+]") (forward-line -1))
+ (forward-line)))))))
+
+(add-hook 'magit-section-goto-successor-hook #'magit-hunk-goto-successor)
+
+(defvar magit-unstaged-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-diff-unstaged)
+ (define-key map [remap magit-delete-thing] 'magit-discard)
+ (define-key map "s" 'magit-stage)
+ (define-key map "u" 'magit-unstage)
+ map)
+ "Keymap for the `unstaged' section.")
+
+(magit-define-section-jumper magit-jump-to-unstaged "Unstaged changes" unstaged)
+
+(defun magit-insert-unstaged-changes ()
+ "Insert section showing unstaged changes."
+ (magit-insert-section (unstaged)
+ (magit-insert-heading "Unstaged changes:")
+ (magit--insert-diff
+ "diff" magit-buffer-diff-args "--no-prefix"
+ "--" magit-buffer-diff-files)))
+
+(defvar magit-staged-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-diff-staged)
+ (define-key map [remap magit-delete-thing] 'magit-discard)
+ (define-key map [remap magit-revert-no-commit] 'magit-reverse)
+ (define-key map "s" 'magit-stage)
+ (define-key map "u" 'magit-unstage)
+ map)
+ "Keymap for the `staged' section.")
+
+(magit-define-section-jumper magit-jump-to-staged "Staged changes" staged)
+
+(defun magit-insert-staged-changes ()
+ "Insert section showing staged changes."
+ ;; Avoid listing all files as deleted when visiting a bare repo.
+ (unless (magit-bare-repo-p)
+ (magit-insert-section (staged)
+ (magit-insert-heading "Staged changes:")
+ (magit--insert-diff
+ "diff" "--cached" magit-buffer-diff-args "--no-prefix"
+ "--" magit-buffer-diff-files))))
+
+;;; Diff Type
+
+(defun magit-diff-type (&optional section)
+ "Return the diff type of SECTION.
+
+The returned type is one of the symbols `staged', `unstaged',
+`committed', or `undefined'. This type serves a similar purpose
+as the general type common to all sections (which is stored in
+the `type' slot of the corresponding `magit-section' struct) but
+takes additional information into account. When the SECTION
+isn't related to diffs and the buffer containing it also isn't
+a diff-only buffer, then return nil.
+
+Currently the type can also be one of `tracked' and `untracked'
+but these values are not handled explicitly everywhere they
+should be and a possible fix could be to just return nil here.
+
+The section has to be a `diff' or `hunk' section, or a section
+whose children are of type `diff'. If optional SECTION is nil,
+return the diff type for the current section. In buffers whose
+major mode is `magit-diff-mode' SECTION is ignored and the type
+is determined using other means. In `magit-revision-mode'
+buffers the type is always `committed'.
+
+Do not confuse this with `magit-diff-scope' (which see)."
+ (--when-let (or section (magit-current-section))
+ (cond ((derived-mode-p 'magit-revision-mode 'magit-stash-mode) 'committed)
+ ((derived-mode-p 'magit-diff-mode)
+ (let ((range magit-buffer-range)
+ (const magit-buffer-typearg))
+ (cond ((equal const "--no-index") 'undefined)
+ ((or (not range)
+ (magit-rev-eq range "HEAD"))
+ (if (equal const "--cached")
+ 'staged
+ 'unstaged))
+ ((equal const "--cached")
+ (if (magit-rev-head-p range)
+ 'staged
+ 'undefined)) ; i.e. committed and staged
+ (t 'committed))))
+ ((derived-mode-p 'magit-status-mode)
+ (let ((stype (oref it type)))
+ (if (memq stype '(staged unstaged tracked untracked))
+ stype
+ (pcase stype
+ ((or `file `module)
+ (let* ((parent (oref it parent))
+ (type (oref parent type)))
+ (if (memq type '(file module))
+ (magit-diff-type parent)
+ type)))
+ (`hunk (thread-first it
+ (oref parent)
+ (oref parent)
+ (oref type)))))))
+ ((derived-mode-p 'magit-log-mode)
+ (if (or (and (magit-section-match 'commit section)
+ (oref section children))
+ (magit-section-match [* file commit] section))
+ 'committed
+ 'undefined))
+ (t 'undefined))))
+
+(cl-defun magit-diff-scope (&optional (section nil ssection) strict)
+ "Return the diff scope of SECTION or the selected section(s).
+
+A diff's \"scope\" describes what part of a diff is selected, it is
+a symbol, one of `region', `hunk', `hunks', `file', `files', or
+`list'. Do not confuse this with the diff \"type\", as returned by
+`magit-diff-type'.
+
+If optional SECTION is non-nil, then return the scope of that,
+ignoring the sections selected by the region. Otherwise return
+the scope of the current section, or if the region is active and
+selects a valid group of diff related sections, the type of these
+sections, i.e. `hunks' or `files'. If SECTION, or if that is nil
+the current section, is a `hunk' section; and the region region
+starts and ends inside the body of a that section, then the type
+is `region'. If the region is empty after a mouse click, then
+`hunk' is returned instead of `region'.
+
+If optional STRICT is non-nil, then return nil if the diff type of
+the section at point is `untracked' or the section at point is not
+actually a `diff' but a `diffstat' section."
+ (let ((siblings (and (not ssection) (magit-region-sections nil t))))
+ (setq section (or section (car siblings) (magit-current-section)))
+ (when (and section
+ (or (not strict)
+ (and (not (eq (magit-diff-type section) 'untracked))
+ (not (eq (--when-let (oref section parent)
+ (oref it type))
+ 'diffstat)))))
+ (pcase (list (oref section type)
+ (and siblings t)
+ (magit-diff-use-hunk-region-p)
+ ssection)
+ (`(hunk nil t ,_)
+ (if (magit-section-internal-region-p section) 'region 'hunk))
+ (`(hunk t t nil) 'hunks)
+ (`(hunk ,_ ,_ ,_) 'hunk)
+ (`(file t t nil) 'files)
+ (`(file ,_ ,_ ,_) 'file)
+ (`(module t t nil) 'files)
+ (`(module ,_ ,_ ,_) 'file)
+ (`(,(or `staged `unstaged `untracked)
+ nil ,_ ,_) 'list)))))
+
+(defun magit-diff-use-hunk-region-p ()
+ (and (region-active-p)
+ ;; TODO implement this from first principals
+ ;; currently it's trial-and-error
+ (not (and (or (eq this-command 'mouse-drag-region)
+ (eq last-command 'mouse-drag-region)
+ ;; When another window was previously
+ ;; selected then the last-command is
+ ;; some byte-code function.
+ (byte-code-function-p last-command))
+ (eq (region-end) (region-beginning))))))
+
+;;; Diff Highlight
+
+(add-hook 'magit-section-unhighlight-hook #'magit-diff-unhighlight)
+(add-hook 'magit-section-highlight-hook #'magit-diff-highlight)
+
+(defun magit-diff-unhighlight (section selection)
+ "Remove the highlighting of the diff-related SECTION."
+ (when (magit-hunk-section-p section)
+ (magit-diff-paint-hunk section selection nil)
+ t))
+
+(defun magit-diff-highlight (section selection)
+ "Highlight the diff-related SECTION.
+If SECTION is not a diff-related section, then do nothing and
+return nil. If SELECTION is non-nil, then it is a list of sections
+selected by the region, including SECTION. All of these sections
+are highlighted."
+ (if (and (magit-section-match 'commit section)
+ (oref section children))
+ (progn (if selection
+ (dolist (section selection)
+ (magit-diff-highlight-list section selection))
+ (magit-diff-highlight-list section))
+ t)
+ (when-let ((scope (magit-diff-scope section t)))
+ (cond ((eq scope 'region)
+ (magit-diff-paint-hunk section selection t))
+ (selection
+ (dolist (section selection)
+ (magit-diff-highlight-recursive section selection)))
+ (t
+ (magit-diff-highlight-recursive section)))
+ t)))
+
+(defun magit-diff-highlight-recursive (section &optional selection)
+ (pcase (magit-diff-scope section)
+ (`list (magit-diff-highlight-list section selection))
+ (`file (magit-diff-highlight-file section selection))
+ (`hunk (magit-diff-highlight-heading section selection)
+ (magit-diff-paint-hunk section selection t))
+ (_ (magit-section-highlight section nil))))
+
+(defun magit-diff-highlight-list (section &optional selection)
+ (let ((beg (oref section start))
+ (cnt (oref section content))
+ (end (oref section end)))
+ (when (or (eq this-command 'mouse-drag-region)
+ (not selection))
+ (unless (and (region-active-p)
+ (<= (region-beginning) beg))
+ (magit-section-make-overlay beg cnt 'magit-section-highlight))
+ (unless (oref section hidden)
+ (dolist (child (oref section children))
+ (when (or (eq this-command 'mouse-drag-region)
+ (not (and (region-active-p)
+ (<= (region-beginning)
+ (oref child start)))))
+ (magit-diff-highlight-recursive child selection)))))
+ (when magit-diff-highlight-hunk-body
+ (magit-section-make-overlay (1- end) end 'magit-section-highlight))))
+
+(defun magit-diff-highlight-file (section &optional selection)
+ (magit-diff-highlight-heading section selection)
+ (unless (oref section hidden)
+ (dolist (child (oref section children))
+ (magit-diff-highlight-recursive child selection))))
+
+(defun magit-diff-highlight-heading (section &optional selection)
+ (magit-section-make-overlay
+ (oref section start)
+ (or (oref section content)
+ (oref section end))
+ (pcase (list (oref section type)
+ (and (member section selection)
+ (not (eq this-command 'mouse-drag-region))))
+ (`(file t) 'magit-diff-file-heading-selection)
+ (`(file nil) 'magit-diff-file-heading-highlight)
+ (`(module t) 'magit-diff-file-heading-selection)
+ (`(module nil) 'magit-diff-file-heading-highlight)
+ (`(hunk t) 'magit-diff-hunk-heading-selection)
+ (`(hunk nil) 'magit-diff-hunk-heading-highlight))))
+
+;;; Hunk Paint
+
+(cl-defun magit-diff-paint-hunk
+ (section &optional selection
+ (highlight (magit-section-selected-p section selection)))
+ (let (paint)
+ (unless magit-diff-highlight-hunk-body
+ (setq highlight nil))
+ (cond (highlight
+ (unless (oref section hidden)
+ (add-to-list 'magit-section-highlighted-sections section)
+ (cond ((memq section magit-section-unhighlight-sections)
+ (setq magit-section-unhighlight-sections
+ (delq section magit-section-unhighlight-sections)))
+ (magit-diff-highlight-hunk-body
+ (setq paint t)))))
+ (t
+ (cond ((and (oref section hidden)
+ (memq section magit-section-unhighlight-sections))
+ (add-to-list 'magit-section-highlighted-sections section)
+ (setq magit-section-unhighlight-sections
+ (delq section magit-section-unhighlight-sections)))
+ (t
+ (setq paint t)))))
+ (when paint
+ (save-excursion
+ (goto-char (oref section start))
+ (let ((end (oref section end))
+ (merging (looking-at "@@@"))
+ (diff-type (magit-diff-type))
+ (stage nil)
+ (tab-width (magit-diff-tab-width
+ (magit-section-parent-value section))))
+ (forward-line)
+ (while (< (point) end)
+ (when (and magit-diff-hide-trailing-cr-characters
+ (char-equal ?\r (char-before (line-end-position))))
+ (put-text-property (1- (line-end-position)) (line-end-position)
+ 'invisible t))
+ (put-text-property
+ (point) (1+ (line-end-position)) 'font-lock-face
+ (cond
+ ((looking-at "^\\+\\+?\\([<=|>]\\)\\{7\\}")
+ (setq stage (pcase (list (match-string 1) highlight)
+ (`("<" nil) 'magit-diff-our)
+ (`("<" t) 'magit-diff-our-highlight)
+ (`("|" nil) 'magit-diff-base)
+ (`("|" t) 'magit-diff-base-highlight)
+ (`("=" nil) 'magit-diff-their)
+ (`("=" t) 'magit-diff-their-highlight)
+ (`(">" nil) nil)))
+ 'magit-diff-conflict-heading)
+ ((looking-at (if merging "^\\(\\+\\| \\+\\)" "^\\+"))
+ (magit-diff-paint-tab merging tab-width)
+ (magit-diff-paint-whitespace merging 'added diff-type)
+ (or stage
+ (if highlight 'magit-diff-added-highlight 'magit-diff-added)))
+ ((looking-at (if merging "^\\(-\\| -\\)" "^-"))
+ (magit-diff-paint-tab merging tab-width)
+ (magit-diff-paint-whitespace merging 'removed diff-type)
+ (if highlight 'magit-diff-removed-highlight 'magit-diff-removed))
+ (t
+ (magit-diff-paint-tab merging tab-width)
+ (magit-diff-paint-whitespace merging 'context diff-type)
+ (if highlight 'magit-diff-context-highlight 'magit-diff-context))))
+ (forward-line))))))
+ (magit-diff-update-hunk-refinement section))
+
+(defvar magit-diff--tab-width-cache nil)
+
+(defun magit-diff-tab-width (file)
+ (setq file (expand-file-name file))
+ (cl-flet ((cache (value)
+ (let ((elt (assoc file magit-diff--tab-width-cache)))
+ (if elt
+ (setcdr elt value)
+ (setq magit-diff--tab-width-cache
+ (cons (cons file value)
+ magit-diff--tab-width-cache))))
+ value))
+ (cond
+ ((not magit-diff-adjust-tab-width)
+ tab-width)
+ ((--when-let (find-buffer-visiting file)
+ (cache (buffer-local-value 'tab-width it))))
+ ((--when-let (assoc file magit-diff--tab-width-cache)
+ (or (cdr it)
+ tab-width)))
+ ((or (eq magit-diff-adjust-tab-width 'always)
+ (and (numberp magit-diff-adjust-tab-width)
+ (>= magit-diff-adjust-tab-width
+ (nth 7 (file-attributes file)))))
+ (cache (buffer-local-value 'tab-width (find-file-noselect file))))
+ (t
+ (cache nil)
+ tab-width))))
+
+(defun magit-diff-paint-tab (merging width)
+ (save-excursion
+ (forward-char (if merging 2 1))
+ (while (= (char-after) ?\t)
+ (put-text-property (point) (1+ (point))
+ 'display (list (list 'space :width width)))
+ (forward-char))))
+
+(defun magit-diff-paint-whitespace (merging line-type diff-type)
+ (when (and magit-diff-paint-whitespace
+ (or (not (memq magit-diff-paint-whitespace '(uncommitted status)))
+ (memq diff-type '(staged unstaged)))
+ (cl-case line-type
+ (added t)
+ (removed (memq magit-diff-paint-whitespace-lines '(all both)))
+ (context (memq magit-diff-paint-whitespace-lines '(all)))))
+ (let ((prefix (if merging "^[-\\+\s]\\{2\\}" "^[-\\+\s]"))
+ (indent
+ (if (local-variable-p 'magit-diff-highlight-indentation)
+ magit-diff-highlight-indentation
+ (setq-local
+ magit-diff-highlight-indentation
+ (cdr (--first (string-match-p (car it) default-directory)
+ (nreverse
+ (default-value
+ 'magit-diff-highlight-indentation))))))))
+ (when (and magit-diff-highlight-trailing
+ (looking-at (concat prefix ".*?\\([ \t]+\\)$")))
+ (let ((ov (make-overlay (match-beginning 1) (match-end 1) nil t)))
+ (overlay-put ov 'font-lock-face 'magit-diff-whitespace-warning)
+ (overlay-put ov 'priority 2)
+ (overlay-put ov 'evaporate t)))
+ (when (or (and (eq indent 'tabs)
+ (looking-at (concat prefix "\\( *\t[ \t]*\\)")))
+ (and (integerp indent)
+ (looking-at (format "%s\\([ \t]* \\{%s,\\}[ \t]*\\)"
+ prefix indent))))
+ (let ((ov (make-overlay (match-beginning 1) (match-end 1) nil t)))
+ (overlay-put ov 'font-lock-face 'magit-diff-whitespace-warning)
+ (overlay-put ov 'priority 2)
+ (overlay-put ov 'evaporate t))))))
+
+(defun magit-diff-update-hunk-refinement (&optional section)
+ (if section
+ (unless (oref section hidden)
+ (pcase (list magit-diff-refine-hunk
+ (oref section refined)
+ (eq section (magit-current-section)))
+ ((or `(all nil ,_) `(t nil t))
+ (oset section refined t)
+ (save-excursion
+ (goto-char (oref section start))
+ ;; `diff-refine-hunk' does not handle combined diffs.
+ (unless (looking-at "@@@")
+ (let ((smerge-refine-ignore-whitespace
+ magit-diff-refine-ignore-whitespace)
+ ;; Avoid fsyncing many small temp files
+ (write-region-inhibit-fsync t))
+ (diff-refine-hunk)))))
+ ((or `(nil t ,_) `(t t nil))
+ (oset section refined nil)
+ (remove-overlays (oref section start)
+ (oref section end)
+ 'diff-mode 'fine))))
+ (cl-labels ((recurse (section)
+ (if (magit-section-match 'hunk section)
+ (magit-diff-update-hunk-refinement section)
+ (dolist (child (oref section children))
+ (recurse child)))))
+ (recurse magit-root-section))))
+
+
+;;; Hunk Region
+
+(defun magit-diff-hunk-region-beginning ()
+ (save-excursion (goto-char (region-beginning))
+ (line-beginning-position)))
+
+(defun magit-diff-hunk-region-end ()
+ (save-excursion (goto-char (region-end))
+ (line-end-position)))
+
+(defun magit-diff-update-hunk-region (section)
+ "Highlight the hunk-internal region if any."
+ (when (eq (magit-diff-scope section t) 'region)
+ (magit-diff--make-hunk-overlay
+ (oref section start)
+ (1- (oref section content))
+ 'font-lock-face 'magit-diff-lines-heading
+ 'display (magit-diff-hunk-region-header section)
+ 'after-string (magit-diff--hunk-after-string 'magit-diff-lines-heading))
+ (run-hook-with-args 'magit-diff-highlight-hunk-region-functions section)
+ t))
+
+(defun magit-diff-highlight-hunk-region-dim-outside (section)
+ "Dim the parts of the hunk that are outside the hunk-internal region.
+This is done by using the same foreground and background color
+for added and removed lines as for context lines."
+ (let ((face (if magit-diff-highlight-hunk-body
+ 'magit-diff-context-highlight
+ 'magit-diff-context)))
+ (when magit-diff-unmarked-lines-keep-foreground
+ (setq face `(,@(and (>= emacs-major-version 27) '(:extend t))
+ :background ,(face-attribute face :background))))
+ (magit-diff--make-hunk-overlay (oref section content)
+ (magit-diff-hunk-region-beginning)
+ 'font-lock-face face
+ 'priority 2)
+ (magit-diff--make-hunk-overlay (1+ (magit-diff-hunk-region-end))
+ (oref section end)
+ 'font-lock-face face
+ 'priority 2)))
+
+(defun magit-diff-highlight-hunk-region-using-face (_section)
+ "Highlight the hunk-internal region by making it bold.
+Or rather highlight using the face `magit-diff-hunk-region', though
+changing only the `:weight' and/or `:slant' is recommended for that
+face."
+ (magit-diff--make-hunk-overlay (magit-diff-hunk-region-beginning)
+ (1+ (magit-diff-hunk-region-end))
+ 'font-lock-face 'magit-diff-hunk-region))
+
+(defun magit-diff-highlight-hunk-region-using-overlays (section)
+ "Emphasize the hunk-internal region using delimiting horizontal lines.
+This is implemented as single-pixel newlines places inside overlays."
+ (if (window-system)
+ (let ((beg (magit-diff-hunk-region-beginning))
+ (end (magit-diff-hunk-region-end))
+ (str (propertize
+ (concat (propertize "\s" 'display '(space :height (1)))
+ (propertize "\n" 'line-height t))
+ 'font-lock-face 'magit-diff-lines-boundary)))
+ (magit-diff--make-hunk-overlay beg (1+ beg) 'before-string str)
+ (magit-diff--make-hunk-overlay end (1+ end) 'after-string str))
+ (magit-diff-highlight-hunk-region-using-face section)))
+
+(defun magit-diff-highlight-hunk-region-using-underline (section)
+ "Emphasize the hunk-internal region using delimiting horizontal lines.
+This is implemented by overlining and underlining the first and
+last (visual) lines of the region."
+ (if (window-system)
+ (let* ((beg (magit-diff-hunk-region-beginning))
+ (end (magit-diff-hunk-region-end))
+ (beg-eol (save-excursion (goto-char beg)
+ (end-of-visual-line)
+ (point)))
+ (end-bol (save-excursion (goto-char end)
+ (beginning-of-visual-line)
+ (point)))
+ (color (face-background 'magit-diff-lines-boundary nil t)))
+ (cl-flet ((ln (b e &rest face)
+ (magit-diff--make-hunk-overlay
+ b e 'font-lock-face face 'after-string
+ (magit-diff--hunk-after-string face))))
+ (if (= beg end-bol)
+ (ln beg beg-eol :overline color :underline color)
+ (ln beg beg-eol :overline color)
+ (ln end-bol end :underline color))))
+ (magit-diff-highlight-hunk-region-using-face section)))
+
+(defun magit-diff--make-hunk-overlay (start end &rest args)
+ (let ((ov (make-overlay start end nil t)))
+ (overlay-put ov 'evaporate t)
+ (while args (overlay-put ov (pop args) (pop args)))
+ (push ov magit-section--region-overlays)
+ ov))
+
+(defun magit-diff--hunk-after-string (face)
+ (propertize "\s"
+ 'font-lock-face face
+ 'display (list 'space :align-to
+ `(+ (0 . right)
+ ,(min (window-hscroll)
+ (- (line-end-position)
+ (line-beginning-position)))))
+ ;; This prevents the cursor from being rendered at the
+ ;; edge of the window.
+ 'cursor t))
+
+;;; Hunk Utilities
+
+(defun magit-diff-inside-hunk-body-p ()
+ "Return non-nil if point is inside the body of a hunk."
+ (and (magit-section-match 'hunk)
+ (when-let ((content (oref (magit-current-section) content)))
+ (> (point) content))))
+
+;;; Diff Extract
+
+(defun magit-diff-file-header (section)
+ (when (magit-hunk-section-p section)
+ (setq section (oref section parent)))
+ (when (magit-file-section-p section)
+ (oref section header)))
+
+(defun magit-diff-hunk-region-header (section)
+ (let ((patch (magit-diff-hunk-region-patch section)))
+ (string-match "\n" patch)
+ (substring patch 0 (1- (match-end 0)))))
+
+(defun magit-diff-hunk-region-patch (section &optional args)
+ (let ((op (if (member "--reverse" args) "+" "-"))
+ (sbeg (oref section start))
+ (rbeg (magit-diff-hunk-region-beginning))
+ (rend (region-end))
+ (send (oref section end))
+ (patch nil))
+ (save-excursion
+ (goto-char sbeg)
+ (while (< (point) send)
+ (looking-at "\\(.\\)\\([^\n]*\n\\)")
+ (cond ((or (string-match-p "[@ ]" (match-string-no-properties 1))
+ (and (>= (point) rbeg)
+ (<= (point) rend)))
+ (push (match-string-no-properties 0) patch))
+ ((equal op (match-string-no-properties 1))
+ (push (concat " " (match-string-no-properties 2)) patch)))
+ (forward-line)))
+ (let ((buffer-list-update-hook nil)) ; #3759
+ (with-temp-buffer
+ (insert (mapconcat #'identity (reverse patch) ""))
+ (diff-fixup-modifs (point-min) (point-max))
+ (setq patch (buffer-string))))
+ patch))
+
+;;; _
+(provide 'magit-diff)
+;;; magit-diff.el ends here
--- /dev/null
+;;; magit-ediff.el --- Ediff extension for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library provides basic support for Ediff.
+
+;;; Code:
+
+(require 'magit)
+
+(require 'ediff)
+(require 'smerge-mode)
+
+(defvar smerge-ediff-buf)
+(defvar smerge-ediff-windows)
+
+;;; Options
+
+(defgroup magit-ediff nil
+ "Ediff support for Magit."
+ :link '(info-link "(magit)Ediffing")
+ :group 'magit-extensions)
+
+(defcustom magit-ediff-quit-hook
+ '(magit-ediff-cleanup-auxiliary-buffers
+ magit-ediff-restore-previous-winconf)
+ "Hooks to run after finishing Ediff, when that was invoked using Magit.
+The hooks are run in the Ediff control buffer. This is similar
+to `ediff-quit-hook' but takes the needs of Magit into account.
+The `ediff-quit-hook' is ignored by Ediff sessions which were
+invoked using Magit."
+ :package-version '(magit . "2.2.0")
+ :group 'magit-ediff
+ :type 'hook
+ :get 'magit-hook-custom-get
+ :options '(magit-ediff-cleanup-auxiliary-buffers
+ magit-ediff-restore-previous-winconf))
+
+(defcustom magit-ediff-dwim-show-on-hunks nil
+ "Whether `magit-ediff-dwim' runs show variants on hunks.
+If non-nil, `magit-ediff-show-staged' or
+`magit-ediff-show-unstaged' are called based on what section the
+hunk is in. Otherwise, `magit-ediff-dwim' runs
+`magit-ediff-stage' when point is on an uncommitted hunk."
+ :package-version '(magit . "2.2.0")
+ :group 'magit-ediff
+ :type 'boolean)
+
+(defcustom magit-ediff-show-stash-with-index t
+ "Whether `magit-ediff-show-stash' shows the state of the index.
+
+If non-nil, use a third Ediff buffer to distinguish which changes
+in the stash were staged. In cases where the stash contains no
+staged changes, fall back to a two-buffer Ediff.
+
+More specifically, a stash is a merge commit, stash@{N}, with
+potentially three parents.
+
+* stash@{N}^1 represents the `HEAD' commit at the time the stash
+ was created.
+
+* stash@{N}^2 records any changes that were staged when the stash
+ was made.
+
+* stash@{N}^3, if it exists, contains files that were untracked
+ when stashing.
+
+If this option is non-nil, `magit-ediff-show-stash' will run
+Ediff on a file using three buffers: one for stash@{N}, another
+for stash@{N}^1, and a third for stash@{N}^2.
+
+Otherwise, Ediff uses two buffers, comparing
+stash@{N}^1..stash@{N}. Along with any unstaged changes, changes
+in the index commit, stash@{N}^2, will be shown in this
+comparison unless they conflicted with changes in the working
+tree at the time of stashing."
+ :package-version '(magit . "2.6.0")
+ :group 'magit-ediff
+ :type 'boolean)
+
+;;; Commands
+
+(defvar magit-ediff-previous-winconf nil)
+
+;;;###autoload (autoload 'magit-ediff "magit-ediff" nil)
+(transient-define-prefix magit-ediff ()
+ "Show differences using the Ediff package."
+ :info-manual "(ediff)"
+ ["Ediff"
+ [("E" "Dwim" magit-ediff-dwim)
+ ("s" "Stage" magit-ediff-stage)
+ ("m" "Resolve" magit-ediff-resolve)]
+ [("u" "Show unstaged" magit-ediff-show-unstaged)
+ ("i" "Show staged" magit-ediff-show-staged)
+ ("w" "Show worktree" magit-ediff-show-working-tree)]
+ [("c" "Show commit" magit-ediff-show-commit)
+ ("r" "Show range" magit-ediff-compare)
+ ("z" "Show stash" magit-ediff-show-stash)]])
+
+;;;###autoload
+(defun magit-ediff-resolve (file)
+ "Resolve outstanding conflicts in FILE using Ediff.
+FILE has to be relative to the top directory of the repository.
+
+In the rare event that you want to manually resolve all
+conflicts, including those already resolved by Git, use
+`ediff-merge-revisions-with-ancestor'."
+ (interactive
+ (let ((current (magit-current-file))
+ (unmerged (magit-unmerged-files)))
+ (unless unmerged
+ (user-error "There are no unresolved conflicts"))
+ (list (magit-completing-read "Resolve file" unmerged nil t nil nil
+ (car (member current unmerged))))))
+ (magit-with-toplevel
+ (with-current-buffer (find-file-noselect file)
+ (smerge-ediff)
+ (setq-local
+ ediff-quit-hook
+ (lambda ()
+ (let ((bufC ediff-buffer-C)
+ (bufS smerge-ediff-buf))
+ (with-current-buffer bufS
+ (when (yes-or-no-p (format "Conflict resolution finished; save %s? "
+ buffer-file-name))
+ (erase-buffer)
+ (insert-buffer-substring bufC)
+ (save-buffer))))
+ (when (buffer-live-p ediff-buffer-A) (kill-buffer ediff-buffer-A))
+ (when (buffer-live-p ediff-buffer-B) (kill-buffer ediff-buffer-B))
+ (when (buffer-live-p ediff-buffer-C) (kill-buffer ediff-buffer-C))
+ (when (buffer-live-p ediff-ancestor-buffer)
+ (kill-buffer ediff-ancestor-buffer))
+ (let ((magit-ediff-previous-winconf smerge-ediff-windows))
+ (run-hooks 'magit-ediff-quit-hook)))))))
+
+;;;###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* ((conf (current-window-configuration))
+ (bufA (magit-get-revision-buffer "HEAD" file))
+ (bufB (magit-get-revision-buffer "{index}" file))
+ (bufBrw (and bufB (with-current-buffer bufB (not buffer-read-only))))
+ (bufC (get-file-buffer file))
+ (fileBufC (or bufC (find-file-noselect file)))
+ (coding-system-for-read
+ (with-current-buffer fileBufC buffer-file-coding-system)))
+ (ediff-buffers3
+ (or bufA (magit-find-file-noselect "HEAD" file))
+ (with-current-buffer (magit-find-file-index-noselect file t)
+ (setq buffer-read-only nil)
+ (current-buffer))
+ fileBufC
+ `((lambda ()
+ (setq-local
+ ediff-quit-hook
+ (lambda ()
+ (and (buffer-live-p ediff-buffer-B)
+ (buffer-modified-p ediff-buffer-B)
+ (with-current-buffer ediff-buffer-B
+ (magit-update-index)))
+ (and (buffer-live-p ediff-buffer-C)
+ (buffer-modified-p ediff-buffer-C)
+ (with-current-buffer ediff-buffer-C
+ (when (y-or-n-p
+ (format "Save file %s? " buffer-file-name))
+ (save-buffer))))
+ ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
+ ,@(if bufB
+ (unless bufBrw '((with-current-buffer ediff-buffer-B
+ (setq buffer-read-only t))))
+ '((ediff-kill-buffer-carefully ediff-buffer-B)))
+ ,@(unless bufC '((ediff-kill-buffer-carefully ediff-buffer-C)))
+ (let ((magit-ediff-previous-winconf ,conf))
+ (run-hooks 'magit-ediff-quit-hook))))))
+ 'ediff-buffers3))))
+
+;;;###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-with-toplevel
+ (let ((conf (current-window-configuration))
+ (bufA (if revA
+ (magit-get-revision-buffer revA fileA)
+ (get-file-buffer fileA)))
+ (bufB (if revB
+ (magit-get-revision-buffer revB fileB)
+ (get-file-buffer fileB))))
+ (ediff-buffers
+ (or bufA (if revA
+ (magit-find-file-noselect revA fileA)
+ (find-file-noselect fileA)))
+ (or bufB (if revB
+ (magit-find-file-noselect revB fileB)
+ (find-file-noselect fileB)))
+ `((lambda ()
+ (setq-local
+ ediff-quit-hook
+ (lambda ()
+ ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
+ ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
+ (let ((magit-ediff-previous-winconf ,conf))
+ (run-hooks 'magit-ediff-quit-hook))))))
+ 'ediff-revision))))
+
+(defun magit-ediff-compare--read-revisions (&optional arg mbase)
+ (let ((input (or arg (magit-diff-read-range-or-commit
+ "Compare range or commit"
+ nil mbase))))
+ (--if-let (magit-split-range input)
+ (-cons-to-list it)
+ (list input nil))))
+
+(defun magit-ediff-read-files (revA revB &optional fileB)
+ "Read file in REVB, return it and the corresponding file in REVA.
+When FILEB is non-nil, use this as REVB's file instead of
+prompting for it."
+ (unless fileB
+ (setq fileB (magit-read-file-choice
+ (format "File to compare between %s and %s"
+ revA (or revB "the working tree"))
+ (magit-changed-files revA revB)
+ (format "No changed files between %s and %s"
+ revA (or revB "the working tree")))))
+ (list (or (car (member fileB (magit-revision-files revA)))
+ (cdr (assoc fileB (magit-renamed-files revB revA)))
+ (magit-read-file-choice
+ (format "File in %s to compare with %s in %s"
+ revA fileB (or revB "the working tree"))
+ (magit-changed-files revB revA)
+ (format "No files have changed between %s and %s"
+ revA revB)))
+ fileB))
+
+;;;###autoload
+(defun magit-ediff-dwim ()
+ "Compare, stage, or resolve using Ediff.
+This command tries to guess what file, and what commit or range
+the user wants to compare, stage, or resolve using Ediff. It
+might only be able to guess either the file, or range or commit,
+in which case the user is asked about the other. It might not
+always guess right, in which case the appropriate `magit-ediff-*'
+command has to be used explicitly. If it cannot read the user's
+mind at all, then it asks the user for a command to run."
+ (interactive)
+ (magit-section-case
+ (hunk (save-excursion
+ (goto-char (oref (oref it parent) start))
+ (magit-ediff-dwim)))
+ (t
+ (let ((range (magit-diff--dwim))
+ (file (magit-current-file))
+ command revA revB)
+ (pcase range
+ ((and (guard (not magit-ediff-dwim-show-on-hunks))
+ (or `unstaged `staged))
+ (setq command (if (magit-anything-unmerged-p)
+ #'magit-ediff-resolve
+ #'magit-ediff-stage)))
+ (`unstaged (setq command #'magit-ediff-show-unstaged))
+ (`staged (setq command #'magit-ediff-show-staged))
+ (`(commit . ,value)
+ (setq command #'magit-ediff-show-commit)
+ (setq revB value))
+ (`(stash . ,value)
+ (setq command #'magit-ediff-show-stash)
+ (setq revB value))
+ ((pred stringp)
+ (pcase-let ((`(,a ,b) (magit-ediff-compare--read-revisions range)))
+ (setq command #'magit-ediff-compare)
+ (setq revA a)
+ (setq revB b)))
+ (_
+ (when (derived-mode-p 'magit-diff-mode)
+ (pcase (magit-diff-type)
+ (`committed (pcase-let ((`(,a ,b)
+ (magit-ediff-compare--read-revisions
+ magit-buffer-range)))
+ (setq revA a)
+ (setq revB b)))
+ ((guard (not magit-ediff-dwim-show-on-hunks))
+ (setq command #'magit-ediff-stage))
+ (`unstaged (setq command #'magit-ediff-show-unstaged))
+ (`staged (setq command #'magit-ediff-show-staged))
+ (`undefined (setq command nil))
+ (_ (setq command nil))))))
+ (cond ((not command)
+ (call-interactively
+ (magit-read-char-case
+ "Failed to read your mind; do you want to " t
+ (?c "[c]ommit" 'magit-ediff-show-commit)
+ (?r "[r]ange" 'magit-ediff-compare)
+ (?s "[s]tage" 'magit-ediff-stage)
+ (?v "resol[v]e" 'magit-ediff-resolve))))
+ ((eq command 'magit-ediff-compare)
+ (apply 'magit-ediff-compare revA revB
+ (magit-ediff-read-files revA revB file)))
+ ((eq command 'magit-ediff-show-commit)
+ (magit-ediff-show-commit revB))
+ ((eq command 'magit-ediff-show-stash)
+ (magit-ediff-show-stash revB))
+ (file
+ (funcall command file))
+ (t
+ (call-interactively command)))))))
+
+;;;###autoload
+(defun magit-ediff-show-staged (file)
+ "Show staged changes using Ediff.
+
+This only allows looking at the changes; to stage, unstage,
+and discard changes using Ediff, use `magit-ediff-stage'.
+
+FILE must be relative to the top directory of the repository."
+ (interactive
+ (list (magit-read-file-choice "Show staged changes for file"
+ (magit-staged-files)
+ "No staged files")))
+ (let ((conf (current-window-configuration))
+ (bufA (magit-get-revision-buffer "HEAD" file))
+ (bufB (get-buffer (concat file ".~{index}~"))))
+ (ediff-buffers
+ (or bufA (magit-find-file-noselect "HEAD" file))
+ (or bufB (magit-find-file-index-noselect file t))
+ `((lambda ()
+ (setq-local
+ ediff-quit-hook
+ (lambda ()
+ ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
+ ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
+ (let ((magit-ediff-previous-winconf ,conf))
+ (run-hooks 'magit-ediff-quit-hook))))))
+ 'ediff-buffers)))
+
+;;;###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-with-toplevel
+ (let ((conf (current-window-configuration))
+ (bufA (get-buffer (concat file ".~{index}~")))
+ (bufB (get-file-buffer file)))
+ (ediff-buffers
+ (or bufA (magit-find-file-index-noselect file t))
+ (or bufB (find-file-noselect file))
+ `((lambda ()
+ (setq-local
+ ediff-quit-hook
+ (lambda ()
+ ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
+ ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
+ (let ((magit-ediff-previous-winconf ,conf))
+ (run-hooks 'magit-ediff-quit-hook))))))
+ 'ediff-buffers))))
+
+;;;###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-with-toplevel
+ (let ((conf (current-window-configuration))
+ (bufA (magit-get-revision-buffer "HEAD" file))
+ (bufB (get-file-buffer file)))
+ (ediff-buffers
+ (or bufA (magit-find-file-noselect "HEAD" file))
+ (or bufB (find-file-noselect file))
+ `((lambda ()
+ (setq-local
+ ediff-quit-hook
+ (lambda ()
+ ,@(unless bufA '((ediff-kill-buffer-carefully ediff-buffer-A)))
+ ,@(unless bufB '((ediff-kill-buffer-carefully ediff-buffer-B)))
+ (let ((magit-ediff-previous-winconf ,conf))
+ (run-hooks 'magit-ediff-quit-hook))))))
+ 'ediff-buffers))))
+
+;;;###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)))
+ (let ((conf (current-window-configuration))
+ (bufA (magit-get-revision-buffer revA fileA))
+ (bufB (magit-get-revision-buffer revB fileB))
+ (bufC (magit-get-revision-buffer revC fileC)))
+ (ediff-buffers3
+ (or bufA (magit-find-file-noselect revA fileA))
+ (or bufB (magit-find-file-noselect revB fileB))
+ (or bufC (magit-find-file-noselect revC fileC))
+ `((lambda ()
+ (setq-local
+ ediff-quit-hook
+ (lambda ()
+ ,@(unless bufA
+ '((ediff-kill-buffer-carefully ediff-buffer-A)))
+ ,@(unless bufB
+ '((ediff-kill-buffer-carefully ediff-buffer-B)))
+ ,@(unless bufC
+ '((ediff-kill-buffer-carefully ediff-buffer-C)))
+ (let ((magit-ediff-previous-winconf ,conf))
+ (run-hooks 'magit-ediff-quit-hook))))))
+ 'ediff-buffers3))
+ (magit-ediff-compare revA revC fileA fileC))))
+
+(defun magit-ediff-cleanup-auxiliary-buffers ()
+ (let* ((ctl-buf ediff-control-buffer)
+ (ctl-win (ediff-get-visible-buffer-window ctl-buf))
+ (ctl-frm ediff-control-frame)
+ (main-frame (cond ((window-live-p ediff-window-A)
+ (window-frame ediff-window-A))
+ ((window-live-p ediff-window-B)
+ (window-frame ediff-window-B)))))
+ (ediff-kill-buffer-carefully ediff-diff-buffer)
+ (ediff-kill-buffer-carefully ediff-custom-diff-buffer)
+ (ediff-kill-buffer-carefully ediff-fine-diff-buffer)
+ (ediff-kill-buffer-carefully ediff-tmp-buffer)
+ (ediff-kill-buffer-carefully ediff-error-buffer)
+ (ediff-kill-buffer-carefully ediff-msg-buffer)
+ (ediff-kill-buffer-carefully ediff-debug-buffer)
+ (when (boundp 'ediff-patch-diagnostics)
+ (ediff-kill-buffer-carefully ediff-patch-diagnostics))
+ (cond ((and (ediff-window-display-p)
+ (frame-live-p ctl-frm))
+ (delete-frame ctl-frm))
+ ((window-live-p ctl-win)
+ (delete-window ctl-win)))
+ (ediff-kill-buffer-carefully ctl-buf)
+ (when (frame-live-p main-frame)
+ (select-frame main-frame))))
+
+(defun magit-ediff-restore-previous-winconf ()
+ (set-window-configuration magit-ediff-previous-winconf))
+
+;;; _
+(provide 'magit-ediff)
+;;; magit-ediff.el ends here
--- /dev/null
+;;; magit-extras.el --- additional functionality for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; Additional functionality for Magit.
+
+;;; Code:
+
+(require 'magit)
+
+(declare-function change-log-insert-entries "add-log" (changelogs))
+(declare-function diff-add-log-current-defuns "diff-mode" ())
+(declare-function dired-read-shell-command "dired-aux" (prompt arg files))
+;; For `magit-project-status'.
+(declare-function project-root "project" (project))
+(declare-function vc-git-command "vc-git" (buffer okstatus file-or-list &rest flags))
+
+(defvar ido-exit)
+(defvar ido-fallback)
+(defvar project-prefix-map)
+(defvar project-switch-commands)
+
+(defgroup magit-extras nil
+ "Additional functionality for Magit."
+ :group 'magit-extensions)
+
+;;; External Tools
+
+(defcustom magit-gitk-executable
+ (or (and (eq system-type 'windows-nt)
+ (let ((exe (magit-git-string
+ "-c" "alias.X=!x() { which \"$1\" | cygpath -mf -; }; x"
+ "X" "gitk.exe")))
+ (and exe (file-executable-p exe) exe)))
+ (executable-find "gitk") "gitk")
+ "The Gitk executable."
+ :group 'magit-extras
+ :set-after '(magit-git-executable)
+ :type 'string)
+
+;;;###autoload
+(defun magit-run-git-gui ()
+ "Run `git gui' for the current git repository."
+ (interactive)
+ (magit-with-toplevel
+ (magit-process-file magit-git-executable nil 0 nil "gui")))
+
+;;;###autoload
+(defun magit-run-git-gui-blame (commit filename &optional linenum)
+ "Run `git gui blame' on the given FILENAME and COMMIT.
+Interactively run it for the current file and the `HEAD', with a
+prefix or when the current file cannot be determined let the user
+choose. When the current buffer is visiting FILENAME instruct
+blame to center around the line point is on."
+ (interactive
+ (let (revision filename)
+ (when (or current-prefix-arg
+ (not (setq revision "HEAD"
+ filename (magit-file-relative-name nil 'tracked))))
+ (setq revision (magit-read-branch-or-commit "Blame from revision"))
+ (setq filename (magit-read-file-from-rev revision "Blame file")))
+ (list revision filename
+ (and (equal filename
+ (ignore-errors
+ (magit-file-relative-name buffer-file-name)))
+ (line-number-at-pos)))))
+ (magit-with-toplevel
+ (apply #'magit-process-file magit-git-executable nil 0 nil "gui" "blame"
+ `(,@(and linenum (list (format "--line=%d" linenum)))
+ ,commit
+ ,filename))))
+
+;;;###autoload
+(defun magit-run-gitk ()
+ "Run `gitk' in the current repository."
+ (interactive)
+ (magit-process-file magit-gitk-executable nil 0))
+
+;;;###autoload
+(defun magit-run-gitk-branches ()
+ "Run `gitk --branches' in the current repository."
+ (interactive)
+ (magit-process-file magit-gitk-executable nil 0 nil "--branches"))
+
+;;;###autoload
+(defun magit-run-gitk-all ()
+ "Run `gitk --all' in the current repository."
+ (interactive)
+ (magit-process-file magit-gitk-executable nil 0 nil "--all"))
+
+;;; Emacs Tools
+
+;;;###autoload
+(defun ido-enter-magit-status ()
+ "Drop into `magit-status' from file switching.
+
+This command does not work in Emacs 26.1.
+See https://github.com/magit/magit/issues/3634
+and https://debbugs.gnu.org/cgi/bugreport.cgi?bug=31707.
+
+To make this command available use something like:
+
+ (add-hook \\='ido-setup-hook
+ (lambda ()
+ (define-key ido-completion-map
+ (kbd \"C-x g\") \\='ido-enter-magit-status)))
+
+Starting with Emacs 25.1 the Ido keymaps are defined just once
+instead of every time Ido is invoked, so now you can modify it
+like pretty much every other keymap:
+
+ (define-key ido-common-completion-map
+ (kbd \"C-x g\") \\='ido-enter-magit-status)"
+ (interactive)
+ (setq ido-exit 'fallback)
+ (setq ido-fallback 'magit-status) ; for Emacs >= 26.2
+ (with-no-warnings (setq fallback 'magit-status)) ; for Emacs 25
+ (exit-minibuffer))
+
+;;;###autoload
+(defun magit-project-status ()
+ "Run `magit-status' in the current project's root."
+ (interactive)
+ (magit-status-setup-buffer (project-root (project-current t))))
+
+(with-eval-after-load 'project
+ ;; Only more recent versions of project.el have `project-prefix-map' and
+ ;; `project-switch-commands', though project.el is available in Emacs 25.
+ (when (boundp 'project-prefix-map)
+ (define-key project-prefix-map "m" #'magit-project-status))
+ (when (boundp 'project-switch-commands)
+ (add-to-list 'project-switch-commands '(?m "Magit" magit-status))))
+
+;;;###autoload
+(defun magit-dired-jump (&optional other-window)
+ "Visit file at point using Dired.
+With a prefix argument, visit in another window. If there
+is no file at point, then instead visit `default-directory'."
+ (interactive "P")
+ (dired-jump other-window
+ (when-let ((file (magit-file-at-point)))
+ (expand-file-name (if (file-directory-p file)
+ (file-name-as-directory file)
+ file)))))
+
+;;;###autoload
+(defun magit-dired-log (&optional follow)
+ "Show log for all marked files, or the current file."
+ (interactive "P")
+ (if-let ((topdir (magit-toplevel default-directory)))
+ (let ((args (car (magit-log-arguments)))
+ (files (dired-get-marked-files nil nil #'magit-file-tracked-p)))
+ (unless files
+ (user-error "No marked file is being tracked by Git"))
+ (when (and follow
+ (not (member "--follow" args))
+ (not (cdr files)))
+ (push "--follow" args))
+ (magit-log-setup-buffer
+ (list (or (magit-get-current-branch) "HEAD"))
+ args
+ (let ((default-directory topdir))
+ (mapcar #'file-relative-name files))
+ magit-log-buffer-file-locked))
+ (magit--not-inside-repository-error)))
+
+;;;###autoload
+(defun magit-do-async-shell-command (file)
+ "Open FILE with `dired-do-async-shell-command'.
+Interactively, open the file at point."
+ (interactive (list (or (magit-file-at-point)
+ (completing-read "Act on file: "
+ (magit-list-files)))))
+ (require 'dired-aux)
+ (dired-do-async-shell-command
+ (dired-read-shell-command "& on %s: " current-prefix-arg (list file))
+ nil (list file)))
+
+;;; Shift Selection
+
+(defun magit--turn-on-shift-select-mode-p ()
+ (and shift-select-mode
+ this-command-keys-shift-translated
+ (not mark-active)
+ (not (eq (car-safe transient-mark-mode) 'only))))
+
+;;;###autoload
+(defun magit-previous-line (&optional arg try-vscroll)
+ "Like `previous-line' but with Magit-specific shift-selection.
+
+Magit's selection mechanism is based on the region but selects an
+area that is larger than the region. This causes `previous-line'
+when invoked while holding the shift key to move up one line and
+thereby select two lines. When invoked inside a hunk body this
+command does not move point on the first invocation and thereby
+it only selects a single line. Which inconsistency you prefer
+is a matter of preference."
+ (declare (interactive-only
+ "use `forward-line' with negative argument instead."))
+ (interactive "p\np")
+ (unless arg (setq arg 1))
+ (let ((stay (or (magit-diff-inside-hunk-body-p)
+ (magit-section-position-in-heading-p))))
+ (if (and stay (= arg 1) (magit--turn-on-shift-select-mode-p))
+ (push-mark nil nil t)
+ (with-no-warnings
+ (handle-shift-selection)
+ (previous-line (if stay (max (1- arg) 1) arg) try-vscroll)))))
+
+;;;###autoload
+(defun magit-next-line (&optional arg try-vscroll)
+ "Like `next-line' but with Magit-specific shift-selection.
+
+Magit's selection mechanism is based on the region but selects
+an area that is larger than the region. This causes `next-line'
+when invoked while holding the shift key to move down one line
+and thereby select two lines. When invoked inside a hunk body
+this command does not move point on the first invocation and
+thereby it only selects a single line. Which inconsistency you
+prefer is a matter of preference."
+ (declare (interactive-only forward-line))
+ (interactive "p\np")
+ (unless arg (setq arg 1))
+ (let ((stay (or (magit-diff-inside-hunk-body-p)
+ (magit-section-position-in-heading-p))))
+ (if (and stay (= arg 1) (magit--turn-on-shift-select-mode-p))
+ (push-mark nil nil t)
+ (with-no-warnings
+ (handle-shift-selection)
+ (next-line (if stay (max (1- arg) 1) arg) try-vscroll)))))
+
+;;; Clean
+
+;;;###autoload
+(defun magit-clean (&optional arg)
+ "Remove untracked files from the working tree.
+With a prefix argument also remove ignored files,
+with two prefix arguments remove ignored files only.
+\n(git clean -f -d [-x|-X])"
+ (interactive "p")
+ (when (yes-or-no-p (format "Remove %s files? "
+ (pcase arg
+ (1 "untracked")
+ (4 "untracked and ignored")
+ (_ "ignored"))))
+ (magit-wip-commit-before-change)
+ (magit-run-git "clean" "-f" "-d" (pcase arg (4 "-x") (16 "-X")))))
+
+(put 'magit-clean 'disabled t)
+
+;;; ChangeLog
+
+(defun magit-generate-changelog (&optional amending)
+ "Insert ChangeLog entries into the current buffer.
+
+The entries are generated from the diff being committed.
+If prefix argument, AMENDING, is non-nil, include changes
+in HEAD as well as staged changes in the diff to check."
+ (interactive "P")
+ (unless (magit-commit-message-buffer)
+ (user-error "No commit in progress"))
+ (require 'diff-mode) ; `diff-add-log-current-defuns'.
+ (require 'vc-git) ; `vc-git-diff'.
+ (require 'add-log) ; `change-log-insert-entries'.
+ (unless (and (fboundp 'change-log-insert-entries)
+ (fboundp 'diff-add-log-current-defuns))
+ (user-error "`magit-generate-changelog' requires Emacs 27 or better"))
+ (setq default-directory
+ (if (and (file-regular-p "gitdir")
+ (not (magit-git-true "rev-parse" "--is-inside-work-tree"))
+ (magit-git-true "rev-parse" "--is-inside-git-dir"))
+ (file-name-directory (magit-file-line "gitdir"))
+ (magit-toplevel)))
+ (let ((rev1 (if amending "HEAD^1" "HEAD"))
+ (rev2 nil))
+ ;; Magit may have updated the files without notifying vc, but
+ ;; `diff-add-log-current-defuns' relies on vc being up-to-date.
+ (mapc #'vc-file-clearprops (magit-staged-files))
+ (change-log-insert-entries
+ (with-temp-buffer
+ (vc-git-command (current-buffer) 1 nil
+ "diff-index" "--exit-code" "--patch"
+ (and (magit-anything-staged-p) "--cached")
+ rev1 "--")
+ ;; `diff-find-source-location' consults these vars.
+ (defvar diff-vc-revisions)
+ (setq-local diff-vc-revisions (list rev1 rev2))
+ (setq-local diff-vc-backend 'Git)
+ (diff-add-log-current-defuns)))))
+
+;;;###autoload
+(defun magit-add-change-log-entry (&optional whoami file-name other-window)
+ "Find change log file and add date entry and item for current change.
+This differs from `add-change-log-entry' (which see) in that
+it acts on the current hunk in a Magit buffer instead of on
+a position in a file-visiting buffer."
+ (interactive (list current-prefix-arg
+ (prompt-for-change-log-name)))
+ (pcase-let ((`(,buf ,pos) (magit-diff-visit-file--noselect)))
+ (magit--with-temp-position buf pos
+ (let ((add-log-buffer-file-name-function
+ (lambda ()
+ (or magit-buffer-file-name
+ (buffer-file-name)))))
+ (add-change-log-entry whoami file-name other-window)))))
+
+;;;###autoload
+(defun magit-add-change-log-entry-other-window (&optional whoami file-name)
+ "Find change log file in other window and add entry and item.
+This differs from `add-change-log-entry-other-window' (which see)
+in that it acts on the current hunk in a Magit buffer instead of
+on a position in a file-visiting buffer."
+ (interactive (and current-prefix-arg
+ (list current-prefix-arg
+ (prompt-for-change-log-name))))
+ (magit-add-change-log-entry whoami file-name t))
+
+;;; Edit Line Commit
+
+;;;###autoload
+(defun magit-edit-line-commit (&optional type)
+ "Edit the commit that added the current line.
+
+With a prefix argument edit the commit that removes the line,
+if any. The commit is determined using `git blame' and made
+editable using `git rebase --interactive' if it is reachable
+from `HEAD', or by checking out the commit (or a branch that
+points at it) otherwise."
+ (interactive (list (and current-prefix-arg 'removal)))
+ (let* ((chunk (magit-current-blame-chunk (or type 'addition)))
+ (rev (oref chunk orig-rev)))
+ (if (equal rev "0000000000000000000000000000000000000000")
+ (message "This line has not been committed yet")
+ (let ((rebase (magit-rev-ancestor-p rev "HEAD"))
+ (file (expand-file-name (oref chunk orig-file)
+ (magit-toplevel))))
+ (if rebase
+ (let ((magit--rebase-published-symbol 'edit-published))
+ (magit-rebase-edit-commit rev (magit-rebase-arguments)))
+ (magit-checkout (or (magit-rev-branch rev) rev)))
+ (unless (and buffer-file-name
+ (file-equal-p file buffer-file-name))
+ (let ((blame-type (and magit-blame-mode magit-blame-type)))
+ (if rebase
+ (set-process-sentinel
+ magit-this-process
+ (lambda (process event)
+ (magit-sequencer-process-sentinel process event)
+ (when (eq (process-status process) 'exit)
+ (find-file file)
+ (when blame-type
+ (magit-blame--pre-blame-setup blame-type)
+ (magit-blame--run (magit-blame-arguments))))))
+ (find-file file)
+ (when blame-type
+ (magit-blame--pre-blame-setup blame-type)
+ (magit-blame--run (magit-blame-arguments))))))))))
+
+(put 'magit-edit-line-commit 'disabled t)
+
+;;;###autoload
+(defun magit-diff-edit-hunk-commit (file)
+ "From a hunk, edit the respective commit and visit the file.
+
+First visit the file being modified by the hunk at the correct
+location using `magit-diff-visit-file'. This actually visits a
+blob. When point is on a diff header, not within an individual
+hunk, then this visits the blob the first hunk is about.
+
+Then invoke `magit-edit-line-commit', which uses an interactive
+rebase to make the commit editable, or if that is not possible
+because the commit is not reachable from `HEAD' by checking out
+that commit directly. This also causes the actual worktree file
+to be visited.
+
+Neither the blob nor the file buffer are killed when finishing
+the rebase. If that is undesirable, then it might be better to
+use `magit-rebase-edit-command' instead of this command."
+ (interactive (list (magit-file-at-point t t)))
+ (let ((magit-diff-visit-previous-blob nil))
+ (with-current-buffer
+ (magit-diff-visit-file--internal file nil #'pop-to-buffer-same-window)
+ (magit-edit-line-commit))))
+
+(put 'magit-diff-edit-hunk-commit 'disabled t)
+
+;;; Reshelve
+
+(defcustom magit-reshelve-since-committer-only nil
+ "Whether `magit-reshelve-since' changes only the committer dates.
+Otherwise the author dates are also changed."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+;;;###autoload
+(defun magit-reshelve-since (rev)
+ "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."
+ (interactive (list nil))
+ (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 'magit-reshelve-since
+ "Type %p on a commit to reshelve it and the commits above it,"))
+ (t
+ (cl-flet ((adjust (time offset)
+ (format-time-string
+ "%F %T %z"
+ (+ (floor time)
+ (* offset 60)
+ (- (car (decode-time time)))))))
+ (let* ((start (concat rev "^"))
+ (range (concat start ".." current))
+ (time-rev (adjust (float-time (string-to-number
+ (magit-rev-format "%at" start)))
+ 1))
+ (time-now (adjust (float-time)
+ (- (string-to-number
+ (magit-git-string "rev-list" "--count"
+ range))))))
+ (push time-rev magit--reshelve-history)
+ (let ((date (floor
+ (float-time
+ (date-to-time
+ (read-string "Date for first commit: "
+ time-now 'magit--reshelve-history)))))
+ (process-environment process-environment))
+ (push "FILTER_BRANCH_SQUELCH_WARNING=1" process-environment)
+ (magit-with-toplevel
+ (magit-run-git-async
+ "filter-branch" "--force" "--env-filter"
+ (format
+ "case $GIT_COMMIT in %s\nesac"
+ (mapconcat
+ (lambda (rev)
+ (prog1 (concat
+ (format "%s) " rev)
+ (and (not magit-reshelve-since-committer-only)
+ (format "export GIT_AUTHOR_DATE=\"%s\"; " date))
+ (format "export GIT_COMMITTER_DATE=\"%s\";;" date))
+ (cl-incf date 60)))
+ (magit-git-lines "rev-list" "--reverse" range)
+ " "))
+ 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: %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 . "2.3.0")
+ :group 'magit-commands
+ :type '(list (choice (string :tag "Insert at point format")
+ (cons (string :tag "Insert at point format")
+ (repeat (string :tag "Argument to git show")))
+ (const :tag "Don't insert at point" nil))
+ (choice (string :tag "Insert at eob format")
+ (cons (string :tag "Insert at eob format")
+ (repeat (string :tag "Argument to git show")))
+ (const :tag "Don't insert at eob" nil))
+ (choice (regexp :tag "Find index regexp")
+ (const :tag "Don't number entries" nil))))
+
+(defcustom magit-copy-revision-abbreviated nil
+ "Whether to save abbreviated revision to `kill-ring' and `magit-revision-stack'."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-miscellaneous
+ :type 'boolean)
+
+;;;###autoload
+(defun magit-pop-revision-stack (rev toplevel)
+ "Insert a representation of a revision into the current buffer.
+
+Pop a revision from the `magit-revision-stack' and insert it into
+the current buffer according to `magit-pop-revision-stack-format'.
+Revisions can be put on the stack using `magit-copy-section-value'
+and `magit-copy-buffer-revision'.
+
+If the stack is empty or with a prefix argument, instead read a
+revision in the minibuffer. By using the minibuffer history this
+allows selecting an item which was popped earlier or to insert an
+arbitrary reference or revision without first pushing it onto the
+stack.
+
+When reading the revision from the minibuffer, then it might not
+be possible to guess the correct repository. When this command
+is called inside a repository (e.g. while composing a commit
+message), then that repository is used. Otherwise (e.g. while
+composing an email) then the repository recorded for the top
+element of the stack is used (even though we insert another
+revision). If not called inside a repository and with an empty
+stack, or with two prefix arguments, then read the repository in
+the minibuffer too."
+ (interactive
+ (if (or current-prefix-arg (not magit-revision-stack))
+ (let ((default-directory
+ (or (and (not (= (prefix-numeric-value current-prefix-arg) 16))
+ (or (magit-toplevel)
+ (cadr (car magit-revision-stack))))
+ (magit-read-repository))))
+ (list (magit-read-branch-or-commit "Insert revision")
+ default-directory))
+ (push (caar magit-revision-stack) magit-revision-history)
+ (pop magit-revision-stack)))
+ (if rev
+ (pcase-let ((`(,pnt-format ,eob-format ,idx-format)
+ magit-pop-revision-stack-format))
+ (let ((default-directory toplevel)
+ (idx (and idx-format
+ (save-excursion
+ (if (re-search-backward idx-format nil t)
+ (number-to-string
+ (1+ (string-to-number (match-string 1))))
+ "1"))))
+ pnt-args eob-args)
+ (when (listp pnt-format)
+ (setq pnt-args (cdr pnt-format))
+ (setq pnt-format (car pnt-format)))
+ (when (listp eob-format)
+ (setq eob-args (cdr eob-format))
+ (setq eob-format (car eob-format)))
+ (when pnt-format
+ (when idx-format
+ (setq pnt-format
+ (replace-regexp-in-string "%N" idx pnt-format t t)))
+ (magit-rev-insert-format pnt-format rev pnt-args)
+ (backward-delete-char 1))
+ (when eob-format
+ (when idx-format
+ (setq eob-format
+ (replace-regexp-in-string "%N" idx eob-format t t)))
+ (save-excursion
+ (goto-char (point-max))
+ (skip-syntax-backward ">s-")
+ (beginning-of-line)
+ (if (and comment-start (looking-at comment-start))
+ (while (looking-at comment-start)
+ (forward-line -1))
+ (forward-line)
+ (unless (= (current-column) 0)
+ (insert ?\n)))
+ (insert ?\n)
+ (magit-rev-insert-format eob-format rev eob-args)
+ (backward-delete-char 1)))))
+ (user-error "Revision stack is empty")))
+
+(define-key git-commit-mode-map
+ (kbd "C-c C-w") 'magit-pop-revision-stack)
+
+;;;###autoload
+(defun magit-copy-section-value (arg)
+ "Save the value of the current section for later use.
+
+Save the section value to the `kill-ring', and, provided that
+the current section is a commit, branch, or tag section, push
+the (referenced) revision to the `magit-revision-stack' for use
+with `magit-pop-revision-stack'.
+
+When `magit-copy-revision-abbreviated' is non-nil, save the
+abbreviated revision to the `kill-ring' and the
+`magit-revision-stack'.
+
+When the current section is a branch or a tag, and a prefix
+argument is used, then save the revision at its tip to the
+`kill-ring' instead of the reference name.
+
+When the region is active, then save that to the `kill-ring',
+like `kill-ring-save' would, instead of behaving as described
+above. If a prefix argument is used and the region is within
+a hunk, then strip the diff marker column and keep only either
+the added or removed lines, depending on the sign of the prefix
+argument."
+ (interactive "P")
+ (cond
+ ((and arg
+ (magit-section-internal-region-p)
+ (magit-section-match 'hunk))
+ (kill-new
+ (thread-last (buffer-substring-no-properties
+ (region-beginning)
+ (region-end))
+ (replace-regexp-in-string
+ (format "^\\%c.*\n?" (if (< (prefix-numeric-value arg) 0) ?+ ?-))
+ "")
+ (replace-regexp-in-string "^[ \\+\\-]" "")))
+ (deactivate-mark))
+ ((use-region-p)
+ (call-interactively #'copy-region-as-kill))
+ (t
+ (when-let ((section (magit-current-section))
+ (value (oref section value)))
+ (magit-section-case
+ ((branch commit module-commit tag)
+ (let ((default-directory default-directory) ref)
+ (magit-section-case
+ ((branch tag)
+ (setq ref value))
+ (module-commit
+ (setq default-directory
+ (file-name-as-directory
+ (expand-file-name (magit-section-parent-value section)
+ (magit-toplevel))))))
+ (setq value (magit-rev-parse
+ (and magit-copy-revision-abbreviated "--short")
+ value))
+ (push (list value default-directory) magit-revision-stack)
+ (kill-new (message "%s" (or (and current-prefix-arg ref)
+ value)))))
+ (t (kill-new (message "%s" value))))))))
+
+;;;###autoload
+(defun magit-copy-buffer-revision ()
+ "Save the revision of the current buffer for later use.
+
+Save the revision shown in the current buffer to the `kill-ring'
+and push it to the `magit-revision-stack'.
+
+This command is mainly intended for use in `magit-revision-mode'
+buffers, the only buffers where it is always unambiguous exactly
+which revision should be saved.
+
+Most other Magit buffers usually show more than one revision, in
+some way or another, so this command has to select one of them,
+and that choice might not always be the one you think would have
+been the best pick.
+
+In such buffers it is often more useful to save the value of
+the current section instead, using `magit-copy-section-value'.
+
+When the region is active, then save that to the `kill-ring',
+like `kill-ring-save' would, instead of behaving as described
+above.
+
+When `magit-copy-revision-abbreviated' is non-nil, save the
+abbreviated revision to the `kill-ring' and the
+`magit-revision-stack'."
+ (interactive)
+ (if (use-region-p)
+ (call-interactively #'copy-region-as-kill)
+ (when-let ((rev (or magit-buffer-revision
+ (cl-case major-mode
+ (magit-diff-mode
+ (if (string-match "\\.\\.\\.?\\(.+\\)"
+ magit-buffer-range)
+ (match-string 1 magit-buffer-range)
+ magit-buffer-range))
+ (magit-status-mode "HEAD")))))
+ (when (magit-commit-p rev)
+ (setq rev (magit-rev-parse
+ (and magit-copy-revision-abbreviated "--short")
+ rev))
+ (push (list rev default-directory) magit-revision-stack)
+ (kill-new (message "%s" rev))))))
+
+;;; Miscellaneous
+
+;;;###autoload
+(defun magit-abort-dwim ()
+ "Abort current operation.
+Depending on the context, this will abort a merge, a rebase, a
+patch application, a cherry-pick, a revert, or a bisect."
+ (interactive)
+ (cond ((magit-merge-in-progress-p) (magit-merge-abort))
+ ((magit-rebase-in-progress-p) (magit-rebase-abort))
+ ((magit-am-in-progress-p) (magit-am-abort))
+ ((magit-sequencer-in-progress-p) (magit-sequencer-abort))
+ ((magit-bisect-in-progress-p) (magit-bisect-reset))))
+
+;;; _
+(provide 'magit-extras)
+;;; magit-extras.el ends here
--- /dev/null
+;;; magit-fetch.el --- download objects and refs -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements fetch commands.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Options
+
+(defcustom magit-fetch-modules-jobs 4
+ "Number of submodules to fetch in parallel.
+Ignored for Git versions before v2.8.0."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-commands
+ :type '(choice (const :tag "one at a time" nil) number))
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-fetch "magit-fetch" nil t)
+(transient-define-prefix magit-fetch ()
+ "Fetch from another repository."
+ :man-page "git-fetch"
+ ["Arguments"
+ ("-p" "Prune deleted branches" ("-p" "--prune"))
+ ("-t" "Fetch all tags" ("-t" "--tags"))
+ (7 "-u" "Fetch full history" "--unshallow")]
+ ["Fetch from"
+ ("p" magit-fetch-from-pushremote)
+ ("u" magit-fetch-from-upstream)
+ ("e" "elsewhere" magit-fetch-other)
+ ("a" "all remotes" magit-fetch-all)]
+ ["Fetch"
+ ("o" "another branch" magit-fetch-branch)
+ ("r" "explicit refspec" magit-fetch-refspec)
+ ("m" "submodules" magit-fetch-modules)]
+ ["Configure"
+ ("C" "variables..." magit-branch-configure)])
+
+(defun magit-fetch-arguments ()
+ (transient-args 'magit-fetch))
+
+(defun magit-git-fetch (remote args)
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "fetch" remote args))
+
+;;;###autoload (autoload 'magit-fetch-from-pushremote "magit-fetch" nil t)
+(transient-define-suffix magit-fetch-from-pushremote (args)
+ "Fetch from the current push-remote.
+
+With a prefix argument or when the push-remote is either not
+configured or unusable, then let the user first configure the
+push-remote."
+ :description 'magit-fetch--pushremote-description
+ (interactive (list (magit-fetch-arguments)))
+ (let ((remote (magit-get-push-remote)))
+ (when (or current-prefix-arg
+ (not (member remote (magit-list-remotes))))
+ (let ((var (magit--push-remote-variable)))
+ (setq remote
+ (magit-read-remote (format "Set %s and fetch from there" var)))
+ (magit-set remote var)))
+ (magit-git-fetch remote args)))
+
+(defun magit-fetch--pushremote-description ()
+ (let* ((branch (magit-get-current-branch))
+ (remote (magit-get-push-remote branch))
+ (v (magit--push-remote-variable branch t)))
+ (cond
+ ((member remote (magit-list-remotes)) remote)
+ (remote
+ (format "%s, replacing invalid" v))
+ (t
+ (format "%s, setting that" v)))))
+
+;;;###autoload (autoload 'magit-fetch-from-upstream "magit-fetch" nil t)
+(transient-define-suffix magit-fetch-from-upstream (remote args)
+ "Fetch from the \"current\" remote, usually the upstream.
+
+If the upstream is configured for the current branch and names
+an existing remote, then use that. Otherwise try to use another
+remote: If only a single remote is configured, then use that.
+Otherwise if a remote named \"origin\" exists, then use that.
+
+If no remote can be determined, then this command is not available
+from the `magit-fetch' transient prefix and invoking it directly
+results in an error."
+ :if (lambda () (magit-get-current-remote t))
+ :description (lambda () (magit-get-current-remote t))
+ (interactive (list (magit-get-current-remote t)
+ (magit-fetch-arguments)))
+ (unless remote
+ (error "The \"current\" remote could not be determined"))
+ (magit-git-fetch remote args))
+
+;;;###autoload
+(defun magit-fetch-other (remote args)
+ "Fetch from another repository."
+ (interactive (list (magit-read-remote "Fetch remote")
+ (magit-fetch-arguments)))
+ (magit-git-fetch remote args))
+
+;;;###autoload
+(defun magit-fetch-branch (remote branch args)
+ "Fetch a BRANCH from a REMOTE."
+ (interactive
+ (let ((remote (magit-read-remote-or-url "Fetch from remote or url")))
+ (list remote
+ (magit-read-remote-branch "Fetch branch" remote)
+ (magit-fetch-arguments))))
+ (magit-git-fetch remote (cons branch args)))
+
+;;;###autoload
+(defun magit-fetch-refspec (remote refspec args)
+ "Fetch a REFSPEC from a REMOTE."
+ (interactive
+ (let ((remote (magit-read-remote-or-url "Fetch from remote or url")))
+ (list remote
+ (magit-read-refspec "Fetch using refspec" remote)
+ (magit-fetch-arguments))))
+ (magit-git-fetch remote (cons refspec args)))
+
+;;;###autoload
+(defun magit-fetch-all (args)
+ "Fetch from all remotes."
+ (interactive (list (magit-fetch-arguments)))
+ (magit-git-fetch nil (cons "--all" args)))
+
+;;;###autoload
+(defun magit-fetch-all-prune ()
+ "Fetch from all remotes, and prune.
+Prune remote tracking branches for branches that have been
+removed on the respective remote."
+ (interactive)
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "remote" "update" "--prune"))
+
+;;;###autoload
+(defun magit-fetch-all-no-prune ()
+ "Fetch from all remotes."
+ (interactive)
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "remote" "update"))
+
+;;;###autoload
+(defun magit-fetch-modules (&optional all)
+ "Fetch all submodules.
+
+Option `magit-fetch-modules-jobs' controls how many submodules
+are being fetched in parallel. Also fetch the super-repository,
+because `git-fetch' does not support not doing that. With a
+prefix argument fetch all remotes."
+ (interactive "P")
+ (magit-with-toplevel
+ (magit-run-git-async
+ "fetch" "--verbose" "--recurse-submodules"
+ (and magit-fetch-modules-jobs
+ (version<= "2.8.0" (magit-git-version))
+ (list "-j" (number-to-string magit-fetch-modules-jobs)))
+ (and all "--all"))))
+
+;;; _
+(provide 'magit-fetch)
+;;; magit-fetch.el ends here
--- /dev/null
+;;; magit-files.el --- finding files -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements support for finding blobs, staged files,
+;; and Git configuration files. It also implements modes useful in
+;; buffers visiting files and blobs, and the commands used by those
+;; modes.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Find Blob
+
+(defvar magit-find-file-hook nil)
+(add-hook 'magit-find-file-hook #'magit-blob-mode)
+
+;;;###autoload
+(defun magit-find-file (rev file)
+ "View FILE from REV.
+Switch to a buffer visiting blob REV:FILE, creating one if none
+already exists. If prior to calling this command the current
+buffer and/or cursor position is about the same file, then go
+to the line and column corresponding to that location."
+ (interactive (magit-find-file-read-args "Find file"))
+ (magit-find-file--internal rev file #'pop-to-buffer-same-window))
+
+;;;###autoload
+(defun magit-find-file-other-window (rev file)
+ "View FILE from REV, in another window.
+Switch to a buffer visiting blob REV:FILE, creating one if none
+already exists. If prior to calling this command the current
+buffer and/or cursor position is about the same file, then go to
+the line and column corresponding to that location."
+ (interactive (magit-find-file-read-args "Find file in other window"))
+ (magit-find-file--internal rev file #'switch-to-buffer-other-window))
+
+;;;###autoload
+(defun magit-find-file-other-frame (rev file)
+ "View FILE from REV, in another frame.
+Switch to a buffer visiting blob REV:FILE, creating one if none
+already exists. If prior to calling this command the current
+buffer and/or cursor position is about the same file, then go to
+the line and column corresponding to that location."
+ (interactive (magit-find-file-read-args "Find file in other frame"))
+ (magit-find-file--internal rev file #'switch-to-buffer-other-frame))
+
+(defun magit-find-file-read-args (prompt)
+ (let ((pseudo-revs '("{worktree}" "{index}")))
+ (if-let ((rev (magit-completing-read "Find file from revision"
+ (append pseudo-revs
+ (magit-list-refnames nil t))
+ nil nil nil 'magit-revision-history
+ (or (magit-branch-or-commit-at-point)
+ (magit-get-current-branch)))))
+ (list rev (magit-read-file-from-rev (if (member rev pseudo-revs)
+ "HEAD"
+ rev)
+ prompt))
+ (user-error "Nothing selected"))))
+
+(defun magit-find-file--internal (rev file fn)
+ (let ((buf (magit-find-file-noselect rev file))
+ line col)
+ (when-let ((visited-file (magit-file-relative-name)))
+ (setq line (line-number-at-pos))
+ (setq col (current-column))
+ (cond
+ ((not (equal visited-file file)))
+ ((equal magit-buffer-revision rev))
+ ((equal rev "{worktree}")
+ (setq line (magit-diff-visit--offset file magit-buffer-revision line)))
+ ((equal rev "{index}")
+ (setq line (magit-diff-visit--offset file nil line)))
+ (magit-buffer-revision
+ (setq line (magit-diff-visit--offset
+ file (concat magit-buffer-revision ".." rev) line)))
+ (t
+ (setq line (magit-diff-visit--offset file (list "-R" rev) line)))))
+ (funcall fn buf)
+ (when line
+ (with-current-buffer buf
+ (widen)
+ (goto-char (point-min))
+ (forward-line (1- line))
+ (move-to-column col)))
+ buf))
+
+(defun magit-find-file-noselect (rev file)
+ "Read FILE from REV into a buffer and return the buffer.
+REV is a revision or one of \"{worktree}\" or \"{index}\".
+FILE must be relative to the top directory of the repository."
+ (magit-find-file-noselect-1 rev file))
+
+(defun magit-find-file-noselect-1 (rev file &optional revert)
+ "Read FILE from REV into a buffer and return the buffer.
+REV is a revision or one of \"{worktree}\" or \"{index}\".
+FILE must be relative to the top directory of the repository.
+Non-nil REVERT means to revert the buffer. If `ask-revert',
+then only after asking. A non-nil value for REVERT is ignored if REV is
+\"{worktree}\"."
+ (if (equal rev "{worktree}")
+ (find-file-noselect (expand-file-name file (magit-toplevel)))
+ (let ((topdir (magit-toplevel)))
+ (when (file-name-absolute-p file)
+ (setq file (file-relative-name file topdir)))
+ (with-current-buffer (magit-get-revision-buffer-create rev file)
+ (when (or (not magit-buffer-file-name)
+ (if (eq revert 'ask-revert)
+ (y-or-n-p (format "%s already exists; revert it? "
+ (buffer-name))))
+ revert)
+ (setq magit-buffer-revision
+ (if (equal rev "{index}")
+ "{index}"
+ (magit-rev-format "%H" rev)))
+ (setq magit-buffer-refname rev)
+ (setq magit-buffer-file-name (expand-file-name file topdir))
+ (setq default-directory
+ (let ((dir (file-name-directory magit-buffer-file-name)))
+ (if (file-exists-p dir) dir topdir)))
+ (setq-local revert-buffer-function #'magit-revert-rev-file-buffer)
+ (revert-buffer t t)
+ (run-hooks (if (equal rev "{index}")
+ 'magit-find-index-hook
+ 'magit-find-file-hook)))
+ (current-buffer)))))
+
+(defun magit-get-revision-buffer-create (rev file)
+ (magit-get-revision-buffer rev file t))
+
+(defun magit-get-revision-buffer (rev file &optional create)
+ (funcall (if create 'get-buffer-create 'get-buffer)
+ (format "%s.~%s~" file (subst-char-in-string ?/ ?_ rev))))
+
+(defun magit-revert-rev-file-buffer (_ignore-auto noconfirm)
+ (when (or noconfirm
+ (and (not (buffer-modified-p))
+ (catch 'found
+ (dolist (regexp revert-without-query)
+ (when (string-match regexp magit-buffer-file-name)
+ (throw 'found t)))))
+ (yes-or-no-p (format "Revert buffer from Git %s? "
+ (if (equal magit-buffer-refname "{index}")
+ "index"
+ (concat "revision " magit-buffer-refname)))))
+ (let* ((inhibit-read-only t)
+ (default-directory (magit-toplevel))
+ (file (file-relative-name magit-buffer-file-name))
+ (coding-system-for-read (or coding-system-for-read 'undecided)))
+ (erase-buffer)
+ (magit-git-insert "cat-file" "-p"
+ (if (equal magit-buffer-refname "{index}")
+ (concat ":" file)
+ (concat magit-buffer-refname ":" file)))
+ (setq buffer-file-coding-system last-coding-system-used))
+ (let ((buffer-file-name magit-buffer-file-name)
+ (after-change-major-mode-hook
+ (remq 'global-diff-hl-mode-enable-in-buffers
+ after-change-major-mode-hook)))
+ (normal-mode t))
+ (setq buffer-read-only t)
+ (set-buffer-modified-p nil)
+ (goto-char (point-min))))
+
+;;; Find Index
+
+(defvar magit-find-index-hook nil)
+
+(defun magit-find-file-index-noselect (file &optional revert)
+ "Read FILE from the index into a buffer and return the buffer.
+FILE must to be relative to the top directory of the repository."
+ (magit-find-file-noselect-1 "{index}" file (or revert 'ask-revert)))
+
+(defun magit-update-index ()
+ "Update the index with the contents of the current buffer.
+The current buffer has to be visiting a file in the index, which
+is done using `magit-find-index-noselect'."
+ (interactive)
+ (let ((file (magit-file-relative-name)))
+ (unless (equal magit-buffer-refname "{index}")
+ (user-error "%s isn't visiting the index" file))
+ (if (y-or-n-p (format "Update index with contents of %s" (buffer-name)))
+ (let ((index (make-temp-file "index"))
+ (buffer (current-buffer)))
+ (when magit-wip-before-change-mode
+ (magit-wip-commit-before-change (list file) " before un-/stage"))
+ (let ((coding-system-for-write buffer-file-coding-system))
+ (with-temp-file index
+ (insert-buffer-substring buffer)))
+ (magit-with-toplevel
+ (magit-call-git "update-index" "--cacheinfo"
+ (substring (magit-git-string "ls-files" "-s" file)
+ 0 6)
+ (magit-git-string "hash-object" "-t" "blob" "-w"
+ (concat "--path=" file)
+ "--" index)
+ file))
+ (set-buffer-modified-p nil)
+ (when magit-wip-after-apply-mode
+ (magit-wip-commit-after-apply (list file) " after un-/stage")))
+ (message "Abort")))
+ (--when-let (magit-get-mode-buffer 'magit-status-mode)
+ (with-current-buffer it (magit-refresh)))
+ t)
+
+;;; Find Config File
+
+(defun magit-find-git-config-file (filename &optional wildcards)
+ "Edit a file located in the current repository's git directory.
+
+When \".git\", located at the root of the working tree, is a
+regular file, then that makes it cumbersome to open a file
+located in the actual git directory.
+
+This command is like `find-file', except that it temporarily
+binds `default-directory' to the actual git directory, while
+reading the FILENAME."
+ (interactive
+ (let ((default-directory (magit-git-dir)))
+ (find-file-read-args "Find file: "
+ (confirm-nonexistent-file-or-buffer))))
+ (find-file filename wildcards))
+
+(defun magit-find-git-config-file-other-window (filename &optional wildcards)
+ "Edit a file located in the current repository's git directory, in another window.
+
+When \".git\", located at the root of the working tree, is a
+regular file, then that makes it cumbersome to open a file
+located in the actual git directory.
+
+This command is like `find-file-other-window', except that it
+temporarily binds `default-directory' to the actual git
+directory, while reading the FILENAME."
+ (interactive
+ (let ((default-directory (magit-git-dir)))
+ (find-file-read-args "Find file in other window: "
+ (confirm-nonexistent-file-or-buffer))))
+ (find-file-other-window filename wildcards))
+
+(defun magit-find-git-config-file-other-frame (filename &optional wildcards)
+ "Edit a file located in the current repository's git directory, in another frame.
+
+When \".git\", located at the root of the working tree, is a
+regular file, then that makes it cumbersome to open a file
+located in the actual git directory.
+
+This command is like `find-file-other-frame', except that it
+temporarily binds `default-directory' to the actual git
+directory, while reading the FILENAME."
+ (interactive
+ (let ((default-directory (magit-git-dir)))
+ (find-file-read-args "Find file in other frame: "
+ (confirm-nonexistent-file-or-buffer))))
+ (find-file-other-frame filename wildcards))
+
+;;; File Dispatch
+
+;;;###autoload (autoload 'magit-file-dispatch "magit" nil t)
+(transient-define-prefix magit-file-dispatch ()
+ "Invoke a Magit command that acts on the visited file.
+When invoked outside a file-visiting buffer, then fall back
+to `magit-dispatch'."
+ :info-manual "(magit) Minor Mode for Buffers Visiting Files"
+ ["Actions"
+ [("s" "Stage" magit-stage-file)
+ ("u" "Unstage" magit-unstage-file)
+ ("c" "Commit" magit-commit)
+ ("e" "Edit line" magit-edit-line-commit)]
+ [("D" "Diff..." magit-diff)
+ ("d" "Diff" magit-diff-buffer-file)
+ ("g" "Status" magit-status-here)]
+ [("L" "Log..." magit-log)
+ ("l" "Log" magit-log-buffer-file)
+ ("t" "Trace" magit-log-trace-definition)]
+ [("B" "Blame..." magit-blame)
+ ("b" "Blame" magit-blame-addition)
+ ("r" "...removal" magit-blame-removal)
+ ("f" "...reverse" magit-blame-reverse)
+ ("m" "Blame echo" magit-blame-echo)
+ ("q" "Quit blame" magit-blame-quit)]
+ [("p" "Prev blob" magit-blob-previous)
+ ("n" "Next blob" magit-blob-next)
+ ("v" "Goto blob" magit-find-file)
+ ("V" "Goto file" magit-blob-visit-file)]
+ [(5 "C-c r" "Rename file" magit-file-rename)
+ (5 "C-c d" "Delete file" magit-file-delete)
+ (5 "C-c u" "Untrack file" magit-file-untrack)
+ (5 "C-c c" "Checkout file" magit-file-checkout)]]
+ (interactive)
+ (transient-setup
+ (if (or buffer-file-name magit-buffer-file-name)
+ 'magit-file-dispatch
+ 'magit-dispatch)))
+
+;;; Blob Mode
+
+(defvar magit-blob-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "p" 'magit-blob-previous)
+ (define-key map "n" 'magit-blob-next)
+ (define-key map "b" 'magit-blame-addition)
+ (define-key map "r" 'magit-blame-removal)
+ (define-key map "f" 'magit-blame-reverse)
+ (define-key map "q" 'magit-kill-this-buffer)
+ map)
+ "Keymap for `magit-blob-mode'.")
+
+(define-minor-mode magit-blob-mode
+ "Enable some Magit features in blob-visiting buffers.
+
+Currently this only adds the following key bindings.
+\n\\{magit-blob-mode-map}"
+ :package-version '(magit . "2.3.0"))
+
+(defun magit-blob-next ()
+ "Visit the next blob which modified the current file."
+ (interactive)
+ (if magit-buffer-file-name
+ (magit-blob-visit (or (magit-blob-successor magit-buffer-revision
+ magit-buffer-file-name)
+ magit-buffer-file-name))
+ (if (buffer-file-name (buffer-base-buffer))
+ (user-error "You have reached the end of time")
+ (user-error "Buffer isn't visiting a file or blob"))))
+
+(defun magit-blob-previous ()
+ "Visit the previous blob which modified the current file."
+ (interactive)
+ (if-let ((file (or magit-buffer-file-name
+ (buffer-file-name (buffer-base-buffer)))))
+ (--if-let (magit-blob-ancestor magit-buffer-revision file)
+ (magit-blob-visit it)
+ (user-error "You have reached the beginning of time"))
+ (user-error "Buffer isn't visiting a file or blob")))
+
+;;;###autoload
+(defun magit-blob-visit-file ()
+ "View the file from the worktree corresponding to the current blob.
+When visiting a blob or the version from the index, then go to
+the same location in the respective file in the working tree."
+ (interactive)
+ (if-let ((file (magit-file-relative-name)))
+ (magit-find-file--internal "{worktree}" file #'pop-to-buffer-same-window)
+ (user-error "Not visiting a blob")))
+
+(defun magit-blob-visit (blob-or-file)
+ (if (stringp blob-or-file)
+ (find-file blob-or-file)
+ (pcase-let ((`(,rev ,file) blob-or-file))
+ (magit-find-file rev file)
+ (apply #'message "%s (%s %s ago)"
+ (magit-rev-format "%s" rev)
+ (magit--age (magit-rev-format "%ct" rev))))))
+
+(defun magit-blob-ancestor (rev file)
+ (let ((lines (magit-with-toplevel
+ (magit-git-lines "log" "-2" "--format=%H" "--name-only"
+ "--follow" (or rev "HEAD") "--" file))))
+ (if rev (cddr lines) (butlast lines 2))))
+
+(defun magit-blob-successor (rev file)
+ (let ((lines (magit-with-toplevel
+ (magit-git-lines "log" "--format=%H" "--name-only" "--follow"
+ "HEAD" "--" file))))
+ (catch 'found
+ (while lines
+ (if (equal (nth 2 lines) rev)
+ (throw 'found (list (nth 0 lines) (nth 1 lines)))
+ (setq lines (nthcdr 2 lines)))))))
+
+;;; File Commands
+
+(defun magit-file-rename (file newname)
+ "Rename or move FILE to NEWNAME.
+NEWNAME may be a file or directory name. If FILE isn't tracked in
+Git, fallback to using `rename-file'."
+ (interactive
+ (let* ((file (magit-read-file "Rename file"))
+ (dir (file-name-directory file))
+ (newname (read-file-name (format "Move %s to destination: " file)
+ (and dir (expand-file-name dir)))))
+ (list (expand-file-name file (magit-toplevel))
+ (expand-file-name newname))))
+ (let ((oldbuf (get-file-buffer file))
+ (dstdir (file-name-directory newname))
+ (dstfile (if (directory-name-p newname)
+ (concat newname (file-name-nondirectory file))
+ newname)))
+ (when (and oldbuf (buffer-modified-p oldbuf))
+ (user-error "Save %s before moving it" file))
+ (when (file-exists-p dstfile)
+ (user-error "%s already exists" dstfile))
+ (unless (file-exists-p dstdir)
+ (user-error "Destination directory %s does not exist" dstdir))
+ (if (magit-file-tracked-p (magit-convert-filename-for-git file))
+ (magit-call-git "mv"
+ (magit-convert-filename-for-git file)
+ (magit-convert-filename-for-git newname))
+ (rename-file file newname current-prefix-arg))
+ (when oldbuf
+ (with-current-buffer oldbuf
+ (let ((buffer-read-only buffer-read-only))
+ (set-visited-file-name dstfile nil t))
+ (if (fboundp 'vc-refresh-state)
+ (vc-refresh-state)
+ (with-no-warnings
+ (vc-find-file-hook))))))
+ (magit-refresh))
+
+(defun magit-file-untrack (files &optional force)
+ "Untrack the selected FILES or one file read in the minibuffer.
+
+With a prefix argument FORCE do so even when the files have
+staged as well as unstaged changes."
+ (interactive (list (or (--if-let (magit-region-values 'file t)
+ (progn
+ (unless (magit-file-tracked-p (car it))
+ (user-error "Already untracked"))
+ (magit-confirm-files 'untrack it "Untrack"))
+ (list (magit-read-tracked-file "Untrack file"))))
+ current-prefix-arg))
+ (magit-with-toplevel
+ (magit-run-git "rm" "--cached" (and force "--force") "--" files)))
+
+(defun magit-file-delete (files &optional force)
+ "Delete the selected FILES or one file read in the minibuffer.
+
+With a prefix argument FORCE do so even when the files have
+uncommitted changes. When the files aren't being tracked in
+Git, then fallback to using `delete-file'."
+ (interactive (list (--if-let (magit-region-values 'file t)
+ (magit-confirm-files 'delete it "Delete")
+ (list (magit-read-file "Delete file")))
+ current-prefix-arg))
+ (if (magit-file-tracked-p (car files))
+ (magit-call-git "rm" (and force "--force") "--" files)
+ (let ((topdir (magit-toplevel)))
+ (dolist (file files)
+ (delete-file (expand-file-name file topdir) t))))
+ (magit-refresh))
+
+;;;###autoload
+(defun magit-file-checkout (rev file)
+ "Checkout FILE from REV."
+ (interactive
+ (let ((rev (magit-read-branch-or-commit
+ "Checkout from revision" magit-buffer-revision)))
+ (list rev (magit-read-file-from-rev rev "Checkout file"))))
+ (magit-with-toplevel
+ (magit-run-git "checkout" rev "--" file)))
+
+;;; Read File
+
+(defvar magit-read-file-hist nil)
+
+(defun magit-read-file-from-rev (rev prompt &optional default)
+ (let ((files (magit-revision-files rev)))
+ (magit-completing-read
+ prompt files nil t nil 'magit-read-file-hist
+ (car (member (or default (magit-current-file)) files)))))
+
+(defun magit-read-file (prompt &optional tracked-only)
+ (let ((choices (nconc (magit-list-files)
+ (unless tracked-only (magit-untracked-files)))))
+ (magit-completing-read
+ prompt choices nil t nil nil
+ (car (member (or (magit-section-value-if '(file submodule))
+ (magit-file-relative-name nil tracked-only))
+ choices)))))
+
+(defun magit-read-tracked-file (prompt)
+ (magit-read-file prompt t))
+
+(defun magit-read-file-choice (prompt files &optional error default)
+ "Read file from FILES.
+
+If FILES has only one member, return that instead of prompting.
+If FILES has no members, give a user error. ERROR can be given
+to provide a more informative error.
+
+If DEFAULT is non-nil, use this as the default value instead of
+`magit-current-file'."
+ (pcase (length files)
+ (0 (user-error (or error "No file choices")))
+ (1 (car files))
+ (_ (magit-completing-read
+ prompt files nil t nil 'magit-read-file-hist
+ (car (member (or default (magit-current-file)) files))))))
+
+(defun magit-read-changed-file (rev-or-range prompt &optional default)
+ (magit-read-file-choice
+ prompt
+ (magit-changed-files rev-or-range)
+ default
+ (concat "No file changed in " rev-or-range)))
+
+;;; _
+(provide 'magit-files)
+;;; magit-files.el ends here
--- /dev/null
+;;; magit-git.el --- Git functionality -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements wrappers for various Git plumbing commands.
+
+;;; Code:
+
+(require 'magit-utils)
+(require 'magit-section)
+
+;; From `magit-branch'.
+(defvar magit-branch-prefer-remote-upstream)
+(defvar magit-published-branches)
+
+;; From `magit-margin'.
+(declare-function magit-maybe-make-margin-overlay "magit-margin" ())
+
+;; From `magit-mode'.
+(declare-function magit-get-mode-buffer "magit-mode"
+ (mode &optional value frame))
+(declare-function magit-refresh "magit-mode" ())
+(defvar magit-buffer-diff-args)
+(defvar magit-buffer-file-name)
+(defvar magit-buffer-log-args)
+(defvar magit-buffer-log-files)
+(defvar magit-buffer-refname)
+(defvar magit-buffer-revision)
+
+;; From `magit-process'.
+(declare-function magit-call-git "magit-process" (&rest args))
+(declare-function magit-process-buffer "magit-process" (&optional nodisplay))
+(declare-function magit-process-file "magit-process" (&rest args))
+(declare-function magit-process-insert-section "magit-process"
+ (pwd program args &optional errcode errlog))
+(defvar magit-this-error)
+(defvar magit-process-error-message-regexps)
+
+;; From later in `magit-git'.
+(defvar magit-tramp-process-environment nil)
+
+(eval-when-compile
+ (cl-pushnew 'number eieio--known-slot-names))
+
+;;; Git implementations
+
+(defvar magit-inhibit-libgit nil
+ "Whether to inhibit the use of libgit.")
+
+(defvar magit--libgit-available-p eieio-unbound
+ "Whether libgit is available.
+Use the function by the same name instead of this variable.")
+
+(defun magit--libgit-available-p ()
+ (if (eq magit--libgit-available-p eieio-unbound)
+ (setq magit--libgit-available-p
+ (and module-file-suffix
+ (let ((libgit (locate-library "libgit")))
+ (and libgit
+ (or (locate-library "libegit2")
+ (let ((load-path
+ (cons (expand-file-name
+ (convert-standard-filename "build")
+ (file-name-directory libgit))
+ load-path)))
+ (locate-library "libegit2")))))))
+ magit--libgit-available-p))
+
+(defun magit-gitimpl ()
+ "Return the Git implementation used in this repository."
+ (if (and (not magit-inhibit-libgit)
+ (not (file-remote-p default-directory))
+ (magit--libgit-available-p))
+ 'libgit
+ 'git))
+
+;;; Options
+
+;; For now this is shared between `magit-process' and `magit-git'.
+(defgroup magit-process nil
+ "Git and other external processes used by Magit."
+ :group 'magit)
+
+(defvar magit-git-environment
+ (list (format "INSIDE_EMACS=%s,magit" emacs-version))
+ "Prepended to `process-environment' while running git.")
+
+(defcustom magit-git-output-coding-system
+ (and (eq system-type 'windows-nt) 'utf-8)
+ "Coding system for receiving output from Git.
+
+If non-nil, the Git config value `i18n.logOutputEncoding' should
+be set via `magit-git-global-arguments' to value consistent with
+this."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-process
+ :type '(choice (coding-system :tag "Coding system to decode Git output")
+ (const :tag "Use system default" nil)))
+
+(defvar magit-git-w32-path-hack nil
+ "Alist of (EXE . (PATHENTRY)).
+This specifies what additional PATH setting needs to be added to
+the environment in order to run the non-wrapper git executables
+successfully.")
+
+(defcustom magit-git-executable
+ ;; Git might be installed in a different location on a remote, so
+ ;; it is better not to use the full path to the executable, except
+ ;; on Window where we would otherwise end up using one of the
+ ;; wrappers "cmd/git.exe" or "cmd/git.cmd", which are much slower
+ ;; than using "bin/git.exe" directly.
+ (or (and (eq system-type 'windows-nt)
+ (--when-let (executable-find "git")
+ (ignore-errors
+ ;; Git for Windows 2.x provides cygpath so we can
+ ;; ask it for native paths.
+ (let* ((core-exe
+ (car
+ (process-lines
+ it "-c"
+ "alias.X=!x() { which \"$1\" | cygpath -mf -; }; x"
+ "X" "git")))
+ (hack-entry (assoc core-exe magit-git-w32-path-hack))
+ ;; Running the libexec/git-core executable
+ ;; requires some extra PATH entries.
+ (path-hack
+ (list (concat "PATH="
+ (car (process-lines
+ it "-c"
+ "alias.P=!cygpath -wp \"$PATH\""
+ "P"))))))
+ ;; The defcustom STANDARD expression can be
+ ;; evaluated many times, so make sure it is
+ ;; idempotent.
+ (if hack-entry
+ (setcdr hack-entry path-hack)
+ (push (cons core-exe path-hack) magit-git-w32-path-hack))
+ core-exe))))
+ "git")
+ "The Git executable used by Magit."
+ :group 'magit-process
+ :type 'string)
+
+(defcustom magit-git-global-arguments
+ `("--no-pager" "--literal-pathspecs"
+ "-c" "core.preloadindex=true"
+ "-c" "log.showSignature=false"
+ "-c" "color.ui=false"
+ "-c" "color.diff=false"
+ ,@(and (eq system-type 'windows-nt)
+ (list "-c" "i18n.logOutputEncoding=UTF-8")))
+ "Global Git arguments.
+
+The arguments set here are used every time the git executable is
+run as a subprocess. They are placed right after the executable
+itself and before the git command - as in `git HERE... COMMAND
+REST'. See the manpage `git(1)' for valid arguments.
+
+Be careful what you add here, especially if you are using Tramp
+to connect to servers with ancient Git versions. Never remove
+anything that is part of the default value, unless you really
+know what you are doing. And think very hard before adding
+something; it will be used every time Magit runs Git for any
+purpose."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-commands
+ :group 'magit-process
+ :type '(repeat string))
+
+(defvar magit-git-debug nil
+ "Whether to enable additional reporting of git errors.
+
+Magit basically calls git for one of these two reasons: for
+side-effects or to do something with its standard output.
+
+When git is run for side-effects then its output, including error
+messages, go into the process buffer which is shown when using \
+\\<magit-status-mode-map>\\[magit-process].
+
+When git's output is consumed in some way, then it would be too
+expensive to also insert it into this buffer, but when this
+option is non-nil and git returns with a non-zero exit status,
+then at least its standard error is inserted into this buffer.
+
+This is only intended for debugging purposes. Do not enable this
+permanently, that would negatively affect performance.")
+
+
+(defcustom magit-prefer-remote-upstream nil
+ "Whether to favor remote branches when reading the upstream branch.
+
+This controls whether commands that read a branch from the user
+and then set it as the upstream branch, offer a local or a remote
+branch as default completion candidate, when they have the choice.
+
+This affects all commands that use `magit-read-upstream-branch'
+or `magit-read-starting-point', which includes most commands
+that change the upstream and many that create new branches."
+ :package-version '(magit . "2.4.2")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-list-refs-sortby nil
+ "How to sort the ref collection in the prompt.
+
+This affects commands that read a ref. More specifically, it
+controls the order of refs returned by `magit-list-refs', which
+is called by functions like `magit-list-branch-names' to generate
+the collection of refs. By default, refs are sorted according to
+their full refname (i.e., 'refs/...').
+
+Any value accepted by the `--sort' flag of `git for-each-ref' can
+be used. For example, \"-creatordate\" places refs with more
+recent committer or tagger dates earlier in the list. A list of
+strings can also be given in order to pass multiple sort keys to
+`git for-each-ref'.
+
+Note that, depending on the completion framework you use, this
+may not be sufficient to change the order in which the refs are
+displayed. It only controls the order of the collection passed
+to `magit-completing-read' or, for commands that support reading
+multiple strings, `read-from-minibuffer'. The completion
+framework ultimately determines how the collection is displayed."
+ :package-version '(magit . "2.11.0")
+ :group 'magit-miscellaneous
+ :type '(choice string (repeat string)))
+
+;;; Git
+
+(defvar magit--refresh-cache nil)
+
+(defmacro magit--with-refresh-cache (key &rest body)
+ (declare (indent 1) (debug (form body)))
+ (let ((k (cl-gensym)))
+ `(if magit--refresh-cache
+ (let ((,k ,key))
+ (--if-let (assoc ,k (cdr magit--refresh-cache))
+ (progn (cl-incf (caar magit--refresh-cache))
+ (cdr it))
+ (cl-incf (cdar magit--refresh-cache))
+ (let ((value ,(macroexp-progn body)))
+ (push (cons ,k value)
+ (cdr magit--refresh-cache))
+ value)))
+ ,@body)))
+
+(defvar magit-with-editor-envvar "GIT_EDITOR"
+ "The environment variable exported by `magit-with-editor'.
+Set this to \"GIT_SEQUENCE_EDITOR\" if you do not want to use
+Emacs to edit commit messages but would like to do so to edit
+rebase sequences.")
+
+(defmacro magit-with-editor (&rest body)
+ "Like `with-editor' but let-bind some more variables.
+Also respect the value of `magit-with-editor-envvar'."
+ (declare (indent 0) (debug (body)))
+ `(let ((magit-process-popup-time -1)
+ ;; The user may have customized `shell-file-name' to
+ ;; something which results in `w32-shell-dos-semantics' nil
+ ;; (which changes the quoting style used by
+ ;; `shell-quote-argument'), but Git for Windows expects shell
+ ;; quoting in the dos style.
+ (shell-file-name (if (and (eq system-type 'windows-nt)
+ ;; If we have Cygwin mount points,
+ ;; the git flavor is cygwin, so dos
+ ;; shell quoting is probably wrong.
+ (not magit-cygwin-mount-points))
+ "cmdproxy"
+ shell-file-name)))
+ (with-editor* magit-with-editor-envvar
+ ,@body)))
+
+(defmacro magit--with-temp-process-buffer (&rest body)
+ "Like `with-temp-buffer', but always propagate `process-environment'.
+When that var is buffer-local in the calling buffer, it is not
+propagated by `with-temp-buffer', so we explicitly ensure that
+happens, so that processes will be invoked consistently. BODY is
+as for that macro."
+ (declare (indent 0) (debug (body)))
+ (let ((p (cl-gensym)))
+ `(let ((,p process-environment))
+ (with-temp-buffer
+ (setq-local process-environment ,p)
+ ,@body))))
+
+(defun magit-process-git-arguments (args)
+ "Prepare ARGS for a function that invokes Git.
+
+Magit has many specialized functions for running Git; they all
+pass arguments through this function before handing them to Git,
+to do the following.
+
+* Flatten ARGS, removing nil arguments.
+* Prepend `magit-git-global-arguments' to ARGS.
+* On w32 systems, encode to `w32-ansi-code-page'."
+ (setq args (append magit-git-global-arguments (-flatten args)))
+ (if (and (eq system-type 'windows-nt) (boundp 'w32-ansi-code-page))
+ ;; On w32, the process arguments *must* be encoded in the
+ ;; current code-page (see #3250).
+ (mapcar (lambda (arg)
+ (encode-coding-string
+ arg (intern (format "cp%d" w32-ansi-code-page))))
+ args)
+ args))
+
+(defun magit-git-exit-code (&rest args)
+ "Execute Git with ARGS, returning its exit code."
+ (apply #'magit-process-file magit-git-executable nil nil nil
+ (magit-process-git-arguments 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 (apply #'magit-process-file magit-git-executable nil t nil
+ (magit-process-git-arguments 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 (apply #'magit-process-file magit-git-executable
+ nil t nil args)))
+ (if (zerop status)
+ (and (not (bobp))
+ (progn
+ (goto-char (point-min))
+ (buffer-substring-no-properties
+ (point) (line-end-position))))
+ (let ((buf (current-buffer)))
+ (with-current-buffer (magit-process-buffer t)
+ (magit-process-insert-section default-directory
+ magit-git-executable args
+ status buf)))
+ (when-let ((status-buf (magit-get-mode-buffer 'magit-status-mode)))
+ (let ((msg (magit--locate-error-message)))
+ (with-current-buffer status-buf
+ (setq magit-this-error msg))))
+ nil)))))
+
+(defun magit-git-str (&rest args)
+ "Execute Git with ARGS, returning the first line of its output.
+If there is no output, return nil. If the output begins with a
+newline, return an empty string. Like `magit-git-string' but
+ignore `magit-git-debug'."
+ (setq args (-flatten args))
+ (magit--with-refresh-cache (cons default-directory args)
+ (magit--with-temp-process-buffer
+ (apply #'magit-process-file magit-git-executable nil (list t nil) nil
+ (magit-process-git-arguments args))
+ (unless (bobp)
+ (goto-char (point-min))
+ (buffer-substring-no-properties (point) (line-end-position))))))
+
+(defun magit-git-output (&rest args)
+ "Execute Git with ARGS, returning its output."
+ (setq args (-flatten args))
+ (magit--with-refresh-cache (cons default-directory args)
+ (magit--with-temp-process-buffer
+ (apply #'magit-process-file magit-git-executable nil (list t nil) nil
+ (magit-process-git-arguments 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 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 output))))
+
+(defun magit-git-insert (&rest args)
+ "Execute Git with ARGS, inserting its output at point.
+If Git exits with a non-zero exit status, then show a message and
+add a section in the respective process buffer."
+ (setq args (magit-process-git-arguments args))
+ (if magit-git-debug
+ (let (log)
+ (unwind-protect
+ (progn
+ (setq log (make-temp-file "magit-stderr"))
+ (delete-file log)
+ (let ((exit (apply #'magit-process-file magit-git-executable
+ nil (list t log) nil args)))
+ (when (> exit 0)
+ (let ((msg "Git failed"))
+ (when (file-exists-p log)
+ (setq msg (with-temp-buffer
+ (insert-file-contents log)
+ (goto-char (point-max))
+ (if (functionp magit-git-debug)
+ (funcall magit-git-debug (buffer-string))
+ (magit--locate-error-message))))
+ (let ((magit-git-debug nil))
+ (with-current-buffer (magit-process-buffer t)
+ (magit-process-insert-section default-directory
+ magit-git-executable
+ args exit log))))
+ (message "%s" msg)))
+ exit))
+ (ignore-errors (delete-file log))))
+ (apply #'magit-process-file magit-git-executable
+ nil (list t nil) nil args)))
+
+(defun magit--locate-error-message ()
+ (goto-char (point-max))
+ (and (run-hook-wrapped 'magit-process-error-message-regexps
+ (lambda (re) (re-search-backward re nil t)))
+ (match-string-no-properties 1)))
+
+(defun magit-git-string (&rest args)
+ "Execute Git with ARGS, returning the first line of its output.
+If there is no output, return nil. If the output begins with a
+newline, return an empty string."
+ (setq args (-flatten args))
+ (magit--with-refresh-cache (cons default-directory args)
+ (magit--with-temp-process-buffer
+ (apply #'magit-git-insert args)
+ (unless (bobp)
+ (goto-char (point-min))
+ (buffer-substring-no-properties (point) (line-end-position))))))
+
+(defun magit-git-lines (&rest args)
+ "Execute Git with ARGS, returning its output as a list of lines.
+Empty lines anywhere in the output are omitted.
+
+If Git exits with a non-zero exit status, then report show a
+message and add a section in the respective process buffer."
+ (magit--with-temp-process-buffer
+ (apply #'magit-git-insert args)
+ (split-string (buffer-string) "\n" t)))
+
+(defun magit-git-items (&rest args)
+ "Execute Git with ARGS, returning its null-separated output as a list.
+Empty items anywhere in the output are omitted.
+
+If Git exits with a non-zero exit status, then report show a
+message and add a section in the respective process buffer."
+ (magit--with-temp-process-buffer
+ (apply #'magit-git-insert args)
+ (split-string (buffer-string) "\0" t)))
+
+(defun magit-git-wash (washer &rest args)
+ "Execute Git with ARGS, inserting washed output at point.
+Actually first insert the raw output at point. If there is no
+output, call `magit-cancel-section'. Otherwise temporarily narrow
+the buffer to the inserted text, move to its beginning, and then
+call function WASHER with ARGS as its sole argument."
+ (declare (indent 1))
+ (let ((beg (point)))
+ (setq args (-flatten args))
+ (magit-git-insert args)
+ (if (= (point) beg)
+ (magit-cancel-section)
+ (unless (bolp)
+ (insert "\n"))
+ (save-restriction
+ (narrow-to-region beg (point))
+ (goto-char beg)
+ (funcall washer args))
+ (when (or (= (point) beg)
+ (= (point) (1+ beg)))
+ (magit-cancel-section))
+ (magit-maybe-make-margin-overlay))))
+
+(defun magit-git-version (&optional raw)
+ (--when-let (let (magit-git-global-arguments)
+ (ignore-errors (substring (magit-git-string "version") 12)))
+ (if raw it (and (string-match "\\`\\([0-9]+\\(\\.[0-9]+\\)\\{1,2\\}\\)" it)
+ (match-string 1 it)))))
+
+;;; Variables
+
+(defun magit-config-get-from-cached-list (key)
+ (gethash
+ ;; `git config --list' downcases first and last components of the key.
+ (--> key
+ (replace-regexp-in-string "\\`[^.]+" #'downcase it t t)
+ (replace-regexp-in-string "[^.]+\\'" #'downcase it t t))
+ (magit--with-refresh-cache (cons (magit-toplevel) 'config)
+ (let ((configs (make-hash-table :test 'equal)))
+ (dolist (conf (magit-git-items "config" "--list" "-z"))
+ (let* ((nl-pos (cl-position ?\n conf))
+ (key (substring conf 0 nl-pos))
+ (val (if nl-pos (substring conf (1+ nl-pos)) "")))
+ (puthash key (nconc (gethash key configs) (list val)) configs)))
+ configs))))
+
+(defun magit-get (&rest keys)
+ "Return the value of the Git variable specified by KEYS."
+ (car (last (apply 'magit-get-all keys))))
+
+(defun magit-get-all (&rest keys)
+ "Return all values of the Git variable specified by KEYS."
+ (let ((magit-git-debug nil)
+ (arg (and (or (null (car keys))
+ (string-prefix-p "--" (car keys)))
+ (pop keys)))
+ (key (mapconcat 'identity keys ".")))
+ (if (and magit--refresh-cache (not arg))
+ (magit-config-get-from-cached-list key)
+ (magit-git-items "config" arg "-z" "--get-all" key))))
+
+(defun magit-get-boolean (&rest keys)
+ "Return the boolean value of the Git variable specified by KEYS."
+ (let ((key (mapconcat 'identity keys ".")))
+ (if magit--refresh-cache
+ (equal "true" (car (last (magit-config-get-from-cached-list key))))
+ (equal (magit-git-str "config" "--bool" key) "true"))))
+
+(defun magit-set (value &rest keys)
+ "Set the value of the Git variable specified by KEYS to VALUE."
+ (let ((arg (and (or (null (car keys))
+ (string-prefix-p "--" (car keys)))
+ (pop keys)))
+ (key (mapconcat 'identity keys ".")))
+ (if value
+ (magit-git-success "config" arg key value)
+ (magit-git-success "config" arg "--unset" key))
+ value))
+
+(gv-define-setter magit-get (val &rest keys)
+ `(magit-set ,val ,@keys))
+
+(defun magit-set-all (values &rest keys)
+ "Set all values of the Git variable specified by KEYS to VALUES."
+ (let ((arg (and (or (null (car keys))
+ (string-prefix-p "--" (car keys)))
+ (pop keys)))
+ (var (mapconcat 'identity keys ".")))
+ (when (magit-get var)
+ (magit-call-git "config" arg "--unset-all" var))
+ (dolist (v values)
+ (magit-call-git "config" arg "--add" var v))))
+
+;;; Files
+
+(defun magit--safe-default-directory (&optional file)
+ (catch 'unsafe-default-dir
+ (let ((dir (file-name-as-directory
+ (expand-file-name (or file default-directory))))
+ (previous nil))
+ (while (not (magit-file-accessible-directory-p dir))
+ (setq dir (file-name-directory (directory-file-name dir)))
+ (when (equal dir previous)
+ (throw 'unsafe-default-dir nil))
+ (setq previous dir))
+ dir)))
+
+(defmacro magit--with-safe-default-directory (file &rest body)
+ (declare (indent 1) (debug (form body)))
+ `(when-let ((default-directory (magit--safe-default-directory ,file)))
+ ,@body))
+
+(defun magit-gitdir (&optional directory)
+ "Return the absolute and resolved path of the .git directory.
+
+If the `GIT_DIR' environment variable is define then return that.
+Otherwise return the .git directory for DIRECTORY, or if that is
+nil, then for `default-directory' instead. If the directory is
+not located inside a Git repository, then return nil."
+ (let ((default-directory (or directory default-directory)))
+ (magit-git-dir)))
+
+(defun magit-git-dir (&optional path)
+ "Return the absolute and resolved path of the .git directory.
+
+If the `GIT_DIR' environment variable is define then return that.
+Otherwise return the .git directory for `default-directory'. If
+the directory is not located inside a Git repository, then return
+nil."
+ (magit--with-refresh-cache (list default-directory 'magit-git-dir path)
+ (magit--with-safe-default-directory nil
+ (when-let ((dir (magit-rev-parse-safe "--git-dir")))
+ (setq dir (file-name-as-directory (magit-expand-git-file-name dir)))
+ (unless (file-remote-p dir)
+ (setq dir (concat (file-remote-p default-directory) dir)))
+ (if path (expand-file-name (convert-standard-filename path) dir) dir)))))
+
+(defvar magit--separated-gitdirs nil)
+
+(defun magit--record-separated-gitdir ()
+ (let ((topdir (magit-toplevel))
+ (gitdir (magit-git-dir)))
+ ;; Kludge: git-annex converts submodule gitdirs to symlinks. See #3599.
+ (when (file-symlink-p (directory-file-name gitdir))
+ (setq gitdir (file-truename gitdir)))
+ ;; We want to delete the entry for `topdir' here, rather than within
+ ;; (unless ...), in case a `--separate-git-dir' repository was switched to
+ ;; the standard structure (i.e., "topdir/.git/").
+ (setq magit--separated-gitdirs (cl-delete topdir
+ magit--separated-gitdirs
+ :key #'car :test #'equal))
+ (unless (equal (file-name-as-directory (expand-file-name ".git" topdir))
+ gitdir)
+ (push (cons topdir gitdir) magit--separated-gitdirs))))
+
+(defun magit-toplevel (&optional directory)
+ "Return the absolute path to the toplevel of the current repository.
+
+From within the working tree or control directory of a repository
+return the absolute path to the toplevel directory of the working
+tree. As a special case, from within a bare repository return
+the control directory instead. When called outside a repository
+then return nil.
+
+When optional DIRECTORY is non-nil then return the toplevel for
+that directory instead of the one for `default-directory'.
+
+Try to respect the option `find-file-visit-truename', i.e. when
+the value of that option is nil, then avoid needlessly returning
+the truename. When a symlink to a sub-directory of the working
+tree is involved, or when called from within a sub-directory of
+the gitdir or from the toplevel of a gitdir, which itself is not
+located within the working tree, then it is not possible to avoid
+returning the truename."
+ (magit--with-refresh-cache
+ (cons (or directory default-directory) 'magit-toplevel)
+ (magit--with-safe-default-directory directory
+ (if-let ((topdir (magit-rev-parse-safe "--show-toplevel")))
+ (let (updir)
+ (setq topdir (magit-expand-git-file-name topdir))
+ (if (and
+ ;; Always honor these settings.
+ (not find-file-visit-truename)
+ (not (getenv "GIT_WORK_TREE"))
+ ;; `--show-cdup' is the relative path to the toplevel
+ ;; from `(file-truename default-directory)'. Here we
+ ;; pretend it is relative to `default-directory', and
+ ;; go to that directory. Then we check whether
+ ;; `--show-toplevel' still returns the same value and
+ ;; whether `--show-cdup' now is the empty string. If
+ ;; both is the case, then we are at the toplevel of
+ ;; the same working tree, but also avoided needlessly
+ ;; following any symlinks.
+ (progn
+ (setq updir (file-name-as-directory
+ (magit-rev-parse-safe "--show-cdup")))
+ (setq updir (if (file-name-absolute-p updir)
+ (concat (file-remote-p default-directory) updir)
+ (expand-file-name updir)))
+ (let ((default-directory updir))
+ (and (string-equal (magit-rev-parse-safe "--show-cdup") "")
+ (--when-let (magit-rev-parse-safe "--show-toplevel")
+ (string-equal (magit-expand-git-file-name it)
+ topdir))))))
+ updir
+ (concat (file-remote-p default-directory)
+ (file-name-as-directory topdir))))
+ (when-let ((gitdir (magit-rev-parse-safe "--git-dir")))
+ (setq gitdir (file-name-as-directory
+ (if (file-name-absolute-p gitdir)
+ ;; We might have followed a symlink.
+ (concat (file-remote-p default-directory)
+ (magit-expand-git-file-name gitdir))
+ (expand-file-name gitdir))))
+ (if (magit-bare-repo-p)
+ gitdir
+ (let* ((link (expand-file-name "gitdir" gitdir))
+ (wtree (and (file-exists-p link)
+ (magit-file-line link))))
+ (cond
+ ((and wtree
+ ;; Ignore .git/gitdir files that result from a
+ ;; Git bug. See #2364.
+ (not (equal wtree ".git")))
+ ;; Return the linked working tree.
+ (concat (file-remote-p default-directory)
+ (file-name-directory wtree)))
+ ;; The working directory may not be the parent directory of
+ ;; .git if it was set up with `git init --separate-git-dir'.
+ ;; See #2955.
+ ((car (rassoc gitdir magit--separated-gitdirs)))
+ (t
+ ;; Step outside the control directory to enter the working tree.
+ (file-name-directory (directory-file-name gitdir)))))))))))
+
+(defmacro magit-with-toplevel (&rest body)
+ (declare (indent defun) (debug (body)))
+ (let ((toplevel (cl-gensym "toplevel")))
+ `(let ((,toplevel (magit-toplevel)))
+ (if ,toplevel
+ (let ((default-directory ,toplevel))
+ ,@body)
+ (magit--not-inside-repository-error)))))
+
+(define-error 'magit-outside-git-repo "Not inside Git repository")
+(define-error 'magit-git-executable-not-found
+ "Git executable cannot be found (see https://magit.vc/goto/e6a78ed2)")
+
+(defun magit--not-inside-repository-error ()
+ (if (executable-find magit-git-executable)
+ (signal 'magit-outside-git-repo default-directory)
+ (signal 'magit-git-executable-not-found magit-git-executable)))
+
+(defun magit-inside-gitdir-p (&optional noerror)
+ "Return t if `default-directory' is below the repository directory.
+If it is below the working directory, then return nil.
+If it isn't below either, then signal an error unless NOERROR
+is non-nil, in which case return nil."
+ (and (magit--assert-default-directory noerror)
+ ;; Below a repository directory that is not located below the
+ ;; working directory "git rev-parse --is-inside-git-dir" prints
+ ;; "false", which is wrong.
+ (let ((gitdir (magit-git-dir)))
+ (cond (gitdir (file-in-directory-p default-directory gitdir))
+ (noerror nil)
+ (t (signal 'magit-outside-git-repo default-directory))))))
+
+(defun magit-inside-worktree-p (&optional noerror)
+ "Return t if `default-directory' is below the working directory.
+If it is below the repository directory, then return nil.
+If it isn't below either, then signal an error unless NOERROR
+is non-nil, in which case return nil."
+ (and (magit--assert-default-directory noerror)
+ (condition-case nil
+ (magit-rev-parse-true "--is-inside-work-tree")
+ (magit-invalid-git-boolean
+ (and (not noerror)
+ (signal 'magit-outside-git-repo default-directory))))))
+
+(cl-defgeneric magit-bare-repo-p (&optional noerror)
+ "Return t if the current repository is bare.
+If it is non-bare, then return nil. If `default-directory'
+isn't below a Git repository, then signal an error unless
+NOERROR is non-nil, in which case return nil."
+ (and (magit--assert-default-directory noerror)
+ (condition-case nil
+ (magit-rev-parse-true "--is-bare-repository")
+ (magit-invalid-git-boolean
+ (and (not noerror)
+ (signal 'magit-outside-git-repo default-directory))))))
+
+(defun magit--assert-default-directory (&optional noerror)
+ (or (file-directory-p default-directory)
+ (and (not noerror)
+ (let ((exists (file-exists-p default-directory)))
+ (signal (if exists 'file-error 'file-missing)
+ (list "Running git in directory"
+ (if exists
+ "Not a directory"
+ "No such file or directory")
+ default-directory))))))
+
+(defun magit-git-repo-p (directory &optional non-bare)
+ "Return t if DIRECTORY is a Git repository.
+When optional NON-BARE is non-nil also return nil if DIRECTORY is
+a bare repository."
+ (and (file-directory-p directory) ; Avoid archives, see #3397.
+ (or (file-regular-p (expand-file-name ".git" directory))
+ (file-directory-p (expand-file-name ".git" directory))
+ (and (not non-bare)
+ (file-regular-p (expand-file-name "HEAD" directory))
+ (file-directory-p (expand-file-name "refs" directory))
+ (file-directory-p (expand-file-name "objects" directory))))))
+
+(defun magit-file-relative-name (&optional file tracked)
+ "Return the path of FILE relative to the repository root.
+
+If optional FILE is nil or omitted, return the relative path of
+the file being visited in the current buffer, if any, else nil.
+If the file is not inside a Git repository, then return nil.
+
+If TRACKED is non-nil, return the path only if it matches a
+tracked file."
+ (unless file
+ (with-current-buffer (or (buffer-base-buffer)
+ (current-buffer))
+ (setq file (or magit-buffer-file-name buffer-file-name
+ (and (derived-mode-p 'dired-mode) default-directory)))))
+ (when (and file (or (not tracked)
+ (magit-file-tracked-p (file-relative-name file))))
+ (--when-let (magit-toplevel
+ (magit--safe-default-directory
+ (directory-file-name (file-name-directory file))))
+ (file-relative-name file it))))
+
+(defun magit-file-tracked-p (file)
+ (magit-git-success "ls-files" "--error-unmatch" file))
+
+(defun magit-list-files (&rest args)
+ (apply #'magit-git-items "ls-files" "-z" "--full-name" args))
+
+(defun magit-tracked-files ()
+ (magit-list-files "--cached"))
+
+(defun magit-untracked-files (&optional all files)
+ (magit-list-files "--other" (unless all "--exclude-standard") "--" files))
+
+(defun magit-unstaged-files (&optional nomodules files)
+ (magit-git-items "diff-files" "-z" "--name-only"
+ (and nomodules "--ignore-submodules")
+ "--" files))
+
+(defun magit-staged-files (&optional nomodules files)
+ (magit-git-items "diff-index" "-z" "--name-only" "--cached"
+ (and nomodules "--ignore-submodules")
+ (magit-headish) "--" files))
+
+(defun magit-binary-files (&rest args)
+ (--mapcat (and (string-match "^-\t-\t\\(.+\\)" it)
+ (list (match-string 1 it)))
+ (apply #'magit-git-items
+ "diff" "-z" "--numstat" "--ignore-submodules"
+ args)))
+
+(defun magit-unmerged-files ()
+ (magit-git-items "diff-files" "-z" "--name-only" "--diff-filter=U"))
+
+(defun magit-ignored-files ()
+ (magit-git-items "ls-files" "-z" "--others" "--ignored"
+ "--exclude-standard" "--directory"))
+
+(defun magit-skip-worktree-files ()
+ (--keep (and (and (= (aref it 0) ?S)
+ (substring it 2)))
+ (magit-list-files "-t")))
+
+(defun magit-assume-unchanged-files ()
+ (--keep (and (and (memq (aref it 0) '(?h ?s ?m ?r ?c ?k))
+ (substring it 2)))
+ (magit-list-files "-v")))
+
+(defun magit-revision-files (rev)
+ (magit-with-toplevel
+ (magit-git-items "ls-tree" "-z" "-r" "--name-only" rev)))
+
+(defun magit-changed-files (rev-or-range &optional other-rev)
+ "Return list of files the have changed between two revisions.
+If OTHER-REV is non-nil, REV-OR-RANGE should be a revision, not a
+range. Otherwise, it can be any revision or range accepted by
+\"git diff\" (i.e., <rev>, <revA>..<revB>, or <revA>...<revB>)."
+ (magit-with-toplevel
+ (magit-git-items "diff" "-z" "--name-only" rev-or-range other-rev)))
+
+(defun magit-renamed-files (revA revB)
+ (--map (cons (nth 1 it) (nth 2 it))
+ (-partition 3 (magit-git-items
+ "diff-tree" "-r" "--diff-filter=R" "-z" "-M"
+ revA revB))))
+
+(defun magit-file-status (&rest args)
+ (magit--with-temp-process-buffer
+ (save-excursion (magit-git-insert "status" "-z" args))
+ (let ((pos (point)) status)
+ (while (> (skip-chars-forward "[:print:]") 0)
+ (let ((x (char-after pos))
+ (y (char-after (1+ pos)))
+ (file (buffer-substring (+ pos 3) (point))))
+ (forward-char)
+ (if (memq x '(?R ?C))
+ (progn
+ (setq pos (point))
+ (skip-chars-forward "[:print:]")
+ (push (list file (buffer-substring pos (point)) x y) status)
+ (forward-char))
+ (push (list file nil x y) status)))
+ (setq pos (point)))
+ status)))
+
+(defcustom magit-cygwin-mount-points
+ (when (eq system-type 'windows-nt)
+ (cl-sort (--map (if (string-match "^\\(.*\\) on \\(.*\\) type" it)
+ (cons (file-name-as-directory (match-string 2 it))
+ (file-name-as-directory (match-string 1 it)))
+ (lwarn '(magit) :error
+ "Failed to parse Cygwin mount: %S" it))
+ ;; If --exec-path is not a native Windows path,
+ ;; then we probably have a cygwin git.
+ (let ((process-environment
+ (append magit-git-environment process-environment)))
+ (and (not (string-match-p
+ "\\`[a-zA-Z]:"
+ (car (process-lines
+ magit-git-executable "--exec-path"))))
+ (ignore-errors (process-lines "mount")))))
+ #'> :key (pcase-lambda (`(,cyg . ,_win)) (length cyg))))
+ "Alist of (CYGWIN . WIN32) directory names.
+Sorted from longest to shortest CYGWIN name."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-process
+ :type '(alist :key-type string :value-type directory))
+
+(defun magit-expand-git-file-name (filename)
+ (unless (file-name-absolute-p filename)
+ (setq filename (expand-file-name filename)))
+ (-if-let ((cyg . win)
+ (cl-assoc filename magit-cygwin-mount-points
+ :test (lambda (f cyg) (string-prefix-p cyg f))))
+ (concat win (substring filename (length cyg)))
+ filename))
+
+(defun magit-convert-filename-for-git (filename)
+ "Convert FILENAME so that it can be passed to git.
+1. If it's a remote filename, then remove the remote part.
+2. Deal with an `windows-nt' Emacs vs. Cygwin Git incompatibility."
+ (if (file-name-absolute-p filename)
+ (-if-let ((cyg . win)
+ (cl-rassoc filename magit-cygwin-mount-points
+ :test (lambda (f win) (string-prefix-p win f))))
+ (concat cyg (substring filename (length win)))
+ (or (file-remote-p filename 'localname)
+ filename))
+ filename))
+
+(defun magit-decode-git-path (path)
+ (if (eq (aref path 0) ?\")
+ (decode-coding-string (read path)
+ (or magit-git-output-coding-system
+ (car default-process-coding-system))
+ t)
+ path))
+
+(defun magit-file-at-point (&optional expand assert)
+ (if-let ((file (magit-section-case
+ (file (oref it value))
+ (hunk (magit-section-parent-value it)))))
+ (if expand
+ (expand-file-name file (magit-toplevel))
+ file)
+ (when assert
+ (user-error "No file at point"))))
+
+(defun magit-current-file ()
+ (or (magit-file-relative-name)
+ (magit-file-at-point)
+ (and (derived-mode-p 'magit-log-mode)
+ (car magit-buffer-log-files))))
+
+;;; Predicates
+
+(defun magit-no-commit-p ()
+ "Return t if there is no commit in the current Git repository."
+ (not (magit-rev-verify "HEAD")))
+
+(defun magit-merge-commit-p (commit)
+ "Return t if COMMIT is a merge commit."
+ (> (length (magit-commit-parents commit)) 1))
+
+(defun magit-anything-staged-p (&optional ignore-submodules &rest files)
+ "Return t if there are any staged changes.
+If optional FILES is non-nil, then only changes to those files
+are considered."
+ (magit-git-failure "diff" "--quiet" "--cached"
+ (and ignore-submodules "--ignore-submodules")
+ "--" files))
+
+(defun magit-anything-unstaged-p (&optional ignore-submodules &rest files)
+ "Return t if there are any unstaged changes.
+If optional FILES is non-nil, then only changes to those files
+are considered."
+ (magit-git-failure "diff" "--quiet"
+ (and ignore-submodules "--ignore-submodules")
+ "--" files))
+
+(defun magit-anything-modified-p (&optional ignore-submodules &rest files)
+ "Return t if there are any staged or unstaged changes.
+If optional FILES is non-nil, then only changes to those files
+are considered."
+ (or (apply 'magit-anything-staged-p ignore-submodules files)
+ (apply 'magit-anything-unstaged-p ignore-submodules files)))
+
+(defun magit-anything-unmerged-p (&rest files)
+ "Return t if there are any merge conflicts.
+If optional FILES is non-nil, then only conflicts in those files
+are considered."
+ (and (magit-git-string "ls-files" "--unmerged" files) t))
+
+(defun magit-module-worktree-p (module)
+ (magit-with-toplevel
+ (file-exists-p (expand-file-name (expand-file-name ".git" module)))))
+
+(defun magit-module-no-worktree-p (module)
+ (not (magit-module-worktree-p module)))
+
+(defun magit-ignore-submodules-p (&optional return-argument)
+ (or (cl-find-if (lambda (arg)
+ (string-prefix-p "--ignore-submodules" arg))
+ magit-buffer-diff-args)
+ (when-let ((value (magit-get "diff.ignoreSubmodules")))
+ (if return-argument
+ (concat "--ignore-submodules=" value)
+ (concat "diff.ignoreSubmodules=" value)))))
+
+;;; Revisions and References
+
+(defun magit-rev-parse (&rest args)
+ "Execute `git rev-parse ARGS', returning first line of output.
+If there is no output, return nil."
+ (apply #'magit-git-string "rev-parse" args))
+
+(defun magit-rev-parse-safe (&rest args)
+ "Execute `git rev-parse ARGS', returning first line of output.
+If there is no output, return nil. Like `magit-rev-parse' but
+ignore `magit-git-debug'."
+ (apply #'magit-git-str "rev-parse" args))
+
+(defun magit-rev-parse-true (&rest args)
+ "Execute `git rev-parse ARGS', returning t if it prints \"true\".
+If it prints \"false\", then return nil. For any other output
+signal an error."
+ (magit-git-true "rev-parse" args))
+
+(defun magit-rev-parse-false (&rest args)
+ "Execute `git rev-parse ARGS', returning t if it prints \"false\".
+If it prints \"true\", then return nil. For any other output
+signal an error."
+ (magit-git-false "rev-parse" args))
+
+(defun magit-rev-parse-p (&rest args)
+ "Execute `git rev-parse ARGS', returning t if it prints \"true\".
+Return t if the first (and usually only) output line is the
+string \"true\", otherwise return nil."
+ (equal (magit-git-str "rev-parse" args) "true"))
+
+(defun magit-rev-verify (rev)
+ (magit-git-string-p "rev-parse" "--verify" rev))
+
+(defun magit-commit-p (rev)
+ "Return full hash for REV if it names an existing commit."
+ (magit-rev-verify (concat rev "^{commit}")))
+
+(defalias 'magit-rev-verify-commit 'magit-commit-p)
+
+(defalias 'magit-rev-hash 'magit-commit-p)
+
+(defun magit-rev-equal (a b)
+ "Return t if there are no differences between the commits A and B."
+ (magit-git-success "diff" "--quiet" a b))
+
+(defun magit-rev-eq (a b)
+ "Return t if A and B refer to the same commit."
+ (let ((a (magit-commit-p a))
+ (b (magit-commit-p b)))
+ (and a b (equal a b))))
+
+(defun magit-rev-ancestor-p (a b)
+ "Return non-nil if commit A is an ancestor of commit B."
+ (magit-git-success "merge-base" "--is-ancestor" a b))
+
+(defun magit-rev-head-p (rev)
+ (or (equal rev "HEAD")
+ (and rev
+ (not (string-match-p "\\.\\." rev))
+ (equal (magit-rev-parse rev)
+ (magit-rev-parse "HEAD")))))
+
+(defun magit-rev-author-p (rev)
+ "Return t if the user is the author of REV.
+More precisely return t if `user.name' is equal to the author
+name of REV and/or `user.email' is equal to the author email
+of REV."
+ (or (equal (magit-get "user.name") (magit-rev-format "%an" rev))
+ (equal (magit-get "user.email") (magit-rev-format "%ae" rev))))
+
+(defun magit-rev-name (rev &optional pattern not-anchored)
+ "Return a symbolic name for REV using `git-name-rev'.
+
+PATTERN can be used to limit the result to a matching ref.
+Unless NOT-ANCHORED is non-nil, the beginning of the ref must
+match PATTERN.
+
+An anchored lookup is done using the arguments
+\"--exclude=*/<PATTERN> --exclude=*/HEAD\" in addition to
+\"--refs=<PATTERN>\", provided at least version v2.13 of Git is
+used. Older versions did not support the \"--exclude\" argument.
+When \"--exclude\" cannot be used and `git-name-rev' returns a
+ref that should have been excluded, then that is discarded and
+this function returns nil instead. This is unfortunate because
+there might be other refs that do match. To fix that, update
+Git."
+ (if (version< (magit-git-version) "2.13")
+ (when-let
+ ((ref (magit-git-string "name-rev" "--name-only" "--no-undefined"
+ (and pattern (concat "--refs=" pattern))
+ rev)))
+ (if (and pattern
+ (string-match-p "\\`refs/[^/]+/\\*\\'" pattern))
+ (let ((namespace (substring pattern 0 -1)))
+ (and (not (or (string-suffix-p "HEAD" ref)
+ (and (string-match-p namespace ref)
+ (not (magit-rev-verify
+ (concat namespace ref))))))
+ ref))
+ ref))
+ (magit-git-string "name-rev" "--name-only" "--no-undefined"
+ (and pattern (concat "--refs=" pattern))
+ (and pattern
+ (not not-anchored)
+ (list "--exclude=*/HEAD"
+ (concat "--exclude=*/" pattern)))
+ rev)))
+
+(defun magit-rev-branch (rev)
+ (--when-let (magit-rev-name rev "refs/heads/*")
+ (unless (string-match-p "[~^]" it) it)))
+
+(defun magit-get-shortname (rev)
+ (let* ((fn (apply-partially 'magit-rev-name rev))
+ (name (or (funcall fn "refs/tags/*")
+ (funcall fn "refs/heads/*")
+ (funcall fn "refs/remotes/*"))))
+ (cond ((not name)
+ (magit-rev-parse "--short" rev))
+ ((string-match "^\\(?:tags\\|remotes\\)/\\(.+\\)" name)
+ (if (magit-ref-ambiguous-p (match-string 1 name))
+ name
+ (match-string 1 name)))
+ (t (magit-ref-maybe-qualify name)))))
+
+(defun magit-name-branch (rev &optional lax)
+ (or (magit-name-local-branch rev)
+ (magit-name-remote-branch rev)
+ (and lax (or (magit-name-local-branch rev t)
+ (magit-name-remote-branch rev t)))))
+
+(defun magit-name-local-branch (rev &optional lax)
+ (--when-let (magit-rev-name rev "refs/heads/*")
+ (and (or lax (not (string-match-p "[~^]" it))) it)))
+
+(defun magit-name-remote-branch (rev &optional lax)
+ (--when-let (magit-rev-name rev "refs/remotes/*")
+ (and (or lax (not (string-match-p "[~^]" it)))
+ (substring it 8))))
+
+(defun magit-name-tag (rev &optional lax)
+ (--when-let (magit-rev-name rev "refs/tags/*")
+ (and (or lax (not (string-match-p "[~^]" it)))
+ (substring it 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 \"HEAD\" or if that doesn't exist the hash of the empty tree."
+ (if (magit-no-commit-p)
+ (magit-git-string "mktree")
+ "HEAD"))
+
+(defun magit-branch-at-point ()
+ (magit-section-case
+ (branch (oref it value))
+ (commit (or (magit--painted-branch-at-point)
+ (magit-name-branch (oref it value))))))
+
+(defun magit--painted-branch-at-point (&optional type)
+ (or (and (not (eq type 'remote))
+ (memq (get-text-property (point) 'font-lock-face)
+ (list 'magit-branch-local
+ 'magit-branch-current))
+ (when-let ((branch (thing-at-point 'git-revision t)))
+ (cdr (magit-split-branch-name branch))))
+ (and (not (eq type 'local))
+ (memq (get-text-property (point) 'font-lock-face)
+ (list 'magit-branch-remote
+ 'magit-branch-remote-head))
+ (thing-at-point 'git-revision t))))
+
+(defun magit-local-branch-at-point ()
+ (magit-section-case
+ (branch (let ((branch (magit-ref-maybe-qualify (oref it value))))
+ (when (member branch (magit-list-local-branch-names))
+ branch)))
+ (commit (or (magit--painted-branch-at-point 'local)
+ (magit-name-local-branch (oref it value))))))
+
+(defun magit-remote-branch-at-point ()
+ (magit-section-case
+ (branch (let ((branch (oref it value)))
+ (when (member branch (magit-list-remote-branch-names))
+ branch)))
+ (commit (or (magit--painted-branch-at-point 'remote)
+ (magit-name-remote-branch (oref it value))))))
+
+(defun magit-commit-at-point ()
+ (or (magit-section-value-if 'commit)
+ (and (derived-mode-p 'magit-stash-mode
+ 'magit-merge-preview-mode
+ 'magit-revision-mode)
+ magit-buffer-revision)))
+
+(defun magit-branch-or-commit-at-point ()
+ (or (and magit-buffer-file-name
+ magit-buffer-refname)
+ (magit-section-case
+ (branch (magit-ref-maybe-qualify (oref it value)))
+ (commit (or (magit--painted-branch-at-point)
+ (let ((rev (oref it value)))
+ (or (magit-name-branch rev) rev))))
+ (tag (magit-ref-maybe-qualify (oref it value) "tags/"))
+ (pullreq (or (and (fboundp 'forge--pullreq-branch)
+ (magit-branch-p
+ (forge--pullreq-branch (oref it value))))
+ (magit-ref-p (format "refs/pullreqs/%s"
+ (oref (oref it value) number))))))
+ (thing-at-point 'git-revision t)
+ (and (derived-mode-p 'magit-stash-mode
+ 'magit-merge-preview-mode
+ 'magit-revision-mode)
+ magit-buffer-revision)))
+
+(defun magit-tag-at-point ()
+ (magit-section-case
+ (tag (oref it value))
+ (commit (magit-name-tag (oref it value)))))
+
+(defun magit-stash-at-point ()
+ (magit-section-value-if 'stash))
+
+(defun magit-remote-at-point ()
+ (magit-section-case
+ (remote (oref it value))
+ (branch (magit-section-parent-value it))))
+
+(defun magit-module-at-point (&optional predicate)
+ (when (magit-section-match 'magit-module-section)
+ (let ((module (oref (magit-current-section) value)))
+ (and (or (not predicate)
+ (funcall predicate module))
+ module))))
+
+(defun magit-get-current-branch ()
+ "Return the refname of the currently checked out branch.
+Return nil if no branch is currently checked out."
+ (magit-git-string "symbolic-ref" "--short" "HEAD"))
+
+(defvar magit-get-previous-branch-timeout 0.5
+ "Maximum time to spend in `magit-get-previous-branch'.
+Given as a number of seconds.")
+
+(defun magit-get-previous-branch ()
+ "Return the refname of the previously checked out branch.
+Return nil if no branch can be found in the `HEAD' reflog
+which is different from the current branch and still exists.
+The amount of time spent searching is limited by
+`magit-get-previous-branch-timeout'."
+ (let ((t0 (float-time))
+ (current (magit-get-current-branch))
+ (i 1) prev)
+ (while (if (> (- (float-time) t0) magit-get-previous-branch-timeout)
+ (setq prev nil) ;; Timed out.
+ (and (setq prev (magit-rev-verify (format "@{-%i}" i)))
+ (or (not (setq prev (magit-rev-branch prev)))
+ (equal prev current))))
+ (cl-incf i))
+ prev))
+
+(defun magit-set-upstream-branch (branch upstream)
+ "Set UPSTREAM as the upstream of BRANCH.
+If UPSTREAM is nil, then unset BRANCH's upstream.
+Otherwise UPSTREAM has to be an existing branch."
+ (if upstream
+ (magit-call-git "branch" "--set-upstream-to" upstream branch)
+ (magit-call-git "branch" "--unset-upstream" branch)))
+
+(defun magit-get-upstream-ref (&optional branch)
+ "Return the upstream branch of BRANCH as a fully qualified ref.
+It BRANCH is nil, then return the upstream of the current branch,
+if any, nil otherwise. If the upstream is not configured, the
+configured remote is an url, or the named branch does not exist,
+then return nil. I.e. return an existing local or
+remote-tracking branch ref."
+ (when-let ((branch (or branch (magit-get-current-branch))))
+ (magit-ref-fullname (concat branch "@{upstream}"))))
+
+(defun magit-get-upstream-branch (&optional branch)
+ "Return the name of the upstream branch of BRANCH.
+It BRANCH is nil, then return the upstream of the current branch
+if any, nil otherwise. If the upstream is not configured, the
+configured remote is an url, or the named branch does not exist,
+then return nil. I.e. return the name of an existing local or
+remote-tracking branch. The returned string is colorized
+according to the branch type."
+ (magit--with-refresh-cache (list 'magit-get-upstream-branch branch)
+ (when-let ((branch (or branch (magit-get-current-branch)))
+ (upstream (magit-ref-abbrev (concat branch "@{upstream}"))))
+ (magit--propertize-face
+ upstream (if (equal (magit-get "branch" branch "remote") ".")
+ 'magit-branch-local
+ 'magit-branch-remote)))))
+
+(defun magit-get-indirect-upstream-branch (branch &optional force)
+ (let ((remote (magit-get "branch" branch "remote")))
+ (and remote (not (equal remote "."))
+ ;; The user has opted in...
+ (or force
+ (--some (if (magit-git-success "check-ref-format" "--branch" it)
+ (equal it branch)
+ (string-match-p it branch))
+ magit-branch-prefer-remote-upstream))
+ ;; and local BRANCH tracks a remote branch...
+ (let ((upstream (magit-get-upstream-branch branch)))
+ ;; whose upstream...
+ (and upstream
+ ;; has the same name as BRANCH...
+ (equal (substring upstream (1+ (length remote))) branch)
+ ;; and can be fast-forwarded to BRANCH.
+ (magit-rev-ancestor-p upstream branch)
+ upstream)))))
+
+(defun magit-get-upstream-remote (&optional branch allow-unnamed)
+ (when-let ((branch (or branch (magit-get-current-branch)))
+ (remote (magit-get "branch" branch "remote")))
+ (and (not (equal remote "."))
+ (cond ((member remote (magit-list-remotes))
+ (magit--propertize-face remote 'magit-branch-remote))
+ ((and allow-unnamed
+ (string-match-p "\\(\\`.\\{0,2\\}/\\|[:@]\\)" remote))
+ (magit--propertize-face remote 'bold))))))
+
+(defun magit-get-unnamed-upstream (&optional branch)
+ (when-let ((branch (or branch (magit-get-current-branch)))
+ (remote (magit-get "branch" branch "remote"))
+ (merge (magit-get "branch" branch "merge")))
+ (and (magit--unnamed-upstream-p remote merge)
+ (list (magit--propertize-face remote 'bold)
+ (magit--propertize-face merge 'magit-branch-remote)))))
+
+(defun magit--unnamed-upstream-p (remote merge)
+ (and remote (string-match-p "\\(\\`\\.\\{0,2\\}/\\|[:@]\\)" remote)
+ merge (string-prefix-p "refs/" merge)))
+
+(defun magit--valid-upstream-p (remote merge)
+ (and (or (equal remote ".")
+ (member remote (magit-list-remotes)))
+ (string-prefix-p "refs/" merge)))
+
+(defun magit-get-current-remote (&optional allow-unnamed)
+ (or (magit-get-upstream-remote nil allow-unnamed)
+ (when-let ((remotes (magit-list-remotes))
+ (remote (if (= (length remotes) 1)
+ (car remotes)
+ (car (member "origin" remotes)))))
+ (magit--propertize-face remote 'magit-branch-remote))))
+
+(defun magit-get-push-remote (&optional branch)
+ (when-let ((remote
+ (or (and (or branch (setq branch (magit-get-current-branch)))
+ (magit-get "branch" branch "pushRemote"))
+ (magit-get "remote.pushDefault"))))
+ (magit--propertize-face remote 'magit-branch-remote)))
+
+(defun magit-get-push-branch (&optional branch verify)
+ (magit--with-refresh-cache (list 'magit-get-push-branch branch verify)
+ (when-let ((branch (or branch (setq branch (magit-get-current-branch))))
+ (remote (magit-get-push-remote branch))
+ (target (concat remote "/" branch)))
+ (and (or (not verify)
+ (magit-rev-verify target))
+ (magit--propertize-face target 'magit-branch-remote)))))
+
+(defun magit-get-@{push}-branch (&optional branch)
+ (let ((ref (magit-rev-parse "--symbolic-full-name"
+ (concat branch "@{push}"))))
+ (when (and ref (string-prefix-p "refs/remotes/" ref))
+ (substring ref 13))))
+
+(defun magit-get-remote (&optional branch)
+ (when (or branch (setq branch (magit-get-current-branch)))
+ (let ((remote (magit-get "branch" branch "remote")))
+ (unless (equal remote ".")
+ remote))))
+
+(defun magit-get-some-remote (&optional branch)
+ (or (magit-get-remote branch)
+ (when-let ((main (magit-main-branch)))
+ (magit-get-remote main))
+ (let ((remotes (magit-list-remotes)))
+ (or (car (member "origin" remotes))
+ (car remotes)))))
+
+(defun magit-branch-merged-p (branch &optional target)
+ "Return non-nil if BRANCH is merged into its upstream and TARGET.
+
+TARGET defaults to the current branch. If `HEAD' is detached and
+TARGET is nil, then always return nil. As a special case, if
+TARGET is t, then return non-nil if BRANCH is merged into any one
+of the other local branches.
+
+If, and only if, BRANCH has an upstream, then only return non-nil
+if BRANCH is merged into both TARGET (as described above) as well
+as into its upstream."
+ (and (--if-let (and (magit-branch-p branch)
+ (magit-get-upstream-branch branch))
+ (magit-git-success "merge-base" "--is-ancestor" branch it)
+ t)
+ (if (eq target t)
+ (delete (magit-name-local-branch branch)
+ (magit-list-containing-branches branch))
+ (--when-let (or target (magit-get-current-branch))
+ (magit-git-success "merge-base" "--is-ancestor" branch it)))))
+
+(defun magit-get-tracked (refname)
+ "Return the remote branch tracked by the remote-tracking branch REFNAME.
+The returned value has the form (REMOTE . REF), where REMOTE is
+the name of a remote and REF is the ref local to the remote."
+ (when-let ((ref (magit-ref-fullname refname)))
+ (save-match-data
+ (seq-some (lambda (line)
+ (and (string-match "\
+\\`remote\\.\\([^.]+\\)\\.fetch=\\+?\\([^:]+\\):\\(.+\\)" line)
+ (let ((rmt (match-string 1 line))
+ (src (match-string 2 line))
+ (dst (match-string 3 line)))
+ (and (string-match (format "\\`%s\\'"
+ (replace-regexp-in-string
+ "*" "\\(.+\\)" dst t t))
+ ref)
+ (cons rmt (replace-regexp-in-string
+ "*" (match-string 1 ref) src))))))
+ (magit-git-lines "config" "--local" "--list")))))
+
+(defun magit-split-branch-name (branch)
+ (cond ((member branch (magit-list-local-branch-names))
+ (cons "." branch))
+ ((string-match "/" branch)
+ (or (seq-some (lambda (remote)
+ (and (string-match
+ (format "\\`\\(%s\\)/\\(.+\\)\\'" remote)
+ branch)
+ (cons (match-string 1 branch)
+ (match-string 2 branch))))
+ (magit-list-remotes))
+ (error "Invalid branch name %s" branch)))))
+
+(defun magit-get-current-tag (&optional rev with-distance)
+ "Return the closest tag reachable from REV.
+
+If optional REV is nil, then default to `HEAD'.
+If optional WITH-DISTANCE is non-nil then return (TAG COMMITS),
+if it is `dirty' return (TAG COMMIT DIRTY). COMMITS is the number
+of commits in `HEAD' but not in TAG and DIRTY is t if there are
+uncommitted changes, nil otherwise."
+ (--when-let (magit-git-str "describe" "--long" "--tags"
+ (and (eq with-distance 'dirty) "--dirty") rev)
+ (save-match-data
+ (string-match
+ "\\(.+\\)-\\(?:0[0-9]*\\|\\([0-9]+\\)\\)-g[0-9a-z]+\\(-dirty\\)?$" it)
+ (if with-distance
+ `(,(match-string 1 it)
+ ,(string-to-number (or (match-string 2 it) "0"))
+ ,@(and (match-string 3 it) (list t)))
+ (match-string 1 it)))))
+
+(defun magit-get-next-tag (&optional rev with-distance)
+ "Return the closest tag from which REV is reachable.
+
+If optional REV is nil, then default to `HEAD'.
+If no such tag can be found or if the distance is 0 (in which
+case it is the current tag, not the next), return nil instead.
+If optional WITH-DISTANCE is non-nil, then return (TAG COMMITS)
+where COMMITS is the number of commits in TAG but not in REV."
+ (--when-let (magit-git-str "describe" "--contains" (or rev "HEAD"))
+ (save-match-data
+ (when (string-match "^[^^~]+" it)
+ (setq it (match-string 0 it))
+ (unless (equal it (magit-get-current-tag rev))
+ (if with-distance
+ (list it (car (magit-rev-diff-count it rev)))
+ it))))))
+
+(defvar magit-list-refs-namespaces
+ '("refs/heads" "refs/remotes" "refs/tags" "refs/pull"))
+
+(defun magit-list-refs (&optional namespaces format sortby)
+ "Return list of references.
+
+When NAMESPACES is non-nil, list refs from these namespaces
+rather than those from `magit-list-refs-namespaces'.
+
+FORMAT is passed to the `--format' flag of `git for-each-ref'
+and defaults to \"%(refname)\". If the format is \"%(refname)\"
+or \"%(refname:short)\", then drop the symbolic-ref \"HEAD\".
+
+SORTBY is a key or list of keys to pass to the `--sort' flag of
+`git for-each-ref'. When nil, use `magit-list-refs-sortby'"
+ (unless format
+ (setq format "%(refname)"))
+ (let ((refs (magit-git-lines "for-each-ref"
+ (concat "--format=" format)
+ (--map (concat "--sort=" it)
+ (pcase (or sortby magit-list-refs-sortby)
+ ((and val (pred stringp)) (list val))
+ ((and val (pred listp)) val)))
+ (or namespaces magit-list-refs-namespaces))))
+ (if (member format '("%(refname)" "%(refname:short)"))
+ (--remove (string-match-p "\\(\\`\\|/\\)HEAD\\'" it) refs)
+ refs)))
+
+(defun magit-list-branches ()
+ (magit-list-refs (list "refs/heads" "refs/remotes")))
+
+(defun magit-list-local-branches ()
+ (magit-list-refs "refs/heads"))
+
+(defun magit-list-remote-branches (&optional remote)
+ (magit-list-refs (concat "refs/remotes/" remote)))
+
+(defun magit-list-related-branches (relation &optional commit &rest args)
+ (--remove (string-match-p "\\(\\`(HEAD\\|HEAD -> \\)" it)
+ (--map (substring it 2)
+ (magit-git-lines "branch" args relation commit))))
+
+(defun magit-list-containing-branches (&optional commit &rest args)
+ (magit-list-related-branches "--contains" commit args))
+
+(defun magit-list-publishing-branches (&optional commit)
+ (--filter (magit-rev-ancestor-p (or commit "HEAD") it)
+ magit-published-branches))
+
+(defun magit-list-merged-branches (&optional commit &rest args)
+ (magit-list-related-branches "--merged" commit args))
+
+(defun magit-list-unmerged-branches (&optional commit &rest args)
+ (magit-list-related-branches "--no-merged" commit args))
+
+(defun magit-list-unmerged-to-upstream-branches ()
+ (--filter (when-let ((upstream (magit-get-upstream-branch it)))
+ (member it (magit-list-unmerged-branches upstream)))
+ (magit-list-local-branch-names)))
+
+(defun magit-list-branches-pointing-at (commit)
+ (let ((re (format "\\`%s refs/\\(heads\\|remotes\\)/\\(.*\\)\\'"
+ (magit-rev-verify commit))))
+ (--keep (and (string-match re it)
+ (let ((name (match-string 2 it)))
+ (and (not (string-suffix-p "HEAD" name))
+ name)))
+ (magit-git-lines "show-ref"))))
+
+(defun magit-list-refnames (&optional namespaces include-special)
+ (nconc (magit-list-refs namespaces "%(refname:short)")
+ (and include-special
+ (magit-list-special-refnames))))
+
+(defvar magit-special-refnames
+ '("HEAD" "ORIG_HEAD" "FETCH_HEAD" "MERGE_HEAD" "CHERRY_PICK_HEAD"))
+
+(defun magit-list-special-refnames ()
+ (let ((gitdir (magit-gitdir)))
+ (cl-mapcan (lambda (name)
+ (and (file-exists-p (expand-file-name name gitdir))
+ (list name)))
+ magit-special-refnames)))
+
+(defun magit-list-branch-names ()
+ (magit-list-refnames (list "refs/heads" "refs/remotes")))
+
+(defun magit-list-local-branch-names ()
+ (magit-list-refnames "refs/heads"))
+
+(defun magit-list-remote-branch-names (&optional remote relative)
+ (if (and remote relative)
+ (let ((regexp (format "^refs/remotes/%s/\\(.+\\)" remote)))
+ (--mapcat (when (string-match regexp it)
+ (list (match-string 1 it)))
+ (magit-list-remote-branches remote)))
+ (magit-list-refnames (concat "refs/remotes/" remote))))
+
+(defun magit-format-refs (format &rest args)
+ (let ((lines (magit-git-lines
+ "for-each-ref" (concat "--format=" format)
+ (or args (list "refs/heads" "refs/remotes" "refs/tags")))))
+ (if (string-match-p "\f" format)
+ (--map (split-string it "\f") lines)
+ lines)))
+
+(defun magit-list-remotes ()
+ (magit-git-lines "remote"))
+
+(defun magit-list-tags ()
+ (magit-git-lines "tag"))
+
+(defun magit-list-stashes (&optional format)
+ (magit-git-lines "stash" "list" (concat "--format=" (or format "%gd"))))
+
+(defun magit-list-active-notes-refs ()
+ "Return notes refs according to `core.notesRef' and `notes.displayRef'."
+ (magit-git-lines "for-each-ref" "--format=%(refname)"
+ (or (magit-get "core.notesRef") "refs/notes/commits")
+ (magit-get-all "notes.displayRef")))
+
+(defun magit-list-notes-refnames ()
+ (--map (substring it 6) (magit-list-refnames "refs/notes")))
+
+(defun magit-remote-list-tags (remote)
+ (--keep (and (not (string-match-p "\\^{}$" it))
+ (substring it 51))
+ (magit-git-lines "ls-remote" "--tags" remote)))
+
+(defun magit-remote-list-branches (remote)
+ (--keep (and (not (string-match-p "\\^{}$" it))
+ (substring it 52))
+ (magit-git-lines "ls-remote" "--heads" remote)))
+
+(defun magit-remote-list-refs (remote)
+ (--keep (and (not (string-match-p "\\^{}$" it))
+ (substring it 41))
+ (magit-git-lines "ls-remote" remote)))
+
+(defun magit-list-modified-modules ()
+ (--keep (and (string-match "\\`\\+\\([^ ]+\\) \\(.+\\) (.+)\\'" it)
+ (match-string 2 it))
+ (magit-git-lines "submodule" "status")))
+
+(defun magit-list-module-paths ()
+ (--mapcat (and (string-match "^160000 [0-9a-z]\\{40\\} 0\t\\(.+\\)$" it)
+ (list (match-string 1 it)))
+ (magit-git-items "ls-files" "-z" "--stage")))
+
+(defun magit-list-module-names ()
+ (mapcar #'magit-get-submodule-name (magit-list-module-paths)))
+
+(defun magit-get-submodule-name (path)
+ "Return the name of the submodule at PATH.
+PATH has to be relative to the super-repository."
+ (magit-git-string "submodule--helper" "name" path))
+
+(defun magit-list-worktrees ()
+ (let (worktrees worktree)
+ (dolist (line (let ((magit-git-global-arguments
+ ;; KLUDGE At least in v2.8.3 this triggers a segfault.
+ (remove "--no-pager" magit-git-global-arguments)))
+ (magit-git-lines "worktree" "list" "--porcelain")))
+ (cond ((string-prefix-p "worktree" line)
+ (push (setq worktree (list (substring line 9) nil nil nil))
+ worktrees))
+ ((string-equal line "bare")
+ (let* ((default-directory (car worktree))
+ (wt (and (not (magit-get-boolean "core.bare"))
+ (magit-get "core.worktree"))))
+ (if (and wt (file-exists-p (expand-file-name wt)))
+ (progn (setf (nth 0 worktree) (expand-file-name wt))
+ (setf (nth 2 worktree) (magit-rev-parse "HEAD"))
+ (setf (nth 3 worktree) (magit-get-current-branch)))
+ (setf (nth 1 worktree) t))))
+ ((string-prefix-p "HEAD" line)
+ (setf (nth 2 worktree) (substring line 5)))
+ ((string-prefix-p "branch" line)
+ (setf (nth 3 worktree) (substring line 18)))
+ ((string-equal line "detached"))))
+ (nreverse worktrees)))
+
+(defun magit-symbolic-ref-p (name)
+ (magit-git-success "symbolic-ref" "--quiet" name))
+
+(defun magit-ref-p (rev)
+ (or (car (member rev (magit-list-refs "refs/")))
+ (car (member rev (magit-list-refnames "refs/")))))
+
+(defun magit-branch-p (rev)
+ (or (car (member rev (magit-list-branches)))
+ (car (member rev (magit-list-branch-names)))))
+
+(defun magit-local-branch-p (rev)
+ (or (car (member rev (magit-list-local-branches)))
+ (car (member rev (magit-list-local-branch-names)))))
+
+(defun magit-remote-branch-p (rev)
+ (or (car (member rev (magit-list-remote-branches)))
+ (car (member rev (magit-list-remote-branch-names)))))
+
+(defun magit-branch-set-face (branch)
+ (magit--propertize-face branch (if (magit-local-branch-p branch)
+ 'magit-branch-local
+ 'magit-branch-remote)))
+
+(defun magit-tag-p (rev)
+ (car (member rev (magit-list-tags))))
+
+(defun magit-remote-p (string)
+ (car (member string (magit-list-remotes))))
+
+(defvar magit-main-branch-names
+ ;; These are the names that Git suggests
+ ;; if `init.defaultBranch' is undefined.
+ '("main" "master" "trunk" "development"))
+
+(defun magit-main-branch ()
+ "Return the main branch.
+
+If a branch exists whose name that 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 matching branch that actually
+exists in the current repository is considered its main branch."
+ (let ((branches (magit-list-local-branch-names)))
+ (seq-find (lambda (name)
+ (member name branches))
+ (delete-dups
+ (delq nil
+ (cons (magit-get "init.defaultBranch")
+ magit-main-branch-names))))))
+
+(defun magit-rev-diff-count (a b)
+ "Return the commits in A but not B and vice versa.
+Return a list of two integers: (A>B B>A)."
+ (mapcar 'string-to-number
+ (split-string (magit-git-string "rev-list"
+ "--count" "--left-right"
+ (concat a "..." b))
+ "\t")))
+
+(defun magit-abbrev-length ()
+ (let ((abbrev (magit-get "core.abbrev")))
+ (if (and abbrev (not (equal abbrev "auto")))
+ (string-to-number abbrev)
+ ;; Guess the length git will be using based on an example
+ ;; abbreviation. Actually HEAD's abbreviation might be an
+ ;; outlier, so use the shorter of the abbreviations for two
+ ;; commits. See #3034.
+ (if-let ((head (magit-rev-parse "--short" "HEAD"))
+ (head-len (length head)))
+ (min head-len
+ (--if-let (magit-rev-parse "--short" "HEAD~")
+ (length it)
+ head-len))
+ ;; We're on an unborn branch, but perhaps the repository has
+ ;; other commits. See #4123.
+ (if-let ((commits (magit-git-lines "rev-list" "-n2" "--all"
+ "--abbrev-commit")))
+ (apply #'min (mapcar #'length commits))
+ ;; A commit does not exist. Fall back to the default of 7.
+ 7)))))
+
+(defun magit-abbrev-arg (&optional arg)
+ (format "--%s=%d" (or arg "abbrev") (magit-abbrev-length)))
+
+(defun magit-rev-abbrev (rev)
+ (magit-rev-parse (magit-abbrev-arg "short") rev))
+
+(defun magit-commit-children (commit &optional args)
+ (mapcar #'car
+ (--filter (member commit (cdr it))
+ (--map (split-string it " ")
+ (magit-git-lines
+ "log" "--format=%H %P"
+ (or args (list "--branches" "--tags" "--remotes"))
+ "--not" commit)))))
+
+(defun magit-commit-parents (commit)
+ (--when-let (magit-git-string "rev-list" "-1" "--parents" commit)
+ (cdr (split-string it))))
+
+(defun magit-patch-id (rev)
+ (magit--with-temp-process-buffer
+ (magit-process-file
+ shell-file-name nil '(t nil) nil shell-command-switch
+ (let ((exec (shell-quote-argument magit-git-executable)))
+ (format "%s diff-tree -u %s | %s patch-id" exec rev exec)))
+ (car (split-string (buffer-string)))))
+
+(defun magit-rev-format (format &optional rev args)
+ (let ((str (magit-git-string "show" "--no-patch"
+ (concat "--format=" format) args
+ (if rev (concat rev "^{commit}") "HEAD") "--")))
+ (unless (string-equal str "")
+ str)))
+
+(defun magit-rev-insert-format (format &optional rev args)
+ (magit-git-insert "show" "--no-patch"
+ (concat "--format=" format) args
+ (if rev (concat rev "^{commit}") "HEAD") "--"))
+
+(defun magit-format-rev-summary (rev)
+ (--when-let (magit-rev-format "%h %s" rev)
+ (string-match " " it)
+ (magit--put-face 0 (match-beginning 0) 'magit-hash it)
+ it))
+
+(defvar magit-ref-namespaces
+ '(("\\`HEAD\\'" . magit-head)
+ ("\\`refs/tags/\\(.+\\)" . magit-tag)
+ ("\\`refs/heads/\\(.+\\)" . magit-branch-local)
+ ("\\`refs/remotes/\\(.+\\)" . magit-branch-remote)
+ ("\\`refs/bisect/\\(bad\\)" . magit-bisect-bad)
+ ("\\`refs/bisect/\\(skip.*\\)" . magit-bisect-skip)
+ ("\\`refs/bisect/\\(good.*\\)" . magit-bisect-good)
+ ("\\`refs/stash$" . magit-refname-stash)
+ ("\\`refs/wip/\\(.+\\)" . magit-refname-wip)
+ ("\\`refs/pullreqs/\\(.+\\)" . magit-refname-pullreq)
+ ("\\`\\(bad\\):" . magit-bisect-bad)
+ ("\\`\\(skip\\):" . magit-bisect-skip)
+ ("\\`\\(good\\):" . magit-bisect-good)
+ ("\\`\\(.+\\)" . magit-refname))
+ "How refs are formatted for display.
+
+Each entry controls how a certain type of ref is displayed, and
+has the form (REGEXP . FACE). REGEXP is a regular expression
+used to match full refs. The first entry whose REGEXP matches
+the reference is used.
+
+In log and revision buffers the first regexp submatch becomes the
+\"label\" that represents the ref and is propertized with FONT.
+In refs buffers the displayed text is controlled by other means
+and this option only controls what face is used.")
+
+(defun magit-format-ref-labels (string)
+ (save-match-data
+ (let ((regexp "\\(, \\|tag: \\|HEAD -> \\)")
+ names)
+ (if (and (derived-mode-p 'magit-log-mode)
+ (member "--simplify-by-decoration" magit-buffer-log-args))
+ (let ((branches (magit-list-local-branch-names))
+ (re (format "^%s/.+" (regexp-opt (magit-list-remotes)))))
+ (setq names
+ (--map (cond ((string-equal it "HEAD") it)
+ ((string-prefix-p "refs/" it) it)
+ ((member it branches) (concat "refs/heads/" it))
+ ((string-match re it) (concat "refs/remotes/" it))
+ (t (concat "refs/" it)))
+ (split-string
+ (replace-regexp-in-string "tag: " "refs/tags/" string)
+ regexp t))))
+ (setq names (split-string string regexp t)))
+ (let (state head upstream tags branches remotes other combined)
+ (dolist (ref names)
+ (let* ((face (cdr (--first (string-match (car it) ref)
+ magit-ref-namespaces)))
+ (name (magit--propertize-face
+ (or (match-string 1 ref) ref) face)))
+ (cl-case face
+ ((magit-bisect-bad magit-bisect-skip magit-bisect-good)
+ (setq state name))
+ (magit-head
+ (setq head (magit--propertize-face "@" 'magit-head)))
+ (magit-tag (push name tags))
+ (magit-branch-local (push name branches))
+ (magit-branch-remote (push name remotes))
+ (t (push name other)))))
+ (setq remotes
+ (-keep
+ (lambda (name)
+ (if (string-match "\\`\\([^/]*\\)/\\(.*\\)\\'" name)
+ (let ((r (match-string 1 name))
+ (b (match-string 2 name)))
+ (and (not (equal b "HEAD"))
+ (if (equal (concat "refs/remotes/" name)
+ (magit-git-string
+ "symbolic-ref"
+ (format "refs/remotes/%s/HEAD" r)))
+ (magit--propertize-face
+ name 'magit-branch-remote-head)
+ name)))
+ name))
+ remotes))
+ (let* ((current (magit-get-current-branch))
+ (target (magit-get-upstream-branch current)))
+ (dolist (name branches)
+ (let ((push (car (member (magit-get-push-branch name) remotes))))
+ (when push
+ (setq remotes (delete push remotes))
+ (string-match "^[^/]*/" push)
+ (setq push (substring push 0 (match-end 0))))
+ (cond
+ ((equal name current)
+ (setq head
+ (concat push
+ (magit--propertize-face
+ name 'magit-branch-current))))
+ ((equal name target)
+ (setq upstream
+ (concat push
+ (magit--propertize-face
+ name '(magit-branch-upstream
+ magit-branch-local)))))
+ (t
+ (push (concat push name) combined)))))
+ (when (and target (not upstream))
+ (if (member target remotes)
+ (progn
+ (magit--add-face-text-property
+ 0 (length target) 'magit-branch-upstream nil target)
+ (setq upstream target)
+ (setq remotes (delete target remotes)))
+ (when-let ((target (car (member target combined))))
+ (magit--add-face-text-property
+ 0 (length target) 'magit-branch-upstream nil target)
+ (setq upstream target)
+ (setq combined (delete target combined))))))
+ (mapconcat #'identity
+ (-flatten `(,state
+ ,head
+ ,upstream
+ ,@(nreverse tags)
+ ,@(nreverse combined)
+ ,@(nreverse remotes)
+ ,@other))
+ " ")))))
+
+(defun magit-object-type (object)
+ (magit-git-string "cat-file" "-t" object))
+
+(defmacro magit-with-blob (commit file &rest body)
+ (declare (indent 2)
+ (debug (form form body)))
+ `(magit--with-temp-process-buffer
+ (let ((buffer-file-name ,file))
+ (save-excursion
+ (magit-git-insert "cat-file" "-p"
+ (concat ,commit ":" buffer-file-name)))
+ (decode-coding-inserted-region
+ (point-min) (point-max) buffer-file-name t nil nil t)
+ ,@body)))
+
+(defmacro magit-with-temp-index (tree arg &rest body)
+ (declare (indent 2) (debug (form form body)))
+ (let ((file (cl-gensym "file")))
+ `(let ((magit--refresh-cache nil)
+ (,file (magit-convert-filename-for-git
+ (make-temp-name (magit-git-dir "index.magit.")))))
+ (unwind-protect
+ (magit-with-toplevel
+ (--when-let ,tree
+ (or (magit-git-success "read-tree" ,arg it
+ (concat "--index-output=" ,file))
+ (error "Cannot read tree %s" it)))
+ (if (file-remote-p default-directory)
+ (let ((magit-tramp-process-environment
+ (cons (concat "GIT_INDEX_FILE=" ,file)
+ magit-tramp-process-environment)))
+ ,@body)
+ (let ((process-environment
+ (cons (concat "GIT_INDEX_FILE=" ,file)
+ process-environment)))
+ ,@body)))
+ (ignore-errors
+ (delete-file (concat (file-remote-p default-directory) ,file)))))))
+
+(defun magit-commit-tree (message &optional tree &rest parents)
+ (magit-git-string "commit-tree" "--no-gpg-sign" "-m" message
+ (--mapcat (list "-p" it) (delq nil parents))
+ (or tree
+ (magit-git-string "write-tree")
+ (error "Cannot write tree"))))
+
+(defun magit-commit-worktree (message &optional arg &rest other-parents)
+ (magit-with-temp-index "HEAD" arg
+ (and (magit-update-files (magit-unstaged-files))
+ (apply #'magit-commit-tree message nil "HEAD" other-parents))))
+
+(defun magit-update-files (files)
+ (magit-git-success "update-index" "--add" "--remove" "--" files))
+
+(defun magit-update-ref (ref message rev &optional stashish)
+ (let ((magit--refresh-cache nil))
+ (or (if (not (version< (magit-git-version) "2.6.0"))
+ (zerop (magit-call-git "update-ref" "--create-reflog"
+ "-m" message ref rev
+ (or (magit-rev-verify ref) "")))
+ ;; `--create-reflog' didn't exist before v2.6.0
+ (let ((oldrev (magit-rev-verify ref))
+ (logfile (magit-git-dir (concat "logs/" ref))))
+ (unless (file-exists-p logfile)
+ (when oldrev
+ (magit-git-success "update-ref" "-d" ref oldrev))
+ (make-directory (file-name-directory logfile) t)
+ (with-temp-file logfile)
+ (when (and oldrev (not stashish))
+ (magit-git-success "update-ref" "-m" "enable reflog"
+ ref oldrev ""))))
+ (magit-git-success "update-ref" "-m" message ref rev
+ (or (magit-rev-verify ref) "")))
+ (error "Cannot update %s with %s" ref rev))))
+
+(defconst magit-range-re
+ (concat "\\`\\([^ \t]*[^.]\\)?" ; revA
+ "\\(\\.\\.\\.?\\)" ; range marker
+ "\\([^.][^ \t]*\\)?\\'")) ; revB
+
+(defun magit-split-range (range)
+ (and (string-match magit-range-re range)
+ (let ((beg (or (match-string 1 range) "HEAD"))
+ (end (or (match-string 3 range) "HEAD")))
+ (cons (if (string-equal (match-string 2 range) "...")
+ (magit-git-string "merge-base" beg end)
+ beg)
+ end))))
+
+(defun magit-hash-range (range)
+ (if (string-match magit-range-re range)
+ (concat (magit-rev-hash (match-string 1 range))
+ (match-string 2 range)
+ (magit-rev-hash (match-string 3 range)))
+ (magit-rev-hash range)))
+
+(put 'git-revision 'thing-at-point 'magit-thingatpt--git-revision)
+(defun magit-thingatpt--git-revision ()
+ (--when-let
+ (let ((c "\s\n\t~^:?*[\\"))
+ (cl-letf (((get 'git-revision 'beginning-op)
+ (lambda ()
+ (if (re-search-backward (format "[%s]" c) nil t)
+ (forward-char)
+ (goto-char (point-min)))))
+ ((get 'git-revision 'end-op)
+ (lambda ()
+ (re-search-forward (format "\\=[^%s]*" c) nil t))))
+ (bounds-of-thing-at-point 'git-revision)))
+ (let ((text (buffer-substring-no-properties (car it) (cdr it))))
+ (and (magit-commit-p text) text))))
+
+;;; Completion
+
+(defvar magit-revision-history nil)
+
+(defun magit-read-branch (prompt &optional secondary-default)
+ (magit-completing-read prompt (magit-list-branch-names)
+ nil t nil 'magit-revision-history
+ (or (magit-branch-at-point)
+ secondary-default
+ (magit-get-current-branch))))
+
+(defun magit-read-branch-or-commit (prompt &optional secondary-default)
+ (or (magit-completing-read prompt (magit-list-refnames nil t)
+ nil nil nil 'magit-revision-history
+ (or (magit-branch-or-commit-at-point)
+ secondary-default
+ (magit-get-current-branch)))
+ (user-error "Nothing selected")))
+
+(defun magit-read-range-or-commit (prompt &optional secondary-default)
+ (magit-read-range
+ prompt
+ (or (--when-let (magit-region-values '(commit branch) t)
+ (deactivate-mark)
+ (concat (car (last it)) ".." (car it)))
+ (magit-branch-or-commit-at-point)
+ secondary-default
+ (magit-get-current-branch))))
+
+(defun magit-read-range (prompt &optional default)
+ (magit-completing-read-multiple prompt
+ (magit-list-refnames)
+ "\\.\\.\\.?"
+ default 'magit-revision-history))
+
+(defun magit-read-remote-branch
+ (prompt &optional remote default local-branch require-match)
+ (let ((choice (magit-completing-read
+ prompt
+ (-union (and local-branch
+ (if remote
+ (concat remote "/" local-branch)
+ (--map (concat it "/" local-branch)
+ (magit-list-remotes))))
+ (magit-list-remote-branch-names remote t))
+ nil require-match nil 'magit-revision-history default)))
+ (if (or remote (string-match "\\`\\([^/]+\\)/\\(.+\\)" choice))
+ choice
+ (user-error "`%s' doesn't have the form REMOTE/BRANCH" choice))))
+
+(defun magit-read-refspec (prompt remote)
+ (magit-completing-read prompt
+ (prog2 (message "Determining available refs...")
+ (magit-remote-list-refs remote)
+ (message "Determining available refs...done"))))
+
+(defun magit-read-local-branch (prompt &optional secondary-default)
+ (magit-completing-read prompt (magit-list-local-branch-names)
+ nil t nil 'magit-revision-history
+ (or (magit-local-branch-at-point)
+ secondary-default
+ (magit-get-current-branch))))
+
+(defun magit-read-local-branch-or-commit (prompt)
+ (let ((choices (nconc (magit-list-local-branch-names)
+ (magit-list-special-refnames)))
+ (commit (magit-commit-at-point)))
+ (when commit
+ (push commit choices))
+ (or (magit-completing-read prompt choices
+ nil nil nil 'magit-revision-history
+ (or (magit-local-branch-at-point) commit))
+ (user-error "Nothing selected"))))
+
+(defun magit-read-local-branch-or-ref (prompt &optional secondary-default)
+ (magit-completing-read prompt (nconc (magit-list-local-branch-names)
+ (magit-list-refs "refs/"))
+ nil t nil 'magit-revision-history
+ (or (magit-local-branch-at-point)
+ secondary-default
+ (magit-get-current-branch))))
+
+(defun magit-read-other-branch
+ (prompt &optional exclude secondary-default no-require-match)
+ (let* ((current (magit-get-current-branch))
+ (atpoint (magit-branch-at-point))
+ (exclude (or exclude current))
+ (default (or (and (not (equal atpoint exclude)) atpoint)
+ (and (not (equal current exclude)) current)
+ secondary-default
+ (magit-get-previous-branch))))
+ (magit-completing-read prompt (delete exclude (magit-list-branch-names))
+ nil (not no-require-match)
+ nil 'magit-revision-history default)))
+
+(defun magit-read-other-branch-or-commit
+ (prompt &optional exclude secondary-default)
+ (let* ((current (magit-get-current-branch))
+ (atpoint (magit-branch-or-commit-at-point))
+ (exclude (or exclude current))
+ (default (or (and (not (equal atpoint exclude))
+ (not (and (not current)
+ (magit-rev-equal atpoint "HEAD")))
+ atpoint)
+ (and (not (equal current exclude)) current)
+ secondary-default
+ (magit-get-previous-branch))))
+ (or (magit-completing-read prompt (delete exclude (magit-list-refnames))
+ nil nil nil 'magit-revision-history default)
+ (user-error "Nothing selected"))))
+
+(defun magit-read-other-local-branch
+ (prompt &optional exclude secondary-default no-require-match)
+ (let* ((current (magit-get-current-branch))
+ (atpoint (magit-local-branch-at-point))
+ (exclude (or exclude current))
+ (default (or (and (not (equal atpoint exclude)) atpoint)
+ (and (not (equal current exclude)) current)
+ secondary-default
+ (magit-get-previous-branch))))
+ (magit-completing-read prompt
+ (delete exclude (magit-list-local-branch-names))
+ nil (not no-require-match)
+ nil 'magit-revision-history default)))
+
+(defun magit-read-branch-prefer-other (prompt)
+ (let* ((current (magit-get-current-branch))
+ (commit (magit-commit-at-point))
+ (atrev (and commit (magit-list-branches-pointing-at commit)))
+ (atpoint (magit--painted-branch-at-point)))
+ (magit-completing-read prompt (magit-list-branch-names)
+ nil t nil 'magit-revision-history
+ (or (magit-section-value-if 'branch)
+ atpoint
+ (and (not (cdr atrev)) (car atrev))
+ (--first (not (equal it current)) atrev)
+ (magit-get-previous-branch)
+ (car atrev)))))
+
+(defun magit-read-upstream-branch (&optional branch prompt)
+ "Read the upstream for BRANCH using PROMPT.
+If optional BRANCH is nil, then read the upstream for the
+current branch, or raise an error if no branch is checked
+out. Only existing branches can be selected."
+ (unless branch
+ (setq branch (or (magit-get-current-branch)
+ (error "Need a branch to set its upstream"))))
+ (let ((branches (delete branch (magit-list-branch-names))))
+ (magit-completing-read
+ (or prompt (format "Change upstream of %s to" branch))
+ branches nil t nil 'magit-revision-history
+ (or (let ((r (car (member (magit-remote-branch-at-point) branches)))
+ (l (car (member (magit-local-branch-at-point) branches))))
+ (if magit-prefer-remote-upstream (or r l) (or l r)))
+ (when-let ((main (magit-main-branch)))
+ (let ((r (car (member (concat "origin/" main) branches)))
+ (l (car (member main branches))))
+ (if magit-prefer-remote-upstream (or r l) (or l r))))
+ (car (member (magit-get-previous-branch) branches))))))
+
+(defun magit-read-starting-point (prompt &optional branch default)
+ (or (magit-completing-read
+ (concat prompt
+ (and branch
+ (if (bound-and-true-p ivy-mode)
+ ;; Ivy-mode strips faces from prompt.
+ (format " `%s'" branch)
+ (concat " " (magit--propertize-face
+ branch 'magit-branch-local))))
+ " starting at")
+ (nconc (list "HEAD")
+ (magit-list-refnames)
+ (directory-files (magit-git-dir) nil "_HEAD\\'"))
+ nil nil nil 'magit-revision-history
+ (or default (magit--default-starting-point)))
+ (user-error "Nothing selected")))
+
+(defun magit--default-starting-point ()
+ (or (let ((r (magit-remote-branch-at-point))
+ (l (magit-local-branch-at-point)))
+ (if magit-prefer-remote-upstream (or r l) (or l r)))
+ (magit-commit-at-point)
+ (magit-stash-at-point)
+ (magit-get-current-branch)))
+
+(defun magit-read-tag (prompt &optional require-match)
+ (magit-completing-read prompt (magit-list-tags) nil
+ require-match nil 'magit-revision-history
+ (magit-tag-at-point)))
+
+(defun magit-read-stash (prompt)
+ (let* ((atpoint (magit-stash-at-point))
+ (default (and atpoint
+ (concat atpoint (magit-rev-format " %s" atpoint))))
+ (choices (mapcar (lambda (c)
+ (pcase-let ((`(,rev ,msg) (split-string c "\0")))
+ (concat (propertize rev 'face 'magit-hash)
+ " " msg)))
+ (magit-list-stashes "%gd%x00%s")))
+ (choice (magit-completing-read prompt choices
+ nil t nil nil
+ default
+ (car choices))))
+ (and choice
+ (string-match "^\\([^ ]+\\) \\(.+\\)" choice)
+ (substring-no-properties (match-string 1 choice)))))
+
+(defun magit-read-remote (prompt &optional default use-only)
+ (let ((remotes (magit-list-remotes)))
+ (if (and use-only (= (length remotes) 1))
+ (car remotes)
+ (magit-completing-read prompt remotes
+ nil t nil nil
+ (or default
+ (magit-remote-at-point)
+ (magit-get-remote))))))
+
+(defun magit-read-remote-or-url (prompt &optional default)
+ (magit-completing-read prompt
+ (nconc (magit-list-remotes)
+ (list "https://" "git://" "git@"))
+ nil nil nil nil
+ (or default
+ (magit-remote-at-point)
+ (magit-get-remote))))
+
+(defun magit-read-module-path (prompt &optional predicate)
+ (magit-completing-read prompt (magit-list-module-paths)
+ predicate t nil nil
+ (magit-module-at-point predicate)))
+
+(defun magit-module-confirm (verb &optional predicate)
+ (let (modules)
+ (if current-prefix-arg
+ (progn
+ (setq modules (magit-list-module-paths))
+ (when predicate
+ (setq modules (-filter predicate modules)))
+ (unless modules
+ (if predicate
+ (user-error "No modules satisfying %s available" predicate)
+ (user-error "No modules available"))))
+ (setq modules (magit-region-values 'magit-module-section))
+ (when modules
+ (when predicate
+ (setq modules (-filter predicate modules)))
+ (unless modules
+ (user-error "No modules satisfying %s selected" predicate))))
+ (if (> (length modules) 1)
+ (magit-confirm t nil (format "%s %%i modules" verb) nil modules)
+ (list (magit-read-module-path (format "%s module" verb) predicate)))))
+
+;;; _
+(provide 'magit-git)
+;;; magit-git.el ends here
--- /dev/null
+;;; magit-gitignore.el --- intentionally untracked files -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements gitignore commands.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Transient
+
+;;;###autoload (autoload 'magit-gitignore "magit-gitignore" nil t)
+(transient-define-prefix magit-gitignore ()
+ "Instruct Git to ignore a file or pattern."
+ :man-page "gitignore"
+ ["Gitignore"
+ ("t" "shared at toplevel (.gitignore)"
+ magit-gitignore-in-topdir)
+ ("s" "shared in subdirectory (path/to/.gitignore)"
+ magit-gitignore-in-subdir)
+ ("p" "privately (.git/info/exclude)"
+ magit-gitignore-in-gitdir)
+ ("g" magit-gitignore-on-system
+ :if (lambda () (magit-get "core.excludesfile"))
+ :description (lambda ()
+ (format "privately for all repositories (%s)"
+ (magit-get "core.excludesfile"))))]
+ ["Skip worktree"
+ (7 "w" "do skip worktree" magit-skip-worktree)
+ (7 "W" "do not skip worktree" magit-no-skip-worktree)]
+ ["Assume unchanged"
+ (7 "u" "do assume unchanged" magit-assume-unchanged)
+ (7 "U" "do not assume unchanged" magit-no-assume-unchanged)])
+
+;;; Gitignore Commands
+
+;;;###autoload
+(defun magit-gitignore-in-topdir (rule)
+ "Add the Git ignore RULE to the top-level \".gitignore\" file.
+Since this file is tracked, it is shared with other clones of the
+repository. Also stage the file."
+ (interactive (list (magit-gitignore-read-pattern)))
+ (magit-with-toplevel
+ (magit--gitignore rule ".gitignore")
+ (magit-run-git "add" ".gitignore")))
+
+;;;###autoload
+(defun magit-gitignore-in-subdir (rule directory)
+ "Add the Git ignore RULE to a \".gitignore\" file.
+Prompted 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" file))))
+
+;;;###autoload
+(defun magit-gitignore-in-gitdir (rule)
+ "Add the Git ignore RULE to \"$GIT_DIR/info/exclude\".
+Rules in that file only affects this clone of the repository."
+ (interactive (list (magit-gitignore-read-pattern)))
+ (magit--gitignore rule (magit-git-dir "info/exclude"))
+ (magit-refresh))
+
+;;;###autoload
+(defun magit-gitignore-on-system (rule)
+ "Add the Git ignore RULE to the file specified by `core.excludesFile'.
+Rules that are defined in that file affect all local repositories."
+ (interactive (list (magit-gitignore-read-pattern)))
+ (magit--gitignore rule
+ (or (magit-get "core.excludesFile")
+ (error "Variable `core.excludesFile' isn't set")))
+ (magit-refresh))
+
+(defun magit--gitignore (rule file)
+ (when-let ((directory (file-name-directory file)))
+ (make-directory directory t))
+ (with-temp-buffer
+ (when (file-exists-p file)
+ (insert-file-contents file))
+ (goto-char (point-max))
+ (unless (bolp)
+ (insert "\n"))
+ (insert (replace-regexp-in-string "\\(\\\\*\\)" "\\1\\1" rule))
+ (insert "\n")
+ (write-region nil nil file)))
+
+(defun magit-gitignore-read-pattern ()
+ (let* ((default (magit-current-file))
+ (base (car magit-buffer-diff-files))
+ (base (and base (file-directory-p base) base))
+ (choices
+ (delete-dups
+ (--mapcat
+ (cons (concat "/" it)
+ (when-let ((ext (file-name-extension it)))
+ (list (concat "/" (file-name-directory it) "*." ext)
+ (concat "*." ext))))
+ (sort (nconc
+ (magit-untracked-files nil base)
+ ;; The untracked section of the status buffer lists
+ ;; directories containing only untracked files.
+ ;; Add those as candidates.
+ (-filter #'directory-name-p
+ (magit-list-files
+ "--other" "--exclude-standard" "--directory"
+ "--no-empty-directory" "--" base)))
+ #'string-lessp)))))
+ (when default
+ (setq default (concat "/" default))
+ (unless (member default choices)
+ (setq default (concat "*." (file-name-extension default)))
+ (unless (member default choices)
+ (setq default nil))))
+ (magit-completing-read "File or pattern to ignore"
+ choices nil nil nil nil default)))
+
+;;; Skip Worktree Commands
+
+;;;###autoload
+(defun magit-skip-worktree (file)
+ "Call \"git update-index --skip-worktree -- FILE\"."
+ (interactive
+ (list (magit-read-file-choice "Skip worktree for"
+ (magit-with-toplevel
+ (cl-set-difference
+ (magit-list-files)
+ (magit-skip-worktree-files))))))
+ (magit-with-toplevel
+ (magit-run-git "update-index" "--skip-worktree" "--" file)))
+
+;;;###autoload
+(defun magit-no-skip-worktree (file)
+ "Call \"git update-index --no-skip-worktree -- FILE\"."
+ (interactive
+ (list (magit-read-file-choice "Do not skip worktree for"
+ (magit-with-toplevel
+ (magit-skip-worktree-files)))))
+ (magit-with-toplevel
+ (magit-run-git "update-index" "--no-skip-worktree" "--" file)))
+
+;;; Assume Unchanged Commands
+
+;;;###autoload
+(defun magit-assume-unchanged (file)
+ "Call \"git update-index --assume-unchanged -- FILE\"."
+ (interactive
+ (list (magit-read-file-choice "Assume file to be unchanged"
+ (magit-with-toplevel
+ (cl-set-difference
+ (magit-list-files)
+ (magit-assume-unchanged-files))))))
+ (magit-with-toplevel
+ (magit-run-git "update-index" "--assume-unchanged" "--" file)))
+
+;;;###autoload
+(defun magit-no-assume-unchanged (file)
+ "Call \"git update-index --no-assume-unchanged -- FILE\"."
+ (interactive
+ (list (magit-read-file-choice "Do not assume file to be unchanged"
+ (magit-with-toplevel
+ (magit-assume-unchanged-files)))))
+ (magit-with-toplevel
+ (magit-run-git "update-index" "--no-assume-unchanged" "--" file)))
+
+;;; _
+(provide 'magit-gitignore)
+;;; magit-gitignore.el ends here
--- /dev/null
+;;; magit-imenu.el --- Integrate Imenu in magit major modes -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Damien Cassou <damienNOSPAMcassou.me>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; Emacs' major modes can facilitate navigation in their buffers by
+;; supporting Imenu. In such major modes, launching Imenu (M-x imenu)
+;; makes Emacs display a list of items (e.g., function definitions in
+;; a programming major mode). Selecting an item from this list moves
+;; point to this item.
+
+;; magit-imenu.el adds Imenu support to every major mode in Magit.
+
+;;; Code:
+
+(require 'magit)
+(require 'git-rebase)
+
+;;; Core
+
+(defun magit-imenu--index-function (entry-types menu-types)
+ "Return an alist of imenu entries in current buffer.
+
+ENTRY-TYPES is a list of section types to be selected through
+`imenu'.
+
+MENU-TYPES is a list of section types containing elements of
+ENTRY-TYPES. Elements of MENU-TYPES are are used to categories
+elements of ENTRY-TYPES.
+
+This function is used as a helper for functions set as
+`imenu-create-index-function'."
+ (let ((entries (make-hash-table :test 'equal)))
+ (goto-char (point-max))
+ (while (magit-section--backward-find
+ (lambda ()
+ (let* ((section (magit-current-section))
+ (type (oref section type))
+ (parent (oref section parent))
+ (parent-type (oref parent type)))
+ (and (-contains-p entry-types type)
+ (-contains-p menu-types parent-type)))))
+ (let* ((section (magit-current-section))
+ (name (buffer-substring-no-properties
+ (line-beginning-position)
+ (line-end-position)))
+ (parent (oref section parent))
+ (parent-title (buffer-substring-no-properties
+ (oref parent start)
+ (1- (oref parent content)))))
+ (puthash parent-title
+ (cons (cons name (point))
+ (gethash parent-title entries (list)))
+ entries)))
+ (mapcar (lambda (menu-title)
+ (cons menu-title (gethash menu-title entries)))
+ (hash-table-keys entries))))
+
+;;; Log mode
+
+;;;###autoload
+(defun magit-imenu--log-prev-index-position-function ()
+ "Move point to previous line in current buffer.
+This function is used as a value for
+`imenu-prev-index-position-function'."
+ (magit-section--backward-find
+ (lambda ()
+ (-contains-p '(commit stash)
+ (oref (magit-current-section) type)))))
+
+;;;###autoload
+(defun magit-imenu--log-extract-index-name-function ()
+ "Return imenu name for line at point.
+This function is used as a value for
+`imenu-extract-index-name-function'. Point should be at the
+beginning of the line."
+ (save-match-data
+ (looking-at "\\([^ ]+\\)[ *|]+\\(.+\\)$")
+ (format "%s: %s"
+ (match-string-no-properties 1)
+ (match-string-no-properties 2))))
+
+;;; Diff mode
+
+;;;###autoload
+(defun magit-imenu--diff-prev-index-position-function ()
+ "Move point to previous file line in current buffer.
+This function is used as a value for
+`imenu-prev-index-position-function'."
+ (magit-section--backward-find
+ (lambda ()
+ (let ((section (magit-current-section)))
+ (and (magit-file-section-p section)
+ (not (equal (oref (oref section parent) type)
+ 'diffstat)))))))
+
+;;;###autoload
+(defun magit-imenu--diff-extract-index-name-function ()
+ "Return imenu name for line at point.
+This function is used as a value for
+`imenu-extract-index-name-function'. Point should be at the
+beginning of the line."
+ (buffer-substring-no-properties (line-beginning-position)
+ (line-end-position)))
+
+;;; Status mode
+
+;;;###autoload
+(defun magit-imenu--status-create-index-function ()
+ "Return an alist of all imenu entries in current buffer.
+This function is used as a value for
+`imenu-create-index-function'."
+ (magit-imenu--index-function
+ '(file commit stash)
+ '(unpushed unstaged unpulled untracked staged stashes)))
+
+;;;; Refs mode
+
+;;;###autoload
+(defun magit-imenu--refs-create-index-function ()
+ "Return an alist of all imenu entries in current buffer.
+This function is used as a value for
+`imenu-create-index-function'."
+ (magit-imenu--index-function
+ '(branch commit tag)
+ '(local remote tags)))
+
+;;;; Cherry mode
+
+;;;###autoload
+(defun magit-imenu--cherry-create-index-function ()
+ "Return an alist of all imenu entries in current buffer.
+This function is used as a value for
+`imenu-create-index-function'."
+ (magit-imenu--index-function
+ '(commit)
+ '(cherries)))
+
+;;;; Submodule list mode
+
+;;;###autoload
+(defun magit-imenu--submodule-prev-index-position-function ()
+ "Move point to previous line in magit-submodule-list buffer.
+This function is used as a value for
+`imenu-prev-index-position-function'."
+ (unless (bobp)
+ (forward-line -1)))
+
+;;;###autoload
+(defun magit-imenu--submodule-extract-index-name-function ()
+ "Return imenu name for line at point.
+This function is used as a value for
+`imenu-extract-index-name-function'. Point should be at the
+beginning of the line."
+ (elt (tabulated-list-get-entry) 0))
+
+;;;; Repolist mode
+
+;;;###autoload
+(defun magit-imenu--repolist-prev-index-position-function ()
+ "Move point to previous line in magit-repolist buffer.
+This function is used as a value for
+`imenu-prev-index-position-function'."
+ (unless (bobp)
+ (forward-line -1)))
+
+;;;###autoload
+(defun magit-imenu--repolist-extract-index-name-function ()
+ "Return imenu name for line at point.
+This function is used as a value for
+`imenu-extract-index-name-function'. Point should be at the
+beginning of the line."
+ (let ((entry (tabulated-list-get-entry)))
+ (format "%s (%s)"
+ (elt entry 0)
+ (elt entry (1- (length entry))))))
+
+;;;; Process mode
+
+;;;###autoload
+(defun magit-imenu--process-prev-index-position-function ()
+ "Move point to previous process in magit-process buffer.
+This function is used as a value for
+`imenu-prev-index-position-function'."
+ (magit-section--backward-find
+ (lambda ()
+ (eq (oref (magit-current-section) type) 'process))))
+
+;;;###autoload
+(defun magit-imenu--process-extract-index-name-function ()
+ "Return imenu name for line at point.
+This function is used as a value for
+`imenu-extract-index-name-function'. Point should be at the
+beginning of the line."
+ (buffer-substring-no-properties (line-beginning-position)
+ (line-end-position)))
+
+;;;; Rebase mode
+
+;;;###autoload
+(defun magit-imenu--rebase-prev-index-position-function ()
+ "Move point to previous commit in git-rebase buffer.
+This function is used as a value for
+`imenu-prev-index-position-function'."
+ (catch 'found
+ (while (not (bobp))
+ (git-rebase-backward-line)
+ (when (git-rebase-line-p)
+ (throw 'found t)))))
+
+;;;###autoload
+(defun magit-imenu--rebase-extract-index-name-function ()
+ "Return imenu name for line at point.
+This function is used as a value for
+`imenu-extract-index-name-function'. Point should be at the
+beginning of the line."
+ (buffer-substring-no-properties (line-beginning-position)
+ (line-end-position)))
+
+;;; _
+(provide 'magit-imenu)
+;;; magit-imenu.el ends here
--- /dev/null
+;;; magit-log.el --- inspect Git history -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements support for looking at Git logs, including
+;; special logs like cherry-logs, as well as for selecting a commit
+;; from a log.
+
+;;; Code:
+
+(require 'magit-core)
+(require 'magit-diff)
+
+(declare-function magit-blob-visit "magit-files" (blob-or-file line))
+(declare-function magit-insert-head-branch-header "magit-status"
+ (&optional branch))
+(declare-function magit-insert-upstream-branch-header "magit-status"
+ (&optional branch pull keyword))
+(declare-function magit-read-file-from-rev "magit-files"
+ (rev prompt &optional default))
+(declare-function magit-show-commit "magit-diff"
+ (arg1 &optional arg2 arg3 arg4))
+(declare-function magit-reflog-format-subject "magit-reflog" (subject))
+(defvar magit-refs-focus-column-width)
+(defvar magit-refs-margin)
+(defvar magit-refs-show-commit-count)
+(defvar magit-buffer-margin)
+(defvar magit-status-margin)
+(defvar magit-status-sections-hook)
+
+(require 'ansi-color)
+(require 'crm)
+(require 'which-func)
+
+;;; Options
+;;;; Log Mode
+
+(defgroup magit-log nil
+ "Inspect and manipulate Git history."
+ :link '(info-link "(magit)Logging")
+ :group 'magit-commands
+ :group 'magit-modes)
+
+(defcustom magit-log-mode-hook nil
+ "Hook run after entering Magit-Log mode."
+ :group 'magit-log
+ :type 'hook)
+
+(defcustom magit-log-remove-graph-args '("--follow" "--grep" "-G" "-S" "-L")
+ "The log arguments that cause the `--graph' argument to be dropped."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-log
+ :type '(repeat (string :tag "Argument"))
+ :options '("--follow" "--grep" "-G" "-S" "-L"))
+
+(defcustom magit-log-revision-headers-format "\
+%+b
+Author: %aN <%aE>
+Committer: %cN <%cE>"
+ "Additional format string used with the `++header' argument."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-log
+ :type 'string)
+
+(defcustom magit-log-auto-more nil
+ "Insert more log entries automatically when moving past the last entry.
+Only considered when moving past the last entry with
+`magit-goto-*-section' commands."
+ :group 'magit-log
+ :type 'boolean)
+
+(defcustom magit-log-margin '(t age magit-log-margin-width t 18)
+ "Format of the margin in `magit-log-mode' buffers.
+
+The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
+
+If INIT is non-nil, then the margin is shown initially.
+STYLE controls how to format the author or committer date.
+ It can be one of `age' (to show the age of the commit),
+ `age-abbreviated' (to abbreviate the time unit to a character),
+ or a string (suitable for `format-time-string') to show the
+ actual date. Option `magit-log-margin-show-committer-date'
+ controls which date is being displayed.
+WIDTH controls the width of the margin. This exists for forward
+ compatibility and currently the value should not be changed.
+AUTHOR controls whether the name of the author is also shown by
+ default.
+AUTHOR-WIDTH has to be an integer. When the name of the author
+ is shown, then this specifies how much space is used to do so."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-log
+ :group 'magit-margin
+ :type magit-log-margin--custom-type
+ :initialize 'magit-custom-initialize-reset
+ :set (apply-partially #'magit-margin-set-variable 'magit-log-mode))
+
+(defcustom magit-log-margin-show-committer-date nil
+ "Whether to show the committer date in the margin.
+
+This option only controls whether the committer date is displayed
+instead of the author date. Whether some date is displayed in
+the margin and whether the margin is displayed at all is
+controlled by other options."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-log
+ :group 'magit-margin
+ :type 'boolean)
+
+(defcustom magit-log-show-refname-after-summary nil
+ "Whether to show refnames after commit summaries.
+This is useful if you use really long branch names."
+ :package-version '(magit . "2.2.0")
+ :group 'magit-log
+ :type 'boolean)
+
+(defcustom magit-log-highlight-keywords t
+ "Whether to highlight bracketed keywords in commit summaries."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-log
+ :type 'boolean)
+
+(defcustom magit-log-header-line-function 'magit-log-header-line-sentence
+ "Function used to generate text shown in header line of log buffers."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-log
+ :type '(choice (function-item magit-log-header-line-arguments)
+ (function-item magit-log-header-line-sentence)
+ function))
+
+(defcustom magit-log-trace-definition-function 'magit-which-function
+ "Function used to determine the function at point.
+This is used by the command `magit-log-trace-definition'.
+You should prefer `magit-which-function' over `which-function'
+because the latter may make use of Imenu's outdated cache."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-log
+ :type '(choice (function-item magit-which-function)
+ (function-item which-function)
+ (function-item add-log-current-defun)
+ function))
+
+(defface magit-log-graph
+ '((((class color) (background light)) :foreground "grey30")
+ (((class color) (background dark)) :foreground "grey80"))
+ "Face for the graph part of the log output."
+ :group 'magit-faces)
+
+(defface magit-log-author
+ '((((class color) (background light))
+ :foreground "firebrick"
+ :slant normal
+ :weight normal)
+ (((class color) (background dark))
+ :foreground "tomato"
+ :slant normal
+ :weight normal))
+ "Face for the author part of the log output."
+ :group 'magit-faces)
+
+(defface magit-log-date
+ '((((class color) (background light))
+ :foreground "grey30"
+ :slant normal
+ :weight normal)
+ (((class color) (background dark))
+ :foreground "grey80"
+ :slant normal
+ :weight normal))
+ "Face for the date part of the log output."
+ :group 'magit-faces)
+
+(defface magit-header-line-log-select
+ '((t :inherit bold))
+ "Face for the `header-line' in `magit-log-select-mode'."
+ :group 'magit-faces)
+
+;;;; File Log
+
+(defcustom magit-log-buffer-file-locked t
+ "Whether `magit-log-buffer-file-quick' uses a dedicated buffer."
+ :package-version '(magit . "2.7.0")
+ :group 'magit-commands
+ :group 'magit-log
+ :type 'boolean)
+
+;;;; Select Mode
+
+(defcustom magit-log-select-show-usage 'both
+ "Whether to show usage information when selecting a commit from a log.
+The message can be shown in the `echo-area' or the `header-line', or in
+`both' places. If the value isn't one of these symbols, then it should
+be nil, in which case no usage information is shown."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-log
+ :type '(choice (const :tag "in echo-area" echo-area)
+ (const :tag "in header-line" header-line)
+ (const :tag "in both places" both)
+ (const :tag "nowhere")))
+
+(defcustom magit-log-select-margin
+ (list (nth 0 magit-log-margin)
+ (nth 1 magit-log-margin)
+ 'magit-log-margin-width t
+ (nth 4 magit-log-margin))
+ "Format of the margin in `magit-log-select-mode' buffers.
+
+The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
+
+If INIT is non-nil, then the margin is shown initially.
+STYLE controls how to format the author or committer date.
+ It can be one of `age' (to show the age of the commit),
+ `age-abbreviated' (to abbreviate the time unit to a character),
+ or a string (suitable for `format-time-string') to show the
+ actual date. Option `magit-log-margin-show-committer-date'
+ controls which date is being displayed.
+WIDTH controls the width of the margin. This exists for forward
+ compatibility and currently the value should not be changed.
+AUTHOR controls whether the name of the author is also shown by
+ default.
+AUTHOR-WIDTH has to be an integer. When the name of the author
+ is shown, then this specifies how much space is used to do so."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-log
+ :group 'magit-margin
+ :type magit-log-margin--custom-type
+ :initialize 'magit-custom-initialize-reset
+ :set-after '(magit-log-margin)
+ :set (apply-partially #'magit-margin-set-variable 'magit-log-select-mode))
+
+;;;; Cherry Mode
+
+(defcustom magit-cherry-sections-hook
+ '(magit-insert-cherry-headers
+ magit-insert-cherry-commits)
+ "Hook run to insert sections into the cherry buffer."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-log
+ :type 'hook)
+
+(defcustom magit-cherry-margin
+ (list (nth 0 magit-log-margin)
+ (nth 1 magit-log-margin)
+ 'magit-log-margin-width t
+ (nth 4 magit-log-margin))
+ "Format of the margin in `magit-cherry-mode' buffers.
+
+The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
+
+If INIT is non-nil, then the margin is shown initially.
+STYLE controls how to format the author or committer date.
+ It can be one of `age' (to show the age of the commit),
+ `age-abbreviated' (to abbreviate the time unit to a character),
+ or a string (suitable for `format-time-string') to show the
+ actual date. Option `magit-log-margin-show-committer-date'
+ controls which date is being displayed.
+WIDTH controls the width of the margin. This exists for forward
+ compatibility and currently the value should not be changed.
+AUTHOR controls whether the name of the author is also shown by
+ default.
+AUTHOR-WIDTH has to be an integer. When the name of the author
+ is shown, then this specifies how much space is used to do so."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-log
+ :group 'magit-margin
+ :type magit-log-margin--custom-type
+ :initialize 'magit-custom-initialize-reset
+ :set-after '(magit-log-margin)
+ :set (apply-partially #'magit-margin-set-variable 'magit-cherry-mode))
+
+;;;; Log Sections
+
+(defcustom magit-log-section-commit-count 10
+ "How many recent commits to show in certain log sections.
+How many recent commits `magit-insert-recent-commits' and
+`magit-insert-unpulled-from-upstream-or-recent' (provided
+the upstream isn't ahead of the current branch) show."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-status
+ :type 'number)
+
+;;; Arguments
+;;;; Prefix Classes
+
+(defclass magit-log-prefix (transient-prefix)
+ ((history-key :initform 'magit-log)
+ (major-mode :initform 'magit-log-mode)))
+
+(defclass magit-log-refresh-prefix (magit-log-prefix)
+ ((history-key :initform 'magit-log)
+ (major-mode :initform nil)))
+
+;;;; Prefix Methods
+
+(cl-defmethod transient-init-value ((obj magit-log-prefix))
+ (pcase-let ((`(,args ,files)
+ (magit-log--get-value 'magit-log-mode
+ magit-prefix-use-buffer-arguments)))
+ (unless (eq transient-current-command 'magit-dispatch)
+ (when-let ((file (magit-file-relative-name)))
+ (setq files (list file))))
+ (oset obj value (if files `(("--" ,@files) ,args) args))))
+
+(cl-defmethod transient-init-value ((obj magit-log-refresh-prefix))
+ (oset obj value (if magit-buffer-log-files
+ `(("--" ,@magit-buffer-log-files)
+ ,magit-buffer-log-args)
+ magit-buffer-log-args)))
+
+(cl-defmethod transient-set-value ((obj magit-log-prefix))
+ (magit-log--set-value obj))
+
+(cl-defmethod transient-save-value ((obj magit-log-prefix))
+ (magit-log--set-value obj 'save))
+
+;;;; Argument Access
+
+(defun magit-log-arguments (&optional mode)
+ "Return the current log arguments."
+ (if (memq transient-current-command '(magit-log magit-log-refresh))
+ (pcase-let ((`(,args ,alist)
+ (-separate #'atom (transient-get-value))))
+ (list args (cdr (assoc "--" alist))))
+ (magit-log--get-value (or mode 'magit-log-mode))))
+
+(defun magit-log--get-value (mode &optional use-buffer-args)
+ (unless use-buffer-args
+ (setq use-buffer-args magit-direct-use-buffer-arguments))
+ (let (args files)
+ (cond
+ ((and (memq use-buffer-args '(always selected current))
+ (eq major-mode mode))
+ (setq args magit-buffer-log-args)
+ (setq files magit-buffer-log-files))
+ ((and (memq use-buffer-args '(always selected))
+ (when-let ((buffer (magit-get-mode-buffer
+ mode nil
+ (eq use-buffer-args 'selected))))
+ (setq args (buffer-local-value 'magit-buffer-log-args buffer))
+ (setq files (buffer-local-value 'magit-buffer-log-files buffer))
+ t)))
+ ((plist-member (symbol-plist mode) 'magit-log-current-arguments)
+ (setq args (get mode 'magit-log-current-arguments)))
+ ((when-let ((elt (assq (intern (format "magit-log:%s" mode))
+ transient-values)))
+ (setq args (cdr elt))
+ t))
+ (t
+ (setq args (get mode 'magit-log-default-arguments))))
+ (list args files)))
+
+(defun magit-log--set-value (obj &optional save)
+ (pcase-let* ((obj (oref obj prototype))
+ (mode (or (oref obj major-mode) major-mode))
+ (key (intern (format "magit-log:%s" mode)))
+ (`(,args ,alist)
+ (-separate #'atom (transient-get-value)))
+ (files (cdr (assoc "--" alist))))
+ (put mode 'magit-log-current-arguments args)
+ (when save
+ (setf (alist-get key transient-values) args)
+ (transient-save-values))
+ (transient--history-push obj)
+ (setq magit-buffer-log-args args)
+ (unless (derived-mode-p 'magit-log-select-mode)
+ (setq magit-buffer-log-files files))
+ (magit-refresh)))
+
+;;; Commands
+;;;; Prefix Commands
+
+;;;###autoload (autoload 'magit-log "magit-log" nil t)
+(transient-define-prefix magit-log ()
+ "Show a commit or reference log."
+ :man-page "git-log"
+ :class 'magit-log-prefix
+ ;; The grouping in git-log(1) appears to be guided by implementation
+ ;; details, so our logical grouping only follows it to an extend.
+ ;; Arguments that are "misplaced" here:
+ ;; 1. From "Commit Formatting".
+ ;; 2. From "Common Diff Options".
+ ;; 3. From unnamed first group.
+ ;; 4. Implemented by Magit.
+ ["Commit limiting"
+ (magit-log:-n)
+ (magit:--author)
+ (7 "=s" "Limit to commits since" "--since=" transient-read-date)
+ (7 "=u" "Limit to commits until" "--until=" transient-read-date)
+ (magit-log:--grep)
+ (7 "-I" "Invert search pattern" "--invert-grep")
+ (magit-log:-G) ;2
+ (magit-log:-S) ;2
+ (magit-log:-L) ;2
+ (7 "=m" "Omit merges" "--no-merges")
+ (7 "=p" "First parent" "--first-parent")]
+ ["History simplification"
+ ( "-D" "Simplify by decoration" "--simplify-by-decoration")
+ (magit:--)
+ ( "-f" "Follow renames when showing single-file log" "--follow") ;3
+ (6 "/s" "Only commits changing given paths" "--sparse")
+ (7 "/d" "Only selected commits plus meaningful history" "--dense")
+ (7 "/a" "Only commits existing directly on ancestry path" "--ancestry-path")
+ (6 "/f" "Do not prune history" "--full-history")
+ (7 "/m" "Prune some history" "--simplify-merges")]
+ ["Commit ordering"
+ (magit-log:--*-order)
+ ("-r" "Reverse order" "--reverse")]
+ ["Formatting"
+ ("-g" "Show graph" "--graph") ;1
+ ("-c" "Show graph in color" "--color") ;2
+ ("-d" "Show refnames" "--decorate") ;3
+ ("=S" "Show signatures" "--show-signature") ;1
+ ("-h" "Show header" "++header") ;4
+ ("-p" "Show diffs" ("-p" "--patch")) ;2
+ ("-s" "Show diffstats" "--stat")] ;2
+ [["Log"
+ ("l" "current" magit-log-current)
+ ("o" "other" magit-log-other)
+ ("h" "HEAD" magit-log-head)]
+ [""
+ ("L" "local branches" magit-log-branches)
+ (7 "B" "matching branches" magit-log-matching-branches)
+ (7 "T" "matching tags" magit-log-matching-tags)
+ ("b" "all branches" magit-log-all-branches)
+ ("a" "all references" magit-log-all)
+ (7 "m" "merged" magit-log-merged)]
+ ["Reflog"
+ ("r" "current" magit-reflog-current)
+ ("O" "other" magit-reflog-other)
+ ("H" "HEAD" magit-reflog-head)]
+ [:if (lambda ()
+ (require 'magit-wip)
+ (magit--any-wip-mode-enabled-p))
+ :description "Wiplog"
+ ("i" "index" magit-wip-log-index)
+ ("w" "worktree" magit-wip-log-worktree)]
+ ["Other"
+ (5 "s" "shortlog" magit-shortlog)]])
+
+;;;###autoload (autoload 'magit-log-refresh "magit-log" nil t)
+(transient-define-prefix magit-log-refresh ()
+ "Change the arguments used for the log(s) in the current buffer."
+ :man-page "git-log"
+ :class 'magit-log-refresh-prefix
+ [:if-mode magit-log-mode
+ :class transient-subgroups
+ ["Commit limiting"
+ (magit-log:-n)
+ (magit:--author)
+ (magit-log:--grep)
+ (7 "-I" "Invert search pattern" "--invert-grep")
+ (magit-log:-G)
+ (magit-log:-S)
+ (magit-log:-L)]
+ ["History simplification"
+ ( "-D" "Simplify by decoration" "--simplify-by-decoration")
+ (magit:--)
+ ( "-f" "Follow renames when showing single-file log" "--follow") ;3
+ (6 "/s" "Only commits changing given paths" "--sparse")
+ (7 "/d" "Only selected commits plus meaningful history" "--dense")
+ (7 "/a" "Only commits existing directly on ancestry path" "--ancestry-path")
+ (6 "/f" "Do not prune history" "--full-history")
+ (7 "/m" "Prune some history" "--simplify-merges")]
+ ["Commit ordering"
+ (magit-log:--*-order)
+ ("-r" "Reverse order" "--reverse")]
+ ["Formatting"
+ ("-g" "Show graph" "--graph")
+ ("-c" "Show graph in color" "--color")
+ ("-d" "Show refnames" "--decorate")
+ ("=S" "Show signatures" "--show-signature")
+ ("-h" "Show header" "++header")
+ ("-p" "Show diffs" ("-p" "--patch"))
+ ("-s" "Show diffstats" "--stat")]]
+ [:if-not-mode magit-log-mode
+ :description "Arguments"
+ (magit-log:-n)
+ (magit-log:--*-order)
+ ("-g" "Show graph" "--graph")
+ ("-c" "Show graph in color" "--color")
+ ("-d" "Show refnames" "--decorate")]
+ [["Refresh"
+ ("g" "buffer" magit-log-refresh)
+ ("s" "buffer and set defaults" transient-set :transient nil)
+ ("w" "buffer and save defaults" transient-save :transient nil)]
+ ["Margin"
+ ("L" "toggle visibility" magit-toggle-margin)
+ ("l" "cycle style" magit-cycle-margin-style)
+ ("d" "toggle details" magit-toggle-margin-details)
+ ("x" "toggle shortstat" magit-toggle-log-margin-style)]
+ [:if-mode magit-log-mode
+ :description "Toggle"
+ ("b" "buffer lock" magit-toggle-buffer-lock)]]
+ (interactive)
+ (cond
+ ((not (eq transient-current-command 'magit-log-refresh))
+ (pcase major-mode
+ (`magit-reflog-mode
+ (user-error "Cannot change log arguments in reflog buffers"))
+ (`magit-cherry-mode
+ (user-error "Cannot change log arguments in cherry buffers")))
+ (transient-setup 'magit-log-refresh))
+ (t
+ (pcase-let ((`(,args ,files) (magit-log-arguments)))
+ (setq magit-buffer-log-args args)
+ (unless (derived-mode-p 'magit-log-select-mode)
+ (setq magit-buffer-log-files files)))
+ (magit-refresh))))
+
+;;;; Infix Commands
+
+(transient-define-argument magit-log:-n ()
+ :description "Limit number of commits"
+ :class 'transient-option
+ ;; For historic reasons (and because it easy to guess what "-n"
+ ;; stands for) this is the only argument where we do not use the
+ ;; long argument ("--max-count").
+ :shortarg "-n"
+ :argument "-n"
+ :reader 'transient-read-number-N+)
+
+(transient-define-argument magit:--author ()
+ :description "Limit to author"
+ :class 'transient-option
+ :key "-A"
+ :argument "--author="
+ :reader 'magit-transient-read-person)
+
+(transient-define-argument magit-log:--*-order ()
+ :description "Order commits by"
+ :class 'transient-switches
+ :key "-o"
+ :argument-format "--%s-order"
+ :argument-regexp "\\(--\\(topo\\|author-date\\|date\\)-order\\)"
+ :choices '("topo" "author-date" "date"))
+
+(transient-define-argument magit-log:--grep ()
+ :description "Search messages"
+ :class 'transient-option
+ :key "-F"
+ :argument "--grep=")
+
+(transient-define-argument magit-log:-G ()
+ :description "Search changes"
+ :class 'transient-option
+ :argument "-G")
+
+(transient-define-argument magit-log:-S ()
+ :description "Search occurrences"
+ :class 'transient-option
+ :argument "-S")
+
+(transient-define-argument magit-log:-L ()
+ :description "Trace line evolution"
+ :class 'transient-option
+ :argument "-L"
+ :reader 'magit-read-file-trace)
+
+(defun magit-read-file-trace (&rest _ignored)
+ (let ((file (magit-read-file-from-rev "HEAD" "File"))
+ (trace (magit-read-string "Trace")))
+ (concat trace ":" file)))
+
+;;;; Setup Commands
+
+(defvar magit-log-read-revs-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map crm-local-completion-map)
+ (define-key map "\s" 'self-insert-command)
+ map))
+
+(defun magit-log-read-revs (&optional use-current)
+ (or (and use-current (--when-let (magit-get-current-branch) (list it)))
+ (let ((collection (magit-list-refnames nil t)))
+ (split-string
+ (magit-completing-read-multiple "Log rev,s" collection
+ "\\(\\.\\.\\.?\\|[, ]\\)"
+ (or (magit-branch-or-commit-at-point)
+ (unless use-current
+ (magit-get-previous-branch)))
+ 'magit-revision-history
+ magit-log-read-revs-map)
+ "[, ]" t))))
+
+(defun magit-log-read-pattern (option)
+ "Read a string from the user to pass as parameter to OPTION."
+ (magit-read-string (format "Type a pattern to pass to %s" option)))
+
+;;;###autoload
+(defun magit-log-current (revs &optional args files)
+ "Show log for the current branch.
+When `HEAD' is detached or with a prefix argument show log for
+one or more revs read from the minibuffer."
+ (interactive (cons (magit-log-read-revs t)
+ (magit-log-arguments)))
+ (magit-log-setup-buffer revs args files))
+
+;;;###autoload
+(defun magit-log-other (revs &optional args files)
+ "Show log for one or more revs read from the minibuffer.
+The user can input any revision or revisions separated by a
+space, or even ranges, but only branches and tags, and a
+representation of the commit at point, are available as
+completion candidates."
+ (interactive (cons (magit-log-read-revs)
+ (magit-log-arguments)))
+ (magit-log-setup-buffer revs args files))
+
+;;;###autoload
+(defun magit-log-head (&optional args files)
+ "Show log for `HEAD'."
+ (interactive (magit-log-arguments))
+ (magit-log-setup-buffer (list "HEAD") args files))
+
+;;;###autoload
+(defun magit-log-branches (&optional args files)
+ "Show log for all local branches and `HEAD'."
+ (interactive (magit-log-arguments))
+ (magit-log-setup-buffer (if (magit-get-current-branch)
+ (list "--branches")
+ (list "HEAD" "--branches"))
+ args files))
+
+;;;###autoload
+(defun magit-log-matching-branches (pattern &optional args files)
+ "Show log for all branches matching PATTERN and `HEAD'."
+ (interactive (cons (magit-log-read-pattern "--branches") (magit-log-arguments)))
+ (magit-log-setup-buffer
+ (list "HEAD" (format "--branches=%s" pattern))
+ args files))
+
+;;;###autoload
+(defun magit-log-matching-tags (pattern &optional args files)
+ "Show log for all tags matching PATTERN and `HEAD'."
+ (interactive (cons (magit-log-read-pattern "--tags") (magit-log-arguments)))
+ (magit-log-setup-buffer
+ (list "HEAD" (format "--tags=%s" pattern))
+ args files))
+
+;;;###autoload
+(defun magit-log-all-branches (&optional args files)
+ "Show log for all local and remote branches and `HEAD'."
+ (interactive (magit-log-arguments))
+ (magit-log-setup-buffer (if (magit-get-current-branch)
+ (list "--branches" "--remotes")
+ (list "HEAD" "--branches" "--remotes"))
+ args files))
+
+;;;###autoload
+(defun magit-log-all (&optional args files)
+ "Show log for all references and `HEAD'."
+ (interactive (magit-log-arguments))
+ (magit-log-setup-buffer (if (magit-get-current-branch)
+ (list "--all")
+ (list "HEAD" "--all"))
+ args files))
+
+;;;###autoload
+(defun magit-log-buffer-file (&optional follow beg end)
+ "Show log for the blob or file visited in the current buffer.
+With a prefix argument or when `--follow' is an active log
+argument, then follow renames. When the region is active,
+restrict the log to the lines that the region touches."
+ (interactive
+ (cons current-prefix-arg
+ (and (region-active-p)
+ (magit-file-relative-name)
+ (save-restriction
+ (widen)
+ (list (line-number-at-pos (region-beginning))
+ (line-number-at-pos
+ (let ((end (region-end)))
+ (if (char-after end)
+ end
+ ;; Ensure that we don't get the line number
+ ;; of a trailing newline.
+ (1- end)))))))))
+ (require 'magit)
+ (if-let ((file (magit-file-relative-name)))
+ (magit-log-setup-buffer
+ (list (or magit-buffer-refname
+ (magit-get-current-branch)
+ "HEAD"))
+ (let ((args (car (magit-log-arguments))))
+ (when (and follow (not (member "--follow" args)))
+ (push "--follow" args))
+ (when (and (file-regular-p
+ (expand-file-name file (magit-toplevel)))
+ beg end)
+ (setq args (cons (format "-L%s,%s:%s" beg end file)
+ (cl-delete "-L" args :test
+ 'string-prefix-p)))
+ (setq file nil))
+ args)
+ (and file (list file))
+ magit-log-buffer-file-locked)
+ (user-error "Buffer isn't visiting a file")))
+
+;;;###autoload
+(defun magit-log-trace-definition (file fn rev)
+ "Show log for the definition at point."
+ (interactive (list (or (magit-file-relative-name)
+ (user-error "Buffer isn't visiting a file"))
+ (or (funcall magit-log-trace-definition-function)
+ (user-error "No function at point found"))
+ (or magit-buffer-refname
+ (magit-get-current-branch)
+ "HEAD")))
+ (require 'magit)
+ (magit-log-setup-buffer
+ (list rev)
+ (cons (format "-L:%s%s:%s"
+ (replace-regexp-in-string ":" "\\:" (regexp-quote fn) nil t)
+ (if (derived-mode-p 'lisp-mode 'emacs-lisp-mode)
+ ;; Git doesn't treat "-" the same way as
+ ;; "_", leading to false-positives such as
+ ;; "foo-suffix" being considered a match
+ ;; for "foo". Wing it.
+ "\\( \\|$\\)"
+ ;; We could use "\\b" here, but since Git
+ ;; already does something equivalent, that
+ ;; isn't necessary.
+ "")
+ file)
+ (cl-delete "-L" (car (magit-log-arguments))
+ :test 'string-prefix-p))
+ nil magit-log-buffer-file-locked))
+
+(defun magit-diff-trace-definition ()
+ "Show log for the definition at point in a diff."
+ (interactive)
+ (pcase-let ((`(,buf ,pos) (magit-diff-visit-file--noselect)))
+ (magit--with-temp-position buf pos
+ (call-interactively #'magit-log-trace-definition))))
+
+;;;###autoload
+(defun magit-log-merged (commit branch &optional args files)
+ "Show log for the merge of COMMIT into BRANCH.
+
+More precisely, find merge commit M that brought COMMIT into
+BRANCH, and show the log of the range \"M^1..M\". If COMMIT is
+directly on BRANCH, then show approximately twenty surrounding
+commits instead.
+
+This command requires git-when-merged, which is available from
+https://github.com/mhagger/git-when-merged."
+ (interactive
+ (append (let ((commit (magit-read-branch-or-commit "Commit")))
+ (list commit
+ (magit-read-other-branch "Merged into" commit)))
+ (magit-log-arguments)))
+ (unless (executable-find "git-when-merged")
+ (user-error "This command requires git-when-merged (%s)"
+ "https://github.com/mhagger/git-when-merged"))
+ (let (exit m)
+ (with-temp-buffer
+ (save-excursion
+ (setq exit (magit-process-file
+ magit-git-executable nil t nil
+ "when-merged" "-c"
+ "--abbrev" (number-to-string (magit-abbrev-length))
+ commit branch)))
+ (setq m (buffer-substring-no-properties (point) (line-end-position))))
+ (if (zerop exit)
+ (magit-log-setup-buffer (list (format "%s^1..%s" m m))
+ args files nil commit)
+ (setq m (string-trim-left (substring m (string-match " " m))))
+ (if (equal m "Commit is directly on this branch.")
+ (let* ((from (concat commit "~10"))
+ (to (- (car (magit-rev-diff-count branch commit)) 10))
+ (to (if (<= to 0)
+ branch
+ (format "%s~%s" branch to))))
+ (unless (magit-rev-verify-commit from)
+ (setq from (magit-git-string "rev-list" "--max-parents=0"
+ commit)))
+ (magit-log-setup-buffer (list (concat from ".." to))
+ (cons "--first-parent" args)
+ files nil commit))
+ (user-error "Could not find when %s was merged into %s: %s"
+ commit branch m)))))
+
+;;;; Limit Commands
+
+(defun magit-log-toggle-commit-limit ()
+ "Toggle the number of commits the current log buffer is limited to.
+If the number of commits is currently limited, then remove that
+limit. Otherwise set it to 256."
+ (interactive)
+ (magit-log-set-commit-limit (lambda (&rest _) nil)))
+
+(defun magit-log-double-commit-limit ()
+ "Double the number of commits the current log buffer is limited to."
+ (interactive)
+ (magit-log-set-commit-limit '*))
+
+(defun magit-log-half-commit-limit ()
+ "Half the number of commits the current log buffer is limited to."
+ (interactive)
+ (magit-log-set-commit-limit '/))
+
+(defun magit-log-set-commit-limit (fn)
+ (let* ((val magit-buffer-log-args)
+ (arg (--first (string-match "^-n\\([0-9]+\\)?$" it) val))
+ (num (and arg (string-to-number (match-string 1 arg))))
+ (num (if num (funcall fn num 2) 256)))
+ (setq val (delete arg val))
+ (setq magit-buffer-log-args
+ (if (and num (> num 0))
+ (cons (format "-n%i" num) val)
+ val)))
+ (magit-refresh))
+
+(defun magit-log-get-commit-limit ()
+ (--when-let (--first (string-match "^-n\\([0-9]+\\)?$" it)
+ magit-buffer-log-args)
+ (string-to-number (match-string 1 it))))
+
+;;;; Mode Commands
+
+(defun magit-log-bury-buffer (&optional arg)
+ "Bury the current buffer or the revision buffer in the same frame.
+Like `magit-mode-bury-buffer' (which see) but with a negative
+prefix argument instead bury the revision buffer, provided it
+is displayed in the current frame."
+ (interactive "p")
+ (if (< arg 0)
+ (let* ((buf (magit-get-mode-buffer 'magit-revision-mode))
+ (win (and buf (get-buffer-window buf (selected-frame)))))
+ (if win
+ (with-selected-window win
+ (with-current-buffer buf
+ (magit-mode-bury-buffer (> (abs arg) 1))))
+ (user-error "No revision buffer in this frame")))
+ (magit-mode-bury-buffer (> arg 1))))
+
+;;;###autoload
+(defun magit-log-move-to-parent (&optional n)
+ "Move to the Nth parent of the current commit."
+ (interactive "p")
+ (when (derived-mode-p 'magit-log-mode)
+ (when (magit-section-match 'commit)
+ (let* ((section (magit-current-section))
+ (parent-rev (format "%s^%s" (oref section value) (or n 1))))
+ (if-let ((parent-hash (magit-rev-parse "--short" parent-rev)))
+ (if-let ((parent (--first (equal (oref it value)
+ parent-hash)
+ (magit-section-siblings section 'next))))
+ (magit-section-goto parent)
+ (user-error
+ (substitute-command-keys
+ (concat "Parent " parent-hash " not found. Try typing "
+ "\\[magit-log-double-commit-limit] first"))))
+ (user-error "Parent %s does not exist" parent-rev))))))
+
+;;;; 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)
+ (with-current-buffer (get-buffer-create "*magit-shortlog*")
+ (erase-buffer)
+ (save-excursion
+ (magit-git-insert "shortlog" args rev))
+ (switch-to-buffer-other-window (current-buffer))))
+
+;;;###autoload
+(defun magit-shortlog-since (rev args)
+ "Show a history summary for commits since REV."
+ (interactive
+ (list (magit-read-branch-or-commit "Shortlog since" (magit-get-current-tag))
+ (transient-args 'magit-shortlog)))
+ (magit-git-shortlog (concat rev "..") args))
+
+;;;###autoload
+(defun magit-shortlog-range (rev-or-range args)
+ "Show a history summary for commit or range REV-OR-RANGE."
+ (interactive
+ (list (magit-read-range-or-commit "Shortlog for revision or range")
+ (transient-args 'magit-shortlog)))
+ (magit-git-shortlog rev-or-range args))
+
+;;; Log Mode
+
+(defvar magit-log-disable-graph-hack-args
+ '("-G" "--grep" "--author")
+ "Arguments which disable the graph speedup hack.")
+
+(defvar magit-log-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-mode-map)
+ (define-key map "\C-c\C-b" 'magit-go-backward)
+ (define-key map "\C-c\C-f" 'magit-go-forward)
+ (define-key map "\C-c\C-n" 'magit-log-move-to-parent)
+ (define-key map "=" 'magit-log-toggle-commit-limit)
+ (define-key map "+" 'magit-log-double-commit-limit)
+ (define-key map "-" 'magit-log-half-commit-limit)
+ (define-key map "q" 'magit-log-bury-buffer)
+ map)
+ "Keymap for `magit-log-mode'.")
+
+(define-derived-mode magit-log-mode magit-mode "Magit Log"
+ "Mode for looking at Git log.
+
+This mode is documented in info node `(magit)Log Buffer'.
+
+\\<magit-mode-map>\
+Type \\[magit-refresh] to refresh the current buffer.
+Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
+to visit the commit at point.
+
+Type \\[magit-branch] to see available branch commands.
+Type \\[magit-merge] to merge the branch or commit at point.
+Type \\[magit-cherry-pick] to apply the commit at point.
+Type \\[magit-reset] to reset `HEAD' to the commit at point.
+
+\\{magit-log-mode-map}"
+ :group 'magit-log
+ (hack-dir-local-variables-non-file-buffer)
+ (setq imenu-prev-index-position-function
+ 'magit-imenu--log-prev-index-position-function)
+ (setq imenu-extract-index-name-function
+ 'magit-imenu--log-extract-index-name-function))
+
+(put 'magit-log-mode 'magit-log-default-arguments
+ '("--graph" "-n256" "--decorate"))
+
+(defun magit-log-setup-buffer (revs args files &optional locked focus)
+ (require 'magit)
+ (with-current-buffer
+ (magit-setup-buffer #'magit-log-mode locked
+ (magit-buffer-revisions revs)
+ (magit-buffer-log-args args)
+ (magit-buffer-log-files files))
+ (when (if focus
+ (magit-log-goto-commit-section focus)
+ (magit-log-goto-same-commit))
+ (magit-section-update-highlight))
+ (current-buffer)))
+
+(defun magit-log-refresh-buffer ()
+ (let ((revs magit-buffer-revisions)
+ (args magit-buffer-log-args)
+ (files magit-buffer-log-files))
+ (magit-set-header-line-format
+ (funcall magit-log-header-line-function revs args files))
+ (if (= (length files) 1)
+ (unless (magit-file-tracked-p (car files))
+ (setq args (cons "--full-history" args)))
+ (setq args (remove "--follow" args)))
+ (when (and (car magit-log-remove-graph-args)
+ (--any-p (string-match-p
+ (concat "^" (regexp-opt magit-log-remove-graph-args)) it)
+ args))
+ (setq args (remove "--graph" args)))
+ (unless (member "--graph" args)
+ (setq args (remove "--color" args)))
+ (when-let ((limit (magit-log-get-commit-limit))
+ (limit (* 2 limit)) ; increase odds for complete graph
+ (count (and (= (length revs) 1)
+ (> limit 1024) ; otherwise it's fast enough
+ (setq revs (car revs))
+ (not (string-match-p "\\.\\." revs))
+ (not (member revs '("--all" "--branches")))
+ (-none-p (lambda (arg)
+ (--any-p (string-prefix-p it arg)
+ magit-log-disable-graph-hack-args))
+ args)
+ (magit-git-string "rev-list" "--count"
+ "--first-parent" args revs))))
+ (setq revs (if (< (string-to-number count) limit)
+ revs
+ (format "%s~%s..%s" revs limit revs))))
+ (magit-insert-section (logbuf)
+ (magit-insert-log revs args files))))
+
+(cl-defmethod magit-buffer-value (&context (major-mode magit-log-mode))
+ (append magit-buffer-revisions
+ (if (and magit-buffer-revisions magit-buffer-log-files)
+ (cons "--" magit-buffer-log-files)
+ magit-buffer-log-files)))
+
+(defun magit-log-header-line-arguments (revs args files)
+ "Return string describing some of the used arguments."
+ (mapconcat (lambda (arg)
+ (if (string-match-p " " arg)
+ (prin1 arg)
+ arg))
+ `("git" "log" ,@args ,@revs "--" ,@files)
+ " "))
+
+(defun magit-log-header-line-sentence (revs args files)
+ "Return string containing all arguments."
+ (concat "Commits in "
+ (mapconcat #'identity revs " ")
+ (and (member "--reverse" args)
+ " in reverse")
+ (and files (concat " touching "
+ (mapconcat 'identity files " ")))
+ (--some (and (string-prefix-p "-L" it)
+ (concat " " it))
+ args)))
+
+(defun magit-insert-log (revs &optional args files)
+ "Insert a log section.
+Do not add this to a hook variable."
+ (let ((magit-git-global-arguments
+ (remove "--literal-pathspecs" magit-git-global-arguments)))
+ (magit-git-wash (apply-partially #'magit-log-wash-log 'log)
+ "log"
+ (format "--format=%s%%h%%x0c%s%%x0c%s%%x0c%%aN%%x0c%s%%x0c%%s%s"
+ (if (and (member "--left-right" args)
+ (not (member "--graph" args)))
+ "%m "
+ "")
+ (if (member "--decorate" args) "%D" "")
+ (if (member "--show-signature" args)
+ (progn (setq args (remove "--show-signature" args)) "%G?")
+ "")
+ (if magit-log-margin-show-committer-date "%ct" "%at")
+ (if (member "++header" args)
+ (if (member "--graph" (setq args (remove "++header" args)))
+ (concat "\n" magit-log-revision-headers-format "\n")
+ (concat "\n\1e" magit-log-revision-headers-format "\1e\n"))
+ ""))
+ (progn
+ (--when-let (--first (string-match "^\\+\\+order=\\(.+\\)$" it) args)
+ (setq args (cons (format "--%s-order" (match-string 1 it))
+ (remove it args))))
+ (when (member "--decorate" args)
+ (setq args (cons "--decorate=full" (remove "--decorate" args))))
+ (when (member "--reverse" args)
+ (setq args (remove "--graph" args)))
+ (setq args (magit-diff--maybe-add-stat-arguments args))
+ args)
+ "--use-mailmap" "--no-prefix" revs "--" files)))
+
+(defvar magit-commit-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-show-commit)
+ (define-key map "a" 'magit-cherry-apply)
+ map)
+ "Keymap for `commit' sections.")
+
+(defvar magit-module-commit-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-show-commit)
+ map)
+ "Keymap for `module-commit' sections.")
+
+(defconst magit-log-heading-re
+ ;; Note: A form feed instead of a null byte is used as the delimiter
+ ;; because using the latter interferes with the graph prefix when
+ ;; ++header is used.
+ (concat "^"
+ "\\(?4:[-_/|\\*o<>. ]*\\)" ; graph
+ "\\(?1:[0-9a-fA-F]+\\)?\f" ; sha1
+ "\\(?3:[^\f\n]+\\)?\f" ; refs
+ "\\(?7:[BGUXYREN]\\)?\f" ; gpg
+ "\\(?5:[^\f\n]*\\)\f" ; author
+ ;; Note: Date is optional because, prior to Git v2.19.0,
+ ;; `git rebase -i --root` corrupts the root's author date.
+ "\\(?6:[^\f\n]*\\)\f" ; date
+ "\\(?2:.*\\)$")) ; msg
+
+(defconst magit-log-cherry-re
+ (concat "^"
+ "\\(?8:[-+]\\) " ; cherry
+ "\\(?1:[0-9a-fA-F]+\\) " ; sha1
+ "\\(?2:.*\\)$")) ; msg
+
+(defconst magit-log-module-re
+ (concat "^"
+ "\\(?:\\(?11:[<>]\\) \\)?" ; side
+ "\\(?1:[0-9a-fA-F]+\\) " ; sha1
+ "\\(?2:.*\\)$")) ; msg
+
+(defconst magit-log-bisect-vis-re
+ (concat "^"
+ "\\(?4:[-_/|\\*o<>. ]*\\)" ; graph
+ "\\(?1:[0-9a-fA-F]+\\)?\0" ; sha1
+ "\\(?3:[^\0\n]+\\)?\0" ; refs
+ "\\(?2:.*\\)$")) ; msg
+
+(defconst magit-log-bisect-log-re
+ (concat "^# "
+ "\\(?3:[^: \n]+:\\) " ; "refs"
+ "\\[\\(?1:[^]\n]+\\)\\] " ; sha1
+ "\\(?2:.*\\)$")) ; msg
+
+(defconst magit-log-reflog-re
+ (concat "^"
+ "\\(?1:[^\0\n]+\\)\0" ; sha1
+ "\\(?5:[^\0\n]*\\)\0" ; author
+ "\\(?:\\(?:[^@\n]+@{\\(?6:[^}\n]+\\)}\0" ; date
+ "\\(?10:merge \\|autosave \\|restart \\|[^:\n]+: \\)?" ; refsub
+ "\\(?2:.*\\)?\\)\\|\0\\)$")) ; msg
+
+(defconst magit-reflog-subject-re
+ (concat "\\(?1:[^ ]+\\) ?" ; command
+ "\\(?2:\\(?: ?-[^ ]+\\)+\\)?" ; option
+ "\\(?: ?(\\(?3:[^)]+\\))\\)?")) ; type
+
+(defconst magit-log-stash-re
+ (concat "^"
+ "\\(?1:[^\0\n]+\\)\0" ; "sha1"
+ "\\(?5:[^\0\n]*\\)\0" ; author
+ "\\(?6:[^\0\n]+\\)\0" ; date
+ "\\(?2:.*\\)$")) ; msg
+
+(defvar magit-log-count nil)
+
+(defvar magit-log-format-message-function 'magit-log-propertize-keywords)
+
+(defun magit-log-wash-log (style args)
+ (setq args (-flatten args))
+ (when (and (member "--graph" args)
+ (member "--color" args))
+ (let ((ansi-color-apply-face-function
+ (lambda (beg end face)
+ (put-text-property beg end 'font-lock-face
+ (or face 'magit-log-graph)))))
+ (ansi-color-apply-on-region (point-min) (point-max))))
+ (when (eq style 'cherry)
+ (reverse-region (point-min) (point-max)))
+ (let ((magit-log-count 0))
+ (when (looking-at "^\\.\\.\\.")
+ (magit-delete-line))
+ (magit-wash-sequence (apply-partially 'magit-log-wash-rev style
+ (magit-abbrev-length)))
+ (if (derived-mode-p 'magit-log-mode 'magit-reflog-mode)
+ (when (eq magit-log-count (magit-log-get-commit-limit))
+ (magit-insert-section (longer)
+ (insert-text-button
+ (substitute-command-keys
+ (format "Type \\<%s>\\[%s] to show more history"
+ 'magit-log-mode-map
+ 'magit-log-double-commit-limit))
+ 'action (lambda (_button)
+ (magit-log-double-commit-limit))
+ 'follow-link t
+ 'mouse-face 'magit-section-highlight)))
+ (insert ?\n))))
+
+(cl-defun magit-log-wash-rev (style abbrev)
+ (when (derived-mode-p 'magit-log-mode 'magit-reflog-mode)
+ (cl-incf magit-log-count))
+ (looking-at (pcase style
+ (`log magit-log-heading-re)
+ (`cherry magit-log-cherry-re)
+ (`module magit-log-module-re)
+ (`reflog magit-log-reflog-re)
+ (`stash magit-log-stash-re)
+ (`bisect-vis magit-log-bisect-vis-re)
+ (`bisect-log magit-log-bisect-log-re)))
+ (magit-bind-match-strings
+ (hash msg refs graph author date gpg cherry _ refsub side) nil
+ (setq msg (substring-no-properties msg))
+ (when refs
+ (setq refs (substring-no-properties refs)))
+ (let ((align (or (eq style 'cherry)
+ (not (member "--stat" magit-buffer-log-args))))
+ (non-graph-re (if (eq style 'bisect-vis)
+ magit-log-bisect-vis-re
+ magit-log-heading-re)))
+ (magit-delete-line)
+ ;; If the reflog entries have been pruned, the output of `git
+ ;; reflog show' includes a partial line that refers to the hash
+ ;; of the youngest expired reflog entry.
+ (when (and (eq style 'reflog) (not date))
+ (cl-return-from magit-log-wash-rev t))
+ (magit-insert-section section (commit hash)
+ (pcase style
+ (`stash (oset section type 'stash))
+ (`module (oset section type 'module-commit))
+ (`bisect-log (setq hash (magit-rev-parse "--short" hash))))
+ (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 (propertize hash 'font-lock-face 'magit-hash) ?\s))
+ (when graph
+ (insert graph))
+ (unless align
+ (insert (propertize hash 'font-lock-face 'magit-hash) ?\s))
+ (when (and refs (not magit-log-show-refname-after-summary))
+ (insert (magit-format-ref-labels refs) ?\s))
+ (when (eq style 'reflog)
+ (insert (format "%-2s " (1- magit-log-count)))
+ (when refsub
+ (insert (magit-reflog-format-subject
+ (substring refsub 0 (if (string-match-p ":" refsub) -2 -1))))))
+ (when msg
+ (when gpg
+ (setq msg (propertize msg 'font-lock-face
+ (pcase (aref gpg 0)
+ (?G 'magit-signature-good)
+ (?B 'magit-signature-bad)
+ (?U 'magit-signature-untrusted)
+ (?X 'magit-signature-expired)
+ (?Y 'magit-signature-expired-key)
+ (?R 'magit-signature-revoked)
+ (?E 'magit-signature-error)))))
+ (insert (funcall magit-log-format-message-function hash msg)))
+ (when (and refs magit-log-show-refname-after-summary)
+ (insert ?\s)
+ (insert (magit-format-ref-labels refs)))
+ (insert ?\n)
+ (when (memq style '(log reflog stash))
+ (goto-char (line-beginning-position))
+ (when (and refsub
+ (string-match "\\`\\([^ ]\\) \\+\\(..\\)\\(..\\)" date))
+ (setq date (+ (string-to-number (match-string 1 date))
+ (* (string-to-number (match-string 2 date)) 60 60)
+ (* (string-to-number (match-string 3 date)) 60))))
+ (save-excursion
+ (backward-char)
+ (magit-log-format-margin hash author date)))
+ (when (and (eq style 'cherry)
+ (magit-buffer-margin-p))
+ (save-excursion
+ (backward-char)
+ (apply #'magit-log-format-margin hash
+ (split-string (magit-rev-format "%aN%x00%ct" hash) "\0"))))
+ (when (and graph
+ (not (eobp))
+ (not (looking-at non-graph-re)))
+ (when (looking-at "\1e")
+ (magit-insert-heading)
+ (delete-char 1)
+ (magit-insert-section (commit-header)
+ (forward-line)
+ (magit-insert-heading)
+ (re-search-forward "\1e")
+ (backward-delete-char 1)
+ (forward-char)
+ (insert ?\n))
+ (delete-char 1))
+ (if (looking-at "^\\(---\\|\n\s\\|\ndiff\\)")
+ (let ((limit (save-excursion
+ (and (re-search-forward non-graph-re nil t)
+ (match-beginning 0)))))
+ (unless (oref magit-insert-section--current content)
+ (magit-insert-heading))
+ (delete-char (if (looking-at "\n") 1 4))
+ (magit-diff-wash-diffs (list "--stat") limit))
+ (when align
+ (setq align (make-string (1+ abbrev) ? )))
+ (when (and (not (eobp)) (not (looking-at non-graph-re)))
+ (when align
+ (setq align (make-string (1+ abbrev) ? )))
+ (while (and (not (eobp)) (not (looking-at non-graph-re)))
+ (when align
+ (save-excursion (insert align)))
+ (magit-make-margin-overlay)
+ (forward-line))
+ ;; When `--format' is used and its value isn't one of the
+ ;; predefined formats, then `git-log' does not insert a
+ ;; separator line.
+ (save-excursion
+ (forward-line -1)
+ (looking-at "[-_/|\\*o<>. ]*"))
+ (setq graph (match-string 0))
+ (unless (string-match-p "[/\\.]" graph)
+ (insert graph ?\n))))))))
+ t)
+
+(defun magit-log-propertize-keywords (_rev msg)
+ (let ((boundary 0))
+ (when (string-match "^\\(?:squash\\|fixup\\)! " msg boundary)
+ (setq boundary (match-end 0))
+ (magit--put-face (match-beginning 0) (1- boundary)
+ 'magit-keyword-squash msg))
+ (when magit-log-highlight-keywords
+ (while (string-match "\\[[^[]*?]" msg boundary)
+ (setq boundary (match-end 0))
+ (magit--put-face (match-beginning 0) boundary
+ 'magit-keyword msg))))
+ msg)
+
+(defun magit-log-maybe-show-more-commits (section)
+ "When point is at the end of a log buffer, insert more commits.
+
+Log buffers end with a button \"Type + to show more history\".
+When the use of a section movement command puts point on that
+button, then automatically show more commits, without the user
+having to press \"+\".
+
+This function is called by `magit-section-movement-hook' and
+exists mostly for backward compatibility reasons."
+ (when (and (eq (oref section type) 'longer)
+ magit-log-auto-more)
+ (magit-log-double-commit-limit)
+ (forward-line -1)
+ (magit-section-forward)))
+
+(add-hook 'magit-section-movement-hook #'magit-log-maybe-show-more-commits)
+
+(defvar magit--update-revision-buffer nil)
+
+(defun magit-log-maybe-update-revision-buffer (&optional _)
+ "When moving in a log or cherry buffer, update the revision buffer.
+If there is no revision buffer in the same frame, then do nothing."
+ (when (derived-mode-p 'magit-log-mode 'magit-cherry-mode 'magit-reflog-mode)
+ (magit--maybe-update-revision-buffer)))
+
+(add-hook 'magit-section-movement-hook #'magit-log-maybe-update-revision-buffer)
+
+(defun magit--maybe-update-revision-buffer ()
+ (when-let ((commit (magit-section-value-if 'commit))
+ (buffer (magit-get-mode-buffer 'magit-revision-mode nil t)))
+ (if magit--update-revision-buffer
+ (setq magit--update-revision-buffer (list commit buffer))
+ (setq magit--update-revision-buffer (list commit buffer))
+ (run-with-idle-timer
+ magit-update-other-window-delay nil
+ (let ((args (with-current-buffer buffer
+ (let ((magit-direct-use-buffer-arguments 'selected))
+ (magit-show-commit--arguments)))))
+ (lambda ()
+ (pcase-let ((`(,rev ,buf) magit--update-revision-buffer))
+ (setq magit--update-revision-buffer nil)
+ (when (buffer-live-p buf)
+ (let ((magit-display-buffer-noselect t))
+ (apply #'magit-show-commit rev args))))
+ (setq magit--update-revision-buffer nil)))))))
+
+(defvar magit--update-blob-buffer nil)
+
+(defun magit-log-maybe-update-blob-buffer (&optional _)
+ "When moving in a log or cherry buffer, update the blob buffer.
+If there is no blob buffer in the same frame, then do nothing."
+ (when (derived-mode-p 'magit-log-mode 'magit-cherry-mode 'magit-reflog-mode)
+ (magit--maybe-update-blob-buffer)))
+
+(defun magit--maybe-update-blob-buffer ()
+ (when-let ((commit (magit-section-value-if 'commit))
+ (buffer (--first (with-current-buffer it
+ (eq revert-buffer-function
+ 'magit-revert-rev-file-buffer))
+ (mapcar #'window-buffer (window-list)))))
+ (if magit--update-blob-buffer
+ (setq magit--update-blob-buffer (list commit buffer))
+ (setq magit--update-blob-buffer (list commit buffer))
+ (run-with-idle-timer
+ magit-update-other-window-delay nil
+ (lambda ()
+ (pcase-let ((`(,rev ,buf) magit--update-blob-buffer))
+ (setq magit--update-blob-buffer nil)
+ (when (buffer-live-p buf)
+ (with-selected-window (get-buffer-window buf)
+ (with-current-buffer buf
+ (save-excursion
+ (magit-blob-visit (list (magit-rev-parse rev)
+ (magit-file-relative-name
+ magit-buffer-file-name))
+ (line-number-at-pos))))))))))))
+
+(defun magit-log-goto-commit-section (rev)
+ (let ((abbrev (magit-rev-format "%h" rev)))
+ (when-let ((section (--first (equal (oref it value) abbrev)
+ (oref magit-root-section children))))
+ (goto-char (oref section start)))))
+
+(defun magit-log-goto-same-commit ()
+ (when (and magit-previous-section
+ (magit-section-match '(commit branch)
+ magit-previous-section))
+ (magit-log-goto-commit-section (oref magit-previous-section value))))
+
+;;; Log Margin
+
+(defvar-local magit-log-margin-show-shortstat nil)
+
+(defun magit-toggle-log-margin-style ()
+ "Toggle between the regular and the shortstat margin style.
+The shortstat style is experimental and rather slow."
+ (interactive)
+ (setq magit-log-margin-show-shortstat
+ (not magit-log-margin-show-shortstat))
+ (magit-set-buffer-margin nil t))
+
+(defun magit-log-format-margin (rev author date)
+ (when (magit-margin-option)
+ (if magit-log-margin-show-shortstat
+ (magit-log-format-shortstat-margin rev)
+ (magit-log-format-author-margin author date))))
+
+(defun magit-log-format-author-margin (author date &optional previous-line)
+ (pcase-let ((`(,_ ,style ,width ,details ,details-width)
+ (or magit-buffer-margin
+ (symbol-value (magit-margin-option)))))
+ (magit-make-margin-overlay
+ (concat (and details
+ (concat (magit--propertize-face
+ (truncate-string-to-width
+ (or author "")
+ details-width
+ nil ?\s (make-string 1 magit-ellipsis))
+ 'magit-log-author)
+ " "))
+ (magit--propertize-face
+ (if (stringp style)
+ (format-time-string
+ style
+ (seconds-to-time (string-to-number date)))
+ (pcase-let* ((abbr (eq style 'age-abbreviated))
+ (`(,cnt ,unit) (magit--age date abbr)))
+ (format (format (if abbr "%%2i%%-%ic" "%%2i %%-%is")
+ (- width (if details (1+ details-width) 0)))
+ cnt unit)))
+ 'magit-log-date))
+ previous-line)))
+
+(defun magit-log-format-shortstat-margin (rev)
+ (magit-make-margin-overlay
+ (if-let ((line (and rev (magit-git-string
+ "show" "--format=" "--shortstat" rev))))
+ (if (string-match "\
+\\([0-9]+\\) files? changed, \
+\\(?:\\([0-9]+\\) insertions?(\\+)\\)?\
+\\(?:\\(?:, \\)?\\([0-9]+\\) deletions?(-)\\)?\\'" line)
+ (magit-bind-match-strings (files add del) line
+ (format
+ "%5s %5s%4s"
+ (if add
+ (magit--propertize-face (format "%s+" add)
+ 'magit-diffstat-added)
+ "")
+ (if del
+ (magit--propertize-face (format "%s-" del)
+ 'magit-diffstat-removed)
+ "")
+ files))
+ "")
+ "")))
+
+(defun magit-log-margin-width (style details details-width)
+ (if magit-log-margin-show-shortstat
+ 16
+ (+ (if details (1+ details-width) 0)
+ (if (stringp style)
+ (length (format-time-string style))
+ (+ 2 ; two digits
+ 1 ; trailing space
+ (if (eq style 'age-abbreviated)
+ 1 ; single character
+ (+ 1 ; gap after digits
+ (apply #'max (--map (max (length (nth 1 it))
+ (length (nth 2 it)))
+ magit--age-spec)))))))))
+
+;;; Select Mode
+
+(defvar magit-log-select-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-log-mode-map)
+ (define-key map "\C-c\C-b" 'undefined)
+ (define-key map "\C-c\C-f" 'undefined)
+ (define-key map "." 'magit-log-select-pick)
+ (define-key map "e" 'magit-log-select-pick)
+ (define-key map "\C-c\C-c" 'magit-log-select-pick)
+ (define-key map "q" 'magit-log-select-quit)
+ (define-key map "\C-c\C-k" 'magit-log-select-quit)
+ map)
+ "Keymap for `magit-log-select-mode'.")
+
+(put 'magit-log-select-pick :advertised-binding [?\C-c ?\C-c])
+(put 'magit-log-select-quit :advertised-binding [?\C-c ?\C-k])
+
+(define-derived-mode magit-log-select-mode magit-log-mode "Magit Select"
+ "Mode for selecting a commit from history.
+
+This mode is documented in info node `(magit)Select from Log'.
+
+\\<magit-mode-map>\
+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.
+
+\\<magit-log-select-mode-map>\
+Type \\[magit-log-select-pick] to select the commit at point.
+Type \\[magit-log-select-quit] to abort without selecting a commit."
+ :group 'magit-log
+ (hack-dir-local-variables-non-file-buffer))
+
+(put 'magit-log-select-mode 'magit-log-default-arguments
+ '("--graph" "-n256" "--decorate"))
+
+(defun magit-log-select-setup-buffer (revs args)
+ (magit-setup-buffer #'magit-log-select-mode nil
+ (magit-buffer-revisions revs)
+ (magit-buffer-log-args args)))
+
+(defun magit-log-select-refresh-buffer ()
+ (magit-insert-section (logbuf)
+ (magit-insert-log magit-buffer-revisions
+ magit-buffer-log-args)))
+
+(cl-defmethod magit-buffer-value (&context (major-mode magit-log-select-mode))
+ magit-buffer-revisions)
+
+(defvar-local magit-log-select-pick-function nil)
+(defvar-local magit-log-select-quit-function nil)
+
+(defun magit-log-select (pick &optional msg quit branch args initial)
+ (declare (indent defun))
+ (unless initial
+ (setq initial (magit-commit-at-point)))
+ (magit-log-select-setup-buffer
+ (or branch (magit-get-current-branch) "HEAD")
+ (append args
+ (car (magit-log--get-value 'magit-log-select-mode
+ magit-direct-use-buffer-arguments))))
+ (when initial
+ (magit-log-goto-commit-section initial))
+ (setq magit-log-select-pick-function pick)
+ (setq magit-log-select-quit-function quit)
+ (when magit-log-select-show-usage
+ (let ((pick (propertize (substitute-command-keys
+ "\\[magit-log-select-pick]")
+ 'font-lock-face
+ 'magit-header-line-key))
+ (quit (propertize (substitute-command-keys
+ "\\[magit-log-select-quit]")
+ 'font-lock-face
+ 'magit-header-line-key)))
+ (setq msg (format-spec
+ (if msg
+ (if (string-suffix-p "," msg)
+ (concat msg " or %q to abort")
+ msg)
+ "Type %p to select commit at point, or %q to abort")
+ `((?p . ,pick)
+ (?q . ,quit)))))
+ (magit--add-face-text-property
+ 0 (length msg) 'magit-header-line-log-select t msg)
+ (when (memq magit-log-select-show-usage '(both header-line))
+ (magit-set-header-line-format msg))
+ (when (memq magit-log-select-show-usage '(both echo-area))
+ (message "%s" (substring-no-properties msg)))))
+
+(defun magit-log-select-pick ()
+ "Select the commit at point and act on it.
+Call `magit-log-select-pick-function' with the selected
+commit as argument."
+ (interactive)
+ (let ((fun magit-log-select-pick-function)
+ (rev (magit-commit-at-point)))
+ (magit-mode-bury-buffer 'kill)
+ (funcall fun rev)))
+
+(defun magit-log-select-quit ()
+ "Abort selecting a commit, don't act on any commit."
+ (interactive)
+ (magit-mode-bury-buffer 'kill)
+ (when magit-log-select-quit-function
+ (funcall magit-log-select-quit-function)))
+
+;;; Cherry Mode
+
+(defvar magit-cherry-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-mode-map)
+ (define-key map "q" 'magit-log-bury-buffer)
+ (define-key map "L" 'magit-margin-settings)
+ map)
+ "Keymap for `magit-cherry-mode'.")
+
+(define-derived-mode magit-cherry-mode magit-mode "Magit Cherry"
+ "Mode for looking at commits not merged upstream.
+
+\\<magit-mode-map>\
+Type \\[magit-refresh] to refresh the current buffer.
+Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
+to visit the commit at point.
+
+Type \\[magit-cherry-pick] to apply the commit at point.
+
+\\{magit-cherry-mode-map}"
+ :group 'magit-log
+ (hack-dir-local-variables-non-file-buffer)
+ (setq imenu-create-index-function
+ 'magit-imenu--cherry-create-index-function))
+
+(defun magit-cherry-setup-buffer (head upstream)
+ (magit-setup-buffer #'magit-cherry-mode nil
+ (magit-buffer-refname head)
+ (magit-buffer-upstream upstream)
+ (magit-buffer-range (concat upstream ".." head))))
+
+(defun magit-cherry-refresh-buffer ()
+ (magit-insert-section (cherry)
+ (magit-run-section-hook 'magit-cherry-sections-hook)))
+
+(cl-defmethod magit-buffer-value (&context (major-mode magit-cherry-mode))
+ magit-buffer-range)
+
+;;;###autoload
+(defun magit-cherry (head upstream)
+ "Show commits in a branch that are not merged in the upstream branch."
+ (interactive
+ (let ((head (magit-read-branch "Cherry head")))
+ (list head (magit-read-other-branch "Cherry upstream" head
+ (magit-get-upstream-branch head)))))
+ (require 'magit)
+ (magit-cherry-setup-buffer head upstream))
+
+(defun magit-insert-cherry-headers ()
+ "Insert headers appropriate for `magit-cherry-mode' buffers."
+ (let ((branch (propertize magit-buffer-refname
+ 'font-lock-face 'magit-branch-local))
+ (upstream (propertize magit-buffer-upstream 'font-lock-face
+ (if (magit-local-branch-p magit-buffer-upstream)
+ 'magit-branch-local
+ 'magit-branch-remote))))
+ (magit-insert-head-branch-header branch)
+ (magit-insert-upstream-branch-header branch upstream "Upstream: ")
+ (insert ?\n)))
+
+(defun magit-insert-cherry-commits ()
+ "Insert commit sections into a `magit-cherry-mode' buffer."
+ (magit-insert-section (cherries)
+ (magit-insert-heading "Cherry commits:")
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry)
+ "cherry" "-v" "--abbrev"
+ magit-buffer-upstream
+ magit-buffer-refname)))
+
+;;; Log Sections
+;;;; Standard Log Sections
+
+(defvar magit-unpulled-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-diff-dwim)
+ map)
+ "Keymap for `unpulled' sections.")
+
+(magit-define-section-jumper magit-jump-to-unpulled-from-upstream
+ "Unpulled from @{upstream}" unpulled "..@{upstream}")
+
+(defun magit-insert-unpulled-from-upstream ()
+ "Insert commits that haven't been pulled from the upstream yet."
+ (when-let ((upstream (magit-get-upstream-branch)))
+ (magit-insert-section (unpulled "..@{upstream}" t)
+ (magit-insert-heading
+ (format (propertize "Unpulled from %s."
+ 'font-lock-face 'magit-section-heading)
+ upstream))
+ (magit-insert-log "..@{upstream}" magit-buffer-log-args)
+ (magit-log-insert-child-count))))
+
+(magit-define-section-jumper magit-jump-to-unpulled-from-pushremote
+ "Unpulled from <push-remote>" unpulled
+ (concat ".." (magit-get-push-branch)))
+
+(defun magit-insert-unpulled-from-pushremote ()
+ "Insert commits that haven't been pulled from the push-remote yet."
+ (--when-let (magit-get-push-branch)
+ (when (magit--insert-pushremote-log-p)
+ (magit-insert-section (unpulled (concat ".." it) t)
+ (magit-insert-heading
+ (format (propertize "Unpulled from %s."
+ 'font-lock-face 'magit-section-heading)
+ (propertize it 'font-lock-face 'magit-branch-remote)))
+ (magit-insert-log (concat ".." it) magit-buffer-log-args)
+ (magit-log-insert-child-count)))))
+
+(defvar magit-unpushed-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-diff-dwim)
+ map)
+ "Keymap for `unpushed' sections.")
+
+(magit-define-section-jumper magit-jump-to-unpushed-to-upstream
+ "Unpushed to @{upstream}" unpushed "@{upstream}..")
+
+(defun magit-insert-unpushed-to-upstream-or-recent ()
+ "Insert section showing unpushed or other recent commits.
+If an upstream is configured for the current branch and it is
+behind of the current branch, then show the commits that have
+not yet been pushed into the upstream branch. If no upstream is
+configured or if the upstream is not behind of the current branch,
+then show the last `magit-log-section-commit-count' commits."
+ (let ((upstream (magit-get-upstream-branch)))
+ (if (or (not upstream)
+ (magit-rev-ancestor-p "HEAD" upstream))
+ (magit-insert-recent-commits 'unpushed "@{upstream}..")
+ (magit-insert-unpushed-to-upstream))))
+
+(defun magit-insert-unpushed-to-upstream ()
+ "Insert commits that haven't been pushed to the upstream yet."
+ (when (magit-git-success "rev-parse" "@{upstream}")
+ (magit-insert-section (unpushed "@{upstream}..")
+ (magit-insert-heading
+ (format (propertize "Unmerged into %s."
+ 'font-lock-face 'magit-section-heading)
+ (magit-get-upstream-branch)))
+ (magit-insert-log "@{upstream}.." magit-buffer-log-args)
+ (magit-log-insert-child-count))))
+
+(defun magit-insert-recent-commits (&optional type value)
+ "Insert section showing recent commits.
+Show the last `magit-log-section-commit-count' commits."
+ (let* ((start (format "HEAD~%s" magit-log-section-commit-count))
+ (range (and (magit-rev-verify start)
+ (concat start "..HEAD"))))
+ (magit-insert-section ((eval (or type 'recent))
+ (or value range)
+ t)
+ (magit-insert-heading "Recent commits")
+ (magit-insert-log range
+ (cons (format "-n%d" magit-log-section-commit-count)
+ (--remove (string-prefix-p "-n" it)
+ magit-buffer-log-args))))))
+
+(magit-define-section-jumper magit-jump-to-unpushed-to-pushremote
+ "Unpushed to <push-remote>" unpushed
+ (concat (magit-get-push-branch) ".."))
+
+(defun magit-insert-unpushed-to-pushremote ()
+ "Insert commits that haven't been pushed to the push-remote yet."
+ (--when-let (magit-get-push-branch)
+ (when (magit--insert-pushremote-log-p)
+ (magit-insert-section (unpushed (concat it "..") t)
+ (magit-insert-heading
+ (format (propertize "Unpushed to %s."
+ 'font-lock-face 'magit-section-heading)
+ (propertize it 'font-lock-face 'magit-branch-remote)))
+ (magit-insert-log (concat it "..") magit-buffer-log-args)
+ (magit-log-insert-child-count)))))
+
+(defun magit--insert-pushremote-log-p ()
+ (magit--with-refresh-cache 'magit--insert-pushremote-log-p
+ (not (and (equal (magit-get-push-branch)
+ (magit-get-upstream-branch))
+ (or (memq 'magit-insert-unpulled-from-upstream
+ magit-status-sections-hook)
+ (memq 'magit-insert-unpulled-from-upstream-or-recent
+ magit-status-sections-hook))))))
+
+(defun magit-log-insert-child-count ()
+ (when magit-section-show-child-count
+ (let ((count (length (oref magit-insert-section--current children))))
+ (when (> count 0)
+ (when (= count (magit-log-get-commit-limit))
+ (setq count (format "%s+" count)))
+ (save-excursion
+ (goto-char (- (oref magit-insert-section--current content) 2))
+ (insert (format " (%s)" count))
+ (delete-char 1))))))
+
+;;;; Auxiliary Log Sections
+
+(defun magit-insert-unpulled-cherries ()
+ "Insert section showing unpulled commits.
+Like `magit-insert-unpulled-from-upstream' but prefix each commit
+which has not been applied yet (i.e. a commit with a patch-id
+not shared with any local commit) with \"+\", and all others with
+\"-\"."
+ (when (magit-git-success "rev-parse" "@{upstream}")
+ (magit-insert-section (unpulled "..@{upstream}")
+ (magit-insert-heading "Unpulled commits:")
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry)
+ "cherry" "-v" (magit-abbrev-arg)
+ (magit-get-current-branch) "@{upstream}"))))
+
+(defun magit-insert-unpushed-cherries ()
+ "Insert section showing unpushed commits.
+Like `magit-insert-unpushed-to-upstream' but prefix each commit
+which has not been applied to upstream yet (i.e. a commit with
+a patch-id not shared with any upstream commit) with \"+\", and
+all others with \"-\"."
+ (when (magit-git-success "rev-parse" "@{upstream}")
+ (magit-insert-section (unpushed "@{upstream}..")
+ (magit-insert-heading "Unpushed commits:")
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry)
+ "cherry" "-v" (magit-abbrev-arg) "@{upstream}"))))
+
+;;; _
+(provide 'magit-log)
+;;; magit-log.el ends here
--- /dev/null
+;;; magit-margin.el --- margins in Magit buffers -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements support for showing additional information
+;; in the margins of Magit buffers. Currently this is only used for
+;; commits, for which the committer date or age, and optionally the
+;; author name are shown.
+
+;;; Code:
+
+(require 'magit-section)
+(require 'magit-transient)
+(require 'magit-mode)
+
+(defgroup magit-margin nil
+ "Information Magit displays in the margin.
+
+You can change the STYLE and AUTHOR-WIDTH of all `magit-*-margin'
+options to the same values by customizing `magit-log-margin'
+*before* `magit' is loaded. If you do that, then the respective
+values for the other options will default to what you have set
+for that variable. Likewise if you set `magit-log-margin's INIT
+to nil, then that is used in the default of all other options. But
+setting it to t, i.e. re-enforcing the default for that option,
+does not carry to other options."
+ :link '(info-link "(magit)Log Margin")
+ :group 'magit-log)
+
+(defvar-local magit-buffer-margin nil)
+(put 'magit-buffer-margin 'permanent-local t)
+
+(defvar-local magit-set-buffer-margin-refresh nil)
+
+(defvar magit--age-spec)
+
+;;; Commands
+
+(transient-define-prefix magit-margin-settings ()
+ "Change what information is displayed in the margin."
+ :info-manual "(magit) Log Margin"
+ ["Margin"
+ ("L" "Toggle visibility" magit-toggle-margin)
+ ("l" "Cycle style" magit-cycle-margin-style)
+ ("d" "Toggle details" magit-toggle-margin-details)
+ ("v" "Change verbosity" magit-refs-set-show-commit-count
+ :if-derived magit-refs-mode)])
+
+(defun magit-toggle-margin ()
+ "Show or hide the Magit margin."
+ (interactive)
+ (unless (magit-margin-option)
+ (user-error "Magit margin isn't supported in this buffer"))
+ (setcar magit-buffer-margin (not (magit-buffer-margin-p)))
+ (magit-set-buffer-margin))
+
+(defun magit-cycle-margin-style ()
+ "Cycle style used for the Magit margin."
+ (interactive)
+ (unless (magit-margin-option)
+ (user-error "Magit margin isn't supported in this buffer"))
+ ;; This is only suitable for commit margins (there are not others).
+ (setf (cadr magit-buffer-margin)
+ (pcase (cadr magit-buffer-margin)
+ (`age 'age-abbreviated)
+ (`age-abbreviated
+ (let ((default (cadr (symbol-value (magit-margin-option)))))
+ (if (stringp default) default "%Y-%m-%d %H:%M ")))
+ (_ 'age)))
+ (magit-set-buffer-margin nil t))
+
+(defun magit-toggle-margin-details ()
+ "Show or hide details in the Magit margin."
+ (interactive)
+ (unless (magit-margin-option)
+ (user-error "Magit margin isn't supported in this buffer"))
+ (setf (nth 3 magit-buffer-margin)
+ (not (nth 3 magit-buffer-margin)))
+ (magit-set-buffer-margin nil t))
+
+;;; Core
+
+(defun magit-buffer-margin-p ()
+ (car magit-buffer-margin))
+
+(defun magit-margin-option ()
+ (pcase major-mode
+ (`magit-cherry-mode 'magit-cherry-margin)
+ (`magit-log-mode 'magit-log-margin)
+ (`magit-log-select-mode 'magit-log-select-margin)
+ (`magit-reflog-mode 'magit-reflog-margin)
+ (`magit-refs-mode 'magit-refs-margin)
+ (`magit-stashes-mode 'magit-stashes-margin)
+ (`magit-status-mode 'magit-status-margin)
+ (`forge-notifications-mode 'magit-status-margin)))
+
+(defun magit-set-buffer-margin (&optional reset refresh)
+ (when-let ((option (magit-margin-option)))
+ (let* ((default (symbol-value option))
+ (default-width (nth 2 default)))
+ (when (or reset (not magit-buffer-margin))
+ (setq magit-buffer-margin (copy-sequence default)))
+ (pcase-let ((`(,enable ,style ,_width ,details ,details-width)
+ magit-buffer-margin))
+ (when (functionp default-width)
+ (setf (nth 2 magit-buffer-margin)
+ (funcall default-width style details details-width)))
+ (dolist (window (get-buffer-window-list nil nil 0))
+ (with-selected-window window
+ (magit-set-window-margin window)
+ (if enable
+ (add-hook 'window-configuration-change-hook
+ 'magit-set-window-margin nil t)
+ (remove-hook 'window-configuration-change-hook
+ 'magit-set-window-margin t))))
+ (when (and enable (or refresh magit-set-buffer-margin-refresh))
+ (magit-refresh-buffer))))))
+
+(defun magit-set-window-margin (&optional window)
+ (when (or window (setq window (get-buffer-window)))
+ (with-selected-window window
+ (set-window-margins
+ nil (car (window-margins))
+ (and (magit-buffer-margin-p)
+ (nth 2 magit-buffer-margin))))))
+
+(defun magit-make-margin-overlay (&optional string previous-line)
+ (if previous-line
+ (save-excursion
+ (forward-line -1)
+ (magit-make-margin-overlay string))
+ ;; Don't put the overlay on the complete line to work around #1880.
+ (let ((o (make-overlay (1+ (line-beginning-position))
+ (line-end-position)
+ nil t)))
+ (overlay-put o 'evaporate t)
+ (overlay-put o 'before-string
+ (propertize "o" 'display
+ (list (list 'margin 'right-margin)
+ (or string " ")))))))
+
+(defun magit-maybe-make-margin-overlay ()
+ (when (or (magit-section-match
+ '(unpulled unpushed recent stashes local cherries)
+ magit-insert-section--current)
+ (and (eq major-mode 'magit-refs-mode)
+ (magit-section-match
+ '(remote commit tags)
+ magit-insert-section--current)))
+ (magit-make-margin-overlay nil t)))
+
+;;; Custom Support
+
+(defun magit-margin-set-variable (mode symbol value)
+ (set-default symbol value)
+ (message "Updating margins in %s buffers..." mode)
+ (dolist (buffer (buffer-list))
+ (with-current-buffer buffer
+ (when (eq major-mode mode)
+ (magit-set-buffer-margin t)
+ (magit-refresh))))
+ (message "Updating margins in %s buffers...done" mode))
+
+(defconst magit-log-margin--custom-type
+ '(list (boolean :tag "Show margin initially")
+ (choice :tag "Show committer"
+ (string :tag "date using time-format" "%Y-%m-%d %H:%M ")
+ (const :tag "date's age" age)
+ (const :tag "date's age (abbreviated)" age-abbreviated))
+ (const :tag "Calculate width using magit-log-margin-width"
+ magit-log-margin-width)
+ (boolean :tag "Show author name by default")
+ (integer :tag "Show author name using width")))
+
+;;; Time Utilities
+
+(defvar magit--age-spec
+ `((?Y "year" "years" ,(round (* 60 60 24 365.2425)))
+ (?M "month" "months" ,(round (* 60 60 24 30.436875)))
+ (?w "week" "weeks" ,(* 60 60 24 7))
+ (?d "day" "days" ,(* 60 60 24))
+ (?h "hour" "hours" ,(* 60 60))
+ (?m "minute" "minutes" 60)
+ (?s "second" "seconds" 1))
+ "Time units used when formatting relative commit ages.
+
+The value is a list of time units, beginning with the longest.
+Each element has the form (CHAR UNIT UNITS SECONDS). UNIT is the
+time unit, UNITS is the plural of that unit. CHAR is a character
+abbreviation. And SECONDS is the number of seconds in one UNIT.
+
+This is defined as a variable to make it possible to use time
+units for a language other than English. It is not defined
+as an option, because most other parts of Magit are always in
+English.")
+
+(defun magit--age (date &optional abbreviate)
+ (cl-labels ((fn (age spec)
+ (pcase-let ((`(,char ,unit ,units ,weight) (car spec)))
+ (let ((cnt (round (/ age weight 1.0))))
+ (if (or (not (cdr spec))
+ (>= (/ age weight) 1))
+ (list cnt (cond (abbreviate char)
+ ((= cnt 1) unit)
+ (t units)))
+ (fn age (cdr spec)))))))
+ (fn (abs (- (float-time)
+ (if (stringp date)
+ (string-to-number date)
+ date)))
+ magit--age-spec)))
+
+;;; _
+(provide 'magit-margin)
+;;; magit-margin.el ends here
--- /dev/null
+;;; magit-merge.el --- merge functionality -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements merge commands.
+
+;;; Code:
+
+(require 'magit)
+(require 'magit-diff)
+
+(declare-function magit-git-push "magit-push" (branch target args))
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-merge "magit" nil t)
+(transient-define-prefix magit-merge ()
+ "Merge branches."
+ :man-page "git-merge"
+ :incompatible '(("--ff-only" "--no-ff"))
+ ["Arguments"
+ :if-not magit-merge-in-progress-p
+ ("-f" "Fast-forward only" "--ff-only")
+ ("-n" "No fast-forward" "--no-ff")
+ (magit-merge:--strategy)
+ (5 magit-merge:--strategy-option)
+ (5 magit-diff:--diff-algorithm :argument "-Xdiff-algorithm=")
+ (5 magit:--gpg-sign)]
+ ["Actions"
+ :if-not magit-merge-in-progress-p
+ [("m" "Merge" magit-merge-plain)
+ ("e" "Merge and edit message" magit-merge-editmsg)
+ ("n" "Merge but don't commit" magit-merge-nocommit)
+ ("a" "Absorb" magit-merge-absorb)]
+ [("p" "Preview merge" magit-merge-preview)
+ ""
+ ("s" "Squash merge" magit-merge-squash)
+ ("i" "Merge into" magit-merge-into)]]
+ ["Actions"
+ :if magit-merge-in-progress-p
+ ("m" "Commit merge" magit-commit-create)
+ ("a" "Abort merge" magit-merge-abort)])
+
+(defun magit-merge-arguments ()
+ (transient-args 'magit-merge))
+
+(transient-define-argument magit-merge:--strategy ()
+ :description "Strategy"
+ :class 'transient-option
+ ;; key for merge and rebase: "-s"
+ ;; key for cherry-pick and revert: "=s"
+ ;; shortarg for merge and rebase: "-s"
+ ;; shortarg for cherry-pick and revert: none
+ :key "-s"
+ :argument "--strategy="
+ :choices '("resolve" "recursive" "octopus" "ours" "subtree"))
+
+(transient-define-argument magit-merge:--strategy-option ()
+ :description "Strategy Option"
+ :class 'transient-option
+ :key "-X"
+ :argument "--strategy-option="
+ :choices '("ours" "theirs" "patience"))
+
+;;;###autoload
+(defun magit-merge-plain (rev &optional args nocommit)
+ "Merge commit REV into the current branch; using default message.
+
+Unless there are conflicts or a prefix argument is used create a
+merge commit using a generic commit message and without letting
+the user inspect the result. With a prefix argument pretend the
+merge failed to give the user the opportunity to inspect the
+merge.
+
+\(git merge --no-edit|--no-commit [ARGS] REV)"
+ (interactive (list (magit-read-other-branch-or-commit "Merge")
+ (magit-merge-arguments)
+ current-prefix-arg))
+ (magit-merge-assert)
+ (magit-run-git-async "merge" (if nocommit "--no-commit" "--no-edit") args rev))
+
+;;;###autoload
+(defun magit-merge-editmsg (rev &optional args)
+ "Merge commit REV into the current branch; and edit message.
+Perform the merge and prepare a commit message but let the user
+edit it.
+\n(git merge --edit --no-ff [ARGS] REV)"
+ (interactive (list (magit-read-other-branch-or-commit "Merge")
+ (magit-merge-arguments)))
+ (magit-merge-assert)
+ (cl-pushnew "--no-ff" args :test #'equal)
+ (apply #'magit-run-git-with-editor "merge" "--edit"
+ (append (delete "--ff-only" args)
+ (list rev))))
+
+;;;###autoload
+(defun magit-merge-nocommit (rev &optional args)
+ "Merge commit REV into the current branch; pretending it failed.
+Pretend the merge failed to give the user the opportunity to
+inspect the merge and change the commit message.
+\n(git merge --no-commit --no-ff [ARGS] REV)"
+ (interactive (list (magit-read-other-branch-or-commit "Merge")
+ (magit-merge-arguments)))
+ (magit-merge-assert)
+ (cl-pushnew "--no-ff" args :test #'equal)
+ (magit-run-git-async "merge" "--no-commit" args rev))
+
+;;;###autoload
+(defun magit-merge-into (branch &optional args)
+ "Merge the current branch into BRANCH and remove the former.
+
+Before merging, force push the source branch to its push-remote,
+provided the respective remote branch already exists, ensuring
+that the respective pull-request (if any) won't get stuck on some
+obsolete version of the commits that are being merged. Finally
+if `forge-branch-pullreq' was used to create the merged branch,
+branch, then also remove the respective remote branch."
+ (interactive
+ (list (magit-read-other-local-branch
+ (format "Merge `%s' into"
+ (or (magit-get-current-branch)
+ (magit-rev-parse "HEAD")))
+ nil
+ (when-let ((upstream (magit-get-upstream-branch))
+ (upstream (cdr (magit-split-branch-name upstream))))
+ (and (magit-branch-p upstream) upstream)))
+ (magit-merge-arguments)))
+ (let ((current (magit-get-current-branch))
+ (head (magit-rev-parse "HEAD")))
+ (when (zerop (magit-call-git "checkout" branch))
+ (if current
+ (magit--merge-absorb current args)
+ (magit-run-git-with-editor "merge" args head)))))
+
+;;;###autoload
+(defun magit-merge-absorb (branch &optional args)
+ "Merge BRANCH into the current branch and remove the former.
+
+Before merging, force push the source branch to its push-remote,
+provided the respective remote branch already exists, ensuring
+that the respective pull-request (if any) won't get stuck on some
+obsolete version of the commits that are being merged. Finally
+if `forge-branch-pullreq' was used to create the merged branch,
+then also remove the respective remote branch."
+ (interactive (list (magit-read-other-local-branch "Absorb branch")
+ (magit-merge-arguments)))
+ (magit--merge-absorb branch args))
+
+(defun magit--merge-absorb (branch args)
+ (when (equal branch (magit-main-branch))
+ (unless (yes-or-no-p
+ (format "Do you really want to merge `%s' into another branch? "
+ branch))
+ (user-error "Abort")))
+ (if-let ((target (magit-get-push-branch branch t)))
+ (progn
+ (magit-git-push branch target (list "--force-with-lease"))
+ (set-process-sentinel
+ magit-this-process
+ (lambda (process event)
+ (when (memq (process-status process) '(exit signal))
+ (if (not (zerop (process-exit-status process)))
+ (magit-process-sentinel process event)
+ (process-put process 'inhibit-refresh t)
+ (magit-process-sentinel process event)
+ (magit--merge-absorb-1 branch args))))))
+ (magit--merge-absorb-1 branch args)))
+
+(defun magit--merge-absorb-1 (branch args)
+ (if-let ((pr (magit-get "branch" branch "pullRequest")))
+ (magit-run-git-async
+ "merge" args "-m"
+ (format "Merge branch '%s'%s [#%s]"
+ branch
+ (let ((current (magit-get-current-branch)))
+ (if (equal current (magit-main-branch))
+ ""
+ (format " into %s" current)))
+ pr)
+ branch)
+ (magit-run-git-async "merge" args "--no-edit" branch))
+ (set-process-sentinel
+ magit-this-process
+ (lambda (process event)
+ (when (memq (process-status process) '(exit signal))
+ (if (> (process-exit-status process) 0)
+ (magit-process-sentinel process event)
+ (process-put process 'inhibit-refresh t)
+ (magit-process-sentinel process event)
+ (magit-branch-maybe-delete-pr-remote branch)
+ (magit-branch-unset-pushRemote branch)
+ (magit-run-git "branch" "-D" branch))))))
+
+;;;###autoload
+(defun magit-merge-squash (rev)
+ "Squash commit REV into the current branch; don't create a commit.
+\n(git merge --squash REV)"
+ (interactive (list (magit-read-other-branch-or-commit "Squash")))
+ (magit-merge-assert)
+ (magit-run-git-async "merge" "--squash" rev))
+
+;;;###autoload
+(defun magit-merge-preview (rev)
+ "Preview result of merging REV into the current branch."
+ (interactive (list (magit-read-other-branch-or-commit "Preview merge")))
+ (magit-merge-preview-setup-buffer rev))
+
+;;;###autoload
+(defun magit-merge-abort ()
+ "Abort the current merge operation.
+\n(git merge --abort)"
+ (interactive)
+ (unless (file-exists-p (magit-git-dir "MERGE_HEAD"))
+ (user-error "No merge in progress"))
+ (magit-confirm 'abort-merge)
+ (magit-run-git-async "merge" "--abort"))
+
+(defun magit-checkout-stage (file arg)
+ "During a conflict checkout and stage side, or restore conflict."
+ (interactive
+ (let ((file (magit-completing-read "Checkout file"
+ (magit-tracked-files) nil nil nil
+ 'magit-read-file-hist
+ (magit-current-file))))
+ (cond ((member file (magit-unmerged-files))
+ (list file (magit-checkout-read-stage file)))
+ ((yes-or-no-p (format "Restore conflicts in %s? " file))
+ (list file "--merge"))
+ (t
+ (user-error "Quit")))))
+ (pcase (cons arg (cddr (car (magit-file-status file))))
+ ((or `("--ours" ?D ,_)
+ `("--theirs" ,_ ?D))
+ (magit-run-git "rm" "--" file))
+ (_ (if (equal arg "--merge")
+ ;; This fails if the file was deleted on one
+ ;; side. And we cannot do anything about it.
+ (magit-run-git "checkout" "--merge" "--" file)
+ (magit-call-git "checkout" arg "--" file)
+ (magit-run-git "add" "-u" "--" file)))))
+
+;;; Utilities
+
+(defun magit-merge-in-progress-p ()
+ (file-exists-p (magit-git-dir "MERGE_HEAD")))
+
+(defun magit--merge-range (&optional head)
+ (unless head
+ (setq head (magit-get-shortname
+ (car (magit-file-lines (magit-git-dir "MERGE_HEAD"))))))
+ (and head
+ (concat (magit-git-string "merge-base" "--octopus" "HEAD" head)
+ ".." head)))
+
+(defun magit-merge-assert ()
+ (or (not (magit-anything-modified-p t))
+ (magit-confirm 'merge-dirty
+ "Merging with dirty worktree is risky. Continue")))
+
+(defun magit-checkout-read-stage (file)
+ (magit-read-char-case (format "For %s checkout: " file) t
+ (?o "[o]ur stage" "--ours")
+ (?t "[t]heir stage" "--theirs")
+ (?c "[c]onflict" "--merge")))
+
+;;; Sections
+
+(defvar magit-unmerged-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-diff-dwim)
+ map)
+ "Keymap for `unmerged' sections.")
+
+(defun magit-insert-merge-log ()
+ "Insert section for the on-going merge.
+Display the heads that are being merged.
+If no merge is in progress, do nothing."
+ (when (magit-merge-in-progress-p)
+ (let* ((heads (mapcar #'magit-get-shortname
+ (magit-file-lines (magit-git-dir "MERGE_HEAD"))))
+ (range (magit--merge-range (car heads))))
+ (magit-insert-section (unmerged range)
+ (magit-insert-heading
+ (format "Merging %s:" (mapconcat #'identity heads ", ")))
+ (magit-insert-log
+ range
+ (let ((args magit-buffer-log-args))
+ (unless (member "--decorate=full" magit-buffer-log-args)
+ (push "--decorate=full" args))
+ args))))))
+
+;;; _
+(provide 'magit-merge)
+;;; magit-merge.el ends here
--- /dev/null
+;;; magit-mode.el --- create and refresh Magit buffers -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements the abstract major-mode `magit-mode' from
+;; which almost all other Magit major-modes derive. The code in here
+;; is mostly concerned with creating and refreshing Magit buffers.
+
+;;; Code:
+
+(require 'magit-section)
+(require 'magit-git)
+
+(require 'format-spec)
+(require 'help-mode)
+(require 'transient)
+
+;; For `magit-display-buffer-fullcolumn-most-v1' from `git-commit'
+(defvar git-commit-mode)
+;; For `magit-refresh'
+(defvar magit-post-commit-hook-commands)
+(defvar magit-post-stage-hook-commands)
+(defvar magit-post-unstage-hook-commands)
+;; For `magit-refresh' and `magit-refresh-all'
+(declare-function magit-auto-revert-buffers "magit-autorevert" ())
+;; For `magit-refresh-buffer'
+(declare-function magit-process-unset-mode-line-error-status "magit-process" ())
+;; For `magit-refresh-get-relative-position'
+(declare-function magit-hunk-section-p "magit-diff" (obj))
+;; For `magit-mode-setup-internal'
+(declare-function magit-status-goto-initial-section "magit-status" ())
+;; For `magit-mode' from `bookmark'
+(defvar bookmark-make-record-function)
+
+;;; Options
+
+(defcustom magit-mode-hook
+ '(magit-load-config-extensions)
+ "Hook run when entering a mode derived from Magit mode."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-modes
+ :type 'hook
+ :options '(magit-load-config-extensions
+ bug-reference-mode))
+
+(defcustom magit-setup-buffer-hook
+ '(magit-maybe-save-repository-buffers
+ magit-set-buffer-margin)
+ "Hook run by `magit-setup-buffer'.
+
+This is run right after displaying the buffer and right before
+generating or updating its content. `magit-mode-hook' and other,
+more specific, `magit-mode-*-hook's on the other hand are run
+right before displaying the buffer. Usually one of these hooks
+should be used instead of this one."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-modes
+ :type 'hook
+ :options '(magit-maybe-save-repository-buffers
+ magit-set-buffer-margin))
+
+(defcustom magit-pre-refresh-hook '(magit-maybe-save-repository-buffers)
+ "Hook run before refreshing in `magit-refresh'.
+
+This hook, or `magit-post-refresh-hook', should be used
+for functions that are not tied to a particular buffer.
+
+To run a function with a particular buffer current, use
+`magit-refresh-buffer-hook' and use `derived-mode-p'
+inside your function."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-refresh
+ :type 'hook
+ :options '(magit-maybe-save-repository-buffers))
+
+(defcustom magit-post-refresh-hook nil
+ "Hook run after refreshing in `magit-refresh'.
+
+This hook, or `magit-pre-refresh-hook', should be used
+for functions that are not tied to a particular buffer.
+
+To run a function with a particular buffer current, use
+`magit-refresh-buffer-hook' and use `derived-mode-p'
+inside your function."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-refresh
+ :type 'hook)
+
+(defcustom magit-display-buffer-function 'magit-display-buffer-traditional
+ "The function used display a Magit buffer.
+
+All Magit buffers (buffers whose major-modes derive from
+`magit-mode') are displayed using `magit-display-buffer',
+which in turn uses the function specified here."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-buffers
+ :type '(radio (function-item magit-display-buffer-traditional)
+ (function-item magit-display-buffer-same-window-except-diff-v1)
+ (function-item magit-display-buffer-fullframe-status-v1)
+ (function-item magit-display-buffer-fullframe-status-topleft-v1)
+ (function-item magit-display-buffer-fullcolumn-most-v1)
+ (function-item display-buffer)
+ (function :tag "Function")))
+
+(defcustom magit-pre-display-buffer-hook '(magit-save-window-configuration)
+ "Hook run by `magit-display-buffer' before displaying the buffer."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-buffers
+ :type 'hook
+ :get 'magit-hook-custom-get
+ :options '(magit-save-window-configuration))
+
+(defcustom magit-post-display-buffer-hook '(magit-maybe-set-dedicated)
+ "Hook run by `magit-display-buffer' after displaying the buffer."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-buffers
+ :type 'hook
+ :get 'magit-hook-custom-get
+ :options '(magit-maybe-set-dedicated))
+
+(defcustom magit-generate-buffer-name-function
+ 'magit-generate-buffer-name-default-function
+ "The function used to generate the name for a Magit buffer."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-buffers
+ :type '(radio (function-item magit-generate-buffer-name-default-function)
+ (function :tag "Function")))
+
+(defcustom magit-buffer-name-format "%x%M%v: %t%x"
+ "The format string used to name Magit buffers.
+
+The following %-sequences are supported:
+
+`%m' The name of the major-mode, but with the `-mode' suffix
+ removed.
+
+`%M' Like \"%m\" but abbreviate `magit-status-mode' as `magit'.
+
+`%v' The value the buffer is locked to, in parentheses, or an
+ empty string if the buffer is not locked to a value.
+
+`%V' Like \"%v\", but the string is prefixed with a space, unless
+ it is an empty string.
+
+`%t' The top-level directory of the working tree of the
+ repository, or if `magit-uniquify-buffer-names' is non-nil
+ an abbreviation of that.
+
+`%x' If `magit-uniquify-buffer-names' is nil \"*\", otherwise the
+ empty string. Due to limitations of the `uniquify' package,
+ buffer names must end with the path.
+
+`%T' Obsolete, use \"%t%x\" instead. Like \"%t\", but append an
+ asterisk if and only if `magit-uniquify-buffer-names' is nil.
+
+The value should always contain \"%m\" or \"%M\", \"%v\" or
+\"%V\", and \"%t\" (or the obsolete \"%T\").
+
+If `magit-uniquify-buffer-names' is non-nil, then the value must
+end with \"%t\" or \"%t%x\" (or the obsolete \"%T\"). See issue
+#2841.
+
+This is used by `magit-generate-buffer-name-default-function'.
+If another `magit-generate-buffer-name-function' is used, then
+it may not respect this option, or on the contrary it may
+support additional %-sequences."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-buffers
+ :type 'string)
+
+(defcustom magit-uniquify-buffer-names t
+ "Whether to uniquify the names of Magit buffers."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-buffers
+ :type 'boolean)
+
+(defcustom magit-bury-buffer-function 'magit-restore-window-configuration
+ "The function used to bury or kill the current Magit buffer."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-buffers
+ :type '(radio (function-item quit-window)
+ (function-item magit-mode-quit-window)
+ (function-item magit-restore-window-configuration)
+ (function :tag "Function")))
+
+(defcustom magit-prefix-use-buffer-arguments 'selected
+ "Whether certain prefix commands reuse arguments active in relevant buffer.
+
+This affects the transient prefix commands `magit-diff',
+`magit-log' and `magit-show-refs'.
+
+Valid values are:
+
+`always': Always use the set of arguments that is currently
+ active in the respective buffer, provided that buffer exists
+ of course.
+`selected': Use the set of arguments from the respective
+ buffer, but only if it is displayed in a window of the current
+ frame. This is the default.
+`current': Use the set of arguments from the respective buffer,
+ but only if it is the current buffer.
+`never': Never use the set of arguments from the respective
+ buffer.
+
+For more information see info node `(magit)Transient Arguments
+and Buffer Arguments'."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-buffers
+ :group 'magit-commands
+ :group 'magit-diff
+ :group 'magit-log
+ :type '(choice
+ (const :tag "always use args from buffer" always)
+ (const :tag "use args from buffer if displayed in frame" selected)
+ (const :tag "use args from buffer if it is current" current)
+ (const :tag "never use args from buffer" never)))
+
+(defcustom magit-direct-use-buffer-arguments 'selected
+ "Whether certain commands reuse arguments active in relevant buffer.
+
+This affects certain commands such as `magit-show-commit' that
+are suffixes of the diff or log transient prefix commands, but
+only if they are invoked directly, i.e. *not* as a suffix.
+
+Valid values are:
+
+`always': Always use the set of arguments that is currently
+ active in the respective buffer, provided that buffer exists
+ of course.
+`selected': Use the set of arguments from the respective
+ buffer, but only if it is displayed in a window of the current
+ frame. This is the default.
+`current': Use the set of arguments from the respective buffer,
+ but only if it is the current buffer.
+`never': Never use the set of arguments from the respective
+ buffer.
+
+For more information see info node `(magit)Transient Arguments
+and Buffer Arguments'."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-buffers
+ :group 'magit-commands
+ :group 'magit-diff
+ :group 'magit-log
+ :type '(choice
+ (const :tag "always use args from buffer" always)
+ (const :tag "use args from buffer if displayed in frame" selected)
+ (const :tag "use args from buffer if it is current" current)
+ (const :tag "never use args from buffer" never)))
+
+(defcustom magit-region-highlight-hook '(magit-diff-update-hunk-region)
+ "Functions used to highlight the region.
+
+Each function is run with the current section as only argument
+until one of them returns non-nil. If all functions return nil,
+then fall back to regular region highlighting."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-refresh
+ :type 'hook
+ :options '(magit-diff-update-hunk-region))
+
+(defcustom magit-create-buffer-hook nil
+ "Normal hook run after creating a new `magit-mode' buffer."
+ :package-version '(magit . "2.90.0")
+ :group 'magit-refresh
+ :type 'hook)
+
+(defcustom magit-refresh-buffer-hook nil
+ "Normal hook for `magit-refresh-buffer' to run after refreshing."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-refresh
+ :type 'hook)
+
+(defcustom magit-refresh-status-buffer t
+ "Whether the status buffer is refreshed after running git.
+
+When this is non-nil, then the status buffer is automatically
+refreshed after running git for side-effects, in addition to the
+current Magit buffer, which is always refreshed automatically.
+
+Only set this to nil after exhausting all other options to
+improve performance."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-refresh
+ :group 'magit-status
+ :type 'boolean)
+
+(defcustom magit-refresh-verbose nil
+ "Whether to revert Magit buffers verbosely."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-refresh
+ :type 'boolean)
+
+(defcustom magit-save-repository-buffers t
+ "Whether to save file-visiting buffers when appropriate.
+
+If non-nil, then all modified file-visiting buffers belonging
+to the current repository may be saved before running Magit
+commands and before creating or refreshing Magit buffers.
+If `dontask', then this is done without user intervention, for
+any other non-nil value the user has to confirm each save.
+
+The default is t to avoid surprises, but `dontask' is the
+recommended value."
+ :group 'magit-essentials
+ :group 'magit-buffers
+ :type '(choice (const :tag "Never" nil)
+ (const :tag "Ask" t)
+ (const :tag "Save without asking" dontask)))
+
+;;; Key Bindings
+
+(defvar magit-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-section-mode-map)
+ (define-key map [C-return] 'magit-visit-thing)
+ (define-key map (kbd "C-m") 'magit-visit-thing)
+ (define-key map (kbd "C-M-i") 'magit-dired-jump)
+ (define-key map [M-tab] 'magit-section-cycle-diffs)
+ (define-key map (kbd "P") 'magit-push)
+ (define-key map (kbd "k") 'magit-delete-thing)
+ (define-key map (kbd "K") 'magit-file-untrack)
+ (define-key map (kbd "i") 'magit-gitignore)
+ (define-key map (kbd "I") 'magit-gitignore)
+ (define-key map (kbd "SPC") 'magit-diff-show-or-scroll-up)
+ (define-key map (kbd "S-SPC") 'magit-diff-show-or-scroll-down)
+ (define-key map (kbd "DEL") 'magit-diff-show-or-scroll-down)
+ (define-key map "+" 'magit-diff-more-context)
+ (define-key map "-" 'magit-diff-less-context)
+ (define-key map "0" 'magit-diff-default-context)
+ (define-key map "$" 'magit-process-buffer)
+ (define-key map "%" 'magit-worktree)
+ (define-key map "a" 'magit-cherry-apply)
+ (define-key map "A" 'magit-cherry-pick)
+ (define-key map "b" 'magit-branch)
+ (define-key map "B" 'magit-bisect)
+ (define-key map "c" 'magit-commit)
+ (define-key map "C" 'magit-clone)
+ (define-key map "d" 'magit-diff)
+ (define-key map "D" 'magit-diff-refresh)
+ (define-key map "e" 'magit-ediff-dwim)
+ (define-key map "E" 'magit-ediff)
+ (define-key map "f" 'magit-fetch)
+ (define-key map "F" 'magit-pull)
+ (define-key map "g" 'magit-refresh)
+ (define-key map "G" 'magit-refresh-all)
+ (define-key map "h" 'magit-dispatch)
+ (define-key map "?" 'magit-dispatch)
+ (define-key map "l" 'magit-log)
+ (define-key map "L" 'magit-log-refresh)
+ (define-key map "m" 'magit-merge)
+ (define-key map "M" 'magit-remote)
+ (define-key map "o" 'magit-submodule)
+ (define-key map "O" 'magit-subtree)
+ (define-key map "q" 'magit-mode-bury-buffer)
+ (define-key map "r" 'magit-rebase)
+ (define-key map "R" 'magit-file-rename)
+ (define-key map "s" 'magit-stage-file)
+ (define-key map "S" 'magit-stage-modified)
+ (define-key map "t" 'magit-tag)
+ (define-key map "T" 'magit-notes)
+ (define-key map "u" 'magit-unstage-file)
+ (define-key map "U" 'magit-unstage-all)
+ (define-key map "v" 'magit-revert-no-commit)
+ (define-key map "V" 'magit-revert)
+ (define-key map "w" 'magit-am)
+ (define-key map "W" 'magit-patch)
+ (define-key map "x" 'magit-reset-quickly)
+ (define-key map "X" 'magit-reset)
+ (define-key map "y" 'magit-show-refs)
+ (define-key map "Y" 'magit-cherry)
+ (define-key map "z" 'magit-stash)
+ (define-key map "Z" 'magit-stash)
+ (define-key map ":" 'magit-git-command)
+ (define-key map "!" 'magit-run)
+ (define-key map (kbd "C-c C-c") 'magit-dispatch)
+ (define-key map (kbd "C-c C-e") 'magit-edit-thing)
+ (define-key map (kbd "C-c C-o") 'magit-browse-thing)
+ (define-key map (kbd "C-c C-w") 'magit-browse-thing)
+ (define-key map (kbd "C-w") 'magit-copy-section-value)
+ (define-key map (kbd "M-w") 'magit-copy-buffer-revision)
+ (define-key map [remap previous-line] 'magit-previous-line)
+ (define-key map [remap next-line] 'magit-next-line)
+ (define-key map [remap evil-previous-line] 'evil-previous-visual-line)
+ (define-key map [remap evil-next-line] 'evil-next-visual-line)
+ map)
+ "Parent keymap for all keymaps of modes derived from `magit-mode'.")
+
+(defun magit-delete-thing ()
+ "This is a placeholder command.
+Where applicable, section-specific keymaps bind another command
+which deletes the thing at point."
+ (interactive)
+ (user-error "There is no thing at point that could be deleted"))
+
+(defun magit-visit-thing ()
+ "This is a placeholder command.
+Where applicable, section-specific keymaps bind another command
+which visits the thing at point."
+ (interactive)
+ (if (eq transient-current-command 'magit-dispatch)
+ (call-interactively (key-binding (this-command-keys)))
+ (user-error "There is no thing at point that could be visited")))
+
+(defun magit-edit-thing ()
+ "This is a placeholder command.
+Where applicable, section-specific keymaps bind another command
+which lets you edit the thing at point, likely in another buffer."
+ (interactive)
+ (if (eq transient-current-command 'magit-dispatch)
+ (call-interactively (key-binding (this-command-keys)))
+ (user-error "There is no thing at point that could be edited")))
+
+(defun magit-browse-thing ()
+ "This is a placeholder command.
+Where applicable, section-specific keymaps bind another command
+which visits the thing at point using `browse-url'."
+ (interactive)
+ (user-error "There is no thing at point that could be browsed"))
+
+(defvar bug-reference-map)
+(with-eval-after-load 'bug-reference
+ (define-key bug-reference-map [remap magit-visit-thing]
+ 'bug-reference-push-button))
+
+(easy-menu-define magit-mode-menu magit-mode-map
+ "Magit menu"
+ '("Magit"
+ ["Refresh" magit-refresh t]
+ ["Refresh all" magit-refresh-all t]
+ "---"
+ ["Stage" magit-stage t]
+ ["Stage modified" magit-stage-modified t]
+ ["Unstage" magit-unstage t]
+ ["Reset index" magit-reset-index t]
+ ["Commit" magit-commit t]
+ ["Add log entry" magit-commit-add-log t]
+ ["Tag" magit-tag-create t]
+ "---"
+ ["Diff working tree" magit-diff-working-tree t]
+ ["Diff" magit-diff t]
+ ("Log"
+ ["Log" magit-log-other t]
+ ["Reflog" magit-reflog-other t]
+ ["Extended..." magit-log t])
+ "---"
+ ["Cherry pick" magit-cherry-pick t]
+ ["Revert commit" magit-revert t]
+ "---"
+ ["Ignore globally" magit-gitignore-globally t]
+ ["Ignore locally" magit-gitignore-locally t]
+ ["Discard" magit-discard t]
+ ["Reset head and index" magit-reset-mixed t]
+ ["Stash" magit-stash-both t]
+ ["Snapshot" magit-snapshot-both t]
+ "---"
+ ["Branch..." magit-checkout t]
+ ["Merge" magit-merge t]
+ ["Ediff resolve" magit-ediff-resolve t]
+ ["Rebase..." magit-rebase t]
+ "---"
+ ["Push" magit-push t]
+ ["Pull" magit-pull-branch t]
+ ["Remote update" magit-fetch-all t]
+ ("Submodule"
+ ["Submodule update" magit-submodule-update t]
+ ["Submodule update and init" magit-submodule-setup t]
+ ["Submodule init" magit-submodule-init t]
+ ["Submodule sync" magit-submodule-sync t])
+ "---"
+ ("Extensions")
+ "---"
+ ["Display Git output" magit-process-buffer t]
+ ["Quit Magit" magit-mode-bury-buffer t]))
+
+;;; Mode
+
+(defun magit-load-config-extensions ()
+ "Load Magit extensions that are defined at the Git config layer."
+ (dolist (ext (magit-get-all "magit.extension"))
+ (let ((sym (intern (format "magit-%s-mode" ext))))
+ (when (fboundp sym)
+ (funcall sym 1)))))
+
+(define-derived-mode magit-mode magit-section-mode "Magit"
+ "Parent major mode from which Magit major modes inherit.
+
+Magit is documented in info node `(magit)'."
+ :group 'magit
+ (hack-dir-local-variables-non-file-buffer)
+ (face-remap-add-relative 'header-line 'magit-header-line)
+ (setq mode-line-process (magit-repository-local-get 'mode-line-process))
+ (setq-local bookmark-make-record-function 'magit--make-bookmark)
+ (setq-local isearch-filter-predicate 'magit-section--open-temporarily))
+
+;;; Local Variables
+
+(defvar-local magit-buffer-arguments nil)
+(defvar-local magit-buffer-diff-args nil)
+(defvar-local magit-buffer-diff-files nil)
+(defvar-local magit-buffer-diff-files-suspended nil)
+(defvar-local magit-buffer-file-name nil)
+(defvar-local magit-buffer-files nil)
+(defvar-local magit-buffer-log-args nil)
+(defvar-local magit-buffer-log-files nil)
+(defvar-local magit-buffer-range nil)
+(defvar-local magit-buffer-range-hashed nil)
+(defvar-local magit-buffer-refname nil)
+(defvar-local magit-buffer-revision nil)
+(defvar-local magit-buffer-revision-hash nil)
+(defvar-local magit-buffer-revisions nil)
+(defvar-local magit-buffer-typearg nil)
+(defvar-local magit-buffer-upstream nil)
+
+;; These variables are also used in file-visiting buffers.
+;; Because the user may change the major-mode, they have
+;; to be permanent buffer-local.
+(put 'magit-buffer-file-name 'permanent-local t)
+(put 'magit-buffer-refname 'permanent-local t)
+(put 'magit-buffer-revision 'permanent-local t)
+(put 'magit-buffer-revision-hash 'permanent-local t)
+
+;; `magit-status' re-enables mode function but its refresher
+;; function does not reinstate this.
+(put 'magit-buffer-diff-files-suspended 'permanent-local t)
+
+(defvar-local magit-refresh-args nil
+ "Obsolete. Possibly the arguments used to refresh the current buffer.
+Some third-party packages might still use this, but Magit does not.")
+(put 'magit-refresh-args 'permanent-local t)
+(make-obsolete-variable 'magit-refresh-args nil "Magit 3.0.0")
+
+(defvar magit-buffer-lock-functions nil
+ "Obsolete buffer-locking support for third-party modes.
+Implement the generic function `magit-buffer-value' for
+your mode instead of adding an entry to this variable.")
+(make-obsolete-variable 'magit-buffer-lock-functions nil "Magit 3.0.0")
+
+(cl-defgeneric magit-buffer-value ()
+ (when-let ((fn (cdr (assq major-mode magit-buffer-lock-functions))))
+ (funcall fn (with-no-warnings magit-refresh-args))))
+
+(defvar-local magit-previous-section nil)
+(put 'magit-previous-section 'permanent-local t)
+
+;;; Setup Buffer
+
+(defmacro magit-setup-buffer (mode &optional locked &rest bindings)
+ (declare (indent 2))
+ `(magit-setup-buffer-internal
+ ,mode ,locked
+ ,(cons 'list (mapcar (pcase-lambda (`(,var ,form))
+ `(list ',var ,form))
+ bindings))))
+
+(defun magit-setup-buffer-internal (mode locked bindings)
+ (let* ((value (and locked
+ (with-temp-buffer
+ (pcase-dolist (`(,var ,val) bindings)
+ (set (make-local-variable var) val))
+ (let ((major-mode mode))
+ (magit-buffer-value)))))
+ (buffer (magit-get-mode-buffer mode value))
+ (section (and buffer (magit-current-section)))
+ (created (not buffer)))
+ (unless buffer
+ (setq buffer (magit-with-toplevel
+ (magit-generate-new-buffer mode value))))
+ (with-current-buffer buffer
+ (setq magit-previous-section section)
+ (funcall mode)
+ (magit-xref-setup 'magit-setup-buffer-internal bindings)
+ (pcase-dolist (`(,var ,val) bindings)
+ (set (make-local-variable var) val))
+ (when created
+ (magit-status-goto-initial-section)
+ (run-hooks 'magit-create-buffer-hook)))
+ (magit-display-buffer buffer)
+ (with-current-buffer buffer
+ (run-hooks 'magit-setup-buffer-hook)
+ (magit-refresh-buffer))
+ buffer))
+
+(defun magit-mode-setup (mode &rest args)
+ "Setup up a MODE buffer using ARGS to generate its content."
+ (declare (obsolete magit-setup-buffer "Magit 3.0.0"))
+ (with-no-warnings
+ (magit-mode-setup-internal mode args)))
+
+(defun magit-mode-setup-internal (mode args &optional locked)
+ "Setup up a MODE buffer using ARGS to generate its content.
+When optional LOCKED is non-nil, then create a buffer that is
+locked to its value, which is derived from MODE and ARGS."
+ (declare (obsolete magit-setup-buffer "Magit 3.0.0"))
+ (let* ((value (and locked
+ (with-temp-buffer
+ (with-no-warnings
+ (setq magit-refresh-args args))
+ (let ((major-mode mode))
+ (magit-buffer-value)))))
+ (buffer (magit-get-mode-buffer mode value))
+ (section (and buffer (magit-current-section)))
+ (created (not buffer)))
+ (unless buffer
+ (setq buffer (magit-with-toplevel
+ (magit-generate-new-buffer mode value))))
+ (with-current-buffer buffer
+ (setq magit-previous-section section)
+ (with-no-warnings
+ (setq magit-refresh-args args))
+ (funcall mode)
+ (magit-xref-setup 'magit-mode-setup-internal args)
+ (when created
+ (magit-status-goto-initial-section)
+ (run-hooks 'magit-create-buffer-hook)))
+ (magit-display-buffer buffer)
+ (with-current-buffer buffer
+ (run-hooks 'magit-mode-setup-hook)
+ (magit-refresh-buffer))))
+
+;;; Display Buffer
+
+(defvar magit-display-buffer-noselect nil
+ "If non-nil, then `magit-display-buffer' doesn't call `select-window'.")
+
+(defun magit-display-buffer (buffer &optional display-function)
+ "Display BUFFER in some window and maybe select it.
+
+If optional DISPLAY-FUNCTION is non-nil, then use that to display
+the buffer. Otherwise use `magit-display-buffer-function', which
+is the normal case.
+
+Then, unless `magit-display-buffer-noselect' is non-nil, select
+the window which was used to display the buffer.
+
+Also run the hooks `magit-pre-display-buffer-hook'
+and `magit-post-display-buffer-hook'."
+ (with-current-buffer buffer
+ (run-hooks 'magit-pre-display-buffer-hook))
+ (let ((window (funcall (or display-function magit-display-buffer-function)
+ buffer)))
+ (unless magit-display-buffer-noselect
+ (let* ((old-frame (selected-frame))
+ (new-frame (window-frame window)))
+ (select-window window)
+ (unless (eq old-frame new-frame)
+ (select-frame-set-input-focus new-frame)))))
+ (with-current-buffer buffer
+ (run-hooks 'magit-post-display-buffer-hook)))
+
+(defun magit-display-buffer-traditional (buffer)
+ "Display BUFFER the way this has traditionally been done."
+ (display-buffer
+ buffer (if (and (derived-mode-p 'magit-mode)
+ (not (memq (with-current-buffer buffer major-mode)
+ '(magit-process-mode
+ magit-revision-mode
+ magit-diff-mode
+ magit-stash-mode
+ magit-status-mode))))
+ '(display-buffer-same-window)
+ nil))) ; display in another window
+
+(defun magit-display-buffer-same-window-except-diff-v1 (buffer)
+ "Display BUFFER in the selected window except for some modes.
+If a buffer's `major-mode' derives from `magit-diff-mode' or
+`magit-process-mode', display it in another window. Display all
+other buffers in the selected window."
+ (display-buffer
+ buffer (if (with-current-buffer buffer
+ (derived-mode-p 'magit-diff-mode 'magit-process-mode))
+ '(nil (inhibit-same-window . t))
+ '(display-buffer-same-window))))
+
+(defun magit--display-buffer-fullframe (buffer alist)
+ (when-let ((window (or (display-buffer-reuse-window buffer alist)
+ (display-buffer-same-window buffer alist)
+ (display-buffer-pop-up-window buffer alist)
+ (display-buffer-use-some-window buffer alist))))
+ (delete-other-windows window)
+ window))
+
+(defun magit-display-buffer-fullframe-status-v1 (buffer)
+ "Display BUFFER, filling entire frame if BUFFER is a status buffer.
+Otherwise, behave like `magit-display-buffer-traditional'."
+ (if (eq (with-current-buffer buffer major-mode)
+ 'magit-status-mode)
+ (display-buffer buffer '(magit--display-buffer-fullframe))
+ (magit-display-buffer-traditional buffer)))
+
+(defun magit--display-buffer-topleft (buffer alist)
+ (or (display-buffer-reuse-window buffer alist)
+ (when-let ((window2 (display-buffer-pop-up-window buffer alist)))
+ (let ((window1 (get-buffer-window))
+ (buffer1 (current-buffer))
+ (buffer2 (window-buffer window2))
+ (w2-quit-restore (window-parameter window2 'quit-restore)))
+ (set-window-buffer window1 buffer2)
+ (set-window-buffer window2 buffer1)
+ (select-window window2)
+ ;; Swap some window state that `magit-mode-quit-window' and
+ ;; `quit-restore-window' inspect.
+ (set-window-prev-buffers window2 (cdr (window-prev-buffers window1)))
+ (set-window-prev-buffers window1 nil)
+ (set-window-parameter window2 'magit-dedicated
+ (window-parameter window1 'magit-dedicated))
+ (set-window-parameter window1 'magit-dedicated t)
+ (set-window-parameter window1 'quit-restore
+ (list 'window 'window
+ (nth 2 w2-quit-restore)
+ (nth 3 w2-quit-restore)))
+ (set-window-parameter window2 'quit-restore nil)
+ window1))))
+
+(defun magit-display-buffer-fullframe-status-topleft-v1 (buffer)
+ "Display BUFFER, filling entire frame if BUFFER is a status buffer.
+When BUFFER derives from `magit-diff-mode' or
+`magit-process-mode', try to display BUFFER to the top or left of
+the current buffer rather than to the bottom or right, as
+`magit-display-buffer-fullframe-status-v1' would. Whether the
+split is made vertically or horizontally is determined by
+`split-window-preferred-function'."
+ (display-buffer
+ buffer
+ (cond ((eq (with-current-buffer buffer major-mode)
+ 'magit-status-mode)
+ '(magit--display-buffer-fullframe))
+ ((with-current-buffer buffer
+ (derived-mode-p 'magit-diff-mode 'magit-process-mode))
+ '(magit--display-buffer-topleft))
+ (t
+ '(display-buffer-same-window)))))
+
+(defun magit--display-buffer-fullcolumn (buffer alist)
+ (when-let ((window (or (display-buffer-reuse-window buffer alist)
+ (display-buffer-same-window buffer alist)
+ (display-buffer-below-selected buffer alist))))
+ (delete-other-windows-vertically window)
+ window))
+
+(defun magit-display-buffer-fullcolumn-most-v1 (buffer)
+ "Display BUFFER using the full column except in some cases.
+For most cases where BUFFER's `major-mode' derives from
+`magit-mode', display it in the selected window and grow that
+window to the full height of the frame, deleting other windows in
+that column as necessary. However, display BUFFER in another
+window if 1) BUFFER's mode derives from `magit-process-mode', or
+2) BUFFER's mode derives from `magit-diff-mode', provided that
+the mode of the current buffer derives from `magit-log-mode' or
+`magit-cherry-mode'."
+ (display-buffer
+ buffer
+ (cond ((and (or git-commit-mode
+ (derived-mode-p 'magit-log-mode
+ 'magit-cherry-mode
+ 'magit-reflog-mode))
+ (with-current-buffer buffer
+ (derived-mode-p 'magit-diff-mode)))
+ nil)
+ ((with-current-buffer buffer
+ (derived-mode-p 'magit-process-mode))
+ nil)
+ (t
+ '(magit--display-buffer-fullcolumn)))))
+
+(defun magit-maybe-set-dedicated ()
+ "Mark the selected window as dedicated if appropriate.
+
+If a new window was created to display the buffer, then remember
+that fact. That information is used by `magit-mode-quit-window',
+to determine whether the window should be deleted when its last
+Magit buffer is buried."
+ (let ((window (get-buffer-window (current-buffer))))
+ (when (and (window-live-p window)
+ (not (window-prev-buffers window)))
+ (set-window-parameter window 'magit-dedicated t))))
+
+;;; Get Buffer
+
+(defvar-local magit--default-directory nil
+ "Value of `default-directory' when buffer is generated.
+This exists to prevent a let-bound `default-directory' from
+tricking `magit-get-mode-buffer' or `magit-mode-get-buffers'
+into thinking a buffer belongs to a repo that it doesn't.")
+(put 'magit--default-directory 'permanent-local t)
+
+(defun magit-mode-get-buffers ()
+ (let ((topdir (magit-toplevel)))
+ (--filter (with-current-buffer it
+ (and (derived-mode-p 'magit-mode)
+ (equal magit--default-directory topdir)))
+ (buffer-list))))
+
+(defvar-local magit-buffer-locked-p nil)
+(put 'magit-buffer-locked-p 'permanent-local t)
+
+(defun magit-get-mode-buffer (mode &optional value frame)
+ "Return buffer belonging to the current repository whose major-mode is MODE.
+
+If no such buffer exists then return nil. Multiple buffers with
+the same major-mode may exist for a repository but only one can
+exist that hasn't been looked to its value. Return that buffer
+\(or nil if there is no such buffer) unless VALUE is non-nil, in
+which case return the buffer that has been looked to that value.
+
+If FRAME nil or omitted, then consider all buffers. Otherwise
+ only consider buffers that are displayed in some live window
+ on some frame.
+If `all', then consider all buffers on all frames.
+If `visible', then only consider buffers on all visible frames.
+If `selected' or t, then only consider buffers on the selected
+ frame.
+If a frame, then only consider buffers on that frame."
+ (if-let ((topdir (magit-toplevel)))
+ (cl-flet* ((b (buffer)
+ (with-current-buffer buffer
+ (and (eq major-mode mode)
+ (equal magit--default-directory topdir)
+ (if value
+ (and magit-buffer-locked-p
+ (equal (magit-buffer-value) value))
+ (not magit-buffer-locked-p))
+ buffer)))
+ (w (window)
+ (b (window-buffer window)))
+ (f (frame)
+ (seq-some #'w (window-list frame 'no-minibuf))))
+ (pcase-exhaustive frame
+ (`nil (seq-some #'b (buffer-list)))
+ (`all (seq-some #'f (frame-list)))
+ (`visible (seq-some #'f (visible-frame-list)))
+ ((or `selected `t) (seq-some #'w (window-list (selected-frame))))
+ ((guard (framep frame)) (seq-some #'w (window-list frame)))))
+ (magit--not-inside-repository-error)))
+
+(defun magit-mode-get-buffer (mode &optional create frame value)
+ (declare (obsolete magit-get-mode-buffer "Magit 3.0.0"))
+ (when create
+ (error "`magit-mode-get-buffer's CREATE argument is obsolete"))
+ (if-let ((topdir (magit-toplevel)))
+ (--first (with-current-buffer it
+ (and (eq major-mode mode)
+ (equal magit--default-directory topdir)
+ (if value
+ (and magit-buffer-locked-p
+ (equal (magit-buffer-value) value))
+ (not magit-buffer-locked-p))))
+ (if frame
+ (mapcar #'window-buffer
+ (window-list (unless (eq frame t) frame)))
+ (buffer-list)))
+ (magit--not-inside-repository-error)))
+
+(defun magit-generate-new-buffer (mode &optional value)
+ (let* ((name (funcall magit-generate-buffer-name-function mode value))
+ (buffer (generate-new-buffer name)))
+ (with-current-buffer buffer
+ (setq magit--default-directory default-directory)
+ (setq magit-buffer-locked-p (and value t))
+ (magit-restore-section-visibility-cache mode))
+ (when magit-uniquify-buffer-names
+ (add-to-list 'uniquify-list-buffers-directory-modes mode)
+ (with-current-buffer buffer
+ (setq list-buffers-directory (abbreviate-file-name default-directory)))
+ (let ((uniquify-buffer-name-style
+ (if (memq uniquify-buffer-name-style '(nil forward))
+ 'post-forward-angle-brackets
+ uniquify-buffer-name-style)))
+ (uniquify-rationalize-file-buffer-names
+ name (file-name-directory (directory-file-name default-directory))
+ buffer)))
+ buffer))
+
+(defun magit-generate-buffer-name-default-function (mode &optional value)
+ "Generate buffer name for a MODE buffer in the current repository.
+The returned name is based on `magit-buffer-name-format' and
+takes `magit-uniquify-buffer-names' and VALUE, if non-nil, into
+account."
+ (let ((m (substring (symbol-name mode) 0 -5))
+ (v (and value (format "%s" (if (listp value) value (list value)))))
+ (n (if magit-uniquify-buffer-names
+ (file-name-nondirectory
+ (directory-file-name default-directory))
+ (abbreviate-file-name default-directory))))
+ (format-spec
+ magit-buffer-name-format
+ `((?m . ,m)
+ (?M . ,(if (eq mode 'magit-status-mode) "magit" m))
+ (?v . ,(or v ""))
+ (?V . ,(if v (concat " " v) ""))
+ (?t . ,n)
+ (?x . ,(if magit-uniquify-buffer-names "" "*"))
+ (?T . ,(if magit-uniquify-buffer-names n (concat n "*")))))))
+
+;;; Buffer Lock
+
+(defun magit-toggle-buffer-lock ()
+ "Lock the current buffer to its value or unlock it.
+
+Locking a buffer to its value prevents it from being reused to
+display another value. The name of a locked buffer contains its
+value, which allows telling it apart from other locked buffers
+and the unlocked buffer.
+
+Not all Magit buffers can be locked to their values, for example
+it wouldn't make sense to lock a status buffer.
+
+There can only be a single unlocked buffer using a certain
+major-mode per repository. So when a buffer is being unlocked
+and another unlocked buffer already exists for that mode and
+repository, then the former buffer is instead deleted and the
+latter is displayed in its place."
+ (interactive)
+ (if magit-buffer-locked-p
+ (if-let ((unlocked (magit-get-mode-buffer major-mode)))
+ (let ((locked (current-buffer)))
+ (switch-to-buffer unlocked nil t)
+ (kill-buffer locked))
+ (setq magit-buffer-locked-p nil)
+ (rename-buffer (funcall magit-generate-buffer-name-function
+ major-mode)))
+ (if-let ((value (magit-buffer-value)))
+ (if-let ((locked (magit-get-mode-buffer major-mode value)))
+ (let ((unlocked (current-buffer)))
+ (switch-to-buffer locked nil t)
+ (kill-buffer unlocked))
+ (setq magit-buffer-locked-p t)
+ (rename-buffer (funcall magit-generate-buffer-name-function
+ major-mode value)))
+ (user-error "Buffer has no value it could be locked to"))))
+
+;;; Bury Buffer
+
+(defun magit-mode-bury-buffer (&optional kill-buffer)
+ "Bury the current buffer.
+With a prefix argument, kill the buffer instead.
+With two prefix arguments, also kill all Magit buffers associated
+with this repository.
+This is done using `magit-bury-buffer-function'."
+ (interactive "P")
+ ;; Kill all associated Magit buffers when a double prefix arg is given.
+ (when (>= (prefix-numeric-value kill-buffer) 16)
+ (let ((current (current-buffer)))
+ (dolist (buf (magit-mode-get-buffers))
+ (unless (eq buf current)
+ (kill-buffer buf)))))
+ (funcall magit-bury-buffer-function kill-buffer))
+
+(defun magit-mode-quit-window (kill-buffer)
+ "Quit the selected window and bury its buffer.
+
+This behaves similar to `quit-window', but when the window
+was originally created to display a Magit buffer and the
+current buffer is the last remaining Magit buffer that was
+ever displayed in the selected window, then delete that
+window."
+ (if (or (one-window-p)
+ (--first (let ((buffer (car it)))
+ (and (not (eq buffer (current-buffer)))
+ (buffer-live-p buffer)
+ (or (not (window-parameter nil 'magit-dedicated))
+ (with-current-buffer buffer
+ (derived-mode-p 'magit-mode
+ 'magit-process-mode)))))
+ (window-prev-buffers)))
+ (quit-window kill-buffer)
+ (let ((window (selected-window)))
+ (quit-window kill-buffer)
+ (when (window-live-p window)
+ (delete-window window)))))
+
+;;; Refresh Buffers
+
+(defvar inhibit-magit-refresh nil)
+
+(defun magit-refresh ()
+ "Refresh some buffers belonging to the current repository.
+
+Refresh the current buffer if its major mode derives from
+`magit-mode', and refresh the corresponding status buffer.
+
+Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
+ (interactive)
+ (unless inhibit-magit-refresh
+ (unwind-protect
+ (let ((start (current-time))
+ (magit--refresh-cache (or magit--refresh-cache
+ (list (cons 0 0)))))
+ (when magit-refresh-verbose
+ (message "Refreshing magit..."))
+ (magit-run-hook-with-benchmark 'magit-pre-refresh-hook)
+ (cond ((derived-mode-p 'magit-mode)
+ (magit-refresh-buffer))
+ ((derived-mode-p 'tabulated-list-mode)
+ (revert-buffer)))
+ (--when-let (and magit-refresh-status-buffer
+ (not (derived-mode-p 'magit-status-mode))
+ (magit-get-mode-buffer 'magit-status-mode))
+ (with-current-buffer it
+ (magit-refresh-buffer)))
+ (magit-auto-revert-buffers)
+ (cond
+ ((and (not this-command)
+ (memq last-command magit-post-commit-hook-commands))
+ (magit-run-hook-with-benchmark 'magit-post-commit-hook))
+ ((memq this-command magit-post-stage-hook-commands)
+ (magit-run-hook-with-benchmark 'magit-post-stage-hook))
+ ((memq this-command magit-post-unstage-hook-commands)
+ (magit-run-hook-with-benchmark 'magit-post-unstage-hook)))
+ (magit-run-hook-with-benchmark 'magit-post-refresh-hook)
+ (when magit-refresh-verbose
+ (let* ((c (caar magit--refresh-cache))
+ (a (+ c (cdar magit--refresh-cache))))
+ (message "Refreshing magit...done (%.3fs, cached %s/%s (%.0f%%))"
+ (float-time (time-subtract (current-time) start))
+ c a (* (/ c (* a 1.0)) 100)))))
+ (run-hooks 'magit-unwind-refresh-hook))))
+
+(defun magit-refresh-all ()
+ "Refresh all buffers belonging to the current repository.
+
+Refresh all Magit buffers belonging to the current repository,
+and revert buffers that visit files located inside the current
+repository.
+
+Run hooks `magit-pre-refresh-hook' and `magit-post-refresh-hook'."
+ (interactive)
+ (magit-run-hook-with-benchmark 'magit-pre-refresh-hook)
+ (dolist (buffer (magit-mode-get-buffers))
+ (with-current-buffer buffer (magit-refresh-buffer)))
+ (magit-auto-revert-buffers)
+ (magit-run-hook-with-benchmark 'magit-post-refresh-hook))
+
+(defvar-local magit-refresh-start-time nil)
+
+(defun magit-refresh-buffer ()
+ "Refresh the current Magit buffer."
+ (setq magit-refresh-start-time (current-time))
+ (let ((refresh (intern (format "%s-refresh-buffer"
+ (substring (symbol-name major-mode) 0 -5))))
+ (magit--refresh-cache (or magit--refresh-cache (list (cons 0 0)))))
+ (when (functionp refresh)
+ (when magit-refresh-verbose
+ (message "Refreshing buffer `%s'..." (buffer-name)))
+ (let* ((buffer (current-buffer))
+ (windows
+ (--mapcat (with-selected-window it
+ (with-current-buffer buffer
+ (when-let ((section (magit-current-section)))
+ (list
+ (nconc (list it section)
+ (magit-refresh-get-relative-position))))))
+ (or (get-buffer-window-list buffer nil t)
+ (list (selected-window))))))
+ (deactivate-mark)
+ (setq magit-section-highlight-overlays nil)
+ (setq magit-section-highlighted-section nil)
+ (setq magit-section-highlighted-sections nil)
+ (setq magit-section-unhighlight-sections nil)
+ (magit-process-unset-mode-line-error-status)
+ (let ((inhibit-read-only t))
+ (erase-buffer)
+ (save-excursion
+ (apply refresh (with-no-warnings magit-refresh-args))))
+ (pcase-dolist (`(,window . ,args) windows)
+ (with-selected-window window
+ (with-current-buffer buffer
+ (apply #'magit-section-goto-successor args))))
+ (run-hooks 'magit-refresh-buffer-hook)
+ (magit-section-update-highlight)
+ (set-buffer-modified-p nil))
+ (when magit-refresh-verbose
+ (message "Refreshing buffer `%s'...done (%.3fs)" (buffer-name)
+ (float-time (time-subtract (current-time)
+ magit-refresh-start-time)))))))
+
+(defun magit-refresh-get-relative-position ()
+ (when-let ((section (magit-current-section)))
+ (let ((start (oref section start)))
+ (list (count-lines start (point))
+ (- (point) (line-beginning-position))
+ (and (magit-hunk-section-p section)
+ (region-active-p)
+ (progn (goto-char (line-beginning-position))
+ (when (looking-at "^[-+]") (forward-line))
+ (while (looking-at "^[ @]") (forward-line))
+ (let ((beg (point)))
+ (cond ((looking-at "^[-+]")
+ (forward-line)
+ (while (looking-at "^[-+]") (forward-line))
+ (while (looking-at "^ ") (forward-line))
+ (forward-line -1)
+ (regexp-quote (buffer-substring-no-properties
+ beg (line-end-position))))
+ (t t)))))))))
+
+;;; Save File-Visiting Buffers
+
+(defvar disable-magit-save-buffers nil)
+
+(defun magit-pre-command-hook ()
+ (setq disable-magit-save-buffers nil))
+(add-hook 'pre-command-hook #'magit-pre-command-hook)
+
+(defvar magit-after-save-refresh-buffers nil)
+
+(defun magit-after-save-refresh-buffers ()
+ (dolist (buffer magit-after-save-refresh-buffers)
+ (when (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (magit-refresh-buffer))))
+ (setq magit-after-save-refresh-buffers nil)
+ (remove-hook 'post-command-hook 'magit-after-save-refresh-buffers))
+
+(defun magit-after-save-refresh-status ()
+ "Refresh the status buffer of the current repository.
+
+This function is intended to be added to `after-save-hook'.
+
+If the status buffer does not exist or the file being visited in
+the current buffer isn't inside the working tree of a repository,
+then do nothing.
+
+Note that refreshing a Magit buffer is done by re-creating its
+contents from scratch, which can be slow in large repositories.
+If you are not satisfied with Magit's performance, then you
+should obviously not add this function to that hook."
+ (when (and (not disable-magit-save-buffers)
+ (magit-inside-worktree-p t))
+ (--when-let (ignore-errors (magit-get-mode-buffer 'magit-status-mode))
+ (add-to-list 'magit-after-save-refresh-buffers it)
+ (add-hook 'post-command-hook 'magit-after-save-refresh-buffers))))
+
+(defun magit-maybe-save-repository-buffers ()
+ "Maybe save file-visiting buffers belonging to the current repository.
+Do so if `magit-save-repository-buffers' is non-nil. You should
+not remove this from any hooks, instead set that variable to nil
+if you so desire."
+ (when (and magit-save-repository-buffers
+ (not disable-magit-save-buffers))
+ (setq disable-magit-save-buffers t)
+ (let ((msg (current-message)))
+ (magit-save-repository-buffers
+ (eq magit-save-repository-buffers 'dontask))
+ (when (and msg
+ (current-message)
+ (not (equal msg (current-message))))
+ (message "%s" msg)))))
+
+(add-hook 'magit-pre-refresh-hook #'magit-maybe-save-repository-buffers)
+(add-hook 'magit-pre-call-git-hook #'magit-maybe-save-repository-buffers)
+(add-hook 'magit-pre-start-git-hook #'magit-maybe-save-repository-buffers)
+
+(defvar-local magit-inhibit-refresh-save nil)
+
+(defun magit-save-repository-buffers (&optional arg)
+ "Save file-visiting buffers belonging to the current repository.
+After any buffer where `buffer-save-without-query' is non-nil
+is saved without asking, the user is asked about each modified
+buffer which visits a file in the current repository. Optional
+argument (the prefix) non-nil means save all with no questions."
+ (interactive "P")
+ (when-let ((topdir (magit-rev-parse-safe "--show-toplevel")))
+ (let ((remote (file-remote-p topdir))
+ (save-some-buffers-action-alist
+ `((?Y (lambda (buffer)
+ (with-current-buffer buffer
+ (setq buffer-save-without-query t)
+ (save-buffer)))
+ "to save the current buffer and remember choice")
+ (?N (lambda (buffer)
+ (with-current-buffer buffer
+ (setq magit-inhibit-refresh-save t)))
+ "to skip the current buffer and remember choice")
+ ,@save-some-buffers-action-alist)))
+ (save-some-buffers
+ arg (lambda ()
+ (and (not magit-inhibit-refresh-save)
+ buffer-file-name
+ ;; Avoid needlessly connecting to unrelated remotes.
+ (equal (file-remote-p buffer-file-name)
+ remote)
+ ;; For remote files this makes network requests and
+ ;; therefore has to come after the above to avoid
+ ;; unnecessarily waiting for unrelated hosts.
+ (file-exists-p (file-name-directory buffer-file-name))
+ (string-prefix-p topdir (file-truename buffer-file-name))
+ (equal (magit-rev-parse-safe "--show-toplevel")
+ topdir)))))))
+
+;;; Restore Window Configuration
+
+(defvar magit-inhibit-save-previous-winconf nil)
+
+(defvar-local magit-previous-window-configuration nil)
+(put 'magit-previous-window-configuration 'permanent-local t)
+
+(defun magit-save-window-configuration ()
+ "Save the current window configuration.
+
+Later, when the buffer is buried, it may be restored by
+`magit-restore-window-configuration'."
+ (if magit-inhibit-save-previous-winconf
+ (when (eq magit-inhibit-save-previous-winconf 'unset)
+ (setq magit-previous-window-configuration nil))
+ (unless (get-buffer-window (current-buffer) (selected-frame))
+ (setq magit-previous-window-configuration
+ (current-window-configuration)))))
+
+(defun magit-restore-window-configuration (&optional kill-buffer)
+ "Bury or kill the current buffer and restore previous window configuration."
+ (let ((winconf magit-previous-window-configuration)
+ (buffer (current-buffer))
+ (frame (selected-frame)))
+ (quit-window kill-buffer (selected-window))
+ (when (and winconf (equal frame (window-configuration-frame winconf)))
+ (set-window-configuration winconf)
+ (when (buffer-live-p buffer)
+ (with-current-buffer buffer
+ (setq magit-previous-window-configuration nil))))))
+
+;;; Buffer History
+
+(defun magit-go-backward ()
+ "Move backward in current buffer's history."
+ (interactive)
+ (if help-xref-stack
+ (help-xref-go-back (current-buffer))
+ (user-error "No previous entry in buffer's history")))
+
+(defun magit-go-forward ()
+ "Move forward in current buffer's history."
+ (interactive)
+ (if help-xref-forward-stack
+ (help-xref-go-forward (current-buffer))
+ (user-error "No next entry in buffer's history")))
+
+(defun magit-insert-xref-buttons ()
+ "Insert xref buttons."
+ (when (and (not magit-buffer-locked-p)
+ (or help-xref-stack help-xref-forward-stack))
+ (when help-xref-stack
+ (magit-xref-insert-button help-back-label 'magit-xref-backward))
+ (when help-xref-forward-stack
+ (when help-xref-stack
+ (insert " "))
+ (magit-xref-insert-button help-forward-label 'magit-xref-forward))))
+
+(defun magit-xref-insert-button (label type)
+ (magit-insert-section (button label)
+ (insert-text-button label 'type type
+ 'help-args (list (current-buffer)))))
+
+(define-button-type 'magit-xref-backward
+ :supertype 'help-back
+ 'mouse-face 'magit-section-highlight
+ 'help-echo (purecopy "mouse-2, RET: go back to previous history entry"))
+
+(define-button-type 'magit-xref-forward
+ :supertype 'help-forward
+ 'mouse-face 'magit-section-highlight
+ 'help-echo (purecopy "mouse-2, RET: go back to next history entry"))
+
+(defvar magit-xref-modes
+ '(magit-log-mode
+ magit-reflog-mode
+ magit-diff-mode
+ magit-revision-mode)
+ "List of modes for which to insert navigation buttons.")
+
+(defun magit-xref-setup (fn args)
+ (when (memq major-mode magit-xref-modes)
+ (when help-xref-stack-item
+ (push (cons (point) help-xref-stack-item) help-xref-stack)
+ (setq help-xref-forward-stack nil))
+ (when (called-interactively-p 'interactive)
+ (--when-let (nthcdr 10 help-xref-stack)
+ (setcdr it nil)))
+ (setq help-xref-stack-item
+ (list 'magit-xref-restore fn default-directory args))))
+
+(defun magit-xref-restore (fn dir args)
+ (setq default-directory dir)
+ (funcall fn major-mode nil args)
+ (magit-refresh-buffer))
+
+;;; Repository-Local Cache
+
+(defvar magit-repository-local-cache nil
+ "Alist mapping `magit-toplevel' paths to alists of key/value pairs.")
+
+(defun magit-repository-local-repository ()
+ "Return the key for the current repository."
+ (or (bound-and-true-p magit--default-directory)
+ (magit-toplevel)))
+
+(defun magit-repository-local-set (key value &optional repository)
+ "Set the repository-local VALUE for KEY.
+
+Unless specified, REPOSITORY is the current buffer's repository.
+
+If REPOSITORY is nil (meaning there is no current repository),
+then the value is not cached, and we return nil."
+ (let* ((repokey (or repository (magit-repository-local-repository)))
+ (cache (assoc repokey magit-repository-local-cache)))
+ ;; Don't cache values for a nil REPOSITORY, as the 'set' and 'get'
+ ;; calls for some KEY may happen in unrelated contexts.
+ (when repokey
+ (if cache
+ (let ((keyvalue (assoc key (cdr cache))))
+ (if keyvalue
+ ;; Update pre-existing value for key.
+ (setcdr keyvalue value)
+ ;; No such key in repository-local cache.
+ (push (cons key value) (cdr cache))))
+ ;; No cache for this repository.
+ (push (cons repokey (list (cons key value)))
+ magit-repository-local-cache)))))
+
+(defun magit-repository-local-exists-p (key &optional repository)
+ "Non-nil when a repository-local value exists for KEY.
+
+Return a (KEY . VALUE) cons cell.
+
+The KEY is matched using `equal'.
+
+Unless specified, REPOSITORY is the current buffer's repository."
+ (when-let ((cache (assoc (or repository
+ (magit-repository-local-repository))
+ magit-repository-local-cache)))
+ (assoc key (cdr cache))))
+
+(defun magit-repository-local-get (key &optional default repository)
+ "Return the repository-local value for KEY.
+
+Return DEFAULT if no value for KEY exists.
+
+The KEY is matched using `equal'.
+
+Unless specified, REPOSITORY is the current buffer's repository."
+ (if-let ((keyvalue (magit-repository-local-exists-p key repository)))
+ (cdr keyvalue)
+ default))
+
+(defun magit-repository-local-delete (key &optional repository)
+ "Delete the repository-local value for KEY.
+
+Unless specified, REPOSITORY is the current buffer's repository."
+ (when-let ((cache (assoc (or repository
+ (magit-repository-local-repository))
+ magit-repository-local-cache)))
+ ;; There is no `assoc-delete-all'.
+ (setf (cdr cache)
+ (cl-delete key (cdr cache) :key #'car :test #'equal))))
+
+(defmacro magit--with-repository-local-cache (key &rest body)
+ (declare (indent 1) (debug (form body)))
+ (let ((k (cl-gensym)))
+ `(let ((,k ,key))
+ (if-let ((kv (magit-repository-local-exists-p ,k)))
+ (cdr kv)
+ (let ((v ,(macroexp-progn body)))
+ (magit-repository-local-set ,k v)
+ v)))))
+
+(defun magit-preserve-section-visibility-cache ()
+ (when (derived-mode-p 'magit-status-mode 'magit-refs-mode)
+ (magit-repository-local-set
+ (cons major-mode 'magit-section-visibility-cache)
+ magit-section-visibility-cache)))
+
+(defun magit-restore-section-visibility-cache (mode)
+ (setq magit-section-visibility-cache
+ (magit-repository-local-get
+ (cons mode 'magit-section-visibility-cache))))
+
+(defun magit-zap-caches ()
+ "Zap caches for the current repository.
+Remove the repository's entry from `magit-repository-local-cache'
+and set `magit-section-visibility-cache' to nil in all of the
+repository's Magit buffers."
+ (interactive)
+ (magit-with-toplevel
+ (setq magit-repository-local-cache
+ (cl-delete default-directory
+ magit-repository-local-cache
+ :key #'car :test #'equal)))
+ (dolist (buffer (magit-mode-get-buffers))
+ (with-current-buffer buffer
+ (setq magit-section-visibility-cache nil)))
+ (setq magit--libgit-available-p eieio-unbound))
+
+;;; Utilities
+
+(defun magit-toggle-verbose-refresh ()
+ "Toggle whether Magit refreshes buffers verbosely.
+Enabling this helps figuring out which sections are bottlenecks.
+The additional output can be found in the *Messages* buffer."
+ (interactive)
+ (setq magit-refresh-verbose (not magit-refresh-verbose))
+ (message "%s verbose refreshing"
+ (if magit-refresh-verbose "Enabled" "Disabled")))
+
+(defun magit-run-hook-with-benchmark (hook)
+ (when hook
+ (if magit-refresh-verbose
+ (let ((start (current-time)))
+ (message "Running %s..." hook)
+ (run-hooks hook)
+ (message "Running %s...done (%.3fs)" hook
+ (float-time (time-subtract (current-time) start))))
+ (run-hooks hook))))
+
+;;; _
+(provide 'magit-mode)
+;;; magit-mode.el ends here
--- /dev/null
+;;; magit-notes.el --- notes support -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements support for `git-notes'.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-notes "magit" nil t)
+(transient-define-prefix magit-notes ()
+ "Edit notes attached to commits."
+ :man-page "git-notes"
+ ["Configure local settings"
+ ("c" magit-core.notesRef)
+ ("d" magit-notes.displayRef)]
+ ["Configure global settings"
+ ("C" magit-global-core.notesRef)
+ ("D" magit-global-notes.displayRef)]
+ ["Arguments for prune"
+ :if-not magit-notes-merging-p
+ ("-n" "Dry run" ("-n" "--dry-run"))]
+ ["Arguments for edit and remove"
+ :if-not magit-notes-merging-p
+ (magit-notes:--ref)]
+ ["Arguments for merge"
+ :if-not magit-notes-merging-p
+ (magit-notes:--strategy)]
+ ["Actions"
+ :if-not magit-notes-merging-p
+ ("T" "Edit" magit-notes-edit)
+ ("r" "Remove" magit-notes-remove)
+ ("m" "Merge" magit-notes-merge)
+ ("p" "Prune" magit-notes-prune)]
+ ["Actions"
+ :if magit-notes-merging-p
+ ("c" "Commit merge" magit-notes-merge-commit)
+ ("a" "Abort merge" magit-notes-merge-abort)])
+
+(defun magit-notes-merging-p ()
+ (let ((dir (magit-git-dir "NOTES_MERGE_WORKTREE")))
+ (and (file-directory-p dir)
+ (directory-files dir nil "^[^.]"))))
+
+(transient-define-infix magit-core.notesRef ()
+ :class 'magit--git-variable
+ :variable "core.notesRef"
+ :reader 'magit-notes-read-ref
+ :prompt "Set local core.notesRef")
+
+(transient-define-infix magit-notes.displayRef ()
+ :class 'magit--git-variable
+ :variable "notes.displayRef"
+ :multi-value t
+ :reader 'magit-notes-read-refs
+ :prompt "Set local notes.displayRef")
+
+(transient-define-infix magit-global-core.notesRef ()
+ :class 'magit--git-variable
+ :variable "core.notesRef"
+ :reader 'magit-notes-read-ref
+ :prompt "Set global core.notesRef")
+
+(transient-define-infix magit-global-notes.displayRef ()
+ :class 'magit--git-variable
+ :variable "notes.displayRef"
+ :multi-value t
+ :reader 'magit-notes-read-refs
+ :prompt "Set global notes.displayRef")
+
+(transient-define-argument magit-notes:--ref ()
+ :description "Merge strategy"
+ :class 'transient-option
+ :key "-r"
+ :argument "--ref="
+ :reader 'magit-notes-read-ref)
+
+(transient-define-argument magit-notes:--strategy ()
+ :description "Merge strategy"
+ :class 'transient-option
+ :shortarg "-s"
+ :argument "--strategy="
+ :choices '("manual" "ours" "theirs" "union" "cat_sort_uniq"))
+
+(defun magit-notes-edit (commit &optional ref)
+ "Edit the note attached to COMMIT.
+REF is the notes ref used to store the notes.
+
+Interactively or when optional REF is nil use the value of Git
+variable `core.notesRef' or \"refs/notes/commits\" if that is
+undefined."
+ (interactive (magit-notes-read-args "Edit notes"))
+ (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref))
+ "edit" commit))
+
+(defun magit-notes-remove (commit &optional ref)
+ "Remove the note attached to COMMIT.
+REF is the notes ref from which the note is removed.
+
+Interactively or when optional REF is nil use the value of Git
+variable `core.notesRef' or \"refs/notes/commits\" if that is
+undefined."
+ (interactive (magit-notes-read-args "Remove notes"))
+ (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref))
+ "remove" commit))
+
+(defun magit-notes-merge (ref)
+ "Merge the notes ref REF into the current notes ref.
+
+The current notes ref is the value of Git variable
+`core.notesRef' or \"refs/notes/commits\" if that is undefined.
+
+When there are conflicts, then they have to be resolved in the
+temporary worktree \".git/NOTES_MERGE_WORKTREE\". When
+done use `magit-notes-merge-commit' to finish. To abort
+use `magit-notes-merge-abort'."
+ (interactive (list (magit-read-string-ns "Merge reference")))
+ (magit-run-git-with-editor "notes" "merge" ref))
+
+(defun magit-notes-merge-commit ()
+ "Commit the current notes ref merge.
+Also see `magit-notes-merge'."
+ (interactive)
+ (magit-run-git-with-editor "notes" "merge" "--commit"))
+
+(defun magit-notes-merge-abort ()
+ "Abort the current notes ref merge.
+Also see `magit-notes-merge'."
+ (interactive)
+ (magit-run-git-with-editor "notes" "merge" "--abort"))
+
+(defun magit-notes-prune (&optional dry-run)
+ "Remove notes about unreachable commits."
+ (interactive (list (and (member "--dry-run" (transient-args 'magit-notes)) t)))
+ (when dry-run
+ (magit-process-buffer))
+ (magit-run-git-with-editor "notes" "prune" (and dry-run "--dry-run")))
+
+;;; Readers
+
+(defun magit-notes-read-ref (prompt _initial-input history)
+ (--when-let (magit-completing-read
+ prompt (magit-list-notes-refnames) nil nil
+ (--when-let (magit-get "core.notesRef")
+ (if (string-prefix-p "refs/notes/" it)
+ (substring it 11)
+ it))
+ history)
+ (if (string-prefix-p "refs/" it)
+ it
+ (concat "refs/notes/" it))))
+
+(defun magit-notes-read-refs (prompt)
+ (mapcar (lambda (ref)
+ (if (string-prefix-p "refs/" ref)
+ ref
+ (concat "refs/notes/" ref)))
+ (completing-read-multiple
+ (concat prompt ": ")
+ (magit-list-notes-refnames) nil nil
+ (mapconcat (lambda (ref)
+ (if (string-prefix-p "refs/notes/" ref)
+ (substring ref 11)
+ ref))
+ (magit-get-all "notes.displayRef")
+ ","))))
+
+(defun magit-notes-read-args (prompt)
+ (list (magit-read-branch-or-commit prompt (magit-stash-at-point))
+ (--when-let (--first (string-match "^--ref=\\(.+\\)" it)
+ (transient-args 'magit-notes))
+ (match-string 1 it))))
+
+;;; _
+(provide 'magit-notes)
+;;; magit-notes.el ends here
--- /dev/null
+;;; magit-obsolete.el --- obsolete definitions -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library defines aliases for obsolete variables and functions.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Obsolete since v3.0.0
+
+(define-obsolete-function-alias 'magit-diff-visit-file-worktree
+ 'magit-diff-visit-worktree-file "Magit 3.0.0")
+
+(define-obsolete-function-alias 'magit-status-internal
+ 'magit-status-setup-buffer "Magit 3.0.0")
+
+(define-obsolete-variable-alias 'magit-mode-setup-hook
+ 'magit-setup-buffer-hook "Magit 3.0.0")
+
+(define-obsolete-variable-alias 'magit-branch-popup-show-variables
+ 'magit-branch-direct-configure "Magit 3.0.0")
+
+(define-obsolete-function-alias 'magit-dispatch-popup
+ 'magit-dispatch "Magit 3.0.0")
+
+(define-obsolete-function-alias 'magit-repolist-column-dirty
+ 'magit-repolist-column-flag "Magit 3.0.0")
+
+(define-obsolete-variable-alias 'magit-disable-line-numbers
+ 'magit-section-disable-line-numbers "Magit 3.0.0")
+
+(defun magit--magit-popup-warning ()
+ (display-warning 'magit "\
+Magit no longer uses Magit-Popup.
+It now uses Transient.
+See https://emacsair.me/2019/02/14/transient-0.1.
+
+However your configuration and/or some third-party package that
+you use still depends on the `magit-popup' package. But because
+`magit' no longer depends on that, `package' has removed it from
+your system.
+
+If some package that you use still depends on `magit-popup' but
+does not declare it as a dependency, then please contact its
+maintainer about that and install `magit-popup' explicitly.
+
+If you yourself use functions that are defined in `magit-popup'
+in your configuration, then the next step depends on what you use
+that for.
+
+* If you use `magit-popup' to define your own popups but do not
+ modify any of Magit's old popups, then you have to install
+ `magit-popup' explicitly. (You can also migrate to Transient,
+ but there is no need to rush that.)
+
+* If you add additional arguments and/or actions to Magit's popups,
+ then you have to port that to modify the new \"transients\" instead.
+ See https://github.com/magit/magit/wiki/\
+Converting-popup-modifications-to-transient-modifications
+
+To find installed packages that still use `magit-popup' you can
+use e.g. \"M-x rgrep RET magit-popup RET RET ~/.emacs.d/ RET\"."))
+(cl-eval-when (eval load)
+ (unless (require (quote magit-popup) nil t)
+ (defun magit-define-popup-switch (&rest _)
+ (magit--magit-popup-warning))
+ (defun magit-define-popup-option (&rest _)
+ (magit--magit-popup-warning))
+ (defun magit-define-popup-variable (&rest _)
+ (magit--magit-popup-warning))
+ (defun magit-define-popup-action (&rest _)
+ (magit--magit-popup-warning))
+ (defun magit-define-popup-sequence-action (&rest _)
+ (magit--magit-popup-warning))
+ (defun magit-define-popup-key (&rest _)
+ (magit--magit-popup-warning))
+ (defun magit-define-popup-keys-deferred (&rest _)
+ (magit--magit-popup-warning))
+ (defun magit-change-popup-key (&rest _)
+ (magit--magit-popup-warning))
+ (defun magit-remove-popup-key (&rest _)
+ (magit--magit-popup-warning))))
+
+;;; _
+(provide 'magit-obsolete)
+;;; magit-obsolete.el ends here
--- /dev/null
+;;; magit-patch.el --- creating and applying patches -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements patch commands.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Options
+
+(defcustom magit-patch-save-arguments '(exclude "--stat")
+ "Control arguments used by the command `magit-patch-save'.
+
+`magit-patch-save' (which see) saves a diff for the changes
+shown in the current buffer in a patch file. It may use the
+same arguments as used in the buffer or a subset thereof, or
+a constant list of arguments, depending on this option and
+the prefix argument."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-diff
+ :type '(choice (const :tag "use buffer arguments" buffer)
+ (cons :tag "use buffer arguments except"
+ (const :format "" exclude)
+ (repeat :format "%v%i\n"
+ (string :tag "Argument")))
+ (repeat :tag "use constant arguments"
+ (string :tag "Argument"))))
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-patch "magit-patch" nil t)
+(transient-define-prefix magit-patch ()
+ "Create or apply patches."
+ ["Actions"
+ ("c" "Create patches" magit-patch-create)
+ ("a" "Apply patch" magit-patch-apply)
+ ("s" "Save diff as patch" magit-patch-save)
+ ("r" "Request pull" magit-request-pull)])
+
+;;;###autoload (autoload 'magit-patch-create "magit-patch" nil t)
+(transient-define-prefix magit-patch-create (range args files)
+ "Create patches for the commits in RANGE.
+When a single commit is given for RANGE, create a patch for the
+changes introduced by that commit (unlike 'git format-patch'
+which creates patches for all commits that are reachable from
+`HEAD' but not from the specified commit)."
+ :man-page "git-format-patch"
+ :incompatible '(("--subject-prefix=" "--rfc"))
+ ["Mail arguments"
+ (6 magit-format-patch:--in-reply-to)
+ (6 magit-format-patch:--thread)
+ (6 magit-format-patch:--from)
+ (6 magit-format-patch:--to)
+ (6 magit-format-patch:--cc)]
+ ["Patch arguments"
+ (magit-format-patch:--base)
+ (magit-format-patch:--reroll-count)
+ (5 magit-format-patch:--interdiff)
+ (magit-format-patch:--range-diff)
+ (magit-format-patch:--subject-prefix)
+ ("C-m r " "RFC subject prefix" "--rfc")
+ ("C-m l " "Add cover letter" "--cover-letter")
+ (5 magit-format-patch:--cover-from-description)
+ (5 magit-format-patch:--notes)
+ (magit-format-patch:--output-directory)]
+ ["Diff arguments"
+ (magit-diff:-U)
+ (magit-diff:-M)
+ (magit-diff:-C)
+ (magit-diff:--diff-algorithm)
+ (magit:--)
+ (7 "-b" "Ignore whitespace changes" ("-b" "--ignore-space-change"))
+ (7 "-w" "Ignore all whitespace" ("-w" "--ignore-all-space"))]
+ ["Actions"
+ ("c" "Create patches" magit-patch-create)]
+ (interactive
+ (if (not (eq transient-current-command 'magit-patch-create))
+ (list nil nil nil)
+ (cons (if-let ((revs (magit-region-values 'commit t)))
+ (concat (car (last revs)) "^.." (car revs))
+ (let ((range (magit-read-range-or-commit
+ "Format range or commit")))
+ (if (string-match-p "\\.\\." range)
+ range
+ (format "%s~..%s" range range))))
+ (let ((args (transient-args 'magit-patch-create)))
+ (list (-filter #'stringp args)
+ (cdr (assoc "--" args)))))))
+ (if (not range)
+ (transient-setup 'magit-patch-create)
+ (magit-run-git "format-patch" range args "--" files)
+ (when (member "--cover-letter" args)
+ (save-match-data
+ (find-file
+ (expand-file-name
+ (concat (when-let ((v (transient-arg-value "--reroll-count=" args)))
+ (format "v%s-" v))
+ "0000-cover-letter.patch")
+ (let ((topdir (magit-toplevel)))
+ (if-let ((dir (transient-arg-value "--output-directory=" args)))
+ (expand-file-name dir topdir)
+ topdir))))))))
+
+(transient-define-argument magit-format-patch:--in-reply-to ()
+ :description "In reply to"
+ :class 'transient-option
+ :key "C-m C-r"
+ :argument "--in-reply-to=")
+
+(transient-define-argument magit-format-patch:--thread ()
+ :description "Thread style"
+ :class 'transient-option
+ :key "C-m s "
+ :argument "--thread="
+ :reader #'magit-format-patch-select-thread-style)
+
+(defun magit-format-patch-select-thread-style (&rest _ignore)
+ (magit-read-char-case "Thread style " t
+ (?d "[d]eep" "deep")
+ (?s "[s]hallow" "shallow")))
+
+(transient-define-argument magit-format-patch:--base ()
+ :description "Insert base commit"
+ :class 'transient-option
+ :key "C-m b "
+ :argument "--base="
+ :reader #'magit-format-patch-select-base)
+
+(defun magit-format-patch-select-base (prompt initial-input history)
+ (or (magit-completing-read prompt (cons "auto" (magit-list-refnames))
+ nil nil initial-input history "auto")
+ (user-error "Nothing selected")))
+
+(transient-define-argument magit-format-patch:--reroll-count ()
+ :description "Reroll count"
+ :class 'transient-option
+ :key "C-m v "
+ :shortarg "-v"
+ :argument "--reroll-count="
+ :reader 'transient-read-number-N+)
+
+(transient-define-argument magit-format-patch:--interdiff ()
+ :description "Insert interdiff"
+ :class 'transient-option
+ :key "C-m d i"
+ :argument "--interdiff="
+ :reader #'magit-transient-read-revision)
+
+(transient-define-argument magit-format-patch:--range-diff ()
+ :description "Insert range-diff"
+ :class 'transient-option
+ :key "C-m d r"
+ :argument "--range-diff="
+ :reader #'magit-format-patch-select-range-diff)
+
+(defun magit-format-patch-select-range-diff (prompt _initial-input _history)
+ (magit-read-range-or-commit prompt))
+
+(transient-define-argument magit-format-patch:--subject-prefix ()
+ :description "Subject Prefix"
+ :class 'transient-option
+ :key "C-m p "
+ :argument "--subject-prefix=")
+
+(transient-define-argument magit-format-patch:--cover-from-description ()
+ :description "Use branch description"
+ :class 'transient-option
+ :key "C-m D "
+ :argument "--cover-from-description="
+ :reader #'magit-format-patch-select-description-mode)
+
+(defun magit-format-patch-select-description-mode (&rest _ignore)
+ (magit-read-char-case "Use description as " t
+ (?m "[m]essage" "message")
+ (?s "[s]ubject" "subject")
+ (?a "[a]uto" "auto")
+ (?n "[n]othing" "none")))
+
+(transient-define-argument magit-format-patch:--notes ()
+ :description "Insert commentary from notes"
+ :class 'transient-option
+ :key "C-m n "
+ :argument "--notes="
+ :reader #'magit-notes-read-ref)
+
+(transient-define-argument magit-format-patch:--from ()
+ :description "From"
+ :class 'transient-option
+ :key "C-m C-f"
+ :argument "--from="
+ :reader 'magit-transient-read-person)
+
+(transient-define-argument magit-format-patch:--to ()
+ :description "To"
+ :class 'transient-option
+ :key "C-m C-t"
+ :argument "--to="
+ :reader 'magit-transient-read-person)
+
+(transient-define-argument magit-format-patch:--cc ()
+ :description "CC"
+ :class 'transient-option
+ :key "C-m C-c"
+ :argument "--cc="
+ :reader 'magit-transient-read-person)
+
+(transient-define-argument magit-format-patch:--output-directory ()
+ :description "Output directory"
+ :class 'transient-option
+ :key "C-m o "
+ :shortarg "-o"
+ :argument "--output-directory="
+ :reader 'transient-read-existing-directory)
+
+;;;###autoload (autoload 'magit-patch-apply "magit-patch" nil t)
+(transient-define-prefix magit-patch-apply (file &rest args)
+ "Apply the patch file FILE."
+ :man-page "git-apply"
+ ["Arguments"
+ ("-i" "Also apply to index" "--index")
+ ("-c" "Only apply to index" "--cached")
+ ("-3" "Fall back on 3way merge" ("-3" "--3way"))]
+ ["Actions"
+ ("a" "Apply patch" magit-patch-apply)]
+ (interactive
+ (if (not (eq transient-current-command 'magit-patch-apply))
+ (list nil)
+ (list (expand-file-name
+ (read-file-name "Apply patch: "
+ default-directory nil nil
+ (when-let ((file (magit-file-at-point)))
+ (file-relative-name file))))
+ (transient-args 'magit-patch-apply))))
+ (if (not file)
+ (transient-setup 'magit-patch-apply)
+ (magit-run-git "apply" args "--" (magit-convert-filename-for-git file))))
+
+;;;###autoload
+(defun magit-patch-save (file &optional arg)
+ "Write current diff into patch FILE.
+
+What arguments are used to create the patch depends on the value
+of `magit-patch-save-arguments' and whether a prefix argument is
+used.
+
+If the value is the symbol `buffer', then use the same arguments
+as the buffer. With a prefix argument use no arguments.
+
+If the value is a list beginning with the symbol `exclude', then
+use the same arguments as the buffer except for those matched by
+entries in the cdr of the list. The comparison is done using
+`string-prefix-p'. With a prefix argument use the same arguments
+as the buffer.
+
+If the value is a list of strings (including the empty list),
+then use those arguments. With a prefix argument use the same
+arguments as the buffer.
+
+Of course the arguments that are required to actually show the
+same differences as those shown in the buffer are always used."
+ (interactive (list (read-file-name "Write patch file: " default-directory)
+ current-prefix-arg))
+ (unless (derived-mode-p 'magit-diff-mode)
+ (user-error "Only diff buffers can be saved as patches"))
+ (let ((rev magit-buffer-range)
+ (typearg magit-buffer-typearg)
+ (args magit-buffer-diff-args)
+ (files magit-buffer-diff-files))
+ (cond ((eq magit-patch-save-arguments 'buffer)
+ (when arg
+ (setq args nil)))
+ ((eq (car-safe magit-patch-save-arguments) 'exclude)
+ (unless arg
+ (setq args (-difference args (cdr magit-patch-save-arguments)))))
+ ((not arg)
+ (setq args magit-patch-save-arguments)))
+ (with-temp-file file
+ (magit-git-insert "diff" rev "-p" typearg args "--" files)))
+ (magit-refresh))
+
+;;;###autoload
+(defun magit-request-pull (url start end)
+ "Request upstream to pull from your public repository.
+
+URL is the url of your publicly accessible repository.
+START is a commit that already is in the upstream repository.
+END is the last commit, usually a branch name, which upstream
+is asked to pull. START has to be reachable from that commit."
+ (interactive
+ (list (magit-get "remote" (magit-read-remote "Remote") "url")
+ (magit-read-branch-or-commit "Start" (magit-get-upstream-branch))
+ (magit-read-branch-or-commit "End")))
+ (let ((dir default-directory))
+ ;; mu4e changes default-directory
+ (compose-mail)
+ (setq default-directory dir))
+ (message-goto-body)
+ (magit-git-insert "request-pull" start url end)
+ (set-buffer-modified-p nil))
+
+;;; _
+(provide 'magit-patch)
+;;; magit-patch.el ends here
--- /dev/null
+(define-package "magit" "20210128.1702" "A Git porcelain inside Emacs."
+ '((emacs "25.1")
+ (dash "20200524")
+ (git-commit "20200516")
+ (transient "20200601")
+ (with-editor "20200522"))
+ :commit "e80eff30d24337a75e07f6d2c154f7d82f140d28" :authors
+ '(("Marius Vollmer" . "marius.vollmerNOSPAMgmail.com"))
+ :maintainer
+ '("Jonas Bernoulli" . "jonasNOSPAMbernoul.li")
+ :keywords
+ '("git" "tools" "vc")
+ :url "https://github.com/magit/magit")
+;; Local Variables:
+;; no-byte-compile: t
+;; End:
--- /dev/null
+;;; magit-process.el --- process functionality -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements the tools used to run Git for side-effects.
+
+;; Note that the functions used to run Git and then consume its
+;; output, are defined in `magit-git.el'. There's a bit of overlap
+;; though.
+
+;;; Code:
+
+(require 'magit-utils)
+(require 'magit-section)
+(require 'magit-git)
+(require 'magit-mode)
+
+(require 'ansi-color)
+(require 'with-editor)
+
+(declare-function auth-source-search "auth-source"
+ (&rest spec &key max require create delete &allow-other-keys))
+
+;;; Options
+
+(defcustom magit-process-connection-type (not (eq system-type 'cygwin))
+ "Connection type used for the Git process.
+
+If nil, use pipes: this is usually more efficient, and works on Cygwin.
+If t, use ptys: this enables Magit to prompt for passphrases when needed."
+ :group 'magit-process
+ :type '(choice (const :tag "pipe" nil)
+ (const :tag "pty" t)))
+
+(defcustom magit-need-cygwin-noglob
+ (and (eq system-type 'windows-nt)
+ (with-temp-buffer
+ (let ((process-environment
+ (append magit-git-environment process-environment)))
+ (condition-case e
+ (process-file magit-git-executable
+ nil (current-buffer) nil
+ "-c" "alias.echo=!echo" "echo" "x{0}")
+ (file-error
+ (lwarn 'magit-process :warning
+ "Could not run Git: %S" e))))
+ (equal "x0\n" (buffer-string))))
+ "Whether to use a workaround for Cygwin's globbing behavior.
+
+If non-nil, add environment variables to `process-environment' to
+prevent the git.exe distributed by Cygwin and MSYS2 from
+attempting to perform glob expansion when called from a native
+Windows build of Emacs. See #2246."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-process
+ :type '(choice (const :tag "Yes" t)
+ (const :tag "No" nil)))
+
+(defcustom magit-process-popup-time -1
+ "Popup the process buffer if a command takes longer than this many seconds."
+ :group 'magit-process
+ :type '(choice (const :tag "Never" -1)
+ (const :tag "Immediately" 0)
+ (integer :tag "After this many seconds")))
+
+(defcustom magit-process-log-max 32
+ "Maximum number of sections to keep in a process log buffer.
+When adding a new section would go beyond the limit set here,
+then the older half of the sections are remove. Sections that
+belong to processes that are still running are never removed.
+When this is nil, no sections are ever removed."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-process
+ :type '(choice (const :tag "Never remove old sections" nil) integer))
+
+(defvar magit-process-extreme-logging nil
+ "Whether `magit-process-file' logs to *Messages* buffer.
+Only intended for temporary use when you try to figure out how
+Magit uses Git behind the scene. Output that normally goes to
+the magit-process buffer continues to go there. Not all output
+goes to either of these two buffers.")
+
+(defcustom magit-process-error-tooltip-max-lines 20
+ "The number of lines for `magit-process-error-lines' to return.
+
+These are displayed in a tooltip for `mode-line-process' errors.
+
+If `magit-process-error-tooltip-max-lines' is nil, the tooltip
+displays the text of `magit-process-error-summary' instead."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-process
+ :type '(choice (const :tag "Use summary line" nil)
+ integer))
+
+(defcustom magit-credential-cache-daemon-socket
+ (--some (pcase-let ((`(,prog . ,args) (split-string it)))
+ (if (and prog
+ (string-match-p
+ "\\`\\(?:\\(?:/.*/\\)?git-credential-\\)?cache\\'" prog))
+ (or (cl-loop for (opt val) on args
+ if (string= opt "--socket")
+ return val)
+ (expand-file-name "~/.git-credential-cache/socket"))))
+ ;; Note: `magit-process-file' is not yet defined when
+ ;; evaluating this form, so we use `process-lines'.
+ (ignore-errors
+ (let ((process-environment
+ (append magit-git-environment process-environment)))
+ (process-lines magit-git-executable
+ "config" "--get-all" "credential.helper"))))
+ "If non-nil, start a credential cache daemon using this socket.
+
+When using Git's cache credential helper in the normal way, Emacs
+sends a SIGHUP to the credential daemon after the git subprocess
+has exited, causing the daemon to also quit. This can be avoided
+by starting the `git-credential-cache--daemon' process directly
+from Emacs.
+
+The function `magit-maybe-start-credential-cache-daemon' takes
+care of starting the daemon if necessary, using the value of this
+option as the socket. If this option is nil, then it does not
+start any daemon. Likewise if another daemon is already running,
+then it starts no new daemon. This function has to be a member
+of the hook variable `magit-credential-hook' for this to work.
+If an error occurs while starting the daemon, most likely because
+the necessary executable is missing, then the function removes
+itself from the hook, to avoid further futile attempts."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-process
+ :type '(choice (file :tag "Socket")
+ (const :tag "Don't start a cache daemon" nil)))
+
+(defcustom magit-process-yes-or-no-prompt-regexp
+ (concat " [\[(]"
+ "\\([Yy]\\(?:es\\)?\\)"
+ "[/|]"
+ "\\([Nn]o?\\)"
+ ;; OpenSSH v8 prints this. See #3969.
+ "\\(?:/\\[fingerprint\\]\\)?"
+ "[\])] ?[?:]? ?$")
+ "Regexp matching Yes-or-No prompts of Git and its subprocesses."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-process
+ :type 'regexp)
+
+(defcustom magit-process-password-prompt-regexps
+ '("^\\(Enter \\)?[Pp]assphrase\\( for \\(RSA \\)?key '.*'\\)?: ?$"
+ ;; Match-group 99 is used to identify the "user@host" part.
+ "^\\(Enter \\)?[Pp]assword\\( for '?\\(https?://\\)?\\(?99:[^']*\\)'?\\)?: ?$"
+ "Please enter the passphrase for the ssh key"
+ "Please enter the passphrase to unlock the OpenPGP secret key"
+ "^.*'s password: ?$"
+ "^Yubikey for .*: ?$"
+ "^Enter PIN for .*: ?$")
+ "List of regexps matching password prompts of Git and its subprocesses.
+Also see `magit-process-find-password-functions'."
+ :package-version '(magit . "2.8.0")
+ :group 'magit-process
+ :type '(repeat (regexp)))
+
+(defcustom magit-process-find-password-functions nil
+ "List of functions to try in sequence to get a password.
+
+These functions may be called when git asks for a password, which
+is detected using `magit-process-password-prompt-regexps'. They
+are called if and only if matching the prompt resulted in the
+value of the 99th submatch to be non-nil. Therefore users can
+control for which prompts these functions should be called by
+putting the host name in the 99th submatch, or not.
+
+If the functions are called, then they are called in the order
+given, with the host name as only argument, until one of them
+returns non-nil. If they are not called or none of them returns
+non-nil, then the password is read from the user instead."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-process
+ :type 'hook
+ :options '(magit-process-password-auth-source))
+
+(defcustom magit-process-username-prompt-regexps
+ '("^Username for '.*': ?$")
+ "List of regexps matching username prompts of Git and its subprocesses."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-process
+ :type '(repeat (regexp)))
+
+(defcustom magit-process-prompt-functions nil
+ "List of functions used to forward arbitrary questions to the user.
+
+Magit has dedicated support for forwarding username and password
+prompts and Yes-or-No questions asked by Git and its subprocesses
+to the user. This can be customized using other options in the
+`magit-process' customization group.
+
+If you encounter a new question that isn't handled by default,
+then those options should be used instead of this hook.
+
+However subprocesses may also ask questions that differ too much
+from what the code related to the above options assume, and this
+hook allows users to deal with such questions explicitly.
+
+Each function is called with the process and the output string
+as arguments until one of the functions returns non-nil. The
+function is responsible for asking the user the appropriate
+question using e.g. `read-char-choice' and then forwarding the
+answer to the process using `process-send-string'.
+
+While functions such as `magit-process-yes-or-no-prompt' may not
+be sufficient to handle some prompt, it may still be of benefit
+to look at the implementations to gain some insights on how to
+implement such functions."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-process
+ :type 'hook)
+
+(defcustom magit-process-ensure-unix-line-ending t
+ "Whether Magit should ensure a unix coding system when talking to Git."
+ :package-version '(magit . "2.6.0")
+ :group 'magit-process
+ :type 'boolean)
+
+(defcustom magit-process-display-mode-line-error t
+ "Whether Magit should retain and highlight process errors in the mode line."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-process
+ :type 'boolean)
+
+(defface magit-process-ok
+ '((t :inherit magit-section-heading :foreground "green"))
+ "Face for zero exit-status."
+ :group 'magit-faces)
+
+(defface magit-process-ng
+ '((t :inherit magit-section-heading :foreground "red"))
+ "Face for non-zero exit-status."
+ :group 'magit-faces)
+
+(defface magit-mode-line-process
+ '((t :inherit mode-line-emphasis))
+ "Face for `mode-line-process' status when Git is running for side-effects."
+ :group 'magit-faces)
+
+(defface magit-mode-line-process-error
+ '((t :inherit error))
+ "Face for `mode-line-process' error status.
+
+Used when `magit-process-display-mode-line-error' is non-nil."
+ :group 'magit-faces)
+
+;;; Process Mode
+
+(defvar magit-process-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-mode-map)
+ map)
+ "Keymap for `magit-process-mode'.")
+
+(define-derived-mode magit-process-mode magit-mode "Magit Process"
+ "Mode for looking at Git process output."
+ :group 'magit-process
+ (hack-dir-local-variables-non-file-buffer)
+ (setq imenu-prev-index-position-function
+ 'magit-imenu--process-prev-index-position-function)
+ (setq imenu-extract-index-name-function
+ 'magit-imenu--process-extract-index-name-function))
+
+(defun magit-process-buffer (&optional nodisplay)
+ "Display the current repository's process buffer.
+
+If that buffer doesn't exist yet, then create it.
+Non-interactively return the buffer and unless
+optional NODISPLAY is non-nil also display it."
+ (interactive)
+ (let ((topdir (magit-toplevel)))
+ (unless topdir
+ (magit--with-safe-default-directory nil
+ (setq topdir default-directory)
+ (let (prev)
+ (while (not (equal topdir prev))
+ (setq prev topdir)
+ (setq topdir (file-name-directory (directory-file-name topdir)))))))
+ (let ((buffer (or (--first (with-current-buffer it
+ (and (eq major-mode 'magit-process-mode)
+ (equal default-directory topdir)))
+ (buffer-list))
+ (let ((default-directory topdir))
+ (magit-generate-new-buffer 'magit-process-mode)))))
+ (with-current-buffer buffer
+ (if magit-root-section
+ (when magit-process-log-max
+ (magit-process-truncate-log))
+ (magit-process-mode)
+ (let ((inhibit-read-only t)
+ (magit-insert-section--parent nil)
+ (magit-insert-section--oldroot nil))
+ (make-local-variable 'text-property-default-nonsticky)
+ (magit-insert-section (processbuf)
+ (insert "\n")))))
+ (unless nodisplay
+ (magit-display-buffer buffer))
+ buffer)))
+
+(defun magit-process-kill ()
+ "Kill the process at point."
+ (interactive)
+ (when-let ((process (magit-section-value-if 'process)))
+ (unless (eq (process-status process) 'run)
+ (user-error "Process isn't running"))
+ (magit-confirm 'kill-process)
+ (kill-process process)))
+
+;;; Synchronous Processes
+
+(defvar magit-process-raise-error nil)
+
+(defun magit-git (&rest args)
+ "Call Git synchronously in a separate process, for side-effects.
+
+Option `magit-git-executable' specifies the Git executable.
+The arguments ARGS specify arguments to Git, they are flattened
+before use.
+
+Process output goes into a new section in the buffer returned by
+`magit-process-buffer'. If Git exits with a non-zero status,
+then raise an error."
+ (let ((magit-process-raise-error t))
+ (magit-call-git args)))
+
+(defun magit-run-git (&rest args)
+ "Call Git synchronously in a separate process, and refresh.
+
+Option `magit-git-executable' specifies the Git executable and
+option `magit-git-global-arguments' specifies constant arguments.
+The arguments ARGS specify arguments to Git, they are flattened
+before use.
+
+After Git returns, the current buffer (if it is a Magit buffer)
+as well as the current repository's status buffer are refreshed.
+
+Process output goes into a new section in the buffer returned by
+`magit-process-buffer'."
+ (let ((magit--refresh-cache (list (cons 0 0))))
+ (magit-call-git args)
+ (when (member (car args) '("init" "clone"))
+ ;; Creating a new repository invalidates the cache.
+ (setq magit--refresh-cache nil))
+ (magit-refresh)))
+
+(defvar magit-pre-call-git-hook nil)
+
+(defun magit-call-git (&rest args)
+ "Call Git synchronously in a separate process.
+
+Option `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-file (process &optional infile buffer display &rest args)
+ "Process files synchronously in a separate process.
+Identical to `process-file' but temporarily enable Cygwin's
+\"noglob\" option during the call and ensure unix eol
+conversion."
+ (when magit-process-extreme-logging
+ (let ((inhibit-message t))
+ (message "$ %s" (magit-process--format-arguments process args))))
+ (let ((process-environment (magit-process-environment))
+ (default-process-coding-system (magit--process-coding-system)))
+ (apply #'process-file process infile buffer display args)))
+
+(defun magit-process-environment ()
+ ;; The various w32 hacks are only applicable when running on the
+ ;; local machine. As of Emacs 25.1, a local binding of
+ ;; process-environment different from the top-level value affects
+ ;; the environment used in
+ ;; tramp-sh-handle-{start-file-process,process-file}.
+ (let ((local (not (file-remote-p default-directory))))
+ (append magit-git-environment
+ (and local
+ (cdr (assoc magit-git-executable magit-git-w32-path-hack)))
+ (and local magit-need-cygwin-noglob
+ (mapcar (lambda (var)
+ (concat var "=" (--if-let (getenv var)
+ (concat it " noglob")
+ "noglob")))
+ '("CYGWIN" "MSYS")))
+ process-environment)))
+
+(defvar magit-this-process nil)
+
+(defun magit-run-git-with-input (&rest args)
+ "Call Git in a separate process.
+ARGS is flattened and then used as arguments to Git.
+
+The current buffer's content is used as the process's standard
+input. The buffer is assumed to be temporary and thus OK to
+modify.
+
+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."
+ (when (eq system-type 'windows-nt)
+ ;; On w32, git expects UTF-8 encoded input, ignore any user
+ ;; configuration telling us otherwise (see #3250).
+ (encode-coding-region (point-min) (point-max) 'utf-8-unix))
+ (if (file-remote-p default-directory)
+ ;; We lack `process-file-region', so fall back to asynch +
+ ;; waiting in remote case.
+ (progn
+ (magit-start-git (current-buffer) args)
+ (while (and magit-this-process
+ (eq (process-status magit-this-process) 'run))
+ (sleep-for 0.005)))
+ (run-hooks 'magit-pre-call-git-hook)
+ (pcase-let* ((process-environment (magit-process-environment))
+ (default-process-coding-system (magit--process-coding-system))
+ (flat-args (magit-process-git-arguments args))
+ (`(,process-buf . ,section)
+ (magit-process-setup magit-git-executable flat-args))
+ (inhibit-read-only t))
+ (magit-process-finish
+ (apply #'call-process-region (point-min) (point-max)
+ magit-git-executable nil process-buf nil flat-args)
+ process-buf nil default-directory section))))
+
+;;; Asynchronous Processes
+
+(defun magit-run-git-async (&rest args)
+ "Start Git, prepare for refresh, and return the process object.
+ARGS is flattened and then used as arguments to Git.
+
+Display the command line arguments in the echo area.
+
+After Git returns some buffers are refreshed: the buffer that was
+current when this function was called (if it is a Magit buffer
+and still alive), as well as the respective Magit status buffer.
+
+See `magit-start-process' for more information."
+ (message "Running %s %s" magit-git-executable
+ (let ((m (mapconcat #'identity (-flatten args) " ")))
+ (remove-list-of-text-properties 0 (length m) '(face) m)
+ m))
+ (magit-start-git nil args))
+
+(defun magit-run-git-with-editor (&rest args)
+ "Export GIT_EDITOR and start Git.
+Also prepare for refresh and return the process object.
+ARGS is flattened and then used as arguments to Git.
+
+Display the command line arguments in the echo area.
+
+After Git returns some buffers are refreshed: the buffer that was
+current when this function was called (if it is a Magit buffer
+and still alive), as well as the respective Magit status buffer.
+
+See `magit-start-process' and `with-editor' for more information."
+ (magit--record-separated-gitdir)
+ (magit-with-editor (magit-run-git-async args)))
+
+(defun magit-run-git-sequencer (&rest args)
+ "Export GIT_EDITOR and start Git.
+Also prepare for refresh and return the process object.
+ARGS is flattened and then used as arguments to Git.
+
+Display the command line arguments in the echo area.
+
+After Git returns some buffers are refreshed: the buffer that was
+current when this function was called (if it is a Magit buffer
+and still alive), as well as the respective Magit status buffer.
+If the sequence stops at a commit, make the section representing
+that commit the current section by moving `point' there.
+
+See `magit-start-process' and `with-editor' for more information."
+ (apply #'magit-run-git-with-editor args)
+ (set-process-sentinel magit-this-process #'magit-sequencer-process-sentinel)
+ magit-this-process)
+
+(defvar magit-pre-start-git-hook nil)
+
+(defun magit-start-git (input &rest args)
+ "Start Git, prepare for refresh, and return the process object.
+
+If INPUT is non-nil, it has to be a buffer or the name of an
+existing buffer. The buffer content becomes the processes
+standard input.
+
+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.
+
+See `magit-start-process' for more information."
+ (run-hooks 'magit-pre-start-git-hook)
+ (let ((default-process-coding-system (magit--process-coding-system)))
+ (apply #'magit-start-process magit-git-executable input
+ (magit-process-git-arguments args))))
+
+(defun magit-start-process (program &optional input &rest args)
+ "Start PROGRAM, prepare for refresh, and return the process object.
+
+If optional argument INPUT is non-nil, it has to be a buffer or
+the name of an existing buffer. The buffer content becomes the
+processes standard input.
+
+The process is started using `start-file-process' and then setup
+to use the sentinel `magit-process-sentinel' and the filter
+`magit-process-filter'. Information required by these functions
+is stored in the process object. When this function returns the
+process has not started to run yet so it is possible to override
+the sentinel and filter.
+
+After the process returns, `magit-process-sentinel' refreshes the
+buffer that was current when `magit-start-process' was called (if
+it is a Magit buffer and still alive), as well as the respective
+Magit status buffer."
+ (pcase-let*
+ ((`(,process-buf . ,section)
+ (magit-process-setup program args))
+ (process
+ (let ((process-connection-type
+ ;; Don't use a pty, because it would set icrnl
+ ;; which would modify the input (issue #20).
+ (and (not input) magit-process-connection-type))
+ (process-environment (magit-process-environment))
+ (default-process-coding-system (magit--process-coding-system)))
+ (apply #'start-file-process
+ (file-name-nondirectory program)
+ process-buf program args))))
+ (with-editor-set-process-filter process #'magit-process-filter)
+ (set-process-sentinel process #'magit-process-sentinel)
+ (set-process-buffer process process-buf)
+ (when (eq system-type 'windows-nt)
+ ;; On w32, git expects UTF-8 encoded input, ignore any user
+ ;; configuration telling us otherwise.
+ (set-process-coding-system process 'utf-8-unix))
+ (process-put process 'section section)
+ (process-put process 'command-buf (current-buffer))
+ (process-put process 'default-dir default-directory)
+ (when inhibit-magit-refresh
+ (process-put process 'inhibit-refresh t))
+ (oset section process process)
+ (with-current-buffer process-buf
+ (set-marker (process-mark process) (point)))
+ (when input
+ (with-current-buffer input
+ (process-send-region process (point-min) (point-max))
+ (process-send-eof process)))
+ (setq magit-this-process process)
+ (oset section value process)
+ (magit-process-display-buffer process)
+ process))
+
+(defun magit-parse-git-async (&rest args)
+ (setq args (magit-process-git-arguments args))
+ (let ((command-buf (current-buffer))
+ (process-buf (generate-new-buffer " *temp*"))
+ (toplevel (magit-toplevel)))
+ (with-current-buffer process-buf
+ (setq default-directory toplevel)
+ (let ((process
+ (let ((process-connection-type nil)
+ (process-environment (magit-process-environment))
+ (default-process-coding-system
+ (magit--process-coding-system)))
+ (apply #'start-file-process "git" process-buf
+ magit-git-executable args))))
+ (process-put process 'command-buf command-buf)
+ (process-put process 'parsed (point))
+ (setq magit-this-process process)
+ process))))
+
+;;; Process Internals
+
+(defun magit-process-setup (program args)
+ (magit-process-set-mode-line program args)
+ (let ((pwd default-directory)
+ (buf (magit-process-buffer t)))
+ (cons buf (with-current-buffer buf
+ (prog1 (magit-process-insert-section pwd program args nil nil)
+ (backward-char 1))))))
+
+(defun magit-process-insert-section (pwd program args &optional errcode errlog)
+ (let ((inhibit-read-only t)
+ (magit-insert-section--parent magit-root-section)
+ (magit-insert-section--oldroot nil))
+ (goto-char (1- (point-max)))
+ (magit-insert-section (process)
+ (insert (if errcode
+ (format "%3s " (propertize (number-to-string errcode)
+ 'font-lock-face 'magit-process-ng))
+ "run "))
+ (unless (equal (expand-file-name pwd)
+ (expand-file-name default-directory))
+ (insert (file-relative-name pwd default-directory) ?\s))
+ (insert (magit-process--format-arguments program args))
+ (magit-insert-heading)
+ (when errlog
+ (if (bufferp errlog)
+ (insert (with-current-buffer errlog
+ (buffer-substring-no-properties (point-min) (point-max))))
+ (insert-file-contents errlog)
+ (goto-char (1- (point-max)))))
+ (insert "\n"))))
+
+(defun magit-process--format-arguments (program args)
+ (cond
+ ((and args (equal program magit-git-executable))
+ (setq args (-split-at (length magit-git-global-arguments) args))
+ (concat (propertize (file-name-nondirectory program)
+ 'font-lock-face 'magit-section-heading)
+ " "
+ (propertize (char-to-string magit-ellipsis)
+ 'font-lock-face 'magit-section-heading
+ 'help-echo (mapconcat #'identity (car args) " "))
+ " "
+ (propertize (mapconcat #'shell-quote-argument (cadr args) " ")
+ 'font-lock-face 'magit-section-heading)))
+ ((and args (equal program shell-file-name))
+ (propertize (cadr args)
+ 'font-lock-face 'magit-section-heading))
+ (t
+ (concat (propertize (file-name-nondirectory program)
+ 'font-lock-face 'magit-section-heading)
+ " "
+ (propertize (mapconcat #'shell-quote-argument args " ")
+ 'font-lock-face 'magit-section-heading)))))
+
+(defun magit-process-truncate-log ()
+ (let* ((head nil)
+ (tail (oref magit-root-section children))
+ (count (length tail)))
+ (when (> (1+ count) magit-process-log-max)
+ (while (and (cdr tail)
+ (> count (/ magit-process-log-max 2)))
+ (let* ((inhibit-read-only t)
+ (section (car tail))
+ (process (oref section process)))
+ (cond ((not process))
+ ((memq (process-status process) '(exit signal))
+ (delete-region (oref section start)
+ (1+ (oref section end)))
+ (cl-decf count))
+ (t
+ (push section head))))
+ (pop tail))
+ (oset magit-root-section children
+ (nconc (reverse head) tail)))))
+
+(defun magit-process-sentinel (process event)
+ "Default sentinel used by `magit-start-process'."
+ (when (memq (process-status process) '(exit signal))
+ (setq event (substring event 0 -1))
+ (when (string-match "^finished" event)
+ (message (concat (capitalize (process-name process)) " finished")))
+ (magit-process-finish process)
+ (when (eq process magit-this-process)
+ (setq magit-this-process nil))
+ (unless (process-get process 'inhibit-refresh)
+ (let ((command-buf (process-get process 'command-buf)))
+ (if (buffer-live-p command-buf)
+ (with-current-buffer command-buf
+ (magit-refresh))
+ (with-temp-buffer
+ (setq default-directory (process-get process 'default-dir))
+ (magit-refresh)))))))
+
+(defun magit-sequencer-process-sentinel (process event)
+ "Special sentinel used by `magit-run-git-sequencer'."
+ (when (memq (process-status process) '(exit signal))
+ (magit-process-sentinel process event)
+ (when-let ((process-buf (process-buffer process)))
+ (when (buffer-live-p process-buf)
+ (when-let ((status-buf (with-current-buffer process-buf
+ (magit-get-mode-buffer 'magit-status-mode))))
+ (with-current-buffer status-buf
+ (--when-let
+ (magit-get-section
+ `((commit . ,(magit-rev-parse "HEAD"))
+ (,(pcase (car (cadr (-split-at
+ (1+ (length magit-git-global-arguments))
+ (process-command process))))
+ ((or "rebase" "am") 'rebase-sequence)
+ ((or "cherry-pick" "revert") 'sequence)))
+ (status)))
+ (goto-char (oref it start))
+ (magit-section-update-highlight))))))))
+
+(defun magit-process-filter (proc string)
+ "Default filter used by `magit-start-process'."
+ (with-current-buffer (process-buffer proc)
+ (let ((inhibit-read-only t))
+ (goto-char (process-mark proc))
+ ;; Find last ^M in string. If one was found, ignore
+ ;; everything before it and delete the current line.
+ (when-let ((ret-pos (cl-position ?\r string :from-end t)))
+ (cl-callf substring string (1+ ret-pos))
+ (delete-region (line-beginning-position) (point)))
+ (insert (propertize string 'magit-section
+ (process-get proc 'section)))
+ (set-marker (process-mark proc) (point))
+ ;; Make sure prompts are matched after removing ^M.
+ (magit-process-yes-or-no-prompt proc string)
+ (magit-process-username-prompt proc string)
+ (magit-process-password-prompt proc string)
+ (run-hook-with-args-until-success 'magit-process-prompt-functions
+ proc string))))
+
+(defmacro magit-process-kill-on-abort (proc &rest body)
+ (declare (indent 1) (debug (form body)))
+ (let ((map (cl-gensym)))
+ `(let ((,map (make-sparse-keymap)))
+ (set-keymap-parent ,map minibuffer-local-map)
+ (define-key ,map "\C-g"
+ (lambda ()
+ (interactive)
+ (ignore-errors (kill-process ,proc))
+ (abort-recursive-edit)))
+ (let ((minibuffer-local-map ,map))
+ ,@body))))
+
+(defun magit-process-yes-or-no-prompt (process string)
+ "Forward Yes-or-No prompts to the user."
+ (when-let ((beg (string-match magit-process-yes-or-no-prompt-regexp string)))
+ (let ((max-mini-window-height 30))
+ (process-send-string
+ process
+ (downcase
+ (concat
+ (match-string
+ (if (save-match-data
+ (magit-process-kill-on-abort process
+ (yes-or-no-p (substring string 0 beg)))) 1 2)
+ string)
+ "\n"))))))
+
+(defun magit-process-password-auth-source (key)
+ "Use `auth-source-search' to get a password.
+If found, return the password. Otherwise, return nil.
+
+To use this function add it to the appropriate hook
+ (add-hook 'magit-process-find-password-functions
+ 'magit-process-password-auth-source)
+
+KEY typically derives from a prompt such as:
+ Password for 'https://tarsiusNOSPAMbitbucket.org'
+in which case it would be the string
+ tarsiusNOSPAMbitbucket.org
+which matches the ~/.authinfo.gpg entry
+ machine bitbucket.org login tarsius password 12345
+or iff that is undefined, for backward compatibility
+ machine tarsiusNOSPAMbitbucket.org password 12345"
+ (require 'auth-source)
+ (and (string-match "\\`\\(.+\\)@\\([^@]+\\)\\'" key)
+ (let* ((user (match-string 1 key))
+ (host (match-string 2 key))
+ (secret
+ (plist-get
+ (car (or (auth-source-search :max 1 :host host :user user)
+ (auth-source-search :max 1 :host key)))
+ :secret)))
+ (if (functionp secret)
+ (funcall secret)
+ secret))))
+
+(defun magit-process-password-prompt (process string)
+ "Find a password based on prompt STRING and send it to git.
+Use `magit-process-password-prompt-regexps' to find a known
+prompt. If and only if one is found, then call functions in
+`magit-process-find-password-functions' until one of them returns
+the password. If all function return nil, then read the password
+from the user."
+ (when-let ((prompt (magit-process-match-prompt
+ magit-process-password-prompt-regexps string)))
+ (process-send-string
+ process (magit-process-kill-on-abort process
+ (concat (or (when-let ((key (match-string 99 string)))
+ (run-hook-with-args-until-success
+ 'magit-process-find-password-functions key))
+ (read-passwd prompt))
+ "\n")))))
+
+(defun magit-process-username-prompt (process string)
+ "Forward username prompts to the user."
+ (--when-let (magit-process-match-prompt
+ magit-process-username-prompt-regexps string)
+ (process-send-string
+ process (magit-process-kill-on-abort process
+ (concat (read-string it nil nil (user-login-name)) "\n")))))
+
+(defun magit-process-match-prompt (prompts string)
+ "Match STRING against PROMPTS and set match data.
+Return the matched string suffixed with \": \", if needed."
+ (when (--any-p (string-match it string) prompts)
+ (let ((prompt (match-string 0 string)))
+ (cond ((string-suffix-p ": " prompt) prompt)
+ ((string-suffix-p ":" prompt) (concat prompt " "))
+ (t (concat prompt ": "))))))
+
+(defun magit--process-coding-system ()
+ (let ((fro (or magit-git-output-coding-system
+ (car default-process-coding-system)))
+ (to (cdr default-process-coding-system)))
+ (if magit-process-ensure-unix-line-ending
+ (cons (coding-system-change-eol-conversion fro 'unix)
+ (coding-system-change-eol-conversion to 'unix))
+ (cons fro to))))
+
+(defvar magit-credential-hook nil
+ "Hook run before Git needs credentials.")
+
+(defvar magit-credential-cache-daemon-process nil)
+
+(defun magit-maybe-start-credential-cache-daemon ()
+ "Maybe start a `git-credential-cache--daemon' process.
+
+If such a process is already running or if the value of option
+`magit-credential-cache-daemon-socket' is nil, then do nothing.
+Otherwise start the process passing the value of that options
+as argument."
+ (unless (or (not magit-credential-cache-daemon-socket)
+ (process-live-p magit-credential-cache-daemon-process)
+ (memq magit-credential-cache-daemon-process
+ (list-system-processes)))
+ (setq magit-credential-cache-daemon-process
+ (or (--first (let* ((attr (process-attributes it))
+ (comm (cdr (assq 'comm attr)))
+ (user (cdr (assq 'user attr))))
+ (and (string= comm "git-credential-cache--daemon")
+ (string= user user-login-name)))
+ (list-system-processes))
+ (condition-case nil
+ (start-process "git-credential-cache--daemon"
+ " *git-credential-cache--daemon*"
+ magit-git-executable
+ "credential-cache--daemon"
+ magit-credential-cache-daemon-socket)
+ ;; Some Git implementations (e.g. Windows) won't have
+ ;; this program; if we fail the first time, stop trying.
+ ((debug error)
+ (remove-hook 'magit-credential-hook
+ #'magit-maybe-start-credential-cache-daemon)))))))
+
+(add-hook 'magit-credential-hook #'magit-maybe-start-credential-cache-daemon)
+
+(defun tramp-sh-handle-start-file-process--magit-tramp-process-environment
+ (fn name buffer program &rest args)
+ (if magit-tramp-process-environment
+ (apply fn name buffer
+ (car magit-tramp-process-environment)
+ (append (cdr magit-tramp-process-environment)
+ (cons program args)))
+ (apply fn name buffer program args)))
+
+(advice-add 'tramp-sh-handle-start-file-process :around
+ 'tramp-sh-handle-start-file-process--magit-tramp-process-environment)
+
+(defun tramp-sh-handle-process-file--magit-tramp-process-environment
+ (fn program &optional infile destination display &rest args)
+ (if magit-tramp-process-environment
+ (apply fn "env" infile destination display
+ (append magit-tramp-process-environment
+ (cons program args)))
+ (apply fn program infile destination display args)))
+
+(advice-add 'tramp-sh-handle-process-file :around
+ 'tramp-sh-handle-process-file--magit-tramp-process-environment)
+
+(defvar magit-mode-line-process-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map (kbd "<mode-line> <mouse-1>")
+ 'magit-process-buffer)
+ map)
+ "Keymap for `mode-line-process'.")
+
+(defun magit-process-set-mode-line (program args)
+ "Display the git command (sans arguments) in the mode line."
+ (when (equal program magit-git-executable)
+ (setq args (nthcdr (length magit-git-global-arguments) args)))
+ (let ((str (concat " " (propertize
+ (concat (file-name-nondirectory program)
+ (and args (concat " " (car args))))
+ 'mouse-face 'highlight
+ 'keymap magit-mode-line-process-map
+ 'help-echo "mouse-1: Show process buffer"
+ 'font-lock-face 'magit-mode-line-process))))
+ (magit-repository-local-set 'mode-line-process str)
+ (dolist (buf (magit-mode-get-buffers))
+ (with-current-buffer buf
+ (setq mode-line-process str)))
+ (force-mode-line-update t)))
+
+(defun magit-process-set-mode-line-error-status (&optional error str)
+ "Apply an error face to the string set by `magit-process-set-mode-line'.
+
+If ERROR is supplied, include it in the `mode-line-process' tooltip.
+
+If STR is supplied, it replaces the `mode-line-process' text."
+ (setq str (or str (magit-repository-local-get 'mode-line-process)))
+ (when str
+ (setq error (format "%smouse-1: Show process buffer"
+ (if (stringp error)
+ (concat error "\n\n")
+ "")))
+ (setq str (concat " " (propertize
+ (substring-no-properties str 1)
+ 'mouse-face 'highlight
+ 'keymap magit-mode-line-process-map
+ 'help-echo error
+ 'font-lock-face 'magit-mode-line-process-error)))
+ (magit-repository-local-set 'mode-line-process str)
+ (dolist (buf (magit-mode-get-buffers))
+ (with-current-buffer buf
+ (setq mode-line-process str)))
+ (force-mode-line-update t)
+ ;; We remove any error status from the mode line when a magit
+ ;; buffer is refreshed (see `magit-refresh-buffer'), but we must
+ ;; ensure that we ignore any refreshes during the remainder of the
+ ;; current command -- otherwise a newly-set error status would be
+ ;; removed before it was seen. We set a flag which prevents the
+ ;; status from being removed prior to the next command, so that
+ ;; the error status is guaranteed to remain visible until then.
+ (let ((repokey (magit-repository-local-repository)))
+ ;; The following closure captures the repokey value, and is
+ ;; added to `pre-command-hook'.
+ (cl-labels ((enable-magit-process-unset-mode-line
+ () ;; Remove ourself from the hook variable, so
+ ;; that we only run once.
+ (remove-hook 'pre-command-hook
+ #'enable-magit-process-unset-mode-line)
+ ;; Clear the inhibit flag for the repository in
+ ;; which we set it.
+ (magit-repository-local-set
+ 'inhibit-magit-process-unset-mode-line nil repokey)))
+ ;; Set the inhibit flag until the next command is invoked.
+ (magit-repository-local-set
+ 'inhibit-magit-process-unset-mode-line t repokey)
+ (add-hook 'pre-command-hook
+ #'enable-magit-process-unset-mode-line)))))
+
+(defun magit-process-unset-mode-line-error-status ()
+ "Remove any current error status from the mode line."
+ (let ((status (or mode-line-process
+ (magit-repository-local-get 'mode-line-process))))
+ (when (and status
+ (eq (get-text-property 1 'font-lock-face status)
+ 'magit-mode-line-process-error))
+ (magit-process-unset-mode-line))))
+
+(defun magit-process-unset-mode-line (&optional directory)
+ "Remove the git command from the mode line."
+ (let ((default-directory (or directory default-directory)))
+ (unless (magit-repository-local-get 'inhibit-magit-process-unset-mode-line)
+ (magit-repository-local-set 'mode-line-process nil)
+ (dolist (buf (magit-mode-get-buffers))
+ (with-current-buffer buf (setq mode-line-process nil)))
+ (force-mode-line-update t))))
+
+(defvar magit-process-error-message-regexps
+ (list "^\\*ERROR\\*: Canceled by user$"
+ "^\\(?:error\\|fatal\\|git\\): \\(.*\\)$"
+ "^\\(Cannot rebase:.*\\)$"))
+
+(define-error 'magit-git-error "Git error")
+
+(defun magit-process-error-summary (process-buf section)
+ "A one-line error summary from the given SECTION."
+ (or (and (buffer-live-p process-buf)
+ (with-current-buffer process-buf
+ (and (oref section content)
+ (save-excursion
+ (goto-char (oref section end))
+ (run-hook-wrapped
+ 'magit-process-error-message-regexps
+ (lambda (re)
+ (save-excursion
+ (and (re-search-backward
+ re (oref section start) t)
+ (or (match-string-no-properties 1)
+ (and (not magit-process-raise-error)
+ 'suppressed))))))))))
+ "Git failed"))
+
+(defun magit-process-error-tooltip (process-buf section)
+ "Returns the text from SECTION of the PROCESS-BUF buffer.
+
+Limited by `magit-process-error-tooltip-max-lines'."
+ (and (integerp magit-process-error-tooltip-max-lines)
+ (> magit-process-error-tooltip-max-lines 0)
+ (buffer-live-p process-buf)
+ (with-current-buffer process-buf
+ (save-excursion
+ (goto-char (or (oref section content)
+ (oref section start)))
+ (buffer-substring-no-properties
+ (point)
+ (save-excursion
+ (forward-line magit-process-error-tooltip-max-lines)
+ (goto-char
+ (if (> (point) (oref section end))
+ (oref section end)
+ (point)))
+ ;; Remove any trailing whitespace.
+ (when (re-search-backward "[^[:space:]\n]"
+ (oref section start) t)
+ (forward-char 1))
+ (point)))))))
+
+(defvar-local magit-this-error nil)
+
+(defvar magit-process-finish-apply-ansi-colors nil)
+
+(defun magit-process-finish (arg &optional process-buf command-buf
+ default-dir section)
+ (unless (integerp arg)
+ (setq process-buf (process-buffer arg))
+ (setq command-buf (process-get arg 'command-buf))
+ (setq default-dir (process-get arg 'default-dir))
+ (setq section (process-get arg 'section))
+ (setq arg (process-exit-status arg)))
+ (when (fboundp 'dired-uncache)
+ (dired-uncache default-dir))
+ (when (buffer-live-p process-buf)
+ (with-current-buffer process-buf
+ (let ((inhibit-read-only t)
+ (marker (oref section start)))
+ (goto-char marker)
+ (save-excursion
+ (delete-char 3)
+ (set-marker-insertion-type marker nil)
+ (insert (propertize (format "%3s" arg)
+ 'magit-section section
+ 'font-lock-face (if (= arg 0)
+ 'magit-process-ok
+ 'magit-process-ng)))
+ (set-marker-insertion-type marker t))
+ (when magit-process-finish-apply-ansi-colors
+ (ansi-color-apply-on-region (oref section content)
+ (oref section end)))
+ (if (= (oref section end)
+ (+ (line-end-position) 2))
+ (save-excursion
+ (goto-char (1+ (line-end-position)))
+ (delete-char -1)
+ (oset section content nil))
+ (let ((buf (magit-process-buffer t)))
+ (when (and (= arg 0)
+ (not (--any-p (eq (window-buffer it) buf)
+ (window-list))))
+ (magit-section-hide section)))))))
+ (if (= arg 0)
+ ;; Unset the `mode-line-process' value upon success.
+ (magit-process-unset-mode-line default-dir)
+ ;; Otherwise process the error.
+ (let ((msg (magit-process-error-summary process-buf section)))
+ ;; Change `mode-line-process' to an error face upon failure.
+ (if magit-process-display-mode-line-error
+ (magit-process-set-mode-line-error-status
+ (or (magit-process-error-tooltip process-buf section)
+ msg))
+ (magit-process-unset-mode-line default-dir))
+ ;; Either signal the error, or else display the error summary in
+ ;; the status buffer and with a message in the echo area.
+ (cond
+ (magit-process-raise-error
+ (signal 'magit-git-error (list (format "%s (in %s)" msg default-dir))))
+ ((not (eq msg 'suppressed))
+ (when (buffer-live-p process-buf)
+ (with-current-buffer process-buf
+ (when-let ((status-buf (magit-get-mode-buffer 'magit-status-mode)))
+ (with-current-buffer status-buf
+ (setq magit-this-error msg)))))
+ (message "%s ... [%s buffer %s for details]" msg
+ (if-let ((key (and (buffer-live-p command-buf)
+ (with-current-buffer command-buf
+ (car (where-is-internal
+ 'magit-process-buffer))))))
+ (format "Hit %s to see" (key-description key))
+ "See")
+ (buffer-name process-buf))))))
+ arg)
+
+(defun magit-process-display-buffer (process)
+ (when (process-live-p process)
+ (let ((buf (process-buffer process)))
+ (cond ((not (buffer-live-p buf)))
+ ((= magit-process-popup-time 0)
+ (if (minibufferp)
+ (switch-to-buffer-other-window buf)
+ (pop-to-buffer buf)))
+ ((> magit-process-popup-time 0)
+ (run-with-timer magit-process-popup-time nil
+ (lambda (p)
+ (when (eq (process-status p) 'run)
+ (let ((buf (process-buffer p)))
+ (when (buffer-live-p buf)
+ (if (minibufferp)
+ (switch-to-buffer-other-window buf)
+ (pop-to-buffer buf))))))
+ process))))))
+
+(defun magit--log-action (summary line list)
+ (let (heading lines)
+ (if (cdr list)
+ (progn (setq heading (funcall summary list))
+ (setq lines (mapcar line list)))
+ (setq heading (funcall line (car list))))
+ (with-current-buffer (magit-process-buffer t)
+ (goto-char (1- (point-max)))
+ (let ((inhibit-read-only t))
+ (magit-insert-section (message)
+ (magit-insert-heading (concat " * " heading))
+ (when lines
+ (dolist (line lines)
+ (insert line "\n"))
+ (insert "\n"))))
+ (let ((inhibit-message t))
+ (when heading
+ (setq lines (cons heading lines)))
+ (message (mapconcat #'identity lines "\n"))))))
+
+;;; _
+(provide 'magit-process)
+;;; magit-process.el ends here
--- /dev/null
+;;; magit-pull.el --- update local objects and refs -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements pull commands.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Options
+
+(defcustom magit-pull-or-fetch nil
+ "Whether `magit-pull' also offers some fetch suffixes."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-pull "magit-pull" nil t)
+(transient-define-prefix magit-pull ()
+ "Pull from another repository."
+ :man-page "git-pull"
+ [:description
+ (lambda () (if magit-pull-or-fetch "Pull arguments" "Arguments"))
+ ("-r" "Rebase local commits" ("-r" "--rebase"))
+ ("-A" "Autostash" "--autostash" :level 7)]
+ [:description
+ (lambda ()
+ (if-let ((branch (magit-get-current-branch)))
+ (concat
+ (propertize "Pull into " 'face 'transient-heading)
+ (propertize branch 'face 'magit-branch-local)
+ (propertize " from" 'face 'transient-heading))
+ (propertize "Pull from" 'face 'transient-heading)))
+ ("p" magit-pull-from-pushremote)
+ ("u" magit-pull-from-upstream)
+ ("e" "elsewhere" magit-pull-branch)]
+ ["Fetch from"
+ :if-non-nil magit-pull-or-fetch
+ ("f" "remotes" magit-fetch-all-no-prune)
+ ("F" "remotes and prune" magit-fetch-all-prune)]
+ ["Fetch"
+ :if-non-nil magit-pull-or-fetch
+ ("o" "another branch" magit-fetch-branch)
+ ("s" "explicit refspec" magit-fetch-refspec)
+ ("m" "submodules" magit-fetch-modules)]
+ ["Configure"
+ ("r" magit-branch.<branch>.rebase :if magit-get-current-branch)
+ ("C" "variables..." magit-branch-configure)]
+ (interactive)
+ (transient-setup 'magit-pull nil nil :scope (magit-get-current-branch)))
+
+(defun magit-pull-arguments ()
+ (transient-args 'magit-pull))
+
+;;;###autoload (autoload 'magit-pull-from-pushremote "magit-pull" nil t)
+(transient-define-suffix magit-pull-from-pushremote (args)
+ "Pull from the push-remote of the current branch.
+
+With a prefix argument or when the push-remote is either not
+configured or unusable, then let the user first configure the
+push-remote."
+ :if 'magit-get-current-branch
+ :description 'magit-pull--pushbranch-description
+ (interactive (list (magit-pull-arguments)))
+ (pcase-let ((`(,branch ,remote)
+ (magit--select-push-remote "pull from there")))
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "pull" args remote branch)))
+
+(defun magit-pull--pushbranch-description ()
+ ;; Also used by `magit-rebase-onto-pushremote'.
+ (let* ((branch (magit-get-current-branch))
+ (target (magit-get-push-branch branch t))
+ (remote (magit-get-push-remote branch))
+ (v (magit--push-remote-variable branch t)))
+ (cond
+ (target)
+ ((member remote (magit-list-remotes))
+ (format "%s, replacing non-existent" v))
+ (remote
+ (format "%s, replacing invalid" v))
+ (t
+ (format "%s, setting that" v)))))
+
+;;;###autoload (autoload 'magit-pull-from-upstream "magit-pull" nil t)
+(transient-define-suffix magit-pull-from-upstream (args)
+ "Pull from the upstream of the current branch.
+
+With a prefix argument or when the upstream is either not
+configured or unusable, then let the user first configure
+the upstream."
+ :if 'magit-get-current-branch
+ :description 'magit-pull--upstream-description
+ (interactive (list (magit-pull-arguments)))
+ (let* ((branch (or (magit-get-current-branch)
+ (user-error "No branch is checked out")))
+ (remote (magit-get "branch" branch "remote"))
+ (merge (magit-get "branch" branch "merge")))
+ (when (or current-prefix-arg
+ (not (or (magit-get-upstream-branch branch)
+ (magit--unnamed-upstream-p remote merge))))
+ (magit-set-upstream-branch
+ branch (magit-read-upstream-branch
+ branch (format "Set upstream of %s and pull from there" branch)))
+ (setq remote (magit-get "branch" branch "remote"))
+ (setq merge (magit-get "branch" branch "merge")))
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-with-editor "pull" args remote merge)))
+
+(defun magit-pull--upstream-description ()
+ (when-let ((branch (magit-get-current-branch)))
+ (or (magit-get-upstream-branch branch)
+ (let ((remote (magit-get "branch" branch "remote"))
+ (merge (magit-get "branch" branch "merge"))
+ (u (magit--propertize-face "@{upstream}" 'bold)))
+ (cond
+ ((magit--unnamed-upstream-p remote merge)
+ (format "%s of %s"
+ (magit--propertize-face merge 'magit-branch-remote)
+ (magit--propertize-face remote 'bold)))
+ ((magit--valid-upstream-p remote merge)
+ (concat u ", replacing non-existent"))
+ ((or remote merge)
+ (concat u ", replacing invalid"))
+ (t
+ (concat u ", setting that")))))))
+
+;;;###autoload
+(defun magit-pull-branch (source args)
+ "Pull from a branch read in the minibuffer."
+ (interactive (list (magit-read-remote-branch "Pull" nil nil nil t)
+ (magit-pull-arguments)))
+ (run-hooks 'magit-credential-hook)
+ (pcase-let ((`(,remote . ,branch)
+ (magit-get-tracked source)))
+ (magit-run-git-with-editor "pull" args remote branch)))
+
+;;; _
+(provide 'magit-pull)
+;;; magit-pull.el ends here
--- /dev/null
+;;; magit-push.el --- update remote objects and refs -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements push commands.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-push "magit-push" nil t)
+(transient-define-prefix magit-push ()
+ "Push to another repository."
+ :man-page "git-push"
+ ["Arguments"
+ ("-f" "Force with lease" (nil "--force-with-lease"))
+ ("-F" "Force" ("-f" "--force"))
+ ("-h" "Disable hooks" "--no-verify")
+ ("-n" "Dry run" ("-n" "--dry-run"))
+ (5 "-u" "Set upstream" "--set-upstream")
+ (7 "-t" "Follow tags" "--follow-tags")]
+ [:if magit-get-current-branch
+ :description (lambda ()
+ (format (propertize "Push %s to" 'face 'transient-heading)
+ (propertize (magit-get-current-branch)
+ 'face 'magit-branch-local)))
+ ("p" magit-push-current-to-pushremote)
+ ("u" magit-push-current-to-upstream)
+ ("e" "elsewhere" magit-push-current)]
+ ["Push"
+ [("o" "another branch" magit-push-other)
+ ("r" "explicit refspecs" magit-push-refspecs)
+ ("m" "matching branches" magit-push-matching)]
+ [("T" "a tag" magit-push-tag)
+ ("t" "all tags" magit-push-tags)
+ (6 "n" "a note ref" magit-push-notes-ref)]]
+ ["Configure"
+ ("C" "Set variables..." magit-branch-configure)])
+
+(defun magit-push-arguments ()
+ (transient-args 'magit-push))
+
+(defun magit-git-push (branch target args)
+ (run-hooks 'magit-credential-hook)
+ ;; If the remote branch already exists, then we do not have to
+ ;; qualify the target, which we prefer to avoid doing because
+ ;; using the default namespace is wrong in obscure cases.
+ (pcase-let ((namespace (if (magit-get-tracked target) "" "refs/heads/"))
+ (`(,remote . ,target)
+ (magit-split-branch-name target)))
+ (magit-run-git-async "push" "-v" args remote
+ (format "%s:%s%s" branch namespace target))))
+
+;;;###autoload (autoload 'magit-push-current-to-pushremote "magit-push" nil t)
+(transient-define-suffix magit-push-current-to-pushremote (args)
+ "Push the current branch to its push-remote.
+
+When the push-remote is not configured, then read the push-remote
+from the user, set it, and then push to it. With a prefix
+argument the push-remote can be changed before pushed to it."
+ :if 'magit-get-current-branch
+ :description 'magit-push--pushbranch-description
+ (interactive (list (magit-push-arguments)))
+ (pcase-let ((`(,branch ,remote ,changed)
+ (magit--select-push-remote "push there")))
+ (when changed
+ (magit-confirm 'set-and-push
+ (format "Really use \"%s\" as push-remote and push \"%s\" there"
+ remote branch)))
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "push" "-v" args remote
+ (format "refs/heads/%s:refs/heads/%s"
+ branch branch)))) ; see #3847 and #3872
+
+(defun magit-push--pushbranch-description ()
+ (let* ((branch (magit-get-current-branch))
+ (target (magit-get-push-branch branch t))
+ (remote (magit-get-push-remote branch))
+ (v (magit--push-remote-variable branch t)))
+ (cond
+ (target)
+ ((member remote (magit-list-remotes))
+ (format "%s, creating it"
+ (magit--propertize-face (concat remote "/" branch)
+ 'magit-branch-remote)))
+ (remote
+ (format "%s, replacing invalid" v))
+ (t
+ (format "%s, setting that" v)))))
+
+;;;###autoload (autoload 'magit-push-current-to-upstream "magit-push" nil t)
+(transient-define-suffix magit-push-current-to-upstream (args)
+ "Push the current branch to its upstream branch.
+
+With a prefix argument or when the upstream is either not
+configured or unusable, then let the user first configure
+the upstream."
+ :if 'magit-get-current-branch
+ :description 'magit-push--upstream-description
+ (interactive (list (magit-push-arguments)))
+ (let* ((branch (or (magit-get-current-branch)
+ (user-error "No branch is checked out")))
+ (remote (magit-get "branch" branch "remote"))
+ (merge (magit-get "branch" branch "merge")))
+ (when (or current-prefix-arg
+ (not (or (magit-get-upstream-branch branch)
+ (magit--unnamed-upstream-p remote merge)
+ (magit--valid-upstream-p remote merge))))
+ (let* ((branches (-union (--map (concat it "/" branch)
+ (magit-list-remotes))
+ (magit-list-remote-branch-names)))
+ (upstream (magit-completing-read
+ (format "Set upstream of %s and push there" branch)
+ branches nil nil nil 'magit-revision-history
+ (or (car (member (magit-remote-branch-at-point) branches))
+ (car (member "origin/master" branches)))))
+ (upstream* (or (magit-get-tracked upstream)
+ (magit-split-branch-name upstream))))
+ (setq remote (car upstream*))
+ (setq merge (cdr upstream*))
+ (unless (string-prefix-p "refs/" merge)
+ ;; User selected a non-existent remote-tracking branch.
+ ;; It is very likely, but not certain, that this is the
+ ;; correct thing to do. It is even more likely that it
+ ;; is what the user wants to happen.
+ (setq merge (concat "refs/heads/" merge)))
+ (magit-confirm 'set-and-push
+ (format "Really use \"%s\" as upstream and push \"%s\" there"
+ upstream branch)))
+ (cl-pushnew "--set-upstream" args :test #'equal))
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "push" "-v" args remote (concat branch ":" merge))))
+
+(defun magit-push--upstream-description ()
+ (when-let ((branch (magit-get-current-branch)))
+ (or (magit-get-upstream-branch branch)
+ (let ((remote (magit-get "branch" branch "remote"))
+ (merge (magit-get "branch" branch "merge"))
+ (u (magit--propertize-face "@{upstream}" 'bold)))
+ (cond
+ ((magit--unnamed-upstream-p remote merge)
+ (format "%s as %s"
+ (magit--propertize-face remote 'bold)
+ (magit--propertize-face merge 'magit-branch-remote)))
+ ((magit--valid-upstream-p remote merge)
+ (format "%s creating %s"
+ (magit--propertize-face remote 'magit-branch-remote)
+ (magit--propertize-face merge 'magit-branch-remote)))
+ ((or remote merge)
+ (concat u ", creating it and replacing invalid"))
+ (t
+ (concat u ", creating it")))))))
+
+;;;###autoload
+(defun magit-push-current (target args)
+ "Push the current branch to a branch read in the minibuffer."
+ (interactive
+ (--if-let (magit-get-current-branch)
+ (list (magit-read-remote-branch (format "Push %s to" it)
+ nil nil it 'confirm)
+ (magit-push-arguments))
+ (user-error "No branch is checked out")))
+ (magit-git-push (magit-get-current-branch) target args))
+
+;;;###autoload
+(defun magit-push-other (source target args)
+ "Push an arbitrary branch or commit somewhere.
+Both the source and the target are read in the minibuffer."
+ (interactive
+ (let ((source (magit-read-local-branch-or-commit "Push")))
+ (list source
+ (magit-read-remote-branch
+ (format "Push %s to" source) nil
+ (if (magit-local-branch-p source)
+ (or (magit-get-push-branch source)
+ (magit-get-upstream-branch source))
+ (and (magit-rev-ancestor-p source "HEAD")
+ (or (magit-get-push-branch)
+ (magit-get-upstream-branch))))
+ source 'confirm)
+ (magit-push-arguments))))
+ (magit-git-push source target args))
+
+(defvar magit-push-refspecs-history nil)
+
+;;;###autoload
+(defun magit-push-refspecs (remote refspecs args)
+ "Push one or multiple REFSPECS to a REMOTE.
+Both the REMOTE and the REFSPECS are read in the minibuffer. To
+use multiple REFSPECS, separate them with commas. Completion is
+only available for the part before the colon, or when no colon
+is used."
+ (interactive
+ (list (magit-read-remote "Push to remote")
+ (split-string (magit-completing-read-multiple
+ "Push refspec,s"
+ (cons "HEAD" (magit-list-local-branch-names))
+ nil nil 'magit-push-refspecs-history)
+ crm-default-separator t)
+ (magit-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.<branch>.pushRemote', `branch.<branch>.remote',
+`branch.<branch>.merge', and `remote.<remote>.push'.
+
+If you add this suffix to a transient prefix without explicitly
+specifying the description, then an attempt is made to predict
+what this command will do. For example:
+
+ (transient-insert-suffix 'magit-push \"p\"
+ '(\"i\" magit-push-implicitly))"
+ :description 'magit-push-implicitly--desc
+ (interactive (list (magit-push-arguments)))
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "push" "-v" args))
+
+(defun magit-push-implicitly--desc ()
+ (let ((default (magit-get "push.default")))
+ (unless (equal default "nothing")
+ (or (when-let ((remote (or (magit-get-remote)
+ (magit-remote-p "origin")))
+ (refspec (magit-get "remote" remote "push")))
+ (format "%s using %s"
+ (magit--propertize-face remote 'magit-branch-remote)
+ (magit--propertize-face refspec 'bold)))
+ (--when-let (and (not (magit-get-push-branch))
+ (magit-get-upstream-branch))
+ (format "%s aka %s\n"
+ (magit-branch-set-face it)
+ (magit--propertize-face "@{upstream}" 'bold)))
+ (--when-let (magit-get-push-branch)
+ (format "%s aka %s\n"
+ (magit-branch-set-face it)
+ (magit--propertize-face "pushRemote" 'bold)))
+ (--when-let (magit-get-@{push}-branch)
+ (format "%s aka %s\n"
+ (magit-branch-set-face it)
+ (magit--propertize-face "@{push}" 'bold)))
+ (format "using %s (%s is %s)\n"
+ (magit--propertize-face "git push" 'bold)
+ (magit--propertize-face "push.default" 'bold)
+ (magit--propertize-face default 'bold))))))
+
+;;;###autoload
+(defun magit-push-to-remote (remote args)
+ "Push to REMOTE without using an explicit refspec.
+The REMOTE is read in the minibuffer.
+
+This command simply runs \"git push -v [ARGS] REMOTE\". ARGS
+are the arguments specified in the popup buffer. No refspec
+arguments are used. Instead the behavior depends on at least
+these Git variables: `push.default', `remote.pushDefault',
+`branch.<branch>.pushRemote', `branch.<branch>.remote',
+`branch.<branch>.merge', and `remote.<remote>.push'."
+ (interactive (list (magit-read-remote "Push to remote")
+ (magit-push-arguments)))
+ (run-hooks 'magit-credential-hook)
+ (magit-run-git-async "push" "-v" args remote))
+
+(defun magit-push-to-remote--desc ()
+ (format "using %s\n" (magit--propertize-face "git push <remote>" 'bold)))
+
+;;; _
+(provide 'magit-push)
+;;; magit-push.el ends here
--- /dev/null
+;;; magit-reflog.el --- inspect ref history -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements support for looking at Git reflogs.
+
+;;; Code:
+
+(require 'magit-core)
+(require 'magit-log)
+
+;;; Options
+
+(defcustom magit-reflog-limit 256
+ "Maximal number of entries initially shown in reflog buffers.
+The limit in the current buffer can be changed using \"+\"
+and \"-\"."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-commands
+ :type 'number)
+
+(defcustom magit-reflog-margin
+ (list (nth 0 magit-log-margin)
+ (nth 1 magit-log-margin)
+ 'magit-log-margin-width nil
+ (nth 4 magit-log-margin))
+ "Format of the margin in `magit-reflog-mode' buffers.
+
+The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
+
+If INIT is non-nil, then the margin is shown initially.
+STYLE controls how to format the author or committer date.
+ It can be one of `age' (to show the age of the commit),
+ `age-abbreviated' (to abbreviate the time unit to a character),
+ or a string (suitable for `format-time-string') to show the
+ actual date. Option `magit-log-margin-show-committer-date'
+ controls which date is being displayed.
+WIDTH controls the width of the margin. This exists for forward
+ compatibility and currently the value should not be changed.
+AUTHOR controls whether the name of the author is also shown by
+ default.
+AUTHOR-WIDTH has to be an integer. When the name of the author
+ is shown, then this specifies how much space is used to do so."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-log
+ :group 'magit-margin
+ :type magit-log-margin--custom-type
+ :initialize 'magit-custom-initialize-reset
+ :set-after '(magit-log-margin)
+ :set (apply-partially #'magit-margin-set-variable 'magit-reflog-mode))
+
+;;; Faces
+
+(defface magit-reflog-commit '((t :foreground "green"))
+ "Face for commit commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-amend '((t :foreground "magenta"))
+ "Face for amend commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-merge '((t :foreground "green"))
+ "Face for merge, checkout and branch commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-checkout '((t :foreground "blue"))
+ "Face for checkout commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-reset '((t :foreground "red"))
+ "Face for reset commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-rebase '((t :foreground "magenta"))
+ "Face for rebase commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-cherry-pick '((t :foreground "green"))
+ "Face for cherry-pick commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-remote '((t :foreground "cyan"))
+ "Face for pull and clone commands in reflogs."
+ :group 'magit-faces)
+
+(defface magit-reflog-other '((t :foreground "cyan"))
+ "Face for other commands in reflogs."
+ :group 'magit-faces)
+
+;;; Commands
+
+;;;###autoload
+(defun magit-reflog-current ()
+ "Display the reflog of the current branch.
+If `HEAD' is detached, then show the reflog for that instead."
+ (interactive)
+ (magit-reflog-setup-buffer (or (magit-get-current-branch) "HEAD")))
+
+;;;###autoload
+(defun magit-reflog-other (ref)
+ "Display the reflog of a branch or another ref."
+ (interactive (list (magit-read-local-branch-or-ref "Show reflog for")))
+ (magit-reflog-setup-buffer ref))
+
+;;;###autoload
+(defun magit-reflog-head ()
+ "Display the `HEAD' reflog."
+ (interactive)
+ (magit-reflog-setup-buffer "HEAD"))
+
+;;; Mode
+
+(defvar magit-reflog-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-log-mode-map)
+ (define-key map "\C-c\C-n" 'undefined)
+ (define-key map "L" 'magit-margin-settings)
+ map)
+ "Keymap for `magit-reflog-mode'.")
+
+(define-derived-mode magit-reflog-mode magit-mode "Magit Reflog"
+ "Mode for looking at Git reflog.
+
+This mode is documented in info node `(magit)Reflog'.
+
+\\<magit-mode-map>\
+Type \\[magit-refresh] to refresh the current buffer.
+Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
+to visit the commit at point.
+
+Type \\[magit-cherry-pick] to apply the commit at point.
+Type \\[magit-reset] to reset `HEAD' to the commit at point.
+
+\\{magit-reflog-mode-map}"
+ :group 'magit-log
+ (hack-dir-local-variables-non-file-buffer))
+
+(defun magit-reflog-setup-buffer (ref)
+ (require 'magit)
+ (magit-setup-buffer #'magit-reflog-mode nil
+ (magit-buffer-refname ref)
+ (magit-buffer-log-args (list (format "-n%s" magit-reflog-limit)))))
+
+(defun magit-reflog-refresh-buffer ()
+ (magit-set-header-line-format (concat "Reflog for " magit-buffer-refname))
+ (magit-insert-section (reflogbuf)
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'reflog)
+ "reflog" "show" "--format=%h%x00%aN%x00%gd%x00%gs" "--date=raw"
+ magit-buffer-log-args magit-buffer-refname "--")))
+
+(cl-defmethod magit-buffer-value (&context (major-mode magit-reflog-mode))
+ magit-buffer-refname)
+
+(defvar magit-reflog-labels
+ '(("commit" . magit-reflog-commit)
+ ("amend" . magit-reflog-amend)
+ ("merge" . magit-reflog-merge)
+ ("checkout" . magit-reflog-checkout)
+ ("branch" . magit-reflog-checkout)
+ ("reset" . magit-reflog-reset)
+ ("rebase" . magit-reflog-rebase)
+ ("cherry-pick" . magit-reflog-cherry-pick)
+ ("initial" . magit-reflog-commit)
+ ("pull" . magit-reflog-remote)
+ ("clone" . magit-reflog-remote)
+ ("autosave" . magit-reflog-commit)
+ ("restart" . magit-reflog-reset)))
+
+(defun magit-reflog-format-subject (subject)
+ (let* ((match (string-match magit-reflog-subject-re subject))
+ (command (and match (match-string 1 subject)))
+ (option (and match (match-string 2 subject)))
+ (type (and match (match-string 3 subject)))
+ (label (if (string= command "commit")
+ (or type command)
+ command))
+ (text (if (string= command "commit")
+ label
+ (mapconcat #'identity
+ (delq nil (list command option type))
+ " "))))
+ (format "%-16s "
+ (magit--propertize-face
+ text (or (cdr (assoc label magit-reflog-labels))
+ 'magit-reflog-other)))))
+
+;;; _
+(provide 'magit-reflog)
+;;; magit-reflog.el ends here
--- /dev/null
+;;; magit-refs.el --- listing references -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements support for listing references in a buffer.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Options
+
+(defgroup magit-refs nil
+ "Inspect and manipulate Git branches and tags."
+ :link '(info-link "(magit)References Buffer")
+ :group 'magit-modes)
+
+(defcustom magit-refs-mode-hook nil
+ "Hook run after entering Magit-Refs mode."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-refs
+ :type 'hook)
+
+(defcustom magit-refs-sections-hook
+ '(magit-insert-error-header
+ magit-insert-branch-description
+ magit-insert-local-branches
+ magit-insert-remote-branches
+ magit-insert-tags)
+ "Hook run to insert sections into a references buffer."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-refs
+ :type 'hook)
+
+(defcustom magit-refs-show-commit-count nil
+ "Whether to show commit counts in Magit-Refs mode buffers.
+
+all Show counts for branches and tags.
+branch Show counts for branches only.
+nil Never show counts.
+
+To change the value in an existing buffer use the command
+`magit-refs-show-commit-count'"
+ :package-version '(magit . "2.1.0")
+ :group 'magit-refs
+ :safe (lambda (val) (memq val '(all branch nil)))
+ :type '(choice (const all :tag "For branches and tags")
+ (const branch :tag "For branches only")
+ (const nil :tag "Never")))
+(put 'magit-refs-show-commit-count 'safe-local-variable 'symbolp)
+(put 'magit-refs-show-commit-count 'permanent-local t)
+
+(defcustom magit-refs-pad-commit-counts nil
+ "Whether to pad all counts on all sides in `magit-refs-mode' buffers.
+
+If this is nil, then some commit counts are displayed right next
+to one of the branches that appear next to the count, without any
+space in between. This might look bad if the branch name faces
+look too similar to `magit-dimmed'.
+
+If this is non-nil, then spaces are placed on both sides of all
+commit counts."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-refs
+ :type 'boolean)
+
+(defvar magit-refs-show-push-remote nil
+ "Whether to show the push-remotes of local branches.
+Also show the commits that the local branch is ahead and behind
+the push-target. Unfortunately there is a bug in Git that makes
+this useless (the commits ahead and behind the upstream are
+shown), so this isn't enabled yet.")
+
+(defcustom magit-refs-show-remote-prefix nil
+ "Whether to show the remote prefix in lists of remote branches.
+
+This is redundant because the name of the remote is already shown
+in the heading preceding the list of its branches."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-refs
+ :type 'boolean)
+
+(defcustom magit-refs-margin
+ (list nil
+ (nth 1 magit-log-margin)
+ 'magit-log-margin-width nil
+ (nth 4 magit-log-margin))
+ "Format of the margin in `magit-refs-mode' buffers.
+
+The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
+
+If INIT is non-nil, then the margin is shown initially.
+STYLE controls how to format the author or committer date.
+ It can be one of `age' (to show the age of the commit),
+ `age-abbreviated' (to abbreviate the time unit to a character),
+ or a string (suitable for `format-time-string') to show the
+ actual date. Option `magit-log-margin-show-committer-date'
+ controls which date is being displayed.
+WIDTH controls the width of the margin. This exists for forward
+ compatibility and currently the value should not be changed.
+AUTHOR controls whether the name of the author is also shown by
+ default.
+AUTHOR-WIDTH has to be an integer. When the name of the author
+ is shown, then this specifies how much space is used to do so."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-refs
+ :group 'magit-margin
+ :safe (lambda (val) (memq val '(all branch nil)))
+ :type magit-log-margin--custom-type
+ :initialize 'magit-custom-initialize-reset
+ :set-after '(magit-log-margin)
+ :set (apply-partially #'magit-margin-set-variable 'magit-refs-mode))
+
+(defcustom magit-refs-margin-for-tags nil
+ "Whether to show information about tags in the margin.
+
+This is disabled by default because it is slow if there are many
+tags."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-refs
+ :group 'magit-margin
+ :type 'boolean)
+
+(defcustom magit-refs-primary-column-width (cons 16 32)
+ "Width of the focus column in `magit-refs-mode' buffers.
+
+The primary column is the column that contains the name of the
+branch that the current row is about.
+
+If this is an integer, then the column is that many columns wide.
+Otherwise it has to be a cons-cell of two integers. The first
+specifies the minimal width, the second the maximal width. In that
+case the actual width is determined using the length of the names
+of the shown local branches. (Remote branches and tags are not
+taken into account when calculating to optimal width.)"
+ :package-version '(magit . "2.12.0")
+ :group 'magit-refs
+ :type '(choice (integer :tag "Constant wide")
+ (cons :tag "Wide constrains"
+ (integer :tag "Minimum")
+ (integer :tag "Maximum"))))
+
+(defcustom magit-refs-focus-column-width 5
+ "Width of the focus column in `magit-refs-mode' buffers.
+
+The focus column is the first column, which marks one
+branch (usually the current branch) as the focused branch using
+\"*\" or \"@\". For each other reference, this column optionally
+shows how many commits it is ahead of the focused branch and \"<\", or
+if it isn't ahead then the commits it is behind and \">\", or if it
+isn't behind either, then a \"=\".
+
+This column may also display only \"*\" or \"@\" for the focused
+branch, in which case this option is ignored. Use \"L v\" to
+change the verbosity of this column."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-refs
+ :type 'integer)
+
+(defcustom magit-refs-filter-alist nil
+ "Alist controlling which refs are omitted from `magit-refs-mode' buffers.
+
+The purpose of this option is to forgo displaying certain refs
+based on their name. If you want to not display any refs of a
+certain type, then you should remove the appropriate function
+from `magit-refs-sections-hook' instead.
+
+All keys are tried in order until one matches. Then its value
+is used and subsequent elements are ignored. If the value is
+non-nil, then the reference is displayed, otherwise it is not.
+If no element matches, then the reference is displayed.
+
+A key can either be a regular expression that the refname has to
+match, or a function that takes the refname as only argument and
+returns a boolean. A remote branch such as \"origin/master\" is
+displayed as just \"master\", however for this comparison the
+former is used."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-refs
+ :type '(alist :key-type (choice :tag "Key" regexp function)
+ :value-type (boolean :tag "Value"
+ :on "show (non-nil)"
+ :off "omit (nil)")))
+
+(defcustom magit-visit-ref-behavior nil
+ "Control how `magit-visit-ref' behaves in `magit-refs-mode' buffers.
+
+By default `magit-visit-ref' behaves like `magit-show-commit',
+in all buffers, including `magit-refs-mode' buffers. When the
+type of the section at point is `commit' then \"RET\" is bound to
+`magit-show-commit', and when the type is either `branch' or
+`tag' then it is bound to `magit-visit-ref'.
+
+\"RET\" is one of Magit's most essential keys and at least by
+default it should behave consistently across all of Magit,
+especially because users quickly learn that it does something
+very harmless; it shows more information about the thing at point
+in another buffer.
+
+However \"RET\" used to behave differently in `magit-refs-mode'
+buffers, doing surprising things, some of which cannot really be
+described as \"visit this thing\". If you have grown accustomed
+to such inconsistent, but to you useful, behavior, then you can
+restore that by adding one or more of the below symbols to the
+value of this option. But keep in mind that by doing so you
+don't only introduce inconsistencies, you also lose some
+functionality and might have to resort to `M-x magit-show-commit'
+to get it back.
+
+`magit-visit-ref' looks for these symbols in the order in which
+they are described here. If the presence of a symbol applies to
+the current situation, then the symbols that follow do not affect
+the outcome.
+
+`focus-on-ref'
+
+ With a prefix argument update the buffer to show commit counts
+ and lists of cherry commits relative to the reference at point
+ instead of relative to the current buffer or `HEAD'.
+
+ Instead of adding this symbol, consider pressing \"C-u y o RET\".
+
+`create-branch'
+
+ If point is on a remote branch, then create a new local branch
+ with the same name, use the remote branch as its upstream, and
+ then check out the local branch.
+
+ Instead of adding this symbol, consider pressing \"b c RET RET\",
+ like you would do in other buffers.
+
+`checkout-any'
+
+ Check out the reference at point. If that reference is a tag
+ or a remote branch, then this results in a detached `HEAD'.
+
+ Instead of adding this symbol, consider pressing \"b b RET\",
+ like you would do in other buffers.
+
+`checkout-branch'
+
+ Check out the local branch at point.
+
+ Instead of adding this symbol, consider pressing \"b b RET\",
+ like you would do in other buffers."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-refs
+ :group 'magit-commands
+ :options '(focus-on-ref create-branch checkout-any checkout-branch)
+ :type '(list :convert-widget custom-hook-convert-widget))
+
+;;; Mode
+
+(defvar magit-refs-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-mode-map)
+ (define-key map "\C-y" 'magit-refs-set-show-commit-count)
+ (define-key map "L" 'magit-margin-settings)
+ map)
+ "Keymap for `magit-refs-mode'.")
+
+(define-derived-mode magit-refs-mode magit-mode "Magit Refs"
+ "Mode which lists and compares references.
+
+This mode is documented in info node `(magit)References Buffer'.
+
+\\<magit-mode-map>\
+Type \\[magit-refresh] to refresh the current buffer.
+Type \\[magit-section-toggle] to expand or hide the section at point.
+Type \\[magit-visit-thing] or \\[magit-diff-show-or-scroll-up] \
+to visit the commit or branch at point.
+
+Type \\[magit-branch] to see available branch commands.
+Type \\[magit-merge] to merge the branch or commit at point.
+Type \\[magit-cherry-pick] to apply the commit at point.
+Type \\[magit-reset] to reset `HEAD' to the commit at point.
+
+\\{magit-refs-mode-map}"
+ :group 'magit-refs
+ (hack-dir-local-variables-non-file-buffer)
+ (setq imenu-create-index-function
+ #'magit-imenu--refs-create-index-function))
+
+(defun magit-refs-setup-buffer (ref args)
+ (magit-setup-buffer #'magit-refs-mode nil
+ (magit-buffer-upstream ref)
+ (magit-buffer-arguments args)))
+
+(defun magit-refs-refresh-buffer ()
+ (setq magit-set-buffer-margin-refresh (not (magit-buffer-margin-p)))
+ (unless (magit-rev-verify magit-buffer-upstream)
+ (setq magit-refs-show-commit-count nil))
+ (magit-set-header-line-format
+ (format "%s %s" magit-buffer-upstream
+ (mapconcat #'identity magit-buffer-arguments " ")))
+ (magit-insert-section (branchbuf)
+ (magit-run-section-hook 'magit-refs-sections-hook))
+ (add-hook 'kill-buffer-hook 'magit-preserve-section-visibility-cache))
+
+(cl-defmethod magit-buffer-value (&context (major-mode magit-refs-mode))
+ (cons magit-buffer-upstream magit-buffer-arguments))
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-show-refs "magit-refs" nil t)
+(transient-define-prefix magit-show-refs (&optional transient)
+ "List and compare references in a dedicated buffer."
+ :man-page "git-branch"
+ :value (lambda ()
+ (magit-show-refs-arguments magit-prefix-use-buffer-arguments))
+ ["Arguments"
+ (magit-for-each-ref:--contains)
+ ("-M" "Merged" "--merged=" magit-transient-read-revision)
+ ("-m" "Merged to HEAD" "--merged")
+ ("-N" "Not merged" "--no-merged=" magit-transient-read-revision)
+ ("-n" "Not merged to HEAD" "--no-merged")
+ (magit-for-each-ref:--sort)]
+ ["Actions"
+ ("y" "Show refs, comparing them with HEAD" magit-show-refs-head)
+ ("c" "Show refs, comparing them with current branch" magit-show-refs-current)
+ ("o" "Show refs, comparing them with other branch" magit-show-refs-other)]
+ (interactive (list (or (derived-mode-p 'magit-refs-mode)
+ current-prefix-arg)))
+ (if transient
+ (transient-setup 'magit-show-refs)
+ (magit-refs-setup-buffer "HEAD" (magit-show-refs-arguments))))
+
+(defun magit-show-refs-arguments (&optional use-buffer-args)
+ (unless use-buffer-args
+ (setq use-buffer-args magit-direct-use-buffer-arguments))
+ (let (args)
+ (cond
+ ((eq transient-current-command 'magit-show-refs)
+ (setq args (transient-args 'magit-show-refs)))
+ ((eq major-mode 'magit-refs-mode)
+ (setq args magit-buffer-arguments))
+ ((and (memq use-buffer-args '(always selected))
+ (when-let ((buffer (magit-get-mode-buffer
+ 'magit-refs-mode nil
+ (eq use-buffer-args 'selected))))
+ (setq args (buffer-local-value 'magit-buffer-arguments buffer))
+ t)))
+ (t
+ (setq args (alist-get 'magit-show-refs transient-values))))
+ args))
+
+(transient-define-argument magit-for-each-ref:--contains ()
+ :description "Contains"
+ :class 'transient-option
+ :key "-c"
+ :argument "--contains="
+ :reader 'magit-transient-read-revision)
+
+(transient-define-argument magit-for-each-ref:--sort ()
+ :description "Sort"
+ :class 'transient-option
+ :key "-s"
+ :argument "--sort="
+ :reader 'magit-read-ref-sort)
+
+(defun magit-read-ref-sort (prompt initial-input _history)
+ (magit-completing-read prompt
+ '("-committerdate" "-authordate"
+ "committerdate" "authordate")
+ nil nil initial-input))
+
+;;;###autoload
+(defun magit-show-refs-head (&optional args)
+ "List and compare references in a dedicated buffer.
+Compared with `HEAD'."
+ (interactive (list (magit-show-refs-arguments)))
+ (magit-refs-setup-buffer "HEAD" args))
+
+;;;###autoload
+(defun magit-show-refs-current (&optional args)
+ "List and compare references in a dedicated buffer.
+Compare with the current branch or `HEAD' if it is detached."
+ (interactive (list (magit-show-refs-arguments)))
+ (magit-refs-setup-buffer (magit-get-current-branch) args))
+
+;;;###autoload
+(defun magit-show-refs-other (&optional ref args)
+ "List and compare references in a dedicated buffer.
+Compared with a branch read from the user."
+ (interactive (list (magit-read-other-branch "Compare with")
+ (magit-show-refs-arguments)))
+ (magit-refs-setup-buffer ref args))
+
+(defun magit-refs-set-show-commit-count ()
+ "Change for which refs the commit count is shown."
+ (interactive)
+ (setq-local magit-refs-show-commit-count
+ (magit-read-char-case "Show commit counts for " nil
+ (?a "[a]ll refs" 'all)
+ (?b "[b]ranches only" t)
+ (?n "[n]othing" nil)))
+ (magit-refresh))
+
+(defun magit-visit-ref ()
+ "Visit the reference or revision at point in another buffer.
+If there is no revision at point or with a prefix argument prompt
+for a revision.
+
+This command behaves just like `magit-show-commit', except if
+point is on a reference in a `magit-refs-mode' buffer (a buffer
+listing branches and tags), in which case the behavior may be
+different, but only if you have customized the option
+`magit-visit-ref-behavior' (which see)."
+ (interactive)
+ (if (and (derived-mode-p 'magit-refs-mode)
+ (magit-section-match '(branch tag)))
+ (let ((ref (oref (magit-current-section) value)))
+ (cond (current-prefix-arg
+ (cond ((memq 'focus-on-ref magit-visit-ref-behavior)
+ (magit-refs-setup-buffer ref (magit-show-refs-arguments)))
+ (magit-visit-ref-behavior
+ ;; Don't prompt for commit to visit.
+ (let ((current-prefix-arg nil))
+ (call-interactively #'magit-show-commit)))))
+ ((and (memq 'create-branch magit-visit-ref-behavior)
+ (magit-section-match [branch remote]))
+ (let ((branch (cdr (magit-split-branch-name ref))))
+ (if (magit-branch-p branch)
+ (if (magit-rev-eq branch ref)
+ (magit-call-git "checkout" branch)
+ (setq branch (propertize branch 'face 'magit-branch-local))
+ (setq ref (propertize ref 'face 'magit-branch-remote))
+ (pcase (prog1 (read-char-choice (format (propertize "\
+Branch %s already exists.
+ [c]heckout %s as-is
+ [r]reset %s to %s and checkout %s
+ [a]bort " 'face 'minibuffer-prompt) branch branch branch ref branch)
+ '(?c ?r ?a))
+ (message "")) ; otherwise prompt sticks
+ (?c (magit-call-git "checkout" branch))
+ (?r (magit-call-git "checkout" "-B" branch ref))
+ (?a (user-error "Abort"))))
+ (magit-call-git "checkout" "-b" branch ref))
+ (setq magit-buffer-upstream branch)
+ (magit-refresh)))
+ ((or (memq 'checkout-any magit-visit-ref-behavior)
+ (and (memq 'checkout-branch magit-visit-ref-behavior)
+ (magit-section-match [branch local])))
+ (magit-call-git "checkout" ref)
+ (setq magit-buffer-upstream ref)
+ (magit-refresh))
+ (t
+ (call-interactively #'magit-show-commit))))
+ (call-interactively #'magit-show-commit)))
+
+;;; Sections
+
+(defvar magit-remote-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-delete-thing] 'magit-remote-remove)
+ (define-key map "R" 'magit-remote-rename)
+ map)
+ "Keymap for `remote' sections.")
+
+(defvar magit-branch-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-visit-ref)
+ (define-key map [remap magit-delete-thing] 'magit-branch-delete)
+ (define-key map "R" 'magit-branch-rename)
+ map)
+ "Keymap for `branch' sections.")
+
+(defvar magit-tag-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-visit-ref)
+ (define-key map [remap magit-delete-thing] 'magit-tag-delete)
+ map)
+ "Keymap for `tag' sections.")
+
+(defun magit-insert-branch-description ()
+ "Insert header containing the description of the current branch.
+Insert a header line with the name and description of the
+current branch. The description is taken from the Git variable
+`branch.<NAME>.description'; if that is undefined then no header
+line is inserted at all."
+ (when-let ((branch (magit-get-current-branch))
+ (desc (magit-get "branch" branch "description"))
+ (desc (split-string desc "\n")))
+ (when (equal (car (last desc)) "")
+ (setq desc (butlast desc)))
+ (magit-insert-section (branchdesc branch t)
+ (magit-insert-heading branch ": " (car desc))
+ (when (cdr desc)
+ (insert (mapconcat 'identity (cdr desc) "\n"))
+ (insert "\n\n")))))
+
+(defun magit-insert-tags ()
+ "Insert sections showing all tags."
+ (when-let ((tags (magit-git-lines "tag" "--list" "-n" magit-buffer-arguments)))
+ (let ((_head (magit-rev-parse "HEAD")))
+ (magit-insert-section (tags)
+ (magit-insert-heading "Tags:")
+ (dolist (tag tags)
+ (string-match "^\\([^ \t]+\\)[ \t]+\\([^ \t\n].*\\)?" tag)
+ (let ((tag (match-string 1 tag))
+ (msg (match-string 2 tag)))
+ (when (magit-refs--insert-refname-p tag)
+ (magit-insert-section (tag tag t)
+ (magit-insert-heading
+ (magit-refs--format-focus-column tag 'tag)
+ (propertize tag 'font-lock-face 'magit-tag)
+ (make-string (max 1 (- magit-refs-primary-column-width
+ (length tag)))
+ ?\s)
+ (and msg (magit-log-propertize-keywords nil msg)))
+ (when (and magit-refs-margin-for-tags (magit-buffer-margin-p))
+ (magit-refs--format-margin tag))
+ (magit-refs--insert-cherry-commits tag)))))
+ (insert ?\n)
+ (magit-make-margin-overlay nil t)))))
+
+(defun magit-insert-remote-branches ()
+ "Insert sections showing all remote-tracking branches."
+ (dolist (remote (magit-list-remotes))
+ (magit-insert-section (remote remote)
+ (magit-insert-heading
+ (let ((pull (magit-get "remote" remote "url"))
+ (push (magit-get "remote" remote "pushurl")))
+ (format (propertize "Remote %s (%s):"
+ 'font-lock-face 'magit-section-heading)
+ (propertize remote 'font-lock-face 'magit-branch-remote)
+ (concat pull (and pull push ", ") push))))
+ (let (head)
+ (dolist (line (magit-git-lines "for-each-ref" "--format=\
+%(symref:short)%00%(refname:short)%00%(refname)%00%(subject)"
+ (concat "refs/remotes/" remote)
+ magit-buffer-arguments))
+ (pcase-let ((`(,head-branch ,branch ,ref ,msg)
+ (-replace "" nil (split-string line "\0"))))
+ (if head-branch
+ (progn (cl-assert (equal branch (concat remote "/HEAD")))
+ (setq head head-branch))
+ (when (magit-refs--insert-refname-p branch)
+ (magit-insert-section (branch branch t)
+ (let ((headp (equal branch head))
+ (abbrev (if magit-refs-show-remote-prefix
+ branch
+ (substring branch (1+ (length remote))))))
+ (magit-insert-heading
+ (magit-refs--format-focus-column branch)
+ (magit-refs--propertize-branch
+ abbrev ref (and headp 'magit-branch-remote-head))
+ (make-string (max 1 (- magit-refs-primary-column-width
+ (length abbrev)))
+ ?\s)
+ (and msg (magit-log-propertize-keywords nil msg))))
+ (when (magit-buffer-margin-p)
+ (magit-refs--format-margin branch))
+ (magit-refs--insert-cherry-commits branch)))))))
+ (insert ?\n)
+ (magit-make-margin-overlay nil t))))
+
+(defun magit-insert-local-branches ()
+ "Insert sections showing all local branches."
+ (magit-insert-section (local nil)
+ (magit-insert-heading "Branches:")
+ (dolist (line (magit-refs--format-local-branches))
+ (pcase-let ((`(,branch . ,strings) line))
+ (magit-insert-section
+ ((eval (if branch 'branch 'commit))
+ (or branch (magit-rev-parse "HEAD"))
+ t)
+ (apply #'magit-insert-heading strings)
+ (when (magit-buffer-margin-p)
+ (magit-refs--format-margin branch))
+ (magit-refs--insert-cherry-commits branch))))
+ (insert ?\n)
+ (magit-make-margin-overlay nil t)))
+
+(defun magit-refs--format-local-branches ()
+ (let ((lines (-keep 'magit-refs--format-local-branch
+ (magit-git-lines
+ "for-each-ref"
+ (concat "--format=\
+%(HEAD)%00%(refname:short)%00%(refname)%00\
+%(upstream:short)%00%(upstream)%00%(upstream:track)%00"
+ (if magit-refs-show-push-remote "\
+%(push:remotename)%00%(push)%00%(push:track)%00%(subject)"
+ "%00%00%00%(subject)"))
+ "refs/heads"
+ magit-buffer-arguments))))
+ (unless (magit-get-current-branch)
+ (push (magit-refs--format-local-branch
+ (concat "*\0\0\0\0\0\0\0\0" (magit-rev-format "%s")))
+ lines))
+ (setq-local magit-refs-primary-column-width
+ (let ((def (default-value 'magit-refs-primary-column-width)))
+ (if (atom def)
+ def
+ (pcase-let ((`(,min . ,max) def))
+ (min max (apply #'max min (mapcar #'car lines)))))))
+ (mapcar (pcase-lambda (`(,_ ,branch ,focus ,branch-desc ,u:ahead ,p:ahead
+ ,u:behind ,upstream ,p:behind ,push ,msg))
+ (list branch focus branch-desc u:ahead p:ahead
+ (make-string (max 1 (- magit-refs-primary-column-width
+ (length (concat branch-desc
+ u:ahead
+ p:ahead
+ u:behind))))
+ ?\s)
+ u:behind upstream p:behind push
+ msg))
+ lines)))
+
+(defun magit-refs--format-local-branch (line)
+ (pcase-let ((`(,head ,branch ,ref ,upstream ,u:ref ,u:track
+ ,push ,p:ref ,p:track ,msg)
+ (-replace "" nil (split-string line "\0"))))
+ (when (or (not branch)
+ (magit-refs--insert-refname-p branch))
+ (let* ((headp (equal head "*"))
+ (pushp (and push
+ magit-refs-show-push-remote
+ (magit-rev-verify p:ref)
+ (not (equal p:ref u:ref))))
+ (branch-desc
+ (if branch
+ (magit-refs--propertize-branch
+ branch ref (and headp 'magit-branch-current))
+ (magit--propertize-face "(detached)"
+ 'font-lock-warning-face)))
+ (u:ahead (and u:track
+ (string-match "ahead \\([0-9]+\\)" u:track)
+ (magit--propertize-face
+ (concat (and magit-refs-pad-commit-counts " ")
+ (match-string 1 u:track)
+ ">")
+ 'magit-dimmed)))
+ (u:behind (and u:track
+ (string-match "behind \\([0-9]+\\)" u:track)
+ (magit--propertize-face
+ (concat "<"
+ (match-string 1 u:track)
+ (and magit-refs-pad-commit-counts " "))
+ 'magit-dimmed)))
+ (p:ahead (and pushp p:track
+ (string-match "ahead \\([0-9]+\\)" p:track)
+ (magit--propertize-face
+ (concat (match-string 1 p:track)
+ ">"
+ (and magit-refs-pad-commit-counts " "))
+ 'magit-branch-remote)))
+ (p:behind (and pushp p:track
+ (string-match "behind \\([0-9]+\\)" p:track)
+ (magit--propertize-face
+ (concat "<"
+ (match-string 1 p:track)
+ (and magit-refs-pad-commit-counts " "))
+ 'magit-dimmed))))
+ (list (1+ (length (concat branch-desc u:ahead p:ahead u:behind)))
+ branch
+ (magit-refs--format-focus-column branch headp)
+ branch-desc u:ahead p:ahead u:behind
+ (and upstream
+ (concat (if (equal u:track "[gone]")
+ (magit--propertize-face upstream 'error)
+ (magit-refs--propertize-branch upstream u:ref))
+ " "))
+ (and pushp
+ (concat p:behind
+ (magit--propertize-face
+ push 'magit-branch-remote)
+ " "))
+ (and msg (magit-log-propertize-keywords nil msg)))))))
+
+(defun magit-refs--format-focus-column (ref &optional type)
+ (let ((focus magit-buffer-upstream)
+ (width (if magit-refs-show-commit-count
+ magit-refs-focus-column-width
+ 1)))
+ (format
+ (format "%%%ss " width)
+ (cond ((or (equal ref focus)
+ (and (eq type t)
+ (equal focus "HEAD")))
+ (magit--propertize-face (concat (if (equal focus "HEAD") "@" "*")
+ (make-string (1- width) ?\s))
+ 'magit-section-heading))
+ ((if (eq type 'tag)
+ (eq magit-refs-show-commit-count 'all)
+ magit-refs-show-commit-count)
+ (pcase-let ((`(,behind ,ahead)
+ (magit-rev-diff-count magit-buffer-upstream ref)))
+ (magit--propertize-face
+ (cond ((> ahead 0) (concat "<" (number-to-string ahead)))
+ ((> behind 0) (concat (number-to-string behind) ">"))
+ (t "="))
+ 'magit-dimmed)))
+ (t "")))))
+
+(defun magit-refs--propertize-branch (branch ref &optional head-face)
+ (let ((face (cdr (cl-find-if (pcase-lambda (`(,re . ,_))
+ (string-match-p re ref))
+ magit-ref-namespaces))))
+ (magit--propertize-face
+ branch (if head-face (list face head-face) face))))
+
+(defun magit-refs--insert-refname-p (refname)
+ (--if-let (-first (pcase-lambda (`(,key . ,_))
+ (if (functionp key)
+ (funcall key refname)
+ (string-match-p key refname)))
+ magit-refs-filter-alist)
+ (cdr it)
+ t))
+
+(defun magit-refs--insert-cherry-commits (ref)
+ (magit-insert-section-body
+ (let ((start (point))
+ (magit-insert-section--current nil))
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'cherry)
+ "cherry" "-v" (magit-abbrev-arg) magit-buffer-upstream ref)
+ (if (= (point) start)
+ (message "No cherries for %s" ref)
+ (magit-make-margin-overlay nil t)))))
+
+(defun magit-refs--format-margin (commit)
+ (save-excursion
+ (goto-char (line-beginning-position 0))
+ (let ((line (magit-rev-format "%ct%cN" commit)))
+ (magit-log-format-margin commit
+ (substring line 10)
+ (substring line 0 10)))))
+
+;;; _
+(provide 'magit-refs)
+;;; magit-refs.el ends here
--- /dev/null
+;;; magit-remote.el --- transfer Git commits -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements remote commands.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Options
+
+(defcustom magit-remote-add-set-remote.pushDefault 'ask-if-unset
+ "Whether to set the value of `remote.pushDefault' after adding a remote.
+
+If `ask', then always ask. If `ask-if-unset', then ask, but only
+if the variable isn't set already. If nil, then don't ever set.
+If the value is a string, then set without asking, provided that
+the name of the added remote is equal to that string and the
+variable isn't already set."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-commands
+ :type '(choice (const :tag "ask if unset" ask-if-unset)
+ (const :tag "always ask" ask)
+ (string :tag "set if named")
+ (const :tag "don't set")))
+
+(defcustom magit-remote-direct-configure t
+ "Whether the command `magit-remote' shows Git variables.
+When set to nil, no variables are displayed by this transient
+command, instead the sub-transient `magit-remote-configure'
+has to be used to view and change remote related variables."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defcustom magit-prefer-push-default nil
+ "Whether to prefer `remote.pushDefault' over per-branch variables."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-remote "magit-remote" nil t)
+(transient-define-prefix magit-remote (remote)
+ "Add, configure or remove a remote."
+ :man-page "git-remote"
+ :value '("-f")
+ ["Variables"
+ :if (lambda ()
+ (and magit-remote-direct-configure
+ (oref transient--prefix scope)))
+ ("u" magit-remote.<remote>.url)
+ ("U" magit-remote.<remote>.fetch)
+ ("s" magit-remote.<remote>.pushurl)
+ ("S" magit-remote.<remote>.push)
+ ("O" magit-remote.<remote>.tagopt)]
+ ["Arguments for add"
+ ("-f" "Fetch after add" "-f")]
+ ["Actions"
+ [("a" "Add" magit-remote-add)
+ ("r" "Rename" magit-remote-rename)
+ ("k" "Remove" magit-remote-remove)]
+ [("C" "Configure..." magit-remote-configure)
+ ("p" "Prune stale branches" magit-remote-prune)
+ ("P" "Prune stale refspecs" magit-remote-prune-refspecs)]]
+ (interactive (list (magit-get-current-remote)))
+ (transient-setup 'magit-remote nil nil :scope remote))
+
+(defun magit-read-url (prompt &optional initial-input)
+ (let ((url (magit-read-string-ns prompt initial-input)))
+ (if (string-prefix-p "~" url)
+ (expand-file-name url)
+ url)))
+
+;;;###autoload
+(defun magit-remote-add (remote url &optional args)
+ "Add a remote named REMOTE and fetch it."
+ (interactive
+ (let ((origin (magit-get "remote.origin.url"))
+ (remote (magit-read-string-ns "Remote name")))
+ (list remote
+ (magit-read-url
+ "Remote url"
+ (and origin
+ (string-match "\\([^:/]+\\)/[^/]+\\(\\.git\\)?\\'" origin)
+ (replace-match remote t t origin 1)))
+ (transient-args 'magit-remote))))
+ (if (pcase (list magit-remote-add-set-remote.pushDefault
+ (magit-get "remote.pushDefault"))
+ (`(,(pred stringp) ,_) t)
+ ((or `(ask ,_) `(ask-if-unset nil))
+ (y-or-n-p (format "Set `remote.pushDefault' to \"%s\"? " remote))))
+ (progn (magit-call-git "remote" "add" args remote url)
+ (setf (magit-get "remote.pushDefault") remote)
+ (magit-refresh))
+ (magit-run-git-async "remote" "add" args remote url)))
+
+;;;###autoload
+(defun magit-remote-rename (old new)
+ "Rename the remote named OLD to NEW."
+ (interactive
+ (let ((remote (magit-read-remote "Rename remote")))
+ (list remote (magit-read-string-ns (format "Rename %s to" remote)))))
+ (unless (string= old new)
+ (magit-call-git "remote" "rename" old new)
+ (magit-remote--cleanup-push-variables old new)
+ (magit-refresh)))
+
+;;;###autoload
+(defun magit-remote-remove (remote)
+ "Delete the remote named REMOTE."
+ (interactive (list (magit-read-remote "Delete remote")))
+ (magit-call-git "remote" "rm" remote)
+ (magit-remote--cleanup-push-variables remote)
+ (magit-refresh))
+
+(defun magit-remote--cleanup-push-variables (remote &optional new-name)
+ (magit-with-toplevel
+ (when (equal (magit-get "remote.pushDefault") remote)
+ (magit-set new-name "remote.pushDefault"))
+ (dolist (var (magit-git-lines "config" "--name-only"
+ "--get-regexp" "^branch\.[^.]*\.pushRemote"
+ (format "^%s$" remote)))
+ (magit-call-git "config" (and (not new-name) "--unset") var new-name))))
+
+(defconst magit--refspec-re "\\`\\(\\+\\)?\\([^:]+\\):\\(.*\\)\\'")
+
+;;;###autoload
+(defun magit-remote-prune (remote)
+ "Remove stale remote-tracking branches for REMOTE."
+ (interactive (list (magit-read-remote "Prune stale branches of remote")))
+ (magit-run-git-async "remote" "prune" remote))
+
+;;;###autoload
+(defun magit-remote-prune-refspecs (remote)
+ "Remove stale refspecs for REMOTE.
+
+A refspec is stale if there no longer exists at least one branch
+on the remote that would be fetched due to that refspec. A stale
+refspec is problematic because its existence causes Git to refuse
+to fetch according to the remaining non-stale refspecs.
+
+If only stale refspecs remain, then offer to either delete the
+remote or to replace the stale refspecs with the default refspec.
+
+Also remove the remote-tracking branches that were created due to
+the now stale refspecs. Other stale branches are not removed."
+ (interactive (list (magit-read-remote "Prune refspecs of remote")))
+ (let* ((tracking-refs (magit-list-remote-branches remote))
+ (remote-refs (magit-remote-list-refs remote))
+ (variable (format "remote.%s.fetch" remote))
+ (refspecs (magit-get-all variable))
+ stale)
+ (dolist (refspec refspecs)
+ (when (string-match magit--refspec-re refspec)
+ (let ((theirs (match-string 2 refspec))
+ (ours (match-string 3 refspec)))
+ (unless (if (string-match "\\*" theirs)
+ (let ((re (replace-match ".*" t t theirs)))
+ (--some (string-match-p re it) remote-refs))
+ (member theirs remote-refs))
+ (push (cons refspec
+ (if (string-match "\\*" ours)
+ (let ((re (replace-match ".*" t t ours)))
+ (--filter (string-match-p re it) tracking-refs))
+ (list (car (member ours tracking-refs)))))
+ stale)))))
+ (if (not stale)
+ (message "No stale refspecs for remote %S" remote)
+ (if (= (length stale)
+ (length refspecs))
+ (magit-read-char-case
+ (format "All of %s's refspecs are stale. " remote) nil
+ (?s "replace with [d]efault refspec"
+ (magit-set-all
+ (list (format "+refs/heads/*:refs/remotes/%s/*" remote))
+ variable))
+ (?r "[r]emove remote"
+ (magit-call-git "remote" "rm" remote))
+ (?a "or [a]abort"
+ (user-error "Abort")))
+ (if (if (= (length stale) 1)
+ (pcase-let ((`(,refspec . ,refs) (car stale)))
+ (magit-confirm 'prune-stale-refspecs
+ (format "Prune stale refspec %s and branch %%s" refspec)
+ (format "Prune stale refspec %s and %%i branches" refspec)
+ nil refs))
+ (magit-confirm 'prune-stale-refspecs nil
+ (format "Prune %%i stale refspecs and %i branches"
+ (length (cl-mapcan (lambda (s) (copy-sequence (cdr s)))
+ stale)))
+ nil
+ (mapcar (pcase-lambda (`(,refspec . ,refs))
+ (concat refspec "\n"
+ (mapconcat (lambda (b) (concat " " b))
+ refs "\n")))
+ stale)))
+ (pcase-dolist (`(,refspec . ,refs) stale)
+ (magit-call-git "config" "--unset" variable
+ (regexp-quote refspec))
+ (magit--log-action
+ (lambda (refs)
+ (format "Deleting %i branches" (length refs)))
+ (lambda (ref)
+ (format "Deleting branch %s (was %s)" ref
+ (magit-rev-parse "--short" ref)))
+ refs)
+ (dolist (ref refs)
+ (magit-call-git "update-ref" "-d" ref)))
+ (user-error "Abort")))
+ (magit-refresh))))
+
+;;;###autoload
+(defun magit-remote-set-head (remote &optional branch)
+ "Set the local representation of REMOTE's default branch.
+Query REMOTE and set the symbolic-ref refs/remotes/<remote>/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/<remote>/HEAD\"."
+ (interactive (list (magit-read-remote "Unset HEAD for remote")))
+ (magit-run-git "remote" "set-head" remote "--delete"))
+
+;;; Configure
+
+;;;###autoload (autoload 'magit-remote-configure "magit-remote" nil t)
+(transient-define-prefix magit-remote-configure (remote)
+ "Configure a remote."
+ :man-page "git-remote"
+ [:description
+ (lambda ()
+ (concat
+ (propertize "Configure " 'face 'transient-heading)
+ (propertize (oref transient--prefix scope) 'face 'magit-branch-remote)))
+ ("u" magit-remote.<remote>.url)
+ ("U" magit-remote.<remote>.fetch)
+ ("s" magit-remote.<remote>.pushurl)
+ ("S" magit-remote.<remote>.push)
+ ("O" magit-remote.<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) "<name>"))
+ "Configure remote")))
+
+(transient-define-infix magit-remote.<remote>.url ()
+ :class 'magit--git-variable:urls
+ :scope 'magit--read-remote-scope
+ :variable "remote.%s.url"
+ :multi-value t
+ :history-key 'magit-remote.<remote>.*url)
+
+(transient-define-infix magit-remote.<remote>.fetch ()
+ :class 'magit--git-variable
+ :scope 'magit--read-remote-scope
+ :variable "remote.%s.fetch"
+ :multi-value t)
+
+(transient-define-infix magit-remote.<remote>.pushurl ()
+ :class 'magit--git-variable:urls
+ :scope 'magit--read-remote-scope
+ :variable "remote.%s.pushurl"
+ :multi-value t
+ :history-key 'magit-remote.<remote>.*url
+ :seturl-arg "--push")
+
+(transient-define-infix magit-remote.<remote>.push ()
+ :class 'magit--git-variable
+ :scope 'magit--read-remote-scope
+ :variable "remote.%s.push")
+
+(transient-define-infix magit-remote.<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
--- /dev/null
+;;; magit-repos.el --- listing repositories -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements support for listing repositories. This
+;; includes getting a Lisp list of known repositories as well as a
+;; mode for listing repositories in a buffer.
+
+;;; Code:
+
+(require 'magit-core)
+
+(declare-function magit-status-setup-buffer "magit-status" (directory))
+
+(defvar x-stretch-cursor)
+
+;;; Options
+
+(defcustom magit-repository-directories nil
+ "List of directories that are or contain Git repositories.
+
+Each element has the form (DIRECTORY . DEPTH). DIRECTORY has
+to be a directory or a directory file-name, a string. DEPTH,
+an integer, specifies the maximum depth to look for Git
+repositories. If it is 0, then only add DIRECTORY itself.
+
+This option controls which repositories are being listed by
+`magit-list-repositories'. It also affects `magit-status'
+\(which see) in potentially surprising ways."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-essentials
+ :type '(repeat (cons directory (integer :tag "Depth"))))
+
+(defgroup magit-repolist nil
+ "List repositories in a buffer."
+ :link '(info-link "(magit)Repository List")
+ :group 'magit-modes)
+
+(defcustom magit-repolist-mode-hook '(hl-line-mode)
+ "Hook run after entering Magit-Repolist mode."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-repolist
+ :type 'hook
+ :get 'magit-hook-custom-get
+ :options '(hl-line-mode))
+
+(defcustom magit-repolist-columns
+ '(("Name" 25 magit-repolist-column-ident nil)
+ ("Version" 25 magit-repolist-column-version nil)
+ ("B<U" 3 magit-repolist-column-unpulled-from-upstream
+ ((:right-align t)
+ (:help-echo "Upstream changes not in branch")))
+ ("B>U" 3 magit-repolist-column-unpushed-to-upstream
+ ((:right-align t)
+ (:help-echo "Local changes not in upstream")))
+ ("Path" 99 magit-repolist-column-path nil))
+ "List of columns displayed by `magit-list-repositories'.
+
+Each element has the form (HEADER WIDTH FORMAT PROPS).
+
+HEADER is the string displayed in the header. WIDTH is the width
+of the column. FORMAT is a function that is called with one
+argument, the repository identification (usually its basename),
+and with `default-directory' bound to the toplevel of its working
+tree. It has to return a string to be inserted or nil. PROPS is
+an alist that supports the keys `:right-align' and `:pad-right'.
+Some entries also use `:help-echo', but `tabulated-list' does not
+actually support that yet."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-repolist
+ :type `(repeat (list :tag "Column"
+ (string :tag "Header Label")
+ (integer :tag "Column Width")
+ (function :tag "Inserter Function")
+ (repeat :tag "Properties"
+ (list (choice :tag "Property"
+ (const :right-align)
+ (const :pad-right)
+ (symbol))
+ (sexp :tag "Value"))))))
+
+(defcustom magit-repolist-column-flag-alist
+ '((magit-untracked-files . "N")
+ (magit-unstaged-files . "U")
+ (magit-staged-files . "S"))
+ "Association list of predicates and flags for `magit-repolist-column-flag'.
+
+Each element is of the form (FUNCTION . FLAG). Each FUNCTION is
+called with no arguments, with `default-directory' bound to the
+top level of a repository working tree, until one of them returns
+a non-nil value. FLAG corresponding to that function is returned
+as the value of `magit-repolist-column-flag'."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-repolist
+ :type '(alist :key-type (function :tag "Predicate Function")
+ :value-type (string :tag "Flag")))
+
+;;; List Repositories
+;;;; Command
+;;;###autoload
+(defun magit-list-repositories ()
+ "Display a list of repositories.
+
+Use the options `magit-repository-directories' to control which
+repositories are displayed."
+ (interactive)
+ (if magit-repository-directories
+ (with-current-buffer (get-buffer-create "*Magit Repositories*")
+ (magit-repolist-mode)
+ (magit-repolist-refresh)
+ (tabulated-list-print)
+ (switch-to-buffer (current-buffer)))
+ (message "You need to customize `magit-repository-directories' %s"
+ "before you can list repositories")))
+
+;;;; Mode
+
+(defvar magit-repolist-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map tabulated-list-mode-map)
+ (define-key map (kbd "C-m") 'magit-repolist-status)
+ map)
+ "Local keymap for Magit-Repolist mode buffers.")
+
+(defun magit-repolist-status (&optional _button)
+ "Show the status for the repository at point."
+ (interactive)
+ (--if-let (tabulated-list-get-id)
+ (magit-status-setup-buffer (expand-file-name it))
+ (user-error "There is no repository at point")))
+
+(define-derived-mode magit-repolist-mode tabulated-list-mode "Repos"
+ "Major mode for browsing a list of Git repositories."
+ (setq-local x-stretch-cursor nil)
+ (setq tabulated-list-padding 0)
+ (setq tabulated-list-sort-key
+ (cons (or (car (assoc "Path" magit-repolist-columns))
+ (caar magit-repolist-columns))
+ nil))
+ (setq tabulated-list-format
+ (vconcat (mapcar (pcase-lambda (`(,title ,width ,_fn ,props))
+ (nconc (list title width t)
+ (-flatten props)))
+ magit-repolist-columns)))
+ (tabulated-list-init-header)
+ (add-hook 'tabulated-list-revert-hook 'magit-repolist-refresh nil t)
+ (setq imenu-prev-index-position-function
+ 'magit-imenu--repolist-prev-index-position-function)
+ (setq imenu-extract-index-name-function
+ 'magit-imenu--repolist-extract-index-name-function))
+
+(defun magit-repolist-refresh ()
+ (setq tabulated-list-entries
+ (mapcar (pcase-lambda (`(,id . ,path))
+ (let ((default-directory path))
+ (list path
+ (vconcat (--map (or (funcall (nth 2 it) id) "")
+ magit-repolist-columns)))))
+ (magit-list-repos-uniquify
+ (--map (cons (file-name-nondirectory (directory-file-name it))
+ it)
+ (magit-list-repos))))))
+
+;;;; Columns
+
+(defun magit-repolist-column-ident (id)
+ "Insert the identification of the repository.
+Usually this is just its basename."
+ id)
+
+(defun magit-repolist-column-path (_id)
+ "Insert the absolute path of the repository."
+ (abbreviate-file-name default-directory))
+
+(defun magit-repolist-column-version (_id)
+ "Insert a description of the repository's `HEAD' revision."
+ (when-let ((v (or (magit-git-string "describe" "--tags" "--dirty")
+ ;; If there are no tags, use the date in MELPA format.
+ (magit-git-string "show" "--no-patch" "--format=%cd-g%h"
+ "--date=format:%Y%m%d.%H%M"))))
+ (save-match-data
+ (when (string-match "-dirty\\'" v)
+ (magit--put-face (1+ (match-beginning 0)) (length v) 'error v))
+ (if (and v (string-match "\\`[0-9]" v))
+ (concat " " v)
+ v))))
+
+(defun magit-repolist-column-branch (_id)
+ "Insert the current branch."
+ (magit-get-current-branch))
+
+(defun magit-repolist-column-upstream (_id)
+ "Insert the upstream branch of the current branch."
+ (magit-get-upstream-branch))
+
+(defun magit-repolist-column-flag (_id)
+ "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-unpulled-from-upstream (_id)
+ "Insert number of upstream commits not in the current branch."
+ (--when-let (magit-get-upstream-branch)
+ (let ((n (cadr (magit-rev-diff-count "HEAD" it))))
+ (magit--propertize-face
+ (number-to-string n) (if (> n 0) 'bold 'shadow)))))
+
+(defun magit-repolist-column-unpulled-from-pushremote (_id)
+ "Insert number of commits in the push branch but not the current branch."
+ (--when-let (magit-get-push-branch nil t)
+ (let ((n (cadr (magit-rev-diff-count "HEAD" it))))
+ (magit--propertize-face
+ (number-to-string n) (if (> n 0) 'bold 'shadow)))))
+
+(defun magit-repolist-column-unpushed-to-upstream (_id)
+ "Insert number of commits in the current branch but not its upstream."
+ (--when-let (magit-get-upstream-branch)
+ (let ((n (car (magit-rev-diff-count "HEAD" it))))
+ (magit--propertize-face
+ (number-to-string n) (if (> n 0) 'bold 'shadow)))))
+
+(defun magit-repolist-column-unpushed-to-pushremote (_id)
+ "Insert number of commits in the current branch but not its push branch."
+ (--when-let (magit-get-push-branch nil t)
+ (let ((n (car (magit-rev-diff-count "HEAD" it))))
+ (magit--propertize-face
+ (number-to-string n) (if (> n 0) 'bold 'shadow)))))
+
+(defun magit-repolist-column-branches (_id)
+ "Insert number of branches."
+ (let ((n (length (magit-list-local-branches))))
+ (magit--propertize-face (number-to-string n) (if (> n 1) 'bold 'shadow))))
+
+(defun magit-repolist-column-stashes (_id)
+ "Insert number of stashes."
+ (let ((n (length (magit-list-stashes))))
+ (magit--propertize-face (number-to-string n) (if (> n 0) 'bold 'shadow))))
+
+;;; Read Repository
+
+(defun magit-read-repository (&optional read-directory-name)
+ "Read a Git repository in the minibuffer, with completion.
+
+The completion choices are the basenames of top-levels of
+repositories found in the directories specified by option
+`magit-repository-directories'. In case of name conflicts
+the basenames are prefixed with the name of the respective
+parent directories. The returned value is the actual path
+to the selected repository.
+
+If READ-DIRECTORY-NAME is non-nil or no repositories can be
+found based on the value of `magit-repository-directories',
+then read an arbitrary directory using `read-directory-name'
+instead."
+ (if-let ((repos (and (not read-directory-name)
+ magit-repository-directories
+ (magit-repos-alist))))
+ (let ((reply (magit-completing-read "Git repository" repos)))
+ (file-name-as-directory
+ (or (cdr (assoc reply repos))
+ (if (file-directory-p reply)
+ (expand-file-name reply)
+ (user-error "Not a repository or a directory: %s" reply)))))
+ (file-name-as-directory
+ (read-directory-name "Git repository: "
+ (or (magit-toplevel) default-directory)))))
+
+(defun magit-list-repos ()
+ (cl-mapcan (pcase-lambda (`(,dir . ,depth))
+ (magit-list-repos-1 dir depth))
+ magit-repository-directories))
+
+(defun magit-list-repos-1 (directory depth)
+ (cond ((file-readable-p (expand-file-name ".git" directory))
+ (list (file-name-as-directory directory)))
+ ((and (> depth 0) (magit-file-accessible-directory-p directory))
+ (--mapcat (and (file-directory-p it)
+ (magit-list-repos-1 it (1- depth)))
+ (directory-files directory t
+ directory-files-no-dot-files-regexp t)))))
+
+(defun magit-list-repos-uniquify (alist)
+ (let (result (dict (make-hash-table :test 'equal)))
+ (dolist (a (delete-dups alist))
+ (puthash (car a) (cons (cdr a) (gethash (car a) dict)) dict))
+ (maphash
+ (lambda (key value)
+ (if (= (length value) 1)
+ (push (cons key (car value)) result)
+ (setq result
+ (append result
+ (magit-list-repos-uniquify
+ (--map (cons (concat
+ key "\\"
+ (file-name-nondirectory
+ (directory-file-name
+ (substring it 0 (- (1+ (length key)))))))
+ it)
+ value))))))
+ dict)
+ result))
+
+(defun magit-repos-alist ()
+ (magit-list-repos-uniquify
+ (--map (cons (file-name-nondirectory (directory-file-name it)) it)
+ (magit-list-repos))))
+
+;;; _
+(provide 'magit-repos)
+;;; magit-repos.el ends here
--- /dev/null
+;;; magit-reset.el --- reset fuctionality -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements reset commands.
+
+;;; Code:
+
+(require 'magit)
+
+;;;###autoload (autoload 'magit-reset "magit" nil t)
+(transient-define-prefix magit-reset ()
+ "Reset the `HEAD', index and/or worktree to a previous state."
+ :man-page "git-reset"
+ ["Reset"
+ ("m" "mixed (HEAD and index)" magit-reset-mixed)
+ ("s" "soft (HEAD only)" magit-reset-soft)
+ ("h" "hard (HEAD, index and files)" magit-reset-hard)
+ ("k" "keep (HEAD and index, keeping uncommitted)" magit-reset-keep)
+ ("i" "index (only)" magit-reset-index)
+ ("w" "worktree (only)" magit-reset-worktree)
+ ""
+ ("f" "a file" magit-file-checkout)])
+
+;;;###autoload
+(defun magit-reset-mixed (commit)
+ "Reset the `HEAD' and index to COMMIT, but not the working tree.
+\n(git reset --mixed COMMIT)"
+ (interactive (list (magit-reset-read-branch-or-commit "Reset %s to")))
+ (magit-reset-internal "--mixed" commit))
+
+;;;###autoload
+(defun magit-reset-soft (commit)
+ "Reset the `HEAD' to COMMIT, but not the index and working tree.
+\n(git reset --soft REVISION)"
+ (interactive (list (magit-reset-read-branch-or-commit "Soft reset %s to")))
+ (magit-reset-internal "--soft" commit))
+
+;;;###autoload
+(defun magit-reset-hard (commit)
+ "Reset the `HEAD', index, and working tree to COMMIT.
+\n(git reset --hard REVISION)"
+ (interactive (list (magit-reset-read-branch-or-commit
+ (concat (magit--propertize-face "Hard" 'bold)
+ " reset %s to"))))
+ (magit-reset-internal "--hard" commit))
+
+;;;###autoload
+(defun magit-reset-keep (commit)
+ "Reset the `HEAD' and index to COMMIT, while keeping uncommitted changes.
+\n(git reset --keep REVISION)"
+ (interactive (list (magit-reset-read-branch-or-commit "Reset %s to")))
+ (magit-reset-internal "--keep" commit))
+
+;;;###autoload
+(defun magit-reset-index (commit)
+ "Reset the index to COMMIT.
+Keep the `HEAD' and working tree as-is, so if COMMIT refers to the
+head this effectively unstages all changes.
+\n(git reset COMMIT .)"
+ (interactive (list (magit-read-branch-or-commit "Reset index to")))
+ (magit-reset-internal nil commit "."))
+
+;;;###autoload
+(defun magit-reset-worktree (commit)
+ "Reset the worktree to COMMIT.
+Keep the `HEAD' and index as-is."
+ (interactive (list (magit-read-branch-or-commit "Reset worktree to")))
+ (magit-wip-commit-before-change nil " before reset")
+ (magit-with-temp-index commit nil
+ (magit-call-git "checkout-index" "--all" "--force"))
+ (magit-wip-commit-after-apply nil " after reset")
+ (magit-refresh))
+
+;;;###autoload
+(defun magit-reset-quickly (commit &optional hard)
+ "Reset the `HEAD' and index to COMMIT, and possibly the working tree.
+With a prefix argument reset the working tree otherwise don't.
+\n(git reset --mixed|--hard COMMIT)"
+ (interactive (list (magit-reset-read-branch-or-commit
+ (if current-prefix-arg
+ (concat (magit--propertize-face "Hard" 'bold)
+ " reset %s to")
+ "Reset %s to"))
+ current-prefix-arg))
+ (magit-reset-internal (if hard "--hard" "--mixed") commit))
+
+(defun magit-reset-read-branch-or-commit (prompt)
+ "Prompt for and return a ref to reset HEAD to.
+
+PROMPT is a format string, where either the current branch name
+or \"detached head\" will be substituted for %s."
+ (magit-read-branch-or-commit
+ (format prompt (or (magit-get-current-branch) "detached head"))))
+
+(defun magit-reset-internal (arg commit &optional path)
+ (when (and (not (member arg '("--hard" nil)))
+ (equal (magit-rev-parse commit)
+ (magit-rev-parse "HEAD~")))
+ (with-temp-buffer
+ (magit-git-insert "show" "-s" "--format=%B" "HEAD")
+ (when git-commit-major-mode
+ (funcall git-commit-major-mode))
+ (git-commit-setup-font-lock)
+ (git-commit-save-message)))
+ (let ((cmd (if (and (equal commit "HEAD") (not arg)) "unstage" "reset")))
+ (magit-wip-commit-before-change nil (concat " before " cmd))
+ (magit-run-git "reset" arg commit "--" path)
+ (when (equal cmd "unstage")
+ (magit-wip-commit-after-apply nil " after unstage"))))
+
+;;; _
+(provide 'magit-reset)
+;;; magit-reset.el ends here
--- /dev/null
+;;; magit-section.el --- Sections for read-only buffers -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Package-Requires: ((emacs "25.1") (dash "20200524"))
+;; Keywords: tools
+;; Homepage: https://github.com/magit/magit
+
+;; Magit-Section is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit-Section is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This package implements the main user interface of Magit — the
+;; collapsible sections that make up its buffers. This package used
+;; to be distributed as part of Magit but now it can also be used by
+;; other packages that have nothing to do with Magit or Git.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'dash)
+(require 'eieio)
+(require 'seq)
+(require 'subr-x)
+
+(eval-when-compile (require 'benchmark))
+
+;;; Hooks
+
+(defvar magit-section-movement-hook nil
+ "Hook run by `magit-section-goto'.
+That function in turn is used by all section movement commands.")
+
+(defvar magit-section-highlight-hook
+ '(magit-section-highlight
+ magit-section-highlight-selection)
+ "Functions used to highlight the current section.
+Each function is run with the current section as only argument
+until one of them returns non-nil.")
+
+(defvar magit-section-unhighlight-hook nil
+ "Functions used to unhighlight the previously current section.
+Each function is run with the current section as only argument
+until one of them returns non-nil. Most sections are properly
+unhighlighted without requiring a specialized unhighlighter,
+diff-related sections being the only exception.")
+
+(defvar magit-section-set-visibility-hook
+ '(magit-section-cached-visibility)
+ "Hook used to set the initial visibility of a section.
+Stop at the first function that returns non-nil. The returned
+value should be `show', `hide' or nil. If no function returns
+non-nil, determine the visibility as usual, i.e. use the
+hardcoded section specific default (see `magit-insert-section').")
+
+(defvar magit-section-goto-successor-hook nil
+ "Hook used to go to the same section as was current before a refresh.
+This is only used if the standard mechanism for doing so did not
+succeed.")
+
+;;; Options
+
+(defgroup magit-section nil
+ "Expandable sections."
+ :link '(info-link "(magit)Sections")
+ :group 'extensions)
+
+(defcustom magit-section-show-child-count t
+ "Whether to append the number of children to section headings.
+This only applies to sections for which doing so makes sense."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-section
+ :type 'boolean)
+
+(defcustom magit-section-cache-visibility t
+ "Whether to cache visibility of sections.
+
+Sections always retain their visibility state when they are being
+recreated during a refresh. But if a section disappears and then
+later reappears again, then this option controls whether this is
+the case.
+
+If t, then cache the visibility of all sections. If a list of
+section types, then only do so for matching sections. If nil,
+then don't do so for any sections."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-section
+ :type '(choice (const :tag "Don't cache visibility" nil)
+ (const :tag "Cache visibility of all sections" t)
+ (repeat :tag "Cache visibility for section types" symbol)))
+
+(defcustom magit-section-initial-visibility-alist
+ '((stashes . hide))
+ "Alist controlling the initial visibility of sections.
+
+Each element maps a section type or lineage to the initial
+visibility state for such sections. The state has to be one of
+`show' or `hide', or a function that returns one of these symbols.
+A function is called with the section as the only argument.
+
+Use the command `magit-describe-section' to determine a section's
+lineage or type. The vector in the output is the section lineage
+and the type is the first element of that vector. Wildcards can
+be used, see `magit-section-match'.
+
+Currently this option is only used to override hardcoded defaults,
+but in the future it will also be used set the defaults.
+
+An entry whose key is `magit-status-initial-section' specifies
+the visibility of the section `magit-status-goto-initial-section'
+jumps to. This does not only override defaults, but also other
+entries of this alist."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-section
+ :type '(alist :key-type (sexp :tag "Section type/lineage")
+ :value-type (choice (const hide)
+ (const show)
+ function)))
+
+(defcustom magit-section-visibility-indicator
+ (if (window-system)
+ '(magit-fringe-bitmap> . magit-fringe-bitmapv)
+ '("…" . t))
+ "Whether and how to indicate that a section can be expanded/collapsed.
+
+If nil, then don't show any indicators.
+Otherwise the value has to have one of these two forms:
+
+\(EXPANDABLE-BITMAP . COLLAPSIBLE-BITMAP)
+
+ Both values have to be variables whose values are fringe
+ bitmaps. In this case every section that can be expanded or
+ collapsed gets an indicator in the left fringe.
+
+ To provide extra padding around the indicator, set
+ `left-fringe-width' in `magit-mode-hook'.
+
+\(STRING . BOOLEAN)
+
+ In this case STRING (usually an ellipsis) is shown at the end
+ of the heading of every collapsed section. Expanded sections
+ get no indicator. The cdr controls whether the appearance of
+ these ellipsis take section highlighting into account. Doing
+ so might potentially have an impact on performance, while not
+ doing so is kinda ugly."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-section
+ :type '(choice (const :tag "No indicators" nil)
+ (cons :tag "Use +- fringe indicators"
+ (const magit-fringe-bitmap+)
+ (const magit-fringe-bitmap-))
+ (cons :tag "Use >v fringe indicators"
+ (const magit-fringe-bitmap>)
+ (const magit-fringe-bitmapv))
+ (cons :tag "Use bold >v fringe indicators)"
+ (const magit-fringe-bitmap-bold>)
+ (const magit-fringe-bitmap-boldv))
+ (cons :tag "Use custom fringe indicators"
+ (variable :tag "Expandable bitmap variable")
+ (variable :tag "Collapsible bitmap variable"))
+ (cons :tag "Use ellipses at end of headings"
+ (string :tag "Ellipsis" "…")
+ (choice :tag "Use face kludge"
+ (const :tag "Yes (potentially slow)" t)
+ (const :tag "No (kinda ugly)" nil)))))
+
+(defcustom magit-keep-region-overlay nil
+ "Whether to keep the region overlay when there is a valid selection.
+
+By default Magit removes the regular region overlay if, and only
+if, that region constitutes a valid selection as understood by
+Magit commands. Otherwise it does not remove that overlay, and
+the region looks like it would in other buffers.
+
+There are two types of such valid selections: hunk-internal
+regions and regions that select two or more sibling sections.
+In such cases Magit removes the region overlay and instead
+highlights a slightly larger range. All text (for hunk-internal
+regions) or the headings of all sections (for sibling selections)
+that are inside that range (not just inside the region) are acted
+on by commands such as the staging command. This buffer range
+begins at the beginning of the line on which the region begins
+and ends at the end of the line on which the region ends.
+
+Because Magit acts on this larger range and not the region, it is
+actually quite important to visualize that larger range. If we
+don't do that, then one might think that these commands act on
+the region instead. If you want to *also* visualize the region,
+then set this option to t. But please note that when the region
+does *not* constitute a valid selection, then the region is
+*always* visualized as usual, and that it is usually under such
+circumstances that you want to use a non-magit command to act on
+the region.
+
+Besides keeping the region overlay, setting this option to t also
+causes all face properties, except for `:foreground', to be
+ignored for the faces used to highlight headings of selected
+sections. This avoids the worst conflicts that result from
+displaying the region and the selection overlays at the same
+time. We are not interested in dealing with other conflicts.
+In fact we *already* provide a way to avoid all of these
+conflicts: *not* changing the value of this option.
+
+It should be clear by now that we consider it a mistake to set
+this to display the region when the Magit selection is also
+visualized, but since it has been requested a few times and
+because it doesn't cost much to offer this option we do so.
+However that might change. If the existence of this option
+starts complicating other things, then it will be removed."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-section
+ :type 'boolean)
+
+(defcustom magit-section-disable-line-numbers t
+ "In Magit buffers, whether to disable modes that display line numbers.
+
+Some users who turn on `global-display-line-numbers-mode' (or
+`global-nlinum-mode' or `global-linum-mode') expect line numbers
+to be displayed everywhere except in Magit buffers. Other users
+do not expect Magit buffers to be treated differently. At least
+in theory users in the first group should not use the global mode,
+but that ship has sailed, thus this option."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-section
+ :type 'boolean)
+
+;;; Faces
+
+(defgroup magit-section-faces nil
+ "Faces used by Magit-Section."
+ :group 'magit-section
+ :group 'faces)
+
+(defface magit-section-highlight
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "grey95")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :background "grey20"))
+ "Face for highlighting the current section."
+ :group 'magit-section-faces)
+
+(defface magit-section-heading
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :foreground "DarkGoldenrod4"
+ :weight bold)
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :foreground "LightGoldenrod2"
+ :weight bold))
+ "Face for section headings."
+ :group 'magit-section-faces)
+
+(defface magit-section-secondary-heading
+ `((t ,@(and (>= emacs-major-version 27) '(:extend t))
+ :weight bold))
+ "Face for section headings of some secondary headings."
+ :group 'magit-section-faces)
+
+(defface magit-section-heading-selection
+ `((((class color) (background light))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :foreground "salmon4")
+ (((class color) (background dark))
+ ,@(and (>= emacs-major-version 27) '(:extend t))
+ :foreground "LightSalmon3"))
+ "Face for selected section headings."
+ :group 'magit-section-faces)
+
+;;; Classes
+
+(defvar magit--current-section-hook nil
+ "Internal variable used for `magit-describe-section'.")
+
+(defvar magit--section-type-alist nil)
+
+(defclass magit-section ()
+ ((keymap :initform nil :allocation :class)
+ (type :initform nil :initarg :type)
+ (value :initform nil :initarg :value)
+ (start :initform nil :initarg :start)
+ (content :initform nil)
+ (end :initform nil)
+ (hidden :initform nil)
+ (washer :initform nil)
+ (process :initform nil)
+ (heading-highlight-face :initform nil)
+ (inserter :initform (symbol-value 'magit--current-section-hook))
+ (parent :initform nil :initarg :parent)
+ (children :initform nil)))
+
+;;; Mode
+
+(defvar symbol-overlay-inhibit-map)
+
+(defvar magit-section-mode-map
+ (let ((map (make-keymap)))
+ (suppress-keymap map t)
+ (define-key map (kbd "C-i") 'magit-section-toggle)
+ (define-key map [C-tab] 'magit-section-cycle)
+ (define-key map [M-tab] 'magit-section-cycle)
+ ;; [backtab] is the most portable binding for Shift+Tab.
+ (define-key map [backtab] 'magit-section-cycle-global)
+ (define-key map (kbd "^") 'magit-section-up)
+ (define-key map (kbd "p") 'magit-section-backward)
+ (define-key map (kbd "n") 'magit-section-forward)
+ (define-key map (kbd "M-p") 'magit-section-backward-sibling)
+ (define-key map (kbd "M-n") 'magit-section-forward-sibling)
+ (define-key map "1" 'magit-section-show-level-1)
+ (define-key map "2" 'magit-section-show-level-2)
+ (define-key map "3" 'magit-section-show-level-3)
+ (define-key map "4" 'magit-section-show-level-4)
+ (define-key map (kbd "M-1") 'magit-section-show-level-1-all)
+ (define-key map (kbd "M-2") 'magit-section-show-level-2-all)
+ (define-key map (kbd "M-3") 'magit-section-show-level-3-all)
+ (define-key map (kbd "M-4") 'magit-section-show-level-4-all)
+ map))
+
+(define-derived-mode magit-section-mode special-mode "Magit-Sections"
+ "Parent major mode from which major modes with Magit-like sections inherit.
+
+Magit-Section is documented in info node `(magit-section)'."
+ :group 'magit-section
+ (buffer-disable-undo)
+ (setq truncate-lines t)
+ (setq buffer-read-only t)
+ (setq-local line-move-visual t) ; see #1771
+ ;; Turn off syntactic font locking, but not by setting
+ ;; `font-lock-defaults' because that would enable font locking, and
+ ;; not all magit plugins may be ready for that (see #3950).
+ (setq-local font-lock-syntactic-face-function #'ignore)
+ (setq show-trailing-whitespace nil)
+ (setq-local symbol-overlay-inhibit-map t)
+ (setq list-buffers-directory (abbreviate-file-name default-directory))
+ ;; (hack-dir-local-variables-non-file-buffer)
+ (make-local-variable 'text-property-default-nonsticky)
+ (push (cons 'keymap t) text-property-default-nonsticky)
+ (add-hook 'post-command-hook #'magit-section-update-highlight t t)
+ (add-hook 'deactivate-mark-hook #'magit-section-update-highlight t t)
+ (setq-local redisplay-highlight-region-function
+ 'magit-section--highlight-region)
+ (setq-local redisplay-unhighlight-region-function
+ 'magit-section--unhighlight-region)
+ (when magit-section-disable-line-numbers
+ (when (bound-and-true-p global-linum-mode)
+ (linum-mode -1))
+ (when (and (fboundp 'nlinum-mode)
+ (bound-and-true-p global-nlinum-mode))
+ (nlinum-mode -1))
+ (when (and (fboundp 'display-line-numbers-mode)
+ (bound-and-true-p global-display-line-numbers-mode))
+ (display-line-numbers-mode -1)))
+ (when (fboundp 'magit-preserve-section-visibility-cache)
+ (add-hook 'kill-buffer-hook #'magit-preserve-section-visibility-cache)))
+
+;;; Core
+
+(defvar-local magit-root-section nil
+ "The root section in the current buffer.
+All other sections are descendants of this section. The value
+of this variable is set by `magit-insert-section' and you should
+never modify it.")
+(put 'magit-root-section 'permanent-local t)
+
+(defun magit-current-section ()
+ "Return the section at point."
+ (or (get-text-property (point) 'magit-section) magit-root-section))
+
+(defun magit-section-ident (section)
+ "Return an unique identifier for SECTION.
+The return value has the form ((TYPE . VALUE)...)."
+ (with-slots (type value parent) section
+ (cons (cons type
+ (cond ((eieio-object-p value)
+ (magit-section-ident-value value))
+ ((not (memq type '(unpulled unpushed))) value)
+ ((string-match-p "@{upstream}" value) value)
+ ;; Unfortunately Git chokes on "@{push}" when
+ ;; the value of `push.default' does not allow a
+ ;; 1:1 mapping. Arbitrary commands may consult
+ ;; the section value so we cannot use "@{push}".
+ ;; But `unpushed' and `unpulled' sections should
+ ;; keep their identity when switching branches
+ ;; so we have to use another value here.
+ ((string-match-p "\\`\\.\\." value) "..@{push}")
+ (t "@{push}..")))
+ (and parent
+ (magit-section-ident parent)))))
+
+(cl-defgeneric magit-section-ident-value (value)
+ "Return a constant representation of VALUE.
+VALUE is the value of a `magit-section' object. If that is an
+object itself, then that is not suitable to be used to identify
+the section because two objects may represent the same thing but
+not be equal. If possible a method should be added for such
+objects, which returns a value that is equal. Otherwise the
+catch-all method is used, which just returns the argument
+itself.")
+
+(cl-defmethod magit-section-ident-value (arg) arg)
+
+(defun magit-get-section (ident &optional root)
+ "Return the section identified by IDENT.
+IDENT has to be a list as returned by `magit-section-ident'.
+If optional ROOT is non-nil, then search in that section tree
+instead of in the one whose root `magit-root-section' is."
+ (setq ident (reverse ident))
+ (let ((section (or root magit-root-section)))
+ (when (eq (car (pop ident))
+ (oref section type))
+ (while (and ident
+ (pcase-let* ((`(,type . ,value) (car ident))
+ (value (magit-section-ident-value value)))
+ (setq section
+ (cl-find-if (lambda (section)
+ (and (eq (oref section type) type)
+ (equal (magit-section-ident-value
+ (oref section value))
+ value)))
+ (oref section children)))))
+ (pop ident))
+ section)))
+
+(defun magit-section-lineage (section)
+ "Return the lineage of SECTION.
+The return value has the form (TYPE...)."
+ (cons (oref section type)
+ (when-let ((parent (oref section parent)))
+ (magit-section-lineage parent))))
+
+(defvar magit-insert-section--current nil "For internal use only.")
+(defvar magit-insert-section--parent nil "For internal use only.")
+(defvar magit-insert-section--oldroot nil "For internal use only.")
+
+;;; Commands
+;;;; Movement
+
+(defun magit-section-forward ()
+ "Move to the beginning of the next visible section."
+ (interactive)
+ (if (eobp)
+ (user-error "No next section")
+ (let ((section (magit-current-section)))
+ (if (oref section parent)
+ (let ((next (and (not (oref section hidden))
+ (not (= (oref section end)
+ (1+ (point))))
+ (car (oref section children)))))
+ (while (and section (not next))
+ (unless (setq next (car (magit-section-siblings section 'next)))
+ (setq section (oref section parent))))
+ (if next
+ (magit-section-goto next)
+ (user-error "No next section")))
+ (magit-section-goto 1)))))
+
+(defun magit-section-backward ()
+ "Move to the beginning of the current or the previous visible section.
+When point is at the beginning of a section then move to the
+beginning of the previous visible section. Otherwise move to
+the beginning of the current section."
+ (interactive)
+ (if (bobp)
+ (user-error "No previous section")
+ (let ((section (magit-current-section)) children)
+ (cond
+ ((and (= (point)
+ (1- (oref section end)))
+ (setq children (oref section children)))
+ (magit-section-goto (car (last children))))
+ ((and (oref section parent)
+ (not (= (point)
+ (oref section start))))
+ (magit-section-goto section))
+ (t
+ (let ((prev (car (magit-section-siblings section 'prev))))
+ (if prev
+ (while (and (not (oref prev hidden))
+ (setq children (oref prev children)))
+ (setq prev (car (last children))))
+ (setq prev (oref section parent)))
+ (cond (prev
+ (magit-section-goto prev))
+ ((oref section parent)
+ (user-error "No previous section"))
+ ;; Eob special cases.
+ ((not (get-text-property (1- (point)) 'invisible))
+ (magit-section-goto -1))
+ (t
+ (goto-char (previous-single-property-change
+ (1- (point)) 'invisible))
+ (forward-line -1)
+ (magit-section-goto (magit-current-section))))))))))
+
+(defun magit-section-up ()
+ "Move to the beginning of the parent section."
+ (interactive)
+ (--if-let (oref (magit-current-section) parent)
+ (magit-section-goto it)
+ (user-error "No parent section")))
+
+(defun magit-section-forward-sibling ()
+ "Move to the beginning of the next sibling section.
+If there is no next sibling section, then move to the parent."
+ (interactive)
+ (let ((current (magit-current-section)))
+ (if (oref current parent)
+ (--if-let (car (magit-section-siblings current 'next))
+ (magit-section-goto it)
+ (magit-section-forward))
+ (magit-section-goto 1))))
+
+(defun magit-section-backward-sibling ()
+ "Move to the beginning of the previous sibling section.
+If there is no previous sibling section, then move to the parent."
+ (interactive)
+ (let ((current (magit-current-section)))
+ (if (oref current parent)
+ (--if-let (car (magit-section-siblings current 'prev))
+ (magit-section-goto it)
+ (magit-section-backward))
+ (magit-section-goto -1))))
+
+(defun magit-section-goto (arg)
+ (if (integerp arg)
+ (progn (forward-line arg)
+ (setq arg (magit-current-section)))
+ (goto-char (oref arg start)))
+ (run-hook-with-args 'magit-section-movement-hook arg))
+
+(defun magit-section-set-window-start (section)
+ "Ensure the beginning of SECTION is visible."
+ (unless (pos-visible-in-window-p (oref section end))
+ (set-window-start (selected-window) (oref section start))))
+
+(defmacro magit-define-section-jumper (name heading type &optional value)
+ "Define an interactive function to go some section.
+Together TYPE and VALUE identify the section.
+HEADING is the displayed heading of the section."
+ (declare (indent defun))
+ `(defun ,name (&optional expand) ,(format "\
+Jump to the section \"%s\".
+With a prefix argument also expand it." heading)
+ (interactive "P")
+ (--if-let (magit-get-section
+ (cons (cons ',type ,value)
+ (magit-section-ident magit-root-section)))
+ (progn (goto-char (oref it start))
+ (when expand
+ (with-local-quit (magit-section-show it))
+ (recenter 0)))
+ (message ,(format "Section \"%s\" wasn't found" heading)))))
+
+;;;; Visibility
+
+(defun magit-section-show (section)
+ "Show the body of the current section."
+ (interactive (list (magit-current-section)))
+ (oset section hidden nil)
+ (magit-section--maybe-wash section)
+ (when-let ((beg (oref section content)))
+ (remove-overlays beg (oref section end) 'invisible t))
+ (magit-section-maybe-update-visibility-indicator section)
+ (magit-section-maybe-cache-visibility section)
+ (dolist (child (oref section children))
+ (if (oref child hidden)
+ (magit-section-hide child)
+ (magit-section-show child))))
+
+(defun magit-section--maybe-wash (section)
+ (when-let ((washer (oref section washer)))
+ (oset section washer nil)
+ (let ((inhibit-read-only t)
+ (magit-insert-section--parent section)
+ (content (oref section content)))
+ (save-excursion
+ (if (and content (< content (oref section end)))
+ (funcall washer section) ; already partially washed (hunk)
+ (goto-char (oref section end))
+ (oset section content (point-marker))
+ (funcall washer)
+ (oset section end (point-marker)))))
+ (magit-section-update-highlight)))
+
+(defun magit-section-hide (section)
+ "Hide the body of the current section."
+ (interactive (list (magit-current-section)))
+ (if (eq section magit-root-section)
+ (user-error "Cannot hide root section")
+ (oset section hidden t)
+ (when-let ((beg (oref section content)))
+ (let ((end (oref section end)))
+ (remove-overlays beg end 'invisible t)
+ (let ((o (make-overlay beg end)))
+ (overlay-put o 'evaporate t)
+ (overlay-put o 'invisible t))))
+ (magit-section-maybe-update-visibility-indicator section)
+ (magit-section-maybe-cache-visibility section)))
+
+(defun magit-section-toggle (section)
+ "Toggle visibility of the body of the current section."
+ (interactive (list (magit-current-section)))
+ (if (eq section magit-root-section)
+ (user-error "Cannot hide root section")
+ (goto-char (oref section start))
+ (if (oref section hidden)
+ (magit-section-show section)
+ (magit-section-hide section))))
+
+(defun magit-section-toggle-children (section)
+ "Toggle visibility of bodies of children of the current section."
+ (interactive (list (magit-current-section)))
+ (goto-char (oref section start))
+ (let* ((children (oref section children))
+ (show (--any-p (oref it hidden) children)))
+ (dolist (c children)
+ (oset c hidden show)))
+ (magit-section-show section))
+
+(defun magit-section-show-children (section &optional depth)
+ "Recursively show the bodies of children of the current section.
+With a prefix argument show children that deep and hide deeper
+children."
+ (interactive (list (magit-current-section)))
+ (magit-section-show-children-1 section depth)
+ (magit-section-show section))
+
+(defun magit-section-show-children-1 (section &optional depth)
+ (dolist (child (oref section children))
+ (oset child hidden nil)
+ (if depth
+ (if (> depth 0)
+ (magit-section-show-children-1 child (1- depth))
+ (magit-section-hide child))
+ (magit-section-show-children-1 child))))
+
+(defun magit-section-hide-children (section)
+ "Recursively hide the bodies of children of the current section."
+ (interactive (list (magit-current-section)))
+ (mapc 'magit-section-hide (oref section children)))
+
+(defun magit-section-show-headings (section)
+ "Recursively show headings of children of the current section.
+Only show the headings, previously shown text-only bodies are
+hidden."
+ (interactive (list (magit-current-section)))
+ (magit-section-show-headings-1 section)
+ (magit-section-show section))
+
+(defun magit-section-show-headings-1 (section)
+ (dolist (child (oref section children))
+ (oset child hidden nil)
+ (when (or (oref child children)
+ (not (oref child content)))
+ (magit-section-show-headings-1 child))))
+
+(defun magit-section-cycle (section)
+ "Cycle visibility of current section and its children."
+ (interactive (list (magit-current-section)))
+ (goto-char (oref section start))
+ (if (oref section hidden)
+ (progn (magit-section-show section)
+ (magit-section-hide-children section))
+ (let ((children (oref section children)))
+ (cond ((and (--any-p (oref it hidden) children)
+ (--any-p (oref it children) children))
+ (magit-section-show-headings section))
+ ((seq-some 'magit-section-hidden-body children)
+ (magit-section-show-children section))
+ (t
+ (magit-section-hide section))))))
+
+(defun magit-section-cycle-global ()
+ "Cycle visibility of all sections in the current buffer."
+ (interactive)
+ (let ((children (oref magit-root-section children)))
+ (cond ((and (--any-p (oref it hidden) children)
+ (--any-p (oref it children) children))
+ (magit-section-show-headings magit-root-section))
+ ((seq-some 'magit-section-hidden-body children)
+ (magit-section-show-children magit-root-section))
+ (t
+ (mapc 'magit-section-hide children)))))
+
+(defun magit-section-hidden-body (section &optional pred)
+ (--if-let (oref section children)
+ (funcall (or pred '-any-p) 'magit-section-hidden-body it)
+ (and (oref section content)
+ (oref section hidden))))
+
+(defun magit-section-invisible-p (section)
+ "Return t if the SECTION's body is invisible.
+When the body of an ancestor of SECTION is collapsed then
+SECTION's body (and heading) obviously cannot be visible."
+ (or (oref section hidden)
+ (--when-let (oref section parent)
+ (magit-section-invisible-p it))))
+
+(defun magit-section-show-level (level)
+ "Show surrounding sections up to LEVEL.
+If LEVEL is negative, show up to the absolute value.
+Sections at higher levels are hidden."
+ (if (< level 0)
+ (let ((s (magit-current-section)))
+ (setq level (- level))
+ (while (> (1- (length (magit-section-ident s))) level)
+ (setq s (oref s parent))
+ (goto-char (oref s start)))
+ (magit-section-show-children magit-root-section (1- level)))
+ (cl-do* ((s (magit-current-section)
+ (oref s parent))
+ (i (1- (length (magit-section-ident s)))
+ (cl-decf i)))
+ ((cond ((< i level) (magit-section-show-children s (- level i 1)) t)
+ ((= i level) (magit-section-hide s) t))
+ (magit-section-goto s)))))
+
+(defun magit-section-show-level-1 ()
+ "Show surrounding sections on first level."
+ (interactive)
+ (magit-section-show-level 1))
+
+(defun magit-section-show-level-1-all ()
+ "Show all sections on first level."
+ (interactive)
+ (magit-section-show-level -1))
+
+(defun magit-section-show-level-2 ()
+ "Show surrounding sections up to second level."
+ (interactive)
+ (magit-section-show-level 2))
+
+(defun magit-section-show-level-2-all ()
+ "Show all sections up to second level."
+ (interactive)
+ (magit-section-show-level -2))
+
+(defun magit-section-show-level-3 ()
+ "Show surrounding sections up to third level."
+ (interactive)
+ (magit-section-show-level 3))
+
+(defun magit-section-show-level-3-all ()
+ "Show all sections up to third level."
+ (interactive)
+ (magit-section-show-level -3))
+
+(defun magit-section-show-level-4 ()
+ "Show surrounding sections up to fourth level."
+ (interactive)
+ (magit-section-show-level 4))
+
+(defun magit-section-show-level-4-all ()
+ "Show all sections up to fourth level."
+ (interactive)
+ (magit-section-show-level -4))
+
+;;;; Auxiliary
+
+(defun magit-describe-section-briefly (section &optional ident)
+ "Show information about the section at point.
+With a prefix argument show the section identity instead of the
+section lineage. This command is intended for debugging purposes."
+ (interactive (list (magit-current-section) current-prefix-arg))
+ (let ((str (format "#<%s %S %S %s-%s%s>"
+ (eieio-object-class section)
+ (let ((val (oref section value)))
+ (cond ((stringp val)
+ (substring-no-properties val))
+ ((and (eieio-object-p val)
+ (fboundp 'cl-prin1-to-string))
+ (cl-prin1-to-string val))
+ (t
+ val)))
+ (if ident
+ (magit-section-ident section)
+ (apply #'vector (magit-section-lineage section)))
+ (when-let ((m (oref section start)))
+ (marker-position m))
+ (if-let ((m (oref section content)))
+ (format "[%s-]" (marker-position m))
+ "")
+ (when-let ((m (oref section end)))
+ (marker-position m)))))
+ (if (called-interactively-p 'any)
+ (message "%s" str)
+ str)))
+
+(cl-defmethod cl-print-object ((section magit-section) stream)
+ "Print `magit-describe-section' result of SECTION."
+ ;; Used by debug and edebug as of Emacs 26.
+ (princ (magit-describe-section-briefly section) stream))
+
+(defun magit-describe-section (section &optional interactive-p)
+ "Show information about the section at point."
+ (interactive (list (magit-current-section) t))
+ (let ((inserter-section section))
+ (while (and inserter-section (not (oref inserter-section inserter)))
+ (setq inserter-section (oref inserter-section parent)))
+ (when (and inserter-section (oref inserter-section inserter))
+ (setq section inserter-section)))
+ (pcase (oref section inserter)
+ (`((,hook ,fun) . ,src-src)
+ (help-setup-xref `(magit-describe-section ,section) interactive-p)
+ (with-help-window (help-buffer)
+ (with-current-buffer standard-output
+ (insert (format-message
+ "%s\n is inserted by `%s'\n from `%s'"
+ (magit-describe-section-briefly section)
+ (make-text-button (symbol-name fun) nil
+ :type 'help-function
+ 'help-args (list fun))
+ (make-text-button (symbol-name hook) nil
+ :type 'help-variable
+ 'help-args (list hook))))
+ (pcase-dolist (`(,hook ,fun) src-src)
+ (insert (format-message
+ ",\n called by `%s'\n from `%s'"
+ (make-text-button (symbol-name fun) nil
+ :type 'help-function
+ 'help-args (list fun))
+ (make-text-button (symbol-name hook) nil
+ :type 'help-variable
+ 'help-args (list hook)))))
+ (insert ".\n\n")
+ (insert
+ (format-message
+ "`%s' is "
+ (make-text-button (symbol-name fun) nil
+ :type 'help-function 'help-args (list fun))))
+ (describe-function-1 fun))))
+ (_ (message "%s, inserter unknown"
+ (magit-describe-section-briefly section)))))
+
+;;; Match
+
+(cl-defun magit-section-match
+ (condition &optional (section (magit-current-section)))
+ "Return t if SECTION matches CONDITION.
+
+SECTION defaults to the section at point. If SECTION is not
+specified and there also is no section at point, then return
+nil.
+
+CONDITION can take the following forms:
+ (CONDITION...) matches if any of the CONDITIONs matches.
+ [CLASS...] matches if the section's class is the same
+ as the first CLASS or a subclass of that;
+ the section's parent class matches the
+ second CLASS; and so on.
+ [* CLASS...] matches sections that match [CLASS...] and
+ also recursively all their child sections.
+ CLASS matches if the section's class is the same
+ as CLASS or a subclass of that; regardless
+ of the classes of the parent sections.
+
+Each CLASS should be a class symbol, identifying a class that
+derives from `magit-section'. For backward compatibility CLASS
+can also be a \"type symbol\". A section matches such a symbol
+if the value of its `type' slot is `eq'. If a type symbol has
+an entry in `magit--section-type-alist', then a section also
+matches that type if its class is a subclass of the class that
+corresponds to the type as per that alist.
+
+Note that it is not necessary to specify the complete section
+lineage as printed by `magit-describe-section-briefly', unless
+of course you want to be that precise."
+ (and section (magit-section-match-1 condition section)))
+
+(defun magit-section-match-1 (condition section)
+ (cl-assert condition)
+ (and section
+ (if (listp condition)
+ (--first (magit-section-match-1 it section) condition)
+ (magit-section-match-2 (if (symbolp condition)
+ (list condition)
+ (cl-coerce condition 'list))
+ section))))
+
+(defun magit-section-match-2 (condition section)
+ (if (eq (car condition) '*)
+ (or (magit-section-match-2 (cdr condition) section)
+ (when-let ((parent (oref section parent)))
+ (magit-section-match-2 condition parent)))
+ (and (let ((c (car condition)))
+ (if (class-p c)
+ (cl-typep section c)
+ (if-let ((class (cdr (assq c magit--section-type-alist))))
+ (cl-typep section class)
+ (eq (oref section type) c))))
+ (or (not (setq condition (cdr condition)))
+ (when-let ((parent (oref section parent)))
+ (magit-section-match-2 condition parent))))))
+
+(defun magit-section-value-if (condition &optional section)
+ "If the section at point matches CONDITION, then return its value.
+
+If optional SECTION is non-nil then test whether that matches
+instead. If there is no section at point and SECTION is nil,
+then return nil. If the section does not match, then return
+nil.
+
+See `magit-section-match' for the forms CONDITION can take."
+ (when-let ((section (or section (magit-current-section))))
+ (and (magit-section-match condition section)
+ (oref section value))))
+
+(defmacro magit-section-when (condition &rest body)
+ "If the section at point matches CONDITION, evaluate BODY.
+
+If the section matches, then evaluate BODY forms sequentially
+with `it' bound to the section and return the value of the last
+form. If there are no BODY forms, then return the value of the
+section. If the section does not match or if there is no section
+at point, then return nil.
+
+See `magit-section-match' for the forms CONDITION can take."
+ (declare (obsolete
+ "instead use `magit-section-match' or `magit-section-value-if'."
+ "Magit 2.90.0")
+ (indent 1)
+ (debug (sexp body)))
+ `(--when-let (magit-current-section)
+ ;; Quoting CONDITION here often leads to double-quotes, which
+ ;; isn't an issue because `magit-section-match-1' implicitly
+ ;; deals with that. We shouldn't force users of this function
+ ;; to not quote CONDITION because that would needlessly break
+ ;; backward compatibility.
+ (when (magit-section-match ',condition it)
+ ,@(or body '((oref it value))))))
+
+(defmacro magit-section-case (&rest clauses)
+ "Choose among clauses on the type of the section at point.
+
+Each clause looks like (CONDITION BODY...). The type of the
+section is compared against each CONDITION; the BODY forms of the
+first match are evaluated sequentially and the value of the last
+form is returned. Inside BODY the symbol `it' is bound to the
+section at point. If no clause succeeds or if there is no
+section at point, return nil.
+
+See `magit-section-match' for the forms CONDITION can take.
+Additionally a CONDITION of t is allowed in the final clause, and
+matches if no other CONDITION match, even if there is no section
+at point."
+ (declare (indent 0)
+ (debug (&rest (sexp body))))
+ `(let* ((it (magit-current-section)))
+ (cond ,@(mapcar (lambda (clause)
+ `(,(or (eq (car clause) t)
+ `(and it
+ (magit-section-match-1 ',(car clause) it)))
+ ,@(cdr clause)))
+ clauses))))
+
+(defun magit-section-match-assoc (section alist)
+ "Return the value associated with SECTION's type or lineage in ALIST."
+ (seq-some (pcase-lambda (`(,key . ,val))
+ (and (magit-section-match-1 key section) val))
+ alist))
+
+;;; Create
+
+(defvar magit-insert-section-hook nil
+ "Hook run after `magit-insert-section's BODY.
+Avoid using this hook and only ever do so if you know
+what you are doing and are sure there is no other way.")
+
+(defmacro magit-insert-section (&rest args)
+ "Insert a section at point.
+
+Create a section object of type CLASS, storing VALUE in its
+`value' slot, and insert the section at point. CLASS is a
+subclass of `magit-section' or has the form `(eval FORM)', in
+which case FORM is evaluated at runtime and should return a
+subclass. In other places a sections class is oftern referred
+to as its \"type\".
+
+Many commands behave differently depending on the class of the
+current section and sections of a certain class can have their
+own keymap, which is specified using the `keymap' class slot.
+The value of that slot should be a variable whose value is a
+keymap.
+
+For historic reasons Magit and Forge in most cases use symbols
+as CLASS that don't actually identify a class and that lack the
+appropriate package prefix. This works due to some undocumented
+kludges, which are not available to other packages.
+
+When optional HIDE is non-nil collapse the section body by
+default, i.e. when first creating the section, but not when
+refreshing the buffer. Else expand it by default. This can be
+overwritten using `magit-section-set-visibility-hook'. When a
+section is recreated during a refresh, then the visibility of
+predecessor is inherited and HIDE is ignored (but the hook is
+still honored).
+
+BODY is any number of forms that actually insert the section's
+heading and body. Optional NAME, if specified, has to be a
+symbol, which is then bound to the object of the section being
+inserted.
+
+Before BODY is evaluated the `start' of the section object is set
+to the value of `point' and after BODY was evaluated its `end' is
+set to the new value of `point'; BODY is responsible for moving
+`point' forward.
+
+If it turns out inside BODY that the section is empty, then
+`magit-cancel-section' can be used to abort and remove all traces
+of the partially inserted section. This can happen when creating
+a section by washing Git's output and Git didn't actually output
+anything this time around.
+
+\(fn [NAME] (CLASS &optional VALUE HIDE) &rest BODY)"
+ (declare (indent defun)
+ (debug ([&optional symbolp]
+ (&or [("eval" form) &optional form form]
+ [symbolp &optional form form])
+ body)))
+ (let ((tp (cl-gensym "type"))
+ (s* (and (symbolp (car args))
+ (pop args)))
+ (s (cl-gensym "section")))
+ `(let* ((,tp ,(let ((type (nth 0 (car args))))
+ (if (eq (car-safe type) 'eval)
+ (cadr type)
+ `',type)))
+ (,s (funcall (if (class-p ,tp)
+ ,tp
+ (or (cdr (assq ,tp magit--section-type-alist))
+ 'magit-section))
+ :type
+ (or (and (class-p ,tp)
+ (car (rassq ,tp magit--section-type-alist)))
+ ,tp)
+ :value ,(nth 1 (car args))
+ :start (point-marker)
+ :parent magit-insert-section--parent)))
+ (oset ,s hidden
+ (let ((value (run-hook-with-args-until-success
+ 'magit-section-set-visibility-hook ,s)))
+ (if value
+ (eq value 'hide)
+ (let ((incarnation (and magit-insert-section--oldroot
+ (magit-get-section
+ (magit-section-ident ,s)
+ magit-insert-section--oldroot))))
+ (if incarnation
+ (oref incarnation hidden)
+ (let ((value (magit-section-match-assoc
+ ,s magit-section-initial-visibility-alist)))
+ (if value
+ (progn
+ (when (functionp value)
+ (setq value (funcall value ,s)))
+ (eq value 'hide))
+ ,(nth 2 (car args)))))))))
+ (let ((magit-insert-section--current ,s)
+ (magit-insert-section--parent ,s)
+ (magit-insert-section--oldroot
+ (or magit-insert-section--oldroot
+ (unless magit-insert-section--parent
+ (prog1 magit-root-section
+ (setq magit-root-section ,s))))))
+ (catch 'cancel-section
+ ,@(if s*
+ `((let ((,s* ,s))
+ ,@(cdr args)))
+ (cdr args))
+ ;; `magit-insert-section-hook' should *not* be run with
+ ;; `magit-run-section-hook' because it's a hook that runs
+ ;; on section insertion, not a section inserting hook.
+ (run-hooks 'magit-insert-section-hook)
+ (magit-insert-child-count ,s)
+ (set-marker-insertion-type (oref ,s start) t)
+ (let* ((end (oset ,s end (point-marker)))
+ (class-map (oref-default ,s keymap))
+ (magit-map (intern (format "magit-%s-section-map"
+ (oref ,s type))))
+ (forge-map (intern (format "forge-%s-section-map"
+ (oref ,s type))))
+ (map (or (and class-map (symbol-value class-map))
+ (and (boundp magit-map) (symbol-value magit-map))
+ (and (boundp forge-map) (symbol-value forge-map)))))
+ (save-excursion
+ (goto-char (oref ,s start))
+ (while (< (point) end)
+ (let ((next (or (next-single-property-change
+ (point) 'magit-section)
+ end)))
+ (unless (get-text-property (point) 'magit-section)
+ (put-text-property (point) next 'magit-section ,s)
+ (when map
+ (put-text-property (point) next 'keymap map)))
+ (goto-char next)))))
+ (if (eq ,s magit-root-section)
+ (let ((magit-section-cache-visibility nil))
+ (magit-section-show ,s))
+ (oset (oref ,s parent) children
+ (nconc (oref (oref ,s parent) children)
+ (list ,s)))))
+ ,s))))
+
+(defun magit-cancel-section ()
+ "Cancel inserting the section that is currently being inserted.
+Remove all traces of that section."
+ (when magit-insert-section--current
+ (if (not (oref magit-insert-section--current parent))
+ (insert "(empty)\n")
+ (delete-region (oref magit-insert-section--current start)
+ (point))
+ (setq magit-insert-section--current nil)
+ (throw 'cancel-section nil))))
+
+(defun magit-insert-heading (&rest args)
+ "Insert the heading for the section currently being inserted.
+
+This function should only be used inside `magit-insert-section'.
+
+When called without any arguments, then just set the `content'
+slot of the object representing the section being inserted to
+a marker at `point'. The section should only contain a single
+line when this function is used like this.
+
+When called with arguments ARGS, which have to be strings, or
+nil, then insert those strings at point. The section should not
+contain any text before this happens and afterwards it should
+again only contain a single line. If the `face' property is set
+anywhere inside any of these strings, then insert all of them
+unchanged. Otherwise use the `magit-section-heading' face for
+all inserted text.
+
+The `content' property of the section object is the end of the
+heading (which lasts from `start' to `content') and the beginning
+of the the body (which lasts from `content' to `end'). If the
+value of `content' is nil, then the section has no heading and
+its body cannot be collapsed. If a section does have a heading,
+then its height must be exactly one line, including a trailing
+newline character. This isn't enforced, you are responsible for
+getting it right. The only exception is that this function does
+insert a newline character if necessary."
+ (declare (indent defun))
+ (when args
+ (let ((heading (apply #'concat args)))
+ (insert (if (or (text-property-not-all 0 (length heading)
+ 'font-lock-face nil heading)
+ (text-property-not-all 0 (length heading)
+ 'face nil heading))
+ heading
+ (propertize heading 'font-lock-face 'magit-section-heading)))))
+ (unless (bolp)
+ (insert ?\n))
+ (when (fboundp 'magit-maybe-make-margin-overlay)
+ (magit-maybe-make-margin-overlay))
+ (oset magit-insert-section--current content (point-marker)))
+
+(defmacro magit-insert-section-body (&rest body)
+ "Use BODY to insert the section body, once the section is expanded.
+If the section is expanded when it is created, then this is
+like `progn'. Otherwise BODY isn't evaluated until the section
+is explicitly expanded."
+ (declare (indent 0))
+ (let ((f (cl-gensym))
+ (s (cl-gensym)))
+ `(let ((,f (lambda () ,@body))
+ (,s magit-insert-section--current))
+ (if (oref ,s hidden)
+ (oset ,s washer
+ (lambda ()
+ (funcall ,f)
+ (magit-section-maybe-remove-visibility-indicator ,s)))
+ (funcall ,f)))))
+
+(defun magit-insert-headers (hook)
+ (let* ((header-sections nil)
+ (magit-insert-section-hook
+ (cons (lambda ()
+ (push magit-insert-section--current
+ header-sections))
+ (if (listp magit-insert-section-hook)
+ magit-insert-section-hook
+ (list magit-insert-section-hook)))))
+ (magit-run-section-hook hook)
+ (when header-sections
+ (insert "\n")
+ ;; Make the first header into the parent of the rest.
+ (when (cdr header-sections)
+ (cl-callf nreverse header-sections)
+ (let* ((1st-header (pop header-sections))
+ (header-parent (oref 1st-header parent)))
+ (oset header-parent children (list 1st-header))
+ (oset 1st-header children header-sections)
+ (oset 1st-header content (oref (car header-sections) start))
+ (oset 1st-header end (oref (car (last header-sections)) end))
+ (dolist (sub-header header-sections)
+ (oset sub-header parent 1st-header)))))))
+
+(defun magit-insert-child-count (section)
+ "Modify SECTION's heading to contain number of child sections.
+
+If `magit-section-show-child-count' is non-nil and the SECTION
+has children and its heading ends with \":\", then replace that
+with \" (N)\", where N is the number of child sections.
+
+This function is called by `magit-insert-section' after that has
+evaluated its BODY. Admittedly that's a bit of a hack."
+ ;; This has to be fast, not pretty!
+ (let (content count)
+ (when (and magit-section-show-child-count
+ (setq count (length (oref section children)))
+ (> count 0)
+ (setq content (oref section content))
+ (eq (char-before (1- content)) ?:))
+ (save-excursion
+ (goto-char (- content 2))
+ (insert (format " (%s)" count))
+ (delete-char 1)))))
+
+;;; Highlight
+
+(defvar-local magit-section-highlight-overlays nil)
+(defvar-local magit-section-highlighted-section nil)
+(defvar-local magit-section-highlighted-sections nil)
+(defvar-local magit-section-unhighlight-sections nil)
+(defun magit-section-update-highlight ()
+ (let ((section (magit-current-section)))
+ (unless (eq section magit-section-highlighted-section)
+ (let ((inhibit-read-only t)
+ (deactivate-mark nil)
+ (selection (magit-region-sections)))
+ (mapc #'delete-overlay magit-section-highlight-overlays)
+ (setq magit-section-highlight-overlays nil)
+ (setq magit-section-unhighlight-sections
+ magit-section-highlighted-sections)
+ (setq magit-section-highlighted-sections nil)
+ (unless (eq section magit-root-section)
+ (run-hook-with-args-until-success
+ 'magit-section-highlight-hook section selection))
+ (dolist (s magit-section-unhighlight-sections)
+ (run-hook-with-args-until-success
+ 'magit-section-unhighlight-hook s selection))
+ (restore-buffer-modified-p nil)
+ (unless (eq magit-section-highlighted-section section)
+ (setq magit-section-highlighted-section
+ (and (not (oref section hidden))
+ section)))))
+ (magit-section-maybe-paint-visibility-ellipses)))
+
+(defun magit-section-highlight (section selection)
+ "Highlight SECTION and if non-nil all sections in SELECTION.
+This function works for any section but produces undesirable
+effects for diff related sections, which by default are
+highlighted using `magit-diff-highlight'. Return t."
+ (when-let ((face (oref section heading-highlight-face)))
+ (dolist (section (or selection (list section)))
+ (magit-section-make-overlay
+ (oref section start)
+ (or (oref section content)
+ (oref section end))
+ face)))
+ (cond (selection
+ (magit-section-make-overlay (oref (car selection) start)
+ (oref (car (last selection)) end)
+ 'magit-section-highlight)
+ (magit-section-highlight-selection nil selection))
+ (t
+ (magit-section-make-overlay (oref section start)
+ (oref section end)
+ 'magit-section-highlight)))
+ t)
+
+(defun magit-section-highlight-selection (_ selection)
+ "Highlight the section-selection region.
+If SELECTION is non-nil, then it is a list of sections selected by
+the region. The headings of these sections are then highlighted.
+
+This is a fallback for people who don't want to highlight the
+current section and therefore removed `magit-section-highlight'
+from `magit-section-highlight-hook'.
+
+This function is necessary to ensure that a representation of
+such a region is visible. If neither of these functions were
+part of the hook variable, then such a region would be
+invisible."
+ (when (and selection
+ (not (and (eq this-command 'mouse-drag-region))))
+ (dolist (section selection)
+ (magit-section-make-overlay (oref section start)
+ (or (oref section content)
+ (oref section end))
+ 'magit-section-heading-selection))
+ t))
+
+(defun magit-section-make-overlay (start end face)
+ ;; Yes, this doesn't belong here. But the alternative of
+ ;; spreading this hack across the code base is even worse.
+ (when (and magit-keep-region-overlay
+ (memq face '(magit-section-heading-selection
+ magit-diff-file-heading-selection
+ magit-diff-hunk-heading-selection)))
+ (setq face (list :foreground (face-foreground face))))
+ (let ((ov (make-overlay start end nil t)))
+ (overlay-put ov 'font-lock-face face)
+ (overlay-put ov 'evaporate t)
+ (push ov magit-section-highlight-overlays)
+ ov))
+
+(defun magit-section-goto-successor (section line char arg)
+ (let ((ident (magit-section-ident section)))
+ (--if-let (magit-get-section ident)
+ (let ((start (oref it start)))
+ (goto-char start)
+ (unless (eq it magit-root-section)
+ (ignore-errors
+ (forward-line line)
+ (forward-char char))
+ (unless (eq (magit-current-section) it)
+ (goto-char start))))
+ (or (run-hook-with-args-until-success
+ 'magit-section-goto-successor-hook section arg)
+ (goto-char (--if-let (magit-section-goto-successor-1 section)
+ (if (eq (oref it type) 'button)
+ (point-min)
+ (oref it start))
+ (point-min)))))))
+
+(defun magit-section-goto-successor-1 (section)
+ (or (--when-let (pcase (oref section type)
+ (`staged 'unstaged)
+ (`unstaged 'staged)
+ (`unpushed 'unpulled)
+ (`unpulled 'unpushed))
+ (magit-get-section `((,it) (status))))
+ (--when-let (car (magit-section-siblings section 'next))
+ (magit-get-section (magit-section-ident it)))
+ (--when-let (car (magit-section-siblings section 'prev))
+ (magit-get-section (magit-section-ident it)))
+ (--when-let (oref section parent)
+ (or (magit-get-section (magit-section-ident it))
+ (magit-section-goto-successor-1 it)))))
+
+;;; Region
+
+(defvar-local magit-section--region-overlays nil)
+
+(defun magit-section--delete-region-overlays ()
+ (mapc #'delete-overlay magit-section--region-overlays)
+ (setq magit-section--region-overlays nil))
+
+(defun magit-section--highlight-region (start end window rol)
+ (magit-section--delete-region-overlays)
+ (if (and (not magit-keep-region-overlay)
+ (or (magit-region-sections)
+ (run-hook-with-args-until-success 'magit-region-highlight-hook
+ (magit-current-section)))
+ (not (= (line-number-at-pos start)
+ (line-number-at-pos end)))
+ ;; (not (eq (car-safe last-command-event) 'mouse-movement))
+ )
+ (funcall (default-value 'redisplay-unhighlight-region-function) rol)
+ (funcall (default-value 'redisplay-highlight-region-function)
+ start end window rol)))
+
+(defun magit-section--unhighlight-region (rol)
+ (setq magit-section-highlighted-section nil)
+ (magit-section--delete-region-overlays)
+ (funcall (default-value 'redisplay-unhighlight-region-function) rol))
+
+;;; Visibility
+
+(defvar-local magit-section-visibility-cache nil)
+(put 'magit-section-visibility-cache 'permanent-local t)
+
+(defun magit-section-cached-visibility (section)
+ "Set SECTION's visibility to the cached value."
+ (cdr (assoc (magit-section-ident section)
+ magit-section-visibility-cache)))
+
+(cl-defun magit-section-cache-visibility
+ (&optional (section magit-insert-section--current))
+ ;; Emacs 25's `alist-get' lacks TESTFN.
+ (let* ((id (magit-section-ident section))
+ (elt (assoc id magit-section-visibility-cache))
+ (val (if (oref section hidden) 'hide 'show)))
+ (if elt
+ (setcdr elt val)
+ (push (cons id val) magit-section-visibility-cache))))
+
+(cl-defun magit-section-maybe-cache-visibility
+ (&optional (section magit-insert-section--current))
+ (when (or (eq magit-section-cache-visibility t)
+ (memq (oref section type)
+ magit-section-cache-visibility))
+ (magit-section-cache-visibility section)))
+
+(defun magit-section-maybe-update-visibility-indicator (section)
+ (when magit-section-visibility-indicator
+ (let ((beg (oref section start))
+ (cnt (oref section content))
+ (end (oref section end)))
+ (when (and cnt (or (not (= cnt end)) (oref section washer)))
+ (let ((eoh (save-excursion
+ (goto-char beg)
+ (line-end-position))))
+ (cond
+ ((symbolp (car-safe magit-section-visibility-indicator))
+ ;; It would make more sense to put the overlay only on the
+ ;; location we actually don't put it on, but then inserting
+ ;; before that location (while taking care not to mess with
+ ;; the overlay) would cause the fringe bitmap to disappear
+ ;; (but not other effects of the overlay).
+ (let ((ov (magit--overlay-at (1+ beg) 'magit-vis-indicator 'fringe)))
+ (unless ov
+ (setq ov (make-overlay (1+ beg) eoh))
+ (overlay-put ov 'evaporate t)
+ (overlay-put ov 'magit-vis-indicator 'fringe))
+ (overlay-put
+ ov 'before-string
+ (propertize "fringe" 'display
+ (list 'left-fringe
+ (if (oref section hidden)
+ (car magit-section-visibility-indicator)
+ (cdr magit-section-visibility-indicator))
+ 'fringe)))))
+ ((stringp (car-safe magit-section-visibility-indicator))
+ (let ((ov (magit--overlay-at (1- eoh) 'magit-vis-indicator 'eoh)))
+ (cond ((oref section hidden)
+ (unless ov
+ (setq ov (make-overlay (1- eoh) eoh))
+ (overlay-put ov 'evaporate t)
+ (overlay-put ov 'magit-vis-indicator 'eoh))
+ (overlay-put ov 'after-string
+ (car magit-section-visibility-indicator)))
+ (ov
+ (delete-overlay ov)))))))))))
+
+(defvar-local magit--ellipses-sections nil)
+
+(defun magit-section-maybe-paint-visibility-ellipses ()
+ ;; This is needed because we hide the body instead of "the body
+ ;; except the final newline and additionally the newline before
+ ;; the body"; otherwise we could use `buffer-invisibility-spec'.
+ (when (stringp (car-safe magit-section-visibility-indicator))
+ (let* ((sections (append magit--ellipses-sections
+ (setq magit--ellipses-sections
+ (or (magit-region-sections)
+ (list (magit-current-section))))))
+ (beg (--map (oref it start) sections))
+ (end (--map (oref it end) sections)))
+ (when (region-active-p)
+ ;; This ensures that the region face is removed from ellipses
+ ;; when the region becomes inactive, but fails to ensure that
+ ;; all ellipses within the active region use the region face,
+ ;; because the respective overlay has not yet been updated at
+ ;; this time. The magit-selection face is always applied.
+ (push (region-beginning) beg)
+ (push (region-end) end))
+ (setq beg (apply #'min beg))
+ (setq end (apply #'max end))
+ (dolist (ov (overlays-in beg end))
+ (when (eq (overlay-get ov 'magit-vis-indicator) 'eoh)
+ (overlay-put
+ ov 'after-string
+ (propertize
+ (car magit-section-visibility-indicator) 'font-lock-face
+ (let ((pos (overlay-start ov)))
+ (delq nil (nconc (--map (overlay-get it 'font-lock-face)
+ (overlays-at pos))
+ (list (get-char-property
+ pos 'font-lock-face))))))))))))
+
+(defun magit-section-maybe-remove-visibility-indicator (section)
+ (when (and magit-section-visibility-indicator
+ (= (oref section content)
+ (oref section end)))
+ (dolist (o (overlays-in (oref section start)
+ (save-excursion
+ (goto-char (oref section start))
+ (1+ (line-end-position)))))
+ (when (overlay-get o 'magit-vis-indicator)
+ (delete-overlay o)))))
+
+(defvar-local magit-section--opened-sections nil)
+
+(defun magit-section--open-temporarily (beg end)
+ (save-excursion
+ (goto-char beg)
+ (let ((section (magit-current-section)))
+ (while section
+ (let ((content (oref section content)))
+ (if (and (magit-section-invisible-p section)
+ (<= (or content (oref section start))
+ beg
+ (oref section end)))
+ (progn
+ (when content
+ (magit-section-show section)
+ (push section magit-section--opened-sections))
+ (setq section (oref section parent)))
+ (setq section nil))))))
+ (or (eq search-invisible t)
+ (not (isearch-range-invisible beg end))))
+
+(defun isearch-clean-overlays@magit-mode (fn)
+ (if (derived-mode-p 'magit-mode)
+ (let ((pos (point)))
+ (dolist (section magit-section--opened-sections)
+ (unless (<= (oref section content) pos (oref section end))
+ (magit-section-hide section)))
+ (setq magit-section--opened-sections nil))
+ (funcall fn)))
+
+(advice-add 'isearch-clean-overlays :around
+ 'isearch-clean-overlays@magit-mode)
+
+;;; Utilities
+
+(cl-defun magit-section-selected-p (section &optional (selection nil sselection))
+ (and (not (eq section magit-root-section))
+ (or (eq section (magit-current-section))
+ (memq section (if sselection
+ selection
+ (setq selection (magit-region-sections))))
+ (--when-let (oref section parent)
+ (magit-section-selected-p it selection)))))
+
+(defun magit-section-parent-value (section)
+ (when-let ((parent (oref section parent)))
+ (oref parent value)))
+
+(defun magit-section-siblings (section &optional direction)
+ "Return a list of the sibling sections of SECTION.
+
+If optional DIRECTION is `prev', then return siblings that come
+before SECTION. If it is `next', then return siblings that come
+after SECTION. For all other values, return all siblings
+excluding SECTION itself."
+ (when-let ((parent (oref section parent)))
+ (let ((siblings (oref parent children)))
+ (pcase direction
+ (`prev (cdr (member section (reverse siblings))))
+ (`next (cdr (member section siblings)))
+ (_ (remq section siblings))))))
+
+(defun magit-region-values (&optional condition multiple)
+ "Return a list of the values of the selected sections.
+
+Return the values that themselves would be returned by
+`magit-region-sections' (which see)."
+ (--map (oref it value)
+ (magit-region-sections condition multiple)))
+
+(defun magit-region-sections (&optional condition multiple)
+ "Return a list of the selected sections.
+
+When the region is active and constitutes a valid section
+selection, then return a list of all selected sections. This is
+the case when the region begins in the heading of a section and
+ends in the heading of the same section or in that of a sibling
+section. If optional MULTIPLE is non-nil, then the region cannot
+begin and end in the same section.
+
+When the selection is not valid, then return nil. In this case,
+most commands that can act on the selected sections will instead
+act on the section at point.
+
+When the region looks like it would in any other buffer then
+the selection is invalid. When the selection is valid then the
+region uses the `magit-section-highlight' face. This does not
+apply to diffs where things get a bit more complicated, but even
+here if the region looks like it usually does, then that's not
+a valid selection as far as this function is concerned.
+
+If optional CONDITION is non-nil, then the selection not only
+has to be valid; all selected sections additionally have to match
+CONDITION, or nil is returned. See `magit-section-match' for the
+forms CONDITION can take."
+ (when (region-active-p)
+ (let* ((rbeg (region-beginning))
+ (rend (region-end))
+ (sbeg (get-text-property rbeg 'magit-section))
+ (send (get-text-property rend 'magit-section)))
+ (when (and send
+ (not (eq send magit-root-section))
+ (not (and multiple (eq send sbeg))))
+ (let ((siblings (cons sbeg (magit-section-siblings sbeg 'next)))
+ sections)
+ (when (and (memq send siblings)
+ (magit-section-position-in-heading-p sbeg rbeg)
+ (magit-section-position-in-heading-p send rend))
+ (while siblings
+ (push (car siblings) sections)
+ (when (eq (pop siblings) send)
+ (setq siblings nil)))
+ (setq sections (nreverse sections))
+ (when (or (not condition)
+ (--all-p (magit-section-match condition it) sections))
+ sections)))))))
+
+(defun magit-section-position-in-heading-p (&optional section pos)
+ "Return t if POSITION is inside the heading of SECTION.
+POSITION defaults to point and SECTION defaults to the
+current section."
+ (unless section
+ (setq section (magit-current-section)))
+ (unless pos
+ (setq pos (point)))
+ (and section
+ (>= pos (oref section start))
+ (< pos (or (oref section content)
+ (oref section end)))
+ t))
+
+(defun magit-section-internal-region-p (&optional section)
+ "Return t if the region is active and inside SECTION's body.
+If optional SECTION is nil, use the current section."
+ (and (region-active-p)
+ (or section (setq section (magit-current-section)))
+ (let ((beg (get-text-property (region-beginning) 'magit-section)))
+ (and (eq beg (get-text-property (region-end) 'magit-section))
+ (eq beg section)))
+ (not (or (magit-section-position-in-heading-p section (region-beginning))
+ (magit-section-position-in-heading-p section (region-end))))
+ t))
+
+(defun magit-section--backward-protected ()
+ "Move to the beginning of the current or the previous visible section.
+Same as `magit-section-backward' but for non-interactive use.
+Suppress `magit-section-movement-hook', and return a boolean to
+indicate whether a section was found, instead of raising an error
+if not."
+ (condition-case nil
+ (let ((magit-section-movement-hook nil))
+ (magit-section-backward)
+ t)
+ (user-error nil)))
+
+(defun magit-section--backward-find (predicate)
+ "Move to the first previous section satisfying PREDICATE.
+PREDICATE does not take any parameter and should not move
+point."
+ (let (found)
+ (while (and (setq found (magit-section--backward-protected))
+ (not (funcall predicate))))
+ found))
+
+(defun magit-wash-sequence (function)
+ "Repeatedly call FUNCTION until it returns nil or eob is reached.
+FUNCTION has to move point forward or return nil."
+ (while (and (not (eobp)) (funcall function))))
+
+(defun magit-add-section-hook (hook function &optional at append local)
+ "Add to the value of section hook HOOK the function FUNCTION.
+
+Add FUNCTION at the beginning of the hook list unless optional
+APPEND is non-nil, in which case FUNCTION is added at the end.
+If FUNCTION already is a member, then move it to the new location.
+
+If optional AT is non-nil and a member of the hook list, then
+add FUNCTION next to that instead. Add before or after AT, or
+replace AT with FUNCTION depending on APPEND. If APPEND is the
+symbol `replace', then replace AT with FUNCTION. For any other
+non-nil value place FUNCTION right after AT. If nil, then place
+FUNCTION right before AT. If FUNCTION already is a member of the
+list but AT is not, then leave FUNCTION where ever it already is.
+
+If optional LOCAL is non-nil, then modify the hook's buffer-local
+value rather than its global value. This makes the hook local by
+copying the default value. That copy is then modified.
+
+HOOK should be a symbol. If HOOK is void, it is first set to nil.
+HOOK's value must not be a single hook function. FUNCTION should
+be a function that takes no arguments and inserts one or multiple
+sections at point, moving point forward. FUNCTION may choose not
+to insert its section(s), when doing so would not make sense. It
+should not be abused for other side-effects. To remove FUNCTION
+again use `remove-hook'."
+ (unless (boundp hook)
+ (error "Cannot add function to undefined hook variable %s" hook))
+ (unless (default-boundp hook)
+ (set-default hook nil))
+ (let ((value (if local
+ (if (local-variable-p hook)
+ (symbol-value hook)
+ (unless (local-variable-if-set-p hook)
+ (make-local-variable hook))
+ (copy-sequence (default-value hook)))
+ (default-value hook))))
+ (if at
+ (when (setq at (member at value))
+ (setq value (delq function value))
+ (cond ((eq append 'replace)
+ (setcar at function))
+ (append
+ (push function (cdr at)))
+ (t
+ (push (car at) (cdr at))
+ (setcar at function))))
+ (setq value (delq function value)))
+ (unless (member function value)
+ (setq value (if append
+ (append value (list function))
+ (cons function value))))
+ (when (eq append 'replace)
+ (setq value (delq at value)))
+ (if local
+ (set hook value)
+ (set-default hook value))))
+
+(defvar-local magit-disabled-section-inserters nil)
+
+(defun magit-disable-section-inserter (fn)
+ "Disable the section inserter FN in the current repository.
+It is only intended for use in \".dir-locals.el\" and
+\".dir-locals-2.el\". Also see info node `(magit)Per-Repository
+Configuration'."
+ (cl-pushnew fn magit-disabled-section-inserters))
+
+(put 'magit-disable-section-inserter 'safe-local-eval-function t)
+
+(defun magit-run-section-hook (hook &rest args)
+ "Run HOOK with ARGS, warning about invalid entries."
+ (let ((entries (symbol-value hook)))
+ (unless (listp entries)
+ (setq entries (list entries)))
+ (--when-let (-remove #'functionp entries)
+ (message "`%s' contains entries that are no longer valid.
+%s\nUsing standard value instead. Please re-configure hook variable."
+ hook
+ (mapconcat (lambda (sym) (format " `%s'" sym)) it "\n"))
+ (sit-for 5)
+ (setq entries (eval (car (get hook 'standard-value)))))
+ (dolist (entry entries)
+ (let ((magit--current-section-hook (cons (list hook entry)
+ magit--current-section-hook)))
+ (unless (memq entry magit-disabled-section-inserters)
+ (if (bound-and-true-p magit-refresh-verbose)
+ (let ((time (benchmark-elapse (apply entry args))))
+ (message " %-50s %s %s" entry time
+ (cond ((> time 0.03) "!!")
+ ((> time 0.01) "!")
+ (t ""))))
+ (apply entry args)))))))
+
+(cl-defun magit--overlay-at (pos prop &optional (val nil sval) testfn)
+ (cl-find-if (lambda (o)
+ (let ((p (overlay-properties o)))
+ (and (plist-member p prop)
+ (or (not sval)
+ (funcall (or testfn #'eql)
+ (plist-get p prop)
+ val)))))
+ (overlays-at pos t)))
+
+;;; _
+(provide 'magit-section)
+;;; magit-section.el ends here
--- /dev/null
+;;; magit-sequence.el --- history manipulation in Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2011-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; Support for Git commands that replay commits and help the user make
+;; changes along the way. Supports `cherry-pick', `revert', `rebase',
+;; `rebase--interactive' and `am'.
+
+;;; Code:
+
+(require 'magit)
+
+;; For `magit-rebase--todo'.
+(declare-function git-rebase-current-line "git-rebase" ())
+(eval-when-compile
+ (cl-pushnew 'action-type eieio--known-slot-names)
+ (cl-pushnew 'action eieio--known-slot-names)
+ (cl-pushnew 'action-options eieio--known-slot-names)
+ (cl-pushnew 'target eieio--known-slot-names))
+
+;;; Options
+;;;; Faces
+
+(defface magit-sequence-pick
+ '((t :inherit default))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+(defface magit-sequence-stop
+ '((((class color) (background light)) :foreground "DarkOliveGreen4")
+ (((class color) (background dark)) :foreground "DarkSeaGreen2"))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+(defface magit-sequence-part
+ '((((class color) (background light)) :foreground "Goldenrod4")
+ (((class color) (background dark)) :foreground "LightGoldenrod2"))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+(defface magit-sequence-head
+ '((((class color) (background light)) :foreground "SkyBlue4")
+ (((class color) (background dark)) :foreground "LightSkyBlue1"))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+(defface magit-sequence-drop
+ '((((class color) (background light)) :foreground "IndianRed")
+ (((class color) (background dark)) :foreground "IndianRed"))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+(defface magit-sequence-done
+ '((t :inherit magit-hash))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+(defface magit-sequence-onto
+ '((t :inherit magit-sequence-done))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+(defface magit-sequence-exec
+ '((t :inherit magit-hash))
+ "Face used in sequence sections."
+ :group 'magit-faces)
+
+;;; Common
+
+;;;###autoload
+(defun magit-sequencer-continue ()
+ "Resume the current cherry-pick or revert sequence."
+ (interactive)
+ (if (magit-sequencer-in-progress-p)
+ (if (magit-anything-unstaged-p t)
+ (user-error "Cannot continue due to unstaged changes")
+ (magit-run-git-sequencer
+ (if (magit-revert-in-progress-p) "revert" "cherry-pick") "--continue"))
+ (user-error "No cherry-pick or revert in progress")))
+
+;;;###autoload
+(defun magit-sequencer-skip ()
+ "Skip the stopped at commit during a cherry-pick or revert sequence."
+ (interactive)
+ (if (magit-sequencer-in-progress-p)
+ (progn (magit-call-git "reset" "--hard")
+ (magit-sequencer-continue))
+ (user-error "No cherry-pick or revert in progress")))
+
+;;;###autoload
+(defun magit-sequencer-abort ()
+ "Abort the current cherry-pick or revert sequence.
+This discards all changes made since the sequence started."
+ (interactive)
+ (if (magit-sequencer-in-progress-p)
+ (magit-run-git-sequencer
+ (if (magit-revert-in-progress-p) "revert" "cherry-pick") "--abort")
+ (user-error "No cherry-pick or revert in progress")))
+
+(defun magit-sequencer-in-progress-p ()
+ (or (magit-cherry-pick-in-progress-p)
+ (magit-revert-in-progress-p)))
+
+;;; Cherry-Pick
+
+(defvar magit-perl-executable "perl"
+ "The Perl executable.")
+
+;;;###autoload (autoload 'magit-cherry-pick "magit-sequence" nil t)
+(transient-define-prefix magit-cherry-pick ()
+ "Apply or transplant commits."
+ :man-page "git-cherry-pick"
+ :value '("--ff")
+ :incompatible '(("--ff" "-x"))
+ ["Arguments"
+ :if-not magit-sequencer-in-progress-p
+ (magit-cherry-pick:--mainline)
+ ("=s" magit-merge:--strategy)
+ ("-F" "Attempt fast-forward" "--ff")
+ ("-x" "Reference cherry in commit message" "-x")
+ ("-e" "Edit commit messages" ("-e" "--edit"))
+ ("-s" "Add Signed-off-by lines" ("-s" "--signoff"))
+ (5 magit:--gpg-sign)]
+ [:if-not magit-sequencer-in-progress-p
+ ["Apply here"
+ ("A" "Pick" magit-cherry-copy)
+ ("a" "Apply" magit-cherry-apply)
+ ("h" "Harvest" magit-cherry-harvest)]
+ ["Apply elsewhere"
+ ("d" "Donate" magit-cherry-donate)
+ ("n" "Spinout" magit-cherry-spinout)
+ ("s" "Spinoff" magit-cherry-spinoff)]]
+ ["Actions"
+ :if magit-sequencer-in-progress-p
+ ("A" "Continue" magit-sequencer-continue)
+ ("s" "Skip" magit-sequencer-skip)
+ ("a" "Abort" magit-sequencer-abort)])
+
+(transient-define-argument magit-cherry-pick:--mainline ()
+ :description "Replay merge relative to parent"
+ :class 'transient-option
+ :shortarg "-m"
+ :argument "--mainline="
+ :reader 'transient-read-number-N+)
+
+(defun magit-cherry-pick-read-args (prompt)
+ (list (or (nreverse (magit-region-values 'commit))
+ (magit-read-other-branch-or-commit prompt))
+ (transient-args 'magit-cherry-pick)))
+
+(defun magit--cherry-move-read-args (verb away fn)
+ (declare (indent defun))
+ (let ((commits (or (nreverse (magit-region-values 'commit))
+ (list (funcall (if away
+ 'magit-read-branch-or-commit
+ 'magit-read-other-branch-or-commit)
+ (format "%s cherry" (capitalize verb))))))
+ (current (magit-get-current-branch)))
+ (unless current
+ (user-error "Cannot %s cherries while HEAD is detached" verb))
+ (let ((reachable (magit-rev-ancestor-p (car commits) current))
+ (msg "Cannot %s cherries that %s reachable from HEAD"))
+ (pcase (list away reachable)
+ (`(nil t) (user-error msg verb "are"))
+ (`(t nil) (user-error msg verb "are not"))))
+ `(,commits
+ ,@(funcall fn commits)
+ ,(transient-args 'magit-cherry-pick))))
+
+(defun magit--cherry-spinoff-read-args (verb)
+ (magit--cherry-move-read-args verb t
+ (lambda (commits)
+ (magit-branch-read-args
+ (format "Create branch from %s cherries" (length commits))
+ (magit-get-upstream-branch)))))
+
+;;;###autoload
+(defun magit-cherry-copy (commits &optional args)
+ "Copy COMMITS from another branch onto the current branch.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then pick all of them,
+without prompting."
+ (interactive (magit-cherry-pick-read-args "Cherry-pick"))
+ (magit--cherry-pick commits args))
+
+;;;###autoload
+(defun magit-cherry-apply (commits &optional args)
+ "Apply the changes in COMMITS but do not commit them.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then apply all of them,
+without prompting."
+ (interactive (magit-cherry-pick-read-args "Apply changes from commit"))
+ (magit--cherry-pick commits (cons "--no-commit" (remove "--ff" args))))
+
+;;;###autoload
+(defun magit-cherry-harvest (commits branch &optional args)
+ "Move COMMITS from another BRANCH onto the current branch.
+Remove the COMMITS from BRANCH and stay on the current branch.
+If a conflict occurs, then you have to fix that and finish the
+process manually."
+ (interactive
+ (magit--cherry-move-read-args "harvest" nil
+ (lambda (commits)
+ (list (let ((branches (magit-list-containing-branches (car commits))))
+ (pcase (length branches)
+ (0 nil)
+ (1 (car branches))
+ (_ (magit-completing-read
+ (format "Remove %s cherries from branch" (length commits))
+ branches nil t))))))))
+ (magit--cherry-move commits branch (magit-get-current-branch) args nil t))
+
+;;;###autoload
+(defun magit-cherry-donate (commits branch &optional args)
+ "Move COMMITS from the current branch onto another existing BRANCH.
+Remove COMMITS from the current branch and stay on that branch.
+If a conflict occurs, then you have to fix that and finish the
+process manually."
+ (interactive
+ (magit--cherry-move-read-args "donate" t
+ (lambda (commits)
+ (list (magit-read-other-branch (format "Move %s cherries to branch"
+ (length commits)))))))
+ (magit--cherry-move commits (magit-get-current-branch) branch args))
+
+;;;###autoload
+(defun magit-cherry-spinout (commits branch start-point &optional args)
+ "Move COMMITS from the current branch onto a new BRANCH.
+Remove COMMITS from the current branch and stay on that branch.
+If a conflict occurs, then you have to fix that and finish the
+process manually."
+ (interactive (magit--cherry-spinoff-read-args "spinout"))
+ (magit--cherry-move commits (magit-get-current-branch) branch args
+ start-point))
+
+;;;###autoload
+(defun magit-cherry-spinoff (commits branch start-point &optional args)
+ "Move COMMITS from the current branch onto a new BRANCH.
+Remove COMMITS from the current branch and checkout BRANCH.
+If a conflict occurs, then you have to fix that and finish
+the process manually."
+ (interactive (magit--cherry-spinoff-read-args "spinoff"))
+ (magit--cherry-move commits (magit-get-current-branch) branch args
+ start-point t))
+
+(defun magit--cherry-move (commits src dst args
+ &optional start-point checkout-dst)
+ (let ((current (magit-get-current-branch)))
+ (unless (magit-branch-p dst)
+ (let ((magit-process-raise-error t))
+ (magit-call-git "branch" dst start-point))
+ (--when-let (magit-get-indirect-upstream-branch start-point)
+ (magit-call-git "branch" "--set-upstream-to" it dst)))
+ (unless (equal dst current)
+ (let ((magit-process-raise-error t))
+ (magit-call-git "checkout" dst)))
+ (if (not src) ; harvest only
+ (magit--cherry-pick commits args)
+ (let ((tip (car (last commits)))
+ (keep (concat (car commits) "^")))
+ (magit--cherry-pick commits args)
+ (set-process-sentinel
+ magit-this-process
+ (lambda (process event)
+ (when (memq (process-status process) '(exit signal))
+ (if (> (process-exit-status process) 0)
+ (magit-process-sentinel process event)
+ (process-put process 'inhibit-refresh t)
+ (magit-process-sentinel process event)
+ (cond
+ ((magit-rev-equal tip src)
+ (magit-call-git "update-ref"
+ "-m" (format "reset: moving to %s" keep)
+ (magit-ref-fullname src)
+ keep tip)
+ (if (not checkout-dst)
+ (magit-run-git "checkout" src)
+ (magit-refresh)))
+ (t
+ (magit-git "checkout" src)
+ (let ((process-environment process-environment))
+ (push (format "%s=%s -i -ne '/^pick (%s)/ or print'"
+ "GIT_SEQUENCE_EDITOR"
+ magit-perl-executable
+ (mapconcat #'magit-rev-abbrev commits "|"))
+ process-environment)
+ (magit-run-git-sequencer "rebase" "-i" keep))
+ (when checkout-dst
+ (set-process-sentinel
+ magit-this-process
+ (lambda (process event)
+ (when (memq (process-status process) '(exit signal))
+ (if (> (process-exit-status process) 0)
+ (magit-process-sentinel process event)
+ (process-put process 'inhibit-refresh t)
+ (magit-process-sentinel process event)
+ (magit-run-git "checkout" dst))))))))))))))))
+
+(defun magit--cherry-pick (commits args &optional revert)
+ (let ((command (if revert "revert" "cherry-pick")))
+ (when (stringp commits)
+ (setq commits (if (string-match-p "\\.\\." commits)
+ (split-string commits "\\.\\.")
+ (list commits))))
+ (magit-run-git-sequencer
+ (if revert "revert" "cherry-pick")
+ (pcase-let ((`(,merge ,non-merge)
+ (-separate 'magit-merge-commit-p commits)))
+ (cond
+ ((not merge)
+ (--remove (string-prefix-p "--mainline=" it) args))
+ (non-merge
+ (user-error "Cannot %s merge and non-merge commits at once"
+ command))
+ ((--first (string-prefix-p "--mainline=" it) args)
+ args)
+ (t
+ (cons (format "--mainline=%s"
+ (read-number "Replay merges relative to parent: "))
+ args))))
+ commits)))
+
+(defun magit-cherry-pick-in-progress-p ()
+ ;; .git/sequencer/todo does not exist when there is only one commit left.
+ (file-exists-p (magit-git-dir "CHERRY_PICK_HEAD")))
+
+;;; Revert
+
+;;;###autoload (autoload 'magit-revert "magit-sequence" nil t)
+(transient-define-prefix magit-revert ()
+ "Revert existing commits, with or without creating new commits."
+ :man-page "git-revert"
+ :value '("--edit")
+ ["Arguments"
+ :if-not magit-sequencer-in-progress-p
+ (magit-cherry-pick:--mainline)
+ ("-e" "Edit commit message" ("-e" "--edit"))
+ ("-E" "Don't edit commit message" "--no-edit")
+ ("=s" magit-merge:--strategy)
+ ("-s" "Add Signed-off-by lines" ("-s" "--signoff"))
+ (5 magit:--gpg-sign)]
+ ["Actions"
+ :if-not magit-sequencer-in-progress-p
+ ("V" "Revert commit(s)" magit-revert-and-commit)
+ ("v" "Revert changes" magit-revert-no-commit)]
+ ["Actions"
+ :if magit-sequencer-in-progress-p
+ ("V" "Continue" magit-sequencer-continue)
+ ("s" "Skip" magit-sequencer-skip)
+ ("a" "Abort" magit-sequencer-abort)])
+
+(defun magit-revert-read-args (prompt)
+ (list (or (magit-region-values 'commit)
+ (magit-read-branch-or-commit prompt))
+ (transient-args 'magit-revert)))
+
+;;;###autoload
+(defun magit-revert-and-commit (commit &optional args)
+ "Revert COMMIT by creating a new commit.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then revert all of them,
+without prompting."
+ (interactive (magit-revert-read-args "Revert commit"))
+ (magit--cherry-pick commit args t))
+
+;;;###autoload
+(defun magit-revert-no-commit (commit &optional args)
+ "Revert COMMIT by applying it in reverse to the worktree.
+Prompt for a commit, defaulting to the commit at point. If
+the region selects multiple commits, then revert all of them,
+without prompting."
+ (interactive (magit-revert-read-args "Revert changes"))
+ (magit--cherry-pick commit (cons "--no-commit" args) t))
+
+(defun magit-revert-in-progress-p ()
+ ;; .git/sequencer/todo does not exist when there is only one commit left.
+ (file-exists-p (magit-git-dir "REVERT_HEAD")))
+
+;;; Patch
+
+;;;###autoload (autoload 'magit-am "magit-sequence" nil t)
+(transient-define-prefix magit-am ()
+ "Apply patches received by email."
+ :man-page "git-am"
+ :value '("--3way")
+ ["Arguments"
+ :if-not magit-am-in-progress-p
+ ("-3" "Fall back on 3way merge" ("-3" "--3way"))
+ (magit-apply:-p)
+ ("-c" "Remove text before scissors line" ("-c" "--scissors"))
+ ("-k" "Inhibit removal of email cruft" ("-k" "--keep"))
+ ("-b" "Limit removal of email cruft" "--keep-non-patch")
+ ("-d" "Use author date as committer date" "--committer-date-is-author-date")
+ ("-D" "Use committer date as author date" "--ignore-date")
+ ("-s" "Add Signed-off-by lines" ("-s" "--signoff"))
+ (5 magit:--gpg-sign)]
+ ["Apply"
+ :if-not magit-am-in-progress-p
+ ("m" "maildir" magit-am-apply-maildir)
+ ("w" "patches" magit-am-apply-patches)
+ ("a" "plain patch" magit-patch-apply)]
+ ["Actions"
+ :if magit-am-in-progress-p
+ ("w" "Continue" magit-am-continue)
+ ("s" "Skip" magit-am-skip)
+ ("a" "Abort" magit-am-abort)])
+
+(defun magit-am-arguments ()
+ (transient-args 'magit-am))
+
+(transient-define-argument magit-apply:-p ()
+ :description "Remove leading slashes from paths"
+ :class 'transient-option
+ :argument "-p"
+ :reader 'transient-read-number-N+)
+
+;;;###autoload
+(defun magit-am-apply-patches (&optional files args)
+ "Apply the patches FILES."
+ (interactive (list (or (magit-region-values 'file)
+ (list (let ((default (magit-file-at-point)))
+ (read-file-name
+ (if default
+ (format "Apply patch (%s): " default)
+ "Apply patch: ")
+ nil default))))
+ (magit-am-arguments)))
+ (magit-run-git-sequencer "am" args "--"
+ (--map (magit-convert-filename-for-git
+ (expand-file-name it))
+ files)))
+
+;;;###autoload
+(defun magit-am-apply-maildir (&optional maildir args)
+ "Apply the patches from MAILDIR."
+ (interactive (list (read-file-name "Apply mbox or Maildir: ")
+ (magit-am-arguments)))
+ (magit-run-git-sequencer "am" args (magit-convert-filename-for-git
+ (expand-file-name maildir))))
+
+;;;###autoload
+(defun magit-am-continue ()
+ "Resume the current patch applying sequence."
+ (interactive)
+ (if (magit-am-in-progress-p)
+ (if (magit-anything-unstaged-p t)
+ (error "Cannot continue due to unstaged changes")
+ (magit-run-git-sequencer "am" "--continue"))
+ (user-error "Not applying any patches")))
+
+;;;###autoload
+(defun magit-am-skip ()
+ "Skip the stopped at patch during a patch applying sequence."
+ (interactive)
+ (if (magit-am-in-progress-p)
+ (magit-run-git-sequencer "am" "--skip")
+ (user-error "Not applying any patches")))
+
+;;;###autoload
+(defun magit-am-abort ()
+ "Abort the current patch applying sequence.
+This discards all changes made since the sequence started."
+ (interactive)
+ (if (magit-am-in-progress-p)
+ (magit-run-git "am" "--abort")
+ (user-error "Not applying any patches")))
+
+(defun magit-am-in-progress-p ()
+ (file-exists-p (magit-git-dir "rebase-apply/applying")))
+
+;;; Rebase
+
+;;;###autoload (autoload 'magit-rebase "magit-sequence" nil t)
+(transient-define-prefix magit-rebase ()
+ "Transplant commits and/or modify existing commits."
+ :man-page "git-rebase"
+ ["Arguments"
+ :if-not magit-rebase-in-progress-p
+ ("-k" "Keep empty commits" "--keep-empty")
+ ("-p" "Preserve merges" ("-p" "--preserve-merges"))
+ (7 magit-merge:--strategy)
+ (7 magit-merge:--strategy-option)
+ (7 "=X" magit-diff:--diff-algorithm :argument "-Xdiff-algorithm=")
+ ("-d" "Lie about committer date" "--committer-date-is-author-date")
+ ("-a" "Autosquash" "--autosquash")
+ ("-A" "Autostash" "--autostash")
+ ("-i" "Interactive" ("-i" "--interactive"))
+ ("-h" "Disable hooks" "--no-verify")
+ (7 magit-rebase:--exec)
+ (5 magit:--gpg-sign)
+ (5 "-r" "Rebase merges" "--rebase-merges=" magit-rebase-merges-select-mode)]
+ [:if-not magit-rebase-in-progress-p
+ :description (lambda ()
+ (format (propertize "Rebase %s onto" 'face 'transient-heading)
+ (propertize (or (magit-get-current-branch) "HEAD")
+ 'face 'magit-branch-local)))
+ ("p" magit-rebase-onto-pushremote)
+ ("u" magit-rebase-onto-upstream)
+ ("e" "elsewhere" magit-rebase-branch)]
+ ["Rebase"
+ :if-not magit-rebase-in-progress-p
+ [("i" "interactively" magit-rebase-interactive)
+ ("s" "a subset" magit-rebase-subset)]
+ [("m" "to modify a commit" magit-rebase-edit-commit)
+ ("w" "to reword a commit" magit-rebase-reword-commit)
+ ("k" "to remove a commit" magit-rebase-remove-commit)
+ ("f" "to autosquash" magit-rebase-autosquash)
+ (6 "t" "to change dates" magit-reshelve-since)]]
+ ["Actions"
+ :if magit-rebase-in-progress-p
+ ("r" "Continue" magit-rebase-continue)
+ ("s" "Skip" magit-rebase-skip)
+ ("e" "Edit" magit-rebase-edit)
+ ("a" "Abort" magit-rebase-abort)])
+
+(transient-define-argument magit-rebase:--exec ()
+ :description "Run command after commits"
+ :class 'transient-option
+ :shortarg "-x"
+ :argument "--exec="
+ :reader #'read-shell-command)
+
+(defun magit-rebase-merges-select-mode (&rest _ignore)
+ (magit-read-char-case nil t
+ (?n "[n]o-rebase-cousins" "no-rebase-cousins")
+ (?r "[r]ebase-cousins" "rebase-cousins")))
+
+(defun magit-rebase-arguments ()
+ (transient-args 'magit-rebase))
+
+(defun magit-git-rebase (target args)
+ (magit-run-git-sequencer "rebase" args target))
+
+;;;###autoload (autoload 'magit-rebase-onto-pushremote "magit-sequence" nil t)
+(transient-define-suffix magit-rebase-onto-pushremote (args)
+ "Rebase the current branch onto its push-remote branch.
+
+With a prefix argument or when the push-remote is either not
+configured or unusable, then let the user first configure the
+push-remote."
+ :if 'magit-get-current-branch
+ :description 'magit-pull--pushbranch-description
+ (interactive (list (magit-rebase-arguments)))
+ (pcase-let ((`(,branch ,remote)
+ (magit--select-push-remote "rebase onto that")))
+ (magit-git-rebase (concat remote "/" branch) args)))
+
+;;;###autoload (autoload 'magit-rebase-onto-upstream "magit-sequence" nil t)
+(transient-define-suffix magit-rebase-onto-upstream (args)
+ "Rebase the current branch onto its upstream branch.
+
+With a prefix argument or when the upstream is either not
+configured or unusable, then let the user first configure
+the upstream."
+ :if 'magit-get-current-branch
+ :description 'magit-rebase--upstream-description
+ (interactive (list (magit-rebase-arguments)))
+ (let* ((branch (or (magit-get-current-branch)
+ (user-error "No branch is checked out")))
+ (upstream (magit-get-upstream-branch branch)))
+ (when (or current-prefix-arg (not upstream))
+ (setq upstream
+ (magit-read-upstream-branch
+ branch (format "Set upstream of %s and rebase onto that" branch)))
+ (magit-set-upstream-branch branch upstream))
+ (magit-git-rebase upstream args)))
+
+(defun magit-rebase--upstream-description ()
+ (when-let ((branch (magit-get-current-branch)))
+ (or (magit-get-upstream-branch branch)
+ (let ((remote (magit-get "branch" branch "remote"))
+ (merge (magit-get "branch" branch "merge"))
+ (u (magit--propertize-face "@{upstream}" 'bold)))
+ (cond
+ ((magit--unnamed-upstream-p remote merge)
+ (concat u ", replacing unnamed"))
+ ((magit--valid-upstream-p remote merge)
+ (concat u ", replacing non-existent"))
+ ((or remote merge)
+ (concat u ", replacing invalid"))
+ (t
+ (concat u ", setting that")))))))
+
+;;;###autoload
+(defun magit-rebase-branch (target args)
+ "Rebase the current branch onto a branch read in the minibuffer.
+All commits that are reachable from `HEAD' but not from the
+selected branch TARGET are being rebased."
+ (interactive (list (magit-read-other-branch-or-commit "Rebase onto")
+ (magit-rebase-arguments)))
+ (message "Rebasing...")
+ (magit-git-rebase target args)
+ (message "Rebasing...done"))
+
+;;;###autoload
+(defun magit-rebase-subset (newbase start args)
+ "Rebase a subset of the current branch's history onto a new base.
+Rebase commits from START to `HEAD' onto NEWBASE.
+START has to be selected from a list of recent commits."
+ (interactive (list (magit-read-other-branch-or-commit
+ "Rebase subset onto" nil
+ (magit-get-upstream-branch))
+ nil
+ (magit-rebase-arguments)))
+ (if start
+ (progn (message "Rebasing...")
+ (magit-run-git-sequencer "rebase" "--onto" newbase start args)
+ (message "Rebasing...done"))
+ (magit-log-select
+ `(lambda (commit)
+ (magit-rebase-subset ,newbase (concat commit "^") (list ,@args)))
+ (concat "Type %p on a commit to rebase it "
+ "and commits above it onto " newbase ","))))
+
+(defvar magit-rebase-interactive-include-selected t)
+
+(defun magit-rebase-interactive-1
+ (commit args message &optional editor delay-edit-confirm noassert confirm)
+ (declare (indent 2))
+ (when commit
+ (if (eq commit :merge-base)
+ (setq commit (--if-let (magit-get-upstream-branch)
+ (magit-git-string "merge-base" it "HEAD")
+ nil))
+ (unless (magit-rev-ancestor-p commit "HEAD")
+ (user-error "%s isn't an ancestor of HEAD" commit))
+ (if (magit-commit-parents commit)
+ (when (or (not (eq this-command 'magit-rebase-interactive))
+ magit-rebase-interactive-include-selected)
+ (setq commit (concat commit "^")))
+ (setq args (cons "--root" args)))))
+ (when (and commit (not noassert))
+ (setq commit (magit-rebase-interactive-assert
+ commit delay-edit-confirm
+ (--some (string-prefix-p "--rebase-merges" it) args))))
+ (if (and commit (not confirm))
+ (let ((process-environment process-environment))
+ (when editor
+ (push (concat "GIT_SEQUENCE_EDITOR="
+ (if (functionp editor)
+ (funcall editor commit)
+ editor))
+ process-environment))
+ (magit-run-git-sequencer "rebase" "-i" args
+ (unless (member "--root" args) commit)))
+ (magit-log-select
+ `(lambda (commit)
+ ;; In some cases (currently just magit-rebase-remove-commit), "-c
+ ;; commentChar=#" is added to the global arguments for git. Ensure
+ ;; that the same happens when we chose the commit via
+ ;; magit-log-select, below.
+ (let ((magit-git-global-arguments (list ,@magit-git-global-arguments)))
+ (magit-rebase-interactive-1 commit (list ,@args)
+ ,message ,editor ,delay-edit-confirm ,noassert)))
+ message)))
+
+(defvar magit--rebase-published-symbol nil)
+(defvar magit--rebase-public-edit-confirmed nil)
+
+(defun magit-rebase-interactive-assert
+ (since &optional delay-edit-confirm rebase-merges)
+ (let* ((commit (magit-rebase--target-commit since))
+ (branches (magit-list-publishing-branches commit)))
+ (setq magit--rebase-public-edit-confirmed
+ (delete (magit-toplevel) magit--rebase-public-edit-confirmed))
+ (when (and branches
+ (or (not delay-edit-confirm)
+ ;; The user might have stopped at a published commit
+ ;; merely to add new commits *after* it. Try not to
+ ;; ask users whether they really want to edit public
+ ;; commits, when they don't actually intend to do so.
+ (not (--all-p (magit-rev-equal it commit) branches))))
+ (let ((m1 "Some of these commits have already been published to ")
+ (m2 ".\nDo you really want to modify them"))
+ (magit-confirm (or magit--rebase-published-symbol 'rebase-published)
+ (concat m1 "%s" m2)
+ (concat m1 "%i public branches" m2)
+ nil branches))
+ (push (magit-toplevel) magit--rebase-public-edit-confirmed)))
+ (if (and (magit-git-lines "rev-list" "--merges" (concat since "..HEAD"))
+ (not rebase-merges))
+ (magit-read-char-case "Proceed despite merge in rebase range? " nil
+ (?c "[c]ontinue" since)
+ (?s "[s]elect other" nil)
+ (?a "[a]bort" (user-error "Quit")))
+ since))
+
+(defun magit-rebase--target-commit (since)
+ (if (string-suffix-p "^" since)
+ ;; If SINCE is "REV^", then the user selected
+ ;; "REV", which is the first commit that will
+ ;; be replaced. (from^..to] <=> [from..to]
+ (substring since 0 -1)
+ ;; The "--root" argument is being used.
+ since))
+
+;;;###autoload
+(defun magit-rebase-interactive (commit args)
+ "Start an interactive rebase sequence."
+ (interactive (list (magit-commit-at-point)
+ (magit-rebase-arguments)))
+ (magit-rebase-interactive-1 commit args
+ "Type %p on a commit to rebase it and all commits above it,"
+ nil t))
+
+;;;###autoload
+(defun magit-rebase-autosquash (args)
+ "Combine squash and fixup commits with their intended targets."
+ (interactive (list (magit-rebase-arguments)))
+ (magit-rebase-interactive-1 :merge-base
+ (nconc (list "--autosquash" "--keep-empty") args)
+ "Type %p on a commit to squash into it and then rebase as necessary,"
+ "true" nil t))
+
+;;;###autoload
+(defun magit-rebase-edit-commit (commit args)
+ "Edit a single older commit using rebase."
+ (interactive (list (magit-commit-at-point)
+ (magit-rebase-arguments)))
+ (magit-rebase-interactive-1 commit args
+ "Type %p on a commit to edit it,"
+ (apply-partially #'magit-rebase--perl-editor 'edit)
+ t))
+
+;;;###autoload
+(defun magit-rebase-reword-commit (commit args)
+ "Reword a single older commit using rebase."
+ (interactive (list (magit-commit-at-point)
+ (magit-rebase-arguments)))
+ (magit-rebase-interactive-1 commit args
+ "Type %p on a commit to reword its message,"
+ (apply-partially #'magit-rebase--perl-editor 'reword)))
+
+;;;###autoload
+(defun magit-rebase-remove-commit (commit args)
+ "Remove a single older commit using rebase."
+ (interactive (list (magit-commit-at-point)
+ (magit-rebase-arguments)))
+ ;; magit-rebase--perl-editor assumes that the comment character is "#".
+ (let ((magit-git-global-arguments
+ (nconc (list "-c" "core.commentChar=#")
+ magit-git-global-arguments)))
+ (magit-rebase-interactive-1 commit args
+ "Type %p on a commit to remove it,"
+ (apply-partially #'magit-rebase--perl-editor 'remove)
+ nil nil t)))
+
+(defun magit-rebase--perl-editor (action since)
+ (let ((commit (magit-rev-abbrev (magit-rebase--target-commit since))))
+ (format "%s -i -p -e '++$x if not $x and s/^pick %s/%s %s/'"
+ magit-perl-executable
+ commit
+ (cl-case action
+ (edit "edit")
+ (remove "noop\n# pick")
+ (reword "reword")
+ (t (error "unknown action: %s" action)))
+ commit)))
+
+;;;###autoload
+(defun magit-rebase-continue (&optional noedit)
+ "Restart the current rebasing operation.
+In some cases this pops up a commit message buffer for you do
+edit. With a prefix argument the old message is reused as-is."
+ (interactive "P")
+ (if (magit-rebase-in-progress-p)
+ (if (magit-anything-unstaged-p t)
+ (user-error "Cannot continue rebase with unstaged changes")
+ (when (and (magit-anything-staged-p)
+ (file-exists-p (magit-git-dir "rebase-merge"))
+ (not (member (magit-toplevel)
+ magit--rebase-public-edit-confirmed)))
+ (magit-commit-amend-assert
+ (magit-file-line (magit-git-dir "rebase-merge/orig-head"))))
+ (if noedit
+ (let ((process-environment process-environment))
+ (push "GIT_EDITOR=true" process-environment)
+ (magit-run-git-async (magit--rebase-resume-command) "--continue")
+ (set-process-sentinel magit-this-process
+ #'magit-sequencer-process-sentinel)
+ magit-this-process)
+ (magit-run-git-sequencer (magit--rebase-resume-command) "--continue")))
+ (user-error "No rebase in progress")))
+
+;;;###autoload
+(defun magit-rebase-skip ()
+ "Skip the current commit and restart the current rebase operation."
+ (interactive)
+ (unless (magit-rebase-in-progress-p)
+ (user-error "No rebase in progress"))
+ (magit-run-git-sequencer (magit--rebase-resume-command) "--skip"))
+
+;;;###autoload
+(defun magit-rebase-edit ()
+ "Edit the todo list of the current rebase operation."
+ (interactive)
+ (unless (magit-rebase-in-progress-p)
+ (user-error "No rebase in progress"))
+ (magit-run-git-sequencer "rebase" "--edit-todo"))
+
+;;;###autoload
+(defun magit-rebase-abort ()
+ "Abort the current rebase operation, restoring the original branch."
+ (interactive)
+ (unless (magit-rebase-in-progress-p)
+ (user-error "No rebase in progress"))
+ (magit-confirm 'abort-rebase "Abort this rebase")
+ (magit-run-git (magit--rebase-resume-command) "--abort"))
+
+(defun magit-rebase-in-progress-p ()
+ "Return t if a rebase is in progress."
+ (or (file-exists-p (magit-git-dir "rebase-merge"))
+ (file-exists-p (magit-git-dir "rebase-apply/onto"))))
+
+(defun magit--rebase-resume-command ()
+ (if (file-exists-p (magit-git-dir "rebase-recursive")) "rbr" "rebase"))
+
+;;; Sections
+
+(defun magit-insert-sequencer-sequence ()
+ "Insert section for the on-going cherry-pick or revert sequence.
+If no such sequence is in progress, do nothing."
+ (let ((picking (magit-cherry-pick-in-progress-p)))
+ (when (or picking (magit-revert-in-progress-p))
+ (magit-insert-section (sequence)
+ (magit-insert-heading (if picking "Cherry Picking" "Reverting"))
+ (when-let ((lines
+ (cdr (magit-file-lines (magit-git-dir "sequencer/todo")))))
+ (dolist (line (nreverse lines))
+ (when (string-match
+ "^\\(pick\\|revert\\) \\([^ ]+\\) \\(.*\\)$" line)
+ (magit-bind-match-strings (cmd hash msg) line
+ (magit-insert-section (commit hash)
+ (insert (propertize cmd 'font-lock-face 'magit-sequence-pick)
+ " " (propertize hash 'font-lock-face 'magit-hash)
+ " " msg "\n"))))))
+ (magit-sequence-insert-sequence
+ (magit-file-line (magit-git-dir (if picking
+ "CHERRY_PICK_HEAD"
+ "REVERT_HEAD")))
+ (magit-file-line (magit-git-dir "sequencer/head")))
+ (insert "\n")))))
+
+(defun magit-insert-am-sequence ()
+ "Insert section for the on-going patch applying sequence.
+If no such sequence is in progress, do nothing."
+ (when (magit-am-in-progress-p)
+ (magit-insert-section (rebase-sequence)
+ (magit-insert-heading "Applying patches")
+ (let ((patches (nreverse (magit-rebase-patches)))
+ patch commit)
+ (while patches
+ (setq patch (pop patches))
+ (setq commit (magit-commit-p
+ (cadr (split-string (magit-file-line patch)))))
+ (cond ((and commit patches)
+ (magit-sequence-insert-commit
+ "pick" commit 'magit-sequence-pick))
+ (patches
+ (magit-sequence-insert-am-patch
+ "pick" patch 'magit-sequence-pick))
+ (commit
+ (magit-sequence-insert-sequence commit "ORIG_HEAD"))
+ (t
+ (magit-sequence-insert-am-patch
+ "stop" patch 'magit-sequence-stop)
+ (magit-sequence-insert-sequence nil "ORIG_HEAD")))))
+ (insert ?\n))))
+
+(defun magit-sequence-insert-am-patch (type patch face)
+ (magit-insert-section (file patch)
+ (let ((title
+ (with-temp-buffer
+ (insert-file-contents patch nil nil 4096)
+ (unless (re-search-forward "^Subject: " nil t)
+ (goto-char (point-min)))
+ (buffer-substring (point) (line-end-position)))))
+ (insert (propertize type 'font-lock-face face)
+ ?\s (propertize (file-name-nondirectory patch)
+ 'font-lock-face 'magit-hash)
+ ?\s title
+ ?\n))))
+
+(defun magit-insert-rebase-sequence ()
+ "Insert section for the on-going rebase sequence.
+If no such sequence is in progress, do nothing."
+ (when (magit-rebase-in-progress-p)
+ (let* ((interactive (file-directory-p (magit-git-dir "rebase-merge")))
+ (dir (if interactive "rebase-merge/" "rebase-apply/"))
+ (name (thread-first (concat dir "head-name")
+ magit-git-dir
+ magit-file-line))
+ (onto (thread-first (concat dir "onto")
+ magit-git-dir
+ magit-file-line))
+ (onto (or (magit-rev-name onto name)
+ (magit-rev-name onto "refs/heads/*") onto))
+ (name (or (magit-rev-name name "refs/heads/*") name)))
+ (magit-insert-section (rebase-sequence)
+ (magit-insert-heading (format "Rebasing %s onto %s" name onto))
+ (if interactive
+ (magit-rebase-insert-merge-sequence onto)
+ (magit-rebase-insert-apply-sequence onto))
+ (insert ?\n)))))
+
+(defun magit-rebase--todo ()
+ "Return `git-rebase-action' instances for remaining rebase actions.
+These are ordered in that the same way they'll be sorted in the
+status buffer (i.e. the reverse of how they will be applied)."
+ (let ((comment-start (or (magit-get "core.commentChar") "#"))
+ lines)
+ (with-temp-buffer
+ (insert-file-contents (magit-git-dir "rebase-merge/git-rebase-todo"))
+ (while (not (eobp))
+ (let ((ln (git-rebase-current-line)))
+ (when (oref ln action-type)
+ (push ln lines)))
+ (forward-line)))
+ lines))
+
+(defun magit-rebase-insert-merge-sequence (onto)
+ (dolist (line (magit-rebase--todo))
+ (with-slots (action-type action action-options target) line
+ (pcase action-type
+ (`commit
+ (magit-sequence-insert-commit action target 'magit-sequence-pick))
+ ((or (or `exec `label)
+ (and `merge (guard (not action-options))))
+ (insert (propertize action 'font-lock-face 'magit-sequence-onto) "\s"
+ (propertize target 'font-lock-face 'git-rebase-label) "\n"))
+ (`merge
+ (if-let ((hash (and (string-match "-[cC] \\([^ ]+\\)" action-options)
+ (match-string 1 action-options))))
+ (magit-insert-section (commit hash)
+ (magit-insert-heading
+ (propertize "merge" 'font-lock-face 'magit-sequence-pick)
+ "\s"
+ (magit-format-rev-summary hash) "\n"))
+ (error "failed to parse merge message hash"))))))
+ (magit-sequence-insert-sequence
+ (magit-file-line (magit-git-dir "rebase-merge/stopped-sha"))
+ onto
+ (--when-let (magit-file-lines (magit-git-dir "rebase-merge/done"))
+ (cadr (split-string (car (last it)))))))
+
+(defun magit-rebase-insert-apply-sequence (onto)
+ (let ((rewritten
+ (--map (car (split-string it))
+ (magit-file-lines (magit-git-dir "rebase-apply/rewritten"))))
+ (stop (magit-file-line (magit-git-dir "rebase-apply/original-commit"))))
+ (dolist (patch (nreverse (cdr (magit-rebase-patches))))
+ (let ((hash (cadr (split-string (magit-file-line patch)))))
+ (unless (or (member hash rewritten)
+ (equal hash stop))
+ (magit-sequence-insert-commit "pick" hash 'magit-sequence-pick)))))
+ (magit-sequence-insert-sequence
+ (magit-file-line (magit-git-dir "rebase-apply/original-commit"))
+ onto))
+
+(defun magit-rebase-patches ()
+ (directory-files (magit-git-dir "rebase-apply") t "^[0-9]\\{4\\}$"))
+
+(defun magit-sequence-insert-sequence (stop onto &optional orig)
+ (let ((head (magit-rev-parse "HEAD")) done)
+ (setq onto (if onto (magit-rev-parse onto) head))
+ (setq done (magit-git-lines "log" "--format=%H" (concat onto "..HEAD")))
+ (when (and stop (not (member (magit-rev-parse stop) done)))
+ (let ((id (magit-patch-id stop)))
+ (--if-let (--first (equal (magit-patch-id it) id) done)
+ (setq stop it)
+ (cond
+ ((--first (magit-rev-equal it stop) done)
+ ;; The commit's testament has been executed.
+ (magit-sequence-insert-commit "void" stop 'magit-sequence-drop))
+ ;; The faith of the commit is still undecided...
+ ((magit-anything-unmerged-p)
+ ;; ...and time travel isn't for the faint of heart.
+ (magit-sequence-insert-commit "join" stop 'magit-sequence-part))
+ ((magit-anything-modified-p t)
+ ;; ...and the dust hasn't settled yet...
+ (magit-sequence-insert-commit
+ (let* ((magit--refresh-cache nil)
+ (staged (magit-commit-tree "oO" nil "HEAD"))
+ (unstaged (magit-commit-worktree "oO" "--reset")))
+ (cond
+ ;; ...but we could end up at the same tree just by committing.
+ ((or (magit-rev-equal staged stop)
+ (magit-rev-equal unstaged stop)) "goal")
+ ;; ...but the changes are still there, untainted.
+ ((or (equal (magit-patch-id staged) id)
+ (equal (magit-patch-id unstaged) id)) "same")
+ ;; ...and some changes are gone and/or others were added.
+ (t "work")))
+ stop 'magit-sequence-part))
+ ;; The commit is definitely gone...
+ ((--first (magit-rev-equal it stop) done)
+ ;; ...but all of its changes are still in effect.
+ (magit-sequence-insert-commit "poof" stop 'magit-sequence-drop))
+ (t
+ ;; ...and some changes are gone and/or other changes were added.
+ (magit-sequence-insert-commit "gone" stop 'magit-sequence-drop)))
+ (setq stop nil))))
+ (dolist (rev done)
+ (apply 'magit-sequence-insert-commit
+ (cond ((equal rev stop)
+ ;; ...but its reincarnation lives on.
+ ;; Or it didn't die in the first place.
+ (list (if (and (equal rev head)
+ (equal (magit-patch-id rev)
+ (magit-patch-id orig)))
+ "stop" ; We haven't done anything yet.
+ "like") ; There are new commits.
+ rev (if (equal rev head)
+ 'magit-sequence-head
+ 'magit-sequence-stop)))
+ ((equal rev head)
+ (list "done" rev 'magit-sequence-head))
+ (t
+ (list "done" rev 'magit-sequence-done)))))
+ (magit-sequence-insert-commit "onto" onto
+ (if (equal onto head)
+ 'magit-sequence-head
+ 'magit-sequence-onto))))
+
+(defun magit-sequence-insert-commit (type hash face)
+ (magit-insert-section (commit hash)
+ (magit-insert-heading
+ (propertize type 'font-lock-face face) "\s"
+ (magit-format-rev-summary hash) "\n")))
+
+;;; _
+(provide 'magit-sequence)
+;;; magit-sequence.el ends here
--- /dev/null
+;;; magit-stash.el --- stash support for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; Support for Git stashes.
+
+;;; Code:
+
+(require 'magit)
+(require 'magit-reflog)
+
+;; For `magit-stash-drop'.
+(defvar helm-comp-read-use-marked)
+
+;;; Options
+
+(defgroup magit-stash nil
+ "List stashes and show stash diffs."
+ :group 'magit-modes)
+
+;;;; Diff options
+
+(defcustom magit-stash-sections-hook
+ '(magit-insert-stash-notes
+ magit-insert-stash-worktree
+ magit-insert-stash-index
+ magit-insert-stash-untracked)
+ "Hook run to insert sections into stash diff buffers."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-stash
+ :type 'hook)
+
+;;;; Log options
+
+(defcustom magit-stashes-margin
+ (list (nth 0 magit-log-margin)
+ (nth 1 magit-log-margin)
+ 'magit-log-margin-width nil
+ (nth 4 magit-log-margin))
+ "Format of the margin in `magit-stashes-mode' buffers.
+
+The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
+
+If INIT is non-nil, then the margin is shown initially.
+STYLE controls how to format the author or committer date.
+ It can be one of `age' (to show the age of the commit),
+ `age-abbreviated' (to abbreviate the time unit to a character),
+ or a string (suitable for `format-time-string') to show the
+ actual date. Option `magit-log-margin-show-committer-date'
+ controls which date is being displayed.
+WIDTH controls the width of the margin. This exists for forward
+ compatibility and currently the value should not be changed.
+AUTHOR controls whether the name of the author is also shown by
+ default.
+AUTHOR-WIDTH has to be an integer. When the name of the author
+ is shown, then this specifies how much space is used to do so."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-stash
+ :group 'magit-margin
+ :type magit-log-margin--custom-type
+ :initialize 'magit-custom-initialize-reset
+ :set-after '(magit-log-margin)
+ :set (apply-partially #'magit-margin-set-variable 'magit-stashes-mode))
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-stash "magit-stash" nil t)
+(transient-define-prefix magit-stash ()
+ "Stash uncommitted changes."
+ :man-page "git-stash"
+ ["Arguments"
+ ("-u" "Also save untracked files" ("-u" "--include-untracked"))
+ ("-a" "Also save untracked and ignored files" ("-a" "--all"))]
+ [["Stash"
+ ("z" "both" magit-stash-both)
+ ("i" "index" magit-stash-index)
+ ("w" "worktree" magit-stash-worktree)
+ ("x" "keeping index" magit-stash-keep-index)]
+ ["Snapshot"
+ ("Z" "both" magit-snapshot-both)
+ ("I" "index" magit-snapshot-index)
+ ("W" "worktree" magit-snapshot-worktree)
+ ("r" "to wip ref" magit-wip-commit)]
+ ["Use"
+ ("a" "Apply" magit-stash-apply)
+ ("p" "Pop" magit-stash-pop)
+ ("k" "Drop" magit-stash-drop)]
+ ["Inspect"
+ ("l" "List" magit-stash-list)
+ ("v" "Show" magit-stash-show)]
+ ["Transform"
+ ("b" "Branch" magit-stash-branch)
+ ("B" "Branch here" magit-stash-branch-here)
+ ("f" "Format patch" magit-stash-format-patch)]])
+
+(defun magit-stash-arguments ()
+ (transient-args 'magit-stash))
+
+;;;###autoload
+(defun magit-stash-both (message &optional include-untracked)
+ "Create a stash of the index and working tree.
+Untracked files are included according to infix arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'."
+ (interactive (magit-stash-read-args))
+ (magit-stash-save message t t include-untracked t))
+
+;;;###autoload
+(defun magit-stash-index (message)
+ "Create a stash of the index only.
+Unstaged and untracked changes are not stashed. The stashed
+changes are applied in reverse to both the index and the
+worktree. This command can fail when the worktree is not clean.
+Applying the resulting stash has the inverse effect."
+ (interactive (list (magit-stash-read-message)))
+ (magit-stash-save message t nil nil t 'worktree))
+
+;;;###autoload
+(defun magit-stash-worktree (message &optional include-untracked)
+ "Create a stash of unstaged changes in the working tree.
+Untracked files are included according to infix arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'."
+ (interactive (magit-stash-read-args))
+ (magit-stash-save message nil t include-untracked t 'index))
+
+;;;###autoload
+(defun magit-stash-keep-index (message &optional include-untracked)
+ "Create a stash of the index and working tree, keeping index intact.
+Untracked files are included according to infix arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'."
+ (interactive (magit-stash-read-args))
+ (magit-stash-save message t t include-untracked t 'index))
+
+(defun magit-stash-read-args ()
+ (list (magit-stash-read-message)
+ (magit-stash-read-untracked)))
+
+(defun magit-stash-read-untracked ()
+ (let ((prefix (prefix-numeric-value current-prefix-arg))
+ (args (magit-stash-arguments)))
+ (cond ((or (= prefix 16) (member "--all" args)) 'all)
+ ((or (= prefix 4) (member "--include-untracked" args)) t))))
+
+(defun magit-stash-read-message ()
+ (let* ((default (format "On %s: "
+ (or (magit-get-current-branch) "(no branch)")))
+ (input (magit-read-string "Stash message" default)))
+ (if (equal input default)
+ (concat default (magit-rev-format "%h %s"))
+ input)))
+
+;;;###autoload
+(defun magit-snapshot-both (&optional include-untracked)
+ "Create a snapshot of the index and working tree.
+Untracked files are included according to infix arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'."
+ (interactive (magit-snapshot-read-args))
+ (magit-snapshot-save t t include-untracked t))
+
+;;;###autoload
+(defun magit-snapshot-index ()
+ "Create a snapshot of the index only.
+Unstaged and untracked changes are not stashed."
+ (interactive)
+ (magit-snapshot-save t nil nil t))
+
+;;;###autoload
+(defun magit-snapshot-worktree (&optional include-untracked)
+ "Create a snapshot of unstaged changes in the working tree.
+Untracked files are included according to infix arguments.
+One prefix argument is equivalent to `--include-untracked'
+while two prefix arguments are equivalent to `--all'."
+ (interactive (magit-snapshot-read-args))
+ (magit-snapshot-save nil t include-untracked t))
+
+(defun magit-snapshot-read-args ()
+ (list (magit-stash-read-untracked)))
+
+(defun magit-snapshot-save (index worktree untracked &optional refresh)
+ (magit-stash-save (concat "WIP on " (magit-stash-summary))
+ index worktree untracked refresh t))
+
+;;;###autoload
+(defun magit-stash-apply (stash)
+ "Apply a stash to the working tree.
+Try to preserve the stash index. If that fails because there
+are staged changes, apply without preserving the stash index."
+ (interactive (list (magit-read-stash "Apply stash")))
+ (if (= (magit-call-git "stash" "apply" "--index" stash) 0)
+ (magit-refresh)
+ (magit-run-git "stash" "apply" stash)))
+
+(defun magit-stash-pop (stash)
+ "Apply a stash to the working tree and remove it from stash list.
+Try to preserve the stash index. If that fails because there
+are staged changes, apply without preserving the stash index
+and forgo removing the stash."
+ (interactive (list (magit-read-stash "Pop stash")))
+ (if (= (magit-call-git "stash" "apply" "--index" stash) 0)
+ (magit-stash-drop stash)
+ (magit-run-git "stash" "apply" stash)))
+
+;;;###autoload
+(defun magit-stash-drop (stash)
+ "Remove a stash from the stash list.
+When the region is active offer to drop all contained stashes."
+ (interactive
+ (list (--if-let (magit-region-values 'stash)
+ (magit-confirm 'drop-stashes nil "Drop %i stashes" nil it)
+ (let ((helm-comp-read-use-marked t))
+ (magit-read-stash "Drop stash")))))
+ (dolist (stash (if (listp stash)
+ (nreverse (prog1 stash (setq stash (car stash))))
+ (list stash)))
+ (message "Deleted refs/%s (was %s)" stash
+ (magit-rev-parse "--short" stash))
+ (magit-call-git "rev-parse" stash)
+ (magit-call-git "reflog" "delete" "--updateref" "--rewrite" stash))
+ (when-let ((ref (and (string-match "\\(.+\\)@{[0-9]+}$" stash)
+ (match-string 1 stash))))
+ (unless (string-match "^refs/" ref)
+ (setq ref (concat "refs/" ref)))
+ (unless (magit-rev-verify (concat ref "@{0}"))
+ (magit-run-git "update-ref" "-d" ref)))
+ (magit-refresh))
+
+;;;###autoload
+(defun magit-stash-clear (ref)
+ "Remove all stashes saved in REF's reflog by deleting REF."
+ (interactive (let ((ref (or (magit-section-value-if 'stashes) "refs/stash")))
+ (magit-confirm t (format "Drop all stashes in %s" ref))
+ (list ref)))
+ (magit-run-git "update-ref" "-d" ref))
+
+;;;###autoload
+(defun magit-stash-branch (stash branch)
+ "Create and checkout a new BRANCH from STASH."
+ (interactive (list (magit-read-stash "Branch stash")
+ (magit-read-string-ns "Branch name")))
+ (magit-run-git "stash" "branch" branch stash))
+
+;;;###autoload
+(defun magit-stash-branch-here (stash branch)
+ "Create and checkout a new BRANCH and apply STASH.
+The branch is created using `magit-branch-and-checkout', using the
+current branch or `HEAD' as the start-point."
+ (interactive (list (magit-read-stash "Branch stash")
+ (magit-read-string-ns "Branch name")))
+ (let ((inhibit-magit-refresh t))
+ (magit-branch-and-checkout branch (or (magit-get-current-branch) "HEAD")))
+ (magit-stash-apply stash))
+
+;;;###autoload
+(defun magit-stash-format-patch (stash)
+ "Create a patch from STASH"
+ (interactive (list (magit-read-stash "Create patch from stash")))
+ (with-temp-file (magit-rev-format "0001-%f.patch" stash)
+ (magit-git-insert "stash" "show" "-p" stash))
+ (magit-refresh))
+
+;;; Plumbing
+
+(defun magit-stash-save (message index worktree untracked
+ &optional refresh keep noerror ref)
+ (if (or (and index (magit-staged-files t))
+ (and worktree (magit-unstaged-files t))
+ (and untracked (magit-untracked-files (eq untracked 'all))))
+ (magit-with-toplevel
+ (magit-stash-store message (or ref "refs/stash")
+ (magit-stash-create message index worktree untracked))
+ (if (eq keep 'worktree)
+ (with-temp-buffer
+ (magit-git-insert "diff" "--cached")
+ (magit-run-git-with-input
+ "apply" "--reverse" "--cached" "--ignore-space-change" "-")
+ (magit-run-git-with-input
+ "apply" "--reverse" "--ignore-space-change" "-"))
+ (unless (eq keep t)
+ (if (eq keep 'index)
+ (magit-call-git "checkout" "--" ".")
+ (magit-call-git "reset" "--hard" "HEAD" "--"))
+ (when untracked
+ (magit-call-git "clean" "--force" "-d"
+ (and (eq untracked 'all) "-x")))))
+ (when refresh
+ (magit-refresh)))
+ (unless noerror
+ (user-error "No %s changes to save" (cond ((not index) "unstaged")
+ ((not worktree) "staged")
+ (t "local"))))))
+
+(defun magit-stash-store (message ref commit)
+ (magit-update-ref ref message commit t))
+
+(defun magit-stash-create (message index worktree untracked)
+ (unless (magit-rev-parse "--verify" "HEAD")
+ (error "You do not have the initial commit yet"))
+ (let ((magit-git-global-arguments (nconc (list "-c" "commit.gpgsign=false")
+ magit-git-global-arguments))
+ (default-directory (magit-toplevel))
+ (summary (magit-stash-summary))
+ (head "HEAD"))
+ (when (and worktree (not index))
+ (setq head (or (magit-commit-tree "pre-stash index" nil "HEAD")
+ (error "Cannot save the current index state"))))
+ (or (setq index (magit-commit-tree (concat "index on " summary) nil head))
+ (error "Cannot save the current index state"))
+ (and untracked
+ (setq untracked (magit-untracked-files (eq untracked 'all)))
+ (setq untracked (magit-with-temp-index nil nil
+ (or (and (magit-update-files untracked)
+ (magit-commit-tree
+ (concat "untracked files on " summary)))
+ (error "Cannot save the untracked files")))))
+ (magit-with-temp-index index "-m"
+ (when worktree
+ (or (magit-update-files (magit-git-items "diff" "-z" "--name-only" head))
+ (error "Cannot save the current worktree state")))
+ (or (magit-commit-tree message nil head index untracked)
+ (error "Cannot save the current worktree state")))))
+
+(defun magit-stash-summary ()
+ (concat (or (magit-get-current-branch) "(no branch)")
+ ": " (magit-rev-format "%h %s")))
+
+;;; Sections
+
+(defvar magit-stashes-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-delete-thing] 'magit-stash-clear)
+ map)
+ "Keymap for `stashes' section.")
+
+(defvar magit-stash-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-stash-show)
+ (define-key map [remap magit-delete-thing] 'magit-stash-drop)
+ (define-key map "a" 'magit-stash-apply)
+ (define-key map "A" 'magit-stash-pop)
+ map)
+ "Keymap for `stash' sections.")
+
+(magit-define-section-jumper magit-jump-to-stashes
+ "Stashes" stashes "refs/stash")
+
+(cl-defun magit-insert-stashes (&optional (ref "refs/stash")
+ (heading "Stashes:"))
+ "Insert `stashes' section showing reflog for \"refs/stash\".
+If optional REF is non-nil, show reflog for that instead.
+If optional HEADING is non-nil, use that as section heading
+instead of \"Stashes:\"."
+ (let ((verified (magit-rev-verify ref))
+ (autostash
+ (and (magit-rebase-in-progress-p)
+ (thread-first
+ (if (file-directory-p (magit-git-dir "rebase-merge"))
+ "rebase-merge/autostash"
+ "rebase-apply/autostash")
+ magit-git-dir
+ magit-file-line))))
+ (when (or autostash verified)
+ (magit-insert-section (stashes ref)
+ (magit-insert-heading heading)
+ (when autostash
+ (pcase-let ((`(,author ,date ,msg)
+ (split-string
+ (car (magit-git-lines
+ "show" "-q" "--format=%aN%x00%at%x00%s"
+ autostash))
+ "\0")))
+ (magit-insert-section (stash autostash)
+ (insert (propertize "AUTOSTASH" 'font-lock-face 'magit-hash))
+ (insert " " msg "\n")
+ (save-excursion
+ (backward-char)
+ (magit-log-format-margin autostash author date)))))
+ (if verified
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'stash)
+ "reflog" "--format=%gd%x00%aN%x00%at%x00%gs" ref)
+ (insert ?\n)
+ (save-excursion
+ (backward-char)
+ (magit-make-margin-overlay)))))))
+
+;;; List Stashes
+
+;;;###autoload
+(defun magit-stash-list ()
+ "List all stashes in a buffer."
+ (interactive)
+ (magit-stashes-setup-buffer))
+
+(define-derived-mode magit-stashes-mode magit-reflog-mode "Magit Stashes"
+ "Mode for looking at lists of stashes."
+ :group 'magit-log
+ (hack-dir-local-variables-non-file-buffer))
+
+(defun magit-stashes-setup-buffer ()
+ (magit-setup-buffer #'magit-stashes-mode nil
+ (magit-buffer-refname "refs/stash")))
+
+(defun magit-stashes-refresh-buffer ()
+ (magit-insert-section (stashesbuf)
+ (magit-insert-heading (if (equal magit-buffer-refname "refs/stash")
+ "Stashes:"
+ (format "Stashes [%s]:" magit-buffer-refname)))
+ (magit-git-wash (apply-partially 'magit-log-wash-log 'stash)
+ "reflog" "--format=%gd%x00%aN%x00%at%x00%gs" magit-buffer-refname)))
+
+(cl-defmethod magit-buffer-value (&context (major-mode magit-stashes-mode))
+ magit-buffer-refname)
+
+(defvar magit--update-stash-buffer nil)
+
+(defun magit-stashes-maybe-update-stash-buffer (&optional _)
+ "When moving in the stashes buffer, update the stash buffer.
+If there is no stash buffer in the same frame, then do nothing."
+ (when (derived-mode-p 'magit-stashes-mode)
+ (magit--maybe-update-stash-buffer)))
+
+(defun magit--maybe-update-stash-buffer ()
+ (when-let ((stash (magit-section-value-if 'stash))
+ (buffer (magit-get-mode-buffer 'magit-stash-mode nil t)))
+ (if magit--update-stash-buffer
+ (setq magit--update-stash-buffer (list stash buffer))
+ (setq magit--update-stash-buffer (list stash buffer))
+ (run-with-idle-timer
+ magit-update-other-window-delay nil
+ (let ((args (with-current-buffer buffer
+ (let ((magit-direct-use-buffer-arguments 'selected))
+ (magit-show-commit--arguments)))))
+ (lambda ()
+ (pcase-let ((`(,stash ,buf) magit--update-stash-buffer))
+ (setq magit--update-stash-buffer nil)
+ (when (buffer-live-p buf)
+ (let ((magit-display-buffer-noselect t))
+ (apply #'magit-stash-show stash args))))
+ (setq magit--update-stash-buffer nil)))))))
+
+;;; Show Stash
+
+;;;###autoload
+(defun magit-stash-show (stash &optional args files)
+ "Show all diffs of a stash in a buffer."
+ (interactive (cons (or (and (not current-prefix-arg)
+ (magit-stash-at-point))
+ (magit-read-stash "Show stash"))
+ (pcase-let ((`(,args ,files)
+ (magit-diff-arguments 'magit-stash-mode)))
+ (list (delete "--stat" args) files))))
+ (magit-stash-setup-buffer stash args files))
+
+(define-derived-mode magit-stash-mode magit-diff-mode "Magit Stash"
+ "Mode for looking at individual stashes."
+ :group 'magit-diff
+ (hack-dir-local-variables-non-file-buffer))
+
+(defun magit-stash-setup-buffer (stash args files)
+ (magit-setup-buffer #'magit-stash-mode nil
+ (magit-buffer-revision stash)
+ (magit-buffer-range (format "%s^..%s" stash stash))
+ (magit-buffer-diff-args args)
+ (magit-buffer-diff-files files)))
+
+(defun magit-stash-refresh-buffer ()
+ (magit-set-header-line-format
+ (concat (capitalize magit-buffer-revision) " "
+ (propertize (magit-rev-format "%s" magit-buffer-revision)
+ 'font-lock-face
+ (list :weight 'normal :foreground
+ (face-attribute 'default :foreground)))))
+ (setq magit-buffer-revision-hash (magit-rev-parse magit-buffer-revision))
+ (magit-insert-section (stash)
+ (magit-run-section-hook 'magit-stash-sections-hook)))
+
+(cl-defmethod magit-buffer-value (&context (major-mode magit-stash-mode))
+ magit-buffer-revision)
+
+(defun magit-stash-insert-section (commit range message &optional files)
+ (magit-insert-section (commit commit)
+ (magit-insert-heading message)
+ (magit--insert-diff "diff" range "-p" "--no-prefix" magit-buffer-diff-args
+ "--" (or files magit-buffer-diff-files))))
+
+(defun magit-insert-stash-notes ()
+ "Insert section showing notes for a stash.
+This shows the notes for stash@{N} but not for the other commits
+that make up the stash."
+ (magit-insert-section section (note)
+ (magit-insert-heading "Notes")
+ (magit-git-insert "notes" "show" magit-buffer-revision)
+ (if (= (point)
+ (oref section content))
+ (magit-cancel-section)
+ (insert "\n"))))
+
+(defun magit-insert-stash-index ()
+ "Insert section showing staged changes of the stash."
+ (magit-stash-insert-section
+ (format "%s^2" magit-buffer-revision)
+ (format "%s^..%s^2" magit-buffer-revision magit-buffer-revision)
+ "Staged"))
+
+(defun magit-insert-stash-worktree ()
+ "Insert section showing unstaged changes of the stash."
+ (magit-stash-insert-section
+ magit-buffer-revision
+ (format "%s^2..%s" magit-buffer-revision magit-buffer-revision)
+ "Unstaged"))
+
+(defun magit-insert-stash-untracked ()
+ "Insert section showing the untracked files commit of the stash."
+ (let ((stash magit-buffer-revision)
+ (rev (concat magit-buffer-revision "^3")))
+ (when (magit-rev-verify rev)
+ (magit-stash-insert-section (format "%s^3" stash)
+ (format "%s^..%s^3" stash stash)
+ "Untracked files"
+ (magit-git-items "ls-tree" "-z" "--name-only"
+ "-r" "--full-tree" rev)))))
+
+;;; _
+(provide 'magit-stash)
+;;; magit-stash.el ends here
--- /dev/null
+;;; magit-status.el --- the grand overview -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements the status buffer.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Options
+
+(defgroup magit-status nil
+ "Inspect and manipulate Git repositories."
+ :link '(info-link "(magit)Status Buffer")
+ :group 'magit-modes)
+
+(defcustom magit-status-mode-hook nil
+ "Hook run after entering Magit-Status mode."
+ :group 'magit-status
+ :type 'hook)
+
+(defcustom magit-status-headers-hook
+ '(magit-insert-error-header
+ magit-insert-diff-filter-header
+ magit-insert-head-branch-header
+ magit-insert-upstream-branch-header
+ magit-insert-push-branch-header
+ magit-insert-tags-header)
+ "Hook run to insert headers into the status buffer.
+
+This hook is run by `magit-insert-status-headers', which in turn
+has to be a member of `magit-status-sections-hook' to be used at
+all."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-status
+ :type 'hook
+ :options '(magit-insert-error-header
+ magit-insert-diff-filter-header
+ magit-insert-repo-header
+ magit-insert-remote-header
+ magit-insert-head-branch-header
+ magit-insert-upstream-branch-header
+ magit-insert-push-branch-header
+ magit-insert-tags-header))
+
+(defcustom magit-status-sections-hook
+ '(magit-insert-status-headers
+ magit-insert-merge-log
+ magit-insert-rebase-sequence
+ magit-insert-am-sequence
+ magit-insert-sequencer-sequence
+ magit-insert-bisect-output
+ magit-insert-bisect-rest
+ magit-insert-bisect-log
+ magit-insert-untracked-files
+ magit-insert-unstaged-changes
+ magit-insert-staged-changes
+ magit-insert-stashes
+ magit-insert-unpushed-to-pushremote
+ magit-insert-unpushed-to-upstream-or-recent
+ magit-insert-unpulled-from-pushremote
+ magit-insert-unpulled-from-upstream)
+ "Hook run to insert sections into a status buffer."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-status
+ :type 'hook)
+
+(defcustom magit-status-initial-section '(1)
+ "The section point is placed on when a status buffer is created.
+
+When such a buffer is merely being refreshed or being shown again
+after it was merely buried, then this option has no effect.
+
+If this is nil, then point remains on the very first section as
+usual. Otherwise it has to be a list of integers and section
+identity lists. The members of that list are tried in order
+until a matching section is found.
+
+An integer means to jump to the nth section, 1 for example
+jumps over the headings. To get a section's \"identity list\"
+use \\[universal-argument] \\[magit-describe-section-briefly].
+
+If, for example, you want to jump to the commits that haven't
+been pulled from the upstream, or else the second section, then
+use: (((unpulled . \"..@{upstream}\") (status)) 1).
+
+See option `magit-section-initial-visibility-alist' for how to
+control the initial visibility of the jumped to section."
+ :package-version '(magit . "2.90.0")
+ :group 'magit-status
+ :type '(choice (const :tag "as usual" nil)
+ (repeat (choice (number :tag "nth top-level section")
+ (sexp :tag "section identity")))))
+
+(defcustom magit-status-goto-file-position nil
+ "Whether to go to position corresponding to file position.
+
+If this is non-nil and the current buffer is visiting a file,
+then `magit-status' tries to go to the position in the status
+buffer that corresponds to the position in the file-visiting
+buffer. This jumps into either the diff of unstaged changes
+or the diff of staged changes.
+
+If the previously current buffer does not visit a file, or if
+the file has neither unstaged nor staged changes then this has
+no effect.
+
+The command `magit-status-here' tries to go to that position,
+regardless of the value of this option."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-status
+ :type 'boolean)
+
+(defcustom magit-status-show-hashes-in-headers nil
+ "Whether headers in the status buffer show hashes.
+The functions which respect this option are
+`magit-insert-head-branch-header',
+`magit-insert-upstream-branch-header', and
+`magit-insert-push-branch-header'."
+ :package-version '(magit . "2.4.0")
+ :group 'magit-status
+ :type 'boolean)
+
+(defcustom magit-status-margin
+ (list nil
+ (nth 1 magit-log-margin)
+ 'magit-log-margin-width nil
+ (nth 4 magit-log-margin))
+ "Format of the margin in `magit-status-mode' buffers.
+
+The value has the form (INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH).
+
+If INIT is non-nil, then the margin is shown initially.
+STYLE controls how to format the author or committer date.
+ It can be one of `age' (to show the age of the commit),
+ `age-abbreviated' (to abbreviate the time unit to a character),
+ or a string (suitable for `format-time-string') to show the
+ actual date. Option `magit-log-margin-show-committer-date'
+ controls which date is being displayed.
+WIDTH controls the width of the margin. This exists for forward
+ compatibility and currently the value should not be changed.
+AUTHOR controls whether the name of the author is also shown by
+ default.
+AUTHOR-WIDTH has to be an integer. When the name of the author
+ is shown, then this specifies how much space is used to do so."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-status
+ :group 'magit-margin
+ :type magit-log-margin--custom-type
+ :initialize 'magit-custom-initialize-reset
+ :set-after '(magit-log-margin)
+ :set (apply-partially #'magit-margin-set-variable 'magit-status-mode))
+
+(defcustom magit-status-use-buffer-arguments 'selected
+ "Whether `magit-status' reuses arguments when the buffer already exists.
+
+This option has no effect when merely refreshing the status
+buffer using `magit-refresh'.
+
+Valid values are:
+
+`always': Always use the set of arguments that is currently
+ active in the status buffer, provided that buffer exists
+ of course.
+`selected': Use the set of arguments from the status
+ buffer, but only if it is displayed in a window of the
+ current frame. This is the default.
+`current': Use the set of arguments from the status buffer,
+ but only if it is the current buffer.
+`never': Never use the set of arguments from the status
+ buffer."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-buffers
+ :group 'magit-commands
+ :type '(choice
+ (const :tag "always use args from buffer" always)
+ (const :tag "use args from buffer if displayed in frame" selected)
+ (const :tag "use args from buffer if it is current" current)
+ (const :tag "never use args from buffer" never)))
+
+;;; Commands
+
+;;;###autoload
+(defun magit-init (directory)
+ "Initialize a Git repository, then show its status.
+
+If the directory is below an existing repository, then the user
+has to confirm that a new one should be created inside. If the
+directory is the root of the existing repository, then the user
+has to confirm that it should be reinitialized.
+
+Non-interactively DIRECTORY is (re-)initialized unconditionally."
+ (interactive
+ (let ((directory (file-name-as-directory
+ (expand-file-name
+ (read-directory-name "Create repository in: ")))))
+ (when-let ((toplevel (magit-toplevel directory)))
+ (setq toplevel (expand-file-name toplevel))
+ (unless (y-or-n-p (if (file-equal-p toplevel directory)
+ (format "Reinitialize existing repository %s? "
+ directory)
+ (format "%s is a repository. Create another in %s? "
+ toplevel directory)))
+ (user-error "Abort")))
+ (list directory)))
+ ;; `git init' does not understand the meaning of "~"!
+ (magit-call-git "init" (magit-convert-filename-for-git
+ (expand-file-name directory)))
+ (magit-status-setup-buffer directory))
+
+;;;###autoload
+(defun magit-status (&optional directory cache)
+ "Show the status of the current Git repository in a buffer.
+
+If the current directory isn't located within a Git repository,
+then prompt for an existing repository or an arbitrary directory,
+depending on option `magit-repository-directories', and show the
+status of the selected repository instead.
+
+* If that option specifies any existing repositories, then offer
+ those for completion and show the status buffer for the
+ selected one.
+
+* Otherwise read an arbitrary directory using regular file-name
+ completion. If the selected directory is the top-level of an
+ existing working tree, then show the status buffer for that.
+
+* Otherwise offer to initialize the selected directory as a new
+ repository. After creating the repository show its status
+ buffer.
+
+These fallback behaviors can also be forced using one or more
+prefix arguments:
+
+* With two prefix arguments (or more precisely a numeric prefix
+ value of 16 or greater) read an arbitrary directory and act on
+ it as described above. The same could be accomplished using
+ the command `magit-init'.
+
+* With a single prefix argument read an existing repository, or
+ if none can be found based on `magit-repository-directories',
+ then fall back to the same behavior as with two prefix
+ arguments."
+ (interactive
+ (let ((magit--refresh-cache (list (cons 0 0))))
+ (list (and (or current-prefix-arg (not (magit-toplevel)))
+ (magit-read-repository
+ (>= (prefix-numeric-value current-prefix-arg) 16)))
+ magit--refresh-cache)))
+ (let ((magit--refresh-cache (or cache (list (cons 0 0)))))
+ (if directory
+ (let ((toplevel (magit-toplevel directory)))
+ (setq directory (file-name-as-directory
+ (expand-file-name directory)))
+ (if (and toplevel (file-equal-p directory toplevel))
+ (magit-status-setup-buffer directory)
+ (when (y-or-n-p
+ (if toplevel
+ (format "%s is a repository. Create another in %s? "
+ toplevel directory)
+ (format "Create repository in %s? " directory)))
+ ;; Creating a new repository invalidates cached values.
+ (setq magit--refresh-cache nil)
+ (magit-init directory))))
+ (magit-status-setup-buffer default-directory))))
+
+(put 'magit-status 'interactive-only 'magit-status-setup-buffer)
+
+;;;###autoload
+(defalias 'magit 'magit-status
+ "An alias for `magit-status' for better discoverability.
+
+Instead of invoking this alias for `magit-status' using
+\"M-x magit RET\", you should bind a key to `magit-status'
+and read the info node `(magit)Getting Started', which
+also contains other useful hints.")
+
+;;;###autoload
+(defun magit-status-here ()
+ "Like `magit-status' but with non-nil `magit-status-goto-file-position'."
+ (interactive)
+ (let ((magit-status-goto-file-position t))
+ (call-interactively #'magit-status)))
+
+(put 'magit-status-here 'interactive-only 'magit-status-setup-buffer)
+
+(defvar magit--remotes-using-recent-git nil)
+
+(defun magit--tramp-asserts (directory)
+ (when-let ((remote (file-remote-p directory)))
+ (unless (member remote magit--remotes-using-recent-git)
+ (if-let ((version (let ((default-directory directory))
+ (magit-git-version))))
+ (if (version<= magit--minimal-git version)
+ (push remote magit--remotes-using-recent-git)
+ (display-warning 'magit (format "\
+Magit requires Git >= %s, but on %s the version is %s.
+
+If multiple Git versions are installed on the host, then the
+problem might be that TRAMP uses the wrong executable.
+
+First check the value of `magit-git-executable'. Its value is
+used when running git locally as well as when running it on a
+remote host. The default value is \"git\", except on Windows
+where an absolute path is used for performance reasons.
+
+If the value already is just \"git\" but TRAMP never-the-less
+doesn't use the correct executable, then consult the info node
+`(tramp)Remote programs'.\n" magit--minimal-git remote version) :error))
+ (display-warning 'magit (format "\
+Magit cannot find Git on %s.
+
+First check the value of `magit-git-executable'. Its value is
+used when running git locally as well as when running it on a
+remote host. The default value is \"git\", except on Windows
+where an absolute path is used for performance reasons.
+
+If the value already is just \"git\" but TRAMP never-the-less
+doesn't find the executable, then consult the info node
+`(tramp)Remote programs'.\n" remote) :error)))))
+
+;;; Mode
+
+(defvar magit-status-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-mode-map)
+ (define-key map "j" 'magit-status-jump)
+ (define-key map [remap dired-jump] 'magit-dired-jump)
+ map)
+ "Keymap for `magit-status-mode'.")
+
+(transient-define-prefix magit-status-jump ()
+ "In a Magit-Status buffer, jump to a section."
+ ["Jump to"
+ [("z " "Stashes" magit-jump-to-stashes
+ :if (lambda () (memq 'magit-insert-stashes magit-status-sections-hook)))
+ ("t " "Tracked" magit-jump-to-tracked
+ :if (lambda () (memq 'magit-insert-tracked-files magit-status-sections-hook)))
+ ("n " "Untracked" magit-jump-to-untracked
+ :if (lambda () (memq 'magit-insert-untracked-files magit-status-sections-hook)))
+ ("u " "Unstaged" magit-jump-to-unstaged
+ :if (lambda () (memq 'magit-insert-unstaged-changes magit-status-sections-hook)))
+ ("s " "Staged" magit-jump-to-staged
+ :if (lambda () (memq 'magit-insert-staged-changes magit-status-sections-hook)))]
+ [("fu" "Unpulled from upstream" magit-jump-to-unpulled-from-upstream
+ :if (lambda () (memq 'magit-insert-unpulled-from-upstream magit-status-sections-hook)))
+ ("fp" "Unpulled from pushremote" magit-jump-to-unpulled-from-pushremote
+ :if (lambda () (memq 'magit-insert-unpulled-from-pushremote magit-status-sections-hook)))
+ ("pu" magit-jump-to-unpushed-to-upstream
+ :if (lambda ()
+ (or (memq 'magit-insert-unpushed-to-upstream-or-recent magit-status-sections-hook)
+ (memq 'magit-insert-unpushed-to-upstream magit-status-sections-hook)))
+ :description (lambda ()
+ (let ((upstream (magit-get-upstream-branch)))
+ (if (or (not upstream)
+ (magit-rev-ancestor-p "HEAD" upstream))
+ "Recent commits"
+ "Unmerged into upstream"))))
+ ("pp" "Unpushed to pushremote" magit-jump-to-unpushed-to-pushremote
+ :if (lambda () (memq 'magit-insert-unpushed-to-pushremote magit-status-sections-hook)))
+ ("a " "Assumed unstaged" magit-jump-to-assume-unchanged
+ :if (lambda () (memq 'magit-insert-assume-unchanged-files magit-status-sections-hook)))
+ ("w " "Skip worktree" magit-jump-to-skip-worktree
+ :if (lambda () (memq 'magit-insert-skip-worktree-files magit-status-sections-hook)))]])
+
+(define-derived-mode magit-status-mode magit-mode "Magit"
+ "Mode for looking at Git status.
+
+This mode is documented in info node `(magit)Status Buffer'.
+
+\\<magit-mode-map>\
+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'.
+
+\\<magit-hunk-section-map>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-status-mode-map>\
+Type \\[magit-commit] to create a commit.
+
+\\{magit-status-mode-map}"
+ :group 'magit-status
+ (hack-dir-local-variables-non-file-buffer)
+ (setq imenu-create-index-function
+ 'magit-imenu--status-create-index-function))
+
+(put 'magit-status-mode 'magit-diff-default-arguments
+ '("--no-ext-diff"))
+(put 'magit-status-mode 'magit-log-default-arguments
+ '("-n256" "--decorate"))
+
+;;;###autoload
+(defun magit-status-setup-buffer (&optional directory)
+ (unless directory
+ (setq directory default-directory))
+ (magit--tramp-asserts directory)
+ (let* ((default-directory directory)
+ (d (magit-diff--get-value 'magit-status-mode
+ magit-status-use-buffer-arguments))
+ (l (magit-log--get-value 'magit-status-mode
+ magit-status-use-buffer-arguments))
+ (file (and magit-status-goto-file-position
+ (magit-file-relative-name)))
+ (line (and file (line-number-at-pos)))
+ (col (and file (current-column)))
+ (buf (magit-setup-buffer #'magit-status-mode nil
+ (magit-buffer-diff-args (nth 0 d))
+ (magit-buffer-diff-files (nth 1 d))
+ (magit-buffer-log-args (nth 0 l))
+ (magit-buffer-log-files (nth 1 l)))))
+ (when file
+ (with-current-buffer buf
+ (let ((staged (magit-get-section '((staged) (status)))))
+ (if (and staged
+ (cadr (magit-diff--locate-hunk file line staged)))
+ (magit-diff--goto-position file line col staged)
+ (let ((unstaged (magit-get-section '((unstaged) (status)))))
+ (unless (and unstaged
+ (magit-diff--goto-position file line col unstaged))
+ (when staged
+ (magit-diff--goto-position file line col staged))))))))
+ buf))
+
+(defun magit-status-refresh-buffer ()
+ (magit-git-exit-code "update-index" "--refresh")
+ (magit-insert-section (status)
+ (magit-run-section-hook 'magit-status-sections-hook)))
+
+(defun magit-status-goto-initial-section ()
+ "In a `magit-status-mode' buffer, jump `magit-status-initial-section'.
+Actually doing so is deferred until `magit-refresh-buffer-hook'
+runs `magit-status-goto-initial-section-1'. That function then
+removes itself from the hook, so that this only happens when the
+status buffer is first created."
+ (when (and magit-status-initial-section
+ (derived-mode-p 'magit-status-mode))
+ (add-hook 'magit-refresh-buffer-hook
+ 'magit-status-goto-initial-section-1 nil t)))
+
+(defun magit-status-goto-initial-section-1 ()
+ "In a `magit-status-mode' buffer, jump `magit-status-initial-section'.
+This function removes itself from `magit-refresh-buffer-hook'."
+ (when-let ((section
+ (--some (if (integerp it)
+ (nth (1- it)
+ (magit-section-siblings (magit-current-section)
+ 'next))
+ (magit-get-section it))
+ magit-status-initial-section)))
+ (goto-char (oref section start))
+ (when-let ((vis (cdr (assq 'magit-status-initial-section
+ magit-section-initial-visibility-alist))))
+ (if (eq vis 'hide)
+ (magit-section-hide section)
+ (magit-section-show section))))
+ (remove-hook 'magit-refresh-buffer-hook
+ 'magit-status-goto-initial-section-1 t))
+
+(defun magit-status-maybe-update-revision-buffer (&optional _)
+ "When moving in the status buffer, update the revision buffer.
+If there is no revision buffer in the same frame, then do nothing."
+ (when (derived-mode-p 'magit-status-mode)
+ (magit--maybe-update-revision-buffer)))
+
+(defun magit-status-maybe-update-stash-buffer (&optional _)
+ "When moving in the status buffer, update the stash buffer.
+If there is no stash buffer in the same frame, then do nothing."
+ (when (derived-mode-p 'magit-status-mode)
+ (magit--maybe-update-stash-buffer)))
+
+(defun magit-status-maybe-update-blob-buffer (&optional _)
+ "When moving in the status buffer, update the blob buffer.
+If there is no blob buffer in the same frame, then do nothing."
+ (when (derived-mode-p 'magit-status-mode)
+ (magit--maybe-update-blob-buffer)))
+
+;;; Sections
+;;;; Special Headers
+
+(defun magit-insert-status-headers ()
+ "Insert header sections appropriate for `magit-status-mode' buffers.
+The sections are inserted by running the functions on the hook
+`magit-status-headers-hook'."
+ (if (magit-rev-verify "HEAD")
+ (magit-insert-headers 'magit-status-headers-hook)
+ (insert "In the beginning there was darkness\n\n")))
+
+(defvar magit-error-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-process-buffer)
+ map)
+ "Keymap for `error' sections.")
+
+(defun magit-insert-error-header ()
+ "Insert the message about the Git error that just occurred.
+
+This function is only aware of the last error that occur when Git
+was run for side-effects. If, for example, an error occurs while
+generating a diff, then that error won't be inserted. Refreshing
+the status buffer causes this section to disappear again."
+ (when magit-this-error
+ (magit-insert-section (error 'git)
+ (insert (propertize (format "%-10s" "GitError! ")
+ 'font-lock-face 'magit-section-heading))
+ (insert (propertize magit-this-error
+ 'font-lock-face 'font-lock-warning-face))
+ (when-let ((key (car (where-is-internal 'magit-process-buffer))))
+ (insert (format " [Type `%s' for details]" (key-description key))))
+ (insert ?\n))
+ (setq magit-this-error nil)))
+
+(defun magit-insert-diff-filter-header ()
+ "Insert a header line showing the effective diff filters."
+ (let ((ignore-modules (magit-ignore-submodules-p)))
+ (when (or ignore-modules
+ magit-buffer-diff-files)
+ (insert (propertize (format "%-10s" "Filter! ")
+ 'font-lock-face 'magit-section-heading))
+ (when ignore-modules
+ (insert ignore-modules)
+ (when magit-buffer-diff-files
+ (insert " -- ")))
+ (when magit-buffer-diff-files
+ (insert (mapconcat #'identity magit-buffer-diff-files " ")))
+ (insert ?\n))))
+
+;;;; Reference Headers
+
+(defun magit-insert-head-branch-header (&optional branch)
+ "Insert a header line about the current branch.
+If `HEAD' is detached, then insert information about that commit
+instead. The optional BRANCH argument is for internal use only."
+ (let ((branch (or branch (magit-get-current-branch)))
+ (output (magit-rev-format "%h %s" (or branch "HEAD"))))
+ (string-match "^\\([^ ]+\\) \\(.*\\)" output)
+ (magit-bind-match-strings (commit summary) output
+ (when (equal summary "")
+ (setq summary "(no commit message)"))
+ (if branch
+ (magit-insert-section (branch branch)
+ (insert (format "%-10s" "Head: "))
+ (when magit-status-show-hashes-in-headers
+ (insert (propertize commit 'font-lock-face 'magit-hash) ?\s))
+ (insert (propertize branch 'font-lock-face 'magit-branch-local))
+ (insert ?\s)
+ (insert (funcall magit-log-format-message-function branch summary))
+ (insert ?\n))
+ (magit-insert-section (commit commit)
+ (insert (format "%-10s" "Head: "))
+ (insert (propertize commit 'font-lock-face 'magit-hash))
+ (insert ?\s)
+ (insert (funcall magit-log-format-message-function nil summary))
+ (insert ?\n))))))
+
+(defun magit-insert-upstream-branch-header (&optional branch upstream keyword)
+ "Insert a header line about the upstream of the current branch.
+If no branch is checked out, then insert nothing. The optional
+arguments are for internal use only."
+ (when-let ((branch (or branch (magit-get-current-branch))))
+ (let ((remote (magit-get "branch" branch "remote"))
+ (merge (magit-get "branch" branch "merge"))
+ (rebase (magit-get "branch" branch "rebase")))
+ (when (or remote merge)
+ (unless upstream
+ (setq upstream (magit-get-upstream-branch branch)))
+ (magit-insert-section (branch upstream)
+ (pcase rebase
+ ("true")
+ ("false" (setq rebase nil))
+ (_ (setq rebase (magit-get-boolean "pull.rebase"))))
+ (insert (format "%-10s" (or keyword (if rebase "Rebase: " "Merge: "))))
+ (insert
+ (if upstream
+ (concat (and magit-status-show-hashes-in-headers
+ (concat (propertize (magit-rev-format "%h" upstream)
+ 'font-lock-face 'magit-hash)
+ " "))
+ upstream " "
+ (funcall magit-log-format-message-function upstream
+ (funcall magit-log-format-message-function nil
+ (or (magit-rev-format "%s" upstream)
+ "(no commit message)"))))
+ (cond
+ ((magit--unnamed-upstream-p remote merge)
+ (concat (propertize merge 'font-lock-face 'magit-branch-remote)
+ " from "
+ (propertize remote 'font-lock-face 'bold)))
+ ((magit--valid-upstream-p remote merge)
+ (if (equal remote ".")
+ (concat
+ (propertize merge 'font-lock-face 'magit-branch-local)
+ (propertize " does not exist"
+ 'font-lock-face 'font-lock-warning-face))
+ (concat
+ (propertize merge 'font-lock-face 'magit-branch-remote)
+ (propertize " does not exist on "
+ 'font-lock-face 'font-lock-warning-face)
+ (propertize remote 'font-lock-face 'magit-branch-remote))))
+ (t
+ (propertize "invalid upstream configuration"
+ 'font-lock-face 'font-lock-warning-face)))))
+ (insert ?\n))))))
+
+(defun magit-insert-push-branch-header ()
+ "Insert a header line about the branch the current branch is pushed to."
+ (when-let ((branch (magit-get-current-branch))
+ (target (magit-get-push-branch branch)))
+ (magit-insert-section (branch target)
+ (insert (format "%-10s" "Push: "))
+ (insert
+ (if (magit-rev-verify target)
+ (concat target " "
+ (and magit-status-show-hashes-in-headers
+ (concat (propertize (magit-rev-format "%h" target)
+ 'font-lock-face 'magit-hash)
+ " "))
+ (funcall magit-log-format-message-function target
+ (funcall magit-log-format-message-function nil
+ (or (magit-rev-format "%s" target)
+ "(no commit message)"))))
+ (let ((remote (magit-get-push-remote branch)))
+ (if (magit-remote-p remote)
+ (concat target
+ (propertize " does not exist"
+ 'font-lock-face 'font-lock-warning-face))
+ (concat remote
+ (propertize " remote does not exist"
+ 'font-lock-face 'font-lock-warning-face))))))
+ (insert ?\n))))
+
+(defun magit-insert-tags-header ()
+ "Insert a header line about the current and/or next tag."
+ (let* ((this-tag (magit-get-current-tag nil t))
+ (next-tag (magit-get-next-tag nil t))
+ (this-cnt (cadr this-tag))
+ (next-cnt (cadr next-tag))
+ (this-tag (car this-tag))
+ (next-tag (car next-tag))
+ (both-tags (and this-tag next-tag t)))
+ (when (or this-tag next-tag)
+ (magit-insert-section (tag (or this-tag next-tag))
+ (insert (format "%-10s" (if both-tags "Tags: " "Tag: ")))
+ (cl-flet ((insert-count
+ (tag count face)
+ (insert (concat (propertize tag 'font-lock-face 'magit-tag)
+ (and (> count 0)
+ (format " (%s)"
+ (propertize
+ (format "%s" count)
+ 'font-lock-face face)))))))
+ (when this-tag (insert-count this-tag this-cnt 'magit-branch-local))
+ (when both-tags (insert ", "))
+ (when next-tag (insert-count next-tag next-cnt 'magit-tag)))
+ (insert ?\n)))))
+
+;;;; Auxiliary Headers
+
+(defun magit-insert-user-header ()
+ "Insert a header line about the current user."
+ (let ((name (magit-get "user.name"))
+ (email (magit-get "user.email")))
+ (when (and name email)
+ (magit-insert-section (user name)
+ (insert (format "%-10s" "User: "))
+ (insert (propertize name 'font-lock-face 'magit-log-author))
+ (insert " <" email ">\n")))))
+
+(defun magit-insert-repo-header ()
+ "Insert a header line showing the path to the repository top-level."
+ (let ((topdir (magit-toplevel)))
+ (magit-insert-section (repo topdir)
+ (insert (format "%-10s%s\n" "Repo: " (abbreviate-file-name topdir))))))
+
+(defun magit-insert-remote-header ()
+ "Insert a header line about the remote of the current branch.
+
+If no remote is configured for the current branch, then fall back
+showing the \"origin\" remote, or if that does not exist the first
+remote in alphabetic order."
+ (when-let ((name (magit-get-some-remote))
+ ;; Under certain configurations it's possible for url
+ ;; to be nil, when name is not, see #2858.
+ (url (magit-get "remote" name "url")))
+ (magit-insert-section (remote name)
+ (insert (format "%-10s" "Remote: "))
+ (insert (propertize name 'font-lock-face 'magit-branch-remote) ?\s)
+ (insert url ?\n))))
+
+;;;; File Sections
+
+(defvar magit-untracked-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-delete-thing] 'magit-discard)
+ (define-key map "s" 'magit-stage)
+ map)
+ "Keymap for the `untracked' section.")
+
+(magit-define-section-jumper magit-jump-to-untracked "Untracked files" untracked)
+
+(defun magit-insert-untracked-files ()
+ "Maybe insert a list or tree of untracked files.
+
+Do so depending on the value of `status.showUntrackedFiles'.
+Note that even if the value is `all', Magit still initially
+only shows directories. But the directory sections can then
+be expanded using \"TAB\".
+
+If the first element of `magit-buffer-diff-files' is a
+directory, then limit the list to files below that. The value
+value of that variable can be set using \"D -- DIRECTORY RET g\"."
+ (let* ((show (or (magit-get "status.showUntrackedFiles") "normal"))
+ (base (car magit-buffer-diff-files))
+ (base (and base (file-directory-p base) base)))
+ (unless (equal show "no")
+ (if (equal show "all")
+ (when-let ((files (magit-untracked-files nil base)))
+ (magit-insert-section (untracked)
+ (magit-insert-heading "Untracked files:")
+ (magit-insert-files files base)
+ (insert ?\n)))
+ (when-let ((files
+ (--mapcat (and (eq (aref it 0) ??)
+ (list (substring it 3)))
+ (magit-git-items "status" "-z" "--porcelain"
+ (magit-ignore-submodules-p t)
+ "--" base))))
+ (magit-insert-section (untracked)
+ (magit-insert-heading "Untracked files:")
+ (dolist (file files)
+ (magit-insert-section (file file)
+ (insert (propertize file 'font-lock-face 'magit-filename) ?\n)))
+ (insert ?\n)))))))
+
+(magit-define-section-jumper magit-jump-to-tracked "Tracked files" tracked)
+
+(defun magit-insert-tracked-files ()
+ "Insert a tree of tracked files.
+
+If the first element of `magit-buffer-diff-files' is a
+directory, then limit the list to files below that. The value
+value of that variable can be set using \"D -- DIRECTORY RET g\"."
+ (when-let ((files (magit-list-files)))
+ (let* ((base (car magit-buffer-diff-files))
+ (base (and base (file-directory-p base) base)))
+ (magit-insert-section (tracked nil t)
+ (magit-insert-heading "Tracked files:")
+ (magit-insert-files files base)
+ (insert ?\n)))))
+
+(defun magit-insert-ignored-files ()
+ "Insert a tree of ignored files.
+
+If the first element of `magit-buffer-diff-files' is a
+directory, then limit the list to files below that. The value
+of that variable can be set using \"D -- DIRECTORY RET g\"."
+ (when-let ((files (magit-ignored-files)))
+ (let* ((base (car magit-buffer-diff-files))
+ (base (and base (file-directory-p base) base)))
+ (magit-insert-section (tracked nil t)
+ (magit-insert-heading "Ignored files:")
+ (magit-insert-files files base)
+ (insert ?\n)))))
+
+(magit-define-section-jumper magit-jump-to-skip-worktree "Skip-worktree files" skip-worktree)
+
+(defun magit-insert-skip-worktree-files ()
+ "Insert a tree of skip-worktree files.
+
+If the first element of `magit-buffer-diff-files' is a
+directory, then limit the list to files below that. The value
+of that variable can be set using \"D -- DIRECTORY RET g\"."
+ (when-let ((files (magit-skip-worktree-files)))
+ (let* ((base (car magit-buffer-diff-files))
+ (base (and base (file-directory-p base) base)))
+ (magit-insert-section (skip-worktree nil t)
+ (magit-insert-heading "Skip-worktree files:")
+ (magit-insert-files files base)
+ (insert ?\n)))))
+
+(magit-define-section-jumper magit-jump-to-assume-unchanged "Assume-unchanged files" assume-unchanged)
+
+(defun magit-insert-assume-unchanged-files ()
+ "Insert a tree of files that are assumed to be unchanged.
+
+If the first element of `magit-buffer-diff-files' is a
+directory, then limit the list to files below that. The value
+of that variable can be set using \"D -- DIRECTORY RET g\"."
+ (when-let ((files (magit-assume-unchanged-files)))
+ (let* ((base (car magit-buffer-diff-files))
+ (base (and base (file-directory-p base) base)))
+ (magit-insert-section (assume-unchanged nil t)
+ (magit-insert-heading "Assume-unchanged files:")
+ (magit-insert-files files base)
+ (insert ?\n)))))
+
+(defun magit-insert-files (files directory)
+ (while (and files (string-prefix-p (or directory "") (car files)))
+ (let ((dir (file-name-directory (car files))))
+ (if (equal dir directory)
+ (let ((file (pop files)))
+ (magit-insert-section (file file)
+ (insert (propertize file 'font-lock-face 'magit-filename) ?\n)))
+ (magit-insert-section (file dir t)
+ (insert (propertize dir 'file 'magit-filename) ?\n)
+ (magit-insert-heading)
+ (setq files (magit-insert-files files dir))))))
+ files)
+
+;;; _
+(provide 'magit-status)
+;;; magit-status.el ends here
--- /dev/null
+;;; magit-submodule.el --- submodule support for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2011-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Code:
+
+(require 'magit)
+
+(defvar x-stretch-cursor)
+
+;;; Options
+
+(defcustom magit-module-sections-hook
+ '(magit-insert-modules-overview
+ magit-insert-modules-unpulled-from-upstream
+ magit-insert-modules-unpulled-from-pushremote
+ magit-insert-modules-unpushed-to-upstream
+ magit-insert-modules-unpushed-to-pushremote)
+ "Hook run by `magit-insert-modules'.
+
+That function isn't part of `magit-status-sections-hook's default
+value, so you have to add it yourself for this hook to have any
+effect."
+ :package-version '(magit . "2.11.0")
+ :group 'magit-status
+ :type 'hook)
+
+(defcustom magit-module-sections-nested t
+ "Whether `magit-insert-modules' wraps inserted sections.
+
+If this is non-nil, then only a single top-level section
+is inserted. If it is nil, then all sections listed in
+`magit-module-sections-hook' become top-level sections."
+ :package-version '(magit . "2.11.0")
+ :group 'magit-status
+ :type 'boolean)
+
+(defcustom magit-submodule-list-mode-hook '(hl-line-mode)
+ "Hook run after entering Magit-Submodule-List mode."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-repolist
+ :type 'hook
+ :get 'magit-hook-custom-get
+ :options '(hl-line-mode))
+
+(defcustom magit-submodule-list-columns
+ '(("Path" 25 magit-modulelist-column-path nil)
+ ("Version" 25 magit-repolist-column-version nil)
+ ("Branch" 20 magit-repolist-column-branch nil)
+ ("B<U" 3 magit-repolist-column-unpulled-from-upstream ((:right-align t)))
+ ("B>U" 3 magit-repolist-column-unpushed-to-upstream ((:right-align t)))
+ ("B<P" 3 magit-repolist-column-unpulled-from-pushremote ((:right-align t)))
+ ("B>P" 3 magit-repolist-column-unpushed-to-pushremote ((:right-align t)))
+ ("B" 3 magit-repolist-column-branches ((:right-align t)))
+ ("S" 3 magit-repolist-column-stashes ((:right-align t))))
+ "List of columns displayed by `magit-list-submodules'.
+
+Each element has the form (HEADER WIDTH FORMAT PROPS).
+
+HEADER is the string displayed in the header. WIDTH is the width
+of the column. FORMAT is a function that is called with one
+argument, the repository identification (usually its basename),
+and with `default-directory' bound to the toplevel of its working
+tree. It has to return a string to be inserted or nil. PROPS is
+an alist that supports the keys `:right-align' and `:pad-right'."
+ :package-version '(magit . "2.8.0")
+ :group 'magit-repolist-mode
+ :type `(repeat (list :tag "Column"
+ (string :tag "Header Label")
+ (integer :tag "Column Width")
+ (function :tag "Inserter Function")
+ (repeat :tag "Properties"
+ (list (choice :tag "Property"
+ (const :right-align)
+ (const :pad-right)
+ (symbol))
+ (sexp :tag "Value"))))))
+
+(defcustom magit-submodule-remove-trash-gitdirs nil
+ "Whether `magit-submodule-remove' offers to trash module gitdirs.
+
+If this is nil, then that command does not offer to do so unless
+a prefix argument is used. When this is t, then it does offer to
+do so even without a prefix argument.
+
+In both cases the action still has to be confirmed unless that is
+disabled using the option `magit-no-confirm'. Doing the latter
+and also setting this variable to t will lead to tears."
+ :package-version '(magit . "2.90.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+;;; Popup
+
+;;;###autoload (autoload 'magit-submodule "magit-submodule" nil t)
+(transient-define-prefix magit-submodule ()
+ "Act on a submodule."
+ :man-page "git-submodule"
+ ["Arguments"
+ ("-f" "Force" ("-f" "--force"))
+ ("-r" "Recursive" "--recursive")
+ ("-N" "Do not fetch" ("-N" "--no-fetch"))
+ ("-C" "Checkout tip" "--checkout")
+ ("-R" "Rebase onto tip" "--rebase")
+ ("-M" "Merge tip" "--merge")
+ ("-U" "Use upstream tip" "--remote")]
+ ["One module actions"
+ ("a" magit-submodule-add)
+ ("r" magit-submodule-register)
+ ("p" magit-submodule-populate)
+ ("u" magit-submodule-update)
+ ("s" magit-submodule-synchronize)
+ ("d" magit-submodule-unpopulate)
+ ("k" "Remove" magit-submodule-remove)]
+ ["All modules actions"
+ ("l" "List all modules" magit-list-submodules)
+ ("f" "Fetch all modules" magit-fetch-modules)])
+
+(defun magit-submodule-arguments (&rest filters)
+ (--filter (and (member it filters) it)
+ (transient-args 'magit-submodule)))
+
+(defclass magit--git-submodule-suffix (transient-suffix)
+ ())
+
+(cl-defmethod transient-format-description ((obj magit--git-submodule-suffix))
+ (let ((value (delq nil (mapcar 'transient-infix-value transient--suffixes))))
+ (replace-regexp-in-string
+ "\\[--[^]]+\\]"
+ (lambda (match)
+ (format (propertize "[%s]" 'face 'transient-inactive-argument)
+ (mapconcat (lambda (arg)
+ (propertize arg 'face
+ (if (member arg value)
+ 'transient-argument
+ 'transient-inactive-argument)))
+ (save-match-data
+ (split-string (substring match 1 -1) "|"))
+ (propertize "|" 'face 'transient-inactive-argument))))
+ (cl-call-next-method obj))))
+
+;;;###autoload (autoload 'magit-submodule-add "magit-submodule" nil t)
+(transient-define-suffix magit-submodule-add (url &optional path name args)
+ "Add the repository at URL as a module.
+
+Optional PATH is the path to the module relative to the root of
+the superproject. If it is nil, then the path is determined
+based on the URL. Optional NAME is the name of the module. If
+it is nil, then PATH also becomes the name."
+ :class 'magit--git-submodule-suffix
+ :description "Add git submodule add [--force]"
+ (interactive
+ (magit-with-toplevel
+ (let* ((url (magit-read-string-ns "Add submodule (remote url)"))
+ (path (let ((read-file-name-function
+ (if (or (eq read-file-name-function 'ido-read-file-name)
+ (advice-function-member-p
+ 'ido-read-file-name
+ read-file-name-function))
+ ;; The Ido variant doesn't work properly here.
+ #'read-file-name-default
+ read-file-name-function)))
+ (directory-file-name
+ (file-relative-name
+ (read-directory-name
+ "Add submodules at path: " nil nil nil
+ (and (string-match "\\([^./]+\\)\\(\\.git\\)?$" url)
+ (match-string 1 url))))))))
+ (list url
+ (directory-file-name path)
+ (magit-submodule-read-name-for-path path)
+ (magit-submodule-arguments "--force")))))
+ (magit-submodule-add-1 url path name args))
+
+(defun magit-submodule-add-1 (url &optional path name args)
+ (magit-with-toplevel
+ (magit-submodule--maybe-reuse-gitdir name path)
+ (magit-run-git-async "submodule" "add"
+ (and name (list "--name" name))
+ args "--" url path)
+ (set-process-sentinel
+ magit-this-process
+ (lambda (process event)
+ (when (memq (process-status process) '(exit signal))
+ (if (> (process-exit-status process) 0)
+ (magit-process-sentinel process event)
+ (process-put process 'inhibit-refresh t)
+ (magit-process-sentinel process event)
+ (unless (version< (magit-git-version) "2.12.0")
+ (magit-call-git "submodule" "absorbgitdirs" path))
+ (magit-refresh)))))))
+
+;;;###autoload
+(defun magit-submodule-read-name-for-path (path &optional prefer-short)
+ (let* ((path (directory-file-name (file-relative-name path)))
+ (name (file-name-nondirectory path)))
+ (push (if prefer-short path name) minibuffer-history)
+ (magit-read-string-ns
+ "Submodule name" nil (cons 'minibuffer-history 2)
+ (or (--keep (pcase-let ((`(,var ,val) (split-string it "=")))
+ (and (equal val path)
+ (cadr (split-string var "\\."))))
+ (magit-git-lines "config" "--list" "-f" ".gitmodules"))
+ (if prefer-short name path)))))
+
+;;;###autoload (autoload 'magit-submodule-register "magit-submodule" nil t)
+(transient-define-suffix magit-submodule-register (modules)
+ "Register MODULES.
+
+With a prefix argument act on all suitable modules. Otherwise,
+if the region selects modules, then act on those. Otherwise, if
+there is a module at point, then act on that. Otherwise read a
+single module from the user."
+ ;; This command and the underlying "git submodule init" do NOT
+ ;; "initialize" modules. They merely "register" modules in the
+ ;; super-projects $GIT_DIR/config file, the purpose of which is to
+ ;; allow users to change such values before actually initializing
+ ;; the modules.
+ :description "Register git submodule init"
+ (interactive
+ (list (magit-module-confirm "Register" 'magit-module-no-worktree-p)))
+ (magit-with-toplevel
+ (magit-run-git-async "submodule" "init" "--" modules)))
+
+;;;###autoload (autoload 'magit-submodule-populate "magit-submodule" nil t)
+(transient-define-suffix magit-submodule-populate (modules)
+ "Create MODULES working directories, checking out the recorded commits.
+
+With a prefix argument act on all suitable modules. Otherwise,
+if the region selects modules, then act on those. Otherwise, if
+there is a module at point, then act on that. Otherwise read a
+single module from the user."
+ ;; This is the command that actually "initializes" modules.
+ ;; A module is initialized when it has a working directory,
+ ;; a gitlink, and a .gitmodules entry.
+ :description "Populate git submodule update --init"
+ (interactive
+ (list (magit-module-confirm "Populate" 'magit-module-no-worktree-p)))
+ (magit-with-toplevel
+ (magit-run-git-async "submodule" "update" "--init" "--" modules)))
+
+;;;###autoload (autoload 'magit-submodule-update "magit-submodule" nil t)
+(transient-define-suffix magit-submodule-update (modules args)
+ "Update MODULES by checking out the recorded commits.
+
+With a prefix argument act on all suitable modules. Otherwise,
+if the region selects modules, then act on those. Otherwise, if
+there is a module at point, then act on that. Otherwise read a
+single module from the user."
+ ;; Unlike `git-submodule's `update' command ours can only update
+ ;; "initialized" modules by checking out other commits but not
+ ;; "initialize" modules by creating the working directories.
+ ;; To do the latter we provide the "setup" command.
+ :class 'magit--git-submodule-suffix
+ :description "Update git submodule update [--force] [--no-fetch]
+ [--remote] [--recursive] [--checkout|--rebase|--merge]"
+ (interactive
+ (list (magit-module-confirm "Update" 'magit-module-worktree-p)
+ (magit-submodule-arguments
+ "--force" "--remote" "--recursive" "--checkout" "--rebase" "--merge"
+ "--no-fetch")))
+ (magit-with-toplevel
+ (magit-run-git-async "submodule" "update" args "--" modules)))
+
+;;;###autoload (autoload 'magit-submodule-synchronize "magit-submodule" nil t)
+(transient-define-suffix magit-submodule-synchronize (modules args)
+ "Synchronize url configuration of MODULES.
+
+With a prefix argument act on all suitable modules. Otherwise,
+if the region selects modules, then act on those. Otherwise, if
+there is a module at point, then act on that. Otherwise read a
+single module from the user."
+ :class 'magit--git-submodule-suffix
+ :description "Synchronize git submodule sync [--recursive]"
+ (interactive
+ (list (magit-module-confirm "Synchronize" 'magit-module-worktree-p)
+ (magit-submodule-arguments "--recursive")))
+ (magit-with-toplevel
+ (magit-run-git-async "submodule" "sync" args "--" modules)))
+
+;;;###autoload (autoload 'magit-submodule-unpopulate "magit-submodule" nil t)
+(transient-define-suffix magit-submodule-unpopulate (modules args)
+ "Remove working directories of MODULES.
+
+With a prefix argument act on all suitable modules. Otherwise,
+if the region selects modules, then act on those. Otherwise, if
+there is a module at point, then act on that. Otherwise read a
+single module from the user."
+ ;; Even though a package is "uninitialized" (it has no worktree)
+ ;; the super-projects $GIT_DIR/config may never-the-less set the
+ ;; module's url. This may happen if you `deinit' and then `init'
+ ;; to register (NOT initialize). Because the purpose of `deinit'
+ ;; is to remove the working directory AND to remove the url, this
+ ;; command does not limit itself to modules that have no working
+ ;; directory.
+ :class 'magit--git-submodule-suffix
+ :description "Unpopulate git submodule deinit [--force]"
+ (interactive
+ (list (magit-module-confirm "Unpopulate")
+ (magit-submodule-arguments "--force")))
+ (magit-with-toplevel
+ (magit-run-git-async "submodule" "deinit" args "--" modules)))
+
+;;;###autoload
+(defun magit-submodule-remove (modules args trash-gitdirs)
+ "Unregister MODULES and remove their working directories.
+
+For safety reasons, do not remove the gitdirs and if a module has
+uncommitted changes, then do not remove it at all. If a module's
+gitdir is located inside the working directory, then move it into
+the gitdir of the superproject first.
+
+With the \"--force\" argument offer to remove dirty working
+directories and with a prefix argument offer to delete gitdirs.
+Both actions are very dangerous and have to be confirmed. There
+are additional safety precautions in place, so you might be able
+to recover from making a mistake here, but don't count on it."
+ (interactive
+ (list (if-let ((modules (magit-region-values 'magit-module-section t)))
+ (magit-confirm 'remove-modules nil "Remove %i modules" nil modules)
+ (list (magit-read-module-path "Remove module")))
+ (magit-submodule-arguments "--force")
+ current-prefix-arg))
+ (when (version< (magit-git-version) "2.12.0")
+ (error "This command requires Git v2.12.0"))
+ (when magit-submodule-remove-trash-gitdirs
+ (setq trash-gitdirs t))
+ (magit-with-toplevel
+ (when-let
+ ((modified
+ (-filter (lambda (module)
+ (let ((default-directory (file-name-as-directory
+ (expand-file-name module))))
+ (and (cddr (directory-files default-directory))
+ (magit-anything-modified-p))))
+ modules)))
+ (if (member "--force" args)
+ (if (magit-confirm 'remove-dirty-modules
+ "Remove dirty module %s"
+ "Remove %i dirty modules"
+ t modified)
+ (dolist (module modified)
+ (let ((default-directory (file-name-as-directory
+ (expand-file-name module))))
+ (magit-git "stash" "push"
+ "-m" "backup before removal of this module")))
+ (setq modules (cl-set-difference modules modified)))
+ (if (cdr modified)
+ (message "Omitting %s modules with uncommitted changes: %s"
+ (length modified)
+ (mapconcat #'identity modified ", "))
+ (message "Omitting module %s, it has uncommitted changes"
+ (car modified)))
+ (setq modules (cl-set-difference modules modified))))
+ (when modules
+ (let ((alist
+ (and trash-gitdirs
+ (--map (split-string it "\0")
+ (magit-git-lines "submodule" "foreach" "-q"
+ "printf \"$sm_path\\0$name\n\"")))))
+ (magit-git "submodule" "absorbgitdirs" "--" modules)
+ (magit-git "submodule" "deinit" args "--" modules)
+ (magit-git "rm" args "--" modules)
+ (when (and trash-gitdirs
+ (magit-confirm 'trash-module-gitdirs
+ "Trash gitdir of module %s"
+ "Trash gitdirs of %i modules"
+ t modules))
+ (dolist (module modules)
+ (if-let ((name (cadr (assoc module alist))))
+ ;; Disregard if `magit-delete-by-moving-to-trash'
+ ;; is nil. Not doing so would be too dangerous.
+ (delete-directory (magit-git-dir
+ (convert-standard-filename
+ (concat "modules/" name)))
+ t t)
+ (error "BUG: Weird module name and/or path for %s" module)))))
+ (magit-refresh))))
+
+;;; Sections
+
+;;;###autoload
+(defun magit-insert-modules ()
+ "Insert submodule sections.
+Hook `magit-module-sections-hook' controls which module sections
+are inserted, and option `magit-module-sections-nested' controls
+whether they are wrapped in an additional section."
+ (when-let ((modules (magit-list-module-paths)))
+ (if magit-module-sections-nested
+ (magit-insert-section (modules nil t)
+ (magit-insert-heading
+ (format "%s (%s)"
+ (propertize "Modules"
+ 'font-lock-face 'magit-section-heading)
+ (length modules)))
+ (magit-insert-section-body
+ (magit--insert-modules)))
+ (magit--insert-modules))))
+
+(defun magit--insert-modules (&optional _section)
+ (magit-run-section-hook 'magit-module-sections-hook))
+
+;;;###autoload
+(defun magit-insert-modules-overview ()
+ "Insert sections for all modules.
+For each section insert the path and the output of `git describe --tags',
+or, failing that, the abbreviated HEAD commit hash."
+ (when-let ((modules (magit-list-module-paths)))
+ (magit-insert-section (modules nil t)
+ (magit-insert-heading
+ (format "%s (%s)"
+ (propertize "Modules overview"
+ 'font-lock-face 'magit-section-heading)
+ (length modules)))
+ (magit-insert-section-body
+ (magit--insert-modules-overview)))))
+
+(defvar magit-modules-overview-align-numbers t)
+
+(defun magit--insert-modules-overview (&optional _section)
+ (magit-with-toplevel
+ (let* ((modules (magit-list-module-paths))
+ (path-format (format "%%-%is "
+ (min (apply 'max (mapcar 'length modules))
+ (/ (window-width) 2))))
+ (branch-format (format "%%-%is " (min 25 (/ (window-width) 3)))))
+ (dolist (module modules)
+ (let ((default-directory
+ (expand-file-name (file-name-as-directory module))))
+ (magit-insert-section (magit-module-section module t)
+ (insert (propertize (format path-format module)
+ 'font-lock-face 'magit-diff-file-heading))
+ (if (not (file-exists-p ".git"))
+ (insert "(unpopulated)")
+ (insert (format
+ branch-format
+ (--if-let (magit-get-current-branch)
+ (propertize it 'font-lock-face 'magit-branch-local)
+ (propertize "(detached)" 'font-lock-face 'warning))))
+ (--if-let (magit-git-string "describe" "--tags")
+ (progn (when (and magit-modules-overview-align-numbers
+ (string-match-p "\\`[0-9]" it))
+ (insert ?\s))
+ (insert (propertize it 'font-lock-face 'magit-tag)))
+ (--when-let (magit-rev-format "%h")
+ (insert (propertize it 'font-lock-face 'magit-hash)))))
+ (insert ?\n))))))
+ (insert ?\n))
+
+(defvar magit-modules-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-list-submodules)
+ map)
+ "Keymap for `modules' sections.")
+
+(defvar magit-module-section-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-file-section-map)
+ (define-key map (kbd "C-j") 'magit-submodule-visit)
+ (define-key map [C-return] 'magit-submodule-visit)
+ (define-key map [remap magit-visit-thing] 'magit-submodule-visit)
+ (define-key map [remap magit-delete-thing] 'magit-submodule-unpopulate)
+ (define-key map "K" 'magit-file-untrack)
+ (define-key map "R" 'magit-file-rename)
+ map)
+ "Keymap for `module' sections.")
+
+(defun magit-submodule-visit (module &optional other-window)
+ "Visit MODULE by calling `magit-status' on it.
+Offer to initialize MODULE if it's not checked out yet.
+With a prefix argument, visit in another window."
+ (interactive (list (or (magit-section-value-if 'module)
+ (magit-read-module-path "Visit module"))
+ current-prefix-arg))
+ (magit-with-toplevel
+ (let ((path (expand-file-name module)))
+ (cond
+ ((file-exists-p (expand-file-name ".git" module))
+ (magit-diff-visit-directory path other-window))
+ ((y-or-n-p (format "Initialize submodule '%s' first?" module))
+ (magit-run-git-async "submodule" "update" "--init" "--" module)
+ (set-process-sentinel
+ magit-this-process
+ (lambda (process event)
+ (let ((magit-process-raise-error t))
+ (magit-process-sentinel process event))
+ (when (and (eq (process-status process) 'exit)
+ (= (process-exit-status process) 0))
+ (magit-diff-visit-directory path other-window)))))
+ ((file-exists-p path)
+ (dired-jump other-window (concat path "/.")))))))
+
+;;;###autoload
+(defun magit-insert-modules-unpulled-from-upstream ()
+ "Insert sections for modules that haven't been pulled from the upstream.
+These sections can be expanded to show the respective commits."
+ (magit--insert-modules-logs "Modules unpulled from @{upstream}"
+ 'modules-unpulled-from-upstream
+ "HEAD..@{upstream}"))
+
+;;;###autoload
+(defun magit-insert-modules-unpulled-from-pushremote ()
+ "Insert sections for modules that haven't been pulled from the push-remote.
+These sections can be expanded to show the respective commits."
+ (magit--insert-modules-logs "Modules unpulled from @{push}"
+ 'modules-unpulled-from-pushremote
+ "HEAD..@{push}"))
+
+;;;###autoload
+(defun magit-insert-modules-unpushed-to-upstream ()
+ "Insert sections for modules that haven't been pushed to the upstream.
+These sections can be expanded to show the respective commits."
+ (magit--insert-modules-logs "Modules unmerged into @{upstream}"
+ 'modules-unpushed-to-upstream
+ "@{upstream}..HEAD"))
+
+;;;###autoload
+(defun magit-insert-modules-unpushed-to-pushremote ()
+ "Insert sections for modules that haven't been pushed to the push-remote.
+These sections can be expanded to show the respective commits."
+ (magit--insert-modules-logs "Modules unpushed to @{push}"
+ 'modules-unpushed-to-pushremote
+ "@{push}..HEAD"))
+
+(defun magit--insert-modules-logs (heading type range)
+ "For internal use, don't add to a hook."
+ (unless (magit-ignore-submodules-p)
+ (when-let ((modules (magit-list-module-paths)))
+ (magit-insert-section section ((eval type) nil t)
+ (string-match "\\`\\(.+\\) \\([^ ]+\\)\\'" heading)
+ (magit-insert-heading
+ (propertize (match-string 1 heading)
+ 'font-lock-face 'magit-section-heading)
+ " "
+ (propertize (match-string 2 heading)
+ 'font-lock-face 'magit-branch-remote)
+ ":")
+ (magit-with-toplevel
+ (dolist (module modules)
+ (when (magit-module-worktree-p module)
+ (let ((default-directory
+ (expand-file-name (file-name-as-directory module))))
+ (when (magit-file-accessible-directory-p default-directory)
+ (magit-insert-section sec (magit-module-section module t)
+ (magit-insert-heading
+ (propertize module
+ 'font-lock-face 'magit-diff-file-heading)
+ ":")
+ (magit-git-wash
+ (apply-partially 'magit-log-wash-log 'module)
+ "-c" "push.default=current" "log" "--oneline" range)
+ (when (> (point)
+ (oref sec content))
+ (delete-char -1))))))))
+ (if (> (point)
+ (oref section content))
+ (insert ?\n)
+ (magit-cancel-section))))))
+
+;;; List
+
+;;;###autoload
+(defun magit-list-submodules ()
+ "Display a list of the current repository's submodules."
+ (interactive)
+ (magit-display-buffer
+ (or (magit-get-mode-buffer 'magit-submodule-list-mode)
+ (magit-with-toplevel
+ (magit-generate-new-buffer 'magit-submodule-list-mode))))
+ (magit-submodule-list-mode)
+ (magit-submodule-list-refresh)
+ (tabulated-list-print))
+
+(defvar magit-submodule-list-mode-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map magit-repolist-mode-map)
+ map)
+ "Local keymap for Magit-Submodule-List mode buffers.")
+
+(define-derived-mode magit-submodule-list-mode tabulated-list-mode "Modules"
+ "Major mode for browsing a list of Git submodules."
+ :group 'magit-repolist-mode
+ (setq-local x-stretch-cursor nil)
+ (setq tabulated-list-padding 0)
+ (setq tabulated-list-sort-key (cons "Path" nil))
+ (setq tabulated-list-format
+ (vconcat (mapcar (pcase-lambda (`(,title ,width ,_fn ,props))
+ (nconc (list title width t)
+ (-flatten props)))
+ magit-submodule-list-columns)))
+ (tabulated-list-init-header)
+ (add-hook 'tabulated-list-revert-hook 'magit-submodule-list-refresh nil t)
+ (setq imenu-prev-index-position-function
+ #'magit-imenu--submodule-prev-index-position-function)
+ (setq imenu-extract-index-name-function
+ #'magit-imenu--submodule-extract-index-name-function))
+
+(defun magit-submodule-list-refresh ()
+ (setq tabulated-list-entries
+ (-keep (lambda (module)
+ (let ((default-directory
+ (expand-file-name (file-name-as-directory module))))
+ (and (file-exists-p ".git")
+ (list module
+ (vconcat
+ (--map (or (funcall (nth 2 it) module) "")
+ magit-submodule-list-columns))))))
+ (magit-list-module-paths))))
+
+(defun magit-modulelist-column-path (path)
+ "Insert the relative path of the submodule."
+ path)
+
+;;; Utilities
+
+(defun magit-submodule--maybe-reuse-gitdir (name path)
+ (let ((gitdir
+ (magit-git-dir (convert-standard-filename (concat "modules/" name)))))
+ (when (and (file-exists-p gitdir)
+ (not (file-exists-p path)))
+ (pcase (read-char-choice
+ (concat
+ gitdir " already exists.\n"
+ "Type [u] to use the existing gitdir and create the working tree\n"
+ " [r] to rename the existing gitdir and clone again\n"
+ " [t] to trash the existing gitdir and clone again\n"
+ " [C-g] to abort ")
+ '(?u ?r ?t))
+ (?u (magit-submodule--restore-worktree (expand-file-name path) gitdir))
+ (?r (rename-file gitdir (concat gitdir "-"
+ (format-time-string "%F-%T"))))
+ (?t (delete-directory gitdir t t))))))
+
+(defun magit-submodule--restore-worktree (worktree gitdir)
+ (make-directory worktree t)
+ (with-temp-file (expand-file-name ".git" worktree)
+ (insert "gitdir: " (file-relative-name gitdir worktree) "\n"))
+ (let ((default-directory worktree))
+ (magit-call-git "reset" "--hard" "HEAD" "--")))
+
+;;; _
+(provide 'magit-submodule)
+;;; magit-submodule.el ends here
--- /dev/null
+;;; magit-subtree.el --- subtree support for Magit -*- lexical-binding: t -*-
+
+;; Copyright (C) 2011-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-subtree "magit-subtree" nil t)
+(transient-define-prefix magit-subtree ()
+ "Import or export subtrees."
+ :man-page "git-subtree"
+ ["Actions"
+ ("i" "Import" magit-subtree-import)
+ ("e" "Export" magit-subtree-export)])
+
+;;;###autoload (autoload 'magit-subtree-import "magit-subtree" nil t)
+(transient-define-prefix magit-subtree-import ()
+ "Import subtrees."
+ :man-page "git-subtree"
+ ["Arguments"
+ (magit-subtree:--prefix)
+ (magit-subtree:--message)
+ ("-s" "Squash" "--squash")]
+ ["Actions"
+ [("a" "Add" magit-subtree-add)
+ ("c" "Add commit" magit-subtree-add-commit)]
+ [("m" "Merge" magit-subtree-merge)
+ ("f" "Pull" magit-subtree-pull)]])
+
+;;;###autoload (autoload 'magit-subtree-export "magit-subtree" nil t)
+(transient-define-prefix magit-subtree-export ()
+ "Export subtrees."
+ :man-page "git-subtree"
+ ["Arguments"
+ (magit-subtree:--prefix)
+ (magit-subtree:--annotate)
+ (magit-subtree:--branch)
+ (magit-subtree:--onto)
+ ("-i" "Ignore joins" "--ignore-joins")
+ ("-j" "Rejoin" "--rejoin")]
+ ["Actions"
+ ("p" "Push" magit-subtree-push)
+ ("s" "Split" magit-subtree-split)])
+
+(transient-define-argument magit-subtree:--prefix ()
+ :description "Prefix"
+ :class 'transient-option
+ :shortarg "-P"
+ :argument "--prefix="
+ :reader 'magit-subtree-read-prefix)
+
+(defun magit-subtree-read-prefix (prompt &optional default _history)
+ (let* ((insert-default-directory nil)
+ (topdir (magit-toplevel))
+ (prefix (read-directory-name (concat prompt ": ") topdir default)))
+ (if (file-name-absolute-p prefix)
+ ;; At least `ido-mode's variant is not compatible.
+ (if (string-prefix-p topdir prefix)
+ (file-relative-name prefix topdir)
+ (user-error "%s isn't inside the repository at %s" prefix topdir))
+ prefix)))
+
+(transient-define-argument magit-subtree:--message ()
+ :description "Message"
+ :class 'transient-option
+ :shortarg "-m"
+ :argument "--message=")
+
+(transient-define-argument magit-subtree:--annotate ()
+ :description "Annotate"
+ :class 'transient-option
+ :key "-a"
+ :argument "--annotate=")
+
+(transient-define-argument magit-subtree:--branch ()
+ :description "Branch"
+ :class 'transient-option
+ :shortarg "-b"
+ :argument "--branch=")
+
+(transient-define-argument magit-subtree:--onto ()
+ :description "Onto"
+ :class 'transient-option
+ :key "-o"
+ :argument "--onto="
+ :reader 'magit-transient-read-revision)
+
+(defun magit-subtree-prefix (transient prompt)
+ (--if-let (--first (string-prefix-p "--prefix=" it)
+ (transient-args transient))
+ (substring it 9)
+ (magit-subtree-read-prefix prompt)))
+
+(defun magit-subtree-arguments (transient)
+ (--remove (string-prefix-p "--prefix=" it)
+ (transient-args transient)))
+
+(defun magit-git-subtree (subcmd prefix &rest args)
+ (magit-run-git-async "subtree" subcmd (concat "--prefix=" prefix) args))
+
+;;;###autoload
+(defun magit-subtree-add (prefix repository ref args)
+ "Add REF from REPOSITORY as a new subtree at PREFIX."
+ (interactive
+ (cons (magit-subtree-prefix 'magit-subtree-import "Add subtree")
+ (let ((remote (magit-read-remote-or-url "From repository")))
+ (list remote
+ (magit-read-refspec "Ref" remote)
+ (magit-subtree-arguments 'magit-subtree-import)))))
+ (magit-git-subtree "add" prefix args repository ref))
+
+;;;###autoload
+(defun magit-subtree-add-commit (prefix commit args)
+ "Add COMMIT as a new subtree at PREFIX."
+ (interactive
+ (list (magit-subtree-prefix 'magit-subtree-import "Add subtree")
+ (magit-read-string-ns "Commit")
+ (magit-subtree-arguments 'magit-subtree-import)))
+ (magit-git-subtree "add" prefix args commit))
+
+;;;###autoload
+(defun magit-subtree-merge (prefix commit args)
+ "Merge COMMIT into the PREFIX subtree."
+ (interactive
+ (list (magit-subtree-prefix 'magit-subtree-import "Merge into subtree")
+ (magit-read-string-ns "Commit")
+ (magit-subtree-arguments 'magit-subtree-import)))
+ (magit-git-subtree "merge" prefix args commit))
+
+;;;###autoload
+(defun magit-subtree-pull (prefix repository ref args)
+ "Pull REF from REPOSITORY into the PREFIX subtree."
+ (interactive
+ (cons (magit-subtree-prefix 'magit-subtree-import "Pull into subtree")
+ (let ((remote (magit-read-remote-or-url "From repository")))
+ (list remote
+ (magit-read-refspec "Ref" remote)
+ (magit-subtree-arguments 'magit-subtree-import)))))
+ (magit-git-subtree "pull" prefix args repository ref))
+
+;;;###autoload
+(defun magit-subtree-push (prefix repository ref args)
+ "Extract the history of the subtree PREFIX and push it to REF on REPOSITORY."
+ (interactive (list (magit-subtree-prefix 'magit-subtree-export "Push subtree")
+ (magit-read-remote-or-url "To repository")
+ (magit-read-string-ns "To reference")
+ (magit-subtree-arguments 'magit-subtree-export)))
+ (magit-git-subtree "push" prefix args repository ref))
+
+;;;###autoload
+(defun magit-subtree-split (prefix commit args)
+ "Extract the history of the subtree PREFIX."
+ (interactive (list (magit-subtree-prefix 'magit-subtree-export "Split subtree")
+ (magit-read-string-ns "Commit")
+ (magit-subtree-arguments 'magit-subtree-export)))
+ (magit-git-subtree "split" prefix args commit))
+
+;;; _
+(provide 'magit-subtree)
+;;; magit-subtree.el ends here
--- /dev/null
+;;; magit-tag.el --- tag functionality -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements tag commands.
+
+;;; Code:
+
+(require 'magit)
+
+;; For `magit-tag-delete'.
+(defvar helm-comp-read-use-marked)
+
+;;;###autoload (autoload 'magit-tag "magit" nil t)
+(transient-define-prefix magit-tag ()
+ "Create or delete a tag."
+ :man-page "git-tag"
+ ["Arguments"
+ ("-f" "Force" ("-f" "--force"))
+ ("-a" "Annotate" ("-a" "--annotate"))
+ ("-s" "Sign" ("-s" "--sign"))
+ (magit-tag:--local-user)]
+ [["Create"
+ ("t" "tag" magit-tag-create)
+ ("r" "release" magit-tag-release)]
+ ["Do"
+ ("k" "delete" magit-tag-delete)
+ ("p" "prune" magit-tag-prune)]])
+
+(defun magit-tag-arguments ()
+ (transient-args 'magit-tag))
+
+(transient-define-argument magit-tag:--local-user ()
+ :description "Sign as"
+ :class 'transient-option
+ :shortarg "-u"
+ :argument "--local-user="
+ :reader 'magit-read-gpg-secret-key
+ :history-key 'magit:--gpg-sign)
+
+;;;###autoload
+(defun magit-tag-create (name rev &optional args)
+ "Create a new tag with the given NAME at REV.
+With a prefix argument annotate the tag.
+\n(git tag [--annotate] NAME REV)"
+ (interactive (list (magit-read-tag "Tag name")
+ (magit-read-branch-or-commit "Place tag on")
+ (let ((args (magit-tag-arguments)))
+ (when current-prefix-arg
+ (cl-pushnew "--annotate" args))
+ args)))
+ (magit-run-git-with-editor "tag" args name rev))
+
+;;;###autoload
+(defun magit-tag-delete (tags)
+ "Delete one or more tags.
+If the region marks multiple tags (and nothing else), then offer
+to delete those, otherwise prompt for a single tag to be deleted,
+defaulting to the tag at point.
+\n(git tag -d TAGS)"
+ (interactive (list (--if-let (magit-region-values 'tag)
+ (magit-confirm t nil "Delete %i tags" nil it)
+ (let ((helm-comp-read-use-marked t))
+ (magit-read-tag "Delete tag" t)))))
+ (magit-run-git "tag" "-d" tags))
+
+;;;###autoload
+(defun magit-tag-prune (tags remote-tags remote)
+ "Offer to delete tags missing locally from REMOTE, and vice versa."
+ (interactive
+ (let* ((remote (magit-read-remote "Prune tags using remote"))
+ (tags (magit-list-tags))
+ (rtags (prog2 (message "Determining remote tags...")
+ (magit-remote-list-tags remote)
+ (message "Determining remote tags...done")))
+ (ltags (-difference tags rtags))
+ (rtags (-difference rtags tags)))
+ (unless (or ltags rtags)
+ (message "Same tags exist locally and remotely"))
+ (unless (magit-confirm t
+ "Delete %s locally"
+ "Delete %i tags locally"
+ 'noabort ltags)
+ (setq ltags nil))
+ (unless (magit-confirm t
+ "Delete %s from remote"
+ "Delete %i tags from remote"
+ 'noabort rtags)
+ (setq rtags nil))
+ (list ltags rtags remote)))
+ (when tags
+ (magit-call-git "tag" "-d" tags))
+ (when remote-tags
+ (magit-run-git-async "push" remote (--map (concat ":" it) remote-tags))))
+
+(defvar magit-tag-version-regexp-alist
+ '(("^[-._+ ]?snapshot\\.?$" . -4)
+ ("^[-._+]$" . -4)
+ ("^[-._+ ]?\\(cvs\\|git\\|bzr\\|svn\\|hg\\|darcs\\)\\.?$" . -4)
+ ("^[-._+ ]?unknown\\.?$" . -4)
+ ("^[-._+ ]?alpha\\.?$" . -3)
+ ("^[-._+ ]?beta\\.?$" . -2)
+ ("^[-._+ ]?\\(pre\\|rc\\)\\.?$" . -1))
+ "Overrides `version-regexp-alist' for `magit-tag-release'.
+See also `magit-release-tag-regexp'.")
+
+(defvar magit-release-tag-regexp "\\`\
+\\(?1:\\(?:v\\(?:ersion\\)?\\|r\\(?:elease\\)?\\)?[-_]?\\)?\
+\\(?2:[0-9]+\\(?:\\.[0-9]+\\)*\
+\\(?:-[a-zA-Z0-9-]+\\(?:\\.[a-zA-Z0-9-]+\\)*\\)?\\)\\'"
+ "Regexp used by `magit-tag-release' to parse release tags.
+
+The first submatch must match the prefix, if any. The second
+submatch must match the version string.
+
+If this matches versions that are not dot separated numbers,
+then `magit-tag-version-regexp-alist' has to contain entries
+for the separators allowed here.")
+
+;;;###autoload
+(defun magit-tag-release (tag msg &optional args)
+ "Create a release tag.
+
+Assume that release tags match `magit-release-tag-regexp'.
+
+First prompt for the name of the new tag using the highest
+existing tag as initial input and leaving it to the user to
+increment the desired part of the version string.
+
+If `--annotate' is enabled, then prompt for the message of the
+new tag. Base the proposed tag message on the message of the
+highest tag, provided that that contains the corresponding
+version string and substituting the new version string for that.
+Otherwise propose something like \"Foo-Bar 1.2.3\", given, for
+example, a TAG \"v1.2.3\" and a repository located at something
+like \"/path/to/foo-bar\"."
+ (interactive
+ (save-match-data
+ (pcase-let*
+ ((`(,pver ,ptag ,pmsg) (car (magit--list-releases)))
+ (tag (read-string "Create release tag: " ptag))
+ (ver (and (string-match magit-release-tag-regexp tag)
+ (match-string 2 tag)))
+ (args (magit-tag-arguments)))
+ (list tag
+ (and (member "--annotate" args)
+ (read-string
+ (format "Message for %S: " tag)
+ (cond ((and pver (string-match (regexp-quote pver) pmsg))
+ (replace-match ver t t pmsg))
+ ((and ptag (string-match (regexp-quote ptag) pmsg))
+ (replace-match tag t t pmsg))
+ (t (format "%s %s"
+ (capitalize
+ (file-name-nondirectory
+ (directory-file-name (magit-toplevel))))
+ ver)))))
+ args))))
+ (magit-run-git-async "tag" args (and msg (list "-m" msg)) tag)
+ (set-process-sentinel
+ magit-this-process
+ (lambda (process event)
+ (when (memq (process-status process) '(exit signal))
+ (magit-process-sentinel process event)
+ (magit-refs-setup-buffer "HEAD" (magit-show-refs-arguments))))))
+
+(defun magit--list-releases ()
+ "Return a list of releases.
+The list is ordered, beginning with the highest release.
+Each release element has the form (VERSION TAG MESSAGE).
+`magit-release-tag-regexp' is used to determine whether
+a tag qualifies as a release tag."
+ (save-match-data
+ (mapcar
+ #'cdr
+ (nreverse
+ (cl-sort (cl-mapcan
+ (lambda (line)
+ (and (string-match " +" line)
+ (let ((tag (substring line 0 (match-beginning 0)))
+ (msg (substring line (match-end 0))))
+ (and (string-match magit-release-tag-regexp tag)
+ (let ((ver (match-string 2 tag))
+ (version-regexp-alist
+ magit-tag-version-regexp-alist))
+ (list (list (version-to-list ver)
+ ver tag msg)))))))
+ ;; Cannot rely on "--sort=-version:refname" because
+ ;; that gets confused if the version prefix has changed.
+ (magit-git-lines "tag" "-n"))
+ ;; The inverse of this function does not exist.
+ #'version-list-< :key #'car)))))
+
+;;; _
+(provide 'magit-tag)
+;;; magit-tag.el ends here
--- /dev/null
+;;; magit-transient.el --- support for transients -*- lexical-binding: t -*-
+
+;; Copyright (C) 2008-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements Magit-specific prefix and suffix classes,
+;; and their methods.
+
+;;; Code:
+
+(require 'magit-git)
+(require 'magit-mode)
+(require 'magit-process)
+
+(require 'transient)
+
+;;; Classes
+
+(defclass magit--git-variable (transient-variable)
+ ((scope :initarg :scope)))
+
+(defclass magit--git-variable:choices (magit--git-variable)
+ ((choices :initarg :choices)
+ (fallback :initarg :fallback :initform nil)
+ (default :initarg :default :initform nil)))
+
+(defclass magit--git-variable:urls (magit--git-variable)
+ ((seturl-arg :initarg :seturl-arg :initform nil)))
+
+;;; Methods
+;;;; Init
+
+(cl-defmethod transient-init-scope ((obj magit--git-variable))
+ (oset obj scope
+ (cond (transient--prefix
+ (oref transient--prefix scope))
+ ((slot-boundp obj 'scope)
+ (funcall (oref obj scope) obj)))))
+
+(cl-defmethod transient-init-value ((obj magit--git-variable))
+ (let ((variable (format (oref obj variable)
+ (oref obj scope))))
+ (oset obj variable variable)
+ (oset obj value
+ (cond ((oref obj multi-value)
+ (magit-get-all variable))
+ (t
+ (magit-git-string "config" "--local" variable))))))
+
+;;;; Read
+
+(cl-defmethod transient-infix-read :around ((obj magit--git-variable:urls))
+ (mapcar (lambda (url)
+ (if (string-prefix-p "~" url)
+ (expand-file-name url)
+ url))
+ (cl-call-next-method obj)))
+
+(cl-defmethod transient-infix-read ((obj magit--git-variable:choices))
+ (let ((choices (oref obj choices)))
+ (when (functionp choices)
+ (setq choices (funcall choices)))
+ (if-let ((value (oref obj value)))
+ (cadr (member value choices))
+ (car choices))))
+
+;;;; Readers
+
+(defun magit-transient-read-person (prompt initial-input history)
+ (magit-completing-read
+ prompt
+ (mapcar (lambda (line)
+ (save-excursion
+ (and (string-match "\\`[\s\t]+[0-9]+\t" line)
+ (list (substring line (match-end 0))))))
+ (magit-git-lines "shortlog" "-n" "-s" "-e" "HEAD"))
+ nil nil initial-input history))
+
+(defun magit-transient-read-revision (prompt initial-input history)
+ (or (magit-completing-read prompt (cons "HEAD" (magit-list-refnames))
+ nil nil initial-input history
+ (or (magit-branch-or-commit-at-point)
+ (magit-get-current-branch)))
+ (user-error "Nothing selected")))
+
+;;;; Set
+
+(cl-defmethod transient-infix-set ((obj magit--git-variable) value)
+ (let ((variable (oref obj variable)))
+ (oset obj value value)
+ (if (oref obj multi-value)
+ (magit-set-all value variable)
+ (magit-set value variable))
+ (magit-refresh)
+ (unless (or value transient--prefix)
+ (message "Unset %s" variable))))
+
+(cl-defmethod transient-infix-set ((obj magit--git-variable:urls) values)
+ (let ((previous (oref obj value))
+ (seturl (oref obj seturl-arg))
+ (remote (oref transient--prefix scope)))
+ (oset obj value values)
+ (dolist (v (-difference values previous))
+ (magit-call-git "remote" "set-url" seturl "--add" remote v))
+ (dolist (v (-difference previous values))
+ (magit-call-git "remote" "set-url" seturl "--delete" remote
+ (concat "^" (regexp-quote v) "$")))
+ (magit-refresh)))
+
+;;;; Draw
+
+(cl-defmethod transient-format-description ((obj magit--git-variable))
+ (or (oref obj description)
+ (oref obj variable)))
+
+(cl-defmethod transient-format-value ((obj magit--git-variable))
+ (if-let ((value (oref obj value)))
+ (if (oref obj multi-value)
+ (if (cdr value)
+ (mapconcat (lambda (v)
+ (concat "\n "
+ (propertize v 'face 'transient-value)))
+ value "")
+ (propertize (car value) 'face 'transient-value))
+ (propertize (car (split-string value "\n"))
+ 'face 'transient-value))
+ (propertize "unset" 'face 'transient-inactive-value)))
+
+(cl-defmethod transient-format-value ((obj magit--git-variable:choices))
+ (let* ((variable (oref obj variable))
+ (choices (oref obj choices))
+ (local (magit-git-string "config" "--local" variable))
+ (global (magit-git-string "config" "--global" variable))
+ (default (oref obj default))
+ (fallback (oref obj fallback))
+ (fallback (and fallback
+ (when-let ((val (magit-get fallback)))
+ (concat fallback ":" val)))))
+ (when (functionp choices)
+ (setq choices (funcall choices)))
+ (concat
+ (propertize "[" 'face 'transient-inactive-value)
+ (mapconcat (lambda (choice)
+ (propertize choice 'face (if (equal choice local)
+ (if (member choice choices)
+ 'transient-value
+ 'font-lock-warning-face)
+ 'transient-inactive-value)))
+ (if (and local (not (member local choices)))
+ (cons local choices)
+ choices)
+ (propertize "|" 'face 'transient-inactive-value))
+ (and (or global fallback default)
+ (concat
+ (propertize "|" 'face 'transient-inactive-value)
+ (cond (global
+ (propertize (concat "global:" global)
+ 'face (cond (local
+ 'transient-inactive-value)
+ ((member global choices)
+ 'transient-value)
+ (t
+ 'font-lock-warning-face))))
+ (fallback
+ (propertize fallback
+ 'face (if local
+ 'transient-inactive-value
+ 'transient-value)))
+ (default
+ (propertize (concat "default:" default)
+ 'face (if local
+ 'transient-inactive-value
+ 'transient-value))))))
+ (propertize "]" 'face 'transient-inactive-value))))
+
+;;; _
+(provide 'magit-transient)
+;;; magit-transient.el ends here
+
--- /dev/null
+;;; magit-utils.el --- various utilities -*- lexical-binding: t; coding: utf-8 -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonas@bernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Contains code from GNU Emacs https://www.gnu.org/software/emacs,
+;; released under the GNU General Public License version 3 or later.
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library defines several utility functions used by several
+;; other libraries which cannot depend on one another (because
+;; circular dependencies are not good). Luckily most (all) of these
+;; functions have very little (nothing) to do with Git, so we not only
+;; have to do this, it even makes sense.
+
+;; Unfortunately there are also some options which are used by several
+;; libraries which cannot depend on one another, they are defined here
+;; too.
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'dash)
+(require 'eieio)
+(require 'seq)
+(require 'subr-x)
+
+(require 'crm)
+
+(eval-when-compile (require 'ido))
+(declare-function ido-completing-read+ "ido-completing-read+"
+ (prompt collection &optional predicate
+ require-match initial-input
+ hist def inherit-input-method))
+(declare-function Info-get-token "info" (pos start all &optional errorstring))
+
+(eval-when-compile (require 'vc-git))
+(declare-function vc-git--run-command-string "vc-git" (file &rest args))
+
+(eval-when-compile (require 'which-func))
+(declare-function which-function "which-func" ())
+
+(defvar magit-wip-before-change-mode)
+
+;;; Options
+
+(defcustom magit-completing-read-function 'magit-builtin-completing-read
+ "Function to be called when requesting input from the user.
+
+If you have enabled `ivy-mode' or `helm-mode', then you don't
+have to customize this option; `magit-builtin-completing-read'
+will work just fine. However, if you use Ido completion, then
+you do have to use `magit-ido-completing-read', because Ido is
+less well behaved than the former, more modern alternatives.
+
+If you would like to use Ivy or Helm completion with Magit but
+not enable the respective modes globally, then customize this
+option to use `ivy-completing-read' or
+`helm--completing-read-default'. If you choose to use
+`ivy-completing-read', note that the items may always be shown in
+alphabetical order, depending on your version of Ivy."
+ :group 'magit-essentials
+ :type '(radio (function-item magit-builtin-completing-read)
+ (function-item magit-ido-completing-read)
+ (function-item ivy-completing-read)
+ (function-item helm--completing-read-default)
+ (function :tag "Other function")))
+
+(defcustom magit-dwim-selection
+ '((magit-stash-apply nil t)
+ (magit-stash-branch nil t)
+ (magit-stash-branch-here nil t)
+ (magit-stash-format-patch nil t)
+ (magit-stash-drop nil ask)
+ (magit-stash-pop nil ask)
+ (forge-browse-dwim nil t)
+ (forge-browse-commit nil t)
+ (forge-browse-branch nil t)
+ (forge-browse-remote nil t)
+ (forge-browse-issue nil t)
+ (forge-browse-pullreq nil t)
+ (forge-edit-topic-title nil t)
+ (forge-edit-topic-state nil t)
+ (forge-edit-topic-milestone nil t)
+ (forge-edit-topic-labels nil t)
+ (forge-edit-topic-marks nil t)
+ (forge-edit-topic-assignees nil t)
+ (forge-edit-topic-review-requests nil t)
+ (forge-edit-topic-note nil t)
+ (forge-pull-pullreq nil t)
+ (forge-visit-issue nil t)
+ (forge-visit-pullreq nil t))
+ "When not to offer alternatives and ask for confirmation.
+
+Many commands by default ask the user to select from a list of
+possible candidates. They do so even when there is a thing at
+point that they can act on, which is then offered as the default.
+
+This option can be used to tell certain commands to use the thing
+at point instead of asking the user to select a candidate to act
+on, with or without confirmation.
+
+The value has the form ((COMMAND nil|PROMPT DEFAULT)...).
+
+- COMMAND is the command that should not prompt for a choice.
+ To have an effect, the command has to use the function
+ `magit-completing-read' or a utility function which in turn uses
+ that function.
+
+- If the command uses `magit-completing-read' multiple times, then
+ PROMPT can be used to only affect one of these uses. PROMPT, if
+ non-nil, is a regular expression that is used to match against
+ the PROMPT argument passed to `magit-completing-read'.
+
+- DEFAULT specifies how to use the default. If it is t, then
+ the DEFAULT argument passed to `magit-completing-read' is used
+ without confirmation. If it is `ask', then the user is given
+ a chance to abort. DEFAULT can also be nil, in which case the
+ entry has no effect."
+ :package-version '(magit . "2.12.0")
+ :group 'magit-commands
+ :type '(repeat
+ (list (symbol :tag "Command") ; It might not be fboundp yet.
+ (choice (const :tag "for all prompts" nil)
+ (regexp :tag "for prompts matching regexp"))
+ (choice (const :tag "offer other choices" nil)
+ (const :tag "require confirmation" ask)
+ (const :tag "use default without confirmation" t)))))
+
+(defconst magit--confirm-actions
+ '((const discard)
+ (const reverse)
+ (const stage-all-changes)
+ (const unstage-all-changes)
+ (const delete)
+ (const trash)
+ (const resurrect)
+ (const untrack)
+ (const rename)
+ (const reset-bisect)
+ (const abort-rebase)
+ (const abort-merge)
+ (const merge-dirty)
+ (const delete-unmerged-branch)
+ (const delete-pr-remote)
+ (const drop-stashes)
+ (const set-and-push)
+ (const amend-published)
+ (const rebase-published)
+ (const edit-published)
+ (const remove-modules)
+ (const remove-dirty-modules)
+ (const trash-module-gitdirs)
+ (const kill-process)
+ (const safe-with-wip)))
+
+(defcustom magit-no-confirm '(set-and-push)
+ "A list of symbols for actions Magit should not confirm, or t.
+
+Many potentially dangerous commands by default ask the user for
+confirmation. Each of the below symbols stands for an action
+which, when invoked unintentionally or without being fully aware
+of the consequences, could lead to tears. In many cases there
+are several commands that perform variations of a certain action,
+so we don't use the command names but more generic symbols.
+
+Applying changes:
+
+ `discard' Discarding one or more changes (i.e. hunks or the
+ complete diff for a file) loses that change, obviously.
+
+ `reverse' Reverting one or more changes can usually be undone
+ by reverting the reversion.
+
+ `stage-all-changes', `unstage-all-changes' When there are both
+ staged and unstaged changes, then un-/staging everything would
+ destroy that distinction. Of course that also applies when
+ un-/staging a single change, but then less is lost and one does
+ that so often that having to confirm every time would be
+ unacceptable.
+
+Files:
+
+ `delete' When a file that isn't yet tracked by Git is deleted
+ then it is completely lost, not just the last changes. Very
+ dangerous.
+
+ `trash' Instead of deleting a file it can also be move to the
+ system trash. Obviously much less dangerous than deleting it.
+
+ Also see option `magit-delete-by-moving-to-trash'.
+
+ `resurrect' A deleted file can easily be resurrected by
+ \"deleting\" the deletion, which is done using the same command
+ that was used to delete the same file in the first place.
+
+ `untrack' Untracking a file can be undone by tracking it again.
+
+ `rename' Renaming a file can easily be undone.
+
+Sequences:
+
+ `reset-bisect' Aborting (known to Git as \"resetting\") a
+ bisect operation loses all information collected so far.
+
+ `abort-rebase' Aborting a rebase throws away all already
+ modified commits, but it's possible to restore those from the
+ reflog.
+
+ `abort-merge' Aborting a merge throws away all conflict
+ resolutions which has already been carried out by the user.
+
+ `merge-dirty' Merging with a dirty worktree can make it hard to
+ go back to the state before the merge was initiated.
+
+References:
+
+ `delete-unmerged-branch' Once a branch has been deleted it can
+ only be restored using low-level recovery tools provided by
+ Git. And even then the reflog is gone. The user always has
+ to confirm the deletion of a branch by accepting the default
+ choice (or selecting another branch), but when a branch has
+ not been merged yet, also make sure the user is aware of that.
+
+ `delete-pr-remote' When deleting a branch that was created from
+ a pull-request and if no other branches still exist on that
+ remote, then `magit-branch-delete' offers to delete the remote
+ as well. This should be safe because it only happens if no
+ other refs exist in the remotes namespace, and you can recreate
+ the remote if necessary.
+
+ `drop-stashes' Dropping a stash is dangerous because Git stores
+ stashes in the reflog. Once a stash is removed, there is no
+ going back without using low-level recovery tools provided by
+ Git. When a single stash is dropped, then the user always has
+ to confirm by accepting the default (or selecting another).
+ This action only concerns the deletion of multiple stashes at
+ once.
+
+Publishing:
+
+ `set-and-push' When pushing to the upstream or the push-remote
+ and that isn't actually configured yet, then the user can first
+ set the target. If s/he confirms the default too quickly, then
+ s/he might end up pushing to the wrong branch and if the remote
+ repository is configured to disallow fixing such mistakes, then
+ that can be quite embarrassing and annoying.
+
+Edit published history:
+
+ Without adding these symbols here, you will be warned before
+ editing commits that have already been pushed to one of the
+ branches listed in `magit-published-branches'.
+
+ `amend-published' Affects most commands that amend to \"HEAD\".
+
+ `rebase-published' Affects commands that perform interactive
+ rebases. This includes commands from the commit popup that
+ modify a commit other than \"HEAD\", namely the various fixup
+ and squash variants.
+
+ `edit-published' Affects the commands `magit-edit-line-commit'
+ and `magit-diff-edit-hunk-commit'. These two commands make
+ it quite easy to accidentally edit a published commit, so you
+ should think twice before configuring them not to ask for
+ confirmation.
+
+ To disable confirmation completely, add all three symbols here
+ or set `magit-published-branches' to nil.
+
+Removing modules:
+
+ `remove-modules' When you remove the working directory of a
+ module that does not contain uncommitted changes, then that is
+ safer than doing so when there are uncommitted changes and/or
+ when you also remove the gitdir. Still, you don't want to do
+ that by accident.
+
+ `remove-dirty-modules' When you remove the working directory of
+ a module that contains uncommitted changes, then those changes
+ are gone for good. It is better to go to the module, inspect
+ these changes and only if appropriate discard them manually.
+
+ `trash-module-gitdirs' When you remove the gitdir of a module,
+ then all unpushed changes are gone for good. It is very easy
+ to forget that you have some unfinished work on an unpublished
+ feature branch or even in a stash.
+
+ Actually there are some safety precautions in place, that might
+ help you out if you make an unwise choice here, but don't count
+ on it. In case of emergency, stay calm and check the stash and
+ the `trash-directory' for traces of lost work.
+
+Various:
+
+ `kill-process' There seldom is a reason to kill a process.
+
+Global settings:
+
+ Instead of adding all of the above symbols to the value of this
+ option you can also set it to the atom `t', which has the same
+ effect as adding all of the above symbols. Doing that most
+ certainly is a bad idea, especially because other symbols might
+ be added in the future. So even if you don't want to be asked
+ for confirmation for any of these actions, you are still better
+ of adding all of the respective symbols individually.
+
+ When `magit-wip-before-change-mode' is enabled then these actions
+ can fairly easily be undone: `discard', `reverse',
+ `stage-all-changes', and `unstage-all-changes'. If and only if
+ this mode is enabled, then `safe-with-wip' has the same effect
+ as adding all of these symbols individually."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-essentials
+ :group 'magit-commands
+ :type `(choice (const :tag "Always require confirmation" nil)
+ (const :tag "Never require confirmation" t)
+ (set :tag "Require confirmation except for"
+ ;; `remove-dirty-modules' and
+ ;; `trash-module-gitdirs' intentionally
+ ;; omitted.
+ ,@magit--confirm-actions)))
+
+(defcustom magit-slow-confirm '(drop-stashes)
+ "Whether to ask user \"y or n\" or \"yes or no\" questions.
+
+When this is nil, then `y-or-n-p' is used when the user has to
+confirm a potentially destructive action. When this is t, then
+`yes-or-no-p' is used instead. If this is a list of symbols
+identifying actions, then `yes-or-no-p' is used for those,
+`y-or-no-p' for all others. The list of actions is the same as
+for `magit-no-confirm' (which see)."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-miscellaneous
+ :type `(choice (const :tag "Always ask \"yes or no\" questions" t)
+ (const :tag "Always ask \"y or n\" questions" nil)
+ (set :tag "Ask \"yes or no\" questions only for"
+ ,@magit--confirm-actions)))
+
+(defcustom magit-no-message nil
+ "A list of messages Magit should not display.
+
+Magit displays most echo area messages using `message', but a few
+are displayed using `magit-message' instead, which takes the same
+arguments as the former, FORMAT-STRING and ARGS. `magit-message'
+forgoes printing a message if any member of this list is a prefix
+of the respective FORMAT-STRING.
+
+If Magit prints a message which causes you grief, then please
+first investigate whether there is another option which can be
+used to suppress it. If that is not the case, then ask the Magit
+maintainers to start using `magit-message' instead of `message'
+in that case. We are not proactively replacing all uses of
+`message' with `magit-message', just in case someone *might* find
+some of these messages useless.
+
+Messages which can currently be suppressed using this option are:
+* \"Turning on magit-auto-revert-mode...\""
+ :package-version '(magit . "2.8.0")
+ :group 'magit-miscellaneous
+ :type '(repeat string))
+
+(defcustom magit-ellipsis ?…
+ "Character used to abbreviate text.
+
+Currently this is used to abbreviate author names in the margin
+and in process buffers to elide `magit-git-global-arguments'."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-miscellaneous
+ :type 'character)
+
+(defcustom magit-update-other-window-delay 0.2
+ "Delay before automatically updating the other window.
+
+When moving around in certain buffers, then certain other
+buffers, which are being displayed in another window, may
+optionally be updated to display information about the
+section at point.
+
+When holding down a key to move by more than just one section,
+then that would update that buffer for each section on the way.
+To prevent that, updating the revision buffer is delayed, and
+this option controls for how long. For optimal experience you
+might have to adjust this delay and/or the keyboard repeat rate
+and delay of your graphical environment or operating system."
+ :package-version '(magit . "2.3.0")
+ :group 'magit-miscellaneous
+ :type 'number)
+
+(defcustom magit-view-git-manual-method 'info
+ "How links to Git documentation are followed from Magit's Info manuals.
+
+`info' Follow the link to the node in the `gitman' Info manual
+ as usual. Unfortunately that manual is not installed by
+ default on some platforms, and when it is then the nodes
+ look worse than the actual manpages.
+
+`man' View the respective man-page using the `man' package.
+
+`woman' View the respective man-page using the `woman' package."
+ :package-version '(magit . "2.9.0")
+ :group 'magit-miscellaneous
+ :type '(choice (const :tag "view info manual" info)
+ (const :tag "view manpage using `man'" man)
+ (const :tag "view manpage using `woman'" woman)))
+
+;;; User Input
+
+(defvar helm-completion-in-region-default-sort-fn)
+(defvar helm-crm-default-separator)
+(defvar ivy-sort-functions-alist)
+(defvar ivy-sort-matches-functions-alist)
+
+(defvar magit-completing-read--silent-default nil)
+
+(defun magit-completing-read (prompt collection &optional
+ predicate require-match initial-input
+ hist def fallback)
+ "Read a choice in the minibuffer, or use the default choice.
+
+This is the function that Magit commands use when they need the
+user to select a single thing to act on. The arguments have the
+same meaning as for `completing-read', except for FALLBACK, which
+is unique to this function and is described below.
+
+Instead of asking the user to choose from a list of possible
+candidates, this function may instead just return the default
+specified by DEF, with or without requiring user confirmation.
+Whether that is the case depends on PROMPT, `this-command' and
+`magit-dwim-selection'. See the documentation of the latter for
+more information.
+
+If it does use the default without the user even having to
+confirm that, then `magit-completing-read--silent-default' is set
+to t, otherwise nil.
+
+If it does read a value in the minibuffer, then this function
+acts similarly to `completing-read', except for the following:
+
+- COLLECTION must be a list of choices. A function is not
+ supported.
+
+- If REQUIRE-MATCH is nil and the user exits without a choice,
+ then nil is returned instead of an empty string.
+
+- If REQUIRE-MATCH is non-nil and the user exits without a
+ choice, `user-error' is raised.
+
+- FALLBACK specifies a secondary default that is only used if
+ the primary default DEF is nil. The secondary default is not
+ subject to `magit-dwim-selection' — if DEF is nil but FALLBACK
+ is not, then this function always asks the user to choose a
+ candidate, just as if both defaults were nil.
+
+- \": \" is appended to PROMPT.
+
+- PROMPT is modified to end with \" (default DEF|FALLBACK): \"
+ provided that DEF or FALLBACK is non-nil, that neither
+ `ivy-mode' nor `helm-mode' is enabled, and that
+ `magit-completing-read-function' is set to its default value of
+ `magit-builtin-completing-read'."
+ (setq magit-completing-read--silent-default nil)
+ (if-let ((dwim (and def
+ (nth 2 (-first (pcase-lambda (`(,cmd ,re ,_))
+ (and (eq this-command cmd)
+ (or (not re)
+ (string-match-p re prompt))))
+ magit-dwim-selection)))))
+ (if (eq dwim 'ask)
+ (if (y-or-n-p (format "%s %s? " prompt def))
+ def
+ (user-error "Abort"))
+ (setq magit-completing-read--silent-default t)
+ def)
+ (unless def
+ (setq def fallback))
+ (let ((command this-command)
+ (reply (funcall magit-completing-read-function
+ (concat prompt ": ")
+ (if (and def (not (member def collection)))
+ (cons def collection)
+ collection)
+ predicate
+ require-match initial-input hist def)))
+ (setq this-command command)
+ ;; Note: Avoid `string=' to support `helm-comp-read-use-marked'.
+ (if (equal reply "")
+ (if require-match
+ (user-error "Nothing selected")
+ nil)
+ reply))))
+
+(defun magit--completion-table (collection)
+ (lambda (string pred action)
+ (if (eq action 'metadata)
+ '(metadata (display-sort-function . identity))
+ (complete-with-action action collection string pred))))
+
+(defun magit-builtin-completing-read
+ (prompt choices &optional predicate require-match initial-input hist def)
+ "Magit wrapper for standard `completing-read' function."
+ (unless (or (bound-and-true-p helm-mode)
+ (bound-and-true-p ivy-mode))
+ (setq prompt (magit-prompt-with-default prompt def))
+ (setq choices (magit--completion-table choices)))
+ (cl-letf (((symbol-function 'completion-pcm--all-completions)
+ #'magit-completion-pcm--all-completions))
+ (let ((ivy-sort-functions-alist nil))
+ (completing-read prompt choices
+ predicate require-match
+ initial-input hist def))))
+
+(defun magit-completing-read-multiple
+ (prompt choices &optional sep default hist keymap)
+ "Read multiple items from CHOICES, separated by SEP.
+
+Set up the `crm' variables needed to read multiple values with
+`read-from-minibuffer'.
+
+SEP is a regexp matching characters that can separate choices.
+When SEP is nil, it defaults to `crm-default-separator'.
+DEFAULT, HIST, and KEYMAP are passed to `read-from-minibuffer'.
+When KEYMAP is nil, it defaults to `crm-local-completion-map'.
+
+Unlike `completing-read-multiple', the return value is not split
+into a list."
+ (let* ((crm-separator (or sep crm-default-separator))
+ (crm-completion-table (magit--completion-table choices))
+ (choose-completion-string-functions
+ '(crm--choose-completion-string))
+ (minibuffer-completion-table #'crm--collection-fn)
+ (minibuffer-completion-confirm t)
+ (helm-completion-in-region-default-sort-fn nil)
+ (helm-crm-default-separator nil)
+ (ivy-sort-matches-functions-alist nil)
+ (input
+ (cl-letf (((symbol-function 'completion-pcm--all-completions)
+ #'magit-completion-pcm--all-completions))
+ (read-from-minibuffer
+ (concat prompt (and default (format " (%s)" default)) ": ")
+ nil (or keymap crm-local-completion-map)
+ nil hist default))))
+ (when (string-equal input "")
+ (or (setq input default)
+ (user-error "Nothing selected")))
+ input))
+
+(defun magit-completing-read-multiple*
+ (prompt table &optional predicate require-match initial-input
+ hist def inherit-input-method)
+ "Read multiple strings in the minibuffer, with completion.
+Like `completing-read-multiple' but don't mess with order of
+TABLE. Also bind `helm-completion-in-region-default-sort-fn'
+to nil."
+ (unwind-protect
+ (cl-letf (((symbol-function 'completion-pcm--all-completions)
+ #'magit-completion-pcm--all-completions))
+ (add-hook 'choose-completion-string-functions
+ 'crm--choose-completion-string)
+ (let* ((minibuffer-completion-table #'crm--collection-fn)
+ (minibuffer-completion-predicate predicate)
+ ;; see completing_read in src/minibuf.c
+ (minibuffer-completion-confirm
+ (unless (eq require-match t) require-match))
+ (crm-completion-table (magit--completion-table table))
+ (map (if require-match
+ crm-local-must-match-map
+ crm-local-completion-map))
+ (helm-completion-in-region-default-sort-fn nil)
+ (ivy-sort-matches-functions-alist nil)
+ ;; If the user enters empty input, `read-from-minibuffer'
+ ;; returns the empty string, not DEF.
+ (input (read-from-minibuffer
+ prompt initial-input map
+ nil hist def inherit-input-method)))
+ (and def (string-equal input "") (setq input def))
+ ;; Remove empty strings in the list of read strings.
+ (split-string input crm-separator t)))
+ (remove-hook 'choose-completion-string-functions
+ 'crm--choose-completion-string)))
+
+(defun magit-ido-completing-read
+ (prompt choices &optional predicate require-match initial-input hist def)
+ "Ido-based `completing-read' almost-replacement.
+
+Unfortunately `ido-completing-read' is not suitable as a
+drop-in replacement for `completing-read', instead we use
+`ido-completing-read+' from the third-party package by the
+same name."
+ (if (require 'ido-completing-read+ nil t)
+ (ido-completing-read+ prompt choices predicate require-match
+ initial-input hist
+ (or def (and require-match (car choices))))
+ (display-warning 'magit "ido-completing-read+ is not installed
+
+To use Ido completion with Magit you need to install the
+third-party `ido-completing-read+' packages. Falling
+back to built-in `completing-read' for now." :error)
+ (magit-builtin-completing-read prompt choices predicate require-match
+ initial-input hist def)))
+
+(defun magit-prompt-with-default (prompt def)
+ (if (and def (> (length prompt) 2)
+ (string-equal ": " (substring prompt -2)))
+ (format "%s (default %s): " (substring prompt 0 -2) def)
+ prompt))
+
+(defvar magit-minibuffer-local-ns-map
+ (let ((map (make-sparse-keymap)))
+ (set-keymap-parent map minibuffer-local-map)
+ (define-key map "\s" 'magit-whitespace-disallowed)
+ (define-key map "\t" 'magit-whitespace-disallowed)
+ map))
+
+(defun magit-whitespace-disallowed ()
+ "Beep to tell the user that whitespace is not allowed."
+ (interactive)
+ (ding)
+ (message "Whitespace isn't allowed here")
+ (setq defining-kbd-macro nil)
+ (force-mode-line-update))
+
+(defun magit-read-string (prompt &optional initial-input history default-value
+ inherit-input-method no-whitespace)
+ "Read a string from the minibuffer, prompting with string PROMPT.
+
+This is similar to `read-string', but
+* empty input is only allowed if DEFAULT-VALUE is non-nil in
+ which case that is returned,
+* whitespace is not allowed and leading and trailing whitespace is
+ removed automatically if NO-WHITESPACE is non-nil,
+* \": \" is appended to PROMPT, and
+* an invalid DEFAULT-VALUE is silently ignored."
+ (when default-value
+ (when (consp default-value)
+ (setq default-value (car default-value)))
+ (unless (stringp default-value)
+ (setq default-value nil)))
+ (let* ((minibuffer-completion-table nil)
+ (val (read-from-minibuffer
+ (magit-prompt-with-default (concat prompt ": ") default-value)
+ initial-input (and no-whitespace magit-minibuffer-local-ns-map)
+ nil history default-value inherit-input-method))
+ (trim (lambda (regexp string)
+ (save-match-data
+ (if (string-match regexp string)
+ (replace-match "" t t string)
+ string)))))
+ (when (and (string= val "") default-value)
+ (setq val default-value))
+ (when no-whitespace
+ (setq val (funcall trim "\\`\\(?:[ \t\n\r]+\\)"
+ (funcall trim "\\(?:[ \t\n\r]+\\)\\'" val))))
+ (cond ((string= val "")
+ (user-error "Need non-empty input"))
+ ((and no-whitespace (string-match-p "[\s\t\n]" val))
+ (user-error "Input contains whitespace"))
+ (t val))))
+
+(defun magit-read-string-ns (prompt &optional initial-input history
+ default-value inherit-input-method)
+ "Call `magit-read-string' with non-nil NO-WHITESPACE."
+ (magit-read-string prompt initial-input history default-value
+ inherit-input-method t))
+
+(defmacro magit-read-char-case (prompt verbose &rest clauses)
+ (declare (indent 2)
+ (debug (form form &rest (characterp form body))))
+ `(prog1 (pcase (read-char-choice
+ (concat ,prompt
+ (mapconcat #'identity
+ (list ,@(mapcar #'cadr clauses))
+ ", ")
+ ,(if verbose ", or [C-g] to abort " " "))
+ ',(mapcar #'car clauses))
+ ,@(--map `(,(car it) ,@(cddr it)) clauses))
+ (message "")))
+
+(defun magit-y-or-n-p (prompt &optional action)
+ "Ask user a \"y or n\" or a \"yes or no\" question using PROMPT.
+Which kind of question is used depends on whether
+ACTION is a member of option `magit-slow-confirm'."
+ (if (or (eq magit-slow-confirm t)
+ (and action (member action magit-slow-confirm)))
+ (yes-or-no-p prompt)
+ (y-or-n-p prompt)))
+
+(defvar magit--no-confirm-alist
+ '((safe-with-wip magit-wip-before-change-mode
+ discard reverse stage-all-changes unstage-all-changes)))
+
+(cl-defun magit-confirm (action &optional prompt prompt-n noabort
+ (items nil sitems))
+ (declare (indent defun))
+ (setq prompt-n (format (concat (or prompt-n prompt) "? ") (length items)))
+ (setq prompt (format (concat (or prompt (magit-confirm-make-prompt action))
+ "? ")
+ (car items)))
+ (or (cond ((and (not (eq action t))
+ (or (eq magit-no-confirm t)
+ (memq action magit-no-confirm)
+ (cl-member-if (pcase-lambda (`(,key ,var . ,sub))
+ (and (memq key magit-no-confirm)
+ (memq action sub)
+ (or (not var)
+ (and (boundp var)
+ (symbol-value var)))))
+ magit--no-confirm-alist)))
+ (or (not sitems) items))
+ ((not sitems)
+ (magit-y-or-n-p prompt action))
+ ((= (length items) 1)
+ (and (magit-y-or-n-p prompt action) items))
+ ((> (length items) 1)
+ (and (magit-y-or-n-p (concat (mapconcat #'identity items "\n")
+ "\n\n" prompt-n)
+ action)
+ items)))
+ (if noabort nil (user-error "Abort"))))
+
+(defun magit-confirm-files (action files &optional prompt)
+ (when files
+ (unless prompt
+ (setq prompt (magit-confirm-make-prompt action)))
+ (magit-confirm action
+ (concat prompt " %s")
+ (concat prompt " %i files")
+ nil files)))
+
+(defun magit-confirm-make-prompt (action)
+ (let ((prompt (symbol-name action)))
+ (replace-regexp-in-string
+ "-" " " (concat (upcase (substring prompt 0 1)) (substring prompt 1)))))
+
+(defun magit-read-number-string (prompt &optional default _history)
+ "Like `read-number' but return value is a string.
+DEFAULT may be a number or a numeric string."
+ (number-to-string
+ (read-number prompt (if (stringp default)
+ (string-to-number default)
+ default))))
+
+;;; Debug Utilities
+
+;;;###autoload
+(defun magit-emacs-Q-command ()
+ "Show a shell command that runs an uncustomized Emacs with only Magit loaded.
+See info node `(magit)Debugging Tools' for more information."
+ (interactive)
+ (let ((cmd (mapconcat
+ #'shell-quote-argument
+ `(,(concat invocation-directory invocation-name)
+ "-Q" "--eval" "(setq debug-on-error t)"
+ ,@(cl-mapcan
+ (lambda (dir) (list "-L" dir))
+ (delete-dups
+ (cl-mapcan
+ (lambda (lib)
+ (let ((path (locate-library lib)))
+ (cond
+ (path
+ (list (file-name-directory path)))
+ ((not (equal lib "libgit"))
+ (error "Cannot find mandatory dependency %s" lib)))))
+ '(;; Like `LOAD_PATH' in `default.mk'.
+ "dash"
+ "libgit"
+ "transient"
+ "with-editor"
+ ;; Obviously `magit' itself is needed too.
+ "magit"
+ ;; While this is part of the Magit repository,
+ ;; it is distributed as a separate package.
+ "git-commit"
+ ;; Even though `async' is a dependency of the
+ ;; `magit' package, it is not required here.
+ ))))
+ ;; Avoid Emacs bug#16406 by using full path.
+ "-l" ,(file-name-sans-extension (locate-library "magit")))
+ " ")))
+ (message "Uncustomized Magit command saved to kill-ring, %s"
+ "please run it in a terminal.")
+ (kill-new cmd)))
+
+;;; Text Utilities
+
+(defmacro magit-bind-match-strings (varlist string &rest body)
+ "Bind variables to submatches according to VARLIST then evaluate BODY.
+Bind the symbols in VARLIST to submatches of the current match
+data, starting with 1 and incrementing by 1 for each symbol. If
+the last match was against a string, then that has to be provided
+as STRING."
+ (declare (indent 2) (debug (listp form body)))
+ (let ((s (cl-gensym "string"))
+ (i 0))
+ `(let ((,s ,string))
+ (let ,(save-match-data
+ (--map (list it (list 'match-string (cl-incf i) s)) varlist))
+ ,@body))))
+
+(defun magit-delete-line ()
+ "Delete the rest of the current line."
+ (delete-region (point) (1+ (line-end-position))))
+
+(defun magit-delete-match (&optional num)
+ "Delete text matched by last search.
+If optional NUM is specified, only delete that subexpression."
+ (delete-region (match-beginning (or num 0))
+ (match-end (or num 0))))
+
+(defun magit-file-line (file)
+ "Return the first line of FILE as a string."
+ (when (file-regular-p file)
+ (with-temp-buffer
+ (insert-file-contents file)
+ (buffer-substring-no-properties (point-min)
+ (line-end-position)))))
+
+(defun magit-file-lines (file &optional keep-empty-lines)
+ "Return a list of strings containing one element per line in FILE.
+Unless optional argument KEEP-EMPTY-LINES is t, trim all empty lines."
+ (when (file-regular-p file)
+ (with-temp-buffer
+ (insert-file-contents file)
+ (split-string (buffer-string) "\n" (not keep-empty-lines)))))
+
+(defun magit-set-header-line-format (string)
+ "Set the header-line using STRING.
+Propertize STRING with the `magit-header-line'. If the `face'
+property of any part of STRING is already set, then that takes
+precedence. Also pad the left side of STRING so that it aligns
+with the text area."
+ (setq header-line-format
+ (concat (propertize " " 'display '(space :align-to 0))
+ string)))
+
+(defun magit-face-property-all (face string)
+ "Return non-nil if FACE is present in all of STRING."
+ (catch 'missing
+ (let ((pos 0))
+ (while (setq pos (next-single-property-change pos 'font-lock-face string))
+ (let ((val (get-text-property pos 'font-lock-face string)))
+ (unless (if (consp val)
+ (memq face val)
+ (eq face val))
+ (throw 'missing nil))))
+ (not pos))))
+
+(defun magit--add-face-text-property (beg end face &optional append object)
+ "Like `add-face-text-property' but for `font-lock-face'."
+ (while (< beg end)
+ (let* ((pos (next-single-property-change beg 'font-lock-face object end))
+ (val (get-text-property beg 'font-lock-face object))
+ (val (if (listp val) val (list val))))
+ (put-text-property beg pos 'font-lock-face
+ (if append
+ (append val (list face))
+ (cons face val))
+ object)
+ (setq beg pos))))
+
+(defun magit--propertize-face (string face)
+ (propertize string 'face face 'font-lock-face face))
+
+(defun magit--put-face (beg end face string)
+ (put-text-property beg end 'face face string)
+ (put-text-property beg end 'font-lock-face face string))
+
+(defun magit--format-spec (format specification)
+ "Like `format-spec' but preserve text properties in SPECIFICATION."
+ (with-temp-buffer
+ (insert format)
+ (goto-char (point-min))
+ (while (search-forward "%" nil t)
+ (cond
+ ;; Quoted percent sign.
+ ((eq (char-after) ?%)
+ (delete-char 1))
+ ;; Valid format spec.
+ ((looking-at "\\([-0-9.]*\\)\\([a-zA-Z]\\)")
+ (let* ((num (match-string 1))
+ (spec (string-to-char (match-string 2)))
+ (val (assq spec specification)))
+ (unless val
+ (error "Invalid format character: `%%%c'" spec))
+ (setq val (cdr val))
+ ;; Pad result to desired length.
+ (let ((text (format (concat "%" num "s") val)))
+ ;; Insert first, to preserve text properties.
+ (if (next-property-change 0 (concat " " text))
+ ;; If the inserted text has properties, then preserve those.
+ (insert text)
+ ;; Otherwise preserve FORMAT's properties, like `format-spec'.
+ (insert-and-inherit text))
+ ;; Delete the specifier body.
+ (delete-region (+ (match-beginning 0) (length text))
+ (+ (match-end 0) (length text)))
+ ;; Delete the percent sign.
+ (delete-region (1- (match-beginning 0)) (match-beginning 0)))))
+ ;; Signal an error on bogus format strings.
+ (t
+ (error "Invalid format string"))))
+ (buffer-string)))
+
+;;; Missing from Emacs
+
+(defun magit-kill-this-buffer ()
+ "Kill the current buffer."
+ (interactive)
+ (kill-buffer (current-buffer)))
+
+(defun magit--buffer-string (&optional min max trim)
+ "Like `buffer-substring-no-properties' but the arguments are optional.
+
+This combines the benefits of `buffer-string', `buffer-substring'
+and `buffer-substring-no-properties' into one function that is
+not as painful to use as the latter. I.e. you can write
+ (magit--buffer-string)
+instead of
+ (buffer-substring-no-properties (point-min)
+ (point-max))
+
+Optional MIN defaults to the value of `point-min'.
+Optional MAX defaults to the value of `point-max'.
+
+If optional TRIM is non-nil, then all leading and trailing
+whitespace is remove. If it is the newline character, then
+one trailing newline is added."
+ ;; Lets write that one last time and be done with it:
+ (let ((str (buffer-substring-no-properties (or min (point-min))
+ (or max (point-max)))))
+ (if trim
+ (concat (string-trim str)
+ (and (eq trim ?\n) "\n"))
+ str)))
+
+;;; Kludges for Emacs Bugs
+
+(defun magit-file-accessible-directory-p (filename)
+ "Like `file-accessible-directory-p' but work around an Apple bug.
+See http://debbugs.gnu.org/cgi/bugreport.cgi?bug=21573#17
+and https://github.com/magit/magit/issues/2295."
+ (and (file-directory-p filename)
+ (file-accessible-directory-p filename)))
+
+(when (version<= "25.1" emacs-version)
+ (with-eval-after-load 'vc-git
+ (defun vc-git-conflicted-files (directory)
+ "Return the list of files with conflicts in DIRECTORY."
+ (let* ((status
+ (vc-git--run-command-string directory "diff-files"
+ "--name-status"))
+ (lines (when status (split-string status "\n" 'omit-nulls)))
+ files)
+ (dolist (line lines files)
+ (when (string-match "\\([ MADRCU?!]\\)[ \t]+\\(.+\\)" line)
+ (let ((state (match-string 1 line))
+ (file (match-string 2 line)))
+ (when (equal state "U")
+ (push (expand-file-name file directory) files)))))))))
+
+(when (< emacs-major-version 27)
+ (defun vc-git--call@bug21559 (fn buffer command &rest args)
+ "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559."
+ (let ((process-environment process-environment))
+ (when revert-buffer-in-progress-p
+ (push "GIT_OPTIONAL_LOCKS=0" process-environment))
+ (apply fn buffer command args)))
+ (advice-add 'vc-git--call :around 'vc-git--call@bug21559)
+
+ (defun vc-git-command@bug21559
+ (fn buffer okstatus file-or-list &rest flags)
+ "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559."
+ (let ((process-environment process-environment))
+ (when revert-buffer-in-progress-p
+ (push "GIT_OPTIONAL_LOCKS=0" process-environment))
+ (apply fn buffer okstatus file-or-list flags)))
+ (advice-add 'vc-git-command :around 'vc-git-command@bug21559)
+
+ (defun auto-revert-handler@bug21559 (fn)
+ "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559."
+ (let ((revert-buffer-in-progress-p t))
+ (funcall fn)))
+ (advice-add 'auto-revert-handler :around 'auto-revert-handler@bug21559)
+ )
+
+;; `completion-pcm--all-completions' reverses the completion list. To
+;; preserve the order of our pre-sorted completions, we'll temporarily
+;; override it with the function below. bug#24676
+(defun magit-completion-pcm--all-completions (prefix pattern table pred)
+ (if (completion-pcm--pattern-trivial-p pattern)
+ (all-completions (concat prefix (car pattern)) table pred)
+ (let* ((regex (completion-pcm--pattern->regex pattern))
+ (case-fold-search completion-ignore-case)
+ (completion-regexp-list (cons regex completion-regexp-list))
+ (compl (all-completions
+ (concat prefix
+ (if (stringp (car pattern)) (car pattern) ""))
+ table pred)))
+ (if (not (functionp table))
+ compl
+ (let ((poss ()))
+ (dolist (c compl)
+ (when (string-match-p regex c) (push c poss)))
+ ;; This `nreverse' call is the only code change made to the
+ ;; `completion-pcm--all-completions' that shipped with Emacs 25.1.
+ (nreverse poss))))))
+
+(defun magit-which-function ()
+ "Return current function name based on point.
+
+This is a simple wrapper around `which-function', that resets
+Imenu's potentially outdated and therefore unreliable cache by
+setting `imenu--index-alist' to nil before calling that function."
+ (setq imenu--index-alist nil)
+ (which-function))
+
+;;; Kludges for Custom
+
+(defun magit-custom-initialize-reset (symbol exp)
+ "Initialize SYMBOL based on EXP.
+Set the symbol, using `set-default' (unlike
+`custom-initialize-reset' which uses the `:set' function if any.)
+The value is either the symbol's current value
+ (as obtained using the `:get' function), if any,
+or the value in the symbol's `saved-value' property if any,
+or (last of all) the value of EXP."
+ (set-default-toplevel-value
+ symbol
+ (condition-case nil
+ (let ((def (default-toplevel-value symbol))
+ (getter (get symbol 'custom-get)))
+ (if getter (funcall getter symbol) def))
+ (error
+ (eval (let ((sv (get symbol 'saved-value)))
+ (if sv (car sv) exp)))))))
+
+(defun magit-hook-custom-get (symbol)
+ (if (symbol-file symbol 'defvar)
+ (default-toplevel-value symbol)
+ ;;
+ ;; Called by `custom-initialize-reset' on behalf of `symbol's
+ ;; `defcustom', which is being evaluated for the first time to
+ ;; set the initial value, but there's already a default value,
+ ;; which most likely was established by one or more `add-hook'
+ ;; calls.
+ ;;
+ ;; We combine the `standard-value' and the current value, while
+ ;; preserving the order established by `:options', and return
+ ;; the result of that to be used as the "initial" default value.
+ ;;
+ (let ((standard (eval (car (get symbol 'standard-value))))
+ (current (default-toplevel-value symbol))
+ (value nil))
+ (dolist (fn (get symbol 'custom-options))
+ (when (or (memq fn standard)
+ (memq fn current))
+ (push fn value)))
+ (dolist (fn current)
+ (unless (memq fn value)
+ (push fn value)))
+ (nreverse value))))
+
+;;; Kludges for Info Manuals
+
+;;;###autoload
+(defun Info-follow-nearest-node--magit-gitman (fn &optional fork)
+ (let ((node (Info-get-token
+ (point) "\\*note[ \n\t]+"
+ "\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?")))
+ (if (and node (string-match "^(gitman)\\(.+\\)" node))
+ (pcase magit-view-git-manual-method
+ (`info (funcall fn fork))
+ (`man (require 'man)
+ (man (match-string 1 node)))
+ (`woman (require 'woman)
+ (woman (match-string 1 node)))
+ (_
+ (user-error "Invalid value for `magit-view-git-manual-method'")))
+ (funcall fn fork))))
+
+;;;###autoload
+(advice-add 'Info-follow-nearest-node :around
+ 'Info-follow-nearest-node--magit-gitman)
+
+;;;###autoload
+(defun org-man-export--magit-gitman (fn link description format)
+ (if (and (eq format 'texinfo)
+ (string-match-p "\\`git" link))
+ (replace-regexp-in-string "%s" link "
+@ifinfo
+@ref{%s,,,gitman,}.
+@end ifinfo
+@ifhtml
+@html
+the <a href=\"http://git-scm.com/docs/%s\">%s(1)</a> manpage.
+@end html
+@end ifhtml
+@iftex
+the %s(1) manpage.
+@end iftex
+")
+ (funcall fn link description format)))
+
+;;;###autoload
+(advice-add 'org-man-export :around
+ 'org-man-export--magit-gitman)
+
+;;; Kludges for Package Managers
+
+(defun magit--straight-chase-links (filename)
+ "Chase links in FILENAME until a name that is not a link.
+
+This is the same as `file-chase-links', except that it also
+handles fake symlinks that are created by the package manager
+straight.el on Windows.
+
+See <https://github.com/raxod502/straight.el/issues/520>."
+ (when (and (bound-and-true-p straight-symlink-emulation-mode)
+ (fboundp 'straight-chase-emulated-symlink))
+ (when-let ((target (straight-chase-emulated-symlink filename)))
+ (unless (eq target 'broken)
+ (setq filename target))))
+ (file-chase-links filename))
+
+;;; Bitmaps
+
+(when (fboundp 'define-fringe-bitmap)
+ (define-fringe-bitmap 'magit-fringe-bitmap+
+ [#b00000000
+ #b00011000
+ #b00011000
+ #b01111110
+ #b01111110
+ #b00011000
+ #b00011000
+ #b00000000])
+ (define-fringe-bitmap 'magit-fringe-bitmap-
+ [#b00000000
+ #b00000000
+ #b00000000
+ #b01111110
+ #b01111110
+ #b00000000
+ #b00000000
+ #b00000000])
+
+ (define-fringe-bitmap 'magit-fringe-bitmap>
+ [#b01100000
+ #b00110000
+ #b00011000
+ #b00001100
+ #b00011000
+ #b00110000
+ #b01100000
+ #b00000000])
+ (define-fringe-bitmap 'magit-fringe-bitmapv
+ [#b00000000
+ #b10000010
+ #b11000110
+ #b01101100
+ #b00111000
+ #b00010000
+ #b00000000
+ #b00000000])
+
+ (define-fringe-bitmap 'magit-fringe-bitmap-bold>
+ [#b11100000
+ #b01110000
+ #b00111000
+ #b00011100
+ #b00011100
+ #b00111000
+ #b01110000
+ #b11100000])
+ (define-fringe-bitmap 'magit-fringe-bitmap-boldv
+ [#b10000001
+ #b11000011
+ #b11100111
+ #b01111110
+ #b00111100
+ #b00011000
+ #b00000000
+ #b00000000])
+ )
+
+;;; Miscellaneous
+
+(defun magit-message (format-string &rest args)
+ "Display a message at the bottom of the screen, or not.
+Like `message', except that if the users configured option
+`magit-no-message' to prevent the message corresponding to
+FORMAT-STRING to be displayed, then don't."
+ (unless (--first (string-prefix-p it format-string) magit-no-message)
+ (apply #'message format-string args)))
+
+(defun magit-msg (format-string &rest args)
+ "Display a message at the bottom of the screen, but don't log it.
+Like `message', except that `message-log-max' is bound to nil."
+ (let ((message-log-max nil))
+ (apply #'message format-string args)))
+
+(defmacro magit--with-temp-position (buf pos &rest body)
+ (declare (indent 2))
+ `(with-current-buffer ,buf
+ (save-excursion
+ (save-restriction
+ (widen)
+ (goto-char (or ,pos 1))
+ ,@body))))
+
+;;; _
+(provide 'magit-utils)
+;;; magit-utils.el ends here
--- /dev/null
+;;; magit-wip.el --- commit snapshots to work-in-progress refs -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library defines tree global modes which automatically commit
+;; snapshots to branch-specific work-in-progress refs before and after
+;; making changes, and two commands which can be used to do so on
+;; demand.
+
+;;; Code:
+
+(require 'magit-core)
+(require 'magit-log)
+
+;;; Options
+
+(defgroup magit-wip nil
+ "Automatically commit to work-in-progress refs."
+ :link '(info-link "(magit)Wip Modes")
+ :group 'magit-modes
+ :group 'magit-essentials)
+
+(defgroup magit-wip-legacy nil
+ "It is better to not use these modes individually."
+ :link '(info-link "(magit)Legacy Wip Modes")
+ :group 'magit-wip)
+
+(defcustom magit-wip-mode-lighter " Wip"
+ "Lighter for Magit-Wip mode."
+ :package-version '(magit . "2.90.0")
+ :group 'magit-wip
+ :type 'string)
+
+(defcustom magit-wip-after-save-local-mode-lighter ""
+ "Lighter for Magit-Wip-After-Save-Local mode."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip-legacy
+ :type 'string)
+
+(defcustom magit-wip-after-apply-mode-lighter ""
+ "Lighter for Magit-Wip-After-Apply mode."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip-legacy
+ :type 'string)
+
+(defcustom magit-wip-before-change-mode-lighter ""
+ "Lighter for Magit-Wip-Before-Change mode."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip-legacy
+ :type 'string)
+
+(defcustom magit-wip-initial-backup-mode-lighter ""
+ "Lighter for Magit-Wip-Initial Backup mode."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip-legacy
+ :type 'string)
+
+(defcustom magit-wip-merge-branch nil
+ "Whether to merge the current branch into its wip ref.
+
+If non-nil and the current branch has new commits, then it is
+merged into the wip ref before creating a new wip commit. This
+makes it easier to inspect wip history and the wip commits are
+never garbage collected.
+
+If nil and the current branch has new commits, then the wip ref
+is reset to the tip of the branch before creating a new wip
+commit. With this setting wip commits are eventually garbage
+collected. This is currently the default."
+ :package-version '(magit . "2.90.0")
+ :group 'magit-wip
+ :type 'boolean)
+
+(defcustom magit-wip-namespace "refs/wip/"
+ "Namespace used for work-in-progress refs.
+The wip refs are named \"<namespace/>index/<branchref>\"
+and \"<namespace/>wtree/<branchref>\". When snapshots
+are created while the `HEAD' is detached then \"HEAD\"
+is used as `branch-ref'."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip
+ :type 'string)
+
+;;; Modes
+
+;;;###autoload
+(define-minor-mode magit-wip-mode
+ "Save uncommitted changes to work-in-progress refs.
+
+Whenever appropriate (i.e. when dataloss would be a possibility
+otherwise) this mode causes uncommitted changes to be committed
+to dedicated work-in-progress refs.
+
+For historic reasons this mode is implemented on top of four
+other `magit-wip-*' modes, which can also be used individually,
+if you want finer control over when the wip refs are updated;
+but that is discouraged."
+ :package-version '(magit . "2.90.0")
+ :lighter magit-wip-mode-lighter
+ :global t
+ (let ((arg (if magit-wip-mode 1 -1)))
+ (magit-wip-after-save-mode arg)
+ (magit-wip-after-apply-mode arg)
+ (magit-wip-before-change-mode arg)
+ (magit-wip-initial-backup-mode arg)))
+
+(define-minor-mode magit-wip-after-save-local-mode
+ "After saving, also commit to a worktree work-in-progress ref.
+
+After saving the current file-visiting buffer this mode also
+commits the changes to the worktree work-in-progress ref for
+the current branch.
+
+This mode should be enabled globally by turning on the globalized
+variant `magit-wip-after-save-mode'."
+ :package-version '(magit . "2.1.0")
+ :lighter magit-wip-after-save-local-mode-lighter
+ (if magit-wip-after-save-local-mode
+ (if (and buffer-file-name (magit-inside-worktree-p t))
+ (add-hook 'after-save-hook 'magit-wip-commit-buffer-file t t)
+ (setq magit-wip-after-save-local-mode nil)
+ (user-error "Need a worktree and a file"))
+ (remove-hook 'after-save-hook 'magit-wip-commit-buffer-file t)))
+
+(defun magit-wip-after-save-local-mode-turn-on ()
+ (and buffer-file-name
+ (magit-inside-worktree-p t)
+ (magit-file-tracked-p buffer-file-name)
+ (magit-wip-after-save-local-mode)))
+
+;;;###autoload
+(define-globalized-minor-mode magit-wip-after-save-mode
+ magit-wip-after-save-local-mode magit-wip-after-save-local-mode-turn-on
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip)
+
+(defun magit-wip-commit-buffer-file (&optional msg)
+ "Commit visited file to a worktree work-in-progress ref.
+
+Also see `magit-wip-after-save-mode' which calls this function
+automatically whenever a buffer visiting a tracked file is saved."
+ (interactive)
+ (--when-let (magit-wip-get-ref)
+ (magit-with-toplevel
+ (let ((file (file-relative-name buffer-file-name)))
+ (magit-wip-commit-worktree
+ it (list file)
+ (format (cond (msg)
+ ((called-interactively-p 'any)
+ "wip-save %s after save")
+ (t
+ "autosave %s after save"))
+ file))))))
+
+;;;###autoload
+(define-minor-mode magit-wip-after-apply-mode
+ "Commit to work-in-progress refs.
+
+After applying a change using any \"apply variant\"
+command (apply, stage, unstage, discard, and reverse) commit the
+affected files to the current wip refs. For each branch there
+may be two wip refs; one contains snapshots of the files as found
+in the worktree and the other contains snapshots of the entries
+in the index."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip
+ :lighter magit-wip-after-apply-mode-lighter
+ :global t)
+
+(defun magit-wip-commit-after-apply (&optional files msg)
+ (when magit-wip-after-apply-mode
+ (magit-wip-commit files msg)))
+
+;;;###autoload
+(define-minor-mode magit-wip-before-change-mode
+ "Commit to work-in-progress refs before certain destructive changes.
+
+Before invoking a revert command or an \"apply variant\"
+command (apply, stage, unstage, discard, and reverse) commit the
+affected tracked files to the current wip refs. For each branch
+there may be two wip refs; one contains snapshots of the files
+as found in the worktree and the other contains snapshots of the
+entries in the index.
+
+Only changes to files which could potentially be affected by the
+command which is about to be called are committed."
+ :package-version '(magit . "2.1.0")
+ :group 'magit-wip
+ :lighter magit-wip-before-change-mode-lighter
+ :global t)
+
+(defun magit-wip-commit-before-change (&optional files msg)
+ (when magit-wip-before-change-mode
+ (magit-with-toplevel
+ (magit-wip-commit files msg))))
+
+(define-minor-mode magit-wip-initial-backup-mode
+ "Before saving a buffer for the first time, commit to a wip ref."
+ :package-version '(magit . "2.90.0")
+ :group 'magit-wip
+ :lighter magit-wip-initial-backup-mode-lighter
+ :global t
+ (if magit-wip-initial-backup-mode
+ (add-hook 'before-save-hook 'magit-wip-commit-initial-backup)
+ (remove-hook 'before-save-hook 'magit-wip-commit-initial-backup)))
+
+(defun magit--any-wip-mode-enabled-p ()
+ "Return non-nil if any global wip mode is enabled."
+ (or magit-wip-mode
+ magit-wip-after-save-mode
+ magit-wip-after-apply-mode
+ magit-wip-before-change-mode
+ magit-wip-initial-backup-mode))
+
+(defvar-local magit-wip-buffer-backed-up nil)
+(put 'magit-wip-buffer-backed-up 'permanent-local t)
+
+;;;###autoload
+(defun magit-wip-commit-initial-backup ()
+ "Before saving, commit current file to a worktree wip ref.
+
+The user has to add this function to `before-save-hook'.
+
+Commit the current state of the visited file before saving the
+current buffer to that file. This backs up the same version of
+the file as `backup-buffer' would, but stores the backup in the
+worktree wip ref, which is also used by the various Magit Wip
+modes, instead of in a backup file as `backup-buffer' would.
+
+This function ignores the variables that affect `backup-buffer'
+and can be used along-side that function, which is recommended
+because this function only backs up files that are tracked in
+a Git repository."
+ (when (and (not magit-wip-buffer-backed-up)
+ buffer-file-name
+ (magit-inside-worktree-p t)
+ (magit-file-tracked-p buffer-file-name))
+ (let ((magit-save-repository-buffers nil))
+ (magit-wip-commit-buffer-file "autosave %s before save"))
+ (setq magit-wip-buffer-backed-up t)))
+
+;;; Core
+
+(defun magit-wip-commit (&optional files msg)
+ "Commit all tracked files to the work-in-progress refs.
+
+Interactively, commit all changes to all tracked files using
+a generic commit message. With a prefix-argument the commit
+message is read in the minibuffer.
+
+Non-interactively, only commit changes to FILES using MSG as
+commit message."
+ (interactive (list nil (if current-prefix-arg
+ (magit-read-string "Wip commit message")
+ "wip-save tracked files")))
+ (--when-let (magit-wip-get-ref)
+ (magit-wip-commit-index it files msg)
+ (magit-wip-commit-worktree it files msg)))
+
+(defun magit-wip-commit-index (ref files msg)
+ (let* ((wipref (magit--wip-index-ref ref))
+ (parent (magit-wip-get-parent ref wipref))
+ (tree (magit-git-string "write-tree")))
+ (magit-wip-update-wipref ref wipref tree parent files msg "index")))
+
+(defun magit-wip-commit-worktree (ref files msg)
+ (let* ((wipref (magit--wip-wtree-ref ref))
+ (parent (magit-wip-get-parent ref wipref))
+ (tree (magit-with-temp-index parent (list "--reset" "-i")
+ (if files
+ ;; Note: `update-index' is used instead of `add'
+ ;; because `add' will fail if a file is already
+ ;; deleted in the temporary index.
+ (magit-call-git
+ "update-index" "--add" "--remove"
+ (and (pcase (magit-repository-local-get
+ 'update-index-has-ignore-sw-p 'unset)
+ (`unset
+ (let ((val (version<= "2.25.0"
+ (magit-git-version))))
+ (magit-repository-local-set
+ 'update-index-has-ignore-sw-p val)
+ val))
+ (val val))
+ "--ignore-skip-worktree-entries")
+ "--" files)
+ (magit-with-toplevel
+ (magit-call-git "add" "-u" ".")))
+ (magit-git-string "write-tree"))))
+ (magit-wip-update-wipref ref wipref tree parent files msg "worktree")))
+
+(defun magit-wip-update-wipref (ref wipref tree parent files msg start-msg)
+ (cond
+ ((and (not (equal parent wipref))
+ (or (not magit-wip-merge-branch)
+ (not (magit-rev-verify wipref))))
+ (setq start-msg (concat "start autosaving " start-msg))
+ (magit-update-ref wipref start-msg
+ (magit-git-string "commit-tree" "--no-gpg-sign"
+ "-p" parent "-m" start-msg
+ (concat parent "^{tree}")))
+ (setq parent wipref))
+ ((and magit-wip-merge-branch
+ (or (not (magit-rev-ancestor-p ref wipref))
+ (not (magit-rev-ancestor-p
+ (concat (magit-git-string "log" "--format=%H"
+ "-1" "--merges" wipref)
+ "^2")
+ ref))))
+ (setq start-msg (format "merge %s into %s" ref start-msg))
+ (magit-update-ref wipref start-msg
+ (magit-git-string "commit-tree" "--no-gpg-sign"
+ "-p" wipref "-p" ref
+ "-m" start-msg
+ (concat ref "^{tree}")))
+ (setq parent wipref)))
+ (when (magit-git-failure "diff-tree" "--quiet" parent tree "--" files)
+ (unless (and msg (not (= (aref msg 0) ?\s)))
+ (let ((len (length files)))
+ (setq msg (concat
+ (cond ((= len 0) "autosave tracked files")
+ ((> len 1) (format "autosave %s files" len))
+ (t (concat "autosave "
+ (file-relative-name (car files)
+ (magit-toplevel)))))
+ msg))))
+ (magit-update-ref wipref msg
+ (magit-git-string "commit-tree" "--no-gpg-sign"
+ "-p" parent "-m" msg tree))))
+
+(defun magit-wip-get-ref ()
+ (let ((ref (or (magit-git-string "symbolic-ref" "HEAD") "HEAD")))
+ (and (magit-rev-verify ref)
+ ref)))
+
+(defun magit-wip-get-parent (ref wipref)
+ (if (and (magit-rev-verify wipref)
+ (equal (magit-git-string "merge-base" wipref ref)
+ (magit-rev-verify ref)))
+ wipref
+ ref))
+
+(defun magit--wip-index-ref (&optional ref)
+ (magit--wip-ref "index/" ref))
+
+(defun magit--wip-wtree-ref (&optional ref)
+ (magit--wip-ref "wtree/" ref))
+
+(defun magit--wip-ref (namespace &optional ref)
+ (concat magit-wip-namespace namespace
+ (or (and ref (string-prefix-p "refs/" ref) ref)
+ (when-let ((branch (and (not (equal ref "HEAD"))
+ (or ref (magit-get-current-branch)))))
+ (concat "refs/heads/" branch))
+ "HEAD")))
+
+(defun magit-wip-maybe-add-commit-hook ()
+ (when (and magit-wip-merge-branch
+ (magit-wip-any-enabled-p))
+ (add-hook 'git-commit-post-finish-hook 'magit-wip-commit nil t)))
+
+(defun magit-wip-any-enabled-p ()
+ (or magit-wip-mode
+ magit-wip-after-save-local-mode
+ magit-wip-after-save-mode
+ magit-wip-after-apply-mode
+ magit-wip-before-change-mode
+ magit-wip-initial-backup-mode))
+
+;;; Log
+
+(defun magit-wip-log-index (args files)
+ "Show log for the index wip ref of the current branch."
+ (interactive (magit-log-arguments))
+ (magit-log-setup-buffer (list (magit--wip-index-ref)) args files))
+
+(defun magit-wip-log-worktree (args files)
+ "Show log for the worktree wip ref of the current branch."
+ (interactive (magit-log-arguments))
+ (magit-log-setup-buffer (list (magit--wip-wtree-ref)) args files))
+
+(defun magit-wip-log-current (branch args files count)
+ "Show log for the current branch and its wip refs.
+With a negative prefix argument only show the worktree wip ref.
+The absolute numeric value of the prefix argument controls how
+many \"branches\" of each wip ref are shown."
+ (interactive
+ (nconc (list (or (magit-get-current-branch) "HEAD"))
+ (magit-log-arguments)
+ (list (prefix-numeric-value current-prefix-arg))))
+ (magit-wip-log branch args files count))
+
+(defun magit-wip-log (branch args files count)
+ "Show log for a branch and its wip refs.
+With a negative prefix argument only show the worktree wip ref.
+The absolute numeric value of the prefix argument controls how
+many \"branches\" of each wip ref are shown."
+ (interactive
+ (nconc (list (magit-completing-read
+ "Log branch and its wip refs"
+ (-snoc (magit-list-local-branch-names) "HEAD")
+ nil t nil 'magit-revision-history
+ (or (magit-branch-at-point)
+ (magit-get-current-branch)
+ "HEAD")))
+ (magit-log-arguments)
+ (list (prefix-numeric-value current-prefix-arg))))
+ (magit-log-setup-buffer (nconc (list branch)
+ (magit-wip-log-get-tips
+ (magit--wip-wtree-ref branch)
+ (abs count))
+ (and (>= count 0)
+ (magit-wip-log-get-tips
+ (magit--wip-index-ref branch)
+ (abs count))))
+ args files))
+
+(defun magit-wip-log-get-tips (wipref count)
+ (when-let ((reflog (magit-git-lines "reflog" wipref)))
+ (let (tips)
+ (while (and reflog (> count 1))
+ (setq reflog (cl-member "^[^ ]+ [^:]+: restart autosaving"
+ reflog :test #'string-match-p))
+ (when (and (cadr reflog)
+ (string-match "^[^ ]+ \\([^:]+\\)" (cadr reflog)))
+ (push (match-string 1 (cadr reflog)) tips))
+ (setq reflog (cddr reflog))
+ (cl-decf count))
+ (cons wipref (nreverse tips)))))
+
+;;; _
+(provide 'magit-wip)
+;;; magit-wip.el ends here
--- /dev/null
+;;; magit-worktree.el --- worktree support -*- lexical-binding: t -*-
+
+;; Copyright (C) 2010-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; This library implements support for `git-worktree'.
+
+;;; Code:
+
+(require 'magit)
+
+;;; Options
+
+(defcustom magit-worktree-read-directory-name-function 'read-directory-name
+ "Function used to read a directory for worktree commands.
+This is called with one argument, the prompt, and can be used
+to e.g. use a base directory other than `default-directory'.
+Used by `magit-worktree-checkout' and `magit-worktree-branch'."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-commands
+ :type 'function)
+
+;;; Commands
+
+;;;###autoload (autoload 'magit-worktree "magit-worktree" nil t)
+(transient-define-prefix magit-worktree ()
+ "Act on a worktree."
+ :man-page "git-worktree"
+ [["Create new"
+ ("b" "worktree" magit-worktree-checkout)
+ ("c" "branch and worktree" magit-worktree-branch)]
+ ["Commands"
+ ("m" "Move worktree" magit-worktree-move)
+ ("k" "Delete worktree" magit-worktree-delete)
+ ("g" "Visit worktree" magit-worktree-status)]])
+
+;;;###autoload
+(defun magit-worktree-checkout (path branch)
+ "Checkout BRANCH in a new worktree at PATH."
+ (interactive
+ (let ((branch (magit-read-branch-or-commit "Checkout")))
+ (list (funcall magit-worktree-read-directory-name-function
+ (format "Checkout %s in new worktree: " branch))
+ branch)))
+ (magit-run-git "worktree" "add" (expand-file-name path) branch)
+ (magit-diff-visit-directory path))
+
+;;;###autoload
+(defun magit-worktree-branch (path branch start-point &optional force)
+ "Create a new BRANCH and check it out in a new worktree at PATH."
+ (interactive
+ `(,(funcall magit-worktree-read-directory-name-function
+ "Create worktree: ")
+ ,@(magit-branch-read-args "Create and checkout branch")
+ ,current-prefix-arg))
+ (magit-run-git "worktree" "add" (if force "-B" "-b")
+ branch (expand-file-name path) start-point)
+ (magit-diff-visit-directory path))
+
+;;;###autoload
+(defun magit-worktree-move (worktree path)
+ "Move WORKTREE to PATH."
+ (interactive
+ (list (magit-completing-read "Move worktree"
+ (cdr (magit-list-worktrees))
+ nil t nil nil
+ (magit-section-value-if 'worktree))
+ (funcall magit-worktree-read-directory-name-function
+ "Move worktree to: ")))
+ (if (file-directory-p (expand-file-name ".git" worktree))
+ (user-error "You may not move the main working tree")
+ (let ((preexisting-directory (file-directory-p path)))
+ (when (and (zerop (magit-call-git "worktree" "move" worktree
+ (expand-file-name path)))
+ (not (file-exists-p default-directory))
+ (derived-mode-p 'magit-status-mode))
+ (kill-buffer)
+ (magit-diff-visit-directory
+ (if preexisting-directory
+ (concat (file-name-as-directory path)
+ (file-name-nondirectory worktree))
+ path)))
+ (magit-refresh))))
+
+(defun magit-worktree-delete (worktree)
+ "Delete a worktree, defaulting to the worktree at point.
+The primary worktree cannot be deleted."
+ (interactive
+ (list (magit-completing-read "Delete worktree"
+ (cdr (magit-list-worktrees))
+ nil t nil nil
+ (magit-section-value-if 'worktree))))
+ (if (file-directory-p (expand-file-name ".git" worktree))
+ (user-error "Deleting %s would delete the shared .git directory" worktree)
+ (let ((primary (file-name-as-directory (caar (magit-list-worktrees)))))
+ (magit-confirm-files (if magit-delete-by-moving-to-trash 'trash 'delete)
+ (list "worktree"))
+ (when (file-exists-p worktree)
+ (let ((delete-by-moving-to-trash magit-delete-by-moving-to-trash))
+ (delete-directory worktree t magit-delete-by-moving-to-trash)))
+ (if (file-exists-p default-directory)
+ (magit-run-git "worktree" "prune")
+ (let ((default-directory primary))
+ (magit-run-git "worktree" "prune"))
+ (when (derived-mode-p 'magit-status-mode)
+ (kill-buffer)
+ (magit-status-setup-buffer primary))))))
+
+(defun magit-worktree-status (worktree)
+ "Show the status for the worktree at point.
+If there is no worktree at point, then read one in the
+minibuffer. If the worktree at point is the one whose
+status is already being displayed in the current buffer,
+then show it in Dired instead."
+ (interactive
+ (list (or (magit-section-value-if 'worktree)
+ (magit-completing-read
+ "Show status for worktree"
+ (cl-delete (directory-file-name (magit-toplevel))
+ (magit-list-worktrees)
+ :test #'equal :key #'car)))))
+ (magit-diff-visit-directory worktree))
+
+;;; Sections
+
+(defvar magit-worktree-section-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map [remap magit-visit-thing] 'magit-worktree-status)
+ (define-key map [remap magit-delete-thing] 'magit-worktree-delete)
+ map)
+ "Keymap for `worktree' sections.")
+
+(defun magit-insert-worktrees ()
+ "Insert sections for all worktrees.
+If there is only one worktree, then insert nothing."
+ (let ((worktrees (magit-list-worktrees)))
+ (when (> (length worktrees) 1)
+ (magit-insert-section (worktrees)
+ (magit-insert-heading "Worktrees:")
+ (let* ((cols
+ (mapcar
+ (pcase-lambda (`(,path ,barep ,commit ,branch))
+ (cons (cond
+ (branch (propertize
+ branch 'font-lock-face
+ (if (equal branch (magit-get-current-branch))
+ 'magit-branch-current
+ 'magit-branch-local)))
+ (commit (propertize (magit-rev-abbrev commit)
+ 'font-lock-face 'magit-hash))
+ (barep "(bare)"))
+ path))
+ worktrees))
+ (align (1+ (-max (--map (string-width (car it)) cols)))))
+ (pcase-dolist (`(,head . ,path) cols)
+ (magit-insert-section (worktree path)
+ (insert head)
+ (insert (make-string (- align (length head)) ?\s))
+ (insert (let ((r (file-relative-name path))
+ (a (abbreviate-file-name path)))
+ (if (< (string-width r) (string-width a)) r a)))
+ (insert ?\n))))
+ (insert ?\n)))))
+
+;;; _
+(provide 'magit-worktree)
+;;; magit-worktree.el ends here
--- /dev/null
+;;; magit.el --- A Git porcelain inside Emacs -*- lexical-binding: t; coding: utf-8 -*-
+
+;; Copyright (C) 2008-2021 The Magit Project Contributors
+;;
+;; You should have received a copy of the AUTHORS.md file which
+;; lists all contributors. If not, see http://magit.vc/authors.
+
+;; Author: Marius Vollmer <marius.vollmerNOSPAMgmail.com>
+;; Maintainer: Jonas Bernoulli <jonasNOSPAMbernoul.li>
+;; Kyle Meyer <kyleNOSPAMkyleam.com>
+;; Noam Postavsky <npostavsNOSPAMusers.sourceforge.net>
+;; Former-Maintainers:
+;; Nicolas Dudebout <nicolas.dudeboutNOSPAMgatech.edu>
+;; Peter J. Weisberg <pjNOSPAMirregularexpressions.net>
+;; Phil Jackson <philNOSPAMshellarchive.co.uk>
+;; Rémi Vanicat <vanicatNOSPAMdebian.org>
+;; Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+
+;; Keywords: git tools vc
+;; Homepage: https://github.com/magit/magit
+
+;; Magit requires at least GNU Emacs 25.1 and Git 2.2.0.
+
+;; Magit is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; Magit is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+;; License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with Magit. If not, see http://www.gnu.org/licenses.
+
+;;; Commentary:
+
+;; 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.
+
+;;; Code:
+
+(require 'magit-core)
+(require 'magit-diff)
+(require 'magit-log)
+(require 'magit-wip)
+(require 'magit-apply)
+(require 'magit-repos)
+(require 'git-commit)
+
+(require 'format-spec)
+(require 'package nil t) ; used in `magit-version'
+(require 'with-editor)
+
+(defconst magit--minimal-git "2.2.0")
+(defconst magit--minimal-emacs "25.1")
+
+;;; Faces
+
+(defface magit-header-line
+ '((t :inherit magit-section-heading))
+ "Face for the `header-line' in some Magit modes.
+Note that some modes, such as `magit-log-select-mode', have their
+own faces for the `header-line', or for parts of the
+`header-line'."
+ :group 'magit-faces)
+
+(defface magit-header-line-key
+ '((t :inherit font-lock-builtin-face))
+ "Face for keys in the `header-line'."
+ :group 'magit-faces)
+
+(defface magit-dimmed
+ '((((class color) (background light)) :foreground "grey50")
+ (((class color) (background dark)) :foreground "grey50"))
+ "Face for text that shouldn't stand out."
+ :group 'magit-faces)
+
+(defface magit-hash
+ '((((class color) (background light)) :foreground "grey60")
+ (((class color) (background dark)) :foreground "grey40"))
+ "Face for the sha1 part of the log output."
+ :group 'magit-faces)
+
+(defface magit-tag
+ '((((class color) (background light)) :foreground "Goldenrod4")
+ (((class color) (background dark)) :foreground "LightGoldenrod2"))
+ "Face for tag labels shown in log buffer."
+ :group 'magit-faces)
+
+(defface magit-branch-remote
+ '((((class color) (background light)) :foreground "DarkOliveGreen4")
+ (((class color) (background dark)) :foreground "DarkSeaGreen2"))
+ "Face for remote branch head labels shown in log buffer."
+ :group 'magit-faces)
+
+(defface magit-branch-remote-head
+ '((((class color) (background light)) :inherit magit-branch-remote :box t)
+ (((class color) (background dark)) :inherit magit-branch-remote :box t))
+ "Face for current branch."
+ :group 'magit-faces)
+
+(defface magit-branch-local
+ '((((class color) (background light)) :foreground "SkyBlue4")
+ (((class color) (background dark)) :foreground "LightSkyBlue1"))
+ "Face for local branches."
+ :group 'magit-faces)
+
+(defface magit-branch-current
+ '((((class color) (background light)) :inherit magit-branch-local :box t)
+ (((class color) (background dark)) :inherit magit-branch-local :box t))
+ "Face for current branch."
+ :group 'magit-faces)
+
+(defface magit-branch-upstream
+ '((t :slant italic))
+ "Face for upstream branch.
+This face is only used in logs and it gets combined
+ with `magit-branch-local', `magit-branch-remote'
+and/or `magit-branch-remote-head'."
+ :group 'magit-faces)
+
+(defface magit-head
+ '((((class color) (background light)) :inherit magit-branch-local)
+ (((class color) (background dark)) :inherit magit-branch-local))
+ "Face for the symbolic ref `HEAD'."
+ :group 'magit-faces)
+
+(defface magit-refname
+ '((((class color) (background light)) :foreground "grey30")
+ (((class color) (background dark)) :foreground "grey80"))
+ "Face for refnames without a dedicated face."
+ :group 'magit-faces)
+
+(defface magit-refname-stash
+ '((t :inherit magit-refname))
+ "Face for stash refnames."
+ :group 'magit-faces)
+
+(defface magit-refname-wip
+ '((t :inherit magit-refname))
+ "Face for wip refnames."
+ :group 'magit-faces)
+
+(defface magit-refname-pullreq
+ '((t :inherit magit-refname))
+ "Face for pullreq refnames."
+ :group 'magit-faces)
+
+(defface magit-keyword
+ '((t :inherit font-lock-string-face))
+ "Face for parts of commit messages inside brackets."
+ :group 'magit-faces)
+
+(defface magit-keyword-squash
+ '((t :inherit font-lock-warning-face))
+ "Face for squash! and fixup! keywords in commit messages."
+ :group 'magit-faces)
+
+(defface magit-signature-good
+ '((t :foreground "green"))
+ "Face for good signatures."
+ :group 'magit-faces)
+
+(defface magit-signature-bad
+ '((t :foreground "red" :weight bold))
+ "Face for bad signatures."
+ :group 'magit-faces)
+
+(defface magit-signature-untrusted
+ '((t :foreground "cyan"))
+ "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 "firebrick3"))
+ "Face for signatures that cannot be checked (e.g. missing key)."
+ :group 'magit-faces)
+
+(defface magit-cherry-unmatched
+ '((t :foreground "cyan"))
+ "Face for unmatched cherry commits."
+ :group 'magit-faces)
+
+(defface magit-cherry-equivalent
+ '((t :foreground "magenta"))
+ "Face for equivalent cherry commits."
+ :group 'magit-faces)
+
+(defface magit-filename
+ '((t :weight normal))
+ "Face for filenames."
+ :group 'magit-faces)
+
+;;; Global Bindings
+
+;;;###autoload
+(define-obsolete-variable-alias 'global-magit-file-mode
+ 'magit-define-global-key-bindings "Magit 3.0.0")
+
+;;;###autoload
+(defcustom magit-define-global-key-bindings t
+ "Whether to bind some Magit commands in the global keymap.
+
+If this variable is non-nil, then the following bindings may
+be added to the global keymap. The default is t.
+
+key binding
+--- -------
+C-x g magit-status
+C-x M-g magit-dispatch
+C-c M-g magit-file-dispatch
+
+These bindings may be added when `after-init-hook' is called.
+Each binding is added if and only if at that time no other key
+is bound to the same command and no other command is bound to
+the same key. In other words we try to avoid adding bindings
+that are unnecessary, as well as bindings that conflict with
+other bindings.
+
+Adding the above bindings is delayed until `after-init-hook'
+is called to allow users to set the variable anywhere in their
+init file (without having to make sure to do so before `magit'
+is loaded or autoloaded) and to increase the likelihood that
+all the potentially conflicting user bindings have already
+been added.
+
+Setting this variable after the hook has already been called
+has no effect.
+
+We recommend that you bind \"C-c g\" instead of \"C-c M-g\" to
+`magit-file-dispatch'. The former is a much better binding
+but the \"C-c <letter>\" namespace is strictly reserved for
+users; preventing Magit from using it by default.
+
+Also see info node `(magit)Commands for Buffers Visiting Files'."
+ :package-version '(magit . "3.0.0")
+ :group 'magit-essentials
+ :type 'boolean)
+
+;;;###autoload
+(progn
+ (defun magit-maybe-define-global-key-bindings ()
+ (when magit-define-global-key-bindings
+ (let ((map (current-global-map)))
+ (dolist (elt '(("C-x g" . magit-status)
+ ("C-x M-g" . magit-dispatch)
+ ("C-c M-g" . magit-file-dispatch)))
+ (let ((key (kbd (car elt)))
+ (def (cdr elt)))
+ (unless (or (lookup-key map key)
+ (where-is-internal def (make-sparse-keymap) t))
+ (define-key map key def)))))))
+ (if after-init-time
+ (magit-maybe-define-global-key-bindings)
+ (add-hook 'after-init-hook 'magit-maybe-define-global-key-bindings t)))
+
+;;; Dispatch Popup
+
+;;;###autoload (autoload 'magit-dispatch "magit" nil t)
+(transient-define-prefix magit-dispatch ()
+ "Invoke a Magit command from a list of available commands."
+ :info-manual "(magit)Top"
+ ["Transient and dwim commands"
+ [("A" "Apply" magit-cherry-pick)
+ ("b" "Branch" magit-branch)
+ ("B" "Bisect" magit-bisect)
+ ("c" "Commit" magit-commit)
+ ("C" "Clone" magit-clone)
+ ("d" "Diff" magit-diff)
+ ("D" "Diff (change)" magit-diff-refresh)
+ ("e" "Ediff (dwim)" magit-ediff-dwim)
+ ("E" "Ediff" magit-ediff)]
+ [("f" "Fetch" magit-fetch)
+ ("F" "Pull" magit-pull)
+ ("l" "Log" magit-log)
+ ("L" "Log (change)" magit-log-refresh)
+ ("m" "Merge" magit-merge)
+ ("M" "Remote" magit-remote)
+ ("o" "Submodule" magit-submodule)
+ ("O" "Subtree" magit-subtree)]
+ [("P" "Push" magit-push)
+ ("r" "Rebase" magit-rebase)
+ ("t" "Tag" magit-tag)
+ ("T" "Note" magit-notes)
+ ("V" "Revert" magit-revert)
+ ("w" "Apply patches" magit-am)
+ ("W" "Format patches" magit-patch)
+ ("X" "Reset" magit-reset)]
+ [("y" "Show Refs" magit-show-refs)
+ ("Y" "Cherries" magit-cherry)
+ ("z" "Stash" magit-stash)
+ ("!" "Run" magit-run)
+ ("%" "Worktree" magit-worktree)]]
+ ["Applying changes"
+ :if-derived magit-mode
+ [("a" "Apply" magit-apply)
+ ("v" "Reverse" magit-reverse)
+ ("k" "Discard" magit-discard)]
+ [("s" "Stage" magit-stage)
+ ("u" "Unstage" magit-unstage)]
+ [("S" "Stage all" magit-stage-modified)
+ ("U" "Unstage all" magit-unstage-all)]]
+ ["Essential commands"
+ :if-derived magit-mode
+ ("g" " refresh current buffer" magit-refresh)
+ ("<tab>" " toggle section at point" magit-section-toggle)
+ ("<return>" "visit thing at point" magit-visit-thing)
+ ("C-h m" " show all key bindings" describe-mode)])
+
+;;; Git Popup
+
+(defcustom magit-shell-command-verbose-prompt t
+ "Whether to show the working directory when reading a command.
+This affects `magit-git-command', `magit-git-command-topdir',
+`magit-shell-command', and `magit-shell-command-topdir'."
+ :package-version '(magit . "2.11.0")
+ :group 'magit-commands
+ :type 'boolean)
+
+(defvar magit-git-command-history nil)
+
+;;;###autoload (autoload 'magit-run "magit" nil t)
+(transient-define-prefix magit-run ()
+ "Run git or another command, or launch a graphical utility."
+
+
+ [["Run git subcommand"
+ ("!" "in repository root" magit-git-command-topdir)
+ ("p" "in working directory" magit-git-command)]
+ ["Run shell command"
+ ("s" "in repository root" magit-shell-command-topdir)
+ ("S" "in working directory" magit-shell-command)]
+ ["Launch"
+ ("k" "gitk" magit-run-gitk)
+ ("a" "gitk --all" magit-run-gitk-all)
+ ("b" "gitk --branches" magit-run-gitk-branches)
+ ("g" "git gui" magit-run-git-gui)]])
+
+;;;###autoload
+(defun magit-git-command (command)
+ "Execute COMMAND asynchronously; display output.
+
+Interactively, prompt for COMMAND in the minibuffer. \"git \" is
+used as initial input, but can be deleted to run another command.
+
+With a prefix argument COMMAND is run in the top-level directory
+of the current working tree, otherwise in `default-directory'."
+ (interactive (list (magit-read-shell-command nil "git ")))
+ (magit--shell-command command))
+
+;;;###autoload
+(defun magit-git-command-topdir (command)
+ "Execute COMMAND asynchronously; display output.
+
+Interactively, prompt for COMMAND in the minibuffer. \"git \" is
+used as initial input, but can be deleted to run another command.
+
+COMMAND is run in the top-level directory of the current
+working tree."
+ (interactive (list (magit-read-shell-command t "git ")))
+ (magit--shell-command command (magit-toplevel)))
+
+;;;###autoload
+(defun magit-shell-command (command)
+ "Execute COMMAND asynchronously; display output.
+
+Interactively, prompt for COMMAND in the minibuffer. With a
+prefix argument COMMAND is run in the top-level directory of
+the current working tree, otherwise in `default-directory'."
+ (interactive (list (magit-read-shell-command)))
+ (magit--shell-command command))
+
+;;;###autoload
+(defun magit-shell-command-topdir (command)
+ "Execute COMMAND asynchronously; display output.
+
+Interactively, prompt for COMMAND in the minibuffer. COMMAND
+is run in the top-level directory of the current working tree."
+ (interactive (list (magit-read-shell-command t)))
+ (magit--shell-command command (magit-toplevel)))
+
+(defun magit--shell-command (command &optional directory)
+ (let ((default-directory (or directory default-directory))
+ (process-environment process-environment))
+ (push "GIT_PAGER=cat" process-environment)
+ (magit-start-process shell-file-name nil
+ shell-command-switch command))
+ (magit-process-buffer))
+
+(defun magit-read-shell-command (&optional toplevel initial-input)
+ (let ((default-directory
+ (if (or toplevel current-prefix-arg)
+ (or (magit-toplevel)
+ (magit--not-inside-repository-error))
+ default-directory)))
+ (read-shell-command (if magit-shell-command-verbose-prompt
+ (format "Async shell command in %s: "
+ (abbreviate-file-name default-directory))
+ "Async shell command: ")
+ initial-input 'magit-git-command-history)))
+
+;;; Font-Lock Keywords
+
+(defconst magit-font-lock-keywords
+ (eval-when-compile
+ `((,(concat "(\\(magit-define-section-jumper\\)\\_>"
+ "[ \t'\(]*"
+ "\\(\\(?:\\sw\\|\\s_\\)+\\)?")
+ (1 'font-lock-keyword-face)
+ (2 'font-lock-function-name-face nil t))
+ (,(concat "(" (regexp-opt '("magit-insert-section"
+ "magit-section-case"
+ "magit-bind-match-strings"
+ "magit-with-temp-index"
+ "magit-with-blob"
+ "magit-with-toplevel") t)
+ "\\_>")
+ . 1))))
+
+(font-lock-add-keywords 'emacs-lisp-mode magit-font-lock-keywords)
+
+;;; Version
+
+(defvar magit-version 'undefined
+ "The version of Magit that you're using.
+Use the function by the same name instead of this variable.")
+
+;;;###autoload
+(defun magit-version (&optional print-dest)
+ "Return the version of Magit currently in use.
+If optional argument PRINT-DEST is non-nil, output
+stream (interactively, the echo area, or the current buffer with
+a prefix argument), also print the used versions of Magit, Git,
+and Emacs to it."
+ (interactive (list (if current-prefix-arg (current-buffer) t)))
+ (let ((magit-git-global-arguments nil)
+ (toplib (or load-file-name buffer-file-name))
+ debug)
+ (unless (and toplib
+ (equal (file-name-nondirectory toplib) "magit.el"))
+ (setq toplib (locate-library "magit.el")))
+ (setq toplib (and toplib (magit--straight-chase-links toplib)))
+ (push toplib debug)
+ (when toplib
+ (let* ((topdir (file-name-directory toplib))
+ (gitdir (expand-file-name
+ ".git" (file-name-directory
+ (directory-file-name topdir))))
+ (static (locate-library "magit-version.el" nil (list topdir)))
+ (static (and static (magit--straight-chase-links static))))
+ (or (progn
+ (push 'repo debug)
+ (when (and (file-exists-p gitdir)
+ ;; It is a repo, but is it the Magit repo?
+ (file-exists-p
+ (expand-file-name "../lisp/magit.el" gitdir)))
+ (push t debug)
+ ;; Inside the repo the version file should only exist
+ ;; while running make.
+ (when (and static (not noninteractive))
+ (ignore-errors (delete-file static)))
+ (setq magit-version
+ (let ((default-directory topdir))
+ (magit-git-string "describe"
+ "--tags" "--dirty" "--always")))))
+ (progn
+ (push 'static debug)
+ (when (and static (file-exists-p static))
+ (push t debug)
+ (load-file static)
+ magit-version))
+ (when (featurep 'package)
+ (push 'elpa debug)
+ (ignore-errors
+ (--when-let (assq 'magit package-alist)
+ (push t debug)
+ (setq magit-version
+ (and (fboundp 'package-desc-version)
+ (package-version-join
+ (package-desc-version (cadr it))))))))
+ (progn
+ (push 'dirname debug)
+ (let ((dirname (file-name-nondirectory
+ (directory-file-name topdir))))
+ (when (string-match "\\`magit-\\([0-9].*\\)" dirname)
+ (setq magit-version (match-string 1 dirname)))))
+ ;; If all else fails, just report the commit hash. It's
+ ;; better than nothing and we cannot do better in the case
+ ;; of e.g. a shallow clone.
+ (progn
+ (push 'hash debug)
+ ;; Same check as above to see if it's really the Magit repo.
+ (when (and (file-exists-p gitdir)
+ (file-exists-p
+ (expand-file-name "../lisp/magit.el" gitdir)))
+ (setq magit-version
+ (let ((default-directory topdir))
+ (magit-git-string "rev-parse" "HEAD"))))))))
+ (if (stringp magit-version)
+ (when print-dest
+ (princ (format "Magit %s, Git %s, Emacs %s, %s"
+ (or magit-version "(unknown)")
+ (or (let ((magit-git-debug
+ (lambda (err)
+ (display-warning '(magit git)
+ err :error))))
+ (magit-git-version t))
+ "(unknown)")
+ emacs-version
+ system-type)
+ print-dest))
+ (setq debug (reverse debug))
+ (setq magit-version 'error)
+ (when magit-version
+ (push magit-version debug))
+ (unless (equal (getenv "CI") "true")
+ ;; The repository is a sparse clone.
+ (message "Cannot determine Magit's version %S" debug)))
+ magit-version))
+
+;;; Debugging Tools
+
+(defun magit-debug-git-executable ()
+ "Display a buffer with information about `magit-git-executable'.
+See info node `(magit)Debugging Tools' for more information."
+ (interactive)
+ (with-current-buffer (get-buffer-create "*magit-git-debug*")
+ (pop-to-buffer (current-buffer))
+ (erase-buffer)
+ (insert (concat
+ (format "magit-git-executable: %S" magit-git-executable)
+ (and (not (file-name-absolute-p magit-git-executable))
+ (format " [%S]" (executable-find magit-git-executable)))
+ (format " (%s)\n"
+ (let* ((errmsg nil)
+ (magit-git-debug (lambda (err) (setq errmsg err))))
+ (or (magit-git-version t) errmsg)))))
+ (insert (format "exec-path: %S\n" exec-path))
+ (--when-let (cl-set-difference
+ (-filter #'file-exists-p (remq nil (parse-colon-path
+ (getenv "PATH"))))
+ (-filter #'file-exists-p (remq nil exec-path))
+ :test #'file-equal-p)
+ (insert (format " entries in PATH, but not in exec-path: %S\n" it)))
+ (dolist (execdir exec-path)
+ (insert (format " %s (%s)\n" execdir (car (file-attributes execdir))))
+ (when (file-directory-p execdir)
+ (dolist (exec (directory-files
+ execdir t (concat
+ "\\`git" (regexp-opt exec-suffixes) "\\'")))
+ (insert (format " %s (%s)\n" exec
+ (let* ((magit-git-executable exec)
+ (errmsg nil)
+ (magit-git-debug (lambda (err) (setq errmsg err))))
+ (or (magit-git-version t) errmsg)))))))))
+
+;;; Startup Asserts
+
+(defun magit-startup-asserts ()
+ (when-let ((val (getenv "GIT_DIR")))
+ (setenv "GIT_DIR")
+ (message "Magit unset $GIT_DIR (was %S). See \
+https://github.com/magit/magit/wiki/Don't-set-$GIT_DIR-and-alike" val))
+ (when-let ((val (getenv "GIT_WORK_TREE")))
+ (setenv "GIT_WORK_TREE")
+ (message "Magit unset $GIT_WORK_TREE (was %S). See \
+https://github.com/magit/magit/wiki/Don't-set-$GIT_DIR-and-alike" val))
+ (let ((version (magit-git-version)))
+ (when (and version
+ (version< version magit--minimal-git)
+ (not (equal (getenv "CI") "true")))
+ (display-warning 'magit (format "\
+Magit requires Git >= %s, you are using %s.
+
+If this comes as a surprise to you, because you do actually have
+a newer version installed, then that probably means that the
+older version happens to appear earlier on the `$PATH'. If you
+always start Emacs from a shell, then that can be fixed in the
+shell's init file. If you start Emacs by clicking on an icon,
+or using some sort of application launcher, then you probably
+have to adjust the environment as seen by graphical interface.
+For X11 something like ~/.xinitrc should work.
+
+If you use Tramp to work inside remote Git repositories, then you
+have to make sure a suitable Git is used on the remote machines
+too.\n" magit--minimal-git version) :error)))
+ (when (version< emacs-version magit--minimal-emacs)
+ (display-warning 'magit (format "\
+Magit requires Emacs >= %s, you are using %s.
+
+If this comes as a surprise to you, because you do actually have
+a newer version installed, then that probably means that the
+older version happens to appear earlier on the `$PATH'. If you
+always start Emacs from a shell, then that can be fixed in the
+shell's init file. If you start Emacs by clicking on an icon,
+or using some sort of application launcher, then you probably
+have to adjust the environment as seen by graphical interface.
+For X11 something like ~/.xinitrc should work.\n"
+ magit--minimal-emacs emacs-version)
+ :error)))
+
+;;; Loading Libraries
+
+(provide 'magit)
+
+(cl-eval-when (load eval)
+ (require 'magit-status)
+ (require 'magit-refs)
+ (require 'magit-files)
+ (require 'magit-reset)
+ (require 'magit-branch)
+ (require 'magit-merge)
+ (require 'magit-tag)
+ (require 'magit-worktree)
+ (require 'magit-notes)
+ (require 'magit-sequence)
+ (require 'magit-commit)
+ (require 'magit-remote)
+ (require 'magit-clone)
+ (require 'magit-fetch)
+ (require 'magit-pull)
+ (require 'magit-push)
+ (require 'magit-bisect)
+ (require 'magit-stash)
+ (require 'magit-blame)
+ (require 'magit-obsolete)
+ (require 'magit-submodule)
+ (unless (load "magit-autoloads" t t)
+ (require 'magit-patch)
+ (require 'magit-subtree)
+ (require 'magit-ediff)
+ (require 'magit-gitignore)
+ (require 'magit-extras)
+ (require 'git-rebase)
+ (require 'magit-imenu)
+ (require 'magit-bookmark)))
+
+(eval-after-load 'bookmark
+ '(require 'magit-bookmark))
+
+(if after-init-time
+ (progn (magit-startup-asserts)
+ (magit-version))
+ (add-hook 'after-init-hook #'magit-startup-asserts t)
+ (add-hook 'after-init-hook #'magit-version t))
+
+;;; magit.el ends here
--- /dev/null
+This is magit.info, produced by makeinfo version 6.5 from magit.texi.
+
+ Copyright (C) 2015-2021 Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+ 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
+
+\1f
+Indirect:
+magit.info-1: 754
+magit.info-2: 301131
+\1f
+Tag Table:
+(Indirect)
+Node: Top\7f754
+Node: Introduction\7f6512
+Node: Installation\7f11235
+Node: Installing from Melpa\7f11565
+Node: Installing from the Git Repository\7f12638
+Node: Post-Installation Tasks\7f15370
+Node: Getting Started\7f16655
+Node: Interface Concepts\7f21895
+Node: Modes and Buffers\7f22256
+Node: Switching Buffers\7f24005
+Node: Naming Buffers\7f28756
+Node: Quitting Windows\7f32063
+Node: Automatic Refreshing of Magit Buffers\7f33809
+Node: Automatic Saving of File-Visiting Buffers\7f36661
+Node: Automatic Reverting of File-Visiting Buffers\7f37846
+Node: Risk of Reverting Automatically\7f42841
+Node: Sections\7f45223
+Node: Section Movement\7f46149
+Node: Section Visibility\7f51059
+Node: Section Hooks\7f57136
+Node: Section Types and Values\7f59543
+Node: Section Options\7f60846
+Node: Transient Commands\7f61318
+Node: Transient Arguments and Buffer Variables\7f62555
+Node: Completion Confirmation and the Selection\7f69573
+Node: Action Confirmation\7f70017
+Node: Completion and Confirmation\7f77833
+Node: The Selection\7f81019
+Node: The hunk-internal region\7f83918
+Node: Support for Completion Frameworks\7f85007
+Node: Additional Completion Options\7f89914
+Node: Running Git\7f90513
+Node: Viewing Git Output\7f90786
+Node: Git Process Status\7f91919
+Node: Running Git Manually\7f92884
+Node: Git Executable\7f95354
+Node: Global Git Arguments\7f97636
+Node: Inspecting\7f98442
+Node: Status Buffer\7f99599
+Node: Status Sections\7f103589
+Node: Status Header Sections\7f109141
+Node: Status Module Sections\7f111771
+Node: Status Options\7f114276
+Node: Repository List\7f115745
+Node: Logging\7f118783
+Node: Refreshing Logs\7f121344
+Node: Log Buffer\7f122790
+Node: Log Margin\7f126646
+Node: Select from Log\7f129825
+Node: Reflog\7f132050
+Node: Cherries\7f133707
+Node: Diffing\7f135555
+Node: Refreshing Diffs\7f138634
+Node: Commands Available in Diffs\7f142213
+Node: Diff Options\7f144749
+Node: Revision Buffer\7f150230
+Node: Ediffing\7f153560
+Node: References Buffer\7f157208
+Node: References Sections\7f167728
+Node: Bisecting\7f168589
+Node: Visiting Files and Blobs\7f170941
+Node: General-Purpose Visit Commands\7f171411
+Node: Visiting Files and Blobs from a Diff\7f172367
+Node: Blaming\7f175826
+Node: Manipulating\7f182167
+Node: Creating Repository\7f182509
+Node: Cloning Repository\7f183064
+Node: Staging and Unstaging\7f188469
+Node: Staging from File-Visiting Buffers\7f192552
+Node: Applying\7f193720
+Node: Committing\7f195613
+Node: Initiating a Commit\7f196196
+Node: Editing Commit Messages\7f199581
+Node: Using the Revision Stack\7f202384
+Node: Commit Pseudo Headers\7f205435
+Node: Commit Mode and Hooks\7f206771
+Node: Commit Message Conventions\7f209709
+Node: Branching\7f211837
+Node: The Two Remotes\7f212063
+Node: Branch Commands\7f214716
+Node: Branch Git Variables\7f227097
+Node: Auxiliary Branch Commands\7f232488
+Node: Merging\7f233606
+Node: Resolving Conflicts\7f237614
+Node: Rebasing\7f242615
+Node: Editing Rebase Sequences\7f247474
+Node: Information About In-Progress Rebase\7f251802
+Ref: Information About In-Progress Rebase-Footnote-1\7f260684
+Node: Cherry Picking\7f261280
+Node: Reverting\7f265611
+Node: Resetting\7f267060
+Node: Stashing\7f268926
+Node: Transferring\7f273627
+Node: Remotes\7f273849
+Node: Remote Commands\7f274001
+Node: Remote Git Variables\7f278082
+Node: Fetching\7f279361
+Node: Pulling\7f281848
+Node: Pushing\7f282894
+Node: Plain Patches\7f286647
+Node: Maildir Patches\7f288138
+Node: Miscellaneous\7f289652
+Node: Tagging\7f289966
+Node: Notes\7f291883
+Node: Submodules\7f294255
+Node: Listing Submodules\7f294473
+Node: Submodule Transient\7f295879
+Node: Subtree\7f298401
+Node: Worktree\7f301131
+Node: Common Commands\7f302236
+Node: Wip Modes\7f304359
+Node: Wip Graph\7f309290
+Node: Legacy Wip Modes\7f311604
+Node: Commands for Buffers Visiting Files\7f314499
+Node: Minor Mode for Buffers Visiting Blobs\7f320121
+Node: Customizing\7f320932
+Node: Per-Repository Configuration\7f322528
+Node: Essential Settings\7f324783
+Node: Safety\7f325128
+Node: Performance\7f326889
+Node: Microsoft Windows Performance\7f334057
+Node: MacOS Performance\7f335248
+Ref: MacOS Performance-Footnote-1\7f336425
+Node: Default Bindings\7f336507
+Node: Plumbing\7f338362
+Node: Calling Git\7f339191
+Node: Getting a Value from Git\7f340716
+Node: Calling Git for Effect\7f343802
+Node: Section Plumbing\7f350079
+Node: Creating Sections\7f350307
+Node: Section Selection\7f354207
+Node: Matching Sections\7f356006
+Node: Refreshing Buffers\7f361979
+Node: Conventions\7f365127
+Node: Theming Faces\7f365319
+Node: FAQ\7f373434
+Node: FAQ - How to ...?\7f373876
+Node: How to pronounce Magit?\7f374289
+Node: How to show git's output?\7f375091
+Node: How to install the gitman info manual?\7f375877
+Node: How to show diffs for gpg-encrypted files?\7f376847
+Node: How does branching and pushing work?\7f377443
+Node: Can Magit be used as ediff-version-control-package?\7f377806
+Node: Should I disable VC?\7f379824
+Node: FAQ - Issues and Errors\7f380442
+Node: Magit is slow\7f381338
+Node: I changed several thousand files at once and now Magit is unusable\7f381552
+Node: I am having problems committing\7f382281
+Node: I am using MS Windows and cannot push with Magit\7f382762
+Node: I am using OS X and SOMETHING works in shell but not in Magit\7f383379
+Node: Expanding a file to show the diff causes it to disappear\7f384210
+Node: Point is wrong in the COMMIT_EDITMSG buffer\7f384791
+Node: The mode-line information isn't always up-to-date\7f385837
+Node: A branch and tag sharing the same name breaks SOMETHING\7f386900
+Node: My Git hooks work on the command-line but not inside Magit\7f387786
+Node: git-commit-mode isn't used when committing from the command-line\7f388632
+Node: Point ends up inside invisible text when jumping to a file-visiting buffer\7f390903
+Node: Debugging Tools\7f391701
+Node: Keystroke Index\7f393880
+Node: Command Index\7f427986
+Node: Function Index\7f465125
+Node: Variable Index\7f481396
+\1f
+End Tag Table
+
+\1f
+Local Variables:
+coding: utf-8
+End:
--- /dev/null
+This is magit.info, produced by makeinfo version 6.5 from magit.texi.
+
+ Copyright (C) 2015-2021 Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+ 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
+
+\1f
+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 2.90.1 (v2.90.1-1157-g10a931f15+1).
+
+ Copyright (C) 2015-2021 Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+ You can redistribute this document and/or modify it under the terms
+ of the GNU General Public License as published by the Free Software
+ Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ This document is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+* Menu:
+
+* Introduction::
+* Installation::
+* Getting Started::
+* Interface Concepts::
+* Inspecting::
+* Manipulating::
+* Transferring::
+* Miscellaneous::
+* Customizing::
+* Plumbing::
+* FAQ::
+* Debugging Tools::
+* Keystroke Index::
+* Command Index::
+* Function Index::
+* Variable Index::
+
+— The Detailed Node Listing —
+
+Installation
+
+* Installing from Melpa::
+* Installing from the Git Repository::
+* Post-Installation Tasks::
+
+Interface Concepts
+
+* Modes and Buffers::
+* Sections::
+* Transient Commands::
+* Transient Arguments and Buffer Variables::
+* Completion, Confirmation and the Selection: Completion Confirmation and the Selection.
+* Running Git::
+
+Modes and Buffers
+
+* Switching Buffers::
+* Naming Buffers::
+* Quitting Windows::
+* Automatic Refreshing of Magit Buffers::
+* Automatic Saving of File-Visiting Buffers::
+* Automatic Reverting of File-Visiting Buffers::
+
+
+Sections
+
+* Section Movement::
+* Section Visibility::
+* Section Hooks::
+* Section Types and Values::
+* Section Options::
+
+
+Completion, Confirmation and the Selection
+
+* Action Confirmation::
+* Completion and Confirmation::
+* The Selection::
+* The hunk-internal region::
+* Support for Completion Frameworks::
+* Additional Completion Options::
+
+
+Running Git
+
+* Viewing Git Output::
+* Git Process Status::
+* Running Git Manually::
+* Git Executable::
+* Global Git Arguments::
+
+
+Inspecting
+
+* Status Buffer::
+* Repository List::
+* Logging::
+* Diffing::
+* Ediffing::
+* References Buffer::
+* Bisecting::
+* Visiting Files and Blobs::
+* Blaming::
+
+Status Buffer
+
+* Status Sections::
+* Status Header Sections::
+* Status Module Sections::
+* Status Options::
+
+
+Logging
+
+* Refreshing Logs::
+* Log Buffer::
+* Log Margin::
+* Select from Log::
+* Reflog::
+* Cherries::
+
+
+Diffing
+
+* Refreshing Diffs::
+* Commands Available in Diffs::
+* Diff Options::
+* Revision Buffer::
+
+
+References Buffer
+
+* References Sections::
+
+
+Visiting Files and Blobs
+
+* General-Purpose Visit Commands::
+* Visiting Files and Blobs from a Diff::
+
+
+Manipulating
+
+* Creating Repository::
+* Cloning Repository::
+* Staging and Unstaging::
+* Applying::
+* Committing::
+* Branching::
+* Merging::
+* Resolving Conflicts::
+* Rebasing::
+* Cherry Picking::
+* Resetting::
+* Stashing::
+
+Staging and Unstaging
+
+* Staging from File-Visiting Buffers::
+
+
+Committing
+
+* Initiating a Commit::
+* Editing Commit Messages::
+
+
+Branching
+
+* The Two Remotes::
+* Branch Commands::
+* Branch Git Variables::
+* Auxiliary Branch Commands::
+
+
+Rebasing
+
+* Editing Rebase Sequences::
+* Information About In-Progress Rebase::
+
+
+Cherry Picking
+
+* Reverting::
+
+
+Transferring
+
+* Remotes::
+* Fetching::
+* Pulling::
+* Pushing::
+* Plain Patches::
+* Maildir Patches::
+
+Remotes
+
+* Remote Commands::
+* Remote Git Variables::
+
+
+Miscellaneous
+
+* Tagging::
+* Notes::
+* Submodules::
+* Subtree::
+* Worktree::
+* Common Commands::
+* Wip Modes::
+* Commands for Buffers Visiting Files::
+* Minor Mode for Buffers Visiting Blobs::
+
+Submodules
+
+* Listing Submodules::
+* Submodule Transient::
+
+
+Wip Modes
+
+* Wip Graph::
+* Legacy Wip Modes::
+
+
+Customizing
+
+* Per-Repository Configuration::
+* Essential Settings::
+
+Essential Settings
+
+* Safety::
+* Performance::
+* Default Bindings::
+
+
+Plumbing
+
+* Calling Git::
+* Section Plumbing::
+* Refreshing Buffers::
+* Conventions::
+
+Calling Git
+
+* Getting a Value from Git::
+* Calling Git for Effect::
+
+
+Section Plumbing
+
+* Creating Sections::
+* Section Selection::
+* Matching Sections::
+
+
+Conventions
+
+* Theming Faces::
+
+
+FAQ
+
+* FAQ - How to ...?::
+* FAQ - Issues and Errors::
+
+FAQ - How to ...?
+
+* How to pronounce Magit?::
+* How to show git's output?::
+* How to install the gitman info manual?::
+* How to show diffs for gpg-encrypted files?::
+* How does branching and pushing work?::
+* Can Magit be used as ediff-version-control-package?::
+* Should I disable VC?::
+
+
+FAQ - Issues and Errors
+
+* Magit is slow::
+* I changed several thousand files at once and now Magit is unusable::
+* I am having problems committing::
+* I am using MS Windows and cannot push with Magit::
+* I am using OS X and SOMETHING works in shell, but not in Magit: I am using OS X and SOMETHING works in shell but not in Magit.
+* Expanding a file to show the diff causes it to disappear::
+* Point is wrong in the COMMIT_EDITMSG buffer::
+* The mode-line information isn't always up-to-date::
+* A branch and tag sharing the same name breaks SOMETHING::
+* My Git hooks work on the command-line but not inside Magit::
+* git-commit-mode isn't used when committing from the command-line::
+* Point ends up inside invisible text when jumping to a file-visiting buffer::
+
+
+
+\1f
+File: magit.info, Node: Introduction, Next: Installation, Prev: Top, Up: Top
+
+1 Introduction
+**************
+
+Magit is an interface to the version control system Git, implemented as
+an Emacs package. Magit aspires to be a complete Git porcelain. While
+we cannot (yet) claim that Magit wraps and improves upon each and every
+Git command, it is complete enough to allow even experienced Git users
+to perform almost all of their daily version control tasks directly from
+within Emacs. While many fine Git clients exist, only Magit and Git
+itself deserve to be called porcelains.
+
+ Staging and otherwise applying changes is one of the most important
+features in a Git porcelain and here Magit outshines anything else,
+including Git itself. Git’s own staging interface (‘git add --patch’)
+is so cumbersome that many users only use it in exceptional cases. In
+Magit staging a hunk or even just part of a hunk is as trivial as
+staging all changes made to a file.
+
+ The most visible part of Magit’s interface is the status buffer,
+which displays information about the current repository. Its content is
+created by running several Git commands and making their output
+actionable. Among other things, it displays information about the
+current branch, lists unpulled and unpushed changes and contains
+sections displaying the staged and unstaged changes. That might sound
+noisy, but, since sections are collapsible, it’s not.
+
+ To stage or unstage a change one places the cursor on the change and
+then types ‘s’ or ‘u’. The change can be a file or a hunk, or when the
+region is active (i.e. when there is a selection) several files or
+hunks, or even just part of a hunk. The change or changes that these
+commands - and many others - would act on are highlighted.
+
+ Magit also implements several other "apply variants" in addition to
+staging and unstaging. One can discard or reverse a change, or apply it
+to the working tree. Git’s own porcelain only supports this for staging
+and unstaging and you would have to do something like ‘git diff ... |
+??? | git apply ...’ to discard, revert, or apply a single hunk on the
+command line. In fact that’s exactly what Magit does internally (which
+is what lead to the term "apply variants").
+
+ Magit isn’t just for Git experts, but it does assume some prior
+experience with Git as well as Emacs. That being said, many users have
+reported that using Magit was what finally taught them what Git is
+capable of and how to use it to its fullest. Other users wished they
+had switched to Emacs sooner so that they would have gotten their hands
+on Magit earlier.
+
+ While one has to know the basic features of Emacs to be able to make
+full use of Magit, acquiring just enough Emacs skills doesn’t take long
+and is worth it, even for users who prefer other editors. Vim users are
+advised to give Evil (https://bitbucket.org/lyro/evil/wiki/Home), the
+"Extensible VI Layer for Emacs", and Spacemacs
+(https://github.com/syl20bnr/spacemacs), an "Emacs starter-kit focused
+on Evil" a try.
+
+ Magit provides a consistent and efficient Git porcelain. After a
+short learning period, you will be able to perform most of your daily
+version control tasks faster than you would on the command line. You
+will likely also start using features that seemed too daunting in the
+past.
+
+ Magit fully embraces Git. It exposes many advanced features using a
+simple but flexible interface instead of only wrapping the trivial ones
+like many GUI clients do. Of course Magit supports logging, cloning,
+pushing, and other commands that usually don’t fail in spectacular ways;
+but it also supports tasks that often cannot be completed in a single
+step. Magit fully supports tasks such as merging, rebasing,
+cherry-picking, reverting, and blaming by not only providing a command
+to initiate these tasks but also by displaying context sensitive
+information along the way and providing commands that are useful for
+resolving conflicts and resuming the sequence after doing so.
+
+ Magit wraps and in many cases improves upon at least the following
+Git porcelain commands: ‘add’, ‘am’, ‘bisect’, ‘blame’, ‘branch’,
+‘checkout’, ‘cherry’, ‘cherry-pick’, ‘clean’, ‘clone’, ‘commit’,
+‘config’, ‘describe’, ‘diff’, ‘fetch’, ‘format-patch’, ‘init’, ‘log’,
+‘merge’, ‘merge-tree’, ‘mv’, ‘notes’, ‘pull’, ‘rebase’, ‘reflog’,
+‘remote’, ‘request-pull’, ‘reset’, ‘revert’, ‘rm’, ‘show’, ‘stash’,
+‘submodule’, ‘subtree’, ‘tag’, and ‘worktree.’ Many more Magit porcelain
+commands are implemented on top of Git plumbing commands.
+
+\1f
+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::
+
+\1f
+File: magit.info, Node: Installing from Melpa, Next: Installing from the Git Repository, Up: Installation
+
+2.1 Installing from Melpa
+=========================
+
+Magit is available from Melpa and Melpa-Stable. If you haven’t used
+Emacs’ package manager before, then it is high time you familiarize
+yourself with it by reading the documentation in the Emacs manual, see
+*note (emacs)Packages::. Then add one of the archives to
+‘package-archives’:
+
+ • To use Melpa:
+
+ (require 'package)
+ (add-to-list 'package-archives
+ '("melpa" . "http://melpa.org/packages/") t)
+
+ • To use Melpa-Stable:
+
+ (require 'package)
+ (add-to-list 'package-archives
+ '("melpa-stable" . "http://stable.melpa.org/packages/") t)
+
+ Once you have added your preferred archive, you need to update the
+local package list using:
+
+ M-x package-refresh-contents RET
+
+ Once you have done that, you can install Magit and its dependencies
+using:
+
+ M-x package-install RET magit RET
+
+ Now see *note Post-Installation Tasks::.
+
+\1f
+File: magit.info, Node: Installing from the Git Repository, Next: Post-Installation Tasks, Prev: Installing from Melpa, Up: Installation
+
+2.2 Installing from the Git Repository
+======================================
+
+Magit depends on the ‘dash’, ‘transient’ and ‘with-editor’ libraries
+which are available from Melpa and Melpa-Stable. Install them using
+‘M-x package-install RET <package> RET’. Of course you may also install
+them manually from their repository.
+
+ Then clone the Magit repository:
+
+ $ git clone https://github.com/magit/magit.git ~/.emacs.d/site-lisp/magit
+ $ cd ~/.emacs.d/site-lisp/magit
+
+ Then compile the libraries and generate the info manuals:
+
+ $ make
+
+ If you haven’t installed ‘dash’, ‘transient’ and ‘with-editor’ from
+Melpa or at ‘/path/to/magit/../<package>’, then you have to tell ‘make’
+where to find them. To do so create the file ‘/path/to/magit/config.mk’
+with the following content before running ‘make’:
+
+ LOAD_PATH = -L ~/.emacs.d/site-lisp/magit/lisp
+ LOAD_PATH += -L ~/.emacs.d/site-lisp/dash
+ LOAD_PATH += -L ~/.emacs.d/site-lisp/transient/lisp
+ LOAD_PATH += -L ~/.emacs.d/site-lisp/with-editor
+
+ Finally add this to your init file:
+
+ (add-to-list 'load-path "~/.emacs.d/site-lisp/magit/lisp")
+ (require 'magit)
+
+ (with-eval-after-load 'info
+ (info-initialize)
+ (add-to-list 'Info-directory-list
+ "~/.emacs.d/site-lisp/magit/Documentation/"))
+
+ Of course if you installed the dependencies manually as well, then
+you have to tell Emacs about them too, by prefixing the above with:
+
+ (add-to-list 'load-path "~/.emacs.d/site-lisp/dash")
+ (add-to-list 'load-path "~/.emacs.d/site-lisp/transient/lisp")
+ (add-to-list 'load-path "~/.emacs.d/site-lisp/with-editor")
+
+ Note that you have to add the ‘lisp’ subdirectory to the ‘load-path’,
+not the top-level of the repository, and that elements of ‘load-path’
+should not end with a slash, while those of ‘Info-directory-list’
+should.
+
+ Instead of requiring the feature ‘magit’, you could load just the
+autoload definitions, by loading the file ‘magit-autoloads.el’.
+
+ (load "/path/to/magit/lisp/magit-autoloads")
+
+ Instead of running Magit directly from the repository by adding that
+to the ‘load-path’, you might want to instead install it in some other
+directory using ‘sudo make install’ and setting ‘load-path’ accordingly.
+
+ To update Magit use:
+
+ $ git pull
+ $ make
+
+ At times it might be necessary to run ‘make clean all’ instead.
+
+ To view all available targets use ‘make help’.
+
+ Now see *note Post-Installation Tasks::.
+
+\1f
+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 <https://magit.vc/donations>.
+for various donation options.
+
+\1f
+File: magit.info, Node: Getting Started, Next: Interface Concepts, Prev: Installation, Up: Top
+
+3 Getting Started
+*****************
+
+This short tutorial describes the most essential features that many
+Magitians use on a daily basis. It only scratches the surface but
+should be enough to get you started.
+
+ IMPORTANT: It is safest if you clone some repository just for this
+tutorial. Alternatively you can use an existing local repository, but
+if you do that, then you should commit all uncommitted changes before
+proceeding.
+
+ Type ‘C-x g’ to display information about the current Git repository
+in a dedicated buffer, called the status buffer.
+
+ Most Magit commands are commonly invoked from the status buffer. It
+can be considered the primary interface for interacting with Git using
+Magit. Many other Magit buffers may exist at a given time, but they are
+often created from this buffer.
+
+ Depending on what state your repository is in, this buffer may
+contain sections titled "Staged changes", "Unstaged changes", "Unmerged
+into origin/master", "Unpushed to origin/master", and many others.
+
+ Since we are starting from a safe state, which you can easily return
+to (by doing a ‘git reset --hard PRE-MAGIT-STATE’), there currently are
+no staged or unstaged changes. Edit some files and save the changes.
+Then go back to the status buffer, while at the same time refreshing it,
+by typing ‘C-x g’. (When the status buffer, or any Magit buffer for
+that matter, is the current buffer, then you can also use just ‘g’ to
+refresh it).
+
+ Move between sections using ‘p’ and ‘n’. Note that the bodies of
+some sections are hidden. Type ‘TAB’ to expand or collapse the section
+at point. You can also use ‘C-tab’ to cycle the visibility of the
+current section and its children. Move to a file section inside the
+section named "Unstaged changes" and type ‘s’ to stage the changes you
+have made to that file. That file now appears under "Staged changes".
+
+ Magit can stage and unstage individual hunks, not just complete
+files. Move to the file you have just staged, expand it using ‘TAB’,
+move to one of the hunks using ‘n’, and unstage just that by typing ‘u’.
+Note how the staging (‘s’) and unstaging (‘u’) commands operate on the
+change at point. Many other commands behave the same way.
+
+ You can also un-/stage just part of a hunk. Inside the body of a
+hunk section (move there using ‘C-n’), set the mark using ‘C-SPC’ and
+move down until some added and/or removed lines fall inside the region
+but not all of them. Again type ‘s’ to stage.
+
+ It is also possible to un-/stage multiple files at once. Move to a
+file section, type ‘C-SPC’, move to the next file using ‘n’, and then
+‘s’ to stage both files. Note that both the mark and point have to be
+on the headings of sibling sections for this to work. If the region
+looks like it does in other buffers, then it doesn’t select Magit
+sections that can be acted on as a unit.
+
+ And then of course you want to commit your changes. Type ‘c’. This
+shows the available commit commands and arguments in a buffer at the
+bottom of the frame. Each command and argument is prefixed with the key
+that invokes/sets it. Do not worry about this for now. We want to
+create a "normal" commit, which is done by typing ‘c’ again.
+
+ Now two new buffers appear. One is for writing the commit message,
+the other shows a diff with the changes that you are about to commit.
+Write a message and then type ‘C-c C-c’ to actually create the commit.
+
+ You probably don’t want to push the commit you just created because
+you just committed some random changes, but if that is not the case you
+could push it by typing ‘P’ to show all the available push commands and
+arguments and then ‘p’ to push to a branch with the same name as the
+local branch onto the remote configured as the push-remote. (If the
+push-remote is not configured yet, then you would first be prompted for
+the remote to push to.)
+
+ So far we have mentioned the commit, push, and log menu commands.
+These are probably among the menus you will be using the most, but many
+others exist. To show a menu that lists all other menus (as well as the
+various apply commands and some other essential commands), type ‘h’.
+Try a few. (Such menus are also called "transient prefix commands" or
+just "transients".)
+
+ The key bindings in that menu correspond to the bindings in Magit
+buffers, including but not limited to the status buffer. So you could
+type ‘h d’ to bring up the diff menu, but once you remember that "d"
+stands for "diff", you would usually do so by just typing ‘d’. But this
+"prefix of prefixes" is useful even once you have memorized all the
+bindings, as it can provide easy access to Magit commands from non-Magit
+buffers. The global binding is ‘C-x M-g’.
+
+ In file visiting buffers ‘C-c M-g’ brings up a similar menu featuring
+commands that act on just the visited file, see *note Commands for
+Buffers Visiting Files::.
+
+ It is not necessary that you do so now, but if you stick with Magit,
+then it is highly recommended that you read the next section too.
+
+\1f
+File: magit.info, Node: Interface Concepts, Next: Inspecting, Prev: Getting Started, Up: Top
+
+4 Interface Concepts
+********************
+
+* Menu:
+
+* Modes and Buffers::
+* Sections::
+* Transient Commands::
+* Transient Arguments and Buffer Variables::
+* Completion, Confirmation and the Selection: Completion Confirmation and the Selection.
+* Running Git::
+
+\1f
+File: magit.info, Node: Modes and Buffers, Next: Sections, Up: Interface Concepts
+
+4.1 Modes and Buffers
+=====================
+
+Magit provides several major-modes. For each of these modes there
+usually exists only one buffer per repository. Separate modes and thus
+buffers exist for commits, diffs, logs, and some other things.
+
+ Besides these special purpose buffers, there also exists an overview
+buffer, called the *status buffer*. It’s usually from this buffer that
+the user invokes Git commands, or creates or visits other buffers.
+
+ In this manual we often speak about "Magit buffers". By that we mean
+buffers whose major-modes derive from ‘magit-mode’.
+
+‘M-x magit-toggle-buffer-lock’ (‘magit-toggle-buffer-lock’)
+
+ This command locks the current buffer to its value or if the buffer
+ is already locked, then it unlocks it.
+
+ Locking a buffer to its value prevents it from being reused to
+ display another value. The name of a locked buffer contains its
+ value, which allows telling it apart from other locked buffers and
+ the unlocked buffer.
+
+ Not all Magit buffers can be locked to their values; for example,
+ it wouldn’t make sense to lock a status buffer.
+
+ There can only be a single unlocked buffer using a certain
+ major-mode per repository. So when a buffer is being unlocked and
+ another unlocked buffer already exists for that mode and
+ repository, then the former buffer is instead deleted and the
+ latter is displayed in its place.
+
+* Menu:
+
+* Switching Buffers::
+* Naming Buffers::
+* Quitting Windows::
+* Automatic Refreshing of Magit Buffers::
+* Automatic Saving of File-Visiting Buffers::
+* Automatic Reverting of File-Visiting Buffers::
+
+\1f
+File: magit.info, Node: Switching Buffers, Next: Naming Buffers, Up: Modes and Buffers
+
+4.1.1 Switching Buffers
+-----------------------
+
+ -- Function: magit-display-buffer buffer &optional display-function
+
+ This function is a wrapper around ‘display-buffer’ and is used to
+ display any Magit buffer. It displays BUFFER in some window and,
+ unlike ‘display-buffer’, also selects that window, provided
+ ‘magit-display-buffer-noselect’ is ‘nil’. It also runs the hooks
+ mentioned below.
+
+ If optional DISPLAY-FUNCTION is non-nil, then that is used to
+ display the buffer. Usually that is ‘nil’ and the function
+ specified by ‘magit-display-buffer-function’ is used.
+
+ -- Variable: magit-display-buffer-noselect
+
+ When this is non-nil, then ‘magit-display-buffer’ only displays the
+ buffer but forgoes also selecting the window. This variable should
+ not be set globally, it is only intended to be let-bound, by code
+ that automatically updates "the other window". This is used for
+ example when the revision buffer is updated when you move inside
+ the log buffer.
+
+ -- User Option: magit-display-buffer-function
+
+ The function specified here is called by ‘magit-display-buffer’
+ with one argument, a buffer, to actually display that buffer. This
+ function should call ‘display-buffer’ with that buffer as first and
+ a list of display actions as second argument.
+
+ Magit provides several functions, listed below, that are suitable
+ values for this option. If you want to use different rules, then a
+ good way of doing that is to start with a copy of one of these
+ functions and then adjust it to your needs.
+
+ Instead of using a wrapper around ‘display-buffer’, that function
+ itself can be used here, in which case the display actions have to
+ be specified by adding them to ‘display-buffer-alist’ instead.
+
+ To learn about display actions, see *note (elisp)Choosing Window::.
+
+ -- Function: magit-display-buffer-traditional buffer
+
+ This function is the current default value of the option
+ ‘magit-display-buffer-function’. Before that option and this
+ function were added, the behavior was hard-coded in many places all
+ over the code base but now all the rules are contained in this one
+ function (except for the "noselect" special case mentioned above).
+
+ -- Function: magit-display-buffer-same-window-except-diff-v1
+
+ This function displays most buffers in the currently selected
+ window. If a buffer’s mode derives from ‘magit-diff-mode’ or
+ ‘magit-process-mode’, it is displayed in another window.
+
+ -- Function: magit-display-buffer-fullframe-status-v1
+
+ This function fills the entire frame when displaying a status
+ buffer. Otherwise, it behaves like
+ ‘magit-display-buffer-traditional’.
+
+ -- Function: magit-display-buffer-fullframe-status-topleft-v1
+
+ This function fills the entire frame when displaying a status
+ buffer. It behaves like ‘magit-display-buffer-fullframe-status-v1’
+ except that it displays buffers that derive from ‘magit-diff-mode’
+ or ‘magit-process-mode’ to the top or left of the current buffer
+ rather than to the bottom or right. As a result, Magit buffers
+ tend to pop up on the same side as they would if
+ ‘magit-display-buffer-traditional’ were in use.
+
+ -- Function: magit-display-buffer-fullcolumn-most-v1
+
+ This function displays most buffers so that they fill the entire
+ height of the frame. However, the buffer is displayed in another
+ window if (1) the buffer’s mode derives from ‘magit-process-mode’,
+ or (2) the buffer’s mode derives from ‘magit-diff-mode’, provided
+ that the mode of the current buffer derives from ‘magit-log-mode’
+ or ‘magit-cherry-mode’.
+
+ -- User Option: magit-pre-display-buffer-hook
+
+ This hook is run by ‘magit-display-buffer’ before displaying the
+ buffer.
+
+ -- Function: magit-save-window-configuration
+
+ This function saves the current window configuration. Later when
+ the buffer is buried, it may be restored by
+ ‘magit-restore-window-configuration’.
+
+ -- User Option: magit-post-display-buffer-hook
+
+ This hook is run by ‘magit-display-buffer’ after displaying the
+ buffer.
+
+ -- Function: magit-maybe-set-dedicated
+
+ This function remembers if a new window had to be created to
+ display the buffer, or whether an existing window was reused. This
+ information is later used by ‘magit-mode-quit-window’, to determine
+ whether the window should be deleted when its last Magit buffer is
+ buried.
+
+\1f
+File: magit.info, Node: Naming Buffers, Next: Quitting Windows, Prev: Switching Buffers, Up: Modes and Buffers
+
+4.1.2 Naming Buffers
+--------------------
+
+ -- User Option: magit-generate-buffer-name-function
+
+ The function used to generate the names of Magit buffers.
+
+ Such a function should take the options
+ ‘magit-uniquify-buffer-names’ as well as ‘magit-buffer-name-format’
+ into account. If it doesn’t, then should be clearly stated in the
+ doc-string. And if it supports %-sequences beyond those mentioned
+ in the doc-string of the option ‘magit-buffer-name-format’, then
+ its own doc-string should describe the additions.
+
+ -- Function: magit-generate-buffer-name-default-function mode
+
+ This function returns a buffer name suitable for a buffer whose
+ major-mode is MODE and which shows information about the repository
+ in which ‘default-directory’ is located.
+
+ This function uses ‘magit-buffer-name-format’ and supporting all of
+ the %-sequences mentioned the documentation of that option. It
+ also respects the option ‘magit-uniquify-buffer-names’.
+
+ -- User Option: magit-buffer-name-format
+
+ The format string used to name Magit buffers.
+
+ At least the following %-sequences are supported:
+
+ • ‘%m’
+
+ The name of the major-mode, but with the ‘-mode’ suffix
+ removed.
+
+ • ‘%M’
+
+ Like ‘%m’ but abbreviate ‘magit-status-mode’ as ‘magit’.
+
+ • ‘%v’
+
+ The value the buffer is locked to, in parentheses, or an empty
+ string if the buffer is not locked to a value.
+
+ • ‘%V’
+
+ Like ‘%v’, but the string is prefixed with a space, unless it
+ is an empty string.
+
+ • ‘%t’
+
+ The top-level directory of the working tree of the repository,
+ or if ‘magit-uniquify-buffer-names’ is non-nil an abbreviation
+ of that.
+
+ • ‘%x’
+
+ If ‘magit-uniquify-buffer-names’ is nil "*", otherwise the
+ empty string. Due to limitations of the ‘uniquify’ package,
+ buffer names must end with the path.
+
+ • ‘%T’
+
+ Obsolete, use "%t%x" instead. Like ‘%t’, but append an
+ asterisk if and only if ‘magit-uniquify-buffer-names’ is nil.
+
+ The value should always contain ‘%m’ or ‘%M’, ‘%v’ or ‘%V’, and
+ ‘%t’ (or the obsolete ‘%T’). If ‘magit-uniquify-buffer-names’ is
+ non-nil, then the value must end with ‘%t’ or ‘%t%x’ (or the
+ obsolete ‘%T’). See issue #2841.
+
+ -- User Option: magit-uniquify-buffer-names
+
+ This option controls whether the names of Magit buffers are
+ uniquified. If the names are not being uniquified, then they
+ contain the full path of the top-level of the working tree of the
+ corresponding repository. If they are being uniquified, then they
+ end with the basename of the top-level, or if that would conflict
+ with the name used for other buffers, then the names of all these
+ buffers are adjusted until they no longer conflict.
+
+ This is done using the ‘uniquify’ package; customize its options to
+ control how buffer names are uniquified.
+
+\1f
+File: magit.info, Node: Quitting Windows, Next: Automatic Refreshing of Magit Buffers, Prev: Naming Buffers, Up: Modes and Buffers
+
+4.1.3 Quitting Windows
+----------------------
+
+‘q’ (‘magit-mode-bury-buffer’)
+
+ This command buries the current Magit buffer.
+
+ With a prefix argument, it instead kills the buffer. With a double
+ prefix argument, also kills all other Magit buffers associated with
+ the current project.
+
+ -- User Option: magit-bury-buffer-function
+
+ The function used to actually bury or kill the current buffer.
+
+ ‘magit-mode-bury-buffer’ calls this function with one argument. If
+ the argument is non-nil, then the function has to kill the current
+ buffer. Otherwise it has to bury it alive. The default value
+ currently is ‘magit-restore-window-configuration’.
+
+ -- Function: magit-restore-window-configuration kill-buffer
+
+ Bury or kill the current buffer using ‘quit-window’, which is
+ called with KILL-BUFFER as first and the selected window as second
+ argument.
+
+ Then restore the window configuration that existed right before the
+ current buffer was displayed in the selected frame. Unfortunately
+ that also means that point gets adjusted in all the buffers, which
+ are being displayed in the selected frame.
+
+ -- Function: magit-mode-quit-window kill-buffer
+
+ Bury or kill the current buffer using ‘quit-window’, which is
+ called with KILL-BUFFER as first and the selected window as second
+ argument.
+
+ Then, if the window was originally created to display a Magit
+ buffer and the buried buffer was the last remaining Magit buffer
+ that was ever displayed in the window, then that is deleted.
+
+\1f
+File: magit.info, Node: Automatic Refreshing of Magit Buffers, Next: Automatic Saving of File-Visiting Buffers, Prev: Quitting Windows, Up: Modes and Buffers
+
+4.1.4 Automatic Refreshing of Magit Buffers
+-------------------------------------------
+
+After running a command which may change the state of the current
+repository, the current Magit buffer and the corresponding status buffer
+are refreshed. The status buffer can be automatically refreshed
+whenever a buffer is saved to a file inside the respective repository by
+adding a hook, like so:
+
+ (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.
+
+\1f
+File: magit.info, Node: Automatic Saving of File-Visiting Buffers, Next: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Refreshing of Magit Buffers, Up: Modes and Buffers
+
+4.1.5 Automatic Saving of File-Visiting Buffers
+-----------------------------------------------
+
+File-visiting buffers are by default saved at certain points in time.
+This doesn’t guarantee that Magit buffers are always up-to-date, but,
+provided one only edits files by editing them in Emacs and uses only
+Magit to interact with Git, one can be fairly confident. When in doubt
+or after outside changes, type ‘g’ (‘magit-refresh’) to save and refresh
+explicitly.
+
+ -- User Option: magit-save-repository-buffers
+
+ This option controls whether file-visiting buffers are saved before
+ certain events.
+
+ If this is non-nil then all modified file-visiting buffers
+ belonging to the current repository may be saved before running
+ commands, before creating new Magit buffers, and before explicitly
+ refreshing such buffers. If this is ‘dontask’ then this is done
+ without user intervention. If it is ‘t’ then the user has to
+ confirm each save.
+
+\1f
+File: magit.info, Node: Automatic Reverting of File-Visiting Buffers, Prev: Automatic Saving of File-Visiting Buffers, Up: Modes and Buffers
+
+4.1.6 Automatic Reverting of File-Visiting Buffers
+--------------------------------------------------
+
+By default Magit automatically reverts buffers that are visiting files
+that are being tracked in a Git repository, after they have changed on
+disk. When using Magit one often changes files on disk by running Git,
+i.e. "outside Emacs", making this a rather important feature.
+
+ For example, if you discard a change in the status buffer, then that
+is done by running ‘git apply --reverse ...’, and Emacs considers the
+file to have "changed on disk". If Magit did not automatically revert
+the buffer, then you would have to type ‘M-x revert-buffer RET RET’ in
+the visiting buffer before you could continue making changes.
+
+ -- User Option: magit-auto-revert-mode
+
+ When this mode is enabled, then buffers that visit tracked files
+ are automatically reverted after the visited files change on disk.
+
+ -- User Option: global-auto-revert-mode
+
+ When this mode is enabled, then any file-visiting buffer is
+ automatically reverted after the visited file changes on disk.
+
+ If you like buffers that visit tracked files to be automatically
+ reverted, then you might also like any buffer to be reverted, not
+ just those visiting tracked files. If that is the case, then
+ enable this mode _instead of_ ‘magit-auto-revert-mode’.
+
+ -- User Option: magit-auto-revert-immediately
+
+ This option controls whether Magit reverts buffers immediately.
+
+ If this is non-nil and either ‘global-auto-revert-mode’ or
+ ‘magit-auto-revert-mode’ is enabled, then Magit immediately reverts
+ buffers by explicitly calling ‘auto-revert-buffers’ after running
+ Git for side-effects.
+
+ If ‘auto-revert-use-notify’ is non-nil (and file notifications are
+ actually supported), then ‘magit-auto-revert-immediately’ does not
+ have to be non-nil, because the reverts happen immediately anyway.
+
+ If ‘magit-auto-revert-immediately’ and ‘auto-revert-use-notify’ are
+ both ‘nil’, then reverts happen after ‘auto-revert-interval’
+ seconds of user inactivity. That is not desirable.
+
+ -- User Option: auto-revert-use-notify
+
+ This option controls whether file notification functions should be
+ used. Note that this variable unfortunately defaults to ‘t’ even
+ on systems on which file notifications cannot be used.
+
+ -- User Option: magit-auto-revert-tracked-only
+
+ This option controls whether ‘magit-auto-revert-mode’ only reverts
+ tracked files or all files that are located inside Git
+ repositories, including untracked files and files located inside
+ Git’s control directory.
+
+ -- User Option: auto-revert-mode
+
+ The global mode ‘magit-auto-revert-mode’ works by turning on this
+ local mode in the appropriate buffers (but
+ ‘global-auto-revert-mode’ is implemented differently). You can
+ also turn it on or off manually, which might be necessary if Magit
+ does not notice that a previously untracked file now is being
+ tracked or vice-versa.
+
+ -- User Option: auto-revert-stop-on-user-input
+
+ This option controls whether the arrival of user input suspends the
+ automatic reverts for ‘auto-revert-interval’ seconds.
+
+ -- User Option: auto-revert-interval
+
+ This option controls how many seconds Emacs waits for before
+ resuming suspended reverts.
+
+ -- User Option: auto-revert-buffer-list-filter
+
+ This option specifies an additional filter used by
+ ‘auto-revert-buffers’ to determine whether a buffer should be
+ reverted or not.
+
+ This option is provided by Magit, which also advises
+ ‘auto-revert-buffers’ to respect it. Magit users who do not turn
+ on the local mode ‘auto-revert-mode’ themselves, are best served by
+ setting the value to ‘magit-auto-revert-repository-buffer-p’.
+
+ However the default is nil, so as not to disturb users who do use
+ the local mode directly. If you experience delays when running
+ Magit commands, then you should consider using one of the
+ predicates provided by Magit - especially if you also use Tramp.
+
+ Users who do turn on ‘auto-revert-mode’ in buffers in which Magit
+ doesn’t do that for them, should likely not use any filter. Users
+ who turn on ‘global-auto-revert-mode’, do not have to worry about
+ this option, because it is disregarded if the global mode is
+ enabled.
+
+ -- User Option: auto-revert-verbose
+
+ This option controls whether Emacs reports when a buffer has been
+ reverted.
+
+ The options with the ‘auto-revert-’ prefix are located in the Custom
+group named ‘auto-revert’. The other, Magit-specific, options are
+located in the ‘magit’ group.
+
+* Menu:
+
+* Risk of Reverting Automatically::
+
+\1f
+File: magit.info, Node: Risk of Reverting Automatically, Up: Automatic Reverting of File-Visiting Buffers
+
+Risk of Reverting Automatically
+...............................
+
+For the vast majority of users, automatically reverting file-visiting
+buffers after they have changed on disk is harmless.
+
+ If a buffer is modified (i.e. it contains changes that haven’t been
+saved yet), then Emacs will refuse to automatically revert it. If you
+save a previously modified buffer, then that results in what is seen by
+Git as an uncommitted change. Git will then refuse to carry out any
+commands that would cause these changes to be lost. In other words, if
+there is anything that could be lost, then either Git or Emacs will
+refuse to discard the changes.
+
+ However, if you use file-visiting buffers as a sort of ad hoc
+"staging area", then the automatic reverts could potentially cause data
+loss. So far I have heard from only one user who uses such a workflow.
+
+ An example: You visit some file in a buffer, edit it, and save the
+changes. Then, outside of Emacs (or at least not using Magit or by
+saving the buffer) you change the file on disk again. At this point the
+buffer is the only place where the intermediate version still exists.
+You have saved the changes to disk, but that has since been overwritten.
+Meanwhile Emacs considers the buffer to be unmodified (because you have
+not made any changes to it since you last saved it to the visited file)
+and therefore would not object to it being automatically reverted. At
+this point an Auto-Revert mode would kick in. It would check whether
+the buffer is modified and since that is not the case it would revert
+it. The intermediate version would be lost. (Actually you could still
+get it back using the ‘undo’ command.)
+
+ If your workflow depends on Emacs preserving the intermediate version
+in the buffer, then you have to disable all Auto-Revert modes. But
+please consider that such a workflow would be dangerous even without
+using an Auto-Revert mode, and should therefore be avoided. If Emacs
+crashes or if you quit Emacs by mistake, then you would also lose the
+buffer content. There would be no autosave file still containing the
+intermediate version (because that was deleted when you saved the
+buffer) and you would not be asked whether you want to save the buffer
+(because it isn’t modified).
+
+\1f
+File: magit.info, Node: Sections, Next: Transient Commands, Prev: Modes and Buffers, Up: Interface Concepts
+
+4.2 Sections
+============
+
+Magit buffers are organized into nested sections, which can be collapsed
+and expanded, similar to how sections are handled in Org mode. Each
+section also has a type, and some sections also have a value. For each
+section type there can also be a local keymap, shared by all sections of
+that type.
+
+ Taking advantage of the section value and type, many commands operate
+on the current section, or when the region is active and selects
+sections of the same type, all of the selected sections. Commands that
+only make sense for a particular section type (as opposed to just
+behaving differently depending on the type) are usually bound in section
+type keymaps.
+
+* Menu:
+
+* Section Movement::
+* Section Visibility::
+* Section Hooks::
+* Section Types and Values::
+* Section Options::
+
+\1f
+File: magit.info, Node: Section Movement, Next: Section Visibility, Up: Sections
+
+4.2.1 Section Movement
+----------------------
+
+To move within a section use the usual keys (‘C-p’, ‘C-n’, ‘C-b’, ‘C-f’
+etc), whose global bindings are not shadowed. To move to another
+section use the following commands.
+
+‘p’ (‘magit-section-backward’)
+
+ When not at the beginning of a section, then move to the beginning
+ of the current section. At the beginning of a section, instead
+ move to the beginning of the previous visible section.
+
+‘n’ (‘magit-section-forward’)
+
+ Move to the beginning of the next visible section.
+
+‘M-p’ (‘magit-section-backward-siblings’)
+
+ Move to the beginning of the previous sibling section. If there is
+ no previous sibling section, then move to the parent section
+ instead.
+
+‘M-n’ (‘magit-section-forward-siblings’)
+
+ Move to the beginning of the next sibling section. If there is no
+ next sibling section, then move to the parent section instead.
+
+‘^’ (‘magit-section-up’)
+
+ Move to the beginning of the parent of the current section.
+
+ The above commands all call the hook ‘magit-section-movement-hook’.
+Any of the functions listed below can be used as members of this hook.
+
+ You might want to remove some of the functions that Magit adds using
+‘add-hook’. In doing so you have to make sure you do not attempt to
+remove function that haven’t even been added yet, for example:
+
+ (with-eval-after-load 'magit-diff
+ (remove-hook 'magit-section-movement-hook
+ 'magit-hunk-set-window-start))
+
+ -- Variable: magit-section-movement-hook
+
+ This hook is run by all of the above movement commands, after
+ arriving at the destination.
+
+ -- Function: magit-hunk-set-window-start
+
+ This hook function ensures that the beginning of the current
+ section is visible, provided it is a ‘hunk’ section. Otherwise, it
+ does nothing.
+
+ Loading ‘magit-diff’ adds this function to the hook.
+
+ -- Function: magit-section-set-window-start
+
+ This hook function ensures that the beginning of the current
+ section is visible, regardless of the section’s type. If you add
+ this to ‘magit-section-movement-hook’, then you must remove the
+ hunk-only variant in turn.
+
+ -- Function: magit-log-maybe-show-more-commits
+
+ This hook function only has an effect in log buffers, and ‘point’
+ is on the "show more" section. If that is the case, then it
+ doubles the number of commits that are being shown.
+
+ Loading ‘magit-log’ adds this function to the hook.
+
+ -- Function: magit-log-maybe-update-revision-buffer
+
+ When moving inside a log buffer, then this function updates the
+ revision buffer, provided it is already being displayed in another
+ window of the same frame.
+
+ Loading ‘magit-log’ adds this function to the hook.
+
+ -- Function: magit-log-maybe-update-blob-buffer
+
+ When moving inside a log buffer and another window of the same
+ frame displays a blob buffer, then this function instead displays
+ the blob buffer for the commit at point in that window.
+
+ -- Function: magit-status-maybe-update-revision-buffer
+
+ When moving inside a status buffer, then this function updates the
+ revision buffer, provided it is already being displayed in another
+ window of the same frame.
+
+ -- Function: magit-status-maybe-update-stash-buffer
+
+ When moving inside a status buffer, then this function updates the
+ stash buffer, provided it is already being displayed in another
+ window of the same frame.
+
+ -- Function: magit-status-maybe-update-blob-buffer
+
+ When moving inside a status buffer and another window of the same
+ frame displays a blob buffer, then this function instead displays
+ the blob buffer for the commit at point in that window.
+
+ -- Function: magit-stashes-maybe-update-stash-buffer
+
+ When moving inside a buffer listing stashes, then this function
+ updates the stash buffer, provided it is already being displayed in
+ another window of the same frame.
+
+ -- User Option: magit-update-other-window-delay
+
+ Delay before automatically updating the other window.
+
+ When moving around in certain buffers, then certain other buffers,
+ which are being displayed in another window, may optionally be
+ updated to display information about the section at point.
+
+ When holding down a key to move by more than just one section, then
+ that would update that buffer for each section on the way. To
+ prevent that, updating the revision buffer is delayed, and this
+ option controls for how long. For optimal experience you might
+ have to adjust this delay and/or the keyboard repeat rate and delay
+ of your graphical environment or operating system.
+
+\1f
+File: magit.info, Node: Section Visibility, Next: Section Hooks, Prev: Section Movement, Up: Sections
+
+4.2.2 Section Visibility
+------------------------
+
+Magit provides many commands for changing the visibility of sections,
+but all you need to get started are the next two.
+
+‘TAB’ (‘magit-section-toggle’)
+
+ Toggle the visibility of the body of the current section.
+
+‘C-<tab>’ (‘magit-section-cycle’)
+
+ Cycle the visibility of current section and its children.
+
+‘M-<tab>’ (‘magit-section-cycle-diffs’)
+
+ Cycle the visibility of diff-related sections in the current
+ buffer.
+
+‘S-<tab>’ (‘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.
+
+\1f
+File: magit.info, Node: Section Hooks, Next: Section Types and Values, Prev: Section Visibility, Up: Sections
+
+4.2.3 Section Hooks
+-------------------
+
+Which sections are inserted into certain buffers is controlled with
+hooks. This includes the status and the refs buffers. For other
+buffers, e.g. log and diff buffers, this is not possible. The command
+‘magit-describe-section’ can be used to see which hook (if any) was
+responsible for inserting the section at point.
+
+ For buffers whose sections can be customized by the user, a hook
+variable called ‘magit-TYPE-sections-hook’ exists. This hook should be
+changed using ‘magit-add-section-hook’. Avoid using ‘add-hooks’ or the
+Custom interface.
+
+ The various available section hook variables are described later in
+this manual along with the appropriate "section inserter functions".
+
+ -- Function: magit-add-section-hook hook function &optional at append
+ local
+
+ Add the function FUNCTION to the value of section hook HOOK.
+
+ Add FUNCTION at the beginning of the hook list unless optional
+ APPEND is non-nil, in which case FUNCTION is added at the end. If
+ FUNCTION already is a member then move it to the new location.
+
+ If optional AT is non-nil and a member of the hook list, then add
+ FUNCTION next to that instead. Add before or after AT, or replace
+ AT with FUNCTION depending on APPEND. If APPEND is the symbol
+ ‘replace’, then replace AT with FUNCTION. For any other non-nil
+ value place FUNCTION right after AT. If nil, then place FUNCTION
+ right before AT. If FUNCTION already is a member of the list but
+ AT is not, then leave FUNCTION where ever it already is.
+
+ If optional LOCAL is non-nil, then modify the hook’s buffer-local
+ value rather than its global value. This makes the hook local by
+ copying the default value. That copy is then modified.
+
+ HOOK should be a symbol. If HOOK is void, it is first set to nil.
+ HOOK’s value must not be a single hook function. FUNCTION should
+ be a function that takes no arguments and inserts one or multiple
+ sections at point, moving point forward. FUNCTION may choose not
+ to insert its section(s), when doing so would not make sense. It
+ should not be abused for other side-effects.
+
+ To remove a function from a section hook, use ‘remove-hook’.
+
+\1f
+File: magit.info, Node: Section Types and Values, Next: Section Options, Prev: Section Hooks, Up: Sections
+
+4.2.4 Section Types and Values
+------------------------------
+
+Each section has a type, for example ‘hunk’, ‘file’, and ‘commit’.
+Instances of certain section types also have a value. The value of a
+section of type ‘file’, for example, is a file name.
+
+ Users usually do not have to worry about a section’s type and value,
+but knowing them can be handy at times.
+
+‘M-x magit-describe-section-briefly’ (‘magit-describe-section-briefly’)
+
+ Show information about the section at point in the echo area, as
+ "#<magit-section VALUE [TYPE PARENT-TYPE...] BEGINNING-END>".
+
+ 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.
+
+\1f
+File: magit.info, Node: Section Options, Prev: Section Types and Values, Up: Sections
+
+4.2.5 Section Options
+---------------------
+
+This section describes options that have an effect on more than just a
+certain type of sections. As you can see there are not many of those.
+
+ -- User Option: magit-section-show-child-count
+
+ Whether to append the number of children to section headings. This
+ only affects sections that could benefit from this information.
+
+\1f
+File: magit.info, Node: Transient Commands, Next: Transient Arguments and Buffer Variables, Prev: Sections, Up: Interface Concepts
+
+4.3 Transient Commands
+======================
+
+Many Magit commands are implemented as *transient* commands. First the
+user invokes a *prefix* command, which causes its *infix* arguments and
+*suffix* commands to be displayed in the echo area. The user then
+optionally sets some infix arguments and finally invokes one of the
+suffix commands.
+
+ This is implemented in the library ‘transient’. Earlier Magit
+releases used the package ‘magit-popup’ and even earlier versions
+library ‘magit-key-mode’.
+
+ Transient is documented in *note (transient)Top::.
+
+‘C-c C-c’ (‘magit-dispatch’)
+
+ This transient prefix command binds most of Magit’s other prefix
+ commands as suffix commands and displays them in a temporary buffer
+ until one of them is invoked. Invoking such a sub-prefix causes
+ the suffixes of that command to be bound and displayed instead of
+ those of ‘magit-dispatch’.
+
+ This command is also, or especially, useful outside Magit buffers, so
+you should setup a global binding:
+
+ (global-set-key (kbd "C-x M-g") 'magit-dispatch)
+
+\1f
+File: magit.info, Node: Transient Arguments and Buffer Variables, Next: Completion Confirmation and the Selection, Prev: Transient Commands, Up: Interface Concepts
+
+4.4 Transient Arguments and Buffer Variables
+============================================
+
+The infix arguments of many of Magit’s transient prefix commands cease
+to have an effect once the ‘git’ command that is called with those
+arguments has returned. Commands that create a commit are a good
+example for this. If the user changes the arguments, then that only
+affects the next invocation of a suffix command. If the same transient
+prefix command is later invoked again, then the arguments are initially
+reset to the default value. This default value can be set for the
+current Emacs session or saved permanently, see *note (transient)Saving
+Values::. It is also possible to cycle through previously used sets of
+arguments using ‘M-p’ and ‘M-n’, see *note (transient)Using History::.
+
+ However the infix arguments of many other transient commands continue
+to have an effect even after the ‘git’ command that was called with
+those arguments has returned. The most important commands like this are
+those that display a diff or log in a dedicated buffer. Their arguments
+obviously continue to have an effect for as long as the respective diff
+or log is being displayed. Furthermore the used arguments are stored in
+buffer-local variables for future reference.
+
+ For commands in the second group it isn’t always desirable to reset
+their arguments to the global value when the transient prefix command is
+invoked again.
+
+ As mentioned above, it is possible to cycle through previously used
+sets of arguments while a transient popup is visible. That means that
+we could always reset the infix arguments to the default because the set
+of arguments that is active in the existing buffer is only a few ‘M-p’
+away. Magit can be configured to behave like that, but because I expect
+that most users would not find that very convenient, it is not the
+default.
+
+ Also note that it is possible to change the diff and log arguments
+used in the current buffer (including the status buffer, which contains
+both diff and log sections) using the respective "refresh" transient
+prefix commands on ‘D’ and ‘L’. (‘d’ and ‘l’ on the other hand are
+intended to change *what* diff or log is being displayed. It is
+possible to also change *how* the diff or log is being displayed at the
+same time, but if you only want to do the latter, then you should use
+the refresh variants.) Because these secondary diff and log transient
+prefixes are about *changing* the arguments used in the current buffer,
+they *always* start out with the set of arguments that are currently in
+effect in that buffer.
+
+ Some commands are usually invoked directly even though they can also
+be invoked as the suffix of a transient prefix command. Most
+prominently ‘magit-show-commit’ is usually invoked by typing ‘RET’ while
+point is on a commit in a log, but it can also be invoked from the
+‘magit-diff’ transient prefix.
+
+ When such a command is invoked directly, then it is important to
+reuse the arguments as specified by the respective buffer-local values,
+instead of using the default arguments. Imagine you press ‘RET’ in a
+log to display the commit at point in a different buffer and then use
+‘D’ to change how the diff is displayed in that buffer. And then you
+press ‘RET’ on another commit to show that instead and the diff
+arguments are reset to the default. Not cool; so Magit does not do that
+by default.
+
+ -- User Option: magit-prefix-use-buffer-arguments
+
+ This option controls whether the infix arguments initially shown in
+ certain transient prefix commands are based on the arguments that
+ are currently in effect in the buffer that their suffixes update.
+
+ The ‘magit-diff’ and ‘magit-log’ transient prefix commands are
+ affected by this option.
+
+ -- User Option: magit-direct-use-buffer-arguments
+
+ This option controls whether certain commands, when invoked
+ directly (i.e. not as the suffix of a transient prefix command),
+ use the arguments that are currently active in the buffer that they
+ are about to update. The alternative is to use the default value
+ for these arguments, which might change the arguments that are used
+ in the buffer.
+
+Valid values for both of the above options are:
+
+ • ‘always’: Always use the set of arguments that is currently active
+ in the respective buffer, provided that buffer exists of course.
+
+ • ‘selected’ or ‘t’: Use the set of arguments from the respective
+ buffer, but only if it is displayed in a window of the current
+ frame. This is the default for both variables.
+
+ • ‘current’: Use the set of arguments from the respective buffer, but
+ only if it is the current buffer.
+
+ • ‘never’: Never use the set of arguments from the respective buffer.
+
+I am afraid it gets more complicated still:
+
+ • The global diff and log arguments are set for each support mode
+ individually. The diff arguments for example have different values
+ in ‘magit-diff-mode’, ‘magit-revision-mode’,
+ ‘magit-merge-preview-mode’ and ‘magit-status-mode’ buffers.
+ Setting or saving the value for one mode does not change the value
+ for other modes. The history however is shared.
+
+ • When ‘magit-show-commit’ is invoked directly from a log buffer,
+ then the file filter is picked up from that buffer, not from the
+ revision buffer and or the mode’s global diff arguments.
+
+ • Even though they are suffixes of the diff prefix
+ ‘magit-show-commit’ and ‘magit-stash-show’ do not use the diff
+ buffer used by the diff commands, instead they use the dedicated
+ revision and stash buffers.
+
+ At the time you invoke the diff prefix it is unknown to Magit which
+ of the suffix commands you are going to invoke. While not certain,
+ more often than not users invoke one of the commands that use the
+ diff buffer, so the initial infix arguments are those used in that
+ buffer. However if you invoke one of these commands directly, then
+ Magit knows that it should use the arguments from the revision
+ resp. stash buffer.
+
+ • The log prefix also features reflog commands, but these commands do
+ not use the log arguments.
+
+ • If ‘magit-show-refs’ is invoked from a ‘magit-refs-mode’ buffer,
+ then it acts as a refresh prefix and therefore unconditionally uses
+ the buffer’s arguments as initial arguments. If it is invoked
+ elsewhere with a prefix argument, then it acts as regular prefix
+ and therefore respects ‘magit-prefix-use-buffer-arguments’. If it
+ is invoked elsewhere without a prefix argument, then it acts as a
+ direct command and therefore respects
+ ‘magit-direct-use-buffer-arguments’.
+
+\1f
+File: magit.info, Node: Completion Confirmation and the Selection, Next: Running Git, Prev: Transient Arguments and Buffer Variables, Up: Interface Concepts
+
+4.5 Completion, Confirmation and the Selection
+==============================================
+
+* Menu:
+
+* Action Confirmation::
+* Completion and Confirmation::
+* The Selection::
+* The hunk-internal region::
+* Support for Completion Frameworks::
+* Additional Completion Options::
+
+\1f
+File: magit.info, Node: Action Confirmation, Next: Completion and Confirmation, Up: Completion Confirmation and the Selection
+
+4.5.1 Action Confirmation
+-------------------------
+
+By default many actions that could potentially lead to data loss have to
+be confirmed. This includes many very common actions, so this can
+quickly become annoying. Many of these actions can be undone and if you
+have thought about how to undo certain mistakes, then it should be safe
+to disable confirmation for the respective actions.
+
+ The option ‘magit-no-confirm’ can be used to tell Magit to perform
+certain actions without the user having to confirm them. Note that
+while this option can only be used to disable confirmation for a
+specific set of actions, the next section explains another way of
+telling Magit to ask fewer questions.
+
+ -- User Option: magit-no-confirm
+
+ The value of this option is a list of symbols, representing actions
+ that do not have to be confirmed by the user before being carried
+ out.
+
+ By default many potentially dangerous commands ask the user for
+ confirmation. Each of the below symbols stands for an action
+ which, when invoked unintentionally or without being fully aware of
+ the consequences, could lead to tears. In many cases there are
+ several commands that perform variations of a certain action, so we
+ don’t use the command names but more generic symbols.
+
+ • Applying changes:
+
+ • ‘discard’ Discarding one or more changes (i.e. hunks or
+ the complete diff for a file) loses that change,
+ obviously.
+
+ • ‘reverse’ Reverting one or more changes can usually be
+ undone by reverting the reversion.
+
+ • ‘stage-all-changes’, ‘unstage-all-changes’ When there are
+ both staged and unstaged changes, then un-/staging
+ everything would destroy that distinction. Of course
+ that also applies when un-/staging a single change, but
+ then less is lost and one does that so often that having
+ to confirm every time would be unacceptable.
+
+ • Files:
+
+ • ‘delete’ When a file that isn’t yet tracked by Git is
+ deleted, then it is completely lost, not just the last
+ changes. Very dangerous.
+
+ • ‘trash’ Instead of deleting a file it can also be move to
+ the system trash. Obviously much less dangerous than
+ deleting it.
+
+ Also see option ‘magit-delete-by-moving-to-trash’.
+
+ • ‘resurrect’ A deleted file can easily be resurrected by
+ "deleting" the deletion, which is done using the same
+ command that was used to delete the same file in the
+ first place.
+
+ • ‘untrack’ Untracking a file can be undone by tracking it
+ again.
+
+ • ‘rename’ Renaming a file can easily be undone.
+
+ • Sequences:
+
+ • ‘reset-bisect’ Aborting (known to Git as "resetting") a
+ bisect operation loses all information collected so far.
+
+ • ‘abort-rebase’ Aborting a rebase throws away all already
+ modified commits, but it’s possible to restore those from
+ the reflog.
+
+ • ‘abort-merge’ Aborting a merge throws away all conflict
+ resolutions which have already been carried out by the
+ user.
+
+ • ‘merge-dirty’ Merging with a dirty worktree can make it
+ hard to go back to the state before the merge was
+ initiated.
+
+ • References:
+
+ • ‘delete-unmerged-branch’ Once a branch has been deleted,
+ it can only be restored using low-level recovery tools
+ provided by Git. And even then the reflog is gone. The
+ user always has to confirm the deletion of a branch by
+ accepting the default choice (or selecting another
+ branch), but when a branch has not been merged yet, also
+ make sure the user is aware of that.
+
+ • ‘delete-pr-remote’ When deleting a branch that was
+ created from a pull-request and if no other branches
+ still exist on that remote, then ‘magit-branch-delete’
+ offers to delete the remote as well. This should be safe
+ because it only happens if no other refs exist in the
+ remotes namespace, and you can recreate the remote if
+ necessary.
+
+ • ‘drop-stashes’ Dropping a stash is dangerous because Git
+ stores stashes in the reflog. Once a stash is removed,
+ there is no going back without using low-level recovery
+ tools provided by Git. When a single stash is dropped,
+ then the user always has to confirm by accepting the
+ default (or selecting another). This action only
+ concerns the deletion of multiple stashes at once.
+
+ • Publishing:
+
+ ‘set-and-push’ When pushing to the upstream or the push-remote
+ and that isn’t actually configured yet, then the user can
+ first set the target. If s/he confirms the default too
+ quickly, then s/he might end up pushing to the wrong branch
+ and if the remote repository is configured to disallow fixing
+ such mistakes, then that can be quite embarrassing and
+ annoying.
+
+ • Edit published history:
+
+ Without adding these symbols here, you will be warned before
+ editing commits that have already been pushed to one of the
+ branches listed in ‘magit-published-branches’.
+
+ • ‘amend-published’ Affects most commands that amend to
+ "HEAD".
+
+ • ‘rebase-published’ Affects commands that perform
+ interactive rebases. This includes commands from the
+ commit transient that modify a commit other than "HEAD",
+ namely the various fixup and squash variants.
+
+ • ‘edit-published’ Affects the commands
+ ‘magit-edit-line-commit’ and
+ ‘magit-diff-edit-hunk-commit’. These two commands make
+ it quite easy to accidentally edit a published commit, so
+ you should think twice before configuring them not to ask
+ for confirmation.
+
+ To disable confirmation completely, add all three symbols here
+ or set ‘magit-published-branches’ to ‘nil’.
+
+ • Various:
+
+ • ‘kill-process’ There seldom is a reason to kill a
+ process.
+
+ • Global settings:
+
+ Instead of adding all of the above symbols to the value of
+ this option, you can also set it to the atom ‘t’, which has
+ the same effect as adding all of the above symbols. Doing
+ that most certainly is a bad idea, especially because other
+ symbols might be added in the future. So even if you don’t
+ want to be asked for confirmation for any of these actions,
+ you are still better of adding all of the respective symbols
+ individually.
+
+ When ‘magit-wip-before-change-mode’ is enabled, then the
+ following actions can be undone fairly easily: ‘discard’,
+ ‘reverse’, ‘stage-all-changes’, and ‘unstage-all-changes’. If
+ and only if this mode is enabled, then ‘safe-with-wip’ has the
+ same effect as adding all of these symbols individually.
+
+\1f
+File: magit.info, Node: Completion and Confirmation, Next: The Selection, Prev: Action Confirmation, Up: Completion Confirmation and the Selection
+
+4.5.2 Completion and Confirmation
+---------------------------------
+
+Many Magit commands ask the user to select from a list of possible
+things to act on, while offering the most likely choice as the default.
+For many of these commands the default is the thing at point, provided
+that it actually is a valid thing to act on. For many commands that act
+on a branch, the current branch serves as the default if there is no
+branch at point.
+
+ These commands combine asking for confirmation and asking for a
+target to act on into a single action. The user can confirm the default
+target using ‘RET’ or abort using ‘C-g’. This is similar to a
+‘y-or-n-p’ prompt, but the keys to confirm or abort differ.
+
+ At the same time the user is also given the opportunity to select
+another target, which is useful because for some commands and/or in some
+situations you might want to select the action before selecting the
+target by moving to it.
+
+ However you might find that for some commands you always want to use
+the default target, if any, or even that you want the command to act on
+the default without requiring any confirmation at all. The option
+‘magit-dwim-selection’ can be used to configure certain commands to that
+effect.
+
+ Note that when the region is active then many commands act on the
+things that are selected using a mechanism based on the region, in many
+cases after asking for confirmation. This region-based mechanism is
+called the "selection" and is described in detail in the next section.
+When a selection exists that is valid for the invoked command, then that
+command never offers to act on something else, and whether it asks for
+confirmation is not controlled by this option.
+
+ Also note that Magit asks for confirmation of certain actions that
+are not coupled with completion (or the selection). Such dialogs are
+also not affected by this option and are described in the previous
+section.
+
+ -- User Option: magit-dwim-selection
+
+ This option can be used to tell certain commands to use the thing at
+point instead of asking the user to select a candidate to act on, with
+or without confirmation.
+
+ The value has the form ‘((COMMAND nil|PROMPT DEFAULT)...)’.
+
+ • COMMAND is the command that should not prompt for a choice. To
+ have an effect, the command has to use the function
+ ‘magit-completing-read’ or a utility function which in turn uses
+ that function.
+
+ • If the command uses ‘magit-completing-read’ multiple times, then
+ PROMPT can be used to only affect one of these uses. PROMPT, if
+ non-nil, is a regular expression that is used to match against the
+ PROMPT argument passed to ‘magit-completing-read’.
+
+ • DEFAULT specifies how to use the default. If it is ‘t’, then the
+ DEFAULT argument passed to ‘magit-completing-read’ is used without
+ confirmation. If it is ‘ask’, then the user is given a chance to
+ abort. DEFAULT can also be ‘nil’, in which case the entry has no
+ effect.
+
+\1f
+File: magit.info, Node: The Selection, Next: The hunk-internal region, Prev: Completion and Confirmation, Up: Completion Confirmation and the Selection
+
+4.5.3 The Selection
+-------------------
+
+If the region is active, then many Magit commands act on the things that
+are selected using a mechanism based on the region instead of one single
+thing. When the region is not active, then these commands act on the
+thing at point or read a single thing to act on. This is described in
+the previous section — this section only covers how multiple things are
+selected, how that is visualized, and how certain commands behave when
+that is the case.
+
+ Magit’s mechanism for selecting multiple things, or rather sections
+that represent these things, is based on the Emacs region, but the area
+that Magit considers to be selected is typically larger than the region
+and additional restrictions apply.
+
+ Magit makes a distinction between a region that qualifies as forming
+a valid Magit selection and a region that does not. If the region does
+not qualify, then it is displayed as it is in other Emacs buffers. If
+the region does qualify as a Magit selection, then the selection is
+always visualized, while the region itself is only visualized if it
+begins and ends on the same line.
+
+ For a region to qualify as a Magit selection, it must begin in the
+heading of one section and end in the heading of a sibling section.
+Note that if the end of the region is at the very beginning of section
+heading (i.e. at the very beginning of a line) then that section is
+considered to be *inside* the selection.
+
+ This is not consistent with how the region is normally treated in
+Emacs — if the region ends at the beginning of a line, then that line is
+outside the region. Due to how Magit visualizes the selection, it
+should be obvious that this difference exists.
+
+ Not every command acts on every valid selection. Some commands do
+not even consider the location of point, others may act on the section
+at point but not support acting on the selection, and even commands that
+do support the selection of course only do so if it selects things that
+they can act on.
+
+ This is the main reason why the selection must include the section at
+point. Even if a selection exists, the invoked command may disregard
+it, in which case it may act on the current section only. It is much
+safer to only act on the current section but not the other selected
+sections than it is to act on the current section *instead* of the
+selected sections. The latter would be much more surprising and if the
+current section always is part of the selection, then that cannot
+happen.
+
+ -- Variable: magit-keep-region-overlay
+
+ This variable controls whether the region is visualized as usual
+ even when a valid Magit selection or a hunk-internal region exists.
+ See the doc-string for more information.
+
+\1f
+File: magit.info, Node: The hunk-internal region, Next: Support for Completion Frameworks, Prev: The Selection, Up: Completion Confirmation and the Selection
+
+4.5.4 The hunk-internal region
+------------------------------
+
+Somewhat related to the Magit selection described in the previous
+section is the hunk-internal region.
+
+ Like the selection, the hunk-internal region is based on the Emacs
+region but causes that region to not be visualized as it would in other
+Emacs buffers, and includes the line on which the region ends even if it
+ends at the very beginning of that line.
+
+ Unlike the selection, which is based on a region that must begin in
+the heading of one section and ends in the section of a sibling section,
+the hunk-internal region must begin inside the *body* of a hunk section
+and end in the body of the *same* section.
+
+ The hunk-internal region is honored by "apply" commands, which can,
+among other targets, act on a hunk. If the hunk-internal region is
+active, then such commands act only on the marked part of the hunk
+instead of on the complete hunk.
+
+\1f
+File: magit.info, Node: Support for Completion Frameworks, Next: Additional Completion Options, Prev: The hunk-internal region, Up: Completion Confirmation and the Selection
+
+4.5.5 Support for Completion Frameworks
+---------------------------------------
+
+The built-in option ‘completing-read-function’ specifies the low-level
+function used by ‘completing-read’ to ask a user to select from a list
+of choices. Its default value is ‘completing-read-default’.
+Alternative completion frameworks typically activate themselves by
+substituting their own implementation.
+
+ Mostly for historic reasons Magit provides a similar option named
+‘magit-completing-read-function’, which only controls the low-level
+function used by ‘magit-completing-read’. This option also makes it
+possible to use a different completing mechanism for Magit than for the
+rest of Emacs, but doing that is not recommend.
+
+ You most likely don’t have to customize the magit-specific option to
+use an alternative completion framework. For example, if you enable
+‘ivy-mode’, then Magit will respect that, and if you enable ‘helm-mode’,
+then you are done too.
+
+ However if you want to use Ido, then ‘ido-mode’ won’t do the trick.
+You will also have to install the ‘ido-completing-read+’ package and use
+‘magit-ido-completing-read’ as ‘magit-completing-read-function’.
+
+ -- User Option: magit-completing-read-function
+
+ The value of this variable is the low-level function used to
+ perform completion by code that uses ‘magit-completing-read’ (as
+ opposed to the built-in ‘completing-read’).
+
+ The default value, ‘magit-builtin-completing-read’, is suitable for
+ the standard completion mechanism, ‘ivy-mode’, and ‘helm-mode’ at
+ least.
+
+ The built-in ‘completing-read’ and ‘completing-read-default’ are
+ *not* suitable to be used here. ‘magit-builtin-completing-read’
+ performs some additional work, and any function used in its place
+ has to do the same.
+
+ -- Function: magit-builtin-completing-read prompt choices &optional
+ predicate require-match initial-input hist def
+
+ This function performs completion using the built-in
+ ‘completing-read’ and does some additional magit-specific work.
+
+ -- Function: magit-ido-completing-read prompt choices &optional
+ predicate require-match initial-input hist def
+
+ This function performs completion using ‘ido-completing-read+’ from
+ the package by the same name (which you have to explicitly install)
+ and does some additional magit-specific work.
+
+ We have to use ‘ido-completing-read+’ instead of the
+ ‘ido-completing-read’ that comes with Ido itself, because the
+ latter, while intended as a drop-in replacement, cannot serve that
+ purpose because it violates too many of the implicit conventions.
+
+ -- Function: magit-completing-read prompt choices &optional predicate
+ require-match initial-input hist def fallback
+
+ This is the function that Magit commands use when they need the
+ user to select a single thing to act on. The arguments have the
+ same meaning as for ‘completing-read’, except for FALLBACK, which
+ is unique to this function and is described below.
+
+ Instead of asking the user to choose from a list of possible
+ candidates, this function may just return the default specified by
+ DEF, with or without requiring user confirmation. Whether that is
+ the case depends on PROMPT, ‘this-command’ and
+ ‘magit-dwim-selection’. See the documentation of the latter for
+ more information.
+
+ If it does read a value in the minibuffer, then this function acts
+ similar to ‘completing-read’, except for the following:
+
+ • COLLECTION must be a list of choices. A function is not
+ supported.
+
+ • If REQUIRE-MATCH is ‘nil’ and the user exits without a choice,
+ then ‘nil’ is returned instead of an empty string.
+
+ • If REQUIRE-MATCH is non-nil and the users exits without a
+ choice, an user-error is raised.
+
+ • FALLBACK specifies a secondary default that is only used if
+ the primary default DEF is ‘nil’. The secondary default is
+ not subject to ‘magit-dwim-selection’ — if DEF is ‘nil’ but
+ FALLBACK is not, then this function always asks the user to
+ choose a candidate, just as if both defaults were ‘nil’.
+
+ • ": " is appended to PROMPT.
+
+ • PROMPT is modified to end with \" (default DEF|FALLBACK): \"
+ provided that DEF or FALLBACK is non-nil, that neither
+ ‘ivy-mode’ nor ‘helm-mode’ is enabled, and that
+ ‘magit-completing-read-function’ is set to its default value
+ of ‘magit-builtin-completing-read’.
+
+\1f
+File: magit.info, Node: Additional Completion Options, Prev: Support for Completion Frameworks, Up: Completion Confirmation and the Selection
+
+4.5.6 Additional Completion Options
+-----------------------------------
+
+ -- User Option: magit-list-refs-sortby
+
+ For many commands that read a ref or refs from the user, the value
+ of this option can be used to control the order of the refs. Valid
+ values include any key accepted by the ‘--sort’ flag of ‘git
+ for-each-ref’. By default, refs are sorted alphabetically by their
+ full name (e.g., "refs/heads/master").
+
+\1f
+File: magit.info, Node: Running Git, Prev: Completion Confirmation and the Selection, Up: Interface Concepts
+
+4.6 Running Git
+===============
+
+* Menu:
+
+* Viewing Git Output::
+* Git Process Status::
+* Running Git Manually::
+* Git Executable::
+* Global Git Arguments::
+
+\1f
+File: magit.info, Node: Viewing Git Output, Next: Git Process Status, Up: Running Git
+
+4.6.1 Viewing Git Output
+------------------------
+
+Magit runs Git either for side-effects (e.g. when pushing) or to get
+some value (e.g. the name of the current branch).
+
+ When Git is run for side-effects, the process output is logged in a
+per-repository log buffer, which can be consulted using the
+‘magit-process’ command when things don’t go as expected.
+
+ The output/errors for up to ‘magit-process-log-max’ Git commands are
+retained.
+
+‘$’ (‘magit-process’)
+
+ This commands displays the process buffer for the current
+ repository.
+
+ Inside that buffer, the usual key bindings for navigating and showing
+sections are available. There is one additional command.
+
+‘k’ (‘magit-process-kill’)
+
+ This command kills the process represented by the section at point.
+
+ -- User Option: magit-git-debug
+
+ When this is non-nil then the output of all calls to git are logged
+ in the process buffer. This is useful when debugging, otherwise it
+ just negatively affects performance.
+
+\1f
+File: magit.info, Node: Git Process Status, Next: Running Git Manually, Prev: Viewing Git Output, Up: Running Git
+
+4.6.2 Git Process Status
+------------------------
+
+When a Git process is running for side-effects, Magit displays an
+indicator in the mode line, using the ‘magit-mode-line-process’ face.
+
+ If the Git process exits successfully, the process indicator is
+removed from the mode line immediately.
+
+ In the case of a Git error, the process indicator is not removed, but
+is instead highlighted with the ‘magit-mode-line-process-error’ face,
+and the error details from the process buffer are provided as a tooltip
+for mouse users. This error indicator persists in the mode line until
+the next magit buffer refresh.
+
+ If you do not wish process errors to be indicated in the mode line,
+customize the ‘magit-process-display-mode-line-error’ user option.
+
+ Process errors are additionally indicated at the top of the status
+buffer.
+
+\1f
+File: magit.info, Node: Running Git Manually, Next: Git Executable, Prev: Git Process Status, Up: Running Git
+
+4.6.3 Running Git Manually
+--------------------------
+
+While Magit provides many Emacs commands to interact with Git, it does
+not cover everything. In those cases your existing Git knowledge will
+come in handy. Magit provides some commands for running arbitrary Git
+commands by typing them into the minibuffer, instead of having to switch
+to a shell.
+
+‘!’ (‘magit-run’)
+
+ This transient prefix command binds the following suffix commands
+ and displays them in a temporary buffer until a suffix is invoked.
+
+‘! !’ (‘magit-git-command-topdir’)
+
+ This command reads a command from the user and executes it in the
+ top-level directory of the current working tree.
+
+ The string "git " is used as initial input when prompting the user
+ for the command. It can be removed to run another command.
+
+‘! p’ (‘magit-git-command’)
+
+ This command reads a command from the user and executes it in
+ ‘default-directory’. With a prefix argument the command is
+ executed in the top-level directory of the current working tree
+ instead.
+
+ The string "git " is used as initial input when prompting the user
+ for the command. It can be removed to run another command.
+
+‘! s’ (‘magit-shell-command-topdir’)
+
+ This command reads a command from the user and executes it in the
+ top-level directory of the current working tree.
+
+‘! S’ (‘magit-shell-command’)
+
+ This command reads a command from the user and executes it in
+ ‘default-directory’. With a prefix argument the command is
+ executed in the top-level directory of the current working tree
+ instead.
+
+ -- User Option: magit-shell-command-verbose-prompt
+
+ Whether the prompt, used by the above commands when reading a shell
+ command, shows the directory in which it will be run.
+
+ These suffix commands start external gui tools.
+
+‘! k’ (‘magit-run-gitk’)
+
+ This command runs ‘gitk’ in the current repository.
+
+‘! a’ (‘magit-run-gitk-all’)
+
+ This command runs ‘gitk --all’ in the current repository.
+
+‘! b’ (‘magit-run-gitk-branches’)
+
+ This command runs ‘gitk --branches’ in the current repository.
+
+‘! g’ (‘magit-run-git-gui’)
+
+ This command runs ‘git gui’ in the current repository.
+
+\1f
+File: magit.info, Node: Git Executable, Next: Global Git Arguments, Prev: Running Git Manually, Up: Running Git
+
+4.6.4 Git Executable
+--------------------
+
+Except on MS Windows, Magit defaults to running Git without specifying
+the path to the git executable. Instead the first executable found by
+Emacs on ‘exec-path’ is used (whose value in turn is set based on the
+value of the environment variable ‘$PATH’ when Emacs was started).
+
+ This has the advantage that it continues to work even when using
+Tramp to connect to a remote machine on which the executable is found in
+a different place. The downside is that if you have multiple versions
+of Git installed, then you might end up using another version than the
+one you think you are using.
+
+‘M-x magit-version’ (‘magit-version’)
+
+ This command shows the currently used versions of Magit, Git, and
+ Emacs in the echo area. Non-interactively this just returns the
+ Magit version.
+
+ When the ‘system-type’ is ‘windows-nt’, then ‘magit-git-executable’
+is set to an absolute path when Magit is first loaded. This is
+necessary because Git on that platform comes with several wrapper
+scripts for the actual git binary, which are also placed on ‘$PATH’, and
+using one of these wrappers instead of the binary would degrade
+performance horribly.
+
+ If Magit doesn’t find the correct executable then you *can* work
+around that by setting ‘magit-git-executable’ to an absolute path. But
+note that doing so is a kludge. It is better to make sure the order in
+the environment variable ‘$PATH’ is correct, and that Emacs is started
+with that environment in effect. The command
+‘magit-debug-git-executable’ can be useful to find out where Emacs is
+searching for git. If you have to connect from Windows to a non-Windows
+machine, then you must change the value to "git".
+
+ -- User Option: magit-git-executable
+
+ The git executable used by Magit, either the full path to the
+ executable or the string "git" to let Emacs find the executable
+ itself, using the standard mechanism for doing such things.
+
+‘M-x magit-debug-git-executable’ (‘magit-debug-git-executable’)
+
+ Display a buffer with information about ‘magit-git-executable’.
+
+\1f
+File: magit.info, Node: Global Git Arguments, Prev: Git Executable, Up: Running Git
+
+4.6.5 Global Git Arguments
+--------------------------
+
+ -- User Option: magit-git-global-arguments
+
+ The arguments set here are used every time the git executable is
+ run as a subprocess. They are placed right after the executable
+ itself and before the git command - as in ‘git HERE... COMMAND
+ REST’. For valid arguments see *note (gitman)git::.
+
+ Be careful what you add here, especially if you are using Tramp to
+ connect to servers with ancient Git versions. Never remove
+ anything that is part of the default value, unless you really know
+ what you are doing. And think very hard before adding something;
+ it will be used every time Magit runs Git for any purpose.
+
+\1f
+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::
+
+\1f
+File: magit.info, Node: Status Buffer, Next: Repository List, Up: Inspecting
+
+5.1 Status Buffer
+=================
+
+While other Magit buffers contain e.g. one particular diff or one
+particular log, the status buffer contains the diffs for staged and
+unstaged changes, logs for unpushed and unpulled commits, lists of
+stashes and untracked files, and information related to the current
+branch.
+
+ During certain incomplete operations – for example when a merge
+resulted in a conflict – additional information is displayed that helps
+proceeding with or aborting the operation.
+
+ The command ‘magit-status’ displays the status buffer belonging to
+the current repository in another window. This command is used so often
+that it should be bound globally. We recommend using ‘C-x g’:
+
+ (global-set-key (kbd "C-x g") 'magit-status)
+
+‘C-x g’ (‘magit-status’)
+
+ When invoked from within an existing Git repository, then this
+ command shows the status of that repository in a buffer.
+
+ If the current directory isn’t located within a Git repository,
+ then this command prompts for an existing repository or an
+ arbitrary directory, depending on the option
+ ‘magit-repository-directories’, and the status for the selected
+ repository is shown instead.
+
+ • If that option specifies any existing repositories, then the
+ user is asked to select one of them.
+
+ • Otherwise the user is asked to select an arbitrary directory
+ using regular file-name completion. If the selected directory
+ is the top-level directory of an existing working tree, then
+ the status buffer for that is shown.
+
+ • Otherwise the user is offered to initialize the selected
+ directory as a new repository. After creating the repository
+ its status buffer is shown.
+
+ These fallback behaviors can also be forced using one or more
+ prefix arguments:
+
+ • With two prefix arguments (or more precisely a numeric prefix
+ value of 16 or greater) an arbitrary directory is read, which
+ is then acted on as described above. The same could be
+ accomplished using the command ‘magit-init’.
+
+ • With a single prefix argument an existing repository is read
+ from the user, or if no repository can be found based on the
+ value of ‘magit-repository-directories’, then the behavior is
+ the same as with two prefix arguments.
+
+ -- User Option: magit-repository-directories
+
+ List of directories that are Git repositories or contain Git
+ repositories.
+
+ Each element has the form ‘(DIRECTORY . DEPTH)’. DIRECTORY has to
+ be a directory or a directory file-name, a string. DEPTH, an
+ integer, specifies the maximum depth to look for Git repositories.
+ If it is 0, then only add DIRECTORY itself.
+
+ This option controls which repositories are being listed by
+ ‘magit-list-repositories’. It also affects ‘magit-status’ (which
+ see) in potentially surprising ways (see above).
+
+ -- Command: ido-enter-magit-status
+
+ From an Ido prompt used to open a file, instead drop into
+ ‘magit-status’. This is similar to ‘ido-magic-delete-char’, which,
+ despite its name, usually causes a Dired buffer to be created.
+
+ To make this command available, use something like:
+
+ (add-hook 'ido-setup-hook
+ (lambda ()
+ (define-key ido-completion-map
+ (kbd \"C-x g\") 'ido-enter-magit-status)))
+
+ Starting with Emacs 25.1 the Ido keymaps are defined just once
+ instead of every time Ido is invoked, so now you can modify it like
+ pretty much every other keymap:
+
+ (define-key ido-common-completion-map
+ (kbd \"C-x g\") 'ido-enter-magit-status)
+
+* Menu:
+
+* Status Sections::
+* Status Header Sections::
+* Status Module Sections::
+* Status Options::
+
+\1f
+File: magit.info, Node: Status Sections, Next: Status Header Sections, Up: Status Buffer
+
+5.1.1 Status Sections
+---------------------
+
+The contents of status buffers is controlled using the hook
+‘magit-status-sections-hook’. See *note Section Hooks:: to learn about
+such hooks and how to customize them.
+
+ -- User Option: magit-status-sections-hook
+
+ Hook run to insert sections into a status buffer.
+
+ The first function on that hook by default is
+‘magit-insert-status-headers’; it is described in the next section. By
+default the following functions are also members of that hook:
+
+ -- Function: magit-insert-merge-log
+
+ Insert section for the on-going merge. Display the heads that are
+ being merged. If no merge is in progress, do nothing.
+
+ -- Function: magit-insert-rebase-sequence
+
+ Insert section for the on-going rebase sequence. If no such
+ sequence is in progress, do nothing.
+
+ -- Function: magit-insert-am-sequence
+
+ Insert section for the on-going patch applying sequence. If no
+ such sequence is in progress, do nothing.
+
+ -- Function: magit-insert-sequencer-sequence
+
+ Insert section for the on-going cherry-pick or revert sequence. If
+ no such sequence is in progress, do nothing.
+
+ -- Function: magit-insert-bisect-output
+
+ While bisecting, insert section with output from ‘git bisect’.
+
+ -- Function: magit-insert-bisect-rest
+
+ While bisecting, insert section visualizing the bisect state.
+
+ -- Function: magit-insert-bisect-log
+
+ While bisecting, insert section logging bisect progress.
+
+ -- Function: magit-insert-untracked-files
+
+ Maybe insert a list or tree of untracked files.
+
+ Do so depending on the value of ‘status.showUntrackedFiles’. Note
+ that even if the value is ‘all’, Magit still initially only shows
+ directories. But the directory sections can then be expanded using
+ ‘TAB’.
+
+ -- Function: magit-insert-unstaged-changes
+
+ Insert section showing unstaged changes.
+
+ -- Function: magit-insert-staged-changes
+
+ Insert section showing staged changes.
+
+ -- Function: magit-insert-stashes &optional ref heading
+
+ Insert the ‘stashes’ section showing reflog for "refs/stash". If
+ optional REF is non-nil show reflog for that instead. If optional
+ HEADING is non-nil use that as section heading instead of
+ "Stashes:".
+
+ -- Function: magit-insert-unpulled-from-upstream
+
+ Insert section showing commits that haven’t been pulled from the
+ upstream branch yet.
+
+ -- Function: magit-insert-unpulled-from-pushremote
+
+ Insert section showing commits that haven’t been pulled from the
+ push-remote branch yet.
+
+ -- Function: magit-insert-unpushed-to-upstream
+
+ Insert section showing commits that haven’t been pushed to the
+ upstream yet.
+
+ -- Function: magit-insert-unpushed-to-pushremote
+
+ Insert section showing commits that haven’t been pushed to the
+ push-remote yet.
+
+ The following functions can also be added to the above hook:
+
+ -- Function: magit-insert-tracked-files
+
+ Insert a tree of tracked files.
+
+ -- Function: magit-insert-ignored-files
+
+ Insert a tree of ignored files. Its possible to limit the logs in
+ the current buffer to a certain directory using ‘D = f <DIRECTORY>
+ RET g’. If you do that, then that that also affects this command.
+
+ The log filter can be used to limit to multiple files. In that
+ case this function only respects the first of the files and only if
+ it is a directory.
+
+ -- Function: magit-insert-skip-worktree-files
+
+ Insert a tree of skip-worktree files. If the first element of
+ ‘magit-buffer-diff-files’ is a directory, then limit the list to
+ files below that. The value of that variable can be set using ‘D
+ -- DIRECTORY RET g’.
+
+ -- Function: magit-insert-assumed-unchanged-files
+
+ Insert a tree of files that are assumed to be unchanged. If the
+ first element of ‘magit-buffer-diff-files’ is a directory, then
+ limit the list to files below that. The value of that variable can
+ be set using ‘D -- DIRECTORY RET g’.
+
+ -- Function: magit-insert-unpulled-or-recent-commits
+
+ Insert section showing unpulled or recent commits. If an upstream
+ is configured for the current branch and it is ahead of the current
+ branch, then show the missing commits. Otherwise, show the last
+ ‘magit-log-section-commit-count’ commits.
+
+ -- Function: magit-insert-recent-commits
+
+ Insert section showing the last ‘magit-log-section-commit-count’
+ commits.
+
+ -- User Option: magit-log-section-commit-count
+
+ How many recent commits ‘magit-insert-recent-commits’ and
+ ‘magit-insert-unpulled-or-recent-commits’ (provided there are no
+ unpulled commits) show.
+
+ -- Function: magit-insert-unpulled-cherries
+
+ Insert section showing unpulled commits. Like
+ ‘magit-insert-unpulled-commits’ but prefix each commit that has not
+ been applied yet (i.e. a commit with a patch-id not shared with
+ any local commit) with "+", and all others with "-".
+
+ -- Function: magit-insert-unpushed-cherries
+
+ Insert section showing unpushed commits. Like
+ ‘magit-insert-unpushed-commits’ but prefix each commit which has
+ not been applied to upstream yet (i.e. a commit with a patch-id
+ not shared with any upstream commit) with "+" and all others with
+ "-".
+
+ See *note References Buffer:: for some more section inserters, which
+could be used here.
+
+\1f
+File: magit.info, Node: Status Header Sections, Next: Status Module Sections, Prev: Status Sections, Up: Status Buffer
+
+5.1.2 Status Header Sections
+----------------------------
+
+The contents of status buffers is controlled using the hook
+‘magit-status-sections-hook’ (see *note Status Sections::).
+
+ By default ‘magit-insert-status-headers’ is the first member of that
+hook variable.
+
+ -- Function: magit-insert-status-headers
+
+ Insert headers sections appropriate for ‘magit-status-mode’
+ buffers. The sections are inserted by running the functions on the
+ hook ‘magit-status-headers-hook’.
+
+ -- User Option: magit-status-headers-hook
+
+ Hook run to insert headers sections into the status buffer.
+
+ This hook is run by ‘magit-insert-status-headers’, which in turn
+ has to be a member of ‘magit-status-sections-hook’ to be used at
+ all.
+
+ By default the following functions are members of the above hook:
+
+ -- Function: magit-insert-error-header
+
+ Insert a header line showing the message about the Git error that
+ just occurred.
+
+ This function is only aware of the last error that occur when Git
+ was run for side-effects. If, for example, an error occurs while
+ generating a diff, then that error won’t be inserted. Refreshing
+ the status buffer causes this section to disappear again.
+
+ -- Function: magit-insert-diff-filter-header
+
+ Insert a header line showing the effective diff filters.
+
+ -- Function: magit-insert-head-branch-header
+
+ Insert a header line about the current branch or detached ‘HEAD’.
+
+ -- Function: magit-insert-upstream-branch-header
+
+ Insert a header line about the branch that is usually pulled into
+ the current branch.
+
+ -- Function: magit-insert-push-branch-header
+
+ Insert a header line about the branch that the current branch is
+ usually pushed to.
+
+ -- Function: magit-insert-tags-header
+
+ Insert a header line about the current and/or next tag, along with
+ the number of commits between the tag and ‘HEAD’.
+
+ The following functions can also be added to the above hook:
+
+ -- Function: magit-insert-repo-header
+
+ Insert a header line showing the path to the repository top-level.
+
+ -- Function: magit-insert-remote-header
+
+ Insert a header line about the remote of the current branch.
+
+ If no remote is configured for the current branch, then fall back
+ showing the "origin" remote, or if that does not exist the first
+ remote in alphabetic order.
+
+ -- Function: magit-insert-user-header
+
+ Insert a header line about the current user.
+
+\1f
+File: magit.info, Node: Status Module Sections, Next: Status Options, Prev: Status Header Sections, Up: Status Buffer
+
+5.1.3 Status Module Sections
+----------------------------
+
+The contents of status buffers is controlled using the hook
+‘magit-status-sections-hook’ (see *note Status Sections::).
+
+ By default ‘magit-insert-modules’ is _not_ a member of that hook
+variable.
+
+ -- Function: magit-insert-modules
+
+ Insert submodule sections.
+
+ Hook ‘magit-module-sections-hook’ controls which module sections
+ are inserted, and option ‘magit-module-sections-nested’ controls
+ whether they are wrapped in an additional section.
+
+ -- User Option: magit-module-sections-hook
+
+ Hook run by ‘magit-insert-modules’.
+
+ -- User Option: magit-module-sections-nested
+
+ This option controls whether ‘magit-insert-modules’ wraps inserted
+ sections in an additional section.
+
+ If this is non-nil, then only a single top-level section is
+ inserted. If it is nil, then all sections listed in
+ ‘magit-module-sections-hook’ become top-level sections.
+
+ -- Function: magit-insert-modules-overview
+
+ Insert sections for all submodules. For each section insert the
+ path, the branch, and the output of ‘git describe --tags’, or,
+ failing that, the abbreviated HEAD commit hash.
+
+ Press ‘RET’ on such a submodule section to show its own status
+ buffer. Press ‘RET’ on the "Modules" section to display a list of
+ submodules in a separate buffer. This shows additional information
+ not displayed in the super-repository’s status buffer.
+
+ -- Function: magit-insert-modules-unpulled-from-upstream
+
+ Insert sections for modules that haven’t been pulled from the
+ upstream yet. These sections can be expanded to show the
+ respective commits.
+
+ -- Function: magit-insert-modules-unpulled-from-pushremote
+
+ Insert sections for modules that haven’t been pulled from the
+ push-remote yet. These sections can be expanded to show the
+ respective commits.
+
+ -- Function: magit-insert-modules-unpushed-to-upstream
+
+ Insert sections for modules that haven’t been pushed to the
+ upstream yet. These sections can be expanded to show the
+ respective commits.
+
+ -- Function: magit-insert-modules-unpushed-to-pushremote
+
+ Insert sections for modules that haven’t been pushed to the
+ push-remote yet. These sections can be expanded to show the
+ respective commits.
+
+\1f
+File: magit.info, Node: Status Options, Prev: Status Module Sections, Up: Status Buffer
+
+5.1.4 Status Options
+--------------------
+
+ -- User Option: magit-status-refresh-hook
+
+ Hook run after a status buffer has been refreshed.
+
+ -- User Option: magit-status-margin
+
+ This option specifies whether the margin is initially shown in
+ Magit-Status mode buffers and how it is formatted.
+
+ The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’.
+
+ • If INIT is non-nil, then the margin is shown initially.
+
+ • STYLE controls how to format the author or committer date. It
+ can be one of ‘age’ (to show the age of the commit),
+ ‘age-abbreviated’ (to abbreviate the time unit to a
+ character), or a string (suitable for ‘format-time-string’) to
+ show the actual date. Option
+ ‘magit-log-margin-show-committer-date’ controls which date is
+ being displayed.
+
+ • WIDTH controls the width of the margin. This exists for
+ forward compatibility and currently the value should not be
+ changed.
+
+ • AUTHOR controls whether the name of the author is also shown
+ by default.
+
+ • AUTHOR-WIDTH has to be an integer. When the name of the
+ author is shown, then this specifies how much space is used to
+ do so.
+
+ Also see the proceeding section for more options concerning status
+buffers.
+
+\1f
+File: magit.info, Node: Repository List, Next: Logging, Prev: Status Buffer, Up: Inspecting
+
+5.2 Repository List
+===================
+
+ -- Command: magit-list-repositories
+
+ This command displays a list of repositories in a separate buffer.
+
+ The options ‘magit-repository-directories’ and
+ ‘magit-repository-directories-depth’ control which repositories are
+ displayed.
+
+ -- User Option: magit-repolist-columns
+
+ This option controls what columns are displayed by the command
+ ‘magit-list-repositories’ and how they are displayed.
+
+ Each element has the form ‘(HEADER WIDTH FORMAT PROPS)’.
+
+ HEADER is the string displayed in the header. WIDTH is the width
+ of the column. FORMAT is a function that is called with one
+ argument, the repository identification (usually its basename), and
+ with ‘default-directory’ bound to the toplevel of its working tree.
+ It has to return a string to be inserted or nil. PROPS is an alist
+ that supports the keys ‘:right-align’ and ‘:pad-right’.
+
+ The following functions can be added to the above option:
+
+ -- Function: magit-repolist-column-ident
+
+ This function inserts the identification of the repository.
+ Usually this is just its basename.
+
+ -- Function: magit-repolist-column-path
+
+ This function inserts the absolute path of the repository.
+
+ -- Function: magit-repolist-column-version
+
+ This function inserts a description of the repository’s ‘HEAD’
+ revision.
+
+ -- Function: magit-repolist-column-branch
+
+ This function inserts the name of the current branch.
+
+ -- Function: magit-repolist-column-upstream
+
+ This function inserts the name of the upstream branch of the
+ current branch.
+
+ -- Function: magit-repolist-column-branches
+
+ This function inserts the number of branches.
+
+ -- Function: magit-repolist-column-stashes
+
+ This function inserts the number of stashes.
+
+ -- Function: magit-repolist-column-flag
+
+ This function inserts a flag as specified by
+ ‘magit-repolist-column-flag-alist’.
+
+ By default this indicates whether there are uncommitted changes.
+
+ • ‘N’ if there is at least one untracked file.
+
+ • ‘U’ if there is at least one unstaged file.
+
+ • ‘S’ if there is at least one staged file.
+
+ Only the first one of these that applies is shown.
+
+ -- Function: magit-repolist-column-unpulled-from-upstream
+
+ This function inserts the number of upstream commits not in the
+ current branch.
+
+ -- Function: magit-repolist-column-unpulled-from-pushremote
+
+ This function inserts the number of commits in the push branch but
+ not the current branch.
+
+ -- Function: magit-repolist-column-unpushed-to-upstream
+
+ This function inserts the number of commits in the current branch
+ but not its upstream.
+
+ -- Function: magit-repolist-column-unpushed-to-pushremote
+
+ This function inserts the number of commits in the current branch
+ but not its push branch.
+
+\1f
+File: magit.info, Node: Logging, Next: Diffing, Prev: Repository List, Up: Inspecting
+
+5.3 Logging
+===========
+
+The status buffer contains logs for the unpushed and unpulled commits,
+but that obviously isn’t enough. The transient prefix command
+‘magit-log’, on ‘l’, features several suffix commands, which show a
+specific log in a separate log buffer.
+
+ Like other transient prefix commands, ‘magit-log’ also features
+several infix arguments that can be changed before invoking one of the
+suffix commands. However, in the case of the log transient, these
+arguments may be taken from those currently in use in the current
+repository’s log buffer, depending on the value of
+‘magit-prefix-use-buffer-arguments’ (see *note Transient Arguments and
+Buffer Variables::).
+
+ For information about the various arguments, see *note
+(gitman)git-log::.
+
+ The switch ‘++order=VALUE’ is converted to one of
+‘--author-date-order’, ‘--date-order’, or ‘--topo-order’ before being
+passed to ‘git log’.
+
+ The log transient also features several reflog commands. See *note
+Reflog::.
+
+‘l’ (‘magit-log’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+‘l l’ (‘magit-log-current’)
+
+ Show log for the current branch. When ‘HEAD’ is detached or with a
+ prefix argument, show log for one or more revs read from the
+ minibuffer.
+
+‘l o’ (‘magit-log-other’)
+
+ Show log for one or more revs read from the minibuffer. The user
+ can input any revision or revisions separated by a space, or even
+ ranges, but only branches, tags, and a representation of the commit
+ at point are available as completion candidates.
+
+‘l h’ (‘magit-log-head’)
+
+ Show log for ‘HEAD’.
+
+‘l L’ (‘magit-log-branches’)
+
+ Show log for all local branches and ‘HEAD’.
+
+‘l b’ (‘magit-log-all-branches’)
+
+ Show log for all local and remote branches and ‘HEAD’.
+
+‘l a’ (‘magit-log-all’)
+
+ Show log for all references and ‘HEAD’.
+
+ Two additional commands that show the log for the file or blob that
+is being visited in the current buffer exists, see *note Commands for
+Buffers Visiting Files::. The command ‘magit-cherry’ also shows a log,
+see *note Cherries::.
+
+* Menu:
+
+* Refreshing Logs::
+* Log Buffer::
+* Log Margin::
+* Select from Log::
+* Reflog::
+* Cherries::
+
+\1f
+File: magit.info, Node: Refreshing Logs, Next: Log Buffer, Up: Logging
+
+5.3.1 Refreshing Logs
+---------------------
+
+The transient prefix command ‘magit-log-refresh’, on ‘L’, can be used to
+change the log arguments used in the current buffer, without changing
+which log is shown. This works in dedicated log buffers, but also in
+the status buffer.
+
+‘L’ (‘magit-log-refresh’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+‘L g’ (‘magit-log-refresh’)
+
+ This suffix command sets the local log arguments for the current
+ buffer.
+
+‘L s’ (‘magit-log-set-default-arguments’)
+
+ This suffix command sets the default log arguments for buffers of
+ the same type as that of the current buffer. Other existing
+ buffers of the same type are not affected because their local
+ values have already been initialized.
+
+‘L w’ (‘magit-log-save-default-arguments’)
+
+ This suffix command sets the default log arguments for buffers of
+ the same type as that of the current buffer, and saves the value
+ for future sessions. Other existing buffers of the same type are
+ not affected because their local values have already been
+ initialized.
+
+‘L t’ (‘magit-toggle-margin’)
+
+ Show or hide the margin.
+
+\1f
+File: magit.info, Node: Log Buffer, Next: Log Margin, Prev: Refreshing Logs, Up: Logging
+
+5.3.2 Log Buffer
+----------------
+
+‘L’ (‘magit-log-refresh’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+ See *note Refreshing Logs::.
+
+‘q’ (‘magit-log-bury-buffer’)
+
+ Bury the current buffer or the revision buffer in the same frame.
+ Like ‘magit-mode-bury-buffer’ (which see) but with a negative
+ prefix argument instead bury the revision buffer, provided it is
+ displayed in the current frame.
+
+‘C-c C-b’ (‘magit-go-backward’)
+
+ Move backward in current buffer’s history.
+
+‘C-c C-f’ (‘magit-go-forward’)
+
+ Move forward in current buffer’s history.
+
+‘C-c C-n’ (‘magit-log-move-to-parent’)
+
+ Move to a parent of the current commit. By default, this is the
+ first parent, but a numeric prefix can be used to specify another
+ parent.
+
+‘SPC’ (‘magit-diff-show-or-scroll-up’)
+
+ Update the commit or diff buffer for the thing at point.
+
+ Either show the commit or stash at point in the appropriate buffer,
+ or if that buffer is already being displayed in the current frame
+ and contains information about that commit or stash, then instead
+ scroll the buffer up. If there is no commit or stash at point,
+ then prompt for a commit.
+
+‘DEL’ (‘magit-diff-show-or-scroll-down’)
+
+ Update the commit or diff buffer for the thing at point.
+
+ Either show the commit or stash at point in the appropriate buffer,
+ or if that buffer is already being displayed in the current frame
+ and contains information about that commit or stash, then instead
+ scroll the buffer down. If there is no commit or stash at point,
+ then prompt for a commit.
+
+‘=’ (‘magit-log-toggle-commit-limit’)
+
+ Toggle the number of commits the current log buffer is limited to.
+ If the number of commits is currently limited, then remove that
+ limit. Otherwise set it to 256.
+
+‘+’ (‘magit-log-double-commit-limit’)
+
+ Double the number of commits the current log buffer is limited to.
+
+‘-’ (‘magit-log-half-commit-limit’)
+
+ Half the number of commits the current log buffer is limited to.
+
+ -- User Option: magit-log-auto-more
+
+ Insert more log entries automatically when moving past the last
+ entry. Only considered when moving past the last entry with
+ ‘magit-goto-*-section’ commands.
+
+ -- User Option: magit-log-show-refname-after-summary
+
+ Whether to show the refnames after the commit summaries. This is
+ useful if you use really long branch names.
+
+ Magit displays references in logs a bit differently from how Git does
+it.
+
+ Local branches are blue and remote branches are green. Of course
+that depends on the used theme, as do the colors used for other types of
+references. The current branch has a box around it, as do remote
+branches that are their respective remote’s ‘HEAD’ branch.
+
+ If a local branch and its push-target point at the same commit, then
+their names are combined to preserve space and to make that relationship
+visible. For example:
+
+ origin/feature
+ [green][blue-]
+
+ instead of
+
+ feature origin/feature
+ [blue-] [green-------]
+
+ Also note that while the transient features the ‘--show-signature’
+argument, that won’t actually be used when enabled, because Magit
+defaults to use just one line per commit. Instead the commit colorized
+to indicate the validity of the signed commit object, using the faces
+named ‘magit-signature-*’ (which see).
+
+ For a description of ‘magit-log-margin’ see *note Log Margin::.
+
+\1f
+File: magit.info, Node: Log Margin, Next: Select from Log, Prev: Log Buffer, Up: Logging
+
+5.3.3 Log Margin
+----------------
+
+In buffers which show one or more logs, it is possible to show
+additional information about each commit in the margin. The options
+used to configure the margin are named ‘magit-INFIX-margin’, where INFIX
+is the same as in the respective major-mode ‘magit-INFIX-mode’. In
+regular log buffers that would be ‘magit-log-margin’.
+
+ -- User Option: magit-log-margin
+
+ This option specifies whether the margin is initially shown in
+ Magit-Log mode buffers and how it is formatted.
+
+ The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’.
+
+ • If INIT is non-nil, then the margin is shown initially.
+
+ • STYLE controls how to format the author or committer date. It
+ can be one of ‘age’ (to show the age of the commit),
+ ‘age-abbreviated’ (to abbreviate the time unit to a
+ character), or a string (suitable for ‘format-time-string’) to
+ show the actual date. Option
+ ‘magit-log-margin-show-committer-date’ controls which date is
+ being displayed.
+
+ • WIDTH controls the width of the margin. This exists for
+ forward compatibility and currently the value should not be
+ changed.
+
+ • AUTHOR controls whether the name of the author is also shown
+ by default.
+
+ • AUTHOR-WIDTH has to be an integer. When the name of the
+ author is shown, then this specifies how much space is used to
+ do so.
+
+ You can change the STYLE and AUTHOR-WIDTH of all ‘magit-INFIX-margin’
+options to the same values by customizing ‘magit-log-margin’ *before*
+‘magit’ is loaded. If you do that, then the respective values for the
+other options will default to what you have set for that variable.
+Likewise if you set INIT in ‘magit-log-margin’ to ‘nil’, then that is
+used in the default of all other options. But setting it to ‘t’, i.e.
+re-enforcing the default for that option, does not carry to other
+options.
+
+ -- User Option: magit-log-margin-show-committer-date
+
+ This option specifies whether to show the committer date in the
+ margin. This option only controls whether the committer date is
+ displayed instead of the author date. Whether some date is
+ displayed in the margin and whether the margin is displayed at all
+ is controlled by other options.
+
+‘L’ (‘magit-margin-settings’)
+
+ This transient prefix command binds the following suffix commands,
+ each of which changes the appearance of the margin in some way.
+
+ In some buffers that support the margin, ‘L’ is instead bound to
+‘magit-log-refresh’, but that transient features the same commands, and
+then some other unrelated commands.
+
+‘L L’ (‘magit-toggle-margin’)
+
+ This command shows or hides the margin.
+
+‘L l’ (‘magit-cycle-margin-style’)
+
+ This command cycles the style used for the margin.
+
+‘L d’ (‘magit-toggle-margin-details’)
+
+ This command shows or hides details in the margin.
+
+\1f
+File: magit.info, Node: Select from Log, Next: Reflog, Prev: Log Margin, Up: Logging
+
+5.3.4 Select from Log
+---------------------
+
+When the user has to select a recent commit that is reachable from
+‘HEAD’, using regular completion would be inconvenient (because most
+humans cannot remember hashes or "HEAD~5", at least not without double
+checking). Instead a log buffer is used to select the commit, which has
+the advantage that commits are presented in order and with the commit
+message.
+
+ Such selection logs are used when selecting the beginning of a rebase
+and when selecting the commit to be squashed into.
+
+ In addition to the key bindings available in all log buffers, the
+following additional key bindings are available in selection log
+buffers:
+
+‘C-c C-c’ (‘magit-log-select-pick’)
+
+ Select the commit at point and act on it. Call
+ ‘magit-log-select-pick-function’ with the selected commit as
+ argument.
+
+‘C-c C-k’ (‘magit-log-select-quit’)
+
+ Abort selecting a commit, don’t act on any commit.
+
+ -- User Option: magit-log-select-margin
+
+ This option specifies whether the margin is initially shown in
+ Magit-Log-Select mode buffers and how it is formatted.
+
+ The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’.
+
+ • If INIT is non-nil, then the margin is shown initially.
+
+ • STYLE controls how to format the author or committer date. It
+ can be one of ‘age’ (to show the age of the commit),
+ ‘age-abbreviated’ (to abbreviate the time unit to a
+ character), or a string (suitable for ‘format-time-string’) to
+ show the actual date. Option
+ ‘magit-log-margin-show-committer-date’ controls which date is
+ being displayed.
+
+ • WIDTH controls the width of the margin. This exists for
+ forward compatibility and currently the value should not be
+ changed.
+
+ • AUTHOR controls whether the name of the author is also shown
+ by default.
+
+ • AUTHOR-WIDTH has to be an integer. When the name of the
+ author is shown, then this specifies how much space is used to
+ do so.
+
+\1f
+File: magit.info, Node: Reflog, Next: Cherries, Prev: Select from Log, Up: Logging
+
+5.3.5 Reflog
+------------
+
+Also see *note (gitman)git-reflog::.
+
+ These reflog commands are available from the log transient. See
+*note Logging::.
+
+‘l r’ (‘magit-reflog-current’)
+
+ Display the reflog of the current branch.
+
+‘l O’ (‘magit-reflog-other’)
+
+ Display the reflog of a branch or another ref.
+
+‘l H’ (‘magit-reflog-head’)
+
+ Display the ‘HEAD’ reflog.
+
+ -- User Option: magit-reflog-margin
+
+ This option specifies whether the margin is initially shown in
+ Magit-Reflog mode buffers and how it is formatted.
+
+ The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’.
+
+ • If INIT is non-nil, then the margin is shown initially.
+
+ • STYLE controls how to format the author or committer date. It
+ can be one of ‘age’ (to show the age of the commit),
+ ‘age-abbreviated’ (to abbreviate the time unit to a
+ character), or a string (suitable for ‘format-time-string’) to
+ show the actual date. Option
+ ‘magit-log-margin-show-committer-date’ controls which date is
+ being displayed.
+
+ • WIDTH controls the width of the margin. This exists for
+ forward compatibility and currently the value should not be
+ changed.
+
+ • AUTHOR controls whether the name of the author is also shown
+ by default.
+
+ • AUTHOR-WIDTH has to be an integer. When the name of the
+ author is shown, then this specifies how much space is used to
+ do so.
+
+\1f
+File: magit.info, Node: Cherries, Prev: Reflog, Up: Logging
+
+5.3.6 Cherries
+--------------
+
+Cherries are commits that haven’t been applied upstream (yet), and are
+usually visualized using a log. Each commit is prefixed with ‘-’ if it
+has an equivalent in the upstream and ‘+’ if it does not, i.e. if it is
+a cherry.
+
+ The command ‘magit-cherry’ shows cherries for a single branch, but
+the references buffer (see *note References Buffer::) can show cherries
+for multiple "upstreams" at once.
+
+ Also see *note (gitman)git-reflog::.
+
+‘Y’ (‘magit-cherry’)
+
+ Show commits that are in a certain branch but that have not been
+ merged in the upstream branch.
+
+ -- User Option: magit-cherry-margin
+
+ This option specifies whether the margin is initially shown in
+ Magit-Cherry mode buffers and how it is formatted.
+
+ The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’.
+
+ • If INIT is non-nil, then the margin is shown initially.
+
+ • STYLE controls how to format the author or committer date. It
+ can be one of ‘age’ (to show the age of the commit),
+ ‘age-abbreviated’ (to abbreviate the time unit to a
+ character), or a string (suitable for ‘format-time-string’) to
+ show the actual date. Option
+ ‘magit-log-margin-show-committer-date’ controls which date is
+ being displayed.
+
+ • WIDTH controls the width of the margin. This exists for
+ forward compatibility and currently the value should not be
+ changed.
+
+ • AUTHOR controls whether the name of the author is also shown
+ by default.
+
+ • AUTHOR-WIDTH has to be an integer. When the name of the
+ author is shown, then this specifies how much space is used to
+ do so.
+
+\1f
+File: magit.info, Node: Diffing, Next: Ediffing, Prev: Logging, Up: Inspecting
+
+5.4 Diffing
+===========
+
+The status buffer contains diffs for the staged and unstaged commits,
+but that obviously isn’t enough. The transient prefix command
+‘magit-diff’, on ‘d’, features several suffix commands, which show a
+specific diff in a separate diff buffer.
+
+ Like other transient prefix commands, ‘magit-diff’ also features
+several infix arguments that can be changed before invoking one of the
+suffix commands. However, in the case of the diff transient, these
+arguments may be taken from those currently in use in the current
+repository’s diff buffer, depending on the value of
+‘magit-prefix-use-buffer-arguments’ (see *note Transient Arguments and
+Buffer Variables::).
+
+ Also see *note (gitman)git-diff::.
+
+‘d’ (‘magit-diff’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+‘d d’ (‘magit-diff-dwim’)
+
+ Show changes for the thing at point.
+
+‘d r’ (‘magit-diff-range’)
+
+ Show differences between two commits.
+
+ RANGE should be a range (A..B or A...B) but can also be a single
+ commit. If one side of the range is omitted, then it defaults to
+ ‘HEAD’. If just a commit is given, then changes in the working
+ tree relative to that commit are shown.
+
+ If the region is active, use the revisions on the first and last
+ line of the region. With a prefix argument, instead of diffing the
+ revisions, choose a revision to view changes along, starting at the
+ common ancestor of both revisions (i.e., use a "..." range).
+
+‘d w’ (‘magit-diff-working-tree’)
+
+ Show changes between the current working tree and the ‘HEAD’
+ commit. With a prefix argument show changes between the working
+ tree and a commit read from the minibuffer.
+
+‘d s’ (‘magit-diff-staged’)
+
+ Show changes between the index and the ‘HEAD’ commit. With a
+ prefix argument show changes between the index and a commit read
+ from the minibuffer.
+
+‘d u’ (‘magit-diff-unstaged’)
+
+ Show changes between the working tree and the index.
+
+‘d p’ (‘magit-diff-paths’)
+
+ Show changes between any two files on disk.
+
+ All of the above suffix commands update the repository’s diff buffer.
+The diff transient also features two commands which show differences in
+another buffer:
+
+‘d c’ (‘magit-show-commit’)
+
+ Show the commit at point. If there is no commit at point or with a
+ prefix argument, prompt for a commit.
+
+‘d t’ (‘magit-stash-show’)
+
+ Show all diffs of a stash in a buffer.
+
+ Two additional commands that show the diff for the file or blob that
+is being visited in the current buffer exists, see *note Commands for
+Buffers Visiting Files::.
+
+* Menu:
+
+* Refreshing Diffs::
+* Commands Available in Diffs::
+* Diff Options::
+* Revision Buffer::
+
+\1f
+File: magit.info, Node: Refreshing Diffs, Next: Commands Available in Diffs, Up: Diffing
+
+5.4.1 Refreshing Diffs
+----------------------
+
+The transient prefix command ‘magit-diff-refresh’, on ‘D’, can be used
+to change the diff arguments used in the current buffer, without
+changing which diff is shown. This works in dedicated diff buffers, but
+also in the status buffer.
+
+‘D’ (‘magit-diff-refresh’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+‘D g’ (‘magit-diff-refresh’)
+
+ This suffix command sets the local diff arguments for the current
+ buffer.
+
+‘D s’ (‘magit-diff-set-default-arguments’)
+
+ This suffix command sets the default diff arguments for buffers of
+ the same type as that of the current buffer. Other existing
+ buffers of the same type are not affected because their local
+ values have already been initialized.
+
+‘D w’ (‘magit-diff-save-default-arguments’)
+
+ This suffix command sets the default diff arguments for buffers of
+ the same type as that of the current buffer, and saves the value
+ for future sessions. Other existing buffers of the same type are
+ not affected because their local values have already been
+ initialized.
+
+‘D t’ (‘magit-diff-toggle-refine-hunk’)
+
+ This command toggles hunk refinement on or off.
+
+‘D r’ (‘magit-diff-switch-range-type’)
+
+ This command converts the diff range type from "revA..revB" to
+ "revB...revA", or vice versa.
+
+‘D f’ (‘magit-diff-flip-revs’)
+
+ This command swaps revisions in the diff range from "revA..revB" to
+ "revB..revA", or vice versa.
+
+‘D F’ (‘magit-diff-toggle-file-filter’)
+
+ This command toggles the file restriction of the diffs in the
+ current buffer, allowing you to quickly switch between viewing all
+ the changes in the commit and the restricted subset. As a special
+ case, when this command is called from a log buffer, it toggles the
+ file restriction in the repository’s revision buffer, which is
+ useful when you display a revision from a log buffer that is
+ restricted to a file or files.
+
+ In addition to the above transient, which allows changing any of the
+supported arguments, there also exist some commands that change only a
+particular argument.
+
+‘-’ (‘magit-diff-less-context’)
+
+ This command decreases the context for diff hunks by COUNT lines.
+
+‘+’ (‘magit-diff-more-context’)
+
+ This command increases the context for diff hunks by COUNT lines.
+
+‘0’ (‘magit-diff-default-context’)
+
+ This command resets the context for diff hunks to the default
+ height.
+
+ The following commands quickly change what diff is being displayed
+without having to using one of the diff transient.
+
+‘C-c C-d’ (‘magit-diff-while-committing’)
+
+ While committing, this command shows the changes that are about to
+ be committed. While amending, invoking the command again toggles
+ between showing just the new changes or all the changes that will
+ be committed.
+
+ This binding is available in the diff buffer as well as the commit
+ message buffer.
+
+‘C-c C-b’ (‘magit-go-backward’)
+
+ This command moves backward in current buffer’s history.
+
+‘C-c C-f’ (‘magit-go-forward’)
+
+ This command moves forward in current buffer’s history.
+
+\1f
+File: magit.info, Node: Commands Available in Diffs, Next: Diff Options, Prev: Refreshing Diffs, Up: Diffing
+
+5.4.2 Commands Available in Diffs
+---------------------------------
+
+Some commands are only available if point is inside a diff.
+
+ ‘magit-diff-visit-file’ and related commands visit the appropriate
+version of the file that the diff at point is about. Likewise
+‘magit-diff-visit-worktree-file’ and related commands visit the worktree
+version of the file that the diff at point is about. See *note Visiting
+Files and Blobs from a Diff:: for more information and the key bindings.
+
+‘C-c C-t’ (‘magit-diff-trace-definition’)
+
+ This command shows a log for the definition at point.
+
+ -- User Option: magit-log-trace-definition-function
+
+ The function specified by this option is used by
+ ‘magit-log-trace-definition’ to determine the function at point.
+ For major-modes that have special needs, you could set the local
+ value using the mode’s hook.
+
+‘C-c C-e’ (‘magit-diff-edit-hunk-commit’)
+
+ From a hunk, this command edits the respective commit and visits
+ the file.
+
+ First it visits the file being modified by the hunk at the correct
+ location using ‘magit-diff-visit-file’. This actually visits a
+ blob. When point is on a diff header, not within an individual
+ hunk, then this visits the blob the first hunk is about.
+
+ Then it invokes ‘magit-edit-line-commit’, which uses an interactive
+ rebase to make the commit editable, or if that is not possible
+ because the commit is not reachable from ‘HEAD’ by checking out
+ that commit directly. This also causes the actual worktree file to
+ be visited.
+
+ Neither the blob nor the file buffer are killed when finishing the
+ rebase. If that is undesirable, then it might be better to use
+ ‘magit-rebase-edit-command’ instead of this command.
+
+‘j’ (‘magit-jump-to-diffstat-or-diff’)
+
+ This command jumps to the diffstat or diff. When point is on a
+ file inside the diffstat section, then jump to the respective diff
+ section. Otherwise, jump to the diffstat section or a child
+ thereof.
+
+ The next two commands are not specific to Magit-Diff mode (or and
+Magit buffer for that matter), but it might be worth pointing out that
+they are available here too.
+
+‘SPC’ (‘scroll-up’)
+
+ This command scrolls text upward.
+
+‘DEL’ (‘scroll-down’)
+
+ This command scrolls text downward.
+
+\1f
+File: magit.info, Node: Diff Options, Next: Revision Buffer, Prev: Commands Available in Diffs, Up: Diffing
+
+5.4.3 Diff Options
+------------------
+
+ -- User Option: magit-diff-refine-hunk
+
+ Whether to show word-granularity differences within diff hunks.
+
+ • ‘nil’ Never show fine differences.
+
+ • ‘t’ Show fine differences for the current diff hunk only.
+
+ • ‘all’ Show fine differences for all displayed diff hunks.
+
+ -- User Option: magit-diff-refine-ignore-whitespace
+
+ Whether to ignore whitespace changes in word-granularity
+ differences.
+
+ -- User Option: magit-diff-adjust-tab-width
+
+ Whether to adjust the width of tabs in diffs.
+
+ Determining the correct width can be expensive if it requires
+ opening large and/or many files, so the widths are cached in the
+ variable ‘magit-diff--tab-width-cache’. Set that to nil to
+ invalidate the cache.
+
+ • ‘nil’ Never adjust tab width. Use ‘tab-width’s value from the
+ Magit buffer itself instead.
+
+ • ‘t’ If the corresponding file-visiting buffer exits, then use
+ ‘tab-width’’s value from that buffer. Doing this is cheap, so
+ this value is used even if a corresponding cache entry exists.
+
+ • ‘always’ If there is no such buffer, then temporarily visit
+ the file to determine the value.
+
+ • NUMBER Like ‘always’, but don’t visit files larger than NUMBER
+ bytes.
+
+ -- User Option: magit-diff-paint-whitespace
+
+ Specify where to highlight whitespace errors.
+
+ See ‘magit-diff-highlight-trailing’,
+ ‘magit-diff-highlight-indentation’. The symbol ‘t’ means in all
+ diffs, ‘status’ means only in the status buffer, and nil means
+ nowhere.
+
+ • ‘nil’ Never highlight whitespace errors.
+
+ • ‘t’ Highlight whitespace errors everywhere.
+
+ • ‘uncommitted’ Only highlight whitespace errors in diffs
+ showing uncommitted changes. For backward compatibility
+ ‘status’ is treated as a synonym.
+
+ -- User Option: magit-diff-paint-whitespace-lines
+
+ Specify in what kind of lines to highlight whitespace errors.
+
+ • ‘t’ Highlight only in added lines.
+
+ • ‘both’ Highlight in added and removed lines.
+
+ • ‘all’ Highlight in added, removed and context lines.
+
+ -- User Option: magit-diff-highlight-trailing
+
+ Whether to highlight whitespace at the end of a line in diffs.
+ Used only when ‘magit-diff-paint-whitespace’ is non-nil.
+
+ -- User Option: magit-diff-highlight-indentation
+
+ This option controls whether to highlight the indentation in case
+ it used the "wrong" indentation style. Indentation is only
+ highlighted if ‘magit-diff-paint-whitespace’ is also non-nil.
+
+ The value is an alist of the form ‘((REGEXP . INDENT)...)’. The
+ path to the current repository is matched against each element in
+ reverse order. Therefore if a REGEXP matches, then earlier
+ elements are not tried.
+
+ If the used INDENT is ‘tabs’, highlight indentation with tabs. If
+ INDENT is an integer, highlight indentation with at least that many
+ spaces. Otherwise, highlight neither.
+
+ -- User Option: magit-diff-hide-trailing-cr-characters
+
+ Whether to hide ^M characters at the end of a line in diffs.
+
+ -- User Option: magit-diff-highlight-hunk-region-functions
+
+ This option specifies the functions used to highlight the
+ hunk-internal region.
+
+ ‘magit-diff-highlight-hunk-region-dim-outside’ overlays the outside
+ of the hunk internal selection with a face that causes the added
+ and removed lines to have the same background color as context
+ lines. This function should not be removed from the value of this
+ option.
+
+ ‘magit-diff-highlight-hunk-region-using-overlays’ and
+ ‘magit-diff-highlight-hunk-region-using-underline’ emphasize the
+ region by placing delimiting horizontal lines before and after it.
+ Both of these functions have glitches which cannot be fixed due to
+ limitations of Emacs’ display engine. For more information see
+ <https://github.com/magit/magit/issues/2758> ff.
+
+ Instead of, or in addition to, using delimiting horizontal lines,
+ to emphasize the boundaries, you may which to emphasize the text
+ itself, using ‘magit-diff-highlight-hunk-region-using-face’.
+
+ In terminal frames it’s not possible to draw lines as the overlay
+ and underline variants normally do, so there they fall back to
+ calling the face function instead.
+
+ -- User Option: magit-diff-unmarked-lines-keep-foreground
+
+ This option controls whether added and removed lines outside the
+ hunk-internal region only lose their distinct background color or
+ also the foreground color. Whether the outside of the region is
+ dimmed at all depends on
+ ‘magit-diff-highlight-hunk-region-functions’.
+
+ -- User Option: magit-diff-extra-stat-arguments
+
+ This option specifies additional arguments to be used alongside
+ ‘--stat’.
+
+ The value is a list of zero or more arguments or a function that
+ takes no argument and returns such a list. These arguments are
+ allowed here: ‘--stat-width’, ‘--stat-name-width’,
+ ‘--stat-graph-width’ and ‘--compact-summary’. Also see *note
+ (gitman)git-diff::.
+
+\1f
+File: magit.info, Node: Revision Buffer, Prev: Diff Options, Up: Diffing
+
+5.4.4 Revision Buffer
+---------------------
+
+ -- User Option: magit-revision-insert-related-refs
+
+ Whether to show related branches in revision buffers.
+
+ • ‘nil’ Don’t show any related branches.
+
+ • ‘t’ Show related local branches.
+
+ • ‘all’ Show related local and remote branches.
+
+ • ‘mixed’ Show all containing branches and local merged
+ branches.
+
+ -- User Option: magit-revision-show-gravatars
+
+ Whether to show gravatar images in revision buffers.
+
+ If ‘nil’, then don’t insert any gravatar images. If ‘t’, then
+ insert both images. If ‘author’ or ‘committer’, then insert only
+ the respective image.
+
+ If you have customized the option ‘magit-revision-headers-format’
+ and want to insert the images then you might also have to specify
+ where to do so. In that case the value has to be a cons-cell of
+ two regular expressions. The car specifies where to insert the
+ author’s image. The top half of the image is inserted right after
+ the matched text, the bottom half on the next line in the same
+ column. The cdr specifies where to insert the committer’s image,
+ accordingly. Either the car or the cdr may be nil."
+
+ -- User Option: magit-revision-use-hash-sections
+
+ Whether to turn hashes inside the commit message into sections.
+
+ If non-nil, then hashes inside the commit message are turned into
+ ‘commit’ sections. There is a trade off to be made between
+ performance and reliability:
+
+ • ‘slow’ calls git for every word to be absolutely sure.
+
+ • ‘quick’ skips words less than seven characters long.
+
+ • ‘quicker’ additionally skips words that don’t contain a
+ number.
+
+ • ‘quickest’ uses all words that are at least seven characters
+ long and which contain at least one number as well as at least
+ one letter.
+
+ If nil, then no hashes are turned into sections, but you can still
+ visit the commit at point using "RET".
+
+ The diffs shown in the revision buffer may be automatically
+restricted to a subset of the changed files. If the revision buffer is
+displayed from a log buffer, the revision buffer will share the same
+file restriction as that log buffer (also see the command
+‘magit-diff-toggle-file-filter’).
+
+ -- User Option: magit-revision-filter-files-on-follow
+
+ Whether showing a commit from a log buffer honors the log’s file
+ filter when the log arguments include ‘--follow’.
+
+ When this option is nil, displaying a commit from a log ignores the
+ log’s file filter if the log arguments include ‘--follow’. Doing
+ so avoids showing an empty diff in revision buffers for commits
+ before a rename event. In such cases, the ‘--patch’ argument of
+ the log transient can be used to show the file-restricted diffs
+ inline.
+
+ Set this option to non-nil to keep the log’s file restriction even
+ if ‘--follow’ is present in the log arguments.
+
+ If the revision buffer is not displayed from a log buffer, the file
+restriction is determined as usual (see *note Transient Arguments and
+Buffer Variables::).
+
+\1f
+File: magit.info, Node: Ediffing, Next: References Buffer, Prev: Diffing, Up: Inspecting
+
+5.5 Ediffing
+============
+
+This section describes how to enter Ediff from Magit buffers. For
+information on how to use Ediff itself, see *note (ediff)Top::.
+
+‘e’ (‘magit-ediff-dwim’)
+
+ Compare, stage, or resolve using Ediff.
+
+ This command tries to guess what file, and what commit or range the
+ user wants to compare, stage, or resolve using Ediff. It might
+ only be able to guess either the file, or range/commit, in which
+ case the user is asked about the other. It might not always guess
+ right, in which case the appropriate ‘magit-ediff-*’ command has to
+ be used explicitly. If it cannot read the user’s mind at all, then
+ it asks the user for a command to run.
+
+‘E’ (‘magit-ediff’)
+
+ This transient prefix command binds the following suffix commands
+ and displays them in a temporary buffer until a suffix is invoked.
+
+‘E r’ (‘magit-ediff-compare’)
+
+ Compare two revisions of a file using Ediff.
+
+ If the region is active, use the revisions on the first and last
+ line of the region. With a prefix argument, instead of diffing the
+ revisions, choose a revision to view changes along, starting at the
+ common ancestor of both revisions (i.e., use a "..." range).
+
+‘E m’ (‘magit-ediff-resolve’)
+
+ Resolve outstanding conflicts in a file using Ediff, defaulting to
+ the file at point.
+
+ Provided that the value of ‘merge.conflictstyle’ is ‘diff3’, you
+ can view the file’s merge-base revision using ‘/’ in the Ediff
+ control buffer.
+
+ In the rare event that you want to manually resolve all conflicts,
+ including those already resolved by Git, use
+ ‘ediff-merge-revisions-with-ancestor’.
+
+‘E s’ (‘magit-ediff-stage’)
+
+ Stage and unstage changes to a file using Ediff, defaulting to the
+ file at point.
+
+‘E u’ (‘magit-ediff-show-unstaged’)
+
+ Show unstaged changes to a file using Ediff.
+
+‘E i’ (‘magit-ediff-show-staged’)
+
+ Show staged changes to a file using Ediff.
+
+‘E w’ (‘magit-ediff-show-working-tree’)
+
+ Show changes in a file between ‘HEAD’ and working tree using Ediff.
+
+‘E c’ (‘magit-ediff-show-commit’)
+
+ Show changes to a file introduced by a commit using Ediff.
+
+‘E z’ (‘magit-ediff-show-stash’)
+
+ Show changes to a file introduced by a stash using Ediff.
+
+ -- User Option: magit-ediff-dwim-show-on-hunks
+
+ This option controls what command ‘magit-ediff-dwim’ calls when
+ point is on uncommitted hunks. When nil, always run
+ ‘magit-ediff-stage’. Otherwise, use ‘magit-ediff-show-staged’ and
+ ‘magit-ediff-show-unstaged’ to show staged and unstaged changes,
+ respectively.
+
+ -- User Option: magit-ediff-show-stash-with-index
+
+ This option controls whether ‘magit-ediff-show-stash’ includes a
+ buffer containing the file’s state in the index at the time the
+ stash was created. This makes it possible to tell which changes in
+ the stash were staged.
+
+ -- User Option: magit-ediff-quit-hook
+
+ This hook is run after quitting an Ediff session that was created
+ using a Magit command. The hook functions are run inside the Ediff
+ control buffer, and should not change the current buffer.
+
+ This is similar to ‘ediff-quit-hook’ but takes the needs of Magit
+ into account. The regular ‘ediff-quit-hook’ is ignored by Ediff
+ sessions that were created using a Magit command.
+
+\1f
+File: magit.info, Node: References Buffer, Next: Bisecting, Prev: Ediffing, Up: Inspecting
+
+5.6 References Buffer
+=====================
+
+‘y’ (‘magit-show-refs’)
+
+ This command lists branches and tags in a dedicated buffer.
+
+ However if this command is invoked again from this buffer or if it
+ is invoked with a prefix argument, then it acts as a transient
+ prefix command, which binds the following suffix commands and some
+ infix arguments.
+
+ All of the following suffix commands list exactly the same branches
+and tags. The only difference the optional feature that can be enabled
+by changing the value of ‘magit-refs-show-commit-count’ (see below).
+These commands specify a different branch or commit against which all
+the other references are compared.
+
+‘y y’ (‘magit-show-refs-head’)
+
+ This command lists branches and tags in a dedicated buffer. Each
+ reference is being compared with ‘HEAD’.
+
+‘y c’ (‘magit-show-refs-current’)
+
+ This command lists branches and tags in a dedicated buffer. Each
+ reference is being compared with the current branch or ‘HEAD’ if it
+ is detached.
+
+‘y o’ (‘magit-show-refs-other’)
+
+ This command lists branches and tags in a dedicated buffer. Each
+ reference is being compared with a branch read from the user.
+
+ -- User Option: magit-refs-show-commit-count
+
+ Whether to show commit counts in Magit-Refs mode buffers.
+
+ • ‘all’ Show counts for branches and tags.
+
+ • ‘branch’ Show counts for branches only.
+
+ • ‘nil’ Never show counts.
+
+ The default is ‘nil’ because anything else can be very expensive.
+
+ -- User Option: magit-refs-pad-commit-counts
+
+ Whether to pad all commit counts on all sides in Magit-Refs mode
+ buffers.
+
+ If this is nil, then some commit counts are displayed right next to
+ one of the branches that appear next to the count, without any
+ space in between. This might look bad if the branch name faces
+ look too similar to ‘magit-dimmed’.
+
+ If this is non-nil, then spaces are placed on both sides of all
+ commit counts.
+
+ -- User Option: magit-refs-show-remote-prefix
+
+ Whether to show the remote prefix in lists of remote branches.
+
+ Showing the prefix is redundant because the name of the remote is
+ already shown in the heading preceding the list of its branches.
+
+ -- User Option: magit-refs-primary-column-width
+
+ Width of the primary column in ‘magit-refs-mode’ buffers. The
+ primary column is the column that contains the name of the branch
+ that the current row is about.
+
+ If this is an integer, then the column is that many columns wide.
+ Otherwise it has to be a cons-cell of two integers. The first
+ specifies the minimal width, the second the maximal width. In that
+ case the actual width is determined using the length of the names
+ of the shown local branches. (Remote branches and tags are not
+ taken into account when calculating to optimal width.)
+
+ -- User Option: magit-refs-focus-column-width
+
+ Width of the focus column in ‘magit-refs-mode’ buffers.
+
+ The focus column is the first column, which marks one branch
+ (usually the current branch) as the focused branch using ‘*’ or
+ ‘@’. For each other reference, this column optionally shows how
+ many commits it is ahead of the focused branch and ‘<’, or if it
+ isn’t ahead then the commits it is behind and ‘>’, or if it isn’t
+ behind either, then a ‘=’.
+
+ This column may also display only ‘*’ or ‘@’ for the focused
+ branch, in which case this option is ignored. Use ‘L v’ to change
+ the verbosity of this column.
+
+ -- User Option: magit-refs-margin
+
+ This option specifies whether the margin is initially shown in
+ Magit-Refs mode buffers and how it is formatted.
+
+ The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’.
+
+ • If INIT is non-nil, then the margin is shown initially.
+
+ • STYLE controls how to format the author or committer date. It
+ can be one of ‘age’ (to show the age of the commit),
+ ‘age-abbreviated’ (to abbreviate the time unit to a
+ character), or a string (suitable for ‘format-time-string’) to
+ show the actual date. Option
+ ‘magit-log-margin-show-committer-date’ controls which date is
+ being displayed.
+
+ • WIDTH controls the width of the margin. This exists for
+ forward compatibility and currently the value should not be
+ changed.
+
+ • AUTHOR controls whether the name of the author is also shown
+ by default.
+
+ • AUTHOR-WIDTH has to be an integer. When the name of the
+ author is shown, then this specifies how much space is used to
+ do so.
+
+ -- User Option: magit-refs-margin-for-tags
+
+ This option specifies whether to show information about tags in the
+ margin. This is disabled by default because it is slow if there
+ are many tags.
+
+ The following variables control how individual refs are displayed.
+If you change one of these variables (especially the "%c" part), then
+you should also change the others to keep things aligned. The following
+%-sequences are supported:
+
+ • ‘%a’ Number of commits this ref has over the one we compare to.
+
+ • ‘%b’ Number of commits the ref we compare to has over this one.
+
+ • ‘%c’ Number of commits this ref has over the one we compare to.
+ For the ref which all other refs are compared this is instead "@",
+ if it is the current branch, or "#" otherwise.
+
+ • ‘%C’ For the ref which all other refs are compared this is "@", if
+ it is the current branch, or "#" otherwise. For all other refs "
+ ".
+
+ • ‘%h’ Hash of this ref’s tip.
+
+ • ‘%m’ Commit summary of the tip of this ref.
+
+ • ‘%n’ Name of this ref.
+
+ • ‘%u’ Upstream of this local branch.
+
+ • ‘%U’ Upstream of this local branch and additional local vs.
+ upstream information.
+
+ -- User Option: magit-refs-filter-alist
+
+ The purpose of this option is to forgo displaying certain refs
+ based on their name. If you want to not display any refs of a
+ certain type, then you should remove the appropriate function from
+ ‘magit-refs-sections-hook’ instead.
+
+ This alist controls which tags and branches are omitted from being
+ displayed in ‘magit-refs-mode’ buffers. If it is ‘nil’, then all
+ refs are displayed (subject to ‘magit-refs-sections-hook’).
+
+ All keys are tried in order until one matches. Then its value is
+ used and subsequent elements are ignored. If the value is non-nil,
+ then the reference is displayed, otherwise it is not. If no
+ element matches, then the reference is displayed.
+
+ A key can either be a regular expression that the refname has to
+ match, or a function that takes the refname as only argument and
+ returns a boolean. A remote branch such as "origin/master" is
+ displayed as just "master", however for this comparison the former
+ is used.
+
+‘RET’ (‘magit-visit-ref’)
+
+ This command visits the reference or revision at point in another
+ buffer. If there is no revision at point or with a prefix argument
+ then it prompts for a revision.
+
+ This command behaves just like ‘magit-show-commit’ as described
+ above, except if point is on a reference in a ‘magit-refs-mode’
+ buffer, in which case the behavior may be different, but only if
+ you have customized the option ‘magit-visit-ref-behavior’.
+
+ -- User Option: magit-visit-ref-behavior
+
+ This option controls how ‘magit-visit-ref’ behaves in
+ ‘magit-refs-mode’ buffers.
+
+ By default ‘magit-visit-ref’ behaves like ‘magit-show-commit’, in
+ all buffers, including ‘magit-refs-mode’ buffers. When the type of
+ the section at point is ‘commit’ then "RET" is bound to
+ ‘magit-show-commit’, and when the type is either ‘branch’ or ‘tag’
+ then it is bound to ‘magit-visit-ref’.
+
+ "RET" is one of Magit’s most essential keys and at least by default
+ it should behave consistently across all of Magit, especially
+ because users quickly learn that it does something very harmless;
+ it shows more information about the thing at point in another
+ buffer.
+
+ However "RET" used to behave differently in ‘magit-refs-mode’
+ buffers, doing surprising things, some of which cannot really be
+ described as "visit this thing". If you’ve grown accustomed this
+ behavior, you can restore it by adding one or more of the below
+ symbols to the value of this option. But keep in mind that by
+ doing so you don’t only introduce inconsistencies, you also lose
+ some functionality and might have to resort to ‘M-x
+ magit-show-commit’ to get it back.
+
+ ‘magit-visit-ref’ looks for these symbols in the order in which
+ they are described here. If the presence of a symbol applies to
+ the current situation, then the symbols that follow do not affect
+ the outcome.
+
+ • ‘focus-on-ref’
+
+ With a prefix argument update the buffer to show commit counts
+ and lists of cherry commits relative to the reference at point
+ instead of relative to the current buffer or ‘HEAD’.
+
+ Instead of adding this symbol, consider pressing "C-u y o
+ RET".
+
+ • ‘create-branch’
+
+ If point is on a remote branch, then create a new local branch
+ with the same name, use the remote branch as its upstream, and
+ then check out the local branch.
+
+ Instead of adding this symbol, consider pressing "b c RET
+ RET", like you would do in other buffers.
+
+ • ‘checkout-any’
+
+ Check out the reference at point. If that reference is a tag
+ or a remote branch, then this results in a detached ‘HEAD’.
+
+ Instead of adding this symbol, consider pressing "b b RET",
+ like you would do in other buffers.
+
+ • ‘checkout-branch’
+
+ Check out the local branch at point.
+
+ Instead of adding this symbol, consider pressing "b b RET",
+ like you would do in other buffers.
+
+* Menu:
+
+* References Sections::
+
+\1f
+File: magit.info, Node: References Sections, Up: References Buffer
+
+5.6.1 References Sections
+-------------------------
+
+The contents of references buffers is controlled using the hook
+‘magit-refs-sections-hook’. See *note Section Hooks:: to learn about
+such hooks and how to customize them. All of the below functions are
+members of the default value. Note that it makes much less sense to
+customize this hook than it does for the respective hook used for the
+status buffer.
+
+ -- User Option: magit-refs-sections-hook
+
+ Hook run to insert sections into a references buffer.
+
+ -- Function: magit-insert-local-branches
+
+ Insert sections showing all local branches.
+
+ -- Function: magit-insert-remote-branches
+
+ Insert sections showing all remote-tracking branches.
+
+ -- Function: magit-insert-tags
+
+ Insert sections showing all tags.
+
+\1f
+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.
+
+\1f
+File: magit.info, Node: Visiting Files and Blobs, Next: Blaming, Prev: Bisecting, Up: Inspecting
+
+5.8 Visiting Files and Blobs
+============================
+
+Magit provides several commands that visit a file or blob (the version
+of a file that is stored in a certain commit). Actually it provides
+several *groups* of such commands and the several *variants* within each
+group.
+
+* Menu:
+
+* General-Purpose Visit Commands::
+* Visiting Files and Blobs from a Diff::
+
+\1f
+File: magit.info, Node: General-Purpose Visit Commands, Next: Visiting Files and Blobs from a Diff, Up: Visiting Files and Blobs
+
+5.8.1 General-Purpose Visit Commands
+------------------------------------
+
+These commands can be used anywhere to open any blob. Currently no keys
+are bound to these commands by default, but that is likely to change.
+
+ -- Command: magit-find-file
+
+ This command reads a filename and revision from the user and visits
+ the respective blob in a buffer. The buffer is displayed in the
+ selected window.
+
+ -- Command: magit-find-file-other-window
+
+ This command reads a filename and revision from the user and visits
+ the respective blob in a buffer. The buffer is displayed in
+ another window.
+
+ -- Command: magit-find-file-other-frame
+
+ This command reads a filename and revision from the user and visits
+ the respective blob in a buffer. The buffer is displayed in
+ another frame.
+
+\1f
+File: magit.info, Node: Visiting Files and Blobs from a Diff, Prev: General-Purpose Visit Commands, Up: Visiting Files and Blobs
+
+5.8.2 Visiting Files and Blobs from a Diff
+------------------------------------------
+
+These commands can only be used when point is inside a diff.
+
+‘RET’ (‘magit-diff-visit-file’)
+
+ This command visits the appropriate version of the file that the
+ diff at point is about.
+
+ This commands visits the worktree version of the appropriate file.
+ The location of point inside the diff determines which file is
+ being visited. The visited version depends on what changes the
+ diff is about.
+
+ • If the diff shows uncommitted changes (i.e. staged or
+ unstaged changes), then visit the file in the working tree
+ (i.e. the same "real" file that ‘find-file’ would visit. In
+ all other cases visit a "blob" (i.e. the version of a file as
+ stored in some commit).
+
+ • If point is on a removed line, then visit the blob for the
+ first parent of the commit that removed that line, i.e. the
+ last commit where that line still exists.
+
+ • If point is on an added or context line, then visit the blob
+ that adds that line, or if the diff shows from more than a
+ single commit, then visit the blob from the last of these
+ commits.
+
+ In the file-visiting buffer this command goes to the line that
+ corresponds to the line that point is on in the diff.
+
+ The buffer is displayed in the selected window. With a prefix
+ argument the buffer is displayed in another window instead.
+
+ -- User Option: magit-diff-visit-previous-blob
+
+ This option controls whether ‘magit-diff-visit-file’ may visit the
+ previous blob. When this is ‘t’ (the default) and point is on a
+ removed line in a diff for a committed change, then
+ ‘magit-diff-visit-file’ visits the blob from the last revision
+ which still had that line.
+
+ Currently this is only supported for committed changes, for staged
+ and unstaged changes ‘magit-diff-visit-file’ always visits the file
+ in the working tree.
+
+‘C-<return>’ (‘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
+
+\1f
+File: magit.info, Node: Blaming, Prev: Visiting Files and Blobs, Up: Inspecting
+
+5.9 Blaming
+===========
+
+Also see *note (gitman)git-blame::.
+
+ To start blaming invoke the ‘magit-file-dispatch’ transient prefix
+command by pressing ‘C-c M-g’.
+
+ The blaming suffix commands can be invoked from the dispatch
+transient. However if you want to set an infix argument, then you have
+to enter the blaming sub-transient first.
+
+ The key bindings shown below assume that you enter the dispatch
+transient using the default binding.
+
+‘C-c M-g B’ (‘magit-blame’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+ Note that not all of the following suffixes are available at all
+times. For example if ‘magit-blame-mode’ is not enabled, then the
+command whose purpose is to turn off that mode would not be of any use
+and therefore isn’t available.
+
+‘C-c M-g b’ (‘magit-blame-addition’)
+‘C-c M-g B b’ (‘magit-blame-addition’)
+
+ This command augments each line or chunk of lines in the current
+ file-visiting or blob-visiting buffer with information about what
+ commits last touched these lines.
+
+ If the buffer visits a revision of that file, then history up to
+ that revision is considered. Otherwise, the file’s full history is
+ considered, including uncommitted changes.
+
+ If Magit-Blame mode is already turned on in the current buffer then
+ blaming is done recursively, by visiting REVISION:FILE (using
+ ‘magit-find-file’), where REVISION is a parent of the revision that
+ added the current line or chunk of lines.
+
+‘C-c M-g r’ (‘magit-blame-removal’)
+‘C-c M-g B r’ (‘magit-blame-removal’)
+
+ This command augments each line or chunk of lines in the current
+ blob-visiting buffer with information about the revision that
+ removes it. It cannot be used in file-visiting buffers.
+
+ Like ‘magit-blame-addition’, this command can be used recursively.
+
+‘C-c M-g f’ (‘magit-blame-reverse’)
+‘C-c M-g B f’ (‘magit-blame-reverse’)
+
+ This command augments each line or chunk of lines in the current
+ file-visiting or blob-visiting buffer with information about the
+ last revision in which a line still existed.
+
+ Like ‘magit-blame-addition’, this command can be used recursively.
+
+‘C-c M-g e’ (‘magit-blame-echo’)
+‘C-c M-g B e’ (‘magit-blame-echo’)
+
+ This command is like ‘magit-blame-addition’ except that it doesn’t
+ turn on ‘read-only-mode’ and that it initially uses the
+ visualization style specified by option ‘magit-blame-echo-style’.
+
+ The following key bindings are available when Magit-Blame mode is
+enabled and Read-Only mode is not enabled. These commands are also
+available in other buffers; here only the behavior is described that is
+relevant in file-visiting buffers that are being blamed.
+
+‘RET’ (‘magit-show-commit’)
+
+ This command shows the commit that last touched the line at point.
+
+‘SPC’ (‘magit-diff-show-or-scroll-up’)
+
+ This command updates the commit buffer.
+
+ This either shows the commit that last touched the line at point in
+ the appropriate buffer, or if that buffer is already being
+ displayed in the current frame and if that buffer contains
+ information about that commit, then the buffer is scrolled up
+ instead.
+
+‘DEL’ (‘magit-diff-show-or-scroll-down’)
+
+ This command updates the commit buffer.
+
+ This either shows the commit that last touched the line at point in
+ the appropriate buffer, or if that buffer is already being
+ displayed in the current frame and if that buffer contains
+ information about that commit, then the buffer is scrolled down
+ instead.
+
+ The following key bindings are available when both Magit-Blame mode
+and Read-Only mode are enabled.
+
+‘b’ (‘magit-blame’)
+
+ See above.
+
+‘n’ (‘magit-blame-next-chunk’)
+
+ This command moves to the next chunk.
+
+‘N’ (‘magit-blame-next-chunk-same-commit’)
+
+ This command moves to the next chunk from the same commit.
+
+‘p’ (‘magit-blame-previous-chunk’)
+
+ This command moves to the previous chunk.
+
+‘P’ (‘magit-blame-previous-chunk-same-commit’)
+
+ This command moves to the previous chunk from the same commit.
+
+‘q’ (‘magit-blame-quit’)
+
+ This command turns off Magit-Blame mode. If the buffer was created
+ during a recursive blame, then it also kills the buffer.
+
+‘M-w’ (‘magit-blame-copy-hash’)
+
+ This command saves the hash of the current chunk’s commit to the
+ kill ring.
+
+ When the region is active, the command saves the region’s content
+ instead of the hash, like ‘kill-ring-save’ would.
+
+‘c’ (‘magit-blame-cycle-style’)
+
+ This command changes how blame information is visualized in the
+ current buffer by cycling through the styles specified using the
+ option ‘magit-blame-styles’.
+
+ Blaming is also controlled using the following options.
+
+ -- User Option: magit-blame-styles
+
+ This option defines a list of styles used to visualize blame
+ information. For now see its doc-string to learn more.
+
+ -- User Option: magit-blame-echo-style
+
+ This option specifies the blame visualization style used by the
+ command ‘magit-blame-echo’. This must be a symbol that is used as
+ the identifier for one of the styles defined in
+ ‘magit-blame-styles’.
+
+ -- User Option: magit-blame-time-format
+
+ This option specifies the format string used to display times when
+ showing blame information.
+
+ -- User Option: magit-blame-read-only
+
+ This option controls whether blaming a buffer also makes
+ temporarily read-only.
+
+ -- User Option: magit-blame-disable-modes
+
+ This option lists incompatible minor-modes that should be disabled
+ temporarily when a buffer contains blame information. They are
+ enabled again when the buffer no longer shows blame information.
+
+ -- User Option: magit-blame-goto-chunk-hook
+
+ This hook is run when moving between chunks.
+
+\1f
+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::
+
+\1f
+File: magit.info, Node: Creating Repository, Next: Cloning Repository, Up: Manipulating
+
+6.1 Creating Repository
+=======================
+
+‘M-x magit-init’ (‘magit-init’)
+
+ This command initializes a repository and then shows the status
+ buffer for the new repository.
+
+ If the directory is below an existing repository, then the user has
+ to confirm that a new one should be created inside. If the
+ directory is the root of the existing repository, then the user has
+ to confirm that it should be reinitialized.
+
+\1f
+File: magit.info, Node: Cloning Repository, Next: Staging and Unstaging, Prev: Creating Repository, Up: Manipulating
+
+6.2 Cloning Repository
+======================
+
+To clone a remote or local repository use ‘C’, which is bound to the
+command ‘magit-clone’. This command either act as a transient prefix
+command, which binds several infix arguments and suffix commands, or it
+can invoke ‘git clone’ directly, depending on whether a prefix argument
+is used and on the value of ‘magit-clone-always-transient’.
+
+ -- User Option: magit-clone-always-transient
+
+ This option controls whether the command ‘magit-clone’ always acts
+ as a transient prefix command, regardless of whether a prefix
+ argument is used or not. If ‘t’, then that command always acts as
+ a transient prefix. If ‘nil’, then a prefix argument has to be
+ used for it to act as a transient.
+
+‘C’ (‘magit-clone’)
+
+ This command either acts as a transient prefix command as described
+ above or does the same thing as ‘transient-clone-regular’ as
+ described below.
+
+ If it acts as a transient prefix, then it binds the following
+ suffix commands and several infix arguments.
+
+‘C C’ (‘magit-clone-regular’)
+
+ This command creates a regular clone of an existing repository.
+ The repository and the target directory are read from the user.
+
+‘C s’ (‘magit-clone-shallow’)
+
+ This command creates a shallow clone of an existing repository.
+ The repository and the target directory are read from the user. By
+ default the depth of the cloned history is a single commit, but
+ with a prefix argument the depth is read from the user.
+
+‘C b’ (‘magit-clone-bare’)
+
+ This command creates a bare clone of an existing repository. The
+ repository and the target directory are read from the user.
+
+‘C m’ (‘magit-clone-mirror’)
+
+ This command creates a mirror of an existing repository. The
+ repository and the target directory are read from the user.
+
+ The following suffixes are disabled by default. See *note
+(transient)Enabling and Disabling Suffixes:: for how to enable them.
+
+‘C d’ (‘magit-clone-shallow-since’)
+
+ This command creates a shallow clone of an existing repository.
+ Only commits that were committed after a date are cloned, which is
+ read from the user. The repository and the target directory are
+ also read from the user.
+
+‘C e’ (‘magit-clone-shallow-exclude’)
+
+ This command creates a shallow clone of an existing repository.
+ This reads a branch or tag from the user. Commits that are
+ reachable from that are not cloned. The repository and the target
+ directory are also read from the user.
+
+ -- User Option: magit-clone-set-remote-head
+
+ This option controls whether cloning causes the reference
+ ‘refs/remotes/<remote>/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.
+
+\1f
+File: magit.info, Node: Staging and Unstaging, Next: Applying, Prev: Cloning Repository, Up: Manipulating
+
+6.3 Staging and Unstaging
+=========================
+
+Like Git, Magit can of course stage and unstage complete files. Unlike
+Git, it also allows users to gracefully un-/stage individual hunks and
+even just part of a hunk. To stage individual hunks and parts of hunks
+using Git directly, one has to use the very modal and rather clumsy
+interface of a ‘git add --interactive’ session.
+
+ With Magit, on the other hand, one can un-/stage individual hunks by
+just moving point into the respective section inside a diff displayed in
+the status buffer or a separate diff buffer and typing ‘s’ or ‘u’. To
+operate on just parts of a hunk, mark the changes that should be
+un-/staged using the region and then press the same key that would be
+used to un-/stage. To stage multiple files or hunks at once use a
+region that starts inside the heading of such a section and ends inside
+the heading of a sibling section of the same type.
+
+ Besides staging and unstaging, Magit also provides several other
+"apply variants" that can also operate on a file, multiple files at
+once, a hunk, multiple hunks at once, and on parts of a hunk. These
+apply variants are described in the next section.
+
+ You can also use Ediff to stage and unstage. See *note Ediffing::.
+
+‘s’ (‘magit-stage’)
+
+ Add the change at point to the staging area.
+
+ With a prefix argument and an untracked file (or files) at point,
+ stage the file but not its content. This makes it possible to
+ stage only a subset of the new file’s changes.
+
+‘S’ (‘magit-stage-modified’)
+
+ Stage all changes to files modified in the worktree. Stage all new
+ content of tracked files and remove tracked files that no longer
+ exist in the working tree from the index also. With a prefix
+ argument also stage previously untracked (but not ignored) files.
+
+‘u’ (‘magit-unstage’)
+
+ Remove the change at point from the staging area.
+
+ Only staged changes can be unstaged. But by default this command
+ performs an action that is somewhat similar to unstaging, when it
+ is called on a committed change: it reverses the change in the
+ index but not in the working tree.
+
+‘U’ (‘magit-unstage-all’)
+
+ Remove all changes from the staging area.
+
+ -- User Option: magit-unstage-committed
+
+ This option controls whether ‘magit-unstage’ "unstages" committed
+ changes by reversing them in the index but not the working tree.
+ The alternative is to raise an error.
+
+‘M-x magit-reverse-in-index’ (‘magit-reverse-in-index’)
+
+ This command reverses the committed change at point in the index
+ but not the working tree. By default no key is bound directly to
+ this command, but it is indirectly called when ‘u’
+ (‘magit-unstage’) is pressed on a committed change.
+
+ This allows extracting a change from ‘HEAD’, while leaving it in
+ the working tree, so that it can later be committed using a
+ separate commit. A typical workflow would be:
+
+ • Optionally make sure that there are no uncommitted changes.
+
+ • Visit the ‘HEAD’ commit and navigate to the change that should
+ not have been included in that commit.
+
+ • Type ‘u’ (‘magit-unstage’) to reverse it in the index. This
+ assumes that ‘magit-unstage-committed-changes’ is non-nil.
+
+ • Type ‘c e’ to extend ‘HEAD’ with the staged changes, including
+ those that were already staged before.
+
+ • Optionally stage the remaining changes using ‘s’ or ‘S’ and
+ then type ‘c c’ to create a new commit.
+
+‘M-x magit-reset-index’ (‘magit-reset-index’)
+
+ Reset the index to some commit. The commit is read from the user
+ and defaults to the commit at point. If there is no commit at
+ point, then it defaults to ‘HEAD’.
+
+* Menu:
+
+* Staging from File-Visiting Buffers::
+
+\1f
+File: magit.info, Node: Staging from File-Visiting Buffers, Up: Staging and Unstaging
+
+6.3.1 Staging from File-Visiting Buffers
+----------------------------------------
+
+Fine-grained un-/staging has to be done from the status or a diff
+buffer, but it’s also possible to un-/stage all changes made to the file
+visited in the current buffer right from inside that buffer.
+
+‘M-x magit-stage-file’ (‘magit-stage-file’)
+
+ When invoked inside a file-visiting buffer, then stage all changes
+ to that file. In a Magit buffer, stage the file at point if any.
+ Otherwise prompt for a file to be staged. With a prefix argument
+ always prompt the user for a file, even in a file-visiting buffer
+ or when there is a file section at point.
+
+‘M-x magit-unstage-file’ (‘magit-unstage-file’)
+
+ When invoked inside a file-visiting buffer, then unstage all
+ changes to that file. In a Magit buffer, unstage the file at point
+ if any. Otherwise prompt for a file to be unstaged. With a prefix
+ argument always prompt the user for a file, even in a file-visiting
+ buffer or when there is a file section at point.
+
+\1f
+File: magit.info, Node: Applying, Next: Committing, Prev: Staging and Unstaging, Up: Manipulating
+
+6.4 Applying
+============
+
+Magit provides several "apply variants": stage, unstage, discard,
+reverse, and "regular apply". At least when operating on a hunk they
+are all implemented using ‘git apply’, which is why they are called
+"apply variants".
+
+ • Stage. Apply a change from the working tree to the index. The
+ change also remains in the working tree.
+
+ • Unstage. Remove a change from the index. The change remains in
+ the working tree.
+
+ • Discard. On a staged change, remove it from the working tree and
+ the index. On an unstaged change, remove it from the working tree
+ only.
+
+ • Reverse. Reverse a change in the working tree. Both committed and
+ staged changes can be reversed. Unstaged changes cannot be
+ reversed. Discard them instead.
+
+ • Apply. Apply a change to the working tree. Both committed and
+ staged changes can be applied. Unstaged changes cannot be applied
+ - as they already have been applied.
+
+ The previous section described the staging and unstaging commands.
+What follows are the commands which implement the remaining apply
+variants.
+
+‘a’ (‘magit-apply’)
+
+ Apply the change at point to the working tree.
+
+ With a prefix argument fallback to a 3-way merge. Doing so causes
+ the change to be applied to the index as well.
+
+‘k’ (‘magit-discard’)
+
+ Remove the change at point from the working tree.
+
+‘v’ (‘magit-reverse’)
+
+ Reverse the change at point in the working tree.
+
+ With a prefix argument fallback to a 3-way merge. Doing so causes
+ the change to be applied to the index as well.
+
+ With a prefix argument all apply variants attempt a 3-way merge when
+appropriate (i.e. when ‘git apply’ is used internally).
+
+\1f
+File: magit.info, Node: Committing, Next: Branching, Prev: Applying, Up: Manipulating
+
+6.5 Committing
+==============
+
+When the user initiates a commit, Magit calls ‘git commit’ without any
+arguments, so Git has to get it from the user. It creates the file
+‘.git/COMMIT_EDITMSG’ and then opens that file in an editor. Magit
+arranges for that editor to be the Emacsclient. Once the user finishes
+the editing session, the Emacsclient exits and Git creates the commit
+using the file’s content as message.
+
+* Menu:
+
+* Initiating a Commit::
+* Editing Commit Messages::
+
+\1f
+File: magit.info, Node: Initiating a Commit, Next: Editing Commit Messages, Up: Committing
+
+6.5.1 Initiating a Commit
+-------------------------
+
+Also see *note (gitman)git-commit::.
+
+‘c’ (‘magit-commit’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+‘c c’ (‘magit-commit-create’)
+
+ Create a new commit on ‘HEAD’. With a prefix argument amend to the
+ commit at ‘HEAD’ instead.
+
+‘c a’ (‘magit-commit-amend’)
+
+ Amend the last commit.
+
+‘c e’ (‘magit-commit-extend’)
+
+ Amend the last commit, without editing the message. With a prefix
+ argument keep the committer date, otherwise change it. The option
+ ‘magit-commit-extend-override-date’ can be used to inverse the
+ meaning of the prefix argument.
+
+ Non-interactively respect the optional OVERRIDE-DATE argument and
+ ignore the option.
+
+‘c w’ (‘magit-commit-reword’)
+
+ Reword the last commit, ignoring staged changes. With a prefix
+ argument keep the committer date, otherwise change it. The option
+ ‘magit-commit-reword-override-date’ can be used to inverse the
+ meaning of the prefix argument.
+
+ Non-interactively respect the optional OVERRIDE-DATE argument and
+ ignore the option.
+
+‘c f’ (‘magit-commit-fixup’)
+
+ Create a fixup commit.
+
+ With a prefix argument the target commit has to be confirmed.
+ Otherwise the commit at point may be used without confirmation
+ depending on the value of option ‘magit-commit-squash-confirm’.
+
+‘c F’ (‘magit-commit-instant-fixup’)
+
+ Create a fixup commit and instantly rebase.
+
+‘c s’ (‘magit-commit-squash’)
+
+ Create a squash commit, without editing the squash message.
+
+ With a prefix argument the target commit has to be confirmed.
+ Otherwise the commit at point may be used without confirmation
+ depending on the value of option ‘magit-commit-squash-confirm’.
+
+‘c S’ (‘magit-commit-instant-squash’)
+
+ Create a squash commit and instantly rebase.
+
+‘c A’ (‘magit-commit-augment’)
+
+ Create a squash commit, editing the squash message.
+
+ With a prefix argument the target commit has to be confirmed.
+ Otherwise the commit at point may be used without confirmation
+ depending on the value of option ‘magit-commit-squash-confirm’.
+
+ -- User Option: magit-commit-ask-to-stage
+
+ Whether to ask to stage all unstaged changes when committing and
+ nothing is staged.
+
+ -- User Option: magit-commit-extend-override-date
+
+ Whether using ‘magit-commit-extend’ changes the committer date.
+
+ -- User Option: magit-commit-reword-override-date
+
+ Whether using ‘magit-commit-reword’ changes the committer date.
+
+ -- User Option: magit-commit-squash-confirm
+
+ Whether the commit targeted by squash and fixup has to be
+ confirmed. When non-nil then the commit at point (if any) is used
+ as default choice. Otherwise it has to be confirmed. This option
+ only affects ‘magit-commit-squash’ and ‘magit-commit-fixup’. The
+ "instant" variants always require confirmation because making an
+ error while using those is harder to recover from.
+
+\1f
+File: magit.info, Node: Editing Commit Messages, Prev: Initiating a Commit, Up: Committing
+
+6.5.2 Editing Commit Messages
+-----------------------------
+
+After initiating a commit as described in the previous section, two new
+buffers appear. One shows the changes that are about to be committed,
+while the other is used to write the message.
+
+ Commit messages are edited in an edit session - in the background
+‘git’ is waiting for the editor, in our case ‘emacsclient’, to save the
+commit message in a file (in most cases ‘.git/COMMIT_EDITMSG’) and then
+return. If the editor returns with a non-zero exit status then ‘git’
+does not create the commit. So the most important commands are those
+for finishing and aborting the commit.
+
+‘C-c C-c’ (‘with-editor-finish’)
+
+ Finish the current editing session by returning with exit code 0.
+ Git then creates the commit using the message it finds in the file.
+
+‘C-c C-k’ (‘with-editor-cancel’)
+
+ Cancel the current editing session by returning with exit code 1.
+ Git then cancels the commit, but leaves the file untouched.
+
+ In addition to being used by ‘git commit’, messages may also be
+stored in a ring that persists until Emacs is closed. By default the
+message is stored at the beginning and the end of an edit session
+(regardless of whether the session is finished successfully or was
+canceled). It is sometimes useful to bring back messages from that
+ring.
+
+‘C-c M-s’ (‘git-commit-save-message’)
+
+ Save the current buffer content to the commit message ring.
+
+‘M-p’ (‘git-commit-prev-message’)
+
+ Cycle backward through the commit message ring, after saving the
+ current message to the ring. With a numeric prefix ARG, go back
+ ARG comments.
+
+‘M-n’ (‘git-commit-next-message’)
+
+ Cycle forward through the commit message ring, after saving the
+ current message to the ring. With a numeric prefix ARG, go back
+ ARG comments.
+
+ By default the diff for the changes that are about to be committed
+are automatically shown when invoking the commit. To prevent that,
+remove ‘magit-commit-diff’ from ‘server-switch-hook’.
+
+ When amending to an existing commit it may be useful to show either
+the changes that are about to be added to that commit or to show those
+changes alongside those that have already been committed.
+
+‘C-c C-d’ (‘magit-diff-while-committing’)
+
+ While committing, show the changes that are about to be committed.
+ While amending, invoking the command again toggles between showing
+ just the new changes or all the changes that will be committed.
+
+* Menu:
+
+* Using the Revision Stack::
+* Commit Pseudo Headers::
+* Commit Mode and Hooks::
+* Commit Message Conventions::
+
+\1f
+File: magit.info, Node: Using the Revision Stack, Next: Commit Pseudo Headers, Up: Editing Commit Messages
+
+Using the Revision Stack
+........................
+
+‘C-c C-w’ (‘magit-pop-revision-stack’)
+
+ This command inserts a representation of a revision into the
+ current buffer. It can be used inside buffers used to write commit
+ messages but also in other buffers such as buffers used to edit
+ emails or ChangeLog files.
+
+ By default this command pops the revision which was last added to
+ the ‘magit-revision-stack’ and inserts it into the current buffer
+ according to ‘magit-pop-revision-stack-format’. Revisions can be
+ put on the stack using ‘magit-copy-section-value’ and
+ ‘magit-copy-buffer-revision’.
+
+ If the stack is empty or with a prefix argument it instead reads a
+ revision in the minibuffer. By using the minibuffer history this
+ allows selecting an item which was popped earlier or to insert an
+ arbitrary reference or revision without first pushing it onto the
+ stack.
+
+ When reading the revision from the minibuffer, then it might not be
+ possible to guess the correct repository. When this command is
+ called inside a repository (e.g. while composing a commit
+ message), then that repository is used. Otherwise (e.g. while
+ composing an email) then the repository recorded for the top
+ element of the stack is used (even though we insert another
+ revision). If not called inside a repository and with an empty
+ stack, or with two prefix arguments, then read the repository in
+ the minibuffer too.
+
+ -- User Option: magit-pop-revision-stack-format
+
+ This option controls how the command ‘magit-pop-revision-stack’
+ inserts a revision into the current buffer.
+
+ The entries on the stack have the format ‘(HASH TOPLEVEL)’ and this
+ option has the format ‘(POINT-FORMAT EOB-FORMAT INDEX-REGEXP)’, all
+ of which may be nil or a string (though either one of EOB-FORMAT or
+ POINT-FORMAT should be a string, and if INDEX-REGEXP is non-nil,
+ then the two formats should be too).
+
+ First INDEX-REGEXP is used to find the previously inserted entry,
+ by searching backward from point. The first submatch must match
+ the index number. That number is incremented by one, and becomes
+ the index number of the entry to be inserted. If you don’t want to
+ number the inserted revisions, then use nil for INDEX-REGEXP.
+
+ If INDEX-REGEXP is non-nil then both POINT-FORMAT and EOB-FORMAT
+ should contain \"%N\", which is replaced with the number that was
+ determined in the previous step.
+
+ Both formats, if non-nil and after removing %N, are then expanded
+ using ‘git show --format=FORMAT ...’ inside TOPLEVEL.
+
+ The expansion of POINT-FORMAT is inserted at point, and the
+ expansion of EOB-FORMAT is inserted at the end of the buffer (if
+ the buffer ends with a comment, then it is inserted right before
+ that).
+
+\1f
+File: magit.info, Node: Commit Pseudo Headers, Next: Commit Mode and Hooks, Prev: Using the Revision Stack, Up: Editing Commit Messages
+
+Commit Pseudo Headers
+.....................
+
+Some projects use pseudo headers in commit messages. Magit colorizes
+such headers and provides some commands to insert such headers.
+
+ -- User Option: git-commit-known-pseudo-headers
+
+ A list of Git pseudo headers to be highlighted.
+
+‘C-c C-i’ (‘git-commit-insert-pseudo-header’)
+
+ Insert a commit message pseudo header.
+
+‘C-c C-a’ (‘git-commit-ack’)
+
+ Insert a header acknowledging that you have looked at the commit.
+
+‘C-c C-r’ (‘git-commit-review’)
+
+ Insert a header acknowledging that you have reviewed the commit.
+
+‘C-c C-s’ (‘git-commit-signoff’)
+
+ Insert a header to sign off the commit.
+
+‘C-c C-t’ (‘git-commit-test’)
+
+ Insert a header acknowledging that you have tested the commit.
+
+‘C-c C-o’ (‘git-commit-cc’)
+
+ Insert a header mentioning someone who might be interested.
+
+‘C-c C-p’ (‘git-commit-reported’)
+
+ Insert a header mentioning the person who reported the issue being
+ fixed by the commit.
+
+‘C-c M-i’ (‘git-commit-suggested’)
+
+ Insert a header mentioning the person who suggested the change.
+
+\1f
+File: magit.info, Node: Commit Mode and Hooks, Next: Commit Message Conventions, Prev: Commit Pseudo Headers, Up: Editing Commit Messages
+
+Commit Mode and Hooks
+.....................
+
+‘git-commit-mode’ is a minor mode that is only used to establish certain
+key bindings. This makes it possible to use an arbitrary major mode in
+buffers used to edit commit messages. It is even possible to use
+different major modes in different repositories, which is useful when
+different projects impose different commit message conventions.
+
+ -- User Option: git-commit-major-mode
+
+ The value of this option is the major mode used to edit Git commit
+ messages.
+
+ Because ‘git-commit-mode’ is a minor mode, we don’t use its mode hook
+to setup the buffer, except for the key bindings. All other setup
+happens in the function ‘git-commit-setup’, which among other things
+runs the hook ‘git-commit-setup-hook’.
+
+ -- User Option: git-commit-setup-hook
+
+ Hook run at the end of ‘git-commit-setup’.
+
+The following functions are suitable for this hook:
+
+ -- Function: git-commit-save-message
+
+ Save the current buffer content to the commit message ring.
+
+ -- Function: git-commit-setup-changelog-support
+
+ After this function is called, ChangeLog entries are treated as
+ paragraphs.
+
+ -- Function: git-commit-turn-on-auto-fill
+
+ Turn on ‘auto-fill-mode’ and set ‘fill-column’ to the value of
+ ‘git-commit-fill-column’.
+
+ -- Function: git-commit-turn-on-flyspell
+
+ Turn on Flyspell mode. Also prevent comments from being checked
+ and finally check current non-comment text.
+
+ -- Function: git-commit-propertize-diff
+
+ Propertize the diff shown inside the commit message buffer. Git
+ inserts such diffs into the commit message template when the
+ ‘--verbose’ argument is used. ‘magit-commit’ by default does not
+ offer that argument because the diff that is shown in a separate
+ buffer is more useful. But some users disagree, which is why this
+ function exists.
+
+ -- Function: bug-reference-mode
+
+ Hyperlink bug references in the buffer.
+
+ -- Function: with-editor-usage-message
+
+ Show usage information in the echo area.
+
+ -- User Option: git-commit-setup-hook
+
+ Hook run after the user finished writing a commit message.
+
+ This hook is only run after pressing ‘C-c C-c’ in a buffer used to
+ edit a commit message. If a commit is created without the user
+ typing a message into a buffer, then this hook is not run.
+
+ This hook is not run until the new commit has been created. If
+ doing so takes Git longer than one second, then this hook isn’t run
+ at all. For certain commands such as ‘magit-rebase-continue’ this
+ hook is never run because doing so would lead to a race condition.
+
+ This hook is only run if ‘magit’ is available.
+
+ Also see ‘magit-post-commit-hook’.
+
+\1f
+File: magit.info, Node: Commit Message Conventions, Prev: Commit Mode and Hooks, Up: Editing Commit Messages
+
+Commit Message Conventions
+..........................
+
+Git-Commit highlights certain violations of commonly accepted commit
+message conventions. Certain violations even cause Git-Commit to ask
+you to confirm that you really want to do that. This nagging can of
+course be turned off, but the result of doing that usually is that
+instead of some code it’s now the human who is reviewing your commits
+who has to waste some time telling you to fix your commits.
+
+ -- User Option: git-commit-summary-max-length
+
+ The intended maximal length of the summary line of commit messages.
+ Characters beyond this column are colorized to indicate that this
+ preference has been violated.
+
+ -- User Option: git-commit-fill-column
+
+ Column beyond which automatic line-wrapping should happen in commit
+ message buffers.
+
+ -- User Option: git-commit-finish-query-functions
+
+ List of functions called to query before performing commit.
+
+ The commit message buffer is current while the functions are
+ called. If any of them returns nil, then the commit is not
+ performed and the buffer is not killed. The user should then fix
+ the issue and try again.
+
+ The functions are called with one argument. If it is non-nil then
+ that indicates that the user used a prefix argument to force
+ finishing the session despite issues. Functions should usually
+ honor this wish and return non-nil.
+
+ By default the only member is ‘git-commit-check-style-conventions’.
+
+ -- Function: git-commit-check-style-conventions
+
+ This function checks for violations of certain basic style
+ conventions. For each violation it asks users if they want to
+ proceed anyway.
+
+ -- User Option: git-commit-style-convention-checks
+
+ This option controls what conventions the function by the same name
+ tries to enforce. The value is a list of self-explanatory symbols
+ identifying certain conventions; ‘non-empty-second-line’ and
+ ‘overlong-summary-line’.
+
+\1f
+File: magit.info, Node: Branching, Next: Merging, Prev: Committing, Up: Manipulating
+
+6.6 Branching
+=============
+
+* Menu:
+
+* The Two Remotes::
+* Branch Commands::
+* Branch Git Variables::
+* Auxiliary Branch Commands::
+
+\1f
+File: magit.info, Node: The Two Remotes, Next: Branch Commands, Up: Branching
+
+6.6.1 The Two Remotes
+---------------------
+
+The upstream branch of some local branch is the branch into which the
+commits on that local branch should eventually be merged, usually
+something like ‘origin/master’. For the ‘master’ branch itself the
+upstream branch and the branch it is being pushed to, are usually the
+same remote branch. But for a feature branch the upstream branch and
+the branch it is being pushed to should differ.
+
+ The commits on feature branches too should _eventually_ end up in a
+remote branch such as ‘origin/master’ or ‘origin/maint’. Such a branch
+should therefore be used as the upstream. But feature branches
+shouldn’t be pushed directly to such branches. Instead a feature branch
+‘my-feature’ is usually pushed to ‘my-fork/my-feature’ or if you are a
+contributor ‘origin/my-feature’. After the new feature has been
+reviewed, the maintainer merges the feature into ‘master’. And finally
+‘master’ (not ‘my-feature’ itself) is pushed to ‘origin/master’.
+
+ But new features seldom are perfect on the first try, and so feature
+branches usually have to be reviewed, improved, and re-pushed several
+times. Pushing should therefore be easy to do, and for that reason many
+Git users have concluded that it is best to use the remote branch to
+which the local feature branch is being pushed as its upstream.
+
+ But luckily Git has long ago gained support for a push-remote which
+can be configured separately from the upstream branch, using the
+variables ‘branch.<name>.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::).
+
+\1f
+File: magit.info, Node: Branch Commands, Next: Branch Git Variables, Prev: The Two Remotes, Up: Branching
+
+6.6.2 Branch Commands
+---------------------
+
+The transient prefix command ‘magit-branch’ is used to create and
+checkout branches, and to make changes to existing branches. It is not
+used to fetch, pull, merge, rebase, or push branches, i.e. this command
+deals with branches themselves, not with the commits reachable from
+them. Those features are available from separate transient command.
+
+‘b’ (‘magit-branch’)
+
+ This transient prefix command binds the following suffix commands
+ and displays them in a temporary buffer until a suffix is invoked.
+
+ By default it also binds and displays the values of some
+ branch-related Git variables and allows changing their values.
+
+ -- User Option: magit-branch-direct-configure
+
+ This option controls whether the transient command ‘magit-branch’
+ can be used directly change the values Git variables. This
+ defaults to ‘t’ (to avoid changing key bindings). When set to
+ ‘nil’, then no variables are displayed by that transient command,
+ and its suffix command ‘magit-branch-configure’ has to be used
+ instead to view and change branch related variables.
+
+‘b C’ (‘magit-branch-configure’)
+‘f C’ (‘magit-branch-configure’)
+‘F C’ (‘magit-branch-configure’)
+‘P C’ (‘magit-branch-configure’)
+
+ This transient prefix command binds commands that set the value of
+ branch-related variables and displays them in a temporary buffer
+ until the transient is exited.
+
+ With a prefix argument, this command always prompts for a branch.
+
+ Without a prefix argument this depends on whether it was invoked as
+ a suffix of ‘magit-branch’ and on the
+ ‘magit-branch-direct-configure’ option. If ‘magit-branch’ already
+ displays the variables for the current branch, then it isn’t useful
+ to invoke another transient that displays them for the same branch.
+ In that case this command prompts for a branch.
+
+ The variables are described in *note Branch Git Variables::.
+
+‘b b’ (‘magit-checkout’)
+
+ Checkout a revision read in the minibuffer and defaulting to the
+ branch or arbitrary revision at point. If the revision is a local
+ branch then that becomes the current branch. If it is something
+ else then ‘HEAD’ becomes detached. Checkout fails if the working
+ tree or the staging area contain changes.
+
+‘b n’ (‘magit-branch-create’)
+
+ Create a new branch. The user is asked for a branch or arbitrary
+ revision to use as the starting point of the new branch. When a
+ branch name is provided, then that becomes the upstream branch of
+ the new branch. The name of the new branch is also read in the
+ minibuffer.
+
+ Also see option ‘magit-branch-prefer-remote-upstream’.
+
+‘b c’ (‘magit-branch-and-checkout’)
+
+ This command creates a new branch like ‘magit-branch’, but then
+ also checks it out.
+
+ Also see option ‘magit-branch-prefer-remote-upstream’.
+
+‘b l’ (‘magit-branch-checkout’)
+
+ This command checks out an existing or new local branch. It reads
+ a branch name from the user offering all local branches and a
+ subset of remote branches as candidates. Remote branches for which
+ a local branch by the same name exists are omitted from the list of
+ candidates. The user can also enter a completely new branch name.
+
+ • If the user selects an existing local branch, then that is
+ checked out.
+
+ • If the user selects a remote branch, then it creates and
+ checks out a new local branch with the same name, and
+ configures the selected remote branch as the push target.
+
+ • If the user enters a new branch name, then it creates and
+ checks that out, after also reading the starting-point from
+ the user.
+
+ In the latter two cases the upstream is also set. Whether it is
+ set to the chosen starting point or something else depends on the
+ value of ‘magit-branch-adjust-remote-upstream-alist’.
+
+‘b s’ (‘magit-branch-spinoff’)
+
+ This command creates and checks out a new branch starting at and
+ tracking the current branch. That branch in turn is reset to the
+ last commit it shares with its upstream. If the current branch has
+ no upstream or no unpushed commits, then the new branch is created
+ anyway and the previously current branch is not touched.
+
+ This is useful to create a feature branch after work has already
+ began on the old branch (likely but not necessarily "master").
+
+ If the current branch is a member of the value of option
+ ‘magit-branch-prefer-remote-upstream’ (which see), then the current
+ branch will be used as the starting point as usual, but the
+ upstream of the starting-point may be used as the upstream of the
+ new branch, instead of the starting-point itself.
+
+ If optional FROM is non-nil, then the source branch is reset to
+ ‘FROM~’, instead of to the last commit it shares with its upstream.
+ Interactively, FROM is only ever non-nil, if the region selects
+ some commits, and among those commits, FROM is the commit that is
+ the fewest commits ahead of the source branch.
+
+ The commit at the other end of the selection actually does not
+ matter, all commits between FROM and ‘HEAD’ are moved to the new
+ branch. If FROM is not reachable from ‘HEAD’ or is reachable from
+ the source branch’s upstream, then an error is raised.
+
+‘b S’ (‘magit-branch-spinout’)
+
+ This command behaves like ‘magit-branch-spinoff’, except that it
+ does not change the current branch. If there are any uncommitted
+ changes, then it behaves exactly like ‘magit-branch-spinoff’.
+
+‘b x’ (‘magit-branch-reset’)
+
+ This command resets a branch, defaulting to the branch at point, to
+ the tip of another branch or any other commit.
+
+ When the branch being reset is the current branch, then a hard
+ reset is performed. If there are any uncommitted changes, then the
+ user has to confirm the reset because those changes would be lost.
+
+ This is useful when you have started work on a feature branch but
+ realize it’s all crap and want to start over.
+
+ When resetting to another branch and a prefix argument is used,
+ then the target branch is set as the upstream of the branch that is
+ being reset.
+
+‘b k’ (‘magit-branch-delete’)
+
+ Delete one or multiple branches. If the region marks multiple
+ branches, then offer to delete those. Otherwise, prompt for a
+ single branch to be deleted, defaulting to the branch at point.
+
+‘b r’ (‘magit-branch-rename’)
+
+ Rename a branch. The branch and the new name are read in the
+ minibuffer. With prefix argument the branch is renamed even if
+ that name conflicts with an existing branch.
+
+ -- User Option: magit-branch-read-upstream-first
+
+ When creating a branch, whether to read the upstream branch before
+ the name of the branch that is to be created. The default is ‘t’,
+ and I recommend you leave it at that.
+
+ -- User Option: magit-branch-prefer-remote-upstream
+
+ This option specifies whether remote upstreams are favored over
+ local upstreams when creating new branches.
+
+ When a new branch is created, then the branch, commit, or stash at
+ point is suggested as the starting point of the new branch, or if
+ there is no such revision at point the current branch. In either
+ case the user may choose another starting point.
+
+ If the chosen starting point is a branch, then it may also be set
+ as the upstream of the new branch, depending on the value of the
+ Git variable ‘branch.autoSetupMerge’. By default this is done for
+ remote branches, but not for local branches.
+
+ You might prefer to always use some remote branch as upstream. If
+ the chosen starting point is (1) a local branch, (2) whose name
+ matches a member of the value of this option, (3) the upstream of
+ that local branch is a remote branch with the same name, and (4)
+ that remote branch can be fast-forwarded to the local branch, then
+ the chosen branch is used as starting point, but its own upstream
+ is used as the upstream of the new branch.
+
+ Members of this option’s value are treated as branch names that
+ have to match exactly unless they contain a character that makes
+ them invalid as a branch name. Recommended characters to use to
+ trigger interpretation as a regexp are "*" and "^". Some other
+ characters which you might expect to be invalid, actually are not,
+ e.g. ".+$" are all perfectly valid. More precisely, if ‘git
+ check-ref-format --branch STRING’ exits with a non-zero status,
+ then treat STRING as a regexp.
+
+ Assuming the chosen branch matches these conditions you would end
+ up with with e.g.:
+
+ feature --upstream--> origin/master
+
+ instead of
+
+ feature --upstream--> master --upstream--> origin/master
+
+ Which you prefer is a matter of personal preference. If you do
+ prefer the former, then you should add branches such as ‘master’,
+ ‘next’, and ‘maint’ to the value of this options.
+
+ -- User Option: magit-branch-adjust-remote-upstream-alist
+
+ The value of this option is an alist of branches to be used as the
+ upstream when branching a remote branch.
+
+ When creating a local branch from an ephemeral branch located on a
+ remote, e.g. a feature or hotfix branch, then that remote branch
+ should usually not be used as the upstream branch, since the
+ push-remote already allows accessing it and having both the
+ upstream and the push-remote reference the same related branch
+ would be wasteful. Instead a branch like "maint" or "master"
+ should be used as the upstream.
+
+ This option allows specifying the branch that should be used as the
+ upstream when branching certain remote branches. The value is an
+ alist of the form ‘((UPSTREAM . RULE)...)’. The first matching
+ element is used, the following elements are ignored.
+
+ UPSTREAM is the branch to be used as the upstream for branches
+ specified by RULE. It can be a local or a remote branch.
+
+ RULE can either be a regular expression, matching branches whose
+ upstream should be the one specified by UPSTREAM. Or it can be a
+ list of the only branches that should *not* use UPSTREAM; all other
+ branches will. Matching is done after stripping the remote part of
+ the name of the branch that is being branched from.
+
+ If you use a finite set of non-ephemeral branches across all your
+ repositories, then you might use something like:
+
+ (("origin/master" "master" "next" "maint"))
+
+ Or if the names of all your ephemeral branches contain a slash, at
+ least in some repositories, then a good value could be:
+
+ (("origin/master" . "/"))
+
+ Of course you can also fine-tune:
+
+ (("origin/maint" . "\\`hotfix/")
+ ("origin/master" . "\\`feature/"))
+
+ -- 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))
+
+\1f
+File: magit.info, Node: Branch Git Variables, Next: Auxiliary Branch Commands, Prev: Branch Commands, Up: Branching
+
+6.6.3 Branch Git Variables
+--------------------------
+
+These variables can be set from the transient prefix command
+‘magit-branch-configure’. By default they can also be set from
+‘magit-branch’. See *note Branch Commands::.
+
+ -- Variable: branch.NAME.merge
+
+ Together with ‘branch.NAME.remote’ this variable defines the
+ upstream branch of the local branch named NAME. The value of this
+ variable is the full reference of the upstream _branch_.
+
+ -- Variable: branch.NAME.remote
+
+ Together with ‘branch.NAME.merge’ this variable defines the
+ upstream branch of the local branch named NAME. The value of this
+ variable is the name of the upstream _remote_.
+
+ -- Variable: branch.NAME.rebase
+
+ This variable controls whether pulling into the branch named NAME
+ is done by rebasing or by merging the fetched branch.
+
+ • When ‘true’ then pulling is done by rebasing.
+
+ • When ‘false’ then pulling is done by merging.
+
+ • When undefined then the value of ‘pull.rebase’ is used. The
+ default of that variable is ‘false’.
+
+ -- Variable: branch.NAME.pushRemote
+
+ This variable specifies the remote that the branch named NAME is
+ usually pushed to. The value has to be the name of an existing
+ remote.
+
+ It is not possible to specify the name of _branch_ to push the
+ local branch to. The name of the remote branch is always the same
+ as the name of the local branch.
+
+ If this variable is undefined but ‘remote.pushDefault’ is defined,
+ then the value of the latter is used. By default
+ ‘remote.pushDefault’ is undefined.
+
+ -- Variable: branch.NAME.description
+
+ This variable can be used to describe the branch named NAME. That
+ description is used e.g. when turning the branch into a series of
+ patches.
+
+ The following variables specify defaults which are used if the above
+branch-specific variables are not set.
+
+ -- Variable: pull.rebase
+
+ This variable specifies whether pulling is done by rebasing or by
+ merging. It can be overwritten using ‘branch.NAME.rebase’.
+
+ • When ‘true’ then pulling is done by rebasing.
+
+ • When ‘false’ (the default) then pulling is done by merging.
+
+ Since it is never a good idea to merge the upstream branch into a
+ feature or hotfix branch and most branches are such branches, you
+ should consider setting this to ‘true’, and ‘branch.master.rebase’
+ to ‘false’.
+
+ -- Variable: remote.pushDefault
+
+ This variable specifies what remote the local branches are usually
+ pushed to. This can be overwritten per branch using
+ ‘branch.NAME.pushRemote’.
+
+ The following variables are used during the creation of a branch and
+control whether the various branch-specific variables are automatically
+set at this time.
+
+ -- Variable: branch.autoSetupMerge
+
+ This variable specifies under what circumstances creating a branch
+ NAME should result in the variables ‘branch.NAME.merge’ and
+ ‘branch.NAME.remote’ being set according to the starting point used
+ to create the branch. If the starting point isn’t a branch, then
+ these variables are never set.
+
+ • When ‘always’ then the variables are set regardless of whether
+ the starting point is a local or a remote branch.
+
+ • When ‘true’ (the default) then the variables are set when the
+ starting point is a remote branch, but not when it is a local
+ branch.
+
+ • When ‘false’ then the variables are never set.
+
+ -- Variable: branch.autoSetupRebase
+
+ This variable specifies whether creating a branch NAME should
+ result in the variable ‘branch.NAME.rebase’ being set to ‘true’.
+
+ • When ‘always’ then the variable is set regardless of whether
+ the starting point is a local or a remote branch.
+
+ • When ‘local’ then the variable are set when the starting point
+ is a local branch, but not when it is a remote branch.
+
+ • When ‘remote’ then the variable are set when the starting
+ point is a remote branch, but not when it is a local branch.
+
+ • When ‘never’ (the default) then the variable is never set.
+
+ Note that the respective commands always change the repository-local
+values. If you want to change the global value, which is used when the
+local value is undefined, then you have to do so on the command line,
+e.g.:
+
+ git config --global remote.autoSetupMerge always
+
+ For more information about these variables you should also see
+
+ *note (gitman)git-config::. Also see *note (gitman)git-branch::. ,
+*note (gitman)git-checkout::. and *note Pushing::.
+
+ -- User Option: magit-prefer-remote-upstream
+
+ This option controls whether commands that read a branch from the
+ user and then set it as the upstream branch, offer a local or a
+ remote branch as default completion candidate, when they have the
+ choice.
+
+ This affects all commands that use ‘magit-read-upstream-branch’ or
+ ‘magit-read-starting-point’, which includes all commands that
+ change the upstream and many which create new branches.
+
+\1f
+File: magit.info, Node: Auxiliary Branch Commands, Prev: Branch Git Variables, Up: Branching
+
+6.6.4 Auxiliary Branch Commands
+-------------------------------
+
+These commands are not available from the transient ‘magit-branch’ by
+default.
+
+ -- Command: magit-branch-shelve
+
+ This command shelves a branch. This is done by deleting the
+ branch, and creating a new reference "refs/shelved/BRANCH-NAME"
+ pointing at the same commit as the branch pointed at. If the
+ deleted branch had a reflog, then that is preserved as the reflog
+ of the new reference.
+
+ This is useful if you want to move a branch out of sight, but are
+ not ready to completely discard it yet.
+
+ -- Command: magit-branch-unshelve
+
+ This command unshelves a branch that was previously shelved using
+ ‘magit-branch-shelve’. This is done by deleting the reference
+ "refs/shelved/BRANCH-NAME" and creating a branch "BRANCH-NAME"
+ pointing at the same commit as the deleted reference pointed at.
+ If the deleted reference had a reflog, then that is restored as the
+ reflog of the branch.
+
+\1f
+File: magit.info, Node: Merging, Next: Resolving Conflicts, Prev: Branching, Up: Manipulating
+
+6.7 Merging
+===========
+
+Also see *note (gitman)git-merge::. For information on how to resolve
+merge conflicts see the next section.
+
+‘m’ (‘magit-merge’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+ When no merge is in progress, then the transient features the
+following suffix commands.
+
+‘m m’ (‘magit-merge-plain’)
+
+ This command merges another branch or an arbitrary revision into
+ the current branch. The branch or revision to be merged is read in
+ the minibuffer and defaults to the branch at point.
+
+ Unless there are conflicts or a prefix argument is used, then the
+ resulting merge commit uses a generic commit message, and the user
+ does not get a chance to inspect or change it before the commit is
+ created. With a prefix argument this does not actually create the
+ merge commit, which makes it possible to inspect how conflicts were
+ resolved and to adjust the commit message.
+
+‘m e’ (‘magit-merge-editmsg’)
+
+ This command merges another branch or an arbitrary revision into
+ the current branch and opens a commit message buffer, so that the
+ user can make adjustments. The commit is not actually created
+ until the user finishes with ‘C-c C-c’.
+
+‘m n’ (‘magit-merge-nocommit’)
+
+ This command merges another branch or an arbitrary revision into
+ the current branch, but does not actually create the merge commit.
+ The user can then further adjust the merge, even when automatic
+ conflict resolution succeeded and/or adjust the commit message.
+
+‘m a’ (‘magit-merge-absorb’)
+
+ This command merges another local branch into the current branch
+ and then removes the former.
+
+ Before the source branch is merged, it is first force pushed to its
+ push-remote, provided the respective remote branch already exists.
+ This ensures that the respective pull-request (if any) won’t get
+ stuck on some obsolete version of the commits that are being
+ merged. Finally, if ‘magit-branch-pull-request’ was used to create
+ the merged branch, then the respective remote branch is also
+ removed.
+
+‘m i’ (‘magit-merge-into’)
+
+ This command merges the current branch into another local branch
+ and then removes the former. The latter becomes the new current
+ branch.
+
+ Before the source branch is merged, it is first force pushed to its
+ push-remote, provided the respective remote branch already exists.
+ This ensures that the respective pull-request (if any) won’t get
+ stuck on some obsolete version of the commits that are being
+ merged. Finally, if ‘magit-branch-pull-request’ was used to create
+ the merged branch, then the respective remote branch is also
+ removed.
+
+‘m s’ (‘magit-merge-squash’)
+
+ This command squashes the changes introduced by another branch or
+ an arbitrary revision into the current branch. This only applies
+ the changes made by the squashed commits. No information is
+ preserved that would allow creating an actual merge commit.
+ Instead of this command you should probably use a command from the
+ apply transient.
+
+‘m p’ (‘magit-merge-preview’)
+
+ This command shows a preview of merging another branch or an
+ arbitrary revision into the current branch.
+
+ When a merge is in progress, then the transient instead features the
+following suffix commands.
+
+‘m m’ (‘magit-merge’)
+
+ After the user resolved conflicts, this command proceeds with the
+ merge. If some conflicts weren’t resolved, then this command
+ fails.
+
+‘m a’ (‘magit-merge-abort’)
+
+ This command aborts the current merge operation.
+
+\1f
+File: magit.info, Node: Resolving Conflicts, Next: Rebasing, Prev: Merging, Up: Manipulating
+
+6.8 Resolving Conflicts
+=======================
+
+When merging branches (or otherwise combining or changing history)
+conflicts can occur. If you edited two completely different parts of
+the same file in two branches and then merge one of these branches into
+the other, then Git can resolve that on its own, but if you edit the
+same area of a file, then a human is required to decide how the two
+versions, or "sides of the conflict", are to be combined into one.
+
+ Here we can only provide a brief introduction to the subject and
+point you toward some tools that can help. If you are new to this, then
+please also consult Git’s own documentation as well as other resources.
+
+ If a file has conflicts and Git cannot resolve them by itself, then
+it puts both versions into the affected file along with special markers
+whose purpose is to denote the boundaries of the unresolved part of the
+file and between the different versions. These boundary lines begin
+with the strings consisting of six times the same character, one of ‘<’,
+‘|’, ‘=’ and ‘>’ and are followed by information about the source of the
+respective versions, e.g.:
+
+ <<<<<<< HEAD
+ Take the blue pill.
+ =======
+ Take the red pill.
+ >>>>>>> feature
+
+ In this case you have chosen to take the red pill on one branch and
+on another you picked the blue pill. Now that you are merging these two
+diverging branches, Git cannot possibly know which pill you want to
+take.
+
+ To resolve that conflict you have to create a version of the affected
+area of the file by keeping only one of the sides, possibly by editing
+it in order to bring in the changes from the other side, remove the
+other versions as well as the markers, and then stage the result. A
+possible resolution might be:
+
+ Take both pills.
+
+ Often it is useful to see not only the two sides of the conflict but
+also the "original" version from before the same area of the file was
+modified twice on different branches. Instruct Git to insert that
+version as well by running this command once:
+
+ git config --global merge.conflictStyle diff3
+
+ The above conflict might then have looked like this:
+
+ <<<<<<< HEAD
+ Take the blue pill.
+ ||||||| merged common ancestors
+ Take either the blue or the red pill, but not both.
+ =======
+ Take the red pill.
+ >>>>>>> feature
+
+ If that were the case, then the above conflict resolution would not
+have been correct, which demonstrates why seeing the original version
+alongside the conflicting versions can be useful.
+
+ You can perform the conflict resolution completely by hand, but Emacs
+also provides some packages that help in the process: Smerge, Ediff
+(*note (ediff)Top::), and Emerge (*note (emacs)Emerge::). Magit does
+not provide its own tools for conflict resolution, but it does make
+using Smerge and Ediff more convenient. (Ediff supersedes Emerge, so
+you probably don’t want to use the latter anyway.)
+
+ In the Magit status buffer, files with unresolved conflicts are
+listed in the "Unstaged changes" and/or "Staged changes" sections. They
+are prefixed with the word "unmerged", which in this context essentially
+is a synonym for "unresolved".
+
+ Pressing ‘RET’ while point is on such a file section shows a buffer
+visiting that file, turns on ‘smerge-mode’ in that buffer, and places
+point inside the first area with conflicts. You should then resolve
+that conflict using regular edit commands and/or Smerge commands.
+
+ Unfortunately Smerge does not have a manual, but you can get a list
+of commands and binding ‘C-c ^ C-h’ and press ‘RET’ while point is on a
+command name to read its documentation.
+
+ Normally you would edit one version and then tell Smerge to keep only
+that version. Use ‘C-c ^ m’ (‘smerge-keep-mine’) to keep the ‘HEAD’
+version or ‘C-c ^ o’ (‘smerge-keep-other’) to keep the version that
+follows "|||||||". Then use ‘C-c ^ n’ to move to the next conflicting
+area in the same file. Once you are done resolving conflicts, return to
+the Magit status buffer. The file should now be shown as "modified", no
+longer as "unmerged", because Smerge automatically stages the file when
+you save the buffer after resolving the last conflict.
+
+ Alternatively you could use Ediff, which uses separate buffers for
+the different versions of the file. To resolve conflicts in a file
+using Ediff press ‘e’ while point is on such a file in the status
+buffer.
+
+ Ediff can be used for other purposes as well. For more information
+on how to enter Ediff from Magit, see *note Ediffing::. Explaining how
+to use Ediff is beyond the scope of this manual, instead see *note
+(ediff)Top::.
+
+ If you are unsure whether you should Smerge or Ediff, then use the
+former. It is much easier to understand and use, and except for truly
+complex conflicts, the latter is usually overkill.
+
+\1f
+File: magit.info, Node: Rebasing, Next: Cherry Picking, Prev: Resolving Conflicts, Up: Manipulating
+
+6.9 Rebasing
+============
+
+Also see *note (gitman)git-rebase::. For information on how to resolve
+conflicts that occur during rebases see the preceding section.
+
+‘r’ (‘magit-rebase’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+ When no rebase is in progress, then the transient features the
+following suffix commands.
+
+ Using one of these commands _starts_ a rebase sequence. Git might
+then stop somewhere along the way, either because you told it to do so,
+or because applying a commit failed due to a conflict. When that
+happens, then the status buffer shows information about the rebase
+sequence which is in progress in a section similar to a log section.
+See *note Information About In-Progress Rebase::.
+
+ For information about the upstream and the push-remote, see *note The
+Two Remotes::.
+
+‘r p’ (‘magit-rebase-onto-pushremote’)
+
+ This command rebases the current branch onto its push-remote.
+
+ With a prefix argument or when the push-remote is either not
+ configured or unusable, then let the user first configure the
+ push-remote.
+
+‘r u’ (‘magit-rebase-onto-upstream’)
+
+ This command rebases the current branch onto its upstream branch.
+
+ With a prefix argument or when the upstream is either not
+ configured or unusable, then let the user first configure the
+ upstream.
+
+‘r e’ (‘magit-rebase-branch’)
+
+ This command rebases the current branch onto a branch read in the
+ minibuffer. All commits that are reachable from head but not from
+ the selected branch TARGET are being rebased.
+
+‘r s’ (‘magit-rebase-subset’)
+
+ This command starts a non-interactive rebase sequence to transfer
+ commits from START to ‘HEAD’ onto NEWBASE. START has to be
+ selected from a list of recent commits.
+
+ By default Magit uses the ‘--autostash’ argument, which causes
+uncommitted changes to be stored in a stash before the rebase begins.
+These changes are restored after the rebase completes and if possible
+the stash is removed. If the stash does not apply cleanly, then the
+stash is not removed. In case something goes wrong when resolving the
+conflicts, this allows you to start over.
+
+ Even though one of the actions is dedicated to interactive rebases,
+the transient also features the infix argument ‘--interactive’. This
+can be used to turn one of the other, non-interactive rebase variants
+into an interactive rebase.
+
+ For example if you want to clean up a feature branch and at the same
+time rebase it onto ‘master’, then you could use ‘r-iu’. But we
+recommend that you instead do that in two steps. First use ‘ri’ to
+cleanup the feature branch, and then in a second step ‘ru’ to rebase it
+onto ‘master’. That way if things turn out to be more complicated than
+you thought and/or you make a mistake and have to start over, then you
+only have to redo half the work.
+
+ Explicitly enabling ‘--interactive’ won’t have an effect on the
+following commands as they always use that argument anyway, even if it
+is not enabled in the transient.
+
+‘r i’ (‘magit-rebase-interactive’)
+
+ This command starts an interactive rebase sequence.
+
+‘r f’ (‘magit-rebase-autosquash’)
+
+ This command combines squash and fixup commits with their intended
+ targets.
+
+‘r m’ (‘magit-rebase-edit-commit’)
+
+ This command starts an interactive rebase sequence that lets the
+ user edit a single older commit.
+
+‘r w’ (‘magit-rebase-reword-commit’)
+
+ This command starts an interactive rebase sequence that lets the
+ user reword a single older commit.
+
+‘r k’ (‘magit-rebase-remove-commit’)
+
+ This command removes a single older commit using rebase.
+
+ When a rebase is in progress, then the transient instead features the
+following suffix commands.
+
+‘r r’ (‘magit-rebase-continue’)
+
+ This command restart the current rebasing operation.
+
+ In some cases this pops up a commit message buffer for you do edit.
+ With a prefix argument the old message is reused as-is.
+
+‘r s’ (‘magit-rebase-skip’)
+
+ This command skips the current commit and restarts the current
+ rebase operation.
+
+‘r e’ (‘magit-rebase-edit’)
+
+ This command lets the user edit the todo list of the current rebase
+ operation.
+
+‘r a’ (‘magit-rebase-abort’)
+
+ This command aborts the current rebase operation, restoring the
+ original branch.
+
+* Menu:
+
+* Editing Rebase Sequences::
+* Information About In-Progress Rebase::
+
+\1f
+File: magit.info, Node: Editing Rebase Sequences, Next: Information About In-Progress Rebase, Up: Rebasing
+
+6.9.1 Editing Rebase Sequences
+------------------------------
+
+‘C-c C-c’ (‘with-editor-finish’)
+
+ Finish the current editing session by returning with exit code 0.
+ Git then uses the rebase instructions it finds in the file.
+
+‘C-c C-k’ (‘with-editor-cancel’)
+
+ Cancel the current editing session by returning with exit code 1.
+ Git then forgoes starting the rebase sequence.
+
+‘RET’ (‘git-rebase-show-commit’)
+
+ Show the commit on the current line in another buffer and select
+ that buffer.
+
+‘SPC’ (‘git-rebase-show-or-scroll-up’)
+
+ Show the commit on the current line in another buffer without
+ selecting that buffer. If the revision buffer is already visible
+ in another window of the current frame, then instead scroll that
+ window up.
+
+‘DEL’ (‘git-rebase-show-or-scroll-down’)
+
+ Show the commit on the current line in another buffer without
+ selecting that buffer. If the revision buffer is already visible
+ in another window of the current frame, then instead scroll that
+ window down.
+
+‘p’ (‘git-rebase-backward-line’)
+
+ Move to previous line.
+
+‘n’ (‘forward-line’)
+
+ Move to next line.
+
+‘M-p’ (‘git-rebase-move-line-up’)
+
+ Move the current commit (or command) up.
+
+‘M-n’ (‘git-rebase-move-line-down’)
+
+ Move the current commit (or command) down.
+
+‘r’ (‘git-rebase-reword’)
+
+ Edit message of commit on current line.
+
+‘e’ (‘git-rebase-edit’)
+
+ Stop at the commit on the current line.
+
+‘s’ (‘git-rebase-squash’)
+
+ Meld commit on current line into previous commit, and edit message.
+
+‘f’ (‘git-rebase-fixup’)
+
+ Meld commit on current line into previous commit, discarding the
+ current commit’s message.
+
+‘k’ (‘git-rebase-kill-line’)
+
+ Kill the current action line.
+
+‘c’ (‘git-rebase-pick’)
+
+ Use commit on current line.
+
+‘x’ (‘git-rebase-exec’)
+
+ Insert a shell command to be run after the proceeding commit.
+
+ If there already is such a command on the current line, then edit
+ that instead. With a prefix argument insert a new command even
+ when there already is one on the current line. With empty input
+ remove the command on the current line, if any.
+
+‘b’ (‘git-rebase-break’)
+
+ Insert a break action before the current line, instructing Git to
+ return control to the user.
+
+‘y’ (‘git-rebase-insert’)
+
+ Read an arbitrary commit and insert it below current line.
+
+‘C-x u’ (‘git-rebase-undo’)
+
+ Undo some previous changes. Like ‘undo’ but works in read-only
+ buffers.
+
+ -- User Option: git-rebase-auto-advance
+
+ Whether to move to next line after changing a line.
+
+ -- User Option: git-rebase-show-instructions
+
+ Whether to show usage instructions inside the rebase buffer.
+
+ -- User Option: git-rebase-confirm-cancel
+
+ Whether confirmation is required to cancel.
+
+ When a rebase is performed with the ‘--rebase-merges’ option, the
+sequence will include a few other types of actions and the following
+commands become relevant.
+
+‘l’ (‘git-rebase-label’)
+
+ This commands inserts a label action or edits the one at point.
+
+‘t’ (‘git-rebase-reset’)
+
+ This command inserts a reset action or edits the one at point. The
+ prompt will offer the labels that are currently present in the
+ buffer.
+
+‘MM’ (‘git-rebase-merge’)
+
+ The command inserts a merge action or edits the one at point. The
+ prompt will offer the labels that are currently present in the
+ buffer. Specifying a message to reuse via ‘-c’ or ‘-C’ is not
+ supported; an editor will always be invoked for the merge.
+
+‘Mt’ (‘git-rebase-merge-toggle-editmsg’)
+
+ This command toggles between the ‘-C’ and ‘-c’ options of the merge
+ action at point. These options both specify a commit whose message
+ should be reused. The lower-case variant instructs Git to invoke
+ the editor when creating the merge, allowing the user to edit the
+ message.
+
+\1f
+File: magit.info, Node: Information About In-Progress Rebase, Prev: Editing Rebase Sequences, Up: Rebasing
+
+6.9.2 Information About In-Progress Rebase
+------------------------------------------
+
+While a rebase sequence is in progress, the status buffer features a
+section that lists the commits that have already been applied as well as
+the commits that still have to be applied.
+
+ The commits are split in two halves. When rebase stops at a commit,
+either because the user has to deal with a conflict or because s/he
+explicitly requested that rebase stops at that commit, then point is
+placed on the commit that separates the two groups, i.e. on ‘HEAD’.
+The commits above it have not been applied yet, while the ‘HEAD’ and the
+commits below it have already been applied. In between these two groups
+of applied and yet-to-be applied commits, there sometimes is a commit
+which has been dropped.
+
+ Each commit is prefixed with a word and these words are additionally
+shown in different colors to indicate the status of the commits.
+
+ The following colors are used:
+
+ • Yellow commits have not been applied yet.
+
+ • Gray commits have already been applied.
+
+ • The blue commit is the ‘HEAD’ commit.
+
+ • The green commit is the commit the rebase sequence stopped at. If
+ this is the same commit as ‘HEAD’ (e.g. because you haven’t done
+ anything yet after rebase stopped at the commit, then this commit
+ is shown in blue, not green). There can only be a green *and* a
+ blue commit at the same time, if you create one or more new commits
+ after rebase stops at a commit.
+
+ • Red commits have been dropped. They are shown for reference only,
+ e.g. to make it easier to diff.
+
+ Of course these colors are subject to the color-theme in use.
+
+ The following words are used:
+
+ • Commits prefixed with ‘pick’, ‘reword’, ‘edit’, ‘squash’, and
+ ‘fixup’ have not been applied yet. These words have the same
+ meaning here as they do in the buffer used to edit the rebase
+ sequence. See *note Editing Rebase Sequences::. When the
+ ‘--rebase-merges’ option was specified, ‘reset’, ‘label’, and
+ ‘merge’ lines may also be present.
+
+ • Commits prefixed with ‘done’ and ‘onto’ have already been applied.
+ It is possible for such a commit to be the ‘HEAD’, in which case it
+ is blue. Otherwise it is grey.
+
+ • The commit prefixed with ‘onto’ is the commit on top of which
+ all the other commits are being re-applied. This commit
+ itself did not have to be re-applied, it is the commit rebase
+ did rewind to before starting to re-apply other commits.
+
+ • Commits prefixed with ‘done’ have already been re-applied.
+ This includes commits that have been re-applied but also new
+ commits that you have created during the rebase.
+
+ • All other commits, those not prefixed with any of the above words,
+ are in some way related to the commit at which rebase stopped.
+
+ To determine whether a commit is related to the stopped-at commit
+ their hashes, trees and patch-ids (1) are being compared. The
+ commit message is not used for this purpose.
+
+ Generally speaking commits that are related to the stopped-at
+ commit can have any of the used colors, though not all color/word
+ combinations are possible.
+
+ Words used for stopped-at commits are:
+
+ • When a commit is prefixed with ‘void’, then that indicates
+ that Magit knows for sure that all the changes in that commit
+ have been applied using several new commits. This commit is
+ no longer reachable from ‘HEAD’, and it also isn’t one of the
+ commits that will be applied when resuming the session.
+
+ • When a commit is prefixed with ‘join’, then that indicates
+ that the rebase sequence stopped at that commit due to a
+ conflict - you now have to join (merge) the changes with what
+ has already been applied. In a sense this is the commit
+ rebase stopped at, but while its effect is already in the
+ index and in the worktree (with conflict markers), the commit
+ itself has not actually been applied yet (it isn’t the
+ ‘HEAD’). So it is shown in yellow, like the other commits
+ that still have to be applied.
+
+ • When a commit is prefixed with ‘stop’ or a _blue_ or _green_
+ ‘same’, then that indicates that rebase stopped at this
+ commit, that it is still applied or has been applied again,
+ and that at least its patch-id is unchanged.
+
+ • When a commit is prefixed with ‘stop’, then that
+ indicates that rebase stopped at that commit because you
+ requested that earlier, and its patch-id is unchanged.
+ It might even still be the exact same commit.
+
+ • When a commit is prefixed with a _blue_ or _green_
+ ‘same’, then that indicates that while its tree or hash
+ changed, its patch-id did not. If it is blue, then it is
+ the ‘HEAD’ commit (as always for blue). When it is
+ green, then it no longer is ‘HEAD’ because other commit
+ have been created since (but before continuing the
+ rebase).
+
+ • When a commit is prefixed with ‘goal’, a _yellow_ ‘same,’ or
+ ‘work’, then that indicates that rebase applied that commit
+ but that you then reset ‘HEAD’ to an earlier commit (likely to
+ split it up into multiple commits), and that there are some
+ uncommitted changes remaining which likely (but not
+ necessarily) originate from that commit.
+
+ • When a commit is prefixed with ‘goal’, then that
+ indicates that it is still possible to create a new
+ commit with the exact same tree (the "goal") without
+ manually editing any files, by committing the index, or
+ by staging all changes and then committing that. This is
+ the case when the original tree still exists in the index
+ or worktree in untainted form.
+
+ • When a commit is prefixed with a yellow ‘same’, then that
+ indicates that it is no longer possible to create a
+ commit with the exact same tree, but that it is still
+ possible to create a commit with the same patch-id. This
+ would be the case if you created a new commit with other
+ changes, but the changes from the original commit still
+ exist in the index or working tree in untainted form.
+
+ • When a commit is prefixed with ‘work’, then that
+ indicates that you reset ‘HEAD’ to an earlier commit, and
+ that there are some staged and/or unstaged changes
+ (likely, but not necessarily) originating from that
+ commit. However it is no longer possible to create a new
+ commit with the same tree or at least the same patch-id
+ because you have already made other changes.
+
+ • When a commit is prefixed with ‘poof’ or ‘gone’, then that
+ indicates that rebase applied that commit but that you then
+ reset ‘HEAD’ to an earlier commit (likely to split it up into
+ multiple commits), and that there are no uncommitted changes.
+
+ • When a commit is prefixed with ‘poof’, then that
+ indicates that it is no longer reachable from ‘HEAD’, but
+ that it has been replaced with one or more commits, which
+ together have the exact same effect.
+
+ • When a commit is prefixed with ‘gone’, then that
+ indicates that it is no longer reachable from ‘HEAD’ and
+ that we also cannot determine whether its changes are
+ still in effect in one or more new commits. They might
+ be, but if so, then there must also be other changes
+ which makes it impossible to know for sure.
+
+ Do not worry if you do not fully understand the above. That’s okay,
+you will acquire a good enough understanding through practice.
+
+ For other sequence operations such as cherry-picking, a similar
+section is displayed, but they lack some of the features described
+above, due to limitations in the git commands used to implement them.
+Most importantly these sequences only support "picking" a commit but not
+other actions such as "rewording", and they do not keep track of the
+commits which have already been applied.
+
+ ---------- Footnotes ----------
+
+ (1) The patch-id is a hash of the _changes_ introduced by a commit.
+It differs from the hash of the commit itself, which is a hash of the
+result of applying that change (i.e. the resulting trees and blobs) as
+well as author and committer information, the commit message, and the
+hashes of the parents of the commit. The patch-id hash on the other
+hand is created only from the added and removed lines, even line numbers
+and whitespace changes are ignored when calculating this hash. The
+patch-ids of two commits can be used to answer the question "Do these
+commits make the same change?".
+
+\1f
+File: magit.info, Node: Cherry Picking, Next: Resetting, Prev: Rebasing, Up: Manipulating
+
+6.10 Cherry Picking
+===================
+
+Also see *note (gitman)git-cherry-pick::.
+
+‘A’ (‘magit-cherry-pick’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+ When no cherry-pick or revert is in progress, then the transient
+features the following suffix commands.
+
+‘A A’ (‘magit-cherry-copy’)
+
+ This command copies COMMITS from another branch onto the current
+ branch. If the region selects multiple commits, then those are
+ copied, without prompting. Otherwise the user is prompted for a
+ commit or range, defaulting to the commit at point.
+
+‘A a’ (‘magit-cherry-apply’)
+
+ This command applies the changes in COMMITS from another branch
+ onto the current branch. If the region selects multiple commits,
+ then those are used, without prompting. Otherwise the user is
+ prompted for a commit or range, defaulting to the commit at point.
+
+ This command also has a top-level binding, which can be invoked
+ without using the transient by typing ‘a’ at the top-level.
+
+ The following commands not only apply some commits to some branch,
+but also remove them from some other branch. The removal is performed
+using either ‘git-update-ref’ or if necessary ‘git-rebase’. Both
+applying commits as well as removing them using ‘git-rebase’ can lead to
+conflicts. If that happens, then these commands abort and you not only
+have to resolve the conflicts but also finish the process the same way
+you would have to if these commands didn’t exist at all.
+
+‘A h’ (‘magit-cherry-harvest’)
+
+ This command moves the selected COMMITS that must be located on
+ another BRANCH onto the current branch instead, removing them from
+ the former. When this command succeeds, then the same branch is
+ current as before.
+
+ Applying the commits on the current branch or removing them from
+ the other branch can lead to conflicts. When that happens, then
+ this command stops and you have to resolve the conflicts and then
+ finish the process manually.
+
+‘A d’ (‘magit-cherry-donate’)
+
+ This command moves the selected COMMITS from the current branch
+ onto another existing BRANCH, removing them from the former. When
+ this command succeeds, then the same branch is current as before.
+
+ Applying the commits on the other branch or removing them from the
+ current branch can lead to conflicts. When that happens, then this
+ command stops and you have to resolve the conflicts and then finish
+ the process manually.
+
+‘A n’ (‘magit-cherry-spinout’)
+
+ This command moves the selected COMMITS from the current branch
+ onto a new branch BRANCH, removing them from the former. When this
+ command succeeds, then the same branch is current as before.
+
+ Applying the commits on the other branch or removing them from the
+ current branch can lead to conflicts. When that happens, then this
+ command stops and you have to resolve the conflicts and then finish
+ the process manually.
+
+‘A s’ (‘magit-cherry-spinoff’)
+
+ This command moves the selected COMMITS from the current branch
+ onto a new branch BRANCH, removing them from the former. When this
+ command succeeds, then the new branch is checked out.
+
+ Applying the commits on the other branch or removing them from the
+ current branch can lead to conflicts. When that happens, then this
+ command stops and you have to resolve the conflicts and then finish
+ the process manually.
+
+ When a cherry-pick or revert is in progress, then the transient
+instead features the following suffix commands.
+
+‘A A’ (‘magit-sequence-continue’)
+
+ Resume the current cherry-pick or revert sequence.
+
+‘A s’ (‘magit-sequence-skip’)
+
+ Skip the stopped at commit during a cherry-pick or revert sequence.
+
+‘A a’ (‘magit-sequence-abort’)
+
+ Abort the current cherry-pick or revert sequence. This discards
+ all changes made since the sequence started.
+
+* Menu:
+
+* Reverting::
+
+\1f
+File: magit.info, Node: Reverting, Up: Cherry Picking
+
+6.10.1 Reverting
+----------------
+
+‘V’ (‘magit-revert’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+ When no cherry-pick or revert is in progress, then the transient
+features the following suffix commands.
+
+‘V V’ (‘magit-revert-and-commit’)
+
+ Revert a commit by creating a new commit. Prompt for a commit,
+ defaulting to the commit at point. If the region selects multiple
+ commits, then revert all of them, without prompting.
+
+‘V v’ (‘magit-revert-no-commit’)
+
+ Revert a commit by applying it in reverse to the working tree.
+ Prompt for a commit, defaulting to the commit at point. If the
+ region selects multiple commits, then revert all of them, without
+ prompting.
+
+ When a cherry-pick or revert is in progress, then the transient
+instead features the following suffix commands.
+
+‘V A’ (‘magit-sequence-continue’)
+
+ Resume the current cherry-pick or revert sequence.
+
+‘V s’ (‘magit-sequence-skip’)
+
+ Skip the stopped at commit during a cherry-pick or revert sequence.
+
+‘V a’ (‘magit-sequence-abort’)
+
+ Abort the current cherry-pick or revert sequence. This discards
+ all changes made since the sequence started.
+
+\1f
+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.
+
+\1f
+File: magit.info, Node: Stashing, Prev: Resetting, Up: Manipulating
+
+6.12 Stashing
+=============
+
+Also see *note (gitman)git-stash::.
+
+‘z’ (‘magit-stash’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+‘z z’ (‘magit-stash-both’)
+
+ Create a stash of the index and working tree. Untracked files are
+ included according to infix arguments. One prefix argument is
+ equivalent to ‘--include-untracked’ while two prefix arguments are
+ equivalent to ‘--all’.
+
+‘z i’ (‘magit-stash-index’)
+
+ Create a stash of the index only. Unstaged and untracked changes
+ are not stashed.
+
+‘z w’ (‘magit-stash-worktree’)
+
+ Create a stash of unstaged changes in the working tree. Untracked
+ files are included according to infix arguments. One prefix
+ argument is equivalent to ‘--include-untracked’ while two prefix
+ arguments are equivalent to ‘--all’.
+
+‘z x’ (‘magit-stash-keep-index’)
+
+ Create a stash of the index and working tree, keeping index intact.
+ Untracked files are included according to infix arguments. One
+ prefix argument is equivalent to ‘--include-untracked’ while two
+ prefix arguments are equivalent to ‘--all’.
+
+‘z Z’ (‘magit-snapshot-both’)
+
+ Create a snapshot of the index and working tree. Untracked files
+ are included according to infix arguments. One prefix argument is
+ equivalent to ‘--include-untracked’ while two prefix arguments are
+ equivalent to ‘--all’.
+
+‘z I’ (‘magit-snapshot-index’)
+
+ Create a snapshot of the index only. Unstaged and untracked
+ changes are not stashed.
+
+‘z W’ (‘magit-snapshot-worktree’)
+
+ Create a snapshot of unstaged changes in the working tree.
+ Untracked files are included according to infix arguments. One
+ prefix argument is equivalent to ‘--include-untracked’ while two
+ prefix arguments are equivalent to ‘--all’-.
+
+‘z a’ (‘magit-stash-apply’)
+
+ Apply a stash to the working tree. Try to preserve the stash
+ index. If that fails because there are staged changes, apply
+ without preserving the stash index.
+
+‘z p’ (‘magit-stash-pop’)
+
+ Apply a stash to the working tree and remove it from stash list.
+ Try to preserve the stash index. If that fails because there are
+ staged changes, apply without preserving the stash index and forgo
+ removing the stash.
+
+‘z k’ (‘magit-stash-drop’)
+
+ Remove a stash from the stash list. When the region is active,
+ offer to drop all contained stashes.
+
+‘z v’ (‘magit-stash-show’)
+
+ Show all diffs of a stash in a buffer.
+
+‘z b’ (‘magit-stash-branch’)
+
+ Create and checkout a new BRANCH from STASH. The branch starts at
+ the commit that was current when the stash was created.
+
+‘z B’ (‘magit-stash-branch-here’)
+
+ Create and checkout a new BRANCH using ‘magit-branch’ with the
+ current branch or ‘HEAD’ as the starting-point. Then apply STASH,
+ dropping it if it applies cleanly.
+
+‘z f’ (‘magit-stash-format-patch’)
+
+ Create a patch from STASH.
+
+‘k’ (‘magit-stash-clear’)
+
+ Remove all stashes saved in REF’s reflog by deleting REF.
+
+‘z l’ (‘magit-stash-list’)
+
+ List all stashes in a buffer.
+
+ -- User Option: magit-stashes-margin
+
+ This option specifies whether the margin is initially shown in
+ stashes buffers and how it is formatted.
+
+ The value has the form ‘(INIT STYLE WIDTH AUTHOR AUTHOR-WIDTH)’.
+
+ • If INIT is non-nil, then the margin is shown initially.
+
+ • STYLE controls how to format the author or committer date. It
+ can be one of ‘age’ (to show the age of the commit),
+ ‘age-abbreviated’ (to abbreviate the time unit to a
+ character), or a string (suitable for ‘format-time-string’) to
+ show the actual date. Option
+ ‘magit-log-margin-show-committer-date’ controls which date is
+ being displayed.
+
+ • WIDTH controls the width of the margin. This exists for
+ forward compatibility and currently the value should not be
+ changed.
+
+ • AUTHOR controls whether the name of the author is also shown
+ by default.
+
+ • AUTHOR-WIDTH has to be an integer. When the name of the
+ author is shown, then this specifies how much space is used to
+ do so.
+
+\1f
+File: magit.info, Node: Transferring, Next: Miscellaneous, Prev: Manipulating, Up: Top
+
+7 Transferring
+**************
+
+* Menu:
+
+* Remotes::
+* Fetching::
+* Pulling::
+* Pushing::
+* Plain Patches::
+* Maildir Patches::
+
+\1f
+File: magit.info, Node: Remotes, Next: Fetching, Up: Transferring
+
+7.1 Remotes
+===========
+
+* Menu:
+
+* Remote Commands::
+* Remote Git Variables::
+
+\1f
+File: magit.info, Node: Remote Commands, Next: Remote Git Variables, Up: Remotes
+
+7.1.1 Remote Commands
+---------------------
+
+The transient prefix command ‘magit-remote’ is used to add remotes and
+to make changes to existing remotes. This command only deals with
+remotes themselves, not with branches or the transfer of commits. Those
+features are available from separate transient commands.
+
+ Also see *note (gitman)git-remote::.
+
+‘M’ (‘magit-remote’)
+
+ This transient prefix command binds the following suffix commands
+ and displays them in a temporary buffer until a suffix is invoked.
+
+ By default it also binds and displays the values of some
+ remote-related Git variables and allows changing their values.
+
+ -- User Option: magit-remote-direct-configure
+
+ This option controls whether remote-related Git variables are
+ accessible directly from the transient ‘magit-remote’.
+
+ If ‘t’ (the default) and a local branch is checked out, then
+ ‘magit-remote’ features the variables for the upstream remote of
+ that branch, or if ‘HEAD’ is detached, for ‘origin’, provided that
+ exists.
+
+ If ‘nil’, then ‘magit-remote-configure’ has to be used to do so.
+
+‘M C’ (‘magit-remote-configure’)
+
+ This transient prefix command binds commands that set the value of
+ remote-related variables and displays them in a temporary buffer
+ until the transient is exited.
+
+ With a prefix argument, this command always prompts for a remote.
+
+ Without a prefix argument this depends on whether it was invoked as
+ a suffix of ‘magit-remote’ and on the
+ ‘magit-remote-direct-configure’ option. If ‘magit-remote’ already
+ displays the variables for the upstream, then it does not make
+ sense to invoke another transient that displays them for the same
+ remote. In that case this command prompts for a remote.
+
+ The variables are described in *note Remote Git Variables::.
+
+‘M a’ (‘magit-remote-add’)
+
+ This command add a remote and fetches it. The remote name and url
+ are read in the minibuffer.
+
+‘M r’ (‘magit-remote-rename’)
+
+ This command renames a remote. Both the old and the new names are
+ read in the minibuffer.
+
+‘M u’ (‘magit-remote-set-url’)
+
+ This command changes the url of a remote. Both the remote and the
+ new url are read in the minibuffer.
+
+‘M k’ (‘magit-remote-remove’)
+
+ This command deletes a remote, read in the minibuffer.
+
+‘M p’ (‘magit-remote-prune’)
+
+ This command removes stale remote-tracking branches for a remote
+ read in the minibuffer.
+
+‘M P’ (‘magit-remote-prune-refspecs’)
+
+ This command removes stale refspecs for a remote read in the
+ minibuffer.
+
+ A refspec is stale if there no longer exists at least one branch on
+ the remote that would be fetched due to that refspec. A stale
+ refspec is problematic because its existence causes Git to refuse
+ to fetch according to the remaining non-stale refspecs.
+
+ If only stale refspecs remain, then this command offers to either
+ delete the remote or to replace the stale refspecs with the default
+ refspec ("+refs/heads/*:refs/remotes/REMOTE/*").
+
+ This command also removes the remote-tracking branches that were
+ created due to the now stale refspecs. Other stale branches are
+ not removed.
+
+ -- User Option: magit-remote-add-set-remote.pushDefault
+
+ This option controls whether the user is asked whether they want to
+ set ‘remote.pushDefault’ after adding a remote.
+
+ If ‘ask’, then users is always ask. If ‘ask-if-unset’, then the
+ user is only if the variable isn’t set already. If ‘nil’, then the
+ user isn’t asked and the variable isn’t set. If the value is a
+ string, then the variable is set without the user being asked,
+ provided that the name of the added remote is equal to that string
+ and the variable isn’t already set.
+
+\1f
+File: magit.info, Node: Remote Git Variables, Prev: Remote Commands, Up: Remotes
+
+7.1.2 Remote Git Variables
+--------------------------
+
+These variables can be set from the transient prefix command
+‘magit-remote-configure’. By default they can also be set from
+‘magit-remote’. See *note Remote Commands::.
+
+ -- Variable: remote.NAME.url
+
+ This variable specifies the url of the remote named NAME. It can
+ have multiple values.
+
+ -- Variable: remote.NAME.fetch
+
+ The refspec used when fetching from the remote named NAME. It can
+ have multiple values.
+
+ -- Variable: remote.NAME.pushurl
+
+ This variable specifies the url used for fetching from the remote
+ named NAME. If it is not specified, then ‘remote.NAME.url’ is used
+ instead. It can have multiple values.
+
+ -- Variable: remote.NAME.push
+
+ The refspec used when pushing to the remote named NAME. It can
+ have multiple values.
+
+ -- Variable: remote.NAME.tagOpts
+
+ This variable specifies what tags are fetched by default. If the
+ value is ‘--no-tags’ then no tags are fetched. If the value is
+ ‘--tags’, then all tags are fetched. If this variable has no
+ value, then only tags are fetched that are reachable from fetched
+ branches.
+
+\1f
+File: magit.info, Node: Fetching, Next: Pulling, Prev: Remotes, Up: Transferring
+
+7.2 Fetching
+============
+
+Also see *note (gitman)git-fetch::. For information about the upstream
+and the push-remote, see *note The Two Remotes::.
+
+‘f’ (‘magit-fetch’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+‘f p’ (‘magit-fetch-from-pushremote’)
+
+ This command fetches from the current push-remote.
+
+ With a prefix argument or when the push-remote is either not
+ configured or unusable, then let the user first configure the
+ push-remote.
+
+‘f u’ (‘magit-fetch-from-upstream’)
+
+ This command fetch from the upstream of the current branch.
+
+ If the upstream is configured for the current branch and names an
+ existing remote, then use that. Otherwise try to use another
+ remote: If only a single remote is configured, then use that.
+ Otherwise if a remote named "origin" exists, then use that.
+
+ If no remote can be determined, then this command is not available
+ from the ‘magit-fetch’ transient prefix and invoking it directly
+ results in an error.
+
+‘f e’ (‘magit-fetch-other’)
+
+ This command fetch from a repository read from the minibuffer.
+
+‘f o’ (‘magit-fetch-branch’)
+
+ This command fetches a branch from a remote, both of which are read
+ from the minibuffer.
+
+‘f r’ (‘magit-fetch-refspec’)
+
+ This command fetches from a remote using an explicit refspec, both
+ of which are read from the minibuffer.
+
+‘f a’ (‘magit-fetch-all’)
+
+ This command fetches from all remotes.
+
+‘f m’ (‘magit-submodule-fetch’)
+
+ This command fetches all submodules. With a prefix argument it
+ fetches all remotes of all submodules.
+
+ -- User Option: magit-pull-or-fetch
+
+ By default fetch and pull commands are available from separate
+ transient prefix command. Setting this to ‘t’ adds some (but not
+ all) of the above suffix commands to the ‘magit-pull’ transient.
+
+ If you do that, then you might also want to change the key binding
+ for these prefix commands, e.g.:
+
+ (setq magit-pull-or-fetch t)
+ (define-key magit-mode-map "f" 'magit-pull) ; was magit-fetch
+ (define-key magit-mode-map "F" nil) ; was magit-pull
+
+\1f
+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.
+
+\1f
+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.
+
+ 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.<branch>.pushRemote’,
+ ‘branch.<branch>.remote’, ‘branch.<branch>.merge’, and
+ ‘remote.<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.<branch>.pushRemote’,
+ ‘branch.<branch>.remote’, ‘branch.<branch>.merge’, and
+ ‘remote.<remote>.push’.
+
+\1f
+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.
+
+\1f
+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.
+
+\1f
+File: magit.info, Node: Miscellaneous, Next: Customizing, Prev: Transferring, Up: Top
+
+8 Miscellaneous
+***************
+
+* Menu:
+
+* Tagging::
+* Notes::
+* Submodules::
+* Subtree::
+* Worktree::
+* Common Commands::
+* Wip Modes::
+* Commands for Buffers Visiting Files::
+* Minor Mode for Buffers Visiting Blobs::
+
+\1f
+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 annotate 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.
+
+\1f
+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).
+
+\1f
+File: magit.info, Node: Submodules, Next: Subtree, Prev: Notes, Up: Miscellaneous
+
+8.3 Submodules
+==============
+
+Also see *note (gitman)git-submodule::.
+
+* Menu:
+
+* Listing Submodules::
+* Submodule Transient::
+
+\1f
+File: magit.info, Node: Listing Submodules, Next: Submodule Transient, Up: Submodules
+
+8.3.1 Listing Submodules
+------------------------
+
+The command ‘magit-list-submodules’ displays a list of the current
+repository’s submodules in a separate buffer. It’s also possible to
+display information about submodules directly in the status buffer of
+the super-repository by adding ‘magit-insert-modules’ to the hook
+‘magit-status-sections-hook’ as described in *note Status Module
+Sections::.
+
+ -- Command: magit-list-submodules
+
+ This command displays a list of the current repository’s submodules
+ in a separate buffer.
+
+ It can be invoked by pressing ‘RET’ on the section titled
+ "Modules".
+
+ -- User Option: magit-submodule-list-columns
+
+ This option controls what columns are displayed by the command
+ ‘magit-list-submodules’ and how they are displayed.
+
+ Each element has the form ‘(HEADER WIDTH FORMAT PROPS)’.
+
+ HEADER is the string displayed in the header. WIDTH is the width
+ of the column. FORMAT is a function that is called with one
+ argument, the repository identification (usually its basename), and
+ with ‘default-directory’ bound to the toplevel of its working tree.
+ It has to return a string to be inserted or nil. PROPS is an alist
+ that supports the keys ‘:right-align’ and ‘:pad-right’.
+
+\1f
+File: magit.info, Node: Submodule Transient, Prev: Listing Submodules, Up: Submodules
+
+8.3.2 Submodule Transient
+-------------------------
+
+‘o’ (‘magit-submodule’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+ Some of the below commands default to act on the modules that are
+selected using the region. For brevity their description talk about
+"the selected modules", but if no modules are selected, then they act on
+the current module instead, or if point isn’t on a module, then the read
+a single module to act on. With a prefix argument these commands ignore
+the selection and the current module and instead act on all suitable
+modules.
+
+‘o a’ (‘magit-submodule-add’)
+
+ This commands adds the repository at URL as a module. Optional
+ PATH is the path to the module relative to the root of the
+ super-project. If it is nil then the path is determined based on
+ URL.
+
+‘o r’ (‘magit-submodule-register’)
+
+ This command registers the selected modules by copying their urls
+ from ".gitmodules" to "$GIT_DIR/config". These values can then be
+ edited before running ‘magit-submodule-populate’. If you don’t
+ need to edit any urls, then use the latter directly.
+
+‘o p’ (‘magit-submodule-populate’)
+
+ This command creates the working directory or directories of the
+ selected modules, checking out the recorded commits.
+
+‘o u’ (‘magit-submodule-update’)
+
+ This command updates the selected modules checking out the recorded
+ commits.
+
+‘o s’ (‘magit-submodule-synchronize’)
+
+ This command synchronizes the urls of the selected modules, copying
+ the values from ".gitmodules" to the ".git/config" of the
+ super-project as well those of the modules.
+
+‘o d’ (‘magit-submodule-unpopulate’)
+
+ This command removes the working directory of the selected modules.
+
+‘o l’ (‘magit-list-submodules’)
+
+ This command displays a list of the current repository’s modules.
+
+‘o f’ (‘magit-fetch-modules’)
+
+ This command fetches all modules.
+
+ Option ‘magit-fetch-modules-jobs’ controls how many submodules are
+ being fetched in parallel. Also fetch the super-repository,
+ because ‘git fetch’ does not support not doing that. With a prefix
+ argument fetch all remotes.
+
+\1f
+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.
+
--- /dev/null
+This is magit.info, produced by makeinfo version 6.5 from magit.texi.
+
+ Copyright (C) 2015-2021 Jonas Bernoulli <jonasNOSPAMbernoul.li>
+
+ 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
+
+\1f
+File: magit.info, Node: Worktree, Next: Common Commands, Prev: Subtree, Up: Miscellaneous
+
+8.5 Worktree
+============
+
+Also see *note (gitman)git-worktree::.
+
+‘%’ (‘magit-worktree’)
+
+ This transient prefix command binds the following suffix commands
+ and displays them in a temporary buffer until a suffix is invoked.
+
+‘% b’ (‘magit-worktree-checkout’)
+
+ Checkout BRANCH in a new worktree at PATH.
+
+‘% c’ (‘magit-worktree-branch’)
+
+ Create a new BRANCH and check it out in a new worktree at PATH.
+
+‘% m’ (‘magit-worktree-move’)
+
+ Move an existing worktree to a new PATH.
+
+‘% k’ (‘magit-worktree-delete’)
+
+ Delete a worktree, defaulting to the worktree at point. The
+ primary worktree cannot be deleted.
+
+‘% g’ (‘magit-worktree-status’)
+
+ Show the status for the worktree at point.
+
+ If there is no worktree at point, then read one in the minibuffer.
+ If the worktree at point is the one whose status is already being
+ displayed in the current buffer, then show it in Dired instead.
+
+\1f
+File: magit.info, Node: Common Commands, Next: Wip Modes, Prev: Worktree, Up: Miscellaneous
+
+8.6 Common Commands
+===================
+
+These are some of the commands that can be used in all buffers whose
+major-modes derive from ‘magit-mode’. There are other common commands
+beside the ones below, but these didn’t fit well anywhere else.
+
+‘C-w’ (‘magit-copy-section-value’)
+
+ This command saves the value of the current section to the
+ ‘kill-ring’, and, provided that the current section is a commit,
+ branch, or tag section, it also pushes the (referenced) revision to
+ the ‘magit-revision-stack’.
+
+ When the current section is a branch or a tag, and a prefix
+ argument is used, then it saves the revision at its tip to the
+ ‘kill-ring’ instead of the reference name.
+
+ When the region is active, this command saves that to the
+ ‘kill-ring’, like ‘kill-ring-save’ would, instead of behaving as
+ described above. If a prefix argument is used and the region is
+ within a hunk, then it strips the diff marker column and keeps only
+ either the added or removed lines, depending on the sign of the
+ prefix argument.
+
+‘M-w’ (‘magit-copy-buffer-revision’)
+
+ This command saves the revision being displayed in the current
+ buffer to the ‘kill-ring’ and also pushes it to the
+ ‘magit-revision-stack’. It is mainly intended for use in
+ ‘magit-revision-mode’ buffers, the only buffers where it is always
+ unambiguous exactly which revision should be saved.
+
+ Most other Magit buffers usually show more than one revision, in
+ some way or another, so this command has to select one of them, and
+ that choice might not always be the one you think would have been
+ the best pick.
+
+ Outside of Magit ‘M-w’ and ‘C-w’ are usually bound to
+‘kill-ring-save’ and ‘kill-region’, and these commands would also be
+useful in Magit buffers. Therefore when the region is active, then both
+of these commands behave like ‘kill-ring-save’ instead of as described
+above.
+
+\1f
+File: magit.info, Node: Wip Modes, Next: Commands for Buffers Visiting Files, Prev: Common Commands, Up: Miscellaneous
+
+8.7 Wip Modes
+=============
+
+Git keeps *committed* changes around long enough for users to recover
+changes they have accidentally deleted. It does so by not garbage
+collecting any committed but no longer referenced objects for a certain
+period of time, by default 30 days.
+
+ But Git does *not* keep track of *uncommitted* changes in the working
+tree and not even the index (the staging area). Because Magit makes it
+so convenient to modify uncommitted changes, it also makes it easy to
+shoot yourself in the foot in the process.
+
+ For that reason Magit provides a global mode that saves *tracked*
+files to work-in-progress references after or before certain actions.
+(At present untracked files are never saved and for technical reasons
+nothing is saved before the first commit has been created).
+
+ Two separate work-in-progress references are used to track the state
+of the index and of the working tree: ‘refs/wip/index/<branchref>’ and
+‘refs/wip/wtree/<branchref>’, where ‘<branchref>’ 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 ‘<branchref>’.
+
+ Checking out another branch (or detaching ‘HEAD’) causes the use of
+different wip refs for subsequent changes.
+
+ -- User Option: magit-wip-mode
+
+ When this mode is enabled, then uncommitted changes are committed
+ to dedicated work-in-progress refs whenever appropriate (i.e. when
+ dataloss would be a possibility otherwise).
+
+ Setting this variable directly does not take effect; either use the
+ Custom interface to do so or call the respective mode function.
+
+ For historic reasons this mode is implemented on top of four other
+ ‘magit-wip-*’ modes, which can also be used individually, if you
+ want finer control over when the wip refs are updated; but that is
+ discouraged. See *note Legacy Wip Modes::.
+
+ To view the log for a branch and its wip refs use the commands
+‘magit-wip-log’ and ‘magit-wip-log-current’. You should use ‘--graph’
+when using these commands.
+
+ -- Command: magit-wip-log
+
+ This command shows the log for a branch and its wip refs. With a
+ negative prefix argument only the worktree wip ref is shown.
+
+ The absolute numeric value of the prefix argument controls how many
+ "branches" of each wip ref are shown. This is only relevant if the
+ value of ‘magit-wip-merge-branch’ is ‘nil’.
+
+ -- Command: magit-wip-log-current
+
+ This command shows the log for the current branch and its wip refs.
+ With a negative prefix argument only the worktree wip ref is shown.
+
+ The absolute numeric value of the prefix argument controls how many
+ "branches" of each wip ref are shown. This is only relevant if the
+ value of ‘magit-wip-merge-branch’ is ‘nil’.
+
+‘X w’ (‘magit-reset-worktree’)
+
+ This command resets the working tree to some commit read from the
+ user and defaulting to the commit at point, while keeping the
+ ‘HEAD’ and index as-is.
+
+ This can be used to restore files to the state committed to a wip
+ ref. Note that this will discard any unstaged changes that might
+ have existed before invoking this command (but of course only after
+ committing that to the working tree wip ref).
+
+ Note that even if you enable ‘magit-wip-mode’ this won’t give you
+perfect protection. The most likely scenario for losing changes despite
+the use of ‘magit-wip-mode’ is making a change outside Emacs and then
+destroying it also outside Emacs. In some such a scenario, Magit, being
+an Emacs package, didn’t get the opportunity to keep you from shooting
+yourself in the foot.
+
+ When you are unsure whether Magit did commit a change to the wip
+refs, then you can explicitly request that all changes to all tracked
+files are being committed.
+
+‘M-x magit-wip-commit’ (‘magit-wip-commit’)
+
+ This command commits all changes to all tracked files to the index
+ and working tree work-in-progress refs. Like the modes described
+ above, it does not commit untracked files, but it does check all
+ tracked files for changes. Use this command when you suspect that
+ the modes might have overlooked a change made outside Emacs/Magit.
+
+ -- User Option: magit-wip-namespace
+
+ The namespace used for work-in-progress refs. It has to end with a
+ slash. The wip refs are named ‘<namespace>index/<branchref>’ and
+ ‘<namespace>wtree/<branchref>’. When snapshots are created while
+ the ‘HEAD’ is detached then ‘HEAD’ is used in place of
+ ‘<branchref>’.
+
+ -- User Option: magit-wip-mode-lighter
+
+ Mode-line lighter for ‘magit-wip--mode’.
+
+* Menu:
+
+* Wip Graph::
+* Legacy Wip Modes::
+
+\1f
+File: magit.info, Node: Wip Graph, Next: Legacy Wip Modes, Up: Wip Modes
+
+8.7.1 Wip Graph
+---------------
+
+ -- User Option: magit-wip-merge-branch
+
+ This option controls whether the current branch is merged into the
+ wip refs after a new commit was created on the branch.
+
+ If non-nil and the current branch has new commits, then it is
+ merged into the wip ref before creating a new wip commit. This
+ makes it easier to inspect wip history and the wip commits are
+ never garbage collected.
+
+ If nil and the current branch has new commits, then the wip ref is
+ reset to the tip of the branch before creating a new wip commit.
+ With this setting wip commits are eventually garbage collected.
+
+ When ‘magit-wip-merge-branch’ is ‘t’, then the history looks like
+this:
+
+ *--*--*--*--*--* refs/wip/index/refs/heads/master
+ / / /
+ A-----B-----C refs/heads/master
+
+ When ‘magit-wip-merge-branch’ is ‘nil’, then creating a commit on the
+real branch and then making a change causes the wip refs to be recreated
+to fork from the new commit. But the old commits on the wip refs are
+not lost. They are still available from the reflog. To make it easier
+to see when the fork point of a wip ref was changed, an additional
+commit with the message "restart autosaving" is created on it (‘xxO’
+commits below are such boundary commits).
+
+ Starting with
+
+ BI0---BI1 refs/wip/index/refs/heads/master
+ /
+ A---B refs/heads/master
+ \
+ BW0---BW1 refs/wip/wtree/refs/heads/master
+
+ and committing the staged changes and editing and saving a file would
+result in
+
+ BI0---BI1 refs/wip/index/refs/heads/master
+ /
+ A---B---C refs/heads/master
+ \ \
+ \ CW0---CW1 refs/wip/wtree/refs/heads/master
+ \
+ BW0---BW1 refs/wip/wtree/refs/heads/master@{2}
+
+ The fork-point of the index wip ref is not changed until some change
+is being staged. Likewise just checking out a branch or creating a
+commit does not change the fork-point of the working tree wip ref. The
+fork-points are not adjusted until there actually is a change that
+should be committed to the respective wip ref.
+
+\1f
+File: magit.info, Node: Legacy Wip Modes, Prev: Wip Graph, Up: Wip Modes
+
+8.7.2 Legacy Wip Modes
+----------------------
+
+It is recommended that you use the mode ‘magit-wip-mode’ (which see) and
+ignore the existence of the following modes, which are preserved for
+historic reasons.
+
+ Setting the following variables directly does not take effect; either
+use the Custom interface to do so or call the respective mode functions.
+
+ -- User Option: magit-wip-after-save-mode
+
+ When this mode is enabled, then saving a buffer that visits a file
+ tracked in a Git repository causes its current state to be
+ committed to the working tree wip ref for the current branch.
+
+ -- User Option: magit-wip-after-apply-mode
+
+ When this mode is enabled, then applying (i.e. staging, unstaging,
+ discarding, reversing, and regularly applying) a change to a file
+ tracked in a Git repository causes its current state to be
+ committed to the index and/or working tree wip refs for the current
+ branch.
+
+ If you only ever edit files using Emacs and only ever interact with
+Git using Magit, then the above two modes should be enough to protect
+each and every change from accidental loss. In practice nobody does
+that. Two additional modes exists that do commit to the wip refs before
+making changes that could cause the loss of earlier changes.
+
+ -- User Option: magit-wip-before-change-mode
+
+ When this mode is enabled, then certain commands commit the
+ existing changes to the files they are about to make changes to.
+
+ -- User Option: magit-wip-initial-backup-mode
+
+ When this mode is enabled, then the current version of a file is
+ committed to the worktree wip ref before the buffer visiting that
+ file is saved for the first time since the buffer was created.
+
+ This backs up the same version of the file that ‘backup-buffer’
+ would save. While ‘backup-buffer’ uses a backup file, this mode
+ uses the same worktree wip ref as used by the other Magit Wip
+ modes. Like ‘backup-buffer’, it only does this once; unless you
+ kill the buffer and visit the file again only one backup will be
+ created per Emacs session.
+
+ This mode ignores the variables that affect ‘backup-buffer’ and can
+ be used along-side that function, which is recommended because it
+ only backs up files that are tracked in a Git repository.
+
+ -- User Option: magit-wip-after-save-local-mode-lighter
+
+ Mode-line lighter for ‘magit-wip-after-save-local-mode’.
+
+ -- User Option: magit-wip-after-apply-mode-lighter
+
+ Mode-line lighter for ‘magit-wip-after-apply-mode’.
+
+ -- User Option: magit-wip-before-change-mode-lighter
+
+ Mode-line lighter for ‘magit-wip-before-change-mode’.
+
+ -- User Option: magit-wip-initial-backup-mode-lighter
+
+ Mode-line lighter for ‘magit-wip-initial-backup-mode’.
+
+\1f
+File: magit.info, Node: Commands for Buffers Visiting Files, Next: Minor Mode for Buffers Visiting Blobs, Prev: Wip Modes, Up: Miscellaneous
+
+8.8 Commands for Buffers Visiting Files
+=======================================
+
+Magit defines a few global key bindings unless the user sets
+‘magit-define-global-key-bindings’ to ‘nil’. This includes binding ‘C-c
+M-g’ to ‘magit-file-dispatch’. ‘C-c g’ would be a much better binding
+but the ‘C-c <letter>’ namespace is reserved for users, meaning that
+packages are not allowed to use it. If you want to use ‘C-c g’, then
+you have to add that binding yourself. Also see *note Default
+Bindings:: and *note (elisp)Key Binding Conventions::.
+
+ If you want a better binding, you have to add it yourself:
+
+ (global-set-key (kbd "C-c g") 'magit-file-dispatch)
+
+ The key bindings shown below assume that you have not improved the
+binding for ‘magit-file-dispatch’.
+
+‘C-c M-g’ (‘magit-file-dispatch’)
+
+ This transient prefix command binds the following suffix commands
+ and displays them in a temporary buffer until a suffix is invoked.
+
+ When invoked in a buffer that does not visit a file, then it falls
+ back to regular ‘magit-dispatch’.
+
+‘C-c M-g s’ (‘magit-stage-file’)
+
+ Stage all changes to the file being visited in the current buffer.
+
+‘C-c M-g u’ (‘magit-unstage-file’)
+
+ Unstage all changes to the file being visited in the current
+ buffer.
+
+‘C-c M-g c’ (‘magit-commit’)
+
+ This transient prefix command binds the following suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked. See *note Initiating a
+ Commit::.
+
+‘C-c M-g D’ (‘magit-diff’)
+
+ This transient prefix command binds several diff suffix commands
+ and infix arguments and displays them in a temporary buffer until a
+ suffix is invoked. See *note Diffing::.
+
+ This is the same command that ‘d’ is bound to in Magit buffers. If
+ this command is invoked from a file-visiting buffer, then the
+ initial value of the option (‘--’) that limits the diff to certain
+ file(s) is set to the visited file.
+
+‘C-c M-g d’ (‘magit-diff-buffer-file’)
+
+ This command shows the diff for the file of blob that the current
+ buffer visits.
+
+ -- User Option: magit-diff-buffer-file-locked
+
+ This option controls whether ‘magit-diff-buffer-file’ uses a
+ dedicated buffer. See *note Modes and Buffers::.
+
+‘C-c M-g L’ (‘magit-log’)
+
+ This transient prefix command binds several log suffix commands and
+ infix arguments and displays them in a temporary buffer until a
+ suffix is invoked. See *note Logging::.
+
+ This is the same command that ‘l’ is bound to in Magit buffers. If
+ this command is invoked from a file-visiting buffer, then the
+ initial value of the option (‘--’) that limits the log to certain
+ file(s) is set to the visited file.
+
+‘C-c M-g l’ (‘magit-log-buffer-file’)
+
+ This command shows the log for the file of blob that the current
+ buffer visits. Renames are followed when a prefix argument is used
+ or when ‘--follow’ is an active log argument. When the region is
+ active, the log is restricted to the selected line range.
+
+‘C-c M-g t’ (‘magit-log-trace-definition’)
+
+ This command shows the log for the definition at point.
+
+ -- User Option: magit-log-buffer-file-locked
+
+ This option controls whether ‘magit-log-buffer-file’ uses a
+ dedicated buffer. See *note Modes and Buffers::.
+
+‘C-c M-g B’ (‘magit-blame’)
+
+ This transient prefix command binds all blaming suffix commands
+ along with the appropriate infix arguments and displays them in a
+ temporary buffer until a suffix is invoked.
+
+ For more information about this and the following commands also see
+ *note Blaming::.
+
+ In addition to the ‘magit-blame’ sub-transient, the dispatch
+transient also binds several blaming suffix commands directly. See
+*note Blaming:: for information about those commands and bindings.
+
+‘C-c M-g e’ (‘magit-edit-line-commit’)
+
+ This command makes the commit editable that added the current line.
+
+ With a prefix argument it makes the commit editable that removes
+ the line, if any. The commit is determined using ‘git blame’ and
+ made editable using ‘git rebase --interactive’ if it is reachable
+ from ‘HEAD’, or by checking out the commit (or a branch that points
+ at it) otherwise.
+
+‘C-c M-g p’ (‘magit-blob-previous’)
+
+ Visit the previous blob which modified the current file.
+
+ There are a few additional commands that operate on a single file but
+are not enabled in the file transient command by default:
+
+ -- Command: magit-file-rename
+
+ This command renames a file read from the user.
+
+ -- Command: magit-file-delete
+
+ This command deletes a file read from the user.
+
+ -- Command: magit-file-untrack
+
+ This command untracks a file read from the user.
+
+ -- Command: magit-file-checkout
+
+ This command updates a file in the working tree and index to the
+ contents from a revision. Both the revision and file are read from
+ the user.
+
+ To enable them invoke the transient (‘C-c M-g’), enter "edit mode"
+(‘C-x l’), set the "transient level" (‘C-x l’ again), enter ‘5’, and
+leave edit mode (‘C-g’). Also see *note (transient)Enabling and
+Disabling Suffixes::.
+
+\1f
+File: magit.info, Node: Minor Mode for Buffers Visiting Blobs, Prev: Commands for Buffers Visiting Files, Up: Miscellaneous
+
+8.9 Minor Mode for Buffers Visiting Blobs
+=========================================
+
+The ‘magit-blob-mode’ enables certain Magit features in blob-visiting
+buffers. Such buffers can be created using ‘magit-find-file’ and some
+of the commands mentioned below, which also take care of turning on this
+minor mode. Currently this mode only establishes a few key bindings,
+but this might be extended.
+
+‘p’ (‘magit-blob-previous’)
+
+ Visit the previous blob which modified the current file.
+
+‘n’ (‘magit-blob-next’)
+
+ Visit the next blob which modified the current file.
+
+‘q’ (‘magit-kill-this-buffer’)
+
+ Kill the current buffer.
+
+\1f
+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::
+
+\1f
+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)
+
+\1f
+File: magit.info, Node: Essential Settings, Prev: Per-Repository Configuration, Up: Customizing
+
+9.2 Essential Settings
+======================
+
+The next two sections list and discuss several variables that many users
+might want to customize, for safety and/or performance reasons.
+
+* Menu:
+
+* Safety::
+* Performance::
+* Default Bindings::
+
+\1f
+File: magit.info, Node: Safety, Next: Performance, Up: Essential Settings
+
+9.2.1 Safety
+------------
+
+This section discusses various variables that you might want to change
+(or *not* change) for safety reasons.
+
+ Git keeps *committed* changes around long enough for users to recover
+changes they have accidentally been deleted. It does not do the same
+for *uncommitted* changes in the working tree and not even the index
+(the staging area). Because Magit makes it so easy to modify
+uncommitted changes, it also makes it easy to shoot yourself in the foot
+in the process. For that reason Magit provides three global modes that
+save *tracked* files to work-in-progress references after or before
+certain actions. See *note Wip Modes::.
+
+ These modes are not enabled by default because of performance
+concerns. Instead a lot of potentially destructive commands require
+confirmation every time they are used. In many cases this can be
+disabled by adding a symbol to ‘magit-no-confirm’ (see *note Completion
+and Confirmation::). If you enable the various wip modes then you
+should add ‘safe-with-wip’ to this list.
+
+ Similarly it isn’t necessary to require confirmation before moving a
+file to the system trash - if you trashed a file by mistake then you can
+recover it from there. Option ‘magit-delete-by-moving-to-trash’
+controls whether the system trash is used, which is the case by default.
+Nevertheless, ‘trash’ isn’t a member of ‘magit-no-confirm’ - you might
+want to change that.
+
+ By default buffers visiting files are automatically reverted when the
+visited file changes on disk. This isn’t as risky as it might seem, but
+to make an informed decision you should see *note Risk of Reverting
+Automatically::.
+
+\1f
+File: magit.info, Node: Performance, Next: Default Bindings, Prev: Safety, Up: Essential Settings
+
+9.2.2 Performance
+-----------------
+
+After Magit has run ‘git’ for side-effects, it also refreshes the
+current Magit buffer and the respective status buffer. This is
+necessary because otherwise outdated information might be displayed
+without the user noticing. Magit buffers are updated by recreating
+their content from scratch, which makes updating simpler and less
+error-prone, but also more costly. Keeping it simple and just
+re-creating everything from scratch is an old design decision and
+departing from that will require major refactoring.
+
+ I plan to do that in time for the next major release. I also intend
+to create logs and diffs asynchronously, which should also help a lot
+but also requires major refactoring.
+
+ Meanwhile you can tell Magit to only automatically refresh the
+current Magit buffer, but not the status buffer. If you do that, then
+the status buffer is only refreshed automatically if it is the current
+buffer.
+
+ (setq magit-refresh-status-buffer nil)
+
+ You should also check whether any third-party packages have added
+anything to ‘magit-refresh-buffer-hook’, ‘magit-status-refresh-hook’,
+‘magit-pre-refresh-hook’, and ‘magit-post-refresh-hook’. If so, then
+check whether those additions impact performance significantly.
+
+ Magit can be told to refresh buffers verbosely using ‘M-x
+magit-toggle-verbose-refresh’. Enabling this helps figuring out which
+sections are bottlenecks. The additional output can be found in the
+‘*Messages*’ buffer.
+
+ Magit also reverts buffers for visited files located inside the
+current repository when the visited file changes on disk. That is
+implemented on top of ‘auto-revert-mode’ from the built-in library
+‘autorevert’. To figure out whether that impacts performance, check
+whether performance is significantly worse, when many buffers exist
+and/or when some buffers visit files using TRAMP. If so, then this
+should help.
+
+ (setq auto-revert-buffer-list-filter
+ 'magit-auto-revert-repository-buffer-p)
+
+ For alternative approaches see *note Automatic Reverting of
+File-Visiting Buffers::.
+
+ If you have enabled any features that are disabled by default, then
+you should check whether they impact performance significantly. It’s
+likely that they were not enabled by default because it is known that
+they reduce performance at least in large repositories.
+
+ If performance is only slow inside certain unusually large
+repositories, then you might want to disable certain features on a
+per-repository or per-repository-class basis only. See *note
+Per-Repository Configuration::. For example it takes a long time to
+determine the next and current tag in repository with exceptional
+numbers of tags. It would therefore be a good idea to disable
+‘magit-insert-tags-headers’, as explained at the mentioned node.
+
+* Menu:
+
+* Microsoft Windows Performance::
+* MacOS Performance::
+
+Log Performance
+...............
+
+When showing logs, Magit limits the number of commits initially shown in
+the hope that this avoids unnecessary work. When using ‘--graph’ is
+used, then this unfortunately does not have the desired effect for large
+histories. Junio, Git’s maintainer, said on the git mailing list
+(<http://www.spinics.net/lists/git/msg232230.html>): "‘--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 ‘-<N>’ but by also using a range. But unfortunately
+that’s not always possible.
+
+ When more than a few thousand commits are shown, then the use of
+‘--graph’ can slow things down.
+
+ Using ‘--color --graph’ is even slower. Magit uses code that is part
+of Emacs to turn control characters into faces. That code is pretty
+slow and this is quite noticeable when showing a log with many branches
+and merges. For that reason ‘--color’ is not enabled by default
+anymore. Consider leaving it at that.
+
+Diff Performance
+................
+
+If diffs are slow, then consider turning off some optional diff features
+by setting all or some of the following variables to ‘nil’:
+‘magit-diff-highlight-indentation’, ‘magit-diff-highlight-trailing’,
+‘magit-diff-paint-whitespace’, ‘magit-diff-highlight-hunk-body’, and
+‘magit-diff-refine-hunk’.
+
+ When showing a commit instead of some arbitrary diff, then some
+additional information is displayed. Calculating this information can
+be quite expensive given certain circumstances. If looking at a commit
+using ‘magit-revision-mode’ takes considerably more time than looking at
+the same commit in ‘magit-diff-mode’, then consider setting
+‘magit-revision-insert-related-refs’ to ‘nil’.
+
+ When you are often confronted with diffs that contain deleted files,
+then you might want to enable the ‘--irreversible-delete’ argument. If
+you do that then diffs still show that a file was deleted but without
+also showing the complete deleted content of the file. This argument is
+not available by default, see *note (transient)Enabling and Disabling
+Suffixes::. Once you have done that you should enable it and save that
+setting, see *note (transient)Saving Values::. You should do this in
+both the diff (‘d’) and the diff refresh (‘D’) transient popups.
+
+Refs Buffer Performance
+.......................
+
+When refreshing the "references buffer" is slow, then that’s usually
+because several hundred refs are being displayed. The best way to
+address that is to display fewer refs, obviously.
+
+ If you are not, or only mildly, interested in seeing the list of
+tags, then start by not displaying them:
+
+ (remove-hook 'magit-refs-sections-hook 'magit-insert-tags)
+
+ Then you should also make sure that the listed remote branches
+actually all exist. You can do so by pruning branches which no longer
+exist using ‘f-pa’.
+
+Committing Performance
+......................
+
+When you initiate a commit, then Magit by default automatically shows a
+diff of the changes you are about to commit. For large commits this can
+take a long time, which is especially distracting when you are
+committing large amounts of generated data which you don’t actually
+intend to inspect before committing. This behavior can be turned off
+using:
+
+ (remove-hook 'server-switch-hook 'magit-commit-diff)
+
+ Then you can type ‘C-c C-d’ to show the diff when you actually want
+to see it, but only then. Alternatively you can leave the hook alone
+and just type ‘C-g’ in those cases when it takes too long to generate
+the diff. If you do that, then you will end up with a broken diff
+buffer, but doing it this way has the advantage that you usually get to
+see the diff, which is useful because it increases the odds that you
+spot potential issues.
+
+\1f
+File: magit.info, Node: Microsoft Windows Performance, Next: MacOS Performance, Up: Performance
+
+Microsoft Windows Performance
+.............................
+
+In order to update the status buffer, ‘git’ has to be run a few dozen
+times. That is problematic on Microsoft Windows, because that operating
+system is exceptionally slow at starting processes. Sadly this is an
+issue that can only be fixed by Microsoft itself, and they don’t appear
+to be particularly interested in doing so.
+
+ Beside the subprocess issue, there are also other Windows-specific
+performance issues. Some of these have workarounds. The maintainers of
+"Git for Windows" try to improve performance on Windows. Always use the
+latest release in order to benefit from the latest performance tweaks.
+Magit too tries to work around some Windows-specific issues.
+
+ According to some sources, setting the following Git variables can
+also help.
+
+ git config --global core.preloadindex true # default since v2.1
+ git config --global core.fscache true # default since v2.8
+ git config --global gc.auto 256
+
+ You should also check whether an anti-virus program is affecting
+performance.
+
+\1f
+File: magit.info, Node: MacOS Performance, Prev: Microsoft Windows Performance, Up: Performance
+
+MacOS Performance
+.................
+
+Before Emacs 26.1 child processes were created using ‘fork’ on macOS.
+That needlessly copied GUI resources, which is expensive. The result
+was that forking took about 30 times as long on Darwin than on Linux,
+and because Magit starts many ‘git’ processes that made quite a
+difference.
+
+ So make sure that you are using at least Emacs 26.1, in which case
+the faster ‘vfork’ will be used. (The creation of child processes still
+takes about twice as long on Darwin compared to Linux.) See (1) for
+more information.
+
+ On Catalina, and potentially other macOS releases, there may be a
+performance problem where any action takes 20 times longer on Darwin
+than on Linux. This can be worked around by setting
+‘magit-git-executable’ to the absolute path of the ‘git’ executable,
+instead of relying on resolving the ‘$PATH’. You should not do that if
+you want to use Magit on remote machines using Tramp and if ‘git’ is not
+installed in the same location on those machines.
+
+ ---------- Footnotes ----------
+
+ (1)
+<https://lists.gnu.org/archive/html/bug-gnu-emacs/2017-04/msg00201.html>
+
+\1f
+File: magit.info, Node: Default Bindings, Prev: Performance, Up: Essential Settings
+
+9.2.3 Default Bindings
+----------------------
+
+ -- User Option: magit-define-global-key-bindings
+
+ This option controls whether some Magit commands are automatically
+ bound in the global keymap even before Magit is used for the first
+ time in the current session.
+
+ If this variable is non-nil, which it is by default, then the
+ following bindings may be added to the global keymap.
+
+ ‘C-x g’ ‘magit-status’
+ ‘C-x M-g’ ‘magit-dispatch’
+ ‘C-c M-g’ ‘magit-file-dispatch’
+
+ These bindings may be added when ‘after-init-hook’ is called. Each
+ binding is added if and only if at that time no other key is bound
+ to the same command and no other command is bound to the same key.
+ In other words we try to avoid adding bindings that are
+ unnecessary, as well as bindings that conflict with other bindings.
+
+ Adding the above bindings is delayed until ‘after-init-hook’ is
+ called to allow users to set the variable anywhere in their init
+ file (without having to make sure to do so before ‘magit’ is loaded
+ or autoloaded) and to increase the likelihood that all the
+ potentially conflicting user bindings have already been added.
+
+ Setting this variable after the hook has already been called has no
+ effect.
+
+ We recommend that you bind ‘C-c g’ instead of ‘C-c M-g’ to
+ ‘magit-file-dispatch’. The former is a much better binding but the
+ ‘C-c <letter>’ namespace is strictly reserved for users; preventing
+ Magit from using it by default.
+
+ (global-set-key (kbd "C-c g") 'magit-file-dispatch)
+
+ Also see *note Commands for Buffers Visiting Files:: and *note
+ (elisp)Key Binding Conventions::.
+
+\1f
+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
+<https://github.com/magit/magit/wiki/Plugin-Dispatch-Key-Registry>.
+
+* Menu:
+
+* Calling Git::
+* Section Plumbing::
+* Refreshing Buffers::
+* Conventions::
+
+\1f
+File: magit.info, Node: Calling Git, Next: Section Plumbing, Up: Plumbing
+
+10.1 Calling Git
+================
+
+Magit provides many specialized functions for calling Git. All of these
+functions are defined in either ‘magit-git.el’ or ‘magit-process.el’ and
+have one of the prefixes ‘magit-run-’, ‘magit-call-’, ‘magit-start-’, or
+‘magit-git-’ (which is also used for other things).
+
+ All of these functions accept an indefinite number of arguments,
+which are strings that specify command line arguments for Git (or in
+some cases an arbitrary executable). These arguments are flattened
+before being passed on to the executable; so instead of strings they can
+also be lists of strings and arguments that are ‘nil’ are silently
+dropped. Some of these functions also require a single mandatory
+argument before these command line arguments.
+
+ Roughly speaking, these functions run Git either to get some value or
+for side-effects. The functions that return a value are useful to
+collect the information necessary to populate a Magit buffer, while the
+others are used to implement Magit commands.
+
+ The functions in the value-only group always run synchronously, and
+they never trigger a refresh. The function in the side-effect group can
+be further divided into subgroups depending on whether they run Git
+synchronously or asynchronously, and depending on whether they trigger a
+refresh when the executable has finished.
+
+* Menu:
+
+* Getting a Value from Git::
+* Calling Git for Effect::
+
+\1f
+File: magit.info, Node: Getting a Value from Git, Next: Calling Git for Effect, Up: Calling Git
+
+10.1.1 Getting a Value from Git
+-------------------------------
+
+These functions run Git in order to get a value, an exit status, or
+output. Of course you could also use them to run Git commands that have
+side-effects, but that should be avoided.
+
+ -- Function: magit-git-exit-code &rest args
+
+ Executes git with ARGS and returns its exit code.
+
+ -- Function: magit-git-success &rest args
+
+ Executes git with ARGS and returns ‘t’ if the exit code is ‘0’,
+ ‘nil’ otherwise.
+
+ -- Function: magit-git-failure &rest args
+
+ Executes git with ARGS and returns ‘t’ if the exit code is ‘1’,
+ ‘nil’ otherwise.
+
+ -- Function: magit-git-true &rest args
+
+ Executes git with ARGS and returns ‘t’ if the first line printed by
+ git is the string "true", ‘nil’ otherwise.
+
+ -- Function: magit-git-false &rest args
+
+ Executes git with ARGS and returns ‘t’ if the first line printed by
+ git is the string "false", ‘nil’ otherwise.
+
+ -- Function: magit-git-insert &rest args
+
+ Executes git with ARGS and inserts its output at point.
+
+ -- Function: magit-git-string &rest args
+
+ Executes git with ARGS and returns the first line of its output.
+ If there is no output or if it begins with a newline character,
+ then this returns ‘nil’.
+
+ -- Function: magit-git-lines &rest args
+
+ Executes git with ARGS and returns its output as a list of lines.
+ Empty lines anywhere in the output are omitted.
+
+ -- Function: magit-git-items &rest args
+
+ Executes git with ARGS and returns its null-separated output as a
+ list. Empty items anywhere in the output are omitted.
+
+ If the value of option ‘magit-git-debug’ is non-nil and git exits
+ with a non-zero exit status, then warn about that in the echo area
+ and add a section containing git’s standard error in the current
+ repository’s process buffer.
+
+ 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.
+
+\1f
+File: magit.info, Node: Calling Git for Effect, Prev: Getting a Value from Git, Up: Calling Git
+
+10.1.2 Calling Git for Effect
+-----------------------------
+
+These functions are used to run git to produce some effect. Most Magit
+commands that actually run git do so by using such a function.
+
+ Because we do not need to consume git’s output when using these
+functions, their output is instead logged into a per-repository buffer,
+which can be shown using ‘$’ from a Magit buffer or ‘M-x magit-process’
+elsewhere.
+
+ These functions can have an effect in two distinct ways. Firstly,
+running git may change something, i.e. create or push a new commit.
+Secondly, that change may require that Magit buffers are refreshed to
+reflect the changed state of the repository. But refreshing isn’t
+always desirable, so only some of these functions do perform such a
+refresh after git has returned.
+
+ Sometimes it is useful to run git asynchronously. For example, when
+the user has just initiated a push, then there is no reason to make her
+wait until that has completed. In other cases it makes sense to wait
+for git to complete before letting the user do something else. For
+example after staging a change it is useful to wait until after the
+refresh because that also automatically moves to the next change.
+
+ -- Function: magit-call-git &rest args
+
+ Calls git synchronously with ARGS.
+
+ -- Function: magit-call-process program &rest args
+
+ Calls PROGRAM synchronously with ARGS.
+
+ -- Function: magit-run-git &rest args
+
+ Calls git synchronously with ARGS and then refreshes.
+
+ -- Function: magit-run-git-with-input &rest args
+
+ Calls git synchronously with ARGS and sends it the content of the
+ current buffer on standard input.
+
+ If the current buffer’s ‘default-directory’ is on a remote
+ filesystem, this function actually runs git asynchronously. But
+ then it waits for the process to return, so the function itself is
+ synchronous.
+
+ -- Function: magit-run-git-with-logfile file &rest args
+
+ Calls git synchronously with ARGS. The process’s output is saved
+ in FILE. This is rarely useful and so this function might be
+ removed in the future.
+
+ This function actually runs git asynchronously. But then it waits
+ for the process to return, so the function itself is synchronous.
+
+ -- 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.
+
+\1f
+File: magit.info, Node: Section Plumbing, Next: Refreshing Buffers, Prev: Calling Git, Up: Plumbing
+
+10.2 Section Plumbing
+=====================
+
+* Menu:
+
+* Creating Sections::
+* Section Selection::
+* Matching Sections::
+
+\1f
+File: magit.info, Node: Creating Sections, Next: Section Selection, Up: Section Plumbing
+
+10.2.1 Creating Sections
+------------------------
+
+ -- Macro: magit-insert-section &rest args
+
+ Insert a section at point.
+
+ TYPE is the section type, a symbol. Many commands that act on the
+ current section behave differently depending on that type. Also if
+ a variable ‘magit-TYPE-section-map’ exists, then use that as the
+ text-property ‘keymap’ of all text belonging to the section (but
+ this may be overwritten in subsections). TYPE can also have the
+ form ‘(eval FORM)’ in which case FORM is evaluated at runtime.
+
+ Optional VALUE is the value of the section, usually a string that
+ is required when acting on the section.
+
+ When optional HIDE is non-nil collapse the section body by default,
+ i.e. when first creating the section, but not when refreshing the
+ buffer. Otherwise, expand it by default. This can be overwritten
+ using ‘magit-section-set-visibility-hook’. When a section is
+ recreated during a refresh, then the visibility of predecessor is
+ inherited and HIDE is ignored (but the hook is still honored).
+
+ BODY is any number of forms that actually insert the section’s
+ heading and body. Optional NAME, if specified, has to be a symbol,
+ which is then bound to the struct of the section being inserted.
+
+ Before BODY is evaluated the ‘start’ of the section object is set
+ to the value of ‘point’ and after BODY was evaluated its ‘end’ is
+ set to the new value of ‘point’; BODY is responsible for moving
+ ‘point’ forward.
+
+ If it turns out inside BODY that the section is empty, then
+ ‘magit-cancel-section’ can be used to abort and remove all traces
+ of the partially inserted section. This can happen when creating a
+ section by washing Git’s output and Git didn’t actually output
+ anything this time around.
+
+ -- Function: magit-insert-heading &rest args
+
+ Insert the heading for the section currently being inserted.
+
+ This function should only be used inside ‘magit-insert-section’.
+
+ When called without any arguments, then just set the ‘content’ slot
+ of the object representing the section being inserted to a marker
+ at ‘point’. The section should only contain a single line when
+ this function is used like this.
+
+ When called with arguments ARGS, which have to be strings, then
+ insert those strings at point. The section should not contain any
+ text before this happens and afterwards it should again only
+ contain a single line. If the ‘face’ property is set anywhere
+ inside any of these strings, then insert all of them unchanged.
+ Otherwise use the ‘magit-section-heading’ face for all inserted
+ text.
+
+ The ‘content’ property of the section struct is the end of the
+ heading (which lasts from ‘start’ to ‘content’) and the beginning
+ of the body (which lasts from ‘content’ to ‘end’). If the value of
+ ‘content’ is nil, then the section has no heading and its body
+ cannot be collapsed. If a section does have a heading then its
+ height must be exactly one line, including a trailing newline
+ character. This isn’t enforced; you are responsible for getting it
+ right. The only exception is that this function does insert a
+ newline character if necessary.
+
+ -- Function: magit-cancel-section
+
+ Cancel the section currently being inserted. This exits the
+ innermost call to ‘magit-insert-section’ and removes all traces of
+ what has already happened inside that call.
+
+ -- Function: magit-define-section-jumper sym title &optional value
+
+ Define an interactive function to go to section SYM. TITLE is the
+ displayed title of the section.
+
+\1f
+File: magit.info, Node: Section Selection, Next: Matching Sections, Prev: Creating Sections, Up: Section Plumbing
+
+10.2.2 Section Selection
+------------------------
+
+ -- Function: magit-current-section
+
+ Return the section at point.
+
+ -- Function: magit-region-sections &optional condition multiple
+
+ Return a list of the selected sections.
+
+ When the region is active and constitutes a valid section
+ selection, then return a list of all selected sections. This is
+ the case when the region begins in the heading of a section and
+ ends in the heading of the same section or in that of a sibling
+ section. If optional MULTIPLE is non-nil, then the region cannot
+ begin and end in the same section.
+
+ When the selection is not valid, then return nil. In this case,
+ most commands that can act on the selected sections will instead
+ act on the section at point.
+
+ When the region looks like it would in any other buffer then the
+ selection is invalid. When the selection is valid then the region
+ uses the ‘magit-section-highlight’ face. This does not apply to
+ diffs where things get a bit more complicated, but even here if the
+ region looks like it usually does, then that’s not a valid
+ selection as far as this function is concerned.
+
+ If optional CONDITION is non-nil, then the selection not only has
+ to be valid; all selected sections additionally have to match
+ CONDITION, or nil is returned. See ‘magit-section-match’ for the
+ forms CONDITION can take.
+
+ -- Function: magit-region-values &optional condition multiple
+
+ Return a list of the values of the selected sections.
+
+ Return the values that themselves would be returned by
+ ‘magit-region-sections’ (which see).
+
+\1f
+File: magit.info, Node: Matching Sections, Prev: Section Selection, Up: Section Plumbing
+
+10.2.3 Matching Sections
+------------------------
+
+‘M-x magit-describe-section-briefly’ (‘magit-describe-section-briefly’)
+
+ Show information about the section at point. This command is
+ intended for debugging purposes.
+
+ -- Function: magit-section-ident section
+
+ Return an unique identifier for SECTION. The return value has the
+ form ‘((TYPE . VALUE)...)’.
+
+ -- Function: magit-get-section ident &optional root
+
+ Return the section identified by IDENT. IDENT has to be a list as
+ returned by ‘magit-section-ident’.
+
+ -- Function: magit-section-match condition &optional section
+
+ Return ‘t’ if SECTION matches CONDITION. SECTION defaults to the
+ section at point. If SECTION is not specified and there also is no
+ section at point, then return ‘nil’.
+
+ CONDITION can take the following forms:
+ • ‘(CONDITION...)’
+
+ matches if any of the CONDITIONs matches.
+
+ • ‘[CLASS...]’
+
+ matches if the section’s class is the same as the first CLASS
+ or a subclass of that; the section’s parent class matches the
+ second CLASS; and so on.
+
+ • ‘[* CLASS...]’
+
+ matches sections that match ‘[CLASS...]’ and also recursively
+ all their child sections.
+
+ • ‘CLASS’
+
+ matches if the section’s class is the same as CLASS or a
+ subclass of that; regardless of the classes of the parent
+ sections.
+
+ Each CLASS should be a class symbol, identifying a class that
+ derives from ‘magit-section’. For backward compatibility CLASS can
+ also be a "type symbol". A section matches such a symbol if the
+ value of its ‘type’ slot is ‘eq’. If a type symbol has an entry in
+ ‘magit--section-type-alist’, then a section also matches that type
+ if its class is a subclass of the class that corresponds to the
+ type as per that alist.
+
+ Note that it is not necessary to specify the complete section
+ lineage as printed by ‘magit-describe-section-briefly’, unless of
+ course you want to be that precise.
+
+ -- Function: magit-section-value-if condition &optional section
+
+ If the section at point matches CONDITION, then return its value.
+
+ If optional SECTION is non-nil then test whether that matches
+ instead. If there is no section at point and SECTION is nil, then
+ return nil. If the section does not match, then return nil.
+
+ See ‘magit-section-match’ for the forms CONDITION can take.
+
+ -- Function: magit-section-case &rest clauses
+
+ Choose among clauses on the type of the section at point.
+
+ Each clause looks like (CONDITION BODY...). The type of the
+ section is compared against each CONDITION; the BODY forms of the
+ first match are evaluated sequentially and the value of the last
+ form is returned. Inside BODY the symbol ‘it’ is bound to the
+ section at point. If no clause succeeds or if there is no section
+ at point return nil.
+
+ See ‘magit-section-match’ for the forms CONDITION can take.
+ Additionally a CONDITION of t is allowed in the final clause and
+ matches if no other CONDITION match, even if there is no section at
+ point.
+
+ -- Variable: magit-root-section
+
+ The root section in the current buffer. All other sections are
+ descendants of this section. The value of this variable is set by
+ ‘magit-insert-section’ and you should never modify it.
+
+ For diff related sections a few additional tools exist.
+
+ -- Function: magit-diff-type &optional section
+
+ Return the diff type of SECTION.
+
+ The returned type is one of the symbols ‘staged’, ‘unstaged’,
+ ‘committed’, or ‘undefined’. This type serves a similar purpose as
+ the general type common to all sections (which is stored in the
+ ‘type’ slot of the corresponding ‘magit-section’ struct) but takes
+ additional information into account. When the SECTION isn’t
+ related to diffs and the buffer containing it also isn’t a
+ diff-only buffer, then return nil.
+
+ Currently the type can also be one of ‘tracked’ and ‘untracked’,
+ but these values are not handled explicitly in every place they
+ should be. A possible fix could be to just return nil here.
+
+ The section has to be a ‘diff’ or ‘hunk’ section, or a section
+ whose children are of type ‘diff’. If optional SECTION is nil,
+ return the diff type for the current section. In buffers whose
+ major mode is ‘magit-diff-mode’ SECTION is ignored and the type is
+ determined using other means. In ‘magit-revision-mode’ buffers the
+ type is always ‘committed’.
+
+ -- Function: magit-diff-scope &optional section strict
+
+ Return the diff scope of SECTION or the selected section(s).
+
+ A diff’s "scope" describes what part of a diff is selected, it is a
+ symbol, one of ‘region’, ‘hunk’, ‘hunks’, ‘file’, ‘files’, or
+ ‘list’. Do not confuse this with the diff "type", as returned by
+ ‘magit-diff-type’.
+
+ If optional SECTION is non-nil, then return the scope of that,
+ ignoring the sections selected by the region. Otherwise return the
+ scope of the current section, or if the region is active and
+ selects a valid group of diff related sections, the type of these
+ sections, i.e. ‘hunks’ or ‘files’. If SECTION (or if the current
+ section that is nil) is a ‘hunk’ section and the region starts and
+ ends inside the body of a that section, then the type is ‘region’.
+
+ If optional STRICT is non-nil then return nil if the diff type of
+ the section at point is ‘untracked’ or the section at point is not
+ actually a ‘diff’ but a ‘diffstat’ section.
+
+\1f
+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<N>’ argument. In
+ both case this is done by changing the value of this variable and
+ then calling this ‘magit-refresh-function’.
+
+\1f
+File: magit.info, Node: Conventions, Prev: Refreshing Buffers, Up: Plumbing
+
+10.4 Conventions
+================
+
+Also see *note Completion and Confirmation::.
+
+* Menu:
+
+* Theming Faces::
+
+\1f
+File: magit.info, Node: Theming Faces, Up: Conventions
+
+10.4.1 Theming Faces
+--------------------
+
+The default theme uses blue for local branches, green for remote
+branches, and goldenrod (brownish yellow) for tags. When creating a new
+theme, you should probably follow that example. If your theme already
+uses other colors, then stick to that.
+
+ In older releases these reference faces used to have a background
+color and a box around them. The basic default faces no longer do so,
+to make Magit buffers much less noisy, and you should follow that
+example at least with regards to boxes. (Boxes were used in the past to
+work around a conflict between the highlighting overlay and text
+property backgrounds. That’s no longer necessary because highlighting
+no longer causes other background colors to disappear.) Alternatively
+you can keep the background color and/or box, but then have to take
+special care to adjust ‘magit-branch-current’ accordingly. By default
+it looks mostly like ‘magit-branch-local’, but with a box (by default
+the former is the only face that uses a box, exactly so that it sticks
+out). If the former also uses a box, then you have to make sure that it
+differs in some other way from the latter.
+
+ The most difficult faces to theme are those related to diffs,
+headings, highlighting, and the region. There are faces that fall into
+all four groups - expect to spend some time getting this right.
+
+ The ‘region’ face in the default theme, in both the light and dark
+variants, as well as in many other themes, distributed with Emacs or by
+third-parties, is very ugly. It is common to use a background color
+that really sticks out, which is ugly but if that were the only problem
+then it would be acceptable. Unfortunately many themes also set the
+foreground color, which ensures that all text within the region is
+readable. Without doing that there might be cases where some foreground
+color is too close to the region background color to still be readable.
+But it also means that text within the region loses all syntax
+highlighting.
+
+ I consider the work that went into getting the ‘region’ face right to
+be a good indicator for the general quality of a theme. My
+recommendation for the ‘region’ face is this: use a background color
+slightly different from the background color of the ‘default’ face, and
+do not set the foreground color at all. So for a light theme you might
+use a light (possibly tinted) gray as the background color of ‘default’
+and a somewhat darker gray for the background of ‘region’. That should
+usually be enough to not collide with the foreground color of any other
+face. But if some other faces also set a light gray as background
+color, then you should also make sure it doesn’t collide with those (in
+some cases it might be acceptable though).
+
+ Magit only uses the ‘region’ face when the region is "invalid" by its
+own definition. In a Magit buffer the region is used to either select
+multiple sibling sections, so that commands which support it act on all
+of these sections instead of just the current section, or to select
+lines within a single hunk section. In all other cases, the section is
+considered invalid and Magit won’t act on it. But such invalid sections
+happen, either because the user has not moved point enough yet to make
+it valid or because she wants to use a non-magit command to act on the
+region, e.g. ‘kill-region’.
+
+ So using the regular ‘region’ face for invalid sections is a feature.
+It tells the user that Magit won’t be able to act on it. It’s
+acceptable if that face looks a bit odd and even (but less so) if it
+collides with the background colors of section headings and other things
+that have a background color.
+
+ Magit highlights the current section. If a section has subsections,
+then all of them are highlighted. This is done using faces that have
+"highlight" in their names. For most sections,
+‘magit-section-highlight’ is used for both the body and the heading.
+Like the ‘region’ face, it should only set the background color to
+something similar to that of ‘default’. The highlight background color
+must be different from both the ‘region’ background color and the
+‘default’ background color.
+
+ For diff related sections Magit uses various faces to highlight
+different parts of the selected section(s). Note that hunk headings,
+unlike all other section headings, by default have a background color,
+because it is useful to have very visible separators between hunks.
+That face ‘magit-diff-hunk-heading’, should be different from both
+‘magit-diff-hunk-heading-highlight’ and ‘magit-section-highlight’, as
+well as from ‘magit-diff-context’ and ‘magit-diff-context-highlight’.
+By default we do that by changing the foreground color. Changing the
+background color would lead to complications, and there are already
+enough we cannot get around. (Also note that it is generally a good
+idea for section headings to always be bold, but only for sections that
+have subsections).
+
+ When there is a valid region selecting diff-related sibling sections,
+i.e. multiple files or hunks, then the bodies of all these sections use
+the respective highlight faces, but additionally the headings instead
+use one of the faces ‘magit-diff-file-heading-selection’ or
+‘magit-diff-hunk-heading-selection’. These faces have to be different
+from the regular highlight variants to provide explicit visual
+indication that the region is active.
+
+ When theming diff related faces, start by setting the option
+‘magit-diff-refine-hunk’ to ‘all’. You might personally prefer to only
+refine the current hunk or not use hunk refinement at all, but some of
+the users of your theme want all hunks to be refined, so you have to
+cater to that.
+
+ (Also turn on ‘magit-diff-highlight-indentation’,
+‘magit-diff-highlight-trailing’, and ‘magit-diff-paint-whitespace’; and
+insert some whitespace errors into the code you use for testing.)
+
+ For e.g. "added lines" you have to adjust three faces:
+‘magit-diff-added’, ‘magit-diff-added-highlight’, and
+‘smerge-refined-added’. Make sure that the latter works well with both
+of the former, as well as ‘smerge-other’ and ‘diff-added’. Then do the
+same for the removed lines, context lines, lines added by us, and lines
+added by them. Also make sure the respective added, removed, and
+context faces use approximately the same saturation for both the
+highlighted and unhighlighted variants. Also make sure the file and
+diff headings work nicely with context lines (e.g. make them look
+different). Line faces should set both the foreground and the
+background color. For example, for added lines use two different
+greens.
+
+ It’s best if the foreground color of both the highlighted and the
+unhighlighted variants are the same, so you will need to have to find a
+color that works well on the highlight and unhighlighted background, the
+refine background, and the highlight context background. When there is
+an hunk internal region, then the added- and removed-lines background
+color is used only within that region. Outside the region the
+highlighted context background color is used. This makes it easier to
+see what is being staged. With an hunk internal region the hunk heading
+is shown using ‘magit-diff-hunk-heading-selection’, and so are the thin
+lines that are added around the lines that fall within the region. The
+background color of that has to be distinct enough from the various
+other involved background colors.
+
+ Nobody said this would be easy. If your theme restricts itself to a
+certain set of colors, then you should make an exception here.
+Otherwise it would be impossible to make the diffs look good in each and
+every variation. Actually you might want to just stick to the default
+definitions for these faces. You have been warned. Also please note
+that if you do not get this right, this will in some cases look to users
+like bugs in Magit - so please do it right or not at all.
+
+\1f
+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
+<https://github.com/magit/magit/wiki/FAQ>.
+
+ Please also use the *note Debugging Tools::.
+
+* Menu:
+
+* FAQ - How to ...?::
+* FAQ - Issues and Errors::
+
+\1f
+File: magit.info, Node: FAQ - How to ...?, Next: FAQ - Issues and Errors, Up: FAQ
+
+A.1 FAQ - How to ...?
+=====================
+
+* Menu:
+
+* How to pronounce Magit?::
+* How to show git's output?::
+* How to install the gitman info manual?::
+* How to show diffs for gpg-encrypted files?::
+* How does branching and pushing work?::
+* Can Magit be used as ediff-version-control-package?::
+* Should I disable VC?::
+
+\1f
+File: magit.info, Node: How to pronounce Magit?, Next: How to show git's output?, Up: FAQ - How to ...?
+
+A.1.1 How to pronounce Magit?
+-----------------------------
+
+Either ‘mu[m's] git’ or ‘magi{c => t}’ is fine.
+
+ The slogan is "It’s Magit! The magical Git client", so it makes
+sense to pronounce Magit like magic, while taking into account that C
+and T do not sound the same.
+
+ The German "Magie" is not pronounced the same as the English "magic",
+so if you speak German then you can use the above rational to justify
+using the former pronunciation; ‘Mag{ie => it}’.
+
+ You can also choose to use the former pronunciation just because you
+like it better.
+
+ Also see <https://magit.vc/assets/videos/magic.mp4>. Also see
+<https://emacs.stackexchange.com/questions/13696>.
+
+\1f
+File: magit.info, Node: How to show git's output?, Next: How to install the gitman info manual?, Prev: How to pronounce Magit?, Up: FAQ - How to ...?
+
+A.1.2 How to show git’s output?
+-------------------------------
+
+To show the output of recently run git commands, press ‘$’ (or, if that
+isn’t available, ‘M-x magit-process-buffer’). This will show a buffer
+containing a section per git invocation; as always press ‘TAB’ to expand
+or collapse them.
+
+ By default, git’s output is only inserted into the process buffer if
+it is run for side-effects. When the output is consumed in some way,
+also inserting it into the process buffer would be too expensive. For
+debugging purposes, it’s possible to do so anyway by setting
+‘magit-git-debug’ to ‘t’.
+
+\1f
+File: magit.info, Node: How to install the gitman info manual?, Next: How to show diffs for gpg-encrypted files?, Prev: How to show git's output?, Up: FAQ - How to ...?
+
+A.1.3 How to install the gitman info manual?
+--------------------------------------------
+
+Git’s manpages can be exported as an info manual called ‘gitman’.
+Magit’s own info manual links to nodes in that manual instead of the
+actual manpages because Info doesn’t support linking to manpages.
+
+ Unfortunately some distributions do not install the ‘gitman’ manual
+by default and you will have to install a separate documentation package
+to get it.
+
+ Magit patches Info adding the ability to visit links to the ‘gitman’
+Info manual by instead viewing the respective manpage. If you prefer
+that approach, then set the value of ‘magit-view-git-manual-method’ to
+one of the supported packages ‘man’ or ‘woman’, e.g.:
+
+ (setq magit-view-git-manual-method 'man)
+
+\1f
+File: magit.info, Node: How to show diffs for gpg-encrypted files?, Next: How does branching and pushing work?, Prev: How to install the gitman info manual?, Up: FAQ - How to ...?
+
+A.1.4 How to show diffs for gpg-encrypted files?
+------------------------------------------------
+
+Git supports showing diffs for encrypted files, but has to be told to do
+so. Since Magit just uses Git to get the diffs, configuring Git also
+affects the diffs displayed inside Magit.
+
+ git config --global diff.gpg.textconv "gpg --no-tty --decrypt"
+ echo "*.gpg filter=gpg diff=gpg" > .gitattributes
+
+\1f
+File: magit.info, Node: How does branching and pushing work?, Next: Can Magit be used as ediff-version-control-package?, Prev: How to show diffs for gpg-encrypted files?, Up: FAQ - How to ...?
+
+A.1.5 How does branching and pushing work?
+------------------------------------------
+
+Please see *note Branching:: and
+<http://emacsair.me/2016/01/18/magit-2.4>
+
+\1f
+File: magit.info, Node: Can Magit be used as ediff-version-control-package?, Next: Should I disable VC?, Prev: How does branching and pushing work?, Up: FAQ - How to ...?
+
+A.1.6 Can Magit be used as ‘ediff-version-control-package’?
+-----------------------------------------------------------
+
+No, it cannot. For that to work the functions ‘ediff-magit-internal’
+and ‘ediff-magit-merge-internal’ would have to be implemented, and they
+are not. These two functions are only used by the three commands
+‘ediff-revision’, ‘ediff-merge-revisions-with-ancestor’, and
+‘ediff-merge-revisions’.
+
+ These commands only delegate the task of populating buffers with
+certain revisions to the "internal" functions. The equally important
+task of determining which revisions are to be compared/merged is not
+delegated. Instead this is done without any support whatsoever from the
+version control package/system - meaning that the user has to enter the
+revisions explicitly. Instead of implementing ‘ediff-magit-internal’ we
+provide ‘magit-ediff-compare’, which handles both tasks like it is 2005.
+
+ The other commands ‘ediff-merge-revisions’ and
+‘ediff-merge-revisions-with-ancestor’ are normally not what you want
+when using a modern version control system like Git. Instead of letting
+the user resolve only those conflicts which Git could not resolve on its
+own, they throw away all work done by Git and then expect the user to
+manually merge all conflicts, including those that had already been
+resolved. That made sense back in the days when version control systems
+couldn’t merge (or so I have been told), but not anymore. Once in a
+blue moon you might actually want to see all conflicts, in which case
+you *can* use these commands, which then use ‘ediff-vc-merge-internal’.
+So we don’t actually have to implement ‘ediff-magit-merge-internal’.
+Instead we provide the more useful command ‘magit-ediff-resolve’ which
+only shows yet-to-be resolved conflicts.
+
+\1f
+File: magit.info, Node: Should I disable VC?, Prev: Can Magit be used as ediff-version-control-package?, Up: FAQ - How to ...?
+
+A.1.7 Should I disable VC?
+--------------------------
+
+If you don’t use VC (the built-in version control interface) then you
+might be tempted to disable it, not least because we used to recommend
+that you do that.
+
+ We no longer recommend that you disable VC. Doing so would break
+useful third-party packages (such as ‘diff-hl’), which depend on VC
+being enabled.
+
+ If you choose to disable VC anyway, then you can do so by changing
+the value of ‘vc-handled-backends’.
+
+\1f
+File: magit.info, Node: FAQ - Issues and Errors, Prev: FAQ - How to ...?, Up: FAQ
+
+A.2 FAQ - Issues and Errors
+===========================
+
+* Menu:
+
+* Magit is slow::
+* I changed several thousand files at once and now Magit is unusable::
+* I am having problems committing::
+* I am using MS Windows and cannot push with Magit::
+* I am using OS X and SOMETHING works in shell, but not in Magit: I am using OS X and SOMETHING works in shell but not in Magit.
+* Expanding a file to show the diff causes it to disappear::
+* Point is wrong in the COMMIT_EDITMSG buffer::
+* The mode-line information isn't always up-to-date::
+* A branch and tag sharing the same name breaks SOMETHING::
+* My Git hooks work on the command-line but not inside Magit::
+* git-commit-mode isn't used when committing from the command-line::
+* Point ends up inside invisible text when jumping to a file-visiting buffer::
+
+\1f
+File: magit.info, Node: Magit is slow, Next: I changed several thousand files at once and now Magit is unusable, Up: FAQ - Issues and Errors
+
+A.2.1 Magit is slow
+-------------------
+
+See *note Performance::.
+
+\1f
+File: magit.info, Node: I changed several thousand files at once and now Magit is unusable, Next: I am having problems committing, Prev: Magit is slow, Up: FAQ - Issues and Errors
+
+A.2.2 I changed several thousand files at once and now Magit is unusable
+------------------------------------------------------------------------
+
+Magit is *currently* not expected to work under such conditions. It
+sure would be nice if it did, and v2.5 will hopefully be a big step into
+that direction. But it might take until v3.1 to accomplish fully
+satisfactory performance, because that requires some heavy refactoring.
+
+ But for now we recommend you use the command line to complete this
+one commit. Also see *note Performance::.
+
+\1f
+File: magit.info, Node: I am having problems committing, Next: I am using MS Windows and cannot push with Magit, Prev: I changed several thousand files at once and now Magit is unusable, Up: FAQ - Issues and Errors
+
+A.2.3 I am having problems committing
+-------------------------------------
+
+That likely means that Magit is having problems finding an appropriate
+emacsclient executable. See *note (with-editor)Configuring
+With-Editor:: and *note (with-editor)Debugging::.
+
+\1f
+File: magit.info, Node: I am using MS Windows and cannot push with Magit, Next: I am using OS X and SOMETHING works in shell but not in Magit, Prev: I am having problems committing, Up: FAQ - Issues and Errors
+
+A.2.4 I am using MS Windows and cannot push with Magit
+------------------------------------------------------
+
+It’s almost certain that Magit is only incidental to this issue. It is
+much more likely that this is a configuration issue, even if you can
+push on the command line.
+
+ Detailed setup instructions can be found at
+<https://github.com/magit/magit/wiki/Pushing-with-Magit-from-Windows>.
+
+\1f
+File: magit.info, Node: I am using OS X and SOMETHING works in shell but not in Magit, Next: Expanding a file to show the diff causes it to disappear, Prev: I am using MS Windows and cannot push with Magit, Up: FAQ - Issues and Errors
+
+A.2.5 I am using OS X and SOMETHING works in shell, but not in Magit
+--------------------------------------------------------------------
+
+This usually occurs because Emacs doesn’t have the same environment
+variables as your shell. Try installing and configuring
+<https://github.com/purcell/exec-path-from-shell>. 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’.
+
+\1f
+File: magit.info, Node: Expanding a file to show the diff causes it to disappear, Next: Point is wrong in the COMMIT_EDITMSG buffer, Prev: I am using OS X and SOMETHING works in shell but not in Magit, Up: FAQ - Issues and Errors
+
+A.2.6 Expanding a file to show the diff causes it to disappear
+--------------------------------------------------------------
+
+This is probably caused by a change of a ‘diff.*’ Git variable. You
+probably set that variable for a reason, and should therefore only undo
+that setting in Magit by customizing ‘magit-git-global-arguments’.
+
+\1f
+File: magit.info, Node: Point is wrong in the COMMIT_EDITMSG buffer, Next: The mode-line information isn't always up-to-date, Prev: Expanding a file to show the diff causes it to disappear, Up: FAQ - Issues and Errors
+
+A.2.7 Point is wrong in the ‘COMMIT_EDITMSG’ buffer
+---------------------------------------------------
+
+Neither Magit nor ‘git-commit‘ fiddle with point in the buffer used to
+write commit messages, so something else must be doing it.
+
+ You have probably globally enabled a mode which does restore point in
+file-visiting buffers. It might be a bit surprising, but when you write
+a commit message, then you are actually editing a file.
+
+ So you have to figure out which package is doing. ‘saveplace’,
+‘pointback’, and ‘session’ are likely candidates. These snippets might
+help:
+
+ (setq session-name-disable-regexp "\\(?:\\`'\\.git/[A-Z_]+\\'\\)")
+
+ (with-eval-after-load 'pointback
+ (lambda ()
+ (when (or git-commit-mode git-rebase-mode)
+ (pointback-mode -1))))
+
+\1f
+File: magit.info, Node: The mode-line information isn't always up-to-date, Next: A branch and tag sharing the same name breaks SOMETHING, Prev: Point is wrong in the COMMIT_EDITMSG buffer, Up: FAQ - Issues and Errors
+
+A.2.8 The mode-line information isn’t always up-to-date
+-------------------------------------------------------
+
+Magit is not responsible for the version control information that is
+being displayed in the mode-line and looks something like ‘Git-master’.
+The built-in "Version Control" package, also known as "VC", updates that
+information, and can be told to do so more often:
+
+ (setq auto-revert-check-vc-info t)
+
+ But doing so isn’t good for performance. For more (overly
+optimistic) information see *note (emacs)VC Mode Line::.
+
+ If you don’t really care about seeing this information in the
+mode-line, but just don’t want to see _incorrect_ information, then
+consider simply not displaying it in the mode-line:
+
+ (setq-default mode-line-format
+ (delete '(vc-mode vc-mode) mode-line-format))
+
+\1f
+File: magit.info, Node: A branch and tag sharing the same name breaks SOMETHING, Next: My Git hooks work on the command-line but not inside Magit, Prev: The mode-line information isn't always up-to-date, Up: FAQ - Issues and Errors
+
+A.2.9 A branch and tag sharing the same name breaks SOMETHING
+-------------------------------------------------------------
+
+Or more generally, ambiguous refnames break SOMETHING.
+
+ Magit assumes that refs are named non-ambiguously across the
+"refs/heads/", "refs/tags/", and "refs/remotes/" namespaces (i.e., all
+the names remain unique when those prefixes are stripped). We consider
+ambiguous refnames unsupported and recommend that you use a
+non-ambiguous naming scheme. However, if you do work with a repository
+that has ambiguous refnames, please report any issues you encounter so
+that we can investigate whether there is a simple fix.
+
+\1f
+File: magit.info, Node: My Git hooks work on the command-line but not inside Magit, Next: git-commit-mode isn't used when committing from the command-line, Prev: A branch and tag sharing the same name breaks SOMETHING, Up: FAQ - Issues and Errors
+
+A.2.10 My Git hooks work on the command-line but not inside Magit
+-----------------------------------------------------------------
+
+When Magit calls ‘git’ it adds a few global arguments including
+‘--literal-pathspecs’ and the ‘git’ process started by Magit then passes
+that setting on to other ‘git’ process it starts itself. It does so by
+setting the environment variable ‘GIT_LITERAL_PATHSPECS’, not by calling
+subprocesses with the ‘--literal-pathspecs’ argument. You can therefore
+override this setting in hook scripts using ‘unset
+GIT_LITERAL_PATHSPECS’.
+
+\1f
+File: magit.info, Node: git-commit-mode isn't used when committing from the command-line, Next: Point ends up inside invisible text when jumping to a file-visiting buffer, Prev: My Git hooks work on the command-line but not inside Magit, Up: FAQ - Issues and Errors
+
+A.2.11 ‘git-commit-mode’ isn’t used when committing from the command-line
+-------------------------------------------------------------------------
+
+The reason for this is that ‘git-commit.el’ has not been loaded yet
+and/or that the server has not been started yet. These things have
+always already been taken care of when you commit from Magit because in
+order to do so, Magit has to be loaded and doing that involves loading
+‘git-commit’ and starting the server.
+
+ If you want to commit from the command-line, then you have to take
+care of these things yourself. Your ‘init.el’ file should contain:
+
+ (require 'git-commit)
+ (server-mode)
+
+ Instead of ‘(require ’git-commit)‘ you may also use:
+
+ (load "/path/to/magit-autoloads.el")
+
+ You might want to do that because loading ‘git-commit’ causes large
+parts of Magit to be loaded.
+
+ There are also some variations of ‘(server-mode)’ that you might want
+to try. Personally I use:
+
+ (use-package server
+ :config (or (server-running-p) (server-mode)))
+
+ Now you can use:
+
+ $ emacs&
+ $ EDITOR=emacsclient git commit
+
+ However you cannot use:
+
+ $ killall emacs
+ $ EDITOR="emacsclient --alternate-editor emacs" git commit
+
+ This will actually end up using ‘emacs’, not ‘emacsclient’. If you
+do this, then you can still edit the commit message but
+‘git-commit-mode’ won’t be used and you have to exit ‘emacs’ to finish
+the process.
+
+ Tautology ahead. If you want to be able to use ‘emacsclient’ to
+connect to a running ‘emacs’ instance, even though no ‘emacs’ instance
+is running, then you cannot use ‘emacsclient’ directly.
+
+ Instead you have to create a script that does something like this:
+
+ Try to use ‘emacsclient’ (without using ‘--alternate-editor’). If
+that succeeds, do nothing else. Otherwise start ‘emacs &’ (and
+‘init.el’ must call ‘server-start’) and try to use ‘emacsclient’ again.
+
+\1f
+File: magit.info, Node: Point ends up inside invisible text when jumping to a file-visiting buffer, Prev: git-commit-mode isn't used when committing from the command-line, Up: FAQ - Issues and Errors
+
+A.2.12 Point ends up inside invisible text when jumping to a file-visiting buffer
+---------------------------------------------------------------------------------
+
+This can happen when you type ‘RET’ on a hunk to visit the respective
+file at the respective position. One solution to this problem is to use
+‘global-reveal-mode’. It makes sure that text around point is always
+visible. If that is too drastic for your taste, then you may instead
+use ‘magit-diff-visit-file-hook’ to reveal the text, possibly using
+‘reveal-post-command’ or for Org buffers ‘org-reveal’.
+
+\1f
+File: magit.info, Node: Debugging Tools, Next: Keystroke Index, Prev: FAQ, Up: Top
+
+B Debugging Tools
+*****************
+
+Magit and its dependencies provide a few debugging tools, and we
+appreciate it very much if you use those tools before reporting an
+issue. Please include all relevant output when reporting an issue.
+
+‘M-x magit-version’ (‘magit-version’)
+
+ This command shows the currently used versions of Magit, Git, and
+ Emacs in the echo area. Non-interactively this just returns the
+ Magit version.
+
+‘M-x magit-emacs-Q-command’ (‘magit-emacs-Q-command’)
+
+ This command shows a debugging shell command in the echo area and
+ adds it to the kill ring. Paste that command into a shell and run
+ it.
+
+ This shell command starts ‘emacs’ with only ‘magit’ and its
+ dependencies loaded. Neither your configuration nor other
+ installed packages are loaded. This makes it easier to determine
+ whether some issue lays with Magit or something else.
+
+ If you run Magit from its Git repository, then you should be able
+ to use ‘make emacs-Q’ instead of the output of this command.
+
+‘M-x magit-toggle-verbose-refresh’ (‘magit-toggle-verbose-refresh’)
+
+ This command toggles whether Magit refreshes buffers verbosely.
+ Enabling this helps figuring out which sections are bottlenecks.
+ The additional output can be found in the ‘*Messages*’ buffer.
+
+‘M-x magit-debug-git-executable’ (‘magit-debug-git-executable’)
+
+ This command displays a buffer containing information about the
+ available and used ‘git’ executable(s), and can be useful when
+ investigating ‘exec-path’ issues.
+
+ Also see *note Git Executable::.
+
+‘M-x with-editor-debug’ (‘with-editor-debug’)
+
+ This command displays a buffer containing information about the
+ available and used ‘emacsclient’ executable(s), and can be useful
+ when investigating why Magit (or rather ‘with-editor’) cannot find
+ an appropriate ‘emacsclient’ executable.
+
+ Also see *note (with-editor)Debugging::.
+
+ Please also see the *note FAQ::.
+
+\1f
+File: magit.info, Node: Keystroke Index, Next: Command Index, Prev: Debugging Tools, Up: Top
+
+Appendix C Keystroke Index
+**************************
+
+\0\b[index\0\b]
+* Menu:
+
+* !: Running Git Manually.
+ (line 12)
+* ! !: Running Git Manually.
+ (line 17)
+* ! a: Running Git Manually.
+ (line 58)
+* ! b: Running Git Manually.
+ (line 62)
+* ! g: Running Git Manually.
+ (line 66)
+* ! k: Running Git Manually.
+ (line 54)
+* ! p: Running Git Manually.
+ (line 25)
+* ! s: Running Git Manually.
+ (line 35)
+* ! S: Running Git Manually.
+ (line 40)
+* $: Viewing Git Output. (line 16)
+* %: Worktree. (line 8)
+* % b: Worktree. (line 13)
+* % c: Worktree. (line 17)
+* % g: Worktree. (line 30)
+* % k: Worktree. (line 25)
+* % m: Worktree. (line 21)
+* +: Log Buffer. (line 61)
+* + <1>: Refreshing Diffs. (line 69)
+* -: Log Buffer. (line 65)
+* - <1>: Refreshing Diffs. (line 65)
+* 0: Refreshing Diffs. (line 73)
+* 1: Section Visibility. (line 26)
+* 2: Section Visibility. (line 27)
+* 3: Section Visibility. (line 28)
+* 4: Section Visibility. (line 29)
+* =: Log Buffer. (line 55)
+* ^: Section Movement. (line 31)
+* a: Applying. (line 33)
+* A: Cherry Picking. (line 8)
+* A A: Cherry Picking. (line 17)
+* A a: Cherry Picking. (line 24)
+* A A <1>: Cherry Picking. (line 90)
+* A a <1>: Cherry Picking. (line 98)
+* A d: Cherry Picking. (line 54)
+* A h: Cherry Picking. (line 42)
+* A n: Cherry Picking. (line 65)
+* A s: Cherry Picking. (line 76)
+* A s <1>: Cherry Picking. (line 94)
+* B: Bisecting. (line 8)
+* b: Blaming. (line 102)
+* b <1>: Branch Commands. (line 12)
+* b <2>: Editing Rebase Sequences.
+ (line 85)
+* B B: Bisecting. (line 16)
+* B b: Bisecting. (line 34)
+* b b: Branch Commands. (line 49)
+* b C: Branch Commands. (line 29)
+* b c: Branch Commands. (line 67)
+* B g: Bisecting. (line 39)
+* B k: Bisecting. (line 51)
+* b k: Branch Commands. (line 147)
+* b l: Branch Commands. (line 74)
+* B m: Bisecting. (line 44)
+* b n: Branch Commands. (line 57)
+* B r: Bisecting. (line 57)
+* b r: Branch Commands. (line 153)
+* B s: Bisecting. (line 27)
+* b s: Branch Commands. (line 97)
+* b S: Branch Commands. (line 125)
+* b x: Branch Commands. (line 131)
+* c: Blaming. (line 135)
+* C: Cloning Repository. (line 20)
+* c <1>: Initiating a Commit. (line 8)
+* c <2>: Editing Rebase Sequences.
+ (line 72)
+* c a: Initiating a Commit. (line 19)
+* c A: Initiating a Commit. (line 67)
+* C b: Cloning Repository. (line 41)
+* C C: Cloning Repository. (line 29)
+* c c: Initiating a Commit. (line 14)
+* C d: Cloning Repository. (line 54)
+* C e: Cloning Repository. (line 61)
+* c e: Initiating a Commit. (line 23)
+* c f: Initiating a Commit. (line 43)
+* c F: Initiating a Commit. (line 51)
+* C m: Cloning Repository. (line 46)
+* C s: Cloning Repository. (line 34)
+* c s: Initiating a Commit. (line 55)
+* c S: Initiating a Commit. (line 63)
+* c w: Initiating a Commit. (line 33)
+* C-<return>: Visiting Files and Blobs from a Diff.
+ (line 51)
+* C-<tab>: Section Visibility. (line 13)
+* C-c C-a: Commit Pseudo Headers.
+ (line 17)
+* C-c C-b: Log Buffer. (line 21)
+* C-c C-b <1>: Refreshing Diffs. (line 91)
+* C-c C-c: Transient Commands. (line 18)
+* C-c C-c <1>: Select from Log. (line 20)
+* C-c C-c <2>: Editing Commit Messages.
+ (line 17)
+* C-c C-c <3>: Editing Rebase Sequences.
+ (line 6)
+* C-c C-d: Refreshing Diffs. (line 81)
+* C-c C-d <1>: Editing Commit Messages.
+ (line 58)
+* C-c C-e: Commands Available in Diffs.
+ (line 25)
+* C-c C-f: Log Buffer. (line 25)
+* C-c C-f <1>: Refreshing Diffs. (line 95)
+* C-c C-i: Commit Pseudo Headers.
+ (line 13)
+* C-c C-k: Select from Log. (line 26)
+* C-c C-k <1>: Editing Commit Messages.
+ (line 22)
+* C-c C-k <2>: Editing Rebase Sequences.
+ (line 11)
+* C-c C-n: Log Buffer. (line 29)
+* C-c C-o: Commit Pseudo Headers.
+ (line 33)
+* C-c C-p: Commit Pseudo Headers.
+ (line 37)
+* C-c C-r: Commit Pseudo Headers.
+ (line 21)
+* C-c C-s: Commit Pseudo Headers.
+ (line 25)
+* C-c C-t: Commands Available in Diffs.
+ (line 14)
+* C-c C-t <1>: Commit Pseudo Headers.
+ (line 29)
+* C-c C-w: Using the Revision Stack.
+ (line 6)
+* C-c M-g: Commands for Buffers Visiting Files.
+ (line 21)
+* C-c M-g B: Blaming. (line 18)
+* C-c M-g b: Blaming. (line 29)
+* C-c M-g B <1>: Commands for Buffers Visiting Files.
+ (line 93)
+* C-c M-g B b: Blaming. (line 30)
+* C-c M-g B e: Blaming. (line 64)
+* C-c M-g B f: Blaming. (line 55)
+* C-c M-g B r: Blaming. (line 46)
+* C-c M-g c: Commands for Buffers Visiting Files.
+ (line 38)
+* C-c M-g D: Commands for Buffers Visiting Files.
+ (line 45)
+* C-c M-g d: Commands for Buffers Visiting Files.
+ (line 56)
+* C-c M-g e: Blaming. (line 63)
+* C-c M-g e <1>: Commands for Buffers Visiting Files.
+ (line 106)
+* C-c M-g f: Blaming. (line 54)
+* C-c M-g L: Commands for Buffers Visiting Files.
+ (line 66)
+* C-c M-g l: Commands for Buffers Visiting Files.
+ (line 77)
+* C-c M-g p: Commands for Buffers Visiting Files.
+ (line 116)
+* C-c M-g r: Blaming. (line 45)
+* C-c M-g s: Commands for Buffers Visiting Files.
+ (line 29)
+* C-c M-g t: Commands for Buffers Visiting Files.
+ (line 84)
+* C-c M-g u: Commands for Buffers Visiting Files.
+ (line 33)
+* C-c M-i: Commit Pseudo Headers.
+ (line 42)
+* C-c M-s: Editing Commit Messages.
+ (line 34)
+* C-w: Common Commands. (line 10)
+* C-x g: Status Buffer. (line 22)
+* C-x u: Editing Rebase Sequences.
+ (line 94)
+* d: Diffing. (line 21)
+* D: Refreshing Diffs. (line 11)
+* d c: Diffing. (line 69)
+* d d: Diffing. (line 27)
+* D f: Refreshing Diffs. (line 46)
+* D F: Refreshing Diffs. (line 51)
+* D g: Refreshing Diffs. (line 17)
+* d p: Diffing. (line 61)
+* d r: Diffing. (line 31)
+* D r: Refreshing Diffs. (line 41)
+* d s: Diffing. (line 51)
+* D s: Refreshing Diffs. (line 22)
+* d t: Diffing. (line 74)
+* D t: Refreshing Diffs. (line 37)
+* d u: Diffing. (line 57)
+* d w: Diffing. (line 45)
+* D w: Refreshing Diffs. (line 29)
+* DEL: Log Buffer. (line 45)
+* DEL <1>: Commands Available in Diffs.
+ (line 60)
+* DEL <2>: Blaming. (line 89)
+* DEL <3>: Editing Rebase Sequences.
+ (line 28)
+* e: Ediffing. (line 9)
+* E: Ediffing. (line 21)
+* e <1>: Editing Rebase Sequences.
+ (line 55)
+* E c: Ediffing. (line 65)
+* E i: Ediffing. (line 57)
+* E m: Ediffing. (line 35)
+* E r: Ediffing. (line 26)
+* E s: Ediffing. (line 48)
+* E u: Ediffing. (line 53)
+* E w: Ediffing. (line 61)
+* E z: Ediffing. (line 69)
+* f: Editing Rebase Sequences.
+ (line 63)
+* f <1>: Fetching. (line 9)
+* F: Pulling. (line 9)
+* f a: Fetching. (line 50)
+* f C: Branch Commands. (line 30)
+* F C: Branch Commands. (line 31)
+* f e: Fetching. (line 36)
+* F e: Pulling. (line 30)
+* f m: Fetching. (line 54)
+* f o: Fetching. (line 40)
+* f p: Fetching. (line 15)
+* F p: Pulling. (line 14)
+* f r: Fetching. (line 45)
+* f u: Fetching. (line 23)
+* F u: Pulling. (line 22)
+* g: Automatic Refreshing of Magit Buffers.
+ (line 24)
+* G: Automatic Refreshing of Magit Buffers.
+ (line 33)
+* j: Commands Available in Diffs.
+ (line 45)
+* k: Viewing Git Output. (line 24)
+* k <1>: Applying. (line 40)
+* k <2>: Editing Rebase Sequences.
+ (line 68)
+* k <3>: Stashing. (line 96)
+* l: Logging. (line 29)
+* L: Refreshing Logs. (line 11)
+* L <1>: Log Buffer. (line 6)
+* L <2>: Log Margin. (line 57)
+* l <1>: Editing Rebase Sequences.
+ (line 115)
+* l a: Logging. (line 60)
+* l b: Logging. (line 56)
+* L d: Log Margin. (line 74)
+* L g: Refreshing Logs. (line 17)
+* l h: Logging. (line 48)
+* l H: Reflog. (line 19)
+* l l: Logging. (line 35)
+* l L: Logging. (line 52)
+* L L: Log Margin. (line 66)
+* L l: Log Margin. (line 70)
+* l o: Logging. (line 41)
+* l O: Reflog. (line 15)
+* l r: Reflog. (line 11)
+* L s: Refreshing Logs. (line 22)
+* L t: Refreshing Logs. (line 37)
+* L w: Refreshing Logs. (line 29)
+* m: Merging. (line 9)
+* M: Remote Commands. (line 13)
+* m a: Merging. (line 45)
+* m a <1>: Merging. (line 95)
+* M a: Remote Commands. (line 50)
+* M C: Remote Commands. (line 33)
+* m e: Merging. (line 31)
+* m i: Merging. (line 58)
+* M k: Remote Commands. (line 65)
+* m m: Merging. (line 18)
+* m m <1>: Merging. (line 89)
+* m n: Merging. (line 38)
+* m p: Merging. (line 81)
+* M p: Remote Commands. (line 69)
+* M P: Remote Commands. (line 74)
+* M r: Remote Commands. (line 55)
+* m s: Merging. (line 72)
+* M u: Remote Commands. (line 60)
+* M-1: Section Visibility. (line 33)
+* M-2: Section Visibility. (line 34)
+* M-3: Section Visibility. (line 35)
+* M-4: Section Visibility. (line 36)
+* M-<tab>: Section Visibility. (line 17)
+* M-n: Section Movement. (line 26)
+* M-n <1>: Editing Commit Messages.
+ (line 44)
+* M-n <2>: Editing Rebase Sequences.
+ (line 47)
+* M-p: Section Movement. (line 20)
+* M-p <1>: Editing Commit Messages.
+ (line 38)
+* M-p <2>: Editing Rebase Sequences.
+ (line 43)
+* M-w: Blaming. (line 127)
+* M-w <1>: Common Commands. (line 28)
+* M-x magit-debug-git-executable: Git Executable. (line 45)
+* M-x magit-debug-git-executable <1>: Debugging Tools. (line 36)
+* M-x magit-describe-section-briefly: Section Types and Values.
+ (line 13)
+* M-x magit-describe-section-briefly <1>: Matching Sections. (line 6)
+* M-x magit-emacs-Q-command: Debugging Tools. (line 16)
+* M-x magit-init: Creating Repository. (line 6)
+* M-x magit-reset-index: Staging and Unstaging.
+ (line 87)
+* M-x magit-reverse-in-index: Staging and Unstaging.
+ (line 62)
+* M-x magit-stage-file: Staging from File-Visiting Buffers.
+ (line 10)
+* M-x magit-toggle-buffer-lock: Modes and Buffers. (line 17)
+* M-x magit-toggle-verbose-refresh: Debugging Tools. (line 30)
+* M-x magit-unstage-file: Staging from File-Visiting Buffers.
+ (line 18)
+* M-x magit-version: Git Executable. (line 17)
+* M-x magit-version <1>: Debugging Tools. (line 10)
+* M-x magit-wip-commit: Wip Modes. (line 88)
+* M-x with-editor-debug: Debugging Tools. (line 44)
+* MM: Editing Rebase Sequences.
+ (line 125)
+* Mt: Editing Rebase Sequences.
+ (line 132)
+* n: Section Movement. (line 16)
+* n <1>: Blaming. (line 106)
+* N: Blaming. (line 110)
+* n <2>: Editing Rebase Sequences.
+ (line 39)
+* n <3>: Minor Mode for Buffers Visiting Blobs.
+ (line 16)
+* o: Submodule Transient. (line 6)
+* O: Subtree. (line 8)
+* o a: Submodule Transient. (line 20)
+* o d: Submodule Transient. (line 50)
+* O e: Subtree. (line 42)
+* O e p: Subtree. (line 54)
+* O e s: Subtree. (line 59)
+* o f: Submodule Transient. (line 58)
+* O i: Subtree. (line 13)
+* O i a: Subtree. (line 25)
+* O i c: Subtree. (line 30)
+* O i f: Subtree. (line 38)
+* O i m: Subtree. (line 34)
+* o l: Submodule Transient. (line 54)
+* o p: Submodule Transient. (line 34)
+* o r: Submodule Transient. (line 27)
+* o s: Submodule Transient. (line 44)
+* o u: Submodule Transient. (line 39)
+* p: Section Movement. (line 10)
+* p <1>: Blaming. (line 114)
+* P: Blaming. (line 118)
+* p <2>: Editing Rebase Sequences.
+ (line 35)
+* P <1>: Pushing. (line 9)
+* p <3>: Minor Mode for Buffers Visiting Blobs.
+ (line 12)
+* P C: Branch Commands. (line 32)
+* P e: Pushing. (line 31)
+* P m: Pushing. (line 50)
+* P o: Pushing. (line 36)
+* P p: Pushing. (line 15)
+* P r: Pushing. (line 41)
+* P t: Pushing. (line 58)
+* P T: Pushing. (line 66)
+* P u: Pushing. (line 23)
+* q: Quitting Windows. (line 6)
+* q <1>: Log Buffer. (line 14)
+* q <2>: Blaming. (line 122)
+* q <3>: Minor Mode for Buffers Visiting Blobs.
+ (line 20)
+* r: Rebasing. (line 9)
+* r <1>: Editing Rebase Sequences.
+ (line 51)
+* r a: Rebasing. (line 123)
+* r e: Rebasing. (line 44)
+* r e <1>: Rebasing. (line 118)
+* r f: Rebasing. (line 84)
+* r i: Rebasing. (line 80)
+* r k: Rebasing. (line 99)
+* r m: Rebasing. (line 89)
+* r p: Rebasing. (line 28)
+* r r: Rebasing. (line 106)
+* r s: Rebasing. (line 50)
+* r s <1>: Rebasing. (line 113)
+* r u: Rebasing. (line 36)
+* r w: Rebasing. (line 94)
+* RET: References Buffer. (line 181)
+* RET <1>: Visiting Files and Blobs from a Diff.
+ (line 8)
+* RET <2>: Blaming. (line 75)
+* RET <3>: Editing Rebase Sequences.
+ (line 16)
+* s: Staging and Unstaging.
+ (line 28)
+* S: Staging and Unstaging.
+ (line 36)
+* s <1>: Editing Rebase Sequences.
+ (line 59)
+* S-<tab>: Section Visibility. (line 22)
+* SPC: Log Buffer. (line 35)
+* SPC <1>: Commands Available in Diffs.
+ (line 56)
+* SPC <2>: Blaming. (line 79)
+* SPC <3>: Editing Rebase Sequences.
+ (line 21)
+* t: Editing Rebase Sequences.
+ (line 119)
+* t <1>: Tagging. (line 8)
+* T: Notes. (line 8)
+* T a: Notes. (line 52)
+* T c: Notes. (line 47)
+* t k: Tagging. (line 39)
+* T m: Notes. (line 38)
+* t p: Tagging. (line 46)
+* T p: Notes. (line 30)
+* t r: Tagging. (line 19)
+* T r: Notes. (line 22)
+* t t: Tagging. (line 14)
+* T T: Notes. (line 14)
+* TAB: Section Visibility. (line 9)
+* u: Staging and Unstaging.
+ (line 43)
+* U: Staging and Unstaging.
+ (line 52)
+* v: Applying. (line 44)
+* V: Reverting. (line 6)
+* V A: Reverting. (line 31)
+* V a: Reverting. (line 39)
+* V s: Reverting. (line 35)
+* V V: Reverting. (line 15)
+* V v: Reverting. (line 21)
+* W: Plain Patches. (line 6)
+* w: Maildir Patches. (line 8)
+* w a: Plain Patches. (line 21)
+* w a <1>: Maildir Patches. (line 25)
+* w a <2>: Maildir Patches. (line 43)
+* W c: Plain Patches. (line 12)
+* w m: Maildir Patches. (line 21)
+* W s: Plain Patches. (line 28)
+* w s: Maildir Patches. (line 38)
+* w w: Maildir Patches. (line 14)
+* w w <1>: Maildir Patches. (line 34)
+* x: Editing Rebase Sequences.
+ (line 76)
+* x <1>: Resetting. (line 8)
+* X f: Resetting. (line 50)
+* X h: Resetting. (line 26)
+* X i: Resetting. (line 37)
+* X k: Resetting. (line 31)
+* X m: Resetting. (line 15)
+* X s: Resetting. (line 20)
+* X w: Resetting. (line 44)
+* X w <1>: Wip Modes. (line 66)
+* Y: Cherries. (line 17)
+* y: References Buffer. (line 6)
+* y <1>: Editing Rebase Sequences.
+ (line 90)
+* y c: References Buffer. (line 26)
+* y o: References Buffer. (line 32)
+* y y: References Buffer. (line 21)
+* z: Stashing. (line 8)
+* z a: Stashing. (line 59)
+* z b: Stashing. (line 81)
+* z B: Stashing. (line 86)
+* z f: Stashing. (line 92)
+* z i: Stashing. (line 21)
+* z I: Stashing. (line 47)
+* z k: Stashing. (line 72)
+* z l: Stashing. (line 100)
+* z p: Stashing. (line 65)
+* z v: Stashing. (line 77)
+* z w: Stashing. (line 26)
+* z W: Stashing. (line 52)
+* z x: Stashing. (line 33)
+* z z: Stashing. (line 14)
+* z Z: Stashing. (line 40)
+
+\1f
+File: magit.info, Node: Command Index, Next: Function Index, Prev: Keystroke Index, Up: Top
+
+Appendix D Command Index
+************************
+
+\0\b[index\0\b]
+* Menu:
+
+* forward-line: Editing Rebase Sequences.
+ (line 39)
+* git-commit-ack: Commit Pseudo Headers.
+ (line 17)
+* git-commit-cc: Commit Pseudo Headers.
+ (line 33)
+* git-commit-insert-pseudo-header: Commit Pseudo Headers.
+ (line 13)
+* git-commit-next-message: Editing Commit Messages.
+ (line 44)
+* git-commit-prev-message: Editing Commit Messages.
+ (line 38)
+* git-commit-reported: Commit Pseudo Headers.
+ (line 37)
+* git-commit-review: Commit Pseudo Headers.
+ (line 21)
+* git-commit-save-message: Editing Commit Messages.
+ (line 34)
+* git-commit-signoff: Commit Pseudo Headers.
+ (line 25)
+* git-commit-suggested: Commit Pseudo Headers.
+ (line 42)
+* git-commit-test: Commit Pseudo Headers.
+ (line 29)
+* git-rebase-backward-line: Editing Rebase Sequences.
+ (line 35)
+* git-rebase-break: Editing Rebase Sequences.
+ (line 85)
+* git-rebase-edit: Editing Rebase Sequences.
+ (line 55)
+* git-rebase-exec: Editing Rebase Sequences.
+ (line 76)
+* git-rebase-fixup: Editing Rebase Sequences.
+ (line 63)
+* git-rebase-insert: Editing Rebase Sequences.
+ (line 90)
+* git-rebase-kill-line: Editing Rebase Sequences.
+ (line 68)
+* git-rebase-label: Editing Rebase Sequences.
+ (line 115)
+* git-rebase-merge: Editing Rebase Sequences.
+ (line 125)
+* git-rebase-merge-toggle-editmsg: Editing Rebase Sequences.
+ (line 132)
+* git-rebase-move-line-down: Editing Rebase Sequences.
+ (line 47)
+* git-rebase-move-line-up: Editing Rebase Sequences.
+ (line 43)
+* git-rebase-pick: Editing Rebase Sequences.
+ (line 72)
+* git-rebase-reset: Editing Rebase Sequences.
+ (line 119)
+* git-rebase-reword: Editing Rebase Sequences.
+ (line 51)
+* git-rebase-show-commit: Editing Rebase Sequences.
+ (line 16)
+* git-rebase-show-or-scroll-down: Editing Rebase Sequences.
+ (line 28)
+* git-rebase-show-or-scroll-up: Editing Rebase Sequences.
+ (line 21)
+* git-rebase-squash: Editing Rebase Sequences.
+ (line 59)
+* git-rebase-undo: Editing Rebase Sequences.
+ (line 94)
+* ido-enter-magit-status: Status Buffer. (line 72)
+* magit-am: Maildir Patches. (line 8)
+* magit-am-abort: Maildir Patches. (line 43)
+* magit-am-apply-maildir: Maildir Patches. (line 21)
+* magit-am-apply-patches: Maildir Patches. (line 14)
+* magit-am-continue: Maildir Patches. (line 34)
+* magit-am-skip: Maildir Patches. (line 38)
+* magit-apply: Applying. (line 33)
+* magit-bisect: Bisecting. (line 8)
+* magit-bisect-bad: Bisecting. (line 34)
+* magit-bisect-good: Bisecting. (line 39)
+* magit-bisect-mark: Bisecting. (line 44)
+* magit-bisect-reset: Bisecting. (line 57)
+* magit-bisect-run: Bisecting. (line 27)
+* magit-bisect-skip: Bisecting. (line 51)
+* magit-bisect-start: Bisecting. (line 16)
+* magit-blame: Blaming. (line 18)
+* magit-blame <1>: Blaming. (line 102)
+* magit-blame <2>: Commands for Buffers Visiting Files.
+ (line 93)
+* magit-blame-addition: Blaming. (line 29)
+* magit-blame-addition <1>: Blaming. (line 30)
+* magit-blame-copy-hash: Blaming. (line 127)
+* magit-blame-cycle-style: Blaming. (line 135)
+* magit-blame-echo: Blaming. (line 63)
+* magit-blame-echo <1>: Blaming. (line 64)
+* magit-blame-next-chunk: Blaming. (line 106)
+* magit-blame-next-chunk-same-commit: Blaming. (line 110)
+* magit-blame-previous-chunk: Blaming. (line 114)
+* magit-blame-previous-chunk-same-commit: Blaming. (line 118)
+* magit-blame-quit: Blaming. (line 122)
+* magit-blame-removal: Blaming. (line 45)
+* magit-blame-removal <1>: Blaming. (line 46)
+* magit-blame-reverse: Blaming. (line 54)
+* magit-blame-reverse <1>: Blaming. (line 55)
+* magit-blob-next: Minor Mode for Buffers Visiting Blobs.
+ (line 16)
+* magit-blob-previous: Commands for Buffers Visiting Files.
+ (line 116)
+* magit-blob-previous <1>: Minor Mode for Buffers Visiting Blobs.
+ (line 12)
+* magit-branch: Branch Commands. (line 12)
+* magit-branch-and-checkout: Branch Commands. (line 67)
+* magit-branch-checkout: Branch Commands. (line 74)
+* magit-branch-configure: Branch Commands. (line 29)
+* magit-branch-configure <1>: Branch Commands. (line 30)
+* magit-branch-configure <2>: Branch Commands. (line 31)
+* magit-branch-configure <3>: Branch Commands. (line 32)
+* magit-branch-create: Branch Commands. (line 57)
+* magit-branch-delete: Branch Commands. (line 147)
+* magit-branch-or-checkout: Branch Commands. (line 257)
+* magit-branch-orphan: Branch Commands. (line 252)
+* magit-branch-rename: Branch Commands. (line 153)
+* magit-branch-reset: Branch Commands. (line 131)
+* magit-branch-shelve: Auxiliary Branch Commands.
+ (line 9)
+* magit-branch-spinoff: Branch Commands. (line 97)
+* magit-branch-spinout: Branch Commands. (line 125)
+* magit-branch-unshelve: Auxiliary Branch Commands.
+ (line 20)
+* magit-checkout: Branch Commands. (line 49)
+* magit-cherry: Cherries. (line 17)
+* magit-cherry-apply: Cherry Picking. (line 24)
+* magit-cherry-copy: Cherry Picking. (line 17)
+* magit-cherry-donate: Cherry Picking. (line 54)
+* magit-cherry-harvest: Cherry Picking. (line 42)
+* magit-cherry-pick: Cherry Picking. (line 8)
+* magit-cherry-spinoff: Cherry Picking. (line 76)
+* magit-cherry-spinout: Cherry Picking. (line 65)
+* magit-clone: Cloning Repository. (line 20)
+* magit-clone-bare: Cloning Repository. (line 41)
+* magit-clone-mirror: Cloning Repository. (line 46)
+* magit-clone-regular: Cloning Repository. (line 29)
+* magit-clone-shallow: Cloning Repository. (line 34)
+* magit-clone-shallow-exclude: Cloning Repository. (line 61)
+* magit-clone-shallow-since: Cloning Repository. (line 54)
+* magit-commit: Initiating a Commit. (line 8)
+* magit-commit <1>: Commands for Buffers Visiting Files.
+ (line 38)
+* magit-commit-amend: Initiating a Commit. (line 19)
+* magit-commit-augment: Initiating a Commit. (line 67)
+* magit-commit-create: Initiating a Commit. (line 14)
+* magit-commit-extend: Initiating a Commit. (line 23)
+* magit-commit-fixup: Initiating a Commit. (line 43)
+* magit-commit-instant-fixup: Initiating a Commit. (line 51)
+* magit-commit-instant-squash: Initiating a Commit. (line 63)
+* magit-commit-reword: Initiating a Commit. (line 33)
+* magit-commit-squash: Initiating a Commit. (line 55)
+* magit-copy-buffer-revision: Common Commands. (line 28)
+* magit-copy-section-value: Common Commands. (line 10)
+* magit-cycle-margin-style: Log Margin. (line 70)
+* magit-debug-git-executable: Git Executable. (line 45)
+* magit-debug-git-executable <1>: Debugging Tools. (line 36)
+* magit-describe-section-briefly: Section Types and Values.
+ (line 13)
+* magit-describe-section-briefly <1>: Matching Sections. (line 6)
+* magit-diff: Diffing. (line 21)
+* magit-diff <1>: Commands for Buffers Visiting Files.
+ (line 45)
+* magit-diff-buffer-file: Commands for Buffers Visiting Files.
+ (line 56)
+* magit-diff-default-context: Refreshing Diffs. (line 73)
+* magit-diff-dwim: Diffing. (line 27)
+* magit-diff-edit-hunk-commit: Commands Available in Diffs.
+ (line 25)
+* magit-diff-flip-revs: Refreshing Diffs. (line 46)
+* magit-diff-less-context: Refreshing Diffs. (line 65)
+* magit-diff-more-context: Refreshing Diffs. (line 69)
+* magit-diff-paths: Diffing. (line 61)
+* magit-diff-range: Diffing. (line 31)
+* magit-diff-refresh: Refreshing Diffs. (line 11)
+* magit-diff-refresh <1>: Refreshing Diffs. (line 17)
+* magit-diff-save-default-arguments: Refreshing Diffs. (line 29)
+* magit-diff-set-default-arguments: Refreshing Diffs. (line 22)
+* magit-diff-show-or-scroll-down: Log Buffer. (line 45)
+* magit-diff-show-or-scroll-down <1>: Blaming. (line 89)
+* magit-diff-show-or-scroll-up: Log Buffer. (line 35)
+* magit-diff-show-or-scroll-up <1>: Blaming. (line 79)
+* magit-diff-staged: Diffing. (line 51)
+* magit-diff-switch-range-type: Refreshing Diffs. (line 41)
+* magit-diff-toggle-file-filter: Refreshing Diffs. (line 51)
+* magit-diff-toggle-refine-hunk: Refreshing Diffs. (line 37)
+* magit-diff-trace-definition: Commands Available in Diffs.
+ (line 14)
+* magit-diff-unstaged: Diffing. (line 57)
+* magit-diff-visit-file: Visiting Files and Blobs from a Diff.
+ (line 8)
+* magit-diff-visit-file-other-frame: Visiting Files and Blobs from a Diff.
+ (line 74)
+* magit-diff-visit-file-other-window: Visiting Files and Blobs from a Diff.
+ (line 73)
+* magit-diff-visit-file-worktree: Visiting Files and Blobs from a Diff.
+ (line 51)
+* magit-diff-visit-worktree-file-other-frame: Visiting Files and Blobs from a Diff.
+ (line 76)
+* magit-diff-visit-worktree-file-other-window: Visiting Files and Blobs from a Diff.
+ (line 75)
+* magit-diff-while-committing: Refreshing Diffs. (line 81)
+* magit-diff-while-committing <1>: Editing Commit Messages.
+ (line 58)
+* magit-diff-working-tree: Diffing. (line 45)
+* magit-discard: Applying. (line 40)
+* magit-dispatch: Transient Commands. (line 18)
+* magit-ediff: Ediffing. (line 21)
+* magit-ediff-compare: Ediffing. (line 26)
+* magit-ediff-dwim: Ediffing. (line 9)
+* magit-ediff-resolve: Ediffing. (line 35)
+* magit-ediff-show-commit: Ediffing. (line 65)
+* magit-ediff-show-staged: Ediffing. (line 57)
+* magit-ediff-show-stash: Ediffing. (line 69)
+* magit-ediff-show-unstaged: Ediffing. (line 53)
+* magit-ediff-show-working-tree: Ediffing. (line 61)
+* magit-ediff-stage: Ediffing. (line 48)
+* magit-edit-line-commit: Commands for Buffers Visiting Files.
+ (line 106)
+* magit-emacs-Q-command: Debugging Tools. (line 16)
+* magit-fetch: Fetching. (line 9)
+* magit-fetch-all: Fetching. (line 50)
+* magit-fetch-branch: Fetching. (line 40)
+* magit-fetch-from-pushremote: Fetching. (line 15)
+* magit-fetch-from-upstream: Fetching. (line 23)
+* magit-fetch-modules: Submodule Transient. (line 58)
+* magit-fetch-other: Fetching. (line 36)
+* magit-fetch-refspec: Fetching. (line 45)
+* magit-file-checkout: Resetting. (line 50)
+* magit-file-checkout <1>: Commands for Buffers Visiting Files.
+ (line 135)
+* magit-file-delete: Commands for Buffers Visiting Files.
+ (line 127)
+* magit-file-dispatch: Commands for Buffers Visiting Files.
+ (line 21)
+* magit-file-rename: Commands for Buffers Visiting Files.
+ (line 123)
+* magit-file-untrack: Commands for Buffers Visiting Files.
+ (line 131)
+* magit-find-file: General-Purpose Visit Commands.
+ (line 9)
+* magit-find-file-other-frame: General-Purpose Visit Commands.
+ (line 21)
+* magit-find-file-other-window: General-Purpose Visit Commands.
+ (line 15)
+* magit-git-command: Running Git Manually.
+ (line 25)
+* magit-git-command-topdir: Running Git Manually.
+ (line 17)
+* magit-go-backward: Log Buffer. (line 21)
+* magit-go-backward <1>: Refreshing Diffs. (line 91)
+* magit-go-forward: Log Buffer. (line 25)
+* magit-go-forward <1>: Refreshing Diffs. (line 95)
+* magit-init: Creating Repository. (line 6)
+* magit-jump-to-diffstat-or-diff: Commands Available in Diffs.
+ (line 45)
+* magit-kill-this-buffer: Minor Mode for Buffers Visiting Blobs.
+ (line 20)
+* magit-list-repositories: Repository List. (line 6)
+* magit-list-submodules: Listing Submodules. (line 13)
+* magit-list-submodules <1>: Submodule Transient. (line 54)
+* magit-log: Logging. (line 29)
+* magit-log <1>: Commands for Buffers Visiting Files.
+ (line 66)
+* magit-log-all: Logging. (line 60)
+* magit-log-all-branches: Logging. (line 56)
+* magit-log-branches: Logging. (line 52)
+* magit-log-buffer-file: Commands for Buffers Visiting Files.
+ (line 77)
+* magit-log-bury-buffer: Log Buffer. (line 14)
+* magit-log-current: Logging. (line 35)
+* magit-log-double-commit-limit: Log Buffer. (line 61)
+* magit-log-half-commit-limit: Log Buffer. (line 65)
+* magit-log-head: Logging. (line 48)
+* magit-log-move-to-parent: Log Buffer. (line 29)
+* magit-log-other: Logging. (line 41)
+* magit-log-refresh: Refreshing Logs. (line 11)
+* magit-log-refresh <1>: Refreshing Logs. (line 17)
+* magit-log-refresh <2>: Log Buffer. (line 6)
+* magit-log-save-default-arguments: Refreshing Logs. (line 29)
+* magit-log-select-pick: Select from Log. (line 20)
+* magit-log-select-quit: Select from Log. (line 26)
+* magit-log-set-default-arguments: Refreshing Logs. (line 22)
+* magit-log-toggle-commit-limit: Log Buffer. (line 55)
+* magit-log-trace-definition: Commands for Buffers Visiting Files.
+ (line 84)
+* magit-margin-settings: Log Margin. (line 57)
+* magit-merge: Merging. (line 9)
+* magit-merge <1>: Merging. (line 89)
+* magit-merge-abort: Merging. (line 95)
+* magit-merge-absorb: Merging. (line 45)
+* magit-merge-editmsg: Merging. (line 31)
+* magit-merge-into: Merging. (line 58)
+* magit-merge-nocommit: Merging. (line 38)
+* magit-merge-plain: Merging. (line 18)
+* magit-merge-preview: Merging. (line 81)
+* magit-merge-squash: Merging. (line 72)
+* magit-mode-bury-buffer: Quitting Windows. (line 6)
+* magit-notes: Notes. (line 8)
+* magit-notes-edit: Notes. (line 14)
+* magit-notes-merge: Notes. (line 38)
+* magit-notes-merge-abort: Notes. (line 52)
+* magit-notes-merge-commit: Notes. (line 47)
+* magit-notes-prune: Notes. (line 30)
+* magit-notes-remove: Notes. (line 22)
+* magit-patch: Plain Patches. (line 6)
+* magit-patch-apply: Plain Patches. (line 21)
+* magit-patch-apply <1>: Maildir Patches. (line 25)
+* magit-patch-create: Plain Patches. (line 12)
+* magit-patch-save: Plain Patches. (line 28)
+* magit-pop-revision-stack: Using the Revision Stack.
+ (line 6)
+* magit-process: Viewing Git Output. (line 16)
+* magit-process-kill: Viewing Git Output. (line 24)
+* magit-pull: Pulling. (line 9)
+* magit-pull-branch: Pulling. (line 30)
+* magit-pull-from-pushremote: Pulling. (line 14)
+* magit-pull-from-upstream: Pulling. (line 22)
+* magit-push: Pushing. (line 9)
+* magit-push-current: Pushing. (line 31)
+* magit-push-current-to-pushremote: Pushing. (line 15)
+* magit-push-current-to-upstream: Pushing. (line 23)
+* magit-push-implicitly args: Pushing. (line 74)
+* magit-push-matching: Pushing. (line 50)
+* magit-push-other: Pushing. (line 36)
+* magit-push-refspecs: Pushing. (line 41)
+* magit-push-tag: Pushing. (line 66)
+* magit-push-tags: Pushing. (line 58)
+* magit-push-to-remote remote args: Pushing. (line 92)
+* magit-rebase: Rebasing. (line 9)
+* magit-rebase-abort: Rebasing. (line 123)
+* magit-rebase-autosquash: Rebasing. (line 84)
+* magit-rebase-branch: Rebasing. (line 44)
+* magit-rebase-continue: Rebasing. (line 106)
+* magit-rebase-edit: Rebasing. (line 118)
+* magit-rebase-edit-commit: Rebasing. (line 89)
+* magit-rebase-interactive: Rebasing. (line 80)
+* magit-rebase-onto-pushremote: Rebasing. (line 28)
+* magit-rebase-onto-upstream: Rebasing. (line 36)
+* magit-rebase-remove-commit: Rebasing. (line 99)
+* magit-rebase-reword-commit: Rebasing. (line 94)
+* magit-rebase-skip: Rebasing. (line 113)
+* magit-rebase-subset: Rebasing. (line 50)
+* magit-reflog-current: Reflog. (line 11)
+* magit-reflog-head: Reflog. (line 19)
+* magit-reflog-other: Reflog. (line 15)
+* magit-refresh: Automatic Refreshing of Magit Buffers.
+ (line 24)
+* magit-refresh-all: Automatic Refreshing of Magit Buffers.
+ (line 33)
+* magit-remote: Remote Commands. (line 13)
+* magit-remote-add: Remote Commands. (line 50)
+* magit-remote-configure: Remote Commands. (line 33)
+* magit-remote-prune: Remote Commands. (line 69)
+* magit-remote-prune-refspecs: Remote Commands. (line 74)
+* magit-remote-remove: Remote Commands. (line 65)
+* magit-remote-rename: Remote Commands. (line 55)
+* magit-remote-set-url: Remote Commands. (line 60)
+* magit-reset-hard: Resetting. (line 26)
+* magit-reset-index: Staging and Unstaging.
+ (line 87)
+* magit-reset-index <1>: Resetting. (line 37)
+* magit-reset-keep: Resetting. (line 31)
+* magit-reset-mixed: Resetting. (line 15)
+* magit-reset-quickly: Resetting. (line 8)
+* magit-reset-soft: Resetting. (line 20)
+* magit-reset-worktree: Resetting. (line 44)
+* magit-reset-worktree <1>: Wip Modes. (line 66)
+* magit-reverse: Applying. (line 44)
+* magit-reverse-in-index: Staging and Unstaging.
+ (line 62)
+* magit-revert: Reverting. (line 6)
+* magit-revert-and-commit: Reverting. (line 15)
+* magit-revert-no-commit: Reverting. (line 21)
+* magit-run: Running Git Manually.
+ (line 12)
+* magit-run-git-gui: Running Git Manually.
+ (line 66)
+* magit-run-gitk: Running Git Manually.
+ (line 54)
+* magit-run-gitk-all: Running Git Manually.
+ (line 58)
+* magit-run-gitk-branches: Running Git Manually.
+ (line 62)
+* magit-section-backward: Section Movement. (line 10)
+* magit-section-backward-siblings: Section Movement. (line 20)
+* magit-section-cycle: Section Visibility. (line 13)
+* magit-section-cycle-diffs: Section Visibility. (line 17)
+* magit-section-cycle-global: Section Visibility. (line 22)
+* magit-section-forward: Section Movement. (line 16)
+* magit-section-forward-siblings: Section Movement. (line 26)
+* magit-section-hide: Section Visibility. (line 49)
+* magit-section-hide-children: Section Visibility. (line 64)
+* magit-section-show: Section Visibility. (line 45)
+* magit-section-show-children: Section Visibility. (line 58)
+* magit-section-show-headings: Section Visibility. (line 53)
+* magit-section-show-level-1: Section Visibility. (line 26)
+* magit-section-show-level-1-all: Section Visibility. (line 33)
+* magit-section-show-level-2: Section Visibility. (line 27)
+* magit-section-show-level-2-all: Section Visibility. (line 34)
+* magit-section-show-level-3: Section Visibility. (line 28)
+* magit-section-show-level-3-all: Section Visibility. (line 35)
+* magit-section-show-level-4: Section Visibility. (line 29)
+* magit-section-show-level-4-all: Section Visibility. (line 36)
+* magit-section-toggle: Section Visibility. (line 9)
+* magit-section-toggle-children: Section Visibility. (line 68)
+* magit-section-up: Section Movement. (line 31)
+* magit-sequence-abort: Cherry Picking. (line 98)
+* magit-sequence-abort <1>: Reverting. (line 39)
+* magit-sequence-continue: Cherry Picking. (line 90)
+* magit-sequence-continue <1>: Reverting. (line 31)
+* magit-sequence-skip: Cherry Picking. (line 94)
+* magit-sequence-skip <1>: Reverting. (line 35)
+* magit-shell-command: Running Git Manually.
+ (line 40)
+* magit-shell-command-topdir: Running Git Manually.
+ (line 35)
+* magit-show-commit: Diffing. (line 69)
+* magit-show-commit <1>: Blaming. (line 75)
+* magit-show-refs: References Buffer. (line 6)
+* magit-show-refs-current: References Buffer. (line 26)
+* magit-show-refs-head: References Buffer. (line 21)
+* magit-show-refs-other: References Buffer. (line 32)
+* magit-snapshot-both: Stashing. (line 40)
+* magit-snapshot-index: Stashing. (line 47)
+* magit-snapshot-worktree: Stashing. (line 52)
+* magit-stage: Staging and Unstaging.
+ (line 28)
+* magit-stage-file: Staging from File-Visiting Buffers.
+ (line 10)
+* magit-stage-file <1>: Commands for Buffers Visiting Files.
+ (line 29)
+* magit-stage-modified: Staging and Unstaging.
+ (line 36)
+* magit-stash: Stashing. (line 8)
+* magit-stash-apply: Stashing. (line 59)
+* magit-stash-both: Stashing. (line 14)
+* magit-stash-branch: Stashing. (line 81)
+* magit-stash-branch-here: Stashing. (line 86)
+* magit-stash-clear: Stashing. (line 96)
+* magit-stash-drop: Stashing. (line 72)
+* magit-stash-format-patch: Stashing. (line 92)
+* magit-stash-index: Stashing. (line 21)
+* magit-stash-keep-index: Stashing. (line 33)
+* magit-stash-list: Stashing. (line 100)
+* magit-stash-pop: Stashing. (line 65)
+* magit-stash-show: Diffing. (line 74)
+* magit-stash-show <1>: Stashing. (line 77)
+* magit-stash-worktree: Stashing. (line 26)
+* magit-status: Status Buffer. (line 22)
+* magit-submodule: Submodule Transient. (line 6)
+* magit-submodule-add: Submodule Transient. (line 20)
+* magit-submodule-fetch: Fetching. (line 54)
+* magit-submodule-populate: Submodule Transient. (line 34)
+* magit-submodule-register: Submodule Transient. (line 27)
+* magit-submodule-synchronize: Submodule Transient. (line 44)
+* magit-submodule-unpopulate: Submodule Transient. (line 50)
+* magit-submodule-update: Submodule Transient. (line 39)
+* magit-subtree: Subtree. (line 8)
+* magit-subtree-add: Subtree. (line 25)
+* magit-subtree-add-commit: Subtree. (line 30)
+* magit-subtree-export: Subtree. (line 42)
+* magit-subtree-import: Subtree. (line 13)
+* magit-subtree-merge: Subtree. (line 34)
+* magit-subtree-pull: Subtree. (line 38)
+* magit-subtree-push: Subtree. (line 54)
+* magit-subtree-split: Subtree. (line 59)
+* magit-tag: Tagging. (line 8)
+* magit-tag-create: Tagging. (line 14)
+* magit-tag-delete: Tagging. (line 39)
+* magit-tag-prune: Tagging. (line 46)
+* magit-tag-release: Tagging. (line 19)
+* magit-toggle-buffer-lock: Modes and Buffers. (line 17)
+* magit-toggle-margin: Refreshing Logs. (line 37)
+* magit-toggle-margin <1>: Log Margin. (line 66)
+* magit-toggle-margin-details: Log Margin. (line 74)
+* magit-toggle-verbose-refresh: Debugging Tools. (line 30)
+* magit-unstage: Staging and Unstaging.
+ (line 43)
+* magit-unstage-all: Staging and Unstaging.
+ (line 52)
+* magit-unstage-file: Staging from File-Visiting Buffers.
+ (line 18)
+* magit-unstage-file <1>: Commands for Buffers Visiting Files.
+ (line 33)
+* magit-version: Git Executable. (line 17)
+* magit-version <1>: Debugging Tools. (line 10)
+* magit-visit-ref: References Buffer. (line 181)
+* magit-wip-commit: Wip Modes. (line 88)
+* magit-wip-log: Wip Modes. (line 48)
+* magit-wip-log-current: Wip Modes. (line 57)
+* magit-worktree: Worktree. (line 8)
+* magit-worktree-branch: Worktree. (line 17)
+* magit-worktree-checkout: Worktree. (line 13)
+* magit-worktree-delete: Worktree. (line 25)
+* magit-worktree-move: Worktree. (line 21)
+* magit-worktree-status: Worktree. (line 30)
+* scroll-down: Commands Available in Diffs.
+ (line 60)
+* scroll-up: Commands Available in Diffs.
+ (line 56)
+* with-editor-cancel: Editing Commit Messages.
+ (line 22)
+* with-editor-cancel <1>: Editing Rebase Sequences.
+ (line 11)
+* with-editor-debug: Debugging Tools. (line 44)
+* with-editor-finish: Editing Commit Messages.
+ (line 17)
+* with-editor-finish <1>: Editing Rebase Sequences.
+ (line 6)
+
+\1f
+File: magit.info, Node: Function Index, Next: Variable Index, Prev: Command Index, Up: Top
+
+Appendix E Function Index
+*************************
+
+\0\b[index\0\b]
+* Menu:
+
+* bug-reference-mode: Commit Mode and Hooks.
+ (line 56)
+* git-commit-check-style-conventions: Commit Message Conventions.
+ (line 40)
+* git-commit-propertize-diff: Commit Mode and Hooks.
+ (line 47)
+* git-commit-save-message: Commit Mode and Hooks.
+ (line 28)
+* git-commit-setup-changelog-support: Commit Mode and Hooks.
+ (line 32)
+* git-commit-turn-on-auto-fill: Commit Mode and Hooks.
+ (line 37)
+* git-commit-turn-on-flyspell: Commit Mode and Hooks.
+ (line 42)
+* ido-enter-magit-status: Status Buffer. (line 72)
+* magit-add-section-hook: Section Hooks. (line 20)
+* magit-after-save-refresh-status: Automatic Refreshing of Magit Buffers.
+ (line 58)
+* magit-branch-or-checkout: Branch Commands. (line 257)
+* magit-branch-orphan: Branch Commands. (line 252)
+* magit-branch-shelve: Auxiliary Branch Commands.
+ (line 9)
+* magit-branch-unshelve: Auxiliary Branch Commands.
+ (line 20)
+* magit-builtin-completing-read: Support for Completion Frameworks.
+ (line 42)
+* magit-call-git: Calling Git for Effect.
+ (line 28)
+* magit-call-process: Calling Git for Effect.
+ (line 32)
+* magit-cancel-section: Creating Sections. (line 71)
+* magit-completing-read: Support for Completion Frameworks.
+ (line 60)
+* magit-current-section: Section Selection. (line 6)
+* magit-define-section-jumper: Creating Sections. (line 77)
+* magit-diff-scope: Matching Sections. (line 118)
+* magit-diff-type: Matching Sections. (line 95)
+* magit-diff-visit-file-other-frame: Visiting Files and Blobs from a Diff.
+ (line 74)
+* magit-diff-visit-file-other-window: Visiting Files and Blobs from a Diff.
+ (line 73)
+* magit-diff-visit-worktree-file-other-frame: Visiting Files and Blobs from a Diff.
+ (line 76)
+* magit-diff-visit-worktree-file-other-window: Visiting Files and Blobs from a Diff.
+ (line 75)
+* magit-disable-section-inserter: Per-Repository Configuration.
+ (line 31)
+* magit-display-buffer: Switching Buffers. (line 6)
+* magit-display-buffer-fullcolumn-most-v1: Switching Buffers. (line 75)
+* magit-display-buffer-fullframe-status-topleft-v1: Switching Buffers.
+ (line 65)
+* magit-display-buffer-fullframe-status-v1: Switching Buffers.
+ (line 59)
+* magit-display-buffer-same-window-except-diff-v1: Switching Buffers.
+ (line 53)
+* magit-display-buffer-traditional: Switching Buffers. (line 45)
+* magit-file-checkout: Commands for Buffers Visiting Files.
+ (line 135)
+* magit-file-delete: Commands for Buffers Visiting Files.
+ (line 127)
+* magit-file-rename: Commands for Buffers Visiting Files.
+ (line 123)
+* magit-file-untrack: Commands for Buffers Visiting Files.
+ (line 131)
+* magit-find-file: General-Purpose Visit Commands.
+ (line 9)
+* magit-find-file-other-frame: General-Purpose Visit Commands.
+ (line 21)
+* magit-find-file-other-window: General-Purpose Visit Commands.
+ (line 15)
+* magit-generate-buffer-name-default-function: Naming Buffers.
+ (line 17)
+* magit-get-section: Matching Sections. (line 16)
+* magit-git: Calling Git for Effect.
+ (line 59)
+* magit-git-exit-code: Getting a Value from Git.
+ (line 10)
+* magit-git-failure: Getting a Value from Git.
+ (line 19)
+* magit-git-false: Getting a Value from Git.
+ (line 29)
+* magit-git-insert: Getting a Value from Git.
+ (line 34)
+* magit-git-items: Getting a Value from Git.
+ (line 49)
+* magit-git-lines: Getting a Value from Git.
+ (line 44)
+* magit-git-str: Getting a Value from Git.
+ (line 72)
+* magit-git-string: Getting a Value from Git.
+ (line 38)
+* magit-git-success: Getting a Value from Git.
+ (line 14)
+* magit-git-true: Getting a Value from Git.
+ (line 24)
+* magit-git-wash: Calling Git for Effect.
+ (line 64)
+* magit-hunk-set-window-start: Section Movement. (line 51)
+* magit-ido-completing-read: Support for Completion Frameworks.
+ (line 48)
+* magit-insert-am-sequence: Status Sections. (line 28)
+* magit-insert-assumed-unchanged-files: Status Sections. (line 117)
+* magit-insert-bisect-log: Status Sections. (line 46)
+* magit-insert-bisect-output: Status Sections. (line 38)
+* magit-insert-bisect-rest: Status Sections. (line 42)
+* magit-insert-diff-filter-header: Status Header Sections.
+ (line 38)
+* magit-insert-error-header: Status Header Sections.
+ (line 28)
+* magit-insert-head-branch-header: Status Header Sections.
+ (line 42)
+* magit-insert-heading: Creating Sections. (line 42)
+* magit-insert-ignored-files: Status Sections. (line 100)
+* magit-insert-local-branches: References Sections. (line 17)
+* magit-insert-merge-log: Status Sections. (line 18)
+* magit-insert-modules: Status Module Sections.
+ (line 12)
+* magit-insert-modules-overview: Status Module Sections.
+ (line 33)
+* magit-insert-modules-unpulled-from-pushremote: Status Module Sections.
+ (line 50)
+* magit-insert-modules-unpulled-from-upstream: Status Module Sections.
+ (line 44)
+* magit-insert-modules-unpushed-to-pushremote: Status Module Sections.
+ (line 62)
+* magit-insert-modules-unpushed-to-upstream: Status Module Sections.
+ (line 56)
+* magit-insert-push-branch-header: Status Header Sections.
+ (line 51)
+* magit-insert-rebase-sequence: Status Sections. (line 23)
+* magit-insert-recent-commits: Status Sections. (line 131)
+* magit-insert-remote-branches: References Sections. (line 21)
+* magit-insert-remote-header: Status Header Sections.
+ (line 67)
+* magit-insert-repo-header: Status Header Sections.
+ (line 63)
+* magit-insert-section: Creating Sections. (line 6)
+* magit-insert-sequencer-sequence: Status Sections. (line 33)
+* magit-insert-skip-worktree-files: Status Sections. (line 110)
+* magit-insert-staged-changes: Status Sections. (line 63)
+* magit-insert-stashes: Status Sections. (line 67)
+* magit-insert-status-headers: Status Header Sections.
+ (line 12)
+* magit-insert-tags: References Sections. (line 25)
+* magit-insert-tags-header: Status Header Sections.
+ (line 56)
+* magit-insert-tracked-files: Status Sections. (line 96)
+* magit-insert-unpulled-cherries: Status Sections. (line 142)
+* magit-insert-unpulled-from-pushremote: Status Sections. (line 79)
+* magit-insert-unpulled-from-upstream: Status Sections. (line 74)
+* magit-insert-unpulled-or-recent-commits: Status Sections. (line 124)
+* magit-insert-unpushed-cherries: Status Sections. (line 149)
+* magit-insert-unpushed-to-pushremote: Status Sections. (line 89)
+* magit-insert-unpushed-to-upstream: Status Sections. (line 84)
+* magit-insert-unstaged-changes: Status Sections. (line 59)
+* magit-insert-untracked-files: Status Sections. (line 50)
+* magit-insert-upstream-branch-header: Status Header Sections.
+ (line 46)
+* magit-insert-user-header: Status Header Sections.
+ (line 75)
+* magit-list-repositories: Repository List. (line 6)
+* magit-list-submodules: Listing Submodules. (line 13)
+* magit-log-maybe-show-more-commits: Section Movement. (line 66)
+* magit-log-maybe-update-blob-buffer: Section Movement. (line 82)
+* magit-log-maybe-update-revision-buffer: Section Movement. (line 74)
+* magit-maybe-set-dedicated: Switching Buffers. (line 100)
+* magit-mode-display-buffer: Refreshing Buffers. (line 33)
+* magit-mode-quit-window: Quitting Windows. (line 34)
+* magit-mode-setup: Refreshing Buffers. (line 17)
+* magit-push-implicitly: Pushing. (line 74)
+* magit-push-to-remote: Pushing. (line 92)
+* magit-region-sections: Section Selection. (line 10)
+* magit-region-values: Section Selection. (line 37)
+* magit-repolist-column-branch: Repository List. (line 44)
+* magit-repolist-column-branches: Repository List. (line 53)
+* magit-repolist-column-flag: Repository List. (line 61)
+* magit-repolist-column-ident: Repository List. (line 30)
+* magit-repolist-column-path: Repository List. (line 35)
+* magit-repolist-column-stashes: Repository List. (line 57)
+* magit-repolist-column-unpulled-from-pushremote: Repository List.
+ (line 81)
+* magit-repolist-column-unpulled-from-upstream: Repository List.
+ (line 76)
+* magit-repolist-column-unpushed-to-pushremote: Repository List.
+ (line 91)
+* magit-repolist-column-unpushed-to-upstream: Repository List.
+ (line 86)
+* magit-repolist-column-upstream: Repository List. (line 48)
+* magit-repolist-column-version: Repository List. (line 39)
+* magit-restore-window-configuration: Quitting Windows. (line 23)
+* magit-run-git: Calling Git for Effect.
+ (line 36)
+* magit-run-git-async: Calling Git for Effect.
+ (line 74)
+* magit-run-git-with-editor: Calling Git for Effect.
+ (line 87)
+* magit-run-git-with-input: Calling Git for Effect.
+ (line 40)
+* magit-run-git-with-logfile: Calling Git for Effect.
+ (line 50)
+* magit-save-window-configuration: Switching Buffers. (line 89)
+* magit-section-case: Matching Sections. (line 71)
+* magit-section-hide: Section Visibility. (line 49)
+* magit-section-hide-children: Section Visibility. (line 64)
+* magit-section-ident: Matching Sections. (line 11)
+* magit-section-match: Matching Sections. (line 21)
+* magit-section-set-window-start: Section Movement. (line 59)
+* magit-section-show: Section Visibility. (line 45)
+* magit-section-show-children: Section Visibility. (line 58)
+* magit-section-show-headings: Section Visibility. (line 53)
+* magit-section-toggle-children: Section Visibility. (line 68)
+* magit-section-value-if: Matching Sections. (line 61)
+* magit-start-git: Calling Git for Effect.
+ (line 99)
+* magit-start-process: Calling Git for Effect.
+ (line 118)
+* magit-stashes-maybe-update-stash-buffer: Section Movement. (line 106)
+* magit-status-maybe-update-blob-buffer: Section Movement. (line 100)
+* magit-status-maybe-update-revision-buffer: Section Movement.
+ (line 88)
+* magit-status-maybe-update-stash-buffer: Section Movement. (line 94)
+* magit-wip-log: Wip Modes. (line 48)
+* magit-wip-log-current: Wip Modes. (line 57)
+* with-editor-usage-message: Commit Mode and Hooks.
+ (line 60)
+
+\1f
+File: magit.info, Node: Variable Index, Prev: Function Index, Up: Top
+
+Appendix F Variable Index
+*************************
+
+\0\b[index\0\b]
+* Menu:
+
+* auto-revert-buffer-list-filter: Automatic Reverting of File-Visiting Buffers.
+ (line 81)
+* auto-revert-interval: Automatic Reverting of File-Visiting Buffers.
+ (line 76)
+* auto-revert-mode: Automatic Reverting of File-Visiting Buffers.
+ (line 62)
+* auto-revert-stop-on-user-input: Automatic Reverting of File-Visiting Buffers.
+ (line 71)
+* auto-revert-use-notify: Automatic Reverting of File-Visiting Buffers.
+ (line 49)
+* auto-revert-verbose: Automatic Reverting of File-Visiting Buffers.
+ (line 103)
+* branch.autoSetupMerge: Branch Git Variables.
+ (line 81)
+* branch.autoSetupRebase: Branch Git Variables.
+ (line 98)
+* branch.NAME.description: Branch Git Variables.
+ (line 48)
+* branch.NAME.merge: Branch Git Variables.
+ (line 10)
+* branch.NAME.pushRemote: Branch Git Variables.
+ (line 34)
+* branch.NAME.rebase: Branch Git Variables.
+ (line 22)
+* branch.NAME.remote: Branch Git Variables.
+ (line 16)
+* core.notesRef: Notes. (line 60)
+* git-commit-fill-column: Commit Message Conventions.
+ (line 19)
+* git-commit-finish-query-functions: Commit Message Conventions.
+ (line 24)
+* git-commit-known-pseudo-headers: Commit Pseudo Headers.
+ (line 9)
+* git-commit-major-mode: Commit Mode and Hooks.
+ (line 12)
+* git-commit-setup-hook: Commit Mode and Hooks.
+ (line 22)
+* git-commit-setup-hook <1>: Commit Mode and Hooks.
+ (line 64)
+* git-commit-style-convention-checks: Commit Message Conventions.
+ (line 46)
+* git-commit-summary-max-length: Commit Message Conventions.
+ (line 13)
+* git-rebase-auto-advance: Editing Rebase Sequences.
+ (line 99)
+* git-rebase-confirm-cancel: Editing Rebase Sequences.
+ (line 107)
+* git-rebase-show-instructions: Editing Rebase Sequences.
+ (line 103)
+* global-auto-revert-mode: Automatic Reverting of File-Visiting Buffers.
+ (line 22)
+* magit-auto-revert-immediately: Automatic Reverting of File-Visiting Buffers.
+ (line 32)
+* magit-auto-revert-mode: Automatic Reverting of File-Visiting Buffers.
+ (line 17)
+* magit-auto-revert-tracked-only: Automatic Reverting of File-Visiting Buffers.
+ (line 55)
+* magit-bisect-show-graph: Bisecting. (line 65)
+* magit-blame-disable-modes: Blaming. (line 165)
+* magit-blame-echo-style: Blaming. (line 148)
+* magit-blame-goto-chunk-hook: Blaming. (line 171)
+* magit-blame-read-only: Blaming. (line 160)
+* magit-blame-styles: Blaming. (line 143)
+* magit-blame-time-format: Blaming. (line 155)
+* magit-branch-adjust-remote-upstream-alist: Branch Commands. (line 210)
+* magit-branch-direct-configure: Branch Commands. (line 20)
+* magit-branch-prefer-remote-upstream: Branch Commands. (line 165)
+* magit-branch-read-upstream-first: Branch Commands. (line 159)
+* magit-buffer-name-format: Naming Buffers. (line 27)
+* magit-bury-buffer-function: Quitting Windows. (line 14)
+* magit-cherry-margin: Cherries. (line 22)
+* magit-clone-always-transient: Cloning Repository. (line 12)
+* magit-clone-default-directory: Cloning Repository. (line 90)
+* magit-clone-name-alist: Cloning Repository. (line 103)
+* magit-clone-set-remote-head: Cloning Repository. (line 68)
+* magit-clone-set-remote.pushDefault: Cloning Repository. (line 78)
+* magit-clone-url-format: Cloning Repository. (line 124)
+* magit-commit-ask-to-stage: Initiating a Commit. (line 75)
+* magit-commit-extend-override-date: Initiating a Commit. (line 80)
+* magit-commit-reword-override-date: Initiating a Commit. (line 84)
+* magit-commit-squash-confirm: Initiating a Commit. (line 88)
+* magit-completing-read-function: Support for Completion Frameworks.
+ (line 27)
+* magit-define-global-key-bindings: Default Bindings. (line 6)
+* magit-diff-adjust-tab-width: Diff Options. (line 21)
+* magit-diff-buffer-file-locked: Commands for Buffers Visiting Files.
+ (line 61)
+* magit-diff-extra-stat-arguments: Diff Options. (line 128)
+* magit-diff-hide-trailing-cr-characters: Diff Options. (line 90)
+* magit-diff-highlight-hunk-region-functions: Diff Options. (line 94)
+* magit-diff-highlight-indentation: Diff Options. (line 75)
+* magit-diff-highlight-trailing: Diff Options. (line 70)
+* magit-diff-paint-whitespace: Diff Options. (line 43)
+* magit-diff-paint-whitespace-lines: Diff Options. (line 60)
+* magit-diff-refine-hunk: Diff Options. (line 6)
+* magit-diff-refine-ignore-whitespace: Diff Options. (line 16)
+* magit-diff-unmarked-lines-keep-foreground: Diff Options. (line 120)
+* magit-diff-visit-previous-blob: Visiting Files and Blobs from a Diff.
+ (line 39)
+* magit-direct-use-buffer-arguments: Transient Arguments and Buffer Variables.
+ (line 73)
+* magit-display-buffer-function: Switching Buffers. (line 27)
+* magit-display-buffer-noselect: Switching Buffers. (line 18)
+* magit-dwim-selection: Completion and Confirmation.
+ (line 42)
+* magit-ediff-dwim-show-on-hunks: Ediffing. (line 73)
+* magit-ediff-quit-hook: Ediffing. (line 88)
+* magit-ediff-show-stash-with-index: Ediffing. (line 81)
+* magit-generate-buffer-name-function: Naming Buffers. (line 6)
+* magit-git-debug: Viewing Git Output. (line 28)
+* magit-git-debug <1>: Getting a Value from Git.
+ (line 64)
+* magit-git-executable: Git Executable. (line 39)
+* magit-git-global-arguments: Global Git Arguments.
+ (line 6)
+* magit-keep-region-overlay: The Selection. (line 52)
+* magit-list-refs-sortby: Additional Completion Options.
+ (line 6)
+* magit-log-auto-more: Log Buffer. (line 69)
+* magit-log-buffer-file-locked: Commands for Buffers Visiting Files.
+ (line 88)
+* magit-log-margin: Log Margin. (line 12)
+* magit-log-margin-show-committer-date: Log Margin. (line 49)
+* magit-log-section-commit-count: Status Sections. (line 136)
+* magit-log-select-margin: Select from Log. (line 30)
+* magit-log-show-refname-after-summary: Log Buffer. (line 75)
+* magit-log-trace-definition-function: Commands Available in Diffs.
+ (line 18)
+* magit-module-sections-hook: Status Module Sections.
+ (line 20)
+* magit-module-sections-nested: Status Module Sections.
+ (line 24)
+* magit-no-confirm: Action Confirmation. (line 18)
+* magit-pop-revision-stack-format: Using the Revision Stack.
+ (line 35)
+* magit-post-display-buffer-hook: Switching Buffers. (line 95)
+* magit-pre-display-buffer-hook: Switching Buffers. (line 84)
+* magit-prefer-remote-upstream: Branch Git Variables.
+ (line 126)
+* magit-prefix-use-buffer-arguments: Transient Arguments and Buffer Variables.
+ (line 64)
+* magit-process-raise-error: Calling Git for Effect.
+ (line 145)
+* magit-pull-or-fetch: Fetching. (line 59)
+* magit-reflog-margin: Reflog. (line 23)
+* magit-refresh-args: Refreshing Buffers. (line 55)
+* magit-refresh-buffer-hook: Automatic Refreshing of Magit Buffers.
+ (line 42)
+* magit-refresh-function: Refreshing Buffers. (line 49)
+* magit-refresh-status-buffer: Automatic Refreshing of Magit Buffers.
+ (line 48)
+* magit-refs-filter-alist: References Buffer. (line 159)
+* magit-refs-focus-column-width: References Buffer. (line 82)
+* magit-refs-margin: References Buffer. (line 97)
+* magit-refs-margin-for-tags: References Buffer. (line 125)
+* magit-refs-pad-commit-counts: References Buffer. (line 49)
+* magit-refs-primary-column-width: References Buffer. (line 69)
+* magit-refs-sections-hook: References Sections. (line 13)
+* magit-refs-show-commit-count: References Buffer. (line 37)
+* magit-refs-show-remote-prefix: References Buffer. (line 62)
+* magit-remote-add-set-remote.pushDefault: Remote Commands. (line 92)
+* magit-remote-direct-configure: Remote Commands. (line 21)
+* magit-repolist-columns: Repository List. (line 14)
+* magit-repository-directories: Status Buffer. (line 58)
+* magit-revision-filter-files-on-follow: Revision Buffer. (line 64)
+* magit-revision-insert-related-refs: Revision Buffer. (line 6)
+* magit-revision-show-gravatars: Revision Buffer. (line 19)
+* magit-revision-use-hash-sections: Revision Buffer. (line 36)
+* magit-root-section: Matching Sections. (line 87)
+* magit-save-repository-buffers: Automatic Saving of File-Visiting Buffers.
+ (line 13)
+* magit-section-cache-visibility: Section Visibility. (line 95)
+* magit-section-initial-visibility-alist: Section Visibility. (line 78)
+* magit-section-movement-hook: Section Movement. (line 46)
+* magit-section-set-visibility-hook: Section Visibility. (line 106)
+* magit-section-show-child-count: Section Options. (line 9)
+* magit-section-visibility-indicator: Section Visibility. (line 124)
+* magit-shell-command-verbose-prompt: Running Git Manually.
+ (line 47)
+* magit-stashes-margin: Stashing. (line 104)
+* magit-status-headers-hook: Status Header Sections.
+ (line 18)
+* magit-status-margin: Status Options. (line 10)
+* magit-status-refresh-hook: Status Options. (line 6)
+* magit-status-sections-hook: Status Sections. (line 10)
+* magit-submodule-list-columns: Listing Submodules. (line 21)
+* magit-this-process: Calling Git for Effect.
+ (line 140)
+* magit-uniquify-buffer-names: Naming Buffers. (line 74)
+* magit-unstage-committed: Staging and Unstaging.
+ (line 56)
+* magit-update-other-window-delay: Section Movement. (line 112)
+* magit-visit-ref-behavior: References Buffer. (line 192)
+* magit-wip-after-apply-mode: Legacy Wip Modes. (line 19)
+* magit-wip-after-apply-mode-lighter: Legacy Wip Modes. (line 59)
+* magit-wip-after-save-local-mode-lighter: Legacy Wip Modes. (line 55)
+* magit-wip-after-save-mode: Legacy Wip Modes. (line 13)
+* magit-wip-before-change-mode: Legacy Wip Modes. (line 33)
+* magit-wip-before-change-mode-lighter: Legacy Wip Modes. (line 63)
+* magit-wip-initial-backup-mode: Legacy Wip Modes. (line 38)
+* magit-wip-initial-backup-mode-lighter: Legacy Wip Modes. (line 67)
+* magit-wip-merge-branch: Wip Graph. (line 6)
+* magit-wip-mode: Wip Modes. (line 30)
+* magit-wip-mode-lighter: Wip Modes. (line 104)
+* magit-wip-namespace: Wip Modes. (line 96)
+* notes.displayRef: Notes. (line 65)
+* pull.rebase: Branch Git Variables.
+ (line 57)
+* remote.NAME.fetch: Remote Git Variables.
+ (line 15)
+* remote.NAME.push: Remote Git Variables.
+ (line 26)
+* remote.NAME.pushurl: Remote Git Variables.
+ (line 20)
+* remote.NAME.tagOpts: Remote Git Variables.
+ (line 31)
+* remote.NAME.url: Remote Git Variables.
+ (line 10)
+* remote.pushDefault: Branch Git Variables.
+ (line 71)
+
+++ /dev/null
-;;; magit-todos-autoloads.el --- automatically extracted autoloads
-;;
-;;; Code:
-
-(add-to-list 'load-path (directory-file-name
- (or (file-name-directory #$) (car load-path))))
-
-\f
-;;;### (autoloads nil "magit-todos" "magit-todos.el" (0 0 0 0))
-;;; Generated autoloads from magit-todos.el
-
-(defvar magit-todos-mode nil "\
-Non-nil if Magit-Todos mode is enabled.
-See the `magit-todos-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-todos-mode'.")
-
-(custom-autoload 'magit-todos-mode "magit-todos" nil)
-
-(autoload 'magit-todos-mode "magit-todos" "\
-Show list of to-do items in Magit status buffer for tracked files in repo.
-
-\(fn &optional ARG)" t nil)
-
-(autoload 'magit-todos-list "magit-todos" "\
-Show to-do list of the current Git repository in a buffer.
-With prefix, prompt for repository.
-
-\(fn &optional DIRECTORY)" t nil)
-
-(autoload 'magit-todos-list-internal "magit-todos" "\
-Open buffer showing to-do list of repository at DIRECTORY.
-
-\(fn DIRECTORY)" nil nil)
-
-(if (fboundp 'register-definition-prefixes) (register-definition-prefixes "magit-todos" '("magit-todos-")))
-
-;;;***
-\f
-;; Local Variables:
-;; version-control: never
-;; no-byte-compile: t
-;; no-update-autoloads: t
-;; coding: utf-8
-;; End:
-;;; magit-todos-autoloads.el ends here
+++ /dev/null
-;;; -*- no-byte-compile: t -*-
-(define-package "magit-todos" "20200128.828" "Show source file TODOs in Magit" '((emacs "25.2") (async "1.9.2") (dash "2.13.0") (f "0.17.2") (hl-todo "1.9.0") (magit "2.13.0") (pcre2el "1.8") (s "1.12.0")) :commit "5d42e20b47daf844ac42d4d5aa93d3a75958eee7" :keywords '("magit" "vc") :authors '(("Adam Porter" . "adamNOSPAMalphapapa.net")) :maintainer '("Adam Porter" . "adamNOSPAMalphapapa.net") :url "http://github.com/alphapapa/magit-todos")
+++ /dev/null
-;;; magit-todos.el --- Show source file TODOs in Magit -*- lexical-binding: t; -*-
-
-;; Copyright (C) 2018 Adam Porter
-
-;; Author: Adam Porter <adamNOSPAMalphapapa.net>
-;; URL: http://github.com/alphapapa/magit-todos
-;; Package-Version: 20200128.828
-;; Version: 1.5
-;; Package-Requires: ((emacs "25.2") (async "1.9.2") (dash "2.13.0") (f "0.17.2") (hl-todo "1.9.0") (magit "2.13.0") (pcre2el "1.8") (s "1.12.0"))
-;; Keywords: magit, vc
-
-;;; Commentary:
-
-;; This package displays keyword entries from source code comments and Org files
-;; in the Magit status buffer. Activating an item jumps to it in its file. By
-;; default, it uses keywords from `hl-todo', minus a few (like "NOTE").
-
-;;;; Usage:
-
-;; Run `magit-todos-mode', then open a Magit status buffer.
-
-;;;; Tips:
-
-;; + You can customize settings in the `magit-todos' group.
-
-;;; Installation:
-
-;;;; MELPA
-
-;; If you installed from MELPA, you're done.
-
-;;;; Manual
-
-;; Install these required packages:
-
-;; async
-;; dash
-;; f
-;; hl-todo
-;; magit
-;; pcre2el
-;; s
-
-;; Then put this file in your load-path, and put this in your init file:
-
-;; (require 'magit-todos)
-
-;;; License:
-
-;; 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 <http://www.gnu.org/licenses/>.
-
-;;; Code:
-
-;;;; Requirements
-
-(require 'cl-lib)
-(require 'org)
-(require 'grep)
-(require 'seq)
-
-(require 'async)
-(require 'dash)
-(require 'f)
-(require 'hl-todo)
-(require 'magit)
-(require 'pcre2el)
-(require 's)
-
-;;;; Structs
-
-(cl-defstruct magit-todos-item
- filename org-level line column position keyword suffix description)
-
-;;;; Variables
-
-(defvar magit-todos-keywords-list nil
- "List of to-do keywords.
-Set automatically by `magit-todos-keywords' customization.")
-
-(defvar magit-todos-grep-result-regexp nil
- "Regular expression for grep results.
-This should be set automatically by customizing
-`magit-todos-keywords'.")
-
-(defvar magit-todos-ag-result-regexp nil
- "Regular expression for ag results.
-This should be set automatically by customizing
-`magit-todos-keywords'.")
-
-(defvar magit-todos-rg-result-regexp nil
- "Regular expression for rg results.
-This should be set automatically by customizing
-`magit-todos-keywords'.")
-
-(defvar magit-todos-git-grep-result-regexp nil
- "Regular expression for git-grep results.
-This should be set automatically by customizing
-`magit-todos-keywords'.")
-
-(defvar magit-todos-search-regexp nil
- "Regular expression to match keyword items with rg, ag, and git-grep.
-This should be set automatically by customizing
-`magit-todos-keywords'.")
-
-(defvar-local magit-todos-active-scan nil
- "The current scan's process.
-Used to avoid running multiple simultaneous scans for a
-magit-status buffer.")
-
-(defvar magit-todos-section-map
- (let ((map (make-sparse-keymap)))
- (define-key map "jT" #'magit-todos-jump-to-todos)
- (define-key map "jl" #'magit-todos-list)
- (define-key map "b" #'magit-todos-branch-list-toggle)
- (define-key map "B" #'magit-todos-branch-list-set-commit)
- (define-key map [remap magit-visit-thing] #'magit-todos-list)
- map)
- "Keymap for `magit-todos' top-level section.")
-
-(defvar magit-todos-item-section-map
- (let ((map (copy-keymap magit-todos-section-map)))
- (define-key map [remap magit-visit-thing] #'magit-todos-jump-to-item)
- (define-key map [remap magit-diff-show-or-scroll-up] #'magit-todos-peek-at-item)
- map)
- "Keymap for `magit-todos' individual to-do item sections.
-See https://magit.vc/manual/magit/Creating-Sections.html for more
-details about how section maps work.")
-
-(defvar-local magit-todos-show-filenames nil
- "Whether to show filenames next to to-do items.
-Set automatically depending on grouping.")
-
-(defvar-local magit-todos-updating nil
- "Whether items are being updated now.")
-
-(defvar-local magit-todos-last-update-time nil
- "When the items were last updated.
-A time value as returned by `current-time'.")
-
-(defvar-local magit-todos-item-cache nil
- "Items found by most recent scan.")
-
-(defvar magit-todos-scanners nil
- "Scanners defined by `magit-todos-defscanner'.")
-
-(defvar magit-todos-section-heading "TODOs"
- "Allows overriding of section heading.")
-
-;;;; Customization
-
-(defgroup magit-todos nil
- "Show TODO items in source code comments in repos' files."
- :group 'magit)
-
-(defcustom magit-todos-scanner nil
- "File scanning method.
-\"Automatic\" will attempt to use rg, ag, git-grep, and
-find-grep, in that order. "
- :type '(choice (const :tag "Automatic" nil)
- (function :tag "Custom function"))
- :set (lambda (option value)
- (when magit-todos-scanners
- ;; Only try to set when scanners are defined.
- (unless value
- ;; Choosing automatically
- (setq value (or (magit-todos--choose-scanner)
- (progn
- (display-warning 'magit-todos
- "`magit-todos' was unable to find a suitable scanner. Please install \"rg\", or a PCRE-compatible version of \"git\" or \"grep\". Disabling `magit-todos-mode'."
- :error)
- (magit-todos-mode -1)
- nil))))
- (set-default option value))))
-
-(defcustom magit-todos-nice t
- "Run scanner with \"nice\"."
- :type 'boolean)
-
-(defcustom magit-todos-ignore-case nil
- "Upcase keywords found in files.
-If nil, a keyword like \"Todo:\" will not be shown. `upcase' can
-be a relatively expensive function, so this can be disabled if
-necessary."
- :type 'boolean)
-
-(defcustom magit-todos-update t
- "When or how often to scan for to-dos.
-When set to manual updates, the list can be updated with the
-command `magit-todos-update'. When caching is enabled, scan for
-items whenever the Magit status buffer is refreshed and at least
-N seconds have passed since the last scan; otherwise, use cached
-items."
- :type '(choice (const :tag "Automatically, when the Magit status buffer is refreshed" t)
- (integer :tag "Automatically, but cache items for N seconds")
- (const :tag "Manually" nil)))
-
-(defcustom magit-todos-fontify-keyword-headers t
- "Apply keyword faces to group keyword headers."
- :type 'boolean)
-
-(defcustom magit-todos-keyword-suffix (rx (optional "(" (1+ (not (any ")"))) ")") ":")
- "Regular expression matching suffixes after keywords.
-e.g. to match a keyword like \"TODO(user):\", use \"([^)]+):\".
-
-If the suffix should be optional, the entire regexp should be
-made explicitly optional. However, it is not necessary to
-account for optional whitespace after the suffix, as this is done
-automatically.
-
-Note: the suffix applies only to non-Org files."
- :type `(choice (const :tag "Optional username in parens, then required colon (matching e.g. \"TODO:\" or \"TODO(user):\")"
- ,(rx (optional "(" (1+ (not (any ")"))) ")") ":"))
- (const :tag "Required colon (matching e.g. \"TODO:\"" ":")
- (string :tag "Custom regexp"))
- :package-version '(magit-todos . "1.2"))
-
-(defcustom magit-todos-ignored-keywords '("NOTE" "DONE")
- "Ignored keywords. Automatically removed from `magit-todos-keywords'."
- :type '(repeat string)
- :set (lambda (option value)
- (set-default option value)
- (when (boundp 'magit-todos-keywords)
- ;; Avoid setting `magit-todos-keywords' before it's defined.
-
- ;; HACK: Testing with `fboundp' is the only way I have been able to find that fixes this
- ;; problem. I tried using ":set-after '(magit-todos-ignored-keywords)" on
- ;; `magit-todos-keywords', but it had no effect. I looked in the manual, which seems to
- ;; suggest that using ":initialize 'custom-initialize-safe-set" might fix it--but that
- ;; function is no longer to be found in the Emacs source tree. It was committed in 2005,
- ;; and now it's gone, but the manual still mentions it. ???
- (custom-reevaluate-setting 'magit-todos-keywords))))
-
-(defcustom magit-todos-keywords 'hl-todo-keyword-faces
- "To-do keywords to display in Magit status buffer.
-If set to a list variable, may be a plain list or an alist in
-which the keys are the keywords.
-
-When set, sets `magit-todos-search-regexp' to the appropriate
-regular expression."
- :type '(choice (repeat :tag "Custom list" string)
- (const :tag "Keywords from `hl-todo'" hl-todo-keyword-faces)
- (variable :tag "List variable"))
- :set (lambda (option value)
- (set-default option value)
- (let ((keywords (cl-typecase value
- (null (user-error "Please add some keywords"))
- (symbol (if (and (consp (symbol-value value))
- (consp (car (symbol-value value))))
- (mapcar #'car (symbol-value value))
- (symbol-value value)))
- (list value))))
- (setq magit-todos-keywords-list (seq-difference keywords magit-todos-ignored-keywords)))))
-
-(defcustom magit-todos-max-items 10
- "Automatically collapse the section if there are more than this many items."
- :type 'integer)
-
-(defcustom magit-todos-auto-group-items 20
- "Whether or when to automatically group items."
- :type '(choice (integer :tag "When there are more than this many items")
- (const :tag "Always" always)
- (const :tag "Never" never)))
-
-(defcustom magit-todos-buffer-item-factor 10
- "Multiply `magit-todos-auto-group-items' and `magit-todos-max-items' by this factor in dedicated `magit-todos' buffers."
- :type 'integer)
-
-(defcustom magit-todos-group-by '(magit-todos-item-keyword magit-todos-item-filename)
- "How to group items.
-One or more attributes may be chosen, and they will be grouped in
-order."
- :type '(repeat (choice (const :tag "By filename" magit-todos-item-filename)
- (const :tag "By keyword" magit-todos-item-keyword)
- (const :tag "By suffix" magit-todos-item-suffix)
- (const :tag "By first path component" magit-todos-item-first-path-component))))
-
-(defcustom magit-todos-fontify-org t
- "Fontify items from Org files as Org headings."
- :type 'boolean)
-
-(defcustom magit-todos-sort-order '(magit-todos--sort-by-keyword
- magit-todos--sort-by-filename
- magit-todos--sort-by-position)
- "Order in which to sort items."
- :type '(repeat (choice (const :tag "Keyword" magit-todos--sort-by-keyword)
- (const :tag "Suffix" magit-todos--sort-by-suffix)
- (const :tag "Filename" magit-todos--sort-by-filename)
- (const :tag "Buffer position" magit-todos--sort-by-position)
- (function :tag "Custom function"))))
-
-(defcustom magit-todos-depth nil
- "Maximum depth of files in repo working tree to scan for to-dos.
-A value of 0 means to search only the current directory, while a
-value of 1 means to search directories one level deeper, etc.
-Deeper scans can be slow in large projects. You may wish to set
-this in a directory-local variable for certain projects."
- :type '(choice (const :tag "Unlimited" nil)
- (const :tag "Repo root directory only" 0)
- (integer :tag "N levels below the repo root")))
-
-(defcustom magit-todos-insert-at 'bottom
- "Insert the to-dos section after this section in the Magit status buffer.
-Specific sections may be chosen, using the first symbol returned
-by evaluating \"(magit-section-ident (magit-current-section))\"
-in the status buffer with point on the desired section,
-e.g. `recent' for the \"Recent commits\" section. Note that this
-may not work exactly as desired when the built-in scanner is
-used."
- :type '(choice (const :tag "Top" top)
- (const :tag "Bottom" bottom)
- (const :tag "After untracked files" untracked)
- (const :tag "After unstaged files" unstaged)
- (symbol :tag "After selected section")))
-
-(defcustom magit-todos-exclude-globs nil
- "Glob patterns to exclude from searches."
- :type '(repeat string))
-
-(defcustom magit-todos-branch-list 'branch
- "Show branch diff to-do list.
-
-This can be toggled locally in Magit buffers with command
-`magit-todos-branch-list-toggle'."
- :type '(choice (const :tag "Never" nil)
- (const :tag "In non-master branches" branch)
- (const :tag "Always" t)))
-
-(defcustom magit-todos-branch-list-merge-base-ref "master"
- "Commit ref passed to command \"git merge-base HEAD\".
-Determines the ancestor commit from which the current branch's
-todos should be searched for. May be overridden in the case that
-a branch is branched off another branch rather than master. For
-example, consider the following commit graph:
-
----A1---A2---A3 (master)
- \
- B1---B2---B3 (topic)
- \
- C1---C2---C3 (topic2, HEAD)
-
-By default, the branch todo list would show todos from both the
-\"topic\" branch and the \"topic2\" branch. To show only todos
-from the \"topic2\" branch, this option could be set to
-\"topic\"."
- :type 'string)
-
-;;;; Commands
-
-;;;###autoload
-(define-minor-mode magit-todos-mode
- "Show list of to-do items in Magit status buffer for tracked files in repo."
- :require 'magit-todos
- :group 'magit-todos
- :global t
- (if magit-todos-mode
- (progn
- (pcase (lookup-key magit-status-mode-map "jT")
- ('nil (define-key magit-status-mode-map "jT" #'magit-todos-jump-to-todos))
- ('magit-todos-jump-to-todos nil)
- (_ (message "magit-todos: Not overriding bind of \"jT\" in `magit-status-mode-map'.")))
- (magit-add-section-hook 'magit-status-sections-hook
- #'magit-todos--insert-todos
- 'magit-insert-staged-changes
- 'append)
- (add-hook 'magit-status-mode-hook #'magit-todos--add-to-status-buffer-kill-hook 'append))
- ;; Disable mode
- (when (equal (lookup-key magit-status-mode-map "jT") #'magit-todos-jump-to-todos)
- (define-key magit-status-mode-map "jT" nil))
- (remove-hook 'magit-status-sections-hook #'magit-todos--insert-todos)
- (remove-hook 'magit-status-mode-hook #'magit-todos--add-to-status-buffer-kill-hook)))
-
-(defun magit-todos-update ()
- "Update the to-do list manually.
-Only necessary when option `magit-todos-update' is nil."
- (interactive)
- (unless magit-todos-mode
- (user-error "Please activate `magit-todos-mode'"))
- (let ((inhibit-read-only t))
- ;; Delete twice since there might also be the branch-local section.
- (magit-todos--delete-section [* todos])
- (magit-todos--delete-section [* todos])
- ;; HACK: See other note on `magit-todos-updating'.
- (setq magit-todos-updating t)
- (magit-todos--insert-todos)))
-
-(defun magit-todos-branch-list-toggle ()
- "Toggle branch diff to-do list in current Magit buffer."
- (interactive)
- (setq-local magit-todos-branch-list (not magit-todos-branch-list))
- (magit-todos-update))
-
-(defun magit-todos-branch-list-set-commit (ref)
- "Set commit ref used in branch to-do list."
- (interactive (list (completing-read "Refname: " (magit-list-refnames))))
- (setq-local magit-todos-branch-list-merge-base-ref ref)
- (magit-todos-update))
-
-(cl-defun magit-todos-jump-to-item (&key peek (item (oref (magit-current-section) value)))
- "Show current item.
-If PEEK is non-nil, keep focus in status buffer window."
- (interactive)
- (let* ((status-window (selected-window))
- (buffer (magit-todos--item-buffer item)))
- (pop-to-buffer buffer)
- (magit-todos--goto-item item)
- (when (derived-mode-p 'org-mode)
- (org-show-entry))
- (when peek
- (select-window status-window))))
-
-(defun magit-todos-peek-at-item ()
- "Peek at current item."
- (interactive)
- (magit-todos-jump-to-item :peek t))
-
-;;;;; Jump to section
-
-(magit-define-section-jumper magit-jump-to-todos "TODOs" todos)
-
-(defun magit-todos-jump-to-todos ()
- "Jump to TODOs section, and update it if empty."
- (interactive)
- (let ((already-in-section-p (magit-section-match [* todos])))
- (magit-jump-to-todos)
- (when (and (or (integerp magit-todos-update)
- (not magit-todos-update))
- (or already-in-section-p
- (= 0 (length (oref (magit-current-section) children)))))
- (magit-todos-update))))
-
-;;;; Dedicated buffer
-
-;;;###autoload
-(defun magit-todos-list (&optional directory)
- "Show to-do list of the current Git repository in a buffer.
-With prefix, prompt for repository."
- ;; Mostly copied from `magit-status'
- (interactive
- (let ((magit--refresh-cache (list (cons 0 0))))
- (list (and (or current-prefix-arg (not (magit-toplevel)))
- (magit-read-repository)))))
- (condition-case nil
- (let ((magit--refresh-cache (list (cons 0 0))))
- (setq directory (if directory
- (file-name-as-directory (expand-file-name directory))
- default-directory))
- (magit-todos-list-internal directory))
- ('magit-outside-git-repo (cl-letf (((symbol-function 'magit-toplevel) (lambda (&rest _) default-directory)))
- (call-interactively #'magit-todos-list)))))
-
-(put 'magit-todos-list 'interactive-only 'magit-todos-list-internal)
-
-;;;###autoload
-(defun magit-todos-list-internal (directory)
- "Open buffer showing to-do list of repository at DIRECTORY."
- (magit--tramp-asserts directory)
- (let ((default-directory directory))
- (magit-setup-buffer #'magit-todos-list-mode)))
-
-(define-derived-mode magit-todos-list-mode magit-status-mode "Magit"
- "Mode for looking at repository to-do list.
-
-\\<magit-todos-mode-map>\
-Type \\[magit-refresh] to refresh the list.
-Type \\[magit-section-toggle] to expand or hide the section at point.
-Type \\[magit-visit-thing] to visit the item at point.
-Type \\[magit-diff-show-or-scroll-up] to peek at the item at point."
- :group 'magit-todos)
-
-(defun magit-todos-list-refresh-buffer ()
- "Refresh the current `magit-todos-list-mode' buffer."
- (setq-local magit-todos-max-items (* magit-todos-max-items magit-todos-buffer-item-factor))
- (when (numberp magit-todos-auto-group-items)
- (setq-local magit-todos-auto-group-items (* magit-todos-auto-group-items magit-todos-buffer-item-factor)))
- (magit-section-show (magit-insert-section (type magit-root-section)
- (magit-insert-status-headers)
- (magit-todos--insert-todos))))
-
-;;;; Functions
-
-(defun magit-todos--coalesce-groups (groups)
- "Return GROUPS, coalescing any groups with `equal' keys.
-GROUPS should be an alist. Assumes that each group contains
-unique items. Intended for post-processing the result of
-`-group-by'."
- (cl-loop with keys = (-uniq (-map #'car groups))
- for key in keys
- for matching-groups = (--select (equal key (car it)) groups)
- collect (cons key (apply #'append (-map #'cdr matching-groups)))))
-
-(defun magit-todos--add-to-status-buffer-kill-hook ()
- "Add `magit-todos--kill-active-scan' to `kill-buffer-hook' locally."
- (add-hook 'kill-buffer-hook #'magit-todos--kill-active-scan 'append 'local))
-
-(defun magit-todos--kill-active-scan ()
- "Kill `magit-todos-active-scan'.
-To be called in status buffers' `kill-buffer-hook'."
- (when (and magit-todos-active-scan
- (process-live-p magit-todos-active-scan))
- (kill-process magit-todos-active-scan)
- (when-let* ((buffer (process-buffer magit-todos-active-scan))
- (alive (buffer-live-p buffer)))
- (kill-buffer buffer))))
-
-(defun magit-todos--add-to-custom-type (symbol value)
- "Add VALUE to the end of SYMBOL's `custom-type' property."
- (declare (indent defun))
- (pcase-let* ((`(,type . ,choices) (get symbol 'custom-type))
- (choices (append (list value) choices)))
- (put symbol 'custom-type
- (append (list type) choices))))
-
-(defun magit-todos--choose-scanner ()
- "Return function to call to scan for items with.
-Chooses automatically in order defined in `magit-todos-scanners'."
- (cl-loop for scanner in magit-todos-scanners
- ;; I guess it would be better to avoid `eval', but it seems like the natural
- ;; way to do this.
- when (eval (alist-get 'test scanner))
- return (alist-get 'function scanner)))
-
-(cl-defun magit-todos--scan-callback (&key callback magit-status-buffer results-regexp process &allow-other-keys)
- "Call CALLBACK with arguments MAGIT-STATUS-BUFFER and match items.
-Match items are a list of `magit-todos-item' found in PROCESS's buffer for RESULTS-REGEXP."
- (funcall callback magit-status-buffer
- (with-current-buffer (process-buffer process)
- (magit-todos--buffer-items results-regexp))))
-
-(defun magit-todos--buffer-items (results-regexp)
- "Return list of `magit-todos-item' found in current buffer for RESULTS-REGEXP."
- (let ((items))
- (save-excursion
- (goto-char (point-min))
- (while (not (eobp))
- (--when-let (condition-case err
- (magit-todos--line-item results-regexp)
- ;; Files with very, very long lines may cause Emacs's regexp matcher to overflow.
- ;; Rather than abort the whole scan and raise an error, try to handle it gracefully.
- ;; FIXME: This may raise multiple warnings per file.
- (error (if (string= "Stack overflow in regexp matcher" (error-message-string err))
- (let ((filename (buffer-substring (point) (1- (re-search-forward ":")))))
- (display-warning 'magit-todos (concat "File has lines too long for Emacs to search. Consider excluding it from scans: " filename)))
- (signal (car err) (cdr err)))))
- (push it items))
- (forward-line 1)))
- (nreverse items)))
-
-(cl-defun magit-todos--git-diff-callback (&key magit-status-buffer results-regexp search-regexp-elisp process heading
- &allow-other-keys)
- "Callback for git diff scanner output."
- ;; NOTE: Doesn't handle newlines in filenames or diff.mnemonicPrefix.
- (cl-macrolet ((next-diff () `(re-search-forward (rx bol "diff --git ") nil t))
- (next-filename () `(when (re-search-forward (rx bol "+++ b/" (group (1+ nonl))) nil t)
- (match-string 1)))
- (next-hunk-line-number () `(when (re-search-forward (rx bol "@@ -"
- (1+ digit) (optional "," (1+ digit)) (1+ space)
- "+" (group (1+ digit)) (optional "," (1+ digit)))
- file-end t)
- (string-to-number (match-string 1))))
- (file-end () `(or (save-excursion
- (when (re-search-forward (rx bol "diff --git ")
- nil t)
- (match-beginning 0)))
- (point-max)))
- (hunk-end () `(or (save-excursion
- (when (re-search-forward (rx (or (seq bol "diff --git ")
- (seq bol "@@ ")))
- nil t)
- (match-beginning 0)))
- (point-max))))
- (with-current-buffer (process-buffer process)
- (goto-char (point-min))
- (let (items filename file-end hunk-end line-number)
- (while (next-diff)
- (while (setf filename (next-filename))
- (setf file-end (file-end))
- (while (setf line-number (next-hunk-line-number))
- (setf hunk-end (hunk-end))
- (while (re-search-forward (rx bol "+") hunk-end t)
- ;; Since "git diff-index" doesn't accept PCREs to its "-G" option, we have to test the search regexp ourselves.
- (when (re-search-forward search-regexp-elisp (line-end-position) t)
- (when-let* ((line (buffer-substring (line-beginning-position) (line-end-position)))
- (item (with-temp-buffer
- ;; NOTE: We fake grep output by inserting the filename, line number, position, etc.
- ;; This lets us use the same results regexp that's used for grep-like output.
- (save-excursion
- (insert filename ":" (number-to-string line-number) ":0: " line))
- (magit-todos--line-item results-regexp filename))))
- (push item items)))
- (cl-incf line-number)))))
- (let ((magit-todos-section-heading heading))
- (magit-todos--insert-items magit-status-buffer items :branch-p t))))))
-
-(defun magit-todos--delete-section (condition)
- "Delete the section specified by CONDITION from the Magit status buffer.
-See `magit-section-match'. Also delete it from root section's children."
- (save-excursion
- (goto-char (point-min))
- (when-let ((section (cl-loop until (magit-section-match condition)
- ;; Use `forward-line' instead of `magit-section-forward' because
- ;; sometimes it skips our section.
- do (forward-line 1)
- when (eobp)
- return nil
- finally return (magit-current-section))))
- ;; Delete the section from root section's children. This makes the section-jumper command
- ;; work when a replacement section is inserted after deleting this section.
- (object-remove-from-list magit-root-section 'children section)
- (with-slots (start end) section
- ;; NOTE: We delete 1 past the end because we insert a newline after the section. I'm not
- ;; sure if this would generalize to all Magit sections. But if the end is the same as
- ;; `point-max', which may be the case if todo items have not yet been inserted, we only
- ;; delete up to `point-max'.
- (delete-region start (if (= end (point-max))
- end
- (1+ end)))))))
-
-(defun magit-todos--item-buffer (item)
- "Return buffer visiting ITEM."
- (or (find-buffer-visiting (magit-todos-item-filename item))
- (find-file-noselect (magit-todos-item-filename item))))
-
-(defun magit-todos--goto-item (item)
- "Move point to ITEM.
-Assumes current buffer is ITEM's buffer."
- (pcase-let* (((cl-struct magit-todos-item position line column keyword) item))
- (if position
- (goto-char position)
- (goto-char (point-min))
- (forward-line (1- line))
- (if column
- (forward-char column)
- (when (re-search-forward (regexp-quote keyword) (line-end-position) t)
- (goto-char (match-beginning 0)))))))
-
-(defun magit-todos--insert-todos ()
- "Insert to-do items into current buffer.
-This function should be called from inside a ‘magit-status’ buffer."
- (declare (indent defun))
- (when magit-todos-active-scan
- ;; Avoid running multiple scans for a single magit-status buffer.
- (let ((buffer (process-buffer magit-todos-active-scan)))
- (when (process-live-p magit-todos-active-scan)
- (delete-process magit-todos-active-scan))
- (when (buffer-live-p buffer)
- (kill-buffer buffer)))
- (setq magit-todos-active-scan nil))
- (pcase magit-todos-update
- ((or 't ; Automatic
- ;; Manual and updating now
- (and 'nil (guard magit-todos-updating))
- ;; Caching and cache expired
- (and (pred integerp) (guard (or magit-todos-updating ; Forced update
- (>= (float-time
- (time-subtract (current-time)
- magit-todos-last-update-time))
- magit-todos-update)
- (null magit-todos-last-update-time)))))
- ;; Scan and insert.
- ;; HACK: I don't like setting a special var here, because it seems like lexically binding a
- ;; special var should follow down the chain, but it isn't working, so we'll do this.
- (setq magit-todos-updating t)
- (setq magit-todos-active-scan (funcall magit-todos-scanner
- :callback #'magit-todos--insert-items
- :magit-status-buffer (current-buffer)
- :directory default-directory
- :depth magit-todos-depth)))
- (_ ; Caching and cache not expired, or not automatic and not manually updating now
- (magit-todos--insert-items (current-buffer) magit-todos-item-cache)))
- (when (or (eq magit-todos-branch-list t)
- (and (eq magit-todos-branch-list 'branch)
- (not (string= "master" (magit-get-current-branch)))))
- ;; Insert branch-local items.
- (magit-todos--scan-with-git-diff :magit-status-buffer (current-buffer)
- :directory default-directory
- :depth magit-todos-depth
- :heading (format "TODOs (branched from %s)" magit-todos-branch-list-merge-base-ref))))
-
-(cl-defun magit-todos--insert-items (magit-status-buffer items &key branch-p)
- "Insert to-do ITEMS into MAGIT-STATUS-BUFFER.
-If BRANCH-P is non-nil, do not update `magit-todos-item-cache',
-`magit-todos-last-update-time', and `magit-todos-updating'."
- (declare (indent defun))
- ;; NOTE: This could be factored out into some kind of `magit-insert-section-async' macro if necessary.
- ;; MAYBE: Use `magit-insert-section-body'.
- (when (not (buffer-live-p magit-status-buffer))
- (message "`magit-todos--insert-items-callback': Callback called for deleted buffer"))
- (let* ((items (magit-todos--sort items))
- (num-items (length items))
- (group-fns (pcase magit-todos-auto-group-items
- ('never nil)
- ('always magit-todos-group-by)
- ((pred integerp) (when (> num-items magit-todos-auto-group-items)
- magit-todos-group-by))
- (_ (error "Invalid value for magit-todos-auto-group-items"))))
- (magit-todos-show-filenames (not (member 'magit-todos-item-filename group-fns)))
- (magit-section-show-child-count t)
- ;; HACK: "For internal use only." But this makes collapsing the new section work!
- (magit-insert-section--parent magit-root-section)
- (inhibit-read-only t))
- (when (buffer-live-p magit-status-buffer)
- ;; Don't try to select a killed status buffer
- (with-current-buffer magit-status-buffer
- (unless branch-p
- ;; Don't do any of this for the branch-diff scanner.
- (when magit-todos-updating
- (when (or (null magit-todos-update) ; Manual updates
- (integerp magit-todos-update)) ; Caching
- (setq magit-todos-item-cache items)
- (setq magit-todos-last-update-time (current-time)))
- ;; HACK: I don't like setting this special var, but it works. See other comment where
- ;; it's set t.
- (setq magit-todos-updating nil)))
- (save-excursion
- ;; Insert items
- (goto-char (point-min))
- ;; Go to insertion position
- (pcase magit-todos-insert-at
- ('top (cl-loop for ((this-section . _) . _) = (magit-section-ident (magit-current-section))
- until (not (member this-section '(branch tags)))
- do (magit-section-forward)))
- ('bottom (goto-char (oref (-last-item (oref magit-root-section children)) end)))
- (_ (magit-todos--skip-section (vector '* magit-todos-insert-at))))
- ;; Insert section
- (let ((reminder (if magit-todos-update
- "" ; Automatic updates: no reminder
- ;; Manual updates: remind user
- " (update manually)")))
- (if (not items)
- (unless magit-todos-update
- ;; Manual updates: Insert section to remind user
- (let ((magit-insert-section--parent magit-root-section))
- (magit-insert-section (todos)
- (magit-insert-heading (concat (propertize magit-todos-section-heading 'face 'magit-section-heading)
- " (0)" reminder "\n")))))
- (let ((section (magit-todos--insert-groups :type 'todos
- :heading (format "%s (%s)%s"
- (propertize magit-todos-section-heading 'face 'magit-section-heading)
- num-items reminder)
- :group-fns group-fns
- :items items
- :depth 0)))
- (insert "\n")
- (magit-todos--set-visibility :section section :num-items num-items)))))))))
-
-(cl-defun magit-todos--insert-groups (&key depth group-fns heading type items)
- "Insert ITEMS into grouped Magit section and return the section.
-
-DEPTH sets indentation and should be 0 for a top-level group. It
-is automatically incremented when this function calls itself.
-
-GROUP-FNS may be a list of functions to which ITEMS are applied
-with `-group-by' to group them. Items are grouped
-hierarchically, i.e. when GROUP-FNS has more than one function,
-items are first grouped by the first function, then subgroups are
-created which group items by subsequent functions.
-
-HEADING is a string which is the group's heading. The count of
-items in each group is automatically appended.
-
-TYPE is a symbol which is used by Magit internally to identify
-sections."
- ;; NOTE: `magit-insert-section' seems to bind `magit-section-visibility-cache' to nil, so setting
- ;; visibility within calls to it probably won't work as intended.
- (declare (indent defun))
- (let* ((indent (s-repeat (* 2 depth) " "))
- (heading (concat indent heading))
- (magit-insert-section--parent (if (= 0 depth)
- magit-root-section
- magit-insert-section--parent)))
- (if (and (consp group-fns)
- (> (length group-fns) 0))
- ;; Insert more groups
- (let* ((groups (--> (-group-by (car group-fns) items)
- (cl-loop for group in-ref it
- ;; HACK: Set ":" keys to nil so they'll be grouped together.
- do (pcase (car group)
- (":" (setf (car group) nil)))
- finally return it)
- (magit-todos--coalesce-groups it)))
- (section (magit-insert-section ((eval type))
- (magit-insert-heading heading)
- (cl-loop for (group-type . items) in groups
- for group-name = (pcase group-type
- ;; Use "[Other]" instead of empty group name.
- ;; HACK: ":" is hard-coded, even though the
- ;; suffix regexp could differ. If users change
- ;; the suffix so this doesn't apply, it
- ;; shouldn't cause any problems, it just won't
- ;; look as pretty.
- ((or "" ":" 'nil) "[Other]")
- (_ (s-chop-suffix ":" group-type)))
- do (magit-todos--insert-groups
- :depth (1+ depth) :group-fns (cdr group-fns)
- :type (intern group-name) :items items
- :heading (concat
- (if (and magit-todos-fontify-keyword-headers
- (member group-name magit-todos-keywords-list))
- (propertize group-name 'face (magit-todos--keyword-face group-name))
- group-name)
- ;; Item count
- (if (= 1 (length group-fns))
- ":" ; Let Magit add the count.
- ;; Add count ourselves.
- (concat " " (format "(%s)" (length items))))))))))
- (magit-todos--set-visibility :depth depth :num-items (length items) :section section)
- ;; Add top-level section to root section's children
- (when (= 0 depth)
- (push section (oref magit-root-section children)))
- ;; Don't forget to return the section!
- section)
- ;; Insert individual to-do items
- (magit-todos--insert-group :depth (1+ depth) :type type :items items :heading heading))))
-
-(cl-defun magit-todos--insert-group (&key depth heading type items)
- "Insert ITEMS into Magit section and return the section.
-
-DEPTH sets indentation and should be 0 for a top-level group.
-
-HEADING is a string which is the group's heading. The count of
-items in each group is automatically appended.
-
-TYPE is a symbol which is used by Magit internally to identify
-sections."
- ;; NOTE: `magit-insert-section' seems to bind `magit-section-visibility-cache' to nil, so setting
- ;; visibility within calls to it probably won't work as intended.
- (declare (indent defun))
- (let* ((indent (s-repeat (* 2 depth) " "))
- (magit-insert-section--parent (if (= 0 depth)
- magit-root-section
- magit-insert-section--parent))
- (width (- (window-text-width) depth))
- (section (magit-insert-section ((eval type))
- (magit-insert-heading heading)
- (dolist (item items)
- (let* ((filename (propertize (magit-todos-item-filename item) 'face 'magit-filename))
- (string (--> (concat indent
- (when magit-todos-show-filenames
- (concat filename " "))
- (funcall (if (s-suffix? ".org" filename)
- #'magit-todos--format-org
- #'magit-todos--format-plain)
- item))
- (truncate-string-to-width it width))))
- (magit-insert-section (todos-item item)
- (insert string "\n")))))))
- (magit-todos--set-visibility :depth depth :num-items (length items) :section section)
- ;; Don't forget to return the section!
- section))
-
-(cl-defun magit-todos--set-visibility (&key section num-items depth)
- "Set the visibility of SECTION.
-
-If the section's visibility is cached by Magit, the cached
-setting is applied. Otherwise, visibility is set according to
-whether NUM-ITEMS is greater than `magit-todos-max-items'.
-
-When DEPTH is greater than 0, NUM-ITEMS is compared to
-`magit-todos-max-items' divided by DEPTH multiplied by 2,
-i.e. the max number of items which cause sections to be
-automatically hidden halves at each deeper level."
- (declare (indent defun))
- (pcase (magit-section-cached-visibility section)
- ('hide (magit-section-hide section))
- ('show (magit-section-show section))
- (_ (if (> num-items (pcase depth
- (0 magit-todos-max-items)
- (_ (/ magit-todos-max-items (* depth 2)))))
- ;; HACK: We have to do this manually because the set-visibility-hook doesn't work.
- (magit-section-hide section)
- ;; Not hidden: show section manually (necessary for some reason)
- (magit-section-show section)))))
-
-(defun magit-todos--skip-section (condition)
- "Move past the section matching CONDITION.
-See `magit-section-match'."
- (goto-char (point-min))
- (cl-loop until (magit-section-match condition)
- do (magit-section-forward))
- (cl-loop until (not (magit-section-match condition))
- do (condition-case nil
- ;; `magit-section-forward' raises an error when there are no more sections.
- (magit-section-forward)
- (error (progn
- (goto-char (1- (point-max)))
- (cl-return))))))
-
-(cl-defun magit-todos--line-item (regexp &optional filename)
- "Return item on current line, parsing current buffer with REGEXP.
-FILENAME is added to the item as its filename. Sets match data.
-This should be called in a process's output buffer from one of
-the async callback functions. The calling function should
-advance to the next line."
- (let ((case-fold-search magit-todos-ignore-case))
- (when (re-search-forward regexp (line-end-position) t)
- (make-magit-todos-item :filename (or filename
- (match-string 8))
- :line (--when-let (match-string 2)
- (string-to-number it))
- :column (--when-let (match-string 3)
- (string-to-number it))
- :position (--when-let (match-string 9)
- (string-to-number it))
- :org-level (match-string 1)
- :keyword (match-string 4)
- :suffix (match-string 6)
- :description (match-string 5)))))
-
-(defun magit-todos--keyword-face (keyword)
- "Return face for KEYWORD."
- ;; TODO(alphapapa): Instead of upcasing here, upcase in the lookup, so it can still be displayed
- ;; non-uppercase. Preserving the distinction might be useful.
- (when magit-todos-ignore-case
- (setq keyword (upcase keyword)))
- (let ((face (assoc-default keyword hl-todo-keyword-faces #'string=)))
- (cl-typecase face
- (string (list :inherit 'hl-todo :foreground face))
- (t face))))
-
-(defun magit-todos--fontify-like-in-org-mode (s &optional odd-levels)
- "Fontify string S like in Org-mode.
-
-`org-fontify-like-in-org-mode' is a very, very slow function
-because it creates a new temporary buffer and runs `org-mode' for
-every string it fontifies. This function reuses a single
-invisible buffer and only runs `org-mode' when the buffer is
-created."
- (let ((buffer (get-buffer " *magit-todos--fontify-like-in-org-mode*")))
- (unless buffer
- (setq buffer (get-buffer-create " *magit-todos--fontify-like-in-org-mode*"))
- (with-current-buffer buffer
- (buffer-disable-undo)
- (org-mode)))
- (with-current-buffer buffer
- (erase-buffer)
- (insert s)
- (let ((org-odd-levels-only odd-levels))
- (font-lock-ensure)
- (buffer-string)))))
-
-(defun magit-todos-item-first-path-component (item)
- "Return ITEM's first directory.
-This assumes that ITEM's filename is already set to a path
-relative to the repo's directory (i.e. this would not be very
-useful with absolute paths)."
- (car (f-split (magit-todos-item-filename item))))
-
-(cl-defun magit-todos--async-start-process (name &key command finish-func)
- "Start the executable PROGRAM asynchronously. See `async-start'.
-PROGRAM is passed PROGRAM-ARGS, calling FINISH-FUNC with the
-process object when done. If FINISH-FUNC is nil, the future
-object will return the process object when the program is
-finished. Set DEFAULT-DIRECTORY to change PROGRAM's current
-working directory.
-
-This is a copy of `async-start-process' that does not override
-`process-connection-type'. It also uses keyword arguments."
- (declare (indent defun))
- ;; TODO: Drop this function when possible. See
- ;; <https://github.com/jwiegley/emacs-async/issues/102>.
- (let* ((args (cdr command))
- (command (car command))
- (buf (generate-new-buffer (concat " *" name "*")))
- (proc (apply #'start-file-process name buf command args)))
- (with-current-buffer buf
- (set-process-query-on-exit-flag proc nil)
- (set (make-local-variable 'async-callback) finish-func)
- (set-process-sentinel proc #'magit-todos--async-when-done)
- (unless (string= name "emacs")
- (set (make-local-variable 'async-callback-for-process) t))
- proc)))
-
-(defun magit-todos--async-when-done (proc &optional _change)
- "Process sentinel used to retrieve the value from the child process.
-
-This is a copy of `async-when-done' that does not raise an error
-if the process's buffer has already been deleted."
- ;; I wish it weren't necessary to copy this function here, but at the moment it seems like the
- ;; only reasonable way to work around this problem of `async-when-done' trying to select deleted
- ;; buffers. I already tried not deleting the buffers, but then I got bug reports about that and
- ;; had to revert it. I don't know if I'm encountering a bug in my code, in `async', or in Emacs
- ;; itself, because it seems that `async-when-done' is being called on the wrong buffers: When I'm
- ;; connected with `matrix-client', and when I have a Magit status buffer opened with
- ;; `magit-todos-mode' active, then when one of the `url' process buffers from Matrix gets its
- ;; sentinel called, I get an error from `async-when-done' trying to select the already-deleted
- ;; `rg' scanner buffer! It's as if Emacs is mixing up the process buffers. I really don't know
- ;; what's going on. But maybe I can work around it by copying this function and checking whether
- ;; the process's buffer is alive.
- ;; NOTE: TRAMP processes seem to have the status `signal' instead of
- ;; `exit'. I can't find documentation as to why.
- (when (and (memq (process-status proc) '(exit signal))
- (buffer-live-p (process-buffer proc)))
- (with-current-buffer (process-buffer proc)
- (let ((async-current-process proc))
- ;; TRAMP processes seem to have the exit status 9 instead of
- ;; 0. I can't find documentation or code about it.
- (if (memq (process-exit-status proc) '(0 9))
- (if async-callback-for-process
- (if async-callback
- (prog1
- (funcall async-callback proc)
- (unless async-debug
- (kill-buffer (current-buffer))))
- (set (make-local-variable 'async-callback-value) proc)
- (set (make-local-variable 'async-callback-value-set) t))
- (goto-char (point-max))
- (backward-sexp)
- (async-handle-result async-callback (read (current-buffer))
- (current-buffer)))
- (set (make-local-variable 'async-callback-value)
- (list 'error
- (format "Async process '%s' failed with exit code %d"
- (process-name proc) (process-exit-status proc))))
- (set (make-local-variable 'async-callback-value-set) t))))))
-
-;;;;; Formatters
-
-(defun magit-todos--format-plain (item)
- "Return ITEM formatted as from a non-Org file."
- (format "%s%s %s"
- (propertize (magit-todos-item-keyword item)
- 'face (magit-todos--keyword-face (magit-todos-item-keyword item)))
- (or (magit-todos-item-suffix item) "")
- (or (magit-todos-item-description item) "")))
-
-(defun magit-todos--format-org (item)
- "Return ITEM formatted as from an Org file."
- (magit-todos--fontify-like-in-org-mode
- (concat (magit-todos-item-org-level item) " "
- (magit-todos-item-keyword item) " "
- (magit-todos-item-description item))))
-
-;;;;; Sorting
-
-(defun magit-todos--sort (items)
- "Return ITEMS sorted according to `magit-todos-sort-order'."
- (dolist (fn (reverse magit-todos-sort-order) items)
- (setq items (sort items fn))))
-
-(defun magit-todos--sort-by-keyword (a b)
- "Return non-nil if A's keyword is before B's in `magit-todos-keywords-list'."
- (cl-flet ((keyword-index (keyword)
- (or (-elem-index keyword magit-todos-keywords-list) 0)))
- (< (keyword-index (magit-todos-item-keyword a))
- (keyword-index (magit-todos-item-keyword b)))))
-
-(defun magit-todos--sort-by-position (a b)
- "Return non-nil if A's position in its file is before B's."
- (let ((a-position (or (magit-todos-item-position a)
- (magit-todos-item-line a)))
- (b-position (or (magit-todos-item-position b)
- (magit-todos-item-line b))))
- (< a-position b-position)))
-
-(defun magit-todos--sort-by-filename (a b)
- "Return non-nil if A's filename is `string<' B's."
- (string< (magit-todos-item-filename a)
- (magit-todos-item-filename b)))
-
-(defun magit-todos--sort-by-suffix (a b)
- "Return non-nil if A's suffix is `string<' B's."
- (string< (magit-todos-item-suffix a)
- (magit-todos-item-suffix b)))
-
-;;;; Scanners
-
-(cl-defmacro magit-todos-defscanner (name &key test command results-regexp
- (callback (function 'magit-todos--scan-callback)))
- "Define a `magit-todos' scanner named NAME.
-
-NAME is a string, which may contain spaces. It is only used for
-descriptive purposes.
-
-TEST is an unquoted sexp which is used to determine whether the
-scanner is usable. In most cases, it should use
-`executable-find' to look for the scanner command.
-
-COMMAND is a sexp which should evaluate to the scanner command,
-i.e. a list of strings to be eventually passed to
-`start-process'. Nil elements are removed, numbers are converted
-to strings, and nested lists are flattened into a single list.
-It is evaluated each time the scanner is run.
-
-Within the COMMAND list these variables are available:
-
-`depth': When non-nil, an integer, which is the depth that should
-be passed to the scanner's max-depth option (i.e. `magit-todos-depth').
-
-`directory': The directory in which the scan should be run.
-
-`extra-args': The value of the customization variable
-\"magit-todos-NAME-extra-args\" (see below).
-
-`keywords': List of item keywords defined in
-`magit-todos-keywords-list'.
-
-`search-regexp-pcre': PCRE-compatible regular expression to be passed
-to the scanner process.
-
-`search-regexp-elisp': Emacs regular expression, which may be
-used for scanners written as Emacs Lisp functions.
-
-RESULTS-REGEXP is an optional string or unquoted sexp which is
-used to match results in the scanner process's output buffer.
-Typically this will be a sexp which calls `rx-to-string'. It is
-evaluated each time the scanner is run. If nil, the appropriate
-default is used which matches results in the form:
-
- FILENAME:LINE:MATCH
-
-Where MATCH may also match Org outline heading stars when
-appropriate. Custom regexps may also match column numbers or
-byte offsets in the appropriate numbered groups; see
-`make-magit-todos-item'.
-
-CALLBACK is called to process the process's output buffer.
-Normally the default should be used, which inserts items into the
-Magit status buffer which is passed as an argument to the scanner
-function.
-
-The macro defines the following:
-
-\"magit-todos-NAME-extra-args\": A customization setting, a list
-of strings to be passed to the scanner as extra arguments.
-
-\"magit-todos--scan-with-NAME\": The function which runs the
-scanner command.
-
-It also adds the scanner to the customization variable
-`magit-todos-scanner', and to the variable
-`magit-todos-scanners' (which is used to set
-`magit-todos-scanner' by calling `magit-todos--choose-scanner')."
- ;; TODO: Try to obviate the -scanners variable, let --choose-scanner use the
- ;; custom-type of -scanner directly. Maybe, anyway--I don't want to ugly up the UI
- ;; for users.
- (declare (indent defun) (debug (stringp [&rest &or [":test" def-form]
- [":command" def-form]
- [":results-regexp" [&or stringp def-form]]])))
- (let* ((name-without-spaces (s-replace " " "-" name))
- (scan-fn-name (concat "magit-todos--scan-with-" name-without-spaces))
- (scan-fn-symbol (intern scan-fn-name))
- (extra-args-var (intern (format "magit-todos-%s-extra-args" name-without-spaces))))
- `(progn
- (defcustom ,extra-args-var nil
- ,(format "Extra arguments passed to %s." name)
- :type '(repeat string))
-
- ;; NOTE: Both the macro and the macro-defined function have `callback' arguments. Pay attention to unquoting.
- ;; FIXME: That is confusing.
-
- (cl-defun ,scan-fn-symbol (&key magit-status-buffer directory depth heading sync callback)
- ,(format "Scan for to-dos with %s, then call `%s'.
-MAGIT-STATUS-BUFFER is what it says. DIRECTORY is the directory in which to run the scan. DEPTH should be an integer, typically the value of `magit-todos-depth'. HEADING is passed to `%s'.
-
-When SYNC is nil, the scanner process is returned, and CALLBACK
-is a function which is called by the process sentinel with one
-argument, a list of match items.
-
-When SYNC is non-nil, match items are returned."
- name callback callback)
- (let* ((process-connection-type 'pipe)
- (directory (f-relative directory default-directory))
- (extra-args (when ,extra-args-var
- (--map (s-split (rx (1+ space)) it 'omit-nulls)
- ,extra-args-var)))
- (keywords magit-todos-keywords-list)
- (search-regexp-elisp (rx-to-string
- `(or
- ;; Org item
- (seq bol (group (1+ "*"))
- (1+ blank)
- (group (or ,@keywords))
- (1+ space)
- (group (1+ not-newline)))
- ;; Non-Org
- (seq (or bol (1+ blank))
- (group (or ,@keywords))
- (regexp ,magit-todos-keyword-suffix)
- (optional (1+ blank)
- (group (1+ not-newline)))))))
- (search-regexp-pcre (rxt-elisp-to-pcre search-regexp-elisp))
- (results-regexp (or ,results-regexp
- (rx-to-string
- `(seq bol
- ;; Filename
- (group-n 8 (1+ (not (any ":")))) ":"
- ;; Line
- (group-n 2 (1+ digit)) ":"
- (or
- ;; Org item
- (seq (group-n 1 (1+ "*"))
- (1+ blank)
- (group-n 4 (or ,@keywords))
- (1+ blank)
- (group-n 5 (1+ not-newline)))
- ;; Non-Org
- (seq (optional (1+ not-newline))
- (group-n 4 (or ,@keywords))
- (optional (group-n 6 (regexp ,magit-todos-keyword-suffix)))
- (optional (1+ blank))
- (optional (group-n 5 (1+ not-newline)))))))))
- (command (-flatten
- (-non-nil
- (list (when magit-todos-nice
- (list "nice" "-n5"))
- ,command)))))
- ;; Convert any numbers in command to strings (e.g. depth).
- (cl-loop for elt in-ref command
- when (numberp elt)
- do (setf elt (number-to-string elt)))
- ;; Run command.
- (if sync
- ;; Synchronous: return matching items.
- (with-temp-buffer
- (unless (= 0 (apply #'call-process (car command) nil (current-buffer) nil
- (cdr command)))
- (user-error (concat (car command) " failed")))
- (magit-todos--buffer-items results-regexp))
- ;; Async: return process.
- (magit-todos--async-start-process ,scan-fn-name
- :command command
- ;; NOTE: This callback chain.
- :finish-func (apply-partially ,callback
- :callback callback
- :magit-status-buffer magit-status-buffer
- :results-regexp results-regexp
- :search-regexp-elisp search-regexp-elisp
- :heading heading
- :process))))) ; Process is appended to the list.
- (magit-todos--add-to-custom-type 'magit-todos-scanner
- (list 'const :tag ,name #',scan-fn-symbol))
- (add-to-list 'magit-todos-scanners
- (list (cons 'name ,name)
- (cons 'function #',scan-fn-symbol)
- (cons 'test ',test))
- 'append))))
-
-;; NOTE: These scanners handle the max-depth option differently. git-grep seems to handle it in the
-;; most useful way, with a setting of 0 meaning to look no deeper than the current directory, and a
-;; setting of 1 searching directories one level deeper. In comparison, rg and find effectively
-;; subtract one from the value, as a setting of 0 returns no results, and a setting of 1 searches
-;; only the current directory (which means that when the max-depth is set to 0, the whole command is
-;; essentially a no-op, which is pointless). Since we want `magit-todos-depth' to behave
-;; consistently with all scanners, we will treat it the way git-grep does, and for the other
-;; scanners we'll add one to its value.
-
-(magit-todos-defscanner "rg"
- :test (executable-find "rg")
- :command (list "rg" "--no-heading" "--line-number"
- (when depth
- (list "--maxdepth" (1+ depth)))
- (when magit-todos-ignore-case
- "--ignore-case")
- (when magit-todos-exclude-globs
- (--map (list "--glob" (concat "!" it))
- magit-todos-exclude-globs))
- extra-args search-regexp-pcre directory))
-
-(magit-todos-defscanner "git grep"
- :test (string-match "--perl-regexp" (shell-command-to-string "git grep --magit-todos-testing-git-grep"))
- :command (list "git" "--no-pager" "grep"
- "--full-name" "--no-color" "-n"
- (when depth
- (list "--max-depth" depth))
- (when magit-todos-ignore-case
- "--ignore-case")
- "--perl-regexp"
- "-e" search-regexp-pcre
- extra-args "--" directory
- (when magit-todos-exclude-globs
- (--map (concat ":!" it)
- magit-todos-exclude-globs))))
-
-(magit-todos-defscanner "git diff"
- ;; NOTE: This scanner implements the regexp *searching* in elisp rather than in the
- ;; external process because, unlike "git grep", "git diff" does not support PCRE.
- :test t
- :command (progn
- ;; Silence byte-compiler warnings about these vars we don't use in this scanner.
- (ignore search-regexp-elisp search-regexp-pcre extra-args directory depth)
- (list "git" "--no-pager" "diff" "--no-color" "-U0"
- (-> "git merge-base HEAD "
- (concat magit-todos-branch-list-merge-base-ref)
- shell-command-to-string
- string-trim)))
- :callback 'magit-todos--git-diff-callback)
-
-(magit-todos-defscanner "find|grep"
- ;; NOTE: The filenames output by find|grep have a leading "./". I don't expect this scanner to be
- ;; used much, if at all, so I'm not going to go to the trouble to fix this now.
- :test (string-match "--perl-regexp" (shell-command-to-string "grep --help"))
- :command (let* ((grep-find-template (progn
- (unless grep-find-template
- (grep-compute-defaults))
- (->> grep-find-template
- (s-replace " grep " " grep -b -E ")
- (s-replace " -nH " " -H "))))
- (_ (when depth
- (setq grep-find-template
- (s-replace " <D> " (concat " <D> -maxdepth " (1+ depth) " ")
- grep-find-template)))))
- ;; Modified from `rgrep-default-command'
- (list "find" directory
- (list (when grep-find-ignored-directories
- (list "-type" "d"
- "(" "-path"
- (-interpose (list "-o" "-path")
- (-non-nil (--map (cond ((stringp it)
- (concat "*/" it))
- ((consp it)
- (and (funcall (car it) it)
- (concat "*/" (cdr it)))))
- grep-find-ignored-directories)))
- ")" "-prune"))
- (when grep-find-ignored-files
- (list "-o" "-type" "f"
- "(" "-name"
- (-interpose (list "-o" "-name")
- (--map (cond ((stringp it) it)
- ((consp it) (and (funcall (car it) it)
- (cdr it))))
- grep-find-ignored-files))
- ")" "-prune"))
- (when magit-todos-exclude-globs
- (list "-o" "("
- (--map (list "-iname" it)
- magit-todos-exclude-globs)
- ")" "-prune")))
- (list "-o" "-type" "f")
- ;; NOTE: This uses "grep -P", i.e. "Interpret the pattern as a
- ;; Perl-compatible regular expression (PCRE). This is highly
- ;; experimental and grep -P may warn of unimplemented features." But it
- ;; does seem to work properly, at least on GNU grep. Using "grep -E"
- ;; with this PCRE regexp doesn't work quite right, as it doesn't match
- ;; all the keywords, but pcre2el doesn't convert to "extended regular
- ;; expressions", so this will have to do. Maybe we should test whether
- ;; the version of grep installed supports "-P".
- ;; NOTE: For some reason, when "-execdir" is used, the callback function is never
- ;; called, even though the process terminates and its buffer has the correct
- ;; output. It works correctly when "-exec" is used, so we use that.
- (list "-exec" "grep" "-bPH"
- (when magit-todos-ignore-case
- "--ignore-case")
- extra-args
- search-regexp-pcre "{}" "+"))))
-
-;;;;; Set scanner default value
-
-;; Now that all the scanners have been defined, we can set the value.
-(custom-reevaluate-setting 'magit-todos-scanner)
-
-;;;; Helm/Ivy
-
-;; These add optional support for Helm and Ivy. This code does not require
-;; Helm or Ivy to be installed; it is only called after one of them is loaded.
-
-(declare-function helm-make-source "ext:helm-source")
-
-(with-eval-after-load 'helm
- (defvar helm-magit-todos-source
- ;; We use `helm-make-source' instead of `helm-make-sync-source', which is a
- ;; macro, which won't be present if the user doesn't have Helm installed.
- (helm-make-source "helm-magit-todos" 'helm-source-sync
- :candidates #'magit-todos-candidates
- :action (lambda (item)
- (magit-todos-jump-to-item :item item))))
-
- (defun helm-magit-todos ()
- "Display `magit-todos' items with Helm.
-Note that this uses `magit-todos-items-cache' when a Magit status
-buffer is available for the repository directory, in which case
-the cache is not updated from this command."
- (interactive)
- (helm :sources '(helm-magit-todos-source))))
-
-(declare-function ivy-read "ext:ivy")
-
-(with-eval-after-load 'ivy
- (defvar ivy-magit-todos-history nil
- "History for `ivy-magit-todos'.")
-
- (defun ivy-magit-todos ()
- "Display `magit-todos' items with Ivy.
-Note that this uses `magit-todos-items-cache' when a Magit status
-buffer is available for the repository directory, in which case
-the cache is not updated from this command."
- (interactive)
- (ivy-read "TODOs: " (magit-todos-candidates)
- :action (lambda (item)
- (magit-todos-jump-to-item :item (cdr item)))
- :history 'ivy-magit-todos-history
- :caller 'ivy-magit-todos)))
-
-;;;;; Support
-
-;; These functions are used by both Helm and Ivy.
-
-(defsubst magit-todos-item-cons (item)
- "Return ITEM as a (DISPLAY . ITEM) pair.
-Used for e.g. Helm and Ivy."
- (cons (concat (magit-todos-item-filename item) " "
- (funcall (if (s-suffix? ".org" (magit-todos-item-filename item))
- #'magit-todos--format-org
- #'magit-todos--format-plain)
- item))
- item))
-
-(defun magit-todos-candidates ()
- "Return list of (DISPLAY . ITEM) candidates for e.g. Helm and Ivy."
- ;; MAYBE: Update the cache appropriately from here.
- (if-let* ((magit-status-buffer (magit-get-mode-buffer 'magit-status-mode))
- (items (buffer-local-value 'magit-todos-item-cache magit-status-buffer)))
- ;; Use cached items.
- (cl-loop for item in items
- collect (magit-todos-item-cons item))
- ;; No cached items: run scan.
- (when-let* ((items (funcall magit-todos-scanner :sync t
- :directory default-directory
- :depth magit-todos-depth)))
- (cl-loop for item in items
- collect (magit-todos-item-cons item)))))
-
-;;;; Footer
-
-(provide 'magit-todos)
-
-;;; magit-todos.el ends here