The Disconnected Git Workflow
The Disconnected Git Workflow
Using git-send-email while being offline and with multiple email accounts
WARNING: the following is a technical reminder for my future self. If you don’t use the "git" software, you can safely ignore this post.
The more I work with git-send-email, the less I find the GitHub interface sufferable.
Want to send a small patch to a GitHub project? You need to clone the repository, push your changes to your own branch, then ask for a pull request using the cumbersome web interface, replying to comments online while trying to avoid smileys.
With git send-email, I simply work offline, do my local commit, then:
git send-email HEAD^
And I’m done. I reply to comments by email, with Vim/Mutt. When the patch is accepted, getting a clean tree usually boils down to:
git pull
git rebase
Yeah for git-send-email!
And, yes, I do that while offline and with multiple email accounts. That’s one more reason to hate GitHub.
- How GitHub monopoly is destroying the open source ecosystem (ploum.net)
- We need to talk about your GitHub addiction (ploum.net)
One mail account for each git repository
The secret is not to configure email accounts in git but to use "msmtp" to send email. Msmtp is a really cool sendmail replacement.
In .msmtprc, you can configure multiple accounts with multiple options, including calling a command to get your password.
# account 1 - pro account work host smtp.company.com port 465 user login@company.com from ploum@company.com password SuPeRstr0ngP4ssw0rd tls_starttls off # personal account for FLOSS account floss host mail.provider.net port 465 user ploum@mydomain.net from ploum@mydomain.net from ploum*@mydomain.net passwordeval "cat ~/incredibly_encrypted_password.txt | rot13" tls_starttls off
The important bit here is that you can set multiple "from" addresses for a given account, including a regexp to catch multiple aliases!
Now, we will ask git to automatically use the right msmtp account. In your global .gitconfig, set the following:
[sendemail] sendmailCmd = /usr/bin/msmtp --set-from-header=on envelopeSender = auto
The "envelopesender" option will ensure that the sendemail.from will be used and given to msmtp as a "from address." This might be redundant with "--set-from-header=on" in msmtp but, in my tests, having both was required. And, cherry on the cake, it automatically works for all accounts configured in msmtprc.
Older git versions (< 2.33) don’t have sendmailCmd and should do:
[sendemail] smtpserver = /usr/bin/msmtp smtpserveroption = --set-from-header=on envelopesender = auto
I usually stick to a "ploum-PROJECT@mydomain.net" for each project I contribute to. This allows me to easily cut spam when needed. So far, the worst has been with a bug reported on the FreeBSD Bugzilla. The address used there (and nowhere else) has since been spammed to death.
In each git project, you need to do the following:
1. Set the email address used in your commit that will appear in "git log" (if different from the global one)
git config user.email "Ploum <ploum-PROJECT@mydomain.net>"
2. Set the email address that will be used to actually send the patch (could be different from the first one)
git config sendemail.from "Ploum <ploum-PROJECT@mydomain.net>"
3. Set the email address of the developer or the mailing list to which you want to contribute
git config sendemail.to project-devel@mailing-list.com
Damn, I did a commit with the wrong user.email!
Yep, I always forget to change it when working on a new project or from a fresh git clone. Not a problem. Just use "git config" like above, then:
git commit --amend --reset-author
And that’s it.
Working offline
I told you I mostly work offline. And, as you might expect, msmtp requires a working Internet connection to send an email.
But msmtp comes with three wonderful little scripts: msmtp-enqueue.sh, msmtp-listqueue.sh and msmtp-runqueue.sh.
The first one saves your email to be sent in ~/.msmtpqueue, with the sending options in a separate file. The second one lists the unsent emails, and the third one actually sends all the emails in the queue.
All you need to do is change the msmtp line in your global .gitconfig to call the msmtpqueue.sh script:
[sendemail]
sendmailcmd = /usr/libexec/msmtp/msmtpqueue/msmtp-enqueue.sh --set-from-header=on
envelopeSender = auto
In Debian, the scripts are available with the msmtp package. But the three are simple bash scripts that can be run from any path if your msmtp package doesn’t provide them.
You can test sending a mail, then check the ~/.msmtpqueue folder for the email itself (.email file) and the related msmtp command line (.msmtp file). It happens nearly every day that I visit this folder to quickly add missing information to an email or simply remove it completely from the queue.
Of course, once connected, you need to remember to run:
/usr/libexec/msmtp/msmtpqueue/msmtp-runqueue.sh
If not connected, mails will not be sent and will be kept in the queue. This line is obviously part of my do_the_internet.sh script, along with "offpunk --sync".
It is not only git!
If it works for git, it works for any mail client. I use neomutt with the following configuration to use msmtp-enqueue and reply to email using the address it was sent to.
set sendmail="/usr/libexec/msmtp/msmtpqueue/msmtp-enqueue.sh --set-from-header=on" unset envelope_from_address set use_envelope_from set reverse_name set from="ploum@mydomain.net" alternates ploum[A-Za-z0-9]*@mydomain.net
Of course, the whole config is a little more complex to handle multiple accounts that are all stored locally in Maildir format through offlineimap and indexed with notmuch. But this is a bit out of the scope of this post.
At least, you get the idea, and you could probably adapt it to your own mail client.
Conclusion
Sure, it’s a whole blog post just to get the config right. But there’s nothing really out of this world. And once the setup is done, it is done for good. No need to adapt to every change in a clumsy web interface, no need to use your mouse. Simple command lines and simple git flow!
Sometimes, I work late at night. When finished, I close the lid of my laptop and call it a day without reconnecting my laptop. This allows me not to see anything new before going to bed. When this happens, queued mails are sent the next morning, when I run the first do_the_internet.sh of the day.
And it always brings a smile to my face to see those bits being sent while I’ve completely forgotten about them…
About the author
I’m Ploum, a writer and an engineer. I like to explore how technology impacts society. You can subscribe by email or by rss. I value privacy and never share your adress.
I write science-fiction novels in French. For Bikepunk, my new post-apocalyptic-cyclist book, my publisher is looking for contacts in other countries to distribute it in languages other than French. If you can help, contact me!