Giter Club home page Giter Club logo

obsidian-git's Introduction

Git

Plugin that allows you to back up your Obsidian.md vault to a remote Git repository (e.g. private repo on GitHub).

Requirements, installation steps (including setup for mobile), tips and tricks, common issues and more can be found in the documentation.

For mobile users see Mobile section below.

Highlighted Features

  • Automatic vault backup every X minutes
  • Pull changes from remote repository on Obsidian startup
  • Assign hotkeys for pulling/pushing changes to a remote repository
  • Manage different repositories via Git submodules (after enabling this feature in settings)
  • The Source Control View allows you to stage and commit individual files. It can be opened with the Open Source Control View command.
  • The History View shows the commits and their changed files. So basically an integrated git log. It can be opened with the Open History View command.
  • For viewing the history of a file, I strongly recommend you the Version History Diff plugin

Source Control View

Source Control View

History View

History View

Available Commands

  • Changes
    • List changed files: Lists all changes in a modal
    • Open diff view: Open diff view for the current file
    • Stage current file
    • Unstage current file
  • Commit
    • Commit all changes: Only commits all changes without pushing
    • Commit all changes with specific message: Same as above, but with a custom message
    • Commit staged: Commits only files that have been staged
    • Commit staged with specific message: Same as above, but with a custom message
  • Backup
    • Create Backup: Commits all changes. If "Push on backup" setting is enabled, will also push the commit.
    • Create Backup with specific message: Same as above, but with a custom message
    • Create backup and close: Same as Create Backup, but if running on desktop, will close the Obsidian window. Will not exit Obsidian app on mobile.
  • Remote
    • Push
    • Pull
    • Edit remotes
    • Remove remote
    • Clone an existing remote repo: Opens dialog that will prompt for URL and authentication to clone a remote repo
    • Open file on GitHub: Open the file view of the current file on GitHub in a browser window. Note: only works on desktop
    • Open file history on GitHub: Open the file history of the current file on GitHub in a browser window. Note: only works on desktop
  • Local
    • Initialize a new repo
    • Create new branch
    • Delete branch
    • CAUTION: Delete repository
  • Source Control View
    • Open source control view: Opens side pane displaying Source control view
    • Edit .gitignore
    • Add file to .gitignore: Add current file to .gitignore

Desktop

Authentication

Authentication may require additional setup. See more in the Authentication documentation

Obsidian on Linux

  • ⚠ Snap is not supported.
  • ⚠ Flatpak is not recommended, because it doesn't have access to all system files.

Please use AppImage instead (Linux installation guide)

Mobile

The git implementation on mobile is very unstable!

Restrictions

I am using isomorphic-git, which is a re-implementation of Git in JavaScript, because you cannot use native Git on Android or iOS.

  • SSH authentication is not supported (isomorphic-git issue)
  • Repo size is limited, because of memory restrictions
  • Rebase merge strategy is not supported
  • Submodules are not supported

Performance on mobile

Caution

Depending on your device and available free RAM, Obsidian may

  • crash on clone/pull
  • create buffer overflow errors
  • run indefinitely.

It's caused by the underlying git implementation on mobile, which is not efficient. I don't know how to fix this. If that's the case for you, I have to admit this plugin won't work for you. So commenting on any issue or creating a new one won't help. I am sorry.

Setup: iPad Pro M1 with a repo of 3000 files reduced from 10000 markdown files

The initial clone took 0m25s. After that, the most time consuming part is to check the whole working directory for file changes. On this setup, checking all files for changes to stage takes 03m40s. Other commands like pull, push and commit are very fast (1-5 seconds).

The fastest way to work on mobile if you have a large repo/vault is to stage individual files and only commit staged files.

Contact

The Line Authoring feature was developed by GollyTicker, so any questions may be best answered by him.

If you have any kind of feedback or questions, feel free to reach out via GitHub issues or @Vinadon on Obsidian Discord server.

This plugin was initial developed by denolehov. Since March 2021, it is Vinzent03 who is developing on this plugin.

If you want to support me (Vinzent03) you can support me on Ko-fi

ko-fi

obsidian-git's People

Contributors

akirabaruah avatar amitkot avatar bd-g avatar cesarmontalverne avatar coddingtonbear avatar denolehov avatar ethyi avatar freeman-jiang avatar furkanakkurt1335 avatar gollyticker avatar injust avatar jagget avatar jakobhellermann avatar jamiemair avatar jkamenik avatar jtams avatar keeev avatar kovetskiy avatar mbseid avatar phibr0 avatar pscoriae avatar ronilaukkarinen avatar smathewmanuel avatar supetorus avatar tamiroh avatar vinzent03 avatar warrenalphonso avatar weph avatar yentlprojects avatar zanets avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

obsidian-git's Issues

Pull Failed: No such device or address

Hi there,

I'm getting this error in my console when launching Obsidian, and when toggling the plugin on and off.

Uncaught (in promise) Error: bash: /dev/tty: No such device or address
error: failed to execute prompt script (exit code 1)
fatal: could not read Username for 'https://github.com': No such file or directory

    at GitExecutorChain.onFatalException (eval at <anonymous> (app.js:1), <anonymous>:2536:85)
    at GitExecutorChain.eval (eval at <anonymous> (app.js:1), <anonymous>:2527:28)
    at Generator.throw (<anonymous>)
    at rejected (eval at <anonymous> (app.js:1), <anonymous>:2482:65)

I am unable to access the configuration options for the plugin with this issue occurring.
No actual pull occurs.
No other functionality works (automatic push)

Stuck on "pushing changes"

First of all: AWESOME plugin. It was the first one I installed and it's extremely useful as-is.

I installed it with no apparent errors. It pulls changes at startup and creates the commits, but it's stuck on "pushing changes".
Screenshot 2020-11-05 at 14 22 26

This shows up in the console:
Screenshot 2020-11-05 at 14 21 01

If I push them manually, in the command line, all goes well.

Any clue about what's causing this? Am I missing something?

Attempting to push when the remote is ahead of the local branch causes odd behaviour

Actual behaviour

If your remote branch is ahead of your local branch and you attempt to push, the status bar indicates git: pushing changes until the next operation.

An error is logged to the console, but this isn't surfaced to the user.

Expected behaviour

A notice which indicates the operation failed and the status bar reflects this too.

Pushing not working

I've installed this plugin, but I'm unable to push or pull commits. Whenever I push, the plugin creates a commit, but fails on pushing with this error (from the console). I have access rights to the repository, and I can push from the command line, so I'm not sure what the problem is. I'm on Ubuntu 20.04, and ssh-askpass is installed. I connect to my repository using SSH, not username/password.

The error and stack in question:

Uncaught (in promise) Error: Pushing to github.com:NicholasMamo/xyz.git
ssh_askpass: exec(/usr/libexec/ssh-askpass): No such file or directory
[email protected]: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

    at GitExecutorChain.onFatalException (eval at <anonymous> (app.js:1), <anonymous>:2536:85)
    at GitExecutorChain.eval (eval at <anonymous> (app.js:1), <anonymous>:2527:28)
    at Generator.throw (<anonymous>)
    at rejected (eval at <anonymous> (app.js:1), <anonymous>:2482:65)

Clarify the way to use plugin with Git for Windows

First of all, I'd like to thank you guys for creating the plugin, much appreciate it.

I'd like to suggest to clarify a bit the way to use the plugin in Obsidian.

Today after installing Obsidian on my home Windows PC I faced a problem that obsidian-git is not working and is not shown in "Settings" window in Obsidian (even if it was turned on at the "Third-party plugins tab", pic.1).

pic. 1
изображение

I used to have git bash installed and git not integrated with default Windows cmd and 3rd party apps. After reinstalling "Git bash for windows" with option "Git from the command line and also from 3rd-party software" (pic. 2) I got the plugin up and running in Obsidian.

pic. 2
изображение

pic. 3
изображение

All in all, I'd like to suppose a pair of things:

  1. If possible, send a notification that git command is not executable when a user tries to turn the plugin on. Is there a callback in Obsidian API which we could define to test if the git command is defined or not?
  2. If possible, put an accent in README.md that git command should be defined in PATH (if I understood correctly).

Thanks in advance, I will be glad to discuss the proposal!

Stuck at "git: checking repo status", missing styles.css?

Just installed the plugin today and ran git init in my Obsidian vault folder and was able to push files to my repo without any issues using command line. However, I noticed that the plugin seems to be stuck on "git: checking repo status..". I do not have a .gitignore file in my repo and running Windows 10.

Here's the developer console output:
image

Prerequisite Software?

Is anything else need to be installed or do you just need Obsidian installed & this plugin?

Feature Request: Push on save

Instead of backing up all changes by committing everything every N minutes. I would love Obsidian Git to commit and push after each file is edited. It results in segments of work being synced when I expect them to instead of in the middle or work or long after work (if I edit and then shut my computer). It also results in each commit representing edits to a single file which is easier to grok.

Changes to .obsidian would still need to be batched up every N minutes

Using a custom SSH key

Hi there, and thank you for this great plugin!

I'd like a way to use a specific SSH key with minimal change to the code. The plugin could have a new config to specify the GIT_SSH_COMMAND environment variable and pass it down to the simple-git package. I came across this option after reading https://superuser.com/a/912281.

The simple-git npm README uses this environment variable as an example, so I think it's likely to work: https://github.com/steveukx/git-js#environment-variables

While this sort of config is a bit low-level, it does allow future users to make unforeseen SSH customizations they might need through this environment variable.


The specific problem I'm trying to solve is one of convenience while balancing security: the plugin doesn't work after a reboot until my passphrase-protected SSH key is loaded into ssh-agent. This is solved by generating a passphrase-less SSH key. However, I want to restrict this less-secure SSH key to be valid for just that repo, rather than all my repos. This can be done by adding it as a deploy key to the repo's GitHub config.

I can take a pass at adding support for GIT_SSH_COMMAND and submitting a PR. What do you think?

Future of this plugin

May I ask @denolehov , what is your plan with this plugin? There were no commits since late December and "fixed" issues are not getting closed. I think this plugin is too important, as it can be not maintained anymore. So my question is, will you merge pull requests and release new versions in the future or is a new plugin needed?
Adding me or someone else as a collaborator would be perfectly fine too.

Commit -> pull -> push

I'm not sure what the current plugin does, but the only pull related setting is "Pull updated on startup". What would probably be better, would be to just do what people do manually, which is to always pull before pushing. So commit locally, pull, then push if OK.

Feature: allow a user to select what branch to use

Hi! Thanks for this wonderful plugin! I have a feature request, which would be the following:

  • Allow a user to input the branch name in the settings
  • Use the specified branch (or default to master) to sync.

I'm using the main branch instead of master. So that's the reasoning behind it.

Thanks!

Pull from remote which causes merge conflicts causes odd behaviour

Actual behaviour

If your pull from remote causes merge conflicts in your local state, the status bar indicates git: pulling changes from remote repo... until the next command.

An error is logged to the console, but this isn't surfaced to the user.

Expected behaviour

A notice which indicates the operation failed and the status bar reflects this too.

I don't expect the plugin to help me resolve the conflicts necessarily, but just a heads up that this happened 😄

automatic gpg signing doesn't seem to work

I automatically sign all of my commits: my ~/.gitconfig includes

[commit]
	gpgsign = true

When the plugin attempted to commit some changes, I got this error in the console:

git-error.js:32 Uncaught (in promise) Error: error: cannot run gpg: No such file or directory
error: gpg failed to sign the data
fatal: failed to write commit object

    at GitExecutorChain.onFatalException (eval at <anonymous> (app.js:1), <anonymous>:2536:85)
    at GitExecutorChain.eval (eval at <anonymous> (app.js:1), <anonymous>:2527:28)
    at Generator.throw (<anonymous>)
    at rejected (eval at <anonymous> (app.js:1), <anonymous>:2482:65)

Feature request: trigger vault backup manually

First up, loving the plugin so far! Exactly what I needed for my workflow.

Personally, I would to be able to manually trigger the vault backup within Obsidian. My vault is hooked up to my website so rather than constantly backing up (and triggering new builds each time) every x minutes, it would be nice to be able to write a post and then push the changes within Obsidian when I am ready to publish.

You could do this from the terminal/git client but for me that circumnavigates the biggest convenience of this plugin which is managing everything within Obsidian.

Failed to load resource - blocks plugin at 'git: checking repo status...'

image
image

Hi, I've wanted to use this for version control of my vault, just in case I need to roll back changes. I'm using git via command line at the moment, but I'd really love to automate it using this plugin. Unfortunately, it appears this css resource is not included in the .obsidian/plugins folder, and the link appears to be dead.

This is a request to add that css file to the repo so that we can link it locally.

Stuck at : git: Checking Repo status

as soon as I activate the plugin it gets stuck at: git: Cecking Repo Status
Thats the error in the Dev Console:

D-11-20-3

I'm using SSH instead of https, might that be a problem?
My remote origin isn't named the default "origin", i named it "remote".
The branch is called mainVault.
(So i can do: git push remote mainVault)

Plugin initialization procedure

Inside the onload function, I recommend doing all the synchronous actions first, such as registering your command and setting page. This way, a user who enables your plugin sees the setting tab right away, and also any errors during initialization won't prevent the setting page from showing up.

let branchInfo = await git.branch();

I would highly recommend avoid doing intensive/long running work in the onload function, but rather, defer this to later.
This is because if your await takes a long time, it will prevent the app from loading. The user will spend a significant amount of time seeing the loading bar, until your plugin finishes the loading process.
Start a new async function, but don't await on it (so it can run independently of your onload).

this.settings = (await this.loadData()) || new ObsidianGitSettings();

Don't use a class for your setting. loadData will return a generic object, so you should use an interface instead.

Authentication issue with ssh passphrase

Hi,

I am getting the error message:
Screen Shot 2021-01-23 at 9 43 00 AM

About my setup:

I have obsidian-git running on both my Mac and an Arch Linux install. It works great on Arch Linux, but I get the above error message on Mac whenever I start Obsidian. I use SSH to pull from Git, and I have two different SSH keys on my two machines. The key on my Arch Linux machine is not password protected, and my Mac's is. They are both added to ssh-agent and I have no problems pulling or pushing to git outside of this on either machine.

Happy to provide any more info. I checked the Issues and could not find any similar to mine. Thank you.

Rendering problem with mermaid

Hello, I'm currently playing with mermaid in Obsidian and I encountered a problem with user journey diagrams

Input (example from documentation) :

journey
  title My working day
  section Go to work
    Make tea: 5: Me
    Go upstairs: 3: Me
    Do work: 1: Me, Cat
  section Go home
    Go downstairs: 5: Me
    Sit down: 5: Me

Rendering (missing text):
Screenshot_20210218_132947

Resoving Conflicts in repo

It would be fantastic to implement a way to manage conflicts in the repo. Now, when I am using a vault on two computers sometimes I need to resolve each conflict manually by the console.

The solution could be done by adding the possibility lu launch an external tool to do this.

.gitignore example not working

The example .gitignore file is the following:

.obsidian/  # to exclude Obsidian workspace settings (including plugin and hotkey configurations)
# OR
.obsidian/workspace  # to exlude workspace cache

# Add below lines to exclude OS settings and caches
.trash/
.DS_Store

When I use this, because of the comments in lines 1 and 3, it actually won't ignore those folders/files by default, you have to remove the comments. In order to allow people to just copy paste this .gitignore and have it work, I propose the following reformatting.

# to exclude Obsidian workspace settings (including plugin and hotkey configurations)
.obsidian/  
# OR only to exlude workspace cache
.obsidian/workspace 

# Add below lines to exclude OS settings and caches
.trash/
.DS_Store

I'm on macOS 10.15.6 with Obsidian v0.10.11.

sorry, mistaken issue

Sorry, I was submitting two issues at two repos and mistook this with the other 🤦🏻 .

Does not push if no changes detected even though there are unpushed commits.

For example, this can happen if a user manually adds a commit. Or they mess around with the history in such a way as to be have commits that have not been pushed but the working directory is clean.

To Reproduce:

touch test.txt
git add .
git commit -m "manual commit"

In Obsidian => commit all and push command => says no changes detected.

git status
# produces:
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

Plugin will commit but not push on Windows

I am trying to get the plugin to work on my windows machine, and can't seem to get it to push. The plugin will display the message "git obsidian: committed x files," and will print the same thing to the console:

image

But when I check the git repo using the git cli, I find the following:
image
So clearly it's able to commit files, but isn't pushing.
I have git set up with ssh so that there is no extra prompts or passwords required when using git push. So in the cli, if I type git push, I don't need to type anything else and it will push fine.

Any help would be appreicated!

Feature: Add specified message

I like the shortcut to commit my current state in one go to GIT. However, I would like to specify a short message when I invoke the command myself. Workflow for me is;

Hotkey -> Commit prompt (may be pre-filled with default message) -> Commit & Push all

Ideally I see the files and check / uncheck the ones excluded, but I understand the philosophy of the backup plugin, and I can use a separate source control tool e.g. Sourcetree to do a fine grained commit. But in small bursts (e.g. an adjustment to one jounal entry) I would like to specify a more fine grained message.

Thank you for this plugin!

Nested repository backups

I use nested git repositories to backup parts of my vault in different repositories. This allows me to be able to write notes/documentation that I can share with others in a public github repo, while the rest of my vault remains in a private repo.

Is there a way for this extension to sync all git repos inside of the vault? It doesn't seem to happen by default.

Not able to push

Hey, love the plug-in. But I'm not able to get it to push commits
It shows the login, but it keeps giving me an error about not being able to reach the host or find the repo... Which definitely exists, and it's the right login as well
I'm able to make a work around of manually pushing it through GitKraken if I need to, but would love to not have to go through the extra steps if at all possible

Line endings on Windows

I can't seem to get the plugin to stop showing a popup on the line endings conversion, regardless of the "Disable Notifications" setting

Issues detecting and pushing changes

Hello,

I'm writing because this plugin has been phenomenal but I recently discovered that about ~6 days ago my changes stopped being pushed. Which was strange, because the status bar had said it had been pushing the changes throughout these six days. I tried to manually push any changes, but it said that no changes were detected. To check if this was the case, I edited some pages and moved some and the plugin still was not able to detect changes.

Thanks for your help!

Specs
OS: Windows 10
Obsidian v0.9.16
Obsidian Git v1.4.0

Screenshots
Turning plugin off and on
image
After changing files
image
Repo not updated in 6 days:
image

Valid git repository not found

Hi, I am using an indirect git repository. This means my git folder itself is not stored in the obsidian folder but outside. This worked well in the past, and also works with the git client and SourceTree (atlassian product).

It means there is a textfile in your folder called .git (not a folder) in which a redirect link is located. The contents of that file is:

gitdir: C:/Users/ZZZ/Documents/repos/Obsidian.git

This worked in the past, and is broken now, I assume there is a check before push if the .git folder is there? It does not have to be, it can also be a file.

It would be great if this can be fixed.

Pushing not working: "LF will be replaced by CRLF"

Whenever I try to push, this error shows up:

Uncaught (in promise) Error: warning: LF will be replaced by CRLF in .obsidian/plugins/obsidian-citation-plugin/main.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in .obsidian/plugins/obsidian-citation-plugin/styles.css.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in .obsidian/plugins/templater-obsidian/main.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in .obsidian/workspace.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in proton.md.

the error message goes on for lots of files, possibly every file in the vault, and ends on this:

warning: LF will be replaced by CRLF in fonction (math).mapp.js:1), <anonymous>:2304:85)
    at GitExecutorChain.eval (eval at <anonymous> (app.js:1), <anonymous>:2295:28)
    at Generator.throw (<anonymous>)
    at rejected (eval at <anonymous> (app.js:1), <anonymous>:2249:65)

The initial commit worked, and I checked and realized that no push ever worked since.
Any help/idea is appreciated.
on Windows 10 x64

Large File Storage

@denolehov, thank you for this plugin!

I tried to use git-lfs feature for my images sub-folder and here is error in my console:

This repository is configured for Git LFS but 'git-lfs' was not found on your path.
If you no longer wish to use Git LFS, remove this hook by deleting .git/hooks/pre-push.

Basically, hook content looks like this:

#!/bin/sh
command -v git-lfs && git lfs pre-push "$@"

I wonder if this can be fixed just by passing parent PATH via this option.

More context:
Obsidian: 0.9.14
OS: macOS Big Sur

To reproduce, I guess it would be enough to follow this setup.
Also, maybe I'll be able to figure out obsidian plugin development setup and debug it on my own.

UPD. As I can see, obsidian process doesn't contain /usr/local/bin directory in its PATH, i.e. it uses system-wide git command instead of homebrew-installed one.

Keeps showing "git:checking repo status"

How does it work?

I have github client installed, I have a working repo of my vault. I thought this plugin will automatically trigger pushes? But it seems like it's stuck somewhere. Can someone please explain what I need to do to get it up and running?

Empty files after Git Update

Hi, i have had the same error multiple times: After the vault is synced with github, some fiels are empty except for heading. I have disabled pull update and push and am working only on one device.

No options panel and constantly on `git: ready` without committing after updating Obsidian to v0.11.0

Hi, thanks for this nice plugin.

It's been working great until I updated Obsidian to v0.11.0.

After the update, at least that's when I happened to notice, the settings panel disappeared and the status was stuck on git: ready without ever committing. I uninstalled and tried to install again, but it just says "installation failed".

Just as I'm writing this, I tried again and it worked, but the options panel still isn't there and still stuck on git: ready.

Git still works fine when I use it manually.

I'm on a Mac. Happy to provide more debugging info if you can guide me how to do so.

Thanks!

Github Token Authentication is coming this year

Hi Denis,
I've started getting emails from Github like this:

You recently used a password to access the repository at blahblah/obsidian with git using git/2.20.1.

Basic authentication using a password to Git is deprecated and will soon no longer work. Visit https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/ for more information around suggested workarounds and removal dates.

Thanks,
The GitHub Team

It looks like Github is going to be doing away with username/password authentication in July/August of this year, and if nothing is done about it in this plug-in, it will stop working for everyone then.

I'm pretty sure you are aware of this already, but I didn't see it listed in the open issues so I thought I would post this so we can track your progress on it. LOVE the plugin, by the way!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.