<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: vast cow</title>
    <description>The latest articles on DEV Community by vast cow (@vast-cow).</description>
    <link>https://dev.to/vast-cow</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3717506%2F91ec5ce0-4f1b-458d-b9ad-d524e0befb41.png</url>
      <title>DEV Community: vast cow</title>
      <link>https://dev.to/vast-cow</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vast-cow"/>
    <language>en</language>
    <item>
      <title>Controlling CPU Fan Speed on Mac mini 5,2 with Ubuntu 24.04</title>
      <dc:creator>vast cow</dc:creator>
      <pubDate>Wed, 09 Sep 2026 01:54:03 +0000</pubDate>
      <link>https://dev.to/vast-cow/controlling-cpu-fan-speed-on-mac-mini-52-with-ubuntu-2404-5f0b</link>
      <guid>https://dev.to/vast-cow/controlling-cpu-fan-speed-on-mac-mini-52-with-ubuntu-2404-5f0b</guid>
      <description>&lt;p&gt;If you have a Mac mini 5,2 (Mid 2011) running Ubuntu 24.04, a convenient setup is to use &lt;strong&gt;&lt;code&gt;applesmc&lt;/code&gt; + &lt;code&gt;mbpfan&lt;/code&gt;&lt;/strong&gt;. &lt;code&gt;mbpfan 2.4.0&lt;/code&gt; is also included as a standard package in Ubuntu 24.04 (Noble). &lt;a href="https://packages.ubuntu.com/ja/source/noble/mbpfan?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Ubuntu Packages&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Linux &lt;code&gt;applesmc&lt;/code&gt; driver provides Intel Mac temperature sensors and fan control via sysfs. &lt;a href="https://github.com/torvalds/linux/blob/master/drivers/hwmon/Kconfig?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  1. First, check &lt;code&gt;applesmc&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;modprobe applesmc
&lt;span class="nb"&gt;sudo &lt;/span&gt;modprobe coretemp

lsmod | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'applesmc|coretemp'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, check the fan interface.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SMC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;find /sys/devices/platform &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 1 &lt;span class="nt"&gt;-type&lt;/span&gt; d &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'applesmc.*'&lt;/span&gt; &lt;span class="nt"&gt;-print&lt;/span&gt; &lt;span class="nt"&gt;-quit&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/fan&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, if you see something like this, you can control it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fan1_input
fan1_manual
fan1_max
fan1_min
fan1_output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be sure to check &lt;code&gt;fan1_min&lt;/code&gt; and &lt;code&gt;fan1_max&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_min"&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_max"&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_input"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The values will vary depending on the Mac, so it is safer &lt;strong&gt;not to assume values like 1800-5500 RPM&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Manually change the rotation speed
&lt;/h2&gt;

&lt;p&gt;You can first test it temporarily at, for example, 3000 RPM.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;1 | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_manual"&lt;/span&gt;
&lt;span class="nb"&gt;echo &lt;/span&gt;3000 | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_output"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Current actual rotation speed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_input"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a few seconds, it should be around 3000 RPM.&lt;/p&gt;

&lt;p&gt;On Intel Macs in Linux, the method of setting &lt;code&gt;fan1_manual=1&lt;/code&gt; and then writing the target RPM to &lt;code&gt;fan1_output&lt;/code&gt; is used. &lt;a href="https://askubuntu.com/questions/1413150/macmini-2010-with-ubuntu-22-04-temperature-problems-fan-control?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Ask Ubuntu&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Return to automatic control
&lt;/h3&gt;

&lt;p&gt;This is important.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;0 | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_manual"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you leave it in manual mode and fix it at a low rotation speed, the rotation speed will not increase even when the CPU/GPU load increases.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Recommended: Use &lt;code&gt;mbpfan&lt;/code&gt; to link to temperature
&lt;/h2&gt;

&lt;p&gt;On Ubuntu 24.04,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;mbpfan lm-sensors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Enable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; mbpfan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl status mbpfan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;mbpfan&lt;/code&gt; reads the CPU temperature from &lt;code&gt;coretemp&lt;/code&gt; and changes the fan speed via &lt;code&gt;applesmc&lt;/code&gt;. &lt;a href="https://github.com/linux-on-mac/mbpfan?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/mbpfan.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, for Mac mini 5,2, I would first try the following as a gentle setting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[general]&lt;/span&gt;

&lt;span class="py"&gt;low_temp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;55&lt;/span&gt;
&lt;span class="py"&gt;high_temp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;65&lt;/span&gt;
&lt;span class="py"&gt;max_temp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;80&lt;/span&gt;

&lt;span class="py"&gt;polling_interval&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the fan's min/max, &lt;code&gt;mbpfan&lt;/code&gt; can use the values reported by &lt;code&gt;applesmc&lt;/code&gt;. If you want to specify it explicitly,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_min"&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_max"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and then&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;min_fan1_speed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;2000&lt;/span&gt;
&lt;span class="py"&gt;max_fan1_speed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;5500&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set it using the &lt;strong&gt;actual values of your machine&lt;/strong&gt;. &lt;code&gt;mbpfan&lt;/code&gt;'s default setting also specifies that it refers to &lt;code&gt;/sys/devices/platform/applesmc.768/fan*_min&lt;/code&gt; and &lt;code&gt;fan*_max&lt;/code&gt;. &lt;a href="https://github.com/linux-on-mac/mbpfan/blob/master/mbpfan.conf?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After changing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart mbpfan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Monitor temperature and RPM in real time
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sensors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;watch &lt;span class="nt"&gt;-n&lt;/span&gt; 1 sensors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to see the fan RPM directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;watch &lt;span class="nt"&gt;-n&lt;/span&gt; 1 &lt;span class="s2"&gt;"cat &lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_input; sensors"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  macmini5,2 ubuntu24.04でcpuファンスピードをコントロールしたい
&lt;/h1&gt;

&lt;p&gt;Macmini5,2（Mid 2011）+ Ubuntu 24.04 なら、&lt;strong&gt;&lt;code&gt;applesmc&lt;/code&gt; + &lt;code&gt;mbpfan&lt;/code&gt;&lt;/strong&gt; が扱いやすい構成です。Ubuntu 24.04（Noble）にも &lt;code&gt;mbpfan 2.4.0&lt;/code&gt; が標準パッケージとしてあります。(&lt;a href="https://packages.ubuntu.com/ja/source/noble/mbpfan?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Ubuntu Packages&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Linux の &lt;code&gt;applesmc&lt;/code&gt; ドライバは Intel Mac の温度センサーとファン制御を sysfs 経由で提供しています。(&lt;a href="https://github.com/torvalds/linux/blob/master/drivers/hwmon/Kconfig?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  1. まず &lt;code&gt;applesmc&lt;/code&gt; を確認
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;modprobe applesmc
&lt;span class="nb"&gt;sudo &lt;/span&gt;modprobe coretemp

lsmod | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'applesmc|coretemp'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;次にファンのインターフェースを確認します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SMC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;find /sys/devices/platform &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 1 &lt;span class="nt"&gt;-type&lt;/span&gt; d &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'applesmc.*'&lt;/span&gt; &lt;span class="nt"&gt;-print&lt;/span&gt; &lt;span class="nt"&gt;-quit&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/fan&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;例えば、以下のようなものが出れば制御できます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;fan1_input
fan1_manual
fan1_max
fan1_min
fan1_output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;fan1_min&lt;/code&gt; と &lt;code&gt;fan1_max&lt;/code&gt; を必ず確認してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_min"&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_max"&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_input"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mac によって値は違うので、&lt;strong&gt;1800～5500 RPM などと決め打ちしない方が安全&lt;/strong&gt;です。&lt;/p&gt;




&lt;h2&gt;
  
  
  2. 手動で回転数を変更する
&lt;/h2&gt;

&lt;p&gt;まず一時的に 3000 RPM などでテストできます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;1 | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_manual"&lt;/span&gt;
&lt;span class="nb"&gt;echo &lt;/span&gt;3000 | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_output"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;現在の実回転数：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_input"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;数秒すると 3000 RPM 前後になっているはずです。&lt;/p&gt;

&lt;p&gt;Linux 上の Intel Mac では、&lt;code&gt;fan1_manual=1&lt;/code&gt; にしてから &lt;code&gt;fan1_output&lt;/code&gt; に目標RPMを書く方法が使われています。(&lt;a href="https://askubuntu.com/questions/1413150/macmini-2010-with-ubuntu-22-04-temperature-problems-fan-control?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Ask Ubuntu&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  自動制御に戻す
&lt;/h3&gt;

&lt;p&gt;これは重要です。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;0 | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_manual"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;手動モードのまま低回転に固定すると、CPU/GPU負荷が上がっても回転数が上がらなくなります。&lt;/p&gt;




&lt;h2&gt;
  
  
  3. おすすめ：&lt;code&gt;mbpfan&lt;/code&gt; で温度連動
&lt;/h2&gt;

&lt;p&gt;Ubuntu 24.04 なら、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;mbpfan lm-sensors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;有効化：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; mbpfan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;状態確認：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl status mbpfan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;mbpfan&lt;/code&gt; は &lt;code&gt;coretemp&lt;/code&gt; からCPU温度を読み、&lt;code&gt;applesmc&lt;/code&gt; 経由でファン速度を変更します。(&lt;a href="https://github.com/linux-on-mac/mbpfan?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;設定は：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nano /etc/mbpfan.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;例えば私は Macmini5,2 なら、まず穏当な設定として次のあたりから試します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[general]&lt;/span&gt;

&lt;span class="py"&gt;low_temp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;55&lt;/span&gt;
&lt;span class="py"&gt;high_temp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;65&lt;/span&gt;
&lt;span class="py"&gt;max_temp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;80&lt;/span&gt;

&lt;span class="py"&gt;polling_interval&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ファンの min/max は &lt;code&gt;applesmc&lt;/code&gt; が報告する値を &lt;code&gt;mbpfan&lt;/code&gt; が利用できます。明示的に設定したい場合は、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_min"&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_max"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を確認してから、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="py"&gt;min_fan1_speed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;2000&lt;/span&gt;
&lt;span class="py"&gt;max_fan1_speed&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;5500&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のように&lt;strong&gt;実機の値を使って&lt;/strong&gt;設定します。&lt;code&gt;mbpfan&lt;/code&gt; の標準設定も &lt;code&gt;/sys/devices/platform/applesmc.768/fan*_min&lt;/code&gt; と &lt;code&gt;fan*_max&lt;/code&gt; を参照する仕様です。(&lt;a href="https://github.com/linux-on-mac/mbpfan/blob/master/mbpfan.conf?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;変更後：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl restart mbpfan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. 温度とRPMをリアルタイム監視
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sensors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;または、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;watch &lt;span class="nt"&gt;-n&lt;/span&gt; 1 sensors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ファンRPMも直接見たいなら：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;watch &lt;span class="nt"&gt;-n&lt;/span&gt; 1 &lt;span class="s2"&gt;"cat &lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;/fan1_input; sensors"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Macmini5,2 なら私ならこうします
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;常用は &lt;code&gt;mbpfan&lt;/code&gt;、手動の &lt;code&gt;fan1_output&lt;/code&gt; は動作確認用&lt;/strong&gt;にします。&lt;/p&gt;

&lt;p&gt;最初に、次の結果を貼ってもらえれば、Macmini5,2 の実機値に合わせて &lt;code&gt;/etc/mbpfan.conf&lt;/code&gt; を具体的に作れます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt;
lsmod | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-E&lt;/span&gt; &lt;span class="s1"&gt;'applesmc|coretemp'&lt;/span&gt;
&lt;span class="nv"&gt;SMC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;find /sys/devices/platform &lt;span class="nt"&gt;-maxdepth&lt;/span&gt; 1 &lt;span class="nt"&gt;-type&lt;/span&gt; d &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'applesmc.*'&lt;/span&gt; &lt;span class="nt"&gt;-print&lt;/span&gt; &lt;span class="nt"&gt;-quit&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;for &lt;/span&gt;f &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SMC&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;/fan&lt;span class="k"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt; = "&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$f&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;done
&lt;/span&gt;sensors
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;特に &lt;strong&gt;&lt;code&gt;fan1_min&lt;/code&gt; / &lt;code&gt;fan1_max&lt;/code&gt; とアイドル時・負荷時CPU温度&lt;/strong&gt;が分かれば、「静音寄り」「冷却寄り」のファンカーブを決められます。&lt;/p&gt;

</description>
      <category>hardware</category>
      <category>linux</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Checking if a Used Core i7-6700 is Genuine Without Benchmarks</title>
      <dc:creator>vast cow</dc:creator>
      <pubDate>Fri, 04 Sep 2026 04:07:06 +0000</pubDate>
      <link>https://dev.to/vast-cow/checking-if-a-used-core-i7-6700-is-genuine-without-benchmarks-41hb</link>
      <guid>https://dev.to/vast-cow/checking-if-a-used-core-i7-6700-is-genuine-without-benchmarks-41hb</guid>
      <description>&lt;p&gt;When purchasing a used Intel CPU, you might wonder if the heat spreader has been swapped with another CPU or if it's a fake with a modified model number.&lt;/p&gt;

&lt;p&gt;This time, using an actual &lt;strong&gt;Intel Core i7-6700&lt;/strong&gt; as an example, we'll try to determine how much we can verify its authenticity without using performance measurements, by checking:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Heat spreader markings&lt;/li&gt;
&lt;li&gt;  S-Spec&lt;/li&gt;
&lt;li&gt;  FPO (Batch Number)&lt;/li&gt;
&lt;li&gt;  ATPO (Serial Number)&lt;/li&gt;
&lt;li&gt;  Data Matrix&lt;/li&gt;
&lt;li&gt;  Partial ATPO&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Core i7-6700 We're Checking
&lt;/h2&gt;

&lt;p&gt;The CPU surface has the following markings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;i7-6700
SR2L2 3.40GHZ
X012C345 (e4)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, let's clarify what each of these means.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Display&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;i7-6700&lt;/td&gt;
&lt;td&gt;CPU model name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SR2L2&lt;/td&gt;
&lt;td&gt;S-Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.40GHZ&lt;/td&gt;
&lt;td&gt;Base clock speed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X012C345&lt;/td&gt;
&lt;td&gt;FPO (Batch Number)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(e4)&lt;/td&gt;
&lt;td&gt;Not ATPO&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;According to Intel's official information, the Core i7-6700 has an S-Spec of &lt;code&gt;SR2L2&lt;/code&gt; and an R0 stepping. Also, the i7-6700 has a base clock speed of 3.40GHz.&lt;/p&gt;

&lt;p&gt;Therefore, there are no inconsistencies in the markings on the surface so far.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is FPO?
&lt;/h2&gt;

&lt;p&gt;FPO stands for "Finished Process Order," and Intel treats it as the Batch Number.&lt;/p&gt;

&lt;p&gt;In this CPU,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;X012C345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is the FPO.&lt;/p&gt;

&lt;p&gt;The FPO is located on the heat spreader.&lt;/p&gt;

&lt;p&gt;Importantly, it is different from &lt;code&gt;SR2L2&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SR2L2    → S-Spec
X012C345 → FPO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even in Intel's Warranty Information, the FPO is entered as the "Batch number."&lt;/p&gt;

&lt;h2&gt;
  
  
  What is ATPO?
&lt;/h2&gt;

&lt;p&gt;ATPO stands for "Assembly Test Process Order," and it is treated as the CPU's Serial Number.&lt;/p&gt;

&lt;p&gt;While the FPO is a batch number, the ATPO is a number to identify each individual processor.&lt;/p&gt;

&lt;p&gt;Intel CPUs have a very small &lt;strong&gt;2D Matrix&lt;/strong&gt; on the outer edge of the substrate.&lt;/p&gt;

&lt;p&gt;Decoding this 2D Matrix allows you to obtain the Full ATPO (complete serial number).&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading a 2D Matrix with a Smartphone
&lt;/h2&gt;

&lt;p&gt;This time, I was able to read the code using the "Code Scan - QR &amp;amp; Barcode Scanner" app from the App Store on my iPhone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apps.apple.com/jp/app/code-scan-qr-barcode-scanner/id1554812545" rel="noopener noreferrer"&gt;https://apps.apple.com/jp/app/code-scan-qr-barcode-scanner/id1554812545&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because the Intel CPU code is very small, it may not be recognized properly by a regular QR code reader. Intel also states that you can read the 2D Matrix using a compatible app that utilizes your smartphone's camera.&lt;/p&gt;

&lt;p&gt;When reading, it helps to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Clean the surface of the CPU to remove any dirt.&lt;/li&gt;
&lt;li&gt;  Take the picture in a well-lit area.&lt;/li&gt;
&lt;li&gt;  If there is reflection, shine a light on it from an angle.&lt;/li&gt;
&lt;li&gt;  Focus on the code.&lt;/li&gt;
&lt;li&gt;  If necessary, use macro photography.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Cover the parts other than the 2D Matrix with dark paper or objects to increase the contrast between the code and the board.&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This will increase the chances of success.&lt;/p&gt;

&lt;p&gt;In particular, in the tests I conducted, &lt;strong&gt;covering the parts other than the code with something dark and making the 2D Matrix stand out made it easier to recognize.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The CPU board has characters, wiring patterns, and metal parts, so when viewed from the camera, there are many fine patterns in addition to the 2D Matrix. Therefore, the method of covering the surroundings to hide them and making only the code you want to read stand out is worth trying when the scan is unstable.&lt;/p&gt;

&lt;p&gt;With this i7-6700, I scanned it with my iPhone using this method as well, and the app gave me the following result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;U6SG012345678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What you need is the &lt;code&gt;Content&lt;/code&gt; side.&lt;/p&gt;

&lt;p&gt;Therefore, the Full ATPO of this CPU is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;U6SG012345678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that &lt;code&gt;Hex&lt;/code&gt; is not a different serial number.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;55 → U
36 → 6
53 → S
47 → G
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is a hexadecimal representation of the characters in the Content string.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding the Partial ATPO
&lt;/h2&gt;

&lt;p&gt;Next, carefully examine the outer edge of the CPU substrate.&lt;/p&gt;

&lt;p&gt;On this CPU, a very small string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;45678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;was printed.&lt;/p&gt;

&lt;p&gt;This is the Partial ATPO.&lt;/p&gt;

&lt;p&gt;According to Intel, the Partial ATPO is the last 3-5 characters of the Full ATPO.&lt;/p&gt;

&lt;p&gt;Therefore, compare it with the Full ATPO read from the Data Matrix earlier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Full ATPO
U6SG012345678
        ↓↓↓↓↓
        45678

Partial ATPO on the substrate
45678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The last 5 characters matched perfectly.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is an important checkpoint.&lt;/p&gt;

&lt;p&gt;Intel also advises, as a procedure for checking counterfeit CPUs, to read the Full ATPO from the 2D Matrix and compare the last 5 characters with the Partial ATPO printed on the outer edge of the CPU. If it is genuine, they should match.&lt;/p&gt;

&lt;p&gt;Therefore, in this CPU:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Data Matrix
     ↓
U6SG012345678
        ↓
      45678
        ↑
"45678" on the substrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This correspondence was confirmed.&lt;/p&gt;

&lt;p&gt;At least, the &lt;strong&gt;Data Matrix on the substrate and the Partial ATPO that humans can read are correctly matched.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Can the Heat Spreader and Substrate be Directly Matched?
&lt;/h2&gt;

&lt;p&gt;This is the part I was particularly concerned about while researching.&lt;/p&gt;

&lt;p&gt;On the heat spreader side, there is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;i7-6700
SR2L2
X012C345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the other hand, on the substrate side, there is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Full ATPO:
U6SG012345678

Partial ATPO:
45678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In summary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Heat Spreader]
i7-6700
SR2L2
FPO: X012C345
       │
       │ ← This is what I wanted to confirm
       │
[CPU Substrate]
Full ATPO: U6SG012345678
Partial ATPO: 45678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Regarding Full ATPO and Partial ATPO:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;U6SG012345678
        ↓↓↓↓↓
        45678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can be physically confirmed.&lt;/p&gt;

&lt;p&gt;However, there is no publicly available rule that users can use to calculate and confirm the relationship between:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FPO X012C345
      ↕
ATPO U6SG012345678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you can successfully search Intel's Warranty Information, you can confirm the combination of FPO and ATPO, but in this i7-6700, no search results were found.&lt;/p&gt;

&lt;p&gt;Therefore, &lt;strong&gt;I could not completely confirm that the heat spreader was originally attached to this substrate at the factory.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Check for "A Fake with an i7-6700 Heat Spreader Placed on a Different CPU"?
&lt;/h2&gt;

&lt;p&gt;For example, consider the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Different CPU substrate
   ＋
Heat spreader labeled i7-6700
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a form of forgery.&lt;/p&gt;

&lt;p&gt;In this case, it will look like an i7-6700 just by looking at the surface.&lt;/p&gt;

&lt;p&gt;In this case, what is effective is the identification information inside the CPU.&lt;/p&gt;

&lt;p&gt;Intel also advises that if you can install the CPU in a PC, use the &lt;strong&gt;Intel Processor Diagnostic Tool&lt;/strong&gt; to check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Genuine Intel: Pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and that the product name matches.&lt;/p&gt;

&lt;p&gt;Furthermore, with CPU-Z and HWiNFO, check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  Core i7-6700&lt;/li&gt;
&lt;li&gt;  Skylake&lt;/li&gt;
&lt;li&gt;  4 cores, 8 threads&lt;/li&gt;
&lt;li&gt;  8MB L3&lt;/li&gt;
&lt;li&gt;  R0 stepping&lt;/li&gt;
&lt;li&gt;  CPUID is consistent with Skylake&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you check these, it will be much easier to detect a simple forgery where "the heat spreader says i7-6700, but the inside is a different CPU."&lt;/p&gt;

&lt;p&gt;This is different from comparing benchmark scores; it's a method of checking the identification information returned by the CPU itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results This Time
&lt;/h2&gt;

&lt;p&gt;In this Core i7-6700:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;i7-6700 is printed on the surface&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S-Spec &lt;code&gt;SR2L2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Matches Intel's official information&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.40GHZ&lt;/td&gt;
&lt;td&gt;Matches Intel's specifications&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FPO &lt;code&gt;X012C345&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Confirmed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2D Matrix&lt;/td&gt;
&lt;td&gt;Successfully read&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full ATPO&lt;/td&gt;
&lt;td&gt;Successfully obtained&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Partial ATPO&lt;/td&gt;
&lt;td&gt;&lt;code&gt;45678&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full ATPO ending&lt;/td&gt;
&lt;td&gt;&lt;code&gt;45678&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full/Partial ATPO&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5 characters match perfectly&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warranty Information&lt;/td&gt;
&lt;td&gt;Could not find the product&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FPO and ATPO Intel DB check&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Unconfirmed&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Therefore, within the scope that we could confirm this time, &lt;strong&gt;no information contradicting the fact that it is a genuine Core i7-6700 was found.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In particular,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The last 5 characters of the Full ATPO obtained from the Data Matrix and the Partial ATPO printed directly on the substrate matched.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is a strong piece of evidence.&lt;/p&gt;

&lt;p&gt;However, since the combination of FPO and ATPO could not be confirmed in Intel's Warranty Information,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We could not completely confirm that the heat spreader and substrate were originally a set from the factory.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary of How to Check a Used Intel CPU
&lt;/h2&gt;

&lt;p&gt;If you want to check without using performance measurements, the following order is practical:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;① Check the model number on the CPU surface
        ↓
② Compare the S-Spec with Intel's official information
        ↓
③ Record the FPO
        ↓
④ Scan the 2D Matrix on the outer edge of the substrate
        ↓
⑤ Obtain the Full ATPO
        ↓
⑥ Find the Partial ATPO on the substrate
        ↓
⑦ Compare with the last 3-5 characters of the Full ATPO
        ↓
⑧ Enter the FPO + ATPO in Intel Warranty Information
        ↓
⑨ If you can install it in a PC, use the
   Intel Processor Diagnostic Tool to check
   for Genuine Intel and the product name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In particular, ④-⑦ can be checked without running the CPU.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caution: It's Best Not to Publish the ATPO
&lt;/h2&gt;

&lt;p&gt;The ATPO is the CPU's Serial Number.&lt;/p&gt;

&lt;p&gt;When publishing photos on blogs or flea market sites, it is best to hide part of it, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;U6SG0123*****
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, since it may be possible to read the Full ATPO from the code even if you hide the 2D Matrix itself, it is safe to &lt;strong&gt;put a mosaic on the 2D Matrix as well.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Intel CPUs have multiple identification pieces of information, not just "Core i7" written on them:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;S-Spec → FPO → Data Matrix → Full ATPO → Partial ATPO&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In this i7-6700, we were able to confirm up to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SR2L2
FPO: X012C345
Full ATPO: U6SG0123*****
Partial ATPO: 45678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the correspondence between Full ATPO and Partial ATPO was also confirmed.&lt;/p&gt;

&lt;p&gt;When checking the authenticity of a used CPU, it is useful to use not only benchmark results but also &lt;strong&gt;this method of cross-checking physical traceability information.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;However, this does not cryptographically prove the authenticity of the semiconductor. In particular, with older CPUs, search results may not be found in Intel's current Warranty search, so it is practical to combine:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Physical marking consistency + ATPO consistency + identification information inside the CPU&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;to make a judgment.&lt;/p&gt;

&lt;h1&gt;
  
  
  中古のCore i7-6700が本物か、ベンチマークを使わずに確認してみた
&lt;/h1&gt;

&lt;p&gt;中古でIntel CPUを入手したとき、「ヒートスプレッダだけ別のCPUに交換されていないか」「型番を書き換えた偽物ではないか」が気になることがあります。&lt;/p&gt;

&lt;p&gt;今回は実際の&lt;strong&gt;Intel Core i7-6700&lt;/strong&gt;を例に、性能測定を使わず、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ヒートスプレッダの刻印&lt;/li&gt;
&lt;li&gt;S-Spec&lt;/li&gt;
&lt;li&gt;FPO（Batch Number）&lt;/li&gt;
&lt;li&gt;ATPO（Serial Number）&lt;/li&gt;
&lt;li&gt;Data Matrix&lt;/li&gt;
&lt;li&gt;Partial ATPO&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;を使って、どこまで真贋を確認できるのか試してみました。&lt;/p&gt;

&lt;h2&gt;
  
  
  今回確認するCore i7-6700
&lt;/h2&gt;

&lt;p&gt;CPU表面には次のように刻印されています。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;i7-6700
SR2L2 3.40GHZ
X012C345 (e4)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;まず、それぞれの意味を整理します。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;表示&lt;/th&gt;
&lt;th&gt;意味&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;i7-6700&lt;/td&gt;
&lt;td&gt;CPUの製品名&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SR2L2&lt;/td&gt;
&lt;td&gt;S-Spec&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.40GHZ&lt;/td&gt;
&lt;td&gt;ベースクロック&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;X012C345&lt;/td&gt;
&lt;td&gt;FPO（Batch Number）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(e4)&lt;/td&gt;
&lt;td&gt;ATPOではない&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Intel公式情報でも、Core i7-6700の製品版にはS-Spec &lt;code&gt;SR2L2&lt;/code&gt;、R0ステッピングが存在します。また、i7-6700のベースクロックは3.40GHzです。&lt;/p&gt;

&lt;p&gt;したがって、ここまでの表面刻印には矛盾がありません。&lt;/p&gt;

&lt;h2&gt;
  
  
  FPOとは？
&lt;/h2&gt;

&lt;p&gt;FPOは「Finished Process Order」の略で、IntelではBatch Numberとして扱われています。&lt;/p&gt;

&lt;p&gt;今回のCPUでは、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;X012C345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;がFPOだとします。&lt;/p&gt;

&lt;p&gt;FPOはヒートスプレッダ上にあります。&lt;/p&gt;

&lt;p&gt;ここで重要なのは、&lt;code&gt;SR2L2&lt;/code&gt;とは別物ということです。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SR2L2    → S-Spec
X012C345 → FPO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;IntelのWarranty InformationでもFPOは「Batch number」として入力します。&lt;/p&gt;

&lt;h2&gt;
  
  
  ATPOとは？
&lt;/h2&gt;

&lt;p&gt;ATPOは「Assembly Test Process Order」の略で、CPUのSerial Numberとして扱われています。&lt;/p&gt;

&lt;p&gt;FPOがバッチ番号なのに対して、ATPOは個々のプロセッサを識別するための番号です。&lt;/p&gt;

&lt;p&gt;Intel CPUでは、基板外周に非常に小さな&lt;strong&gt;2D Matrix&lt;/strong&gt;があります。&lt;/p&gt;

&lt;p&gt;この2D Matrixをデコードすると、Full ATPO（完全なシリアル番号）を取得できます。&lt;/p&gt;

&lt;h2&gt;
  
  
  2D Matrixをスマートフォンで読み取る
&lt;/h2&gt;

&lt;p&gt;今回、iPhoneではApp Storeの「Code Scan - QR &amp;amp; Barcode Scanner」を使用すると読み取ることができました。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://apps.apple.com/jp/app/code-scan-qr-barcode-scanner/id1554812545" rel="noopener noreferrer"&gt;https://apps.apple.com/jp/app/code-scan-qr-barcode-scanner/id1554812545&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Intel CPUのコードは非常に小さいため、通常のQRコードリーダーではうまく認識されない場合があります。Intelも、スマートフォンのカメラを利用する対応アプリで2D Matrixを読み取れると案内しています。&lt;/p&gt;

&lt;p&gt;読み取り時は、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CPU表面の汚れを落とす&lt;/li&gt;
&lt;li&gt;明るい場所で撮影する&lt;/li&gt;
&lt;li&gt;反射する場合は光を斜めから当てる&lt;/li&gt;
&lt;li&gt;コードにピントを合わせる&lt;/li&gt;
&lt;li&gt;必要ならマクロ撮影する&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;2D Matrix以外の部分を暗めの紙や物で隠し、コード部分と基板とのコントラストを高くする&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;と成功しやすくなります。&lt;/p&gt;

&lt;p&gt;特に今回試した範囲では、&lt;strong&gt;コード以外の部分を暗いもので覆い、2D Matrixだけが目立つ状態にすると認識しやすくなりました。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;CPU基板には文字や配線パターン、金属部分などがあり、カメラから見ると2D Matrix以外にも細かな模様が多数存在します。そのため、周囲を暗く隠して読み取らせたいコードだけを目立たせる方法は、スキャンが安定しない場合に試す価値があります。&lt;/p&gt;

&lt;p&gt;今回のi7-6700では、この方法も併用しながらiPhoneでスキャンしたところ、アプリから次のような結果が得られました。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;U6SG012345678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;必要なのは&lt;code&gt;Content&lt;/code&gt;側です。&lt;/p&gt;

&lt;p&gt;したがって、このCPUのFull ATPOは、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;U6SG012345678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;となります。&lt;/p&gt;

&lt;p&gt;なお、&lt;code&gt;Hex&lt;/code&gt;は別のシリアル番号ではありません。&lt;/p&gt;

&lt;p&gt;例えば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;55 → U
36 → 6
53 → S
47 → G
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;というように、Contentの文字列を16進数で表現したものです。&lt;/p&gt;

&lt;h2&gt;
  
  
  Partial ATPOを探す
&lt;/h2&gt;

&lt;p&gt;次に、CPU基板の外周をよく確認します。&lt;/p&gt;

&lt;p&gt;今回のCPUには、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;45678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という非常に小さな文字が印刷されていました。&lt;/p&gt;

&lt;p&gt;これがPartial ATPOです。&lt;/p&gt;

&lt;p&gt;IntelによるとPartial ATPOは、Full ATPOの末尾3～5文字です。&lt;/p&gt;

&lt;p&gt;そこで先ほどData Matrixから読み取ったFull ATPOと比較します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Full ATPO
U6SG012345678
        ↓↓↓↓↓
        45678

基板上のPartial ATPO
45678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;末尾5文字が完全に一致しました。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;これは重要なチェックポイントです。&lt;/p&gt;

&lt;p&gt;Intel自身も偽造CPUを確認する手順として、2D MatrixからFull ATPOを読み取り、その末尾5文字とCPU外周に印刷されたPartial ATPOを比較し、正規品なら一致することを確認するよう案内しています。&lt;/p&gt;

&lt;p&gt;つまり今回のCPUでは、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Data Matrix
     ↓
U6SG012345678
        ↓
      45678
        ↑
基板上の「45678」
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という対応が確認できました。&lt;/p&gt;

&lt;p&gt;少なくとも、&lt;strong&gt;基板上のData Matrixと人間が読めるPartial ATPOは正しく対応しています。&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ヒートスプレッダと基板は直接照合できるのか？
&lt;/h2&gt;

&lt;p&gt;ここが今回調べていて特に気になった部分です。&lt;/p&gt;

&lt;p&gt;ヒートスプレッダ側には、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;i7-6700
SR2L2
X012C345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;があります。&lt;/p&gt;

&lt;p&gt;一方、基板側には、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Full ATPO:
U6SG012345678

Partial ATPO:
45678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;があります。&lt;/p&gt;

&lt;p&gt;整理すると、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;【ヒートスプレッダ】
i7-6700
SR2L2
FPO: X012C345
       │
       │ ← 本来この対応を確認したい
       │
【CPU基板】
Full ATPO: U6SG012345678
Partial ATPO: 45678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という構造です。&lt;/p&gt;

&lt;p&gt;Full ATPOとPartial ATPOについては、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;U6SG012345678
        ↓↓↓↓↓
        45678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;と物理的に確認できます。&lt;/p&gt;

&lt;p&gt;しかし、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FPO X012C345
      ↕
ATPO U6SG012345678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;について、ユーザーが番号から計算して確認できる公開された規則は見当たりません。&lt;/p&gt;

&lt;p&gt;IntelのWarranty Informationが正常に検索できれば、FPOとATPOを組み合わせて確認できますが、今回のi7-6700では検索結果が得られませんでした。&lt;/p&gt;

&lt;p&gt;そのため、&lt;strong&gt;ヒートスプレッダが本当にこの基板に元々取り付けられていたものなのかを、刻印だけで100％証明するところまでは到達できませんでした。&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  「別CPUにi7-6700のヒートスプレッダを載せた偽物」はどう確認する？
&lt;/h2&gt;

&lt;p&gt;例えば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;別のCPU基板
   ＋
i7-6700と書かれたヒートスプレッダ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という偽装を考えます。&lt;/p&gt;

&lt;p&gt;この場合、表面を見るだけではi7-6700に見えてしまいます。&lt;/p&gt;

&lt;p&gt;そこで有効なのがCPU内部の識別情報です。&lt;/p&gt;

&lt;p&gt;Intel自身も、CPUをPCに搭載できる場合は&lt;strong&gt;Intel Processor Diagnostic Tool&lt;/strong&gt;を使用し、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Genuine Intel: Pass
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;となること、および製品名が一致することを確認する方法を案内しています。&lt;/p&gt;

&lt;p&gt;さらにCPU-ZやHWiNFOなどで、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Core i7-6700&lt;/li&gt;
&lt;li&gt;Skylake&lt;/li&gt;
&lt;li&gt;4コア8スレッド&lt;/li&gt;
&lt;li&gt;8MB L3&lt;/li&gt;
&lt;li&gt;R0ステッピング&lt;/li&gt;
&lt;li&gt;CPUIDがSkylakeとして整合&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;などを確認すれば、「ヒートスプレッダにはi7-6700と書いてあるが、中身は別CPU」という単純な偽装はかなり見抜きやすくなります。&lt;/p&gt;

&lt;p&gt;これはベンチマークのスコア比較とは異なり、CPU自身が返す識別情報を確認する方法です。&lt;/p&gt;

&lt;h2&gt;
  
  
  今回の結果
&lt;/h2&gt;

&lt;p&gt;今回のCore i7-6700では、&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;チェック&lt;/th&gt;
&lt;th&gt;結果&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;表面にi7-6700と刻印&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;S-Spec &lt;code&gt;SR2L2&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Intel公式情報と一致&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.40GHz&lt;/td&gt;
&lt;td&gt;Intel公式仕様と一致&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FPO &lt;code&gt;X012C345&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;確認&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2D Matrix&lt;/td&gt;
&lt;td&gt;読み取り成功&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full ATPO&lt;/td&gt;
&lt;td&gt;取得成功&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Partial ATPO&lt;/td&gt;
&lt;td&gt;&lt;code&gt;45678&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full ATPO末尾&lt;/td&gt;
&lt;td&gt;&lt;code&gt;45678&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full/Partial ATPO&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5文字完全一致&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warranty Information&lt;/td&gt;
&lt;td&gt;製品を発見できず&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FPOとATPOのIntel DB照合&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;未確認&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;したがって、今回確認できた範囲では、&lt;strong&gt;正規のCore i7-6700と矛盾する情報は見つかりませんでした。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;特に、&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Matrixから取得したFull ATPOの末尾5文字と、基板に直接印刷されたPartial ATPOが一致した&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ことは強い確認材料です。&lt;/p&gt;

&lt;p&gt;ただし、Intel Warranty InformationでFPOとATPOの組み合わせを確認できなかったため、&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;「ヒートスプレッダと基板が工場出荷時から同じ組み合わせだった」ことまで完全に証明できたわけではありません。&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  中古Intel CPUを確認するときの手順まとめ
&lt;/h2&gt;

&lt;p&gt;性能測定を使わず確認するなら、次の順番が実用的だと思います。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;① CPU表面の型番を確認
        ↓
② S-SpecをIntel公式情報と照合
        ↓
③ FPOを記録
        ↓
④ 基板外周の2D Matrixをスキャン
        ↓
⑤ Full ATPOを取得
        ↓
⑥ 基板上のPartial ATPOを探す
        ↓
⑦ Full ATPO末尾3～5文字と比較
        ↓
⑧ Intel Warranty Informationに
   FPO + ATPOを入力
        ↓
⑨ PCに搭載できるなら
   Intel Processor Diagnostic Toolで
   Genuine Intelと製品名を確認
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;特に④～⑦は、CPUを動作させなくても確認できます。&lt;/p&gt;

&lt;h2&gt;
  
  
  注意：ATPOは公開しない方がよい
&lt;/h2&gt;

&lt;p&gt;ATPOはCPUのSerial Numberです。&lt;/p&gt;

&lt;p&gt;ブログやフリマサイトなどで写真を公開する場合は、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;U6SG0123*****
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のように一部を隠しておいた方がよいでしょう。&lt;/p&gt;

&lt;p&gt;Data Matrixそのものを鮮明な写真で公開すると、文字を隠していてもコードからFull ATPOを読み取れる可能性があるため、&lt;strong&gt;Data Matrixにもモザイクをかける&lt;/strong&gt;のが安全です。&lt;/p&gt;

&lt;h2&gt;
  
  
  まとめ
&lt;/h2&gt;

&lt;p&gt;Intel CPUには、単に「Core i7」と書かれているだけではなく、&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;S-Spec → FPO → Data Matrix → Full ATPO → Partial ATPO&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;という複数の識別情報があります。&lt;/p&gt;

&lt;p&gt;今回のi7-6700では、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SR2L2
FPO: X012C345
Full ATPO: U6SG0123*****
Partial ATPO: 45678
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;まで確認でき、Full ATPOとPartial ATPOの対応も確認できました。&lt;/p&gt;

&lt;p&gt;中古CPUの真贋確認ではベンチマーク結果だけを見るのではなく、こうした&lt;strong&gt;物理的なトレーサビリティ情報を相互照合する方法も有効&lt;/strong&gt;です。&lt;/p&gt;

&lt;p&gt;ただし、これだけで半導体の真正性を暗号学的に証明できるわけではありません。特に古いCPUではIntelの現行Warranty検索で結果が得られない場合もあるため、&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;物理刻印の整合性 + ATPOの整合性 + CPU内部の識別情報&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;を組み合わせて判断するのが現実的です。&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Remove Specific Files from Git Commit History</title>
      <dc:creator>vast cow</dc:creator>
      <pubDate>Tue, 01 Sep 2026 05:52:58 +0000</pubDate>
      <link>https://dev.to/vast-cow/how-to-remove-specific-files-from-git-commit-history-13b8</link>
      <guid>https://dev.to/vast-cow/how-to-remove-specific-files-from-git-commit-history-13b8</guid>
      <description>&lt;p&gt;When working with Git, you might encounter a situation where you want to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Make it as if this file was never committed in the first place."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you simply delete the file from the current branch, you can use &lt;code&gt;git rm&lt;/code&gt; and commit. However, this only removes the file from the current state; it remains in the past commit history.&lt;/p&gt;

&lt;p&gt;This article introduces a method using &lt;strong&gt;interactive rebase (&lt;code&gt;git rebase --committer-date-is-author-date　-i&lt;/code&gt;) to remove changes related to a specific file from past commits.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Please note that this method rewrites the commit history. Be cautious when using it on branches that have already been pushed to a remote repository or are shared among multiple people.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Find the Commits Related to the Target File
&lt;/h2&gt;

&lt;p&gt;First, identify the commits in which the file you want to remove was added or modified.&lt;/p&gt;

&lt;p&gt;If you know the file path, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--oneline&lt;/span&gt; &lt;span class="nt"&gt;--name-status&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; path/to/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't know the exact name or path of the target file, you can check the commits and the files that were changed together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--oneline&lt;/span&gt; &lt;span class="nt"&gt;--name-status&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important thing here is the status displayed on the left side of the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A    path/to/file
M    path/to/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You mainly need to check the following two:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;A&lt;/code&gt;: The file was newly added.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;M&lt;/code&gt;: An existing file was modified.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The approach will differ depending on this distinction.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Rebase from the Oldest Commit Related to the Target File
&lt;/h2&gt;

&lt;p&gt;After identifying the commits related to the target file, find the &lt;strong&gt;oldest commit&lt;/strong&gt; among them.&lt;/p&gt;

&lt;p&gt;If that commit is &lt;code&gt;earliest_commit_id&lt;/code&gt;, start the interactive rebase as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;--committer-date-is-author-date&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;oldest_commit_id&lt;span class="o"&gt;}&lt;/span&gt;^
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;^&lt;/code&gt; is added to include the target commit itself in the rebase range.&lt;/p&gt;

&lt;p&gt;For example, if the oldest commit is &lt;code&gt;abc1234&lt;/code&gt;, then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;--committer-date-is-author-date&lt;/span&gt;　-i abc1234^
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Change the Target Commit to &lt;code&gt;drop&lt;/code&gt; or &lt;code&gt;edit&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;When you run the command, an editor will open and display the list of commits.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick abc1234 add config
pick def5678 update config
pick ghi9012 implement feature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From here, you will modify the commits related to the target file.&lt;/p&gt;

&lt;h3&gt;
  
  
  If the Commit Only Changes That File
&lt;/h3&gt;

&lt;p&gt;Since the commit itself is unnecessary, change &lt;code&gt;pick&lt;/code&gt; to &lt;code&gt;drop&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;drop abc1234 add config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will remove the commit itself from the history.&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;do not use &lt;code&gt;drop&lt;/code&gt; if the commit contains changes you want to keep.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  If the Commit Includes Changes to Other Files
&lt;/h3&gt;

&lt;p&gt;Since you want to keep the changes to other files, you cannot delete the commit itself.&lt;/p&gt;

&lt;p&gt;In this case, change &lt;code&gt;pick&lt;/code&gt; to &lt;code&gt;edit&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;edit abc1234 implement feature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you start the rebase, the process will temporarily stop at that commit.&lt;/p&gt;

&lt;p&gt;At this point, remove only the changes related to the target file.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Remove Changes to the Target File from the &lt;code&gt;edit&lt;/code&gt; Commit
&lt;/h2&gt;

&lt;p&gt;From here, the operation changes depending on whether the target file was &lt;strong&gt;newly added or an existing file was modified&lt;/strong&gt; in that commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  If the File Was Newly Added
&lt;/h3&gt;

&lt;p&gt;If the file was newly added in that commit, delete the file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nb"&gt;rm &lt;/span&gt;path/to/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, recreate the commit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;--amend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modify the commit message as needed.&lt;/p&gt;

&lt;h3&gt;
  
  
  If an Existing File Was Modified
&lt;/h3&gt;

&lt;p&gt;If the target file was modified in that commit, revert the target file to its state in the commit &lt;strong&gt;immediately before&lt;/strong&gt; that commit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git restore &lt;span class="nt"&gt;--source&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;commit_id&lt;span class="o"&gt;}&lt;/span&gt;^ &lt;span class="nt"&gt;--staged&lt;/span&gt; &lt;span class="nt"&gt;--worktree&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; path/to/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, if the target commit is &lt;code&gt;abc1234&lt;/code&gt;, then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git restore &lt;span class="nt"&gt;--source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;abc1234^ &lt;span class="nt"&gt;--staged&lt;/span&gt; &lt;span class="nt"&gt;--worktree&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; path/to/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will remove the changes to the target file that were included in that commit.&lt;/p&gt;

&lt;p&gt;Next, modify the commit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;--amend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there are any descriptions about the target file in the commit message, modify them here as appropriate.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Continue the Rebase
&lt;/h2&gt;

&lt;p&gt;After finishing the commit modification, continue the rebase.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;--continue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there are multiple commits that you changed to &lt;code&gt;edit&lt;/code&gt;, the process will stop again at the next &lt;code&gt;edit&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Each time, repeat the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Remove the changes to the target file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git commit --amend&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git rebase --continue&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you complete all the steps, the rebase will be finished.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally, Check the History
&lt;/h2&gt;

&lt;p&gt;After the rebase is complete, confirm that the history related to the target file is as intended.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--name-status&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; path/to/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to be sure about the overall state of the branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caution: If You Have Already Pushed
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;git rebase --committer-date-is-author-date　-i&lt;/code&gt; is an operation that rewrites past commits.&lt;/p&gt;

&lt;p&gt;Therefore, if you have already pushed the target commit to a remote repository, the commit IDs will be different between the local and remote repositories after the rebase.&lt;/p&gt;

&lt;p&gt;If you need to reflect the rewritten history in the remote repository, you will need to perform a force push.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;--force-with-lease&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is safer to use &lt;code&gt;--force-with-lease&lt;/code&gt; instead of &lt;code&gt;--force&lt;/code&gt;, as it is less likely to overwrite changes that others have added to the remote repository.&lt;/p&gt;

&lt;p&gt;However, rewriting the history of a shared branch will affect other developers. If you are working on a branch that is used by a team, be sure to check the scope of the impact before running it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;If you want to remove changes related to a specific file from the commit history, follow these steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Find the commits related to the target file.
        ↓
Start git rebase --committer-date-is-author-date -i from the oldest commit.
        ↓
If the commit is unnecessary, use drop.
        ↓
If it includes other changes, use edit.
        ↓
Remove only the changes to the target file.
        ↓
git commit --amend.
        ↓
git rebase --continue.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The key is to use &lt;code&gt;drop&lt;/code&gt; if you can delete the commit, and &lt;code&gt;edit&lt;/code&gt; if you only want to delete part of the commit.&lt;/p&gt;

&lt;p&gt;Also, if using &lt;code&gt;edit&lt;/code&gt;, check whether the target file was "newly added" or "modified to an existing file" in that commit before proceeding.&lt;/p&gt;

&lt;p&gt;Using interactive rebase, you can remove changes related to a specific file from past commits while keeping other changes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Gitのコミット履歴から特定のファイルだけ「なかったこと」にする方法
&lt;/h1&gt;

&lt;p&gt;Gitで作業していると、&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;「このファイル、そもそもコミットしたこと自体をなかったことにしたい」&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;というケースがあります。&lt;/p&gt;

&lt;p&gt;単純に現在のブランチからファイルを削除するだけなら &lt;code&gt;git rm&lt;/code&gt; してコミットすれば済みます。しかし、それでは過去のコミット履歴にはファイルが残ったままです。&lt;/p&gt;

&lt;p&gt;この記事では、&lt;strong&gt;interactive rebase（&lt;code&gt;git rebase --committer-date-is-author-date -i&lt;/code&gt;）を使って、特定のファイルに関する変更を過去のコミットから取り除く方法&lt;/strong&gt;を紹介します。&lt;/p&gt;

&lt;p&gt;なお、この方法はコミット履歴を書き換えます。すでにリモートへ push しているブランチや、複数人で共有しているブランチで実行する場合は注意してください。&lt;/p&gt;

&lt;h2&gt;
  
  
  1. 対象ファイルに関係するコミットを探す
&lt;/h2&gt;

&lt;p&gt;まず、削除したいファイルがどのコミットで追加・変更されたのかを確認します。&lt;/p&gt;

&lt;p&gt;ファイルパスがわかっている場合は、次のコマンドを実行します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--oneline&lt;/span&gt; &lt;span class="nt"&gt;--name-status&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; path/to/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;対象ファイルの正確な名前やパスがわからない場合は、コミットと変更されたファイルをまとめて確認します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--oneline&lt;/span&gt; &lt;span class="nt"&gt;--name-status&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ここで重要なのが、ファイルの左側に表示されるステータスです。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A    path/to/file
M    path/to/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;主に確認するのは次の2つです。&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;A&lt;/code&gt;：ファイルが新規追加された&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;M&lt;/code&gt;：既存ファイルが変更された&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;後ほど、この違いによって対応方法が変わります。&lt;/p&gt;

&lt;h2&gt;
  
  
  2. 一番古い対象コミットからrebaseする
&lt;/h2&gt;

&lt;p&gt;対象ファイルに関係するコミットを洗い出したら、その中で&lt;strong&gt;一番古いコミット&lt;/strong&gt;を確認します。&lt;/p&gt;

&lt;p&gt;そのコミットを &lt;code&gt;earliest_commit_id&lt;/code&gt; とすると、次のように interactive rebase を開始します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;--committer-date-is-author-date&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;oldest_commit_id&lt;span class="o"&gt;}&lt;/span&gt;^
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;^&lt;/code&gt; を付けているのは、対象コミット自身を rebase の範囲に含めるためです。&lt;/p&gt;

&lt;p&gt;たとえば対象となる最古のコミットが &lt;code&gt;abc1234&lt;/code&gt; なら、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;--committer-date-is-author-date&lt;/span&gt;　-i abc1234^
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;となります。&lt;/p&gt;

&lt;h2&gt;
  
  
  3. 対象コミットをdropまたはeditに変更する
&lt;/h2&gt;

&lt;p&gt;コマンドを実行すると、エディターが開いてコミット一覧が表示されます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick abc1234 add config
pick def5678 update config
pick ghi9012 implement feature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ここから、対象ファイルに関係するコミットを修正していきます。&lt;/p&gt;

&lt;h3&gt;
  
  
  そのファイルだけを変更しているコミットの場合
&lt;/h3&gt;

&lt;p&gt;そのコミット自体が不要なので、&lt;code&gt;pick&lt;/code&gt; を &lt;code&gt;drop&lt;/code&gt; に変更します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;drop abc1234 add config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;これによって、そのコミット自体が履歴から削除されます。&lt;/p&gt;

&lt;p&gt;ただし、&lt;strong&gt;同じコミットに残したい変更が含まれている場合は &lt;code&gt;drop&lt;/code&gt; してはいけません。&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  他のファイルの変更も含まれている場合
&lt;/h3&gt;

&lt;p&gt;対象ファイル以外の変更は残したいので、コミットそのものを削除することはできません。&lt;/p&gt;

&lt;p&gt;その場合は &lt;code&gt;pick&lt;/code&gt; を &lt;code&gt;edit&lt;/code&gt; に変更します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;edit abc1234 implement feature
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;rebase を開始すると、そのコミットのところで処理が一時停止します。&lt;/p&gt;

&lt;p&gt;そこで、対象ファイルの変更だけを取り除きます。&lt;/p&gt;

&lt;h2&gt;
  
  
  4. editしたコミットから対象ファイルの変更を取り除く
&lt;/h2&gt;

&lt;p&gt;ここからは、そのコミットで対象ファイルを&lt;strong&gt;新規追加したのか、既存ファイルを変更したのか&lt;/strong&gt;によって操作が変わります。&lt;/p&gt;

&lt;h3&gt;
  
  
  ファイルを新規追加していた場合
&lt;/h3&gt;

&lt;p&gt;そのコミットでファイル自体を新しく追加していたのであれば、ファイルを削除します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git &lt;span class="nb"&gt;rm &lt;/span&gt;path/to/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;その後、コミットを作り直します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;--amend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;必要に応じてコミットメッセージも修正します。&lt;/p&gt;

&lt;h3&gt;
  
  
  既存ファイルを変更していた場合
&lt;/h3&gt;

&lt;p&gt;そのコミットで対象ファイルに変更を加えていた場合は、対象ファイルだけを&lt;strong&gt;そのコミットの直前の状態に戻します&lt;/strong&gt;。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git restore &lt;span class="nt"&gt;--source&lt;/span&gt;&lt;span class="o"&gt;={&lt;/span&gt;commit_id&lt;span class="o"&gt;}&lt;/span&gt;^ &lt;span class="nt"&gt;--staged&lt;/span&gt; &lt;span class="nt"&gt;--worktree&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; path/to/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;たとえば対象コミットが &lt;code&gt;abc1234&lt;/code&gt; なら、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git restore &lt;span class="nt"&gt;--source&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;abc1234^ &lt;span class="nt"&gt;--staged&lt;/span&gt; &lt;span class="nt"&gt;--worktree&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; path/to/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;とします。&lt;/p&gt;

&lt;p&gt;これによって、そのコミットに含まれていた対象ファイルの変更を取り除くことができます。&lt;/p&gt;

&lt;p&gt;続いてコミットを修正します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git commit &lt;span class="nt"&gt;--amend&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;コミットメッセージに対象ファイルについての記述があれば、ここで適宜修正します。&lt;/p&gt;

&lt;h2&gt;
  
  
  5. rebaseを続行する
&lt;/h2&gt;

&lt;p&gt;コミットの修正が終わったら、rebaseを続けます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;--continue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;edit&lt;/code&gt; にしたコミットが複数ある場合は、次の &lt;code&gt;edit&lt;/code&gt; の位置で再び処理が停止します。&lt;/p&gt;

&lt;p&gt;そのたびに、&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;対象ファイルの変更を取り除く&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git commit --amend&lt;/code&gt; する&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git rebase --continue&lt;/code&gt; する&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;という作業を繰り返します。&lt;/p&gt;

&lt;p&gt;すべて処理できれば rebase は完了です。&lt;/p&gt;

&lt;h2&gt;
  
  
  最後に履歴を確認する
&lt;/h2&gt;

&lt;p&gt;rebase が完了したら、対象ファイルに関する履歴が意図したとおりになっているか確認します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--name-status&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; path/to/file
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;あわせて、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;や、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;などでブランチ全体の状態も確認しておくと安心です。&lt;/p&gt;

&lt;h2&gt;
  
  
  注意：すでにpushしている場合
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;git rebase --committer-date-is-author-date　-i&lt;/code&gt; は過去のコミットを書き換える操作です。&lt;/p&gt;

&lt;p&gt;そのため、対象コミットをすでにリモートへ push している場合、rebase 後はローカルとリモートでコミットIDが異なる状態になります。&lt;/p&gt;

&lt;p&gt;リモート側にも書き換え後の履歴を反映する必要がある場合は force push が必要になります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git push &lt;span class="nt"&gt;--force-with-lease&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;--force&lt;/code&gt; よりも、他の人がリモートへ追加した変更を誤って上書きしにくい &lt;code&gt;--force-with-lease&lt;/code&gt; を使うほうが安全です。&lt;/p&gt;

&lt;p&gt;ただし、共有ブランチの履歴を書き換えると他の開発者にも影響します。チームで使用しているブランチの場合は、実行前に影響範囲を確認しておきましょう。&lt;/p&gt;

&lt;h2&gt;
  
  
  まとめ
&lt;/h2&gt;

&lt;p&gt;特定のファイルに関する変更だけをコミット履歴から取り除きたい場合は、次の流れになります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;対象ファイルに関係するコミットを調べる
        ↓
一番古いコミットから git rebase --committer-date-is-author-date　-i
        ↓
不要なコミットなら drop
        ↓
他の変更も含むなら edit
        ↓
対象ファイルの変更だけ取り除く
        ↓
git commit --amend
        ↓
git rebase --continue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ポイントは、&lt;strong&gt;コミット単位で消してよいなら &lt;code&gt;drop&lt;/code&gt;、コミットの一部だけ消したいなら &lt;code&gt;edit&lt;/code&gt;&lt;/strong&gt; と使い分けることです。&lt;/p&gt;

&lt;p&gt;また、&lt;code&gt;edit&lt;/code&gt; の場合は対象ファイルがそのコミットで「新規追加されたもの」なのか「既存ファイルへの変更」なのかを確認してから操作します。&lt;/p&gt;

&lt;p&gt;interactive rebase を使えば、他の変更を残したまま、特定のファイルに関する変更だけを過去のコミットから取り除くことができます。&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Use a Japanese Keyboard (JIS Layout) in GRUB: Rocky Linux / RHEL Compatible</title>
      <dc:creator>vast cow</dc:creator>
      <pubDate>Sun, 30 Aug 2026 07:46:21 +0000</pubDate>
      <link>https://dev.to/vast-cow/how-to-use-a-japanese-keyboard-jis-layout-in-grub-rocky-linux-rhel-compatible-10l</link>
      <guid>https://dev.to/vast-cow/how-to-use-a-japanese-keyboard-jis-layout-in-grub-rocky-linux-rhel-compatible-10l</guid>
      <description>&lt;h1&gt;
  
  
  How to Use a Japanese Keyboard (JIS Layout) in GRUB: Rocky Linux / RHEL Compatible
&lt;/h1&gt;

&lt;p&gt;When working with the GRUB menu or command line, you may encounter issues where the keyboard is treated as a US layout.&lt;/p&gt;

&lt;p&gt;This is particularly problematic with Japanese keyboards, as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;@&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;:&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;\&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;_&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These symbols are located in different positions on US and JIS layouts, making it quite inconvenient to edit kernel parameters or enter commands in GRUB.&lt;/p&gt;

&lt;p&gt;This article summarizes how to change the GRUB keyboard layout to the Japanese JIS layout on RHEL-based Linux distributions such as Rocky Linux, AlmaLinux, RHEL, and CentOS Stream.&lt;/p&gt;

&lt;p&gt;Note that the "Japanese keyboard" referred to here does not refer to the Japanese input IME. It is not intended to enable Japanese character input in GRUB, but rather to configure it to match the physical key layout of a JIS keyboard.&lt;/p&gt;




&lt;h2&gt;
  
  
  Linux Keyboard Settings and GRUB Keyboard Settings Are Different
&lt;/h2&gt;

&lt;p&gt;Normally, you can change the Linux console keymap with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;localectl set-keymap jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, you can specify it in the kernel parameters or configuration file, such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vconsole.keymap=jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, these are settings that take effect after the Linux kernel has booted.&lt;/p&gt;

&lt;p&gt;Since GRUB runs before Linux, the Linux keyboard settings are not reflected in GRUB.&lt;/p&gt;

&lt;p&gt;In other words, in the boot sequence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GRUB
  ↓
Linux kernel
  ↓
systemd / console
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The keyboard layout for GRUB must be configured within GRUB itself.&lt;/p&gt;




&lt;h1&gt;
  
  
  Packages Required for Rocky Linux / RHEL
&lt;/h1&gt;

&lt;p&gt;In Rocky Linux and RHEL-based systems, GRUB-related commands have &lt;code&gt;grub2-&lt;/code&gt; prefixes.&lt;/p&gt;

&lt;p&gt;Install the necessary packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install &lt;/span&gt;grub2-tools-extra kbd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following commands are mainly used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;grub2-kbdcomp
grub2-mkconfig
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;grub2-kbdcomp&lt;/code&gt; to create a keyboard layout file that GRUB can read.&lt;/p&gt;




&lt;h1&gt;
  
  
  Create a Japanese Keymap for GRUB
&lt;/h1&gt;

&lt;p&gt;First, create a save location:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /boot/grub2/layouts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, create the Japanese JIS layout keymap:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;grub2-kbdcomp &lt;span class="nt"&gt;-o&lt;/span&gt; /boot/grub2/layouts/jp.gkb jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify that it was created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; /boot/grub2/layouts/jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a file exists as follows, the preparation is complete:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/boot/grub2/layouts/jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In GRUB, the keyboard layout is changed by loading this &lt;code&gt;.gkb&lt;/code&gt; file.&lt;/p&gt;




&lt;h1&gt;
  
  
  Temporarily Change to JIS Layout Only During GRUB Boot
&lt;/h1&gt;

&lt;p&gt;Instead of making a permanent change all at once, it is recommended to first load it temporarily from the GRUB command line and verify that it works.&lt;/p&gt;

&lt;p&gt;When the GRUB menu is displayed, press:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to enter the GRUB command line.&lt;/p&gt;

&lt;p&gt;Execute the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod keylayouts
keymap jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will change to the Japanese JIS layout for that GRUB session only.&lt;/p&gt;

&lt;p&gt;Since it will revert to the original upon reboot, it is suitable for testing the settings.&lt;/p&gt;




&lt;h2&gt;
  
  
  If &lt;code&gt;keymap jp&lt;/code&gt; Cannot Be Loaded
&lt;/h2&gt;

&lt;p&gt;Check the &lt;code&gt;prefix&lt;/code&gt; used by GRUB:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo $prefix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, it may display:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(hd0,gpt2)/grub2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, check if the keymap is visible:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ls $prefix/layouts/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is displayed, GRUB can access the file.&lt;/p&gt;

&lt;p&gt;In this case, it should normally be loaded with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;keymap jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on the environment, you may want to explicitly specify the file to confirm:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;keymap $prefix/layouts/jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Make the JIS Layout Permanent
&lt;/h1&gt;

&lt;p&gt;Once you have verified that it works, incorporate it into the GRUB configuration.&lt;/p&gt;

&lt;p&gt;On RHEL-based systems, appending to &lt;code&gt;/etc/grub.d/40_custom&lt;/code&gt; is a clear method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vi /etc/grub.d/40_custom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod keylayouts
keymap ${prefix}/layouts/jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, depending on the environment, the following specification may also work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod keylayouts
keymap jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Personally, I prefer to explicitly specify it so that it is clear which file is being used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;keymap ${prefix}/layouts/jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes it easier to troubleshoot.&lt;/p&gt;




&lt;h1&gt;
  
  
  Regenerate grub.cfg
&lt;/h1&gt;

&lt;p&gt;After changing the settings, regenerate the GRUB configuration.&lt;/p&gt;

&lt;p&gt;On newer RHEL-based systems such as Rocky Linux 9:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;grub2-mkconfig &lt;span class="nt"&gt;-o&lt;/span&gt; /boot/grub2/grub.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reboot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the GRUB menu, press &lt;code&gt;c&lt;/code&gt; to open the command line and check the symbol keys.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@
:
"
\
_
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If these can be entered as they are printed on the keycaps, the JIS layout has been applied.&lt;/p&gt;




&lt;h1&gt;
  
  
  Notes for UEFI Environments
&lt;/h1&gt;

&lt;p&gt;Older articles mention examples of running &lt;code&gt;grub2-mkconfig&lt;/code&gt; directly on the following file in UEFI environments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/boot/efi/EFI/redhat/grub.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Rocky Linux, it may be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/boot/efi/EFI/rocky/grub.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, in recent RHEL-based systems, the UEFI &lt;code&gt;grub.cfg&lt;/code&gt; is configured to be used as a stub to load the main &lt;code&gt;/boot/grub2/grub.cfg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Therefore, in Rocky Linux 9 and later, it is generally recommended to use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;grub2-mkconfig &lt;span class="nt"&gt;-o&lt;/span&gt; /boot/grub2/grub.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is safer not to directly overwrite the UEFI &lt;code&gt;grub.cfg&lt;/code&gt; unnecessarily.&lt;/p&gt;




&lt;h1&gt;
  
  
  Is &lt;code&gt;terminal_input at_keyboard&lt;/code&gt; Necessary?
&lt;/h1&gt;

&lt;p&gt;In GRUB keyboard configuration examples, you may see settings like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod at_keyboard
terminal_input at_keyboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, on USB keyboards and UEFI environments, explicitly switching the input path to &lt;code&gt;at_keyboard&lt;/code&gt; may prevent keyboard input.&lt;/p&gt;

&lt;p&gt;If you only want to change to the JIS layout, it is safest to first try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod keylayouts
keymap ${prefix}/layouts/jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unless there is a specific reason, it is not necessary to change the input terminal itself.&lt;/p&gt;




&lt;h1&gt;
  
  
  Temporary Change vs. Permanent Change
&lt;/h1&gt;

&lt;p&gt;To summarize, the following applies:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;After Reboot&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GRUB command line&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;insmod keylayouts&lt;/code&gt; → &lt;code&gt;keymap jp&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Reverts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add to &lt;code&gt;40_custom&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;keymap ${prefix}/layouts/jp.gkb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Persists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux &lt;code&gt;localectl&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Changes only the Linux console&lt;/td&gt;
&lt;td&gt;Does not affect GRUB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It is safe to test with a temporary change first, and then make it permanent if there are no problems.&lt;/p&gt;




&lt;h1&gt;
  
  
  Can I Change to the JIS Layout in GRUB Without Creating a &lt;code&gt;.gkb&lt;/code&gt; File?
&lt;/h1&gt;

&lt;p&gt;Basically, no.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;keymap&lt;/code&gt; command in GRUB is designed to load pre-created GRUB keyboard layout files.&lt;/p&gt;

&lt;p&gt;Therefore, during Linux startup, you need to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;grub2-kbdcomp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to create:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in advance.&lt;/p&gt;

&lt;p&gt;At a minimum, you need to perform the following preparations on the Linux side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /boot/grub2/layouts
&lt;span class="nb"&gt;sudo &lt;/span&gt;grub2-kbdcomp &lt;span class="nt"&gt;-o&lt;/span&gt; /boot/grub2/layouts/jp.gkb jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, you can always run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod keylayouts
keymap jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in the GRUB command line to temporarily switch to the JIS layout.&lt;/p&gt;




&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;When setting GRUB to a Japanese JIS keyboard layout on Rocky Linux or RHEL, the key points are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;First, create a GRUB keymap:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install &lt;/span&gt;grub2-tools-extra kbd
&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /boot/grub2/layouts
&lt;span class="nb"&gt;sudo &lt;/span&gt;grub2-kbdcomp &lt;span class="nt"&gt;-o&lt;/span&gt; /boot/grub2/layouts/jp.gkb jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you want to try it temporarily in GRUB:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod keylayouts
keymap jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;To make it permanent, add to &lt;code&gt;/etc/grub.d/40_custom&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod keylayouts
keymap ${prefix}/layouts/jp.gkb
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;and run:&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;grub2-mkconfig &lt;span class="nt"&gt;-o&lt;/span&gt; /boot/grub2/grub.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;GRUB runs before Linux boots, so the &lt;code&gt;localectl set-keymap jp&lt;/code&gt; and other Linux settings are completely separate.&lt;/p&gt;

&lt;p&gt;If you frequently edit kernel parameters or perform rescue operations in GRUB, setting up the JIS keyboard will make it much easier to operate.&lt;/p&gt;

&lt;h1&gt;
  
  
  GRUBで日本語キーボード（JIS配列）を使う方法：Rocky Linux / RHEL系対応
&lt;/h1&gt;

&lt;p&gt;GRUBのメニューやコマンドラインを操作していると、キーボードがUS配列として扱われて困ることがあります。&lt;/p&gt;

&lt;p&gt;特に日本語キーボードでは、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;@&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;\&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;_&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;などの記号位置がUS配列とJIS配列で異なるため、GRUB上でカーネルパラメータを編集したり、コマンドを入力したりする際にかなり不便です。&lt;/p&gt;

&lt;p&gt;この記事では、Rocky Linux、AlmaLinux、RHEL、CentOS StreamなどのRHEL系Linuxで、GRUBのキーボードレイアウトを日本語JIS配列に変更する方法をまとめます。&lt;/p&gt;

&lt;p&gt;なお、ここでいう「日本語キーボード」は日本語入力IMEのことではありません。GRUB上で日本語文字を入力できるようにするものではなく、&lt;strong&gt;物理的なJISキーボードのキー配置に合わせるための設定&lt;/strong&gt;です。&lt;/p&gt;




&lt;h2&gt;
  
  
  Linuxのキーボード設定とGRUBのキーボード設定は別物
&lt;/h2&gt;

&lt;p&gt;通常、Linux側のコンソールキーマップは次のようなコマンドで変更できます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;localectl set-keymap jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;あるいはカーネルパラメータや設定ファイルで、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;vconsole.keymap=jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のように指定することもあります。&lt;/p&gt;

&lt;p&gt;しかし、これらはLinuxカーネルが起動した後の設定です。&lt;/p&gt;

&lt;p&gt;GRUBはLinuxより前に動作しているため、Linux側のキーボード設定はGRUBには反映されません。&lt;/p&gt;

&lt;p&gt;つまり、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GRUB
  ↓
Linux kernel
  ↓
systemd / console
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という起動順序において、GRUB用のキーボードレイアウトはGRUB自身に設定する必要があります。&lt;/p&gt;




&lt;h1&gt;
  
  
  Rocky Linux / RHEL系で必要なパッケージ
&lt;/h1&gt;

&lt;p&gt;Rocky LinuxやRHEL系では、GRUB関連コマンドの名前に &lt;code&gt;grub2-&lt;/code&gt; が付いています。&lt;/p&gt;

&lt;p&gt;必要なパッケージをインストールします。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install &lt;/span&gt;grub2-tools-extra kbd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;主に使用するのは次のコマンドです。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;grub2-kbdcomp
grub2-mkconfig
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;grub2-kbdcomp&lt;/code&gt; を使って、GRUBが読み込めるキーボードレイアウトファイルを作成します。&lt;/p&gt;




&lt;h1&gt;
  
  
  GRUB用の日本語キーマップを作成する
&lt;/h1&gt;

&lt;p&gt;まず保存先を作ります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /boot/grub2/layouts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;続いて、日本語JIS配列のキーマップを作成します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;grub2-kbdcomp &lt;span class="nt"&gt;-o&lt;/span&gt; /boot/grub2/layouts/jp.gkb jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;生成できたか確認します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; /boot/grub2/layouts/jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;例えば次のようにファイルが存在していれば準備完了です。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/boot/grub2/layouts/jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GRUBでは、この &lt;code&gt;.gkb&lt;/code&gt; ファイルを読み込むことでキーボード配列を変更します。&lt;/p&gt;




&lt;h1&gt;
  
  
  まずはGRUB起動中だけ一時的にJIS配列へ変更する
&lt;/h1&gt;

&lt;p&gt;いきなり永続設定を変更するより、最初はGRUBのコマンドラインから一時的に読み込んで動作確認するのがおすすめです。&lt;/p&gt;

&lt;p&gt;GRUBメニューが表示されたら、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を押してGRUBコマンドラインに入ります。&lt;/p&gt;

&lt;p&gt;次のコマンドを実行します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod keylayouts
keymap jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;これで、そのGRUBセッション中だけ日本語JIS配列になります。&lt;/p&gt;

&lt;p&gt;再起動すれば元に戻るため、設定テストにも向いています。&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;code&gt;keymap jp&lt;/code&gt; で読み込めない場合
&lt;/h2&gt;

&lt;p&gt;GRUBが使用している &lt;code&gt;prefix&lt;/code&gt; を確認します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo $prefix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;例えば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(hd0,gpt2)/grub2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のように表示されることがあります。&lt;/p&gt;

&lt;p&gt;次に、キーマップが見えるか確認します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ls $prefix/layouts/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ここで、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;が表示されれば、GRUBからファイルにアクセスできています。&lt;/p&gt;

&lt;p&gt;その場合は通常、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;keymap jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;で読み込めます。&lt;/p&gt;

&lt;p&gt;環境によっては明示的にファイルを指定して確認してもよいでしょう。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;keymap $prefix/layouts/jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  永続的にJIS配列へ変更する
&lt;/h1&gt;

&lt;p&gt;動作確認できたら、GRUBの設定に組み込みます。&lt;/p&gt;

&lt;p&gt;RHEL系では &lt;code&gt;/etc/grub.d/40_custom&lt;/code&gt; に追記する方法が分かりやすいです。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;vi /etc/grub.d/40_custom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;次の内容を追加します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod keylayouts
keymap ${prefix}/layouts/jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;あるいは、環境によっては次のような指定でも動作します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod keylayouts
keymap jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;個人的には、どのファイルを使用しているか分かりやすいので、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;keymap ${prefix}/layouts/jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のように明示しておく方がトラブルシュートしやすいでしょう。&lt;/p&gt;




&lt;h1&gt;
  
  
  grub.cfgを再生成する
&lt;/h1&gt;

&lt;p&gt;設定を変更したら、GRUB設定を再生成します。&lt;/p&gt;

&lt;p&gt;Rocky Linux 9などの比較的新しいRHEL系では、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;grub2-mkconfig &lt;span class="nt"&gt;-o&lt;/span&gt; /boot/grub2/grub.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を使用します。&lt;/p&gt;

&lt;p&gt;再起動します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GRUBメニューで &lt;code&gt;c&lt;/code&gt; を押してコマンドラインを開き、記号キーを確認します。&lt;/p&gt;

&lt;p&gt;例えば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@
:
"
\
_
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;などがキートップの刻印どおり入力できれば、JIS配列が適用されています。&lt;/p&gt;




&lt;h1&gt;
  
  
  UEFI環境での注意点
&lt;/h1&gt;

&lt;p&gt;古い記事を見ると、UEFI環境では次のようなファイルへ直接 &lt;code&gt;grub2-mkconfig&lt;/code&gt; を実行する例があります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/boot/efi/EFI/redhat/grub.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rocky Linuxでは、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/boot/efi/EFI/rocky/grub.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;となっている場合があります。&lt;/p&gt;

&lt;p&gt;ただし、最近のRHEL系ではUEFI側の &lt;code&gt;grub.cfg&lt;/code&gt; は、本体となる &lt;code&gt;/boot/grub2/grub.cfg&lt;/code&gt; を読み込むためのスタブとして使用される構成があります。&lt;/p&gt;

&lt;p&gt;そのため、Rocky Linux 9などでは基本的に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;grub2-mkconfig &lt;span class="nt"&gt;-o&lt;/span&gt; /boot/grub2/grub.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を使用します。&lt;/p&gt;

&lt;p&gt;UEFI側の &lt;code&gt;grub.cfg&lt;/code&gt; を不用意に直接上書きしない方が安全です。&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;code&gt;terminal_input at_keyboard&lt;/code&gt; は必要か
&lt;/h1&gt;

&lt;p&gt;GRUBのキーボード設定例では、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod at_keyboard
terminal_input at_keyboard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;といった設定を見かけることがあります。&lt;/p&gt;

&lt;p&gt;ただし、USBキーボードやUEFI環境では、入力経路を明示的に &lt;code&gt;at_keyboard&lt;/code&gt; へ切り替えることで、逆にキーボード入力ができなくなる場合があります。&lt;/p&gt;

&lt;p&gt;JIS配列へ変更するだけであれば、まずは、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod keylayouts
keymap ${prefix}/layouts/jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;だけで試すのが無難です。&lt;/p&gt;

&lt;p&gt;特別な理由がない限り、入力端末そのものを変更する必要はありません。&lt;/p&gt;




&lt;h1&gt;
  
  
  一時変更と永続変更の違い
&lt;/h1&gt;

&lt;p&gt;整理すると、次のようになります。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方法&lt;/th&gt;
&lt;th&gt;設定&lt;/th&gt;
&lt;th&gt;再起動後&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GRUBコマンドライン&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;insmod keylayouts&lt;/code&gt; → &lt;code&gt;keymap jp&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;元に戻る&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;40_custom&lt;/code&gt;へ追加&lt;/td&gt;
&lt;td&gt;&lt;code&gt;keymap ${prefix}/layouts/jp.gkb&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;維持される&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linuxの &lt;code&gt;localectl&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Linuxコンソールのみ変更&lt;/td&gt;
&lt;td&gt;GRUBには影響しない&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;まず一時変更でテストし、問題がなければ永続設定にするのが安全です。&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;code&gt;.gkb&lt;/code&gt;を作らずGRUBだけでJIS配列へ変更できるか
&lt;/h1&gt;

&lt;p&gt;基本的にはできません。&lt;/p&gt;

&lt;p&gt;GRUB上の &lt;code&gt;keymap&lt;/code&gt; コマンドは、あらかじめ作成されたGRUB用キーマップファイルを読み込む仕組みです。&lt;/p&gt;

&lt;p&gt;そのため、Linux起動中に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;grub2-kbdcomp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を使って、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を事前に作っておく必要があります。&lt;/p&gt;

&lt;p&gt;最低限、次の準備だけはLinux側で行います。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /boot/grub2/layouts
&lt;span class="nb"&gt;sudo &lt;/span&gt;grub2-kbdcomp &lt;span class="nt"&gt;-o&lt;/span&gt; /boot/grub2/layouts/jp.gkb jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;その後であれば、GRUB起動中にいつでも、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod keylayouts
keymap jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;と実行して、一時的にJIS配列へ切り替えられます。&lt;/p&gt;




&lt;h1&gt;
  
  
  まとめ
&lt;/h1&gt;

&lt;p&gt;Rocky LinuxやRHEL系でGRUBを日本語JISキーボード配列にする場合、ポイントは次の3つです。&lt;/p&gt;

&lt;p&gt;まずGRUB用のキーマップを作ります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;dnf &lt;span class="nb"&gt;install &lt;/span&gt;grub2-tools-extra kbd
&lt;span class="nb"&gt;sudo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /boot/grub2/layouts
&lt;span class="nb"&gt;sudo &lt;/span&gt;grub2-kbdcomp &lt;span class="nt"&gt;-o&lt;/span&gt; /boot/grub2/layouts/jp.gkb jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GRUB上で一時的に試す場合は、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod keylayouts
keymap jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;とします。&lt;/p&gt;

&lt;p&gt;永続化する場合は &lt;code&gt;/etc/grub.d/40_custom&lt;/code&gt; に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;insmod keylayouts
keymap ${prefix}/layouts/jp.gkb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を追加し、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;grub2-mkconfig &lt;span class="nt"&gt;-o&lt;/span&gt; /boot/grub2/grub.cfg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を実行します。&lt;/p&gt;

&lt;p&gt;GRUBはLinux起動前に動作するため、&lt;code&gt;localectl set-keymap jp&lt;/code&gt; などのLinux側設定とは完全に別です。&lt;/p&gt;

&lt;p&gt;GRUB上で頻繁にカーネルパラメータを編集したり、レスキュー操作をしたりする環境では、JISキーボードの設定を入れておくとかなり操作しやすくなります。&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Temporarily Change the Keyboard Layout</title>
      <dc:creator>vast cow</dc:creator>
      <pubDate>Sun, 30 Aug 2026 07:29:13 +0000</pubDate>
      <link>https://dev.to/vast-cow/how-to-temporarily-change-the-keyboard-layout-2jl2</link>
      <guid>https://dev.to/vast-cow/how-to-temporarily-change-the-keyboard-layout-2jl2</guid>
      <description>&lt;p&gt;In a Linux desktop environment, you can temporarily change the keyboard layout using the &lt;code&gt;setxkbmap&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;This is useful if you want to use a US keyboard layout or switch back to a Japanese layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Changing to the US Layout
&lt;/h2&gt;

&lt;p&gt;To change the keyboard layout to the US layout, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;setxkbmap us
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will use the US layout in the current login session.&lt;/p&gt;

&lt;h2&gt;
  
  
  Changing to the Japanese Layout
&lt;/h2&gt;

&lt;p&gt;To change to the Japanese layout, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;setxkbmap jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can also be used to switch back to the Japanese layout after changing to the US layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Checking the Current Settings
&lt;/h2&gt;

&lt;p&gt;To check the keyboard layout currently in use, run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;setxkbmap &lt;span class="nt"&gt;-query&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check the current layout by looking at the &lt;code&gt;layout&lt;/code&gt; item in the displayed output.&lt;/p&gt;

&lt;p&gt;For example, it will display &lt;code&gt;us&lt;/code&gt; for the US layout or &lt;code&gt;jp&lt;/code&gt; for the Japanese layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Note that the Change is Temporary
&lt;/h2&gt;

&lt;p&gt;Changes made with &lt;code&gt;setxkbmap&lt;/code&gt; are generally temporary.&lt;/p&gt;

&lt;p&gt;Logging out or restarting may revert to the original keyboard layout set by the distribution or desktop environment.&lt;/p&gt;

&lt;p&gt;If you want to use the same keyboard layout after logging in, you need to configure a permanent setting. The configuration method varies depending on the distribution you are using, such as Ubuntu, Xubuntu, Debian, or Arch Linux.&lt;/p&gt;

&lt;p&gt;If you just want to temporarily switch layouts, it is convenient to remember the three commands: &lt;code&gt;setxkbmap us&lt;/code&gt;, &lt;code&gt;setxkbmap jp&lt;/code&gt;, and &lt;code&gt;setxkbmap -query&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  一時的にキーボードレイアウトを変更する方法
&lt;/h1&gt;

&lt;p&gt;Linuxのデスクトップ環境では、&lt;code&gt;setxkbmap&lt;/code&gt;コマンドを使うことで、キーボードレイアウトを一時的に変更できます。&lt;/p&gt;

&lt;p&gt;US配列のキーボードを使いたい場合や、日本語配列に戻したい場合に便利です。&lt;/p&gt;

&lt;h2&gt;
  
  
  US配列に変更する
&lt;/h2&gt;

&lt;p&gt;キーボードレイアウトをUS配列に変更するには、次のコマンドを実行します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;setxkbmap us
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;実行すると、現在のログインセッションでUS配列が使用されます。&lt;/p&gt;

&lt;h2&gt;
  
  
  日本語配列に変更する
&lt;/h2&gt;

&lt;p&gt;日本語配列に変更する場合は、次のコマンドを実行します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;setxkbmap jp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;US配列に変更したあと、日本語配列へ戻したい場合にも使用できます。&lt;/p&gt;

&lt;h2&gt;
  
  
  現在の設定を確認する
&lt;/h2&gt;

&lt;p&gt;現在使用しているキーボードレイアウトを確認するには、次のコマンドを実行します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;setxkbmap &lt;span class="nt"&gt;-query&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;表示された内容のうち、&lt;code&gt;layout&lt;/code&gt;の項目を見ることで、現在のレイアウトを確認できます。&lt;/p&gt;

&lt;p&gt;たとえば、US配列の場合は&lt;code&gt;us&lt;/code&gt;、日本語配列の場合は&lt;code&gt;jp&lt;/code&gt;と表示されます。&lt;/p&gt;

&lt;h2&gt;
  
  
  一時的な変更であることに注意
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;setxkbmap&lt;/code&gt;による変更は基本的に一時的なものです。&lt;/p&gt;

&lt;p&gt;ログアウトや再起動をすると、ディストリビューションやデスクトップ環境で設定されている元のキーボードレイアウトに戻ることがあります。&lt;/p&gt;

&lt;p&gt;ログイン後も同じキーボードレイアウトを使用したい場合は、永続的な設定が必要です。設定方法はUbuntuやXubuntu、Debian、Arch Linuxなど、使用しているディストリビューションによって異なります。&lt;/p&gt;

&lt;p&gt;一時的にレイアウトを切り替えたいだけであれば、&lt;code&gt;setxkbmap us&lt;/code&gt;、&lt;code&gt;setxkbmap jp&lt;/code&gt;、&lt;code&gt;setxkbmap -query&lt;/code&gt;の3つを覚えておくと便利です。&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Using Multiple GitHub Accounts: Automatically Select the Correct `gh` PAT Based on Repo Owner</title>
      <dc:creator>vast cow</dc:creator>
      <pubDate>Wed, 26 Aug 2026 07:16:37 +0000</pubDate>
      <link>https://dev.to/vast-cow/using-multiple-github-accounts-automatically-select-the-correct-gh-pat-based-on-repo-owner-4l3g</link>
      <guid>https://dev.to/vast-cow/using-multiple-github-accounts-automatically-select-the-correct-gh-pat-based-on-repo-owner-4l3g</guid>
      <description>&lt;p&gt;When using multiple GitHub accounts, the process of selecting the correct Personal Access Token (PAT) for &lt;code&gt;git push&lt;/code&gt; or &lt;code&gt;git pull&lt;/code&gt; over HTTPS can be a bit cumbersome.&lt;/p&gt;

&lt;p&gt;Specifically, when dealing with repositories from multiple owners, such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://github.com/aont/foo.git
https://github.com/another-user/bar.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Git Credential Manager or &lt;code&gt;gh auth git-credential&lt;/code&gt; might default to the currently active account, leading to errors like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;remote: Permission to owner/repo.git denied to other-user.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To address this, the &lt;code&gt;owner&lt;/code&gt; portion of the remote URL is interpreted as the GitHub CLI account name, and a credential helper is embedded directly into the &lt;code&gt;.gitconfig&lt;/code&gt; file. This helper retrieves the PAT using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth token &lt;span class="nt"&gt;--user&lt;/span&gt; OWNER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and provides it to Git.&lt;/p&gt;

&lt;p&gt;This eliminates the need for external scripts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;First, ensure that you are logged into your GitHub accounts using &lt;code&gt;gh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have multiple accounts registered, you can verify them with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this method, if a repository URL is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://github.com/aont/foo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth token &lt;span class="nt"&gt;--user&lt;/span&gt; aont
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will be executed.&lt;/p&gt;

&lt;p&gt;Therefore, the basic assumption is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repository owner = gh registered account name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;code&gt;.gitconfig&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The configuration should be as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[credential]
    useHttpPath = true

[credential "https://github.com/"]
    helper =
    helper = "!f() { \
        [ \"$1\" = get ] || exit 0; \
        account=''; \
        while IFS='=' read -r k v; do \
            [ \"$k\" = path ] &amp;amp;&amp;amp; account=${v%%/*}; \
        done; \
        [ -n \"$account\" ] || exit 0; \
        token=$(gh auth token --user \"$account\") || exit 0; \
        printf 'username=%s\\npassword=%s\\n' \"$account\" \"$token\"; \
    }; f"

[credential "https://gist.github.com/"]
    helper =
    helper = "!f() { \
        [ \"$1\" = get ] || exit 0; \
        account=''; \
        while IFS='=' read -r k v; do \
            [ \"$k\" = path ] &amp;amp;&amp;amp; account=${v%%/*}; \
        done; \
        [ -n \"$account\" ] || exit 0; \
        token=$(gh auth token --user \"$account\") || exit 0; \
        printf 'username=%s\\npassword=%s\\n' \"$account\" \"$token\"; \
    }; f"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are three key points:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;credential.useHttpPath = true&lt;/code&gt; is Important
&lt;/h2&gt;

&lt;p&gt;Typically, Git's credential helper receives only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protocol=https
host=github.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, in this case, we need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aont/foo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the path.&lt;/p&gt;

&lt;p&gt;Therefore, set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[credential]
    useHttpPath = true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This causes the path to be passed to the credential helper's standard input, such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protocol=https
host=github.com
path=aont/foo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use the Beginning of the Path as the Account
&lt;/h2&gt;

&lt;p&gt;Inside the helper, the first element of the path is extracted using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$k&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; path &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="p"&gt;%%/*&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, if:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;path=aont/foo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;account=aont
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, the corresponding PAT for that account is retrieved from the GitHub CLI using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;gh auth token &lt;span class="nt"&gt;--user&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore, when accessing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://github.com/aont/foo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth token &lt;span class="nt"&gt;--user&lt;/span&gt; aont
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is automatically executed.&lt;/p&gt;

&lt;p&gt;Conversely, for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://github.com/another-user/bar.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth token &lt;span class="nt"&gt;--user&lt;/span&gt; another-user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is executed.&lt;/p&gt;

&lt;p&gt;There is no need to run &lt;code&gt;gh auth switch&lt;/code&gt; every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reset Existing Credential Helpers with &lt;code&gt;helper =&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Another important point is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helper =
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Git for Windows, for example, Git Credential Manager or &lt;code&gt;gh auth git-credential&lt;/code&gt; might already be configured.&lt;/p&gt;

&lt;p&gt;If another helper returns the credentials first, this helper might not be executed.&lt;/p&gt;

&lt;p&gt;As a result, you might encounter an error like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;remote: Permission to foo/bar.git denied to wrong-account.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helper =
helper = "!f() { ... }; f"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first empty &lt;code&gt;helper =&lt;/code&gt; resets any previously configured credential helpers, and then only this helper is registered.&lt;/p&gt;

&lt;p&gt;This is crucial when dealing with multiple GitHub accounts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the Same Mechanism for Gists
&lt;/h2&gt;

&lt;p&gt;The same credential helper can be configured for Gists.&lt;/p&gt;

&lt;p&gt;However, the standard Gist clone URL is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://gist.github.com/GIST_ID.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the username cannot be determined from the URL.&lt;/p&gt;

&lt;p&gt;Therefore, in this setup, the Gist remote URL is intentionally formatted as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://gist.github.com/USER/GIST_ID.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, if:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://gist.github.com/aont/0123456789abcdef.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then, from the credential helper's perspective:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;path=aont/0123456789abcdef.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;so, the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth token &lt;span class="nt"&gt;--user&lt;/span&gt; aont
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is automatically used.&lt;/p&gt;

&lt;p&gt;This allows you to treat GitHub repositories and Gists with the same rules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;github.com/USER/REPO
gist.github.com/USER/GIST
                ↓
             USER is extracted
                ↓
gh auth token --user USER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Verification
&lt;/h2&gt;

&lt;p&gt;You can check which credentials Git is actually retrieving using &lt;code&gt;git credential fill&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For example, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'protocol=https'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'host=github.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'path=aont/foo.git'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;''&lt;/span&gt; |
git credential fill
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The expected output is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protocol=https
host=github.com
username=aont
password=...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the &lt;code&gt;username&lt;/code&gt; is a different account, you can check if another credential helper is still present using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--show-origin&lt;/span&gt; &lt;span class="nt"&gt;--get-all&lt;/span&gt; credential.helper
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why Not Use &lt;code&gt;gh auth git-credential&lt;/code&gt; Directly?
&lt;/h2&gt;

&lt;p&gt;The GitHub CLI has a standard command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth git-credential
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is sufficient for normal single-account usage.&lt;/p&gt;

&lt;p&gt;However, when using multiple accounts with the same host (&lt;code&gt;github.com&lt;/code&gt;), you might want to explicitly control which &lt;code&gt;gh&lt;/code&gt; account is used based on the repository owner.&lt;/p&gt;

&lt;p&gt;This helper uses a very simple rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;remote URL
  ↓
owner is extracted
  ↓
gh auth token --user owner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;so you don't need to be aware of which account is currently active in &lt;code&gt;gh&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Advantages of This Configuration
&lt;/h2&gt;

&lt;p&gt;This method does not save the PAT itself in the &lt;code&gt;.gitconfig&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The PAT is retrieved each time it is needed using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth token &lt;span class="nt"&gt;--user&lt;/span&gt; ACCOUNT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore, the configuration only saves the rule for which account to use.&lt;/p&gt;

&lt;p&gt;Additionally, you do not need to run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth switch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or set:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config credential.username ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for each repository.&lt;/p&gt;

&lt;p&gt;The remote URL itself becomes the credential routing information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;When using multiple GitHub accounts over HTTPS, using the &lt;code&gt;account&lt;/code&gt; portion of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;github.com/&amp;lt;account&amp;gt;/&amp;lt;repo&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;directly for selecting the &lt;code&gt;gh&lt;/code&gt; account can simplify operations.&lt;/p&gt;

&lt;p&gt;The mechanism is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Git remote URL
  ↓
credential.useHttpPath
  ↓
path=owner/repo.git
  ↓
owner is extracted
  ↓
gh auth token --user owner
  ↓
username/password is returned to Git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have multiple personal accounts and the relationship:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repository owner = GitHub account
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;holds true, this method is quite easy to use.&lt;/p&gt;

&lt;p&gt;For organization-owned repositories where:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;owner != account used for authentication
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you will need separate mappings, but this configuration is sufficient for primarily personal accounts.&lt;/p&gt;

&lt;h1&gt;
  
  
  GitHub複数アカウント運用で、repo ownerから自動的にghのPATを選ぶ
&lt;/h1&gt;

&lt;p&gt;GitHubで複数アカウントを使っていると、HTTPSでの&lt;code&gt;git push&lt;/code&gt;や&lt;code&gt;git pull&lt;/code&gt;時に「どのアカウントのPATを使うか」が地味に面倒です。&lt;/p&gt;

&lt;p&gt;特に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://github.com/aont/foo.git
https://github.com/another-user/bar.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のように複数ownerのrepositoryを扱っていると、Git Credential Managerや&lt;code&gt;gh auth git-credential&lt;/code&gt;が現在のアクティブアカウントを使ってしまい、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;remote: Permission to owner/repo.git denied to other-user.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のようなエラーになることがあります。&lt;/p&gt;

&lt;p&gt;そこで、remote URLの&lt;code&gt;owner&lt;/code&gt;部分をそのままGitHub CLIのアカウント名として解釈し、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth token &lt;span class="nt"&gt;--user&lt;/span&gt; OWNER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;からPATを取り出してGitに返すcredential helperを&lt;code&gt;.gitconfig&lt;/code&gt;へ直接埋め込みます。&lt;/p&gt;

&lt;p&gt;外部スクリプトも不要です。&lt;/p&gt;

&lt;h2&gt;
  
  
  前提
&lt;/h2&gt;

&lt;p&gt;まず、利用するGitHubアカウントはあらかじめ&lt;code&gt;gh&lt;/code&gt;にログインしておきます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;複数アカウントを登録している場合は、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;で確認できます。&lt;/p&gt;

&lt;p&gt;この方法では、たとえばrepository URLが&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://github.com/aont/foo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;なら、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth token &lt;span class="nt"&gt;--user&lt;/span&gt; aont
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を実行します。&lt;/p&gt;

&lt;p&gt;したがって、基本的には&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repository owner = ghに登録したaccount名
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という運用を前提にします。&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;.gitconfig&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;設定は次のようにします。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[credential]
    useHttpPath = true

[credential "https://github.com/"]
    helper =
    helper = "!f() { \
        [ \"$1\" = get ] || exit 0; \
        account=''; \
        while IFS='=' read -r k v; do \
            [ \"$k\" = path ] &amp;amp;&amp;amp; account=${v%%/*}; \
        done; \
        [ -n \"$account\" ] || exit 0; \
        token=$(gh auth token --user \"$account\") || exit 0; \
        printf 'username=%s\\npassword=%s\\n' \"$account\" \"$token\"; \
    }; f"

[credential "https://gist.github.com/"]
    helper =
    helper = "!f() { \
        [ \"$1\" = get ] || exit 0; \
        account=''; \
        while IFS='=' read -r k v; do \
            [ \"$k\" = path ] &amp;amp;&amp;amp; account=${v%%/*}; \
        done; \
        [ -n \"$account\" ] || exit 0; \
        token=$(gh auth token --user \"$account\") || exit 0; \
        printf 'username=%s\\npassword=%s\\n' \"$account\" \"$token\"; \
    }; f"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ポイントは3つあります。&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;credential.useHttpPath = true&lt;/code&gt; が重要
&lt;/h2&gt;

&lt;p&gt;通常、Gitのcredential helperには&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protocol=https
host=github.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;程度しか渡されません。&lt;/p&gt;

&lt;p&gt;しかし今回必要なのは、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aont/foo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;というpathです。&lt;/p&gt;

&lt;p&gt;そこで、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[credential]
    useHttpPath = true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を設定します。&lt;/p&gt;

&lt;p&gt;これによってcredential helperの標準入力に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protocol=https
host=github.com
path=aont/foo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のようにpathも渡されます。&lt;/p&gt;

&lt;h2&gt;
  
  
  pathの先頭をaccountとして使う
&lt;/h2&gt;

&lt;p&gt;helper内では、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$k&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; path &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;v&lt;/span&gt;&lt;span class="p"&gt;%%/*&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;として、pathの最初の要素を取得しています。&lt;/p&gt;

&lt;p&gt;たとえば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;path=aont/foo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;なら、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;account=aont
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;になります。&lt;/p&gt;

&lt;p&gt;その後、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;token&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;gh auth token &lt;span class="nt"&gt;--user&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$account&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;で、そのアカウントに対応するPATをGitHub CLIから取得します。&lt;/p&gt;

&lt;p&gt;つまり、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://github.com/aont/foo.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;へのアクセス時は自動的に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth token &lt;span class="nt"&gt;--user&lt;/span&gt; aont
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;相当になります。&lt;/p&gt;

&lt;p&gt;一方、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://github.com/another-user/bar.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;なら、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth token &lt;span class="nt"&gt;--user&lt;/span&gt; another-user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;になります。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;gh auth switch&lt;/code&gt;を毎回実行する必要はありません。&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;helper =&lt;/code&gt; で既存credential helperをリセットする
&lt;/h2&gt;

&lt;p&gt;もう一つ重要なのが、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helper =
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;です。&lt;/p&gt;

&lt;p&gt;Git for Windowsなどでは、すでにGit Credential Managerや&lt;code&gt;gh auth git-credential&lt;/code&gt;などが設定されている場合があります。&lt;/p&gt;

&lt;p&gt;たとえば別のhelperが先にcredentialを返すと、今回のhelperまで処理が回ってきません。&lt;/p&gt;

&lt;p&gt;その結果、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;remote: Permission to foo/bar.git denied to wrong-account.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のようになります。&lt;/p&gt;

&lt;p&gt;そこで、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;helper =
helper = "!f() { ... }; f"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;とします。&lt;/p&gt;

&lt;p&gt;最初の空の&lt;code&gt;helper =&lt;/code&gt;で、それ以前に設定されていたcredential helperをリセットし、その後に今回のhelperだけを登録しています。&lt;/p&gt;

&lt;p&gt;複数GitHubアカウントを扱う場合には、この部分がかなり重要です。&lt;/p&gt;

&lt;h2&gt;
  
  
  Gistにも同じ仕組みを使う
&lt;/h2&gt;

&lt;p&gt;Gistにも同じcredential helperを設定できます。&lt;/p&gt;

&lt;p&gt;ただし通常のGist clone URLは、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://gist.github.com/GIST_ID.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;となっていて、URLからユーザー名を判断できません。&lt;/p&gt;

&lt;p&gt;そこで、この運用ではGistのremote URLを意図的に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://gist.github.com/USER/GIST_ID.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という形式にします。&lt;/p&gt;

&lt;p&gt;たとえば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://gist.github.com/aont/0123456789abcdef.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;なら、credential helperから見ると、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;path=aont/0123456789abcdef.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;となるので、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth token &lt;span class="nt"&gt;--user&lt;/span&gt; aont
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を自動的に使えます。&lt;/p&gt;

&lt;p&gt;つまりGitHub repositoryとGistを同じルールで扱えます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;github.com/USER/REPO
gist.github.com/USER/GIST
                ↓
             USERを抽出
                ↓
gh auth token --user USER
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  動作確認
&lt;/h2&gt;

&lt;p&gt;Gitが実際にどのcredentialを取得するかは、&lt;code&gt;git credential fill&lt;/code&gt;で確認できます。&lt;/p&gt;

&lt;p&gt;たとえば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'%s\n'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'protocol=https'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'host=github.com'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;'path=aont/foo.git'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s1"&gt;''&lt;/span&gt; |
git credential fill
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を実行します。&lt;/p&gt;

&lt;p&gt;期待する出力は、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;protocol=https
host=github.com
username=aont
password=...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;です。&lt;/p&gt;

&lt;p&gt;ここで&lt;code&gt;username&lt;/code&gt;が別アカウントになっている場合は、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config &lt;span class="nt"&gt;--show-origin&lt;/span&gt; &lt;span class="nt"&gt;--get-all&lt;/span&gt; credential.helper
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;で、別のcredential helperが残っていないか確認するとよいです。&lt;/p&gt;

&lt;h2&gt;
  
  
  なぜ&lt;code&gt;gh auth git-credential&lt;/code&gt;をそのまま使わないのか
&lt;/h2&gt;

&lt;p&gt;GitHub CLIには標準で、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth git-credential
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;があります。&lt;/p&gt;

&lt;p&gt;通常の単一アカウント運用ならこれで十分です。&lt;/p&gt;

&lt;p&gt;ただ、複数アカウントを同一ホスト&lt;code&gt;github.com&lt;/code&gt;で使っている場合、「repository ownerに応じてどの&lt;code&gt;gh&lt;/code&gt; accountを使うか」を明示的に制御したくなります。&lt;/p&gt;

&lt;p&gt;今回のhelperでは、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;remote URL
    ↓
ownerを抽出
    ↓
gh auth token --user owner
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という非常に単純な規則にしているため、現在どのアカウントが&lt;code&gt;gh&lt;/code&gt;でactiveになっているかを意識する必要がありません。&lt;/p&gt;

&lt;h2&gt;
  
  
  この構成の利点
&lt;/h2&gt;

&lt;p&gt;この方法だとPATそのものを&lt;code&gt;.gitconfig&lt;/code&gt;に保存しません。&lt;/p&gt;

&lt;p&gt;PATは必要になるたびに、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth token &lt;span class="nt"&gt;--user&lt;/span&gt; ACCOUNT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;から取得します。&lt;/p&gt;

&lt;p&gt;そのため、設定として保存されるのは「どのアカウントを使うか」というルールだけです。&lt;/p&gt;

&lt;p&gt;また、repositoryごとに、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh auth switch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;したり、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git config credential.username ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を設定したりする必要もありません。&lt;/p&gt;

&lt;p&gt;remote URLそのものがcredential routingの情報になります。&lt;/p&gt;

&lt;h2&gt;
  
  
  まとめ
&lt;/h2&gt;

&lt;p&gt;複数GitHubアカウントをHTTPSで使う場合、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;github.com/&amp;lt;account&amp;gt;/&amp;lt;repo&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;の&lt;code&gt;account&lt;/code&gt;部分をそのまま&lt;code&gt;gh&lt;/code&gt;のaccount選択に使うと、かなりシンプルに運用できます。&lt;/p&gt;

&lt;p&gt;仕組みとしては、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Git remote URL
  ↓
credential.useHttpPath
  ↓
path=owner/repo.git
  ↓
ownerを抽出
  ↓
gh auth token --user owner
  ↓
username/passwordとしてGitへ返す
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;だけです。&lt;/p&gt;

&lt;p&gt;個人アカウントを複数使っていて、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;repository owner = GitHub account
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という関係が成立している環境なら、かなり扱いやすい方法だと思います。&lt;/p&gt;

&lt;p&gt;Organization配下のrepositoryなどで、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;owner != 認証に使うaccount
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;となる場合だけは別途マッピングが必要ですが、個人アカウント中心ならまずこの構成で十分です。&lt;/p&gt;

</description>
      <category>automation</category>
      <category>cli</category>
      <category>git</category>
      <category>github</category>
    </item>
    <item>
      <title>Using Windows ssh-agent with MSYS2's ssh</title>
      <dc:creator>vast cow</dc:creator>
      <pubDate>Wed, 26 Aug 2026 06:58:14 +0000</pubDate>
      <link>https://dev.to/vast-cow/using-windows-ssh-agent-with-msys2s-ssh-20e7</link>
      <guid>https://dev.to/vast-cow/using-windows-ssh-agent-with-msys2s-ssh-20e7</guid>
      <description>&lt;h2&gt;
  
  
  Using OmniSSHAgent
&lt;/h2&gt;

&lt;p&gt;Windows comes with standard OpenSSH and &lt;code&gt;ssh-agent&lt;/code&gt;. MSYS2 also has &lt;code&gt;/usr/bin/ssh&lt;/code&gt;, allowing you to use SSH, Git, rsync, and other tools in a Unix-like environment.&lt;/p&gt;

&lt;p&gt;The problem is that &lt;strong&gt;you can't directly use keys registered in Windows' &lt;code&gt;ssh-agent&lt;/code&gt; with MSYS2's &lt;code&gt;ssh&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This article will outline why this problem occurs, what solutions are available, and then introduce a configuration using &lt;strong&gt;OmniSSHAgent&lt;/strong&gt;, which I personally find the easiest to use.&lt;/p&gt;

&lt;p&gt;As of August 2026, using OmniSSHAgent is a good first choice for Windows 11 x64 environments.&lt;/p&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;The configuration is as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MSYS2 /usr/bin/ssh
        │
        │ SSH_AUTH_SOCK
        ▼
Cygwin/MSYS2 compatible socket
        │
        │ OmniSSHAgent
        ▼
Windows OpenSSH ssh-agent
        │
        ▼
Private key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OmniSSHAgent is not an SSH agent that manages private keys itself.&lt;/p&gt;

&lt;p&gt;It's a &lt;strong&gt;bridge that converts the interface&lt;/strong&gt; so that you can use the standard Windows OpenSSH Authentication Agent from MSYS2/Cygwin. The current OmniSSHAgent connects to the Windows OpenSSH agent's &lt;code&gt;\\.\pipe\openssh-ssh-agent&lt;/code&gt; and publishes a Cygwin/MSYS2 compatible interface.&lt;/p&gt;

&lt;p&gt;The advantages of this configuration are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You can use the standard Windows &lt;code&gt;ssh-agent&lt;/code&gt; for key management.&lt;/li&gt;
&lt;li&gt;You can use MSYS2's &lt;code&gt;/usr/bin/ssh&lt;/code&gt; directly.&lt;/li&gt;
&lt;li&gt;Git, scp, rsync, and other tools can use the same agent.&lt;/li&gt;
&lt;li&gt;It can start automatically after Windows relogin.&lt;/li&gt;
&lt;li&gt;It can also be used with the Pageant interface for PuTTY / WinSCP / TortoiseGit.&lt;/li&gt;
&lt;li&gt;OmniSSHAgent itself does not store private keys or passphrases.&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Why can't you use Windows' ssh-agent directly?
&lt;/h1&gt;

&lt;p&gt;Windows OpenSSH and MSYS2 OpenSSH both have commands named &lt;code&gt;ssh&lt;/code&gt;, so it seems like you should be able to connect directly.&lt;/p&gt;

&lt;p&gt;However, the communication methods with the SSH agent are different.&lt;/p&gt;

&lt;p&gt;Windows OpenSSH uses Windows Named Pipes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\\.\pipe\openssh-ssh-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the other hand, MSYS2, Cygwin, and Git for Windows' Unix-like OpenSSH use Cygwin/MSYS2-style sockets via &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Therefore,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows OpenSSH
    ↓
Windows Named Pipe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MSYS2 OpenSSH
    ↓
Cygwin/MSYS2 compatible socket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;are different.&lt;/p&gt;

&lt;p&gt;The OmniSSHAgent README explains that the reason this tool exists is that Windows native OpenSSH, Pageant, and Git for Windows/MSYS2/Cygwin all use incompatible SSH agent interfaces.&lt;/p&gt;

&lt;p&gt;Therefore, simply setting&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\\.\pipe\openssh-ssh-agent'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in MSYS2 will not solve the problem.&lt;/p&gt;

&lt;p&gt;What is needed is a &lt;strong&gt;bridge that translates between the protocols/socket formats&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  Comparing solutions
&lt;/h1&gt;

&lt;p&gt;There are several ways to use Windows' &lt;code&gt;ssh-agent&lt;/code&gt; from MSYS2.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;MSYS2 &lt;code&gt;/usr/bin/ssh&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;Ease of Setup&lt;/th&gt;
&lt;th&gt;Recommendation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OmniSSHAgent&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;★★★★★&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sshwin-msys2&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;td&gt;Relatively High&lt;/td&gt;
&lt;td&gt;★★★★☆&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;socat + npiperelay&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;td&gt;Somewhat Complex&lt;/td&gt;
&lt;td&gt;★★☆☆☆&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use Windows &lt;code&gt;ssh.exe&lt;/code&gt; directly&lt;/td&gt;
&lt;td&gt;×&lt;/td&gt;
&lt;td&gt;Very Easy&lt;/td&gt;
&lt;td&gt;Depends on Use Case&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Directly specify Named Pipe as &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;×&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;Not Possible&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For Windows 11 x64, &lt;strong&gt;OmniSSHAgent is the most complete choice&lt;/strong&gt; at the moment.&lt;/p&gt;




&lt;h1&gt;
  
  
  What is OmniSSHAgent?
&lt;/h1&gt;

&lt;p&gt;OmniSSHAgent is an SSH agent compatibility bridge for Windows.&lt;/p&gt;

&lt;p&gt;In its current design,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows OpenSSH Authentication Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is used as the only backend for key management.&lt;/p&gt;

&lt;p&gt;OmniSSHAgent itself does not:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Store private keys&lt;/li&gt;
&lt;li&gt;Store passphrases&lt;/li&gt;
&lt;li&gt;Replace Windows' &lt;code&gt;ssh-agent&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It specializes in adding a&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pageant
Cygwin/MSYS2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;compatible interface to the Windows OpenSSH agent.&lt;/p&gt;

&lt;p&gt;This design is quite straightforward.&lt;/p&gt;

&lt;p&gt;Key management is centralized in&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows OpenSSH ssh-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and OmniSSHAgent only bridges the clients:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows ssh.exe
MSYS2 ssh
Git for Windows
PuTTY
WinSCP
TortoiseGit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Currently, the target environment for OmniSSHAgent MVP is &lt;strong&gt;Windows 11 x86-64&lt;/strong&gt;. Windows 10 and ARM64 are not supported in the current version.&lt;/p&gt;




&lt;h1&gt;
  
  
  1. Enable Windows ssh-agent
&lt;/h1&gt;

&lt;p&gt;First, enable the standard Windows OpenSSH Authentication Agent.&lt;/p&gt;

&lt;p&gt;Open PowerShell with administrator privileges.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-StartupType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Automatic&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Start-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the status.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it shows &lt;code&gt;Running&lt;/code&gt;, it's OK.&lt;/p&gt;

&lt;p&gt;The Microsoft official documentation also provides this setting as a way to automatically start Windows' &lt;code&gt;ssh-agent&lt;/code&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  2. Register the private key in Windows ssh-agent
&lt;/h1&gt;

&lt;p&gt;For example, for an Ed25519 key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ssh-add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;USERPROFILE&lt;/span&gt;&lt;span class="nx"&gt;\.ssh\id_ed25519&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the registered keys.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ssh-add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it displays something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;256 SHA256:xxxxxxxxxxxxxxxx user@example (ED25519)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then Windows is ready.&lt;/p&gt;

&lt;p&gt;From now on, the main entity managing the keys will be this &lt;strong&gt;Windows &lt;code&gt;ssh-agent&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  3. Install OmniSSHAgent
&lt;/h1&gt;

&lt;p&gt;The OmniSSHAgent official README provides a PowerShell installer.&lt;/p&gt;

&lt;p&gt;Run from PowerShell or PowerShell 7.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;irm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://raw.githubusercontent.com/masahide/OmniSSHAgent/main/install.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The installer will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Obtain the latest x86-64 release&lt;/li&gt;
&lt;li&gt;Verify the SHA-256 checksum&lt;/li&gt;
&lt;li&gt;Place it in &lt;code&gt;%LOCALAPPDATA%\Programs\OmniSSHAgent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create a Start Menu shortcut&lt;/li&gt;
&lt;li&gt;Start OmniSSHAgent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Administrator privileges are not required.&lt;/p&gt;

&lt;p&gt;If you don't want to run the script directly, you can also install it by checking the release contents from GitHub Releases.&lt;/p&gt;

&lt;p&gt;As of August 26, 2026, v0.8.0 is the latest release. v0.8.0 adds tray settings and Windows autostart.&lt;/p&gt;




&lt;h1&gt;
  
  
  4. Enable the Cygwin/MSYS2 interface
&lt;/h1&gt;

&lt;p&gt;When you start OmniSSHAgent, an icon will appear in the notification area.&lt;/p&gt;

&lt;p&gt;From the menu, enable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cygwin/MSYS2 interface
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The current OmniSSHAgent creates a socket descriptor for MSYS2/Cygwin at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%USERPROFILE%\.ssh\omnisshagent-cygwin.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;by default.&lt;/p&gt;




&lt;h1&gt;
  
  
  5. Set SSH_AUTH_SOCK in MSYS2
&lt;/h1&gt;

&lt;p&gt;Start MSYS2 and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;cygpath &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/omnisshagent-cygwin.sock"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/c/Users/example/.ssh/omnisshagent-cygwin.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the same keys that were registered on the Windows side are displayed, it's successful.&lt;/p&gt;

&lt;p&gt;The OmniSSHAgent official README also describes this &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt; setting for MSYS2 / Git Bash / Cygwin.&lt;/p&gt;




&lt;h1&gt;
  
  
  6. Verify that you are actually using MSYS2's ssh
&lt;/h1&gt;

&lt;p&gt;There may be multiple &lt;code&gt;ssh.exe&lt;/code&gt; files on Windows, so it's a good idea to check.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;which ssh
which ssh-add
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The one you want to use is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/bin/ssh
/usr/bin/ssh-add
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;which ssh
/usr/bin/ssh

&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
256 SHA256:...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If so, communication is happening via:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MSYS2 OpenSSH → OmniSSHAgent → Windows ssh-agent&lt;/strong&gt;.&lt;/p&gt;




&lt;h1&gt;
  
  
  7. Automate by adding to .bashrc
&lt;/h1&gt;

&lt;p&gt;You don't need to set &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt; every time.&lt;/p&gt;

&lt;p&gt;Add the following to &lt;code&gt;~/.bashrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;cygpath &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/omnisshagent-cygwin.sock"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open a new MSYS2 shell and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it succeeds, you're done.&lt;/p&gt;




&lt;h1&gt;
  
  
  After restarting/re-logging into Windows
&lt;/h1&gt;

&lt;p&gt;This is another point where OmniSSHAgent is easy to use.&lt;/p&gt;

&lt;p&gt;If autostart is configured correctly, you usually don't need to manually start OmniSSHAgent every time you relogin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Windows ssh-agent
&lt;/h2&gt;

&lt;p&gt;Windows' &lt;code&gt;ssh-agent&lt;/code&gt; is set as a service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-StartupType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Automatic&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;so it starts automatically when Windows starts.&lt;/p&gt;




&lt;h2&gt;
  
  
  OmniSSHAgent
&lt;/h2&gt;

&lt;p&gt;In the notification area, enable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start with Windows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This registers autostart for the current user.&lt;/p&gt;

&lt;p&gt;Administrator privileges are not required.&lt;/p&gt;

&lt;p&gt;This feature was added in OmniSSHAgent v0.8.0.&lt;/p&gt;




&lt;h2&gt;
  
  
  MSYS2
&lt;/h2&gt;

&lt;p&gt;Add the following to &lt;code&gt;~/.bashrc&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;cygpath &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/omnisshagent-cygwin.sock"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;so it's automatically set when the MSYS2 shell starts.&lt;/p&gt;

&lt;p&gt;Therefore, overall:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows startup
    ↓
Windows ssh-agent starts automatically
    ↓
Windows login
    ↓
OmniSSHAgent starts automatically
    ↓
omnisshagent-cygwin.sock is created
    ↓
MSYS2 startup
    ↓
.bashrc sets SSH_AUTH_SOCK
    ↓
/usr/bin/ssh uses Windows ssh-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For normal operation, you just start MSYS2 and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  How to verify after relogin
&lt;/h1&gt;

&lt;p&gt;When problems occur, it's easier to check from the top down.&lt;/p&gt;

&lt;p&gt;First, in PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check if it's &lt;code&gt;Running&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ssh-add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to check if the keys are visible to the Windows agent.&lt;/p&gt;

&lt;p&gt;Next, check if OmniSSHAgent is running in the notification area.&lt;/p&gt;

&lt;p&gt;Finally, in MSYS2:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will make it easier to isolate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Key problem
Windows ssh-agent problem
OmniSSHAgent problem
MSYS2 environment variable problem
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OmniSSHAgent has logging and diagnostics features, and the logs are saved at:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%LOCALAPPDATA%\OmniSSHAgent\logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Security considerations for OmniSSHAgent
&lt;/h1&gt;

&lt;p&gt;When evaluating OmniSSHAgent, it's important to note that &lt;strong&gt;it does not store the private keys themselves&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In the current design:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Private key
    ↓
Windows OpenSSH ssh-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The private key is stored there, and OmniSSHAgent only bridges the signing requests.&lt;/p&gt;

&lt;p&gt;The official README explains the security model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does not store private keys&lt;/li&gt;
&lt;li&gt;Does not store passphrases&lt;/li&gt;
&lt;li&gt;Does not write SSH agent payloads to logs&lt;/li&gt;
&lt;li&gt;Cygwin compatibility listener is bound only to &lt;code&gt;127.0.0.1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Uses nonce handshake for Cygwin socket descriptor&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course, even when using an SSH agent, there are SSH agent-specific security considerations regarding "signing requests from processes that can access the agent."&lt;/p&gt;

&lt;p&gt;However, centralizing key management in Windows OpenSSH agent is a management advantage compared to registering the same private keys in multiple agents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows agent
MSYS2 agent
Pageant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  sshwin-msys2 as an alternative
&lt;/h1&gt;

&lt;p&gt;Another tool, &lt;code&gt;sshwin-msys2&lt;/code&gt;, is also available.&lt;/p&gt;

&lt;p&gt;This also uses the Windows OpenSSH named pipe as a backend and creates a socket descriptor that MSYS2 can recognize.&lt;/p&gt;

&lt;p&gt;In a standard &lt;code&gt;C:\msys64&lt;/code&gt; environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\MSYS64\tmp\sshwin-msys2.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is created, and on the MSYS2 side:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/sshwin-msys2.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is set.&lt;/p&gt;

&lt;p&gt;The README also states that it has been tested with Windows 10 build 19044 and MSYS2, Git Bash, and WSL2.&lt;/p&gt;

&lt;p&gt;Therefore,&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you are using Windows 10, sshwin-msys2 is also a viable option.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;However, for Windows 11 x64, OmniSSHAgent is easier to use because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tray application&lt;/li&gt;
&lt;li&gt;Cygwin/MSYS2 interface&lt;/li&gt;
&lt;li&gt;Pageant interface&lt;/li&gt;
&lt;li&gt;Windows autostart&lt;/li&gt;
&lt;li&gt;Logging&lt;/li&gt;
&lt;li&gt;Diagnostics&lt;/li&gt;
&lt;li&gt;Centralization on the Windows OpenSSH backend&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  What about socat + npiperelay?
&lt;/h1&gt;

&lt;p&gt;Another method often mentioned is combining:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;socat
+
npiperelay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to connect Windows Named Pipes and Unix sockets.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MSYS2 ssh
 ↓
Unix socket
 ↓
socat
 ↓
npiperelay
 ↓
Windows Named Pipe
 ↓
Windows ssh-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a common method in WSL, but problems may arise with how MSYS2 handles native Windows executables and standard input/output.&lt;/p&gt;

&lt;p&gt;In fact, issue #13 in the npiperelay repository describes a case where someone tried to connect from MSYS2 to the Windows OpenSSH agent and encountered:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;copy from stdin to pipe failed:
read /dev/stdin: invalid argument
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Since the number of components is also increasing, OmniSSHAgent or sshwin-msys2 are simpler solutions if the goal is only MSYS2.&lt;/p&gt;




&lt;h1&gt;
  
  
  Using Windows ssh.exe directly may be sufficient for Git
&lt;/h1&gt;

&lt;p&gt;If the goal is only:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone
git pull
git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then you don't need to use MSYS2's &lt;code&gt;ssh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can make Git use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\Windows\System32\OpenSSH\ssh.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;directly, which uses the Windows &lt;code&gt;ssh-agent&lt;/code&gt; directly.&lt;/p&gt;

&lt;p&gt;This method is very simple.&lt;/p&gt;

&lt;p&gt;However, if you want to use the MSYS2 OpenSSH itself, such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/usr/bin/ssh
scp
sftp
rsync &lt;span class="nt"&gt;-e&lt;/span&gt; ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then OmniSSHAgent is more suitable.&lt;/p&gt;




&lt;h1&gt;
  
  
  About WSL2
&lt;/h1&gt;

&lt;p&gt;Note that the current OmniSSHAgent &lt;strong&gt;does not directly bridge the socket for WSL2&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In the current OmniSSHAgent design:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MSYS2 / Cygwin
    → OmniSSHAgent

Pageant
    → OmniSSHAgent

WSL2
    → Pipeferry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the roles are divided.&lt;/p&gt;

&lt;p&gt;If you want to use the Windows OpenSSH agent from WSL2, Pipeferry, which is by the same author, is recommended.&lt;/p&gt;

&lt;p&gt;Older articles about OmniSSHAgent may mention WSL functionality, so be careful when searching.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why I recommend OmniSSHAgent
&lt;/h1&gt;

&lt;p&gt;If the premise is Windows 11 x64 + MSYS2, I recommend OmniSSHAgent.&lt;/p&gt;

&lt;p&gt;It's not just because "it works."&lt;/p&gt;

&lt;p&gt;The design is clearly separated:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Key management
    = Windows OpenSSH ssh-agent

Compatibility conversion
    = OmniSSHAgent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OmniSSHAgent does not create its own key store; it centers on the standard Windows agent.&lt;/p&gt;

&lt;p&gt;Then, it bridges the differences in interface:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows OpenSSH
MSYS2
Cygwin
Git for Windows
PuTTY系アプリ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Furthermore, with v0.8.0, Windows autostart was added, so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh-agent automatic startup
OmniSSHAgent automatic startup
Set SSH_AUTH_SOCK in .bashrc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is all you need to do, and you usually don't need to be aware of the bridge in daily use.&lt;/p&gt;




&lt;h1&gt;
  
  
  Final Settings
&lt;/h1&gt;

&lt;h2&gt;
  
  
  PowerShell — One-time setup
&lt;/h2&gt;

&lt;p&gt;Administrator PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-StartupType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Automatic&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Start-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;ssh-add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;USERPROFILE&lt;/span&gt;&lt;span class="nx"&gt;\.ssh\id_ed25519&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;ssh-add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  OmniSSHAgent
&lt;/h2&gt;

&lt;p&gt;From the notification area:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Cygwin/MSYS2 interface
✓ Start with Windows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  MSYS2 ~/.bashrc
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;cygpath &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/omnisshagent-cygwin.sock"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Verification
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;which ssh
ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/bin/ssh

256 SHA256:xxxxxxxxxxxxxxxx ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This completes the configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MSYS2 /usr/bin/ssh
      ↓
OmniSSHAgent
      ↓
Windows OpenSSH ssh-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;When using SSH in both Windows and MSYS2, the SSH agent can end up being double-managed.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Register the key in Windows ssh-agent
Register the key in MSYS2 ssh-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This configuration can make startup and &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt; management more complex.&lt;/p&gt;

&lt;p&gt;With OmniSSHAgent, you can:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                ┌─ Windows OpenSSH
                │
Windows          ├─ MSYS2 / Cygwin
OpenSSH agent ───┤
                └─ Pageant compatible apps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This centralizes the Windows OpenSSH agent as the key management center.&lt;/p&gt;

&lt;p&gt;In particular, if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows 11 x64&lt;/li&gt;
&lt;li&gt;You want to use MSYS2's &lt;code&gt;/usr/bin/ssh&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;You want to centralize key management in the Windows ssh-agent&lt;/li&gt;
&lt;li&gt;You want it to be available automatically after relogin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;then OmniSSHAgent is a very user-friendly choice at the moment.&lt;/p&gt;

&lt;p&gt;Ultimately, you only need:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;cygpath &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/omnisshagent-cygwin.sock"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in MSYS2.&lt;/p&gt;

&lt;p&gt;I think it's a relatively clean way to resolve the SSH agent issues that often arise at the boundary between Windows and Unix-like tools.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;OmniSSHAgent README / Architecture / Installation / MSYS2 setup / Security model&lt;/li&gt;
&lt;li&gt;OmniSSHAgent Releases — v0.8.0 adds Windows autostart&lt;/li&gt;
&lt;li&gt;Microsoft Learn — Automatically starting Windows &lt;code&gt;ssh-agent&lt;/code&gt; and &lt;code&gt;ssh-add&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;sshwin-msys2 — Another implementation for using Windows OpenSSH agent from MSYS2&lt;/li&gt;
&lt;li&gt;npiperelay issue #13 — MSYS2 + socat standard input error case&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Windows の ssh-agent を MSYS2 の ssh から使う
&lt;/h1&gt;

&lt;h2&gt;
  
  
  OmniSSHAgent を使う方法
&lt;/h2&gt;

&lt;p&gt;Windows には標準の OpenSSH と &lt;code&gt;ssh-agent&lt;/code&gt; が用意されています。一方、MSYS2 にも &lt;code&gt;/usr/bin/ssh&lt;/code&gt; があり、Unix に近い環境で SSH や Git、rsync などを使えます。&lt;/p&gt;

&lt;p&gt;ここで問題になるのが、&lt;strong&gt;Windows の &lt;code&gt;ssh-agent&lt;/code&gt; に登録した鍵を MSYS2 の &lt;code&gt;ssh&lt;/code&gt; からそのまま利用できない&lt;/strong&gt;ことです。&lt;/p&gt;

&lt;p&gt;この記事では、この問題がなぜ起きるのか、どのような解決策があるのかを整理した上で、個人的に最も扱いやすいと考える &lt;strong&gt;OmniSSHAgent&lt;/strong&gt; を使った構成を紹介します。&lt;/p&gt;

&lt;p&gt;2026年8月時点では、Windows 11 x64 環境であれば OmniSSHAgent を使う方法を第一候補にするのがよいでしょう。&lt;/p&gt;




&lt;h1&gt;
  
  
  結論
&lt;/h1&gt;

&lt;p&gt;先に結論を書くと、構成は次のようにします。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MSYS2 /usr/bin/ssh
        │
        │ SSH_AUTH_SOCK
        ▼
Cygwin/MSYS2互換 socket
        │
        │ OmniSSHAgent
        ▼
Windows OpenSSH ssh-agent
        │
        ▼
秘密鍵
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OmniSSHAgent は秘密鍵を独自管理する SSH agent ではありません。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows 標準の OpenSSH Authentication Agent をそのまま使い、そのインターフェースを MSYS2/Cygwin から利用できる形に変換するブリッジ&lt;/strong&gt;として動作します。現在の OmniSSHAgent は Windows OpenSSH agent の &lt;code&gt;\\.\pipe\openssh-ssh-agent&lt;/code&gt; に接続し、MSYS2/Cygwin 向けの互換インターフェースを公開します。&lt;/p&gt;

&lt;p&gt;この構成の利点は、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows 標準 &lt;code&gt;ssh-agent&lt;/code&gt; を鍵管理の中心にできる&lt;/li&gt;
&lt;li&gt;MSYS2 の &lt;code&gt;/usr/bin/ssh&lt;/code&gt; をそのまま使える&lt;/li&gt;
&lt;li&gt;Git、scp、rsync なども同じ agent を利用できる&lt;/li&gt;
&lt;li&gt;Windows 再ログイン後も自動起動できる&lt;/li&gt;
&lt;li&gt;PuTTY / WinSCP / TortoiseGit 用の Pageant インターフェースも利用可能&lt;/li&gt;
&lt;li&gt;OmniSSHAgent 自体は秘密鍵やパスフレーズを保存しない&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;という点です。&lt;/p&gt;




&lt;h1&gt;
  
  
  なぜ Windows の ssh-agent を直接使えないのか
&lt;/h1&gt;

&lt;p&gt;Windows OpenSSH と MSYS2 OpenSSH は、どちらも &lt;code&gt;ssh&lt;/code&gt; という名前なので一見そのまま接続できそうに見えます。&lt;/p&gt;

&lt;p&gt;しかし SSH agent との通信方式が異なります。&lt;/p&gt;

&lt;p&gt;Windows OpenSSH は Windows の Named Pipe を使用します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;\\.\pipe\openssh-ssh-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;一方、MSYS2、Cygwin、Git for Windows の Unix 系 OpenSSH は、Cygwin/MSYS2 形式の socket を &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt; 経由で利用します。&lt;/p&gt;

&lt;p&gt;つまり、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows OpenSSH
    ↓
Windows Named Pipe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;と、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MSYS2 OpenSSH
    ↓
Cygwin/MSYS2互換 socket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という違いがあります。&lt;/p&gt;

&lt;p&gt;OmniSSHAgent の README でも、Windows ネイティブ OpenSSH、Pageant、Git for Windows/MSYS2/Cygwin がそれぞれ互換性のない SSH agent インターフェースを利用していることが、このツールの存在理由として説明されています。&lt;/p&gt;

&lt;p&gt;そのため、単純に MSYS2 で、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\\.\pipe\openssh-ssh-agent'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;などと設定しても解決しません。&lt;/p&gt;

&lt;p&gt;必要なのは &lt;strong&gt;プロトコル／ソケット形式を橋渡しするブリッジ&lt;/strong&gt;です。&lt;/p&gt;




&lt;h1&gt;
  
  
  解決方法の比較
&lt;/h1&gt;

&lt;p&gt;Windows の &lt;code&gt;ssh-agent&lt;/code&gt; を MSYS2 から使う方法はいくつかあります。&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方法&lt;/th&gt;
&lt;th&gt;MSYS2 &lt;code&gt;/usr/bin/ssh&lt;/code&gt;
&lt;/th&gt;
&lt;th&gt;設定の容易さ&lt;/th&gt;
&lt;th&gt;おすすめ度&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OmniSSHAgent&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;td&gt;高い&lt;/td&gt;
&lt;td&gt;★★★★★&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sshwin-msys2&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;td&gt;比較的高い&lt;/td&gt;
&lt;td&gt;★★★★☆&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;socat + npiperelay&lt;/td&gt;
&lt;td&gt;○&lt;/td&gt;
&lt;td&gt;やや複雑&lt;/td&gt;
&lt;td&gt;★★☆☆☆&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Windows &lt;code&gt;ssh.exe&lt;/code&gt; を直接使う&lt;/td&gt;
&lt;td&gt;×&lt;/td&gt;
&lt;td&gt;非常に簡単&lt;/td&gt;
&lt;td&gt;用途次第&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Named Pipe を &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt; に直接指定&lt;/td&gt;
&lt;td&gt;×&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;td&gt;不可&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Windows 11 x64 なら、現在は &lt;strong&gt;OmniSSHAgent が最もまとまりのよい選択肢&lt;/strong&gt;です。&lt;/p&gt;




&lt;h1&gt;
  
  
  OmniSSHAgent とは
&lt;/h1&gt;

&lt;p&gt;OmniSSHAgent は Windows 用の SSH agent compatibility bridge です。&lt;/p&gt;

&lt;p&gt;現在の設計では、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows OpenSSH Authentication Agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を鍵管理の唯一のバックエンドとして利用します。&lt;/p&gt;

&lt;p&gt;OmniSSHAgent 自身が、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;秘密鍵を保存する&lt;/li&gt;
&lt;li&gt;パスフレーズを保存する&lt;/li&gt;
&lt;li&gt;Windows の &lt;code&gt;ssh-agent&lt;/code&gt; を置き換える&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;わけではありません。&lt;/p&gt;

&lt;p&gt;Windows OpenSSH agent に対して、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pageant
Cygwin/MSYS2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という互換インターフェースを追加する役割に特化しています。&lt;/p&gt;

&lt;p&gt;これは設計としてかなり分かりやすいです。&lt;/p&gt;

&lt;p&gt;鍵管理は、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows OpenSSH ssh-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;に一本化し、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows ssh.exe
MSYS2 ssh
Git for Windows
PuTTY
WinSCP
TortoiseGit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;などのクライアント側だけを OmniSSHAgent が橋渡しします。&lt;/p&gt;

&lt;p&gt;なお、現在の OmniSSHAgent MVP の対象環境は &lt;strong&gt;Windows 11 x86-64&lt;/strong&gt; です。Windows 10 や ARM64 は現行版の対象外とされています。&lt;/p&gt;




&lt;h1&gt;
  
  
  1. Windows ssh-agent を有効にする
&lt;/h1&gt;

&lt;p&gt;まず Windows 標準の OpenSSH Authentication Agent を有効にします。&lt;/p&gt;

&lt;p&gt;管理者権限で PowerShell を起動します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-StartupType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Automatic&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Start-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;状態を確認します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Running&lt;/code&gt; になっていれば OK です。&lt;/p&gt;

&lt;p&gt;Microsoft 公式ドキュメントでも、Windows の &lt;code&gt;ssh-agent&lt;/code&gt; を自動起動する方法としてこの設定が案内されています。&lt;/p&gt;




&lt;h1&gt;
  
  
  2. 秘密鍵を Windows ssh-agent に登録する
&lt;/h1&gt;

&lt;p&gt;例えば Ed25519 鍵なら、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ssh-add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;USERPROFILE&lt;/span&gt;&lt;span class="nx"&gt;\.ssh\id_ed25519&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;登録された鍵を確認します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ssh-add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;例えば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;256 SHA256:xxxxxxxxxxxxxxxx user@example (ED25519)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のように表示されれば Windows 側は準備完了です。&lt;/p&gt;

&lt;p&gt;今後、鍵を管理する主体は OmniSSHAgent ではなく、この &lt;strong&gt;Windows &lt;code&gt;ssh-agent&lt;/code&gt;&lt;/strong&gt; になります。&lt;/p&gt;




&lt;h1&gt;
  
  
  3. OmniSSHAgent をインストールする
&lt;/h1&gt;

&lt;p&gt;OmniSSHAgent 公式 README では PowerShell installer が用意されています。&lt;/p&gt;

&lt;p&gt;PowerShell または PowerShell 7 から実行します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;irm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;https://raw.githubusercontent.com/masahide/OmniSSHAgent/main/install.ps1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;iex&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;インストーラは、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;最新 x86-64 release の取得&lt;/li&gt;
&lt;li&gt;SHA-256 checksum の検証&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;%LOCALAPPDATA%\Programs\OmniSSHAgent&lt;/code&gt; への配置&lt;/li&gt;
&lt;li&gt;Start Menu shortcut の作成&lt;/li&gt;
&lt;li&gt;OmniSSHAgent の起動&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;を行います。&lt;/p&gt;

&lt;p&gt;管理者権限は不要です。&lt;/p&gt;

&lt;p&gt;リモートスクリプトをそのまま実行したくない場合は、GitHub Releases からリリース内容を確認した上で導入する方法でも構いません。&lt;/p&gt;

&lt;p&gt;2026年8月26日時点では v0.8.0 が Latest release として公開されています。v0.8.0 では tray settings と Windows autostart が追加されています。&lt;/p&gt;




&lt;h1&gt;
  
  
  4. Cygwin/MSYS2 interface を有効にする
&lt;/h1&gt;

&lt;p&gt;OmniSSHAgent を起動すると通知領域にアイコンが表示されます。&lt;/p&gt;

&lt;p&gt;メニューから、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Cygwin/MSYS2 interface
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を有効にします。&lt;/p&gt;

&lt;p&gt;現在の OmniSSHAgent はデフォルトで、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%USERPROFILE%\.ssh\omnisshagent-cygwin.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;に MSYS2/Cygwin 用 socket descriptor を作成します。&lt;/p&gt;




&lt;h1&gt;
  
  
  5. MSYS2 に SSH_AUTH_SOCK を設定する
&lt;/h1&gt;

&lt;p&gt;MSYS2 を起動して、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;cygpath &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/omnisshagent-cygwin.sock"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を実行します。&lt;/p&gt;

&lt;p&gt;確認します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;例えば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/c/Users/example/.ssh/omnisshagent-cygwin.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のようになります。&lt;/p&gt;

&lt;p&gt;次に重要なのが、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;です。&lt;/p&gt;

&lt;p&gt;Windows 側で登録した鍵と同じものが表示されれば成功です。&lt;/p&gt;

&lt;p&gt;OmniSSHAgent 公式 README でも、MSYS2 / Git Bash / Cygwin についてこの &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt; 設定が案内されています。&lt;/p&gt;




&lt;h1&gt;
  
  
  6. 本当に MSYS2 の ssh を使っているか確認する
&lt;/h1&gt;

&lt;p&gt;Windows には複数の &lt;code&gt;ssh.exe&lt;/code&gt; が存在することがあるので、一度確認しておくことをおすすめします。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;which ssh
which ssh-add
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;今回使いたいのは、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/bin/ssh
/usr/bin/ssh-add
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;です。&lt;/p&gt;

&lt;p&gt;つまり、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;which ssh
/usr/bin/ssh

&lt;span class="nv"&gt;$ &lt;/span&gt;ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
256 SHA256:...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;となれば、&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;MSYS2版 OpenSSH → OmniSSHAgent → Windows ssh-agent&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;という経路で通信できています。&lt;/p&gt;




&lt;h1&gt;
  
  
  7. .bashrc に設定して自動化する
&lt;/h1&gt;

&lt;p&gt;毎回 &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt; を設定する必要はありません。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;~/.bashrc&lt;/code&gt; に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;cygpath &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/omnisshagent-cygwin.sock"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を追加します。&lt;/p&gt;

&lt;p&gt;新しい MSYS2 shell を開いて、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;が成功すれば完了です。&lt;/p&gt;




&lt;h1&gt;
  
  
  Windows を再起動・再ログインした場合
&lt;/h1&gt;

&lt;p&gt;ここも OmniSSHAgent をおすすめしやすいポイントです。&lt;/p&gt;

&lt;p&gt;自動起動を正しく設定しておけば、普段は再ログインのたびに OmniSSHAgent を手動で起動する必要はありません。&lt;/p&gt;

&lt;h2&gt;
  
  
  Windows ssh-agent
&lt;/h2&gt;

&lt;p&gt;Windows の &lt;code&gt;ssh-agent&lt;/code&gt; はサービスとして、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-StartupType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Automatic&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;にしてあります。&lt;/p&gt;

&lt;p&gt;そのため Windows 起動時に自動で立ち上がります。&lt;/p&gt;




&lt;h2&gt;
  
  
  OmniSSHAgent
&lt;/h2&gt;

&lt;p&gt;通知領域の OmniSSHAgent メニューで、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start with Windows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を有効にします。&lt;/p&gt;

&lt;p&gt;これは現在のユーザーに対する autostart を登録します。&lt;/p&gt;

&lt;p&gt;管理者権限は不要です。&lt;/p&gt;

&lt;p&gt;この機能は OmniSSHAgent v0.8.0 で追加されています。&lt;/p&gt;




&lt;h2&gt;
  
  
  MSYS2
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;~/.bashrc&lt;/code&gt; に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;cygpath &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/omnisshagent-cygwin.sock"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を入れてあるので、MSYS2 shell 起動時に自動設定されます。&lt;/p&gt;

&lt;p&gt;したがって全体として、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows起動
    ↓
Windows ssh-agent 自動起動
    ↓
Windowsログイン
    ↓
OmniSSHAgent 自動起動
    ↓
omnisshagent-cygwin.sock 作成
    ↓
MSYS2起動
    ↓
.bashrc が SSH_AUTH_SOCK を設定
    ↓
/usr/bin/ssh が Windows ssh-agent を利用
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;となります。&lt;/p&gt;

&lt;p&gt;普段の操作としては、MSYS2 を起動して、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;するだけです。&lt;/p&gt;




&lt;h1&gt;
  
  
  再ログイン後の確認方法
&lt;/h1&gt;

&lt;p&gt;問題が起きたときは、上流から順番に確認すると分かりやすいです。&lt;/p&gt;

&lt;p&gt;まず PowerShell で、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;Running&lt;/code&gt; か確認します。&lt;/p&gt;

&lt;p&gt;次に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ssh-add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;で Windows agent に鍵が見えているか確認します。&lt;/p&gt;

&lt;p&gt;次に OmniSSHAgent が通知領域で起動しているか確認します。&lt;/p&gt;

&lt;p&gt;最後に MSYS2 で、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を確認します。&lt;/p&gt;

&lt;p&gt;この順番なら、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;鍵の問題
Windows ssh-agent の問題
OmniSSHAgent の問題
MSYS2環境変数の問題
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を切り分けやすくなります。&lt;/p&gt;

&lt;p&gt;OmniSSHAgent にはログや configuration check 用の機能も用意されており、ログは、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;%LOCALAPPDATA%\OmniSSHAgent\logs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;に保存されます。&lt;/p&gt;




&lt;h1&gt;
  
  
  OmniSSHAgent のセキュリティ面
&lt;/h1&gt;

&lt;p&gt;OmniSSHAgent を評価するときに重要なのは、&lt;strong&gt;秘密鍵そのものを保持しない&lt;/strong&gt;点です。&lt;/p&gt;

&lt;p&gt;現在の設計では、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;秘密鍵
    ↓
Windows OpenSSH ssh-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;に保持され、&lt;/p&gt;

&lt;p&gt;OmniSSHAgent は署名要求などを bridge するだけです。&lt;/p&gt;

&lt;p&gt;公式 README では、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;秘密鍵を保存しない&lt;/li&gt;
&lt;li&gt;passphrase を保存しない&lt;/li&gt;
&lt;li&gt;SSH agent payload をログに書かない&lt;/li&gt;
&lt;li&gt;Cygwin compatibility listener は &lt;code&gt;127.0.0.1&lt;/code&gt; のみに bind&lt;/li&gt;
&lt;li&gt;Cygwin socket descriptor の nonce handshake を使用&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;というセキュリティモデルが説明されています。&lt;/p&gt;

&lt;p&gt;もちろん SSH agent 自体を利用する以上、「agent にアクセスできるプロセスによる署名要求」という SSH agent 共通のセキュリティ上の考慮は残ります。&lt;/p&gt;

&lt;p&gt;それでも、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windowsのagent
MSYS2のagent
Pageant
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;などに同じ秘密鍵を何重にも登録するより、Windows OpenSSH agent に一本化できる点は管理上のメリットがあります。&lt;/p&gt;




&lt;h1&gt;
  
  
  sshwin-msys2 という選択肢
&lt;/h1&gt;

&lt;p&gt;OmniSSHAgent 以外では &lt;code&gt;sshwin-msys2&lt;/code&gt; というツールもあります。&lt;/p&gt;

&lt;p&gt;これも Windows OpenSSH の named pipe を backend として利用し、MSYS2 が認識できる socket descriptor を作ります。&lt;/p&gt;

&lt;p&gt;標準的な &lt;code&gt;C:\msys64&lt;/code&gt; 環境では、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\MSYS64\tmp\sshwin-msys2.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を作成し、MSYS2 側では、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/tmp/sshwin-msys2.sock
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;と設定します。&lt;/p&gt;

&lt;p&gt;README では Windows 10 build 19044 と MSYS2、Git Bash、WSL2 でのテスト実績も記載されています。&lt;/p&gt;

&lt;p&gt;そのため、&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows 10 を使っている場合は sshwin-msys2 も有力候補&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;です。&lt;/p&gt;

&lt;p&gt;一方、Windows 11 x64 なら、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;tray application&lt;/li&gt;
&lt;li&gt;Cygwin/MSYS2 interface&lt;/li&gt;
&lt;li&gt;Pageant interface&lt;/li&gt;
&lt;li&gt;Windows autostart&lt;/li&gt;
&lt;li&gt;logging&lt;/li&gt;
&lt;li&gt;diagnostics&lt;/li&gt;
&lt;li&gt;Windows OpenSSH backend への一本化&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;までまとまっている OmniSSHAgent の方が使いやすいと考えます。&lt;/p&gt;




&lt;h1&gt;
  
  
  socat + npiperelay はどうか
&lt;/h1&gt;

&lt;p&gt;Windows Named Pipe と Unix socket を接続する方法として、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;socat
+
npiperelay
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を組み合わせる方法もよく紹介されています。&lt;/p&gt;

&lt;p&gt;概念的には、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MSYS2 ssh
 ↓
Unix socket
 ↓
socat
 ↓
npiperelay
 ↓
Windows Named Pipe
 ↓
Windows ssh-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;となります。&lt;/p&gt;

&lt;p&gt;WSL ではよく利用される方式ですが、MSYS2 では native Windows executable と MSYS2 の標準入出力の扱いが問題になる場合があります。&lt;/p&gt;

&lt;p&gt;実際、npiperelay の issue には MSYS2 から Windows OpenSSH agent に接続しようとして、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;copy from stdin to pipe failed:
read /dev/stdin: invalid argument
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;となった事例があります。&lt;/p&gt;

&lt;p&gt;構成要素も増えるので、MSYS2 だけが目的なら、現在は OmniSSHAgent や sshwin-msys2 の方が素直です。&lt;/p&gt;




&lt;h1&gt;
  
  
  Git だけなら Windows ssh.exe を使う手もある
&lt;/h1&gt;

&lt;p&gt;目的が、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone
git pull
git push
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;だけなら、そもそも MSYS2 の &lt;code&gt;ssh&lt;/code&gt; を使わない方法もあります。&lt;/p&gt;

&lt;p&gt;Windows の、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\Windows\System32\OpenSSH\ssh.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を Git に使わせれば Windows &lt;code&gt;ssh-agent&lt;/code&gt; を直接利用できます。&lt;/p&gt;

&lt;p&gt;この方法は bridge が不要なので非常に単純です。&lt;/p&gt;

&lt;p&gt;ただし、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/usr/bin/ssh
scp
sftp
rsync &lt;span class="nt"&gt;-e&lt;/span&gt; ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;など &lt;strong&gt;MSYS2 OpenSSH 自体を利用したい場合には解決になりません&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;MSYS2 の Unix 的な環境を維持したい場合は OmniSSHAgent の方が適しています。&lt;/p&gt;




&lt;h1&gt;
  
  
  WSL2 について
&lt;/h1&gt;

&lt;p&gt;注意点として、現在の OmniSSHAgent は &lt;strong&gt;WSL2 の socket bridge を直接担当しません&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;OmniSSHAgent の現在の設計では、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MSYS2 / Cygwin
    → OmniSSHAgent

Pageant
    → OmniSSHAgent

WSL2
    → Pipeferry
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;と役割が分けられています。&lt;/p&gt;

&lt;p&gt;WSL2 から Windows OpenSSH agent を使う場合は、同じ作者による Pipeferry が案内されています。&lt;/p&gt;

&lt;p&gt;古い OmniSSHAgent の記事では WSL 機能も紹介されている場合があるため、検索時には注意が必要です。&lt;/p&gt;




&lt;h1&gt;
  
  
  OmniSSHAgent をおすすめする理由
&lt;/h1&gt;

&lt;p&gt;Windows 11 x64 + MSYS2 という前提なら、OmniSSHAgent をおすすめします。&lt;/p&gt;

&lt;p&gt;理由は単に「動くから」だけではありません。&lt;/p&gt;

&lt;p&gt;設計が、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;鍵管理
    = Windows OpenSSH ssh-agent

互換性変換
    = OmniSSHAgent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;と明確に分離されているからです。&lt;/p&gt;

&lt;p&gt;OmniSSHAgent は独自の鍵ストアを作るのではなく、Windows 標準の agent を中心に据えます。&lt;/p&gt;

&lt;p&gt;その上で、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows OpenSSH
MSYS2
Cygwin
Git for Windows
PuTTY系アプリ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のインターフェース差だけを吸収します。&lt;/p&gt;

&lt;p&gt;さらに v0.8.0 では Windows autostart が入ったため、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh-agent 自動起動
OmniSSHAgent 自動起動
SSH_AUTH_SOCK を .bashrc に設定
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;まで行えば、日常的には bridge の存在を意識する必要がほぼありません。&lt;/p&gt;




&lt;h1&gt;
  
  
  最終的な設定
&lt;/h1&gt;

&lt;h2&gt;
  
  
  PowerShell — 一度だけ
&lt;/h2&gt;

&lt;p&gt;管理者 PowerShell：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Set-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-StartupType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Automatic&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Start-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ssh-agent&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;ssh-add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;USERPROFILE&lt;/span&gt;&lt;span class="nx"&gt;\.ssh\id_ed25519&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;ssh-add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-l&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  OmniSSHAgent
&lt;/h2&gt;

&lt;p&gt;通知領域から、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✓ Cygwin/MSYS2 interface
✓ Start with Windows
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を有効にします。&lt;/p&gt;




&lt;h2&gt;
  
  
  MSYS2 ~/.bashrc
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;cygpath &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/omnisshagent-cygwin.sock"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  動作確認
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;which ssh
ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;期待する状態：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/bin/ssh

256 SHA256:xxxxxxxxxxxxxxxx ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;これで、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MSYS2 /usr/bin/ssh
      ↓
OmniSSHAgent
      ↓
Windows OpenSSH ssh-agent
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という構成が完成します。&lt;/p&gt;




&lt;h1&gt;
  
  
  まとめ
&lt;/h1&gt;

&lt;p&gt;Windows と MSYS2 の両方で SSH を使っていると、SSH agent が二重管理になりがちです。&lt;/p&gt;

&lt;p&gt;例えば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Windows ssh-agent に鍵を登録
MSYS2 ssh-agent にも鍵を登録
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という構成にすると、起動処理や &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt; の管理も複雑になります。&lt;/p&gt;

&lt;p&gt;OmniSSHAgent を使えば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;                ┌─ Windows OpenSSH
                │
Windows          ├─ MSYS2 / Cygwin
OpenSSH agent ───┤
                └─ Pageant互換アプリ
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という形で、&lt;strong&gt;Windows OpenSSH agent を SSH 鍵管理の中心にできます&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;特に、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows 11 x64&lt;/li&gt;
&lt;li&gt;MSYS2 の &lt;code&gt;/usr/bin/ssh&lt;/code&gt; を使いたい&lt;/li&gt;
&lt;li&gt;Windows の ssh-agent に鍵管理を一本化したい&lt;/li&gt;
&lt;li&gt;再ログイン後も自動で利用可能にしたい&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;という環境なら、現時点では OmniSSHAgent が非常に扱いやすい選択肢です。&lt;/p&gt;

&lt;p&gt;MSYS2 側に必要なのは最終的に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;cygpath &lt;span class="nt"&gt;-u&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USERPROFILE&lt;/span&gt;&lt;span class="s2"&gt;/.ssh/omnisshagent-cygwin.sock"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;だけです。&lt;/p&gt;

&lt;p&gt;Windows と Unix 系ツールの境界でありがちな SSH agent 問題を、比較的きれいに解消できる構成だと思います。&lt;/p&gt;

&lt;h2&gt;
  
  
  参考資料
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;OmniSSHAgent README / Architecture / Installation / MSYS2 setup / Security model&lt;/li&gt;
&lt;li&gt;OmniSSHAgent Releases — v0.8.0 で Windows autostart を追加&lt;/li&gt;
&lt;li&gt;Microsoft Learn — Windows OpenSSH &lt;code&gt;ssh-agent&lt;/code&gt; の自動起動と &lt;code&gt;ssh-add&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;sshwin-msys2 — MSYS2 から Windows OpenSSH agent を利用する別実装&lt;/li&gt;
&lt;li&gt;npiperelay issue #13 — MSYS2 + socat での標準入力エラー事例&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>What is the "Alerts" Syntax You Can Use in GitHub Markdown?</title>
      <dc:creator>vast cow</dc:creator>
      <pubDate>Wed, 26 Aug 2026 06:55:58 +0000</pubDate>
      <link>https://dev.to/vast-cow/what-is-the-alerts-syntax-you-can-use-in-github-markdown-40l7</link>
      <guid>https://dev.to/vast-cow/what-is-the-alerts-syntax-you-can-use-in-github-markdown-40l7</guid>
      <description>&lt;p&gt;When reading GitHub READMEs or Issues, you may come across syntax like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; **If you are upgrading from a previous version**&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; The configuration method has changed.&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; Please check the migration procedure before upgrading.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not a regular Markdown quote; it's a Markdown extension called &lt;strong&gt;Alerts&lt;/strong&gt; that GitHub supports.&lt;/p&gt;

&lt;p&gt;On GitHub, it is displayed as a note box with icons and decorations according to the type, such as &lt;code&gt;IMPORTANT&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  It's Not Standard Markdown
&lt;/h2&gt;

&lt;p&gt;First, it's important to understand this part:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the standard Markdown quote syntax.&lt;/p&gt;

&lt;p&gt;On the other hand,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;[!IMPORTANT]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is not part of the standard Markdown specification. It is interpreted as having a special meaning.&lt;/p&gt;

&lt;p&gt;Therefore,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; This is important information.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is a &lt;strong&gt;GitHub-specific extension syntax&lt;/strong&gt; that utilizes Markdown's quote syntax.&lt;/p&gt;

&lt;p&gt;As a result, while it may be displayed as a note box on GitHub, it may be displayed as a simple quote in other Markdown renderers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alert Types You Can Use
&lt;/h2&gt;

&lt;p&gt;GitHub mainly supports the following five types of Alerts:&lt;/p&gt;

&lt;h3&gt;
  
  
  NOTE
&lt;/h3&gt;

&lt;p&gt;Use this to indicate supplementary information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!NOTE]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; This setting is optional.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  TIP
&lt;/h3&gt;

&lt;p&gt;Use this to indicate convenient methods or recommended ways of doing things.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!TIP]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; You can easily check the settings using this command.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  IMPORTANT
&lt;/h3&gt;

&lt;p&gt;Use this for important information that users should definitely know.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; Back up your configuration file before upgrading.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  WARNING
&lt;/h3&gt;

&lt;p&gt;Use this to alert users to operations that may cause problems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!WARNING]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; This operation will overwrite existing settings.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CAUTION
&lt;/h3&gt;

&lt;p&gt;Use this for operations that involve particularly serious risks, such as data loss.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!CAUTION]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; Running this command will delete saved data.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Writing Multiple Lines
&lt;/h2&gt;

&lt;p&gt;If you want to write multiple lines of text within an Alert, add a &lt;code&gt;&amp;gt;&lt;/code&gt; to each line.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; The configuration method has changed.&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; Before upgrading,&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; check the new configuration method.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you want to insert a blank line, write:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the same mechanism as a standard Markdown blockquote.&lt;/p&gt;

&lt;h2&gt;
  
  
  You Can Also Use Bold Text and Links
&lt;/h2&gt;

&lt;p&gt;You can also use standard Markdown syntax within Alerts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; **Check before upgrading**&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; See the [Migration Guide](docs/migration.md) for details.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful when you want to guide readers to important documents in the README.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Should You Use It?
&lt;/h2&gt;

&lt;p&gt;Alerts are useful for making the text in a README easier to read and organize.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Notes for upgrading&lt;/li&gt;
&lt;li&gt;Breaking changes&lt;/li&gt;
&lt;li&gt;Security notes&lt;/li&gt;
&lt;li&gt;Configuration notes&lt;/li&gt;
&lt;li&gt;Common mistakes&lt;/li&gt;
&lt;li&gt;Recommended settings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In particular,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Upgrade&lt;/span&gt;

This describes how to upgrade.
&lt;span class="gt"&gt;
&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; The configuration file format has changed in version 2 and later.&lt;/span&gt;

Run the following command.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using it this way clearly separates the main text from important information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Be Careful Not to Overuse It
&lt;/h2&gt;

&lt;p&gt;Although it is a useful syntax, if you use Alerts for all information, you will end up making it difficult to distinguish the importance of each item.&lt;/p&gt;

&lt;p&gt;For example, if a README is filled with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!NOTE]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; ...&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; [!TIP]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; ...&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; ...&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; [!WARNING]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;like a box full of notes, it will be difficult to determine what to read.&lt;/p&gt;

&lt;p&gt;Basically, use regular text, and use Alerts only for information you really want to highlight.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Display May Change Outside of GitHub
&lt;/h2&gt;

&lt;p&gt;Another thing to keep in mind when using this syntax is the environment in which it will be displayed.&lt;/p&gt;

&lt;p&gt;On GitHub,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; Important information&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is displayed as a dedicated Alert.&lt;/p&gt;

&lt;p&gt;However, in Markdown renderers that do not support this syntax, it may be displayed as a regular quote:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[!IMPORTANT]
Important information
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore, while this syntax is easy to use for documents intended to be read on GitHub, such as GitHub READMEs, you need to be aware of compatibility when displaying documents in various Markdown processing systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The syntax you see on GitHub, such as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is a Markdown extension called &lt;strong&gt;Alerts&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;&amp;gt;&lt;/code&gt; is the standard Markdown quote syntax, but the part that interprets &lt;code&gt;[!IMPORTANT]&lt;/code&gt; and so on as a special note box is not included in standard Markdown.&lt;/p&gt;

&lt;p&gt;On GitHub READMEs and Issues, it is a useful way to visually highlight important information.&lt;/p&gt;

&lt;p&gt;The types you can use are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NOTE
TIP
IMPORTANT
WARNING
CAUTION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When writing important notes in a README, using this Alerts syntax can convey the priority of information more clearly than just using bold text.&lt;/p&gt;

&lt;h1&gt;
  
  
  GitHubのMarkdownで使える「Alerts」記法とは？
&lt;/h1&gt;

&lt;p&gt;GitHub の README や Issue を読んでいると、次のような記法を見かけることがあります。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; **以前のバージョンからアップグレードする場合**&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; 設定方法が変更されています。&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; アップグレード前に移行手順を確認してください。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;これは通常の Markdown の引用ではなく、GitHub がサポートしている &lt;strong&gt;Alerts&lt;/strong&gt; という Markdown 拡張です。&lt;/p&gt;

&lt;p&gt;GitHub 上では、&lt;code&gt;IMPORTANT&lt;/code&gt; のような種類に応じてアイコンや装飾が付いた注意ボックスとして表示されます。&lt;/p&gt;

&lt;h2&gt;
  
  
  標準Markdownではない
&lt;/h2&gt;

&lt;p&gt;まず押さえておきたいのは、次の部分です。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;これは標準的な Markdown の引用記法です。&lt;/p&gt;

&lt;p&gt;一方、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;[!IMPORTANT]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を特別な意味として解釈する仕組みは、標準 Markdown の仕様ではありません。&lt;/p&gt;

&lt;p&gt;つまり、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; 重要な情報です&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という記法は、Markdown の引用構文を利用した &lt;strong&gt;GitHub独自の拡張記法&lt;/strong&gt;です。&lt;/p&gt;

&lt;p&gt;そのため、GitHub では注意ボックスとして表示されても、別の Markdown レンダラーでは単なる引用として表示される場合があります。&lt;/p&gt;

&lt;h2&gt;
  
  
  使用できるAlertの種類
&lt;/h2&gt;

&lt;p&gt;GitHub では、主に次の5種類の Alert が利用できます。&lt;/p&gt;

&lt;h3&gt;
  
  
  NOTE
&lt;/h3&gt;

&lt;p&gt;補足情報を示したい場合に使います。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!NOTE]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; この設定は省略可能です。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  TIP
&lt;/h3&gt;

&lt;p&gt;便利な方法やおすすめの使い方を示す場合に使います。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!TIP]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; このコマンドを使うと設定を簡単に確認できます。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  IMPORTANT
&lt;/h3&gt;

&lt;p&gt;ユーザーに必ず知っておいてほしい重要事項に使います。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; アップグレード前に設定ファイルをバックアップしてください。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  WARNING
&lt;/h3&gt;

&lt;p&gt;問題が発生する可能性がある操作について注意を促す場合に使います。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!WARNING]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; この操作を行うと既存の設定が上書きされます。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  CAUTION
&lt;/h3&gt;

&lt;p&gt;データ損失など、特に重大なリスクを伴う操作に使います。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!CAUTION]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; このコマンドを実行すると保存済みデータが削除されます。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  複数行を書く場合
&lt;/h2&gt;

&lt;p&gt;Alert の中に複数行の文章を書く場合は、それぞれの行に &lt;code&gt;&amp;gt;&lt;/code&gt; を付けます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; 設定方法が変更されています。&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; アップグレードする前に、&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; 新しい設定方法を確認してください。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;空行を入れたい場合も、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;と書きます。&lt;/p&gt;

&lt;p&gt;通常の Markdown の blockquote と同じ仕組みです。&lt;/p&gt;

&lt;h2&gt;
  
  
  太字やリンクも使える
&lt;/h2&gt;

&lt;p&gt;Alert の中では、通常の Markdown 記法も利用できます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; **アップグレードする前に確認してください**&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; 詳細は[移行ガイド](docs/migration.md)を参照してください。&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;README の中で重要なドキュメントへ誘導するときには便利です。&lt;/p&gt;

&lt;h2&gt;
  
  
  どんな場面で使うとよいか
&lt;/h2&gt;

&lt;p&gt;Alerts は、README の文章を読みやすく整理するのに向いています。&lt;/p&gt;

&lt;p&gt;たとえば、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;バージョンアップ時の注意事項&lt;/li&gt;
&lt;li&gt;破壊的変更&lt;/li&gt;
&lt;li&gt;セキュリティ上の注意&lt;/li&gt;
&lt;li&gt;設定時の補足&lt;/li&gt;
&lt;li&gt;よくあるミス&lt;/li&gt;
&lt;li&gt;推奨設定&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;などです。&lt;/p&gt;

&lt;p&gt;特に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Upgrade&lt;/span&gt;

アップグレード方法について説明します。
&lt;span class="gt"&gt;
&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; バージョン2以降では設定ファイルの形式が変更されています。&lt;/span&gt;

次のコマンドを実行します。
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のように使うと、通常の本文と重要事項を明確に分けられます。&lt;/p&gt;

&lt;h2&gt;
  
  
  使いすぎには注意
&lt;/h2&gt;

&lt;p&gt;便利な記法ですが、すべての情報を Alert にしてしまうと、かえって重要度が分かりにくくなります。&lt;/p&gt;

&lt;p&gt;たとえば README が、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!NOTE]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; ...&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; [!TIP]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; ...&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; ...&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; [!WARNING]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のような注意ボックスだらけになると、どこを読むべきなのか判断しづらくなります。&lt;/p&gt;

&lt;p&gt;基本的には通常の文章を使い、本当に目立たせたい情報だけを Alert にするのがよいでしょう。&lt;/p&gt;

&lt;h2&gt;
  
  
  GitHub以外では表示が変わる可能性がある
&lt;/h2&gt;

&lt;p&gt;この記法を使う場合にもう一つ注意したいのが、表示する環境です。&lt;/p&gt;

&lt;p&gt;GitHub 上では、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; 重要な情報&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;が専用の Alert として表示されます。&lt;/p&gt;

&lt;p&gt;しかし、この記法に対応していない Markdown レンダラーでは、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[!IMPORTANT]
重要な情報
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という普通の引用として表示される可能性があります。&lt;/p&gt;

&lt;p&gt;そのため、GitHub README のように &lt;strong&gt;GitHub上で読むことを前提とした文書&lt;/strong&gt;では使いやすい記法ですが、さまざまな Markdown 処理系で表示する文書では互換性を意識する必要があります。&lt;/p&gt;

&lt;h2&gt;
  
  
  まとめ
&lt;/h2&gt;

&lt;p&gt;GitHub で見かける、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!IMPORTANT]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という記法は、GitHub の &lt;strong&gt;Alerts&lt;/strong&gt; と呼ばれる Markdown 拡張です。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;gt;&lt;/code&gt; は標準 Markdown の引用記法ですが、&lt;code&gt;[!IMPORTANT]&lt;/code&gt; などを特別な注意ボックスとして解釈する部分は標準 Markdown には含まれていません。&lt;/p&gt;

&lt;p&gt;GitHub の README や Issue では、重要事項を視覚的に目立たせる方法として便利です。&lt;/p&gt;

&lt;p&gt;利用できる種類は、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NOTE
TIP
IMPORTANT
WARNING
CAUTION
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;の5種類です。&lt;/p&gt;

&lt;p&gt;README に重要な注意事項を書くときは、単純な太字だけでなく、この Alerts 記法を使うと情報の優先度をより分かりやすく伝えられます。&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Safely Manually Edit the Bash History File</title>
      <dc:creator>vast cow</dc:creator>
      <pubDate>Mon, 24 Aug 2026 13:52:31 +0000</pubDate>
      <link>https://dev.to/vast-cow/how-to-safely-manually-edit-the-bash-history-file-38ie</link>
      <guid>https://dev.to/vast-cow/how-to-safely-manually-edit-the-bash-history-file-38ie</guid>
      <description>&lt;p&gt;Bash command history is normally stored in &lt;code&gt;$HISTFILE&lt;/code&gt; (in many environments, &lt;code&gt;~/.bash_history&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Sometimes you may want to edit this file directly in an editor, for example to delete a batch of unwanted history entries.&lt;/p&gt;

&lt;p&gt;However, care is required in environments where multiple Bash sessions are open at the same time. If you simply edit &lt;code&gt;$HISTFILE&lt;/code&gt;, your changes may later be overwritten by history held by another Bash session.&lt;/p&gt;

&lt;p&gt;This article outlines a procedure for &lt;strong&gt;editing the history file as safely as possible while keeping multiple Bash sessions open&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bash History Exists Both in Memory and in a File
&lt;/h2&gt;

&lt;p&gt;The first thing to understand is that Bash history is not managed solely through &lt;code&gt;$HISTFILE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Each running Bash process independently keeps its own history in memory.&lt;/p&gt;

&lt;p&gt;For example, if Bash is running in three terminals, the situation looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bash A ── history in memory
Bash B ── history in memory
Bash C ── history in memory
              ↓
         $HISTFILE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore, when directly editing &lt;code&gt;$HISTFILE&lt;/code&gt;, you need to consider not only the file itself, but also &lt;strong&gt;the history held by each Bash process&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, Write Out the History from All Sessions and Disable History Recording
&lt;/h2&gt;

&lt;p&gt;First, run the following in &lt;strong&gt;every Bash session&lt;/strong&gt; that is currently open:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; +o &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;history -a&lt;/code&gt; appends history entries from that Bash session that have not yet been saved to &lt;code&gt;$HISTFILE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In other words, by running it in every session, you can collect each session's unsaved history into the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bash A ─┐
Bash B ─┼─ history -a → $HISTFILE
Bash C ─┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next command,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt; +o &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;temporarily disables history recording in that Bash session.&lt;/p&gt;

&lt;p&gt;The key point is to run this in &lt;strong&gt;every session&lt;/strong&gt; as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edit the History File from One Session
&lt;/h2&gt;

&lt;p&gt;Once you have run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; +o &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in every Bash session, edit &lt;code&gt;$HISTFILE&lt;/code&gt; from one of them.&lt;/p&gt;

&lt;p&gt;For example, with Emacs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;emacsclient &lt;span class="nt"&gt;-nw&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Of course, you can use any editor you like.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vim &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;vi&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will work as well.&lt;/p&gt;

&lt;p&gt;Make the necessary changes, such as deleting unwanted history entries, and save the file.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reload the History in Every Session After Editing
&lt;/h2&gt;

&lt;p&gt;Simply editing the file does not remove the &lt;strong&gt;pre-edit history still held in memory&lt;/strong&gt; by Bash processes that are already running.&lt;/p&gt;

&lt;p&gt;Therefore, run the following again in &lt;strong&gt;every Bash session&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each command has the following meaning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;clears the history currently held in memory by that Bash process.&lt;/p&gt;

&lt;p&gt;Next,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;loads the edited &lt;code&gt;$HISTFILE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Finally,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;re-enables history recording.&lt;/p&gt;

&lt;p&gt;This puts the sessions into the following state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              edited $HISTFILE
                    │
          history -r│
          ┌─────────┼─────────┐
          ↓         ↓         ↓
       Bash A    Bash B    Bash C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All sessions will now operate using the edited history as their baseline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary of the Procedure
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Run in every Bash session
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; +o &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Edit the history in one Bash session
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;vi&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Run in every Bash session
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the basic procedure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use &lt;code&gt;history -a&lt;/code&gt; Instead of &lt;code&gt;history -w&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;At first glance, it may seem safer to run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;before editing.&lt;/p&gt;

&lt;p&gt;However, caution is required when multiple Bash sessions exist.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;history -w&lt;/code&gt; &lt;strong&gt;rewrites &lt;code&gt;$HISTFILE&lt;/code&gt; using the history currently held in memory by the current Bash process&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For example, suppose you have:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bash A history: A1 A2 A3
Bash B history: B1 B2 B3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even if Bash B's history has already been written to &lt;code&gt;$HISTFILE&lt;/code&gt;, Bash A may not have loaded it.&lt;/p&gt;

&lt;p&gt;If you then run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;from Bash A, the file will be rewritten based on the history known to Bash A, potentially causing history originating from other sessions to be lost.&lt;/p&gt;

&lt;p&gt;By contrast,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;appends&lt;/strong&gt; unsaved history entries.&lt;/p&gt;

&lt;p&gt;Therefore, when collecting history from multiple sessions,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is more appropriate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Even This Is Not "Perfect"
&lt;/h2&gt;

&lt;p&gt;Following the procedure above makes the operation considerably safer, but strictly speaking, it is not foolproof.&lt;/p&gt;

&lt;p&gt;The Bash history file is not a transactional database designed for concurrent updates from multiple Bash processes.&lt;/p&gt;

&lt;p&gt;In other words, if a new command is executed in another session while you are running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in each session, or if writes to the history file overlap, timing-dependent problems can still occur.&lt;/p&gt;

&lt;p&gt;Also, commands executed after&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt; +o &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;will not be recorded in that session's normal history.&lt;/p&gt;

&lt;p&gt;Therefore, it is best to avoid continuing normal work while editing the history.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Most Reliable Approach Is to Close the Other Bash Sessions
&lt;/h2&gt;

&lt;p&gt;If reliability is the priority, there is a simpler approach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Close every Bash session except the one you will use to edit the history.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The fact that multiple processes are accessing the same &lt;code&gt;$HISTFILE&lt;/code&gt; is itself the source of potential conflicts, so reducing&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bash A
Bash B
Bash C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bash A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;before editing the history substantially reduces the number of issues you need to account for.&lt;/p&gt;

&lt;p&gt;In other words:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Want to keep multiple sessions open → write out the history from every session, disable recording, edit, and reload it in every session.&lt;/li&gt;
&lt;li&gt;Prioritize reliability → close the other Bash sessions before editing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;If you want to edit &lt;code&gt;$HISTFILE&lt;/code&gt; while keeping multiple Bash sessions open, the following procedure is practical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before editing, in every session:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; +o &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;In one session:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;vi&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After editing, in every session:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important point is not to stop after editing &lt;code&gt;$HISTFILE&lt;/code&gt; itself.&lt;/p&gt;

&lt;p&gt;Each Bash process independently keeps its own history in memory. Therefore, the underlying idea is to &lt;strong&gt;collect each session's unsaved history into &lt;code&gt;$HISTFILE&lt;/code&gt; before editing, and then synchronize every session with the contents of the edited &lt;code&gt;$HISTFILE&lt;/code&gt; afterward&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;However, Bash history management does not provide strong mutual exclusion between multiple processes. If you need to edit the history with maximum reliability, the simplest approach is to close the other Bash sessions before doing so.&lt;/p&gt;

&lt;h1&gt;
  
  
  Bashの履歴ファイルを安全に手動編集する方法
&lt;/h1&gt;

&lt;p&gt;Bash のコマンド履歴は通常 &lt;code&gt;$HISTFILE&lt;/code&gt;（多くの環境では &lt;code&gt;~/.bash_history&lt;/code&gt;）に保存されています。&lt;/p&gt;

&lt;p&gt;不要な履歴をまとめて削除したい場合など、このファイルを直接エディタで編集したくなることがあります。&lt;/p&gt;

&lt;p&gt;ただし、複数の Bash セッションを同時に開いている環境では注意が必要です。単純に &lt;code&gt;$HISTFILE&lt;/code&gt; を編集すると、別の Bash セッションが持っている履歴によって、後から編集内容が上書きされる可能性があります。&lt;/p&gt;

&lt;p&gt;この記事では、&lt;strong&gt;複数の Bash セッションを開いたまま、履歴ファイルをできるだけ安全に編集する手順&lt;/strong&gt;を整理します。&lt;/p&gt;

&lt;h2&gt;
  
  
  Bashの履歴には「メモリ」と「ファイル」がある
&lt;/h2&gt;

&lt;p&gt;まず押さえておきたいのは、Bash の履歴が単純に &lt;code&gt;$HISTFILE&lt;/code&gt; だけで管理されているわけではないことです。&lt;/p&gt;

&lt;p&gt;実行中の各 Bash プロセスは、それぞれ独立して履歴をメモリ上に保持しています。&lt;/p&gt;

&lt;p&gt;例えば3つのターミナルで Bash を起動している場合、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bash A ── メモリ上の履歴
Bash B ── メモリ上の履歴
Bash C ── メモリ上の履歴
              ↓
         $HISTFILE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という状態になります。&lt;/p&gt;

&lt;p&gt;そのため &lt;code&gt;$HISTFILE&lt;/code&gt; を直接編集する場合は、ファイルだけではなく、&lt;strong&gt;各 Bash プロセスが持っている履歴も考慮する必要があります&lt;/strong&gt;。&lt;/p&gt;

&lt;h2&gt;
  
  
  まず全セッションの履歴を書き出して記録を停止する
&lt;/h2&gt;

&lt;p&gt;最初に、現在開いている&lt;strong&gt;すべての Bash セッション&lt;/strong&gt;で次を実行します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; +o &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;history -a&lt;/code&gt; は、その Bash セッションでまだ履歴ファイルに保存されていない履歴を &lt;code&gt;$HISTFILE&lt;/code&gt; に追記します。&lt;/p&gt;

&lt;p&gt;つまり、全セッションで実行することで、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bash A ─┐
Bash B ─┼─ history -a → $HISTFILE
Bash C ─┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という形で、それぞれの未保存履歴をファイルに集められます。&lt;/p&gt;

&lt;p&gt;続く&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt; +o &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;は、その Bash セッションでの履歴記録を一時的に無効化します。&lt;/p&gt;

&lt;p&gt;これも&lt;strong&gt;全セッションで実行する&lt;/strong&gt;のがポイントです。&lt;/p&gt;

&lt;h2&gt;
  
  
  1つのセッションから履歴ファイルを編集する
&lt;/h2&gt;

&lt;p&gt;すべての Bash セッションで&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; +o &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を実行したら、1つのセッションから &lt;code&gt;$HISTFILE&lt;/code&gt; を編集します。&lt;/p&gt;

&lt;p&gt;例えば Emacs なら、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;emacsclient &lt;span class="nt"&gt;-nw&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;もちろんエディタは何でも構いません。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vim &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;や&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;vi&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;でも構いません。&lt;/p&gt;

&lt;p&gt;ここで不要な履歴を削除するなど、必要な編集を行って保存します。&lt;/p&gt;

&lt;h2&gt;
  
  
  編集後は全セッションの履歴を再読み込みする
&lt;/h2&gt;

&lt;p&gt;ファイルを編集しただけでは、既に起動している Bash のメモリ上には&lt;strong&gt;編集前の履歴が残っています&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;そこで、再び&lt;strong&gt;すべての Bash セッション&lt;/strong&gt;で次を実行します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;それぞれの意味は次のとおりです。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;現在の Bash がメモリ上に保持している履歴をクリアします。&lt;/p&gt;

&lt;p&gt;続いて、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;編集済みの &lt;code&gt;$HISTFILE&lt;/code&gt; を読み込みます。&lt;/p&gt;

&lt;p&gt;最後に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;で履歴記録を再び有効化します。&lt;/p&gt;

&lt;p&gt;これによって各 Bash セッションは、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;              編集済み $HISTFILE
                    │
          history -r│
          ┌─────────┼─────────┐
          ↓         ↓         ↓
       Bash A    Bash B    Bash C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という状態になり、全セッションが編集済みの履歴を基準に動作するようになります。&lt;/p&gt;

&lt;h2&gt;
  
  
  手順をまとめると
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. 全 Bash セッションで実行
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; +o &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. 1つの Bash セッションで履歴を編集
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;vi&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. 全 Bash セッションで実行
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;これが基本的な流れです。&lt;/p&gt;

&lt;h2&gt;
  
  
  なぜ &lt;code&gt;history -w&lt;/code&gt; ではなく &lt;code&gt;history -a&lt;/code&gt; なのか
&lt;/h2&gt;

&lt;p&gt;一見すると、編集前に&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を実行した方が確実そうに見えます。&lt;/p&gt;

&lt;p&gt;しかし、複数の Bash セッションが存在する場合には注意が必要です。&lt;/p&gt;

&lt;p&gt;&lt;code&gt;history -w&lt;/code&gt; は、&lt;strong&gt;現在の Bash がメモリ上に持っている履歴を使って &lt;code&gt;$HISTFILE&lt;/code&gt; を書き直します&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;例えば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bash A の履歴: A1 A2 A3
Bash B の履歴: B1 B2 B3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という状態で、Bash B の履歴が &lt;code&gt;$HISTFILE&lt;/code&gt; に反映されていても、Bash A がそれを読み込んでいない可能性があります。&lt;/p&gt;

&lt;p&gt;その状態で Bash A から&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-w&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;すると、Bash A が知っている履歴を基準にファイルが書き直され、他セッション由来の履歴を失う可能性があります。&lt;/p&gt;

&lt;p&gt;これに対して、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;は未保存の履歴を&lt;strong&gt;追記&lt;/strong&gt;します。&lt;/p&gt;

&lt;p&gt;そのため複数セッションから履歴を集める用途では、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を使う方が適しています。&lt;/p&gt;

&lt;h2&gt;
  
  
  それでも「完全」ではない
&lt;/h2&gt;

&lt;p&gt;ここまで行えばかなり安全ですが、厳密には完全な方法ではありません。&lt;/p&gt;

&lt;p&gt;Bash の履歴ファイルは、複数の Bash プロセスから同時に更新するためのトランザクショナルなデータベースではありません。&lt;/p&gt;

&lt;p&gt;つまり、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を各セッションで実行している最中に別セッションで新しいコマンドが実行されたり、履歴ファイルへの書き込みが競合したりすれば、タイミング依存の問題が発生する余地があります。&lt;/p&gt;

&lt;p&gt;また、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt; +o &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を実行した後のコマンドは、そのセッションの通常の履歴には記録されません。&lt;/p&gt;

&lt;p&gt;したがって、履歴編集作業中に通常の作業を続けるのは避けた方がよいでしょう。&lt;/p&gt;

&lt;h2&gt;
  
  
  最も確実なのは他の Bash を終了すること
&lt;/h2&gt;

&lt;p&gt;確実性を優先するなら、もっと単純な方法があります。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;履歴を編集する Bash 以外のセッションを終了してしまうことです。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;複数プロセスが同じ &lt;code&gt;$HISTFILE&lt;/code&gt; を扱っていること自体が競合の原因なので、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bash A
Bash B
Bash C
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Bash A
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;だけにしてから履歴を編集すれば、考慮すべき問題は大幅に減ります。&lt;/p&gt;

&lt;p&gt;つまり、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;複数セッションを維持したい → 全セッションで履歴を書き出し、停止・再読み込みする&lt;/li&gt;
&lt;li&gt;確実性を優先したい → 他の Bash セッションを終了してから編集する&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;という使い分けになります。&lt;/p&gt;

&lt;h2&gt;
  
  
  結論
&lt;/h2&gt;

&lt;p&gt;複数の Bash セッションを開いたまま &lt;code&gt;$HISTFILE&lt;/code&gt; を編集するなら、次の手順が実用的です。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;編集前に全セッションで&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; +o &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1セッションで&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;EDITOR&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;vi&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;編集後に全セッションで&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;
&lt;span class="nb"&gt;history&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HISTFILE&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nb"&gt;history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;重要なのは、&lt;code&gt;$HISTFILE&lt;/code&gt; だけを編集して終わりにしないことです。&lt;/p&gt;

&lt;p&gt;各 Bash プロセスはそれぞれ独立した履歴をメモリ上に保持しています。そのため、&lt;strong&gt;編集前には各セッションの未保存履歴を &lt;code&gt;$HISTFILE&lt;/code&gt; に集約し、編集後には全セッションを編集済み &lt;code&gt;$HISTFILE&lt;/code&gt; の内容に同期する&lt;/strong&gt;、という考え方になります。&lt;/p&gt;

&lt;p&gt;ただし Bash の履歴管理には複数プロセス間の強力な排他制御があるわけではありません。履歴を確実に編集する必要がある場合は、他の Bash セッションを終了してから作業する方法が最もシンプルです。&lt;/p&gt;

</description>
      <category>bash</category>
      <category>cli</category>
      <category>linux</category>
    </item>
    <item>
      <title>How to Squash Past Commits with Git Rebase</title>
      <dc:creator>vast cow</dc:creator>
      <pubDate>Mon, 24 Aug 2026 08:20:38 +0000</pubDate>
      <link>https://dev.to/vast-cow/how-to-squash-past-commits-with-git-rebase-52dh</link>
      <guid>https://dev.to/vast-cow/how-to-squash-past-commits-with-git-rebase-52dh</guid>
      <description>&lt;p&gt;Squashing commits with Git’s &lt;code&gt;rebase&lt;/code&gt; command is useful when you want to clean up your commit history. Here’s a step-by-step guide.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Check Which Commits to Squash
&lt;/h2&gt;

&lt;p&gt;First, review the commit log to decide which commits you want to combine:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a1b2c3d Fix typo
d4e5f6g Add feature X
h7i8j9k WIP: implement feature X
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose you want to squash &lt;code&gt;Add feature X&lt;/code&gt; and &lt;code&gt;WIP: implement feature X&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Start an Interactive Rebase
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;git rebase -i&lt;/code&gt; using the commit &lt;strong&gt;before&lt;/strong&gt; the ones you want to squash as the base:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; &amp;lt;base_commit_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, if &lt;code&gt;a1b2c3d&lt;/code&gt; is the commit before, you would run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; a1b2c3d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Edit the Commit List
&lt;/h2&gt;

&lt;p&gt;Your editor will open with something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick d4e5f6g Add feature X
pick h7i8j9k WIP: implement feature X
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change the second &lt;code&gt;pick&lt;/code&gt; to &lt;code&gt;squash&lt;/code&gt; (or just &lt;code&gt;s&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick d4e5f6g Add feature X
squash h7i8j9k WIP: implement feature X
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Edit the Commit Message
&lt;/h2&gt;

&lt;p&gt;Next, Git will prompt you to combine commit messages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# This is a combination of 2 commits.
# The first commit’s message is:
Add feature X

# The following commit message will also be included:
WIP: implement feature X
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clean it up so the final message is concise:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Add feature X
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Finish the Rebase
&lt;/h2&gt;

&lt;p&gt;Save and close the editor. Git will apply the rebase and squash the commits into one.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Troubleshooting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If you hit conflicts&lt;/strong&gt;: resolve them as usual, then run:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  git add &amp;lt;fixed_files&amp;gt;
  git rebase &lt;span class="nt"&gt;--continue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;If you want to cancel the rebase&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  git rebase &lt;span class="nt"&gt;--abort&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;After rewriting history&lt;/strong&gt;: if the branch is pushed to a remote you will need to force-push the rewritten history:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  git push &lt;span class="nt"&gt;--force-with-lease&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Prefer &lt;code&gt;--force-with-lease&lt;/code&gt; over &lt;code&gt;--force&lt;/code&gt; when collaborating.)&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Squashing Including the Root Commit (&lt;code&gt;--root&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;By default &lt;code&gt;git rebase -i &amp;lt;base&amp;gt;&lt;/code&gt; rebases starting &lt;strong&gt;after&lt;/strong&gt; the specified base commit. If you want to include the very first (root) commit in an interactive rebase — for example to edit or squash the initial commit together with later commits — use the &lt;code&gt;--root&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;--root&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What this does&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lists the root (initial) commit as the first entry in the interactive todo.&lt;/li&gt;
&lt;li&gt;Lets you &lt;code&gt;pick&lt;/code&gt;, &lt;code&gt;reword&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt;, &lt;code&gt;squash&lt;/code&gt;, or &lt;code&gt;fixup&lt;/code&gt; the root commit just like any other commit.&lt;/li&gt;
&lt;li&gt;Rewrites the root and all descendant commits (so every commit ID in the branch will change).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Common uses &amp;amp; examples&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Squash all commits into a single initial commit&lt;/em&gt;
If you want a single commit that contains the whole history, keep the root as &lt;code&gt;pick&lt;/code&gt; and mark every other commit as &lt;code&gt;squash&lt;/code&gt; (or &lt;code&gt;s&lt;/code&gt;):
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   pick a1b2c3d Initial commit
   squash d4e5f6g Add feature X
   squash h7i8j9k WIP: implement feature X
   ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After saving, Git will open the combined commit-message editor so you can craft the final message.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Edit or reword the root commit message&lt;/em&gt;
Change the first line to &lt;code&gt;reword&lt;/code&gt; (or &lt;code&gt;r&lt;/code&gt;) to update the initial commit message during the rebase:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   reword a1b2c3d Initial commit
   pick d4e5f6g Add feature X
   ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rebase will stop and prompt you to edit the root commit message.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Amend the root content&lt;/em&gt;
Use &lt;code&gt;edit&lt;/code&gt; on the root entry if you need to change the actual tree of the root commit (add/remove files). Rebase will stop at that commit; then you can modify files, &lt;code&gt;git add&lt;/code&gt; them, and run &lt;code&gt;git commit --amend&lt;/code&gt; before continuing the rebase:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="c"&gt;# interactive todo:&lt;/span&gt;
   edit a1b2c3d Initial commit
   pick d4e5f6g Add feature X
   ...
   &lt;span class="c"&gt;# when rebase stops:&lt;/span&gt;
   &lt;span class="c"&gt;# make changes to the working tree&lt;/span&gt;
   git add &amp;lt;files&amp;gt;
   git commit &lt;span class="nt"&gt;--amend&lt;/span&gt; &lt;span class="nt"&gt;--no-edit&lt;/span&gt;   &lt;span class="c"&gt;# or edit message as needed&lt;/span&gt;
   git rebase &lt;span class="nt"&gt;--continue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Caveats&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rewriting the root rewrites the entire branch history. This is disruptive if the branch is shared — coordinate with collaborators or avoid rewriting published branches.&lt;/li&gt;
&lt;li&gt;After a &lt;code&gt;--root&lt;/code&gt; rebase you must force-push to update any remote branch (&lt;code&gt;git push --force-with-lease&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git rebase -i --root&lt;/code&gt; behaves like a normal interactive rebase in terms of conflict resolution and aborting (&lt;code&gt;git rebase --abort&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;git rebase -i &amp;lt;base&amp;gt;&lt;/code&gt; to interactively squash commits after &lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Mark commits to squash with &lt;code&gt;squash&lt;/code&gt; (or &lt;code&gt;s&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Edit the commit message when prompted.&lt;/li&gt;
&lt;li&gt;Complete the rebase and resolve conflicts with &lt;code&gt;git rebase --continue&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;To include the initial/root commit in your rebase (so you can squash or edit it), run &lt;code&gt;git rebase -i --root&lt;/code&gt;. Be aware this rewrites the whole branch history and requires a force-push for published branches.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Git Rebaseで過去のコミットをSquashする方法
&lt;/h1&gt;

&lt;p&gt;Gitの&lt;code&gt;rebase&lt;/code&gt;コマンドを使ってコミットをSquash（統合）すると、コミット履歴を整理したいときに便利です。以下に手順を説明します。&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Squashするコミットを確認する
&lt;/h2&gt;

&lt;p&gt;まず、コミットログを確認して、どのコミットをまとめるか決めます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;例：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;a1b2c3d タイポを修正
d4e5f6g 機能Xを追加
h7i8j9k WIP: 機能Xを実装
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ここでは、&lt;code&gt;機能Xを追加&lt;/code&gt;と&lt;code&gt;WIP: 機能Xを実装&lt;/code&gt;をSquashするとします。&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Interactive Rebaseを開始する
&lt;/h2&gt;

&lt;p&gt;Squashしたいコミットの&lt;strong&gt;直前&lt;/strong&gt;のコミットをベースとして、&lt;code&gt;git rebase -i&lt;/code&gt;を実行します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; &amp;lt;base_commit_id&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;この例で、&lt;code&gt;a1b2c3d&lt;/code&gt;がその直前のコミットである場合は、次のように実行します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; a1b2c3d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. コミット一覧を編集する
&lt;/h2&gt;

&lt;p&gt;エディタが開き、次のような内容が表示されます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick d4e5f6g 機能Xを追加
pick h7i8j9k WIP: 機能Xを実装
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;2つ目の&lt;code&gt;pick&lt;/code&gt;を&lt;code&gt;squash&lt;/code&gt;（または単に&lt;code&gt;s&lt;/code&gt;）に変更します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick d4e5f6g 機能Xを追加
squash h7i8j9k WIP: 機能Xを実装
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. コミットメッセージを編集する
&lt;/h2&gt;

&lt;p&gt;次に、Gitからコミットメッセージを統合するよう求められます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# これは2個のコミットを組み合わせたものです。
# 1つ目のコミットメッセージ:
機能Xを追加

# 以下のコミットメッセージも含まれます:
WIP: 機能Xを実装
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;最終的なメッセージが簡潔になるよう整理します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;機能Xを追加
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Rebaseを完了する
&lt;/h2&gt;

&lt;p&gt;保存してエディタを閉じます。GitがRebaseを適用し、コミットを1つにSquashします。&lt;/p&gt;




&lt;h2&gt;
  
  
  6. トラブルシューティング
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;コンフリクトが発生した場合&lt;/strong&gt;：通常どおりコンフリクトを解消してから、次を実行します。
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  git add &amp;lt;fixed_files&amp;gt;
  git rebase &lt;span class="nt"&gt;--continue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Rebaseをキャンセルしたい場合&lt;/strong&gt;：
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  git rebase &lt;span class="nt"&gt;--abort&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;履歴を書き換えた後&lt;/strong&gt;：ブランチをすでにリモートへPushしている場合は、書き換えた履歴をForce Pushする必要があります。
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  git push &lt;span class="nt"&gt;--force-with-lease&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;（共同作業をしている場合は、&lt;code&gt;--force&lt;/code&gt;より&lt;code&gt;--force-with-lease&lt;/code&gt;を使用することを推奨します。）&lt;/p&gt;




&lt;h2&gt;
  
  
  7. ルートコミットを含めてSquashする（&lt;code&gt;--root&lt;/code&gt;）
&lt;/h2&gt;

&lt;p&gt;デフォルトでは、&lt;code&gt;git rebase -i &amp;lt;base&amp;gt;&lt;/code&gt;は指定したベースコミットの&lt;strong&gt;次&lt;/strong&gt;のコミットからRebaseを行います。最初のコミット（ルートコミット）もInteractive Rebaseの対象に含めたい場合（たとえば、初回コミットを編集したり、後続のコミットとSquashしたりする場合）は、&lt;code&gt;--root&lt;/code&gt;オプションを使用します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; &lt;span class="nt"&gt;--root&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;このコマンドの動作&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ルート（初回）コミットがInteractive Rebaseのtodoリストの最初の項目として表示されます。&lt;/li&gt;
&lt;li&gt;他のコミットと同様に、ルートコミットに対して&lt;code&gt;pick&lt;/code&gt;、&lt;code&gt;reword&lt;/code&gt;、&lt;code&gt;edit&lt;/code&gt;、&lt;code&gt;squash&lt;/code&gt;、&lt;code&gt;fixup&lt;/code&gt;を指定できます。&lt;/li&gt;
&lt;li&gt;ルートコミットと、それ以降のすべてのコミットが書き換えられます（そのため、ブランチ内のすべてのコミットIDが変更されます）。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;一般的な用途と例&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;すべてのコミットを1つの初回コミットにSquashする&lt;/em&gt;
履歴全体を含む1つのコミットにしたい場合は、ルートコミットを&lt;code&gt;pick&lt;/code&gt;のままにして、それ以外のすべてのコミットを&lt;code&gt;squash&lt;/code&gt;（または&lt;code&gt;s&lt;/code&gt;）に変更します。
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   pick a1b2c3d 初回コミット
   squash d4e5f6g 機能Xを追加
   squash h7i8j9k WIP: 機能Xを実装
   ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;保存すると、Gitが統合後のコミットメッセージを編集するためのエディタを開くので、最終的なメッセージを作成できます。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;ルートコミットのメッセージを編集・変更する&lt;/em&gt;
Rebase中に初回コミットのメッセージを変更するには、最初の行を&lt;code&gt;reword&lt;/code&gt;（または&lt;code&gt;r&lt;/code&gt;）に変更します。
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   reword a1b2c3d 初回コミット
   pick d4e5f6g 機能Xを追加
   ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rebaseが一時停止し、ルートコミットのメッセージを編集するよう求められます。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;ルートコミットの内容を修正する&lt;/em&gt;
ルートコミットの実際のツリー（ファイルの追加・削除）を変更する必要がある場合は、ルートのエントリに&lt;code&gt;edit&lt;/code&gt;を指定します。Rebaseはそのコミットで一時停止します。その後、ファイルを変更して&lt;code&gt;git add&lt;/code&gt;し、&lt;code&gt;git commit --amend&lt;/code&gt;を実行してからRebaseを続行できます。
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   &lt;span class="c"&gt;# Interactive Rebaseのtodo:&lt;/span&gt;
   edit a1b2c3d 初回コミット
   pick d4e5f6g 機能Xを追加
   ...
   &lt;span class="c"&gt;# Rebaseが停止したら:&lt;/span&gt;
   &lt;span class="c"&gt;# ワーキングツリーに変更を加える&lt;/span&gt;
   git add &amp;lt;files&amp;gt;
   git commit &lt;span class="nt"&gt;--amend&lt;/span&gt; &lt;span class="nt"&gt;--no-edit&lt;/span&gt;   &lt;span class="c"&gt;# 必要に応じてメッセージも編集&lt;/span&gt;
   git rebase &lt;span class="nt"&gt;--continue&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;注意点&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ルートコミットを書き換えると、ブランチの履歴全体が書き換えられます。共有ブランチで行うと大きな影響があるため、共同作業者と調整するか、公開済みブランチの書き換えは避けてください。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--root&lt;/code&gt;を使ってRebaseした後、リモートブランチを更新するにはForce Pushが必要です（&lt;code&gt;git push --force-with-lease&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;git rebase -i --root&lt;/code&gt;でも、コンフリクトの解消や中止（&lt;code&gt;git rebase --abort&lt;/code&gt;）については通常のInteractive Rebaseと同様に動作します。&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  まとめ
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;git rebase -i &amp;lt;base&amp;gt;&lt;/code&gt;を使用すると、&lt;code&gt;&amp;lt;base&amp;gt;&lt;/code&gt;より後のコミットを対話形式でSquashできます。&lt;/li&gt;
&lt;li&gt;Squashするコミットを&lt;code&gt;squash&lt;/code&gt;（または&lt;code&gt;s&lt;/code&gt;）に変更します。&lt;/li&gt;
&lt;li&gt;プロンプトが表示されたらコミットメッセージを編集します。&lt;/li&gt;
&lt;li&gt;Rebaseを完了し、コンフリクトが発生した場合は&lt;code&gt;git rebase --continue&lt;/code&gt;で続行します。&lt;/li&gt;
&lt;li&gt;初回／ルートコミットをRebaseの対象に含めてSquashや編集を行うには、&lt;code&gt;git rebase -i --root&lt;/code&gt;を実行します。この操作ではブランチの履歴全体が書き換えられ、公開済みブランチではForce Pushが必要になる点に注意してください。&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>git</category>
      <category>programming</category>
      <category>softwaredevelopment</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Unlocking GNOME Keyring on a Remote Machine via X11 Forwarding</title>
      <dc:creator>vast cow</dc:creator>
      <pubDate>Wed, 19 Aug 2026 09:42:29 +0000</pubDate>
      <link>https://dev.to/vast-cow/unlocking-gnome-keyring-login-via-ssh-x11-forwarding-1dg8</link>
      <guid>https://dev.to/vast-cow/unlocking-gnome-keyring-login-via-ssh-x11-forwarding-1dg8</guid>
      <description>&lt;p&gt;A memo on unlocking the GNOME Keyring on a Linux server connected via SSH, using Seahorse through X11 Forwarding.&lt;/p&gt;

&lt;p&gt;Also documented are how to unlock it with &lt;code&gt;secret-tool&lt;/code&gt;, and how to use the SSH agent provided by GNOME Keyring / GCR from an SSH session.&lt;/p&gt;

&lt;h2&gt;
  
  
  Environment
&lt;/h2&gt;

&lt;p&gt;Using SSH's X11 Forwarding, display the Seahorse and GNOME Keyring password prompts launched on the remote side on the local side.&lt;/p&gt;

&lt;p&gt;First, establish the SSH connection.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-XY&lt;/span&gt; server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After connecting, also reflect the X11 environment variables into the D-Bus / systemd user session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Unlocking the GNOME Keyring
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Using Seahorse
&lt;/h3&gt;

&lt;p&gt;Launch Seahorse.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;seahorse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once Seahorse is displayed, select&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Passwords → Login → Unlock&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;and enter the GNOME Keyring password.&lt;/p&gt;

&lt;p&gt;This unlocks the Login keyring.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using &lt;code&gt;secret-tool&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Instead of launching Seahorse, you can also request an unlock from &lt;code&gt;secret-tool&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;secret-tool search &lt;span class="nt"&gt;--unlock&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; xdg:schema org.freedesktop.Secret.Generic &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the keyring is locked, a password prompt for unlocking will appear; enter the password there.&lt;/p&gt;

&lt;p&gt;The search results themselves are not needed, so standard output is discarded to &lt;code&gt;/dev/null&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To display the prompt via X11 Forwarding, run the following first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Therefore, if you do not need to open the GUI Seahorse, just the following steps suffice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-XY&lt;/span&gt; server

dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY

secret-tool search &lt;span class="nt"&gt;--unlock&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; xdg:schema org.freedesktop.Secret.Generic &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using the SSH agent
&lt;/h2&gt;

&lt;p&gt;To use the SSH agent on the GNOME Keyring / GCR side, point &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt; to the GCR socket.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After setting this, verify the keys recognized by the agent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A series of operations looks, for example, like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-XY&lt;/span&gt; server

dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY

secret-tool search &lt;span class="nt"&gt;--unlock&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; xdg:schema org.freedesktop.Secret.Generic &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;

ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If using Seahorse, replace the unlock part as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;seahorse
&lt;span class="c"&gt;# Passwords → Login → Unlock&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use the GCR SSH agent every time, you may add the following to your shell's configuration file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, if you are also using another &lt;code&gt;ssh-agent&lt;/code&gt; or agent forwarding, note that this will overwrite the existing &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why &lt;code&gt;dbus-update-activation-environment&lt;/code&gt; is needed
&lt;/h2&gt;

&lt;p&gt;When using SSH's X11 Forwarding, a &lt;code&gt;DISPLAY&lt;/code&gt; like the following is set in the SSH session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localhost:10.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the other hand, GUI prompts around GNOME Keyring may be launched via D-Bus or the systemd user session.&lt;/p&gt;

&lt;p&gt;Therefore, even if &lt;code&gt;DISPLAY&lt;/code&gt; is correctly set in the SSH shell, processes launched via D-Bus may not recognize the SSH X11 display.&lt;/p&gt;

&lt;p&gt;So, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to pass the current SSH session's &lt;code&gt;DISPLAY&lt;/code&gt; and &lt;code&gt;XAUTHORITY&lt;/code&gt; to the activation environment as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Procedure Summary
&lt;/h2&gt;

&lt;p&gt;When using Seahorse.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-XY&lt;/span&gt; server

dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY

seahorse
&lt;span class="c"&gt;# Passwords → Login → Unlock&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;

ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When using &lt;code&gt;secret-tool&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-XY&lt;/span&gt; server

dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY

secret-tool search &lt;span class="nt"&gt;--unlock&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; xdg:schema org.freedesktop.Secret.Generic &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;

ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Troubleshooting Notes
&lt;/h2&gt;

&lt;p&gt;Check whether the GNOME Keyring daemon is running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pgrep &lt;span class="nt"&gt;-af&lt;/span&gt; gnome-keyring-daemon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the behavior is off, restart the user service.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl &lt;span class="nt"&gt;--user&lt;/span&gt; stop gnome-keyring-daemon.service
systemctl &lt;span class="nt"&gt;--user&lt;/span&gt; start gnome-keyring-daemon.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To watch the logs in real time, use the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;journalctl &lt;span class="nt"&gt;--user-unit&lt;/span&gt; gnome-keyring-daemon &lt;span class="nt"&gt;-fe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running this log in another terminal while operating Seahorse or &lt;code&gt;secret-tool&lt;/code&gt; makes it easier to see what is happening on the daemon side.&lt;/p&gt;

&lt;p&gt;For checking the SSH agent side, the following also works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;
ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The expected socket is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$XDG_RUNTIME_DIR/gcr/ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Supplementary Notes
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ssh -X&lt;/code&gt; is regular X11 Forwarding, while &lt;code&gt;ssh -Y&lt;/code&gt; is trusted X11 Forwarding.&lt;/p&gt;

&lt;p&gt;In this case, operation was confirmed with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-XY&lt;/span&gt; server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Trusted X11 Forwarding grants remote applications broader permissions than regular &lt;code&gt;-X&lt;/code&gt;, so it is assumed to be used only with trusted servers.&lt;/p&gt;

&lt;p&gt;Also,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;updates the activation environment of that user's D-Bus / systemd user session.&lt;/p&gt;

&lt;p&gt;In environments where the same user is also using a local GUI session concurrently, be aware that this may affect where GUI applications are displayed.&lt;/p&gt;

&lt;p&gt;Similarly,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;switches the SSH agent used from the current shell to the GCR side.&lt;/p&gt;

&lt;p&gt;If OpenSSH's &lt;code&gt;ssh-agent&lt;/code&gt; or SSH agent forwarding is already in use, the GCR-side agent will be used instead of that socket.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;To unlock the GNOME Keyring on a remote machine over SSH, first set up&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-XY&lt;/span&gt; server
dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then either run&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Passwords → Login → Unlock&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;from Seahorse, or request an unlock with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;secret-tool search &lt;span class="nt"&gt;--unlock&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; xdg:schema org.freedesktop.Secret.Generic &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you also want to use the GCR SSH agent, set&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;
ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If problems occur around the GNOME Keyring daemon, restarting it with &lt;code&gt;systemctl --user&lt;/code&gt; and checking logs with &lt;code&gt;journalctl&lt;/code&gt; proved effective.&lt;/p&gt;

&lt;h1&gt;
  
  
  リモートマシンのGNOME KeyringをX11 ForwardingでUnlockする
&lt;/h1&gt;

&lt;p&gt;SSHで接続したLinuxサーバー上のGNOME Keyringを、X11 Forwarding経由でSeahorseを使ってUnlockしたときのメモ。&lt;/p&gt;

&lt;p&gt;あわせて、&lt;code&gt;secret-tool&lt;/code&gt;でUnlockする方法と、GNOME Keyring / GCRが提供するSSH agentをSSHセッションから利用する方法も記載する。&lt;/p&gt;

&lt;h2&gt;
  
  
  環境
&lt;/h2&gt;

&lt;p&gt;SSHのX11 Forwardingを使い、リモート側で起動したSeahorseやGNOME Keyringのパスワードプロンプトをローカル側に表示する。&lt;/p&gt;

&lt;p&gt;まずSSH接続する。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-XY&lt;/span&gt; server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;接続後、X11用の環境変数をD-Bus / systemd user session側にも反映する。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  GNOME KeyringをUnlockする
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Seahorseを使う方法
&lt;/h3&gt;

&lt;p&gt;Seahorseを起動する。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;seahorse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seahorseが表示されたら、&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Passwords → Login → Unlock&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;を選択し、GNOME Keyringのパスワードを入力する。&lt;/p&gt;

&lt;p&gt;これでLogin keyringをUnlockできる。&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;secret-tool&lt;/code&gt;を使う方法
&lt;/h3&gt;

&lt;p&gt;Seahorseを起動せず、&lt;code&gt;secret-tool&lt;/code&gt;からUnlockを要求することもできる。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;secret-tool search &lt;span class="nt"&gt;--unlock&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; xdg:schema org.freedesktop.Secret.Generic &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keyringがロックされている場合はUnlock用のパスワードプロンプトが表示されるので、そこでパスワードを入力する。&lt;/p&gt;

&lt;p&gt;検索結果そのものは不要なので、標準出力は&lt;code&gt;/dev/null&lt;/code&gt;へ捨てている。&lt;/p&gt;

&lt;p&gt;X11 Forwarding経由でプロンプトを表示するため、先に以下を実行しておく。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;したがって、GUIのSeahorseを開く必要がなければ、次の手順だけでもよい。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-XY&lt;/span&gt; server

dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY

secret-tool search &lt;span class="nt"&gt;--unlock&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; xdg:schema org.freedesktop.Secret.Generic &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  SSH agentを使う
&lt;/h2&gt;

&lt;p&gt;GNOME Keyring / GCR側のSSH agentを利用する場合は、&lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt;をGCRのソケットに向ける。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;設定後、agentに認識されている鍵を確認する。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;一連の操作は例えば以下になる。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-XY&lt;/span&gt; server

dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY

secret-tool search &lt;span class="nt"&gt;--unlock&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; xdg:schema org.freedesktop.Secret.Generic &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;

ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Seahorseを使う場合は、Unlock部分を次のように置き換える。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;seahorse
&lt;span class="c"&gt;# Passwords → Login → Unlock&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;毎回GCRのSSH agentを使う場合は、利用しているshellの設定ファイルなどに次を追加しておいてもよい。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ただし、別の&lt;code&gt;ssh-agent&lt;/code&gt;やagent forwardingを併用している場合は、既存の&lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt;を上書きすることになるため注意する。&lt;/p&gt;

&lt;h2&gt;
  
  
  なぜ &lt;code&gt;dbus-update-activation-environment&lt;/code&gt; が必要なのか
&lt;/h2&gt;

&lt;p&gt;SSHのX11 Forwardingを使うと、SSHセッションには例えば以下のような&lt;code&gt;DISPLAY&lt;/code&gt;が設定される。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;localhost:10.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;一方、GNOME Keyring周辺のGUIプロンプトはD-Busやsystemdのuser session経由で起動されることがある。&lt;/p&gt;

&lt;p&gt;そのため、SSHシェル上では&lt;code&gt;DISPLAY&lt;/code&gt;が正しく設定されていても、D-Bus経由で起動されたプロセス側ではSSHのX11 displayを認識できない場合がある。&lt;/p&gt;

&lt;p&gt;そこで、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を実行して、現在のSSHセッションの&lt;code&gt;DISPLAY&lt;/code&gt;と&lt;code&gt;XAUTHORITY&lt;/code&gt;をactivation environment側にも渡しておく。&lt;/p&gt;

&lt;h2&gt;
  
  
  手順まとめ
&lt;/h2&gt;

&lt;p&gt;Seahorseを使う場合。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-XY&lt;/span&gt; server

dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY

seahorse
&lt;span class="c"&gt;# Passwords → Login → Unlock&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;

ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;secret-tool&lt;/code&gt;を使う場合。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-XY&lt;/span&gt; server

dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY

secret-tool search &lt;span class="nt"&gt;--unlock&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; xdg:schema org.freedesktop.Secret.Generic &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;

ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  不具合時のメモ
&lt;/h2&gt;

&lt;p&gt;GNOME Keyring daemonが動いているか確認する。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pgrep &lt;span class="nt"&gt;-af&lt;/span&gt; gnome-keyring-daemon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;挙動がおかしい場合は、user serviceを再起動する。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl &lt;span class="nt"&gt;--user&lt;/span&gt; stop gnome-keyring-daemon.service
systemctl &lt;span class="nt"&gt;--user&lt;/span&gt; start gnome-keyring-daemon.service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ログをリアルタイムで確認する場合は以下。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;journalctl &lt;span class="nt"&gt;--user-unit&lt;/span&gt; gnome-keyring-daemon &lt;span class="nt"&gt;-fe&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;別ターミナルでこのログを流しながらSeahorseや&lt;code&gt;secret-tool&lt;/code&gt;を操作すると、daemon側で何が起きているか確認しやすい。&lt;/p&gt;

&lt;p&gt;SSH agent側の確認には以下も使える。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;
ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;期待するソケットは以下。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$XDG_RUNTIME_DIR/gcr/ssh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  補足
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;ssh -X&lt;/code&gt;は通常のX11 Forwarding、&lt;code&gt;ssh -Y&lt;/code&gt;はtrusted X11 Forwardingになる。&lt;/p&gt;

&lt;p&gt;今回は、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-XY&lt;/span&gt; server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;で動作を確認した。&lt;/p&gt;

&lt;p&gt;trusted X11 Forwardingは通常の&lt;code&gt;-X&lt;/code&gt;よりリモートアプリケーションに広い権限を与えるため、信頼できるサーバーに対して使用するのが前提。&lt;/p&gt;

&lt;p&gt;また、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;は、そのユーザーのD-Bus / systemd user sessionのactivation environmentを更新する。&lt;/p&gt;

&lt;p&gt;同じユーザーでローカルのGUIセッションも並行して利用している環境では、GUIアプリケーションの表示先に影響する可能性があるため注意する。&lt;/p&gt;

&lt;p&gt;同様に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;は現在のshellから利用するSSH agentをGCR側に切り替える設定になる。&lt;/p&gt;

&lt;p&gt;すでにOpenSSHの&lt;code&gt;ssh-agent&lt;/code&gt;やSSH agent forwardingを利用している場合、そのソケットではなくGCR側のagentを利用することになる。&lt;/p&gt;

&lt;h2&gt;
  
  
  結論
&lt;/h2&gt;

&lt;p&gt;SSH越しにリモートマシンのGNOME KeyringをUnlockする場合は、まず&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-XY&lt;/span&gt; server
dbus-update-activation-environment &lt;span class="nt"&gt;--systemd&lt;/span&gt; DISPLAY XAUTHORITY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;とした上で、Seahorseから&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Passwords → Login → Unlock&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;を実行するか、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;secret-tool search &lt;span class="nt"&gt;--unlock&lt;/span&gt; &lt;span class="nt"&gt;--all&lt;/span&gt; xdg:schema org.freedesktop.Secret.Generic &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;でUnlockを要求する。&lt;/p&gt;

&lt;p&gt;さらにGCRのSSH agentを利用する場合は、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SSH_AUTH_SOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$XDG_RUNTIME_DIR&lt;/span&gt;&lt;span class="s2"&gt;/gcr/ssh"&lt;/span&gt;
ssh-add &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を設定する。&lt;/p&gt;

&lt;p&gt;GNOME Keyring daemon周辺で問題が起きた場合は、&lt;code&gt;systemctl --user&lt;/code&gt;での再起動と&lt;code&gt;journalctl&lt;/code&gt;でのログ確認が有効だった。&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Use a Tool to Remove a Specific App from Windows “File Associations”</title>
      <dc:creator>vast cow</dc:creator>
      <pubDate>Tue, 18 Aug 2026 08:41:19 +0000</pubDate>
      <link>https://dev.to/vast-cow/how-to-use-a-tool-to-remove-a-specific-app-from-windows-file-associations-3im1</link>
      <guid>https://dev.to/vast-cow/how-to-use-a-tool-to-remove-a-specific-app-from-windows-file-associations-3im1</guid>
      <description>&lt;p&gt;On Windows, uninstalled applications or portable applications can sometimes leave behind only their file-association information in the registry.&lt;/p&gt;

&lt;p&gt;For example, when you display “Open with” for files such as &lt;code&gt;.epub&lt;/code&gt; or &lt;code&gt;.pdf&lt;/code&gt;, an application you no longer use may remain listed as an option.&lt;/p&gt;

&lt;p&gt;This section explains how to use a Python tool that examines file associations registered under &lt;code&gt;HKEY_CLASSES_ROOT&lt;/code&gt; and deletes registry keys associated with a specified executable file.&lt;/p&gt;

&lt;h2&gt;
  
  
  What This Tool Does
&lt;/h2&gt;

&lt;p&gt;This tool examines the keys directly under &lt;code&gt;HKEY_CLASSES_ROOT&lt;/code&gt;, abbreviated as &lt;code&gt;HKCR&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For each key, it checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HKEY_CLASSES_ROOT\&amp;lt;key name&amp;gt;\shell\open\command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and retrieves the executable filename from the command set as the default value.&lt;/p&gt;

&lt;p&gt;For example, suppose the following entry exists:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"C:\Program Files\Calibre2\ebook-viewer.exe" "%1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the specified executable filename is &lt;code&gt;ebook-viewer.exe&lt;/code&gt;, this association is detected as a target.&lt;/p&gt;

&lt;p&gt;When run normally, the tool deletes the target registry key. If you add &lt;code&gt;--dry-run&lt;/code&gt;, it only displays the targets without deleting them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;This script is for Windows only.&lt;/p&gt;

&lt;p&gt;It uses only the following Python standard-library modules:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;argparse&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctypes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;os&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;winreg&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, no additional packages need to be installed.&lt;/p&gt;

&lt;p&gt;It can be used on a Windows system with Python 3 installed.&lt;/p&gt;

&lt;h2&gt;
  
  
  First, Save the Script
&lt;/h2&gt;

&lt;p&gt;Save the code under a filename such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;remove_association.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open Command Prompt or PowerShell and move to the directory where you saved the file.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Tools&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Always Check with &lt;code&gt;--dry-run&lt;/code&gt; First
&lt;/h2&gt;

&lt;p&gt;Because this tool deletes registry keys, it is safer not to delete anything immediately. First, use &lt;code&gt;--dry-run&lt;/code&gt; to review the targets.&lt;/p&gt;

&lt;p&gt;The syntax is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove_association.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;executable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, to check entries associated with &lt;code&gt;calibre.exe&lt;/code&gt;, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove_association.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;calibre.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If targets are found, the output will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Found 2 association(s).

HKEY_CLASSES_ROOT\Calibre...
  command = "C:\Program Files\Calibre2\calibre.exe" "%1"

HKEY_CLASSES_ROOT\...
  command = "C:\Program Files\Calibre2\calibre.exe" "%1"

dry-run: No keys were deleted.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the final line says:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dry-run: No keys were deleted.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then the registry has not been modified.&lt;/p&gt;

&lt;h2&gt;
  
  
  Actually Deleting the Entries
&lt;/h2&gt;

&lt;p&gt;After reviewing the &lt;code&gt;--dry-run&lt;/code&gt; results and confirming that only unnecessary associations were detected, run the command again without &lt;code&gt;--dry-run&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove_association.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;calibre.exe&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If deletion succeeds, the tool displays:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DELETED: HKEY_CLASSES_ROOT\...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If multiple associations are found, the detected keys are deleted one by one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Specify Only the Executable Filename
&lt;/h2&gt;

&lt;p&gt;As a general rule, specify only the executable filename as the argument, not the full path.&lt;/p&gt;

&lt;p&gt;For example, instead of:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\Program Files\Calibre2\calibre.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;specify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;calibre.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool parses the command registered in the registry according to Windows command-line rules, extracts only the filename of the executable at the beginning of the command, and compares that filename.&lt;/p&gt;

&lt;p&gt;The comparison is case-insensitive. Therefore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CALIBRE.EXE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;calibre.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;are treated as the same filename.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why It Does Not Use a Simple String Search
&lt;/h2&gt;

&lt;p&gt;An association command does not necessarily contain only the executable path.&lt;/p&gt;

&lt;p&gt;For example, it may look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"C:\Program Files\Example\viewer.exe" "%1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"C:\Program Files\Example\viewer.exe" --open "%1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In addition, Windows command lines have their own rules for handling quotation marks and spaces.&lt;/p&gt;

&lt;p&gt;For this reason, the tool parses the command string using the Windows API function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CommandLineToArgvW
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It then extracts the executable filename from the first parsed argument using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This structure is less prone to false positives than a simple substring check such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;calibre.exe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Support for &lt;code&gt;REG_EXPAND_SZ&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The tool also supports commands stored not only as ordinary &lt;code&gt;REG_SZ&lt;/code&gt; strings, but also as &lt;code&gt;REG_EXPAND_SZ&lt;/code&gt; values containing environment variables.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"%ProgramFiles%\Example\viewer.exe" "%1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, the tool expands the environment variables using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expandvars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;before parsing the command.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Associations Are Searched
&lt;/h2&gt;

&lt;p&gt;The core of the search process is &lt;code&gt;find_associations()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_associations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_exe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function sequentially enumerates the keys directly under &lt;code&gt;HKEY_CLASSES_ROOT&lt;/code&gt; using &lt;code&gt;winreg.EnumKey()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For each key, it reads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;key&amp;gt;\shell\open\command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and, if the executable filename matches the specified name, returns it as a deletion candidate with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In other words, this tool searches &lt;strong&gt;the &lt;code&gt;shell\open\command&lt;/code&gt; entry under each key directly beneath HKCR&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Note that it is not a tool that comprehensively searches every type of file-association information that may exist in Windows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deletion Includes Subkeys
&lt;/h2&gt;

&lt;p&gt;A registry key cannot be deleted directly if it contains subkeys.&lt;/p&gt;

&lt;p&gt;For that reason, &lt;code&gt;delete_registry_tree()&lt;/code&gt; recursively deletes child keys before deleting the parent key.&lt;/p&gt;

&lt;p&gt;Conceptually, if the structure looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Target key
├─ DefaultIcon
├─ shell
│  └─ open
│     └─ command
└─ other entries
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;the tool deletes entries from the bottom of the hierarchy upward, then finally deletes the “Target key” itself.&lt;/p&gt;

&lt;p&gt;Therefore, when this tool deletes a detected key, it removes not only &lt;code&gt;shell\open\command&lt;/code&gt;, but &lt;strong&gt;the entire association key&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This is an important point.&lt;/p&gt;

&lt;h2&gt;
  
  
  If You Get a Permission Error
&lt;/h2&gt;

&lt;p&gt;During deletion, you may see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ACCESS DENIED: HKEY_CLASSES_ROOT\...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This can occur when the current user does not have permission to modify the registry key.&lt;/p&gt;

&lt;p&gt;If necessary, run the command from PowerShell or Command Prompt opened with “Run as administrator.”&lt;/p&gt;

&lt;p&gt;However, a permission error does not mean you should automatically delete the key with administrator privileges.&lt;/p&gt;

&lt;p&gt;First, review the &lt;code&gt;--dry-run&lt;/code&gt; output and confirm that the key is truly unnecessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  If No Target Is Found
&lt;/h2&gt;

&lt;p&gt;If no matching association exists, the tool displays a message such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No associations matching 'calibre.exe' were found.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, nothing is deleted.&lt;/p&gt;

&lt;p&gt;However, there may also be cases where the association is visible in Windows but is not detected by this tool.&lt;/p&gt;

&lt;p&gt;Windows stores file-association information in multiple locations, and this tool checks only registrations in the following form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HKEY_CLASSES_ROOT\&amp;lt;key&amp;gt;\shell\open\command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage Example
&lt;/h2&gt;

&lt;p&gt;To only check associations linked to &lt;code&gt;foo.exe&lt;/code&gt;, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove_association.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;foo.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After reviewing the results, to delete them, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove_association.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;foo.exe&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, suppose the detected result is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Found 1 association(s).

HKEY_CLASSES_ROOT\Foo.Document
  command = "C:\OldApps\Foo\foo.exe" "%1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you run the tool normally in this state, the deletion target is not simply:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HKEY_CLASSES_ROOT\Foo.Document\shell\open\command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead, the entire tree under:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HKEY_CLASSES_ROOT\Foo.Document
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;is deleted.&lt;/p&gt;

&lt;p&gt;Therefore, if &lt;code&gt;Foo.Document&lt;/code&gt; contains other registered information, that information will also be lost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Precautions
&lt;/h2&gt;

&lt;p&gt;This tool directly deletes registry keys. It does not provide a function to restore deleted keys.&lt;/p&gt;

&lt;p&gt;One especially important point is that when it finds a &lt;code&gt;shell\open\command&lt;/code&gt; matching the specified EXE name, it recursively deletes not just that &lt;code&gt;command&lt;/code&gt; key, but &lt;strong&gt;the association key itself directly under HKCR&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For that reason, the following workflow is recommended:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Confirm the target EXE filename.&lt;/li&gt;
&lt;li&gt;Search using &lt;code&gt;--dry-run&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Review every registry key that is displayed.&lt;/li&gt;
&lt;li&gt;If necessary, export the target key from Registry Editor to create a backup.&lt;/li&gt;
&lt;li&gt;Only after confirming there is no problem, run the tool normally.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It is particularly advisable to avoid targeting built-in Windows applications or applications that are currently in use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This tool examines Windows &lt;code&gt;HKEY_CLASSES_ROOT&lt;/code&gt;, searches for associations where the specified executable is registered under:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;key&amp;gt;\shell\open\command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and deletes those keys.&lt;/p&gt;

&lt;p&gt;The basic usage is simple.&lt;/p&gt;

&lt;p&gt;To only check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove_association.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;calibre.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To actually delete:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove_association.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;calibre.exe&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the tool directly modifies the registry, &lt;strong&gt;the most important step is to review the targets with &lt;code&gt;--dry-run&lt;/code&gt; first.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It can be useful for cleaning up old file associations left behind after uninstalling applications or associations for applications you no longer need, but because it deletes the entire association key, review the contents carefully and use it with caution.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wintypes&lt;/span&gt;


&lt;span class="n"&gt;shell32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WinDLL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shell32&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;use_last_error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;kernel32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WinDLL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kernel32&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;use_last_error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;shell32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommandLineToArgvW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argtypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;wintypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LPCWSTR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;POINTER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_int&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;shell32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommandLineToArgvW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;POINTER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wintypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LPWSTR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;kernel32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LocalFree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argtypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;wintypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HLOCAL&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;kernel32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LocalFree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wintypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HLOCAL&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;split_windows_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;c_int&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;argv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;shell32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CommandLineToArgvW&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;byref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WinError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_last_error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;kernel32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LocalFree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_open_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;subkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;rf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\shell\open\command&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OpenKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KEY_READ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;QueryValueEx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value_type&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REG_SZ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REG_EXPAND_SZ&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REG_EXPAND_SZ&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expandvars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;

    &lt;span class="nf"&gt;except &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;FileNotFoundError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PermissionError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;OSError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;executable_name_from_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;split_windows_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;except &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;OSError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_associations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_exe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;target_exe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target_exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;casefold&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HKEY_CLASSES_ROOT&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;key_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;EnumKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;OSError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;

        &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_open_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;

        &lt;span class="n"&gt;executable_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;executable_name_from_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;executable_name&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;executable_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;casefold&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target_exe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delete_registry_tree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subkey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OpenKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;subkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KEY_READ&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KEY_WRITE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;EnumKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;OSError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;

                &lt;span class="nf"&gt;delete_registry_tree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;rf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;subkey&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\{child}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DeleteKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subkey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;FileNotFoundError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Checks the executable name in HKCR\&amp;lt;key&amp;gt;\shell\open\command and &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deletes keys associated with the specified exe.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Executable filename to search for. Example: calibre.exe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--dry-run&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;store_true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;List only the target keys without deleting them&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;find_associations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No associations matching &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt; were found.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Found &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; association(s).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;fr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HKEY_CLASSES_ROOT\{key_name}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  command = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dry_run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dry-run: No keys were deleted.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Deleting.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;full_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;fr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HKEY_CLASSES_ROOT\{key_name}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;delete_registry_tree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HKEY_CLASSES_ROOT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DELETED: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;full_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;PermissionError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ACCESS DENIED: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;full_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;OSError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERROR: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;full_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Windowsの「関連付け」から特定アプリを削除するツールの使い方
&lt;/h1&gt;

&lt;p&gt;Windowsでは、アンインストール済みのアプリやポータブル版のアプリが、ファイルの関連付け情報だけをレジストリに残してしまうことがあります。&lt;/p&gt;

&lt;p&gt;たとえば &lt;code&gt;.epub&lt;/code&gt; や &lt;code&gt;.pdf&lt;/code&gt; などのファイルで「プログラムから開く」を表示したとき、すでに使っていないアプリが候補として残るケースです。&lt;/p&gt;

&lt;p&gt;ここでは、&lt;code&gt;HKEY_CLASSES_ROOT&lt;/code&gt; に登録されているファイル関連付けを調べ、指定した実行ファイルに紐付いているレジストリキーを削除するPythonツールの使い方を説明します。&lt;/p&gt;

&lt;h2&gt;
  
  
  このツールがすること
&lt;/h2&gt;

&lt;p&gt;このツールは &lt;code&gt;HKEY_CLASSES_ROOT&lt;/code&gt;、略して &lt;code&gt;HKCR&lt;/code&gt; の直下にあるキーを調べます。&lt;/p&gt;

&lt;p&gt;各キーについて、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HKEY_CLASSES_ROOT\&amp;lt;キー名&amp;gt;\shell\open\command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を確認し、既定値に設定されているコマンドの実行ファイル名を取得します。&lt;/p&gt;

&lt;p&gt;たとえば次のような登録があったとします。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"C:\Program Files\Calibre2\ebook-viewer.exe" "%1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;指定した実行ファイル名が &lt;code&gt;ebook-viewer.exe&lt;/code&gt; なら、この関連付けを対象として検出します。&lt;/p&gt;

&lt;p&gt;通常実行すると対象のレジストリキーを削除し、&lt;code&gt;--dry-run&lt;/code&gt; を付けると削除せず対象だけを表示します。&lt;/p&gt;

&lt;h2&gt;
  
  
  動作環境
&lt;/h2&gt;

&lt;p&gt;このスクリプトはWindows専用です。&lt;/p&gt;

&lt;p&gt;Pythonの標準ライブラリである、&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;argparse&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ctypes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;os&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;winreg&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;だけを使用しているため、追加パッケージのインストールは必要ありません。&lt;/p&gt;

&lt;p&gt;Python 3をインストールしたWindows環境で使用できます。&lt;/p&gt;

&lt;h2&gt;
  
  
  まずはスクリプトを保存する
&lt;/h2&gt;

&lt;p&gt;コードを、たとえば次の名前で保存します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;remove_association.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;コマンドプロンプトまたはPowerShellを開き、ファイルを保存したディレクトリへ移動してください。&lt;/p&gt;

&lt;p&gt;例:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:\Tools&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  最初は必ず &lt;code&gt;--dry-run&lt;/code&gt; で確認する
&lt;/h2&gt;

&lt;p&gt;レジストリキーを削除するツールなので、最初から削除を実行するのではなく、まず &lt;code&gt;--dry-run&lt;/code&gt; を使って対象を確認するのが安全です。&lt;/p&gt;

&lt;p&gt;書式は次のとおりです。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove_association.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;実行ファイル名&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;たとえば &lt;code&gt;calibre.exe&lt;/code&gt; に関連付けられた項目を調べる場合は、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove_association.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;calibre.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;と実行します。&lt;/p&gt;

&lt;p&gt;対象が見つかると、次のような形式で表示されます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Found 2 association(s).

HKEY_CLASSES_ROOT\Calibre...
  command = "C:\Program Files\Calibre2\calibre.exe" "%1"

HKEY_CLASSES_ROOT\...
  command = "C:\Program Files\Calibre2\calibre.exe" "%1"

dry-run: No keys were deleted.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;最後に&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dry-run: No keys were deleted.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;と表示されている場合、レジストリは変更されていません。&lt;/p&gt;

&lt;h2&gt;
  
  
  実際に削除する
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;--dry-run&lt;/code&gt; の結果を確認し、本当に不要な関連付けだけが検出されていることを確認したら、&lt;code&gt;--dry-run&lt;/code&gt; を外して実行します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove_association.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;calibre.exe&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;削除に成功すると、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DELETED: HKEY_CLASSES_ROOT\...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;と表示されます。&lt;/p&gt;

&lt;p&gt;複数の関連付けが見つかった場合は、検出されたキーが順番に削除されます。&lt;/p&gt;

&lt;h2&gt;
  
  
  実行ファイル名だけを指定する
&lt;/h2&gt;

&lt;p&gt;引数に指定するのは、基本的には実行ファイルのフルパスではなくファイル名です。&lt;/p&gt;

&lt;p&gt;たとえば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\Program Files\Calibre2\calibre.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ではなく、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;calibre.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を指定します。&lt;/p&gt;

&lt;p&gt;このツールはレジストリに登録されたコマンドをWindowsのルールに従って分解し、その先頭にある実行ファイルのファイル名だけを取り出して比較しています。&lt;/p&gt;

&lt;p&gt;比較では大文字・小文字を区別しません。そのため、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CALIBRE.EXE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;と&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;calibre.exe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;は同じものとして扱われます。&lt;/p&gt;

&lt;h2&gt;
  
  
  なぜ単純な文字列検索をしていないのか
&lt;/h2&gt;

&lt;p&gt;関連付けのコマンドは、単純に実行ファイルのパスだけが保存されているとは限りません。&lt;/p&gt;

&lt;p&gt;たとえば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"C:\Program Files\Example\viewer.exe" "%1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;や、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"C:\Program Files\Example\viewer.exe" --open "%1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のような形式があります。&lt;/p&gt;

&lt;p&gt;さらにWindowsのコマンドラインでは、引用符や空白の扱いに独自の規則があります。&lt;/p&gt;

&lt;p&gt;そこでこのツールでは、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CommandLineToArgvW
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;というWindows APIを使ってコマンド文字列を解析しています。&lt;/p&gt;

&lt;p&gt;解析後の最初の引数から、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;で実行ファイル名を取り出しています。&lt;/p&gt;

&lt;p&gt;そのため、単純に&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;calibre.exe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のような部分一致で判定するより、誤検出が起こりにくい構造になっています。&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;REG_EXPAND_SZ&lt;/code&gt; にも対応
&lt;/h2&gt;

&lt;p&gt;レジストリのコマンドが通常の文字列 &lt;code&gt;REG_SZ&lt;/code&gt; だけでなく、環境変数を含む &lt;code&gt;REG_EXPAND_SZ&lt;/code&gt; だった場合にも対応しています。&lt;/p&gt;

&lt;p&gt;たとえば、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"%ProgramFiles%\Example\viewer.exe" "%1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のような値です。&lt;/p&gt;

&lt;p&gt;この場合は、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expandvars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;によって環境変数を展開してから解析します。&lt;/p&gt;

&lt;h2&gt;
  
  
  関連付けの検索方法
&lt;/h2&gt;

&lt;p&gt;検索の中心となっているのが &lt;code&gt;find_associations()&lt;/code&gt; です。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_associations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_exe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ここでは &lt;code&gt;HKEY_CLASSES_ROOT&lt;/code&gt; の直下を &lt;code&gt;winreg.EnumKey()&lt;/code&gt; で順番に走査しています。&lt;/p&gt;

&lt;p&gt;それぞれについて、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;キー&amp;gt;\shell\open\command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;を読み取り、実行ファイル名が指定された名前と一致すると、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;で削除候補として返します。&lt;/p&gt;

&lt;p&gt;つまり、このツールの検索対象は &lt;strong&gt;HKCR直下の各キーに存在する &lt;code&gt;shell\open\command&lt;/code&gt;&lt;/strong&gt; です。&lt;/p&gt;

&lt;p&gt;Windowsに存在するあらゆる種類の関連付け情報を網羅的に検索するツールではない点には注意してください。&lt;/p&gt;

&lt;h2&gt;
  
  
  削除はサブキーも含めて行われる
&lt;/h2&gt;

&lt;p&gt;レジストリキーは、その下にサブキーが存在すると単純には削除できません。&lt;/p&gt;

&lt;p&gt;そのため &lt;code&gt;delete_registry_tree()&lt;/code&gt; では、子キーを再帰的に削除してから親キーを削除しています。&lt;/p&gt;

&lt;p&gt;概念的には、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;対象キー
├─ DefaultIcon
├─ shell
│  └─ open
│     └─ command
└─ その他
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という構造があった場合、下の階層から順番に削除し、最後に「対象キー」そのものを削除します。&lt;/p&gt;

&lt;p&gt;したがって、このツールで検出されたキーを削除すると、&lt;code&gt;shell\open\command&lt;/code&gt; だけではなく &lt;strong&gt;その関連付けキー全体が削除されます。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;これは重要なポイントです。&lt;/p&gt;

&lt;h2&gt;
  
  
  権限エラーが出た場合
&lt;/h2&gt;

&lt;p&gt;削除時に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ACCESS DENIED: HKEY_CLASSES_ROOT\...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;と表示されることがあります。&lt;/p&gt;

&lt;p&gt;これは、そのレジストリキーを書き換えるための権限が現在のユーザーにない場合などに発生します。&lt;/p&gt;

&lt;p&gt;必要であれば「管理者として実行」したPowerShellやコマンドプロンプトから実行します。&lt;/p&gt;

&lt;p&gt;ただし、権限エラーが出たからといって、無条件に管理者権限で削除すべきとは限りません。&lt;/p&gt;

&lt;p&gt;まず &lt;code&gt;--dry-run&lt;/code&gt; の出力を見て、そのキーが本当に不要なものか確認してください。&lt;/p&gt;

&lt;h2&gt;
  
  
  対象が見つからない場合
&lt;/h2&gt;

&lt;p&gt;一致する関連付けが存在しない場合は、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;No associations matching 'calibre.exe' were found.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;のように表示されます。&lt;/p&gt;

&lt;p&gt;この場合、何も削除されません。&lt;/p&gt;

&lt;p&gt;ただし、目的の関連付けがWindows上に表示されているにもかかわらず検出されないこともあります。&lt;/p&gt;

&lt;p&gt;Windowsのファイル関連付けは複数の場所に保存されており、このツールが調べているのは、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HKEY_CLASSES_ROOT\&amp;lt;key&amp;gt;\shell\open\command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;という形式の登録だけだからです。&lt;/p&gt;

&lt;h2&gt;
  
  
  使用例
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;foo.exe&lt;/code&gt; に紐付く関連付けを確認するだけなら、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove_association.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;foo.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;確認後、削除するなら、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove_association.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;foo.exe&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;です。&lt;/p&gt;

&lt;p&gt;たとえば検出結果が、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Found 1 association(s).

HKEY_CLASSES_ROOT\Foo.Document
  command = "C:\OldApps\Foo\foo.exe" "%1"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;だったとします。&lt;/p&gt;

&lt;p&gt;この状態で通常実行すると、削除対象は単に、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HKEY_CLASSES_ROOT\Foo.Document\shell\open\command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;だけではありません。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HKEY_CLASSES_ROOT\Foo.Document
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;以下のツリー全体です。&lt;/p&gt;

&lt;p&gt;そのため、&lt;code&gt;Foo.Document&lt;/code&gt; に別の情報も登録されている場合、それらも失われます。&lt;/p&gt;

&lt;h2&gt;
  
  
  使用上の注意
&lt;/h2&gt;

&lt;p&gt;このツールはレジストリを直接削除します。削除したキーを元に戻す機能はありません。&lt;/p&gt;

&lt;p&gt;特に注意すべきなのは、指定したEXE名に一致した &lt;code&gt;shell\open\command&lt;/code&gt; を見つけると、その &lt;code&gt;command&lt;/code&gt; キーだけでなく &lt;strong&gt;HKCR直下の関連付けキーそのものを再帰的に削除する&lt;/strong&gt; ことです。&lt;/p&gt;

&lt;p&gt;そのため、基本的には次の順序で使うことを推奨します。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;対象となるEXE名を確認する&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--dry-run&lt;/code&gt; で検索する&lt;/li&gt;
&lt;li&gt;表示されたすべてのレジストリキーを確認する&lt;/li&gt;
&lt;li&gt;必要ならレジストリエディターで対象キーをエクスポートしてバックアップする&lt;/li&gt;
&lt;li&gt;問題がないことを確認してから通常実行する&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;特にWindows標準アプリや現在使用中のアプリを対象にするのは避けたほうがよいでしょう。&lt;/p&gt;

&lt;h2&gt;
  
  
  まとめ
&lt;/h2&gt;

&lt;p&gt;このツールは、Windowsの &lt;code&gt;HKEY_CLASSES_ROOT&lt;/code&gt; を調べて、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;キー&amp;gt;\shell\open\command
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;に指定した実行ファイルが登録されている関連付けを探し、そのキーを削除するためのものです。&lt;/p&gt;

&lt;p&gt;基本的な使い方はシンプルです。&lt;/p&gt;

&lt;p&gt;確認だけなら、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove_association.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;calibre.exe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;--dry-run&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;実際に削除するなら、&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;remove_association.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;calibre.exe&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;です。&lt;/p&gt;

&lt;p&gt;レジストリを直接操作するため、&lt;strong&gt;最初に &lt;code&gt;--dry-run&lt;/code&gt; で対象を確認することが最も重要です。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;アンインストール後も残っている古いファイル関連付けや、不要になったアプリの関連付けを整理するときに使えるツールですが、削除対象は関連付けキー全体なので、内容を確認したうえで慎重に使用してください。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;wintypes&lt;/span&gt;


&lt;span class="n"&gt;shell32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WinDLL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;shell32&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;use_last_error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;kernel32&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WinDLL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kernel32&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;use_last_error&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;shell32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommandLineToArgvW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argtypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;wintypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LPCWSTR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;POINTER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c_int&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;shell32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CommandLineToArgvW&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;POINTER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;wintypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LPWSTR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;kernel32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LocalFree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argtypes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;wintypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HLOCAL&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;kernel32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LocalFree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;restype&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;wintypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HLOCAL&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;split_windows_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;c_int&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;argv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;shell32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CommandLineToArgvW&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;byref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WinError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctypes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_last_error&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

    &lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;kernel32&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LocalFree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_open_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;subkey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;rf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\shell\open\command&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OpenKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KEY_READ&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;QueryValueEx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value_type&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REG_SZ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REG_EXPAND_SZ&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;REG_EXPAND_SZ&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expandvars&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;

    &lt;span class="nf"&gt;except &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;FileNotFoundError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;PermissionError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;OSError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;executable_name_from_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;split_windows_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;except &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;OSError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_associations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target_exe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;target_exe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;target_exe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;casefold&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HKEY_CLASSES_ROOT&lt;/span&gt;
    &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;key_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;EnumKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;OSError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;

        &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

        &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_open_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;

        &lt;span class="n"&gt;executable_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;executable_name_from_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;executable_name&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;executable_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;casefold&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;target_exe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;delete_registry_tree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subkey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;OpenKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;subkey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KEY_READ&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;KEY_WRITE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;EnumKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;OSError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;

                &lt;span class="nf"&gt;delete_registry_tree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;rf&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;subkey&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;\{child}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DeleteKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;subkey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;FileNotFoundError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Checks the executable name in HKCR\&amp;lt;key&amp;gt;\shell\open\command and &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deletes keys associated with the specified exe.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Executable filename to search for. Example: calibre.exe&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--dry-run&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;store_true&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;List only the target keys without deleting them&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;find_associations&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;No associations matching &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exe&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s"&gt; were found.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Found &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; association(s).&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;fr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HKEY_CLASSES_ROOT\{key_name}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;  command = &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dry_run&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dry-run: No keys were deleted.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Deleting.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;full_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;fr&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HKEY_CLASSES_ROOT\{key_name}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;delete_registry_tree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;winreg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HKEY_CLASSES_ROOT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;key_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;DELETED: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;full_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;PermissionError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ACCESS DENIED: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;full_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;OSError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERROR: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;full_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>automation</category>
      <category>python</category>
      <category>tools</category>
    </item>
  </channel>
</rss>
