日本語 ▾ トピック ▾ 最新バージョン ▾ gitfaq は 2.46.0 で最終更新されました

名前

gitfaq - Git の使用に関するよくある質問

概要

gitfaq

説明

このFAQの例では、`bash`や`dash`のような標準的なPOSIXシェルと、ホスティングプロバイダ`git.example.org`に`author`アカウントを持つユーザー A U Thor を想定しています。

設定

`user.name` には何を設定すればよいですか?

一般的に、あなたの個人名(名と姓を使った形式)を設定するべきです。例えば、Gitの現在のメンテナーは「Junio C Hamano」を使用しています。これは、あなたが行うすべてのコミットに保存される名前の部分になります。

この設定はリモートサービスへの認証には影響しません。それについては、git-config[1]の`credential.username`を参照してください。

`http.postBuffer` は実際に何をしますか?

このオプションは、GitがHTTPまたはHTTPS経由でリモートにデータをプッシュする際に使用するバッファのサイズを変更します。データがこのサイズより大きい場合、GitのHTTPサポートを処理するlibcurlは、プッシュされるデータのサイズが事前に不明なため、チャンク転送エンコーディングを使用します。

リモートサーバーまたは中間プロキシがHTTP/1.1(チャンク転送エンコーディングを導入したもの)をサポートしていないか、チャンクデータで壊れていることが分かっている場合を除き、この値をデフォルトサイズに設定したままで問題ありません。これは一般的なプッシュ問題の解決策としてしばしば(誤って)提案されますが、ほとんどすべてのサーバーとプロキシが少なくともHTTP/1.1をサポートしているため、この値を大きくしてもほとんどのプッシュ問題は通常解決しません。HTTP/1.1とチャンク転送エンコーディングを正しくサポートしていないサーバーやプロキシは、今日のインターネットでは多くのトラフィックを破壊するため、あまり有用ではありません。

この値を増やすと、GitがHTTPまたはHTTPS経由で行う関連するすべてのプッシュでメモリ使用量が増加することに注意してください。これは、バッファ全体が使用されるかどうかにかかわらず割り当てられるためです。したがって、異なる値が必要だと確信している場合を除き、デフォルトのままにしておくのが最善です。

別のエディタを設定するにはどうすればよいですか?

Git用にエディタを特に指定していない場合、デフォルトでは`VISUAL`または`EDITOR`環境変数で設定したエディタを使用します。どちらも指定されていない場合は、システムデフォルト(通常は`vi`)を使用します。`vi`を使いにくいと感じる人や、別のエディタを好む人もいるため、使用するエディタを変更することが望ましい場合があります。

ほとんどのプログラムで汎用エディタを設定したい場合、シェル設定(例: `~/.bashrc` または `~/.zshenv`)を編集し、`EDITOR`または`VISUAL`環境変数に適切な値を設定する行を追加できます。例えば、エディタ`nano`を好む場合、以下のように記述できます。

export VISUAL=nano

Git専用のエディタを設定したい場合、`core.editor`設定値または`GIT_EDITOR`環境変数を設定できます。これらのオプションが参照される順序の詳細については、git-var[1]を参照してください。

すべての場合において、エディタの値はシェルに渡されるため、スペースを含む引数は適切に引用符で囲む必要があることに注意してください。さらに、通常、エディタが呼び出されたときにターミナルからデタッチされる場合、それをしないようにする引数を指定する必要があります。そうしないと、Gitは変更を認識しません。Windowsでこれらの両方の問題に対処する設定の例は、ファイル名をスペース付きで引用符で囲み、プロセスをバックグラウンドで実行させないための`--nofork`オプションを指定する設定である`"C:\Program Files\Vim\gvim.exe" --nofork`です。

認証情報

HTTPでプッシュする際に認証情報を指定するにはどうすればよいですか?

これを行う最も簡単な方法は、`credential.helper`設定を介して認証ヘルパーを使用することです。ほとんどのシステムは、システム認証マネージャーと統合するための標準的な選択肢を提供しています。例えば、Git for Windowsは`wincred`認証マネージャーを、macOSは`osxkeychain`認証マネージャーを、標準的なデスクトップ環境を持つUnixシステムは`libsecret`認証マネージャーを使用できます。これらはすべて、パスワードやトークンを安全に保つために、暗号化されたストアに認証情報を保存します。

さらに、ホームディレクトリ内のファイルに保存する`store`認証マネージャー、または認証情報を永続的に保存しませんが、一定期間プロンプト表示を抑制する`cache`認証マネージャーを使用できます。

プロンプトが表示されたらパスワードを入力することもできます。パスワード(パーセントエンコードする必要がある)をURLに含めることも可能ですが、これは特に安全ではなく、認証情報の偶発的な漏洩につながる可能性があるため、推奨されません。

環境変数からパスワードやトークンを読み込むにはどうすればよいですか?

`credential.helper`設定オプションは、標準出力に認証プロトコルを出力する任意のシェルコマンドを受け取ることもできます。これは、例えばコンテナに認証情報を渡す場合に便利です。

そのようなシェルコマンドは、オプション値を感嘆符で始めることで指定できます。パスワードやトークンが`GIT_TOKEN`に保存されている場合、認証ヘルパーを設定するために以下のコマンドを実行できます。

$ git config credential.helper \
	'!f() { echo username=author; echo "password=$GIT_TOKEN"; };f'
認証マネージャーに保存したパスワードまたはトークンを変更するにはどうすればよいですか?

通常、パスワードまたはトークンが無効な場合、Gitはそれを消去し、新しいものを要求します。しかし、常にそうとは限らない場合があります。パスワードまたはトークンを変更するには、既存の認証情報を消去すると、Gitは新しいものを要求します。認証情報を消去するには、次のような構文を使用します(ユーザー名とホスト名を置き換えてください)。

$ echo url=https://author@git.example.org | git credential reject
HTTPを使用して同じホスティングプロバイダで複数のアカウントを使用するにはどうすればよいですか?

通常、これらのアカウントを区別する最も簡単な方法は、URLにユーザー名を使用することです。例えば、`git.example.org`に`author`と`committer`のアカウントがある場合、URL https://author@git.example.org/org1/project1.githttps://committer@git.example.org/org2/project2.git を使用できます。これにより、認証ヘルパーを使用する際に、アカウントの正しい認証情報を自動的に検索しようとします。すでにリモートが設定されている場合、`git remote set-url origin https://author@git.example.org/org1/project1.git` のようにURLを変更できます(詳細についてはgit-remote[1]を参照してください)。

SSHを使用して同じホスティングプロバイダで複数のアカウントを使用するにはどうすればよいですか?

SSHをサポートするほとんどのホスティングプロバイダでは、単一のキーペアが一意にユーザーを識別します。したがって、複数のアカウントを使用するには、各アカウントにキーペアを作成する必要があります。比較的新しいOpenSSHバージョンを使用している場合、`ssh-keygen -t ed25519 -f ~/.ssh/id_committer` のようなコマンドで新しいキーペアを作成できます。その後、公開鍵(この場合は`~/.ssh/id_committer.pub`です。`.pub`に注意してください)をホスティングプロバイダに登録できます。

ほとんどのホスティングプロバイダはプッシュに単一のSSHアカウントを使用します。つまり、すべてのユーザーは`git`アカウント(例: `git@git.example.org`)にプッシュします。あなたのプロバイダがそうである場合、SSHで複数のエイリアスを設定して、どのキーペアを使用するかを明確にすることができます。例えば、適切な秘密鍵ファイルに置き換えて、`~/.ssh/config`に以下のように記述できます。

# This is the account for author on git.example.org.
Host example_author
	HostName git.example.org
	User git
	# This is the key pair registered for author with git.example.org.
	IdentityFile ~/.ssh/id_author
	IdentitiesOnly yes
# This is the account for committer on git.example.org.
Host example_committer
	HostName git.example.org
	User git
	# This is the key pair registered for committer with git.example.org.
	IdentityFile ~/.ssh/id_committer
	IdentitiesOnly yes

その後、プッシュURLを`git@example.org`の代わりに`git@example_author`または`git@example_committer`を使用するように調整できます(例: `git remote set-url git@example_author:org1/project1.git`)。

転送

複数のシステム間で作業ツリーを同期するにはどうすればよいですか?

まず、これを行うかどうかを決めてください。Gitは、通常の`git push`および`git fetch`コマンドを使用して作業をプッシュまたはプルするときに最もよく機能し、複数のシステム間で作業ツリーを共有するように設計されていません。これは潜在的にリスクが高く、場合によってはリポジトリの破損やデータ損失を引き起こす可能性があります。

通常、そうすると`git status`は作業ツリー内のすべてのファイルを再読み込みする必要があります。さらに、Gitのセキュリティモデルは信頼できないユーザー間での作業ツリーの共有を許可していないため、作業ツリーがすべてのマシンで単一のユーザーによってのみ使用される場合にのみ、安全に同期できます。

クラウド同期サービスを使用してGitリポジトリの一部を同期しないことが重要です。これは、オブジェクトの欠落、ファイルの変更や追加、参照の破損、その他様々な問題など、破損を引き起こす可能性があるためです。これらのサービスは継続的にファイルごとに同期する傾向があり、Gitリポジトリの構造を理解していません。これは、リポジトリが更新されている最中に同期されると特に悪く、不完全または部分的な更新、ひいてはデータ損失につながる可能性が非常に高くなります。

発生しうる破損の一例は、参照の状態に関する競合です。これにより、両側が相手が持っていないブランチ上で異なるコミットを持つことになります。これにより、重要なオブジェクトが参照されなくなり、`git gc`によって刈り取られる可能性があり、データ損失を引き起こします。

したがって、通常のプッシュおよびプルメカニズムを使用して、作業を他のシステムまたは中央サーバーにプッシュする方が良いでしょう。ただし、これではスタッシュのような重要なデータが常に保持されるわけではないため、複数のシステム間で作業ツリーを共有することを好む人もいます。

これを行う場合、推奨される方法は、リポジトリのルートで`rsync -a --delete-after`を使用することです(理想的には`ssh`のような暗号化された接続を使用します)。これを行う際には、いくつかのことを確認する必要があります。

  • 追加のワークツリーまたは別のGitディレクトリがある場合、それらはメインの作業ツリーおよびリポジトリと同時に同期する必要があります。

  • 宛先ディレクトリがソースディレクトリの正確なコピーとなり、既存のデータをすべて削除することに同意できること。

  • 転送中、リポジトリ(すべてのワークツリーおよびGitディレクトリを含む)は静止状態にあること(つまり、`git gc`のようなバックグラウンド操作やエディタによって呼び出される操作を含め、いかなる種類の操作も行われていないこと)。

    これらの推奨事項に従ったとしても、この方法での同期はGitの通常のリポジトリ整合性チェックをバイパスするため、いくらかのリスクがあることに注意してください。したがって、バックアップを取ることが推奨されます。同期後、宛先システム上のデータの整合性を確認するために`git fsck`を実行することもおすすめします。

よくある問題

最後のコミットで間違いをしました。どうすれば変更できますか?

作業ツリーに適切な変更を加え、必要に応じて`git add <file>`または`git rm <file>`を実行してステージングし、その後`git commit --amend`を実行します。あなたの変更はコミットに含まれ、再度コミットメッセージを編集するよう促されます。元のメッセージをそのまま使用したい場合は、`git commit`に加えて`--no-edit`オプションを使用するか、エディタが開いたときに保存して終了するだけです。

バグのある変更を行ってしまい、それがメインブランチに含まれてしまいました。どうすれば元に戻せますか?

これに対処する一般的な方法は、`git revert`を使用することです。これは、元の変更が行われ、それが貴重な貢献であったという履歴を保持しますが、元の変更に問題があったためにそれらの変更を元に戻す新しいコミットも導入します。revertのコミットメッセージには、revertされたコミットが示され、通常はrevertが行われた理由の説明を含めるように編集されます。

追跡対象ファイルの変更を無視するにはどうすればよいですか?

Gitにはこれを行う方法がありません。その理由は、Gitがこのファイルを上書きする必要がある場合(チェックアウト時など)に、ファイルへの変更が貴重で保持すべきなのか、それとも無関係で安全に破棄できるのかを判断できないためです。したがって、安全な方法を取り、常にそれらを保持する必要があります。

`git update-index`の特定の機能、すなわちassume-unchangedビットとskip-worktreeビットを使用してみたくなるかもしれませんが、これらはこの目的には適切に機能せず、この方法で使用すべきではありません。

設定ファイルを変更することが目的の場合、リポジトリにテンプレートまたはデフォルトのセットとしてチェックインされたファイルを用意し、それをコピーして適宜変更できるようにすると便利な場合があります。この2番目の変更されたファイルは、誤ってコミットされるのを防ぐために通常は無視されます。

Gitに様々なファイルを無視するように指示したのに、それらがまだ追跡されています。

`gitignore`ファイルは、Gitによって追跡されていない特定のファイルが追跡されないままであることを保証します。しかし、`.gitignore`に追加する前に特定のファイルが追跡されていた場合があり、その結果、それらは引き続き追跡されたままになります。ファイルを追跡対象から外し、無視するには、`git rm --cached <file/pattern>`を使用し、<file>に一致するパターンを`.gitignore`に追加します。詳細についてはgitignore[5]を参照してください。

fetchとpullのどちらを実行すべきか、どうすればわかりますか?

fetchは、作業ツリーや現在のブランチを変更せずに、リモートリポジトリからの最新の変更のコピーを保存します。その後、都合の良い時にアップストリームの変更を検査したり、マージしたり、リベースしたり、無視したりできます。pullは、fetchの直後にマージまたはリベースを実行するものです。git-pull[1]を参照してください。

Gitでプロキシを使用できますか?

はい、Gitはプロキシの使用をサポートしています。GitはUnixで一般的に使用される標準の`http_proxy`、`https_proxy`、および`no_proxy`環境変数を尊重し、HTTPSの場合も`http.proxy`および同様のオプションで設定できます(git-config[1]を参照)。`http.proxy`および関連オプションは、URLパターンごとにカスタマイズできます。さらに、Gitは理論的にはネットワーク上に存在する透過型プロキシでも正常に機能します。

SSHの場合、GitはOpenSSHの`ProxyCommand`を使用してプロキシをサポートできます。一般的に使用されるツールには`netcat`や`socat`があります。ただし、標準入力でEOFを見ても終了しないように設定する必要があります。これは通常、`netcat`では`-q`が、`socat`では`-t 10`のようなタイムアウトが必要であることを意味します。これは、Git SSHサーバーがこれ以上リクエストが行われないことを知る方法が標準入力でのEOFだからですが、その時点でサーバーが最終リクエストをまだ処理していない可能性があり、その時点で接続を切断するとそのリクエストが中断されるため、これが必要となります。

HTTPプロキシを使用した`~/.ssh/config`の設定エントリの例は次のようになります。

Host git.example.org
    User git
    ProxyCommand socat -t 10 - PROXY:proxy.example.org:%h:%p,proxyport=8080

すべての場合において、Gitが正しく機能するためには、プロキシは完全に透過的でなければならないことに注意してください。プロキシは接続をいかなる方法でも変更、改ざん、またはバッファリングしてはならず、そうしないとGitはほぼ確実に機能しません。多くのTLSミドルボックス、Windows DefenderおよびWindows Firewall以外のWindowsアンチウイルスおよびファイアウォールプログラム、フィルタリングプロキシを含む多くのプロキシがこの基準を満たしておらず、その結果Gitを壊すことになることに注意してください。問題の報告が多く、セキュリティ履歴も貧弱であるため、これらの種類のソフトウェアやデバイスの使用は推奨しません。

マージとリベース

長期ブランチをスカッシュマージでマージする際に発生しうる問題にはどのようなものがありますか?

一般に、スカッシュマージを使用して2つのブランチを複数回マージする際に、様々な問題が発生する可能性があります。これには、`git log`の出力、GUI、または範囲を表す`...`表記を使用する際に余分なコミットが表示されたり、競合を何度も再解決する必要がある可能性が含まれます。

Gitが2つのブランチ間で通常のマージを行う際、正確に3つの点を考慮します。それは、2つのブランチと、通常はコミットの共通の祖先であるマージベースと呼ばれる3番目のコミットです。マージの結果は、マージベースと各ヘッド間の変更の合計です。通常のコミットで2つのブランチをマージすると、新しいコミットが作成され、それが再度マージされるときにマージベースとして機能します。なぜなら、新しい共通の祖先ができたからです。Gitはマージベース以前に発生した変更を考慮する必要がないため、以前に解決した競合を再度解決する必要はありません。

スカッシュマージを実行すると、マージコミットは作成されません。代わりに、一方の変更がもう一方に通常のコミットとして適用されます。これは、これらのブランチのマージベースが変更されず、Gitが次のマージを実行するときに、前回考慮したすべての変更に加えて新しい変更も考慮することを意味します。つまり、競合を再解決する必要がある場合があります。同様に、`git diff`、`git log`、またはGUIで`...`表記を使用するものはすべて、元のマージベース以降のすべての変更を表示することになります。

その結果、長期にわたる2つのブランチを繰り返しマージしたい場合は、常に通常のコミットを使用するのが最善です。

2つのブランチで変更を行い、片方でそれをrevertした場合、なぜそれらのブランチのマージにその変更が含まれるのですか?

デフォルトでは、Gitがマージを行う際、`ort`戦略と呼ばれる高度な3方向マージ戦略を使用します。このような場合、Gitがマージを実行する際には、正確に3つの点を考慮します。それは、2つのヘッドと、通常それらのコミットの共通の祖先であるマージベースと呼ばれる3番目の点です。Gitは、それらのブランチで発生した履歴や個々のコミットを一切考慮しません。

結果として、両側に変更があり、片側がその変更をrevertした場合、その変更が含まれることになります。これは、片側のコードが変更され、もう一方には正味の変更がないためであり、このシナリオではGitはその変更を採用します。

これが問題となる場合、代わりにリベースを行うことができます。revertを含むブランチを別のブランチにリベースするのです。このシナリオでのリベースは、revertを含む個々のコミットを適用するため、変更を元に戻します。リベースは履歴を書き換えるため、公開されたブランチをリベースすることは、その変更に納得できる場合を除いて避けるべきであることに注意してください。詳細については、git-rebase[1]のNOTESセクションを参照してください。

フック

フックを使用して、ユーザーが特定の変更を行うのを防ぐにはどうすればよいですか?

これらの変更を行う唯一安全な場所は、リモートリポジトリ(つまりGitサーバー)であり、通常は`pre-receive`フックまたは継続的インテグレーション(CI)システムです。これらはポリシーを効果的に強制できる場所です。

これらのことをチェックするために`pre-commit`フック(またはコミットメッセージの場合は`commit-msg`フック)を使用しようとすることがよくあります。これは、あなたが単独の開発者として作業しており、ツールがあなたを助けてほしい場合には素晴らしいことです。しかし、開発者のマシンでフックを使用することはポリシー制御としては効果的ではありません。なぜなら、ユーザーは`--no-verify`を使ってこれらのフックを気づかれずにバイパスできるからです(他にも様々な方法があります)。Gitは、ユーザーが自分のローカルリポジトリを制御していると仮定しており、これを防ごうとしたり、ユーザーを告げ口したりすることはありません。

さらに、一部の高度なユーザーは、`pre-commit`フックが一時的なコミットを使用して作業中の変更をステージングしたり、fixupコミットを作成したりするワークフローの妨げになると感じているため、これらの種類のチェックはやはりサーバーにプッシュする方が良いでしょう。

クロスプラットフォームの問題

Windowsを使用していますが、テキストファイルがバイナリとして検出されます。

GitはテキストファイルをUTF-8で保存する場合に最もよく機能します。Windows上の多くのプログラムはUTF-8をサポートしていますが、一部のプログラムはそうではなく、Gitがバイナリとして検出するリトルエンディアンのUTF-16形式のみを使用します。プログラムでUTF-8を使用できない場合でも、リポジトリにファイルをUTF-8で保存したまま、ファイルをチェックアウトする際のエンコーディングを示す作業ツリーエンコーディングを指定できます。これにより、git-diff[1]のようなツールが期待通りに機能し、同時にあなたのツールも機能することができます。

そのためには、`working-tree-encoding`属性を持つgitattributes[5]パターンを指定できます。例えば、次のパターンはすべてのCファイルにUTF-16LE-BOMを使用するように設定します。これはWindowsで一般的なエンコーディングです。

*.c	working-tree-encoding=UTF-16LE-BOM

これを有効にするには、`git add --renormalize`を実行する必要があります。クロスプラットフォームで使用されるプロジェクトでこれらの変更を行う場合、リポジトリ内の`.gitattributes`ファイルで行うとリポジトリのすべてのユーザーに適用されるため、おそらくユーザーごとの設定ファイル、または`$GIT_DIR/info/attributes`内のファイルで設定することを推奨します。

行末の正規化に関する情報については以下の項目を、属性ファイルに関する詳細についてはgitattributes[5]を参照してください。

Windowsを使用していますが、`git diff`でファイルの末尾に`^M`が表示されます。

デフォルトでは、GitはファイルをUnixスタイルの行末で保存することを想定しています。そのため、Windowsの行末の一部であるキャリッジリターン(`^M`)は、末尾の空白文字と見なされるため表示されます。Gitは、新しい行のみに末尾の空白文字を表示し、既存の行には表示しないのがデフォルトです。

リポジトリにファイルをUnixスタイルの行末で保存し、それらを自動的にプラットフォームの行末に変換することができます。そのためには、設定オプション`core.eol`を`native`に設定し、ファイルをテキストまたはバイナリとして設定する方法については推奨されるストレージ設定に関する質問を参照してください。

行末からキャリッジリターンを削除したくない場合は、`core.whitespace`設定でこの動作を制御することもできます。

常に変更されているファイルがあるのはなぜですか?

内部的には、Gitはファイル名を常にバイトシーケンスとして保存し、エンコーディングや大文字小文字の折りたたみを行いません。しかし、WindowsとmacOSはデフォルトでファイル名の大文字小文字の折りたたみを行います。その結果、名前が大文字小文字のみ異なる複数のファイルやディレクトリが存在する可能性があります。Gitはこれを問題なく処理できますが、ファイルシステムはこれらのファイルのうち1つしか保存できないため、Gitが別のファイルを読み込んでその内容を確認しようとすると、変更されているように見えます。

ファイルが1つになるように、どちらか一方を削除するのが最善です。これは、他にクリーンな作業ツリーがある状態で、以下のコマンド(`AFile.txt`と`afile.txt`の2つのファイルがある場合を想定)を使用して行うことができます。

$ git rm --cached AFile.txt
$ git commit -m 'Remove files conflicting in case'
$ git checkout .

これにより、ディスクに触れることなく、追加のファイルが削除されます。プロジェクトでは、この問題が再び発生するのを避けるために、すべて小文字の名前を使用するなどの命名規則を採用することを推奨する場合があります。このような規則は、`pre-receive`フックまたは継続的インテグレーション(CI)システムの一部としてチェックできます。

また、システムでsmudgeまたはcleanフィルターが使用されているにもかかわらず、以前にsmudgeまたはcleanフィルターを実行せずにファイルがコミットされた場合、どのプラットフォームでも常に変更されているファイルが発生する可能性があります。これを修正するには、他にクリーンな作業ツリーがある状態で、以下を実行します。

$ git add --renormalize .

GIT

git[1]スイートの一部

scroll-to-top