Git Product home page Git Product logo

gitstatus's Introduction

gitstatus

  • THE PROJECT HAS VERY LIMITED SUPPORT
  • NO NEW FEATURES ARE IN THE WORKS
  • MOST BUGS WILL GO UNFIXED

gitstatus is a 10x faster alternative to git status and git describe. Its primary use case is to enable fast git prompt in interactive shells.

Heavy lifting is done by gitstatusd -- a custom binary written in C++. It comes with Zsh and Bash bindings for integration with shell.

Table of Contents

  1. Using from Zsh
  2. Using from Bash
  3. Using from other shells
  4. How it works
  5. Benchmarks
  6. Why fast
  7. Requirements
  8. Compiling
  9. License

Using from Zsh

The easiest way to take advantage of gitstatus from Zsh is to use a theme that's already integrated with it. For example, Powerlevel10k is a flexible and fast theme with first-class gitstatus integration. If you install Powerlevel10k, you don't need to install gitstatus.

Powerlevel10k Zsh Theme

For those who wish to use gitstatus without a theme, there is gitstatus.prompt.zsh. Install it as follows:

git clone --depth=1 https://github.com/romkatv/gitstatus.git ~/gitstatus
echo 'source ~/gitstatus/gitstatus.prompt.zsh' >>! ~/.zshrc

Users in China can use the official mirror on gitee.com for faster download.
**大陆用户可以使用 gitee.com 上的官方镜像加速下载.

git clone --depth=1 https://gitee.com/romkatv/gitstatus.git ~/gitstatus
echo 'source ~/gitstatus/gitstatus.prompt.zsh' >>! ~/.zshrc

Alternatively, if you have Homebrew installed:

brew install romkatv/gitstatus/gitstatus
echo "source $(brew --prefix)/opt/gitstatus/gitstatus.prompt.zsh" >>! ~/.zshrc

(If you choose this option, replace ~/gitstatus with $(brew --prefix)/opt/gitstatus/gitstatus in all code snippets below.)

Make sure to disable your current theme if you have one.

This will give you a basic yet functional prompt with git status in it. It's over 10x faster than any alternative that can give you comparable prompt. In order to customize it, set PROMPT and/or RPROMPT at the end of ~/.zshrc after sourcing gitstatus.prompt.zsh. Insert ${GITSTATUS_PROMPT} where you want git status to go. For example:

source ~/gitstatus/gitstatus.prompt.zsh

PROMPT='%~%# '               # left prompt: directory followed by %/# (normal/root)
RPROMPT='$GITSTATUS_PROMPT'  # right prompt: git status

The expansion of ${GITSTATUS_PROMPT} can contain the following bits:

segment meaning
master current branch
#v1 HEAD is tagged with v1; not shown when on a branch
@5fc6fca4 current commit; not shown when on a branch or tag
⇣1 local branch is behind the remote by 1 commit
⇡2 local branch is ahead of the remote by 2 commits
⇠3 local branch is behind the push remote by 3 commits
⇢4 local branch is ahead of the push remote by 4 commits
*5 there are 5 stashes
merge merge is in progress (could be some other action)
~6 there are 6 merge conflicts
+7 there are 7 staged changes
!8 there are 8 unstaged changes
?9 there are 9 untracked files

$GITSTATUS_PROMPT_LEN tells you how long $GITSTATUS_PROMPT is when printed to the console. gitstatus.prompt.zsh has an example of using it to truncate the current directory.

If you'd like to change the format of git status, or want to have greater control over the process of assembling PROMPT, you can copy and modify parts of gitstatus.prompt.zsh instead of sourcing the script. Your ~/.zshrc might look something like this:

source ~/gitstatus/gitstatus.plugin.zsh

function my_set_prompt() {
  PROMPT='%~%# '
  RPROMPT=''

  if gitstatus_query MY && [[ $VCS_STATUS_RESULT == ok-sync ]]; then
    RPROMPT=${${VCS_STATUS_LOCAL_BRANCH:-@${VCS_STATUS_COMMIT}}//\%/%%}  # escape %
    (( VCS_STATUS_NUM_STAGED    )) && RPROMPT+='+'
    (( VCS_STATUS_NUM_UNSTAGED  )) && RPROMPT+='!'
    (( VCS_STATUS_NUM_UNTRACKED )) && RPROMPT+='?'
  fi

  setopt no_prompt_{bang,subst} prompt_percent  # enable/disable correct prompt expansions
}

gitstatus_stop 'MY' && gitstatus_start -s -1 -u -1 -c -1 -d -1 'MY'
autoload -Uz add-zsh-hook
add-zsh-hook precmd my_set_prompt

This snippet is sourcing gitstatus.plugin.zsh rather than gitstatus.prompt.zsh. The former defines low-level bindings that communicate with gitstatusd over pipes. The latter is a simple script that uses these bindings to assemble git prompt.

Unlike Powerlevel10k, code based on gitstatus.prompt.zsh is communicating with gitstatusd synchronously. This can make your prompt slow when working in a large git repository or on a slow machine. To avoid this problem, call gitstatus_query asynchronously as documented in gitstatus.plugin.zsh. This can be quite challenging.

Using from Bash

The easiest way to take advantage of gitstatus from Bash is via gitstatus.prompt.sh. Install it as follows:

git clone --depth=1 https://github.com/romkatv/gitstatus.git ~/gitstatus
echo 'source ~/gitstatus/gitstatus.prompt.sh' >> ~/.bashrc

Users in China can use the official mirror on gitee.com for faster download.
**大陆用户可以使用 gitee.com 上的官方镜像加速下载.

git clone --depth=1 https://gitee.com/romkatv/gitstatus.git ~/gitstatus
echo 'source ~/gitstatus/gitstatus.prompt.sh' >> ~/.bashrc

Alternatively, if you have Homebrew installed:

brew install romkatv/gitstatus/gitstatus
echo "source $(brew --prefix)/opt/gitstatus/gitstatus.prompt.sh" >> ~/.bashrc

(If you choose this option, replace ~/gitstatus with $(brew --prefix)/opt/gitstatus/gitstatus in all code snippets below.)

This will give you a basic yet functional prompt with git status in it. It's over 10x faster than any alternative that can give you comparable prompt.

Bash Prompt with GitStatus

In order to customize your prompt, set PS1 at the end of ~/.bashrc after sourcing gitstatus.prompt.sh. Insert ${GITSTATUS_PROMPT} where you want git status to go. For example:

source ~/gitstatus/gitstatus.prompt.sh

PS1='\w ${GITSTATUS_PROMPT}\n\$ ' # directory followed by git status and $/# (normal/root)

The expansion of ${GITSTATUS_PROMPT} can contain the following bits:

segment meaning
master current branch
#v1 HEAD is tagged with v1; not shown when on a branch
@5fc6fca4 current commit; not shown when on a branch or tag
⇣1 local branch is behind the remote by 1 commit
⇡2 local branch is ahead of the remote by 2 commits
⇠3 local branch is behind the push remote by 3 commits
⇢4 local branch is ahead of the push remote by 4 commits
*5 there are 5 stashes
merge merge is in progress (could be some other action)
~6 there are 6 merge conflicts
+7 there are 7 staged changes
!8 there are 8 unstaged changes
?9 there are 9 untracked files

If you'd like to change the format of git status, or want to have greater control over the process of assembling PS1, you can copy and modify parts of gitstatus.prompt.sh instead of sourcing the script. Your ~/.bashrc might look something like this:

source ~/gitstatus/gitstatus.plugin.sh

function my_set_prompt() {
  PS1='\w'

  if gitstatus_query && [[ "$VCS_STATUS_RESULT" == ok-sync ]]; then
    if [[ -n "$VCS_STATUS_LOCAL_BRANCH" ]]; then
      PS1+=" ${VCS_STATUS_LOCAL_BRANCH//\\/\\\\}"  # escape backslash
    else
      PS1+=" @${VCS_STATUS_COMMIT//\\/\\\\}"       # escape backslash
    fi
    (( VCS_STATUS_HAS_STAGED"    )) && PS1+='+'
    (( VCS_STATUS_HAS_UNSTAGED"  )) && PS1+='!'
    (( VCS_STATUS_HAS_UNTRACKED" )) && PS1+='?'
  fi

  PS1+='\n\$ '

  shopt -u promptvars  # disable expansion of '$(...)' and the like
}

gitstatus_stop && gitstatus_start
PROMPT_COMMAND=my_set_prompt

This snippet is sourcing gitstatus.plugin.sh rather than gitstatus.prompt.sh. The former defines low-level bindings that communicate with gitstatusd over pipes. The latter is a simple script that uses these bindings to assemble git prompt.

Note: Bash bindings, unlike Zsh bindings, don't support asynchronous calls.

Using from other shells

If there are no gitstatusd bindings for your shell, you'll need to get your hands dirty. Use the existing bindings for inspiration; run gitstatusd --help or read the same thing in options.cc.

How it works

gitstatusd reads requests from stdin and prints responses to stdout. Requests contain an ID and a directory. Responses contain the same ID and machine-readable git status for the directory. gitstatusd keeps some state in memory for the directories it has seen in order to serve future requests faster.

Zsh bindings and Bash bindings start gitstatusd in the background and communicate with it via pipes. Themes such as Powerlevel10k use these bindings to put git status in PROMPT.

Note that gitstatus cannot be used as a drop-in replacement for git status command as it doesn't produce output in the same format. It does perform the same computation though.

Benchmarks

The following benchmark results were obtained on Intel i9-7900X running Ubuntu 18.04 in a clean chromium repository synced to 9394e49a. The repository was checked out to an ext4 filesystem on M.2 SSD.

Three functionally equivalent tools for computing git status were benchmarked:

  • gitstatusd
  • git with core.untrackedcache enabled and core.fsmonitor disabled
  • lg2 -- a demo/example executable from libgit2 that implements a subset of git functionality on top of libgit2 API; for the purposes of this benchmark the subset is sufficient to generate the same data as the other tools

Every tool was benchmark in cold and hot conditions. For git the first run in a repository was considered cold, with the following runs considered hot. lg2 was patched to compute results twice in a single invocation without freeing the repository in between; the second run was considered hot. The same patching was not done for git because git cannot be easily modified to refresh inmemory index state between invocations; in fact, this limitation is one of the primary reasons developers use libgit2. gitstatusd was benchmarked similarly to lg2 with two result computations in the same invocation.

Two commands were benchmarked: status and describe.

Status

In this benchmark all tools were computing the equivalent of git status. Lower numbers are better.

Tool Cold Hot
gitstatus 291 ms 30.9 ms
git 876 ms 295 ms
lg2 1730 ms 1310 ms

gitstatusd is substantially faster than the alternatives, especially on hot runs. Note that hot runs are of primary importance to the main use case of gitstatus in interactive shells.

The performance of git status fluctuated wildly in this benchmarks for reasons unknown to the author. Moreover, performance is sticky -- once git status settles around a number, it stays there for a long time. Numbers as diverse as 295, 352, 663 and 730 had been observed on hot runs on the same repository. The number in the table is the lowest (fastest or best) that git status had shown.

Describe

In this benchmark all tools were computing the equivalent of git describe --tags --exact-match to find tags that resolve to the same commit as HEAD. Lower numbers are better.

Tool Cold Hot
gitstatus 4.04 ms 0.0345 ms
git 18.0 ms 14.5 ms
lg2 185 ms 45.2 ms

gitstatusd is once again faster than the alternatives, more so on hot runs.

Why fast

Since gitstatusd doesn't have to print all staged/unstaged/untracked files but only report whether there are any, it can terminate repository scan early. It can also remember which files were dirty on the previous run and check them first on the next run to avoid the scan entirely if the files are still dirty. However, the benchmarks above were performed in a clean repository where these shortcuts do not trigger. All benchmarked tools had to do the same work -- check the status of every file in the index to see if it has changed, check every directory for newly created files, etc. And yet, gitstatusd came ahead by a large margin. This section describes what it does that makes it so fast.

Most of the following comparisons are done against libgit2 rather than git because of the author's familiarity with the former but not the with latter. libgit2 has clean, well-documented APIs and an elegant implementation, which makes it so much easier to work with and to analyze performance bottlenecks.

Summary for the impatient

Under the benchmark conditions described above, the equivalent of libgit2's git_diff_index_to_workdir (the most expensive part of status command) is 46.3 times faster in gitstatusd. The speedup comes from the following sources.

  • gitstatusd uses more efficient data structures and algorithms and employs performance-conscious coding style throughout the codebase. This reduces CPU time in userspace by 32x compared to libgit2.
  • gitstatusd uses less expensive system calls and makes fewer of them. This reduces CPU time spent in kernel by 1.9x.
  • gitstatusd can utilize multiple cores to scan index and workdir in parallel with almost perfect scaling. This reduces total run time by 12.4x while having virtually no effect on total CPU time.

Problem statement

The most resource-intensive part of the status command is finding the difference between index and workdir (git_diff_index_to_workdir in libgit2). Index is a list of all files in the git repository with their last modification times. This is an obvious simplification but it suffices for this exposition. On disk, index is stored sorted by file path. Here's an example of git index:

File Last modification time
Makefile 2019-04-01T14:12:32Z
src/hello.c 2019-04-01T14:12:00Z
src/hello.h 2019-04-01T14:12:32Z

This list needs to be compared to the list of files in the working directory. If any of the files listed in the index are missing from the workdir or have different last modification time, they are "unstaged" in gitstatusd parlance. If you run git status, they'll be shown as "changes not staged for commit". Thus, any implementation of status command has to call stat() or one of its variants on every file in the index.

In addition, all files in the working directory for which there is no entry in the index at all are "untracked". git status will show them as "untracked files". Finding untracked files requires some form of work directory traversal.

Single-threaded scan

Let's see how git_diff_index_to_workdir from libgit2 accomplishes these tasks. Here's its CPU profile from 200 hot runs over chromium repository.

libgit2 CPU profile (hot)

(The CPU profile was created with gperftools and rendered with pprof).

We can see __GI__lxstat taking a lot of time. This is the stat() call for every file in the index. We can also identify __opendir, __readdir and __GI___close_nocancel -- glibc wrappers for reading the contents of a directory. This is for finding untracked files. Out of the total 232 seconds, 111 seconds -- or 47.7% -- was spent on these calls. The rest is computation -- comparing strings, sorting arrays, etc.

Now let's take a look at the CPU profile of gitstatusd on the same task.

gitstatusd CPU profile (hot)

The first impression is that this profile looks pruned. This isn't an artifact. The profile was generated with the same tools and the same flags as the profile of libgit2.

Since both profiles were generated from the same workload, absolute numbers can be compared. We can see that gitstatusd took 62 seconds in total compared to libgit2's 232 seconds. System calls at the core of the algorithm are clearly visible. __GI___fxstatat is a flavor of stat(), and the other three calls -- __libc_openat64, __libc_close and __GI___fxstat are responsible for opening directories and finding untracked files. Notice that there is almost nothing else in the profile apart from these calls. The rest of the code accounts for 3.77 seconds of CPU time -- 32 times less than in libgit2.

So, one reason gitstatusd is fast is that it has efficient diffing code -- very little time is spent outside of kernel. However, if we look closely, we can notice that system calls in gitstatusd are also faster than in libgit2. For example, libgit2 spent 72.07 seconds in __GI__lxstat while gitstatusd spent only 48.82 seconds in __GI___fxstatat. There are two reasons for this difference. First, libgit2 makes more stat() calls than is strictly required. It's not necessary to stat directories because index only has files. There are 25k directories in chromium repository (and 300k files) -- that's 25k stat() calls that could be avoided. The second reason is that libgit2 and gitstatusd use different flavors of stat(). libgit2 uses lstat(), which takes a path to the file as input. Its performance is linear in the number of subdirectories in the path because it needs to perform a lookup for every one of them and to check permissions. gitstatusd uses fstatat(), which takes a file descriptor to the parent directory and a name of the file. Just a single lookup, less CPU time.

Similarly to lstat() vs fstatat(), it's faster to open files and directories with openat() from the parent directory file descriptor than with regular open() that accepts full file path. gitstatusd takes advantage of openat() to open directories as fast as possible. It opens about 90% of the directories (this depends on the actual directory structure of the repository) from the immediate parent -- the most efficient way -- and the remaining 10% it opens from the repository's root directory. The reason it's done this way is to keep the maximum number of simultaneously open file descriptors bounded. libgit2 can have O(repository depth) simultaneously open file descriptors, which may be OK for a single-threaded application but can balloon to a large number when scans are done by many threads simultaneously, like in gitstatusd.

There is no equivalent to __opendir or __readdir in the gitstatusd profile because it uses the equivalent of untracked cache from git. On the first scan of the workdir gitstatusd lists all files just like libgit2. But, unlike libgit2, it remembers the last modification time of every directory along with the list of untracked files under it. On the next scan, gitstatusd can skip listing files in directories whose last modification time hasn't changed.

To summarize, here's what gitstatusd was doing when the CPU profile was captured:

  1. __libc_openat64: Open every directory for which there are files in the index.
  2. __GI___fxstat: Check last modification time of the directory. Since it's the same as on the last scan, this directory has the same list of untracked files as before, which is empty (the repository is clean).
  3. __GI___fxstatat: Check last modification time for every file in the index that belongs to this directory.
  4. __libc_close: Close the file descriptor to the directory.

Here's how the very first scan of a repository looks like in gitstatusd:

gitstatusd CPU profile (cold)

(Some glibc functions are mislabel on this profile. explicit_bzero and __nss_passwd_lookup are in reality strcmp and memcmp.)

This is a superset of the previous -- hot -- profile, with an extra syscall and string sorting for directory listing. gitstatusd uses getdents64 Linux system call directly, bypassing the glibc wrapper that libgit2 uses. This is 23% faster. The details of this optimization can be found in a separate document.

Multithreading

The diffing algorithm in gitstatusd was designed from the ground up with the intention of using it concurrently from multiple threads. With a fast SSD, status is CPU bound, so taking advantage of all available CPU cores is an obvious way to yield results faster.

gitstatusd exhibits almost perfect scaling from multithreading. Engaging all cores allows it to produce results 12.4 times faster than in single-threaded execution. This is on Intel i9-7900X with 10 cores (20 with hyperthreading) with single-core frequency of 4.3GHz and all-core frequency of 4.0GHz.

Note: git status also uses all available cores in some parts of its algorithm while lg2 does everything in a single thread.

Postprocessing

Once the difference between the index and the workdir is found, we have a list of candidates -- files that may be unstaged or untracked. To make the final judgement, these files need to be checked against .gitignore rules and a few other things.

gitstatusd uses patched libgit2 for this step. This fork adds several optimizations that make libgit2 faster. The patched libgit2 performs more than twice as fast in the benchmark as the original even without changes in the user code (that is, in the code that uses the libgit2 APIs). The fork also adds several API extensions, most notable of which is the support for multi-threaded scans. If lg2 status is modified to take advantage of these extensions, it outperforms the original libgit2 by a factor of 18. Lastly, the fork fixes a score of bugs, most of which become apparent only when using libgit2 from multiple threads.

WARNING: Changes to libgit2 are extensive but the testing they underwent isn't. It is not recommended to use the patched libgit2 in production.

Requirements

  • To compile: binutils, cmake, gcc, g++, git and GNU make.
  • To run: Linux, macOS, FreeBSD, Android, WSL, Cygwin or MSYS2.

Compiling

There are prebuilt gitstatusd binaries in releases. When using the official shell bindings provided by gitstatus, the right binary for your architecture gets downloaded automatically.

If prebuilt binaries don't work for you, you'll need to get your hands dirty.

Compiling for personal use

git clone --depth=1 https://github.com/romkatv/gitstatus.git
cd gitstatus
./build -w -s -d docker

Users in China can use the official mirror on gitee.com for faster download.
**大陆用户可以使用 gitee.com 上的官方镜像加速下载.

git clone --depth=1 https://gitee.com/romkatv/gitstatus.git
cd gitstatus
./build -w -s -d docker
  • If it says that -d docker is not supported on your OS, remove this flag.
  • If it says that -s is not supported on your OS, remove this flag.
  • If it tell you to install docker but you cannot or don't want to, remove -d docker.
  • If it says that some command is missing, install it.

If everything goes well, the newly built binary will appear in ./usrbin. It'll be picked up by shell bindings automatically.

When you update shell bindings, they may refuse to work with the binary you've built earlier. In this case you'll need to rebuild.

If you are using gitstatus through Powerlevel10k, the instructions are the same except that you don't need to clone gitstatus. Instead, change your current directory to /path/to/powerlevel10k/gitstatus (/path/to/powerlevel10k is the directory where you've installed Powerlevel10k) and run ./build -w -s -d docker from there as described above.

Compiling for distribution

It's currently neither easy nor recommended to package and distribute gitstatus. There are no instructions you can follow that would allow you to easily update your package when new versions of gitstatus are released. This may change in the future but not soon.

License

GNU General Public License v3.0. See LICENSE. Contributions are covered by the same license.

gitstatus's People

Contributors

0xflotus avatar adp-psych avatar akianonymus avatar aloxaf avatar andresrinivasan avatar arodland avatar ascherer avatar carlosedp avatar criadoperez avatar dritter avatar hostmaster avatar ianloic avatar iblech avatar imilnb avatar joaogfarias avatar ngokimphu avatar qdel avatar romkatv avatar ryneeverett avatar samiam avatar specialpointcentral avatar toxblh avatar xnuk 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

gitstatus's Issues

'exec zsh -l' will open multiple gitstatuses with the same --parent-pid

Running exec zsh -l will cause a another gitstatus process to appear with the same --parent-pid

Running exec bash -l will leave any gitstatus processes running until the PID stops being used any process.

There is a related bug as well, which is that if gitstatus dies (e.g. kill $(pidof gitstatus)) then gitstatus is never restarted by the shell.

Some off the cuff ideas (some overlap):

  • Do locking per parent-pid.
  • Have the pipe timeout if not used for a while; have zsh restart gitstatusd if the pipe is missing.
  • Use pipe paths not based on (only?) the pid, relying on commands (or lack of) sent via the pipe.
  • Only use one gitstatus per user, instead of per-pid? Spinning up a new one if none is found, using locking to prevent duplicates.

Not compiling on FreeBSD 12.0

OS: FreeBSD 12.0
GCC: 8.3.0

mkdir -p obj
c++ -std=c++17 -funsigned-char -O3 -DNDEBUG -Wall -Werror -I/usr/local/include  -MM -MT obj/logging.o src/logging.cc >obj/logging.dep
c++ -std=c++17 -funsigned-char -O3 -DNDEBUG -Wall -Werror -I/usr/local/include  -Wall -c -o obj/logging.o src/logging.cc
c++ -std=c++17 -funsigned-char -O3 -DNDEBUG -Wall -Werror -I/usr/local/include  -MM -MT obj/response.o src/response.cc >obj/response.dep
c++ -std=c++17 -funsigned-char -O3 -DNDEBUG -Wall -Werror -I/usr/local/include  -Wall -c -o obj/response.o src/response.cc
c++ -std=c++17 -funsigned-char -O3 -DNDEBUG -Wall -Werror -I/usr/local/include  -MM -MT obj/timer.o src/timer.cc >obj/timer.dep
c++ -std=c++17 -funsigned-char -O3 -DNDEBUG -Wall -Werror -I/usr/local/include  -Wall -c -o obj/timer.o src/timer.cc
c++ -std=c++17 -funsigned-char -O3 -DNDEBUG -Wall -Werror -I/usr/local/include  -MM -MT obj/request.o src/request.cc >obj/request.dep
c++ -std=c++17 -funsigned-char -O3 -DNDEBUG -Wall -Werror -I/usr/local/include  -Wall -c -o obj/request.o src/request.cc
src/request.cc:67:5: error: use of undeclared identifier '_p'
    FD_ZERO(&fd_set);
    ^
/usr/include/sys/select.h:88:10: note: expanded from macro 'FD_ZERO'
        fd_set *_p;                                     \
                ^
src/request.cc:67:5: error: use of undeclared identifier '_p'
/usr/include/sys/select.h:91:2: note: expanded from macro 'FD_ZERO'
        _p = (p);                                       \
        ^
src/request.cc:67:5: error: use of undeclared identifier '_p'
/usr/include/sys/select.h:94:3: note: expanded from macro 'FD_ZERO'
                _p->__fds_bits[--_n] = 0;               \
                ^
3 errors generated.
gmake: *** [Makefile:26: obj/request.o] Error 1

Feature request: provide more distinct counters per type (modified unstaged, deleted unstaged, etc.)

I can see you provide VCS_STATUS_NUM_UNSTAGED which shows any modification to tracked files, however I personally found it very useful to distinguish "modified" and "deleted" files.

https://github.com/maximbaz/spaceship-prompt/blob/25b1559fb6f27a44e83df8aff1be557566d9f747/sections/git_status.zsh#L62-L70

I'm not proposing you remove VCS_STATUS_NUM_UNSTAGED, but maybe you would consider providing two new variables VCS_STATUS_NUM_MODIFIED and VCS_STATUS_NUM_DELETED?

macOS Mojave + bash: a problem and a solution

I had /bin before /usr/local/bin in my path, so /bin/bash was taking precedence and gitstatus_start was failing. /usr/local/bin/bash is 5.0.7(1)-release; /bin/bash is 3.2.57(1)-release.

One specific issue seems to be that the newer bash supports wait -n syntax while the older bash does not.

Reversing the order fixed the issue. :)

Feel free to close this; I just wanted it to be searchable in case someone else had the same problem.

Missing `gitstatusd-darwin-x86_64-static`

Of course, let me start by mentioning how much I appreciate the work you're putting into this. I really enjoy using gitstatus as a part of powerlevel10k.
I tried adding my zsh setup on a new computer I'm using and ran into issues with the gitstatus binary when applying the powerlevel10k antigen bundle. Specifically, it seems that there's no suitable gitstatusd for my platform.

I applied the antigen theme and got the following on starting a new session:

[ERROR]: gitstatus failed to initialize.

  Your git prompt may disappear or become slow.

  Run the following command to retry with extra diagnostics:

    GITSTATUS_ENABLE_LOGGING=1 gitstatus_start -s 1 -u 1 -d 1 -m -1 POWERLEVEL9K

Ok, so I ran that and got

[ERROR]: gitstatus failed to initialize.

  Your git prompt may disappear or become slow.

  The content of /var/folders/z3/rhtcsfrs1hv1s01kbqnvrlnh0000gq/T//gitstatus.45363.xtrace.gVWoQDheFK (gitstatus_start_impl xtrace):

    +gitstatus_start_impl:8> local os
    +gitstatus_start_impl:8> os=+gitstatus_start_impl:8> uname -s
    +gitstatus_start_impl:8> os=Darwin
    +gitstatus_start_impl:8> [[ -n Darwin ]]
    +gitstatus_start_impl:9> [[ Darwin != Linux ]]
    +gitstatus_start_impl:10> local arch
    +gitstatus_start_impl:10> arch=+gitstatus_start_impl:10> uname -m
    +gitstatus_start_impl:10> arch=x86_64
    +gitstatus_start_impl:10> [[ -n x86_64 ]]
    +gitstatus_start_impl:11> local ldd_v
    +gitstatus_start_impl:11> ((  0  ))
    +gitstatus_start_impl:11> true
    +gitstatus_start_impl:12> local linkage
    +gitstatus_start_impl:12> [[ '' == (*glibc*|*gnu\ libc*) ]]
    +gitstatus_start_impl:12> linkage=-static
    +gitstatus_start_impl:14> local daemon=/Users/fvm/.antigen/bundles/romkatv/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64-static
    +gitstatus_start_impl:15> [[ -f /Users/fvm/.antigen/bundles/romkatv/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64-static ]]
                               ^ this command failed

  Your system information:

    zsh:      5.7.1
    uname -a: Darwin 192.168.2.120 17.7.0 Darwin Kernel Version 17.7.0: Wed Apr 24 21:17:24 PDT 2019; root:xnu-4570.71.45~1/RELEASE_X86_64 x86_64

Ok, so that made me think: "Why does that fail?". Kinda obvious, there's no binary at ~/.antigen/bundles/romkatv/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64-static. Now, my first thought was: "Maybe that got dropped in the latest version", but going through the git history, that doesn't appear to be the case.

So, I tried digging around for why [[ '' == (*glibc*|*gnu\ libc*) ]] fails. Well, to be honest, I don't get a lot further than this:

~$ (*glibc*|*gnu\ libc*)
zsh: no matches found: *glibc*
zsh: no matches found: *gnu libc*

Now, from what I can tell, that shouldn't even exist for MacOS, but I'm probably wrong on that. It does, however, make me wonder why I even get to that part.

Any ideas? Perhaps on what I'm blatantly overlooking?

.gitignore resolution is inconsistent with `git status`

Under specific conditions, gitstatusd and git status do not resolve .gitignore the same way.

Here is an example: https://github.com/dorian-marchal/gitstatus-issue-59

cd /tmp
git clone https://github.com/dorian-marchal/gitstatus-issue-59
cd gitstatus-issue-59

mkdir foo
touch foo/bar
touch foo/baz

. ~/gitstatus/gitstatus.plugin.sh

gitstatus_start -e -d 99

gitstatus_query

git status # Reports a new foo/ dir.
git status --untracked-files # Reports two new foo/{bar,baz} files.

echo $VCS_STATUS_NUM_UNTRACKED # 0
echo $VCS_STATUS_HAS_UNTRACKED # 0

Get the number of unmerged files

Is this possible to get the number of unmerged (conflicted) files from git status?

Currently, I parse git status --branch --untracked-files=all --porcelain to construct a prompt with these infos:

  • Number of staged files.
  • Number of unstaged files.
  • Number of untracked files.
  • Number of unmerged (conflicted) files.
  • Is the current branch ahead of its upstream?
  • Is the current branch behind its upstream?

It looks like that:

Screenshot from 2019-07-05 11-34-05

(master is ahead of its upstream, there are 4 files staged, 1 unstaged, 2 untracked and 1 unmerged)

It works well, but it's quite slow and I thought omkatv/gitstatus could make it faster.

But it seems I can't get the number of unmerged files.
Is their a way to do that?

Incorrect number of untracked files (`$VCS_STATUS_NUM_UNTRACKED`)

In this example, git status reports 2 untracked files, but echo $VCS_STATUS_NUM_UNTRACKED returns 1:

cd /tmp

mkdir test-repo

cd test-repo/

git init
# Initialized empty Git repository in /tmp/test-repo/.git/

git commit --allow-empty -m 'Initial commit'
# [master (root-commit) b81f127] Initial commit

touch a

touch b

git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
# 	a
# 	b
# nothing added to commit but untracked files present (use "git add" to track)

source ~/gitstatus/gitstatus.plugin.sh

gitstatus_query

echo $VCS_STATUS_NUM_UNTRACKED
1

GitStatus support async pulling of git remote?

Hi there! Love your plugin, I've written just a super basic prompt where I use your gitstatus plugin to pull the vcs info (git specifically). Is there a way to enable async pulling of the git remote (similar to Pure's capability to do that)?

Retrieve the changes count

I switched not too long ago from my own custom zsh theme to https://github.com/romkatv/powerlevel10k which uses this repository to handle the git status information in the prompt.
Before the switch I was using https://github.com/olivierverdier/zsh-git-prompt in order to get the git status in the prompt. zsh-git-prompt offers the change count for staged, changed, conflicts in the prompt (see https://github.com/olivierverdier/zsh-git-prompt#examples).
Furthermore, using the Haskell backend was fast enough for me.

Is it possible to get the change count in the git prompt using this tool?

Bash bindings

There is a partial port of ZSH bindings to bash in bash-prompt-example.sh.

Before it can be declared official it needs to have the following missing features:

  • Error handling.
  • Self-check on initialization.
  • Multiple gitstatusd instances.
  • Relative $GIT_DIR support.
  • exec bash must not leave a stranded gitstatusd behind.

Async API can be added later. It's not hard requirement for the first release.

new gitstattus binary

I think the freebsd binary should be named gitstatusd-freebsd-amd64 not gitstatusd-freebsd-x86_64. The reason for this is uname -m returns amd64

Arm v5 support

Hi,
is it maybe possible to support older ARMs too?
Like armv5tel?

Would be great so we can use powerlevel10k also on NAS systems ;)

Thanks

AUR package

Hey! 👋
Great work. I was skeptic in first place when I hear it uses a daemon for each shell, since I tend to spawn many of them with TMux. But the performance caught me! Not sure how I handle zombie daemons by TMux sessions I forgot about, but I guess this is a general setup problem of mine.

Since I try to keep my computer clean, I always prefer a package version for all my tools. Handling arbitrary repositories is a nightmare. Dependency management etc not even mentioned. So do you consider to publish this also as a package. As a ArchLinux user I would prefer it as an AUR first of cause. 😜

Use `gitstatus` from PATH as fallback

Hello,

due to how NixOS works, pre-built binaries aren't really usable. I am building gitstatusd from source and would like the ZSH plugin to use it automatically.

Right now I'd doing this as a workaround:

rm -rf ~/powerlevel10k/gitstatus/bin
mkdir -p ~/powerlevel10k/gitstatus/bin
ln -s /run/current-system/sw/bin/gitstatusd ~/powerlevel10k/gitstatus/bin/gitstatus-linux-x86_64

Support .git folders containing symlinks

First off, awesome work here! amazingly fast, and IMO preferable to async prompts.

I did hit one issue; the google repo tool uses symlinks in the project .git folders, example:

> ls -al .git
total 36
drwxrwxr-x 2 npendleton npendleton 4096 Apr 10 09:33 .
drwxrwxr-x 7 npendleton npendleton 4096 Apr 10 09:32 ..
lrwxrwxrwx 1 npendleton npendleton   37 Apr 10 09:32 config -> ../../.repo/projects/tokei.git/config
lrwxrwxrwx 1 npendleton npendleton   65 Apr 10 09:32 description -> ../../.repo/project-objects/Aaronepower/tokei.git.git/description
-rw-rw-r-- 1 npendleton npendleton   41 Apr 10 09:32 HEAD
lrwxrwxrwx 1 npendleton npendleton   59 Apr 10 09:32 hooks -> ../../.repo/project-objects/Aaronepower/tokei.git.git/hooks
-rw-rw-r-- 1 npendleton npendleton 9786 Apr 10 09:32 index
lrwxrwxrwx 1 npendleton npendleton   58 Apr 10 09:32 info -> ../../.repo/project-objects/Aaronepower/tokei.git.git/info
lrwxrwxrwx 1 npendleton npendleton   35 Apr 10 09:32 logs -> ../../.repo/projects/tokei.git/logs
lrwxrwxrwx 1 npendleton npendleton   61 Apr 10 09:32 objects -> ../../.repo/project-objects/Aaronepower/tokei.git.git/objects
lrwxrwxrwx 1 npendleton npendleton   42 Apr 10 09:32 packed-refs -> ../../.repo/projects/tokei.git/packed-refs
lrwxrwxrwx 1 npendleton npendleton   35 Apr 10 09:32 refs -> ../../.repo/projects/tokei.git/refs
lrwxrwxrwx 1 npendleton npendleton   62 Apr 10 09:32 rr-cache -> ../../.repo/project-objects/Aaronepower/tokei.git.git/rr-cache
lrwxrwxrwx 1 npendleton npendleton   57 Apr 10 09:32 svn -> ../../.repo/project-objects/Aaronepower/tokei.git.git/svn

Unfotunately this results in a missing scm segment:
image

I'm using oh-my-zsh with the default powerlevel10k settings (I only set ZSH_THEME="powerlevel10k/powerlevel10k" in my ~/.zshrc). Falling back to vcs_info by setting POWERLEVEL9K_DISABLE_GITSTATUS=true restores the segment (but it's slow again 😕 ).

You can repro by installing the repo tool (on ubuntu I did sudo apt install repo), and these commands for a test repo set:

mkdir google-repo-test && cd google-repo-test
repo init -u ssh://[email protected]/noahp/google-repo-example.git
repo sync  # clone the projects (there's only one in this example)
cd tokei
# this is where I encounter the issue; the .git folder here contains symlinks over to the
# parent .repo dir

I've no clue where the symlinks are interfering; I tried adding a single LOG(FATAL) statement to gitstatus here, but didn't notice anything:

diff --git a/src/index.cc b/src/index.cc
index afa8a5e..d2712b9 100644
--- a/src/index.cc
+++ b/src/index.cc
@@ -73,7 +73,11 @@ bool IsModified(const git_index_entry* entry, const struct stat& st, bool trust_
 }
 
 int OpenDir(int parent_fd, const char* name) {
-  return openat(parent_fd, name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+  int ret = openat(parent_fd, name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
+  if (ret) {
+    LOG(FATAL) << "opendir error: " << name;
+  }
+  return ret;
 }
 
 void OpenTail(int* fds, size_t nfds, int root_fd, StringView dirname, Arena& arena) {

But I'm not sure where to see that output either.

I was using c6b74d1 for testing (symlinked the output over, eg ln -s /tmp/gitstatus/gitstatus/bin/gitstatusd-linux-x86_64 $ZSH_CUSTOM/themes/powerlevel10k/gitstatus/bin/gitstatusd-linux-x86_64).

Fresh initialised repo not recognised

When I do a fresh git init, gitstatusd reports norepo-sync, which is suprising to me. Probably it is me doing something wrong..

Here is a screenshot of my approach (ignore the vcs segment here):
Bildschirmfoto 2019-03-24 um 01 40 43

Incorrect default number of threads

Not sure if this is a documentation issue or a bug. The help message says:

-t, --num-threads=NUM [default=-1]
 Use this many threads to scan git workdir for unstaged and untracked files.
 Non-positive value means as many threads as there are CPUs.

However, at least on macOS, it always seems to use 1 thread by default:

[~]─> gitstatusd 
[2019-06-05 13:59:43 INFO src/gitstatus.cc:142] argv[0]: /Users/taazadi1/.elvish/package-data/gitstatus/gitstatusd
[2019-06-05 13:59:43 INFO src/thread_pool.cc:81] Spawning 1 thread(s)

I have a 6-core CPU with hyperthreading, so the system reports 12 CPUs:

[~]─> sysctl hw.ncpu
hw.ncpu: 12
[~]─> getconf _NPROCESSORS_ONLN
12

Build error with Clang 8.0.0

🐛 Bug Report

Compiling with clang 8.0.0 causes an build error.

Expected behaviour

Following command should compile and install the gitstatus and its dependencies.

zsh -c "$(curl -fsSL https://raw.githubusercontent.com/romkatv/gitstatus/master/build.zsh)"

Current behaviour

Compilation fails with the following error.

clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/dir.o src/dir.cc >obj/dir.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/tag_db.o src/tag_db.cc >obj/tag_db.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/response.o src/response.cc >obj/response.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/thread_pool.o src/thread_pool.cc >obj/thread_pool.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/check_dir_mtime.o src/check_dir_mtime.cc >obj/check_dir_mtime.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/repo.o src/repo.cc >obj/repo.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/timer.o src/timer.cc >obj/timer.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/logging.o src/logging.cc >obj/logging.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/logging.o src/logging.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/thread_pool.o src/thread_pool.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/response.o src/response.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/timer.o src/timer.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/dir.o src/dir.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/check_dir_mtime.o src/check_dir_mtime.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/tag_db.o src/tag_db.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/repo.o src/repo.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/git.o src/git.cc >obj/git.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/request.o src/request.cc >obj/request.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/index.o src/index.cc >obj/index.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/git.o src/git.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/request.o src/request.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/index.o src/index.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/gitstatus.o src/gitstatus.cc >obj/gitstatus.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/repo_cache.o src/repo_cache.cc >obj/repo_cache.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/gitstatus.o src/gitstatus.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/repo_cache.o src/repo_cache.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/options.o src/options.cc >obj/options.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/options.o src/options.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/strings.o src/strings.cc >obj/strings.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/strings.o src/strings.cc
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -MM -MT obj/arena.o src/arena.cc >obj/arena.dep
clang++  -I/tmp/gitstatus/libgit2/include -std=c++14 -funsigned-char -O3 -DNDEBUG -Wall -Werror  -Wall -c -o obj/arena.o src/arena.cc
src/arena.cc:46:34: error: no matching function for call to 'operator delete'
  for (const Block& b : blocks_) ::operator delete(reinterpret_cast<void*>(b.start), b.size());
                                 ^~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/new:138:6: note: candidate function not viable:
      no known conversion from 'size_t' (aka 'unsigned long') to 'const std::nothrow_t' for 2nd argument
void operator delete(void*, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT
     ^
/usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/new:174:13: note: candidate function not viable:
      no known conversion from 'size_t' (aka 'unsigned long') to 'void *' for 2nd argument
inline void operator delete  (void*, void*) _GLIBCXX_USE_NOEXCEPT { }
            ^
/usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/new:124:6: note: candidate function not viable:
      requires 1 argument, but 2 were provided
void operator delete(void*) _GLIBCXX_USE_NOEXCEPT
     ^
src/arena.cc:68:5: error: no matching function for call to 'operator delete'
    ::operator delete(reinterpret_cast<void*>(b.start), b.size());
    ^~~~~~~~~~~~~~~~~
/usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/new:138:6: note: candidate function not viable:
      no known conversion from 'size_t' (aka 'unsigned long') to 'const std::nothrow_t' for 2nd argument
void operator delete(void*, const std::nothrow_t&) _GLIBCXX_USE_NOEXCEPT
     ^
/usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/new:174:13: note: candidate function not viable:
      no known conversion from 'size_t' (aka 'unsigned long') to 'void *' for 2nd argument
inline void operator delete  (void*, void*) _GLIBCXX_USE_NOEXCEPT { }
            ^
/usr/lib/gcc/x86_64-linux-gnu/8/../../../../include/c++/8/new:124:6: note: candidate function not viable:
      requires 1 argument, but 2 were provided
void operator delete(void*) _GLIBCXX_USE_NOEXCEPT
     ^
2 errors generated.
Makefile:21: recipe for target 'obj/arena.o' failed
make: *** [obj/arena.o] Error 1
make: *** Waiting for unfinished jobs....

Possible Solution

Clang >= 3.7 requires -fsized-deallocation to allow sized deallocation.

Environment

Software Version(s)
Operating System Lubuntu 18.04
Linux Kernel 4.18.0-18-generic
Clang 8.0.0
C++ Standard Library libstdc++ 8.3.0

Question: Multiple remotes

Hi,

I'm currently trying to incorporate the use of this great project into bash-it to get rid of the resource consuming separate git calls.
At one point there is a distinction if there are multiple remotes.

I do not see this case exposed by gitstatusd.

What is the current and expected behavior for this?

Parameter "parent_fd" not used in V3 code example

Hi,

In the V3 code section you have the following:

void ListDir(int parent_fd, const char* dirname, string& arena, vector<char*>& entries) {  // +  
  entries.clear();  
  int dir_fd = openat(root_fd, dirname, O_NOATIME | O_RDONLY | O_DIRECTORY | O_CLOEXEC);   // +  
  if (dir_fd < 0) return;                                                                  // + 
  if (DIR* dir = fdopendir(dir_fd)) {  
    arena.clear(); 
    while (struct dirent* ent = (errno = 0, readdir(dir))) {  
      if (!Dots(ent->d_name)) { 
        entries.push_back(reinterpret_cast<char*>(arena.size()));  
        arena.append(ent->d_name, strlen(ent->d_name) + 1);  
      }  
    }  
    if (errno) entries.clear();  
    for (char*& p : entries) p = &arena[reinterpret_cast<size_t>(p)];  
    sort(entries.begin(), entries.end(),  
         [](const char* a, const char* b) { return strcmp(a, b) < 0; });  
    closedir(dir);  
  } else {                                                                                 // +  
    close(dir_fd);                                                                         // +  
  }                                                                                        // +  
}

It seems that the int parent_fd parameter is not used in the code itself. I could be missing something of course :)

Faster Dots() implementation

This is probably not very important but after reading your Dots() implementation, I couldn't help but hack together another implementation that runs more than twice as fast on my hardware. (sorry for the crufty testbench)

I believe this is faster because it avoids one or more branches. Note that this code only works on little endian ASCII environments. Big endian and non ASCII versions are probably fairly straightforward.

It looks like you mostly want the inverse of Dots(), in which case you may want to apply DeMorgan's theorem to avoid the extra inversion. I haven't checked the assembler output of gcc or clang to see if it is smart enough to do that automatically for you.

#include<iostream>
bool Dots(const char* name) {
  if (name[0] == '.') {
    if (name[1] == 0) return true;
    if (name[1] == '.' && name[2] == 0) return true;
  }
  return false;
}
bool FasterDots(const char* s) {return (*(int*)s&65535) == '.' | (*(int*)s&16777215) == 0x2e2e; }
const int len = 16777216*2;
int main(){
  int j=0;
  int* a = new int[ len ];
  for( int i = 0; i < len; i++ ) {
    a[i] = i;
  }

  for( int k=0; k<100; k++ ) {
    for( int i = 0; i < len; i++ ) {
      //j+= Dots((char*)(a+i));
      j+= FasterDots((char*)(a+i));
    }
  }
  std::cout<<j<<'\n';
}

Edit: Slightly less bad example code.

Xonsh Shell Support

Xonsh is a python-powered shell, and I am trying to port some popular plugins that I use for myself over.

How to check if binary is compatible?

Edge use case here - trying to load the plugin on a quite dated RHEL system. (School provided cluster...)

The plugin adds a whopping 5 seconds to shell startup even though it fails to load in the end - probably because it has to do some kind of library search?

image

Is there some way I can speed up the check beforehand so it doesn't have to look through glibc versions just to end up crashed?

Untracked files in subdirectory are not counted

Repro (tested on master @ 66376040cec):

$ mkdir /tmp/foo

$ cd /tmp/foo

$ git init
Initialized empty Git repository in /tmp/foo/.git/

$ git commit --allow-empty -m 'Initial commit'
[master (root-commit) 74c5562] Initial commit

$ mkdir bar

$ touch bar/a

$ git add bar/a

$ git commit -m 'Add a'
[master c034577] Add a
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 bar/a

$ touch bar/b

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

	bar/b

nothing added to commit but untracked files present (use "git add" to track)

$ source ~/repos/gitstatus/gitstatus.plugin.sh

$ gitstatus_start

$ gitstatus_query

$ echo $VCS_STATUS_NUM_UNTRACKED
0 # ← Expected 1

$ touch a

$ gitstatus_query

$ git status
On branch master
Untracked files:
  (use "git add <file>..." to include in what will be committed)

	a
	bar/b

nothing added to commit but untracked files present (use "git add" to track)

$ echo $VCS_STATUS_NUM_UNTRACKED
1 # ← Expected 2

Request: Count individual files in untracked directory (--untracked-files)

git status supports an --untracked-files option that can be used to list individual files in untracked directories.

Could a similar option be added to romkatv/gitstatus ?

Example :

mkdir /tmp/foobar

cd /tmp/foobar/

git init
# Initialized empty Git repository in /tmp/foobar/.git/

source ~/gitstatus/gitstatus.plugin.sh

gitstatus_start

mkdir foo

touch foo/bar

touch foo/baz

git status --untracked-files
# On branch master
# 
# No commits yet
# 
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
# 
# 	foo/bar
# 	foo/baz
# 
# nothing added to commit but untracked files present (use "git add" to track)

gitstatus_query

echo $VCS_STATUS_NUM_UNTRACKED
1 # ← Would be "2".

VCS_STATUS_WORKDIR displayed on prompt instead of status

In one particular on my system the gitstatus plugin correctly displays the git status the very first time I'm in that directory but afterwards, the directory name is replaced with VCS_STATUS_WORKDIR:

image

This repository is from the seL4 microkernel and, as long as you have repo installed, this can be duplicated by running:

mkdir sel4test
cd sel4test
repo init -u https://github.com/seL4/sel4test-manifest.git
repo sync
cd kernel
echo "hi"

The .git/config for the kernel directory looks like this:

[core]
        repositoryformatversion = 0
        filemode = true
[filter "lfs"]
        smudge = git-lfs smudge --skip -- %f
        process = git-lfs filter-process --skip
[remote "seL4"]
        url = https://github.com/seL4/seL4.git
        projectname = seL4.git
        fetch = +refs/heads/*:refs/remotes/seL4/*

I'm not sure what other info would be helpful to troubleshoot this.

Using gitstatus in oh-my-zsh theme.

How can I call gitstatus from customized theme oh-my-zsh? I'm using the following code to show status:

function vcs_info() {
  test -d ".bzr" && which bzr >/dev/null 2>&1 && bzr_prompt_info
  test -d ".git" && which git >/dev/null 2>&1 && git_prompt_info
  test -d ".hg"  && which hg  >/dev/null 2>&1 && hg_prompt_info
}

How can I replace git_prompt_info() function with a function using gitstatus plugin?

[ERROR]: gitstatus failed to initialize.

Your git prompt may disappear or become slow.
Run the following command to retry with extra diagnostics:
GITSTATUS_ENABLE_LOGGING=1 gitstatus_start -s 1 -u 1 -d 1 -m -1 POWERLEVEL9K

OUTPUT:

[ERROR]: gitstatus failed to initialize.

Your git prompt may disappear or become slow.

The content of /tmp/gitstatus.6241.xtrace.A1TYYErcG2 (gitstatus_start_impl xtrace):

+gitstatus_start_impl:8> local os
+gitstatus_start_impl:8> os=+gitstatus_start_impl:8> uname -s
+gitstatus_start_impl:8> os=Linux 
+gitstatus_start_impl:8> [[ -n Linux ]]
+gitstatus_start_impl:9> [[ Linux != Linux ||+gitstatus_start_impl:9> uname -o
+gitstatus_start_impl:9> [[ Linux != Linux || GNU/Linux != Android ]]
+gitstatus_start_impl:10> local arch
+gitstatus_start_impl:10> arch=+gitstatus_start_impl:10> uname -m
+gitstatus_start_impl:10> arch=x86_64 
+gitstatus_start_impl:10> [[ -n x86_64 ]]
+gitstatus_start_impl:11> local ldd_v
+gitstatus_start_impl:11> ((  1  ))
+gitstatus_start_impl:11> ldd_v=+gitstatus_start_impl:11> ldd --version
+gitstatus_start_impl:11> ldd_v=$'ldd (GNU libc) 2.12\nCopyright (C) 2010 Free Software Foundation, Inc.\nThis is free software; see the source for copying conditions.  There is NO\nwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\nWritten by Roland McGrath and Ulrich Drepper.' 
+gitstatus_start_impl:12> local linkage
+gitstatus_start_impl:12> [[ Linux != Linux || $'ldd (gnu libc) 2.12\ncopyright (c) 2010 free software foundation, inc.\nthis is free software; see the source for copying conditions.  there is no\nwarranty; not even for merchantability or fitness for a particular purpose.\nwritten by roland mcgrath and ulrich drepper.' == (*glibc*|*gnu\ libc*) ]]
+gitstatus_start_impl:14> local daemon=/home/amursi/powerlevel10k/gitstatus/bin/gitstatusd-linux-x86_64
+gitstatus_start_impl:15> [[ -f /home/amursi/powerlevel10k/gitstatus/bin/gitstatusd-linux-x86_64 ]]
+gitstatus_start_impl:17> lock_file=+gitstatus_start_impl:17> mktemp /tmp/gitstatus.6241.lock.XXXXXXXXXX
+gitstatus_start_impl:17> lock_file=/tmp/gitstatus.6241.lock.SHLkwvnknt 
+gitstatus_start_impl:18> zsystem flock -f lock_fd /tmp/gitstatus.6241.lock.SHLkwvnknt
+gitstatus_start_impl:20> req_fifo=+gitstatus_start_impl:20> mktemp -u /tmp/gitstatus.6241.pipe.req.XXXXXXXXXX
+gitstatus_start_impl:20> req_fifo=/tmp/gitstatus.6241.pipe.req.gsIGfZCIkJ 
+gitstatus_start_impl:21> mkfifo /tmp/gitstatus.6241.pipe.req.gsIGfZCIkJ
+gitstatus_start_impl:22> sysopen -rw -o cloexec,sync -u req_fd /tmp/gitstatus.6241.pipe.req.gsIGfZCIkJ
+gitstatus_start_impl:23> rm -f /tmp/gitstatus.6241.pipe.req.gsIGfZCIkJ
+gitstatus_start_impl:25> resp_fifo=+gitstatus_start_impl:25> mktemp -u /tmp/gitstatus.6241.pipe.resp.XXXXXXXXXX
+gitstatus_start_impl:25> resp_fifo=/tmp/gitstatus.6241.pipe.resp.MDvYbf0PdR 
+gitstatus_start_impl:26> mkfifo /tmp/gitstatus.6241.pipe.resp.MDvYbf0PdR
+gitstatus_start_impl:27> sysopen -rw -o cloexec -u resp_fd /tmp/gitstatus.6241.pipe.resp.MDvYbf0PdR
+gitstatus_start_impl:28> rm -f /tmp/gitstatus.6241.pipe.resp.MDvYbf0PdR
+gitstatus_start_impl:33> zle -F 15 _gitstatus_process_response_POWERLEVEL9K
+gitstatus_start_impl:35> [[ 1 == 1 ]]
+gitstatus_start_impl:36> log_file=+gitstatus_start_impl:36> mktemp /tmp/gitstatus.6241.daemon-log.XXXXXXXXXX
+gitstatus_start_impl:36> log_file=/tmp/gitstatus.6241.daemon-log.kEnSanXUdp 
+gitstatus_start_impl:38> typeset -g 'GITSTATUS_DAEMON_LOG_POWERLEVEL9K=/tmp/gitstatus.6241.daemon-log.kEnSanXUdp'
+gitstatus_start_impl:40> local -i threads=0
+gitstatus_start_impl:41> ((  threads > 0 ))
+gitstatus_start_impl:42> threads=8 
+gitstatus_start_impl:43> case Linux (FreeBSD)
+gitstatus_start_impl:43> case Linux (*)
+gitstatus_start_impl:45> ((  ! 1  ))
+gitstatus_start_impl:45> threads=+gitstatus_start_impl:45> getconf _NPROCESSORS_ONLN
+gitstatus_start_impl:45> threads=16 
+gitstatus_start_impl:47> ((  threads <= 32  ))
+gitstatus_start_impl:63> daemon_pid=6505 
+gitstatus_start_impl:51> zsh -dfxc $'\n      /home/amursi/powerlevel10k/gitstatus/bin/gitstatusd-linux-x86_64                                     --lock-fd=3                                    --parent-pid=6241                                --num-threads=16                         --max-num-staged=1               --max-num-unstaged=1           --max-num-untracked=1         --dirty-max-index-size=-1\n      echo -nE $\'bye\\x1f0\\x1e\'\n    '
+gitstatus_start_impl:64> rm -f /tmp/gitstatus.6241.lock.SHLkwvnknt
+gitstatus_start_impl:66> local reply
+gitstatus_start_impl:67> echo -nE $'hello\C-_\C-^'
+gitstatus_start_impl:68> IFS='' +gitstatus_start_impl:68> read -r -d $'\C-^' -u 15 -t 5.0000000000 reply
+gitstatus_start_impl:69> [[ $'bye\C-_0' == hello0 ]]
                           ^ this command failed

The content of /tmp/gitstatus.6241.daemon-log.kEnSanXUdp (gitstatus daemon log):

+zsh:2> /home/amursi/powerlevel10k/gitstatus/bin/gitstatusd-linux-x86_64 '--lock-fd=3' '--parent-pid=6241' '--num-threads=16' '--max-num-staged=1' '--max-num-unstaged=1' '--max-num-untracked=1' '--dirty-max-index-size=-1'
/home/amursi/powerlevel10k/gitstatus/bin/gitstatusd-linux-x86_64: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by /home/amursi/powerlevel10k/gitstatus/bin/gitstatusd-linux-x86_64)
/home/amursi/powerlevel10k/gitstatus/bin/gitstatusd-linux-x86_64: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by /home/amursi/powerlevel10k/gitstatus/bin/gitstatusd-linux-x86_64)
/home/amursi/powerlevel10k/gitstatus/bin/gitstatusd-linux-x86_64: /lib64/libc.so.6: version `GLIBC_2.17' not found (required by /home/amursi/powerlevel10k/gitstatus/bin/gitstatusd-linux-x86_64)
+zsh:3> echo -nE $'bye\C-_0\C-^'

Your system information:

zsh:      5.7.1
uname -a: Linux orw-amursi-rh6 2.6.32-754.el6.x86_64 #1 SMP Thu May 24 18:18:25 EDT 2018 x86_64 GNU/Linux

If you need help, open an issue and attach this whole error message to it:

https://github.com/romkatv/gitstatus/issues/new

There is no gitstatusd binary for sunos-i86pc

Here's the message that appears:

[ERROR]: gitstatus failed to initialize.

Your git prompt may disappear or become slow.

The content of /tmp/gitstatus.1584.xtrace.XXXX2Ka4ld (gitstatus_start_impl xtrace):

+gitstatus_start_impl:11> local os
+gitstatus_start_impl:11> os=+gitstatus_start_impl:11> uname -s
+gitstatus_start_impl:11> os=SunOS 
+gitstatus_start_impl:11> [[ -n SunOS ]]
+gitstatus_start_impl:12> [[ SunOS != Linux ]]
+gitstatus_start_impl:13> local arch
+gitstatus_start_impl:13> arch=+gitstatus_start_impl:13> uname -m
+gitstatus_start_impl:13> arch=i86pc 
+gitstatus_start_impl:13> [[ -n i86pc ]]
+gitstatus_start_impl:15> local daemon=/export/home/hitch/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-sunos-i86pc
+gitstatus_start_impl:16> [[ -f /export/home/hitch/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-sunos-i86pc ]]
                           ^ this command failed

Your system information:

zsh:      5.7.1
uname -a: SunOS openindiana 5.11 illumos-8d13991861 i86pc i386 i86pc

Thanks,

Alan

Outputting zshoptions

Since 4861c44 my shell has been printing options at initialization. It happens because I have no options to restore and setopt is called without arguments.

I patched it by testing the variable [[ -n ${_gitstatus_opts[@]} ]] && setopt ${_gitstatus_opts[@]}. I guess piping to dev/null would work too.

BTW I noticed powerlevel10k is doing something very similar so maybe someone could have the same issue there.

Setup for fish shell?

Ahoy!

I use the fish shell, which I'm pretty happy with... except I have to disable some git commands for the prompt. Has anyone tried to make gitstatus work with fish's git functions?

(I expected probably not, but I thought I'd ask before I get the itch to do it myself.)

Evaluate the feasibility of mingw port

[ERROR]: gitstatus failed to initialize.

  Your git prompt may disappear or become slow.

  Run the following command to retry with extra diagnostics:

    GITSTATUS_LOG_LEVEL=DEBUG gitstatus_start -s -1 -u -1 -d -1 -c -1 -m -1 POWERLEVEL9K
 ~ ❯ GITSTATUS_LOG_LEVEL=DEBUG gitstatus_start -s -1 -u -1 -d -1 -c -1 -m -1 POWERLEVEL9K
[ERROR]: gitstatus failed to initialize.

  Your git prompt may disappear or become slow.

  The content of /tmp/gitstatus.4176.xtrace.8VbPwLfBYz (gitstatus_start_impl xtrace):

    +gitstatus_start_impl:11> local os
    +gitstatus_start_impl:11> os=+gitstatus_start_impl:11> uname -s
    +gitstatus_start_impl:11> os=MINGW64_NT-10.0-18362
    +gitstatus_start_impl:11> [[ -n MINGW64_NT-10.0-18362 ]]
    +gitstatus_start_impl:12> [[ MINGW64_NT-10.0-18362 != Linux ]]
    +gitstatus_start_impl:13> local arch
    +gitstatus_start_impl:13> arch=+gitstatus_start_impl:13> uname -m
    +gitstatus_start_impl:13> arch=x86_64
    +gitstatus_start_impl:13> [[ -n x86_64 ]]
    +gitstatus_start_impl:15> local daemon=/c/Users/pnzhd/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-mingw64_nt-10.0-18362-x86_64
    +gitstatus_start_impl:16> [[ -f /c/Users/pnzhd/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-mingw64_nt-10.0-18362-x86_64 ]]
                               ^ this command failed

  Your system information:

    zsh:      5.7.1
    uname -a: MINGW64_NT-10.0-18362 blackportable 3.0.7-338.x86_64 2019-07-11 10:58 UTC x86_64 Msys

Bundling a CLI client into the executable

First, great work on this!

Second, I was wondering if you'd be open to PRs adding an optional CLI client into the executable. The purpose of the client is to enable a simple, text-based query interface to the information that the daemon holds. This would simplify the synchronous use case:

> gitstatusd PROMPT --query "branch unpushed-mods"

When called like this, gitstatusd would:

  1. Find the daemon instance with an ID of PROMPT. (I'm not sure if this is possible in the current codebase, but we could set this up via some sort of shared memory.)
  2. Submit a Request to the daemon with the ID of PROMPT for information about the current branch, and whether any modifications are present.
  3. Await a response, then print the following to standard output:
master
false
  1. Exit, with status code 0 denoting success in retrieving the information, 1 denoting no git repo present, and 2 if an error occurred.

The benefit to this approach is that it is easy to read this information from any shell/language/other tool. Error information is conveyed via exit codes, as it should be. Also, only the information requested can be computed.

The only question I have is whether clients parsing the info is sufficiently fast enough for the common use case of shells. It will probably be shell dependent. I'm open to other IPC mechanisms here, but I'm not sure what would be the optimal choice beyond text output.

gitstatus failed to initialize (OSX)

This happens half the time.. sometimes it works, sometimes it doesn't.

GITSTATUS_LOG_LEVEL=DEBUG gitstatus_start -s -1 -u -1 -d -1 -c -1 -m -1 POWERLEVEL9K
[ERROR]: gitstatus failed to initialize.

Your git prompt may disappear or become slow.

The content of /var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.xtrace.WOBCxZr9jZ (gitstatus_start_impl xtrace):

+gitstatus_start_impl:11> local os
+gitstatus_start_impl:11> os=+gitstatus_start_impl:11> uname -s
+gitstatus_start_impl:11> os=Darwin
+gitstatus_start_impl:11> [[ -n Darwin ]]
+gitstatus_start_impl:12> [[ Darwin != Linux ]]
+gitstatus_start_impl:13> local arch
+gitstatus_start_impl:13> arch=+gitstatus_start_impl:13> uname -m
+gitstatus_start_impl:13> arch=x86_64
+gitstatus_start_impl:13> [[ -n x86_64 ]]
+gitstatus_start_impl:15> local daemon=/Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64
+gitstatus_start_impl:16> [[ -f /Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64 ]]
+gitstatus_start_impl:18> lock_file=+gitstatus_start_impl:18> mktemp /var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.lock.XXXXXXXXXX
+gitstatus_start_impl:18> lock_file=/var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.lock.LjUDkystN9
+gitstatus_start_impl:19> zsystem flock -f lock_fd /var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.lock.LjUDkystN9
+gitstatus_start_impl:21> req_fifo=+gitstatus_start_impl:21> mktemp -u /var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.pipe.req.XXXXXXXXXX
+gitstatus_start_impl:21> req_fifo=/var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.pipe.req.PGBH3AX3nW
+gitstatus_start_impl:22> mkfifo /var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.pipe.req.PGBH3AX3nW
+gitstatus_start_impl:24> resp_fifo=+gitstatus_start_impl:24> mktemp -u /var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.pipe.resp.XXXXXXXXXX
+gitstatus_start_impl:24> resp_fifo=/var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.pipe.resp.q1comaOLTb
+gitstatus_start_impl:25> mkfifo /var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.pipe.resp.q1comaOLTb
+gitstatus_start_impl:27> [[ -n DEBUG ]]
+gitstatus_start_impl:28> log_file=+gitstatus_start_impl:28> mktemp /var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.daemon-log.XXXXXXXXXX
+gitstatus_start_impl:28> log_file=/var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.daemon-log.ij6ADxvMJZ
+gitstatus_start_impl:30> typeset -g 'GITSTATUS_DAEMON_LOG_POWERLEVEL9K=/var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.daemon-log.ij6ADxvMJZ'
+gitstatus_start_impl:32> local -i threads=0
+gitstatus_start_impl:33> ((  threads > 0 ))
+gitstatus_start_impl:34> threads=8
+gitstatus_start_impl:35> case Darwin (FreeBSD)
+gitstatus_start_impl:35> case Darwin (*)
+gitstatus_start_impl:37> ((  ! 1  ))
+gitstatus_start_impl:37> threads=+gitstatus_start_impl:37> getconf _NPROCESSORS_ONLN
+gitstatus_start_impl:37> threads=8
+gitstatus_start_impl:39> ((  threads <= 32  ))
+gitstatus_start_impl:42> local -a daemon_args=( '--lock-fd=3' '--parent-pid=27758' '--num-threads=8' '--max-num-staged=-1' '--max-num-unstaged=-1' '--max-num-conflicted=-1' '--max-num-untracked=-1' '--dirty-max-index-size=-1' '--log-level=DEBUG' )
+gitstatus_start_impl:53> local cmd=$'\n      echo $$\n      /Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64 --lock-fd=3 --parent-pid=27758 --num-threads=8 --max-num-staged=-1 --max-num-unstaged=-1 --max-num-conflicted=-1 --max-num-untracked=-1 --dirty-max-index-size=-1 --log-level=DEBUG\n      if [[ $? != (0|10) && $? -le 128 &&\n            -z \'\' &&\n            -f /Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64-static ]]; then\n        /Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64-static --lock-fd=3 --parent-pid=27758 --num-threads=8 --max-num-staged=-1 --max-num-unstaged=-1 --max-num-conflicted=-1 --max-num-untracked=-1 --dirty-max-index-size=-1 --log-level=DEBUG\n      fi\n      echo -nE $\'bye\\x1f0\\x1e\''
+gitstatus_start_impl:62> local setsid=/usr/local/opt/util-linux/bin/setsid
+gitstatus_start_impl:63> [[ -f /usr/local/opt/util-linux/bin/setsid ]]
+gitstatus_start_impl:63> setsid=''
+gitstatus_start_impl:64> cmd='cd /;  zsh -dfxc $'\''\n'\''\ \ \ \ \ \ echo\ \$\$$'\''\n'\''\ \ \ \ \ \ /Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64\ --lock-fd=3\ --parent-pid=27758\ --num-threads=8\ --max-num-staged=-1\ --max-num-unstaged=-1\ --max-num-conflicted=-1\ --max-num-untracked=-1\ --dirty-max-index-size=-1\ --log-level=DEBUG$'\''\n'\''\ \ \ \ \ \ if\ \[\[\ \$\?\ \!=\ \(0\|10\)\ \&\&\ \$\?\ -le\ 128\ \&\&$'\''\n'\''\ \ \ \ \ \ \ \ \ \ \ \ -z\ \'\''\'\''\ \&\&$'\''\n'\''\ \ \ \ \ \ \ \ \ \ \ \ -f\ /Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64-static\ \]\]\;\ then$'\''\n'\''\ \ \ \ \ \ \ \ /Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64-static\ --lock-fd=3\ --parent-pid=27758\ --num-threads=8\ --max-num-staged=-1\ --max-num-unstaged=-1\ --max-num-conflicted=-1\ --max-num-untracked=-1\ --dirty-max-index-size=-1\ --log-level=DEBUG$'\''\n'\''\ \ \ \ \ \ fi$'\''\n'\''\ \ \ \ \ \ echo\ -nE\ \$\'\''bye\\x1f0\\x1e\'\'' &!'
+gitstatus_start_impl:73> sysopen -w -o cloexec,sync -u req_fd /var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.pipe.req.PGBH3AX3nW
+gitstatus_start_impl:74> sysopen -r -o cloexec -u resp_fd /var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.pipe.resp.q1comaOLTb
+gitstatus_start_impl:76> read -u 15 daemon_pid
+gitstatus_start_impl:71> zsh -dfmxc 'cd /;  zsh -dfxc $'\''\n'\''\ \ \ \ \ \ echo\ \$\$$'\''\n'\''\ \ \ \ \ \ /Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64\ --lock-fd=3\ --parent-pid=27758\ --num-threads=8\ --max-num-staged=-1\ --max-num-unstaged=-1\ --max-num-conflicted=-1\ --max-num-untracked=-1\ --dirty-max-index-size=-1\ --log-level=DEBUG$'\''\n'\''\ \ \ \ \ \ if\ \[\[\ \$\?\ \!=\ \(0\|10\)\ \&\&\ \$\?\ -le\ 128\ \&\&$'\''\n'\''\ \ \ \ \ \ \ \ \ \ \ \ -z\ \'\''\'\''\ \&\&$'\''\n'\''\ \ \ \ \ \ \ \ \ \ \ \ -f\ /Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64-static\ \]\]\;\ then$'\''\n'\''\ \ \ \ \ \ \ \ /Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64-static\ --lock-fd=3\ --parent-pid=27758\ --num-threads=8\ --max-num-staged=-1\ --max-num-unstaged=-1\ --max-num-conflicted=-1\ --max-num-untracked=-1\ --dirty-max-index-size=-1\ --log-level=DEBUG$'\''\n'\''\ \ \ \ \ \ fi$'\''\n'\''\ \ \ \ \ \ echo\ -nE\ \$\'\''bye\\x1f0\\x1e\'\'' &!'
+gitstatus_start_impl:78> rm -f /var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.pipe.req.PGBH3AX3nW /var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.pipe.resp.q1comaOLTb /var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.lock.LjUDkystN9
+gitstatus_start_impl:89> zle -F 15 _gitstatus_process_response_POWERLEVEL9K
+gitstatus_start_impl:91> local reply IFS=''
+gitstatus_start_impl:92> echo -nE $'hello\C-_\C-^'
+gitstatus_start_impl:93> read -r -d $'\C-^' -u 15 -t 5.0000000000 reply
                           ^ this command failed

The content of /var/folders/bx/xdcq47c972j5ypgkgyknzs25gqnnkw/T//gitstatus.27758.daemon-log.ij6ADxvMJZ (gitstatus daemon log):

+zsh:1> cd /
+zsh:1> zsh -dfxc $'\n      echo $$\n      /Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64 --lock-fd=3 --parent-pid=27758 --num-threads=8 --max-num-staged=-1 --max-num-unstaged=-1 --max-num-conflicted=-1 --max-num-untracked=-1 --dirty-max-index-size=-1 --log-level=DEBUG\n      if [[ $? != (0|10) && $? -le 128 &&\n            -z \'\' &&\n            -f /Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64-static ]]; then\n        /Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64-static --lock-fd=3 --parent-pid=27758 --num-threads=8 --max-num-staged=-1 --max-num-unstaged=-1 --max-num-conflicted=-1 --max-num-untracked=-1 --dirty-max-index-size=-1 --log-level=DEBUG\n      fi\n      echo -nE $\'bye\\x1f0\\x1e\''
+zsh:2> echo 27814
+zsh:3> /Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64 '--lock-fd=3' '--parent-pid=27758' '--num-threads=8' '--max-num-staged=-1' '--max-num-unstaged=-1' '--max-num-conflicted=-1' '--max-num-untracked=-1' '--dirty-max-index-size=-1' '--log-level=DEBUG'
[2019-08-10 00:38:04 000000011b5d85c0 INFO src/gitstatus.cc:157] argv[0]: "/Users/omarbaza/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/bin/gitstatusd-darwin-x86_64"
[2019-08-10 00:38:04 000000011b5d85c0 INFO src/gitstatus.cc:157] argv[1]: "--lock-fd=3"
[2019-08-10 00:38:04 000000011b5d85c0 INFO src/gitstatus.cc:157] argv[2]: "--parent-pid=27758"
[2019-08-10 00:38:04 000000011b5d85c0 INFO src/gitstatus.cc:157] argv[3]: "--num-threads=8"
[2019-08-10 00:38:04 000000011b5d85c0 INFO src/gitstatus.cc:157] argv[4]: "--max-num-staged=-1"
[2019-08-10 00:38:04 000000011b5d85c0 INFO src/gitstatus.cc:157] argv[5]: "--max-num-unstaged=-1"
[2019-08-10 00:38:04 000000011b5d85c0 INFO src/gitstatus.cc:157] argv[6]: "--max-num-conflicted=-1"
[2019-08-10 00:38:04 000000011b5d85c0 INFO src/gitstatus.cc:157] argv[7]: "--max-num-untracked=-1"
[2019-08-10 00:38:04 000000011b5d85c0 INFO src/gitstatus.cc:157] argv[8]: "--dirty-max-index-size=-1"
[2019-08-10 00:38:04 000000011b5d85c0 INFO src/gitstatus.cc:157] argv[9]: "--log-level=DEBUG"
[2019-08-10 00:38:04 000000011b5d85c0 INFO src/thread_pool.cc:81] Spawning 8 thread(s)
[2019-08-10 00:38:09 000000011b5d85c0 INFO src/request.cc:110] EOF. Exiting.

Your system information:

zsh:      5.7.1
uname -a: Darwin c4b301d3c8fd.ant.amazon.com 18.7.0 Darwin Kernel Version 18.7.0: Thu Jun 20 18:42:21 PDT 2019; root:xnu-4903.270.47~4/RELEASE_X86_64 x86_64

If you need help, open an issue and attach this whole error message to it:

https://github.com/romkatv/gitstatus/issues/new

gitstatusd keeping files opened

Sometimes gitstatusd seems to open a file and doesn't close it until being killed.
It happens often enough to interfere with daily filesystem rotations etc.:

cannot unmount '/poudriere/ports/default': Device busy
The following processes are using '/poudriere/ports/default':
USER CMD PID FD MOUNT INUM MODE SZ|DV R/W
root gitstatusd-freebsd- 55320 4 /poudriere/ports/default 307301 -r--r--r-- 127462930 r
[Error 03:32:08] Can't destroy ZFS filesystem 'data/poudriere/ports/default'.

Even 6 hours after that the file is still open:

╰ fstat -p 55320
USER CMD PID FD MOUNT INUM MODE SZ|DV R/W
root gitstatusd-freebsd- 55320 text /shareddata 2188 -rwxr-xr-x 3252072 r
root gitstatusd-freebsd- 55320 ctty /dev 241 crw--w---- pts/1 rw
root gitstatusd-freebsd- 55320 wd / 20 drwxr-xr-x 36 r
root gitstatusd-freebsd- 55320 root / 4 drwxr-xr-x 32 r
root gitstatusd-freebsd- 55320 0 - 18865 prw-r--r-- 0 r
root gitstatusd-freebsd- 55320 1 - 18867 prw-r--r-- 0 w
root gitstatusd-freebsd- 55320 2 /dev 16 crw-rw-rw- null w
root gitstatusd-freebsd- 55320 3 - 18863 -rw------- 0 r
root gitstatusd-freebsd- 55320 4 /poudriere/ports/default 307301 -r--r--r-- 127462930 r

This is on: 12.0-RELEASE-p7 amd64

Raspberry Pi 3 support

I'm getting this error on my Raspberry Pi 3:

[ERROR]: gitstatus failed to initialize.

  Your git prompt may disappear or become slow.

  Run the following command to retry with extra diagnostics:

    GITSTATUS_ENABLE_LOGGING=1 gitstatus_start -s 1 -u 1 -d POWERLEVEL9K_VCS_UNTRACKED_MAX_NUM -m -1 POWERLEVEL9K

$ GITSTATUS_ENABLE_LOGGING=1 gitstatus_start -s 1 -u 1 -d POWERLEVEL9K_VCS_UNTRACKED_MAX_NUM -m -1 POWERLEVEL9K
[ERROR]: gitstatus failed to initialize.

  Your git prompt may disappear or become slow.

  The content of /tmp/gitstatus.23487.xtrace.bJYZyVdSXj (gitstatus_start_impl xtrace):

    +gitstatus_start_impl:8> local os
    +gitstatus_start_impl:8> os=+gitstatus_start_impl:8> uname -s
    +gitstatus_start_impl:8> os=Linux
    +gitstatus_start_impl:8> [[ -n Linux ]]
    +gitstatus_start_impl:9> local arch
    +gitstatus_start_impl:9> arch=+gitstatus_start_impl:9> uname -m
    +gitstatus_start_impl:9> arch=aarch64
    +gitstatus_start_impl:9> [[ -n aarch64 ]]
    +gitstatus_start_impl:11> local daemon=/home/j2ghz/.antigen/bundles/romkatv/powerlevel10k/gitstatus/bin/gitstatusd-linux-aarch64
    +gitstatus_start_impl:12> [[ -f /home/j2ghz/.antigen/bundles/romkatv/powerlevel10k/gitstatus/bin/gitstatusd-linux-aarch64 ]]
    +gitstatus_start_impl:14> lock_file=+gitstatus_start_impl:14> mktemp /tmp/gitstatus.23487.lock.XXXXXXXXXX
    +gitstatus_start_impl:14> lock_file=/tmp/gitstatus.23487.lock.WEiGE0uhlN
    +gitstatus_start_impl:15> zsystem flock -f lock_fd /tmp/gitstatus.23487.lock.WEiGE0uhlN
    +gitstatus_start_impl:17> req_fifo=+gitstatus_start_impl:17> mktemp -u /tmp/gitstatus.23487.pipe.req.XXXXXXXXXX
    +gitstatus_start_impl:17> req_fifo=/tmp/gitstatus.23487.pipe.req.5k1HR9YOLo
    +gitstatus_start_impl:18> mkfifo /tmp/gitstatus.23487.pipe.req.5k1HR9YOLo
    +gitstatus_start_impl:19> sysopen -rw -o cloexec,sync -u req_fd /tmp/gitstatus.23487.pipe.req.5k1HR9YOLo
    +gitstatus_start_impl:20> rm -f /tmp/gitstatus.23487.pipe.req.5k1HR9YOLo
    +gitstatus_start_impl:22> resp_fifo=+gitstatus_start_impl:22> mktemp -u /tmp/gitstatus.23487.pipe.resp.XXXXXXXXXX
    +gitstatus_start_impl:22> resp_fifo=/tmp/gitstatus.23487.pipe.resp.L2eimo5yuy
    +gitstatus_start_impl:23> mkfifo /tmp/gitstatus.23487.pipe.resp.L2eimo5yuy
    +gitstatus_start_impl:24> sysopen -rw -o cloexec -u resp_fd /tmp/gitstatus.23487.pipe.resp.L2eimo5yuy
    +gitstatus_start_impl:25> rm -f /tmp/gitstatus.23487.pipe.resp.L2eimo5yuy
    +gitstatus_start_impl:30> zle -F 15 _gitstatus_process_response_POWERLEVEL9K
    +gitstatus_start_impl:32> [[ 1 == 1 ]]
    +gitstatus_start_impl:33> log_file=+gitstatus_start_impl:33> mktemp /tmp/gitstatus.23487.daemon-log.XXXXXXXXXX
    +gitstatus_start_impl:33> log_file=/tmp/gitstatus.23487.daemon-log.V03AHATJ2w
    +gitstatus_start_impl:35> typeset -g 'GITSTATUS_DAEMON_LOG_POWERLEVEL9K=/tmp/gitstatus.23487.daemon-log.V03AHATJ2w'
    +gitstatus_start_impl:37> local -i threads=0
    +gitstatus_start_impl:38> ((  threads > 0 ))
    +gitstatus_start_impl:39> case Linux (FreeBSD)
    +gitstatus_start_impl:39> case Linux (*)
    +gitstatus_start_impl:41> threads=+gitstatus_start_impl:41> getconf _NPROCESSORS_ONLN
    +gitstatus_start_impl:41> threads=8
    +gitstatus_start_impl:43> ((  threads <= 32  ))
    +gitstatus_start_impl:59> daemon_pid=23912
    +gitstatus_start_impl:47> zsh -dfxc $'\n      /home/j2ghz/.antigen/bundles/romkatv/powerlevel10k/gitstatus/bin/gitstatusd-linux-aarch64                                     --lock-fd=3                                    --parent-pid=23487                                --num-threads=8                         --max-num-staged=1               --max-num-unstaged=1           --max-num-untracked=1         --dirty-max-index-size=-1\n      echo -nE $\'bye\\x1f0\\x1e\'\n    '
    +gitstatus_start_impl:60> rm -f /tmp/gitstatus.23487.lock.WEiGE0uhlN
    +gitstatus_start_impl:62> local reply
    +gitstatus_start_impl:63> echo -nE $'hello\C-_\C-^'
    +gitstatus_start_impl:64> IFS='' +gitstatus_start_impl:64> read -r -d $'\C-^' -u 15 -t 5.0000000000 reply
    +gitstatus_start_impl:65> [[ $'bye\C-_0' == hello0 ]]
                               ^ this command failed

  The content of /tmp/gitstatus.23487.daemon-log.V03AHATJ2w (gitstatus daemon log):

    +zsh:2> /home/j2ghz/.antigen/bundles/romkatv/powerlevel10k/gitstatus/bin/gitstatusd-linux-aarch64 '--lock-fd=3' '--parent-pid=23487' '--num-threads=8' '--max-num-staged=1' '--max-num-unstaged=1' '--max-num-untracked=1' '--dirty-max-index-size=-1'
    zsh:2: exec format error: /home/j2ghz/.antigen/bundles/romkatv/powerlevel10k/gitstatus/bin/gitstatusd-linux-aarch64
    +zsh:3> echo -nE $'bye\C-_0\C-^'

  Your system information:

    zsh:      5.7.1
    uname -a: Linux rpi 5.1.5-2-ARCH #1 SMP Thu May 30 07:48:43 MDT 2019 aarch64 GNU/Linux

  If you need help, open an issue and attach this whole error message to it:

    https://github.com/romkatv/gitstatus/issues/new

I think this is the problem, but I'm not sure what to do with that:

$ ./gitstatusd-linux-aarch64 --help
zsh: exec format error: ./gitstatusd-linux-aarch64

$ uname -m
aarch64

$ file gitstatusd-linux-aarch64
gitstatusd-linux-aarch64: symbolic link to gitstatusd-linux-armv7l

$ file gitstatusd-linux-armv7l
gitstatusd-linux-armv7l: ELF 32-bit LSB executable, ARM, EABI5 version 1 (GNU/Linux), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=fa8c78ee364e9012eab5883cffb115a03aa27508, stripped

gitstatusd incorrectly reporting an untracked file

I have a repo that has no untracked files, but gitstatusd is reporting one. I've tried restarting gitstatusd, and running git clean -fdX to clean all ignored files.

Screen Shot 2019-05-25 at 11 44 33 AM

Is there some way to see what the file is, or debug the issue?

Windows native port

Are there any plans to port this to native windows code or is there any way to run this within powershell(powershell core would be also cool) as currently there's only git-posh which is super slow.

I know there's wsl and magic stuff but sometimes we're stuck with windows tools and have to work somehow ;)

Files added with `git add -N` are reported as "staged"

This is inconsistent with git status:

mkdir /tmp/foobar

cd /tmp/foobar/

git init
# Initialized empty Git repository in /tmp/foobar/.git/

source ~/gitstatus/gitstatus.plugin.sh

gitstatus_start

echo foo > a

git add -N a

git status
# On branch master
#
# No commits yet
#
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
# 	new file:   a
#
# no changes added to commit (use "git add" and/or "git commit -a")

gitstatus_query

echo $VCS_STATUS_NUM_STAGED
# 1 ← Expected 0

echo $VCS_STATUS_NUM_UNSTAGED
# 1

Document Profiling Graph Creation

This isn't a tool issue; but I couldn't think of a better place to ask this question.

I was quite impressed seeing your profiling graphs in the README and your ListDir() optimization description. Did you create them manually or was it tool assisted? If they were made by some tool, could you add a sentence or two about how you created them?

Also, thanks for this tool; I use a git status prompt and occasionally bump into sluggishness so I'm eager to try this out.

[Question] Portable to use with Golang

I want to use gitstatus to check some git info of repositories from anywhere.

It's possible tu use gitstatus in a cli tool build with Golang? I guess so. But I actually don't know how to do that. How can I do that?

Thanks!

gitstatus_stop missing for zsh plugin

Also I've noticed that gitstatus_check only checks if a previous gitstatus_start succeeded but it doesn't actually check if the daemon is currently running.

Would you accept a PR to update both? (close & check)

Elvish shell support

Just wanted to let ya'll know that there's now an integration for the Elvish shell over at https://github.com/href/elvish-gitstatus.

I figured I move it into my own repository as Elvish is young and pre 1.0, so there might be frequent changes not related to gitstatus. Let me know if you'd rather have the code live here.

gitstatus failed to initialize

I have looked into the source code into seeing if I could possibly come up with a workaround for why this isn't getting loaded. My initial thought is thinking that its because I have my .oh-my-zsh directory completely symlinked, but with that said, I would appreciate any help diving into what could be causing this issue and a potential resolution.

Helpful Info:

$ uname -a
Darwin Grants-iMac 17.7.0 Darwin Kernel Version 17.7.0: Thu Jun 21 22:53:14 PDT 2018; root:xnu-4570.71.2~1/RELEASE_X86_64 x86_64

I have tried setting POWERLEVEL9K_GITSTATUS_DIR to:
~/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/ as well as
/Users/$(whoami)/.oh-my-zsh/custom/themes/powerlevel10k/gitstatus/

I was also getting errors along the lines of unrecognized symbol -le in my powerlevel10k.config in the prompt_zsh_battery_level function and updated the if [ ... ] to if [[ ... ]]

# .zshrc file
export PATH=$HOME/bin:/usr/local/bin:$PATH
export PATH="/usr/local/sbin:$PATH"
export ZSH="/Users/$(whoami)/.oh-my-zsh"
ZSH_THEME="powerlevel10k/powerlevel10k"
plugins=(git)
source $ZSH/oh-my-zsh.sh
source "$ZSH/custom/themes/powerlevel10k.config"

FWIW, I have this same setup on another machine and works without any issues.

OSX version

Hi, @romkatv

I tried your powerlevel10k and its aweasome. Thanks for your work.

And as you suggest I tried it with gitstatus and discover that I can't use it on my osx machine. I couldn't compile it too.

In my fork I made some small changes to make it work in osx. Tested only on my machine with Mojave osx.

It's not crossplatform code. So if you can make it work for all platforms that will be great.

My fork

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.