# Developing Discourse Plugins - Part 4 - Setup git

**URL:** https://meta.discourse.org/t/developing-discourse-plugins-part-4-setup-git/31272
**Category:** Developer Guides
**Tags:** plugin-guides, tutorial
**Created:** [July 21, 2015, 8:54pm UTC](https://meta.discourse.org/t/developing-discourse-plugins-part-4-setup-git/31272 "2015-07-21T20:54:59Z")
**Posts on this page:** 11
**Page:** 1

<div class="post-metadata">

### Author: ![Discourse](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/discourse/32/148734_2.png) [@Discourse](https://meta.discourse.org/u/Discourse)
#### Post date: [July 21, 2015, 8:54pm UTC](https://meta.discourse.org/t/developing-discourse-plugins-part-4-setup-git/31272/1 "2015-07-21T20:54:59Z")

</div>

Previous tutorial: [Developing Discourse Plugins - Part 3 - Add custom site settings](https://meta.discourse.org/t/developing-discourse-plugins-part-3-add-custom-site-settings/31115)

* * *

Now that your plugin is getting more sophisticated, it’s time to get more sophisticated about how you develop it.

We suggest that you use [git](https://git-scm.com/) as version control for your plugin. We also recommend that you use [github](https://github.com) to share your plugin code with others.

### Creating your Git Repo

Once you’ve created your Github account, visit [this url](https://github.com/new) to create a new repository. You can call it anything you want, but generally something that starts with `discourse-` is good. Make sure the repository is **public**. Here’s how my screen looked:

 ![GitHub new repository form](https://global.discourse-cdn.com/meta/original/4X/b/d/4/bd4e72b31887f4016cfe86b0d0617f1799f1d007.png)

### Creating your local working folder

At this point I create a local directory on my computer to hold the plugin. I usually put mine in `~/code` but you can put it anywhere you like on your computer:

```sh
mkdir -p ~/code/discourse-plugin-test
cd ~/code/discourse-plugin-test

```

Now let’s follow the instructions from github to initialize the repo with a README:

```sh
echo "# discourse-plugin-test" >> README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin git@github.com:eviltrout/discourse-plugin-test.git
git push -u origin main

```

Finally, create a `plugin.rb` file for your plugin as explained in [part 1](https://meta.discourse.org/t/beginners-guide-to-creating-discourse-plugins/30515). For this example I just created a dummy one:

**plugin.rb**

```rb
# name: discourse-plugin-test
# about: Shows how to set up Git
# version: 0.0.1
# authors: Robin Ward

```

### Creating a symlink

Because you followed our [developer guide](https://meta.discourse.org/tags/dev-install) you should have a copy of discourse checked out on your computer somewhere. I checked mine out to `~/code/discourse` but again you could have put it anywhere and this should still work if you adjust the following code accordingly:

```sh
cd ~/code/discourse/plugins
ln -s ~/code/discourse-plugin-test .

```

The above code created a [symbolic link](https://en.wikipedia.org/wiki/Symbolic_link) between your discourse code and your plugin folder. Restart your development server and you should find your plugin is working!

The beauty of this setup is you can just check your plugin into github and not worry about the discourse codebase it lives inside. Your changes will be isolated to the plugin itself. If you need to edit discourse’s code you still can, but git will track the changes separately!

I recommend using one editor window for your plugin codebase and one for Discourse itself. It is easier when you think of them as two different things.

* * *

### More in the series

Part 1: [Plugin Basics](https://meta.discourse.org/t/beginners-guide-to-creating-discourse-plugins-part-1/30515)  
Part 2: [Plugin Outlets](https://meta.discourse.org/t/beginners-guide-to-creating-discourse-plugins-part-2-plugin-outlets/31001)  
Part 3: [Site Settings](https://meta.discourse.org/t/beginners-guide-to-creating-discourse-plugins-part-3-custom-settings/31115)  
**Part 4: This topic**  
Part 5: [Admin interfaces](https://meta.discourse.org/t/beginners-guide-to-creating-discourse-plugins-part-5-admin-interfaces/31761)  
Part 6: [Acceptance tests](https://meta.discourse.org/t/beginner-s-guide-to-creating-discourse-plugins-part-6-acceptance-tests/32619)  
Part 7: [Publish your plugin](https://meta.discourse.org/t/beginner-s-guide-to-creating-discourse-plugins-part-7-publish-your-plugin/101636)

* * *

This document is version controlled - suggest changes [on github](https://github.com/discourse/discourse/blob/main/docs/developer-guides/docs/04-plugins/04-git-setup.md).

---

<div class="post-metadata">

### Author: ![AhmadF.Cheema](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ahmadf.cheema/32/87109_2.png) [@AhmadF.Cheema](https://meta.discourse.org/u/AhmadF.Cheema)
#### Post date: [September 14, 2016, 5:08pm UTC](https://meta.discourse.org/t/developing-discourse-plugins-part-4-setup-git/31272/2 "2016-09-14T17:08:00Z")

</div>

- After _many_ frustrating attempts, found out that apparently `ln -s` does not work in a Windows environment, or atleast not how it should.
- `ln -s` essentially just copy-pasted the plugin folder into the `discourse/plugins` folder
- Apparently, in Windows the way to create symbolic links is to use the [mklink](https://technet.microsoft.com/en-us/library/cc753194(v=ws.11).aspx) command in command prompt (run as administrator, and this command does not natively run in Windows PowerShell either).
- Using the `mklink` command (with both arguments `/d` and `/h`), although the created symbolic link could be seen present in the directory, the plugin was not working with discourse (and also not showing in `/admin/plugins`).
- I tried this multiple times with restarting the rails server, deleting the `tmp` folder, but to no avail.

@eviltrout, any idea what could I be doing wrong?

---

<div class="post-metadata">

### Author: ![eviltrout](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/eviltrout/32/5275_2.png) [@eviltrout](https://meta.discourse.org/u/eviltrout)
#### Post date: [September 15, 2016, 2:53pm UTC](https://meta.discourse.org/t/developing-discourse-plugins-part-4-setup-git/31272/3 "2016-09-15T14:53:02Z")

</div>

I assume you are using Vagrant on windows? If you can’t get the symbolic links sent over, I think the only way you can do it is to copy the plugin into discourse/plugins manually and work from there. It should work as long as you are not making changes to the core discourse app at the same time, which confuses git.

When your plugin is ready, you’ll want to copy it to another directory to package it up for git.

---

<div class="post-metadata">

### Author: ![AhmadF.Cheema](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/ahmadf.cheema/32/87109_2.png) [@AhmadF.Cheema](https://meta.discourse.org/u/AhmadF.Cheema)
#### Post date: [September 15, 2016, 3:56pm UTC](https://meta.discourse.org/t/developing-discourse-plugins-part-4-setup-git/31272/4 "2016-09-15T15:56:30Z")

</div>

Yeah, OK this should be fine too.  
Although the OCD side of me, much preferred the comparatively “cleaner” symbolic links method.

Anyway, Thanks.

---

<div class="post-metadata">

### Author: ![pacharanero](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pacharanero/32/500583_2.png) [@pacharanero](https://meta.discourse.org/u/pacharanero)
#### Post date: [October 22, 2017, 2:01pm UTC](https://meta.discourse.org/t/developing-discourse-plugins-part-4-setup-git/31272/5 "2017-10-22T14:01:01Z")

</div>

@AhmadF.Cheema I had similar problems with the symlinking using Vagrant 1.9.8 on Linux, and a completely standard Discourse Vagrant development environment as per the docs.

The problem is simple when you look into it. From the scope of _inside_ the Vagrant VM, the destination of the symlink is not a valid path. Try executing the command `ls -al` in the plugins directory inside your VM (in a [standard install](https://meta.discourse.org/t/142537?silent=true) this is at `/vagrant/plugins`)

```bash
vagrant@discourse:/vagrant/plugins$ ls -al
total 36
drwxr-xr-x 1 vagrant vagrant 4096 Oct 22 09:08 ./
drwxr-xr-x 1 vagrant vagrant 4096 Oct 22 09:10 ../
drwxr-xr-x 1 vagrant vagrant 4096 Sep 7 19:51 discourse-details/
drwxrwxr-x 1 vagrant vagrant 4096 Oct 21 13:56 discourse-narrative-bot/
drwxr-xr-x 1 vagrant vagrant 4096 Oct 21 13:56 discourse-nginx-performance-report/
drwxr-xr-x 1 vagrant vagrant 4096 Sep 7 19:51 discourse-plugin-outlet-locations/
drwxrwxr-x 1 vagrant vagrant 4096 Oct 21 13:56 discourse-presence/
lrwxrwxrwx 1 vagrant vagrant 55 Oct 22 09:08 my-basic-plugin -> /home/marcus/code/discourse/my-basic-plugin
drwxr-xr-x 1 vagrant vagrant 4096 Oct 21 13:56 lazyYT/
drwxr-xr-x 1 vagrant vagrant 4096 Oct 21 13:56 poll/

```

As you can see, the path `/home/marcus/code/discourse/my-basic-plugin` cannot **possibly** be accessible from the VM because it doesn’t exist inside the VM!

The solution is to delete the externally created symlink and set up a separate shared folder in Vagrant, by adding a line to your Vagrantfile:

```plaintext
config.vm.synced_folder "/home/marcus/code/my-basic-plugin", "/my-basic-plugin"

```

Then restart the Vagrant VM: `vagrant halt && vagrant up` so that this change is picked up

Now, when you enter your VM via SSH using `vagrant ssh` you can create a symlink **inside** the VM:

```bash
cd /vagrant/plugins
ln -s /my-basic-plugin .

```

Now you can develop in a neatly isolated local folder, and have the neat Git workflow that @eviltrout describes, and the symlinking happens inside the VM. Note that outside the VM, the symlink will be broken - but this shouldn’t matter for our purposes.

---

<div class="post-metadata">

### Author: ![sam](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/sam/32/102149_2.png) [@sam](https://meta.discourse.org/u/sam)
#### Post date: [October 22, 2017, 9:14pm UTC](https://meta.discourse.org/t/developing-discourse-plugins-part-4-setup-git/31272/6 "2017-10-22T21:14:40Z")

</div>

If you are developing on Linux using our docker based dev is way simpler

---

<div class="post-metadata">

### Author: ![schungx](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/schungx/32/70989_2.png) [@schungx](https://meta.discourse.org/u/schungx)
#### Post date: [October 23, 2017, 1:31am UTC](https://meta.discourse.org/t/developing-discourse-plugins-part-4-setup-git/31272/7 "2017-10-23T01:31:52Z")

</div>

Windows symlinks are different from Unix symlinks, thus your confusion. Windows synlinks are very fussy, requiring particular versions of OS to support and sometimes applications must be written to be aware of this. In other words, the stars must line up perfectly for windows symlinks to work.

A hard link (`/H`) I dont think work with directories. Your `/D` makes a symlink on a directory, trumping your `/H` (which is used to create a hard link to a _file_, not a directory).

Confusing? Welcome to Windows.

There are four types of links in Windows:

- `MKLINK ` (no flags) – symbolic link to file
- `MKLINK /H` – hard link to file
- `MKLINK /D` – symbolic link to directory
- `MKLINK /J` – junction (i.e. hard link) to directory

What you need is is a `junction` which is Windows-speak for hard link to a directory.

Do `MKLINK /J` to your plugins directory and the system will treat it as a subdirectory. In fact it won’t know otherwise. Beware, it is not common to have a Windows directory (`folder` in Windows-speak) to point to the same place as another directory, so you’ll get confused very easy and forget that both are the same things.

That’s why you’ll need to run the command in Administrator mode, otherwise Windows won’t let you create the directory junction.

---

<div class="post-metadata">

### Author: ![pacharanero](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/pacharanero/32/500583_2.png) [@pacharanero](https://meta.discourse.org/u/pacharanero)
#### Post date: [October 23, 2017, 7:40pm UTC](https://meta.discourse.org/t/developing-discourse-plugins-part-4-setup-git/31272/8 "2017-10-23T19:40:59Z")

</div>

Thanks for the info regarding Windows symlinks @schungx - it should be of help to the OP.

The workaround I described should work fine on any platform, since the symlinks happen inside the (Ubuntu) vagrant box

M

---

<div class="post-metadata">

### Author: ![schungx](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/schungx/32/70989_2.png) [@schungx](https://meta.discourse.org/u/schungx)
#### Post date: [October 24, 2017, 12:50am UTC](https://meta.discourse.org/t/developing-discourse-plugins-part-4-setup-git/31272/9 "2017-10-24T00:50:12Z")

</div>

Yup, you’re right. If you can avoid it, avoid messing with Windows. Windows is very picky and may choose to die or go wrong at the most unfortunate moment…

---

<div class="post-metadata">

### Author: ![1c7](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/1c7/32/94822_2.png) [@1c7](https://meta.discourse.org/u/1c7)
#### Post date: [April 29, 2018, 6:15am UTC](https://meta.discourse.org/t/developing-discourse-plugins-part-4-setup-git/31272/10 "2018-04-29T06:15:34Z")

</div>

Work for me! 2018-4-29

### 1. I put discourse & my plugin in Desktop

instead of put `1c7-plugin` under `discourse/plugin`

 ![image](https://global.discourse-cdn.com/meta/original/3X/4/4/44de77ba923c87929b87b57ece16efb782d58d69.jpg)

### 2. and put a “alias” into `discourse/plugins` folder

alias is a macOS concept,  
it’s the same things as `ln -s` command

 ![image](https://global.discourse-cdn.com/meta/original/3X/b/5/b519e4633eb81ed97d6851b2621525ab8f0cc5b6.png)

### 3. Discourse correctly load the plugin

(After reboot server with `rails s`)

 ![image](https://global.discourse-cdn.com/meta/original/3X/9/2/927b18ff094e3db50ba2ea2b1d2fc1ae2df47542.png)

## 4. Now they are separated, use git to manage code is much easier

Thanks!

---

<div class="post-metadata">

### Author: ![maaatt](https://avatars.discourse-cdn.com/v4/letter/m/ecb155/32.png) [@maaatt](https://meta.discourse.org/u/maaatt)
#### Post date: [January 30, 2024, 11:12am UTC](https://meta.discourse.org/t/developing-discourse-plugins-part-4-setup-git/31272/11 "2024-01-30T11:12:28Z")

</div>

not able to let the symlink work in macos docker setup. The plugins works only if copied directly into the plugins folder
