🏠 back to Observable

best practices for version control/branching/feature development?

Was wondering if anyone has developed good practices for collaboratively working on a project that is implemented in an Observable Notebook, in which the project is large enough to include discreet feature development tasks, bug fixes, and other work items that can be tracked and assigned in issue tracking software (Jira, Github issues, etc.)

I’m trying to figure out a system to have a Release notebook (available to client), a Development notebook (most up to date internally), and various branches off of Development for feature implementation that can get pulled into Development upon code review.

I’m running into issues when merging though, in that sometimes all of the changes made in a feature branch don’t seem to make it into Development (I don’t see red and green diffs sometimes when there are definitely differences – okay, granted, this has been when comparing two notebooks where one is not a direct fork of the other).

Just wondering if people had developed their own best practices around this that they were willing to share. I get that it would be better to like, write an actual web application when things get this complex – but writing a web app is slow – and Observable is meeting so many other needs.


Hi Stephanie,

Figuring out good practices for long-running asynchronous collaboration on a complex notebook is such a great topic!

But first — I just wanted to mention that if you ever run into an issue with merging — where a diff isn’t appearing correctly, or a change that you selected hasn’t been merged — please report it to support@observablehq.com. (Including links to the problematic notebooks in question, or a reproducible test case, if possible.) If there are still bugs lingering in the fork/compare/merge system, we would love to get them fixed, and quick!

Hi Jeremy –

Thanks for offering help on diff-ing. Is there any documentation of the Merge/Reverse Merge interface?
I think that perhaps part of my issue is that I don’t understand what the expected outcomes of Merge are. For example, I know that you can make changes to the Fork by clicking on Fork for any cell and then editing it (while in Merge), but I am never sure if those changes will actually stick, as if I then toggle back to Diff, and then to Fork again the changes are gone.

But I will be in touch if I see problems – thanks!

The current documentation for forking, sharing and merging is here: https://observablehq.com/@observablehq/fork-share-merge (although it predates even the introduction of suggestions).

And suggestions to clarify the documentation, are always, of course, welcome, and frequently merged.

Toggling the Parent/Diff/Fork status for a cell does clear any local edits you might have made to the content of that cell since loading the page. We wanted it to be the case that when you click on “Fork”, you see the contents of the fork, and not something else.

When you click “Merge”, the resulting notebook should contain exactly what you see on the page.

In the future, a nice addition might be the ability to keep your local edits as you toggle back and forth — but we’d probably have to introduce a fourth tab, so that you would have: Parent / Diff / Fork / Edited.


Just to make sure I understand: if “the resulting notebook should contain exactly what you see on the page,” which cell view is that referring to – Diff or Fork? (i.e. we will see exactly what is in green and what is in red will be removed?)

Great question. The default state of a compare view contains the contents of the target notebook (i.e., the fork, not the parent).

So, when you have the “Diff” tab toggled, and you see the red and green, if you merge, you’ll get the fork’s contents — the green.

So, I think the situation that is confusing to me is if I have Notebook A, and make Notebooks B + C as forks of A. Someone does some work in B and it gets merged into A. Then someone also does some work in C, and I want to merge it into A.

In this case, when I go to either Merge C into A, or I do Compare reverse, I get something along the lines of the following:

I am unclear what exactly happens with “Apply changes”…and then I am still unclear how to get the changes that came from Notebook B into A to remain if I merge in Notebook C – do I have have to hand copy/paste them over into the “Fork” cell?

For example, here the max-width specification came into the Parent notebook (A) since the Fork notebook C was made. But I don’t want it to be removed when I merge C into A. Essentially I guess I’m trying to figure out how to deal with merge conflicts in Observable?

(maybe then we are back to the thing about changes sticking if you toggle back to diff from fork?)