Two GitHub accounts on one Windows box, HTTPS only? Don't let `gh` be your git credential helper

If you run gh auth setup-git, the GitHub CLI becomes git's credential helper — and it only ever hands out the token for the active account. The moment you git pull a repo belonging to your other account, you get the wrong token (403, or commits land under the wrong identity). There's no per-repo routing; you'd have to gh auth switch every single time you cross accounts.

You can prove it to yourself — ask the helper for the non-active account and it returns nothing:

"protocol=https`nhost=github.com`nusername=second-account`n`n" |
  & gh auth git-credential get      # exit 1, no token

The fix is to hand git over to Git Credential Manager (it already ships with Git for Windows). GCM picks the token by the username embedded in the remote URL, so routing becomes automatic. gh keeps working for gh issue/gh pr — it uses its own keyring, separate from the git helper.

Switch the helper and point GCM at GitHub:

git config --global --unset-all credential.https://github.com.helper
git config --global credential.helper manager
git config --global credential.https://github.com.provider github
git config --global credential.guiPrompt false   # terminal prompts, no GUI popup on a server
…more

tmux Alt+z for pane zoom works better with Chinese IME

tmux's built-in pane zoom (Prefix+z) can be unreliable for users with Chinese input methods. The standalone z keystroke may be intercepted by the IME before tmux sees it, forcing you to switch to English mode first.

Bind Alt+z as a prefix-free shortcut instead:

bind -n M-z resize-pane -Z

M-z (Alt+z) is sent as a Meta key sequence directly to the terminal, which most input methods don't intercept. The same logic applies to navigation—add hjkl pane switching without the prefix:

bind -n M-h select-pane -L
bind -n M-j select-pane -D
bind -n M-k select-pane -U
bind -n M-l select-pane -R

This keeps tmus responsive regardless of your current input state.

网友语录 - 第83期 - 你努力回避的,正是你需要面对和反思的

这里记录我的一周分享,通常在周六或周日发布。


人生可能有的两次觉醒 第一次是弗洛伊德 你明白了,痛苦、自卑、讨好与不安,往往来自童年的匮乏与创伤。你从此不再责备自己。 第二次是阿德勒 你明白了,纵然过去塑造了现在的你,但真正决定自己将来的,是当下的选择。你不再抱怨命运与现实的不公,不再随波逐流,而开始有意识地审视自己的每一个决定。


爽朗君QvQ. 必须学会当面拒绝别人


iklein 你努力回避的,正是你需要面对和反思的。


…more

Show each tmux pane's working directory on its border (with ~ for $HOME)

When you split a window into several panes — say a dev/planner/reviewer layout — it's easy to lose track of which directory each one is actually in. tmux exposes pane_current_path, so you can paint the cwd right onto the pane's top border:

set -g pane-border-status top
set -g pane-border-format " #{pane_index}: #{pane_title} [#{pane_current_path}] "

Full paths get long and crowd out the title. Two ways to trim. #{b:...} gives just the basename (last component):

set -g pane-border-format " #{pane_index}: #{pane_title} [#{b:pane_current_path}] "

Or abbreviate $HOME to ~ with tmux's s/search/replace/ modifier. The neat trick is that the replacement is itself a format, so you can nest #{HOME} inside it — no hardcoded username, so the same dotfile works on every machine:

set -g pane-border-format " #{pane_index}: #{pane_title} [#{s|^#{HOME}|~|:pane_current_path}] "

s takes any delimiter after it; using | keeps the slashes in the path readable, and ^ anchors the match to the start so a directory that merely contains your home path elsewhere isn't touched. A pane in /home/you/Projects/foo now shows [~/Projects/foo].

tmux doesn't watch the config file — after editing, reload the running server with tmux source-file ~/.tmux.conf (or prefix then :source-file ~/.tmux.conf). Without that, only a fresh server start picks up the change.

One caveat worth knowing: pane_current_path is the cwd of the pane's foreground process, and tmux only updates it on chdir(2). A shell reflects it faithfully. But a long-running process that was started in one directory and then operates on files by absolute path — without ever cd-ing — won't move the border, because its cwd never changed. So the border shows the shell's real cwd, which isn't always where a process is "logically" working.

tmux `run-shell` eats your format strings — use `detach-on-destroy off` instead

A common pattern for "hop to another session before killing this one" looks like this:

bind Q run-shell 'next=$(tmux list-sessions -F "#{session_name}" 2>/dev/null \
  | grep -v "^#{session_name}$" | head -1); \
  if [ -n "$next" ]; then tmux switch-client -t "$next"; \
    tmux kill-session -t "#{session_name}"; \
  else tmux kill-session; fi'

It doesn't work. run-shell expands all #{...} format strings before handing the command to the shell. So list-sessions -F "#{session_name}" becomes list-sessions -F "mysession" — a literal string, not a format specifier. Every session prints "mysession", grep -v strips them all, $next is always empty, and you drop straight to bash.

The fix is one line:

set -g detach-on-destroy off
bind Q kill-session

detach-on-destroy off is a native tmux option: when a session is destroyed, the client automatically switches to another surviving session. It only falls back to exit when there's nothing left. No shell escaping, no format-string footguns, and it covers every exit path — not just prefix+Q.