strboul / git-substatus Goto Github PK
View Code? Open in Web Editor NEWInspect git status of multiple (sub-)directories
License: MIT License
Inspect git status of multiple (sub-)directories
License: MIT License
tried on two different directories with git repos:
Traceback (most recent call last):
File "/home/eg/.local/bin/git-substatus", line 8, in <module>
sys.exit(main())
File "/home/eg/.local/lib/python3.9/site-packages/git_substatus/__main__.py", line 11, in main
GitSubstatusApplication(args).exec()
File "/home/eg/.local/lib/python3.9/site-packages/git_substatus/gitsubstatus.py", line 59, in exec
statuses = status.get_status()
File "/home/eg/.local/lib/python3.9/site-packages/git_substatus/status.py", line 149, in get_status
git_status = tuple(self.__get_statuses())
File "/home/eg/.local/lib/python3.9/site-packages/git_substatus/status.py", line 154, in __get_statuses
status = self.__get_git_status(repo)
File "/home/eg/.local/lib/python3.9/site-packages/git_substatus/status.py", line 161, in __get_git_status
if self.__is_status_clean():
File "/home/eg/.local/lib/python3.9/site-packages/git_substatus/status.py", line 181, in __is_status_clean
btw_brackets = self.status_details[0].split("[")
IndexError: list index out of range
Traceback (most recent call last):
File "/home/eg/.local/bin/git-substatus", line 8, in <module>
sys.exit(main())
File "/home/eg/.local/lib/python3.9/site-packages/git_substatus/__main__.py", line 11, in main
GitSubstatusApplication(args).exec()
File "/home/eg/.local/lib/python3.9/site-packages/git_substatus/gitsubstatus.py", line 59, in exec
statuses = status.get_status()
File "/home/eg/.local/lib/python3.9/site-packages/git_substatus/status.py", line 149, in get_status
git_status = tuple(self.__get_statuses())
File "/home/eg/.local/lib/python3.9/site-packages/git_substatus/status.py", line 154, in __get_statuses
status = self.__get_git_status(repo)
File "/home/eg/.local/lib/python3.9/site-packages/git_substatus/status.py", line 164, in __get_git_status
self.status_changes = StatusChanges.get_status_changes(self.status_details)
File "/home/eg/.local/lib/python3.9/site-packages/git_substatus/status.py", line 42, in get_status_changes
cls.mapped_status_count = cls.__get_mapped_status_count()
File "/home/eg/.local/lib/python3.9/site-packages/git_substatus/status.py", line 105, in __get_mapped_status_count
return dict(status_count_gen())
File "/home/eg/.local/lib/python3.9/site-packages/git_substatus/status.py", line 100, in status_count_gen
raise KeyError(f"Unknown status mapping: \"{k}\"")
KeyError: 'Unknown status mapping: "?"'
also I couldn't get the package from pip via pip install git-substatus
Add a command-line option (e.g. -L
, --level
) to choose how deep git-substatus should look at the dirs.
The current default is 1 (and can't be changed with an option), and it could be better if it was 2.
Hi, This is a new warning added in Python 3.8 (release notes). There’s a subtle difference between the Python identity operator (is) and the equality operator (==). The "==" operator compares the value or equality of two objects, whereas the Python "is" operator checks whether two variables point to the same object in memory.
We can filter the warning (library/warnings) or replace the "is" statement with "==".
To be used with certain flags (like, --fetch
, --pull
etc.)
git substatus --fetch --interactive
# Fetching `repo/`
# [Y]es, [N]o, [Q]uit
When running git-substatus
with watch
, the output is not clean due to the escape codes:
watch git-substatus
# Every 2.0s: git-substatus
# ^[90m directory: </home/myazici>^[0m
# • ^[1m^[34mdotfiles^[0m ^[4m^[37mv0.4.4^[0m ^[3m^[32m<sync>^[0m ^[36m^[0m ^[35m^[0m
# • ^[1m^[34mtmp-workbench^[0m ^[4m^[37mupdates^[0m ^[33m2 untracked & ahead 1^[0m ^[36m^[0m ^[35m^[0m
With watch git status
the color is not there; but, when printed onto the screen, it is.
watch --color git-substatus
shows the output with color, but that's a separate parameter added to the watch
command.
If I add watch git -c color.status=always status
, I see the git status with the escape code.
So how does git know when to add the escape codes?
Answer: there's a way to check if a file is opened on terminal
man test
...
-t FD file descriptor FD is opened on a terminal
...
echo '''
#!/bin/bash
text="Hello world"
if [ -t 1 ]; then
echo "***stdout is a terminal***"
text="$(printf "%s" "\e[31m$text\e[0m")"
fi
echo -e "$text"
''' > test.sh
chmod +x test.sh
./test.sh
# ***stdout is a terminal***
# Hello world
#
watch ./test.sh
# Every 2.0s: ./test.sh
#
# Hello world
#
--color
always prints color--no-color
never prints colorwatch
Watch 1 time & parse the output.
watch args | git-substatus args | color codes printed |
---|---|---|
--color |
--color |
false |
--color |
--no-color |
false |
`` | --color |
true |
`` | --no-color |
false |
Pulling an empty repository from upstream creates a status "gone".
To reproduce:
mkdir /tmp/gs-test
cd /tmp/gs-test
mkdir bar-upstream && cd bar-upstream
git init --bare # remote must be 'bare'
cd ..
git clone bar-upstream bar
mkdir foo && cd foo
git init
cd ..
git-substatus
# directory: </tmp/gs-test>
# • bar master gone
# • foo master <sync>
cd bar
git status -sb
## No commits yet on master...origin/master [gone]
The status should instead be called <sync>
because there are no changes.
git-substatus is currently licensed with GPL-3.0, introduced sometime like three years ago. I read that GPL-3 isn't very much OK in the industry. It may be better to change it to a much more permissive license, like MIT. No need to hassle.
- [ ] Ask approval from contributors
For people who have a lot of repositories (like hundreds maybe), add an argument that doesn't show <sync>
repositories but only ones that are not synced.
git-substatus --show-only-sync
CHANGELOG.md
https://keepachangelog.comREADME.md
Along with showing worktrees as (*WT)
next to the folder names, also show the number of worktrees in the table.
Add --json
flag to the CLI to print the output as JSON so some tools like jq can be used to extract structured information.
It might be a better user experience, performance if git-substatus uses more of async operations for, such as:
etc.
In order to run git-substatus with Docker, create a Dockerfile and post to https://hub.docker.com/
Dockerfile
in the repoFROM python:3.8-alpine
LABEL MAINTAINER="strboul"
LABEL REPOSITORY="https://github.com/strboul/git-substatus"
LABEL HOMEPAGE="https://github.com/strboul/git-substatus"
COPY setup.py git-substatus/ .
RUN pip install . # or make install
docker run -t -v "$(pwd)":/repo strboul/git-substatus:latest
Also possible to add an alias in the .bashrc
or .zshrc
.
Optional:
git-substatus
currently prints the folder name while fetching from remote. It'll be more useful to print the remote url instead.
git-substatus --fetch
Fetching from remote "[email protected]:strboul/git-substatus.git"
Fetching from remote "[email protected]:strboul/kwic-ts.git"
Notes:
may use git config --get remote.origin.url
to get the remote url.
If git config --get remote.origin.url
returns non-zero, it means it doesn't have a remote, so don't fetch it, but show a message such as Can't fetch "<folder>" as remote not exist
.
Remove All fetched.
message.
Truncate the names in the output, including:
If the name is greater than n, e.g. 16
characters, get the first n chars and put use Unicode horizontal ellipsis …
(U+2026
) on the 17th char to imply that the branch name is actually truncated.
--no-truncated-names
that shows the full names always.I'm trying on the home directory where my projects.
Python version: 3.9.2
git-substatus version: 0.2.3
[ 12:57 ÖS ] [ adil@debian:~/Projects ]
$ git-substatus
Traceback (most recent call last):
File "/usr/local/bin/git-substatus", line 8, in <module>
sys.exit(main())
File "/usr/local/lib/python3.9/dist-packages/git_substatus/__main__.py", line 11, in main
GitSubstatusApplication(args).exec()
File "/usr/local/lib/python3.9/dist-packages/git_substatus/gitsubstatus.py", line 59, in exec
statuses = status.get_status()
File "/usr/local/lib/python3.9/dist-packages/git_substatus/status.py", line 149, in get_status
git_status = tuple(self.__get_statuses())
File "/usr/local/lib/python3.9/dist-packages/git_substatus/status.py", line 154, in __get_statuses
status = self.__get_git_status(repo)
File "/usr/local/lib/python3.9/dist-packages/git_substatus/status.py", line 164, in __get_git_status
self.status_changes = StatusChanges.get_status_changes(self.status_details)
File "/usr/local/lib/python3.9/dist-packages/git_substatus/status.py", line 42, in get_status_changes
cls.mapped_status_count = cls.__get_mapped_status_count()
File "/usr/local/lib/python3.9/dist-packages/git_substatus/status.py", line 105, in __get_mapped_status_count
return dict(status_count_gen())
File "/usr/local/lib/python3.9/dist-packages/git_substatus/status.py", line 100, in status_count_gen
raise KeyError(f"Unknown status mapping: \"{k}\"")
KeyError: 'Unknown status mapping: "RM"'
Every time a new commit is pushed to master, a new version workflow should be triggered. Push new version on tags. Create a new actions workflow e.g. called release.yml
that does:
Asynchronous fetching operation: fetching should be as fast as possible. (Need to resolve #22)
If fetching isn't fast enough, do it in the background in a forked process invoked when the command is called.
The time is Realtime Timer, not Monotonic, (borrowing here the nomenclature of systemd-timer), so the time is always ticking even when the machine is powered off.
Need to check the date and internal storage that auto-fetch has been done. For internal storage, maybe choose a path like ~/.config/git-substatus/state.json
.
# state.json file (mirroring the data structure of config.json)
{
"autoFetchHooks": [
{
"folders": ["/path/to/folder1", "path/to/folder2"],
"lastRunDate": "2023-01-...", # last command run with autofetchhooks modified.
}
]
}
Pseudocode.
if config.autoFetchHooks.minutes:
if (now() > state.autoFetchHooks.lastRunDate
and now + config.autofetchHooks.minutes > state.autoFetchHooks.lastRunDate):
args.append('--fetch')
Create a config entry. (Need to resolve #7)
autoFetchHooks:
minutes: 60 # after login, after every x minutes, command will be run with the `--fetch` flag. Only positive integers are allowed. Minimum value is `1`.
Show a different color and/or add a symbol to the branch column (like *
) unless it shows the default branch name (mostly master
, main
, release
etc.).
Unfortunately, this issue is a bit complex as there's no standard way of getting the default branch name right away.
Programmatically, it's possible to get the branch name in multiple ways:
git config --get init.defaultBranch
then origin/HEAD
is set automatically.
git symbolic-ref refs/remotes/origin/HEAD | cut -d '/' -f4
master
git rev-parse --abbrev-ref origin/HEAD
origin/master
git ls-remote --symref origin HEAD
ref: refs/heads/master HEAD
28c8d9f868eb9af98618407170da6a63c43e7f62 HEAD
git ls-remote --symref origin HEAD
ref: refs/heads/main HEAD
597b74a4a04c8741db1000901627745b65e5d69a HEAD
The problem with this way is: It takes a while to get this from remote, like (~ 2000ms
) so it's better
to create a cache file in the home directory (e.g. $HOME/.cache/git-substatus/cache.json
)
to make the process faster.
Example cache file:
{
"cache": [
{
"repository": "git-substatus",
"defaultBranch": "master",
"cacheTime": "1631264137"
},
{
"repository": "test",
"default-branch": "main",
"cacheTime": "1631264137"
}
]
}
The risk of caching is that the repository name isn't failproof as it may be replaced with another repository having the same name. That's why need to find a unique identifier for it?
The caching invalidation can happen every week (168h
) and on every time when git-substatus
is called with the --fetch
option.
TODO:
master
)Like --fetch
, add a --pull
flag to be able to pull the repos in batch.
It can be useful to check the git status of the multiple dirs.
git-substatus ~/dir1 ~/dir2
It's also good to check the multiple sub-dirs (but cannot check dirs and sub-dirs at the same time).
git-substatus ~/dir1 ~/dir2 --subdirs
Think a bit more about how dirs and subdirs should be printed on the terminal.
Extra use case:
If you git track the system folders like /etc
(via a tool like etckeeper
) or ~/.config
,
there can be a script written to get a git status of those folders such as:
system_git_status() {
git-substatus --subdirs=\
/etc, \
"${XDG_CONFIG_HOME:-~/.config}", \
"${XDG_DATA_HOME:-~/.local/share}" \
--include-hidden
}
When pressing tab, the CLI should autocomplete the available commands.
Resouces
https://stackoverflow.com/a/187660
https://kislyuk.github.io/argcomplete/
$HOME/.config/git-substatus/config.json
) for some options.If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME/.config should be used.
For example:
{
"styles": {
"repository": {
"color": "blue",
"emphasis": "bold"
},
"stash": {
"color": "green"
}
},
"components": {
"item_bullet": "•",
"display": {
"directory": true,
"branch": true,
"stash": false
}
}
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.