A walk through the Magit interface
emacsair.me
emacsair.me
Example:
When I'm ready to commit my changes:
I can spin-off a new branch:
- If I have an Org-mode task that I'm currently clocked-in, it can check if it contains a ticket number, then query the issue-tracking system and generate a branch name based on the description.
All it takes is pressing two buttons: `b s`, and the rest is done automatically
- I commit my changes, it can use a template and fill out the details, I just need to add a description. I can even make it so it compliant with git-commit format enforcer like gommit. I can add fields like reported-by, cc, etc. with a single keystroke;
- If I suddenly find out that I forgot to add something, I don't have to amend, I don't have to modify the commit, I can just stage my change and press `c e` - "extend". It will quietly add it to my previous commit.
- Using Forge I can create a PR. Once I push the PR, I can trigger a request to issue-tracker that marks the ticket as in "code review"
There are bunch of things that other Git clients can't do* and even when they do it, it's not so easy to extend them to work with different projects, issue-tracking systems, etc.
* e.g. you can select a bunch of files in Dired and see git log pertaining changes only to those files https://twitter.com/iLemming/status/1193025618742349824
Unless I’ve thoroughly misunderstood you, what you’re saying is that “c e” is equivalent to “git commit --amend”. This sounds suspiciously like “amend[ing]”.
Sure, git’s user interface is somewhere between mediocre and abysmal, but it’s not really clear to me that “c e” is a vast improvement.
I say this as a former org-mode user and even one-time contributor. Eventually I decided that the sheer number of magic incantations I had to remember to do anything useful wasn’t worth it.
Of course you could do something similar with shell aliases or reverse search, but then there are other switches and flags that you need occasionally, etc. And it's sooo much more convenient to have everything in one place right in your editor. It's almost unfair how much faster I can get stuff done than folks who don't use it ;)
Magit isn't hype, it's as good as everyone says it is. You just have to try it.
Exactly! People switch to Emacs because someone shows them Magit. Even though they either don't care much about Emacs or it intimidates them.
I myself used IntelliJ for a long time. I have to say, IntelliJ has a superb Git integration. For a very long time I didn't want to switch to Emacs, because I didn't want to lose that. I thought Emacs's Magit thing just not good enough - it can't be, IntelliJ's seemed to be just unbeatable. Oh boy, how wrong I was. Wasted years of my life being ignorant.
Not saying that Magit isn't worth it (never used it), but it's not a fair comparison. I don't `git commit --amend --no-edit`: I `git amend` to edit the last commit, `git amend HASH` to edit any commit, `git amend -i` to pick a commit to edit in a searchable list with preview of their content.
That's 9 characters plus the effort of finding and copy/pasting the hash. With magit it's two characters and you just focus on the hash in question.
> `git amend -i` to pick a commit to edit in a searchable list with preview of their content
That's cool! Still a lot more typing than with Magit, which also has a searchable list with content previews ;)
I'm happy that you've found ways to optimize your workflow, but seriously, Magit is still faster.
That's how your argumentation sounds to me.
Isn't that the point of Magit?
People who never tried Magit often say either of these two things:
- "I'm already an expert in Git, I'm fine with the command line", or
- "Git is confusing already, I don't want to learn yet another thing"
The main point about Magit (unlike many other Git GUIs) - is to help you discover Git features, and allow you to do your work in a very efficient and simple workflow. However, it would do so without hiding Git mechanics from the user. Anytime you can check what the actual Git command gets executed.
Magit doesn't liberate you from learning Git internals, but at the same time it doesn't overwhelm you with tons of different command-line switches. You don't have to memorize anything, the reference for all the commands is always available to you.
I believe, I have become a Git ninja because of Magit. Without it, who knows, maybe I would never learn many features of Git.
Also the workflow I described is not completely automated yet, I'm still experimenting and it's not very clean - things right now are scattered across different config files.
If you have any questions I would gladly try to answer them in a private chat: either email, twitter, signal, telegram or keybase. Let me know.
I can't hook a function to automatically git pull changes when I open it because the pull command only works when the buffer is up.
I'm sure there is some magic to set the current buffer, but for me this is not trivial.
Ideally (magit-diff "myfile.py") should be all I need to do.
What are you talking about? It's written in Emacs-lisp, the possibilities are virtually limited only by Emacs's capabilities. Explain what you're trying to do, maybe post your problem to emacs.stackexchange, r/emacs. I'm sure people would be able to help you.
One small example: I needed to see log of commits since the last pull, basically `git log ORIG_HEAD..HEAD`, but in a way that's compatible with Magit, otherwise I would just do it in the command line. It's not something that people would do very often, it's not usually built into the client. To get something like that to work with Magit, literally takes a single line of emacs-lisp.
https://github.com/caldwell/commit-patch
Works on generic diff buffers, and is not tied to git specifically. And you can just edit the diff buffer, which gives you infinite flexibility. Since emacs already has vc mode, the only extra thing magit does is rebasing. For everything else, vc-mode and commit-patch are superior.
Regarding commit-patch specifically, its readme says that, to commit parts of a patch in separate commits, hunks must be "killed, split, or edited" into separate patches.
Magit is obviously superior to that: with a few keypresses, hunks in the working tree can be staged, hunks in the index can be unstaged, etc. Unstaged changes in the working tree can quickly be sliced and diced and committed separately. Individual lines can be staged or unstaged by selecting them visually. Magit can even automatically back up changes at each stage of the process into special branches, so if you realize, hours or days later, that you accidentally discarded some code without committing it, you can easily retrieve it.
Magit is the most powerful, efficient version control tool. See for yourself: https://magit.vc/
You have no idea on how many levels that statements is false, there's much more than just the rebase:
- You ever needed to see branches in a specific order, sorted by committer-date?
- What about filtering them, maybe showing only those that yet not merged to master?
- What about ordering commits, searching through them, etc.
- You ever wanted to see all the commits authored by you that are at least two months older?
- Ever needed to see commits that only include a specific set of files?
- What about tracing the evolution of a given function?
- Bisects, have you ever done those?
- You ever had a stash that you can't pop because you made changes, and now you have to resolve conflicts?
- Have you ever thought about cherry-picking a specific line from a stash, another branch, etc.?
- Ever needed to work with submodules?
- Ever thought about how nice would it be to issue a Pull request without leaving Emacs?
I'm not sure when was the last time you tried Magit, but maybe try again. Perhaps then you'd appreciate how much good stuff people built into it. It's impressive because aside from a single (hugely successful) Kickstarter campaign and some small voluntary contributions, maintainer and contributors don't get paid for the fantastic work they do, and your comment in that context sounds a bit disingenuous.
Rebasing with Magit is a joy, it feels like you're a tailor and you just need to cut the fabric into nice pieces, and if sometimes things get too big or too small, you can always quickly fix it. And even when it feels that you accidentally ruined everything, you can always look at the reflog and un-ruin everything back to normal.
For the rest of us we can select lines in vscode, and then either:
- right click,
- ctrl+shift+p <type stage, stage selected lines>
You don't have to know Emacs to use Magit. People often try Magit, usually because someone shows them the workflow. They don't even want to learn Emacs to begin with, but Magit looks awesome.
- u for hunks
- 1 for individual lines
`git` (the binary) respects your choice of editor, as indicated by the environment variable `EDITOR`.
You should be able to do something like `EDITOR=code git add -p`, it'll open up hunks for editing in `code` (or intellij, or textedit, or whatever).
I'm sure magit is nice. It's just that everything you list as nice things about magit are in vanilla git as well. Maybe you prefer the presentation in magit, that's fine. The point is to be fully aware of the available options - which the author of the article doesn't seem to be, as they only compare against git add -p, not against git gui.
The one thing that's truly missing in vanilla git as far as I know is the ability to edit the index directly, without editing the checked out files. (Does magit allow that? It's not an advertised feature in the article as far as I can see...)
Magit is not trying to replace Git, it's not pretending to be something else. You still have pretty much everything what's in Git. You can still use your aliases and run vanilla git commands. So why do you need Magit? For efficiency. You don't care about your efficiency? Fine. But please don't make conclusions that the advocates of Magit don't know better. We have tried other alternatives and we have used git command line.
> ability to edit the index directly, without editing the checked out files
What? I don't think I understand what you're asking for here. You stage parts of a file or the whole file. It shows up in "Staged changes" section of Magit buffer. You edit the file, save it, parts that are diverse now will be shown within "Unstaged changes" in a nice diff. You may choose to stage new changes, you may resolve conflicts in a three-way-merge window, discard your changes (staged changes remain), etc.
Why would you want to edit staged parts without modifying the file itself? I don't get it.
The common pattern is that as a consequence of squashing, rebasing, and so on, an early patch in the series has a bug / compile error that is trivially fixed in the next patch in the series.
In those situation, you have to fix the first commit in a middle of a rebase, but keep the result _after_ the next patch the same. This can currently be done by making the change, immediately reverting it, and then squashing things together again. That is, before you have:
o -- A -- B
Then: o -- A -- F -- F^{-1} -- B
Then you squash A and F and F^{-1} and B to get: o -- A' -- B'
Having a more convenient way of doing such fixups would be nice, and I think being able to edit the index directly would help in some of them.---
What about if you overwrite a few lines of something and now the original only exists in another branch? You can peek into that thing, check the diff, even jump into the version in the other branch (without having to check it out) and selectively "cherry-pick" lines of code.
It's a seamless workflow, it doesn't feel like you're doing one thing at a time, it feels more natural and doesn't require undivided focus like: "no, I can't afford a bathroom break right now, I'm in the middle of staging, goddammit."
Seriously, it's not a competition of which git-client has more features.
Magit is much more than just "I can do that" thing. It is extremely efficient, it allows (probably) the most efficient git workflow that can be extended and customized.
It's not the most beautiful thing - the same thing can be said about an industrial excavator. But do you want a beauty or the efficiency? (You want beauty? download GitKraken or something) Can you imagine if someone removes all the controls inside the said excavator and replaces them with a single iPad like device in the middle of the dashboard? Yah, perhaps it'll be aesthetically pleasing, but would it be efficient, even if it has access to all the features and digging modes, etc.?
If you don't care about the efficiency of your git workflow, fine. But if you do, take my word for it, trust me - you wouldn't find a better way to deal with Git than Magit.
Remember how Windows "won" ?
I won't ever use Github now (how are you going to export all those non-git features like tickets when github is not desirable anymore, hmm?), and neither should you if you care even a tiny bit about open source software !
JSON wasn't a very well-thought idea, we tried to "fix" it with yaml (which turned out to be even worse), compare it with EDN (which is far better, but sadly nobody outside of Clojure community uses much)
> Remember how Windows "won"
Windows still dominates desktop OS market and we're still waiting for "Year of Linux on the desktop". Every year some people claim it to be "this is it", but in reality, it is still far from becoming reality. With WSL now even long-time Linux users are tempted to go back to Windows. And honestly I personally don't like that.
My point is - "worse is always better" *
As I said: either you like it or not - we're stuck with Git and now with Github too.
---
[1]: https://www.youtube.com/watch?v=7ywEgcbaiys&list=PLhXZp00uXB...
My only beef is the main interface can feel very slow sometimes.
I've learned to start using the functions directly from the M-x command line when I can. Like rather than going to the main magit interface to stage a file, just M-x stage-file. Time to stash? M-x magit-stash, etc. No need to jump to the main magit UI much of the time.
;; who cares about tags to be displayed in magit-refs buffer?
(remove-hook 'magit-refs-sections-hook 'magit-insert-tags)
Also there are faster shortcuts, like you said, e.g: `magit-file-dispatch (C-c M-g)`
1. Stage some stuff
2. Start writing the commit message
3. Stage something else
4. Commit
The content staged at (3) doesn’t make it into the commit. This doesn’t fit my mental model from the command line: I think of “commit” as transfer all the staged content into a commit.
Initially magit didn’t do this, but I know it is intentional, and in fact the magit author has explained to me that it accurately reflects the command line. But I just seem totally unable to get used to it! I might even change it locally.
When I work, depending on what I'm doing I either commit often and don't think much about it and then later rebase and group things into meaningful chunks of work, or I just keep committing into a single commit and then at some point break it apart into smaller commits.
Most often though I do try to keep commits nice and clean from the get-go, and very often I want to add something into a commit that's a few hashes away from the HEAD. In that case I would just rebase/modify with autostash option. It will stash everything and get into rebase mode, I'll go into the stash, select things I want to be included in the commit and press `a`, then I continue rebasing, it will modify the commit, un-stash and get me to the point where I was before.
(In my original message I do say i've been using magit daily for 10 years; i'm extremely familiar with all the rebasing operations you mention. i agree they're very useful and i use them multiple times a day.)
So the feature you're asking is not even supported by Git.
And the reason you want that feature, because Magit has spoiled you - when almost everything is nonlinear (unlike with git cmd), you want to extend it even further. Let's be pragmatic, don't complain that it is great that Tesla has autopilot option but you actually wanted it to be an amphibious vehicle, because you live next to a lake.
Now, note that you ran `git commit`, with no arguments. Let's think about an alternative narrative on the command line, involving `git commit -m "$message"`
1. Stage a file.
2. Start drafting your commit message.
3. Stage another file.
4. Finish drafting your commit message.
5. Issue git commit -m "$message"
This time, both files make it into the commit.
So basically, we are now thinking of the Magit commit composition buffer as a place where you draft a work-in-progress commit message.
I think we can both agree that the idea of having a place where you can draft your commit message, and meanwhile alter the contents of the staging area, is not unreasonable. Perhaps as an alternative to the standard flow.
So my question to you (and those who might consider working on magit code) is: what advantages does the other model have? (other than it mirroring `git commit` with no arguments). Would one ever really want to mess about with the contents of the staging buffer while you have a pending commit message that you have not yet actually committed? Isn't it in fact more likely that what you want to do, while that commit message is pending, is alter the details of what will be committed?
I'm sure this can be "fixed" by writing some non-trivial Emacs lisp by tapping into `with-editor-finish` or `magit-commit` functions. But honestly, is that worth your time?
Emacs is weird, it makes you want weird things. So many times I would find myself irritated by "an issue" that I just stumbled on, I would write some emacs lips to fix the problem (just because I can), only later to realize there's no problem to begin with.
(defun myrmornis--magit-commit-staged ()
(interactive)
(let ((commit-message (buffer-string)))
(let ((with-editor-cancel-message ""))
(with-editor-cancel nil))
(with-temp-buffer
(insert commit-message)
(goto-char (point-min))
(delete-matching-lines "^[ \t]*#") ;; hack
(magit-run-git-with-input "commit" "-F" "-")))
(magit-refresh-all))
(use-package magit
:bind (:map with-editor-mode-map
("C-c C-c" . myrmornis--magit-commit-staged))As I said, maybe there are people who'd find it extremely useful. Would you mind sharing your "hack" in https://github.com/magit/magit or https://gitter.im/magit/magit ?
Yep sure, I can open an issue to add a setting for this. I suspect it will be rejected but that's OK; I think an issue is justified because I use git and magit very intensively and have been unable to escape the `git commit -m` mental model.
The commit itself holds the draft of the commit message.
It becomes permanent when you stop tweaking the commit and publish it.
Examples: https://twitter.com/iLemming/status/1193025618742349824 https://twitter.com/iLemming/status/1058507342830923776
Also you can run any arbitrary git command from Magit dispatch, just press `!`