「Git」の版間の差分

提供:senooken JP Wiki
(VCS-Gitに分離。)
 
(範囲選択)
(同じ利用者による、間の23版が非表示)
1行目: 1行目:
[[IT]]
[[Category:VCS]]
== log ==
== Host ==
=== GitHub ===


==== Account ====
Username may only contain alphanumeric characters or single hyphens, and cannot begin or end with a hyphen.
ユーザー名は、英数字と-のみが使用可能。
組織別にアカウントを分けるなら、かぶらないように末尾に-組織名のようなサフィックスがあるとよいだろう。
==== README ====
https://chatgpt.com/c/6779ea86-96e4-800b-ba81-eeca2793d397
[https://docs.github.com/ja/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes#about-readmes READMEについて - GitHub Docs]
GitHubではREADME系ファイルを描画表示してくれる。READMEとREADME.*が対象。index.html系はだめ。
==== PR ====
Pull Request。第三者の修正を、本体側でgit pull (取り込む) ことのリクエスト・要請。
===== PR後のブランチ更新 =====
PR作成後にブランチの内容を更新する場合は注意が必要。
マージ元ブランチはPR作成時のバージョンで固定される。マージ元とマージ先の両方にたとえばdevelopなどの共通の修正を取り込んだ場合、GitHubの画面でマージ元ブランチも選択し直して、参照バージョンを更新しておく。
そうしないと、マージ先だけ反映されてしまって、想定していない差分が大量に表示される。
===== Web UIでの編集 =====
[https://qiita.com/kotakagi/items/55739a8b87255e753e9c 素人の私でもわかる「Webブラウザだけでgithubのプルリクをする方法」 #GitHub - Qiita]
他の人のリポジトリーで修正箇所を見つけたら、そのファイルの編集ボタンで編集して、ボタン操作で自動でフォークしてPRを作れる。
レビュー指摘が来た場合、自分の該当ブランチを開いて、編集したらそのままコミットできる。
1ファイル1コミットの場合、Web UIで完結できる。修正が少ない場合、悪くない。
===== 範囲選択 =====
[https://docs.github.com/ja/pull-requests/collaborating-with-pull-requests/reviewing-changes-in-pull-requests/reviewing-proposed-changes-in-a-pull-request プルリクエストで提案された変更をレビューする - GitHub Docs]
[Pull requests]-[File changed] で変更ファイルについてコメントする形でレビューする。
この際、行部分をドラッグすると、行を指定してブロックでコメントできる。
ファイル自体にコメントするには、右上のコメントマーク。
== View ==
=== log ===
* 逆順表示: --reverse
* 逆順表示: --reverse
* 差分表示: -p
* 差分表示: -p


== Commit ==
=== Other ===
 
==== 親コミットの参照 ====
[https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E3%83%AA%E3%83%93%E3%82%B8%E3%83%A7%E3%83%B3%E3%81%AE%E9%81%B8%E6%8A%9E Git - リビジョンの選択]
 
Gitは自分より後ろ (新しい) コミットは参照しやすいが、その逆の先祖の履歴は参照しにくい。なくはない。
 
^Nと~Nで対象コミットのN番目の親コミットを参照できる。これで一応辿れる。
 
=== gitrevisions ===
[https://git-scm.com/docs/gitrevisions Git - gitrevisions Documentation]
 
[https://git-scm.com/book/en/v2/Git-Tools-Revision-Selection Git - Revision Selection]


=== マージコミット後のコミット追加 ===
Gitでは多くの方法でコミット (<rev>) を参照できる。
マージコミット後に次の開発作業を始めることが多い。が、直後の初回のコミットを追加したい場合困る。
{| class="wikitable"
|+
!種類
!例
!説明
|-
|<sha1>
|''dae86e1950b1277e545cee180551750029cfe735  dae86e''
|SHA!-1オブジェクト (40バイトの16進数)、またはリポジトリー内で一意の先頭部分文字列。
|-
|<describeOutput>
|v1.7.4.2-679-g3bee7fb
|git describeの出力。タグ名など
|-
|<refname>
|master、heads/master、refs/heads/master
|シンボリック参照名。
|}
refname


git rebase -iにすると、コミットが残るから。編集はできるが、その直前にコミットの追加ができない。マージコミットは扱いが特殊で直接rebaseで編集できない。
refnameはいろいろある。


しかたないので、該当コミットでブランチを作成して、コミット。その後、既存の修正ブランチをrebaseでそのコミットの後にくっつける。これでいける。
== Commit ==


=== コミットオプション ===
=== コミットオプション ===
45行目: 120行目:


rebase --root [branch] でブランチの第一コミットも参照して改変可能。
rebase --root [branch] でブランチの第一コミットも参照して改変可能。
=== コミットログの文字化け ===
[https://wadahiro.hatenablog.com/entry/20090506/1241622572 Git コミットログの文字化けではまる - wadahiroの日記]
git commitやgit commi --amend実行時のコミットログがgit logで文字化けすることがある。
これは、git commit時に実行しているテキストエディター (vim) の文字エンコーディング設定が由来の可能性が高い。
gitはデフォルトでutf-8なので、以下のような内容を~/.vimrcに書いておいて、utf-8にしておけば解消する。
"" Encoding
set encoding=utf-8
set fileencodings=ucs-bom,iso-2022-jp,utf-8,euc-jp,cp932,cp1252
set fileformats=unix,dos,mac
augroup main
  autocmd!
augroup END
"" Fix 'fileencoding' to use 'encoding' if the buffer only ASCII characters.
autocmd main BufReadPost *
  \  if &modifiable && !search('[^\x00-\x7F]', 'cnw')
  \ |  setlocal fileencoding=utf-8
  \ | endif
=== コミット同士の比較 ===
コマンドで綺麗にはできない。git diffはブランチ同士の比較でコミット以外の過去の状態も比較する。
コミット同士で比較するなら、git showの出力結果をファイルに出力してdiff -uで比較するしかない。
git show sha1 >old.diff
git show sha1 >new.diff
diff -u old.diff new.diff
=== 別のディレクトリーへの修正適用 ===
https://chatgpt.com/c/67bea3ff-56c4-800b-ae92-d40299ad5ade
あるディレクトリーに適用した修正を、ルートのディレクトリー名だけが異なる別ファイルに適用したいことがある。
修正内容の差分をgit format-patch/git diff/git showでファイルに出力して、ファイル内のパスを変更して、そのファイルを使ってgit applyするとうまく取り込める。
== branch ==
[https://git-scm.com/docs/git-branch Git - git-branch Documentation]
=== 誤ったブランチへのコミットの付け直し ===
* [https://dev.classmethod.jp/articles/git-rebase-branch-miss-commits/ [初心者向け] Gitで間違ったブランチにしたコミットを別ブランチに付け替える | DevelopersIO]
* [https://dev.classmethod.jp/articles/git-move-change-to-another-branch/ [Git]誤ったブランチで実施した変更を正しいブランチに移動する | DevelopersIO]
ブランチを変えずに作業していて、コミット量が増えたので、別ブランチにしておけばよかったということがあったりする。
いくつか方法がある。
# cherry-pickで変更コミットだけ別ブランチに抽出。
# git checkoutとreset --hardで分離: 現在の状態を一旦別ブランチにしてコピー。その後、元ブランチはgit reset --hardで打ち消す。
# git rebase --onto <別ブランチ> 起点コミット でコミットを付け替えて、ブランチを削除、解明して元のブランチの名前にする。
git rebase --ontoがきれい。
=== 他のブランチとの同一化 ===
git diff HEAD master | patch -p 1
patchの他にgit applyでもいい。
=== remote ===
リモートトラッキングブランチという概念。
gitのpush/pull時の対象リモートリポジトリーのブランチのローカルの対応ブランチ。リモートブランチのデータのローカルの管理用。
* git branch -u|--set-upstream-to <upstream>: リモートトラッキングブランチを指定。
* git branch --unset-upstream: 設定済みのリモートトラッキングブランチの対応を解除。
== Merge ==
=== rebase時のマージコミット維持 ===
* [https://blog.70-10.net/posts/git-rebase-merge/ rebase時にマージコミットを残したいのなら、--rebase-mergeオプションを使おう | mnml]
* [https://chaika.hatenablog.com/entry/2020/09/07/083000 Git マージコミットを残したまま rebase したい。 - かもメモ]
git rebase -iはマージコミットを削除してしまう。マージコミットを残したいなら、-rを指定する。昔は-pだった。
-rを忘れてしまった場合、git reflogでリベース前のコミットを探してgit reset --hardでそのコミットに戻してからやり直す。
=== マージコミット後のコミット追加 ===
マージコミット後に次の開発作業を始めることが多い。が、直後の初回のコミットを追加したい場合困る。
git rebase -iにすると、コミットが残るから。編集はできるが、その直前にコミットの追加ができない。マージコミットは扱いが特殊で直接rebaseで編集できない。
しかたないので、該当コミットでブランチを作成して、コミット。その後、既存の修正ブランチをrebaseでそのコミットの後にくっつける。これでいける。


=== マージコミットの打ち消し ===
=== マージコミットの打ち消し ===
マージコミットは扱いがやや特殊。
マージコミットは扱いがやや特殊。
git revert -m 1 マージコミット
git revert -m 1 マージコミット
git reset --hard HEAD~1 # マージコミット前
git reset --hard HEAD~1 # マージコミット前
どちらか。
どちらか。
https://chatgpt.com/c/679983bc-a96c-800b-9d8c-a15873d1d068
git revert -mは1か2の数字を指定する。これは、マージはマージ元とマージ先の親ブランチが2個あり、どちらを基準にリバートするかを指定するためにある。
基本はマージ元 (mainやdevelopブランチ) の1を指定する。マージ先のfeatureブランチは2だがこちらを指定することはあまないだろう。
=== git checkoutなしのmerge ===
* https://chatgpt.com/c/677f6038-4fa8-800b-9efb-fae4d2a4ab91
* [https://qiita.com/keisuke-nakata/items/cd8b448215747c29fd81 checkoutせずにmergeする #Git - Qiita]
* [https://stackoverflow.com/questions/3216360/merge-update-and-pull-git-branches-without-using-checkouts Merge, update, and pull Git branches without using checkouts - Stack Overflow]
* [https://coderwall.com/p/0kxphg/merging-branches-without-checkout Merging Branches Without Checkout (Example)]
gitでブランチをマージする場合、基本はマージの取り込み元ブランチに移動してから、対象ブランチを取り込む必要がある。
これは、3wayマージなどのために、マージの元ファイルが必要だからとのこと。
ただ、毎回切り替えるのが面倒くさい。ブランチ同士でのマージが一応可能。
git fetch . src:dst
ただし、このコマンドはfast-fowardsマージの場合だけ。rebase相当。それ以外は上書きされるので、手動マージが必要。注意が必要。
スクリプトの自動処理などで使う感じ。
=== cherry-pick後のmergeで重複コミット ===
[https://ja.stackoverflow.com/questions/92543/git-%E3%81%A7cherry-pick-%E5%BE%8C%E3%81%AB-merge%E3%81%99%E3%82%8B%E3%81%A8%E5%90%8C%E3%81%98commit%E3%81%AE%E5%B1%A5%E6%AD%B4%E3%81%8C%E8%A4%87%E6%95%B0%E3%81%A7%E3%81%8D%E3%81%A6%E3%81%97%E3%81%BE%E3%81%86 github - Git でCherry-pick 後に Mergeすると同じCommitの履歴が複数できてしまう - スタック・オーバーフロー]
ブランチが2個あって、ブランチでコミット・pushした後、間違えたブランチだと気づいて、別ブランチでcherry-pick。その後、ブランチの内容を取り込むためにまたmergeしたら、cherry-pickのコミットのマージができる。
コミット履歴が残っているから、それを素直に取り込んだだけで、残るのは仕方ない。rebaseやreset --hardで消すしかないが、pushしているから、一人とかじゃないとだめ。
重複コミットは諦めるしかない。
=== マージコミット前後の比較 ===
MC=cf128108e43b0d614528d2ab04fc9fa4188761e1
git diff ${MC}~ $MC
~でマージコミットの1個前のコミットを参照して差分をとればいい。


== stash ==
== stash ==
133行目: 329行目:


=== gitignore ===
=== gitignore ===
[https://git-scm.com/docs/gitignore/en Git - gitignore Documentation]
[https://git-scm.com/docs/gitignore Git - gitignore Documentation]
 
gitの管理対象外のファイル。ログや一時ファイルなど。
 
これで指定していないと、git addすると管理対象に入るし、untracked fileで表示が出る。git add .やディレクトリー指定で一括で管理したい場合に混ざっていると邪魔。
 
==== File ====
 
* .gitignore: ディレクトリー内。
* $GIT_DIR/info/exclude: リポジトリー固有のローカル。
* core.excludesFile: ~/.gitconfig内で指定するgitignoreファイル。通常、$XDG_CONFIG_HOME/git/ignoreか$HOME/.config/git/ignore。


==== Format ====
==== Format ====
143行目: 349行目:
* !接頭辞はパターン否定。つまり、除外ではなく含める。以前除外された一致を再び含める。ただし、親ディレクトリーが除外されている場合、以下のファイルは含められない。パフォーマンス上の理由。順番に注意する。
* !接頭辞はパターン否定。つまり、除外ではなく含める。以前除外された一致を再び含める。ただし、親ディレクトリーが除外されている場合、以下のファイルは含められない。パフォーマンス上の理由。順番に注意する。
* /はディレクトリー区切りとして使用。先頭、中間、末尾で登場する。
* /はディレクトリー区切りとして使用。先頭、中間、末尾で登場する。
  ** 先頭と中間の/は相対パスを意味する。
** 先頭と中間の/は相対パスを意味する。
  ** それ以外、末尾の/と/なしの場合、現在以下のディレクトリーにもマッチする。
** それ以外、末尾の/と/なしの場合、現在以下のディレクトリーにもマッチする。
  ** 末尾が/で終わる場合、ディレクトリーのみに一致。/がない場合、ディレクトリーとファイルの両方に一致。
** 末尾が/で終わる場合、ディレクトリーのみに一致。/がない場合、ディレクトリーとファイルの両方に一致。
 
* *は/以外にマッチ。?は/以外の任意の1文字にマッチ。[a-zA-Z] の範囲記法も使用可能。fnmatch(3) FNM_PATHNAMEフラグのパス名展開に準じる。
* *は/以外にマッチ。?は/以外の任意の1文字にマッチ。[a-zA-Z] の範囲記法も使用可能。fnmatch(3) FNM_PATHNAMEフラグのパス名展開に準じる。
* **は特殊な意味がある。
* **は特殊な意味がある。
  ** **/=全ディレクトリー。**/fooは配下の全fooにマッチ。**/foo/barはfoo以下の全barにマッチ。
** **/=全ディレクトリー。**/fooは配下の全fooにマッチ。**/foo/barはfoo以下の全barにマッチ。
  ** /**=配下のすべてにマッチ。
** /**=配下のすべてにマッチ。
  ** a/**/b=a/b a/x/b a/x/y/bのすべてにマッチ。
** a/**/b=a/b a/x/b a/x/y/bのすべてにマッチ。
 
後は特に明記がないが、上から順番に評価されて、最後のマッチが優先されるので、記述の順番に注意する。
後は特に明記がないが、上から順番に評価されて、最後のマッチが優先されるので、記述の順番に注意する。


157行目: 363行目:


先頭スラッシュをつけないと、再帰的になる。
先頭スラッシュをつけないと、再帰的になる。
$ cat .gitignore
$ cat .gitignore
# ディレクトリ foo/bar 以外のすべてを除外
# ディレクトリ foo/bar 以外のすべてを除外
/*
## /*
!/foo
## !/foo
/foo/*
## /foo/*
!/foo/bar
## !/foo/bar
 
==== 空ディレクトリーの維持 ====
==== 空ディレクトリーの維持 ====
[https://stackoverflow.com/questions/115983/how-do-i-add-an-empty-directory-to-a-git-repository How do I add an empty directory to a Git repository? - Stack Overflow]
[https://stackoverflow.com/questions/115983/how-do-i-add-an-empty-directory-to-a-git-repository How do I add an empty directory to a Git repository? - Stack Overflow]
170行目: 376行目:


logなど維持したい空ディレクトリーに、以下の内容の.gitignoreを置く。
logなど維持したい空ディレクトリーに、以下の内容の.gitignoreを置く。
!.gitignore
!.gitignore
.gitignore以外を無視する。これで.gitignoreのみがあるので管理できる。
.gitignore以外を無視する。これで.gitignoreのみがあるので管理できる。


201行目: 409行目:
git rm --cached
git rm --cached


== gitk ==
== Other ==
 
=== .netrc ===
https://social.senooken.jp/conversation/1573147#notice-2217499
 
Gitのパスワード入力の省略方法に~/.netrcがある。
 
しかし、man netrcするとわかるけど、これはもともとFTPのためのもの。なぜGitで使えるんだ?Gitの文書で言及がない。
 
In conversation Thursday, 21-Feb-2019 10:58:47 JST from web permalink
 
せのお (妹尾 賢)せのお (妹尾 賢) in reply to
 
理由が分かった。
 
1. Gitはhttpとhttpsの通信にcURLを使っている。
 
<nowiki>https://github.com/git/git/blob/master/INSTALL#L141</nowiki>
 
2. cURLが.netrcにも対応しているから。


=== problem ===
<nowiki>https://ec.haxx.se/usingcurl-netrc.html</nowiki>
ブランチ名が長いと、右クリックしにくい


== submodule ==
=== submodule ===
https://git-scm.com/docs/git-submodule
https://git-scm.com/docs/git-submodule


https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E3%82%B5%E3%83%96%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB
https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E3%82%B5%E3%83%96%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB


=== foreach ===
==== foreach ====
サブモジュールの全部を一括処理する。
サブモジュールの全部を一括処理する。
foreach [--recursive] <command>
foreach [--recursive] <command>
224行目: 450行目:
git submodule foreach 'git reset --hard'
git submodule foreach 'git reset --hard'


== Other ==
=== gitk ===


=== 他のブランチとの同一化 ===
==== problem ====
git diff HEAD master | patch -p 1
ブランチ名が長いと、右クリックしにくい
patchの他にgit applyでもいい。


=== .netrc ===
=== clean ===
https://social.senooken.jp/conversation/1573147#notice-2217499
git未管理のファイルを削除するためのコマンド。間違えると復元不能なので注意する。


Gitのパスワード入力の省略方法に~/.netrcがある。
必ず-nで削除対象を確認してから、-nの本実行を試すこと。


しかし、man netrcするとわかるけど、これはもともとFTPのためのもの。なぜGitで使えるんだ?Gitの文書で言及がない。
-x/-Xでgitignoreによる無視ファイルも削除できる。


In conversation Thursday, 21-Feb-2019 10:58:47 JST from web permalink
=== Mac ===


せのお (妹尾 賢)せのお (妹尾 賢) in reply to
* /Library/Developer/CommandLineTools/usr/bin/git
* /Library/Developer/CommandLineTools/usr/libexec/git-core/


理由が分かった。
上記2箇所がMac標準のgit関係の格納場所。
 
1. Gitはhttpとhttpsの通信にcURLを使っている。


<nowiki>https://github.com/git/git/blob/master/INSTALL#L141</nowiki>
特に重要な補完ツールは以下にある。


2. cURLが.netrcにも対応しているから。
* /Library/Developer/CommandLineTools//usr/share/git-core/
 
** git-completion.tcsh
<nowiki>https://ec.haxx.se/usingcurl-netrc.html</nowiki>
** git-completion.zsh
** git-completion.bash
** git-prompt.sh

2025年3月17日 (月) 10:19時点における版

Host

GitHub

Account

Username may only contain alphanumeric characters or single hyphens, and cannot begin or end with a hyphen. ユーザー名は、英数字と-のみが使用可能。

組織別にアカウントを分けるなら、かぶらないように末尾に-組織名のようなサフィックスがあるとよいだろう。

README

https://chatgpt.com/c/6779ea86-96e4-800b-ba81-eeca2793d397

READMEについて - GitHub Docs

GitHubではREADME系ファイルを描画表示してくれる。READMEとREADME.*が対象。index.html系はだめ。

PR

Pull Request。第三者の修正を、本体側でgit pull (取り込む) ことのリクエスト・要請。

PR後のブランチ更新

PR作成後にブランチの内容を更新する場合は注意が必要。

マージ元ブランチはPR作成時のバージョンで固定される。マージ元とマージ先の両方にたとえばdevelopなどの共通の修正を取り込んだ場合、GitHubの画面でマージ元ブランチも選択し直して、参照バージョンを更新しておく。

そうしないと、マージ先だけ反映されてしまって、想定していない差分が大量に表示される。

Web UIでの編集

素人の私でもわかる「Webブラウザだけでgithubのプルリクをする方法」 #GitHub - Qiita

他の人のリポジトリーで修正箇所を見つけたら、そのファイルの編集ボタンで編集して、ボタン操作で自動でフォークしてPRを作れる。

レビュー指摘が来た場合、自分の該当ブランチを開いて、編集したらそのままコミットできる。

1ファイル1コミットの場合、Web UIで完結できる。修正が少ない場合、悪くない。

範囲選択

プルリクエストで提案された変更をレビューする - GitHub Docs

[Pull requests]-[File changed] で変更ファイルについてコメントする形でレビューする。

この際、行部分をドラッグすると、行を指定してブロックでコメントできる。

ファイル自体にコメントするには、右上のコメントマーク。

View

log

  • 逆順表示: --reverse
  • 差分表示: -p

Other

親コミットの参照

Git - リビジョンの選択

Gitは自分より後ろ (新しい) コミットは参照しやすいが、その逆の先祖の履歴は参照しにくい。なくはない。

^Nと~Nで対象コミットのN番目の親コミットを参照できる。これで一応辿れる。

gitrevisions

Git - gitrevisions Documentation

Git - Revision Selection

Gitでは多くの方法でコミット (<rev>) を参照できる。

種類 説明
<sha1> dae86e1950b1277e545cee180551750029cfe735 dae86e SHA!-1オブジェクト (40バイトの16進数)、またはリポジトリー内で一意の先頭部分文字列。
<describeOutput> v1.7.4.2-679-g3bee7fb git describeの出力。タグ名など
<refname> master、heads/master、refs/heads/master シンボリック参照名。

refname

refnameはいろいろある。

Commit

コミットオプション

Git - git-commit Documentation

コミットメッセージ指定のためのオプションがある。

  • -m|--message <message>: コミットを文字列で指定。複数指定可能で、その場合段落で区切ってくれる。2行目以後を書きたい場合などで使う。
  • -C|--reuse-message <commit>: 指定したコミットのコミット情報を再使用する。
  • -c|--reedit-message <commit>: -Cの同じだが、編集画面を表示してコミットメッセージを編集して再使用する。
  • -F|--file=<file>: 指定したファイルをコミットメッセージに使う。-を指定すると標準入力を使う。

基本は-m。-mの複数指定。

過去コミットのメールアドレスの変更

単一コミットのメールアドレスを指定する場合、commitに--authorを指定する。 git commit --author="John Doe <john@doe.org>" --amendと併用することで、過去コミットも変更できる。

数が少ないなら、rebase -iで1個ずつamendする。数が多いならfilter-branch。

第一コミットの変更

通常、第一コミットはammend以外では変更できない。

rebase --root [branch] でブランチの第一コミットも参照して改変可能。

コミットログの文字化け

Git コミットログの文字化けではまる - wadahiroの日記

git commitやgit commi --amend実行時のコミットログがgit logで文字化けすることがある。

これは、git commit時に実行しているテキストエディター (vim) の文字エンコーディング設定が由来の可能性が高い。

gitはデフォルトでutf-8なので、以下のような内容を~/.vimrcに書いておいて、utf-8にしておけば解消する。

"" Encoding
set encoding=utf-8
set fileencodings=ucs-bom,iso-2022-jp,utf-8,euc-jp,cp932,cp1252
set fileformats=unix,dos,mac

augroup main
  autocmd!
augroup END

"" Fix 'fileencoding' to use 'encoding' if the buffer only ASCII characters.
autocmd main BufReadPost *
  \   if &modifiable && !search('[^\x00-\x7F]', 'cnw')
  \ |   setlocal fileencoding=utf-8
  \ | endif

コミット同士の比較

コマンドで綺麗にはできない。git diffはブランチ同士の比較でコミット以外の過去の状態も比較する。

コミット同士で比較するなら、git showの出力結果をファイルに出力してdiff -uで比較するしかない。

git show sha1 >old.diff
git show sha1 >new.diff
diff -u old.diff new.diff

別のディレクトリーへの修正適用

https://chatgpt.com/c/67bea3ff-56c4-800b-ae92-d40299ad5ade

あるディレクトリーに適用した修正を、ルートのディレクトリー名だけが異なる別ファイルに適用したいことがある。

修正内容の差分をgit format-patch/git diff/git showでファイルに出力して、ファイル内のパスを変更して、そのファイルを使ってgit applyするとうまく取り込める。

branch

Git - git-branch Documentation

誤ったブランチへのコミットの付け直し

  • [初心者向け Gitで間違ったブランチにしたコミットを別ブランチに付け替える | DevelopersIO]
  • [Git誤ったブランチで実施した変更を正しいブランチに移動する | DevelopersIO]

ブランチを変えずに作業していて、コミット量が増えたので、別ブランチにしておけばよかったということがあったりする。

いくつか方法がある。

  1. cherry-pickで変更コミットだけ別ブランチに抽出。
  2. git checkoutとreset --hardで分離: 現在の状態を一旦別ブランチにしてコピー。その後、元ブランチはgit reset --hardで打ち消す。
  3. git rebase --onto <別ブランチ> 起点コミット でコミットを付け替えて、ブランチを削除、解明して元のブランチの名前にする。

git rebase --ontoがきれい。

他のブランチとの同一化

git diff HEAD master | patch -p 1

patchの他にgit applyでもいい。

remote

リモートトラッキングブランチという概念。

gitのpush/pull時の対象リモートリポジトリーのブランチのローカルの対応ブランチ。リモートブランチのデータのローカルの管理用。

  • git branch -u|--set-upstream-to <upstream>: リモートトラッキングブランチを指定。
  • git branch --unset-upstream: 設定済みのリモートトラッキングブランチの対応を解除。

Merge

rebase時のマージコミット維持

git rebase -iはマージコミットを削除してしまう。マージコミットを残したいなら、-rを指定する。昔は-pだった。

-rを忘れてしまった場合、git reflogでリベース前のコミットを探してgit reset --hardでそのコミットに戻してからやり直す。

マージコミット後のコミット追加

マージコミット後に次の開発作業を始めることが多い。が、直後の初回のコミットを追加したい場合困る。

git rebase -iにすると、コミットが残るから。編集はできるが、その直前にコミットの追加ができない。マージコミットは扱いが特殊で直接rebaseで編集できない。

しかたないので、該当コミットでブランチを作成して、コミット。その後、既存の修正ブランチをrebaseでそのコミットの後にくっつける。これでいける。

マージコミットの打ち消し

マージコミットは扱いがやや特殊。

git revert -m 1 マージコミット
git reset --hard HEAD~1 # マージコミット前

どちらか。

https://chatgpt.com/c/679983bc-a96c-800b-9d8c-a15873d1d068

git revert -mは1か2の数字を指定する。これは、マージはマージ元とマージ先の親ブランチが2個あり、どちらを基準にリバートするかを指定するためにある。

基本はマージ元 (mainやdevelopブランチ) の1を指定する。マージ先のfeatureブランチは2だがこちらを指定することはあまないだろう。

git checkoutなしのmerge

gitでブランチをマージする場合、基本はマージの取り込み元ブランチに移動してから、対象ブランチを取り込む必要がある。

これは、3wayマージなどのために、マージの元ファイルが必要だからとのこと。

ただ、毎回切り替えるのが面倒くさい。ブランチ同士でのマージが一応可能。

git fetch . src:dst

ただし、このコマンドはfast-fowardsマージの場合だけ。rebase相当。それ以外は上書きされるので、手動マージが必要。注意が必要。

スクリプトの自動処理などで使う感じ。

cherry-pick後のmergeで重複コミット

github - Git でCherry-pick 後に Mergeすると同じCommitの履歴が複数できてしまう - スタック・オーバーフロー

ブランチが2個あって、ブランチでコミット・pushした後、間違えたブランチだと気づいて、別ブランチでcherry-pick。その後、ブランチの内容を取り込むためにまたmergeしたら、cherry-pickのコミットのマージができる。

コミット履歴が残っているから、それを素直に取り込んだだけで、残るのは仕方ない。rebaseやreset --hardで消すしかないが、pushしているから、一人とかじゃないとだめ。

重複コミットは諦めるしかない。

マージコミット前後の比較

MC=cf128108e43b0d614528d2ab04fc9fa4188761e1
git diff ${MC}~ $MC

~でマージコミットの1個前のコミットを参照して差分をとればいい。

stash

復元

Git Stashの復元: 誤って削除されたスタッシュの復元方法 #Git-Stash - Qiita

git stash drop実行時に、削除したコミットのSHA1が表示される。

そのSHA1をapplyで指定すれば、取り込める。 git stash apply [stash_hash]

リモート

gitの不要なブランチを消すコマンド #Git - Qiita git fetch -p/--prune リモートの削除済みブランチをローカルに同期する。

リモートの最新タグ

https:/stackoverflow.com/questions/20734181/how-to-get-list-of-latest-tags-in-remote-git

git ls-remote --tag --sort=taggerdate

date関係のsortはオブジェクトへのアクセスが必要なので、ローカルにないとダメとか。

https:/git-scm.com/docs/git-ls-remote.html

https:/stackoverflow.com/questions/10649814/get-last-git-tag-from-a-remote-repo-without-cloning

git rev-listでいけそう。

https:/gist.github.com/rponte/fdc0724dd984088606b0

差分ファイル抽出

情報源: gitで差分ファイルを抽出する #Git - Qiita

git archiveとgit diffを組み合わせる。 git archive --format=zip --prefix=root/ HEAD `git diff --diff-filter=d --name-only HEAD^ HEAD` -o archive.zip ただし、この方法はファイル数がARG_MAX以下の場合だけ。ファイル数が多い場合だめ。

git diff --name-onlyで一覧を出力させて、1個ずつcp -pで階層を維持してコピーするしかないかも?

例: mkdir -p archive git diff --name-only new_base 44765_upgrade-base-version | xargs -i cp -p --parent "{}" archive/

core.autocrlf

warning: in the working copy of 'docker/README.md', LF will be replaced by CRLF the next time Git touches it

Windowsでは改行にCR+LFを使うが、mac/LinuxはLFのみ。これの違いの処理のための設定がcore.autoclrlf

  • true=コミット時にCRLFをLFに自動変換。チェックアウト時に逆。Windows向けの設定。
  • false=変換しない。
  • input=コミット時にCRLFをLFに自動変換のみ。mac/Linux向け。Windowsではチェックアウト時にCRLFになるが、mac/LinuxはLFになる。

わかりにくい。基本はfalseで良いと思われる。

gitkの文字化け対策

gitkのエンコーディングを設定する - Pistolfly

gitkはシステムのデフォルトエンコーディングで表示しようとするので、文字エンコーディングを指定しておく。 git config --global gui.encoding utf-8

ファイル名などの文字化け対策

Git for Windows で日本語を使いたい #Vim - Qiita git config --global core.quotepath false git config --global gui.encoding utf-8

改名と修正

改名と修正を同時にすると、改名を検知できない。

-Mオプションを指定すると、類似度で同時も検知できる。が、基本はリネーム・改名と修正は別コミットにしたほうがよさそう。

差分無視

git diffの--ignoreオプションにおけるスペース、タブ、改行の扱いを理解する #Git - Qiita

-wでインデント違いを無視してくれる。

squash

squashすると、squash対象コミットが、対象の直前のコミットに含められる。

gitignore

Git - gitignore Documentation

gitの管理対象外のファイル。ログや一時ファイルなど。

これで指定していないと、git addすると管理対象に入るし、untracked fileで表示が出る。git add .やディレクトリー指定で一括で管理したい場合に混ざっていると邪魔。

File

  • .gitignore: ディレクトリー内。
  • $GIT_DIR/info/exclude: リポジトリー固有のローカル。
  • core.excludesFile: ~/.gitconfig内で指定するgitignoreファイル。通常、$XDG_CONFIG_HOME/git/ignoreか$HOME/.config/git/ignore。

Format

記述方法を整理する。

  • 空行は無視。
  • #始まりの行はコメント扱い。
  • 終端スペースは無視。
  • !接頭辞はパターン否定。つまり、除外ではなく含める。以前除外された一致を再び含める。ただし、親ディレクトリーが除外されている場合、以下のファイルは含められない。パフォーマンス上の理由。順番に注意する。
  • /はディレクトリー区切りとして使用。先頭、中間、末尾で登場する。
    • 先頭と中間の/は相対パスを意味する。
    • それ以外、末尾の/と/なしの場合、現在以下のディレクトリーにもマッチする。
    • 末尾が/で終わる場合、ディレクトリーのみに一致。/がない場合、ディレクトリーとファイルの両方に一致。
  • *は/以外にマッチ。?は/以外の任意の1文字にマッチ。[a-zA-Z] の範囲記法も使用可能。fnmatch(3) FNM_PATHNAMEフラグのパス名展開に準じる。
  • **は特殊な意味がある。
    • **/=全ディレクトリー。**/fooは配下の全fooにマッチ。**/foo/barはfoo以下の全barにマッチ。
    • /**=配下のすべてにマッチ。
    • a/**/b=a/b a/x/b a/x/y/bのすべてにマッチ。

後は特に明記がないが、上から順番に評価されて、最後のマッチが優先されるので、記述の順番に注意する。

反転の!と/の扱いに特に注意が必要。

先頭スラッシュをつけないと、再帰的になる。

$ cat .gitignore

  1. ディレクトリ foo/bar 以外のすべてを除外
    1. /*
    2. !/foo
    3. /foo/*
    4. !/foo/bar

空ディレクトリーの維持

How do I add an empty directory to a Git repository? - Stack Overflow

gitは空ディレクトリーを履歴管理できない。何かファイルが必要。

logなど維持したい空ディレクトリーに、以下の内容の.gitignoreを置く。

!.gitignore

.gitignore以外を無視する。これで.gitignoreのみがあるので管理できる。

指定ファイルのみ除外

!.gitignore ディレクトリーを残す以外 (.gitignore1ファイル以外) に、サンプルファイルなど複数ファイルを残したい場合は、上記のように*で最初に全部除外して指定ファイルのみ含める。/は必要に応じてつける。

gitattributes

Git - gitattributes Documentation

gitignoreに似ていて、パターンにマッチしたパスに対する設定を行える。

  • text
  • eol
  • working-tree-encoding
  • ident
  • filter
  • diff
  • merge
  • conflict-marker-size
  • whitespace
  • export-ignore: git archiveなどに含めないことをマーク。
  • export-subst
  • delta
  • encoding

ファイルのインデックスのみ削除

git rmは単独だと、gitの履歴とローカルファイルからも削除する。追跡対象から削除のみで、ローカルファイルとして残したい場合、--cachedを指定する。 git rm --cached

Other

.netrc

https://social.senooken.jp/conversation/1573147#notice-2217499

Gitのパスワード入力の省略方法に~/.netrcがある。

しかし、man netrcするとわかるけど、これはもともとFTPのためのもの。なぜGitで使えるんだ?Gitの文書で言及がない。

In conversation Thursday, 21-Feb-2019 10:58:47 JST from web permalink

せのお (妹尾 賢)せのお (妹尾 賢) in reply to

理由が分かった。

1. Gitはhttpとhttpsの通信にcURLを使っている。

https://github.com/git/git/blob/master/INSTALL#L141

2. cURLが.netrcにも対応しているから。

https://ec.haxx.se/usingcurl-netrc.html

submodule

https://git-scm.com/docs/git-submodule

https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E3%82%B5%E3%83%96%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB

foreach

サブモジュールの全部を一括処理する。 foreach [--recursive] <command> <command>部分では$sm_pathでパスを参照できる。 git submodule foreach 'echo $sm_path `git rev-parse HEAD`'

Entering 'XXX' XXX hash submoduleの中に入ってから実行することに注意する。

便利なコマンド。 git submodule foreach 'git reset --hard'

gitk

problem

ブランチ名が長いと、右クリックしにくい

clean

git未管理のファイルを削除するためのコマンド。間違えると復元不能なので注意する。

必ず-nで削除対象を確認してから、-nの本実行を試すこと。

-x/-Xでgitignoreによる無視ファイルも削除できる。

Mac

  • /Library/Developer/CommandLineTools/usr/bin/git
  • /Library/Developer/CommandLineTools/usr/libexec/git-core/

上記2箇所がMac標準のgit関係の格納場所。

特に重要な補完ツールは以下にある。

  • /Library/Developer/CommandLineTools//usr/share/git-core/
    • git-completion.tcsh
    • git-completion.zsh
    • git-completion.bash
    • git-prompt.sh