Restore pre v2.4 key bindings

Jonas Bernoulli edited this page Mar 29, 2016 · 2 revisions

Please also see the release announcement for v2.4 and the documentation about Branching.

What changed?

Starting with version 2.4, Magit supports the push-remote in addition to the upstream. This made it necessary to add and change some key bindings as summarized in the following table.

< v2.4 >= 2.4
f magit-fetch-popup f magit-fetch-popup
f p magit-fetch-from-push-remote
f f magit-fetch-current f u magit-fetch-from-upstream
f o magit-fetch f e magit-fetch from elsewhere
F magit-pull-popup F magit-pull-popup
F p magit-pull-from-push-remote
F F magit-pull-current F u magit-pull-from-upstream
F o magit-pull F e magit-pull from elsewhere
r magit-rebase-popup r magit-rebase-popup
r p magit-rebase-onto-remote
r l magit-rebase-unpushed r u magit-rebase-onto-upstream
r r magit-rebase r e magit-rebase onto elsewhere
P magit-push-popup P magit-push-popup
P Q magit-push-quickly P p magit-push-current-to-push-remote
P P magit-push-current P u magit-push-current-to-upstream
P e magit-push-elsewhere P e magit-push-current to elsewhere

As you can see, the new bindings are consistent across these four popups. p always acts on the push-remote, u always acts on the upstream, and e (for elsewhere) always reads a branch or remote from the user and then acts on that.

The old "same-key-twice" bindings

Previously, pressing the same key, which was used to enter the popup buffer, a second time once inside the popup buffer, did invoke the "most useful and commonly used of the available commands":

  • f f fetched from the upstream of the current branch.
  • F F pulled into the current branch from its upstream.
  • P P pushed the current branch to its upstream.

Unfortunately there was an inconsistency: r r which, by that logic, should have rebased the current branch onto its upstream, did instead ask for a branch to rebase onto. r l did rebase onto the upstream.

It is understandable, that some users would like to preserve these key bindings, even at the cost of the consistency and added safety introduced by the new bindings. I actually did investigate whether I could preserve these bindings by default and offer an option to allow users to opt-in to the new bindings.

Unfortunately it turned out that, due to the added push-remote support and the old inconsistencies, there is not just a single way in which the old bindings could be preserved. Furthermore the most useful variant is also the most dangerous one.

So I decided play it safe and to instead go with the new, consistent bindings by default and document the various ways in which the old bindings can be restored.

Restoring the old bindings

The compromise

I considered using the bindings established by the below code block by default. They constitute a compromise between the bindings which actually ended up as the new default and the old same-key-twice bindings.

(with-eval-after-load 'magit
  (magit-change-popup-key 'magit-fetch-popup  :action ?u ?f)
  (magit-change-popup-key 'magit-pull-popup   :action ?u ?F)
  (magit-change-popup-key 'magit-rebase-popup :action ?e ?r)
  (magit-change-popup-key 'magit-push-popup   :action ?p ?P))

The rule "u acts on upstream, p acts on push-remote, and e acts on elsewhere" is followed; except when the respective command is the most useful command, for that command a same-key-twice binding is used instead.

But this does not actually preserve the old bindings. With these bindings in effect, some of these keys (P P and r r) would do something different from what they used to do. Instead this preserves the idea that pressing the same key twice should call the most useful variant.

Because Magit now supports the push-remote, pushing to the upstream is no longer the most useful push command. On the contrary, except for branches such as master and maint, pushing to the upstream usually is a mistake.

This also fixes the inconsistency regarding r r.

The 2.1 release contained a change which took some users by surprise and caused them to accidentally push to the wrong branch. I very much wanted to prevent something similar from happening again, so this variant was off the table. In my opinion the other variants described below don't make much sense, so I went with the new, fully consistent bindings.

Mostly default to upstream

If you would like the same-key-twice bindings to acted on the upstream even for pushing, then do this:

(with-eval-after-load 'magit
  (magit-change-popup-key 'magit-fetch-popup  :action ?u ?f)  ; 2x upstream
  (magit-change-popup-key 'magit-pull-popup   :action ?u ?F)  ; 2x upstream
  (magit-change-popup-key 'magit-rebase-popup :action ?e ?r)  ; 2x elsewhere
  (magit-change-popup-key 'magit-rebase-popup :action ?u ?l)  ; -- upstream
  (magit-change-popup-key 'magit-push-popup   :action ?u ?P)) ; 2x upstream

The r r inconsistency is faithfully preserved.

Always default to upstream

If you would like the same-key-twice bindings to always acted on the upstream even for pushing and rebasing, then do this:

(with-eval-after-load 'magit
  (magit-change-popup-key 'magit-fetch-popup  :action ?u ?f)  ; 2x upstream
  (magit-change-popup-key 'magit-pull-popup   :action ?u ?F)  ; 2x upstream
  (magit-change-popup-key 'magit-rebase-popup :action ?u ?r)  ; 2x upstream
  (magit-change-popup-key 'magit-push-popup   :action ?u ?P)) ; 2x upstream

This fixes the r r inconsistency.

Muscle memory is sacred

If you would like to undo each and every change to key bindings, then do this:

(with-eval-after-load 'magit
  (magit-change-popup-key 'magit-fetch-popup  :action ?u ?f)  ; upstream
  (magit-change-popup-key 'magit-fetch-popup  :action ?e ?o)  ; elsewhere
  (magit-change-popup-key 'magit-pull-popup   :action ?u ?F)  ; upstream
  (magit-change-popup-key 'magit-pull-popup   :action ?e ?o)  ; elsewhere
  (magit-change-popup-key 'magit-rebase-popup :action ?u ?l)  ; upstream
  (magit-change-popup-key 'magit-rebase-popup :action ?e ?r)  ; elsewhere
  (magit-change-popup-key 'magit-rebase-popup :action ?s ?o)  ; subset
  (magit-change-popup-key 'magit-rebase-popup :action ?m ?e)  ; edit
  (magit-change-popup-key 'magit-push-popup   :action ?p ?Q)  ; push-remote
  (magit-change-popup-key 'magit-push-popup   :action ?u ?P)) ; upstream

This faithfully restores all the old inconsistencies, and due to the added push-remote support also adds a new inconsistency.

  • f p, F p, and r p vs. P Q (push-remote)
  • f f, F F, and P P vs. r l (upstream)
  • f o and F o vs. P e vs. r r (elsewhere)

I also changed some bindings in the branch popup (but so far nobody complained about that). If you want to undo that too , then you also need this:

(with-eval-after-load 'magit
  (magit-change-popup-key 'magit-branch-popup :action ?c ?B)
  (magit-change-popup-key 'magit-branch-popup :action ?n ?c))

The nuclear option

If you don't want to make use of the push-remote support at all, then do this:

(with-eval-after-load 'magit
  (magit-remove-popup-key 'magit-branch-popup :variable ?p)
  (magit-remove-popup-key 'magit-branch-popup :variable ?\M-p)
  (magit-remove-popup-key 'magit-fetch-popup  :action ?p)     ; push-remote
  (magit-change-popup-key 'magit-fetch-popup  :action ?u ?f)  ; upstream
  (magit-change-popup-key 'magit-fetch-popup  :action ?e ?o)  ; elsewhere
  (magit-remove-popup-key 'magit-pull-popup   :action ?p)     ; push-remote
  (magit-change-popup-key 'magit-pull-popup   :action ?u ?F)  ; upstream
  (magit-change-popup-key 'magit-pull-popup   :action ?e ?o)  ; elsewhere
  (magit-remove-popup-key 'magit-rebase-popup :action ?p)     ; push-remote
  (magit-change-popup-key 'magit-rebase-popup :action ?u ?l)  ; upstream
  (magit-change-popup-key 'magit-rebase-popup :action ?e ?r)  ; elsewhere
  (magit-change-popup-key 'magit-rebase-popup :action ?s ?o)  ; subset
  (magit-change-popup-key 'magit-rebase-popup :action ?m ?e)  ; edit
  (magit-remove-popup-key 'magit-push-popup   :action ?p)     ; push-remote
  (magit-change-popup-key 'magit-push-popup   :action ?u ?P)) ; upstream