<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>github — jd:/dev/blog</title><description>Posts tagged &quot;github&quot; on jd:/dev/blog.</description><link>https://julien.danjou.info/</link><item><title>Properly managing your .gitignore file</title><link>https://julien.danjou.info/blog/properly-managing-your-gitignore/</link><guid isPermaLink="true">https://julien.danjou.info/blog/properly-managing-your-gitignore/</guid><description>There&apos;s not a single month where I don&apos;t have to explain this. I thought it&apos;d be a good opportunity to write about this .gitignore file so everyone is up to date on this magic file.  The purpose of .g</description><pubDate>Mon, 02 Dec 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;There&apos;s not a single month where I don&apos;t have to explain this. I thought it&apos;d be a good opportunity to write about this &lt;code&gt;.gitignore&lt;/code&gt; file so everyone is up to date on this magic file.&lt;/p&gt;
&lt;h2&gt;The purpose of &lt;code&gt;.gitignore&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;The &lt;code&gt;.gitignore&lt;/code&gt; file is meant to be a list of files that &lt;em&gt;Git&lt;/em&gt; should not track. It resides at the root directory of your repository. It can be a list of file path relative to the repository, or a list of wildcard. &lt;a href=&quot;https://git-scm.com/docs/gitignore&quot;&gt;The file format and location is fully documented in Git documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For example, this is a valid content for a &lt;code&gt;.gitignore&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;foo
bar/*
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When you&apos;re using Git commands such as &lt;code&gt;git add&lt;/code&gt;, all the files matching what&apos;s listed in &lt;code&gt;.gitignore&lt;/code&gt; are ignored. That makes sure you don&apos;t commit a file that should not be there by mistake. In the example above, any file in the &lt;code&gt;bar&lt;/code&gt; directory or any file named &lt;code&gt;foo&lt;/code&gt; will be completely ignored by all &lt;em&gt;Git&lt;/em&gt; commands.&lt;/p&gt;
&lt;p&gt;Awesome!&lt;/p&gt;
&lt;h3&gt;What&apos;s the problem with it?&lt;/h3&gt;
&lt;p&gt;Soon, developers realize that their directory is cluttered with temporary files. It might be from their build system, their editors or some test files they wrote.&lt;/p&gt;
&lt;p&gt;So what do they do? They add those files to &lt;code&gt;.gitignore&lt;/code&gt; for their project. You end up with a &lt;code&gt;.gitignore&lt;/code&gt; file that contains entries like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;*~
.vscode
*.DS_Store
.idea
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, you&apos;re sure to ignore backup files from &lt;em&gt;vim&lt;/em&gt;, folders from MacOS and temporary files from Visual Studio code, etc.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/11/giphy.gif&quot; alt=&quot;Animated reaction GIF expressing frustration with cluttered gitignore files&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Don&apos;t do this. Not everybody uses your editor or favorite pet tool, and nobody cares. The repository you&apos;re working in is shared with a lot of others developers. Sending pull requests to just add this kind of entry to ignore files generated by your pet editor is &lt;em&gt;wrong and annoying&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Wait, how do I ignore my editor files then?&lt;/h3&gt;
&lt;p&gt;If you read through &lt;em&gt;Git&lt;/em&gt; documentation, the answer lies there: &lt;em&gt;Git&lt;/em&gt; has a global ignore file that works for &lt;strong&gt;EVERY&lt;/strong&gt; repository on your system. No need to hack &lt;em&gt;each&lt;/em&gt; repository. By default, it&apos;s in &lt;code&gt;~/.config/git/ignore&lt;/code&gt;. Here&apos;s mine:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;.#*
*.swp
.DS_Store
.dir-locals.el
.dir-locals-2.el
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&apos;s enough to ignore my editors and OS files in all my repositories so I don&apos;t &lt;code&gt;git add&lt;/code&gt; wrong files by mistake. You can tweak this global file location by changing by tweaking &lt;code&gt;core.excludesFile&lt;/code&gt; in your &lt;em&gt;Git&lt;/em&gt; configuration.&lt;/p&gt;
&lt;h3&gt;So what should I put in .gitignore?&lt;/h3&gt;
&lt;p&gt;You should put in &lt;code&gt;.gitignore&lt;/code&gt; all files and patterns that are generated by the build system of your project, or any file that it might output while running.&lt;/p&gt;
&lt;p&gt;For example, for a Python project, it&apos;s common to have this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;*.pyc
__pycache__
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this, it makes sure that nobody is committing compiled Python files.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/11/tumblr_ma0id4kYlv1rv5x9bo1_400.gif&quot; alt=&quot;Animated GIF celebrating proper gitignore usage&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Thanks for reading through this. I hope you&apos;ll write better &lt;code&gt;.gitignore&lt;/code&gt; files in the future. 🤞&lt;/p&gt;
</content:encoded><category>github</category></item><item><title>Dependencies Handling in Python</title><link>https://julien.danjou.info/blog/dependencies-handling-in-python-automatic-update/</link><guid isPermaLink="true">https://julien.danjou.info/blog/dependencies-handling-in-python-automatic-update/</guid><description>Dependencies are a nightmare. Here&apos;s how to handle them properly in Python with pipenv, poetry, Dependabot, and Mergify for fully automatic updates.</description><pubDate>Mon, 02 Sep 2019 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Dependencies are a nightmare for many people. &lt;a href=&quot;https://thenewstack.io/to-reduce-tech-debt-eliminate-dependencies-and-refactoring/&quot;&gt;Some even argue they are technical debt&lt;/a&gt;. Managing the list of the libraries of your software is a horrible experience. Updating them — automatically? — sounds like a delirium.&lt;/p&gt;
&lt;p&gt;Stick with me here as I am going to help you get a better grasp on something that you cannot, in practice, get rid of — unless you&apos;re incredibly rich and talented and can live without the code of others.&lt;/p&gt;
&lt;p&gt;First, we need to be clear of something about dependencies: there are two types of them. &lt;a href=&quot;https://caremad.io/posts/2013/07/setup-vs-requirement/&quot;&gt;Donald Stuff wrote better than I would about the subject&lt;/a&gt; years ago. To make it simple, one can say that they are two types of code packages depending on  external code: applications and libraries.&lt;/p&gt;
&lt;h3&gt;Libraries Dependencies&lt;/h3&gt;
&lt;p&gt;Python libraries should specify their dependencies in a generic way. A library should not require &lt;code&gt;requests 2.1.5&lt;/code&gt;: it does not make sense. If every library out there needs a different version of &lt;code&gt;requests&lt;/code&gt;, they can&apos;t be used at the same time.&lt;/p&gt;
&lt;p&gt;Libraries need to declare dependencies based on ranges of version numbers. Requiring &lt;code&gt;requests&amp;gt;=2&lt;/code&gt; is correct. Requiring &lt;code&gt;requests&amp;gt;=1,&amp;lt;2&lt;/code&gt; is also correct if you know that &lt;code&gt;requests 2.x&lt;/code&gt; does not work with the library. The problem that your version range specification is solving is the &lt;strong&gt;API compatibility issue&lt;/strong&gt; between your code and your dependencies — &lt;em&gt;nothing else&lt;/em&gt;. That&apos;s a good reason for libraries to use &lt;a href=&quot;https://semver.org/&quot;&gt;Semantic Versioning&lt;/a&gt; whenever possible.&lt;/p&gt;
&lt;p&gt;Therefore, dependencies should be written in &lt;code&gt;setup.py&lt;/code&gt; as something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;from setuptools import setup

setup(
    name=&quot;MyLibrary&quot;,
    version=&quot;1.0&quot;,
    install_requires=[
        &quot;requests&quot;,
    ],
    # ...
)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This way, it is easy for any application to use the library and co-exist with others.&lt;/p&gt;
&lt;h3&gt;Applications Dependencies&lt;/h3&gt;
&lt;p&gt;An application is just a particular case of libraries. They are not intended to be reused (imported) by other libraries of applications — though nothing would prevent it in practice.&lt;/p&gt;
&lt;p&gt;In the end, that means that you should specify the dependencies the same way that you would do for a library in the application&apos;s &lt;code&gt;setup.py&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The main difference is that an application is usually &lt;em&gt;deployed&lt;/em&gt; in production to provide its service. Deployments need to be reproducible. For that, you can&apos;t solely rely on &lt;code&gt;setup.py&lt;/code&gt;: the requested range of the dependencies are too broad. You&apos;re at the mercy of random version changes at any time when re-deploying your application.&lt;/p&gt;
&lt;p&gt;You, therefore, need a different version management mechanism to handle deployment than just &lt;code&gt;setup.py&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;pipenv&lt;/em&gt; has &lt;a href=&quot;https://docs.pipenv.org/en/latest/advanced/#pipfile-vs-setuppy&quot;&gt;an excellent section recapping this&lt;/a&gt; in its documentation. It splits dependency types into &lt;em&gt;abstract&lt;/em&gt; and &lt;em&gt;concrete&lt;/em&gt; dependencies: &lt;em&gt;abstract&lt;/em&gt; dependencies are based on ranges (e.g., libraries) whereas &lt;em&gt;concrete&lt;/em&gt; dependencies are specified with precise versions (e.g., application deployments) — as we&apos;ve just seen here.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Handling Deployment&lt;/h3&gt;
&lt;p&gt;The &lt;code&gt;requirements.txt&lt;/code&gt; file has been used to solve application deployment reproducibility for a long time now. Its format is usually something like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;requests==3.1.5
foobar==2.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Each library sees itself specified to the micro version. That makes sure each of your deployment is going to install the same version of your dependency. Using a &lt;code&gt;requirements.txt&lt;/code&gt; is a simple solution and a first step toward reproducible deployment. However, it&apos;s not &lt;em&gt;enough&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Indeed, while you can specify which version of &lt;code&gt;requests&lt;/code&gt; you want, if &lt;code&gt;requests&lt;/code&gt; depends on &lt;code&gt;urllib3&lt;/code&gt;, that could make &lt;code&gt;pip&lt;/code&gt; install &lt;code&gt;urllib 2.1&lt;/code&gt; or &lt;code&gt;urllib 2.2&lt;/code&gt;. You can&apos;t know which one will be installed, which does not make your deployment 100% reproducible.&lt;/p&gt;
&lt;p&gt;Of course, you &lt;em&gt;could&lt;/em&gt; duplicate all &lt;code&gt;requests&lt;/code&gt; dependencies yourself in your &lt;code&gt;requirements.txt&lt;/code&gt;, but that would be &lt;strong&gt;madness&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/08/image.png&quot; alt=&quot;An application dependency tree can be quite deep and complex sometimes.&quot; /&gt;&lt;/p&gt;
&lt;p&gt;There are various hacks available to fix this limitation, but the real saviors here are &lt;a href=&quot;https://github.com/pypa/pipenv&quot;&gt;&lt;em&gt;pipenv&lt;/em&gt;&lt;/a&gt; and &lt;a href=&quot;https://poetry.eustace.io/&quot;&gt;&lt;em&gt;poetry&lt;/em&gt;&lt;/a&gt;. The way they solve it is similar to many package managers in other programming languages. They generate a &lt;em&gt;lock file&lt;/em&gt; that contains the list of all installed dependencies (and their own dependencies, etc.) with their version numbers. That makes sure the deployment is 100% reproducible.&lt;/p&gt;
&lt;p&gt;Check out their documentation on how to set up and use them!&lt;/p&gt;
&lt;h3&gt;Handling Dependencies Updates&lt;/h3&gt;
&lt;p&gt;Now that you have your &lt;em&gt;lock file&lt;/em&gt; that makes sure your deployment is reproducible in a snap, you&apos;ve another problem. How do you make sure that your dependencies are up-to-date? There is a real security concern about this, but also bug fixes and optimizations that you might miss by staying behind.&lt;/p&gt;
&lt;p&gt;If your project is hosted on &lt;a href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;, &lt;a href=&quot;https://dependabot.com/&quot;&gt;Dependabot&lt;/a&gt; is an excellent solution to solve this issue. Enabling this application on your repository creates automatically pull requests whenever a new version of the library listed in your lock file is available. For example, if you&apos;ve deployed your application with &lt;code&gt;redis 3.3.6&lt;/code&gt;, Dependabot will create a pull request updating to &lt;code&gt;redis 3.3.7&lt;/code&gt; as soon as it gets released. Furthermore, Dependabot supports &lt;code&gt;requirements.txt&lt;/code&gt;, &lt;em&gt;pipenv&lt;/em&gt;, and &lt;em&gt;poetry&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/08/Screenshot-2019-08-14-at-17.57.47.png&quot; alt=&quot;Dependabot updating jinja2 for you&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Automatic Deployment Update&lt;/h2&gt;
&lt;p&gt;You&apos;re almost there. You have a bot that is letting you know that a new version of a library your project needs is available.&lt;/p&gt;
&lt;p&gt;Once the pull request is created, your continuous integration system is going to kick in, deploy your project, and runs the test. If everything works fine, your pull request is ready to be merged. But are &lt;em&gt;you&lt;/em&gt; really needed in this process?&lt;/p&gt;
&lt;p&gt;Unless you have a particular and personal aversion on specific version numbers —&quot;Gosh I hate versions that end with a 3. It&apos;s always bad luck.&quot;— or unless you have zero automated testing, you, human, is useless. This merge can be fully automatic.&lt;/p&gt;
&lt;p&gt;This is where &lt;a href=&quot;https://mergify.io&quot;&gt;&lt;em&gt;Mergify&lt;/em&gt;&lt;/a&gt; comes into play. Mergify is a GitHub application allowing to define precise rules about how to merge your pull requests. Here&apos;s a rule that I use in every project:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pull_requests_rules:
  - name: automatic merge from dependabot
    conditions:
      - author~=^dependabot(|-preview)\[bot\]$
      - label!=work-in-progress
      - &quot;status-success=ci/circleci: pep8&quot;
      - &quot;status-success=ci/circleci: py37&quot;
    actions:
      merge:
        method: merge
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/08/Screenshot-2019-08-14-at-18.38.25.png&quot; alt=&quot;Mergify reports when the rule fully matches&quot; /&gt;&lt;/p&gt;
&lt;p&gt;As soon as your continuous integration system passes, Mergify merges the pull request for you.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/08/Screenshot-2019-08-14-at-18.38.37.png&quot; alt=&quot;Screenshot of Mergify automatically merging a Dependabot pull request&quot; /&gt;&lt;/p&gt;
&lt;p&gt;You can then automatically trigger your deployment hooks to update your production deployment and get the new library version installed right away. This leaves your application always up-to-date with newer libraries and not lagging behind several years of releases.&lt;/p&gt;
&lt;p&gt;If anything goes wrong, you&apos;re still able to revert the commit from Dependabot — which you can also automate if you wish with a Mergify rule.&lt;/p&gt;
&lt;h2&gt;Beyond&lt;/h2&gt;
&lt;p&gt;This is to me the state of the art of dependency management lifecycle right now. And while this applies exceptionally well to Python, it can be applied to many other languages that use a similar pattern — such as Node and &lt;em&gt;npm&lt;/em&gt;.&lt;/p&gt;
</content:encoded><category>python</category><category>mergify</category><category>github</category></item><item><title>More GitHub workflow automation</title><link>https://julien.danjou.info/blog/automating-github-workflows/</link><guid isPermaLink="true">https://julien.danjou.info/blog/automating-github-workflows/</guid><description>The more you use computers, the more you see the potentials for automating everything. Who doesn&apos;t love that?</description><pubDate>Tue, 16 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The more you use computers, the more you see the potentials for automating everything. Who doesn&apos;t love that? By building &lt;a href=&quot;https://mergify.io&quot;&gt;Mergify&lt;/a&gt; those last months, we&apos;ve decided it was time bring more automation to the development workflow.&lt;/p&gt;
&lt;p&gt;Mergify&apos;s first version was a &lt;em&gt;minimal viable product&lt;/em&gt; around automating the merge of pull requests. As &lt;a href=&quot;https://julien.danjou.info/blog/stop-merging-your-pull-request-manually&quot;&gt;I wrote a few months ago&lt;/a&gt;, we wanted to automate the merge of pull requests when it was ready to be merged. For most projects, this is easy and consists of a simple rule: &quot;it must be approved by a developer and pass the CI&quot;.&lt;/p&gt;
&lt;h2&gt;Evolving on Feedback&lt;/h2&gt;
&lt;p&gt;For the first few months, we received a lot of feedback from our users. They were enthusiastic about the product but were frustrated by a couple of things.&lt;/p&gt;
&lt;p&gt;First, Mergify would mess up with branch protections. We thought that people wanted the GitHub UI to match their rules. As I&apos;ll explain later, it turns out to be only partially true, and we found a workaround.&lt;/p&gt;
&lt;p&gt;Then, Mergify&apos;s abilities were capped by some of the limitations of the GitHub workflow and API. For example, GitHub would only allow rules per branch, whereas our users wanted to have rules applied based on a lot of different criteria.&lt;/p&gt;
&lt;h2&gt;Building the Next Engine&lt;/h2&gt;
&lt;p&gt;We rolled up our sleeves and started to build that new engine. The first thing was to get rid of the GitHub branch protection feature altogether and leveraging the Checks API to render something useful to the users in the UI. You can now have a complete overview of the rules that will be applied to your pull requests in the UI, making it easy to understand what&apos;s happening.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/10/1_6XA_yUbEHkgBs86cn31yOw.png&quot; alt=&quot;Screenshot of Mergify Checks API showing rule overview in the GitHub UI&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Then, we wrote a new matching engine that would allow matching any pull requests based on any of its attributes. You can now automate your workflow with a finer-grained configuration.&lt;/p&gt;
&lt;h2&gt;What Does It Look Like?&lt;/h2&gt;
&lt;p&gt;Here&apos;s a simple rule you could write:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;pull_request_rules:
  - name: automatic merge on approval and CI pass
    conditions:
     - &quot;#approved-reviews-by&amp;gt;=1&quot;
     - status-success=continuous-integration/travis-ci/pr
     - label!=work-in-progress
    actions:
      merge:
        method: merge
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With that, any pull request that has been approved by a collaborator, passes the Travis CI job and does not have the label &lt;code&gt;work-in-progress&lt;/code&gt; will be automatically merged by Mergify.&lt;/p&gt;
&lt;p&gt;You could use even more &lt;a href=&quot;https://docs.mergify.io/actions/&quot;&gt;actions&lt;/a&gt; to backport this pull request to another branch, close the pull request or add/remove labels. We&apos;re starting to see users building amazing workflow with that engine!&lt;/p&gt;
&lt;p&gt;We&apos;re thrilled by this new version we launched this week and glad we&apos;re getting amazing feedback (again) from our users.&lt;/p&gt;
&lt;p&gt;When you give it a try, drop me a note and let me know what you think about it!&lt;/p&gt;
</content:encoded><category>mergify</category><category>github</category></item><item><title>A safe GitHub workflow with Pastamaker</title><link>https://julien.danjou.info/blog/pastamaker/</link><guid isPermaLink="true">https://julien.danjou.info/blog/pastamaker/</guid><description>When the Gnocchi project decided to move to GitHub, we developers had to move from a Gerrit based workflow to a GitHub pull-request one.</description><pubDate>Fri, 15 Dec 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;When the &lt;a href=&quot;https://gnocchi.xyz&quot;&gt;Gnocchi&lt;/a&gt; project decided to move to &lt;a href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;, we developers had to move from a Gerrit based workflow to a GitHub pull-request one.&lt;/p&gt;
&lt;p&gt;This has been challenging in some ways. We were satisfied with the workflow we had using Gerrit and &lt;a href=&quot;https://docs.openstack.org/infra/zuul/&quot;&gt;Zuul&lt;/a&gt; for testing so we decided to adapt GitHub to our requirements.&lt;/p&gt;
&lt;p&gt;We know that Zuul now supports GitHub. However, that implies having your own testing infrastructure, something we can&apos;t afford. Instead, we rely on &lt;a href=&quot;http://travis-ci.org&quot;&gt;Travis&lt;/a&gt;, like most open-source projects hosted on GitHub.&lt;/p&gt;
&lt;h2&gt;The workflow&lt;/h2&gt;
&lt;p&gt;The workflow we wanted to have was the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A contributor creates a pull-request on GitHub.&lt;/li&gt;
&lt;li&gt;The pull-request is tested by Travis.&lt;/li&gt;
&lt;li&gt;The pull-request is reviewed by approved projects members.&lt;/li&gt;
&lt;li&gt;If the tests pass and two reviewers have approved the pull-request, then it&lt;br /&gt;
can be merged.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This sounds simple, but it is actually not &lt;em&gt;that&lt;/em&gt; simple.&lt;/p&gt;
&lt;p&gt;First, when Travis tests the pull-request, it checks what has been sent by the contributor. If the contributor created a pull-request on top of an outdated version of the base branch, that&apos;s what will be tested by Travis during the initial pull-request creation.&lt;/p&gt;
&lt;p&gt;Even if the pull-request has been created using the tip of the base branch, as time passes, the base branch will progress. However, the pull-request created by your contributor will not get those new commits – unless rebased manually.&lt;/p&gt;
&lt;p&gt;That means the Travis tests result is now outdated invalid. Still, GitHub and Travis will both show you that this pull-request passed all tests – yes it &lt;em&gt;did&lt;/em&gt; but with an old base branch from a while back!&lt;/p&gt;
&lt;p&gt;If you added new tests in the meantime in your base branch, it&apos;s possible that this pull-request does not work anymore. Pressing the &lt;em&gt;merge&lt;/em&gt; button might just break your project!&lt;/p&gt;
&lt;p&gt;To help with that problem, GitHub recently added a button that allows you to &lt;em&gt;base branch into the pull-request&lt;/em&gt;. That allows, in one click, to get the pull-requested updated with the base branch (e.g., &lt;em&gt;master&lt;/em&gt;) and retested by Travis.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/03/github-update-pr-button.png&quot; alt=&quot;github-update-pr-button&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Still, this means that if you have ten pull-requests, you need to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Merge base branch into PR#1&lt;/li&gt;
&lt;li&gt;Wait for Travis to pass&lt;/li&gt;
&lt;li&gt;Wait for two reviewers to approve&lt;/li&gt;
&lt;li&gt;Merge PR#1&lt;/li&gt;
&lt;li&gt;All other nine pull-requests are not out of date. You need to do start back at operation 1. for each pull-request.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This is very tedious to do manually, especially when your projects has tons of pull-requests.&lt;/p&gt;
&lt;p&gt;This is why &lt;a href=&quot;http://blog.sileht.net&quot;&gt;Mehdi Abaakouk&lt;/a&gt; created &lt;a href=&quot;http://github.com/sileht/pastamaker&quot;&gt;Pastamaker&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Pastamaker to the rescue&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;http://github.com/sileht/pastamaker&quot;&gt;Pastamaker&lt;/a&gt; is a small Web application that implements the described workflow. Once connected to your GitHub project, it will set the proper permissions to protect it for accidental manual merge and force the workflow above to be followed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/03/pastamaker-pr-1.png&quot; alt=&quot;pastamaker-pr-1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Pastamaker listens for GitHub and Travis events to track the state of each pull-request. If it detects that a pull-request has been approved by two reviewers and that the initial Travis test run passed, it will merge the base branch if needed in it, wait for Travis to pass again, and then finally merge it.&lt;/p&gt;
&lt;p&gt;If multiple pull-requests are approved at the same time and are candidates for a merge, it will order them, update once at a time, wait for Travis results and merge them if they pass. It essentially automates the workflow described above.&lt;/p&gt;
&lt;p&gt;Pastamaker exposes its data via a simple dashboard, which allows seeing all the pull-requests for your project in a snap.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/03/pastamaker.png&quot; alt=&quot;pastamaker&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Pastamaker offers a lot of tiny other details that make the developers lives easier, such as posting the job result with direct links to the jobs logs in the pull-request – so you&apos;re informed as soon as they pass or fail and can fix them right away!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://github.com/sileht/pastamaker&quot;&gt;Pastamaker&lt;/a&gt; is obviously open-source, and we would love to see you give it a try!&lt;/p&gt;
</content:encoded><category>mergify</category><category>github</category></item><item><title>Sending GitHub pull-request from your shell</title><link>https://julien.danjou.info/blog/git-pull-request-command-line-tool/</link><guid isPermaLink="true">https://julien.danjou.info/blog/git-pull-request-command-line-tool/</guid><description>I&apos;ve always been frustrated by the GitHub workflow. A while back I wrote how Gerrit workflow was superior to GitHub pull-request system.</description><pubDate>Wed, 24 May 2017 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&apos;ve always been frustrated by the GitHub workflow. A while back I&lt;br /&gt;
wrote &lt;a href=&quot;https://julien.danjou.info/blog/2013/rant-about-github-pull-request-workflow-implementation&quot;&gt;how Gerrit workflow was superior&lt;/a&gt; to GitHub pull-request system. But it seems that GitHub listened and they improved the pull-request system these last years to include reviews, and different workflow implementation, e.g. requiring continuous integration tests to pass before merging a patch.&lt;/p&gt;
&lt;p&gt;All those improvements great helped the Gnocchi team to consider moving to GitHub when leaving OpenStack. Our first days have been great and I cannot say we miss Gerrit much for now.&lt;/p&gt;
&lt;p&gt;The only tool that I loved and miss is &lt;a href=&quot;https://docs.openstack.org/infra/git-review/&quot;&gt;git-review&lt;/a&gt;. It allows pushing a branch of update easily to Gerrit.&lt;/p&gt;
&lt;p&gt;Unfortunately, in the GitHub world, things are different. To send a pull-request you have to execute a few steps which are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Clone the target repository&lt;/li&gt;
&lt;li&gt;Push your local branch to your repository&lt;/li&gt;
&lt;li&gt;Create a pull-request from your pushed local branch to the target branch&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you want to update later your pull-request, you either have to push new commits to your branch or, more often, edit your patches and force push your branch to your forked repository so you can ask for a new review of your pull-request.&lt;/p&gt;
&lt;p&gt;I&apos;m way too lazy to do all of that by hand, so I had a tool for a few years that I used based on &lt;a href=&quot;https://hub.github.com/&quot;&gt;hub&lt;/a&gt;, a command-line tool that interacts with &lt;a href=&quot;https://developer.github.com/&quot;&gt;GitHub API&lt;/a&gt;. Unfortunately, it was pretty simple and did not have all the feature I wanted.&lt;/p&gt;
&lt;p&gt;Which pushed me to write my own tool, humbly entitled &lt;a href=&quot;https://github.com/jd/git-pull-request&quot;&gt;git-pull-request&lt;/a&gt;. It allows to send a pull-request to any GitHub project just after you just cloned it. So there&apos;s no need to manually fork the repository, send branches, etc.&lt;/p&gt;
&lt;p&gt;Once you created a branch and committed to it, just run &lt;code&gt;git pull-request&lt;/code&gt; and everything we&apos;ll be done for you automatically.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;## First pull-request creation
$ git clone https://github.com/gnocchixyz/gnocchi.git
$ cd gnocchi
$ git checkout -b somefeature
&amp;lt;edit files&amp;gt;
$ git commit -a -m &apos;I did some changes&apos;
$ git pull-request
Forked repository: https://github.com/jd/gnocchi
Force-pushing branch `somefeature&apos; to remote `github&apos;
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 562 bytes | 0 bytes/s, done.
Total 5 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
To https://github.com/jd/gnocchi.git
 + 73a733f7...1be2bf29 somefeature -&amp;gt; somefeature (forced update)
Pull-request created: https://github.com/gnocchixyz/gnocchi/pull/33
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you need to update your pull-request with new patches, just edit your branch and call &lt;code&gt;git pull-request&lt;/code&gt; again. It&apos;ll re-push your branch and will not create a pull-request if one already exists.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;edit some more files&amp;gt;
$ git commit --amend -a
$ git pull-request
Forked repository: https://github.com/jd/gnocchi
Force-pushing branch `somefeature to remote `github&apos;
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 562 bytes | 0 bytes/s, done.
Total 5 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
To https://github.com/jd/gnocchi.git
 + 73a733f7...1be2bf29 somefeature -&amp;gt; somefeature (forced update)
Pull-request already exists at: https://github.com/gnocchixyz/gnocchi/pull/33
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This tool was definitely the missing piece to smooth my GitHub workflow, so I&apos;m glad I took some time to write it. I hope you&apos;ll enjoy it and will send me awesome pull-requests, so go &lt;a href=&quot;https://github.com/jd/git-pull-request&quot;&gt;check it out&lt;/a&gt;. This program is written in Python and uses the GitHub API.&lt;/p&gt;
&lt;p&gt;And feel free to request new fancy features!&lt;/p&gt;
</content:encoded><category>github</category></item><item><title>Tracking OpenStack contributions in GitHub</title><link>https://julien.danjou.info/blog/tracking-openstack-contributions-in-github/</link><guid isPermaLink="true">https://julien.danjou.info/blog/tracking-openstack-contributions-in-github/</guid><description>I&apos;ve switched my Git repositories to GitHub recently, and started to watch my contributions statistics, which were very low considering I spend my days hacking on open source software, especially.</description><pubDate>Tue, 19 Aug 2014 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I&apos;ve switched my Git repositories to &lt;a href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt; recently, and started to watch my contributions statistics, which were very low considering I spend my days hacking on open source software, especially &lt;a href=&quot;https://openstack.org&quot;&gt;OpenStack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/03/octocat-on-openstack-2.png&quot; alt=&quot;octocat-on-openstack-2&quot; /&gt;&lt;/p&gt;
&lt;p&gt;OpenStack hosts its Git repositories on its own infrastructure at &lt;a href=&quot;http://git.openstack.org&quot;&gt;git.openstack.org&lt;/a&gt;, but also mirrors them on GitHub. Logically, I was expecting GitHub to track my commits there too, as I&apos;m using the same email address everywhere.&lt;/p&gt;
&lt;p&gt;It turns out that it was not the case, and the &lt;a href=&quot;https://help.github.com/articles/why-are-my-contributions-not-showing-up-on-my-profile&quot;&gt;help page about that&lt;/a&gt; on GitHub describes the rule in place to compute statistics. Indeed, according to GitHub, I had no relations to the OpenStack repositories, as I never forked them nor opened a pull request on them (OpenStack uses &lt;a href=&quot;http://review.openstack.org&quot;&gt;Gerrit&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Starring a repository is enough to build a relationship between a user and a repository, so this is was the only thing needed to inform GitHub that I have contributed to those repositories. Considering OpenStack has hundreds of repositories, I decided to star them all by using a small Python script using &lt;a href=&quot;https://pypi.python.org/pypi/pygithub&quot;&gt;pygithub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;And voilà, &lt;a href=&quot;https://github.com/jd&quot;&gt;my statistics&lt;/a&gt; are now including all my contributions to OpenStack!&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/03/github-openstack-stats.png&quot; alt=&quot;github-openstack-stats&quot; /&gt;&lt;/p&gt;
</content:encoded><category>openstack</category><category>github</category></item><item><title>Rant about Github pull-request workflow implementation</title><link>https://julien.danjou.info/blog/rant-about-github-pull-request-workflow-implementation/</link><guid isPermaLink="true">https://julien.danjou.info/blog/rant-about-github-pull-request-workflow-implementation/</guid><description>One of my recent innocent tweet about Gerrit vs Github triggered much more reponses and debate that I expected it to. I realize that it might be worth explaining a bit what I meant, in a text longer t</description><pubDate>Fri, 10 May 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;One of my recent innocent tweet about &lt;em&gt;Gerrit vs Github&lt;/em&gt; triggered much more reponses and debate that I expected it to. I realize that it might be worth explaining a bit what I meant, in a text longer than 140 characters.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I&apos;m having a hard time now contributing to projects not using Gerrit. Github isn&apos;t that good.&lt;/p&gt;
&lt;p&gt;— Julien Danjou (@juldanjou) &lt;a href=&quot;https://twitter.com/juldanjou/status/332076595521146881&quot;&gt;May 8, 2013&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;The problems with Github pull-requests&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/03/github-1.svg&quot; alt=&quot;github-1&quot; /&gt;&lt;/p&gt;
&lt;p&gt;I always looked at Github from a distant eye, mainly because I always disliked their pull-request handling, and saw no value in the social hype it brings. Why?&lt;/p&gt;
&lt;h3&gt;One click away isn&apos;t one click effort&lt;/h3&gt;
&lt;p&gt;The pull-request system looks like an incredible easy way to contribute to any project hosted on Github. You&apos;re a click away to send your contribution to any software. But the problem is that any worthy contribution isn&apos;t an effort of a single click.&lt;/p&gt;
&lt;p&gt;Doing any proper and useful contribution to a software is never done right the first time. There&apos;s a dance you will have to play. A slowly rhythmed back and forth between you and the software maintainer or team. You&apos;ll have to dance it until your contribution is correct and can be merged.&lt;/p&gt;
&lt;p&gt;But as a software maintainer, not everybody is going to follow you on this choregraphy, and you&apos;ll end up with pull-request you&apos;ll never get finished unless you wrap things up yourself. So the gain in pull-requests here, isn&apos;t really bigger than a good bug report in most cases.&lt;/p&gt;
&lt;p&gt;This is where the social argument of Github isn&apos;t anymore. As soon as you&apos;re talking about projects bigger than a color theme for your favorite text editor, this feature is overrated.&lt;/p&gt;
&lt;h3&gt;Contribution rework&lt;/h3&gt;
&lt;p&gt;If you&apos;re lucky enough, your contributor will play along and follow you on this pull-request review process. You&apos;ll make suggestions, he will listen and will modify his pull-request to follow your advice.&lt;/p&gt;
&lt;p&gt;At this point, there&apos;s two technics he can use to please you.&lt;/p&gt;
&lt;h4&gt;Technic #1: the Topping&lt;/h4&gt;
&lt;p&gt;Github&apos;s pull-requests invite you to send an entire branch, eclipsing the fact that it is composed of several commits. The problem is that a lot of one-click-away contributors do not masterize Git and/or do not make efforts to build a logical patchset, and nothing warns them that their branch history is wrong. So they tend to change stuff around, commit, make a mistake, commit, fix this mistake, commit, etc. This kind of branch is composed of the whole brain&apos;s construction process of your contributor, and is a real pain to review. To the point I quite often give up.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/03/github-pull-request-iterative.png&quot; alt=&quot;github-pull-request-iterative&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Without Github, the old method that all software used, and that many software still use (e.g. Linux), is to send a patch set over e-mail (or any other medium like Gerrit). This method has one positive effect, that it forces the contributor to acknowledge the list of commits he is going to publish. So, if the contributor he has fixup commits in his history, they are going to be seen as first class citizen. And nobody is going to want to see that, neither your contributor, nor the software maintainers. Therefore, such a system tend to push contributors to write atomic, logical and self-contained patchset that can be more easily reviewed.&lt;/p&gt;
&lt;h4&gt;Technic #2: the History Rewriter&lt;/h4&gt;
&lt;p&gt;This is actually the good way to build a working and logical patchset using Git. Rewriting history and amending problematic patches using the famous &lt;code&gt;git rebase --interactive&lt;/code&gt; trick.&lt;/p&gt;
&lt;p&gt;The problem is that if your contributor does this and then repush the branch composing your pull-request to Github, you will both lose the previous review done, each time. There&apos;s no history on the different versions of the branch that has been pushed.&lt;/p&gt;
&lt;p&gt;In the old alternative system like e-mail, no information is lost when reworked patches are resent, obviously. This is far better because it eases the following of the iterative discussions that the patch triggered.&lt;/p&gt;
&lt;p&gt;Of course, it would be possible for Github to enhance this and fix it, but currently it doesn&apos;t handle this use case correctly..&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/03/hylang-pull-request-157.png&quot; alt=&quot;Exercise for the doubtful readers: good luck finding all revisions of my patch in the pull-request #157 of Hy.&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;A quick look at OpenStack workflow&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://julien.danjou.info/content/images/03/openstack-5.png&quot; alt=&quot;openstack-5&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It&apos;s not a secret for anyone that I&apos;ve been contributing to OpenStack as a daily routine for the last 18 months. The more I contribute, the more I like the contribution workflow and process. It&apos;s already &lt;a href=&quot;https://wiki.openstack.org/wiki/Gerrit_Workflow&quot;&gt;well and longly described on the wiki&lt;/a&gt;, so I&apos;ll summarize here my view and what I like about it.&lt;/p&gt;
&lt;h3&gt;Gerrit&lt;/h3&gt;
&lt;p&gt;To send a contribution to any OpenStack project, you need to pass via Gerrit. This is way simpler than doing a pull-request on Github actually, all you have to do is do your commit(s), and type &lt;a href=&quot;https://pypi.python.org/pypi/git-review&quot;&gt;&lt;code&gt;git review&lt;/code&gt;&lt;/a&gt;. That&apos;s it. Your patch will be pushed to Gerrit and available for review.&lt;/p&gt;
&lt;p&gt;Gerrit allows other developers to review your patch, add comments anywhere on it, and score your patch up or down. You can build any rule you want for the score needed for a patch to be merged; OpenStack requires one positive scoring from two core developers before the patch is merged.&lt;/p&gt;
&lt;p&gt;Until a patch is validated, it can be reworked and amended locally using Git, and then resent using &lt;code&gt;git review&lt;/code&gt; again. That simple. The historic and the different version of the patches are available, with the whole comments. Gerrit doesn&apos;t lose any historic information on your workflow.&lt;/p&gt;
&lt;p&gt;Finally, you&apos;ll notice that this is actually the same kind of workflow projects use when they work by patch sent over e-mail. Gerrit just build a single place to regroup and keep track of patchsets, which is really handy. It&apos;s also much easier for people to actually send patch using a command line tool than their MUA or &lt;em&gt;git send-email&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Gate testing&lt;/h3&gt;
&lt;p&gt;Testing is mandatory for any patch sent to OpenStack. Unit tests and functionnals test are run for &lt;em&gt;each version of each patch of the patchset&lt;/em&gt; sent. And until your patch passes all tests, it will be &lt;em&gt;impossible&lt;/em&gt; to merge it.&lt;/p&gt;
&lt;p&gt;Yes, this implies that all patches in a patchset must be working commits and can be merged on their own, without the entire patchset going in! With such a restricution, it&apos;s impossible to have &quot;fixup commits&quot; merged in your project and pollute the history and the testability of the project.&lt;/p&gt;
&lt;p&gt;Once your patch is validated by core developers, the system checks that there is not any merge conflicts. If there&apos;s not, tests are re-run, since the branch you are pushing to might have changed, and if everything&apos;s fine, the patch is merged.&lt;/p&gt;
&lt;p&gt;This is an uncredible force for the quality of the project. This implies that no broken patchset can ever sneak in, and that the project pass always all tests.&lt;/p&gt;
&lt;h2&gt;Conclusion: accessibility vs code review&lt;/h2&gt;
&lt;p&gt;In the end, I think that one of the key of any development process, which is code review, is not well covered by Github pull-request system. It is, along with history integrity, damaged by the goal of making contributions easier.&lt;/p&gt;
&lt;p&gt;Choosing between these features is probably a trade-off that each project should do carefully, considering what are its core goals and the quality of code it want to reach.&lt;/p&gt;
&lt;p&gt;I tend to find that OpenStack found one of the best trade-off available using Gerrit and plugging testing automation via Jenkins on it, and I would probably recommend it for any project taking seriously code reviews and testing.&lt;/p&gt;
</content:encoded><category>github</category><category>openstack</category></item><item><title>My latest contributions to the Emacs&apos; world</title><link>https://julien.danjou.info/blog/my-latest-contributions-to-the-emacs-world/</link><guid isPermaLink="true">https://julien.danjou.info/blog/my-latest-contributions-to-the-emacs-world/</guid><description>I spend too much time writing Emacs Lisp code these days. Unfortunately, the more I do the more I find new useful tools to improve my work-flow and save time for doing more Lisp. D&apos;oh.  I did not work</description><pubDate>Tue, 01 Mar 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I spend too much time writing Emacs Lisp code these days. Unfortunately, the more I do the more I find new useful tools to improve my work-flow and save time for doing more Lisp. D&apos;oh.&lt;/p&gt;
&lt;p&gt;I did not work on any big thing these last weeks, so I&apos;m thinking it&apos;s a good time to talk about the various code and patches I sent to multiple Emacs packages.&lt;/p&gt;
&lt;h2&gt;el-get&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/dimitri/el-get&quot;&gt;el-get&lt;/a&gt;, a fabulous tool that installs and handles all the external Emacs packages I use. A friendly war started on the &lt;a href=&quot;http://blog.gmane.org/gmane.emacs.el-get.devel&quot;&gt;development list&lt;/a&gt; about autoloads handling. The discussion was overall pointless, since we had a very hard time to communicate our ideas, and we did not understand each others several times.&lt;/p&gt;
&lt;p&gt;In the end, &lt;em&gt;el-get&lt;/em&gt; now supports autoload correctly and do not load automatically all your packages, improving the startup time, and using the Emacs way to do things. Which is always better, obviously.&lt;/p&gt;
&lt;h2&gt;git-commit-mode&lt;/h2&gt;
&lt;p&gt;I&apos;ve started to use &lt;a href=&quot;https://github.com/rafl/git-commit-mode&quot;&gt;git-commit-mode&lt;/a&gt; some times ago. I usually use &lt;em&gt;git-commit&lt;/em&gt; with the &lt;em&gt;-v&lt;/em&gt; option to see what I&apos;m committing. I though it would be useful to color the diff with &lt;em&gt;diff-mode&lt;/em&gt;, so I &lt;a href=&quot;https://github.com/rafl/git-commit-mode/commit/3e2d1047fff31358c39486cd890d1eb87a464404&quot;&gt;wrote a patch&lt;/a&gt; just to do that, which&lt;br /&gt;
was merged today by Florian.&lt;/p&gt;
&lt;h2&gt;magit&lt;/h2&gt;
&lt;p&gt;Some weeks ago, I decided to give a try to &lt;a href=&quot;http://philjackson.github.com/magit/&quot;&gt;magit&lt;/a&gt;, and loved it. I am not always using it, but for basic operations it is very useful. But I really soon found some things I did not like and therefore send patches to enhance it.&lt;/p&gt;
&lt;p&gt;First, I&apos;ve added &lt;a href=&quot;https://github.com/philjackson/magit/commit/0314e7fd1df2b37b3cd1699afdf2dc3b98aee2d1&quot;&gt;a patch to honor status.showUntrackedFiles&lt;/a&gt; which I use in my home directory. In the mean time, I&apos;ve also added &lt;a href=&quot;https://github.com/philjackson/magit/commit/43cd05081b7e60d3f2dcce696f3a07c135f4e306&quot;&gt;a patch to allow adding an arbitrary file&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Yesterday, I sent another &lt;a href=&quot;https://github.com/philjackson/magit/pull/128&quot;&gt;pull request&lt;/a&gt;, not closed for now, which adds the &lt;a href=&quot;https://github.com/jd/magit/commit/73afce9f0220146a55c6c63735ce48561a277632&quot;&gt;possibility to visit files in another window&lt;/a&gt; from a diff file, and &lt;a href=&quot;https://github.com/jd/magit/commit/82d43edb123f493d639ef0835734e58fca1b8c0a&quot;&gt;the support for add-change-log-entry&lt;/a&gt; directly from the displayed diff. Useful for these old projects still using &lt;em&gt;ChangeLog&lt;/em&gt; files but accessible through git (hi Emacs &amp;amp; Gnus!).&lt;/p&gt;
&lt;h2&gt;Gnus&lt;/h2&gt;
&lt;p&gt;Nothing remarkable, but I write a couple of &lt;a href=&quot;http://git.gnus.org/cgit/gnus.git/commit/?id=3ccee76adca8a830cf781e697119b980cd9fcbe1&quot;&gt;fixes&lt;/a&gt; and &lt;a href=&quot;http://git.gnus.org/cgit/gnus.git/commit/?id=01c211faea248b5d9e35f3662670bb8d12b9b137&quot;&gt;enhancements&lt;/a&gt; to the Sieve manage mode, to the &lt;a href=&quot;http://git.gnus.org/cgit/gnus.git/commit/?id=d715adda2809176649227153d9e97564e755efb6&quot;&gt;Gravatar code&lt;/a&gt; and cleaned-up some very very old code. Also added the possibility to&lt;br /&gt;
&lt;a href=&quot;http://git.gnus.org/cgit/gnus.git/commit/?id=2bd6537597f51762a4b04f81c70d8f2be5dcb690&quot;&gt;set list-identifier as a group parameter&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Org-mode&lt;/h2&gt;
&lt;p&gt;I spent most of my time working on my &lt;a href=&quot;http://git.naquadah.org/?p=~jd/org-mode.git;a=shortlog;h=refs/heads/jd/agenda-format&quot;&gt;jd/agenda-format&lt;/a&gt; branch, which is soon to be merged. I&apos;ve also just got developer access to the Org-mode patch work and repository, so I&apos;ll be able to break things even more! ;-)&lt;/p&gt;
&lt;h2&gt;ERC&lt;/h2&gt;
&lt;p&gt;I &lt;a href=&quot;http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=391de97a758c44e5d38e0c8f0bd50fe5eae09d5f&quot;&gt;fixed&lt;/a&gt; &lt;strong&gt;the&lt;/strong&gt; bug that annoyed me for a long time. Now &lt;em&gt;erc-track&lt;/em&gt; does not reset the last channel status on window visibility changes not made by the user.&lt;/p&gt;
</content:encoded><category>emacs</category><category>github</category></item></channel></rss>